Skip to content

Commit fdd28b7

Browse files
committed
ci(release): 按组件拆分独立 release 并按 tag 范围检测变更
- 新增 changes 前置 job:diff 上一个 v* tag..当前 tag,按目录门控构建 (fluxDown/ → 扩展、website/ → 官网、docs/ 与 *.md 不触发、其余 → 客户端; 无前驱 tag 时全量构建) - Release 拆分为三个独立发布:客户端沿用推送的 v* tag(保持 latest), 扩展/官网使用 extension-v* / website-v* tag 且 make_latest=false, release notes 用 git-cliff --include-path 只收本目录 commit - 新增 build-website job:npm install + astro build,打包 dist 为 tar.gz - artifact 清理移至最终 cleanup-artifacts job(always 执行) - cliff.toml tag_pattern 锚定 ^v,排除组件 tag 污染 changelog 范围 - 官网 API 适配拆分后的 release 结构:/api/release 按「v* tag 且含 Windows 安装包」选客户端 release、扩展资产改从独立扩展 release 获取; /api/changelog 过滤组件 release;/api/download 无 tag 时按资产名定位
1 parent 05c8591 commit fdd28b7

5 files changed

Lines changed: 301 additions & 36 deletions

File tree

.github/workflows/release.yml

Lines changed: 240 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,68 @@ permissions:
1010
actions: write # 允许在 release job 末尾删除旧 artifact(避免 500MB 配额耗尽)
1111

1212
jobs:
13+
# ── 前置 Job: 检测上一个版本 tag → 当前 tag 之间哪些组件目录有变更 ──
14+
# 规则:
15+
# fluxDown/** → 浏览器扩展(extension)
16+
# website/** → 官网(website)
17+
# docs/**、*.md → 纯文档,不触发任何构建
18+
# 其余任何路径 → 桌面客户端(app)
19+
# 找不到上一个 v* tag(首个版本)时全部视为有变更。
20+
changes:
21+
name: Detect Changed Components
22+
runs-on: ubuntu-latest
23+
outputs:
24+
app: ${{ steps.detect.outputs.app }}
25+
extension: ${{ steps.detect.outputs.extension }}
26+
website: ${{ steps.detect.outputs.website }}
27+
steps:
28+
- name: Checkout repository
29+
uses: actions/checkout@v4
30+
with:
31+
fetch-depth: 0
32+
fetch-tags: true
33+
34+
- name: Detect changes since previous version tag
35+
id: detect
36+
shell: bash
37+
run: |
38+
TAG="${GITHUB_REF#refs/tags/}"
39+
# 只匹配 v0.1.2 形式的版本 tag(glob 从头锚定,
40+
# 自动忽略 release 流程创建的 extension-v* / website-v* 组件 tag)
41+
PREV=$(git describe --tags --abbrev=0 --match 'v[0-9]*' "${TAG}^" 2>/dev/null || true)
42+
43+
APP=false; EXTENSION=false; WEBSITE=false
44+
if [ -z "$PREV" ]; then
45+
echo "No previous version tag found — building everything"
46+
APP=true; EXTENSION=true; WEBSITE=true
47+
else
48+
echo "Diff range: ${PREV}..${TAG}"
49+
CHANGED=$(git diff --name-only "${PREV}" "${TAG}")
50+
echo "── Changed files ──"
51+
echo "$CHANGED"
52+
while IFS= read -r f; do
53+
[ -z "$f" ] && continue
54+
case "$f" in
55+
fluxDown/*) EXTENSION=true ;;
56+
website/*) WEBSITE=true ;;
57+
docs/*|*.md) ;;
58+
*) APP=true ;;
59+
esac
60+
done <<< "$CHANGED"
61+
fi
62+
63+
{
64+
echo "app=$APP"
65+
echo "extension=$EXTENSION"
66+
echo "website=$WEBSITE"
67+
} >> "$GITHUB_OUTPUT"
68+
echo "::notice::Components changed in ${PREV:-<none>}..${TAG}: app=$APP extension=$EXTENSION website=$WEBSITE"
69+
1370
# ── 并行 Job 1: 构建 Windows 安装包(x64 + ARM64)──
1471
build-windows:
1572
name: Build Windows (${{ matrix.arch }})
73+
needs: changes
74+
if: needs.changes.outputs.app == 'true'
1675
strategy:
1776
fail-fast: false
1877
matrix:
@@ -175,6 +234,8 @@ jobs:
175234
build-extension:
176235
name: Build Browser Extension
177236
runs-on: ubuntu-latest
237+
needs: changes
238+
if: needs.changes.outputs.extension == 'true'
178239

179240
steps:
180241
- name: Checkout repository
@@ -420,6 +481,8 @@ jobs:
420481
build-linux:
421482
name: Build Linux (x64)
422483
runs-on: ubuntu-22.04
484+
needs: changes
485+
if: needs.changes.outputs.app == 'true'
423486

424487
steps:
425488
- name: Checkout repository
@@ -710,6 +773,8 @@ jobs:
710773
# ── 并行 Job 4: 构建 macOS DMG + tar.gz(Intel x64 + Apple Silicon arm64)──
711774
build-macos:
712775
name: Build macOS (${{ matrix.arch }})
776+
needs: changes
777+
if: needs.changes.outputs.app == 'true'
713778
strategy:
714779
fail-fast: false
715780
matrix:
@@ -853,11 +918,55 @@ jobs:
853918
path: build/installer/FluxDown-*-macos-${{ matrix.arch }}.tar.gz
854919
if-no-files-found: error
855920

856-
# ── 最终 Job: 等待所有构建完成后统一发布 Release ──
857-
release:
858-
name: Create GitHub Release
921+
# ── 并行 Job 5: 构建官网(website/ 有变更时)──
922+
build-website:
923+
name: Build Website
859924
runs-on: ubuntu-latest
860-
needs: [build-windows, build-extension, build-linux, build-macos]
925+
needs: changes
926+
if: needs.changes.outputs.website == 'true'
927+
928+
steps:
929+
- name: Checkout repository
930+
uses: actions/checkout@v4
931+
932+
- name: Setup Node.js
933+
uses: actions/setup-node@v4
934+
with:
935+
node-version: "22"
936+
937+
- name: Get version from tag
938+
id: version
939+
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> "$GITHUB_OUTPUT"
940+
941+
# website/ 无 package-lock.json,不能用 npm ci
942+
- name: Install dependencies
943+
run: npm install
944+
working-directory: website
945+
946+
- name: Build website
947+
run: npm run build
948+
working-directory: website
949+
950+
# 打包 Node standalone 构建产物(dist/ 含 server + client)
951+
- name: Package website dist
952+
run: |
953+
VERSION=${{ steps.version.outputs.VERSION }}
954+
mkdir -p build/website
955+
tar -czf "build/website/FluxDown-website-${VERSION}.tar.gz" -C website dist
956+
ls -la build/website/
957+
958+
- name: Upload website artifact
959+
uses: actions/upload-artifact@v4
960+
with:
961+
name: website-dist
962+
path: build/website/FluxDown-website-*.tar.gz
963+
if-no-files-found: error
964+
965+
# ── Release Job 1: 桌面客户端(使用推送的 v* tag,保持 GitHub latest release 语义)──
966+
release-app:
967+
name: Release Desktop App
968+
runs-on: ubuntu-latest
969+
needs: [build-windows, build-linux, build-macos]
861970

862971
steps:
863972
- name: Checkout repository
@@ -889,53 +998,167 @@ jobs:
889998
echo "── Release notes ──"
890999
cat RELEASE_NOTES.md
8911000
892-
# ── 下载所有构建产物 ──
1001+
# ── 下载桌面客户端构建产物 ──
8931002
- name: Download all Windows artifacts
8941003
uses: actions/download-artifact@v4
8951004
with:
8961005
pattern: windows-*
8971006
path: release-assets/
8981007
merge-multiple: true
8991008

900-
- name: Download browser extensions
1009+
- name: Download Linux artifacts
9011010
uses: actions/download-artifact@v4
9021011
with:
903-
pattern: browser-extension-*
1012+
pattern: linux-*
9041013
path: release-assets/
9051014
merge-multiple: true
9061015

907-
- name: Download Linux artifacts
1016+
- name: Download macOS artifacts
9081017
uses: actions/download-artifact@v4
9091018
with:
910-
pattern: linux-*
1019+
pattern: macos-*
9111020
path: release-assets/
9121021
merge-multiple: true
9131022

914-
- name: Download macOS artifacts
1023+
- name: List release assets
1024+
run: ls -la release-assets/
1025+
1026+
# ── 创建客户端 Release 并上传所有文件 ──
1027+
- name: Create GitHub Release
1028+
uses: softprops/action-gh-release@v2
1029+
with:
1030+
files: release-assets/*
1031+
body_path: RELEASE_NOTES.md
1032+
generate_release_notes: false
1033+
draft: false
1034+
make_latest: "true"
1035+
1036+
# ── Release Job 2: 浏览器扩展(独立 tag extension-v*,不抢占 latest)──
1037+
release-extension:
1038+
name: Release Browser Extension
1039+
runs-on: ubuntu-latest
1040+
needs: build-extension
1041+
1042+
steps:
1043+
- name: Checkout repository
1044+
uses: actions/checkout@v4
1045+
with:
1046+
fetch-depth: 0
1047+
fetch-tags: true
1048+
1049+
- name: Get version from tag
1050+
id: version
1051+
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> "$GITHUB_OUTPUT"
1052+
1053+
# 只收集 fluxDown/ 目录相关的 commit 作为扩展 release notes
1054+
- name: Generate release notes with git-cliff
1055+
uses: orhun/git-cliff-action@v4
1056+
with:
1057+
args: --latest --strip header --include-path "fluxDown/**"
1058+
env:
1059+
OUTPUT: RELEASE_NOTES.md
1060+
GITHUB_REPO: ${{ github.repository }}
1061+
1062+
- name: Finalize release notes
1063+
shell: bash
1064+
run: |
1065+
if [ ! -s RELEASE_NOTES.md ]; then
1066+
echo "Browser Extension Release v${{ steps.version.outputs.VERSION }}" > RELEASE_NOTES.md
1067+
fi
1068+
echo "── Release notes ──"
1069+
cat RELEASE_NOTES.md
1070+
1071+
- name: Download browser extensions
9151072
uses: actions/download-artifact@v4
9161073
with:
917-
pattern: macos-*
1074+
pattern: browser-extension-*
9181075
path: release-assets/
9191076
merge-multiple: true
9201077

9211078
- name: List release assets
9221079
run: ls -la release-assets/
9231080

924-
# ── 创建 Release 并上传所有文件 ──
1081+
# make_latest=false:避免组件 release 成为 GitHub /releases/latest,
1082+
# 否则会打破客户端自动更新和官网下载页的最新版本判断
9251083
- name: Create GitHub Release
9261084
uses: softprops/action-gh-release@v2
9271085
with:
1086+
tag_name: extension-v${{ steps.version.outputs.VERSION }}
1087+
name: FluxDown Extension v${{ steps.version.outputs.VERSION }}
9281088
files: release-assets/*
9291089
body_path: RELEASE_NOTES.md
9301090
generate_release_notes: false
9311091
draft: false
1092+
make_latest: "false"
9321093

933-
# ── 清理 GitHub Actions Artifact,仅保留当前 tag 这一组 ──
934-
# 原因:Free 账号 artifact 配额仅 500MB,每次 release 会上传 ~400MB
935-
# Release 资产已独立存储在 GitHub Release,artifact 只是 CI 中间产物可安全清理
936-
# 此 step 在 release 创建成功后执行,失败不阻断流程(continue-on-error)
1094+
# ── Release Job 3: 官网(独立 tag website-v*,不抢占 latest)──
1095+
release-website:
1096+
name: Release Website
1097+
runs-on: ubuntu-latest
1098+
needs: build-website
1099+
1100+
steps:
1101+
- name: Checkout repository
1102+
uses: actions/checkout@v4
1103+
with:
1104+
fetch-depth: 0
1105+
fetch-tags: true
1106+
1107+
- name: Get version from tag
1108+
id: version
1109+
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> "$GITHUB_OUTPUT"
1110+
1111+
# 只收集 website/ 目录相关的 commit 作为官网 release notes
1112+
- name: Generate release notes with git-cliff
1113+
uses: orhun/git-cliff-action@v4
1114+
with:
1115+
args: --latest --strip header --include-path "website/**"
1116+
env:
1117+
OUTPUT: RELEASE_NOTES.md
1118+
GITHUB_REPO: ${{ github.repository }}
1119+
1120+
- name: Finalize release notes
1121+
shell: bash
1122+
run: |
1123+
if [ ! -s RELEASE_NOTES.md ]; then
1124+
echo "Website Release v${{ steps.version.outputs.VERSION }}" > RELEASE_NOTES.md
1125+
fi
1126+
echo "── Release notes ──"
1127+
cat RELEASE_NOTES.md
1128+
1129+
- name: Download website artifact
1130+
uses: actions/download-artifact@v4
1131+
with:
1132+
pattern: website-dist
1133+
path: release-assets/
1134+
merge-multiple: true
1135+
1136+
- name: List release assets
1137+
run: ls -la release-assets/
1138+
1139+
- name: Create GitHub Release
1140+
uses: softprops/action-gh-release@v2
1141+
with:
1142+
tag_name: website-v${{ steps.version.outputs.VERSION }}
1143+
name: FluxDown Website v${{ steps.version.outputs.VERSION }}
1144+
files: release-assets/*
1145+
body_path: RELEASE_NOTES.md
1146+
generate_release_notes: false
1147+
draft: false
1148+
make_latest: "false"
1149+
1150+
# ── 最终 Job: 清理 GitHub Actions Artifact,仅保留当前 tag 这一组 ──
1151+
# 原因:Free 账号 artifact 配额仅 500MB,每次 release 会上传 ~400MB
1152+
# Release 资产已独立存储在 GitHub Release,artifact 只是 CI 中间产物可安全清理
1153+
# always():无论哪些组件 release 被跳过/失败都执行清理,失败不阻断(continue-on-error)
1154+
cleanup-artifacts:
1155+
name: Cleanup CI Artifacts
1156+
runs-on: ubuntu-latest
1157+
needs: [release-app, release-extension, release-website]
1158+
if: ${{ always() && !cancelled() }}
1159+
1160+
steps:
9371161
- name: Cleanup GitHub Actions artifacts (keep current tag only)
938-
if: always() && success()
9391162
continue-on-error: true
9401163
env:
9411164
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

cliff.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ commit_parsers = [
6060
]
6161
# 不过滤未被 commit_parsers 匹配的 commit
6262
filter_commits = false
63-
# 匹配版本 tag 的 glob 模式
64-
tag_pattern = "v[0-9].*"
63+
# 匹配版本 tag 的正则(^ 锚定:排除 release 流程创建的 extension-v* / website-v* 组件 tag)
64+
tag_pattern = "^v[0-9].*"
6565
# 跳过的 tag 正则(空 = 不跳过)
6666
skip_tags = ""
6767
# 忽略的 tag 正则(空 = 不忽略)

website/src/pages/api/changelog.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,10 @@ async function getCachedReleases(since: string): Promise<FilteredRelease[]> {
164164
if (!allCache || Date.now() - allCache.timestamp > CACHE_TTL) {
165165
const raw = await fetchAllGitHubReleases();
166166

167+
// 只保留 v* 客户端 release;extension-v* / website-v* 组件 release
168+
// 不属于 App 更新日志(且其 tag 无法按 semver 解析)
167169
const filtered = raw
168-
.filter((r) => !r.draft && !r.prerelease)
170+
.filter((r) => !r.draft && !r.prerelease && /^v\d/.test(r.tag_name))
169171
.sort(
170172
(a, b) =>
171173
new Date(b.published_at).getTime() -

0 commit comments

Comments
 (0)