tech.guitarrapc.cóm

Technical updates

GitHub Actions ことはじめ

GitHub Actions以前調べたのですが、いろいろあって個人プロジェクトでサクッとビルドするのみに使っていました。 今回改めて調べを進めたのでメモ。

幾つかのリポジトリをGitHub Actionsに移行したけど、記事にしようとまとめていたらやった内容以上に調べてめちゃめちゃ時間かかった。

TL;DR

  • とりあえず公式ドキュメント読めばok

Quickstart for GitHub Actions

  • 公式ドキュメントにないのはだいたいフォーラムみればok

GitHub Community - Discussion

  • 基本はAzure pipelineだけど、結構使いやすい感じになってる
  • Azure Pipelinesと違って、stepのnameを省略するとコマンドがそのまま表示されるのでnameは基本省略で行ける。 (これ重要)
  • public repoならGithub Actionsもいい感じ。WindowsやmacOS依存はこっちに移植する
  • private repoは、GitHubを新料金プランにしているか次第。CircleCIのPerformance Planのユーザー課金が納得いかないのでこっちに移行していきたい
  • クラウドホストランナーが基本でよさそうだけど、Kubernetes上でのCDを考えるとセルフホストわんちゃんある
  • AppVeyorでやってたことはほぼ移行できる
  • CircleCIもだいたい行ける。Orbだけ代替あるかが問題になるぽ

トレンド

GitHub Actionsの今のスタイルがブログでアナウンスされた2019/Aug/8ぐらいからトレンド上がってるんですね。

github.blog

github.blog

世界

日本

USA

GitHub Actions の基本

基本的な情報を裏取りする。

使用条件

  • Orgは新GitHub Pricingに移行していること (旧プランの場合Actions自体使えない)

旧プランで使えないのは、最近のGitHubの新サービスによくあることですが、なるほど困るケース結構多いです。

旧プランと新プランは、リポジトリ数課金or人数課金の違い。 小規模な会社で30リポジトリ100ユーザーとかだと、新旧で桁が違うレベルで料金が変わるため移行に踏み切れないのはままある。

  • 旧プランは、人数無制限、リポジトリ数で段階的なプラン選択
  • 新プランは、人数課金、リポジトリ数制約なし

旧プランのほうがお得なケースは多数あってなかなか新プランに移行が難しいケースも見かけるので難しい。とはいえ、新プラン一択でしょう。

使用制限

並列数やAPI、実行時間で制限がある。

Usage limits, billing, and administration

  • 1リポジトリあたりの同時並列は20(Free)、40(Pro)、60(Team)、500(Enterprise)
  • 1時間当たりリポジトリの全アクションで1000 APIリクエスト
  • ワークフローは実行時間6時間が上限 (指定しないと6時間たつまでタイムアウトしないので長すぎ)
  • 無料、有料で同時実行上限がある
GitHub plan Total concurrent jobs Maximum concurrent
macOS jobs
Free 20 5
Pro 40 5
Team 60 5
Enterprise 500 (以前は180) 50 (以前は15)

マイニングがダメとかその辺は当然あるので見ておきましょう。 Serverless Computingがダメなのもそれはそうなんだけど、いい感じにやってみた的にやりそうな人も出てきそうなので規約でしばるのでいいですね。

料金

OSSは無料で並列度高いので気軽に利用できていい感じ。CircleCIより緩くてAzure PipelineやTravis並みに楽。

会社などPrivate Repoだと、Teamでも3000min/month (旧:10000min/month) しかつかないので、十分ではなく追加購入必要になる感じ。 従量課金の体系はシンプルで、GitHubユーザー課金ある前提と合わせて追加なので、もともとGitHub使ってたこと考えるとCircleCIのPerformance Planより納得度は圧倒的にある。だからこそ新料金プランに限定するんでしょうが。

github.co.jp

About billing on GitHub

  • パブリックリポジトリ : 無料
  • プライベートリポジトリ : 含まれる利用時間 + 追加購入

含まれる利用時間

利用時間は毎月リセットされるけど、ストレージはリセットされない。

2020/4/13までは以下でしたが、2020/4/14~ 変更になりました。

~2020/4/13プラン 1か月あたり利用時間 ストレージ
Free 2,000分 500 MB
Pro 3,000分 1 GB
Team 10,000分 2 GB
Enterprise 50,000分 50 GB
2020/4/13~プラン 1か月あたり利用時間 ストレージ
Free 2,000分 500 MB
Team 3,000分 2 GB
Enterprise 50,000分 50 GB
GitHub One 50,000分 50 GB

利用時間的には、GitHub Team が 旧Pro 相当になった感じ。

ストレージ価格がおもむろに出てきたけど、publicは無料。 privateの場合に、アカウントの持つGitHub packagesとGitHub Actionsアーティファクトの利用合計らしい。 制限を超えてアカウントが利用していて、$0を超えるLimit spendingを設定していると料金がかかるので注意がいりそう。 そんなに大きなサイズのArtifactを設定するなという話なのですが、要注意。

アカウント > Settings > Billing > Cost management > Limit spending で設定できる。デフォ $0

ビリングのstorageに関してを見ておくほうがよさそう。ちょっと細かいので随時確認するといいでしょう。

About billing for GitHub Actions

OS別時間消費

Linuxを1として、WindowsやmacOSは利用時間の倍率がついているという考え。

Operating system Minute multiplier
Linux 1
macOS 10
Windows 2

追加購入

倍率に応じてなので、結果としてOS別に価格差が生じる。

Windows高いです。 macOSの価格は10倍なので課金するならセルフホストをまず検討したほうがいいでしょう。

ホストランナー vCPUs 料金
Linux 2 $0.008 1分あたり
Linux 4 $0.016 1分あたり
Linux 8 $0.032 1分あたり
Linux 16 $0.064 1分あたり
Linux 32 $0.128 1分あたり
Linux 64 $0.256 1分あたり
Windows 2 $0.016 1分あたり
Windows 4 $0.032 1分あたり
Windows 8 $0.064 1分あたり
Windows 16 $0.128 1分あたり
Windows 32 $0.256 1分あたり
Windows 64 $0.512 1分あたり
macOS 3 or 4 (M1 or intel) $0.08 1分あたり
macOS 12 $0.12 1分あたり
macOS 6 (M1) $0.16 1分あたり
セルフホスト - Free

料金例

5,000 (3,000 Linux and 2,000 Windows) minutes = $56 USD ($24 USD + $32 USD).

  • 3,000 Linux minutes at $0.008 USD per minute = $24 USD
  • 2,000 Windows minutes at $0.016 USD per minute = $32 USD

ホストランナーの指定

GitHub ActionsはAzure Pipeline同様にホストランナー1をどこで実行するか選択できる。

GitHub ホステッド ランナーの概要 - GitHub Docs

マネージド、セルフホストの選択

ホストランナーはマネージド、セルフホストが選択できる。

  • GitHubホストランナー :マシンメンテナンス、アップグレードがマネージドに提供される
  • セルフホストランナー : 物理、仮想、コンテナ、オンプレミス、クラウドに自分でインストールする

通常はクラウドホストランナー (GitHubが提供するホスト) を選ぶし、それが最も手早く楽。

セルフホストランナーは既にビルドを実行する環境がある、けどビルドの管理をしたくない、何かしらマシンに事前インストールが必要など融通をきかせたいときに便利。ようはAzure PipelineのSelf Hosted Agentと一緒ですし、Jenkinsのようなものです。

例えば、自分たちのKubernetesクラスターにセルフホストランナーを入れてビルドをすることで、クラスターの認証への考慮を減らしてクラスターへのデプロイできる。あるいは、クラウド上のVMに導入することで、クラウド認証を減らしてデプロイできます。

発表当時は、actions-runner-kubernetesは個人プロジェクトでしたが、2024年現在は公式リポジトリになっています。チュートリアルもあります。

アクション ランナー コントローラーのクイック スタート - GitHub Docs

本記事では個人のプロジェクトで考えるので、ここではGitHubホストランナーを前提としてみていく。

ハードウェアリソース

GitHubホストランナーはAzure VM上で動作するのでスペックはVMと同じで素直です。

2024年1月17日にパブリックリポジトリのVMは4CPUへ機能強化されました。ブライベートリポジトリは2 CPU(発表当時、Standard DS_v2相当)のままです。

パブリックリポジトリの性能は次の通り。

  • 4コアCPU
  • 16GBのRAMメモリー
  • 14GBのSSDディスク容量
Virtual Machine Processor (CPU) Memory (RAM) Storage (SSD) OS (YAML workflow label) Notes
Linux 4 16 GB 14 GB Ubuntu-latest, Ubuntu-22.04, Ubuntu-20.04 The Ubuntu-latest label currently uses the Ubuntu 22.04 runner image.
Windows 4 16 GB 14 GB windows-latest, windows-2022, windows-2019 The windows-latest label currently uses the Windows 2022 runner image.
macOS 3 14 GB 14 GB macos-latest, macos-12, macos-11 The macos-latest workflow label currently uses the macOS 12 runner image.
macOS 4 14 GB 14 GB macos-13 N/A
macOS 3 (M1) 7 GB 14 GB macos-14 (Beta) N/A

プライベートリポジトリの性能は次の通り。

  • 2コアCPU
  • 7GBのRAMメモリー
  • 14GBのSSDディスク容量
Virtual Machine Processor (CPU) Memory (RAM) Storage (SSD) OS (YAML workflow label) Notes
Linux 2 7 GB 14 GB Ubuntu-latest, Ubuntu-22.04, Ubuntu-20.04 The Ubuntu-latest label currently uses the Ubuntu 22.04 runner image.
Windows 2 7 GB 14 GB windows-latest, windows-2022, windows-2019 The windows-latest label currently uses the Windows 2022 runner image.
macOS 3 14 GB 14 GB macos-latest, macos-12, macos-11 The macos-latest workflow label currently uses the macOS 12 runner image.
macOS 4 14 GB 14 GB macos-13 N/A
macOS 3 (M1) 7 GB 14 GB macos-14 (Beta) N/A

あるいはLarger Runnerというものもあり、こちらはパブリックリポジトリのみで利用可能です。

より大きなランナーの概要 - GitHub Docs

インストールされるツール

OS毎に一覧があるので入ってないツールはインストールして対応で。

https://docs.github.com/en/actions/using-GitHub-hosted-runners/about-GitHub-hosted-runners/about-GitHub-hosted-runners#preinstalled-softwaredocs.github.com

IP

現在は、https://api.github.com/metaでIPを取得できるようになりました。やったね!

以前はGitHubのIPとは違ったのでIPレンジではなかったので、全てAzure VMでのホスト、かつ現状はus-east-2 regionなのでIPもそこ縛りでした。2

OSの選択

GitHubホストランナーの実行可能な環境は3種類あり、Azure Pipelineと同じ。 ほとんどのケースではLinux選んでおけばいいけど、.NET FrameworkのようなWindows固定、XcodeのようなmacOS固定もあるので用途に応じて。

  • Linux
  • Windows
  • macOS

Azure Pipeline同様にマトリックスビルドには対応しているので、OSSで各種OSむけのビルドはCircleCIより書きやすく、Travis CIの代替になりえる筋はある。

Using a matrix for your jobs

実行権限

CIではツールインストールなど権限を必要とすることが多い。 Linux/Windowsいずれにおいても管理者権限があるので権限で悩むことはないかな。

  • Linux, macOS: パスワードレスsudo状態
  • Windows: UAC無効、管理者状態

ファイルパス

実パスを気にせず、GitHubが提供している環境変数でアクセスできる。

  • $HOME : ユーザーパス。ログイン認証情報を含めてokらしい
  • $GITHUB_WORKSPACE : アクションとシェルコマンドの実行パス、変更可能
  • $GITHUB_EVENT_PATH : webhookイベントのPOSTペイロードへアクセスできる

ホスト仮想マシン

ファイルパスは静的でないため、GitHubが提供している環境変数を使う必要がある。

  • home
  • workspace
  • workflow/event.json

コンテナ

静的にパスを利用するため、USERを指定すると$GITHUB_WORKSPACEにアクセスできなくなる。 /github Path Prefixを予約しているので自分でボリュームマウントするときは気を付ける。

  • /github/home
  • /github/workspace
  • /github/workflow/event.json

環境変数

CircleCIのようにspin upした環境の変数は出してくれない。Azure Pipelineと一緒で不親切、正直なんでやねんっていつも思ってる。

自分で拾う必要があるので、適当にデフォルトの環境変数は把握しておく。

GitHub が使う環境変数は、GITHUB_ prefixがついており、 GITHUB_ prefixを使用して環境変数またはシークレットは設定できない。(エラーになる)

Variables - GitHub Docs

シークレット

Settings > Secretsからシークレットを設定できる。

Azure Pipeline同様に、ログからは自動的にマスクされる。 制約として、ワークフローで最大100シークレット、容量は64K 。

Using secrets in GitHub Actions - GitHub Docs

構造化データを値にするのは避けるべきというのは注意。

GitHubがログのシークレットを確実に削除するよう、構造化データをシークレットの値として使用することは避けてください。たとえば、JSONやエンコードされたGit blobを含むシークレットは作成しないでください。

GITHUB_TOKEN

GitHub Actionsで何気に一番うれしいやつ。GitHubへの操作多いので、Token自動的に生成してくれるの最高。

前提として、writeアクセスがあるユーザーになってるので注意。

リポジトリに対してwriteアクセスがあるユーザなら、誰でもシークレットの作成、読み取りおよび使用ができます。

GitHub Appsをインストールするアクセストークンとして、GITHUB_TOKENが自動生成される。 ジョブごとに「60分で期限切れ」になる一方で、ワークフローはデフォルト6hまでタイムアウトにならないので注意です。(デフォルトが長い)

Automatic token authentication - GitHub Docs

権限は一通り書き込み権限があり、リリースにパッケージ投げたりコメント書いたりは十分。逆に言うと結構強いので注意がいりそう。(もちろんOrg / Team権限はない)

Forkリポジトリからはreadがあるけどwriteがない。PRトリガーのワークフローで書き込み操作ははまりやすいです。

Permission Access type Access by forked repos
checks read/write read
contents read/write read
deployments read/write read
issues read/write read
metadata read read
packages read/write read
pull requests read/write read
repository projects read/write read
statuses read/write read

コンテキスト

コンテキストはかなり便利でメインで使っていくことになります。

Contexts - GitHub Docs

githubコンテキストはREST APIでとれるレスポンス/webhookレスポンスに近く、そのコミットの情報が結構とれます。コミットメッセージまででるので、skip ciに似た処理を自作するときに便利です。envsecretsもコンテキストの一種です。

環境変数GITHUB_でほとんどとれるとか書いてるけど取れるのはよくCIにある情報程度で、少し深くなるとコンテキスト触るしかない。

コンテキストは「stepsじゃなくても参照できる」のが重要で、jobs.ifでも利用できるのでコンテキストが一致するかでjob自体を実行するかとかも制御できます。

Artifact

アーティファクトでjob間のデータ永続はAzure Pipelineまんまです。

GitHub Actions のアーティファクトとは、ワークフロー実行中に生成されるファイル、またはファイルのコレクション。

ワークフロー内の各ジョブが異なるインスタンスで実行されるため、ワークフロー内のジョブ間でデータを受け渡すのには必須となります。ビルドパッケージを置いたり、ログを置いたり何かと使うのはCIサービスでよくあるパターンですね。

Storing workflow data as artifacts - GitHub Docs

アーティファクトはアップロードされるとzipになるけど、ダウンロードは生データが取れるので取り回しは楽。

  • ジョブが終了する前にデータをアップロードして、ワークフロー実行の内部にファイルを保存できる。 アーカイブをアップロードするときは、名前を付ける
  • ファイルをアップロードすると、同じワークフロー実行内の別のジョブでダウンロードできる。 アーカイブをダウンロードするとき、アーカイブは名前で参照できる。 アップロードされているアーティファクトをダウンロードできるのは、同じワークフロー実行中だけ

ワークフロー終了後、ジョブごとにArtifactをWebから取得できるので便利。

トリガーイベント

1つ以上のイベントをトリガーに設定できる。 pushやIssue、PR、webhookなどの各種イベント以外にも定期実行も可能。 ここがCircleCIでは厳しかったのでGitHub Actionsでうれしいところ。

GITHUB_SHAGITHUB_REF環境変数に現在のイベントに応じた状態がでるのでなるほど。(イベントごとに変わる) Wikiページの作成、更新はgollumイベントらしい。

Events that trigger workflows - GitHub Docs

ただ、ワークフローから別のワークフローはトリガーできないので、コメントなり適当なイベントを仲介する必要がある。

実行しているワークフローのアクションからは、新しいワークフローの実行をトリガーできない。

pushイベントでファイルの変更を完全に終えず、REST APIを使って取得が必要なのもなるほど。

GitHub Actionsが利用できるwebhookのペイロードには、commitオブジェクト中のadded、removed、modified属性は含まれない。

Forkされたリポジトリでは動かず、別途動くように設定する必要があります。もし実行するようにしても、ForkされたリポジトリのGitHub Actionsはベースリポジトリではトリガーされず、Fork先のリポジトリで許可が必要なのは普通のCIでよいところです。

Cache

なるほど、CircleCIとよく似てるけど、微妙に違う。

マッチングルールは、keyで完全一致を見て、失敗したらrestore-keysを上から順に前方一致で検索なのでよくあるとおり「長いキーから順に書き並べる」のが王道。さらにrestore-keysで複数一致したら最近のキャッシュが利用されるので素直な印象。

  1. keyの完全一致
  2. restore-keysを上から評価
  3. より最新のもの

Caching dependencies to speed up workflows - GitHub Docs

CacheとRestoreがセットになってるのはうれしいですね。actions/cacheしておくと、指定したキャッシュ対象パスに変更が合った時「Jobの終了時にpost actionとして自動的にキャッシュされる」のは普通に便利。この時キャッシュキーがすでにあればスキップされるので、意図通りの挙動です。

GitHub Actions でキャッシュを使った高速化 - 生産性向上ブログ

OS別なら${{ runner.os }}をキーに入れるのはよくあるパターンです。キャッシュ上書きがなく、7日でキャッシュ消えるものの任意のキャッシュクリアがないので、環境変数などでcache-versionを定義してキャッシュキーに含めるのも王道。

pushとpull_requestイベントだけ使えること、7日間以上アクセスされていないキャッシュエントリは削除されることに注意です。また、リポジトリのキャッシュサイズ制限が2GBと小さいのもはまる。

  • 400MBを超えないキャッシュ内の個々のファイル。 この制限を超えた場合、400 - Bad Requestが返さる
  • リポジトリ内のすべてのキャッシュの合計サイズが2GBを超えない

相変わらずWindows \とmacOS/Linux /でパス文字の解釈が違ってkeyの指定がコケるのはつらい。

hashFiles() does not work for valid patterns · Issue #39 · actions/cache

Actions

CircleCI Orbsじゃないけど、似たような処理の塊はActionsと呼ばれていて、Marketplaceで公開されている。Actionsでやっていることを知りたいときは、追っていくとGitHubリポジトリにたどりつくので、やってることも読めるしいい感じになってます。

GitHub Marketplace · Actions to improve your workflow

Actionsについて概要はドキュメントがあるのでみればok。

Finding and customizing actions - GitHub Docs

ActionsをGitHub Web上で編集する時、右にポップアップが出ます。

シンタックスエラーを検出したり、インテリセンスとかも利くので、こっち使うのが楽。

GitHub Web上ならシンタックスエラーも検出

インテリセンスも利く

通知

WebとEmailが設定できる。

help.github.com

なるほどビルドがコケると通知される。

YAML

実際書くときは、YAML書いてみて、わからないものを調べるという流れで慣れていっている。 ではYAMLで実際にどう書くのかざくっと使うものを見てみる。

Azure Pipeline風味が残ってるような感じで、もうちょっと砕けててほど良さもある。

Getting started

はじめてのYAMLテンプレートは、Actions選択したときに選択できるテンプレートを使うのが楽。

https://help.github.com/en/actions/automating-your-workflow-with-GitHub-actions/starting-with-preconfigured-workflow-templateshelp.github.com

YAMLシンタックス

どのような要素があるのかは、まずはシンタックスを把握すればok。

https://help.github.com/en/actions/automating-your-workflow-with-GitHub-actions/workflow-syntax-for-GitHub-actionshelp.github.com

最低限の定義はこんな感じ。何の意味もないやつ。

on: push
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - run: echo Hello

次の要素が必須だと分かる。

  • name : Workflowの名前でリポジトリのActions画面で表示される名前。省略するとパスになるので付けたほうがいい
  • on: 必須。実行するイベントやブランチなどの指定をする
  • jobs: 必須。とりあえずjobs:でok
  • jobs..runs-on: 動作させるホストランナーの指定。GitHub hostedかSelf-hostedかはここで決まる
  • jobs..steps: 必須。とりあえずsteps:でok。jobsを書くときは、最低1つのstepsが必要
  • jobs..steps.step : stepsの中は最低1つのstepが必要。例はrun stepを使っている

on

実行するトリガーの定義をここでする。 GitHub Actionsが他のCIと決定的に違うのが、ここでGitHubイベントと楽にバインドできることでしょう。

# push のみ
on: push
# push と pull request なら
on: [push, pull_request]

ブランチも含めた制御ができるのはいい感じ。

on:
  # Trigger the workflow on push or pull request,
  # but only for the master branch
  push:
    branches:
      - master
  pull_request:
    branches:
      - master
  # Also trigger on page_build, as well as release created events
  page_build:
  release:
    types: # This configuration does not affect the page_build event above
      - created

定期実行は、scheduleイベントで実行できる。

on:
  schedule:
    # * is a special character in YAML so you have to quote this string
    - cron:  '*/15 * * * *'

env

グローバルに、全Job、全stepから参照する環境変数はここで指定する。 特定のジョブでならjobs.<job_id>.env でいいし、特定のStepでならjobs.<job_id>.steps.envがあるので、あまり使いたくない。

jobs.<job_id>.needs

依存するjobを指定できる。大事。 ここで指定しないと並列に回るので、直列で回すときはCircleCI同様依存関係を作る必要がある。

jobs:
  prepare:
    runs-on: ubuntu-latest
    steps:
      - run: echo prepare

  build:
    runs-on: ubuntu-latest
    needs: prepare
    steps:
      - run: echo build

jobs.<job_id>.runs-on

実行するホストのOSをあらかじめ定義された値から選んで使う。

  • Windows Server 2019: windows-latestまたはwindows-2019
  • Ubuntu 18.04: Ubuntu-latestまたはUbuntu-18.04
  • Ubuntu 16.04: Ubuntu-16.04
  • macOS Catalina 10.15: macos-latest, macOS-10.15
jobs:
  build:
    runs-on: ubuntu-latest

jobs.<job_id>.container

ジョブをコンテナで実行したいときに使う。

jobs:
  my_job:
    runs-on: ubuntu-latest
    container: node:10.16-jessie

何気にイメージ指定するだけじゃなくて、細かくDockerの実行時パラメーターも調整できる。

jobs:
  my_job:
    runs-on: ubuntu-latest
    container:
      image: node:10.16-jessie
      env:
        NODE_ENV: development
      ports:
        - 80
      volumes:
        - my_docker_volume:/volume_mount
      options: --cpus 1

jobs.<job_id>.services

追加のコンテナを動かすときはservicesを用いる。 例えば、CI上でDatabase起動させてテストするとかはこれ。

jobs:
  container-job:
    runs-on: ubuntu-latest
    container:
      image:  node:10.16-jessie
    services:
      redis:
        image: redis
        ports:
          - 6379/tcp

jobやactionをコンテナで実行しているときにservicesのコンテナの参照をするときは、ホスト名でok。

そのステップがホストで実行しているときにservicesのコンテナの参照をするときは、localhost + マッピングしているホストのポートでアクセスする。 ホストでマッピングされたポートは${{ job.services.<service_name>.ports[<port>] }}でとれる。 上のRedisなら、${{ job.services.redis.ports['6379'] }}

jobs.<job_id>.if

ジョブの実行自体をここで制御できる。circleciのwhenをjobで指定するみたいなやつ。 ifではコンテキスト参照できるので、特定のコミットメッセージの場合はジョブを実行しないとかが書ける。

jobs:
  my_first_job:
    runs-on: ubuntu-latest
    if: github.event_name == 'pull_request' && github.event.action == 'unassigned'

あと、ifではコンテキスト参照するときに${{ }}で囲まなくていい。 演算子とか書式はドキュメント見るのがいい。

https://help.github.com/en/actions/automating-your-workflow-with-GitHub-actions/contexts-and-expression-syntax-for-GitHub-actionshelp.github.com

jobじゃなくてstepを条件で実行制御したい場合は、jobs.<job_id>.steps.ifがあるので、stepに対してifを付ければok。

jobs:
  my_first_job:
    runs-on: ubuntu-latest
    steps:
     - name: My first step
       if: github.event_name == 'pull_request' && github.event.action == 'unassigned'
       run: echo This event is a pull request that had an assignee removed.

jobs.<job_id>.steps

ここにやりたい処理を書いていく。 usesでGitHub Actionsを利用したり、runsでシェルのコマンドを実行したりできる。

usesは、stepで特定のコンテナ実行とかもできるのでこれは結構便利。

  • パブリックRepositoryの任意のリリースやブランチ、コミットを指定できる
  • 自分のリポジトリで定義したactionの参照
  • public registoryのdockerをステップで実行
jobs:
  my_first_job:
    runs-on: ubuntu-latest
    steps:
      # use GitHub Actions
      - uses: actions/setup-node@v1
      # use a specific version tag of a public repository
      - name: use AWS Repo
        uses: actions/aws@v2.0.1
      # use a action in workflow repository
      - uses: ./.github/actions/my-action
      # use a docker in public registory
      - uses: docker://gcr.io/cloud-builders/gradle

jobs.<job_id>.steps.run

一行、複数行、所定のパスで実行というのがよく使うパターン。 複数行は、安定の|なのでまぁ大丈夫そう。

jobs:
  my_first_job:
    runs-on: ubuntu-latest
    steps:
      # single line
      - run: sudo apt-get update
      # multi line
      - run: |
          sudo apt-get install google-cloud-sdk && \
          kubectl

他のシェルを指定するにはshell:で指定する。

jobs:
  my_first_job:
    runs-on: ubuntu-latest
    steps:
      - run: sudo apt-get update
        shell: bash
      - run: Get-Location
        shell: pwsh

Windowsのrun、あるいはpowershellpwshなどを指定してPowerShellがシェルの場合、自動的に頭に$ErrorActionPreference = 'stop'が追加されてFail fastになるのと、末尾にif ((Test-Path -LiteralPath variable:\LASTEXITCODE)) { exit $LASTEXITCODE }を追加して実行結果でrunステップが失敗するように処理が差し込まれているので注意。

jobs.<job_id>.steps.with

いわゆるパラメーター。Actionsとかでパラメーター渡すときはwithの中にmap(KeyValue)を書くことになる。

withで指定したキーは、INPUT_ prefixつきで大文字に変換されてActions内部から参照できる。例えばfirst_nameというキーで指定したならINPUT_FIRST_NAMEを指定することで値に参照できる。

jobs:
  my_first_job:
    runs-on: ubuntu-latest
    steps:
      - name: My first step
        uses: actions/hello_world@master
        with:
          first_name: Mona
          middle_name: The
          last_name: Octocat

環境変数

stepのrun実行時に渡したいなら、env: で指定する。

jobs:
  my_first_job:
    runs-on: ubuntu-latest
    steps:
      - name: Hello world
        run: echo Hello world $FIRST_NAME $middle_name $Last_Name!
        env:
          FIRST_NAME: Mona
          middle_name: The
          Last_Name: Octocat

stepのrunの中でいじるなら、シェルに従って環境変数を触ればいい。

# windows
$env:PATH += ";$pwd\build\lib"

step間で環境変数を保持したい場合は、set-envをecho出力する。Azure Pipelineに似た感じだけど微妙に違う。

::set-env name={name}::{value}

action_stateという環境変数にyellowという値をいれる場合はこうなる。

echo "::set-env name=action_state::yellow"

先ほどのPATHをstep間で保持するならこう。

# windows
$env:PATH += ";$pwd\build\lib"
echo "::set-env name=PATH::$env:PATH"

PATH環境変数への追加は、 echo "::add-path::/path/to/dir"が用意されている。 echo "::set-env name=PATH::${PATH}:/path/to/dir"でも動くけど、楽なほうで。

https://help.github.com/en/actions/automating-your-workflow-with-GitHub-actions/development-tools-for-GitHub-actions#set-an-environment-variable-set-envhelp.github.com

シークレット

シークレットの利用は、secretsコンテキスト経由で利用できる。 例えばSuperSecretというキーで登録したなら、${{ secrets.SuperSecret }} 。 利用する際は、with構文かenvなど環境変数経由で参照する。

steps:
  - name: Hello world action
    with: # Set the secret as an input
      super_secret: ${{ secrets.SuperSecret }}
    env: # Or as an environment variable
      super_secret: ${{ secrets.SuperSecret }}

GITHUB_TOKENもシークレットコンテキスト経由で利用できます。

name: Pull request labeler
on:
- pull_request
jobs:
  triage:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/labeler@v2
      with:
        repo-token: ${{ secrets.GITHUB_TOKEN }}

ログの表示で任意の文字列をマスクするために::add-mask::{value}もある。

Artifact

アップロード操作は$GITHUB_WORKSPACEを起点にパスで指定できます。 常に相対パスでいいので、絶対パスを気にする機会が減っていい感じです。

アップロードしてダウンロードする例は次のようになる。

jobs:
  job_1:
    name: Add 3 and 7
    runs-on: ubuntu-latest
    steps:
      - shell: bash
        run: |
          expr 3 + 7 > math-homework.txt
      - name: Upload math result for job 1
        uses: actions/upload-artifact@v4
        with:
          name: homework
          path: math-homework.txt

  job_2:
    name: Multiply by 9
    needs: job_1
    runs-on: windows-latest
    steps:
      - name: Download math result for job 1
        uses: actions/download-artifact@v4
        with:
          name: homework
      - shell: bash
        run: cat homework/math-homework.txt

Cache

サンプルはいくつかあるのでそれをみるのが手っ取り早い。

github.com

.NET Coreのnugetを例で考えます。(.NET Frameworkは忘れましょう)

.NET CoreはPackage Referencesにしているとcsprojにpackage情報が入り厄介です。もしcsprojが1つならこれでいいでしょう。あるいはManage Package Centrrallyを使ってパッケージを一元管理するならDirectory.Packages.propsを使えるでしょう。

steps:
  - uses: actions/cache@v1
    with:
      path: ~/.nuget/packages
      key: ${{ env.cache-version }}-${{ runner.os }}-nuget-${{ hashFiles('src/project.csproj') }}
      restore-keys: |
        ${{ env.cache-version }}-${{ runner.os }}-nuget-${{ hashFiles(''src/project.csproj') }}
        ${{ env.cache-version }}-${{ runner.os }}-nuget-

1つだけプロジェクトがあるならいいのですが、複数のcsprojに分離していると当然パッケージとバージョンの同一性を担保する方法がlockファイルに比べて面倒です。 CirclrCIでやったように、csprojを拾ってきてmd5あたりをキャッシュキーにするのもありです。 CircleCIの例を載せておきます。

steps:
  - run:
      name: Calculate cache key for csproj
      command: |
        {
          md5sum $(find << parameters.search_path >> -name << parameters.target_file_pattern >> | sort -r)
        } > ~/cache-key-source-<< parameters.project >>
      working_directory: << parameters.working_directory >>
  - save_cache:
      name: Cache nuget pacakges
      key: nuget-<< parameters.cache_key >>-<< parameters.project >>-{{ checksum "~/cache-key-source-<< parameters.project >>" }}
      paths:
        - "~/.nuget"

nuget-cache-orb/src/commands/nuget_save_cache.yml at 77c2c0cafe089314ae3d3d08473d429372737289 · guitarrapc/nuget-cache-orb · GitHub

なお、nugetは、macOSはXamarinなどでキャッシュサイズが半端なくなるので、こういうのを避けるためにNuGet Packageのパスを明示的に設定するのはあり。 その場合は、NUGET_PACKAGES環境変数にパスを指定して、actions/cacheのパスにも指定する。

env:
  NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages
steps:
  - uses: actions/cache@v1
    with:
      path: ${{ github.workspace }}/.nuget/packages
      key: ${{ env.cache-version }}-${{ runner.os }}-nuget-${{ hashFiles('src/project.csproj') }}
      restore-keys: |
        ${{ env.cache-version }}-${{ runner.os }}-nuget-${{ hashFiles(''src/project.csproj') }}
        ${{ env.cache-version }}-${{ runner.os }}-nuget-

TIPS

細かいけど知っておくといいTIPSがたまってきたのでメモ。

step の name

stepごとにnameを指定することで、GitHub上の表示を設定できる。

step ごとの name を付ける

省略するとコマンドがそのままでるので、CircleCIのようにname指定しないのもありです。ただ、個人的にはnanemを付けることで意図を示せるので、そういうささいな努力は欠かさないほうがいいと考えています。

step ごとの name を省略する

Azure Pipelieは、コマンドの内容ではなくcommand@1とかのモジュール名の表示になってたので、GitHub Actionsで改善して本当に良かった、神。

タイムアウト

timeout-minutesで指定できる。デフォルトが6hourと長いので、指定した方がいいケースは多い。

タイムアウトは、jobとstepごとの両方に指定可能。

jobs:
  build:
    runs-on: ubuntu-latest
    timeout-minutes: 15
    steps:
      - run: sleep 300
        timeout-minutes: 3

skip ci / ci skip

2021/2/10に、push/pull_requestトリガーで標準サポートされました。

github.blog

競合でもよく使われる[skip ci], [ci skip], [no ci], [skip actions], or [actions skip]が網羅されて、なるほど。

以前は、jobのifで制御してましたがもう不要。

github.com

Organization の他の private repo の参照

ssh-agent Actionを使えばSSHキーでknown_hosts設定したりできるけど、あんまり使いたくはない。

github.com

自動生成されるTokenでその制御はできないので、専用のTokenを生成するのが一番手っ取り早い。

- uses: actions/checkout@v1
  with:
    repository: organization_name/repo_name
    token: ${{ secrets.ACCESS_TOKEN }}

stackoverflow.com

Badge

サポートされてた。ドキュメントないけど。

srz-zumix.blogspot.com

いい感じの Action どこ

安定のawesomeで。

github.com

ローカルで構文チェックするCLIとかないの

Circle CLIのようなローカル実行向けのCLIはないです。 残念。


  1. GitHub Actionsランナーアプリケーションがインストールされた、GitHubがホストする仮想マシン
  2. 今後増える可能性があるとのことですが、本当に増やすのかな?