1+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
2+ # NodeGet Release 工作流
3+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
4+ #
5+ # 整体流程:prepare → build-* (并行) → publish-release → publish-docker
6+ #
7+ # 触发方式:
8+ # 1. 推送 v* 标签(自动发布) — git tag v0.5.6 && git push --tags
9+ # 2. 手动触发 workflow_dispatch — 可选仅编译(不上传),或编译+发布
10+ #
11+ # 构建产物命名规则:nodeget-{agent|server}-{os}-{arch}[-libc].exe?
12+ # 例: nodeget-server-linux-aarch64-musl
13+ # nodeget-agent-windows-x86_64.exe
14+ # nodeget-server-macos-aarch64
15+ #
16+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
17+
118name : nodeget-release
219
20+ # ── 触发条件 ────────────────────────────────────────────────────
321on :
22+ # 手动触发:GitHub Actions 页面点击 "Run workflow"
23+ # 可选参数:
24+ # release_tag — 发布标签,如 v0.3.7。留空 = 仅编译,不上传 Release
25+ # publish_release — 是否创建/更新 GitHub Release + Docker 镜像
426 workflow_dispatch :
527 inputs :
628 release_tag :
1234 required : false
1335 default : false
1436 type : boolean
37+
38+ # 自动触发:推送 v* 格式的 tag 时自动发布
39+ # 例: git tag v0.5.6 && git push origin v0.5.6
1540 push :
1641 tags :
1742 - " v*"
1843
44+ # ── 并发控制 ────────────────────────────────────────────────────
45+ # 同一个 tag 不会重复运行;手动触发无 tag 时用 run_id 兜底
46+ # cancel-in-progress: false — 不取消正在运行的发布,避免中途截断
1947concurrency :
2048 group : ${{ github.workflow }}-${{ github.event_name == 'push' && github.ref_name || inputs.release_tag || github.run_id }}
2149 cancel-in-progress : false
2250
51+ # ── 默认权限 ────────────────────────────────────────────────────
52+ # 最小权限原则:默认只读仓库内容;需要写权限的 job 单独声明
2353permissions :
2454 contents : read
2555
2656env :
2757 CARGO_TERM_COLOR : always
2858
59+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
60+ # Job 1: Prepare — 判断是否发布 + 提取 tag
61+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
62+ #
63+ # 输出两个变量供后续 job 使用:
64+ # publish — "true" 表示需要创建 GitHub Release + Docker 镜像
65+ # tag — 版本标签字符串,如 "v0.5.6"
66+ #
67+ # 逻辑:
68+ # push tag 触发 → 自动发布
69+ # 手动触发 → 由 inputs.publish_release 决定
70+ # tag 格式校验 — 必须匹配 ^v数字.数字... 的语义版本格式
71+ #
2972jobs :
3073 prepare :
3174 name : Prepare release
4184 publish="false"
4285 tag=""
4386
87+ # push tag 触发 → 自动发布;手动触发 → 读取 inputs
4488 if [[ "${GITHUB_EVENT_NAME}" == "push" ]]; then
4589 publish="true"
4690 tag="${GITHUB_REF_NAME}"
4993 tag="${{ inputs.release_tag }}"
5094 fi
5195
96+ # 发布时校验 tag 格式:v + 语义版本,允许 pre-release 后缀如 -rc1, +build123
5297 if [[ "${publish}" == "true" ]]; then
5398 if [[ ! "${tag}" =~ ^v[0-9]+(\.[0-9]+)*([-+][0-9A-Za-z.-]+)?$ ]]; then
5499 echo "release_tag must look like v0.3.7 when publishing" >&2
@@ -59,6 +104,18 @@ jobs:
59104 echo "publish=${publish}" >> "${GITHUB_OUTPUT}"
60105 echo "tag=${tag}" >> "${GITHUB_OUTPUT}"
61106
107+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
108+ # Job 2: build-linux — Linux 多平台交叉编译
109+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
110+ #
111+ # 使用 cross-rs/cross 在 Docker 容器中交叉编译,覆盖 8 个 Linux target:
112+ # - x86_64 / aarch64,musl (静态链接) 和 gnu (glibc 动态链接)
113+ # → 编译 agent + server(server 仅 x86_64/aarch64,因为需要 PostgreSQL 链接)
114+ # - armv7 / arm / i686
115+ # → 仅编译 agent(轻量,无数据库依赖)
116+ #
117+ # fail-fast: false — 某个 target 失败不阻塞其他 target 的构建
118+ #
62119 build-linux :
63120 name : Linux ${{ matrix.platform.release_for }}
64121 needs : prepare
@@ -67,39 +124,46 @@ jobs:
67124 fail-fast : false
68125 matrix :
69126 platform :
70- - release_for : x86_64-musl
127+ # ── 主流服务器架构:musl ( Alpine/静态 ) + gnu ( glibc ) ──
128+ - release_for : x86_64-musl # Alpine / 静态链接,Docker 镜像使用此产物
71129 target : x86_64-unknown-linux-musl
72130 packages : [ agent, server ]
73- - release_for : x86_64-gnu
131+ - release_for : x86_64-gnu # glibc 动态链接,传统 Linux 发行版
74132 target : x86_64-unknown-linux-gnu
75133 packages : [ agent, server ]
76- - release_for : aarch64-musl
134+ - release_for : aarch64-musl # ARM64 Alpine / 静态链接,Docker arm64 使用此产物
77135 target : aarch64-unknown-linux-musl
78136 packages : [ agent, server ]
79- - release_for : aarch64-gnu
137+ - release_for : aarch64-gnu # ARM64 glibc,树莓派 4/5 等
80138 target : aarch64-unknown-linux-gnu
81139 packages : [ agent, server ]
82- - release_for : armv7-musleabihf
140+ # ── 嵌入式 / IoT 架构:仅 agent(server 依赖过重不适合这些平台)──
141+ - release_for : armv7-musleabihf # ARMv7 硬浮点 musl(32位 ARM 静态)
83142 target : armv7-unknown-linux-musleabihf
84143 packages : [ agent ]
85- - release_for : armv7-gnueabihf
144+ - release_for : armv7-gnueabihf # ARMv7 硬浮点 gnu(树莓派 2/3)
86145 target : armv7-unknown-linux-gnueabihf
87146 packages : [ agent ]
88- - release_for : arm-musleabihf
147+ - release_for : arm-musleabihf # ARMv6 硬浮点 musl(树莓派 Zero)
89148 target : arm-unknown-linux-musleabihf
90149 packages : [ agent ]
91- - release_for : i686-musl
150+ - release_for : i686-musl # 32位 x86 musl(老旧硬件/兼容)
92151 target : i686-unknown-linux-musl
93152 packages : [ agent ]
94153 steps :
95154 - name : Checkout
96155 uses : actions/checkout@v6
97156
157+ # 复合 action:安装 Rust stable 工具链 + Cargo 缓存
158+ # cache-shared-key 按 target 区分,避免不同 target 的缓存冲突
98159 - name : Setup Rust
99160 uses : ./.github/actions/setup-rust
100161 with :
101162 cache-shared-key : release-linux-${{ matrix.platform.target }}
102163
164+ # 安装 cross —— Rust 交叉编译工具
165+ # cross 会为每个 target 拉取对应的 Docker 镜像(含交叉工具链和系统库)
166+ # 下载 GitHub release 的预编译二进制,避免 cargo install 的编译开销
103167 - name : Install cross
104168 env :
105169 CROSS_VERSION : v0.2.5
@@ -113,6 +177,9 @@ jobs:
113177 | tar -xz -C "${HOME}/.local/bin"
114178 echo "${HOME}/.local/bin" >> "${GITHUB_PATH}"
115179
180+ # 根据矩阵中的 packages 列表选择性编译 agent/server
181+ # --profile minimal — 自定义 profile,优化二进制体积(LTO + strip)
182+ # --locked — 严格按 Cargo.lock 编译,确保可复现
116183 - name : Build selected packages
117184 env :
118185 TARGET : ${{ matrix.platform.target }}
@@ -126,6 +193,9 @@ jobs:
126193 cross build --package nodeget-server --target "${TARGET}" --profile minimal --locked
127194 fi
128195
196+ # 将编译产物从 target/{target}/minimal/ 复制到 dist/,统一命名
197+ # 命名: nodeget-{agent|server}-linux-{release_for}
198+ # 例: nodeget-server-linux-aarch64-musl
129199 - name : Stage artifacts
130200 shell : bash
131201 env :
@@ -142,6 +212,8 @@ jobs:
142212 cp "target/${TARGET}/minimal/nodeget-server" "dist/nodeget-server-${SUFFIX}"
143213 fi
144214
215+ # 上传到 GitHub Actions 临时存储,供 publish-release job 下载
216+ # retention-days: 14 — 14 天后自动清理(仅编译不上传时仍有产物可下载)
145217 - name : Upload artifacts
146218 uses : actions/upload-artifact@v7
147219 with :
@@ -150,6 +222,13 @@ jobs:
150222 if-no-files-found : error
151223 retention-days : 14
152224
225+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
226+ # Job 3: build-windows — Windows MSVC 编译
227+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
228+ #
229+ # Windows 上直接用 cargo 编译(原生 MSVC 工具链,无需 cross)
230+ # 通过 rustup 添加对应 target 即可交叉编译 aarch64
231+ #
153232 build-windows :
154233 name : Windows ${{ matrix.platform.release_for }}
155234 needs : prepare
@@ -158,16 +237,18 @@ jobs:
158237 fail-fast : false
159238 matrix :
160239 platform :
161- - release_for : x86_64
240+ - release_for : x86_64 # 64位 Windows(主流桌面/服务器)
162241 target : x86_64-pc-windows-msvc
163242 packages : [ agent, server ]
164- - release_for : aarch64
243+ - release_for : aarch64 # Windows ARM64(Surface Pro X 等)
165244 target : aarch64-pc-windows-msvc
166245 packages : [ agent ]
167246 steps :
168247 - name : Checkout
169248 uses : actions/checkout@v6
170249
250+ # setup-rust action 会通过 dtolnay/rust-toolchain 的 targets 参数
251+ # 安装对应 target 的标准库(aarch64 交叉编译需要)
171252 - name : Setup Rust
172253 uses : ./.github/actions/setup-rust
173254 with :
@@ -178,14 +259,16 @@ jobs:
178259 run : |
179260 $target = "${{ matrix.platform.target }}"
180261 $buildAgent = "${{ contains(matrix.platform.packages, 'agent') }}" -eq "true"
181- $buildServer = "${{ contains(matrix.platform.packages, 'server ') }}" -eq "true"
262+ $buildServer = "${{ contains(matrix.platform.packages, 'agent ') }}" -eq "true"
182263 if ($buildAgent) {
183264 cargo build --package nodeget-agent --target $target --profile minimal --locked
184265 }
185266 if ($buildServer) {
186267 cargo build --package nodeget-server --target $target --profile minimal --locked
187268 }
188269
270+ # Windows 产物带 .exe 后缀
271+ # 命名: nodeget-{agent|server}-windows-{arch}.exe
189272 - name : Stage artifacts
190273 shell : pwsh
191274 run : |
@@ -209,6 +292,14 @@ jobs:
209292 if-no-files-found : error
210293 retention-days : 14
211294
295+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
296+ # Job 4: build-macos — macOS Darwin 编译
297+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
298+ #
299+ # macOS 上原生编译(Xcode 工具链),通过 rustup target 切换架构
300+ # aarch64 = Apple Silicon (M1/M2/M3/M4)
301+ # x86_64 = Intel Mac(仅编译 agent,Intel Mac 市场份额递减)
302+ #
212303 build-macos :
213304 name : macOS ${{ matrix.platform.release_for }}
214305 needs : prepare
@@ -217,10 +308,10 @@ jobs:
217308 fail-fast : false
218309 matrix :
219310 platform :
220- - release_for : aarch64
311+ - release_for : aarch64 # Apple Silicon(当前主力 Mac)
221312 target : aarch64-apple-darwin
222313 packages : [ agent, server ]
223- - release_for : x86_64
314+ - release_for : x86_64 # Intel Mac(仅 agent,降级支持)
224315 target : x86_64-apple-darwin
225316 packages : [ agent ]
226317 steps :
@@ -246,6 +337,8 @@ jobs:
246337 cargo build --package nodeget-server --target "${TARGET}" --profile minimal --locked
247338 fi
248339
340+ # macOS 产物无后缀
341+ # 命名: nodeget-{agent|server}-macos-{arch}
249342 - name : Stage artifacts
250343 shell : bash
251344 env :
@@ -270,6 +363,16 @@ jobs:
270363 if-no-files-found : error
271364 retention-days : 14
272365
366+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
367+ # Job 5: publish-release — 创建/更新 GitHub Release
368+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
369+ #
370+ # 仅在 prepare.outputs.publish == 'true' 时执行
371+ # 汇总所有 build-* job 的编译产物,上传为 GitHub Release assets
372+ #
373+ # 依赖:prepare + 三个 build job 全部完成
374+ # 权限:contents: write(创建 Release 需要写权限)
375+ #
273376 publish-release :
274377 name : Publish GitHub Release
275378 needs :
@@ -282,13 +385,17 @@ jobs:
282385 permissions :
283386 contents : write
284387 steps :
388+ # 下载所有 release-* 前缀的 artifact,合并到 dist/ 目录
285389 - name : Download artifacts
286390 uses : actions/download-artifact@v8
287391 with :
288392 pattern : release-*
289393 path : dist
290394 merge-multiple : true
291395
396+ # 创建 GitHub Release 并上传所有编译产物
397+ # make_latest: true — 标记为最新 Release
398+ # softprops/action-gh-release 支持幂等操作(tag 已存在时追加文件)
292399 - name : Upload release assets
293400 uses : softprops/action-gh-release@v3
294401 with :
@@ -297,6 +404,22 @@ jobs:
297404 make_latest : true
298405 files : dist/*
299406
407+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
408+ # Job 6: publish-docker — 构建并推送 Docker 多架构镜像
409+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
410+ #
411+ # 仅在 publish-release 成功后执行(确保 Docker 镜像拉取的 release 二进制已存在)
412+ # 使用 Dockerfile 的 runtime-release target:
413+ # 该 target 从 GitHub Release 下载预编译二进制(不源码编译)
414+ # 通过 TARGETARCH 自动选择 amd64/arm64 对应的资产
415+ #
416+ # 推送双标签:
417+ # genshinmc/nodeget:latest — 始终指向最新版本
418+ # genshinmc/nodeget:v0.5.6 — 带版本号的固定标签
419+ #
420+ # 依赖:prepare + publish-release(顺序依赖,确保 Release 资产先就绪)
421+ # 权限:actions: write(GHA 缓存), contents: read, packages: write(GHCR,备用)
422+ #
300423 publish-docker :
301424 name : Publish Docker image
302425 needs :
@@ -317,25 +440,34 @@ jobs:
317440 - name : Checkout
318441 uses : actions/checkout@v6
319442
443+ # 前置检查:Docker Hub 凭据必须配置,否则提前失败而非在 login 步骤报错
320444 - name : Check Docker Hub credentials
321445 shell : bash
322446 run : |
323447 test -n "${DOCKERHUB_USERNAME}"
324448 test -n "${DOCKERHUB_TOKEN}"
325449
450+ # QEMU — 用户态模拟器,允许在 x86_64 runner 上构建 arm64 镜像
451+ # Docker buildx 的多架构构建底层依赖 QEMU 模拟非原生指令集
326452 - name : Set up QEMU
327453 uses : docker/setup-qemu-action@v4
328454
455+ # Buildx — Docker 的扩展构建器,支持多平台并行构建 + 缓存导出
329456 - name : Set up Docker Buildx
330457 uses : docker/setup-buildx-action@v4
331458
459+ # 登录 Docker Hub(凭据存储在 GitHub Secrets)
332460 - name : Login to Docker Hub
333461 uses : docker/login-action@v4
334462 with :
335463 registry : ${{ env.REGISTRY }}
336464 username : ${{ env.DOCKERHUB_USERNAME }}
337465 password : ${{ env.DOCKERHUB_TOKEN }}
338466
467+ # 生成 Docker 标签和标签元数据
468+ # tags 规则:
469+ # type=raw,value=latest → genshinmc/nodeget:latest
470+ # type=raw,value=${{ needs.prepare.outputs.tag }} → genshinmc/nodeget:v0.5.6
339471 - name : Docker metadata
340472 id : meta
341473 uses : docker/metadata-action@v6
@@ -345,6 +477,14 @@ jobs:
345477 type=raw,value=latest
346478 type=raw,value=${{ needs.prepare.outputs.tag }}
347479
480+ # 多架构构建并推送
481+ # target: runtime-release — Dockerfile 中使用 GitHub Release 下载二进制的 stage
482+ # platforms: linux/amd64,linux/arm64 — 同时构建两个架构
483+ # build-args:
484+ # NODEGET_VERSION — 传给 Dockerfile 的 ARG,指定从哪个 Release 下载二进制
485+ # NODEGET_RELEASE_REPO — 指定 Release 仓库(支持 fork 场景)
486+ # cache-from/to: type=gha — 使用 GitHub Actions 缓存加速重复构建
487+ # mode=max — 缓存所有中间层(不仅是最终层),最大化缓存命中率
348488 - name : Build and push
349489 uses : docker/build-push-action@v7
350490 with :
0 commit comments