oinume journal

Scratchpad of what I learned

GitHub ActionsでReleaseが作成されたら次のバージョンのrelease branchを自動的に作る

はじめに

  • 自分のチームではA successful Git branching modelに近い感じで、リリースする前にrelease branchを作りそこにfeature branchをmergeしてからテストしてリリースする、という流れで開発からリリースまでのサイクルを回している。
  • リリースする前に誰かがrelease branchを作成するという作業が手間だったため、GitHub Actionsで自動化できないかと思い、実際やってみたところ意外と簡単にできたので、そこで得られた知識をこの記事にまとめる

実際のコードと説明

それでは実際のactionsのYAMLファイルをもとに細かく説明する。今回使用したYAMLファイルはここにあがっている。

on でフックしたいイベントを定義する

GitHub Actionsを作成すると、.github/workflows/xxx.yml が作成される。まずこのYAMLに定義するべきものがonである。これはワークフローを実行するためのトリガーの定義である。今回の例だと以下のように、releaseがpublish(公開)されたらワークフローを動かすようにしている。

on:
  release:
    types:
      - published

他にも branchにpushされたら、pull-requestが作成されたらなどをトリガーすることができる。詳細は以下の公式ドキュメントで詳しく説明されている。

jobsで実行する処理を定義する

jobsの下に行いたい処理の名前(job_id)を書いて、その下に行いたい処理を記述していく。

  • runs-on: 実行するmachine typeを指定する。指定できるmachine typeについては公式ドキュメントに書いてある
  • stepにはusesrunが定義できる
    • uses: 他のGitHub Actionsを使う
    • run: コマンドをshellで実行する。

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2

環境変数のセット

何かしら計算した結果を保存して、次のstepで参照できるようにしたいことがある。そういう場合は環境変数をセットする。

    steps:
    ...
    - name: Create local changes
      run: |
        CURRENT_VERSION=$(echo $GITHUB_REF | sed 's/refs\/tags\///')
        echo "CURRENT_VERSION = $CURRENT_VERSION"
        NEXT_VERSION=$(echo $CURRENT_VERSION | perl -ne 'if ($_ =~ /^(\d+)\.(\d+)\.\d+$/) { $v = $2; $v++; print "$1.$v.0\n" } else { print "Invalid tag format."; exit 1 }')
        echo "NEXT_VERSION = $NEXT_VERSION"
        echo "::set-env name=NEXT_VERSION::$(echo $NEXT_VERSION)"

例えば上記のコードは以下の処理を行っている。

  1. GITHUB_REFにあるタグの値(refs/tags/0.1.0)を取得
  2. そこからバージョン部分を抜き出してCURRENT_VERSIONにセット
  3. perlで次のバージョンにインクリメントしてNEXT_VERSIONにセット
  4. ::set-envを使って環境変数NEXT_VERSIONをセット

構文が気持ち悪いが、set-envを使うことで環境変数をセットすることができ、後続のstepで参照することができる。

secrets

    steps:
    ...
    - name: Create a pull request with a new release branch
      uses: peter-evans/create-pull-request@v2
      with:
        token: ${{ secrets.GITHUB_TOKEN }}
        branch: release/${{ env.NEXT_VERSION }}
        base: master
        title: "Release ${{ env.NEXT_VERSION }}"
        body: "## Pull-requests in this release\n- TBD"

上記のコードはpull-requestを作る例だが、GitHub上のリポジトリに対して何か操作を行う場合はGitHubのTokenが必要になる。そういう場合は secrets に定義されているGITHUB_TOKENを使用する。また、secretsはリポジトリの設定画面から自分で値をセットすることもできるので、秘匿したい文字列などはsecretsを通してstep内で使用するのが良い。

GitHub Actionsの良いところは、デフォルトのsecretsとしてGITHUB_TOKENが定義されていて、GitHubのリポジトリに対して操作を行う場合はTokenのことを気にする必要がないことだと思う。

contexts, expressions, functions

GitHub ActionsのYAMLでは式を書くことができる。例えば以下のコードはpeter-evans/create-pull-request@v2の引数としてbranch: release/${{ env.NEXT_VERSION }} を渡しているが、{{ ... }}の中には式を書くことができる。

    - name: Create a pull request with a new release branch
      uses: peter-evans/create-pull-request@v2
      with:
        token: ${{ secrets.GITHUB_TOKEN }}
        branch: release/${{ env.NEXT_VERSION }}
        base: master
        title: "Release ${{ env.NEXT_VERSION }}"
        body: "## Pull-requests in this release\n- TBD"

また、この式の部分では env のようなあらかじめ定義されているcontextsが使える。他にどのようなcontextsがあるかはドキュメントを読むと良い。

さらに、あらかじめ定義されたfunctionsがあり、expressionの部分で呼び出すことが可能である。

GitHub Actions Marketplace

GitHub Marketplace · Actions to improve your workflow · GitHubを見るとたくさんのActionがあることがわかると思う。他の人が作った汎用的なActionがたくさん転がっているので、これを見ているだけでも「ああこんなこともできるのか」と参考になるし、いろいろ組み合わせて面倒な作業を自動化することができる。

まとめ

エンジニアの業務であるコードを書く、コードレビュー、リリースに関連した作業を自動化するならGitHub Actionsはとてもオススメ。