ci(release): M139 发布 CI 只跑两个 Windows 槽位,整表六槽位改为手动取证

build 矩阵从六个槽位裁到 windows-x64 / windows-arm64 两个:
- 矩阵改由新增的 `plan` job 生成(`fromJSON(needs.plan.outputs.matrix)`),槽位表只在该
  job 里有一份,`mode: ci` 默认编、`mode: probe` 只有 `all_slots=true` 才编;
- `workflow_dispatch` 新增 `all_slots` 布尔输入(默认 false = 只跑 Windows),
  Linux/macOS 四档保留完整定义与打开办法(改 mode 一行),取证能力没删;
- `PUBLISH_SLOTS` 不变(两个 Windows 槽位);齐全性检查仍按下载下来的产物判,
  白名单槽位没编/编挂就 fail,不会因矩阵变小而永远过;
- packaging/README.md §1/§3/§4/§9 与 release-notes.md 的 Downloads / Support matrix
  同步成「四档默认不构建」,不留「六槽位都构建」的旧说法。
This commit is contained in:
AskaEth committed 2026-11-06 11:33:52 +08:00
1 parent f617f60134
commit 9de51e16af
3 files changed
+126 -120

No files matched your search

+74 -71
View File
@@ -1,21 +1,18 @@
name: Release
# 发布流水线:tag `v*` → 四平台(六槽位)矩阵**全部构建** → 单文件产物 + SHA256SUMS
# → 上传 artifact + 创建 GitHub Release(pre-release 默认开)。同一 tag 重跑幂等:
# Release 已存在时覆盖资产与说明,不再 `gh release create`(见 release job 末步);
# 重跑**不碰** pre-release 标记,该标记只在 `inputs.prerelease` 显式给出时才被断言。
# 发布流水线:tag `v*` → **只构建两个 Windows 槽位** → 单文件产物 + SHA256SUMS → artifact + GitHub Release
# (pre-release 默认开;同 tag 重跑幂等 = 覆盖资产与说明而不 create;重跑不碰该标记,只在显式 inputs.prerelease 时才断言)
#
# **构建 ≠ 发布**:六槽位一律构建取证,但只有 release job 的 `PUBLISH_SLOTS` 白名单里的槽位会进 Release
# 与 SHA256SUMS。当前只有两个 Windows 槽位 —— Linux/macOS 四档从未真构建成功过一次、也没在真机跑过,
# 未验证的产物不推给用户(开关与打开办法见该处注释)。
# **构建 ≠ 发布**:只有 release job 的 `PUBLISH_SLOTS` 白名单里的槽位才会进 Release 与 SHA256SUMS。
# **CI 只跑两个 Windows 槽位**(M139):Linux x64/arm64、macOS arm64/x64 四档从未真构建成功过一次、
# 也没在真机跑过,默认**一个都不跑**(省 CI 配额、不留没意义的红叉);要整表六槽位取证走手动入口
# `gh workflow run release.yml -f all_slots=true`(槽位表在 `plan` job 里,唯一真相源)。
#
# 契约唯一真相源:packaging/README.md(命名/目录/运行时依赖/发布白名单)。
# 打包本体在 packaging/make_artifacts.py(本地与 CI 同一份脚本,逐字节同布局)。
# 手动触发(workflow_dispatch)默认只跑构建不建 Release —— 用来把六槽位矩阵整体编一遍取证。
# `inputs.prerelease` 只在 **tag ref** 上 dispatch 才可达(Actions 页面只能选分支,要跑 tag 得
# `gh workflow run release.yml --ref v0.2.1`);分支 ref 的 dispatch 与 push 一样被 release job 的
# `if: github.ref_type == 'tag'` 挡在发布之外,所以「dispatch 只构建不发布」与「dispatch 可关
# pre-release」并不矛盾。
# 契约唯一真相源:packaging/README.md(命名/目录/运行时依赖/发布白名单);打包本体在
# packaging/make_artifacts.py(本地与 CI 同一份脚本,逐字节同布局)。`inputs.prerelease` 只在 **tag ref**
# 上 dispatch 才可达(Actions 页面只能选分支,跑 tag 得 `gh workflow run release.yml --ref v0.2.1`);
# 分支 ref 的 dispatch 与 push 一样被 release job 的 `if: github.ref_type == 'tag'` 挡在发布之外,所以
# 「dispatch 只构建不发布」与「dispatch 能关 pre-release」并不矛盾。
on:
push:
@@ -23,6 +20,10 @@ on:
- "v*"
workflow_dispatch:
inputs:
all_slots:
description: "构建全部六个槽位(含未验证的 Linux/macOS 四档);默认只跑两个 Windows"
type: boolean
default: false
prerelease:
description: "标记为 pre-release(仅在 tag ref 上 dispatch 时才生效)"
type: boolean
@@ -40,51 +41,55 @@ concurrency:
cancel-in-progress: false
jobs:
# M139:矩阵不写死在 `build` 里,改由本 job 按 `inputs.all_slots` 生成 —— 矩阵不能带 `if`,而
# `jobs.<id>.strategy` 可读 `needs`,所以「默认两个 Windows / 手动整表六槽位」用
# `fromJSON(needs.plan.outputs.matrix)` 实现。**槽位表只在下面这一处**,改槽位只改这里。
plan:
name: 选槽位(默认两个 Windows)
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.pick.outputs.matrix }}
steps:
- name: 生成 build 矩阵(`all_slots=true` 才整表六槽位)
id: pick
shell: bash
env:
ALL_SLOTS: ${{ inputs.all_slots }}
run: |
set -euo pipefail
python3 - "$ALL_SLOTS" >> "$GITHUB_OUTPUT" <<'PY'
import json, sys
# 槽位表(唯一真相源)。mode:"ci" = 默认在 CI 里构建;"probe" = 未验证,仅 all_slots=true 时构建。
SLOTS = [
# Windows x64:MSVC + 静态 CRT(+crt-static)→ exe 不依赖 VC++ 可再发行包,双击即用的单文件。
dict(slot="windows-x64", os="windows-latest", target="", build_dir="target/release", rustflags="-C target-feature=+crt-static", mode="ci"),
# Windows arm64:在 windows-latest(x64 宿主)**交叉编译**到 aarch64-pc-windows-msvc,产物在
# target/<triple>/release(故 build_dir 参数化);不用原生 windows-11-arm 的理由见 README §4。
dict(slot="windows-arm64", os="windows-latest", target="aarch64-pc-windows-msvc",
build_dir="target/aarch64-pc-windows-msvc/release",
rustflags="-C target-feature=+crt-static", mode="ci"),
# ↓ 四档**未验证,不纳入 CI**:从未真构建成功过一次、也没在真机跑过,默认一个都不编;
# `all_slots=true` 时照编(那是将来验证 Linux/macOS 的唯一入口,别删)。真机验证通过后:
# 把该行 mode 改成 "ci"(一行一改,不用重写矩阵)+ 槽位键加进 PUBLISH_SLOTS + 同步
# packaging/README.md §1/§9 与 release-notes.md 的 published 列 —— 三处不一致即是假话。
# Linux 固定 22.04 而非 latest:否则 glibc 地板跟着 runner 漂移(依据见 README §4)。
dict(slot="linux-x64", os="ubuntu-22.04", target="", build_dir="target/release", rustflags="", mode="probe"),
dict(slot="linux-arm64", os="ubuntu-22.04-arm", target="", build_dir="target/release", rustflags="", mode="probe"),
# macOS:latest = arm64;Intel x64 用 macos-15-intel(macos-13 已下线)。
dict(slot="macos-arm64", os="macos-latest", target="", build_dir="target/release", rustflags="", mode="probe"),
dict(slot="macos-x64", os="macos-15-intel", target="", build_dir="target/release", rustflags="", mode="probe"),
]
keep = [s for s in SLOTS if s["mode"] == "ci" or sys.argv[1] == "true"]
print("matrix=" + json.dumps({"include": keep}, separators=(",", ":")))
print("本次构建槽位:" + " ".join(s["slot"] for s in keep), file=sys.stderr)
PY
build:
name: build (${{ matrix.slot }})
needs: plan
strategy:
fail-fast: false
matrix:
include:
# Windows x64:MSVC + 静态 CRT(+crt-static)→ exe 不依赖 VC++ 可再发行包,
# 双击即用的单文件形态;UCRT 本身就是 Win10+ 的系统组件。
# 产物根 target/release;自检与打包都从 matrix.build_dir 取路径(不硬编码)。
- slot: windows-x64
os: windows-latest
build_dir: target/release
rustflags: -C target-feature=+crt-static
# Windows arm64:在 windows-latest(x64 宿主)上**交叉编译**到 aarch64-pc-windows-msvc。
# 不用 windows-11-arm 原生 runner(GitHub 文档 2026 已把它列为公开仓库免费 runner)的理由:
# ① 双 Windows 槽位共用同一套已验证镜像/工具链,tag 重跑行为与既有槽位一致;② M50 的 dumpbin
# 定位链取 `Hostx64/x64/dumpbin.exe`,它读 ARM64 PE 的导入表没问题,而原生 ARM 宿主上那条链
# 还得再长一条 `Hostarm64/arm64` 分支——为一个槽位放宽刚立的门禁不值得;③ 交叉产物路径变成
# target/<triple>/release,已用 matrix.build_dir 参数化。将来改原生:os 换 windows-11-arm、
# 去掉 target/rustflags 依赖并给 dumpbin 定位链补 Hostarm64 分支(届时再评估)。
- slot: windows-arm64
os: windows-latest
target: aarch64-pc-windows-msvc
build_dir: target/aarch64-pc-windows-msvc/release
rustflags: -C target-feature=+crt-static
# ↓ 下面四档(Linux x64/arm64、macOS arm64/x64)只**构建取证**、不进本次 Release(从未真构建
# 成功过一次、也没在真机跑过);发哪几个槽位由 release job 的 `PUBLISH_SLOTS` 白名单唯一决定。
# Linux:固定 ubuntu-22.04(glibc 2.35 地板)而不是 latest,
# 否则产物的 glibc 底线会跟着 runner 漂移(24.04 的 glibc 明显更高)。
- slot: linux-x64
os: ubuntu-22.04
build_dir: target/release
# Linux arm64:公开仓库免费的原生 ARM64 runner(4C/16GB,原生构建不交叉)。用 22.04-arm
# 而非 24.04 是为了与 x64 同 glibc 地板(2.35),覆盖 Debian 12 / Ubuntu 22.04 arm64 /
# Raspberry Pi OS Bookworm(2.36);该家族标签还有 `ubuntu-24.04-arm` / `ubuntu-26.04-arm`。
- slot: linux-arm64
os: ubuntu-22.04-arm
build_dir: target/release
# macOS:latest = arm64;Intel x64 用 macos-15-intel(macos-13 已下线)。
- slot: macos-arm64
os: macos-latest
build_dir: target/release
- slot: macos-x64
os: macos-15-intel
build_dir: target/release
matrix: ${{ fromJSON(needs.plan.outputs.matrix) }}
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
@@ -130,11 +135,9 @@ jobs:
exit 1
fi
# M118(D26):**Slint 版停发** —— GUI 来源只有 `unlucky-launcher-iced`;`crates/app` 已在根
# Cargo.toml 被 `exclude`,不参与任何 workspace 构建(它连 `--manifest-path` 都编不了)。
# 对外产物名由 packaging/make_artifacts.py 的 `asset_stem()` 统一生成
# `<名字>_<版本号>_<平台>_<架构>`(下划线分段、不带 `iced` 这类实现细节字样);`LAUNCHER_BIN`
# 只用来在构建产物里找文件。
# M118(D26):**Slint 版停发** —— GUI 来源只有 `unlucky-launcher-iced`(`crates/app` 已被根
# Cargo.toml `exclude`,不参与任何 workspace 构建)。对外产物名由 make_artifacts.py 的
# `asset_stem()` 生成 `<名字>_<版本号>_<平台>_<架构>`;`LAUNCHER_BIN` 只用来在产物里找文件。
- name: cargo build --release --locked
shell: bash
env:
@@ -152,9 +155,8 @@ jobs:
if: runner.os == 'Windows'
shell: bash
env:
# 跨槽位的关键点:产物在 target/<triple>/release 而不是 target/release。
# M118:校验的是**构建产物**(iced bin 的原始文件名);对外名 `unlucky-launcher` 由
# packaging/make_artifacts.py 在落盘时才换上,那一步之后才存在。
# 跨槽位的关键点:产物在 target/<triple>/release;校验的是**构建产物**(iced bin 原始名),
# 对外名 `unlucky-launcher` 由 make_artifacts.py 落盘时才换上,那一步之后才存在。
EXE: ${{ matrix.build_dir }}/unlucky-launcher-iced.exe
run: |
set -euo pipefail
@@ -179,8 +181,7 @@ jobs:
done
fi
if [ -z "$DUMPBIN" ]; then
# 镜像里的 VS 根形如 <年>/<版次>(2022/Enterprise、2022/BuildTools……),
# 固定层数的 glob 会在 <年>/<版次> 这两级踩空,所以按路径模式扫。
# VS 根形如 <年>/<版次>(2022/Enterprise、2022/BuildTools……),固定层数的 glob 会踩空,按模式扫。
for root in "C:/Program Files/Microsoft Visual Studio" \
"C:/Program Files (x86)/Microsoft Visual Studio"; do
[ -d "$root" ] || continue
@@ -263,7 +264,7 @@ jobs:
release:
name: GitHub Release
needs: build
# `always()` + `!cancelled()`:白名单外的槽位(Linux/macOS)只是构建取证,它们红了**不能连坐**
# `always()` + `!cancelled()`:白名单外的槽位(只有 `all_slots` 取证跑里才存在)红了**不能连坐**
# Windows 发布。真正拦发布的是下面「发布白名单齐全性」那一步:白名单里少任何一个就 fail。
if: always() && !cancelled() && github.ref_type == 'tag'
runs-on: ubuntu-latest
@@ -272,11 +273,11 @@ jobs:
env:
# ── 发布白名单:唯一决定「哪几个槽位进 Release」的开关(空格分隔,键同 matrix.slot)──
# 为什么只有两个 Windows 槽位:Linux x64/arm64、macOS arm64/x64 这四档**从未真构建成功过一次、
# 更没在真机上跑过**,未验证的产物不推给用户;它们照跑构建,产物留在本次运行的 `dist-<slot>`
# artifact 里取证(可下载验证),不进 Release、不进 SHA256SUMS。
# 将来某槽位真机验证通过后「打开」它只改这一行(把槽位键加进列表,如 `macos-arm64`):齐全性检查
# 与 SHA256SUMS 自动跟着扩;同时把 packaging/README.md §1/§9 与 packaging/release-notes.md 的
# Downloads / Support matrix 同步成「已发布」——三处不一致即是假话。
# 更没在真机上跑过**,未验证的产物不推给用户;它们默认连构建都不跑(M139),只有 `all_slots=true`
# 的取证跑里才有产物,留在本次运行的 `dist-<slot>` artifact 里可下载验证,不进 Release/SHA256SUMS。
# 将来某槽位真机验证通过后「打开」它需同时改三处(缺一即是假话):① `plan` 槽位表里把它的 mode
# 改成 `ci`;② 把槽位键加进这一行(齐全性检查与 SHA256SUMS 自动跟着扩);③ packaging/README.md
# §1/§9 与 packaging/release-notes.md 的 Downloads / Support matrix。
PUBLISH_SLOTS: "windows-x64 windows-arm64"
steps:
- uses: actions/checkout@v4
@@ -318,6 +319,8 @@ jobs:
# GUI 与 CLI 两个资产——只按「槽位名出现过」判会被其中一个掩盖。档位比对用下划线形态:
# 资产名自 D49 起是 `unlucky-launcher_<ver>_windows_x64.exe`,旧写法 `dist/$prefix-*-$slot*`
# (连字符)对现行命名永远匹配不上,已一并修正。
# 矩阵裁到两个槽位(M139)后这条检查依然有效:它比的是**下载下来的产物**,不看矩阵大小 ——
# 白名单里的槽位没编(比如忘了改 plan 里的 mode)或编挂了,就在这里因缺产物 fail,不会永远过。
for slot in $PUBLISH_SLOTS; do
stem=${slot//-/_}
for prefix in unlucky-launcher ull; do
+37 -36
View File
@@ -10,15 +10,17 @@
|------|---------|-----------|------|---------|
| `windows-x64` | ✅ 发布 | `unlucky-launcher_<ver>_windows_x64.exe` | **裸 exe**(双击即用) | exe 单文件;三份合规文本作为并列 Release 资产 |
| `windows-arm64` | ✅ 发布 | `unlucky-launcher_<ver>_windows_arm64.exe` | **裸 exe**(同 x64 策略) | 同上;在 x64 宿主上交叉编译到 `aarch64-pc-windows-msvc` |
| `linux-x64` | ❌ 只构建取证 | `unlucky-launcher_<ver>_linux_x64.tar.gz` | 单二进制归档 | `unlucky-launcher` + `LICENSE` + `NOTICE` + `README.md` |
| `linux-arm64` | ❌ 只构建取证 | `unlucky-launcher_<ver>_linux_arm64.tar.gz` | 单二进制归档(原生 ARM64 runner 构建) | 同上 |
| `macos-arm64` | ❌ 只构建取证 | `unlucky-launcher_<ver>_macos_arm64.tar.gz` | 单二进制归档 | 同上 |
| `macos-x64` | ❌ 只构建取证 | `unlucky-launcher_<ver>_macos_x64.tar.gz` | 单二进制归档 | 同上 |
| `linux-x64` | ❌ 不构建(未验证) | `unlucky-launcher_<ver>_linux_x64.tar.gz` | 单二进制归档 | `unlucky-launcher` + `LICENSE` + `NOTICE` + `README.md` |
| `linux-arm64` | ❌ 不构建(未验证) | `unlucky-launcher_<ver>_linux_arm64.tar.gz` | 单二进制归档(原生 ARM64 runner 构建) | 同上 |
| `macos-arm64` | ❌ 不构建(未验证) | `unlucky-launcher_<ver>_macos_arm64.tar.gz` | 单二进制归档 | 同上 |
| `macos-x64` | ❌ 不构建(未验证) | `unlucky-launcher_<ver>_macos_x64.tar.gz` | 单二进制归档 | 同上 |
| 每槽位 | 随所属槽位 | `ull_<ver>_<平台>_<架构>[.exe]` | **裸 CLI 文件**(独立资产,不进 tar.gz) | 零 UI 依赖的 `ull` 本体,进同一份 `SHA256SUMS.txt` |
| 全平台 | 仅已发布资产 | `SHA256SUMS.txt` | 校验清单 | 每行 `<sha256>␠␠<文件名>`(`sha256sum -c` 可直吃) |
约定细节:
- **「不构建」= CI 默认根本不跑**(M139):那四档未验证,产物不给用户、构建配额也不花;要整表六槽位取证走
`gh workflow run release.yml -f all_slots=true`(§3)。发布白名单仍只有两个 Windows 槽位。
- **产物命名**:`<名字>_<版本号>_<平台>_<架构>`,下划线分段、**不带实现细节字样**(不出现 `iced`);真相源是 `make_artifacts.py::asset_stem()`。
- **"单文件"指可执行文件本身零运行时依赖**(无 WebView、无 JRE、无 sidecar、无 DLL 旁挂);归档里的三份合规文本是许可义务、不是运行时依赖,Windows 因为"一个 exe 装不下文本",
把 `LICENSE` / `NOTICE` / `README.md` 作为 Release 的并列资产分发,条款同样随下载走。
@@ -74,43 +76,42 @@ python packaging/make_artifacts.py --slot windows-arm64 \
`--slot` 与宿主槽位不一致时,`ull --version` 冒烟会**自动跳过并打印原因**(arm64 产物在 x64
宿主机上根本执行不了;拿"跳过"当通过是假证据,所以跳过永远带原因)——那条路径的验证只能落在
CI 真机上:`windows-arm64` 由 cross 构建产物 + M50 的 dumpbin 导入表门禁覆盖,`linux-arm64`
由 `ubuntu-22.04-arm` 原生 runner 上真跑冒烟覆盖。
CI 真机上:`windows-arm64` 由 cross 构建产物 + M50 的 dumpbin 导入表门禁覆盖;`linux-arm64` 的同类
冒烟只在 `all_slots=true` 的取证跑里出现(`ubuntu-22.04-arm` 原生 runner 上真跑 `ull --version`)。
### CI(四平台六槽位矩阵)
### CI(默认只跑两个 Windows 槽位;`all_slots=true` 才整表六槽位)
`.github/workflows/release.yml`:
- 触发:`push` tag `v*`;`workflow_dispatch` 只构建不发布(验证矩阵仍编得过)。
`inputs.prerelease` **只在 tag ref 上 dispatch 才可达**——Actions 页面的 "Run workflow" 只能选分支,
要跑 tag 得 `gh workflow run release.yml --ref v0.2.1`。分支 ref 的 dispatch 与 push 一样被
`release` job 的 `if: github.ref_type == 'tag'` 挡在发布之外,所以「dispatch 只构建不发布」
与「dispatch 能关 pre-release」是两条互不冲突的规则。
- 矩阵(六槽位;`matrix.build_dir` 参数化产物根,脚本不再假设产物一定在 `target/release`):
`windows-latest` x64(MSVC + `-C target-feature=+crt-static`)、`windows-latest` **交叉编译**到
`aarch64-pc-windows-msvc`(产物在 `target/aarch64-pc-windows-msvc/release`)、`ubuntu-22.04`
(glibc 2.35 地板)、`ubuntu-22.04-arm`(原生 ARM64 runner,**与 x64 同 2.35 地板**)、`macos-latest`(arm64)、
`macos-15-intel`(Intel x64;`macos-13` 已下线,`macos-26-intel` 为更新替位)。
- 触发:`push` tag `v*`;`workflow_dispatch` 只构建不发布,且多一个 `all_slots` 开关(**默认 false =
只跑两个 Windows 槽位**,true = 整表六槽位都编一遍取证)。`inputs.prerelease` **只在 tag ref 上 dispatch
才可达**——Actions 页面的 "Run workflow" 只能选分支,要跑 tag 得 `gh workflow run release.yml --ref v0.2.1`。
分支 ref 的 dispatch 与 push 一样被 `release` job 的 `if: github.ref_type == 'tag'` 挡在发布之外,所以
「dispatch 只构建不发布」与「dispatch 能关 pre-release」是两条互不冲突的规则。
- 矩阵**由 `plan` job 按 `all_slots` 生成**(`matrix: ${{ fromJSON(needs.plan.outputs.matrix) }}`:矩阵本身
不能带 `if`,而 `strategy` 可读 `needs`),槽位表只在该 job 里有一份:`windows-latest` x64(MSVC +
`-C target-feature=+crt-static`,产物在 `target/release`)与 `windows-latest` **交叉编译**到
`aarch64-pc-windows-msvc`(产物在 `target/aarch64-pc-windows-msvc/release`)标 `mode: ci`(默认编);
`ubuntu-22.04`(glibc 2.35 地板)/ `ubuntu-22.04-arm`(原生 ARM64,同地板)/ `macos-latest` /
`macos-15-intel` 标 `mode: probe`——**未验证,默认一个都不编**,只有 `all_slots=true` 才进矩阵。
- 每个槽位 `cargo build --release --locked`(交叉槽位多两步:`rustup target add` + ARM64 库体检
——查 VC 的 `lib/arm64/libcmt.lib`(`+crt-static` 靠它)与 SDK 的 `um/arm64/kernel32.lib`,
缺了直接给出"给 VS 加 `VC.Tools.ARM64` 或改用原生 `windows-11-arm`"的可执行提示)→
`make_artifacts.py --slot … --build-dir …` → 归档内容自检 → 上传 artifact。
- **发布白名单(`PUBLISH_SLOTS`,唯一开关)**:六槽位一律构建取证,只有白名单里的槽位进 Release 与
`SHA256SUMS.txt`——当前 = `windows-x64 windows-arm64`;Linux x64/arm64、macOS arm64/x64 四档**从未真构建
成功过一次、也没在真机跑过**,不推给用户(产物留在本次运行的 `dist-<slot>` artifact 里取证,它们红了也
不连坐 Windows 发布)。手动入口 `workflow_dispatch`(分支 ref)把六槽位整体编一遍、不发布;将来某槽位
真机验证通过,把它的键加进这一行即打开(齐全性检查与 SHA256SUMS 自动跟着扩),并同步 §1/§9 与本文件。
- **发布白名单(`PUBLISH_SLOTS`,唯一开关)**:默认只构建两个 Windows 槽位,只有白名单里的槽位进 Release 与
`SHA256SUMS.txt`——当前 = `windows-x64 windows-arm64`;四档未验证的(默认连构建都不跑)不推给用户。
将来某槽位真机验证通过:`plan` 槽位表里把它的 `mode` 从 `probe` 改成 `ci`、把键加进这一行(齐全性检查
与 `SHA256SUMS` 自动跟着扩)、再同步 §1/§9 与 `release-notes.md`——三处缺一即是假话。
- `release` job:下载全部 artifact → **按白名单裁剪** → 重算 `SHA256SUMS.txt` → 用 `packaging/release-notes.md`
模板渲染支持矩阵 → `gh release create`(**pre-release 默认开**:首建时 `push` 触发按 pre-release,`workflow_dispatch` 可关)。
- **同一 tag 重跑幂等**:`gh release view` 命中已存在的 Release 时改走 `gh release upload --clobber`
+ `gh release edit`,覆盖资产与说明而不是再 `create`(`create` 遇已存在会失败,把流水线最后一步染红)。
- **pre-release 标记只按显式输入断言**:`gh release edit` 分支在默认重跑(`push` 触发的 Re-run,
`inputs.prerelease` 为空)时**不传** `--prerelease`,所以重跑**不会**翻转标记;只有 tag ref 上的
`workflow_dispatch` 显式给了输入才断言——`prerelease=true` → `--prerelease`,`prerelease=false` →
`--prerelease=false`。要改标记两条路等价且互不打架:① 走流水线
`gh workflow run release.yml --ref v0.2.1 -f prerelease=false`(会落到 edit 分支显式断言)
② 直接 `gh release edit <tag> --prerelease=false`(不经流水线;后续默认重跑不碰该标记,
不会被翻回去)。首建(`create`)仍保持「pre-release 默认开」的老契约,空输入按 `true` 处理。
`workflow_dispatch` 显式给了输入才断言(`prerelease=true` → `--prerelease`,`false` → `--prerelease=false`)。
要改标记两条路等价且互不打架:① 走流水线 `gh workflow run release.yml --ref v0.2.1 -f prerelease=false`
(会落到 edit 分支显式断言)② 直接 `gh release edit <tag> --prerelease=false`(不经流水线;后续默认重跑
不碰该标记,不会被翻回去)。首建(`create`)仍保持「pre-release 默认开」的老契约,空输入按 `true` 处理。
Windows 为什么用 MSVC 静态 CRT 而不是本机这套 GNU 工具链:两者都属"标准工具链"(D21),
但发布产物要**不依赖 VC++ 可再发行包**,`+crt-static` 把 CRT 静态链进 exe,Win10+ 的 UCRT 本身是
@@ -149,7 +150,7 @@ Windows ARM64 原生库(Mojang/LWJGL 只发 x64/x86),实际游玩仍走系
| 依赖 | 说明 |
|------|------|
| glibc ≥ 2.35 | 由 `ubuntu-22.04` 构建决定;更老的发行版请自行重建或等 musl 版 |
| glibc ≥ 2.35 | 由 `ubuntu-22.04` 构建决定(该槽位默认不编,`all_slots=true` 取证跑才有产物);更老的发行版请自行重建或等 musl 版 |
| `libxkbcommon.so.0` | winit 键盘处理 |
| `libfontconfig.so.1` + `libfreetype.so.6` | 文本渲染 |
| `libGL.so.1` / `libEGL.so.1` | Slint 版:femtovg 的 GL 渲染;iced 版:wgpu 的 GL/EGL 后端(**推断,未实测**)。两者缺失都退到 CPU 软渲染(tiny-skia) |
@@ -166,7 +167,7 @@ arm64 侧同理(同一份依赖树;历史口径里的「winit + femtovg」
### Linux arm64(aarch64)
依赖与 x64 完全同一套(`libxkbcommon` / `fontconfig` / `libGL` / `libxcb` / `libwayland-client`),
**glibc 地板也相同**:arm64 槽位跑在原生 `ubuntu-22.04-arm` runner 上,地板 = **2.35**,与 x64
**glibc 地板也相同**:arm64 槽位跑在原生 `ubuntu-22.04-arm` runner 上(默认矩阵不编它,只有 `all_slots=true` 取证跑才出产物),地板 = **2.35**,与 x64
用的 `ubuntu-22.04` 一致。选 22.04 而不是 24.04 就是为了这个地板——24.04 的 glibc 更高,会把
Debian 12(2.36)、Raspberry Pi OS Bookworm(2.36)这些实际在跑的 ARM 发行版挡在门外。
要抬地板(例如将来 ARM 生态整体上移)换 `release.yml` 里那个槽位的 `os` 即可,脚本与产物名都不用动;
@@ -334,19 +335,19 @@ runner 上的真跑(本机连 `raw.githubusercontent.com` 都解析不了,
|------|---------|------|-----------|
| Windows 10/11 x64 | ✅ | 一等 | 无(UCRT 系统自带) |
| Windows 11 ARM64 | ✅ | 一等(启动器产物) | 无额外库;启动器原生运行,游戏本体走系统 x64 模拟层 + x64 JDK |
| macOS 12+(arm64 / x64) | ❌ 只构建取证 | 一等(未真机验证) | 无第三方库;未签名需去 quarantine |
| Linux x64 X11 | ❌ 只构建取证 | 一等(未真机验证) | glibc 2.35+、xkbcommon、fontconfig、libGL、xcb |
| Linux x64 Wayland | ❌ 只构建取证 | 支持 | 上述 + wayland-client |
| Linux arm64 X11 | ❌ 只构建取证 | 一等(未真机验证) | glibc 2.35+(`ubuntu-22.04-arm` 原生构建,**与 x64 同地板**)、xkbcommon、fontconfig、libGL、xcb |
| Linux arm64 Wayland | ❌ 只构建取证 | 支持 | 上述 + wayland-client |
| macOS 12+(arm64 / x64) | ❌ 不构建 | 一等(未真机验证) | 无第三方库;未签名需去 quarantine |
| Linux x64 X11 | ❌ 不构建 | 一等(未真机验证) | glibc 2.35+、xkbcommon、fontconfig、libGL、xcb |
| Linux x64 Wayland | ❌ 不构建 | 支持 | 上述 + wayland-client |
| Linux arm64 X11 | ❌ 不构建 | 一等(未真机验证) | glibc 2.35+(`ubuntu-22.04-arm` 原生构建,**与 x64 同地板**)、xkbcommon、fontconfig、libGL、xcb |
| Linux arm64 Wayland | ❌ 不构建 | 支持 | 上述 + wayland-client |
| Windows 8.1/8/7 | — | 不支持 | 基线已上调(D21) |
| Android Termux + X11 | — | 试验级(不承诺) | 仅 CLI(源码自建),GUI 未验证,不在本发布矩阵内 |
`packaging/release-notes.md` 的 "Support matrix" 表与上表逐行对应(英文版同样带 published / not
published 一列,Termux 行标注 experimental)——改一边必须同步另一边,否则标题里的"一致"就是假话。
两个 arm64 槽位都是**正式矩阵槽位**(不是 Termux 那种源码自建旁路),但**本版只有 `windows-arm64`
发布**:`linux-arm64` 由原生 runner 编、尚未真机验证,发布开关就是 `release.yml` 的 `PUBLISH_SLOTS`。
两个 arm64 槽位都是**正式矩阵槽位**(不是 Termux 那种源码自建旁路),但本版只有 `windows-arm64` 发布;`linux-arm64` 连构建都不跑
(默认矩阵只有两个 Windows 槽位),发布开关是 `release.yml` 的 `PUBLISH_SLOTS`,取证入口是 `all_slots=true`。
## 10. 已知边界 / 后续
+15 -13
View File
@@ -14,10 +14,12 @@ Asset names are `<name>_<version>_<platform>_<arch>`, underscore separated — t
| Windows 10/11 x64 | `unlucky-launcher_{{VERSION}}_windows_x64.exe` | single exe, double-click to run |
| Windows 11 ARM64 | `unlucky-launcher_{{VERSION}}_windows_arm64.exe` | single exe, runs natively on ARM64 Windows |
**This release ships Windows only.** The Linux (x64 / arm64) and macOS (Apple Silicon / Intel) slots are
built by CI but are not assets of this release: they have not been verified on real machines yet, so
nothing unverified is handed out. They stay out of the download list and out of `SHA256SUMS.txt` until
that verification happens — the support matrix below marks them accordingly.
**This release ships Windows only, and CI builds Windows only.** The Linux (x64 / arm64) and macOS
(Apple Silicon / Intel) slots are not built by the release workflow at all — they have not been verified
on real machines yet, so nothing unverified is handed out and no build minutes are spent on them. They
stay out of the download list and out of `SHA256SUMS.txt` until that verification happens; a manual
workflow run can build all six slots for that purpose, but the four extra slots are never published. The
support matrix below marks those slots accordingly.
The Windows assets are bare `.exe` files, so `LICENSE`, `NOTICE` and `README.md` are attached to this
release next to them: the license terms travel with every download. Slots that ship an archive (Linux /
@@ -45,19 +47,19 @@ Published = shipped as a download of **this** release, listed in `SHA256SUMS.txt
| --- | --- | --- | --- |
| Windows 10/11 x64 | **published** | first class | nothing beyond the OS (UCRT is part of Win10+) |
| Windows 11 ARM64 | **published** | first class (launcher artifact) | nothing extra; the launcher runs natively, the game itself runs through the OS x64 emulation layer with an x64 JDK |
| macOS 12+ Apple Silicon | built by CI, not published | first class (unverified) | nothing; unsigned build, needs the Gatekeeper workaround |
| macOS 12+ Intel | built by CI, not published | first class (unverified) | same as above |
| Linux x64, X11 | built by CI, not published | first class (unverified) | `libxkbcommon`, `fontconfig`, `libGL` (or software renderer), `libxcb` |
| Linux x64, Wayland | built by CI, not published | supported (unverified) | `wayland-client`, `libxkbcommon`, plus the X11 set for XWayland apps |
| Linux arm64, X11 | built by CI, not published | first class (unverified) | glibc 2.35+, `libxkbcommon`, `fontconfig`, `libGL`, `libxcb` |
| Linux arm64, Wayland | built by CI, not published | supported (unverified) | the above plus `wayland-client` |
| macOS 12+ Apple Silicon | not built (unverified) | first class (unverified) | nothing; unsigned build, needs the Gatekeeper workaround |
| macOS 12+ Intel | not built (unverified) | first class (unverified) | same as above |
| Linux x64, X11 | not built (unverified) | first class (unverified) | `libxkbcommon`, `fontconfig`, `libGL` (or software renderer), `libxcb` |
| Linux x64, Wayland | not built (unverified) | supported (unverified) | `wayland-client`, `libxkbcommon`, plus the X11 set for XWayland apps |
| Linux arm64, X11 | not built (unverified) | first class (unverified) | glibc 2.35+, `libxkbcommon`, `fontconfig`, `libGL`, `libxcb` |
| Linux arm64, Wayland | not built (unverified) | supported (unverified) | the above plus `wayland-client` |
| Windows 8.1/8/7 | not built | unsupported | the baseline is Windows 10 |
| Android — Termux + X11 | not built (no CI slot) | experimental, not promised | CLI only and only when built from source; GUI unverified |
Both arm64 rows are formal matrix slots, not the experimental Termux path: Windows ARM64 ships here and
is cross-built with the same static-CRT gate as x64; Linux arm64 builds on a native ARM64 runner and
joins this list once someone has run it on real hardware. The rows above and the matrix table in
`packaging/README.md` §9 are the same list — change one, change the other.
is cross-built with the same static-CRT gate as x64; Linux arm64 is kept as a matrix slot but is not built
by default — someone has to run it on real hardware (via a manual all-slots run) before it joins this list.
The rows above and the matrix table in `packaging/README.md` §9 are the same list — change one, change the other.
## Install