- はじめに
- GitHub Actions の構成
- ワークフローの構成
- アクション
- ワークフローの作成
- アクションの指定方法
- ワークフロー サンプル
- トリガの指定
- 依存のキャッシュ
- コンテキスト
- 環境変数
- Secrets
- Build Matrix
- アーティファクト
- ジョブの依存関係
- ステータスバッチ
はじめに
GitHub Actions は、GitHub 上のリポジトリの操作に応じて、任意のタスクを自動実行できる機能です。
CircleCI や Travis CI といった継続的インテグレーション・継続的デリバリーのサービスと同様ですが、GitHub 内で完結でき、追加投資なしで利用できる点が魅力です。Free プランの場合は月に 2,000 分の実行時間が無料枠となっています。
2019年11月に一般公開で いまさら感はあるものの、適当な粒度の説明がヒットしないためここにまとめます。
GitHub Actions の構成
GitHub Actions は、リポジトリの .github/workflows
にチェックインした YAML形式のファイルで定義します。このファイルをワークフローと呼びます。
ワークフローは自動化したいジョブの集合であり、複数のワークフローをリポジトリに登録できます。Actions タブには、リポジトリのワークフローが一覧され、実行履歴が参照できます。
ワークフローは GitHub上の操作をトリガに自動実行できる他、スケジュールに応じた自動実行も可能です。
ワークフローの構成
ワークフローは .github/workflows
にYAML形式のファイル(.yml
.yaml
)で定義します。リポジトリには複数のワークフローを持つことができ、それぞれのワークフローで異なる処理を実行できる他、ワークフローの中で別のワークフローを参照することもできます。
ワークフローファイルの基本的な構成は以下のようになります。
name: Greeting Workflow # ワークフロー名 on: [push] # トリガーとなる GitHub イベント jobs: job1: # ジョブ名 runs-on: ubuntu-latest # ジョブの実行環境(runner) steps: # ジョブのステップ - name: Greeting run: echo "Hello, world!"
on:
では、ワークフローのトリガーとなる GitHub イベントの名前を指定します。上記例では、リポジトリへの push によりこのワークフローを実行する定義になります。
jobs:
以下にはワークフローで実行するジョブを定義します。
ワークフローは複数のジョブを持つことができ、それぞれのジョブは並行して実行されます(needs:
によりジョブ間の依存関係を定義すれば、順次実行させることもできます)。
上記例では job1
という名前のジョブを1つだけ定義しています。
runs-on:
でランナーを指定します。ランナーとは、このワークフローを実行するサーバであり、上記では Ubuntu を指定しています。
Windows や macOS の runner も提供されていますし、自身でホストしたものを利用することもできます。
steps:
配下に、このジョブで実行する複数の手続きを配列形式で定義します(各ステップ(配列の要素)は -
で始めます)。
上記例では、Greeting という名前で、「Hello, world!」 と出力する1つのステップを定義しています。
run:
はオペレーティングシステムのシェルを使ってコマンドラインプログラムを実行します。
ワークフローは、並行実行されるジョブの集合であり、各ジョブには直列実行される複数のステップ(コマンドの実行や、後述するアクションの実行)を含むという構成になります。
アクション
頻繁に繰り返される複雑なタスクは、GitHub Actions プラットフォームで、アクションとして事前定義されています。また、GitHub Marketplace で提供されるサードパーティ製のアクションを利用することもできます。
ジョブの中でアクションを使うことで、ワークフローファイルのコード量を削減することができます。
例えば、ジョブで利用するリポジトリをチェックアウトするには actions/checkout
というアクションが提供されています。uses
キーワードを使いアクションを実行することができます。
steps: - uses: actions/checkout@v2
@v2
はアクションのバージョン番号です(これについては後述します)。
Java 実行環境を設定する actions/setup-java
というアクションは以下のように指定します。
steps: - name: Set up JDK 17 uses: actions/setup-java@v2 with: java-version: '17' distribution: 'adopt'
with:
でこのアクションのパラメータを指定します。上記では、AdoptOpenJDK の バージョン17 を指定しています。それぞれのアクションで有効なパラメータは、アクションの README を参照します。
Github から提供されるアクションは GitHub Actions のリポジトリで管理されており、一例とし以下のようなものがあります。
- checkout リポジトリからファイルをチェックアウト
- cache 生成物をキャッシュして処理を高速化
- labeler GitHub上でのラベルを管理ファイル .github/labeler.ymlを作成
- github-script GitHub APIを使ってGitHubの各種機能にアクセス
- upload-artifact 指定したファイルを artifact として保存
- download-artifact artifact として保存されているファイルをダウンロード
- setup-java Java 環境のセットアップ
- setup-node Node 環境のセットアップ
- setup-go Go 環境のセットアップ
- setup-python Python 環境のセットアップ
この他、多数のアクションがあり、自身で定義したり GitHub Marketplace から探すこともできます。
ワークフローの作成
ワークフローは、ローカルで作成して Push することもできますが、Actions タブの「New workflow」から画面上で操作することもできます。
テンプレートの選択画面になるので、テンプレートを選択するか、「set up a workflow yourself →」でワークフローの編集画面に遷移します。
以下のように画面上でワークフローを登録することができます。
エディタ上では構文チェックも行われます。
Marketplace サイドバーを使用してアクションを参照できます。
バッジが付いたアクションは、GitHubがアクションの作成者をパートナー組織として確認したことを示します。
アクションの指定方法
アクションは以下で定義されたものを使うことができます。
- 公開リポジトリ
- ワークフローファイルがアクションを参照するのと同じリポジトリ
- DockerHubで公開されたDockerコンテナイメージ
それぞれの指定方法は以下のようになります。
- パブリックリポジトリのサブディレクトリのアクション
{owner}/{repo}/{path}@{ref}
- 例:
uses: actions/aws/ec2@main
- ワークフローディレクトリに配備したアクション
./path/to/dir
- 例:
uses: ./.github/actions/my-action
- リポジトリをチェックアウトする必要あり
- DockerHubアクション
docker://{image}:{tag}
- 例:
uses: docker://alpine:3.8
- GitHubパッケージコンテナレジストリ
docker://{host}/{image}:{tag}
- 例:
uses: docker://ghcr.io/OWNER/IMAGE_NAME
アクションのバージョン指定は Git ref、SHA、またはDockerタグ番号が利用できます。
actions/checkout
を例にすれば、以下のようなバージョン指定が考えられます。
steps: # 特定のコミット SHA - uses: actions/checkout@a81bbbf8298c0fa03ea29cdc473d45769f953675 # 特定バージョンの参照 - uses: actions/[email protected] # メジャーバージョンの参照 - uses: actions/checkout@v2 # ブランチの参照 - uses: actions/checkout@main
@main
のように指定した場合、アクションが不用意に更新され、ワークフローが予期しない動作をする可能性があります。
@v2.2.0
のように指定した場合、重要な修正とセキュリティパッチを受け取ることができない可能性があります。
サードパーティーの提供するアクションに、悪意のある更新がなされるリスクを考慮すれば、リリースされたバージョンのコミットSHAを指定することが最も安全です。
よって、信頼できるアクションについては、@v2
のようにメジャーバージョンを指定し、サードパーティー製の信頼できないアクションについてはリリースバージョンのコミットSHA を利用するのが良いかと思います。
GitHub Marketplace で 「Verified creator」 のバッジは、GitHub により身元が確認されたチームによって作成されたアクションとなるため、これを参考にするのも良いでしょう。また、GitHub に統合された Dependabot を ON にすれば、依存ライブラリの更新に応じて PR が自動作成されるようになるため、これをトリガとして更新を検討するという運用もありかもしれません。
ワークフロー サンプル
ワークフロー全体のサンプルとして、Gradle による CI を行う例は以下のようになります。
name: Java CI on: [push, pull_request] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Set up JDK 11 uses: actions/setup-java@v2 with: java-version: '11' distribution: 'adopt' - name: Validate Gradle wrapper uses: gradle/wrapper-validation-action@v1 - name: Build with Gradle run: ./gradlew build
push
pull_request
をトリガにしてワークフローを実行actions/checkout
でランナーに対象のブランチをチェックアウトactions/setup-java
で Java の実行環境を作成gradle/wrapper-validation-action
でgradle-wrapper.jar
のチェックサムの妥当性を検証- コマンドラインで
./gradlew build
テストとビルドを実行
トリガの指定
リポジトリ内の任意のブランチにコードがプッシュされたときに起動
on: push
ブランチ指定のプッシュ
on: push: branches: [ master ]
プッシュまたはプルリクエストイベントで起動
on: [push, pull_request]
ブランチを指定したプッシュまたはプルリクエスト、ページビルドとリリース作成イベントで起動
on: push: branches: - main pull_request: branches: - main page_build: release: types: - created
毎日UTCの1:00に起動
on: schedule: - cron: "0 1 * * *"
ワークフローを手動でトリガーできるようにするには、workflow_dispatch イベントを構成する必要があります。
on: workflow_dispatch
ブラウザ画面から、または GitHub API の場合は以下でワークフローを実行できます。
curl -L \ -H "Accept: application/vnd.github+json" \ -H "Authorization: Bearer <YOUR-TOKEN>" \ -H "X-GitHub-Api-Version: 2022-11-28" \ https://api.github.com/repos/<OWNER>/<REPO>/actions/runs/RUN_ID
依存のキャッシュ
ビルド時の依存はキャッシュを利用することで高速化が可能です。
これには、actions/cache
を使い、例えば npm の依存をキャッシュするには以下のようになります。
steps: - name: Cache node modules uses: actions/cache@v2 env: cache-name: cache-node-modules with: path: ~/.npm key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} restore-keys: | ${{ runner.os }}-build-${{ env.cache-name }}-
ただし、現在では、大抵のケースで setup-*
アクション側でキャッシュ可能となっています。
例えば、actions/setup-java
で gradle を使う場合は以下のようにすることでキャッシュが有効になるため、actions/cache
を自身で利用する必要はありません。
steps: - uses: actions/checkout@v2 - uses: actions/setup-java@v2 with: java-version: '11' distribution: 'adopt' cache: 'gradle' - run: ./gradlew build
GitHubは、7日以上アクセスされていないキャッシュエントリを削除します。
コンテキスト
コンテキストは、ワークフローの実行、ランナー環境、ジョブ、およびステップに関する情報にアクセスするための方法です。
コンテキストには以下の構文を使用してアクセスできます。
${{ <context> }}
例えば以下のようなものを参照できます。
- run: echo "triggered by a ${{ github.event_name }} event" - run: echo "running on a ${{ runner.os }} server" - run: echo "branch is ${{ github.ref }} and repository is ${{ github.repository }}" - name: Check out repository code uses: actions/checkout@v2 - run: echo "${{ github.repository }} repository has been cloned" - name: List files in the repository run: | ls ${{ github.workspace }} - run: echo "This job's status is ${{ job.status }}."
どのようなものがあるかはコンテキストを参照してください。 なお、コンテキストはタスクの実行状況により、アクセスできるものとできないものがあるため注意が必要です。
${{ }}
には式を書くことができ、例えば、以下のようにジョブのステータスを判断することもできます。
steps: ... - name: The job has succeeded if: ${{ success() }}
環境変数
ワークフローでは環境変数を利用できます。
GitHub が定義するデフォルトの環境変数に加え、独自の環境変数を定義することもできます。
環境変数は、ワークフロー全体(env
)、ジョブ別(jobs.<job_id>.env
)、ステップ別(jobs.<job_id>.steps[*].env
) で定義できます。
以下の例では、ジョブの環境変数 DAY_OF_WEEK
と、ステップの環境変数 FIRST_NAME
Last_Name
を定義しています。
jobs: weekday_job: runs-on: ubuntu-latest env: DAY_OF_WEEK: Mon steps: - name: "Hello world when it's Monday" if: ${{ env.DAY_OF_WEEK == 'Mon' }} run: echo "Hello $FIRST_NAME $Last_Name, today is Monday!" env: FIRST_NAME: Mona Last_Name: Octocat
GITHUB
では始まる名前は、デフォルトの環境変数で利用されるため利用できません。
ファイルシステム上の場所を指すように設定する新しい環境変数には、_PATH接尾辞を付ける必要があります。
Secrets
Settings - Secrets から、特定の名前で secret を作成しておけば、秘密鍵をワーフクローファイルに直書きすることなく、安全に利用できます。
ワークフローファイルでは ${{ secrets.<シークレット名> }}
のように secrets コンテキストから取得できます。
steps: - shell: bash env: SUPER_SECRET: ${{ secrets.SuperSecret }} run: | example-command "$SUPER_SECRET"
Build Matrix
異なるOS、異なるプラットフォームの組み合わせでテストを実行したいケースにはビルドマトリックスが使えます。
ビルドマトリックスは strategy
配下にビルドオプションを配列として定義します。
以下の例では、os と node のバージョン別で6つのジョブのマトリックスを作成している例になります。
runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-18.04, ubuntu-20.04] node: [10, 12, 14] steps: - uses: actions/setup-node@v2 with: node-version: ${{ matrix.node }}
アーティファクト
同じワークフローのジョブ間でデータを共有するにはアーティファクトを使うことができます。
アーティファクトはワークフローの実行中に生成されたファイルまたはファイルのコレクションです。 ジョブ内でアーティファクトをアップロードしておくことで、他のジョブでアーティファクトをダウンロードして利用することができます。
アーティファクトを操作するために actions/upload-artifact
actions/download-artifact
が提供されています。
job1 でファイルをアップロードし、
jobs: job1: name: Save output steps: - shell: bash run: | expr 1 + 1 > output.log - name: Upload output file uses: actions/upload-artifact@v2 with: name: output-log-file path: output.log
job2 でファイルをダウンロードして利用することができます。
jobs: job2: steps: - name: Download a single artifact uses: actions/download-artifact@v2 with: name: output-log-file
アップロードしたアーティファクトは、同じワークフローからであれば、前回保存時のアーティファクトを利用できます。
保存されたアーティファクトは、ワークフローの実行履歴画面から照会できます。保持期間はデフォルトで90日となっています。
ジョブの依存関係
ジョブは、デフォルトで並列実行されます。ジョブ間に依存関係を定義するには needs
を使います。
jobs: build: test: needs: build release: needs: [build, test]
build -> test -> release の順で動作します。
ステータスバッチ
各ワークフローのステータスバッチは、「Create status badge」から作成できます。
様々なイベント用のバッチがあります。
作成された内容をコピーして README.md に貼り付けることでステータスバッチが表示できます。