GitHub ActionsのTipsやベストプラクティスを淡々と記録する

Bookmarks
- Workflow syntax for GitHub Actions
- Events that trigger workflows
- Workflow commands for GitHub Actions
- Expressions
- Contexts
- Environment variables
Learn GitHub Actions
- Understanding GitHub Actions
- Using release management for your custom actions
- Expressions
- Contexts
- Environment variables
- Usage limits, billing, and administration
Using workflows
- About workflows
- Triggering a workflow
- Events that trigger workflows
- Workflow syntax for GitHub Actions
- Workflow commands for GitHub Actions
- Reusing workflows
- Using starter workflows
- Caching dependencies to speed up workflows
- Storing workflow data as artifacts
Using jobs
- Using jobs in a workflow
- Choosing the runner for a job
- Using conditions to control job execution
- Using a matrix for your jobs
- Using concurrency
- Using environments for jobs
- Running jobs in a container
- Setting default values for jobs
- Assigning permissions to jobs
- Defining outputs for jobs
Managing workflow runs
- Manually running a workflow
- Re-running workflows and jobs
- Approving workflow runs from public forks
- Approving or rejecting a job
- Skipping workflow runs
- Downloading workflow artifacts
Automating builds and tests
- About continuous integration
- Building and testing Java with Gradle
- Building and testing Node.js
- Building and testing Ruby
Deployment
- About continuous deployment
- Deploying with GitHub Actions
- Deploying to Amazon Elastic Container Service
- About security hardening with OpenID Connect
- Configuring OpenID Connect in Amazon Web Services
- Configuring OpenID Connect in cloud providers
- Using OpenID Connect with reusable workflows
- Using environments for deployment
- Viewing deployment history
Using containerized services
Publishing packages
Managing issues and pull requests
Monitoring and troubleshooting workflows
Using GitHub-hosted runners
Security guides
Creating actions

Workflows
YAMLの書き方が分からなくなったら下記を参照する。
Trigger workflows
pull_request
on:
pull_request:
paths:
- "**.yml"
- "**.yaml"
- "!.github/workflows/test.yml"
push
on:
push:
paths:
- ".github/workflows/test.yml"
workflow_dispatch
on:
workflow_dispatch:
inputs:
push:
type: choice
required: true
description: "The flag to docker push."
default: "false"
options:
- "true"
- "false"
フィルタリング設定などは下記参照。

Permissions
超重要なので熟読必須。ジョブ単位でも設定できるらしい。
全権限のはく奪
permissions: {}
公式ドキュメントにシレッと書いてあるが、意外と知られてない気がする。
まとめて設定
permissions: read-all|write-all
権限一覧
permissions:
actions: read|write|none
checks: read|write|none
contents: read|write|none
deployments: read|write|none
id-token: read|write|none
issues: read|write|none
discussions: read|write|none
packages: read|write|none
pages: read|write|none
pull-requests: read|write|none
repository-projects: read|write|none
security-events: read|write|none
statuses: read|write|none
Reusable workflowでの挙動検証
- 呼び出し側:未指定
- Reusable workflow:
{}
=> OK/Metadata: read - Reusable workflow:
contents: read
=> OK/Contents: read、Metadata: read
- Reusable workflow:
- 呼び出し側:
contents: read
- Reusable workflow:
{}
=> OK/Metadata: read - Reusable workflow:未指定 => OK/Contents: read、Metadata: read
- Reusable workflow:
- 呼び出し側:
{}
- Reusable workflow:未指定 => OK/Metadata: read
- Reusable workflow:
contents: read
=> NG/contents: none
3.2のエラーメッセージ
Invalid workflow file: .github/workflows/lint.yml#L19
The workflow is not valid. .github/workflows/lint-yaml.yml (Line: 19, Col: 3):
Error calling workflow 'foo/bar/.github/workflows/lint.yml@v0'. The workflow
'foo/bar/.github/workflows/lint.yml@v0' is requesting 'contents: read',
but is only allowed 'contents: none'.
関連

Environment variables
- いろいろな場所に書けるが、どこから参照できるかは地味に制約がある
- Reusable workflowの呼び出しでは
${{ env.FOO }}
のような書き方はNGだった
- Reusable workflowの呼び出しでは
env:
IMAGE_NAME: prettier

defaults
使ったことない。
defaults:
run:
shell: bash
working-directory: scripts

concurrency
もはや毎回オマジナイとして書いてる。
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

Jobs
9割この書き出し。
jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Checkout
uses: actions/checkout@v3
timeout-minutes
超重要。デフォルトタイムアウトが6時間とかいうエグい設定なので、必ず明示する。無料枠を使い潰さないためのセーフティネット。
runs-on
ubuntu-latest
以外使ったことがないが、macOSやWindowsも動く模様。ただしmacOSやWindは高いので、本当に必要なとき以外は使わない。
outputs
ジョブ間での値の受け渡しができる。ステップで echo "::set-output name=key::value"
して、 outputs
でステップの値を参照するという二段階が必要でややメンドウ。また参照時は needs
とセットで使う。
jobs:
job1:
runs-on: ubuntu-latest
# Map a step output to a job output
outputs:
output1: ${{ steps.step1.outputs.test }}
output2: ${{ steps.step2.outputs.test }}
steps:
- id: step1
run: echo "::set-output name=test::hello"
- id: step2
run: echo "::set-output name=test::world"
job2:
runs-on: ubuntu-latest
needs: job1
steps:
- run: echo ${{needs.job1.outputs.output1}} ${{needs.job1.outputs.output2}}
if
ジョブの実行をするか条件定義可能。
name: example-workflow
on: [push]
jobs:
production-deploy:
if: github.repository == 'octo-org/octo-repo-prod'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
matrix
マトリックスビルドがサポートされている。
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-latest, windows-latest, ubuntu-18.04]
node: [8, 10, 12, 14]
include:
# includes a new variable of npm with a value of 6
# for the matrix leg matching the os and version
- os: windows-latest
node: 8
npm: 6
Running jobs in a container
どうもコンテナ内でジョブを実行できるらしい。
jobs:
my_job:
container:
image: node:14.16
env:
NODE_ENV: development
ports:
- 80
volumes:
- my_docker_volume:/volume_mount
options: --cpus 1
横にDBなどもたてれる模様。

Steps
jobs
の下に書く。GitHub Actionsの花形。
jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Echo
run: |
echo "hello"
複数行対応アレコレ
run
run: |
の部分は、YAMLに複数行書くヤツ。詳細は下記。
outputs
複数行のoutputsは頑張ってエスケープする。
steps:
- name: Run yamllint
id: run
run: |
MESSAGE=$(yamllint --strict --format standard .) || EXIT_CODE="$?" && \
MESSAGE="${MESSAGE//'%'/'%25'}" && \
MESSAGE="${MESSAGE//$'\n'/'%0A'}" && \
MESSAGE="${MESSAGE//$'\r'/'%0D'}" && \
echo "::set-output name=message::${MESSAGE}" && \
exit "${EXIT_CODE}"
- name: Echo
env:
MESSAGE: ${{ steps.run.outputs.message }}
run: echo "${MESSAGE}"
用途によっては↓だけでいいかもしれない。
MESSAGE="${MESSAGE//$'\n'/\\n}"
if
if文も複数行に書ける。

Expressions
if文やenvなどで使える。書いたことないが、リテラルも記述できるらしい。
steps:
- uses: actions/hello-world-javascript-action@v1.1
if: ${{ <expression> }}
Operators
よくある条件式はこんな感じ。
if: ${{ github.event.pull_request.merged && github.head_ref == 'main' }}
booleanを判定しようとしたら、YAML的に文字列のtrue/false
として扱われていて動かないことがある。その場合は文字列比較(foo == 'true'
など)を使うこと。
Functions
あまり多くないが関数が使える。
-
contains( search, item )
:if文でたまに使う -
startsWith( searchString, searchValue )
:if文でたまに使う -
endsWith( searchString, searchValue )
:if文でたまに使う format( string, replaceValue0, replaceValue1, ..., replaceValueN)
join( array, optionalSeparator )
toJSON(value)
-
fromJSON(value)
:matrixビルドで使う/文字列からbooleanや数値への変換にも使えるらしい -
hashFiles(path)
:キャッシュ関連で使う
Status check functions
ステップの実行に失敗した場合も継続したい、みたいなニーズに応える。
if: ${{ always() }}
if: ${{ success() }}
if: ${{ cancelled() }}
if: ${{ failure() }}
使い方はこんな感じ。
steps:
...
- name: The job has succeeded
if: ${{ success() }}
Object filters
ややトリッキーな機能。使ったことない。たとえば次のYAMLがあるとする。
[
{ "name": "apple", "quantity": 1 },
{ "name": "orange", "quantity": 2 },
{ "name": "pear", "quantity": 1 }
]
このとき fruits.*.name
と書くと配列の [ "apple", "orange", "pear" ]
が取れるらしい。

Contexts
github
よく使うヤツ。
-
github.base_ref
:マージ先となるターゲットブランチ -
github.head_ref
:マージ元となるソースブランチ -
github.event
:イベントのペイロード全体が取れる -
github.event_name
:イベント名だけ欲しい場合はこっち -
github.ref
:ブランチやタグが取れるrefs/heads/<branch_name>
refs/tags/<tag_name>
-
github.ref_name
:ブランチやタグの名前だけが取れる -
github.repository
:Codertocat/Hello-World
形式のリポジトリ名 -
github.repository_owner
:リポジトリ所有者 -
github. actor
:ワークフロー実行者/dependabotとか取りたい場合に使う -
github.run_id
:ワークフローの識別子 -
github.sha
:commit SHA -
github.workflow
:ワークフロー名
{
"token": "***",
"job": "dump_contexts_to_log",
"ref": "refs/heads/my_branch",
"sha": "c27d339ee6075c1f744c5d4b200f7901aad2c369",
"repository": "octocat/hello-world",
"repository_owner": "octocat",
"repositoryUrl": "git://github.com/octocat/hello-world.git",
"run_id": "1536140711",
"run_number": "314",
"retention_days": "90",
"run_attempt": "1",
"actor": "octocat",
"workflow": "Context testing",
"head_ref": "",
"base_ref": "",
"event_name": "push",
"event": {
...
},
"server_url": "https://github.com",
"api_url": "https://api.github.com",
"graphql_url": "https://api.github.com/graphql",
"ref_name": "my_branch",
"ref_protected": false,
"ref_type": "branch",
"secret_source": "Actions",
"workspace": "/home/runner/work/hello-world/hello-world",
"action": "github_step",
"event_path": "/home/runner/work/_temp/_github_workflow/event.json",
"action_repository": "",
"action_ref": "",
"path": "/home/runner/work/_temp/_runner_file_commands/add_path_b037e7b5-1c88-48e2-bf78-eaaab5e02602",
"env": "/home/runner/work/_temp/_runner_file_commands/set_env_b037e7b5-1c88-48e2-bf78-eaaab5e02602"
}
詳細はgithub contextを参照すること。
steps context
よく使う。
-
steps.<step_id>.outputs.<output_name>
:ステップ間での値の受け渡しに使う -
steps.<step_id>. outcome
:continue-on-error
実行前のステータス -
steps.<step_id>.conclusion
:continue-on-error
実行後のステータス
env context
環境変数をシェル以外の場所で参照する場合に使う。たまに使えない場所がある。
secrets context
自分で登録したシークレットを参照できる。GITHUB_TOKEN
はデフォルトで使える。ログ出力時に自動でマスクするようになっているが、完全ではないのでそもそもログに吐かないこと。
needs context
他のジョブの待ち合わせで使う。
inputs context
Reusable workflowsの入力パラメータ。
その他
使ったことないが他にもある。
- job context
- runner context
- strategy context
- matrix context

Environment variables
GITHUB_XXXX
という名前の環境変数はデフォルトで提供される。未検証だが大半の値はgithub contextから取れる気がする。

Workflow commands
echoコマンドを通して、特殊な命令が発行できる。
Setting an output parameter
ステップ間の値の受け渡しなどで使う。
- name: Set selected color
run: echo '::set-output name=SELECTED_COLOR::green'
id: random-color-generator
- name: Get color
run: echo "The selected color is ${{ steps.random-color-generator.outputs.SELECTED_COLOR }}"
デバッグログ
Secretsに ACTIONS_STEP_DEBUG
を true
で保存すると、デバッグログが吐けるらしい。要検証。
echo "::debug::Set the Octocat variable"
デバッグログの詳細は下記。
ロギング
ログ出力とともに、アノテーションも作成してくれる。アノテーションを見落としがちという欠点がある。
echo "::notice file=app.js,line=1,col=5,endColumn=7::Missing semicolon"
echo "::warning file=app.js,line=1,col=5,endColumn=7::Missing semicolon"
echo "::error file=app.js,line=1,col=5,endColumn=7::Missing semicolon"
Grouping log lines
jobs:
bash-example:
runs-on: ubuntu-latest
steps:
- name: Group of log lines
run: |
echo "::group::My title"
echo "Inside group"
echo "::endgroup::"
Masking a value in log
ログ出力時にマスクしてくれる。
jobs:
bash-example:
runs-on: ubuntu-latest
env:
MY_NAME: "Mona The Octocat"
steps:
- name: bash-version
run: echo "::add-mask::$MY_NAME"
Echoing command outputs
なぜかGitHub Actionsではデフォルトでechoが無効化されている。が、明示的に有効化可能。
jobs:
workflow-command-job:
runs-on: ubuntu-latest
steps:
- name: toggle workflow command echoing
run: |
echo '::set-output name=action_echo::disabled'
echo '::echo::on'
echo '::set-output name=action_echo::enabled'
echo '::echo::off'
echo '::set-output name=action_echo::disabled'
Setting an environment variable
echo "{environment_variable_name}={value}" >> $GITHUB_ENV
で環境変数に値をセットできる。
steps:
- name: Set the value
id: step_one
run: |
echo "action_state=yellow" >> $GITHUB_ENV
- name: Use the value
id: step_two
run: |
echo "${{ env.action_state }}" # This will output 'yellow'
頑張ると複数行書けるらしい。これは読みづらい。
steps:
- name: Set the value in bash
id: step_one
run: |
echo 'JSON_RESPONSE<<EOF' >> $GITHUB_ENV
curl https://example.lab >> $GITHUB_ENV
echo 'EOF' >> $GITHUB_ENV
Adding a system path
PATHの追加コマンドが用意されている。
echo "$HOME/.local/bin" >> $GITHUB_PATH

Custome Actions
よく見る。
Enterprise Cloud版であれば、プライベートリポジトリで完結できるらしい。
参考リンク

Reusable Workflows
よく見る
Starter Workflows
使ったことないがStarter Workflowsというのもある。

セキュリティ
とりあえずここから。
シークレット管理について。
GITHUB_TOKEN
について。

Packaging
全体像。
Dockerについて。

OIDC
OIDCで重要なこと。
AWS

Deployment
プライベートリポジトリはEnterprise版のみ。

GitHub Marketplace
アクションを公開する場合、GitHub ReleasesでDeveloper Agreementへ同意する必要がある。
Publish this release to the GitHub Marketplace
You must accept the GitHub Marketplace Developer Agreement before publishing an Action.