Skip to content

Commit 0fc1dbc

Browse files
sususu98github-actions[bot]
authored andcommitted
ci: add workflow to auto sync upstream and rebase custom commits
1 parent 0b7e061 commit 0fc1dbc

2 files changed

Lines changed: 262 additions & 6 deletions

File tree

.github/workflows/docker-image.yml

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,28 +7,34 @@ on:
77

88
env:
99
APP_NAME: CLIProxyAPI
10-
DOCKERHUB_REPO: eceasy/cli-proxy-api
10+
REGISTRY: ghcr.io
1111

1212
jobs:
1313
docker:
1414
runs-on: ubuntu-latest
15+
permissions:
16+
contents: read
17+
packages: write
1518
steps:
1619
- name: Checkout
1720
uses: actions/checkout@v4
1821
- name: Set up QEMU
1922
uses: docker/setup-qemu-action@v3
2023
- name: Set up Docker Buildx
2124
uses: docker/setup-buildx-action@v3
22-
- name: Login to DockerHub
25+
- name: Login to GHCR
2326
uses: docker/login-action@v3
2427
with:
25-
username: ${{ secrets.DOCKERHUB_USERNAME }}
26-
password: ${{ secrets.DOCKERHUB_TOKEN }}
28+
registry: ${{ env.REGISTRY }}
29+
username: ${{ github.actor }}
30+
password: ${{ secrets.GITHUB_TOKEN }}
2731
- name: Generate Build Metadata
32+
id: meta
2833
run: |
2934
echo VERSION=`git describe --tags --always --dirty` >> $GITHUB_ENV
3035
echo COMMIT=`git rev-parse --short HEAD` >> $GITHUB_ENV
3136
echo BUILD_DATE=`date -u +%Y-%m-%dT%H:%M:%SZ` >> $GITHUB_ENV
37+
echo IMAGE_NAME=$(echo "${{ github.repository }}" | tr '[:upper:]' '[:lower:]') >> $GITHUB_ENV
3238
- name: Build and push
3339
uses: docker/build-push-action@v6
3440
with:
@@ -42,5 +48,5 @@ jobs:
4248
COMMIT=${{ env.COMMIT }}
4349
BUILD_DATE=${{ env.BUILD_DATE }}
4450
tags: |
45-
${{ env.DOCKERHUB_REPO }}:latest
46-
${{ env.DOCKERHUB_REPO }}:${{ env.VERSION }}
51+
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
52+
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.VERSION }}
Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
name: Sync Upstream and Rebase
2+
3+
on:
4+
schedule:
5+
# 每天 UTC 时间 0 点检查一次 (北京时间早上 8 点)
6+
- cron: '0 0 * * *'
7+
workflow_dispatch: # 允许手动触发
8+
9+
# 要保留的 commit message 特征 (用于 cherry-pick)
10+
env:
11+
KEEP_COMMITS: |
12+
ci: add workflow to auto sync upstream
13+
feat(antigravity): add web_search support for Claude via Gemini googleSearch
14+
feat(routing): add session affinity for Claude Code clients
15+
16+
jobs:
17+
sync:
18+
runs-on: ubuntu-latest
19+
steps:
20+
- name: Checkout
21+
uses: actions/checkout@v4
22+
with:
23+
fetch-depth: 0
24+
token: ${{ secrets.PAT_TOKEN }}
25+
26+
- name: Setup Git
27+
run: |
28+
git config user.name "github-actions[bot]"
29+
git config user.email "github-actions[bot]@users.noreply.github.com"
30+
31+
- name: Add upstream remote
32+
run: |
33+
git remote add upstream https://github.com/router-for-me/CLIProxyAPI.git || true
34+
git fetch upstream --tags --force
35+
36+
- name: Check if sync needed
37+
id: check
38+
run: |
39+
UPSTREAM_HEAD=$(git rev-parse upstream/main)
40+
41+
# 检查上游 HEAD 是否已经在本地历史中
42+
if git merge-base --is-ancestor "$UPSTREAM_HEAD" HEAD; then
43+
echo "Already up to date"
44+
echo "need_sync=false" >> $GITHUB_OUTPUT
45+
else
46+
echo "Need to sync"
47+
echo "need_sync=true" >> $GITHUB_OUTPUT
48+
fi
49+
50+
- name: Find commits to preserve
51+
id: find_commits
52+
run: |
53+
echo "Looking for commits to preserve..."
54+
55+
# 找到要保留的 commit (通过 message 匹配)
56+
COMMITS_TO_KEEP=""
57+
58+
# CI workflow commit (排除 merge commit)
59+
CI_COMMIT=$(git log --no-merges --grep="ci: add workflow to auto sync upstream" --format="%H" | head -1)
60+
if [ -n "$CI_COMMIT" ]; then
61+
echo "Found CI commit: $CI_COMMIT"
62+
COMMITS_TO_KEEP="$CI_COMMIT"
63+
fi
64+
65+
# web_search commit (排除 merge commit)
66+
WS_COMMIT=$(git log --no-merges --grep="feat(antigravity): add web_search support for Claude via Gemini googleSearch" --format="%H" | head -1)
67+
if [ -n "$WS_COMMIT" ]; then
68+
echo "Found web_search commit: $WS_COMMIT"
69+
if [ -n "$COMMITS_TO_KEEP" ]; then
70+
COMMITS_TO_KEEP="$COMMITS_TO_KEEP $WS_COMMIT"
71+
else
72+
COMMITS_TO_KEEP="$WS_COMMIT"
73+
fi
74+
fi
75+
76+
# session affinity commit (排除 merge commit)
77+
SA_COMMIT=$(git log --no-merges --grep="feat(routing): add session affinity for Claude Code clients" --format="%H" | head -1)
78+
if [ -n "$SA_COMMIT" ]; then
79+
echo "Found session affinity commit: $SA_COMMIT"
80+
if [ -n "$COMMITS_TO_KEEP" ]; then
81+
COMMITS_TO_KEEP="$COMMITS_TO_KEEP $SA_COMMIT"
82+
else
83+
COMMITS_TO_KEEP="$SA_COMMIT"
84+
fi
85+
fi
86+
87+
echo "Commits to preserve: $COMMITS_TO_KEEP"
88+
echo "commits=$COMMITS_TO_KEEP" >> $GITHUB_OUTPUT
89+
90+
- name: Rebase onto upstream
91+
if: steps.check.outputs.need_sync == 'true'
92+
run: |
93+
# 切到上游 main
94+
git checkout upstream/main
95+
96+
# Cherry-pick 要保留的 commit (按正确顺序: 先 web_search, 后 CI)
97+
COMMITS="${{ steps.find_commits.outputs.commits }}"
98+
99+
# 反转顺序 (因为找到的是新到旧)
100+
REVERSED=$(echo $COMMITS | tr ' ' '\n' | tac | tr '\n' ' ')
101+
102+
for commit in $REVERSED; do
103+
echo "Cherry-picking $commit"
104+
git cherry-pick "$commit" || {
105+
echo "Cherry-pick failed, trying to continue..."
106+
git cherry-pick --abort
107+
exit 1
108+
}
109+
done
110+
111+
# 更新 main 分支
112+
git branch -f main HEAD
113+
git checkout main
114+
115+
echo "Rebase completed successfully"
116+
git log --oneline -5
117+
118+
- name: Force push main
119+
if: steps.check.outputs.need_sync == 'true'
120+
run: |
121+
git push origin main --force-with-lease
122+
echo "Pushed to origin/main"
123+
124+
- name: Check for new upstream tags
125+
id: tags
126+
run: |
127+
# 获取上游最新的 tag
128+
LATEST_UPSTREAM_TAG=$(git describe --tags --abbrev=0 upstream/main 2>/dev/null || echo "")
129+
echo "Latest upstream tag: $LATEST_UPSTREAM_TAG"
130+
131+
if [ -z "$LATEST_UPSTREAM_TAG" ]; then
132+
echo "No tags found"
133+
echo "new_tag=" >> $GITHUB_OUTPUT
134+
exit 0
135+
fi
136+
137+
# 构造我们的 tag 名称
138+
OUR_TAG="${LATEST_UPSTREAM_TAG}-antiWebsearch"
139+
140+
# 检查这个 tag 是否已经在 origin 存在
141+
if git ls-remote --tags origin | grep -q "refs/tags/${OUR_TAG}$"; then
142+
echo "Tag $OUR_TAG already exists in origin"
143+
echo "new_tag=" >> $GITHUB_OUTPUT
144+
else
145+
echo "New tag to create: $OUR_TAG"
146+
echo "new_tag=$LATEST_UPSTREAM_TAG" >> $GITHUB_OUTPUT
147+
fi
148+
149+
- name: Create rebased tag
150+
if: steps.tags.outputs.new_tag != ''
151+
id: create_tag
152+
run: |
153+
UPSTREAM_TAG="${{ steps.tags.outputs.new_tag }}"
154+
# 添加自定义后缀
155+
NEW_TAG="${UPSTREAM_TAG}-antiWebsearch"
156+
echo "Creating tag $NEW_TAG on rebased main (based on upstream $UPSTREAM_TAG)"
157+
158+
# 在当前 HEAD (包含你的 commit) 上创建 tag
159+
git tag -f "$NEW_TAG"
160+
git push origin "$NEW_TAG" --force
161+
162+
echo "Tag $NEW_TAG pushed to origin"
163+
echo "new_tag=$NEW_TAG" >> $GITHUB_OUTPUT
164+
echo "upstream_tag=$UPSTREAM_TAG" >> $GITHUB_OUTPUT
165+
166+
- name: Find previous custom tag
167+
if: steps.tags.outputs.new_tag != ''
168+
id: prev_tag
169+
run: |
170+
# 找到我们之前的 antiWebsearch tag
171+
PREV_TAG=$(git tag -l '*-antiWebsearch' --sort=-version:refname | grep -v "${{ steps.create_tag.outputs.new_tag }}" | head -1)
172+
echo "Previous custom tag: $PREV_TAG"
173+
174+
if [ -n "$PREV_TAG" ]; then
175+
# 提取上游版本号
176+
PREV_UPSTREAM_TAG=$(echo "$PREV_TAG" | sed 's/-antiWebsearch$//')
177+
echo "prev_tag=$PREV_TAG" >> $GITHUB_OUTPUT
178+
echo "prev_upstream_tag=$PREV_UPSTREAM_TAG" >> $GITHUB_OUTPUT
179+
else
180+
echo "prev_tag=" >> $GITHUB_OUTPUT
181+
echo "prev_upstream_tag=" >> $GITHUB_OUTPUT
182+
fi
183+
184+
- name: Generate Release Notes
185+
if: steps.tags.outputs.new_tag != ''
186+
id: release_notes
187+
run: |
188+
NEW_TAG="${{ steps.create_tag.outputs.new_tag }}"
189+
UPSTREAM_TAG="${{ steps.create_tag.outputs.upstream_tag }}"
190+
PREV_UPSTREAM_TAG="${{ steps.prev_tag.outputs.prev_upstream_tag }}"
191+
192+
# 生成 release notes
193+
cat > release_notes.md << 'HEADER'
194+
## 🚀 Custom Features (antiWebsearch)
195+
196+
This release is based on upstream `UPSTREAM_TAG_PLACEHOLDER` with the following custom modifications:
197+
198+
HEADER
199+
200+
sed -i "s/UPSTREAM_TAG_PLACEHOLDER/$UPSTREAM_TAG/" release_notes.md
201+
202+
# 添加自定义 commit 列表
203+
cat >> release_notes.md << 'CUSTOM'
204+
### Custom Commits
205+
- **feat(routing)**: add session affinity for Claude Code clients
206+
- **feat(antigravity)**: add web_search support for Claude via Gemini googleSearch
207+
- **ci**: add workflow to auto sync upstream and rebase custom commits
208+
209+
---
210+
211+
CUSTOM
212+
213+
# 添加上游更新
214+
if [ -n "$PREV_UPSTREAM_TAG" ]; then
215+
echo "## 📦 Upstream Changes (since $PREV_UPSTREAM_TAG)" >> release_notes.md
216+
echo "" >> release_notes.md
217+
echo "Changes from upstream \`$PREV_UPSTREAM_TAG\` → \`$UPSTREAM_TAG\`:" >> release_notes.md
218+
echo "" >> release_notes.md
219+
220+
# 获取上游 commit 列表
221+
git log --oneline "${PREV_UPSTREAM_TAG}..${UPSTREAM_TAG}" --pretty=format:"- %s" 2>/dev/null >> release_notes.md || echo "- Unable to fetch upstream commits" >> release_notes.md
222+
223+
echo "" >> release_notes.md
224+
echo "" >> release_notes.md
225+
echo "📋 [View full upstream changelog](https://github.com/router-for-me/CLIProxyAPI/compare/${PREV_UPSTREAM_TAG}...${UPSTREAM_TAG})" >> release_notes.md
226+
else
227+
echo "## 📦 Upstream Changes" >> release_notes.md
228+
echo "" >> release_notes.md
229+
echo "Based on upstream [\`$UPSTREAM_TAG\`](https://github.com/router-for-me/CLIProxyAPI/releases/tag/$UPSTREAM_TAG)" >> release_notes.md
230+
fi
231+
232+
cat release_notes.md
233+
234+
- name: Create GitHub Release
235+
if: steps.tags.outputs.new_tag != ''
236+
env:
237+
GH_TOKEN: ${{ secrets.PAT_TOKEN }}
238+
run: |
239+
NEW_TAG="${{ steps.create_tag.outputs.new_tag }}"
240+
REPO="${{ github.repository }}"
241+
242+
# 删除已存在的 release(如果有)
243+
gh release delete "$NEW_TAG" --repo "$REPO" --yes 2>/dev/null || true
244+
245+
# 创建新的 release
246+
gh release create "$NEW_TAG" \
247+
--repo "$REPO" \
248+
--title "$NEW_TAG" \
249+
--notes-file release_notes.md \
250+
--latest

0 commit comments

Comments
 (0)