Skip to content

Commit ad908b2

Browse files
committed
feat: add GitHub Actions workflow to check and update MySQL Shell versions automatically
1 parent e66a9ce commit ad908b2

File tree

1 file changed

+380
-0
lines changed

1 file changed

+380
-0
lines changed
Lines changed: 380 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,380 @@
1+
name: Check for new MySQL Shell releases
2+
3+
4+
# このワークフローは以下を行います:
5+
# 1. MySQL Shellの最新リリースタグを検出
6+
# 2. 現在のDockerイメージのバージョンと比較
7+
# 3. 更新が必要な場合は自動的にPRを作成
8+
9+
# このワークフローは以下を行います:
10+
# 1. MySQL Shellの最新リリースタグを検出
11+
# 2. 現在のDockerイメージのバージョンと比較
12+
# 3. 更新が必要な場合は自動的にPRを作成
13+
14+
on:
15+
schedule:
16+
# 毎日 UTC 3時17分に実行 (ランダムな時刻で負荷分散)
17+
- cron: '17 3 * * *'
18+
workflow_dispatch: # 手動実行も可能にする
19+
inputs:
20+
dry_run:
21+
description: '実際のPRを作成せずにテスト実行'
22+
required: false
23+
default: false
24+
type: boolean
25+
innovation_version:
26+
description: 'テスト用の強制Innovation版バージョン(例:9.3.0)'
27+
required: false
28+
type: string
29+
lts_version:
30+
description: 'テスト用の強制LTS版バージョン(例:8.4.5)'
31+
required: false
32+
type: string
33+
inputs:
34+
dry_run:
35+
description: '実際のPRを作成せずにテスト実行'
36+
required: false
37+
default: false
38+
type: boolean
39+
innovation_version:
40+
description: 'テスト用の強制Innovation版バージョン(例:9.3.0)'
41+
required: false
42+
type: string
43+
lts_version:
44+
description: 'テスト用の強制LTS版バージョン(例:8.4.5)'
45+
required: false
46+
type: string
47+
48+
jobs:
49+
check-release:
50+
permissions:
51+
contents: read
52+
pull-requests: write
53+
runs-on: ubuntu-latest
54+
# ジョブの概要説明
55+
name: Check and update MySQL Shell versions
56+
steps:
57+
# ステップ1: リポジトリの取得
58+
- name: Checkout repository
59+
uses: actions/checkout@v4
60+
with:
61+
# プルリクエスト作成のためにトークンが必要
62+
token: ${{ secrets.GITHUB_TOKEN }}
63+
64+
- name: Get current versions
65+
id: current_versions
66+
run: |
67+
# Dockerfileから現在のバージョンを取得
68+
if [[ ! -f docker/innovation/Dockerfile ]] || [[ ! -f docker/lts/Dockerfile ]]; then
69+
echo "::error::Required Dockerfiles not found!"
70+
exit 1
71+
fi
72+
73+
CURRENT_INNOVATION=$(grep -oP '(?<=^ARG MYSQL_SHELL_VERSION=)\d+\.\d+\.\d+' docker/innovation/Dockerfile)
74+
CURRENT_LTS=$(grep -oP '(?<=^ARG MYSQL_SHELL_VERSION=)\d+\.\d+\.\d+' docker/lts/Dockerfile)
75+
76+
if [[ -z "$CURRENT_INNOVATION" ]] || [[ -z "$CURRENT_LTS" ]]; then
77+
echo "::error::Failed to extract current versions from Dockerfiles"
78+
exit 1
79+
fi
80+
81+
echo "CURRENT_INNOVATION=${CURRENT_INNOVATION}" >> $GITHUB_OUTPUT
82+
echo "CURRENT_LTS=${CURRENT_LTS}" >> $GITHUB_OUTPUT
83+
echo "Current Innovation: $CURRENT_INNOVATION"
84+
echo "Current LTS: $CURRENT_LTS"
85+
86+
# メジャーバージョンを抽出 (後で使用)
87+
INNOVATION_MAJOR_VERSION=$(echo "$CURRENT_INNOVATION" | cut -d. -f1)
88+
LTS_MAJOR_VERSION=$(echo "$CURRENT_LTS" | cut -d. -f1)
89+
echo "INNOVATION_MAJOR_VERSION=${INNOVATION_MAJOR_VERSION}" >> $GITHUB_OUTPUT
90+
echo "LTS_MAJOR_VERSION=${LTS_MAJOR_VERSION}" >> $GITHUB_OUTPUT
91+
92+
- name: Get latest MySQL Shell tags
93+
id: latest_tags
94+
run: |
95+
# GitHub APIからタグ情報を取得
96+
INNOVATION_MAJOR="${{ steps.current_versions.outputs.INNOVATION_MAJOR_VERSION }}"
97+
LTS_MAJOR="${{ steps.current_versions.outputs.LTS_MAJOR_VERSION }}"
98+
99+
# テスト用の手動指定バージョンがあれば使用する
100+
if [[ "${{ github.event_name }}" == "workflow_dispatch" && -n "${{ github.event.inputs.innovation_version }}" ]]; then
101+
LATEST_INNOVATION="${{ github.event.inputs.innovation_version }}"
102+
echo "Using manually specified Innovation version: $LATEST_INNOVATION"
103+
else
104+
# GitHub APIからのフェッチを試みる
105+
API_RESPONSE=$(curl -s -H "Accept: application/vnd.github+json" \
106+
-H "X-GitHub-Api-Version: 2022-11-28" \
107+
-H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \
108+
"https://api.github.com/repos/mysql/mysql-shell/tags?per_page=100")
109+
110+
if [[ -z "$API_RESPONSE" ]] || [[ "$API_RESPONSE" == *"rate limit"* ]] || [[ "$API_RESPONSE" == *"Bad credentials"* ]]; then
111+
echo "::error::Failed to fetch data from GitHub API: $(echo "$API_RESPONSE" | grep -o '"message":"[^"]*"' || echo 'Unknown error')"
112+
exit 1
113+
fi
114+
115+
# 正規表現パターンを動的に構築
116+
INNOVATION_PATTERN="^${INNOVATION_MAJOR}\\.\\d+\\.\\d+$"
117+
118+
LATEST_INNOVATION=$(echo "$API_RESPONSE" | jq -r --arg pattern "$INNOVATION_PATTERN" '[.[] | select(.name | test($pattern))][0].name')
119+
fi
120+
121+
# LTSバージョンの取得(手動指定またはAPI)
122+
if [[ "${{ github.event_name }}" == "workflow_dispatch" && -n "${{ github.event.inputs.lts_version }}" ]]; then
123+
LATEST_LTS="${{ github.event.inputs.lts_version }}"
124+
echo "Using manually specified LTS version: $LATEST_LTS"
125+
else
126+
# APIレスポンスを再利用
127+
LTS_PATTERN="^${LTS_MAJOR}\\.\\d+\\.\\d+$"
128+
LATEST_LTS=$(echo "$API_RESPONSE" | jq -r --arg pattern "$LTS_PATTERN" '[.[] | select(.name | test($pattern))][0].name')
129+
fi
130+
131+
# 結果の検証
132+
if [[ -z "$LATEST_INNOVATION" ]] || [[ "$LATEST_INNOVATION" == "null" ]] || [[ -z "$LATEST_LTS" ]] || [[ "$LATEST_LTS" == "null" ]]; then
133+
echo "::warning::Failed to find matching versions. Using hardcoded patterns as fallback."
134+
# フォールバック: ハードコードされたバージョンパターン
135+
LATEST_INNOVATION=${LATEST_INNOVATION:-$(echo "$API_RESPONSE" | jq -r '[.[] | select(.name | test("^9\\.\\d+\\.\\d+$"))][0].name')}
136+
LATEST_LTS=${LATEST_LTS:-$(echo "$API_RESPONSE" | jq -r '[.[] | select(.name | test("^8\\.\\d+\\.\\d+$"))][0].name')}
137+
fi
138+
139+
echo "LATEST_INNOVATION=${LATEST_INNOVATION}" >> $GITHUB_OUTPUT
140+
echo "LATEST_LTS=${LATEST_LTS}" >> $GITHUB_OUTPUT
141+
echo "Latest Innovation: $LATEST_INNOVATION"
142+
echo "Latest LTS: $LATEST_LTS"
143+
144+
- name: Check versions
145+
id: check_versions
146+
run: |
147+
# バージョン比較ユーティリティ関数
148+
version_gt() {
149+
# $1 > $2 の場合に0を返す
150+
test "$(echo "$1 $2" | tr " " "\n" | sort -V | head -n 1)" != "$1"
151+
}
152+
153+
CURRENT_INNOVATION="${{ steps.current_versions.outputs.CURRENT_INNOVATION }}"
154+
LATEST_INNOVATION="${{ steps.latest_tags.outputs.LATEST_INNOVATION }}"
155+
CURRENT_LTS="${{ steps.current_versions.outputs.CURRENT_LTS }}"
156+
LATEST_LTS="${{ steps.latest_tags.outputs.LATEST_LTS }}"
157+
158+
INNOVATION_UPDATE_NEEDED="false"
159+
LTS_UPDATE_NEEDED="false"
160+
161+
# Innovation バージョンのチェック
162+
if [[ -z "$LATEST_INNOVATION" ]] || [[ "$LATEST_INNOVATION" == "null" ]]; then
163+
echo "::warning::No valid Innovation version found in API response"
164+
elif [[ "$CURRENT_INNOVATION" != "$LATEST_INNOVATION" ]]; then
165+
if version_gt "$LATEST_INNOVATION" "$CURRENT_INNOVATION"; then
166+
echo "Update needed for Innovation: $CURRENT_INNOVATION -> $LATEST_INNOVATION (newer version available)"
167+
INNOVATION_UPDATE_NEEDED="true"
168+
else
169+
echo "::warning::Latest Innovation version ($LATEST_INNOVATION) is older than current ($CURRENT_INNOVATION). Skipping update."
170+
fi
171+
else
172+
echo "Innovation is up-to-date at version $CURRENT_INNOVATION."
173+
fi
174+
175+
# LTS バージョンのチェック
176+
if [[ -z "$LATEST_LTS" ]] || [[ "$LATEST_LTS" == "null" ]]; then
177+
echo "::warning::No valid LTS version found in API response"
178+
elif [[ "$CURRENT_LTS" != "$LATEST_LTS" ]]; then
179+
if version_gt "$LATEST_LTS" "$CURRENT_LTS"; then
180+
echo "Update needed for LTS: $CURRENT_LTS -> $LATEST_LTS (newer version available)"
181+
LTS_UPDATE_NEEDED="true"
182+
else
183+
echo "::warning::Latest LTS version ($LATEST_LTS) is older than current ($CURRENT_LTS). Skipping update."
184+
fi
185+
else
186+
echo "LTS is up-to-date at version $CURRENT_LTS."
187+
fi
188+
189+
# テストモードでは常に更新が必要であると報告
190+
if [[ "${{ github.event_name }}" == "workflow_dispatch" && "${{ github.event.inputs.dry_run }}" == "true" ]]; then
191+
if [[ -n "${{ github.event.inputs.innovation_version }}" ]]; then
192+
echo "::notice::テストモード: Innovation更新をテスト実行します"
193+
INNOVATION_UPDATE_NEEDED="true"
194+
fi
195+
if [[ -n "${{ github.event.inputs.lts_version }}" ]]; then
196+
echo "::notice::テストモード: LTS更新をテスト実行します"
197+
LTS_UPDATE_NEEDED="true"
198+
fi
199+
fi
200+
201+
echo "INNOVATION_UPDATE_NEEDED=${INNOVATION_UPDATE_NEEDED}" >> $GITHUB_OUTPUT
202+
echo "LTS_UPDATE_NEEDED=${LTS_UPDATE_NEEDED}" >> $GITHUB_OUTPUT
203+
204+
- name: Update files and create PR if needed
205+
if: steps.check_versions.outputs.INNOVATION_UPDATE_NEEDED == 'true' || steps.check_versions.outputs.LTS_UPDATE_NEEDED == 'true'
206+
env:
207+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
208+
CURRENT_INNOVATION: ${{ steps.current_versions.outputs.CURRENT_INNOVATION }}
209+
LATEST_INNOVATION: ${{ steps.latest_tags.outputs.LATEST_INNOVATION }}
210+
CURRENT_LTS: ${{ steps.current_versions.outputs.CURRENT_LTS }}
211+
LATEST_LTS: ${{ steps.latest_tags.outputs.LATEST_LTS }}
212+
DRY_RUN: ${{ github.event.inputs.dry_run == 'true' }}
213+
run: |
214+
# dry runモードを確認
215+
if [[ "$DRY_RUN" == "true" ]]; then
216+
echo "::notice::dry runモードで実行しています。実際の変更は行いません。"
217+
fi
218+
219+
# ブランチ作成
220+
BRANCH_NAME="bot/update-mysql-shell-$(date +%Y%m%d%H%M%S)"
221+
if [[ "$DRY_RUN" != "true" ]]; then
222+
git config --global user.name 'github-actions[bot]'
223+
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
224+
git checkout -b $BRANCH_NAME
225+
else
226+
echo "dry run: git checkout -b $BRANCH_NAME"
227+
fi
228+
229+
PR_BODY="Automated update for MySQL Shell versions.\n\n"
230+
231+
# バージョン更新関数
232+
update_version() {
233+
local type=$1
234+
local current_version=$2
235+
local new_version=$3
236+
local major_version=$(echo "$new_version" | cut -d. -f1)
237+
local minor_version=$(echo "$new_version" | cut -d. -f2)
238+
local short_version="${major_version}.${minor_version}"
239+
240+
echo "Updating $type to $new_version (major.minor: $short_version)..."
241+
242+
# Dockerfile の更新
243+
if [[ "$DRY_RUN" != "true" ]]; then
244+
sed -i "s/^ARG MYSQL_SHELL_VERSION=.*/ARG MYSQL_SHELL_VERSION=$new_version/" docker/$type/Dockerfile || {
245+
echo "::warning::Failed to update version in docker/$type/Dockerfile, but continuing..."
246+
}
247+
else
248+
echo "dry run: docker/$type/Dockerfile 内の ARG MYSQL_SHELL_VERSION=$current_version を $new_version に更新"
249+
fi
250+
251+
# README.md の更新
252+
if [[ "$type" == "innovation" ]]; then
253+
local match_pattern="Innovation Series ([0-9]\\.[0-9]\\.[x0-9])"
254+
local replace_value="Innovation Series (${major_version}.${minor_version}.x)"
255+
local tag_pattern="snickerjp\/docker-mysql-shell:${major_version}\\.[0-9]"
256+
local tag_replace="snickerjp\/docker-mysql-shell:${short_version}"
257+
258+
if [[ "$DRY_RUN" != "true" ]]; then
259+
# 各sedコマンドを個別にエラーハンドリング
260+
sed -i "s/$match_pattern/$replace_value/g" README.md || {
261+
echo "::warning::Failed to update Innovation Series version in README.md, but continuing..."
262+
}
263+
264+
sed -i "s/$tag_pattern/$tag_replace/g" README.md || {
265+
echo "::warning::Failed to update Innovation image tag in README.md, but continuing..."
266+
}
267+
else
268+
echo "dry run: README.md 内の '$match_pattern' を '$replace_value' に更新"
269+
echo "dry run: README.md 内の '$tag_pattern' を '$tag_replace' に更新"
270+
fi
271+
else
272+
local match_pattern="LTS Series ([0-9]\\.[0-9]\\.[x0-9])"
273+
local replace_value="LTS Series (${major_version}.${minor_version}.x)"
274+
local tag_pattern="snickerjp\/docker-mysql-shell:${major_version}\\.[0-9]"
275+
local tag_replace="snickerjp\/docker-mysql-shell:${short_version}"
276+
277+
if [[ "$DRY_RUN" != "true" ]]; then
278+
sed -i "s/$match_pattern/$replace_value/g" README.md || {
279+
echo "::warning::Failed to update LTS Series version in README.md, but continuing..."
280+
}
281+
282+
sed -i "s/$tag_pattern/$tag_replace/g" README.md || {
283+
echo "::warning::Failed to update LTS image tag in README.md, but continuing..."
284+
}
285+
else
286+
echo "dry run: README.md 内の '$match_pattern' を '$replace_value' に更新"
287+
echo "dry run: README.md 内の '$tag_pattern' を '$tag_replace' に更新"
288+
fi
289+
fi
290+
291+
# GitHub Actions ワークフローファイルの更新
292+
local workflow_pattern="version: ${major_version}\\.[0-9]"
293+
local workflow_replace="version: ${short_version}"
294+
for workflow in .github/workflows/docker-*.yml; do
295+
if [[ -f "$workflow" ]]; then
296+
if [[ "$DRY_RUN" != "true" ]]; then
297+
sed -i "s/$workflow_pattern/$workflow_replace/g" "$workflow" || {
298+
echo "::warning::Failed to update version in $workflow, but continuing..."
299+
}
300+
else
301+
echo "dry run: $workflow 内の '$workflow_pattern' を '$workflow_replace' に更新"
302+
fi
303+
fi
304+
done
305+
306+
# PR本文に変更内容を追加
307+
PR_BODY+="* **${type^}:** ${current_version} -> ${new_version}\n"
308+
309+
# 更新が成功したか確認(少なくともDockerfileは必須)- ドライランでは実行しない
310+
if [[ "$DRY_RUN" != "true" ]]; then
311+
if ! grep -q "ARG MYSQL_SHELL_VERSION=$new_version" docker/$type/Dockerfile; then
312+
echo "::warning::Version update in docker/$type/Dockerfile might have failed, but we'll continue..."
313+
fi
314+
fi
315+
}
316+
317+
# Innovation の更新
318+
if [[ "${{ steps.check_versions.outputs.INNOVATION_UPDATE_NEEDED }}" == "true" ]]; then
319+
update_version "innovation" "$CURRENT_INNOVATION" "$LATEST_INNOVATION"
320+
fi
321+
322+
# LTS の更新
323+
if [[ "${{ steps.check_versions.outputs.LTS_UPDATE_NEEDED }}" == "true" ]]; then
324+
update_version "lts" "$CURRENT_LTS" "$LATEST_LTS"
325+
fi
326+
327+
# 変更をコミットしてプッシュ
328+
changed_files=$(git status --porcelain | awk '{print $2}')
329+
if [[ -z "$changed_files" ]]; then
330+
echo "No changes to commit."
331+
exit 0
332+
fi
333+
334+
# ファイルの変更をチェック
335+
echo "Changed files:"
336+
for file in $changed_files; do
337+
echo "- $file"
338+
done
339+
340+
# すべての変更をステージング
341+
if [[ "$DRY_RUN" != "true" ]]; then
342+
git add $changed_files
343+
git commit -m "Update MySQL Shell versions (Innovation: $LATEST_INNOVATION, LTS: $LATEST_LTS)"
344+
345+
# エラーハンドリング付きでプッシュ
346+
if ! git push origin $BRANCH_NAME; then
347+
echo "::error::Failed to push changes to GitHub"
348+
exit 1
349+
fi
350+
351+
# プルリクエストを作成
352+
if ! gh pr create \
353+
--base develop \
354+
--head $BRANCH_NAME \
355+
--title "Update MySQL Shell versions (Innovation: $LATEST_INNOVATION, LTS: $LATEST_LTS)" \
356+
--body "$PR_BODY"; then
357+
echo "::error::Failed to create Pull Request"
358+
exit 1
359+
fi
360+
361+
echo "Pull request created successfully!"
362+
else
363+
echo "dry run: 以下のファイルが変更されます:"
364+
for file in $changed_files; do
365+
echo "- $file"
366+
done
367+
echo "dry run: コミットメッセージ: Update MySQL Shell versions (Innovation: $LATEST_INNOVATION, LTS: $LATEST_LTS)"
368+
echo "dry run: PR作成: タイトル: Update MySQL Shell versions (Innovation: $LATEST_INNOVATION, LTS: $LATEST_LTS)"
369+
echo "dry run: PR本文:"
370+
echo -e "$PR_BODY"
371+
echo "dry run終了: 実際の変更は行われていません。"
372+
fi
373+
374+
# ステップ6: 更新不要の場合の通知
375+
- name: No update needed
376+
if: steps.check_versions.outputs.INNOVATION_UPDATE_NEEDED == 'false' && steps.check_versions.outputs.LTS_UPDATE_NEEDED == 'false'
377+
run: |
378+
echo "::notice::No new MySQL Shell versions found. All versions are up to date."
379+
echo "Current Innovation: ${{ steps.current_versions.outputs.CURRENT_INNOVATION }}"
380+
echo "Current LTS: ${{ steps.current_versions.outputs.CURRENT_LTS }}"

0 commit comments

Comments
 (0)