CI 自動產生 release build version
.github/workflows/main.ymlDocs/ChangeHistory.mdDocs/development/version.mdTODO.md
commit 9e3c73e7e087cd430486d45400d8a33b20e1a80aAuthor: Nuclear0709 <agp05432@gmail.com>Date: Wed Nov 11 01:08:45 2026 +0800 CI 自動產生 release build version diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml--- a/.github/workflows/main.yml+++ b/.github/workflows/main.yml@@ -80,7 +80,7 @@ jobs: echo "tag=$TAG" >> "$GITHUB_OUTPUT" echo "Using tag: $TAG" - - name: Resolve MARKETING_VERSION 對齊 release tag+ - name: Resolve release versions 對齊 tag id: marketing_version run: | set -euo pipefail@@ -90,9 +90,22 @@ jobs: | sort -u \ | tr '\n' ',' \ | sed 's/,$//' || true)+ OLD_BUILDS=$(grep -Eo 'CURRENT_PROJECT_VERSION = [^;]+;' liveAPP.xcodeproj/project.pbxproj \+ | sed -E 's/.*= ([^;]+);/\1/' \+ | sort -u \+ | tr '\n' ',' \+ | sed 's/,$//' || true)+ # 每次 release 使用單調的 UTC 時間建號;同時覆寫 Info.plist 的 CFBundleVersion。+ BUILD_VERSION=$(date -u +%Y%m%d%H%M%S)+ echo "BUILD_VERSION=$BUILD_VERSION" >> "$GITHUB_ENV" echo "old=$OLD_VERSIONS" >> "$GITHUB_OUTPUT" echo "new=$TAG" >> "$GITHUB_OUTPUT"- echo "MARKETING_VERSION old=$OLD_VERSIONS -> effective=$TAG" | tee -a "$GITHUB_STEP_SUMMARY"+ echo "build_old=$OLD_BUILDS" >> "$GITHUB_OUTPUT"+ echo "build=$BUILD_VERSION" >> "$GITHUB_OUTPUT"+ {+ echo "MARKETING_VERSION old=$OLD_VERSIONS -> effective=$TAG"+ echo "CURRENT_PROJECT_VERSION old=$OLD_BUILDS -> effective=$BUILD_VERSION"+ } | tee -a "$GITHUB_STEP_SUMMARY" if [ "$OLD_VERSIONS" != "$TAG" ]; then echo "::notice::CI 以 xcodebuild 覆寫 MARKETING_VERSION:$OLD_VERSIONS -> $TAG(不修改 repo 檔案)" fi@@ -194,6 +207,7 @@ jobs: filetype_parameter: ${{ steps.filetype_parameter.outputs.filetype_parameter }} file_to_build: ${{ steps.filetype_parameter.outputs.file_to_build }} MARKETING_VERSION: ${{ steps.marketing_version.outputs.new }}+ CURRENT_PROJECT_VERSION: ${{ steps.marketing_version.outputs.build }} run: | set -o pipefail@@ -213,6 +227,7 @@ jobs: -destination "generic/platform=iOS" \ CODE_SIGNING_ALLOWED=NO \ MARKETING_VERSION="$MARKETING_VERSION" \+ CURRENT_PROJECT_VERSION="$CURRENT_PROJECT_VERSION" \ SWIFT_SYMBOL_REDACTION=NO 2>&1 | tee -a build/archive.log @@ -266,6 +281,10 @@ jobs: echo "::error::MARKETING_VERSION override 未生效:archive=$SHORT tag=$TAG" exit 1 fi+ if [ "$BUILD" != "$BUILD_VERSION" ]; then+ echo "::error::CURRENT_PROJECT_VERSION override 未生效:archive=$BUILD expected=$BUILD_VERSION"+ exit 1+ fi - name: Classify release 產生 Release 分類 id: release_metadiff --git a/Docs/ChangeHistory.md b/Docs/ChangeHistory.md--- a/Docs/ChangeHistory.md+++ b/Docs/ChangeHistory.md@@ -11,7 +11,7 @@ - AV Lag 已保存場次在讀取索引時會清理不存在的 segment 檔;非目前 active 且 `endedAt` 仍為 nil 的舊場次會標成「未完成(已中斷)」,不再永久顯示「進行中」。 - `inspect_app_bundle.py` 只在實際 IPA 輸入時顯示 `IPA ZIP 大小`;`.app` 目錄改標示「封存 .app,沒有 IPA ZIP」,分類與最大檔案不再列出容易誤導的逐檔 `ZIP 壓縮大小`。測試補上 IPA 與 `.app` 兩種報告格式。 - `.gitignore` 加入 `DocumentationArtifacts/`、`site/`、`*.doccarchive`。DocC workflow 會產生大型 archive/靜態站;先前未忽略,ChangelogKit 的 `git ls-files --others` 會掃描這些 untracked 產物並在 30 秒 timeout。-- Archive/Release workflow 以 release tag 覆寫 `MARKETING_VERSION`:不修改 repo 的 `project.pbxproj`,但主 App 與 extension 的 `CFBundleShortVersionString` 會是 tag 版本;CI 步驟摘要記錄舊值與 effective 值,避免本地忘記更新造成版本不一致。測試 target 的 `1.0` 仍不列入比較。+- Archive/Release workflow 以 release tag 覆寫 `MARKETING_VERSION`,並以 UTC 時間自動產生 `CURRENT_PROJECT_VERSION`:不修改 repo 的 `project.pbxproj`,但主 App 與 extension 的 `CFBundleShortVersionString`/`CFBundleVersion` 會是本次 release 值;CI 摘要記錄舊值與 effective 值,archive 後再驗證實際 Info.plist 相符。AltStore 來源因此直接取得正確 version/buildVersion,測試 target 的 `1.0` 仍不列入比較。 - DocC Pages 部署避免殘留卡住:workflow 層不再取消整個 run,只讓 DocC 建置 job 可被新 ref 取代;deploy job 保持 `cancel-in-progress: false`,新增 15 分鐘 job timeout 與 `deploy-pages` 10 分鐘輪詢 timeout,卡住的部署會讓 job 失敗並釋放 concurrency,不再無限期等到六小時。 - TTS 過濾器新增三段式「重複無意義字串」設定:關閉/整句都是 ASCII 同字元重複 3 次以上時跳過/移除重複 token 後朗讀其餘內容。`wwww 你好` 在第三段只念「你好」;`hahaha`、`abc`、`asweffeteteh` 與混合正常詞句不會被自動誤刪。設定寫入 `SpeechFilterSettings`、支援 JSON 匯入/匯出與既有備份;預設關閉。 - `add_legacy_alternate_icons.sh` 不再把未被 `CFBundleIconFiles` 引用的 1024 `PersonalIcon.png` 複製到 App 根目錄;Assets.car 仍保留 marketing rendition,約減少 1.79 MB 的重複圖示資料。diff --git a/Docs/development/version.md b/Docs/development/version.md--- a/Docs/development/version.md+++ b/Docs/development/version.md@@ -46,19 +46,21 @@ Archive/Release workflow 會讀取 `x.y.z` tag,並在 `xcodebuild archive` ```text MARKETING_VERSION=<tag>+CURRENT_PROJECT_VERSION=<UTC yyyymmddhhmmss> ``` -這是 Xcode command-line build setting override,會讓主 App 與所有 extension 的 `CFBundleShortVersionString` 使用同一個 tag,不需要先手動修改 `project.pbxproj`。CI 會輸出:+兩者都是 Xcode command-line build setting override,會讓主 App 與所有 extension 的 `CFBundleShortVersionString`/`CFBundleVersion` 使用同一個 release 值,不需要先手動修改 `project.pbxproj`。CI 會輸出: ```text MARKETING_VERSION old=17.6.7 -> effective=17.6.8-Archived app version: CFBundleShortVersionString=17.6.8+CURRENT_PROJECT_VERSION old=2026100601 -> effective=20261110123000+Archived app version: CFBundleShortVersionString=17.6.8 CFBundleVersion=20261110123000 ``` -- 本地忘記改 `MARKETING_VERSION` 時,CI 產物仍會使用 tag 版本。+- 本地忘記改版本時,CI 產物仍會使用 tag 版本與新的單調 build number。 - repo 內的 `project.pbxproj` 不會被 CI 改寫,因此本地 Xcode 建置仍以手動值為準。 - 測試 target 的 `MARKETING_VERSION = 1.0` 是刻意設定,不列入 release 版本比對。-- `CURRENT_PROJECT_VERSION` 目前仍由專案/人工控制,不由此步驟自動改寫。+- AltStore 來源直接使用封存後 Info.plist 的 `CFBundleShortVersionString`/`CFBundleVersion`,所以 version 會等於 tag,buildVersion 會是本次 CI 建號;不需要另改 `AltStoreTest.json`。 ## Why Too Many Versions?為什麼會出現這麼多版本? diff --git a/TODO.md b/TODO.md--- a/TODO.md+++ b/TODO.md@@ -198,7 +198,7 @@ API 遷移屬後續技術評估,不作為以上功能完成的條件;需要 - [x] 來源改由 Release 附件提供,固定 `releases/latest/download/AltStoreTest.json`;`version`/`buildVersion` 取自 Info.plist、`size` 取 IPA bytes、What's New 取最近 10 筆 commit。 - [x] `update_altstore_source.py` 與 7 個測試;repo 樣板不再由 CI 改寫。 - [ ] **首次 Release 附件驗收**:確認 `AltStoreTest.json` 已附上、固定 URL 可下載、版本欄位與 IPA 一致,AltStore 顯示多行 What's New。-- [ ] 版本號未遞增時 AltStore 不會提示更新;CI archive 已用 tag 覆寫 `MARKETING_VERSION`,但 `CURRENT_PROJECT_VERSION` 仍由專案/人工控制,未自動改寫 repo 內 pbxproj。+- [ ] 版本號未遞增時 AltStore 不會提示更新;CI archive 已用 tag 覆寫 `MARKETING_VERSION`,並以 UTC 時間自動覆寫 `CURRENT_PROJECT_VERSION`,AltStore 使用封存後 Info.plist 的 version/buildVersion,不需另改模板。 ## TTS 配置分享實作與驗收