Skip to content

Check for new MySQL Shell releases #7

Check for new MySQL Shell releases

Check for new MySQL Shell releases #7

name: Check for new MySQL Shell releases
# このワークフローは以下を行います:
# 1. MySQL Shellの最新リリースタグを検出
# 2. 現在のDockerイメージのバージョンと比較
# 3. 更新が必要な場合は自動的にPRを作成
on:
schedule:
# 毎日 UTC 3時17分に実行 (ランダムな時刻で負荷分散)
- cron: '17 3 * * *'
workflow_dispatch: # 手動実行も可能にする
inputs:
dry_run:
description: '実際のPRを作成せずにテスト実行'
required: false
default: false
type: boolean
innovation_version:
description: 'テスト用の強制Innovation版バージョン(例:9.3.0)'
required: false
type: string
lts_version:
description: 'テスト用の強制LTS版バージョン(例:8.4.5)'
required: false
type: string
jobs:
check-release:
permissions:
contents: read
pull-requests: write
runs-on: ubuntu-latest
# ジョブの概要説明
name: Check and update MySQL Shell versions
steps:
# ステップ1: リポジトリの取得
- name: Checkout repository
uses: actions/checkout@v4
with:
# プルリクエスト作成のためにトークンが必要
token: ${{ secrets.GITHUB_TOKEN }}
- name: Get current versions
id: current_versions
run: |
# Dockerfileから現在のバージョンを取得
if [[ ! -f docker/innovation/Dockerfile ]] || [[ ! -f docker/lts/Dockerfile ]]; then
echo "::error::Required Dockerfiles not found!"
exit 1
fi
CURRENT_INNOVATION=$(grep -oP '(?<=^ARG MYSQL_SHELL_VERSION=)\d+\.\d+\.\d+' docker/innovation/Dockerfile)
CURRENT_LTS=$(grep -oP '(?<=^ARG MYSQL_SHELL_VERSION=)\d+\.\d+\.\d+' docker/lts/Dockerfile)
if [[ -z "$CURRENT_INNOVATION" ]] || [[ -z "$CURRENT_LTS" ]]; then
echo "::error::Failed to extract current versions from Dockerfiles"
exit 1
fi
echo "CURRENT_INNOVATION=${CURRENT_INNOVATION}" >> $GITHUB_OUTPUT
echo "CURRENT_LTS=${CURRENT_LTS}" >> $GITHUB_OUTPUT
echo "Current Innovation: $CURRENT_INNOVATION"
echo "Current LTS: $CURRENT_LTS"
# メジャーバージョンを抽出 (後で使用)
INNOVATION_MAJOR_VERSION=$(echo "$CURRENT_INNOVATION" | cut -d. -f1)
LTS_MAJOR_VERSION=$(echo "$CURRENT_LTS" | cut -d. -f1)
echo "INNOVATION_MAJOR_VERSION=${INNOVATION_MAJOR_VERSION}" >> $GITHUB_OUTPUT
echo "LTS_MAJOR_VERSION=${LTS_MAJOR_VERSION}" >> $GITHUB_OUTPUT
- name: Get latest MySQL Shell tags
id: latest_tags
run: |
# GitHub APIからタグ情報を取得
INNOVATION_MAJOR="${{ steps.current_versions.outputs.INNOVATION_MAJOR_VERSION }}"
LTS_MAJOR="${{ steps.current_versions.outputs.LTS_MAJOR_VERSION }}"
# テスト用の手動指定バージョンがあれば使用する
if [[ "${{ github.event_name }}" == "workflow_dispatch" && -n "${{ github.event.inputs.innovation_version }}" ]]; then
LATEST_INNOVATION="${{ github.event.inputs.innovation_version }}"
echo "Using manually specified Innovation version: $LATEST_INNOVATION"
else
# GitHub APIからのフェッチを試みる
API_RESPONSE=$(curl -s -H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
-H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \
"https://api.github.com/repos/mysql/mysql-shell/tags?per_page=100")
if [[ -z "$API_RESPONSE" ]] || [[ "$API_RESPONSE" == *"rate limit"* ]] || [[ "$API_RESPONSE" == *"Bad credentials"* ]]; then
echo "::error::Failed to fetch data from GitHub API: $(echo "$API_RESPONSE" | grep -o '"message":"[^"]*"' || echo 'Unknown error')"
exit 1
fi
# 正規表現パターンを動的に構築
INNOVATION_PATTERN="^${INNOVATION_MAJOR}\\.\\d+\\.\\d+$"
LATEST_INNOVATION=$(echo "$API_RESPONSE" | jq -r --arg pattern "$INNOVATION_PATTERN" '[.[] | select(.name | test($pattern))][0].name')
fi
# LTSバージョンの取得(手動指定またはAPI)
if [[ "${{ github.event_name }}" == "workflow_dispatch" && -n "${{ github.event.inputs.lts_version }}" ]]; then
LATEST_LTS="${{ github.event.inputs.lts_version }}"
echo "Using manually specified LTS version: $LATEST_LTS"
else
# APIレスポンスを再利用
LTS_PATTERN="^${LTS_MAJOR}\\.\\d+\\.\\d+$"
LATEST_LTS=$(echo "$API_RESPONSE" | jq -r --arg pattern "$LTS_PATTERN" '[.[] | select(.name | test($pattern))][0].name')
fi
# 結果の検証
if [[ -z "$LATEST_INNOVATION" ]] || [[ "$LATEST_INNOVATION" == "null" ]] || [[ -z "$LATEST_LTS" ]] || [[ "$LATEST_LTS" == "null" ]]; then
echo "::warning::Failed to find matching versions. Using hardcoded patterns as fallback."
# フォールバック: ハードコードされたバージョンパターン
LATEST_INNOVATION=${LATEST_INNOVATION:-$(echo "$API_RESPONSE" | jq -r '[.[] | select(.name | test("^9\\.\\d+\\.\\d+$"))][0].name')}
LATEST_LTS=${LATEST_LTS:-$(echo "$API_RESPONSE" | jq -r '[.[] | select(.name | test("^8\\.\\d+\\.\\d+$"))][0].name')}
fi
echo "LATEST_INNOVATION=${LATEST_INNOVATION}" >> $GITHUB_OUTPUT
echo "LATEST_LTS=${LATEST_LTS}" >> $GITHUB_OUTPUT
echo "Latest Innovation: $LATEST_INNOVATION"
echo "Latest LTS: $LATEST_LTS"
- name: Check versions
id: check_versions
run: |
# バージョン比較ユーティリティ関数
version_gt() {
# $1 > $2 の場合に0を返す
test "$(echo "$1 $2" | tr " " "\n" | sort -V | head -n 1)" != "$1"
}
CURRENT_INNOVATION="${{ steps.current_versions.outputs.CURRENT_INNOVATION }}"
LATEST_INNOVATION="${{ steps.latest_tags.outputs.LATEST_INNOVATION }}"
CURRENT_LTS="${{ steps.current_versions.outputs.CURRENT_LTS }}"
LATEST_LTS="${{ steps.latest_tags.outputs.LATEST_LTS }}"
INNOVATION_UPDATE_NEEDED="false"
LTS_UPDATE_NEEDED="false"
# Innovation バージョンのチェック
if [[ -z "$LATEST_INNOVATION" ]] || [[ "$LATEST_INNOVATION" == "null" ]]; then
echo "::warning::No valid Innovation version found in API response"
elif [[ "$CURRENT_INNOVATION" != "$LATEST_INNOVATION" ]]; then
if version_gt "$LATEST_INNOVATION" "$CURRENT_INNOVATION"; then
echo "Update needed for Innovation: $CURRENT_INNOVATION -> $LATEST_INNOVATION (newer version available)"
INNOVATION_UPDATE_NEEDED="true"
else
echo "::warning::Latest Innovation version ($LATEST_INNOVATION) is older than current ($CURRENT_INNOVATION). Skipping update."
fi
else
echo "Innovation is up-to-date at version $CURRENT_INNOVATION."
fi
# LTS バージョンのチェック
if [[ -z "$LATEST_LTS" ]] || [[ "$LATEST_LTS" == "null" ]]; then
echo "::warning::No valid LTS version found in API response"
elif [[ "$CURRENT_LTS" != "$LATEST_LTS" ]]; then
if version_gt "$LATEST_LTS" "$CURRENT_LTS"; then
echo "Update needed for LTS: $CURRENT_LTS -> $LATEST_LTS (newer version available)"
LTS_UPDATE_NEEDED="true"
else
echo "::warning::Latest LTS version ($LATEST_LTS) is older than current ($CURRENT_LTS). Skipping update."
fi
else
echo "LTS is up-to-date at version $CURRENT_LTS."
fi
# テストモードでは常に更新が必要であると報告
if [[ "${{ github.event_name }}" == "workflow_dispatch" && "${{ github.event.inputs.dry_run }}" == "true" ]]; then
if [[ -n "${{ github.event.inputs.innovation_version }}" ]]; then
echo "::notice::テストモード: Innovation更新をテスト実行します"
INNOVATION_UPDATE_NEEDED="true"
fi
if [[ -n "${{ github.event.inputs.lts_version }}" ]]; then
echo "::notice::テストモード: LTS更新をテスト実行します"
LTS_UPDATE_NEEDED="true"
fi
fi
echo "INNOVATION_UPDATE_NEEDED=${INNOVATION_UPDATE_NEEDED}" >> $GITHUB_OUTPUT
echo "LTS_UPDATE_NEEDED=${LTS_UPDATE_NEEDED}" >> $GITHUB_OUTPUT
- name: Update files and create PR if needed
if: steps.check_versions.outputs.INNOVATION_UPDATE_NEEDED == 'true' || steps.check_versions.outputs.LTS_UPDATE_NEEDED == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CURRENT_INNOVATION: ${{ steps.current_versions.outputs.CURRENT_INNOVATION }}
LATEST_INNOVATION: ${{ steps.latest_tags.outputs.LATEST_INNOVATION }}
CURRENT_LTS: ${{ steps.current_versions.outputs.CURRENT_LTS }}
LATEST_LTS: ${{ steps.latest_tags.outputs.LATEST_LTS }}
DRY_RUN: ${{ github.event.inputs.dry_run == 'true' }}
run: |
# dry runモードを確認
if [[ "$DRY_RUN" == "true" ]]; then
echo "::notice::dry runモードで実行しています。実際の変更は行いません。"
fi
# ブランチ作成
BRANCH_NAME="bot/update-mysql-shell-$(date +%Y%m%d%H%M%S)"
if [[ "$DRY_RUN" != "true" ]]; then
git config --global user.name 'github-actions[bot]'
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
git checkout -b $BRANCH_NAME
else
echo "dry run: git checkout -b $BRANCH_NAME"
fi
PR_BODY="Automated update for MySQL Shell versions.\n\n"
# バージョン更新関数
update_version() {
local type=$1
local current_version=$2
local new_version=$3
local major_version=$(echo "$new_version" | cut -d. -f1)
local minor_version=$(echo "$new_version" | cut -d. -f2)
local short_version="${major_version}.${minor_version}"
echo "Updating $type to $new_version (major.minor: $short_version)..."
# Dockerfile の更新
if [[ "$DRY_RUN" != "true" ]]; then
sed -i "s/^ARG MYSQL_SHELL_VERSION=.*/ARG MYSQL_SHELL_VERSION=$new_version/" docker/$type/Dockerfile || {
echo "::warning::Failed to update version in docker/$type/Dockerfile, but continuing..."
}
else
echo "dry run: docker/$type/Dockerfile 内の ARG MYSQL_SHELL_VERSION=$current_version を $new_version に更新"
fi
# README.md の更新
if [[ "$type" == "innovation" ]]; then
local match_pattern="Innovation Series ([0-9]\\.[0-9]\\.[x0-9])"
local replace_value="Innovation Series (${major_version}.${minor_version}.x)"
local tag_pattern="snickerjp\/docker-mysql-shell:${major_version}\\.[0-9]"
local tag_replace="snickerjp\/docker-mysql-shell:${short_version}"
if [[ "$DRY_RUN" != "true" ]]; then
# 各sedコマンドを個別にエラーハンドリング
sed -i "s/$match_pattern/$replace_value/g" README.md || {
echo "::warning::Failed to update Innovation Series version in README.md, but continuing..."
}
sed -i "s/$tag_pattern/$tag_replace/g" README.md || {
echo "::warning::Failed to update Innovation image tag in README.md, but continuing..."
}
else
echo "dry run: README.md 内の '$match_pattern' を '$replace_value' に更新"
echo "dry run: README.md 内の '$tag_pattern' を '$tag_replace' に更新"
fi
else
local match_pattern="LTS Series ([0-9]\\.[0-9]\\.[x0-9])"
local replace_value="LTS Series (${major_version}.${minor_version}.x)"
local tag_pattern="snickerjp\/docker-mysql-shell:${major_version}\\.[0-9]"
local tag_replace="snickerjp\/docker-mysql-shell:${short_version}"
if [[ "$DRY_RUN" != "true" ]]; then
sed -i "s/$match_pattern/$replace_value/g" README.md || {
echo "::warning::Failed to update LTS Series version in README.md, but continuing..."
}
sed -i "s/$tag_pattern/$tag_replace/g" README.md || {
echo "::warning::Failed to update LTS image tag in README.md, but continuing..."
}
else
echo "dry run: README.md 内の '$match_pattern' を '$replace_value' に更新"
echo "dry run: README.md 内の '$tag_pattern' を '$tag_replace' に更新"
fi
fi
# GitHub Actions ワークフローファイルの更新
local workflow_pattern="version: ${major_version}\\.[0-9]"
local workflow_replace="version: ${short_version}"
for workflow in .github/workflows/docker-*.yml; do
if [[ -f "$workflow" ]]; then
if [[ "$DRY_RUN" != "true" ]]; then
sed -i "s/$workflow_pattern/$workflow_replace/g" "$workflow" || {
echo "::warning::Failed to update version in $workflow, but continuing..."
}
else
echo "dry run: $workflow 内の '$workflow_pattern' を '$workflow_replace' に更新"
fi
fi
done
# PR本文に変更内容を追加
PR_BODY+="* **${type^}:** ${current_version} -> ${new_version}\n"
# 更新が成功したか確認(少なくともDockerfileは必須)- ドライランでは実行しない
if [[ "$DRY_RUN" != "true" ]]; then
if ! grep -q "ARG MYSQL_SHELL_VERSION=$new_version" docker/$type/Dockerfile; then
echo "::warning::Version update in docker/$type/Dockerfile might have failed, but we'll continue..."
fi
fi
}
# Innovation の更新
if [[ "${{ steps.check_versions.outputs.INNOVATION_UPDATE_NEEDED }}" == "true" ]]; then
update_version "innovation" "$CURRENT_INNOVATION" "$LATEST_INNOVATION"
fi
# LTS の更新
if [[ "${{ steps.check_versions.outputs.LTS_UPDATE_NEEDED }}" == "true" ]]; then
update_version "lts" "$CURRENT_LTS" "$LATEST_LTS"
fi
# 変更をコミットしてプッシュ
changed_files=$(git status --porcelain | awk '{print $2}')
if [[ -z "$changed_files" ]]; then
echo "No changes to commit."
exit 0
fi
# ファイルの変更をチェック
echo "Changed files:"
for file in $changed_files; do
echo "- $file"
done
# すべての変更をステージング
if [[ "$DRY_RUN" != "true" ]]; then
git add $changed_files
git commit -m "Update MySQL Shell versions (Innovation: $LATEST_INNOVATION, LTS: $LATEST_LTS)"
# エラーハンドリング付きでプッシュ
if ! git push origin $BRANCH_NAME; then
echo "::error::Failed to push changes to GitHub"
exit 1
fi
# プルリクエストを作成
if ! gh pr create \
--base develop \
--head $BRANCH_NAME \
--title "Update MySQL Shell versions (Innovation: $LATEST_INNOVATION, LTS: $LATEST_LTS)" \
--body "$PR_BODY"; then
echo "::error::Failed to create Pull Request"
exit 1
fi
echo "Pull request created successfully!"
else
echo "dry run: 以下のファイルが変更されます:"
for file in $changed_files; do
echo "- $file"
done
echo "dry run: コミットメッセージ: Update MySQL Shell versions (Innovation: $LATEST_INNOVATION, LTS: $LATEST_LTS)"
echo "dry run: PR作成: タイトル: Update MySQL Shell versions (Innovation: $LATEST_INNOVATION, LTS: $LATEST_LTS)"
echo "dry run: PR本文:"
echo -e "$PR_BODY"
echo "dry run終了: 実際の変更は行われていません。"
fi
# ステップ6: 更新不要の場合の通知
- name: No update needed
if: steps.check_versions.outputs.INNOVATION_UPDATE_NEEDED == 'false' && steps.check_versions.outputs.LTS_UPDATE_NEEDED == 'false'
run: |
echo "::notice::No new MySQL Shell versions found. All versions are up to date."
echo "Current Innovation: ${{ steps.current_versions.outputs.CURRENT_INNOVATION }}"
echo "Current LTS: ${{ steps.current_versions.outputs.CURRENT_LTS }}"