Files
胡飞 416b81400e ci: 发布 PR 只跑发布元数据校验,跳过全平台测试
只改 CHANGELOG.md / main/Cargo.toml / Cargo.lock 的发布 PR 此前仍要跑
macOS / Linux / Windows 三平台全量测试(Windows job 约 25 分钟),而改动里
没有任何代码,这些测试没有意义。

- ci.yml 新增 classify job:PR 场景下用 script/release_pr.py 判定是否只包含
  发布改动,是则跳过 test 与 windows-rdp-probe,改为就地校验发布元数据
- script/release_pr.py:分类规则为「改动文件全部属于发布白名单」且
  「Cargo.toml / Cargo.lock 的差异只有 version = "..." 行」;命中后校验
  main/Cargo.toml 与 Cargo.lock 中 main 包版本一致,且该版本的双语
  changelog 条目完整(更新内容/修复与优化 + What's New/Fixes and
  Improvements,含 CNB 镜像行);无法算出 diff 时回退到全量测试
- ci-gate 仍是唯一必需状态检查,分类或校验失败都会拦住合并
- .github/RELEASE.md 记录该快速通道
- windows_rdp_host 契约测试钉住 classify/needs/if 结构与脚本白名单

验证:
- python3 -m unittest discover -s script/tests -p "test_release_pr.py" — 16 passed
- cargo test -p windows_rdp_host --test contract — 40 passed
- ruby -ryaml 解析 ci.yml,核对 classify/test/windows-rdp-probe/ci-gate 的
  needs 与 if 表达式
- rustfmt --edition 2024 --check crates/windows_rdp_host/tests/contract.rs
2026-09-19 12:55:35 +08:00

8.1 KiB

Navop Release Operations

Normal release

CHANGELOG.md is the single source of truth for user-facing release notes. Generate the bilingual entry before creating a release tag:

python3 script/changelog.py upsert \
  --tag v0.10.1 \
  --date 2026-08-01 \
  --notes-file /private/tmp/navop-v0.10.1-release-notes.md \
  --changelog CHANGELOG.md

python3 script/changelog.py extract \
  --tag v0.10.1 \
  --changelog CHANGELOG.md \
  --output /private/tmp/navop-v0.10.1-release-notes-from-changelog.md

git diff -- CHANGELOG.md

Review the extracted Markdown and make sure it matches the source notes, including both the Chinese 更新内容 / 修复与优化 and English What's New / Fixes and Improvements content sections and the CNB mirror download line. Commit the changelog entry before creating or pushing the tag.

The normal release sequence is:

  1. Generate, review, and commit the target version entry in CHANGELOG.md.
  2. Bump the application version (main/Cargo.toml and Cargo.lock) to the target X.Y.Z inside the same devmain release pull request. main is a protected branch (PR + CI gate, enforce_admins=true), so the version change cannot be pushed to main directly.
  3. Merge the release pull request once CI passes; main now carries both the changelog entry and the bumped version.
  4. On main, run script/release-tag.sh vX.Y.Z. The script refuses to proceed unless main/Cargo.toml already equals the tag and the bilingual changelog entry is present; it then creates and pushes the v* tag (tag pushes are not branch-protected).
  5. Release Trigger dispatches the shared Release workflow on the main branch.
  6. The workflow checks the application version and tagged changelog entry before starting expensive builds.
  7. macOS ARM64, macOS x86_64, Linux x86_64, Linux ARM64, and Windows x86_64 build in parallel in one matrix.
  8. After all requested platforms finish, the workflow extracts the tagged entry, uses it as the GitHub Release body, and writes the same Markdown to the R2 latest.json release_notes field.

The build workflow checks out the requested tag, while the workflow itself runs from main. This keeps Cargo input caches and sccache data reusable across tags and repair runs.

Release-only pull requests

A pull request that only carries the CHANGELOG.md entry and the version bump does not need the platform matrix. .github/workflows/ci.yml classifies every pull request in the classify job through script/release_pr.py check:

  • The pull request qualifies only when every changed file is CHANGELOG.md, main/Cargo.toml, or Cargo.lock, and the Cargo.toml / Cargo.lock diff contains nothing but version = "..." lines. Any other file, or a dependency change in main/Cargo.toml, keeps the full matrix.
  • When it qualifies, the test and windows-rdp-probe jobs are skipped and the release metadata is validated instead: main/Cargo.toml and the main package in Cargo.lock must agree, and the bilingual entry for that version must exist, be complete (更新内容 / 修复与优化 plus What's New / Fixes and Improvements) and carry the CNB mirror line.
  • CI gate stays the only required status check, and it still fails the pull request when the classification itself fails, so an invalid release entry cannot reach main.
  • If the diff cannot be computed (for example a fork pull request whose head commit was not fetched), the classifier falls back to the full matrix.

A release pull request keeps the fast path after main is merged back into dev, because the classifier only looks at the diff against the base branch.

Branch model

  • dev is the beta development branch. Changes are pushed and validated here before a release.
  • main is the stable release branch and is protected: changes land via pull request, and CI must pass before merging.
  • Cut a release by merging the validated work from dev into main — including the main/Cargo.toml / Cargo.lock version bump — then creating the v* tag on main with script/release-tag.sh. The version bump must ride the pull request because direct pushes to main are rejected (GH006); only the tag is pushed directly.

Changelog format

The newest entry belongs immediately after the <!-- NAVOP_RELEASES --> marker:

## [v0.10.1] - 2026-08-01

#### 更新内容

- ...

#### 修复与优化

- ...

国内下载:如果 GitHub 下载较慢,可从 [CNB 镜像](https://cnb.cool/navop-dev/navop/-/releases/tag/v0.10.1) 下载桌面端安装包

---

#### What's New

- ...

#### Fixes and Improvements

- ...

**Full Changelog**: https://github.com/feigeCode/navop/compare/v0.10.0...v0.10.1

Do not edit generated GitHub or R2 release notes independently for a normal release. Update CHANGELOG.md, create a new tag when appropriate, and let the workflows extract the entry. The extraction tool demotes the entry's headings by one level; entries no longer carry the ## 中文 / ## English language headings, and every new entry must include the CNB mirror download line so the GitHub Release body and R2 release_notes show it automatically.

Repair one platform

Do not move the release tag. Open Actions → Release → Run workflow, enter the existing tag, and select only the failed platform:

Selection Target
macos-arm64 aarch64-apple-darwin
macos-x64 x86_64-apple-darwin
linux-x64 x86_64-unknown-linux-gnu
linux-arm64 aarch64-unknown-linux-gnu
windows-x64 x86_64-pc-windows-msvc

The repair run rebuilds only the selected platform, overwrites its assets on the existing GitHub Release, regenerates the complete sha256sums.txt, synchronizes the GitHub Release body from the changelog stored in that tag, and triggers R2 synchronization. Assets from other platforms are preserved.

Tags created before CHANGELOG.md was introduced are treated as legacy repairs: if the GitHub Release already exists, its current body is preserved and reused for R2. A new Release cannot be created from a tag that has neither a tracked changelog entry nor an existing legacy Release body.

For a failed matrix job in the same workflow run, prefer Re-run failed jobs. Successful platform jobs and their workflow artifacts remain available to the final publish job.

Cache model

  • CI, Release, and ARM Linux use the same Cargo registry and Git dependency cache namespace, keyed only by runner OS and Cargo.lock. Linux x86_64 can therefore seed Linux ARM64 inputs, and macOS ARM64 can seed macOS x86_64 inputs.
  • Rust compilation uses sccache with the GitHub Actions backend in every Rust build workflow. All five release platforms run from the same default main workflow scope and reuse compiler objects from earlier runs for the same target and profile.
  • The implicit Swatinem/rust-cache inside actions-rust-lang/setup-rust-toolchain is disabled, and target/ is not stored by actions/cache. This avoids duplicating multi-gigabyte target archives that would evict useful sccache objects from GitHub's repository cache quota.
  • Release jobs explicitly start sccache and keep it alive through long linking and LTO phases so the final statistics cover the complete build.
  • Build caches are shared through workflow runs on the default main branch instead of being isolated under each release tag.
  • ARM Linux uses two Cargo build jobs, thin LTO, and 16 codegen units to reduce peak memory while retaining release optimization.

Safety properties

  • Release operations are serialized per tag and are never auto-cancelled.
  • A single-platform repair requires the GitHub Release to already exist.
  • A new release tag must contain a valid bilingual CHANGELOG.md entry before builds begin.
  • GitHub Release notes and R2 updater release_notes are extracted from the same tagged changelog entry.
  • Publishing uses --clobber only for newly built platform files and sha256sums.txt.
  • Legacy pre-changelog repairs preserve their existing GitHub Release body.
  • All five primary platform builds belong to one matrix, so they start in parallel and a failed job can be rerun without rebuilding successful matrix jobs.