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版のみ。