GitHub CLIやActionsで自動リリース
はじめに
みなさんこんにちは、ALH開発事業部のREIYAです。
今回はGitHubのCLIやActionsを用いて、自動リリースができるような仕組みをまとめました。
また、以下の記事などと合わせて最強のテンプレートレポジトリを作成できます!
今回使用している内容は以下レポジトリにまとまっています。
おことわり
ひとえにリリースと言ってもいろいろありますが、今回は
タグ付け
GitHubレポジトリ上でのrelease作成
をしていきます。
普通にリリースする
まずは普通にリリースすることを考えてみます。
ブラウザからぽちぽちしてもいいのですが、自動化にあたってコマンドでやります。
v1.0.0という名前でタグ付けするなら
git tag v1.0.0
をすることで、現在チェックアウトしているブランチの最新コミットに対してタグが付きます。
また
git push --tags
でタグをリモートにプッシュします。
次にリリースの作成ですが、これは通常のgitコマンドにはないので
GitHub CLIを用いて
gh release create v1.0.0 -n "リリースノートの内容" -t v1.0.0
のようにできます。
「gh release create v1.0.0」
までで、「v1.0.0」という名前でリリースを作成し
-nオプションでリリースノートの文言を指定します。これはghコマンドが対話なので、未指定でもあとから入力することができます。
ファイルから参照させることもできます。(今回は固定文言とし、リリースノートの自由度を捨てることにします。🥲)
-tオプションで、どのタグに対して作成するかを指定します。
詳しくは公式ドキュメントや、Qiitaで説明されているこちらの記事などを参考にするとよいです。
基本的にリリース名とタグ名は同じものにすると思いますので
バージョン名を変数とし
MAIN_VERSION=1
MINOR_VERSION=0
PATCH_VERSION=0
VERSION=v$MAIN_VERSION.$MINOR_VERSION.$PATCH_VERSION
git tag $VERSION
git push --tags
gh release create $VERSION -n "リリースノートの内容" -t $VERSION
のようにすることで、コマンドのみでタグ付け+リリースが作成できます。
Actionsにする
トリガーとしてよくやる作業が
developブランチへプッシュ時:ビルド、テスト
mainブランチへプッシュ時:環境へデプロイ、リリース
とすることが多いと思います。
よって、「mainブランチへのプッシュ時にリリースを作成する」部分を作っていきましょう
name: tag_release
on:
push:
branches: # 私はmasterブランチへのプッシュをトリガとしています
- 'master'
# コミットを作成するため、Actionsへ書き込み権限を付与します
permissions:
contents: write
jobs:
tag_release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: # リリースを作成する対象のブランチへチェックアウトします
ref: master
- name: Modify Tag Badge
env: # コミットをするため、GitHubへコミットする際のトークンが必要です
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "ここからリリース作成のコマンドを書いていきます"
このような形で起動すれば、main(サンプルではmaster)ブランチへのPRマージなどが起こったあとで
自動でリリースが作成されるようにできます。
自動リリースコマンド
では自動リリース作成のshell部分についてみていきましょう。
やや注意点があります。まず全体像は以下のようになります。
https://github.com/serna37/sample-template-repository/blob/master/.github/workflows/tag_release.yml
# 注意点1️⃣
git fetch --prune --unshallow
git pull --tags
LATEST_TAG=$(git describe --tags `git rev-list --tags --max-count=1` || echo "v0.0.0")
COMMIT_CNT=0
if [ "$LATEST_TAG" != "v0.0.0" ]; then
COMMIT_CNT=$(git rev-list --count $LATEST_TAG..HEAD)
fi
VERSION=$(echo "$LATEST_TAG" | sed 's/^v//')
IFS='.' read -r major minor patch <<< "$VERSION"
new_major=0
new_minor=0
new_patch=0
# 注意点2️⃣
if [ "$COMMIT_CNT" -gt 30 ]; then
new_major=$((major + 1))
elif [ "$COMMIT_CNT" -gt 10 ]; then
new_major=$major
new_minor=$((minor + 1))
else
new_major=$major
new_minor=$minor
new_patch=$((patch + 1))
fi
NEW_TAG="v${new_major}.${new_minor}.${new_patch}"
# 注意点3️⃣
sed -i "s/v${major}.${minor}.${patch}/v${new_major}.${new_minor}.${new_patch}/g" README.md
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git add README.md
git commit -m "update tag badge $NEW_TAG"
git push origin master
git tag $NEW_TAG
git push --tags
gh release create $NEW_TAG -n "release ${NEW_TAG}" -t $NEW_TAG
解説
まず前回のタグの最新を知ります。
また、前回のタグからHEADまでのコミット数に応じて、バージョンをどれだけ上げるかを計算しています。
バージョニングはコミット数に応じているので、嫌な方はここを工夫する必要があります。
# 注意点1️⃣
git fetch --prune --unshallow
git pull --tags
# 最新タグを取得、なければv0.0.0を取得する
LATEST_TAG=$(git describe --tags `git rev-list --tags --max-count=1` || echo "v0.0.0")
# 前回タグから今までのコミット数を取得
COMMIT_CNT=0
if [ "$LATEST_TAG" != "v0.0.0" ]; then
COMMIT_CNT=$(git rev-list --count $LATEST_TAG..HEAD)
fi
# 計算のためにバージョンの先頭vを取る
VERSION=$(echo "$LATEST_TAG" | sed 's/^v//')
# 1.0.0から1 0 0を変数で取得する
IFS='.' read -r major minor patch <<< "$VERSION"
new_major=0
new_minor=0
new_patch=0
...
⭐️ポイント
「git rev-list --tags --max-count=1」でタグリストの最新を取得し
その結果に対して「git describe --tags」して、バージョン名を取得しています。
また、「git rev-list --count $LATEST_TAG..HEAD」によって最新タグからHEADまでのコミット数を数えています。
さらに、「IFS='.' read -r major minor patch <<< "$VERSION"」によって「1.4.8」から数字3つを変数で取得しています。
注意点1️⃣
冒頭で
git fetch --prune --unshallow
git pull --tags
をします。タグのpullは当たり前ですが、fetchしているのには大事な理由があります。
Actionsが起動した際のチェックアウトでは、git clone --depth 1でクローンされているらしく
過去分のコミット情報をもっていないため、取得する必要があるのです。
しないと、describeできない旨のエラーが出てきます。
注意点2️⃣
次のバージョン名を知るために、コミット数によってバージョンのあげ方を変えています。
# 30以上コミットされてるならv1.8.5をv2.0.0のように、メジャーバージョンを上げて他を0にする
if [ "$COMMIT_CNT" -gt 30 ]; then
new_major=$((major + 1))
# 10以上30以下であれば、v1.4.7をv1.5.0のように、マイナーバージョンを上げてパッチバージョンを0に
elif [ "$COMMIT_CNT" -gt 10 ]; then
new_major=$major
new_minor=$((minor + 1))
# 10未満であればパッチバージョンだけを上げる
else
new_major=$major
new_minor=$minor
new_patch=$((patch + 1))
fi
NEW_TAG="v${new_major}.${new_minor}.${new_patch}"
このようにすることで、自動で次のバージョンを計算するようにしました。
コミット数の閾値は人ごとに好きに変えたら良いと思います。
注意点3️⃣
そうして新しいバージョン名を計算したところで
README.mdのバッチ
[![tag](https://img.shields.io/badge/tag-v0.0.4-green)](https://github.com/serna37/sample-template-repository/releases/tag/v0.0.4)
のようなものについて
v0.0.4をv0.0.5に置換、のようにしています。
ここの置換の正規表現が広域すぎて、変な部分まで置換してしまう場合などは
適宜カスタムしてください。
# READMEのバッジを置換する
sed -i "s/v${major}.${minor}.${patch}/v${new_major}.${new_minor}.${new_patch}/g" README.md
# コミットする
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git add README.md
git commit -m "update tag badge $NEW_TAG"
# プッシュする
git push origin master
これが終われば
git tag $NEW_TAG
git push --tags
gh release create $NEW_TAG -n "release ${NEW_TAG}" -t $NEW_TAG
と、最初におさらいしたコマンドでのリリース作成をするだけです。
要所でechoしておくと、Actionsのログにでるのでデバッグしやすいです。
できあがったもの
いちおう載せておきます。
注意点のまとめとして
masterブランチへのプッシュ
Actionsでチェックアウトした際、depth 1でクローンされるので注意
コミット数に応じてバージョンを上げている(要カスタム)
README.mdのバッジを置換で更新している(要カスタム)
リリース名とタグ名は同じである(要カスタム)
リリースノートは固定文言にしている(要カスタム)
コミットユーザは「github-actions[bot]」
name: tag_release
on:
push:
branches:
- 'master'
permissions:
contents: write
jobs:
tag_release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: master
- name: Modify Tag Badge
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "===================="
echo "[INFO] To get describe, fech all depth and tags"
git fetch --prune --unshallow
git pull --tags
LATEST_TAG=$(git describe --tags `git rev-list --tags --max-count=1` || echo "v0.0.0")
COMMIT_CNT=0
if [ "$LATEST_TAG" != "v0.0.0" ]; then
COMMIT_CNT=$(git rev-list --count $LATEST_TAG..HEAD)
fi
VERSION=$(echo "$LATEST_TAG" | sed 's/^v//')
echo "===================="
echo "[INFO] latest: $LATEST_TAG"
echo "[INFO] commit cnt: $COMMIT_CNT"
IFS='.' read -r major minor patch <<< "$VERSION"
new_major=0
new_minor=0
new_patch=0
if [ "$COMMIT_CNT" -gt 30 ]; then
new_major=$((major + 1))
elif [ "$COMMIT_CNT" -gt 10 ]; then
new_major=$major
new_minor=$((minor + 1))
else
new_major=$major
new_minor=$minor
new_patch=$((patch + 1))
fi
NEW_TAG="v${new_major}.${new_minor}.${new_patch}"
echo "===================="
echo "[INFO] new tag: $NEW_TAG"
echo "===================="
echo "[INFO] update README.md tag badge..."
#sed -i "s/v0\.0\.0/v${new_major}.${new_minor}.${new_patch}/g" README.md
sed -i "s/v${major}.${minor}.${patch}/v${new_major}.${new_minor}.${new_patch}/g" README.md
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git add README.md
git commit -m "update tag badge $NEW_TAG"
git push origin master
echo "[INFO] done."
echo "===================="
echo "[INFO] create a new tag"
git tag $NEW_TAG
git push --tags
echo "[INFO] create a new release"
gh release create $NEW_TAG -n "release ${NEW_TAG}" -t $NEW_TAG
echo "[INFO] complete all."
これにより、自動リリース作成ができました。
リリースノート(パッチノート)こそ固定文言ですが、これも今までのコミットメッセージからいい感じに作ったりなど
どうにかして充実させることはできそうですね。
毎回のリリースをしたいけど手動で作るのは面倒、という場合
このActionsをいれたのちにPRマージするだけでよいので、とても便利です。
さらに
また、他のActions(cron系やビルド系、ssh接続やメール送信等)や
PR作成時のテンプレートマークダウン、充実したREADME、LICENSE、gitignoreをまとめて
こちらのレポジトリに公開してあります。
ぜひこちらをフォークするなどして、自分なりのテンプレートを作ってみてください。
おわりに
今回は自動リリース作成ができるActionsを紹介してみました。
本来のActionsのCI/CDとしてビルドやSSH接続でのリリース、メールやLINE(notify API)での通知に加え
リリース作成までできれば、もう完璧なんじゃないでしょうか。
PR作成もGitHubCLIでローカルから
gh pr create --base develop --head $(git branch --contains | cut -d " " -f 2) --title "modify" --body ""
等とすれば現在のブランチからdevelopへのPRを作成できますし、その後に
gh browse 数字
でブラウザでPRを開き、マージボタンを押しにいけます。
これらを使いこなして、快適な開発サイクルを構築していきましょう。
ALHについて知る
↓ ↓ ↓ 採用サイトはこちら ↓ ↓ ↓
↓ ↓ ↓ コーポレートサイトはこちら ↓ ↓ ↓
↓ ↓ ↓ もっとALHについて知りたい? ↓ ↓ ↓