Skip to content

Commit 5126676

Browse files
CI: Add GitHub Actions workflows for release management and Rust setup
1 parent a83cf4b commit 5126676

5 files changed

Lines changed: 396 additions & 87 deletions

File tree

File renamed without changes.
Lines changed: 153 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,28 @@
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+
118
name: nodeget-release
219

20+
# ── 触发条件 ────────────────────────────────────────────────────
321
on:
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:
@@ -12,20 +34,41 @@ on:
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 — 不取消正在运行的发布,避免中途截断
1947
concurrency:
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 单独声明
2353
permissions:
2454
contents: read
2555

2656
env:
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+
#
2972
jobs:
3073
prepare:
3174
name: Prepare release
@@ -41,6 +84,7 @@ jobs:
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}"
@@ -49,6 +93,7 @@ jobs:
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

Comments
 (0)