Git タグを自動更新 〜マージされるトピックブランチ毎に更新ルールを変える〜


はじめに

どうも!生産技術部のエンジニアです。Gitのタグを自動更新できる様にGitLab CIに設定してみました。マージされるトピックブランチ毎に更新ルールを変えられるスクリプトを組みましたので紹介します。

GitLabサーバを一から構築される方は、以下からご覧ください。
「proxy環境下でDocker Composeを用いてCentOS7上にGitLab Dockerを作成」

前提条件

GitLab、GitLabRunnerの導入が実施済みであること。

対象のブランチモデル

以下のブランチモデルを利用し、masterブランチにトピックブランチがマージされた時に、タグの更新を行います。利用するブランチモデルについてはここを参照ください。

Developブランチからマージされた場合とそれ以外のブランチからマージされた場合で分けて、タグの更新ルールを以下の様に設定します。

Merge branch 'develop' into 'master'
1.0.0 -> 2.0.0
Merge branch 'hotfix' into 'master'
1.0.0 -> 1.0.1

自動更新スクリプトの作成

作成するスクリプトについて紹介します。作成するファイルは、

  • GitLab CI用の設定ファイル(.gitlab-ci.yml)、
  • マージイベント時に、起動するスクリプト(release.sh)、
  • タグの更新ルールを設定するスクリプト(version_up.sh)

の3つです。

GitLab CIの設定

.gitlab-ci.ymlには、release_jobにリリース用のスクリプトを追加し、リリース用のスクリプト内で、タグ更新用のスクリプトを起動します。masterブランチにマージされた際にタグ更新を実施するように、masterブランチのみに対して設定します。

.gitlab-ci.yml
stages:
  - develop
  - release
  - hotfix

develop_job:
  stage: develop
  script:
    - echo "develop"
  only:
    - develop

release_job:
  stage: release
  before_script:
    - chmod u+x scripts/release.sh 
  script:
    - scripts/release.sh
  only:
    - master

hotfix_job:
  stage: hotfix
  script:
    - echo "hotfix"
  only:
    - hotfix

マージされたトピックブランチを判別

release.shでは、マージされたトピックブランチがdevelopかそれ以外かを判別します。マージされた時のコミットメッセージをログ出力し、トピックブランチの名前を切り出しています。git log --grep "<pattern>"みたいなのを使えばもう少しスッキリ書けるのかもしれないです。切り出した名前がdevelopだった場合はメジャーアップデート、それ以外の場合はバグフィックスできる様に、version_up.shmajor/bugfixを引数に与えています。

下記サンプルは更新されるタグを表示するまでで、実際にタグ付けはしていません。

release.sh
#!/bin/bash
chmod u+x scripts/version_up.sh

# マージ時のgit logからトピックブランチのブランチ名を切り出す
merged_branch_name=$(git log --pretty=oneline --abbrev-commit --merges -n 1 | awk '{print $4}' | sed 's/'\''//g')

# ブランチ名がdevelopだった場合はメジャーアップデート、それ以外はバグフィックス
if [ $merged_branch_name = "develop" ]; then
  git tag -l | tail -n 1 | scripts/version_up.sh major
else
  git tag -l | tail -n 1 |  scripts/version_up.sh bugfix
fi

タグの更新ルールを設定

タグの更新スクリプト(version_up.sh)は、神速様の「gitでタグ名に日付を含めているのはダサい」を参考に作成させて頂きました。更新ルールは、メジャーアップデート、マイナーアップデート、バグフィックスのみとしました。

version_up.sh
#!/bin/sh
version=`awk '{print $1}' < /dev/stdin`
command=$1
major=`echo $version | awk -F '.' '{print $1}'`
minor=`echo $version | awk -F '.' '{print $2}'`
bugfix=`echo $version | awk -F '.' '{print $3}'`

if [ -z "$version" ]; then
  echo "USAGE: echo 1.0.0 | version_up.sh [major|minor|bugfix]"
  exit 1
fi

if [ "$command" = '' ]; then
    bugfix=`expr $bugfix + 1`
elif [ "$command" = 'major' ]; then
  major=`expr $major + 1`
  minor=0
  bugfix=0
elif [ "$command" = 'minor' ]; then
  minor=`expr $minor + 1`
  bugfix=0
elif [ "$command" = 'bugfix' ]; then
  bugfix=`expr $bugfix + 1`
fi

echo ${major}.${minor}.${bugfix}

最後に

タグの自動更新するスクリプトが完成しました。テストに使用したリポジトリはここにあります。もっとスマートなスクリプトがあれば教えてください。

ご参考