diff --git a/.github/workflows/check-new-release.yml b/.github/workflows/check-new-release.yml new file mode 100644 index 0000000..29405a1 --- /dev/null +++ b/.github/workflows/check-new-release.yml @@ -0,0 +1,394 @@ +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: write + pull-requests: write + actions: 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 + + # ワークフローファイルの更新部分を削除 + # この部分を削除または以下のようにコメントアウト + echo "::notice::ワークフローファイルは手動更新が必要です: .github/workflows/docker-*.yml 内の version: ${major_version}.[x] を version: ${short_version} に更新してください" + + # PR本文に変更内容を追加 + PR_BODY+="* **${type^}:** ${current_version} -> ${new_version}\n" + PR_BODY+="* 注意: ワークフローファイル(.github/workflows/docker-*.yml)は手動で更新する必要があります\n" + + # 更新が成功したか確認 + 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 + + # PR作成後に追加のメッセージを表示 + - name: Show post-PR creation message + if: steps.check_versions.outputs.INNOVATION_UPDATE_NEEDED == 'true' || steps.check_versions.outputs.LTS_UPDATE_NEEDED == 'true' + run: | + # DRY_RUNがtrueでない場合のみ実行 + if [[ "$DRY_RUN" != "true" ]]; then + echo "::group::ワークフローファイル更新手順" + echo "PR #xxx が作成されました。次に手動でワークフローファイルを更新してください。" + echo "1. PRブランチをローカルにチェックアウト:" + echo " git fetch origin $BRANCH_NAME && git checkout $BRANCH_NAME" + echo "" + echo "2. 以下のコマンドでワークフローファイルを更新:" + + # Innovation更新の場合 + if [[ "${{ steps.check_versions.outputs.INNOVATION_UPDATE_NEEDED }}" == "true" ]]; then + INNOVATION_MAJOR=$(echo "$LATEST_INNOVATION" | cut -d. -f1) + INNOVATION_MINOR=$(echo "$LATEST_INNOVATION" | cut -d. -f2) + INNOVATION_SHORT="${INNOVATION_MAJOR}.${INNOVATION_MINOR}" + echo " # Innovation更新コマンド:" + echo " find .github/workflows -name \"docker-*.yml\" -exec sed -i 's/version: ${INNOVATION_MAJOR}\.x/version: ${INNOVATION_SHORT}/g' {} \\;" + fi + + # LTS更新の場合 + if [[ "${{ steps.check_versions.outputs.LTS_UPDATE_NEEDED }}" == "true" ]]; then + LTS_MAJOR=$(echo "$LATEST_LTS" | cut -d. -f1) + LTS_MINOR=$(echo "$LATEST_LTS" | cut -d. -f2) + LTS_SHORT="${LTS_MAJOR}.${LTS_MINOR}" + echo " # LTS更新コマンド:" + echo " find .github/workflows -name \"docker-*.yml\" -exec sed -i 's/version: ${LTS_MAJOR}\.x/version: ${LTS_SHORT}/g' {} \\;" + fi + + echo "" + echo "3. 変更をコミット:" + echo " git add .github/workflows/" + echo " git commit -m \"Update workflow files for MySQL Shell versions\"" + echo "" + echo "4. 変更をプッシュ:" + echo " git push origin $BRANCH_NAME" + echo "" + echo "これで既存のPRにワークフロー更新が追加されます。" + echo "::endgroup::" + 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 }}" diff --git a/README.md b/README.md index a7d168f..448c259 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![Codacy Badge](https://api.codacy.com/project/badge/Grade/314c46648b7a4b85a25edfeef95edad5)](https://app.codacy.com/gh/snickerjp/docker-mysql-shell?utm_source=github.com&utm_medium=referral&utm_content=snickerjp/docker-mysql-shell&utm_campaign=Badge_Grade_Settings) This repository contains Dockerfiles for MySQL Shell in two different series: -- Innovation Series (9.2.x) - Latest features [(Dockerfile)](docker/innovation/Dockerfile) +- Innovation Series (9.3.x) - Latest features [(Dockerfile)](docker/innovation/Dockerfile) - LTS Series (8.4.x) - Long Term Support [(Dockerfile)](docker/lts/Dockerfile) Both images are based on Debian 12 (slim) for minimal image size. @@ -11,7 +11,7 @@ Both images are based on Debian 12 (slim) for minimal image size. ## Available Tags ### Innovation Series [(Dockerfile)](docker/innovation/Dockerfile) -- `snickerjp/docker-mysql-shell:9.2` - Innovation series with specific version +- `snickerjp/docker-mysql-shell:9.3` - Innovation series with specific version - `snickerjp/docker-mysql-shell:Innovation` - Latest Innovation series build ### LTS Series [(Dockerfile)](docker/lts/Dockerfile) @@ -21,10 +21,10 @@ Both images are based on Debian 12 (slim) for minimal image size. ## Building the Images -### Innovation Series (9.2.x) [(Dockerfile)](docker/innovation/Dockerfile) +### Innovation Series (9.3.x) [(Dockerfile)](docker/innovation/Dockerfile) ```bash cd docker/innovation -docker build -t snickerjp/docker-mysql-shell:9.2 . +docker build -t snickerjp/docker-mysql-shell:9.3 . ``` ### LTS Series (8.4.x) [(Dockerfile)](docker/lts/Dockerfile) @@ -39,7 +39,7 @@ Run MySQL Shell container: ```bash # Innovation Series -docker run -it snickerjp/docker-mysql-shell:9.2 +docker run -it snickerjp/docker-mysql-shell:9.3 # or docker run -it snickerjp/docker-mysql-shell:Innovation @@ -54,7 +54,7 @@ docker run -it snickerjp/docker-mysql-shell:latest To connect to a MySQL Server: ```bash # Innovation Series -docker run -it snickerjp/docker-mysql-shell:9.2 --uri mysql://user:pass@host:port/schema +docker run -it snickerjp/docker-mysql-shell:9.3 --uri mysql://user:pass@host:port/schema # or using Innovation tag docker run -it snickerjp/docker-mysql-shell:Innovation --uri mysql://user:pass@host:port/schema diff --git a/docker/innovation/Dockerfile b/docker/innovation/Dockerfile index 9c7b619..e3e8b94 100644 --- a/docker/innovation/Dockerfile +++ b/docker/innovation/Dockerfile @@ -1,7 +1,7 @@ FROM debian:12-slim ARG DEBIAN_FRONTEND=noninteractive -ARG MYSQL_SHELL_VERSION=9.2.0 +ARG MYSQL_SHELL_VERSION=9.3.0 # Create a user for the container RUN useradd -ms /bin/bash mysqlshelluser diff --git a/docker/lts/Dockerfile b/docker/lts/Dockerfile index 1a1b175..cf30267 100644 --- a/docker/lts/Dockerfile +++ b/docker/lts/Dockerfile @@ -1,7 +1,7 @@ FROM debian:12-slim ARG DEBIAN_FRONTEND=noninteractive -ARG MYSQL_SHELL_VERSION=8.4.4 +ARG MYSQL_SHELL_VERSION=8.4.5 # Create a user for the container RUN useradd -ms /bin/bash mysqlshelluser