Skip to content

Commit a5b63be

Browse files
highemerlyclaude
andcommitted
ci: add upstream auto-rebase and GHCR build workflow
- check-upstream.yml: 6時間ごとにupstreamの新しいタグを検知し、 rebaseしてGHCRへbuild&push、k8sg1-repoへdev/prd別PRを直接作成する - upstream-vX.Y.Z ブランチ: upstreamタグから作成(-f上書き) - actions-vX.Y.Z-YYYYMMDDHHMMSS ブランチ: rebase作業用(一意) - rebase成功後 handon-production を force update - Docker タグ: X.Y.Z-YYYYMMDDHHMMSS / streaming用は別イメージ - streaming/Dockerfile も別途build - gh pr create でk8sg1-repoにdev/prd別PR直接作成 - build-releases.yml: mastodon/mastodon 以外では実行しないよう条件追加 - build-container-image.yml: ref input追加、rebase後のコードを正しくbuildするよう修正、packages: write権限追加 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent b7ceef5 commit a5b63be

3 files changed

Lines changed: 323 additions & 0 deletions

File tree

.github/workflows/build-container-image.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@ on:
1818
type: string
1919
file_to_build:
2020
type: string
21+
ref:
22+
type: string
23+
description: 'Git ref to checkout (branch, tag, or SHA). Defaults to the workflow ref if not specified.'
24+
default: ''
25+
26+
permissions:
27+
contents: read
28+
packages: write
2129

2230
# This builds multiple images with one runner each, allowing us to build for multiple architectures
2331
# using Github's runners.
@@ -36,6 +44,8 @@ jobs:
3644

3745
steps:
3846
- uses: actions/checkout@v4
47+
with:
48+
ref: ${{ inputs.ref != '' && inputs.ref || github.ref }}
3949

4050
- name: Prepare
4151
env:
@@ -120,6 +130,8 @@ jobs:
120130

121131
steps:
122132
- uses: actions/checkout@v4
133+
with:
134+
ref: ${{ inputs.ref != '' && inputs.ref || github.ref }}
123135

124136
- name: Download digests
125137
uses: actions/download-artifact@v4

.github/workflows/build-releases.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ permissions:
1111
jobs:
1212
check-latest-stable:
1313
runs-on: ubuntu-latest
14+
if: github.repository == 'mastodon/mastodon'
1415
outputs:
1516
latest: ${{ steps.check.outputs.is_latest_stable }}
1617
steps:
Lines changed: 310 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,310 @@
1+
name: Check Upstream and Rebase
2+
3+
on:
4+
schedule:
5+
- cron: '0 */6 * * *' # 6時間ごと
6+
workflow_dispatch:
7+
8+
jobs:
9+
check-and-rebase:
10+
runs-on: ubuntu-latest
11+
outputs:
12+
new_tag: ${{ steps.check.outputs.new_tag }}
13+
current_tag: ${{ steps.check.outputs.current_tag }}
14+
ci_tag: ${{ steps.prepare.outputs.ci_tag }}
15+
docker_tag: ${{ steps.prepare.outputs.docker_tag }}
16+
should_build: ${{ steps.check.outputs.should_build }}
17+
rebase_success: ${{ steps.rebase.outputs.rebase_success }}
18+
19+
steps:
20+
- name: Checkout
21+
uses: actions/checkout@v4
22+
with:
23+
fetch-depth: 0
24+
token: ${{ secrets.GH_PAT }}
25+
26+
- name: Check upstream for new tags
27+
id: check
28+
run: |
29+
UPSTREAM_REPO=mastodon/mastodon
30+
31+
# 自リポジトリの最新タグを取得 (actions-* や upstream-* を除外)
32+
CURRENT_TAG=$(git tag --sort=-v:refname | grep -E '^v?[0-9]+\.[0-9]+\.[0-9]+$' | head -1)
33+
echo "Current tag: $CURRENT_TAG"
34+
35+
# バージョン番号をパース (v4.3.2 -> 4 3 2)
36+
CURRENT_CLEAN=${CURRENT_TAG#v}
37+
IFS='.' read -r CUR_MAJOR CUR_MINOR CUR_PATCH <<< "$CURRENT_CLEAN"
38+
39+
# upstreamの最新タグ一覧を取得し、semver順にソート
40+
UPSTREAM_TAGS=$(gh api repos/$UPSTREAM_REPO/tags --paginate \
41+
--jq '.[].name' \
42+
| grep -E '^v?[0-9]+\.[0-9]+\.[0-9]+$' \
43+
| sort -Vr \
44+
| head -20)
45+
46+
echo "Upstream tags (sorted):"
47+
echo "$UPSTREAM_TAGS"
48+
49+
# 対象となるタグをフィルタ(現在より新しいもの)
50+
TARGET_TAG=""
51+
while IFS= read -r TAG; do
52+
CLEAN=${TAG#v}
53+
IFS='.' read -r UP_MAJOR UP_MINOR UP_PATCH <<< "$CLEAN"
54+
55+
IS_NEWER=false
56+
if [ "$UP_MAJOR" -gt "$CUR_MAJOR" ]; then
57+
IS_NEWER=true
58+
elif [ "$UP_MAJOR" -eq "$CUR_MAJOR" ] && [ "$UP_MINOR" -gt "$CUR_MINOR" ]; then
59+
IS_NEWER=true
60+
elif [ "$UP_MAJOR" -eq "$CUR_MAJOR" ] && [ "$UP_MINOR" -eq "$CUR_MINOR" ] && [ "$UP_PATCH" -gt "$CUR_PATCH" ]; then
61+
IS_NEWER=true
62+
fi
63+
64+
if [ "$IS_NEWER" = "true" ]; then
65+
TARGET_TAG=$TAG
66+
break # 最新1件のみ処理(複数あれば次回以降に処理)
67+
fi
68+
done <<< "$UPSTREAM_TAGS"
69+
70+
if [ -z "$TARGET_TAG" ]; then
71+
echo "No new upstream tag found."
72+
echo "should_build=false" >> $GITHUB_OUTPUT
73+
else
74+
echo "New upstream tag found: $TARGET_TAG"
75+
echo "new_tag=$TARGET_TAG" >> $GITHUB_OUTPUT
76+
echo "current_tag=$CURRENT_TAG" >> $GITHUB_OUTPUT
77+
echo "should_build=true" >> $GITHUB_OUTPUT
78+
fi
79+
env:
80+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
81+
82+
- name: Prepare branch and tag names
83+
id: prepare
84+
if: steps.check.outputs.should_build == 'true'
85+
run: |
86+
TIMESTAMP=$(date "+%Y%m%d%H%M%S")
87+
NEW_TAG=${{ steps.check.outputs.new_tag }}
88+
VERSION=${NEW_TAG#v}
89+
90+
# actions-v4.5.9-YYYYMMDDHHMMSS
91+
CI_TAG="actions-${NEW_TAG}-${TIMESTAMP}"
92+
# 4.5.9-YYYYMMDDHHMMSS (Docker タグ)
93+
DOCKER_TAG="${VERSION}-${TIMESTAMP}"
94+
95+
echo "ci_tag=$CI_TAG" >> $GITHUB_OUTPUT
96+
echo "docker_tag=$DOCKER_TAG" >> $GITHUB_OUTPUT
97+
echo "CI tag: $CI_TAG"
98+
echo "Docker tag: $DOCKER_TAG"
99+
100+
- name: Add upstream remote and fetch
101+
if: steps.check.outputs.should_build == 'true'
102+
run: |
103+
git remote add upstream https://github.com/mastodon/mastodon.git || true
104+
git fetch upstream --tags
105+
106+
- name: Create upstream branch
107+
if: steps.check.outputs.should_build == 'true'
108+
run: |
109+
NEW_TAG=${{ steps.check.outputs.new_tag }}
110+
UPSTREAM_BRANCH="upstream-${NEW_TAG}"
111+
112+
# upstream-v4.5.9 ブランチをupstreamタグから作成(-f で上書き)
113+
git checkout -B "$UPSTREAM_BRANCH" "refs/tags/$NEW_TAG"
114+
git push origin "$UPSTREAM_BRANCH" --force
115+
echo "Pushed branch: $UPSTREAM_BRANCH"
116+
117+
# handon-production に戻る
118+
git checkout handon-production
119+
120+
- name: Create CI branch and rebase
121+
if: steps.check.outputs.should_build == 'true'
122+
id: rebase
123+
run: |
124+
NEW_TAG=${{ steps.check.outputs.new_tag }}
125+
CI_TAG=${{ steps.prepare.outputs.ci_tag }}
126+
UPSTREAM_BRANCH="upstream-${NEW_TAG}"
127+
128+
git config user.name "github-actions[bot]"
129+
git config user.email "github-actions[bot]@users.noreply.github.com"
130+
131+
# handon-production から CI ブランチを作成
132+
git checkout -b "$CI_TAG"
133+
134+
# upstream ブランチにrebase (build-taged-release.sh と同じ流れ)
135+
if git rebase "$UPSTREAM_BRANCH"; then
136+
echo "rebase_success=true" >> $GITHUB_OUTPUT
137+
echo "Rebase succeeded!"
138+
else
139+
echo "rebase_success=false" >> $GITHUB_OUTPUT
140+
git rebase --abort
141+
echo "Rebase failed!"
142+
fi
143+
144+
- name: Push CI branch and update handon-production
145+
if: steps.check.outputs.should_build == 'true' && steps.rebase.outputs.rebase_success == 'true'
146+
run: |
147+
CI_TAG=${{ steps.prepare.outputs.ci_tag }}
148+
NEW_TAG=${{ steps.check.outputs.new_tag }}
149+
150+
# CI ブランチをpush
151+
git push origin "$CI_TAG"
152+
153+
# actions-v4.5.9-YYYYMMDDHHMMSS タグを打つ (refs/tags/ を明示してブランチ名と衝突回避)
154+
git tag "$CI_TAG"
155+
git push origin "refs/tags/$CI_TAG"
156+
157+
# handon-production を force update
158+
git push origin "HEAD:handon-production" --force
159+
160+
- name: Create issue on rebase failure
161+
if: steps.check.outputs.should_build == 'true' && steps.rebase.outputs.rebase_success == 'false'
162+
uses: actions/github-script@v7
163+
with:
164+
script: |
165+
const newTag = '${{ steps.check.outputs.new_tag }}';
166+
const currentTag = '${{ steps.check.outputs.current_tag }}';
167+
await github.rest.issues.create({
168+
owner: context.repo.owner,
169+
repo: context.repo.repo,
170+
title: `🚨 Rebase failed: upstream ${newTag}`,
171+
body: `## Rebase Conflict Detected\n\n` +
172+
`- **Current tag**: \`${currentTag}\`\n` +
173+
`- **Upstream tag**: \`${newTag}\`\n` +
174+
`- **Run**: ${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}\n\n` +
175+
`## 手順\n` +
176+
`\`\`\`bash\n` +
177+
`git fetch upstream\n` +
178+
`git checkout -B upstream-${newTag} refs/tags/${newTag}\n` +
179+
`git checkout handon-production\n` +
180+
`git rebase upstream-${newTag}\n` +
181+
`# conflict解消後\n` +
182+
`git push origin HEAD:handon-production --force\n` +
183+
`\`\`\`\n\n` +
184+
`解消後は workflow_dispatch で build をトリガーしてください。`,
185+
labels: ['rebase-conflict', 'upstream-update']
186+
});
187+
188+
build-and-push:
189+
needs: check-and-rebase
190+
if: needs.check-and-rebase.outputs.should_build == 'true' && needs.check-and-rebase.outputs.rebase_success == 'true'
191+
uses: ./.github/workflows/build-container-image.yml
192+
with:
193+
file_to_build: Dockerfile
194+
push_to_images: ghcr.io/${{ github.repository }}
195+
ref: ${{ needs.check-and-rebase.outputs.ci_tag }}
196+
cache: false
197+
flavor: |
198+
latest=false
199+
tags: |
200+
type=raw,value=${{ needs.check-and-rebase.outputs.docker_tag }}
201+
secrets: inherit
202+
203+
build-and-push-streaming:
204+
needs: check-and-rebase
205+
if: needs.check-and-rebase.outputs.should_build == 'true' && needs.check-and-rebase.outputs.rebase_success == 'true'
206+
uses: ./.github/workflows/build-container-image.yml
207+
with:
208+
file_to_build: streaming/Dockerfile
209+
push_to_images: ghcr.io/${{ github.repository }}-streaming
210+
ref: ${{ needs.check-and-rebase.outputs.ci_tag }}
211+
cache: false
212+
flavor: |
213+
latest=false
214+
tags: |
215+
type=raw,value=${{ needs.check-and-rebase.outputs.docker_tag }}
216+
secrets: inherit
217+
218+
update-gitops:
219+
needs:
220+
- check-and-rebase
221+
- build-and-push
222+
- build-and-push-streaming
223+
if: needs.check-and-rebase.outputs.should_build == 'true' && needs.check-and-rebase.outputs.rebase_success == 'true'
224+
runs-on: ubuntu-latest
225+
env:
226+
DOCKER_TAG: ${{ needs.check-and-rebase.outputs.docker_tag }}
227+
NEW_TAG: ${{ needs.check-and-rebase.outputs.new_tag }}
228+
IMAGE: ghcr.io/${{ github.repository }}
229+
IMAGE_STREAMING: ghcr.io/${{ github.repository }}-streaming
230+
GH_TOKEN: ${{ secrets.GH_PAT }}
231+
232+
steps:
233+
- name: Checkout k8sg1-repo
234+
uses: actions/checkout@v4
235+
with:
236+
repository: highemerly/k8sg1-repo
237+
token: ${{ secrets.GH_PAT }}
238+
path: k8sg1-repo
239+
240+
- name: Update dev manifests and create PR
241+
working-directory: k8sg1-repo
242+
run: |
243+
BRANCH="update/handon-dev-${DOCKER_TAG}"
244+
git config user.name "github-actions[bot]"
245+
git config user.email "github-actions[bot]@users.noreply.github.com"
246+
git checkout -b "$BRANCH"
247+
248+
# web/sidekiq のイメージタグを更新
249+
sed -i "s|image: ${IMAGE}:.*|image: ${IMAGE}:${DOCKER_TAG}|g" \
250+
manifests/handon/dev/web.yaml \
251+
manifests/handon/dev/sidekiq.yaml
252+
253+
# streaming のイメージタグを更新
254+
sed -i "s|image: ${IMAGE_STREAMING}:.*|image: ${IMAGE_STREAMING}:${DOCKER_TAG}|g" \
255+
manifests/handon/dev/streaming.yaml
256+
257+
git add manifests/handon/dev/
258+
git commit -m "chore: update handon dev image to ${NEW_TAG} (${DOCKER_TAG})"
259+
git push origin "$BRANCH"
260+
261+
gh pr create \
262+
--repo highemerly/k8sg1-repo \
263+
--title "Update handon dev: ${NEW_TAG}" \
264+
--body "## Handon Image Update (dev)
265+
266+
- **Upstream tag**: \`${NEW_TAG}\`
267+
- **Docker tag**: \`${DOCKER_TAG}\`
268+
- **Image**: \`${IMAGE}\`
269+
- **Streaming image**: \`${IMAGE_STREAMING}\`
270+
271+
devをマージ・確認後、prd側のPRをマージしてください。" \
272+
--base main \
273+
--head "$BRANCH" \
274+
--label "automated,handon-update,dev"
275+
276+
- name: Update prd manifests and create PR
277+
working-directory: k8sg1-repo
278+
run: |
279+
BRANCH="update/handon-prd-${DOCKER_TAG}"
280+
git checkout main
281+
git checkout -b "$BRANCH"
282+
283+
# web/sidekiq のイメージタグを更新
284+
sed -i "s|image: ${IMAGE}:.*|image: ${IMAGE}:${DOCKER_TAG}|g" \
285+
manifests/handon/prd/web.yaml \
286+
manifests/handon/prd/sidekiq-default.yaml \
287+
manifests/handon/prd/sidekiq-federation.yaml \
288+
manifests/handon/prd/sidekiq-misc.yaml
289+
290+
# streaming のイメージタグを更新
291+
sed -i "s|image: ${IMAGE_STREAMING}:.*|image: ${IMAGE_STREAMING}:${DOCKER_TAG}|g" \
292+
manifests/handon/prd/streaming.yaml
293+
294+
git add manifests/handon/prd/
295+
git commit -m "chore: update handon prd image to ${NEW_TAG} (${DOCKER_TAG})"
296+
git push origin "$BRANCH"
297+
298+
gh pr create \
299+
--repo highemerly/k8sg1-repo \
300+
--title "Update handon prd: ${NEW_TAG}" \
301+
--body "## Handon Image Update (prd)
302+
303+
- **Upstream tag**: \`${NEW_TAG}\`
304+
- **Docker tag**: \`${DOCKER_TAG}\`
305+
- **Image**: \`${IMAGE}\`
306+
307+
**devのPRをマージ・動作確認後にこちらをマージしてください。**" \
308+
--base main \
309+
--head "$BRANCH" \
310+
--label "automated,handon-update,prd"

0 commit comments

Comments
 (0)