tech.guitarrapc.cóm

Technical updates

GitHub Actions ことはじめ

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

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

目次

TL;DR

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

help.github.com

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

github.community

  • 基本は 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

f:id:guitarrapc_tech:20200106074554p:plain
世界

f:id:guitarrapc_tech:20200106074613p:plain
日本

f:id:guitarrapc_tech:20200106074630p:plain
USA

GitHub Actions の基本

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

使用条件

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

f:id:guitarrapc_tech:20200106001331p:plain

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

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

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

旧プランのほうがお得なケースは多数あってなかなか新プランに移行が難しいケースも見かけるので実は難しいやつ。

使用制限

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

help.github.com

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

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

料金

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

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

github.co.jp

help.github.com

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

含まれる利用時間

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

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

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

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

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

https://help.github.com/en/github/setting-up-and-managing-billing-and-payments-on-github/about-billing-for-github-actions#calculating-minute-and-storage-spending

OS別時間消費

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

Operating system Minute multiplier
Linux 1
macOS 10
Windows 2

追加購入

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

Windows たっか。(あるある macOS やばい、これは追加になるとセルフホストまったなしになりそう。

ホストランナー スペック 料金
Linux 2 cores, 7GB $0.008 1分あたり
Windows 2 cores, 7GB $0.016 1分あたり
macOS 2 cores, 7GB $0.08 1分あたり
セルフホスト - Free

ホストランナーの指定

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

help.github.com

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

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

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

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

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

help.github.com

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

github.com

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

ハードウェアリソース

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

  • 2コアCPU
  • 7 GBのRAMメモリー
  • 14 GBのSSDディスク容量

f:id:guitarrapc_tech:20200104221842p:plain
DSv2-series

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

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

help.github.com

IP

GitHub の IP とは違うのが注意で、以下のURL のIPレンジではない。

https://api.github.com/meta

github.community

全て Azure VM でのホスト、かつ現状は us-east-2 region なのでIPもそこ縛りです。2

IPレンジは毎週更新してJSONで公開されているようですが、このリンクはまさかの Download Center で面倒な状況。

www.microsoft.com

サポート回答もこのURLで、常に最新のjsonに直接アクセスできるリンクは用意しない気配。

github.community

直URL も日付入りで、決まったURLへ定期取得するのは想定されてなさそう。

https://download.microsoft.com/download/7/1/D/71D86715-5596-4529-9B13-DA13A5DE5B63/ServiceTags_Public_20191216.json

100日さかのぼってみましたが、今のところ更新ない or URL生成ルール違うので 404でルールはわからなかった。

OSの選択

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

  • Linux
  • Windows
  • macOS

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

https://help.github.com/ja/actions/automating-your-workflow-with-github-actions/configuring-a-workflow#configuring-a-build-matrix

実行権限

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を使用して環境変数またはシークレットは設定できない。(エラーになる)

help.github.com

シークレット

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

f:id:guitarrapc_tech:20200105004654p:plain

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

help.github.com

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

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

GITHUB_TOKEN

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

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

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

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

help.github.com

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

Fork リポジトリからは read があるので、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

コンテキスト

コンテキストはかなり便利。

help.github.com

github コンテキストは REST API でとれるレスポンス/webhook レスポンスに近く、そのコミットの情報が結構とれる。 コミットメッセージまででるので、skip ci の自作とかはこれで。 環境変数 GITHUB_ でほとんどとれるとか書いてるけど、取れるのはよくCIにある情報程度で、少し深くなるとコンテキスト触るしかない。

env や secrets もコンテキストの一種なので、めちゃめちゃ使う。

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

Artifact

なるほど、アーティファクトで job 間のデータ永続は Azure Pipeline まんま。

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

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

help.github.com

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

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

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

f:id:guitarrapc_tech:20200105000841p:plain

トリガーイベント

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

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

help.github.com

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

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

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. より最新のもの

help.github.com

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

www.kaizenprogrammer.com

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

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

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

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

github.com

Actions

CircleCI Orbs じゃないけど、似たような処理の塊は Actions と呼ばれていて、Marketplace で公開されている。

github.com

Actionsでやっていることを知りたいときは、追っていくと GitHub リポジトリにたどりつくので、やってることも読めるしいい感じになってる。

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

help.github.com

Actions を使うときは、GitHub Web 上で YAML を編集する時なら右にポップアップが出る。

f:id:guitarrapc_tech:20200106005534p:plain

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

f:id:guitarrapc_tech:20200106005612p:plain
GitHub Web上ならシンタックスエラーも検出

f:id:guitarrapc_tech:20200106005645p:plain
インテリセンスも利く

通知

Web と Email が設定できる。

help.github.com

f:id:guitarrapc_tech:20200105004804p:plain

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

f:id:guitarrapc_tech:20200105004620p:plain

YAML

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

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

Getting started

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

help.github.com

YAMLシンタックス

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

help.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 の中は最低一つの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 ではコンテキスト参照するときに ${{ }} で囲まなくていい。 演算子とか書式はドキュメント見るのがいい。

help.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

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" でも動くけど、楽なほうで。

help.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を起点に path で指定できます。 常に相対パスでいいので、絶対パスを気にする機会が減っていい感じです。

アップロードしてダウンロード

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@v1
        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@v1
        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 が一つならこれでいいでしょう。

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-

一つだけプロジェクトがあるならならいいのですが、複数の 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/nuget_save_cache.yml at 77c2c0cafe089314ae3d3d08473d429372737289 · guitarrapc/nuget-cache-orb · GitHub

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

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 上の表示を設定できる。

f:id:guitarrapc_tech:20200106010550p:plain
step ごとの name を付ける

省略するとコマンドがそのままでるので、CircleCI のように基本的に name 指定しないのがよさそう。

f:id:guitarrapc_tech:20200106010530p:plain
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

標準ではない。 なので、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. 今後増える可能性があるとのことですが、本当に増やすのかな?