Merge remote-tracking branch 'origin/master' into codex/clear-retired-tables-phase2
This commit is contained in:
@@ -2602,12 +2602,13 @@ function assertAiGameCreatorShellUserDevBoundary() {
|
||||
{ url: 'https://*/api/*' },
|
||||
{ url: 'http://localhost:*/*' },
|
||||
{ url: 'http://127.0.0.1:*/*' },
|
||||
{ url: 'https://*.aliyuncs.com/*' },
|
||||
])
|
||||
) {
|
||||
throw new Error(
|
||||
// 更新清单与安装包下载已改由 tauri-plugin-updater 在原生侧完成,
|
||||
// 不再需要为 webview 的 http 插件放行 OSS 域名。
|
||||
'AI game creator native HTTP scope must match the release, dev, custom HTTPS, and loopback API boundary',
|
||||
// 更新清单与安装包下载由 tauri-plugin-updater 在原生侧完成;
|
||||
// 封面与截图仍通过 webview 的 http 插件向凭证指定的 OSS 地址直传。
|
||||
'AI game creator native HTTP scope must match the release, dev, custom HTTPS, loopback API, and OSS media upload boundary',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2647,7 +2648,7 @@ function assertAiGameCreatorShellUserDevBoundary() {
|
||||
}
|
||||
for (const snippet of [
|
||||
"await invoke<LocalPreviewStatus>(\n 'activate_local_game_preview'",
|
||||
'已切换到客户端运行视图',
|
||||
'已载入客户端运行视图',
|
||||
]) {
|
||||
if (!sourceIncludesSnippet(aiGameCreatorShellAppSource, snippet)) {
|
||||
throw new Error(
|
||||
@@ -2665,6 +2666,14 @@ function assertAiGameCreatorShellUserDevBoundary() {
|
||||
);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 预览**不自动**开系统浏览器:启动与切换运行视图只走内置画面,两条老路必须一直挡着
|
||||
* (App.tsx 里的 `openPreviewInExternalBrowser` / 前端直调 `open_local_game_preview` /
|
||||
* Rust 侧 `.open_url(`)。
|
||||
*
|
||||
* 用户主动点「在浏览器打开」是另一回事:它走 opener 插件的 `openUrl`,入口只有顶栏那一枚
|
||||
* 按钮(见下面那条正向断言)。别把这条负向守卫推广成「任何地方都不许出现 openUrl」。
|
||||
*/
|
||||
if (
|
||||
aiGameCreatorShellAppSource.includes('openPreviewInExternalBrowser') ||
|
||||
aiGameCreatorShellAppSource.includes('open_local_game_preview') ||
|
||||
@@ -2674,6 +2683,31 @@ function assertAiGameCreatorShellUserDevBoundary() {
|
||||
'AI game creator preview must not invoke the external browser',
|
||||
);
|
||||
}
|
||||
for (const snippet of [
|
||||
"'@tauri-apps/plugin-opener'",
|
||||
'在浏览器打开',
|
||||
'await openUrl(embeddedPreviewUrl)',
|
||||
]) {
|
||||
if (
|
||||
!sourceIncludesSnippet(aiGameCreatorProjectDevelopmentSource, snippet)
|
||||
) {
|
||||
throw new Error(
|
||||
`AI game creator in-browser preview entry drifted: missing ${snippet}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 上面那条负向守卫只盯着 App.tsx 里的两条老路,而真正的浏览器出口在运行页视图里。
|
||||
* 这里再补一条「调用点只有一个」的判据:视图里冒出第二个 `openUrl(`(自动跳浏览器、
|
||||
* 或者拿它去开任意地址)时必须先显式改这条守卫,而不是顺手加一行。
|
||||
*/
|
||||
const openUrlCallCount =
|
||||
aiGameCreatorProjectDevelopmentSource.split('openUrl(').length - 1;
|
||||
if (openUrlCallCount !== 1) {
|
||||
throw new Error(
|
||||
`AI game creator must keep exactly one user-clicked browser-open call in the run view (found ${openUrlCallCount})`,
|
||||
);
|
||||
}
|
||||
if (
|
||||
aiGameCreatorShellTauriSource.includes('fn open_developer_window(') ||
|
||||
aiGameCreatorShellTauriSource.includes(
|
||||
|
||||
@@ -7761,7 +7761,7 @@ for (const [file, content] of [
|
||||
if (/\btriggers\s*\{/u.test(content) || content.includes('cron(')) {
|
||||
failed = true;
|
||||
console.error(
|
||||
`[check:production-ops] ${file} 不得自带定时触发器;版本检查与触发必须由 Genarrative-Scheduled-Revision-Trigger 统一负责。`,
|
||||
`[check:production-ops] ${file} 不得自带定时触发器;版本检查与触发必须由两条定时调度管线统一负责。`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -7908,6 +7908,10 @@ for (const [snippet, reason] of [
|
||||
['disableConcurrentBuilds()', '必须禁止 release 调度器并发触发'],
|
||||
['skipDefaultCheckout(true)', 'release 调度器不得依赖本地 SCM 工作区'],
|
||||
['git ls-remote', 'release 调度器必须直接从远端解析分支版本'],
|
||||
[
|
||||
"FULL_BUILD_JOB_NAME = 'Genarrative-Full-Build-And-Deploy'",
|
||||
'必须声明 release Full Build 目标 Job',
|
||||
],
|
||||
[
|
||||
"AGC_WINDOWS_BUILD_JOB_NAME = 'Genarrative-Agc-Windows-Build'",
|
||||
'必须声明 AGC Windows release 构建目标 Job',
|
||||
@@ -7916,6 +7920,19 @@ for (const [snippet, reason] of [
|
||||
"AGC_MACOS_BUILD_JOB_NAME = 'Genarrative-Agc-MacOS-Build'",
|
||||
'必须声明 AGC macOS release 构建目标 Job',
|
||||
],
|
||||
[
|
||||
"FULL_REVISION_STATE_FILE = '.jenkins-last-release-full-revision'",
|
||||
'必须独立记录 Full Build 成功 revision',
|
||||
],
|
||||
[
|
||||
"AGC_REVISION_STATE_FILE = '.jenkins-last-release-agc-revision'",
|
||||
'必须独立记录 AGC 双平台成功 revision',
|
||||
],
|
||||
['full=changed', 'release 调度器必须计算服务端 Full Build scope'],
|
||||
[
|
||||
"env.FULL_BUILD_SCOPE = readScope('full')",
|
||||
'release 调度器必须解析 Full Build scope',
|
||||
],
|
||||
[
|
||||
"string(name: 'AGC_CHANNEL', value: 'release-unified')",
|
||||
'release 调度器必须先通过发号 Job 获取统一总版本号',
|
||||
@@ -7925,27 +7942,64 @@ for (const [snippet, reason] of [
|
||||
'release 调度器必须把 Windows 与 macOS 都发到 release 分区',
|
||||
],
|
||||
[
|
||||
'build job: env.AGC_WINDOWS_BUILD_JOB_NAME, wait: false, propagate: false, parameters: agcParameters',
|
||||
"string(name: 'DEPLOY_TARGET', value: 'release')",
|
||||
'release Full Build 必须固定部署到 release',
|
||||
],
|
||||
[
|
||||
"booleanParam(name: 'CONFIRM_RELEASE_DEPLOY_AGENT', value: true)",
|
||||
'release Full Build 必须确认使用独立 release 部署 agent',
|
||||
],
|
||||
[
|
||||
"string(name: 'DATABASE_BACKUP_MODE', value: params.DATABASE_BACKUP_MODE)",
|
||||
'release Full Build 必须显式透传数据库备份策略',
|
||||
],
|
||||
[
|
||||
"string(name: 'STDB_API_ROLLOUT_MODE', value: params.STDB_API_ROLLOUT_MODE)",
|
||||
'release Full Build 必须显式透传 Stdb/API rollout 策略',
|
||||
],
|
||||
[
|
||||
'def runDownstream = { String jobName, List jobParameters, int timeoutMinutes ->',
|
||||
'release 调度器必须统一等待并收集三个下游结果',
|
||||
],
|
||||
[
|
||||
'build job: jobName,\n wait: true,\n propagate: false,',
|
||||
'release 下游必须等待完成并保留每个 Job 的结果',
|
||||
],
|
||||
[
|
||||
'branches[env.FULL_BUILD_JOB_NAME] = {',
|
||||
'release 调度器必须触发 Full Build',
|
||||
],
|
||||
[
|
||||
'branches[env.AGC_WINDOWS_BUILD_JOB_NAME] = {',
|
||||
'release 调度器必须触发 AGC Windows release 构建',
|
||||
],
|
||||
[
|
||||
'build job: env.AGC_MACOS_BUILD_JOB_NAME, wait: false, propagate: false, parameters: agcMacosParameters',
|
||||
'branches[env.AGC_MACOS_BUILD_JOB_NAME] = {',
|
||||
'release 调度器必须触发 AGC macOS release 构建',
|
||||
],
|
||||
[
|
||||
"booleanParam(name: 'SKIP_IF_SUPERSEDED', value: true)",
|
||||
'release 调度器必须让 macOS 节点恢复后跳过过期排队构建',
|
||||
],
|
||||
[
|
||||
'if (fullSucceeded) {',
|
||||
'只有 Full Build 成功后才能推进 Full Build revision',
|
||||
],
|
||||
['if (agcSucceeded) {', '只有 AGC 双平台成功后才能推进 AGC revision'],
|
||||
[
|
||||
'error("release 下游未全部成功: ${summary}")',
|
||||
'任一 release 下游失败时调度器必须失败',
|
||||
],
|
||||
]) {
|
||||
if (!scheduledReleaseTriggerContent.includes(snippet)) {
|
||||
failed = true;
|
||||
console.error(`[check:production-ops] release 调度管线${reason}。`);
|
||||
}
|
||||
}
|
||||
if (scheduledReleaseTriggerContent.includes('FULL_BUILD_JOB_NAME')) {
|
||||
if (scheduledReleaseTriggerContent.includes('wait: false')) {
|
||||
failed = true;
|
||||
console.error(
|
||||
'[check:production-ops] release 调度管线只负责 AGC release 客户端构建,不得触发 Full Build。',
|
||||
'[check:production-ops] release 调度管线不得 fire-and-forget,必须等待并汇总 Full Build 与 AGC 结果。',
|
||||
);
|
||||
}
|
||||
if (
|
||||
|
||||
Reference in New Issue
Block a user