diff --git a/apps/ai-game-creator-shell/scripts/build-release.test.mjs b/apps/ai-game-creator-shell/scripts/build-release.test.mjs index 798bd206f..d2853082f 100644 --- a/apps/ai-game-creator-shell/scripts/build-release.test.mjs +++ b/apps/ai-game-creator-shell/scripts/build-release.test.mjs @@ -41,6 +41,20 @@ test('manifest contains version, download URL and integrity fields', () => { assert.equal(typeof manifest.size, 'number'); }); +test('manifest preserves multiline release notes', () => { + const previous = process.env.AGC_UPDATE_RELEASE_NOTES; + process.env.AGC_UPDATE_RELEASE_NOTES = '第一行\n第二行\r\n第三行'; + try { + const manifest = createUpdateManifest( + new URL('../package.json', import.meta.url).pathname, + ); + assert.equal(manifest.releaseNotes, '第一行\n第二行\r\n第三行'); + } finally { + if (previous === undefined) delete process.env.AGC_UPDATE_RELEASE_NOTES; + else process.env.AGC_UPDATE_RELEASE_NOTES = previous; + } +}); + test('next release version follows the higher local or OSS version', () => { assert.equal(compareVersions('0.1.15', '0.1.12'), 1); assert.equal(nextPatchVersion('0.1.12', '0.1.15'), '0.1.16'); diff --git a/apps/ai-game-creator-shell/src/styles.css b/apps/ai-game-creator-shell/src/styles.css index 38f586369..ee8e4e96d 100644 --- a/apps/ai-game-creator-shell/src/styles.css +++ b/apps/ai-game-creator-shell/src/styles.css @@ -55,9 +55,10 @@ body { } .app-update-notice p { max-width: 320px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; + max-height: 120px; + overflow-y: auto; + overflow-wrap: anywhere; + white-space: pre-wrap; } .app-update-notice button { flex: 0 0 auto; diff --git a/apps/ai-game-creator-shell/tests/appUpdate.test.ts b/apps/ai-game-creator-shell/tests/appUpdate.test.ts index 1348ce9c2..8bbe1e596 100644 --- a/apps/ai-game-creator-shell/tests/appUpdate.test.ts +++ b/apps/ai-game-creator-shell/tests/appUpdate.test.ts @@ -32,4 +32,16 @@ describe('AGC update manifest', () => { }), ).toBeNull(); }); + + it('preserves multiline release notes', () => { + expect( + parseAppUpdateManifest({ + version: '0.1.13', + downloadUrl: 'https://oss.example/agc.exe', + releaseNotes: '第一行\n第二行\r\n第三行', + }), + ).toMatchObject({ + releaseNotes: '第一行\n第二行\r\n第三行', + }); + }); }); diff --git a/docs/technical/【技术方案】AGC客户端更新检查与下载-2026-08-31.md b/docs/technical/【技术方案】AGC客户端更新检查与下载-2026-08-31.md index 455c37670..29eae7a7f 100644 --- a/docs/technical/【技术方案】AGC客户端更新检查与下载-2026-08-31.md +++ b/docs/technical/【技术方案】AGC客户端更新检查与下载-2026-08-31.md @@ -38,7 +38,7 @@ OSS 请求失败、清单格式错误或版本无效会终止发布,避免覆 生成包含版本、下载地址、大小和 SHA-256 的清单。可通过 `AGC_BUILD_TARGET` 显式覆盖目标(发布仍应使用 Windows x64),通过 `AGC_UPDATE_ARTIFACT` 指定要发布的安装包,通过 `AGC_UPDATE_OSS_BASE_URL` 指定 OSS 前缀,通过 `AGC_RELEASE_VERSION` 指定三段版本号(仅在明确需要复现指定版本时使用),通过 -`AGC_UPDATE_RELEASE_NOTES` 写入发布说明;`--no-bundle` smoke 构建不会读取 OSS、修改版本或生成清单。 +`AGC_UPDATE_RELEASE_NOTES` 写入发布说明,支持多行文本且保留内部换行;`--no-bundle` smoke 构建不会读取 OSS、修改版本或生成清单。 每次发布安装包上传完成后,再使用 ossutil 的 `--force` 覆盖上传同一目录生成的 `latest.json`,确保固定的 latest 指针和 `downloadUrl` 指向已存在的 OSS 对象;未显式强制覆盖时,ossutil 在目标已存在时会交互询问并按默认值跳过,不能作为 Jenkins 非交互发布方式。清单和安装包均使用公开可读对象,不在清单中保存凭据、签名或本地路径。构建脚本本身不负责上传 OSS,发布流水线通过 `release:upload` 完成上传。 @@ -56,7 +56,7 @@ Jenkins Agent 服务必须能在同一用户环境中找到这些命令。Tauri `tauri.windows.conf.json` 中的 `bundle.useLocalToolsDir: true`,把固定版本的 NSIS 工具缓存到 `src-tauri/target/.tauri/NSIS`,不依赖 Jenkins 服务账户的 `%LOCALAPPDATA%\tauri` 或 PATH 中的系统 NSIS。 Jenkins Checkout 的 `git clean -fdx` 会清理该构建目录,因此每次全新工作区可能重新下载 NSIS;这只影响构建耗时,不改变工具来源或执行权限要求。 -流水线执行根 workspace 的 `npm ci`,然后调用 +流水线参数 `AGC_UPDATE_RELEASE_NOTES` 使用 Jenkins `text` 类型,可直接输入多行发布说明;执行根 workspace 的 `npm ci`,然后调用 `npm run ai-game-creator-shell:release:upload`,并归档 Windows 安装包、`latest.json` 与源码 commit。 流水线会将未导出的空参数按空字符串处理:`COMMIT_HASH` 留空时沿用 Jenkins SCM 当前提交,`OSSUTIL_BIN` 留空时使用节点 PATH 中的 `ossutil`,不会因 PowerShell 对空环境变量调用 `.Trim()` 而提前失败。 diff --git a/jenkins/Jenkinsfile.ai-game-creator-shell-build b/jenkins/Jenkinsfile.ai-game-creator-shell-build index 8803fa375..3e304cf63 100644 --- a/jenkins/Jenkinsfile.ai-game-creator-shell-build +++ b/jenkins/Jenkinsfile.ai-game-creator-shell-build @@ -22,7 +22,7 @@ pipeline { string(name: 'SOURCE_BRANCH', defaultValue: 'master', description: '源码分支') string(name: 'COMMIT_HASH', defaultValue: '', description: '可选,指定属于 SOURCE_BRANCH 的 Git commit') string(name: 'AGC_RELEASE_VERSION', defaultValue: '', description: '可选,指定三段版本号;留空则按 OSS 与本地版本自动递增 patch') - string(name: 'AGC_UPDATE_RELEASE_NOTES', defaultValue: '', description: '可选,写入 latest.json 的发布说明') + text(name: 'AGC_UPDATE_RELEASE_NOTES', defaultValue: '', description: '可选,支持多行文本,写入 latest.json 的发布说明') string(name: 'OSSUTIL_BIN', defaultValue: 'ossutil', description: 'ossutil 或 ossutil.exe 的绝对路径/命令名') }