🤖

GitHub Actionsで自動的にセマンティックバージョニングでタグを切る

に公開

前提

タイトル通りですが前提条件です。

  • GitのホスティングサービスはGitHubを想定しています。
  • バージョンの指定はセマンティックバージョニングを想定しています。
  • Gitのベースブランチがmain、mainから派生したdevelop、開発はdevelopから派生したブランチで行います。
  • 最初にmainでv1.0.0というタグを切った状態を想定しています。
    • バージョン以外のタグは切らない想定です。

概要

Gitのmainブランチにpushされたらマイナーバージョンアップ、developブランチにpushされたらパッチバージョンアップとして自動でタグを切ります。
タグを打つだけで、リリースは別物として考えています。

なぜmainだけでタグを切らないのか

一般的にはmainブランチのみでタグを切ってリリースを行うと思います。
しかし自動でタグを切る都合上mainはマイナーバージョン、developはパッチバージョンとしました。

developブランチについて

セマンティックバージョニングの考え方とは少し乖離があります。
パッチバージョンアップはバグFixやセキュリティパッチに当たりますが、合流ブランチにマージされたコードはすぐにリリースする可能性あると思っています。
開発生産上developへマージしたら自動的にタグを切る運用にしました。

mainブランチについて

セマンティックバージョニングの考え方に基づいています。
新しい機能開発やツール導入を行ったらmainへマージしてマイナーバージョンを上げます。

Actions Workflow

トリガーイベント

main、developブランチへのpushとします。

on:
  push:
    branches:
      - main
      - develop

ジョブ

  1. 最新のGitTagを取得しバージョン情報を抽出
    • ref_nameがmainだったら
      • マイナーバージョンを上げてtagをpush
    • ref_nameがdevelopだったら
      • パッチバージョンを上げてtagをpush

ジョブフロー画像
ジョブのフロー

1. 最新のGitTagを取得しバージョン情報を抽出

workflowファイル
jobs:
  extract-semantic-version:
    runs-on: ubuntu-latest
    defaults:
      run:
        shell: bash
    outputs:
      major: ${{ steps.extract_version.outputs.major }}
      minor: ${{ steps.extract_version.outputs.minor }}
      patch: ${{ steps.extract_version.outputs.patch }}
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-tags: true
      - name: Fetch all tags
        run: git fetch --tags
      - name: Describe latest tag
        id: describe_latest_tag
        run: |
          tag=$(git describe --tags `git rev-list --tags --max-count=1`)
          echo "tag=$tag" >> "$GITHUB_OUTPUT"
      - id: extract_version
        run: |
          tag=${{ steps.describe_latest_tag.outputs.tag }}
          tag_without_v=${tag#v}
          IFS='.' read -r major minor patch <<< "$tag_without_v"
          echo "major=$major" >> "$GITHUB_OUTPUT"
          echo "minor=$minor" >> "$GITHUB_OUTPUT"
          echo "patch=$patch" >> "$GITHUB_OUTPUT"

注意点

  • リポジトリのtagが必要なので、actions/checkoutの設定でfetch-tags: trueを指定。
  • actions/checkoutだけではtag情報の取得はできていないので、git fetch --tagsを行う。

2-1. ref_nameがmainだったらマイナーバージョンを上げてtagをpush

workflowファイル
jobs:
  # 省略
  minor-update:
    if: github.ref_name == 'main'
    permissions:
      contents: write
    runs-on: ubuntu-latest
    defaults:
      run:
        shell: bash
    needs: extract-semantic-version
    env:
      MAJOR: ${{ needs.extract-semantic-version.outputs.major }}
      MINOR: ${{ needs.extract-semantic-version.outputs.minor }}
      PATCH: ${{ needs.extract-semantic-version.outputs.patch }}
    steps:
      - uses: actions/checkout@v4
      - name: New Tag
        id: new_tag
        run: echo "tag=v$MAJOR.$((MINOR + 1)).0" >> "$GITHUB_OUTPUT"
      - name: Push Tag
        env:
          TAG: ${{ steps.new_tag.outputs.tag }}
        run: |
          git tag $TAG
          git push origin $TAG

注意点

  • 依存関係としてextract-semantic-versionを指定し、バージョン情報を利用できるようにする。
  • tagをpushするためにcontents: writeの権限が必要。
  • jobの条件if: github.ref_name == 'main'でpushされたブランチ情報を比較。
  • マイナーバージョンを上げる場合はパッチバージョンは0にする。

2-2. ref_nameがdevelopだったらパッチバージョンを上げてtagをpush

workflowファイル
jobs:
  # 省略
  patch-update:
    if: github.ref_name == 'develop'
    permissions:
      contents: write
    runs-on: ubuntu-latest
    defaults:
      run:
        shell: bash
    needs: extract-semantic-version
    env:
      MAJOR: ${{ needs.extract-semantic-version.outputs.major }}
      MINOR: ${{ needs.extract-semantic-version.outputs.minor }}
      PATCH: ${{ needs.extract-semantic-version.outputs.patch }}
    steps:
      - uses: actions/checkout@v4
      - name: New Tag
        id: new_tag
        run: echo "tag=v$MAJOR.$MINOR.$((PATCH + 1))" >> "$GITHUB_OUTPUT"
      - name: Push Tag
        env:
          TAG: ${{ steps.new_tag.outputs.tag }}
        run: |
          git tag $TAG
          git push origin $TAG

注意点

  • 2-1とほぼ同じだが、job実行の条件変更とパッチバージョンのみ上げるようにする。

上記をまとめると自動的に最新のtagを取得しバージョンアップを行うことができます。

終わりに

タグを自動で切ることでリリース時にセレクトボックスでタグを選択でき、オペレーションミスを防ぐことができるようになりました。

Discussion