morishitaです。
当社で最も開発が活発なリポジトリはメインサービスであるいこーよのものです。 毎日、いくつものプルリクエストが登録されてはリリースされクローズしてきます。
プルリクエストの状態や重要度はラベルで表しています。
例えば次のようなラベルがあります。
リポジトリごとにラベルとその色がまちまちだと状況を把握しにくいので、いこーよ以外のプロダクトも概ね同じラベルを登録して使っています。
これまでいこーよのリポジトリに揃えるべくそれぞれのリポジトリでちまちま手で設定をしてきました。
しかし、このところ Github にいくつか新たなリポジトリを作る機会があり、 流石に面倒なので複数のリポジトリのラベルを一元的に管理できる仕組みを作ってみました。
作ったもの
次のようなYAMLファイルで定義されたラベルを複数のリポジトリに適用するGithub Action とそれを使ったワークフローを作りました。
# ラベルの定義 labels: - name: "WIP" description: "作業中" color: "d4c5f9" - name: "レビュー待ち" description: "レビュー待ち" color: "bfe5bf" - name: "プログラマレビュー待ち" description: "レビュー待ち" color: "bfe5bf" - name: "デザイナレビュー待ち" description: "レビュー待ち" color: "bfdadc" - name: "レビュー修正待ち" description: "指摘事項を修正してください" color: "fef2c0" - name: "Ship it!" description: "リリースしましょう" color: "c7def8" - name: "dependencies" description: "Pull requests that update a dependency file" color: "0366d6" - name: "bug" description: "Something isn't working" color: "d73a4a" # リポジトリ毎のラベル設定 repos: - name: actindi/repo1 # labels で定義したラベルから設定する labels: - WIP - レビュー待ち - レビュー修正待ち - Ship it! - dependencies - name: actindi/repo2 labels: - WIP - プログラマレビュー待ち - デザイナレビュー待ち - レビュー修正待ち - Ship it!
labels
以下でラベルそのものを次の項目で定義します。
name
description
color
name
がキーになります。
repos
以下ではそれぞれのリポジトリのラベルを設定しています。
labels
以下で定義したラベルから各リポジトリで必要なものを選択します。
実際にラベルを設定する処理にはgithub-labelerを利用しています3。
これは Golang で作られたCLIツールで、YAML通りにラベルの登録、更新、削除を行ってくれます。
dry-run の機能も備えています。
Github Actions で実行する
github-labeler を実行する仕組みである Github Action について説明します。
Github Action の作成
今回のGihub Actionを構成するファイルは次の3つ。
/ └ .github/ └ actions/ ├ action.yml ├ Dockerfile └ entrypoint.sh
まずは Github Action の定義ファイル actions.yml は次のとおりです。
name: 'Github Labeler' description: 'Githubリポジトリのラベルを一斉に作成・変更・削除します' author: 'actindi' inputs: github_token: description: 'GITHUB_TOKEN.' required: true manifest: description: 'YAML file to be described about labels and repos.' required: false default: 'labels.yaml' dry_run: description: dry run flag required: false default: 'false' runs: using: 'docker' image: 'Dockerfile' args: - ${{ inputs.github_token }} - ${{ inputs.manifest }} - ${{ inputs.dry_run }} branding: icon: 'alert-octagon' color: 'blue'
inputs で次の3つのパラメータを定義しました。
- github_token: ラベル編集APIを使うためのGithubトークン
- manifest:前述のラベル定義YAMLファイルのパス(デフォルト値はlabels.yml)
- dry_run:dry-run か否かのフラグ。
runs 以下は処理の実行系についての定義ですが、見ての通りアクションの実行は Docker で行います。
そのためのDockerイメージをビルドする Dockerfile は次のとおりです。
FROM golang:1.13-alpine AS builder RUN set -eux; \ apk add --no-cache --virtual .build-deps git RUN go get github.com/b4b4r07/github-labeler FROM alpine COPY --from=builder /go/bin/github-labeler /usr/bin/github-labeler COPY entrypoint.sh /entrypoint.sh ENTRYPOINT ["/entrypoint.sh"]
マルチステージビルドでイメージを極力小さくしています。
そしてエントリポイントとなるスクリプトは社内ツールということでちょっと雑ですが次の通りです。
#!/bin/sh cd "$GITHUB_WORKSPACE" export GITHUB_TOKEN=${INPUT_GITHUB_TOKEN} if [ ${INPUT_DRY_RUN} = 'true' ] ; then github-labeler -manifest ${INPUT_MANIFEST} -dry-run > results.txt RUN_RESULT=$? else github-labeler -manifest ${INPUT_MANIFEST} > results.txt RUN_RESULT=$? fi echo '' echo '## RESULTS ##################################' cat results.txt exit ${RUN_RESULT}
actions.yml で定義したパラメータはプレフィックス INPUT_
の環境変数からそれぞれ取得できる仕組みとなっています(Github Action の仕様)。
INPUT_DRY_RUN
が true
ならば dry-run で実行、それ以外では実際にラベルを更新します。
ワークフロー
上記のActionを利用したワークフローについて説明します。
前述のYAMLファイルを管理するリポジトリで、プルリクエストを作ると dry-run で実行して結果を示し、masterにマージすると実際に適用するようにしました。
そのためにワークフローは次の2種類を用意しました。
- dry-run.yml : プルリクエストにPushするたびに実行する
- apply.yml : masterにマージしたときに実行する
dry-run.yml
dry-run.yml は次のとおりです。
name: github-labeler on: pull_request: types: [opened, synchronize] jobs: github-labeler: name: dry-run runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - name: github-labeler uses: ./.github/actions/github-labeler with: github_token: ${{ secrets.admin_token }} dry_run: true
プルリクエストを作成したとき、コミットをPushしたときに実行されるトリガーを設定しています。
uses: ./.github/actions/github-labeler
で同じリポジトリで定義されている先程のアクションを利用するよう指定しています。
Gihubのドキュメントではパブリックな公開アクションを利用する例の説明が多く、同じリポジトリで定義したプライベートなアクションを利用する方法がわかりにくいのですが。この様に相対パスでアクション定義のディレクトリを指定すれば良いです。
プルリクの段階ではまだラベルを変更したくないので dry_run: true
として dry-run にて実行し、結果を確認できるようにしています。
apply.yml
そして、apply.yml は次のとおりです。
name: github-labeler on: push: branches: - master jobs: github-labeler: name: apply runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - name: github-labeler uses: ./.github/actions/github-labeler with: github_token: ${{ secrets.admin_token }}
トリガーon.push.branch[master]
は master にPushしたときに実行されるということです。
これでマージしたときにも実行されます。
実行すると dry-run ではないので、実際に適用します。
Github トークンについて
Github Actionのワークフローでは secrets.github_token
に自動的にトークンが設定されます。それを使ってGithubのAPIを叩いたりできる様になっています。
ただし、このトークンのスコープはワークフローを実行するリポジトリのみとなっています。
今回の場合、別のリポジトリのラベルの編集をしたいのでこれでは足りません。
そのため、以前からCI専用に使っているユーザの Personal access token をadmin_token
という名前でリポジトリの Secrets に登録して使っています。
CI専用のユーザが Collaborators として追加されているリポジトリのラベルの編集を行うことができます。ラベルを変更するのですが、admin 権限は不要で write 権限のみで OK です。
実行の様子
プルリクエストにPushすると、ワークフローが実行され次のような表示で結果が示されます。
矢印で示したDetailsリンクをたどると次のように実行ログが参照でき、そこから実行結果を見ることができます。
上の画像はdry-runの結果ですが、適用するとどのラベルが作られるのか、あるいは変更・削除されるのかを確認できます。
まとめ
今回は、Githubのラベルを宣言的に定義できるツールを作成して、複数リポジトリの運用をちょっぴり便利にしてみました。
Github Action の作り方を学んでおきたいという個人的欲求も満たされました。
最後に
アクトインディではエンジニアを募集しています。 actindi.net
-
アクトインディではデザイナーがJS以外のフロントエンドをコーディングするのでデザイナーもPRを作って、レビューして、リリースしていきます。↩
-
Dependabotが作るPRにつけられるラベルです。↩
-
実はこのライブラリの作者はもうこのCLIツールをメンテナンスする気はなさそうです。Investigate similar projectで別のツールを使ったほうがいいと言っています。しかし、紹介されているツールはリポジトリごとにラベルの定義自体を行う形式のようです。やりたいのは定義を一元管理して、各リポジトリで利用するラベルを設定すること(定義は一つ、利用は複数リポジトリ)なのでgithub-labelerを使うことにしました。↩