概要
本記事では、GitHub ActionsでReleasesを生成する手順を確認した。
RepositoryにあるChangeLogからReleaseの説明文を自動生成する。
はじめに
ソフトウェア開発者 (ユーザ) は、ソフトウェアをリリースする際に幾つかの作業を実施する必要がある。 しかし、それらの作業は、ある程度決められた作業を実施する必要がある。 ヒューマンエラーやユーザの手間を考慮すると、これらの作業を自動化できるとうれしい。
本記事では、GitHubのReleases機能を使用しているプロジェクトを対象とする。
Releases機能は、GitHub上にあるリポジトリと紐づけられていて、リポジトリのタグに対して任意のファイルやメッセージを残すことができる。
この機能を使うユースケースとして、下記の作業が考えられる。
- ユーザは、ChangeLog(または、NEWSなど)に更新点を書き記す。
- ユーザは、任意のコミットにタグを作成する。
- ユーザは、GitHubにあるリモートリポジトリにタグをプッシュする。
- ユーザは、該当リポジトリのパッケージを作成する。
- ユーザは、Releases 機能からメッセージ(リリースノート)の追加や任意のファイル(パッケージ)を添付する。
本記事では、「パッケージを作成する」作業と「Releases 機能」における作業をGitHub Actionsを利用して自動化を目指す。*1
下記は、本記事を適用したときのソフトウェアのリリースするまでの手順を示したものである。
- ユーザは、ChangeLogに更新点を書き記す。
- ユーザは、任意のコミットにタグを作成する。
- ユーザは、GitHubにあるリモートリポジトリにタグをプッシュする。
- GitHub Actionsは、Change Logからメッセージ(リリースノート)の追加とパッケージを生成し、添付する。
本作業は下記のリポジトリのworkflowに導入済みである。本記事では、これを基に説明する。 github.com
本リポジトリでは、automakeを使用しているため、下記のmakeターゲットがデフォルトで用意されている。
make
: ソフトウェアをビルドするmake install
: 成果物をユーザの環境にインストールするmake dist
: 配布用パッケージを生成する (パッケージ名-バージョン名.tar.gz
)
Git-flowは下記のような形式を採用しており、適当なタイミングでtag(図中の灰色吹き出し)を作成している。
このtagが作成されたタイミングで、そのバージョンにおけるパッケージとChangeLogを残すようにしている。
また、図中の白吹き出しはブランチを表している。
- mainブランチ: 製品として常に安定した状態を保つ。
- bugfixブランチ: リリース後に、不具合を修正する。
- developブランチ: 次のリリースに向けた作業をする。
- featureブランチ: 各機能における開発をする。
自動化のための作業
Releases手順の自動化に向けて、あらかじめ以下の作業を完了させておく必要がある。
ChangeLogから変更内容を取得するスクリプトの作成
Releases のリリースノートに記述するための、該当バージョンの更新点をChangeLogから抽出する必要がある。
今回は、下記のようなフォーマットのChangeLogをユーザが作成している場合を考える。
# Changelog ## [1.1.0] - 2020-10-01 ### Added - 新機能C - 新機能D ### Changed - 既存機能Zの修正 ### Removed - 既存機能Yの削除 ## [1.0.1] - 2020-09-11 ### Fixed - 既存機能Xの修正 ## [1.0.0] - 2020-09-01 ### Added - 新機能A - 新機能B
この形式は、第2レベルの見出しに[バージョン] - 日付
が記述されていて、第3レベルの見出しに変更の種類(AddedやChanged)が記述されている。
リリースノートとして必要となるのは、該当バージョンにおける第2レベルの見出し以下の内容となる。
そのため、該当バージョンの第2レベルの見出しの検索とその内容を取得する必要がある。
第2レベルの見出しの検索は^##
でgrepすることで取得できる。
$ grep -n "^## " ChangeLog.md
2## [1.1.0] - 2020-10-01
13:## [1.0.1] - 2020-09-11
17:## [1.0.0] - 2020-09-01
ここから、awk
コマンドでパターンマッチを行い、該当バージョン(VERSION
)内容の先頭と末尾の行番号を取得する。
$ grep -n "^## " ChangeLog.md |\
awk -F: -v version=${VERSION} '/'"${VERSION}"'/ \
{ start = $1 + 1; getline; end = $1 - 1 } \
END { print start, end }' )
sed -n ${sline},${eline}p ${FILE}
例えばv1.1.0の場合、先頭は3行目、末尾12行目が得られる。
ここから、ChangeLogの3行目から12行目を表示することで該当バージョン(v1.1.0)の変更内容を取得できる。
上記の内容を踏まえて、下記のようなChangeLogから変更内容を取得するスクリプトget_changelog.shを用意する。
#!/bin/bash FILE=CHANGELOG.md VER=`echo $1 | tr -d "refs/tags/"` # i.e. v1.0, v20.15.10 VERSION=`echo ${VER} | tr -d v` # i.e. 1.0, 20.15.10 read sline eline <<< \ $( grep -n "^## " ${FILE} | \ awk -F: -v version=${VERSION} '/'"${VERSION}"'/ \ { start = $1 + 1; getline; end = $1 - 1 } \ END { print start, end }' ) sed -n ${sline},${eline}p ${FILE}
Releases 機能を自動的に設定するworkflowの作成
タグのプッシュを契機に、Releases 機能を自動的に設定するworkflowの作成する必要がある。
GitHubでは、Releasesを生成するActions と ReleasesにファイルをアップロードするActionsが用意されている。
create-releaseを利用して、Markdownファイルで記述されたリリースノート(body.md
)からReleasesの作成する場合には下記のように記述する。 (Example workflowを参照)
- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }} # Releasesのタイトル (i.e. Release v1.0.0)
body_path: "body.md" # Releasesのリリースノート
draft: false
prerelease: false
upload-release-assetを利用して、ファイルをアップロードする場合も同様にExample workflowが用意されているのそれに従って記述する。
ただし、Automakeで生成される配布物パッケージ名はパッケージ名-バージョン名.tar.gz
となっており、可変のファイル名である。
upload-release-assetはアップロードするファイルの名前に正規表現をサポートしていないため、Example workflowに一工夫しなければいけない。
コミュニティで提案されているのは、前のステップにて該当ファイルを環境変数に代入する方法である。
- name: Get Name of Artifact
run: |
ARTIFACT_PATHNAME=$(ls debugfatfs-*.tar.gz | head -n 1)
ARTIFACT_NAME=$(basename $ARTIFACT_PATHNAME)
echo "ARTIFACT_NAME=${ARTIFACT_NAME}" >> $GITHUB_ENV
echo "ARTIFACT_PATHNAME=${ARTIFACT_PATHNAME}" >> $GITHUB_ENV
- name: Upload Release Asset
id: upload-release-asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ${{ env.ARTIFACT_PATHNAME }}
asset_name: ${{ env.ARTIFACT_NAME }}
asset_content_type: application/gzip
上記のActionsを用いて、Releases 機能を自動的に設定するworkflowを用意する。
name: Create Releases on: push: tags: - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10 jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: setup environment # パッケージ生成のための環境構築 run: | sudo apt-get update sudo apt-get install autoconf automake libtool help2man make - run: script/bootstrap.sh - run: ./configure - run: make - run: make dist # 配布物パッケージの生成 i.e. debugfatfs-0.1.0.tar.gz env: CI: true - run: | # 更新内容を一時的にbody.mdとして保存しておく ./get_changelog.sh ${{ github.ref }} > body.md - name: Create Release id: create_release uses: actions/create-release@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: tag_name: ${{ github.ref }} release_name: Release ${{ github.ref }} # Releasesのタイトル (i.e. Release v1.0.0) body_path: "body.md" # Releasesのリリースノート draft: false prerelease: false - name: Get Name of Artifact run: | ARTIFACT_PATHNAME=$(ls debugfatfs-*.tar.gz | head -n 1) # 正規表現で成果物パッケージのファイル名を取得する ARTIFACT_NAME=$(basename $ARTIFACT_PATHNAME) echo "ARTIFACT_NAME=${ARTIFACT_NAME}" >> $GITHUB_ENV # 成果物パッケージのファイル名の環境変数に設定する echo "ARTIFACT_PATHNAME=${ARTIFACT_PATHNAME}" >> $GITHUB_ENV - name: Upload Release Asset id: upload-release-asset uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} asset_path: ${{ env.ARTIFACT_PATHNAME }} asset_name: ${{ env.ARTIFACT_NAME }} asset_content_type: application/gzip
実行例
- CHANGELOG.mdを更新する。
# Changelog ## [0.1.0] - 2020-10-24 ### Added - Print main Boot Sector field - Print any cluster - Print Directory list - Backup or restore FAT volume - Convert into update latter - Create file - Remove file - Change any FAT entry - Change any allocation bitmap - Trim deleted directory entry ## Initial Version
tag (v0.1.0)を作成し、リモートリポジトリにプッシュする。
$ git tag v0.1.0 $ git push origin --tags
おわりに
本記事では、ユーザがタグを作成したタイミングでChangeLogからReleasesを自動的に生成するworkflowを作成した。
この手順では、ChangeLogの生成がユーザの手作業で書き記す必要があるが、制度の良いcommitを生成しているのであればこの作業も自動化しても良いだろう。 今回は、正規表現を利用してアップロードファイルを指定しているのでひと手間かかったが、GitHub Actionsは様々なworkflowが用意されているので、任意の作業の自動化が容易である。
このように作業の自動化が容易であるため、定型的な作業がGitHub Actions (などのサービス)を利用して可能な限り自動化していくとよい。
変更履歴
- 2020/10/25: 記事公開
参考
- Git tagとGitHub ReleasesとCHANGELOG.mdの自動化について | Web Scratch
- リリースやリリースノートを自動的に生成するツールのお話
- GitHub Actionsでpush→試験、バージョンタグ→リリース用意、リリース→デプロイを自動化したよ。 | Ginpen.com
- GitHub Actionsでリリースを自動化したお話
- GitHub ActionsでReleaseを自動化する方法としたときに得た学び | sKawashima's blog
- GitHub Actionsでリリースを自動化したお話
- Keep a Changelog
- 良いChangeLogを書くための方法
- セマンティック バージョニング 2.0.0 | Semantic Versioning
- バージョン番号の管理方法の一つ