-
Notifications
You must be signed in to change notification settings - Fork 1
493 lines (458 loc) · 22.8 KB
/
Copy pathrelease.yml
File metadata and controls
493 lines (458 loc) · 22.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
# 发一版 twcore 的二进制。
#
# **它存在的理由是桌面版。**桌面版的 `.app` 里要装一份 twcore,而
# 「装的是哪一版」必须是钉死、可复核的 —— 从隔壁仓库的 target 目录复制
# 一份过去,等于把「发出去的是什么」交给那台机器当时的状态。
#
# 这条流水线不重跑那四道门:tag 是从 main 上打的,而 main 上的每一个
# commit 都过过 `ci.yml`。这里只做 CI 做不了的那件事 —— 产出一个别人
# 能下载、能校验的文件。
#
# **所有平台一起发,或者都不发。**各平台的 job 只构建、自检,把文件交给
# 最后的 `publish`,Release 由它一次写成。各挂各的时候,先编完的那个就把
# Release 建了出来,`releases/latest` 随即指向它,而别的平台的文件还在路上
# —— 那几分钟里 `scripts/install.sh` 和 `twcore upgrade` 在那些平台上找不到
# 文件;某个平台编挂了,发出去的就是缺一块的 Release。
name: Release
on:
push:
tags: ["v*"]
# **排练。**手工触发时照常构建、照常自检,但什么都不发:文件留在这次
# 运行的产物(Artifacts)里,`publish` 照样把它们逐个核对,只是不写 Release。
#
# 理由是这条流水线唯一一个「发现了也没法在本次补救」的性质:tag 一旦
# 推上去,流水线错了就得把它撤回来。而这里新增的那条 Windows 支线要靠
# 交叉编译到 arm64,那件事成不成只有真跑一次才知道 —— 用一个 tag 去
# 问这个问题太贵了。
workflow_dispatch:
permissions:
contents: write
env:
CARGO_TERM_COLOR: always
jobs:
twcore:
name: twcore (aarch64-apple-darwin)
# 只发 Apple Silicon。**不是「暂时」** —— 覆盖不到的那部分机器,
# 拿到的是一个能下载但打不开的文件,而那比没有更糟;真要支持 Intel
# 就得做通用二进制,那是另一个决定。
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
# wasm32:插件沙箱里的 QuickJS(crates/tw-plugin/build.rs)
targets: aarch64-apple-darwin, wasm32-unknown-unknown
- uses: Swatinem/rust-cache@v2
# 编插件沙箱要一个能出 wasm 的 clang:Homebrew 的 llvm
- name: Toolchain for the plugin sandbox
run: bash scripts/wasm-toolchain.sh
# `-p tw-plugin`:网关还没接上插件之前,它不在 twcore 的依赖里,不点名就
# 没人编它 —— 而这条流水线要证明的正是每个目标平台都编得出沙箱
- name: Build
run: cargo build --release -p twcore -p tw-plugin --target aarch64-apple-darwin
# 这个平台的沙箱是哪个 clang 编的、wasm 的哈希:进摘要,也交给 publish
- name: Which compiler built the plugin sandbox
run: bash scripts/wasm-toolchain.sh record target/aarch64-apple-darwin/release guest-build/aarch64-apple-darwin.txt
- uses: actions/upload-artifact@v4
with:
name: guest-build-aarch64-apple-darwin
path: guest-build/
if-no-files-found: error
# **产物自检。**一个编得过但起不来的二进制,从文件列表上看不出
# 任何问题 —— 而它会一路发到用户手里。
- name: It runs, and it is the version on the tag
run: |
set -euo pipefail
BIN=target/aarch64-apple-darwin/release/twcore
file "$BIN" | grep -q arm64
GOT=$("$BIN" --version | awk '{print $2}')
# 排练时没有 tag 可对,只把版本打出来
if [ "$GITHUB_REF_TYPE" = tag ]; then
WANT="${GITHUB_REF_NAME#v}"
if [ "$GOT" != "$WANT" ]; then
echo "tag 是 $WANT,而二进制报的是 $GOT —— Cargo.toml 的版本没跟上" >&2
exit 1
fi
else
echo "排练:二进制报的是 $GOT"
fi
"$BIN" --help > /dev/null
- name: Package
run: |
set -euo pipefail
mkdir -p dist
cp target/aarch64-apple-darwin/release/twcore dist/twcore-aarch64-apple-darwin
cd dist
shasum -a 256 twcore-aarch64-apple-darwin > twcore-aarch64-apple-darwin.sha256
cat twcore-aarch64-apple-darwin.sha256
# 交给 `publish`,Release 只由它来写
- uses: actions/upload-artifact@v4
with:
name: twcore-aarch64-apple-darwin
path: dist/
if-no-files-found: error
twcore-windows:
name: twcore (Windows x64 + arm64)
# **两个架构都发**(x64 和 arm64)。x64 原生编,arm64 在同一台 x64
# runner 上交叉编 —— MSVC 的 ARM64 工具链在这个镜像里,而起一台
# arm64 runner 只为编一个二进制不划算。
#
# 交叉编译成不成,靠上面那个排练模式先问清楚,而不是拿一个 tag 去问。
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
targets: x86_64-pc-windows-msvc, aarch64-pc-windows-msvc, wasm32-unknown-unknown
- uses: Swatinem/rust-cache@v2
# 镜像预装的 LLVM(C:\Program Files\LLVM);没有就装官方发行版
- name: Toolchain for the plugin sandbox
shell: bash
run: bash scripts/wasm-toolchain.sh
# arm64 的沙箱机器码在 x64 上交叉编:build.rs 里的 Cranelift 直接编给目标平台
- name: Build
run: |
cargo build --release -p twcore -p tw-plugin --target x86_64-pc-windows-msvc
cargo build --release -p twcore -p tw-plugin --target aarch64-pc-windows-msvc
- name: Which compiler built the plugin sandbox
shell: bash
run: |
for t in x86_64-pc-windows-msvc aarch64-pc-windows-msvc; do
bash scripts/wasm-toolchain.sh record "target/$t/release" "guest-build/$t.txt"
done
- uses: actions/upload-artifact@v4
with:
name: guest-build-windows
path: guest-build/
if-no-files-found: error
# **产物自检。**一个编得过但起不来的二进制,从文件列表上看不出任何
# 问题 —— 而它会一路发到用户手里。
#
# arm64 那个在这台机器上跑不起来(x64 runner),所以只能查它到底是不是
# arm64 —— 读 PE 头里的 machine 字段,等价于 macOS 那边的 `file | grep
# arm64`。**这一条不是走过场**:交叉编译配错目标的表现正是产出一个
# 名字叫 arm64 的 x64 二进制。
- name: They are what they claim to be, and the x64 one runs
shell: pwsh
run: |
$ErrorActionPreference = "Stop"
function Get-PeMachine([string]$path) {
$fs = [System.IO.File]::OpenRead($path)
try {
$br = New-Object System.IO.BinaryReader($fs)
$fs.Position = 0x3C
$fs.Position = $br.ReadInt32()
if ($br.ReadUInt32() -ne 0x00004550) { throw "$path is not a PE file" }
return $br.ReadUInt16()
} finally { $fs.Dispose() }
}
$want = @{
"target\x86_64-pc-windows-msvc\release\twcore.exe" = 0x8664
"target\aarch64-pc-windows-msvc\release\twcore.exe" = 0xAA64
}
foreach ($p in $want.Keys) {
$got = Get-PeMachine $p
if ($got -ne $want[$p]) {
throw ("{0} is machine 0x{1:X4}, expected 0x{2:X4}" -f $p, $got, $want[$p])
}
Write-Host ("{0}: 0x{1:X4}" -f $p, $got)
}
$exe = "target\x86_64-pc-windows-msvc\release\twcore.exe"
$got = (& $exe --version).Split(" ")[1]
if ($env:GITHUB_REF_TYPE -eq "tag") {
$wantVer = $env:GITHUB_REF_NAME.TrimStart("v")
if ($got -ne $wantVer) {
throw "the tag says $wantVer but the binary reports $got -- Cargo.toml did not keep up"
}
} else {
Write-Host "rehearsal: the binary reports $got"
}
& $exe --help | Out-Null
# **不要用户另装 VC 运行库。**VC 运行库由 `.cargo/config.toml` 静态链接进来;
# 这里查两个 exe 的导入表,里面不许有 Windows 不自带的那几个 DLL。这台
# runner 上装着运行库,exe 照样跑得起来 —— 上一步看不出这件事,只有导入表看得出。
# 用的是链接它的那套 MSVC 里的 dumpbin,arm64 的 exe 一样读得了
- name: No Visual C++ runtime to install
shell: pwsh
run: |
$ErrorActionPreference = "Stop"
$vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
$dumpbin = & $vswhere -latest -products * -find "VC\Tools\MSVC\**\bin\Hostx64\x64\dumpbin.exe" |
Select-Object -First 1
if (-not $dumpbin) { throw "dumpbin.exe not found" }
foreach ($t in @("x86_64-pc-windows-msvc", "aarch64-pc-windows-msvc")) {
$exe = "target\$t\release\twcore.exe"
$deps = & $dumpbin /nologo /dependents $exe |
ForEach-Object { $_.Trim() } |
Where-Object { $_ -match '\.dll$' }
if ($LASTEXITCODE -ne 0 -or -not $deps) { throw "could not read the imports of $exe" }
Write-Host "${exe}: $($deps -join ', ')"
$redist = @($deps | Where-Object { $_ -match '^(vcruntime|msvcp|concrt|vccorlib|vcomp)\d' })
if ($redist.Count -gt 0) {
throw "$exe needs the Visual C++ runtime ($($redist -join ', ')) -- the static CRT in .cargo/config.toml did not apply"
}
}
- name: Package
shell: pwsh
run: |
$ErrorActionPreference = "Stop"
New-Item -ItemType Directory -Force -Path dist | Out-Null
foreach ($t in @("x86_64-pc-windows-msvc", "aarch64-pc-windows-msvc")) {
$out = "dist\twcore-$t.exe"
Copy-Item "target\$t\release\twcore.exe" $out
# **和 macOS 那边同一种校验文件**:`<sha> <文件名>`,两列,
# 两个空格 —— 下载的人用同一条 shasum -c 就能核。
$h = (Get-FileHash $out -Algorithm SHA256).Hash.ToLower()
"$h twcore-$t.exe" | Set-Content -NoNewline -Encoding ascii "$out.sha256"
Get-Content "$out.sha256"
}
- uses: actions/upload-artifact@v4
with:
name: twcore-windows
path: dist/
if-no-files-found: error
twcore-linux:
name: twcore (${{ matrix.target }})
# **两个架构都原生编**,各在自己架构的 runner 上 —— 交叉编 aarch64 要
# 一套 aarch64 的 glibc sysroot 和链接器,而 GitHub 给公开仓库提供了
# arm64 的 Linux runner(`ubuntu-22.04-arm`),原生编还能顺手把产物
# 跑一遍,交叉编的跑不了。
#
# **两个都是 22.04,不是 24.04。**glibc 只向后兼容:在 2.39(24.04)上
# 链出来的二进制,拿到 2.35(22.04)上会报 `GLIBC_2.38 not found` 起不来。
# 桌面版在 Linux 上的底线就是 22.04(WebKitGTK 4.1),core 跟它对齐。
#
# **不用 musl 静态编。**它能摆脱 glibc 版本,但桌面版本体反正要 glibc
# 2.35+,core 单独摆脱它换不来什么;而 musl 的内存分配器在多线程下慢得
# 多、DNS 解析的行为和 glibc 不同 —— 用户机器上出了问题,排查的是一个
# 和系统里其他程序都不一样的运行时。同一个 glibc 底线,排查也简单。
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-unknown-linux-gnu
runner: ubuntu-22.04
file_arch: x86-64
- target: aarch64-unknown-linux-gnu
runner: ubuntu-22.04-arm
file_arch: ARM aarch64
runs-on: ${{ matrix.runner }}
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}, wasm32-unknown-unknown
- uses: Swatinem/rust-cache@v2
with:
key: ${{ matrix.target }}
# 两种 runner 都预装 clang-15,两个架构用同一个版本(见脚本)
- name: Toolchain for the plugin sandbox
run: bash scripts/wasm-toolchain.sh
- name: Build
run: cargo build --release -p twcore -p tw-plugin --target ${{ matrix.target }}
- name: Which compiler built the plugin sandbox
run: bash scripts/wasm-toolchain.sh record "target/${{ matrix.target }}/release" "guest-build/${{ matrix.target }}.txt"
- uses: actions/upload-artifact@v4
with:
name: guest-build-${{ matrix.target }}
path: guest-build/
if-no-files-found: error
# **产物自检。**一个编得过但起不来的二进制,从文件列表上看不出任何
# 问题 —— 而它会一路发到用户手里。
#
# 比 macOS 那段多一条 glibc 的上限:runner 的镜像哪天换了、或者有人把
# 上面的 22.04 改成了 latest,产物就会悄悄要求一个更新的 glibc,而在
# 构建机上它照样跑得起来 —— 只有用户的 22.04 上起不来。
- name: It runs, it is the version on the tag, and it needs glibc 2.35 at most
env:
FILE_ARCH: ${{ matrix.file_arch }}
run: |
set -euo pipefail
BIN=target/${{ matrix.target }}/release/twcore
file "$BIN"
file "$BIN" | grep -q "$FILE_ARCH"
MAX_GLIBC=2.35
NEED=$(objdump -T "$BIN" | grep -o 'GLIBC_[0-9][0-9.]*' | sed 's/GLIBC_//' | sort -uV | tail -n 1)
if [ -z "$NEED" ]; then
echo "objdump found no GLIBC_ symbol versions in $BIN" >&2
exit 1
fi
echo "needs glibc $NEED (limit $MAX_GLIBC)"
if [ "$(printf '%s\n%s\n' "$NEED" "$MAX_GLIBC" | sort -V | tail -n 1)" != "$MAX_GLIBC" ]; then
echo "twcore needs glibc $NEED, newer than $MAX_GLIBC (Ubuntu 22.04)" >&2
exit 1
fi
GOT=$("$BIN" --version | awk '{print $2}')
# 排练时没有 tag 可对,只把版本打出来
if [ "$GITHUB_REF_TYPE" = tag ]; then
WANT="${GITHUB_REF_NAME#v}"
if [ "$GOT" != "$WANT" ]; then
echo "the tag says $WANT but the binary reports $GOT -- Cargo.toml did not keep up" >&2
exit 1
fi
else
echo "rehearsal: the binary reports $GOT"
fi
"$BIN" --help > /dev/null
# **两种形态。**裸二进制给桌面版的流水线和 `twcore upgrade`(它们只要
# 那一个文件);压缩包给服务器上的首次安装(`scripts/install.sh`):
# 里面还有 systemd unit,装的 unit 和装的二进制出自同一个 commit。
# 压缩包还保住了可执行位 —— 裸文件下载下来是 0644。
- name: Package
env:
TARGET: ${{ matrix.target }}
run: |
set -euo pipefail
# 压缩包里的目录和裸二进制同名,所以在 dist 外面搭
STAGE="$RUNNER_TEMP/stage/twcore-$TARGET"
mkdir -p dist "$STAGE"
cp "target/$TARGET/release/twcore" "dist/twcore-$TARGET"
install -m 0755 "target/$TARGET/release/twcore" "$STAGE/twcore"
install -m 0644 packaging/systemd/twcore.service LICENSE "$STAGE/"
tar -czf "dist/twcore-$TARGET.tar.gz" --owner=0 --group=0 -C "$RUNNER_TEMP/stage" "twcore-$TARGET"
cd dist
# 和另外两个平台同一种校验文件:`<sha> <文件名>`
sha256sum "twcore-$TARGET" > "twcore-$TARGET.sha256"
sha256sum "twcore-$TARGET.tar.gz" > "twcore-$TARGET.tar.gz.sha256"
cat ./*.sha256
tar -tzvf "twcore-$TARGET.tar.gz"
# 装脚本认的就是这个布局,这里照着它的步骤解一遍、跑一遍 —— 布局改了
# 而脚本没跟上,在这里就挂,而不是在用户的服务器上。
- name: The archive is what install.sh expects
env:
TARGET: ${{ matrix.target }}
run: |
set -euo pipefail
T=$(mktemp -d)
(cd dist && sha256sum -c "twcore-$TARGET.tar.gz.sha256")
tar -xzf "dist/twcore-$TARGET.tar.gz" -C "$T"
test -x "$T/twcore-$TARGET/twcore"
test -f "$T/twcore-$TARGET/twcore.service"
"$T/twcore-$TARGET/twcore" --version
- uses: actions/upload-artifact@v4
with:
name: twcore-${{ matrix.target }}
path: dist/
if-no-files-found: error
# **Release 只在这里写,而且只写一次。**
#
# 以前每个构建 job 各自用 action-gh-release 挂自己的文件,每一次都带着
# `generate_release_notes`。Release 已经存在时,这个 action 照样再要一份
# 生成的说明,接在原有正文后面 —— 于是 v0.44.0 到 v0.47.0 的说明各有四份
# (四个 job),v0.30.0 到 v0.43.0 各有两份(macOS、Windows 两个 job)。
# 现在正文由下面一步自己拼好交给它,不再让它生成。
publish:
name: Publish
needs: [twcore, twcore-windows, twcore-linux]
runs-on: ubuntu-latest
env:
# 发出去的就是这些,一个不多、一个不少。文件名是和桌面版的流水线、
# `twcore upgrade`、`scripts/install.sh` 之间的约定,`twcore upgrade` 有
# 一条测试读这份文件核对它。加一个平台要在这里加上它的文件 —— 否则
# 下面的核对会指出多出来的那几个
FILES: |
dist/twcore-aarch64-apple-darwin
dist/twcore-aarch64-apple-darwin.sha256
dist/twcore-x86_64-pc-windows-msvc.exe
dist/twcore-x86_64-pc-windows-msvc.exe.sha256
dist/twcore-aarch64-pc-windows-msvc.exe
dist/twcore-aarch64-pc-windows-msvc.exe.sha256
dist/twcore-x86_64-unknown-linux-gnu
dist/twcore-x86_64-unknown-linux-gnu.sha256
dist/twcore-x86_64-unknown-linux-gnu.tar.gz
dist/twcore-x86_64-unknown-linux-gnu.tar.gz.sha256
dist/twcore-aarch64-unknown-linux-gnu
dist/twcore-aarch64-unknown-linux-gnu.sha256
dist/twcore-aarch64-unknown-linux-gnu.tar.gz
dist/twcore-aarch64-unknown-linux-gnu.tar.gz.sha256
steps:
# 发布页的正文要用这个仓库里的脚本和 `release-notes/`。先取代码再下载产物:
# checkout 会清空工作目录
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
path: dist
pattern: twcore-*
merge-multiple: true
# 每个平台的插件沙箱是哪个 clang 编的、wasm 的哈希。**只记录,不卡发版**:
# macOS 用 Homebrew 的 llvm、Linux 用 clang-15、Windows 用镜像里的 LLVM,
# 编译器不同,哈希本来就不同;同一个编译器编的(两个 Linux)应当相同
- uses: actions/download-artifact@v4
with:
path: guest-build
pattern: guest-build-*
merge-multiple: true
- name: Which compiler built each plugin sandbox
run: |
set -euo pipefail
{
echo "### Plugin sandbox"
echo
echo "| target | guest.wasm sha256 | clang |"
echo "|---|---|---|"
for f in guest-build/*.txt; do
t=$(basename "$f" .txt)
sha=$(awk '/^guest.wasm sha256 /{print $3}' "$f")
cc=$(sed -n 's/^clang //p' "$f" | head -n 1)
echo "| $t | \`$sha\` | $cc |"
done
} | tee -a "$GITHUB_STEP_SUMMARY"
# 排练也跑这一步:构建 job 交来的正好是清单上的文件,每个都对得上
# 它的校验和
- name: Every file is here, nothing else is, and each matches its checksum
run: |
set -euo pipefail
diff <(printf '%s' "$FILES" | sort) <(find dist -type f | sort)
cd dist
sha256sum -c ./*.sha256
# 发布页:标题「ThinkWatch Core <版本>」,正文(英文)由
# `scripts/release_notes.py` 写 —— `release-notes/<版本>.md` 里的说明(可以
# 没有)、下载表、服务器上安装和升级的命令、核对方法,最后是 GitHub 按上一版
# 以来合进 main 的 PR 生成的清单。排练也写,写进这次运行的摘要里,不发布。
#
# **正文只写一次。**Release 已经在了 —— 重跑这个 job(比如挂文件挂到一半
# 断了),或者 Release 先手工建好了(v0.11.0 就是这样多出一份说明的)——
# 就不动它的正文。以前这里每跑一次就接上一份生成的清单。
#
# **「不存在」只认 gh 查不到时的那句 `release not found`。**网络断了、令牌
# 不对、被限流,gh 一样失败;把那些也当成「不存在」,Release 其实在的话它的
# 正文就被盖掉。所以别的失败让这一步挂掉,原话留在日志里
- name: The page text, only for a release that does not exist yet
id: notes
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
if [ "$GITHUB_REF_TYPE" = tag ]; then
VERSION="${GITHUB_REF_NAME#v}"
echo "VERSION=$VERSION" >> "$GITHUB_ENV"
if out=$(gh release view "$GITHUB_REF_NAME" --repo "$GITHUB_REPOSITORY" --json tagName 2>&1); then
echo "release $GITHUB_REF_NAME already exists; its text is left as it is"
echo "path=" >> "$GITHUB_OUTPUT"
exit 0
elif ! grep -qx 'release not found' <<<"$out"; then
echo "$out" >&2
exit 1
fi
else
# 排练没有 tag:用代码里的版本号
VERSION=$(awk -F'"' '/^version *= *"/ { print $2; exit }' Cargo.toml)
fi
# 清单向 GitHub 要:和它在发布页上「自动生成」的是同一份。排练时这个 tag
# 可能还不存在,那就算到这次的 commit 为止(tag 存在时 target_commitish
# 不起作用)
gh api "repos/$GITHUB_REPOSITORY/releases/generate-notes" \
-f tag_name="v$VERSION" -f target_commitish="$GITHUB_SHA" \
--jq .body > "$RUNNER_TEMP/changes.md"
python3 scripts/release_notes.py "$VERSION" "$RUNNER_TEMP/changes.md" > "$RUNNER_TEMP/notes.md"
cat "$RUNNER_TEMP/notes.md" >> "$GITHUB_STEP_SUMMARY"
echo "path=$RUNNER_TEMP/notes.md" >> "$GITHUB_OUTPUT"
- uses: softprops/action-gh-release@v2
# 排练到上面为止
if: github.ref_type == 'tag'
with:
name: ThinkWatch Core ${{ env.VERSION }}
# 空的话(Release 已经在了)这个 action 保留原有的正文
body_path: ${{ steps.notes.outputs.path }}
files: ${{ env.FILES }}
fail_on_unmatched_files: true