新增 AGC release 每日调度
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
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 更新生产运维门禁、发号权限、技术方案与共享记忆
This commit is contained in:
@@ -1,5 +1,13 @@
|
||||
# 决策记录
|
||||
|
||||
## 2026-09-22 AGC release 增加每日调度,dev 调度保持双平台
|
||||
|
||||
- 背景:原有 `Genarrative-Scheduled-Revision-Trigger` 每小时跟随 revision 发布 dev 客户端,但没有对应的 release 渠道自动入口;Mac 节点此前已纳入小时 dev 调度,需要避免新增 release 调度时再退回 Windows-only。
|
||||
- 决策:新增 `Genarrative-Scheduled-Release-Trigger`,每天 04:00 检查 `SOURCE_BRANCH`,使用独立的 `.jenkins-last-release-revision` 与客户端相关路径白名单;上一轮 release 调度后有客户端变更时,先经 `Genarrative-Agc-Global-Version-Issue` 发统一总号,再以同一固定 `COMMIT_HASH` 触发 `Genarrative-Agc-Windows-Build` 与 `Genarrative-Agc-MacOS-Build` 的 `AGC_UPDATE_CHANNEL=release` 分区,Mac 继续带 `SKIP_IF_SUPERSEDED=true`。小时 dev 调度保持同时触发 Windows 与 macOS dev。
|
||||
- 原因:release 与 dev 是不同渠道和发布节奏,不能靠同一个小时 Job 隐式切换;独立 Job 能分别去重、记录状态和审计发号。release 调度不触发 Full Build,避免把桌面客户端发布与线上全栈部署绑定。
|
||||
- 影响范围:`jenkins/Jenkinsfile.scheduled-release-trigger`、`jenkins/scheduled-release-trigger-job-config.xml`、`jenkins/Jenkinsfile.agc-global-version-issue`、`scripts/check-production-ops-guardrails.mjs`、开发运维文档、共享开发工作流与 AGC 总版本号技术方案。
|
||||
- 验证方式:`npm run check:production-ops` 校验 release Job 的 cron、发号、双平台 release 参数、Mac 让位和 Copy Artifact 授权;`npm run check:encoding` 与 `git diff --check` 校验文件与补丁。
|
||||
|
||||
## 2026-09-21 合并 origin/master:Supervisor 永久退役,策划 V1V2 退役落到当前两条产品路径
|
||||
|
||||
- 背景:`refactor/split-direct-project`(DirectProject 独立聊天容器)与 `origin/master`(#355 退役策划 Agent V1/V2)在 2026-09-18 之后各走一条线:本分支删掉 Supervisor 前端链路、把立项策划收敛到 `view/project-development/planning/`,master 删掉整套策划 V1/V2(前端会话 / 审批卡 / 适配器 / 类型与 Rust `planning_*_v2` 命令、`planning_gdd_model.rs`、`planning_policy_v2.rs`、`planning_session_v2.rs`)只保留 Design Agent。两边都在删 Supervisor,冲突集中在 `App.tsx`、聊天视图(`PlanningChatView`、`DirectProjectTurn`、`ToolCallGroup`)、Direct composer / 引用输入区、`styles.css`、Rust direct user item 与 appSurface 用例。
|
||||
|
||||
@@ -92,7 +92,7 @@ SpacetimeDB 任务统一先读取 `.codex/skills/genarrative-spacetimedb/SKILL.m
|
||||
|
||||
## Jenkins 定时版本调度
|
||||
|
||||
定时与版本比较只保留在 `Genarrative-Scheduled-Revision-Trigger` 一处:每小时用 `git ls-remote` 解析 `SOURCE_BRANCH` 远端 HEAD,与上一次触发过的 revision 比较,变化时才把同一个 `COMMIT_HASH` 传给 `Genarrative-Full-Build-And-Deploy`,并先经 `Genarrative-Agc-Global-Version-Issue` 发号、再把同一个总版本号透传给 `Genarrative-Agc-Windows-Build` 与 `Genarrative-Agc-MacOS-Build`,保证两个客户端的平台分区发布同一个版本。这三个下游 Job 都不得自带 `triggers` / `cron`,也不得在管线内再做一套版本去重;`npm run check:production-ops` 会拦住这两类回退。macOS 节点是日常办公机,调度触发它时置 `SKIP_IF_SUPERSEDED=true`:节点离线期间排队的旧构建在恢复后会自行让位,不发布过期版本。调度状态与生效步骤见 `docs/【开发运维】本地开发验证与生产运维-2026-05-15.md`。
|
||||
定时与版本比较收口到两条调度器:`Genarrative-Scheduled-Revision-Trigger` 每小时处理 dev 渠道,变化时触发 Full Build、AGC Windows/macOS dev,并让两个客户端平台共用同一个总版本号;`Genarrative-Scheduled-Release-Trigger` 每天 04:00 处理 AGC release 渠道,只在上一轮 release 调度后出现客户端相关路径变化时,经 `Genarrative-Agc-Global-Version-Issue` 发同一个总号并触发 AGC Windows/macOS release。各下游 Job 都不得自带 `triggers` / `cron`,也不得在管线内再做一套版本去重;`npm run check:production-ops` 会拦住回退。macOS 节点是日常办公机,两条调度触发它时都置 `SKIP_IF_SUPERSEDED=true`:节点离线期间排队的旧构建在恢复后会自行让位,不发布过期版本。调度状态与生效步骤见 `docs/【开发运维】本地开发验证与生产运维-2026-05-15.md`。
|
||||
|
||||
## Gitea CI 依赖闭合
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# AGC 总版本号与发号
|
||||
|
||||
更新时间:`2026-09-20`
|
||||
更新时间:`2026-09-22`
|
||||
|
||||
## 背景
|
||||
|
||||
@@ -18,7 +18,7 @@ AGC 客户端此前按「渠道各自比高水位自增」发号:`dev-win` 与
|
||||
|
||||
- `next = 总号 + 1`;总号不存在时先一次性播种,见下节。
|
||||
- 顺序固定为「先写总号 → 再构建 → 再发渠道清单」;任何一步失败都不回滚,只烧号。
|
||||
- 统一构建:发一次号,通过 `AGC_RELEASE_VERSION` 同时传给 `dev-win`、`dev-mac`(以及后续渠道),各渠道共用同一个号。
|
||||
- 统一构建:发一次号,通过 `AGC_RELEASE_VERSION` 同时传给同一渠道组的两个平台;dev 调度写 `dev-win` / `dev-mac`,每日 release 调度写 `release-win` / `release-mac`,组内共用同一个号。
|
||||
- 单渠道热修:发一次号,只传给该渠道;其他渠道清单保持原值。
|
||||
- 显式传入 `AGC_RELEASE_VERSION` 的构建不再自行发号,只做高水位断言。
|
||||
|
||||
@@ -39,8 +39,8 @@ AGC 客户端此前按「渠道各自比高水位自增」发号:`dev-win` 与
|
||||
- 发号模块:`apps/ai-game-creator-shell/scripts/agc-global-version.mjs`(读总号 / 播种 / 发号 / 写后回读 / 渠道高水位断言 / dry-run 预览)。
|
||||
- 发号入口:`apps/ai-game-creator-shell/scripts/issue-global-version.mjs`(CI 与本地共用,输出固定为 `AGC_GLOBAL_VERSION=<version>`)。
|
||||
- 构建侧:`build-release.mjs` 的 `prepareReleaseVersion()` 优先采用传入总号,未传入时现场发号;`resolveRemoteHighWaterVersion()` 降级为断言来源,只用于「请求号低于本渠道清单版本即失败关闭」。
|
||||
- CI:`jenkins/Jenkinsfile.agc-global-version-issue` + `jenkins/agc-global-version-issue-job-config.xml`;调度管线 `jenkins/Jenkinsfile.scheduled-revision-trigger` 与手动管线先调发号 Job,再把号透传给 AGC Build。
|
||||
- 发号 Job 的 Copy Artifact 采用生产权限模式,`options` 里的 `copyArtifactPermission(...)` 必须显式列出**全部**消费者:定时调度 `Genarrative-Scheduled-Revision-Trigger` 与手动发布 `Genarrative-Manual-Build-And-Deploy`。用户触发的构建按「认证用户」判权(SYSTEM 定时构建短路放行),漏列时手动发布会报 `Unable to find project for artifact copy: Genarrative-Agc-Global-Version-Issue`,且失败点在发号之后。改完该 `options` 后必须先单独跑一次发号 Job,让 Declarative Pipeline 把 Job property 写回 Jenkins。
|
||||
- CI:`jenkins/Jenkinsfile.agc-global-version-issue` + `jenkins/agc-global-version-issue-job-config.xml`;dev 调度管线 `jenkins/Jenkinsfile.scheduled-revision-trigger`、每日 release 调度管线 `jenkins/Jenkinsfile.scheduled-release-trigger` 与手动管线先调发号 Job,再把号透传给 AGC Build。
|
||||
- 发号 Job 的 Copy Artifact 采用生产权限模式,`options` 里的 `copyArtifactPermission(...)` 必须显式列出**全部**消费者:小时 dev 调度 `Genarrative-Scheduled-Revision-Trigger`、每日 release 调度 `Genarrative-Scheduled-Release-Trigger` 与手动发布 `Genarrative-Manual-Build-And-Deploy`。用户触发的构建按「认证用户」判权(SYSTEM 定时构建短路放行),漏列时手动发布会报 `Unable to find project for artifact copy: Genarrative-Agc-Global-Version-Issue`,且失败点在发号之后。改完该 `options` 后必须先单独跑一次发号 Job,让 Declarative Pipeline 把 Job property 写回 Jenkins。
|
||||
|
||||
## 不改的东西
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -16,14 +16,15 @@ pipeline {
|
||||
skipDefaultCheckout(true)
|
||||
buildDiscarder(logRotator(numToKeepStr: '100', artifactNumToKeepStr: '20'))
|
||||
// Copy Artifact 保持 Production 权限模式:生产者必须显式授权消费者。
|
||||
// 调度管线与手动发布管线都要 copy 本 Job 的 agc-global-version.txt 才能把总号
|
||||
// 所有调度与手动发布管线都要 copy 本 Job 的 agc-global-version.txt 才能把总号
|
||||
// 透传给渠道构建;缺授权时 copyArtifacts 会报「Unable to find project for
|
||||
// artifact copy」(用户触发的构建按「认证用户」判权,SYSTEM 定时构建会短路放行,
|
||||
// 所以定时调度能过、手动发布必挂;2026-09-20 #103 与 2026-09-21 手动发布
|
||||
// #6/#7 均命中)。这里必须同时列出两条消费者:Genarrative-Scheduled-Revision-Trigger
|
||||
// 与 Genarrative-Manual-Build-And-Deploy。改完本文件后必须先单独跑一次本 Job,
|
||||
// 让 Declarative Pipeline 把 Job property 写回 Jenkins,再重跑调度或手动发布。
|
||||
copyArtifactPermission('Genarrative-Scheduled-Revision-Trigger,Genarrative-Manual-Build-And-Deploy')
|
||||
// #6/#7 均命中)。这里必须列出全部消费者:Genarrative-Scheduled-Revision-Trigger、
|
||||
// Genarrative-Scheduled-Release-Trigger 与 Genarrative-Manual-Build-And-Deploy。
|
||||
// 改完本文件后必须先单独跑一次本 Job,让 Declarative Pipeline 把 Job property
|
||||
// 写回 Jenkins,再重跑调度或手动发布。
|
||||
copyArtifactPermission('Genarrative-Scheduled-Revision-Trigger,Genarrative-Scheduled-Release-Trigger,Genarrative-Manual-Build-And-Deploy')
|
||||
}
|
||||
|
||||
environment {
|
||||
@@ -34,7 +35,7 @@ pipeline {
|
||||
}
|
||||
|
||||
parameters {
|
||||
choice(name: 'AGC_CHANNEL', choices: ['unified', 'dev-win', 'dev-mac'], description: '发号用途:unified 为统一构建(一个号同时给 dev-win 与 dev-mac),其余为单渠道热修')
|
||||
choice(name: 'AGC_CHANNEL', choices: ['unified', 'dev-win', 'dev-mac', 'release-unified', 'release-win', 'release-mac'], description: '发号用途标签:unified / release-unified 为一个号同时给两个平台,其余为单渠道热修')
|
||||
string(name: 'SOURCE_BRANCH', defaultValue: 'master', description: '取发号脚本的源码分支;默认 master')
|
||||
string(name: 'COMMIT_HASH', defaultValue: '', description: '可选:固定提交;留空则解析 SOURCE_BRANCH 当前 revision')
|
||||
booleanParam(name: 'SEED_ONLY', defaultValue: false, description: '仅做一次性播种:写入渠道与仓库版本的最大值作为基线,不递增、不烧号')
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
// 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 ?: ''}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,22 @@
|
||||
<?xml version='1.1' encoding='UTF-8'?>
|
||||
<flow-definition plugin="workflow-job">
|
||||
<actions/>
|
||||
<description>AGC 总版本号唯一发号入口:先写 OSS agc/global-version.json,再由各渠道构建接收号发布。统一构建发一次号给所有渠道;dry-run 只预览不烧号。</description>
|
||||
<description>AGC 总版本号唯一发号入口:先写 OSS agc/global-version.json,再由各渠道构建接收号发布。dev / release 的统一构建各自发一次号给两个平台;dry-run 只预览不烧号。</description>
|
||||
<keepDependencies>false</keepDependencies>
|
||||
<properties>
|
||||
<hudson.model.ParametersDefinitionProperty>
|
||||
<parameterDefinitions>
|
||||
<hudson.model.ChoiceParameterDefinition>
|
||||
<name>AGC_CHANNEL</name>
|
||||
<description>发号用途:unified 为统一构建(一个号同时给 dev-win 与 dev-mac),其余为单渠道热修</description>
|
||||
<description>发号用途标签:unified / release-unified 为一个号同时给两个平台,其余为单渠道热修</description>
|
||||
<choices class="java.util.Arrays$ArrayList">
|
||||
<a class="string-array">
|
||||
<string>unified</string>
|
||||
<string>dev-win</string>
|
||||
<string>dev-mac</string>
|
||||
<string>release-unified</string>
|
||||
<string>release-win</string>
|
||||
<string>release-mac</string>
|
||||
</a>
|
||||
</choices>
|
||||
</hudson.model.ChoiceParameterDefinition>
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
<?xml version='1.1' encoding='UTF-8'?>
|
||||
<flow-definition plugin="workflow-job">
|
||||
<actions/>
|
||||
<description>每天 04:00 检查源码分支版本(cron 定义在 Jenkinsfile 内):revision 变化且出现客户端相关路径变更时,先经 Genarrative-Agc-Global-Version-Issue 发号,再用同一个固定 commit 与总版本号触发 AGC Windows、macOS 两个 release 分区构建;macOS 额外带 SKIP_IF_SUPERSEDED。下游 Job 一律不自带触发器。</description>
|
||||
<keepDependencies>false</keepDependencies>
|
||||
<properties>
|
||||
<hudson.model.ParametersDefinitionProperty>
|
||||
<parameterDefinitions>
|
||||
<hudson.model.StringParameterDefinition>
|
||||
<name>SOURCE_BRANCH</name>
|
||||
<description>被检查的源码分支;默认 master</description>
|
||||
<defaultValue>master</defaultValue>
|
||||
<trim>true</trim>
|
||||
</hudson.model.StringParameterDefinition>
|
||||
<hudson.model.BooleanParameterDefinition>
|
||||
<name>FORCE_TRIGGER</name>
|
||||
<description>勾选后忽略版本与路径比较,强制发布 AGC release 渠道</description>
|
||||
<defaultValue>false</defaultValue>
|
||||
</hudson.model.BooleanParameterDefinition>
|
||||
</parameterDefinitions>
|
||||
</hudson.model.ParametersDefinitionProperty>
|
||||
</properties>
|
||||
<definition class="org.jenkinsci.plugins.workflow.cps.CpsScmFlowDefinition" plugin="workflow-cps">
|
||||
<scm class="hudson.plugins.git.GitSCM" plugin="git">
|
||||
<configVersion>2</configVersion>
|
||||
<userRemoteConfigs>
|
||||
<hudson.plugins.git.UserRemoteConfig>
|
||||
<url>ssh://git@127.0.0.1:2222/GenarrativeAI/Genarrative.git</url>
|
||||
<credentialsId>genarrative-local-gitea-ssh</credentialsId>
|
||||
<refspec>+refs/heads/master:refs/remotes/origin/master</refspec>
|
||||
</hudson.plugins.git.UserRemoteConfig>
|
||||
</userRemoteConfigs>
|
||||
<branches>
|
||||
<hudson.plugins.git.BranchSpec>
|
||||
<name>*/master</name>
|
||||
</hudson.plugins.git.BranchSpec>
|
||||
</branches>
|
||||
<doGenerateSubmoduleConfigurations>false</doGenerateSubmoduleConfigurations>
|
||||
<submoduleCfg class="empty-list"/>
|
||||
<extensions>
|
||||
<hudson.plugins.git.extensions.impl.CloneOption>
|
||||
<shallow>true</shallow>
|
||||
<noTags>true</noTags>
|
||||
<reference></reference>
|
||||
<depth>1</depth>
|
||||
<honorRefspec>true</honorRefspec>
|
||||
</hudson.plugins.git.extensions.impl.CloneOption>
|
||||
</extensions>
|
||||
</scm>
|
||||
<scriptPath>jenkins/Jenkinsfile.scheduled-release-trigger</scriptPath>
|
||||
<lightweight>false</lightweight>
|
||||
</definition>
|
||||
<triggers/>
|
||||
<disabled>false</disabled>
|
||||
</flow-definition>
|
||||
@@ -54,6 +54,17 @@ const checks = [
|
||||
reason:
|
||||
'Copy Artifact Production 模式下,AGC 发号 Job 还必须授权手动发布管线读取总号,否则用户触发的手动发布会停在 copyArtifacts(SYSTEM 定时构建不受影响)。',
|
||||
},
|
||||
{
|
||||
file: 'jenkins/Jenkinsfile.agc-global-version-issue',
|
||||
includes: 'Genarrative-Scheduled-Release-Trigger',
|
||||
reason:
|
||||
'Copy Artifact Production 模式下,AGC 发号 Job 必须授权每日 release 调度器读取总号。',
|
||||
},
|
||||
{
|
||||
file: 'jenkins/agc-global-version-issue-job-config.xml',
|
||||
includes: '<string>release-unified</string>',
|
||||
reason: 'AGC 发号 Job 配置必须保留 release 调度的统一发号用途标签。',
|
||||
},
|
||||
{
|
||||
file: 'jenkins/Jenkinsfile.production-stdb-module-build',
|
||||
includes: 'npm run check:rustfmt',
|
||||
@@ -7733,6 +7744,14 @@ const scheduledRevisionTriggerJobConfig = readFileSync(
|
||||
'jenkins/scheduled-revision-trigger-job-config.xml',
|
||||
'utf8',
|
||||
);
|
||||
const scheduledReleaseTriggerContent = readFileSync(
|
||||
'jenkins/Jenkinsfile.scheduled-release-trigger',
|
||||
'utf8',
|
||||
);
|
||||
const scheduledReleaseTriggerJobConfig = readFileSync(
|
||||
'jenkins/scheduled-release-trigger-job-config.xml',
|
||||
'utf8',
|
||||
);
|
||||
|
||||
// 定时与版本比较统一收敛到调度管线,两个下游流水线不得再自带触发器。
|
||||
for (const [file, content] of [
|
||||
@@ -7883,6 +7902,69 @@ if (
|
||||
'[check:production-ops] scheduled-revision-trigger Job 必须指向调度 Jenkinsfile、使用本机 Git 入口与既有 SSH 凭据,并把定时器留在 Jenkinsfile。',
|
||||
);
|
||||
}
|
||||
|
||||
for (const [snippet, reason] of [
|
||||
["cron('0 4 * * *')", 'release 调度器必须在每天 04:00 检查远端版本'],
|
||||
['disableConcurrentBuilds()', '必须禁止 release 调度器并发触发'],
|
||||
['skipDefaultCheckout(true)', 'release 调度器不得依赖本地 SCM 工作区'],
|
||||
['git ls-remote', 'release 调度器必须直接从远端解析分支版本'],
|
||||
[
|
||||
"AGC_WINDOWS_BUILD_JOB_NAME = 'Genarrative-Agc-Windows-Build'",
|
||||
'必须声明 AGC Windows release 构建目标 Job',
|
||||
],
|
||||
[
|
||||
"AGC_MACOS_BUILD_JOB_NAME = 'Genarrative-Agc-MacOS-Build'",
|
||||
'必须声明 AGC macOS release 构建目标 Job',
|
||||
],
|
||||
[
|
||||
"string(name: 'AGC_CHANNEL', value: 'release-unified')",
|
||||
'release 调度器必须先通过发号 Job 获取统一总版本号',
|
||||
],
|
||||
[
|
||||
"string(name: 'AGC_UPDATE_CHANNEL', value: 'release')",
|
||||
'release 调度器必须把 Windows 与 macOS 都发到 release 分区',
|
||||
],
|
||||
[
|
||||
'build job: env.AGC_WINDOWS_BUILD_JOB_NAME, wait: false, propagate: false, parameters: agcParameters',
|
||||
'release 调度器必须触发 AGC Windows release 构建',
|
||||
],
|
||||
[
|
||||
'build job: env.AGC_MACOS_BUILD_JOB_NAME, wait: false, propagate: false, parameters: agcMacosParameters',
|
||||
'release 调度器必须触发 AGC macOS release 构建',
|
||||
],
|
||||
[
|
||||
"booleanParam(name: 'SKIP_IF_SUPERSEDED', value: true)",
|
||||
'release 调度器必须让 macOS 节点恢复后跳过过期排队构建',
|
||||
],
|
||||
]) {
|
||||
if (!scheduledReleaseTriggerContent.includes(snippet)) {
|
||||
failed = true;
|
||||
console.error(`[check:production-ops] release 调度管线${reason}。`);
|
||||
}
|
||||
}
|
||||
if (scheduledReleaseTriggerContent.includes('FULL_BUILD_JOB_NAME')) {
|
||||
failed = true;
|
||||
console.error(
|
||||
'[check:production-ops] release 调度管线只负责 AGC release 客户端构建,不得触发 Full Build。',
|
||||
);
|
||||
}
|
||||
if (
|
||||
!scheduledReleaseTriggerJobConfig.includes(
|
||||
'<scriptPath>jenkins/Jenkinsfile.scheduled-release-trigger</scriptPath>',
|
||||
) ||
|
||||
!scheduledReleaseTriggerJobConfig.includes(
|
||||
'ssh://git@127.0.0.1:2222/GenarrativeAI/Genarrative.git',
|
||||
) ||
|
||||
!scheduledReleaseTriggerJobConfig.includes(
|
||||
'<credentialsId>genarrative-local-gitea-ssh</credentialsId>',
|
||||
) ||
|
||||
!scheduledReleaseTriggerJobConfig.includes('<triggers/>')
|
||||
) {
|
||||
failed = true;
|
||||
console.error(
|
||||
'[check:production-ops] scheduled-release-trigger Job 必须指向 release 调度 Jenkinsfile、使用本机 Git 入口与既有 SSH 凭据,并把定时器留在 Jenkinsfile。',
|
||||
);
|
||||
}
|
||||
if (
|
||||
!fullPipelineContent.includes(
|
||||
"string(name: 'COMMIT_HASH', value: env.SOURCE_COMMIT)",
|
||||
|
||||
Reference in New Issue
Block a user