fdc14404b2
Project CI / AI game creator shell Rust lane 2/2 (push) Has been cancelled
Project CI / AI game creator shell Rust crates (push) Has been cancelled
Project CI / Backend tests (push) Has been cancelled
Project CI / Native shell tests (push) Has been cancelled
Project CI / Frontend tests (push) Has been cancelled
Project CI / Repository checks (push) Has been cancelled
Project CI / AI game creator shell web tests (push) Has been cancelled
Project CI / AI game creator shell Rust lane 1/2 (push) Has been cancelled
Project CI / AI game creator shell Rust smoke (push) Has been cancelled
新增 Genarrative-Scheduled-Release-Trigger,每天 04:00 发布 Windows/macOS release 渠道 release 调度复用统一发号源,并为 macOS 启用过期构建让位 现有小时 dev 调度保持同时触发 Windows 与 macOS 更新生产运维门禁、发号权限、技术方案与共享记忆
182 lines
9.0 KiB
Plaintext
182 lines
9.0 KiB
Plaintext
// AGC release 每日调度管线:每天 04:00 检查源码分支,
|
||
// 只有上一轮 release 调度之后出现客户端相关路径变更时,才用同一个固定 commit
|
||
// 触发 AGC Windows/macOS 两个 release 分区构建。
|
||
pipeline {
|
||
agent {
|
||
label 'linux && genarrative-build'
|
||
}
|
||
|
||
options {
|
||
disableConcurrentBuilds()
|
||
skipDefaultCheckout(true)
|
||
buildDiscarder(logRotator(numToKeepStr: '100', artifactNumToKeepStr: '10'))
|
||
}
|
||
|
||
triggers {
|
||
cron('0 4 * * *')
|
||
}
|
||
|
||
environment {
|
||
GIT_REMOTE_URL = 'ssh://git@127.0.0.1:2222/GenarrativeAI/Genarrative.git'
|
||
GIT_REMOTE_CREDENTIAL_ID = 'genarrative-local-gitea-ssh'
|
||
AGC_WINDOWS_BUILD_JOB_NAME = 'Genarrative-Agc-Windows-Build'
|
||
AGC_MACOS_BUILD_JOB_NAME = 'Genarrative-Agc-MacOS-Build'
|
||
AGC_GLOBAL_VERSION_JOB_NAME = 'Genarrative-Agc-Global-Version-Issue'
|
||
AGC_GLOBAL_VERSION_ARTIFACT = 'agc-global-version.txt'
|
||
REVISION_STATE_FILE = '.jenkins-last-release-revision'
|
||
AGC_SCOPE_CACHE_DIR = '.agc-release-scope-cache'
|
||
}
|
||
|
||
parameters {
|
||
string(name: 'SOURCE_BRANCH', defaultValue: 'master', description: '被检查的源码分支;默认 master')
|
||
booleanParam(name: 'FORCE_TRIGGER', defaultValue: false, description: '勾选后忽略版本与路径比较,强制发布 AGC release 渠道')
|
||
}
|
||
|
||
stages {
|
||
stage('Resolve Revision') {
|
||
steps {
|
||
withCredentials([sshUserPrivateKey(credentialsId: env.GIT_REMOTE_CREDENTIAL_ID, keyFileVariable: 'GENARRATIVE_GIT_SSH_KEY')]) {
|
||
sh '''#!/usr/bin/env bash
|
||
set -euo pipefail
|
||
export GIT_SSH_COMMAND="ssh -i ${GENARRATIVE_GIT_SSH_KEY:?缺少 Git SSH 凭据} -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new"
|
||
revision="$(git ls-remote "${GIT_REMOTE_URL:?缺少 GIT_REMOTE_URL}" "refs/heads/${SOURCE_BRANCH}" | awk 'NR == 1 { print $1 }')"
|
||
if [[ ! "${revision}" =~ ^[0-9a-f]{40}$ ]]; then
|
||
echo "无法解析远端分支版本: branch=${SOURCE_BRANCH} revision=${revision:-<empty>}" >&2
|
||
exit 1
|
||
fi
|
||
printf '%s' "${revision}" > .jenkins-remote-revision
|
||
echo "release 远端版本: branch=${SOURCE_BRANCH} revision=${revision}"
|
||
'''
|
||
}
|
||
script {
|
||
env.REMOTE_REVISION = readFile('.jenkins-remote-revision').trim()
|
||
env.LAST_TRIGGERED_REVISION = fileExists(env.REVISION_STATE_FILE) ? readFile(env.REVISION_STATE_FILE).trim() : ''
|
||
env.REVISION_CHANGED = (params.FORCE_TRIGGER || env.LAST_TRIGGERED_REVISION != env.REMOTE_REVISION) ? 'true' : 'false'
|
||
if (env.REVISION_CHANGED != 'true') {
|
||
currentBuild.result = 'NOT_BUILT'
|
||
currentBuild.description = "release 版本未变化,跳过:${env.SOURCE_BRANCH} 仍是 ${env.REMOTE_REVISION.take(12)}"
|
||
echo currentBuild.description
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
stage('Resolve AGC Release Scope') {
|
||
when {
|
||
expression { return env.REVISION_CHANGED == 'true' }
|
||
}
|
||
steps {
|
||
withCredentials([sshUserPrivateKey(credentialsId: env.GIT_REMOTE_CREDENTIAL_ID, keyFileVariable: 'GENARRATIVE_GIT_SSH_KEY')]) {
|
||
script {
|
||
// 判定失败一律按「需要发布」处理,避免路径过滤阻塞客户端发布。
|
||
def output = 'agc=changed'
|
||
try {
|
||
output = sh(script: '''#!/usr/bin/env bash
|
||
set -uo pipefail
|
||
export GIT_SSH_COMMAND="ssh -i ${GENARRATIVE_GIT_SSH_KEY:?缺少 Git SSH 凭据} -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new"
|
||
previous="$(cat "${REVISION_STATE_FILE}" 2>/dev/null || true)"
|
||
if [[ -z "${previous}" ]]; then
|
||
printf 'agc=changed\n'
|
||
exit 0
|
||
fi
|
||
mkdir -p "${AGC_SCOPE_CACHE_DIR}"
|
||
if [[ ! -d "${AGC_SCOPE_CACHE_DIR}/.git" ]]; then
|
||
git -C "${AGC_SCOPE_CACHE_DIR}" init --quiet
|
||
git -C "${AGC_SCOPE_CACHE_DIR}" remote add origin "${GIT_REMOTE_URL}" 2>/dev/null || true
|
||
fi
|
||
refspec="+refs/heads/${SOURCE_BRANCH}:refs/remotes/origin/${SOURCE_BRANCH}"
|
||
if ! git -C "${AGC_SCOPE_CACHE_DIR}" fetch --quiet --depth=200 --no-tags --filter=blob:none origin "${refspec}"; then
|
||
git -C "${AGC_SCOPE_CACHE_DIR}" fetch --quiet --depth=200 --no-tags origin "${refspec}" || { printf 'agc=changed\n'; exit 0; }
|
||
fi
|
||
if ! git -C "${AGC_SCOPE_CACHE_DIR}" cat-file -e "${previous}^{commit}" 2>/dev/null; then
|
||
echo "浅取窗口内没有 ${previous},按需要发布处理" >&2
|
||
printf 'agc=changed\n'
|
||
exit 0
|
||
fi
|
||
changed_paths="$(git -C "${AGC_SCOPE_CACHE_DIR}" diff --name-only "${previous}" "${REMOTE_REVISION}" 2>/dev/null || true)"
|
||
agc_scope=unchanged
|
||
while IFS= read -r changed_path; do
|
||
[[ -z "${changed_path}" ]] && continue
|
||
case "${changed_path}" in
|
||
apps/ai-game-creator-shell/*|packages/*|server-rs/crates/*|plugins/agc-cocos-editor/*|plugins/agc-unity-editor/*|plugins/agc-godot-editor/*|apps/desktop-shell/src-tauri/icons/*|package.json|package-lock.json)
|
||
agc_scope=changed
|
||
;;
|
||
esac
|
||
done <<< "${changed_paths}"
|
||
printf 'agc=%s\n' "${agc_scope}"
|
||
''', returnStdout: true).trim()
|
||
} catch (error) {
|
||
echo "release 发布范围判定失败,按需要发布处理:${error}"
|
||
output = 'agc=changed'
|
||
}
|
||
def values = output.split('\n').collect { it.trim() }.findAll { it }
|
||
def entry = values.find { it.startsWith('agc=') }
|
||
def value = entry == null ? '' : entry.split('=')[1]
|
||
env.AGC_RELEASE_SCOPE = (value == 'unchanged') ? 'unchanged' : 'changed'
|
||
echo "release 发布范围:AGC=${env.AGC_RELEASE_SCOPE}(上一轮已触发 revision=${env.LAST_TRIGGERED_REVISION ?: '无'})"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
stage('Trigger AGC Release Builds') {
|
||
when {
|
||
expression { return env.REVISION_CHANGED == 'true' }
|
||
}
|
||
steps {
|
||
script {
|
||
def pinnedRevision = env.REMOTE_REVISION
|
||
def agcTriggered = false
|
||
if (params.FORCE_TRIGGER || env.AGC_RELEASE_SCOPE != 'unchanged') {
|
||
// Windows 与 macOS 共用一个总号;发号 Job 是唯一发号源。
|
||
def versionRun = build job: env.AGC_GLOBAL_VERSION_JOB_NAME,
|
||
wait: true,
|
||
propagate: true,
|
||
parameters: [
|
||
string(name: 'SOURCE_BRANCH', value: env.SOURCE_BRANCH),
|
||
string(name: 'COMMIT_HASH', value: pinnedRevision),
|
||
string(name: 'AGC_CHANNEL', value: 'release-unified'),
|
||
]
|
||
copyArtifacts(
|
||
projectName: env.AGC_GLOBAL_VERSION_JOB_NAME,
|
||
selector: specific(versionRun.number.toString()),
|
||
filter: env.AGC_GLOBAL_VERSION_ARTIFACT,
|
||
target: '.',
|
||
flatten: true,
|
||
)
|
||
env.AGC_GLOBAL_VERSION = readFile(env.AGC_GLOBAL_VERSION_ARTIFACT).trim()
|
||
echo "本轮 AGC release 客户端总版本号: ${env.AGC_GLOBAL_VERSION}"
|
||
def agcParameters = [
|
||
string(name: 'SOURCE_BRANCH', value: env.SOURCE_BRANCH),
|
||
string(name: 'COMMIT_HASH', value: pinnedRevision),
|
||
string(name: 'AGC_UPDATE_CHANNEL', value: 'release'),
|
||
string(name: 'AGC_RELEASE_VERSION', value: env.AGC_GLOBAL_VERSION),
|
||
]
|
||
build job: env.AGC_WINDOWS_BUILD_JOB_NAME, wait: false, propagate: false, parameters: agcParameters
|
||
// macOS 节点是办公机:离线期间排队的旧构建在节点回来后必须自行让位。
|
||
def agcMacosParameters = agcParameters + [
|
||
booleanParam(name: 'SKIP_IF_SUPERSEDED', value: true),
|
||
]
|
||
build job: env.AGC_MACOS_BUILD_JOB_NAME, wait: false, propagate: false, parameters: agcMacosParameters
|
||
agcTriggered = true
|
||
} else {
|
||
echo "上一轮 release 调度后没有 AGC 客户端相关变更,跳过 ${env.AGC_WINDOWS_BUILD_JOB_NAME} 与 ${env.AGC_MACOS_BUILD_JOB_NAME};需要强制发布时勾选 FORCE_TRIGGER"
|
||
}
|
||
writeFile file: env.REVISION_STATE_FILE, text: pinnedRevision
|
||
def target = "${env.SOURCE_BRANCH}@${pinnedRevision.take(12)}"
|
||
currentBuild.description = agcTriggered
|
||
? "已触发 AGC release:${env.AGC_WINDOWS_BUILD_JOB_NAME} 与 ${env.AGC_MACOS_BUILD_JOB_NAME} ${target}"
|
||
: "本轮没有 AGC 客户端相关变更,未触发 release 发布:${target}"
|
||
echo currentBuild.description
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
post {
|
||
always {
|
||
echo "release 调度结束: branch=${env.SOURCE_BRANCH} revision=${env.REMOTE_REVISION ?: ''} changed=${env.REVISION_CHANGED ?: ''} agcScope=${env.AGC_RELEASE_SCOPE ?: ''}"
|
||
}
|
||
}
|
||
}
|