Repository navigation
196 lines (182 loc) · 8.58 KB
/
Copy pathrelease.yml
File metadata and controls
196 lines (182 loc) · 8.58 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
name: Release Electron App
# 由 semantic-release 创建的 v* tag 触发:构建 Electron 安装包并附加到对应 Release
on:
push:
tags: ['v*']
# 兜底触发:semantic-release 若以内置 GITHUB_TOKEN 推 tag,
# GitHub 防递归机制不会派发 push 事件,导致本工作流从不运行、
# Release 资产为空(latest.yml 404)。Release 发布事件可正常触发补跑。
release:
types: [published]
# 手动兜底:在 UI 选择对应 tag 运行,用于补发历史版本资产
workflow_dispatch:
# 上传构建产物到 GitHub Release 需要写权限
permissions:
contents: write
# 同一 tag 的多个触发源(push/release)串行执行,避免重复上传竞争
concurrency:
group: release-electron-${{ github.ref_name }}
cancel-in-progress: false
jobs:
lint-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
cache-dependency-path: client/package-lock.json
- run: cd client && npm ci
- run: cd client && npm run lint
- run: cd client && npm run test -- --run
build:
needs: lint-test
# 本产品为 Windows-only(electron-builder.yml 仅定义 win target)。
# macOS 无有效构建目标必然报 ERR_ELECTRON_BUILDER_CANNOT_EXECUTE,
# 且默认 fail-fast 会连带取消 Windows 构建,导致 release/同步步骤永不执行。
# 如未来支持 mac,需补回带签名的 mac target 后再加入 matrix。
strategy:
matrix:
os: [windows-latest]
runs-on: ${{ matrix.os }}
steps:
# lfs: true 必需:app-icon.png 等 PNG 由 Git LFS 托管(.gitattributes:
# *.png filter=lfs),不拉取则仅为 131 字节指针文件,
# electron-builder 图标转换(PNG→ICO)解码失败,
# 报 ERR_ELECTRON_BUILDER_CANNOT_EXECUTE。
- uses: actions/checkout@v4
with:
lfs: true
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
cache-dependency-path: client/package-lock.json
- run: cd client && npm ci
# --publish never:发布由下方 release job 统一负责,避免 electron-builder
# 因检测到 tag 而自行尝试发布(github provider 无 GH_TOKEN 会报错)
#
# DOWNLOAD_BASE_URL 已配置时,用 -c.publish.0.url 覆盖 generic 更新源为 CDN,
# 使新包内的 app-update.yml 指向 CDN;未配置时沿用 electron-builder.yml
# 中的自建服务器地址。注:存量客户端的更新源已固化在已安装的
# app-update.yml 中,故 ECS 与 GitHub 两侧资产均需继续发布。
- name: Build Electron app
shell: bash
env:
DOWNLOAD_BASE_URL: ${{ secrets.DOWNLOAD_BASE_URL }}
run: |
cd client
if [ -n "$DOWNLOAD_BASE_URL" ]; then
echo "Update feed -> $DOWNLOAD_BASE_URL"
npm run electron:build -- --publish never -c.publish.0.url="$DOWNLOAD_BASE_URL"
else
echo "Update feed -> 默认(electron-builder.yml 中的自建服务器)"
npm run electron:build -- --publish never
fi
- uses: actions/upload-artifact@v4
with:
name: release-${{ matrix.os }}
# latest*.yml 与 *.blockmap 是 electron-updater 自动更新的必需文件
path: |
client/release/*.exe
client/release/*.blockmap
client/release/latest*.yml
release:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v4
with:
pattern: release-*
- uses: softprops/action-gh-release@v2
with:
files: release-*/*
# ---------------------------------------------------------------
# 同步 Windows 安装包至自建服务器(国内主下载源 + 自动更新源)
# latest.json 供官网下载页动态展示版本/直链;latest.yml 供 electron-updater
# ---------------------------------------------------------------
- name: Generate latest.json for website
id: meta
run: |
YML=release-windows-latest/latest.yml
VERSION=$(grep -m1 '^version:' "$YML" | awk '{print $2}')
FILE=$(grep -m1 '^path:' "$YML" | sed 's/^path: //')
SIZE=$(stat -c%s "release-windows-latest/$FILE")
SHA256=$(sha256sum "release-windows-latest/$FILE" | awk '{print $1}')
DATE=$(date -u +%F)
printf '{"version":"%s","fileName":"%s","size":%s,"sha256":"%s","releaseDate":"%s"}\n' \
"$VERSION" "$FILE" "$SIZE" "$SHA256" "$DATE" > release-windows-latest/latest.json
cat release-windows-latest/latest.json
# 供下方 CDN 预热步骤拼接 URL
echo "file=$FILE" >> "$GITHUB_OUTPUT"
- name: Ensure downloads directory on server
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: mkdir -p /opt/Entropydecrease/downloads
# 先传二进制(exe/blockmap),后传元数据(yml/json):
# 避免 latest.yml 率先就位时指向尚未上传完成的安装包(更新 404 窗口期)
- name: Upload installer binaries to server
uses: appleboy/scp-action@v0.1.7
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
source: release-windows-latest/*.exe,release-windows-latest/*.blockmap
target: /opt/Entropydecrease/downloads
strip_components: 1
- name: Publish update metadata (last, avoids 404 window)
uses: appleboy/scp-action@v0.1.7
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
source: release-windows-latest/latest.yml,release-windows-latest/latest.json
target: /opt/Entropydecrease/downloads
strip_components: 1
# 保留策略:仅保留最近 3 个版本的安装包,防止磁盘增长
- name: Prune old versions (keep last 3)
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd /opt/Entropydecrease/downloads
ls -t -- *.exe 2>/dev/null | tail -n +4 | while read -r f; do
rm -f -- "$f" "$f.blockmap"
done
# ---------------------------------------------------------------
# CDN 预热:大文件在 CDN 上按分片缓存,未被请求过的分片不在缓存中,
# 首批用户会退化为实时回源而受源站带宽限制。
# 实测:已缓存分片 10.5MB/s,未缓存分片仅 106KB/s(相差约 95 倍),
# 故预热不是可选优化而是大文件分发的必要步骤。
# 预热为异步任务,API 返回后后台继续拉取,此处不等待完成。
# ---------------------------------------------------------------
- name: Prefetch CDN cache
# 仅在已切换至 CDN 且配置了预热凭证时执行;未配置则跳过
if: ${{ secrets.DOWNLOAD_BASE_URL != '' && secrets.ALIYUN_ACCESS_KEY_ID != '' }}
# 预热失败不应推翻已成功的发布,仅标记警告
continue-on-error: true
env:
ALIBABA_CLOUD_ACCESS_KEY_ID: ${{ secrets.ALIYUN_ACCESS_KEY_ID }}
ALIBABA_CLOUD_ACCESS_KEY_SECRET: ${{ secrets.ALIYUN_ACCESS_KEY_SECRET }}
DOWNLOAD_BASE_URL: ${{ secrets.DOWNLOAD_BASE_URL }}
FILE_NAME: ${{ steps.meta.outputs.file }}
run: |
set -eo pipefail
curl -sL https://aliyuncli.alicdn.com/aliyun-cli-linux-latest-amd64.tgz -o /tmp/aliyun.tgz
tar -xzf /tmp/aliyun.tgz -C /tmp
BASE="${DOWNLOAD_BASE_URL%/}"
# 预热安装包与 blockmap(差量更新依赖);
# latest.yml/json 按设计不缓存,且仅几百字节,无需预热
OBJECTS="$BASE/$FILE_NAME"$'\n'"$BASE/$FILE_NAME.blockmap"
echo "Prefetching:"
echo "$OBJECTS"
/tmp/aliyun cdn PushObjectCache \
--region cn-hangzhou \
--ObjectPath "$OBJECTS" \
--Area domestic