Skip to content

Commit 52e3245

Browse files
committed
feat(ci): add Intel macOS DMG build and improve workflow strategy
- Rewrite release workflow with independent per-platform build jobs - Add macOS Intel (x86_64) DMG distribution - Add pre-release validation with lint/test checks - Add centralized release creation with SHA256 checksums - Support prerelease tags (alpha/beta/rc) - Add version number to release artifact filenames - Add CI concurrency control and paths-ignore for docs - Add cache-cleanup workflow for PR branch and stale caches - Add stale issues/PRs auto-close workflow Fixes #89
1 parent 85655a1 commit 52e3245

5 files changed

Lines changed: 481 additions & 110 deletions

File tree

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
name: Cache Cleanup
2+
3+
on:
4+
# PR 合并/关闭后自动清理该分支的缓存
5+
pull_request:
6+
types: [closed]
7+
8+
# 每周日 UTC 00:00 定期清理过期缓存
9+
schedule:
10+
- cron: '0 0 * * 0'
11+
12+
workflow_dispatch:
13+
inputs:
14+
cleanup_mode:
15+
description: 'Cleanup mode'
16+
required: true
17+
default: 'stale'
18+
type: choice
19+
options:
20+
- stale # 清理 7 天未命中的缓存
21+
- all # 清理所有缓存(慎用)
22+
23+
jobs:
24+
# ============================================================
25+
# PR 分支缓存清理 - PR 关闭后清理该分支产生的所有缓存
26+
# ============================================================
27+
cleanup-pr-branch:
28+
name: Cleanup PR Branch Cache
29+
if: github.event_name == 'pull_request'
30+
runs-on: ubuntu-latest
31+
permissions:
32+
actions: write
33+
steps:
34+
- name: Cleanup caches for PR #${{ github.event.pull_request.number }}
35+
env:
36+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
37+
REPO: ${{ github.repository }}
38+
PR_NUMBER: ${{ github.event.pull_request.number }}
39+
HEAD_BRANCH: refs/heads/${{ github.event.pull_request.head.ref }}
40+
MERGE_BRANCH: refs/pull/${{ github.event.pull_request.number }}/merge
41+
run: |
42+
echo "Cleaning up caches for PR #${PR_NUMBER}"
43+
44+
DELETED=0
45+
46+
for BRANCH in "$HEAD_BRANCH" "$MERGE_BRANCH"; do
47+
echo "Checking branch: $BRANCH"
48+
49+
CACHE_IDS=$(gh api \
50+
-H "Accept: application/vnd.github+json" \
51+
"/repos/${REPO}/actions/caches?ref=${BRANCH}&per_page=100" \
52+
--jq '.actions_caches[].id')
53+
54+
if [ -z "$CACHE_IDS" ]; then
55+
echo " No caches found"
56+
continue
57+
fi
58+
59+
while IFS= read -r id; do
60+
echo " Deleting cache ID: $id"
61+
gh api --method DELETE \
62+
-H "Accept: application/vnd.github+json" \
63+
"/repos/${REPO}/actions/caches/${id}" || true
64+
DELETED=$((DELETED + 1))
65+
done <<< "$CACHE_IDS"
66+
done
67+
68+
echo "::notice::Deleted $DELETED cache(s) for PR #${PR_NUMBER}"
69+
70+
# ============================================================
71+
# 定期清理 - 删除超过 7 天未被访问的缓存
72+
# ============================================================
73+
cleanup-stale:
74+
name: Cleanup Stale Caches
75+
if: github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && inputs.cleanup_mode == 'stale')
76+
runs-on: ubuntu-latest
77+
permissions:
78+
actions: write
79+
steps:
80+
- name: Cleanup stale caches (>7 days)
81+
env:
82+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
83+
REPO: ${{ github.repository }}
84+
run: |
85+
echo "Fetching all caches..."
86+
87+
THRESHOLD_DATE=$(date -u -d "7 days ago" +%Y-%m-%dT%H:%M:%SZ 2>/dev/null \
88+
|| date -u -v-7d +%Y-%m-%dT%H:%M:%SZ)
89+
90+
echo "Deleting caches last accessed before: $THRESHOLD_DATE"
91+
92+
DELETED=0
93+
PAGE=1
94+
95+
while true; do
96+
RESPONSE=$(gh api \
97+
-H "Accept: application/vnd.github+json" \
98+
"/repos/${REPO}/actions/caches?per_page=100&page=${PAGE}&sort=last_accessed_at&direction=asc")
99+
100+
TOTAL=$(echo "$RESPONSE" | jq '.total_count')
101+
STALE=$(echo "$RESPONSE" | jq -r \
102+
".actions_caches[] | select(.last_accessed_at < \"$THRESHOLD_DATE\") | .id")
103+
104+
if [ -z "$STALE" ]; then
105+
break
106+
fi
107+
108+
while IFS= read -r id; do
109+
echo "Deleting stale cache ID: $id"
110+
gh api --method DELETE \
111+
-H "Accept: application/vnd.github+json" \
112+
"/repos/${REPO}/actions/caches/${id}" || true
113+
DELETED=$((DELETED + 1))
114+
done <<< "$STALE"
115+
116+
COUNT=$(echo "$RESPONSE" | jq '.actions_caches | length')
117+
if [ "$COUNT" -lt 100 ]; then
118+
break
119+
fi
120+
121+
PAGE=$((PAGE + 1))
122+
done
123+
124+
echo "::notice::Deleted $DELETED stale cache(s) (total caches in repo: $TOTAL)"
125+
126+
# ============================================================
127+
# 全量清理 - 手动触发,删除所有缓存
128+
# ============================================================
129+
cleanup-all:
130+
name: Cleanup All Caches
131+
if: github.event_name == 'workflow_dispatch' && inputs.cleanup_mode == 'all'
132+
runs-on: ubuntu-latest
133+
permissions:
134+
actions: write
135+
steps:
136+
- name: Delete all caches
137+
env:
138+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
139+
REPO: ${{ github.repository }}
140+
run: |
141+
echo "Deleting ALL caches for $REPO"
142+
143+
DELETED=0
144+
145+
while true; do
146+
CACHE_IDS=$(gh api \
147+
-H "Accept: application/vnd.github+json" \
148+
"/repos/${REPO}/actions/caches?per_page=100" \
149+
--jq '.actions_caches[].id')
150+
151+
if [ -z "$CACHE_IDS" ]; then
152+
break
153+
fi
154+
155+
while IFS= read -r id; do
156+
echo "Deleting cache ID: $id"
157+
gh api --method DELETE \
158+
-H "Accept: application/vnd.github+json" \
159+
"/repos/${REPO}/actions/caches/${id}" || true
160+
DELETED=$((DELETED + 1))
161+
done <<< "$CACHE_IDS"
162+
done
163+
164+
echo "::notice::Deleted $DELETED cache(s) in total"

.github/workflows/ci.yml

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,23 @@ on:
44
push:
55
branches: [main, next, develop]
66
tags: ['v*']
7+
paths-ignore:
8+
- '**.md'
9+
- '.gitignore'
10+
- '.github/ISSUE_TEMPLATE/**'
11+
- 'docs/**'
712
pull_request:
813
branches: [main, next, develop]
14+
paths-ignore:
15+
- '**.md'
16+
- '.gitignore'
17+
- '.github/ISSUE_TEMPLATE/**'
18+
- 'docs/**'
19+
20+
# Cancel in-progress runs for the same branch/PR
21+
concurrency:
22+
group: ${{ github.workflow }}-${{ github.ref }}
23+
cancel-in-progress: true
924

1025
env:
1126
CARGO_TERM_COLOR: always
@@ -127,6 +142,8 @@ jobs:
127142
target: x86_64-pc-windows-msvc
128143
- os: macos-latest
129144
target: aarch64-apple-darwin
145+
- os: macos-13
146+
target: x86_64-apple-darwin
130147

131148
runs-on: ${{ matrix.os }}
132149
steps:
@@ -169,12 +186,20 @@ jobs:
169186
path: src-tauri/target/${{ matrix.target }}/release/ctfcracktools-x.exe
170187
if-no-files-found: warn
171188

172-
- name: Upload artifacts (macOS)
189+
- name: Upload artifacts (macOS ARM64)
173190
if: matrix.os == 'macos-latest'
174191
uses: actions/upload-artifact@v4
175192
with:
176-
name: ctfcracktools-macos
177-
path: src-tauri/target/${{ matrix.target }}/release/ctfcracktools-x
193+
name: ctfcracktools-macos-arm64
194+
path: src-tauri/target/${{ matrix.target }}/release/bundle/dmg/*.dmg
195+
if-no-files-found: warn
196+
197+
- name: Upload artifacts (macOS Intel)
198+
if: matrix.os == 'macos-13'
199+
uses: actions/upload-artifact@v4
200+
with:
201+
name: ctfcracktools-macos-x64
202+
path: src-tauri/target/${{ matrix.target }}/release/bundle/dmg/*.dmg
178203
if-no-files-found: warn
179204

180205
# ============================================

0 commit comments

Comments
 (0)