Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,14 @@ beta 验证稳定后,按正常发布流程把 `dev` 合进 `main`:在 releas
- 万一稳定清单被污染(例如误用 beta tag 跑了 stable 通道):用一个已知正确的稳定 tag 重跑 `upload-r2.yml`(`-f tag=vX.Y.Z -f channel=stable`),脚本会幂等重建 `updates/latest.json` 与 `releases/<tag>/` 下的安装包。
- `node script/test-release-packaging.mjs` 里有一组回归断言(含假 aws 仿真),保证 beta tag 永远只写 `updates/beta/latest.json`。

## Update feed assets and the CNB mirror(feed 资产与 CNB 镜像)

Every run of `upload-r2.yml` also copies the channel manifests onto the GitHub Release under flat `feed-*.json` asset names: `feed-navop.json` / `feed-navop-shell.json` / `feed-navop-data.json` on the stable channel and `feed-navop-beta.json` / `feed-navop-shell-beta.json` / `feed-navop-data-beta.json` on beta. This is not a second feed format — it exists because the CNB mirror (`https://cnb.cool/navop-dev/navop`) only synchronizes **GitHub Release assets**, and repository file raw URLs are not anonymously readable there. The Release assets are therefore the only place the CNB side can serve a manifest from a plain GET.

- **稳定发布同时刷新 beta 清单**:a stable run also publishes the exact same stable manifests as `feed-<product>-beta.json` and overwrites the R2 beta keys (`updates/beta/latest.json`, `updates/navop-shell/shell/beta/latest.json`, `updates/navop-data/data/beta/latest.json`) with that same stable manifest. Beta clients only read the beta feed/assets; without this refresh they would stay pinned to the last beta forever and never receive a new stable release. A beta run still writes only the beta keys and beta asset names, so the stable feed and the un-suffixed asset names are never touched.
- **CNB 同步由 `upload-r2.yml` 最后派发**:`sync-cnb-release-assets.yml` must run after the `feed-*.json` assets exist. The dispatch used to live at the end of `release.yml`, which raced the concurrent `upload-r2.yml` run and could complete before the feed assets were uploaded. `release.yml` now dispatches only `upload-r2.yml` (with `-f channel`), and the CNB sync is dispatched by the last step of `upload-r2.yml`.
- **`feed-*.json` 不会被误当成安装包**:the installer download/upload globs are `navop-*` / `navop_*`, and the manifest's `packages` list keeps only names matching `/^navop[-_]/`, so feed assets never appear in `downloads`, `fallback_downloads` or `packages`, and never land under the R2 `releases/<tag>/` prefix.

## Changelog format

The newest entry belongs immediately after the `<!-- NAVOP_RELEASES -->` marker:
Expand Down
7 changes: 3 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1051,7 +1051,6 @@ jobs:
-f tag="$RELEASE_TAG" \
-f channel="$CHANNEL"

gh workflow run sync-cnb-release-assets.yml \
--repo "$GITHUB_REPOSITORY" \
--ref main \
-f tag="$RELEASE_TAG"
# CNB 镜像同步不在这里派发:它只同步 GitHub Release 资产,必须等
# upload-r2.yml 把 feed-*.json 写回 Release 之后再跑,所以由
# upload-r2.yml 的最后一步派发 sync-cnb-release-assets.yml。
71 changes: 69 additions & 2 deletions .github/workflows/upload-r2.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@ on:
default: ""
type: string

# actions: write 用于在最后派发 sync-cnb-release-assets.yml;contents: write
# 用于把更新清单以 feed-*.json 资产名回写到本次 GitHub Release(CNB 镜像只
# 同步 Release 资产,这是 CNB 侧唯一能匿名直接 GET 的清单位置)。
permissions:
actions: read
contents: read
actions: write
contents: write

concurrency:
group: ${{ github.workflow }}-${{ inputs.tag }}
Expand Down Expand Up @@ -494,6 +497,54 @@ jobs:
upload_object "artifacts/updates/navop-shell/shell/latest.json" "${shell_manifest_key}" "application/json; charset=utf-8" "no-store, max-age=0"
upload_object "artifacts/updates/navop-data/data/latest.json" "${data_manifest_key}" "application/json; charset=utf-8" "no-store, max-age=0"

# 稳定发布时把同一份稳定清单再写一遍 beta 键位。原因:beta 客户端只
# 读 beta 清单,不写这里它就永远停在最后一个 beta,收不到新的正式版。
# stable 自己的两个键位(上面的 ${manifest_key} 等)原有写入不动。
if [ "${CHANNEL}" = "stable" ]; then
upload_object "artifacts/updates/latest.json" "updates/beta/latest.json" "application/json; charset=utf-8" "no-store, max-age=0"
upload_object "artifacts/updates/navop-shell/shell/latest.json" "updates/navop-shell/shell/beta/latest.json" "application/json; charset=utf-8" "no-store, max-age=0"
upload_object "artifacts/updates/navop-data/data/latest.json" "updates/navop-data/data/beta/latest.json" "application/json; charset=utf-8" "no-store, max-age=0"
fi

# 更新清单同时以扁平资产名(feed-*.json)回写到本次 GitHub Release。
# CNB 镜像(sync-cnb-release-assets.yml)只同步 GitHub Release 资产,CNB
# 仓库文件的 raw 直链对匿名不可用,所以这些 Release 资产就是 CNB 侧唯一
# 能直接 GET 的更新清单。
- name: Publish update feed assets for mirrors
if: ${{ steps.r2_config.outputs.skip != 'true' && steps.release.outputs.skip != 'true' }}
env:
GH_TOKEN: ${{ github.token }}
RELEASE_TAG: ${{ steps.release.outputs.tag }}
CHANNEL: ${{ steps.release.outputs.channel }}
run: |
set -euo pipefail
mkdir -p artifacts/feed

if [ "${CHANNEL}" = "stable" ]; then
cp artifacts/updates/latest.json artifacts/feed/feed-navop.json
cp artifacts/updates/navop-shell/shell/latest.json artifacts/feed/feed-navop-shell.json
cp artifacts/updates/navop-data/data/latest.json artifacts/feed/feed-navop-data.json
# 稳定通道额外发一份 feed-<product>-beta.json,内容与稳定清单完全
# 相同。原因:beta 客户端只读 beta 清单/资产,不发这份它永远停在
# 最后一个 beta,收不到新的正式版。
cp artifacts/updates/latest.json artifacts/feed/feed-navop-beta.json
cp artifacts/updates/navop-shell/shell/latest.json artifacts/feed/feed-navop-shell-beta.json
cp artifacts/updates/navop-data/data/latest.json artifacts/feed/feed-navop-data-beta.json
else
# beta 通道只发 beta 命名的资产:不带 -beta 的稳定资产名属于稳定
# Release,beta 不该占用它们。
cp artifacts/updates/latest.json artifacts/feed/feed-navop-beta.json
cp artifacts/updates/navop-shell/shell/latest.json artifacts/feed/feed-navop-shell-beta.json
cp artifacts/updates/navop-data/data/latest.json artifacts/feed/feed-navop-data-beta.json
fi

ls -l artifacts/feed
# --clobber:同一个 tag 的修复重跑要能覆盖上一次的 feed 资产。
gh release upload "$RELEASE_TAG" \
--repo "$GITHUB_REPOSITORY" \
--clobber \
artifacts/feed/*.json

# 桶里只留这次上传的版本:旧安装包在 R2 上只占空间,下载入口都不依赖它们
# —— updates/latest.json 只指向本次 tag,旧版本另有 GitHub Release 与 CNB
# 镜像作为存档。这一步必须待在上传与逐对象校验之后,且不能加 always():
Expand Down Expand Up @@ -602,3 +653,19 @@ jobs:
done

echo "R2 now keeps ${keep_tags}(under ${prefix}/)"

# CNB 镜像只同步 GitHub Release 资产,所以必须先有上一步回写的 feed-*.json
# 资产再同步,否则 CNB 侧拿不到可直接 GET 的更新清单。派发原先在
# release.yml 末尾,与本 workflow 并发,可能在 feed 资产就位之前就跑完;
# 现在挪到这里,顺序有保证。
- name: Dispatch CNB release asset sync
if: ${{ steps.r2_config.outputs.skip != 'true' && steps.release.outputs.skip != 'true' }}
env:
GH_TOKEN: ${{ github.token }}
RELEASE_TAG: ${{ steps.release.outputs.tag }}
run: |
set -euo pipefail
gh workflow run sync-cnb-release-assets.yml \
--repo "$GITHUB_REPOSITORY" \
--ref main \
-f tag="$RELEASE_TAG"
2 changes: 1 addition & 1 deletion crates/app_kit/src/update/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ fn feed_url(base: &str, identity: &AppIdentity, channel: UpdateChannel) -> Optio
))
}

fn is_legacy_full(identity: &AppIdentity) -> bool {
pub(super) fn is_legacy_full(identity: &AppIdentity) -> bool {
identity.app_id == LEGACY_FULL_APP_ID
}

Expand Down
Loading
Loading