GitHub Actions

全レポジトリの artifacts を削除
gh repo list --limit 1000 | awk '{print $1}' | xargs -L 1 -I% gh api repos/%/actions/artifacts --paginate | jq '.artifacts[]' | jq '.url' | xargs -L 1 gh api -X DELETE
gh repo list yorifuji --limit 1000 --json nameWithOwner | jq -r ".[].nameWithOwner" | grep ^yorifuji | xargs -L 1 -I% gh api repos/%/actions/artifacts --paginate | jq -r ".artifacts[].url" | xargs -L 1 gh api -X DELETE

wokflowからsecretsのリストを生成する
grep -o -h -E 'secrets\.[0-9a-zA-Z_]+' -- .github/workflows/* | grep -v '^secrets.GITHUB_TOKEN$' | sed -e 's/secrets\.//g' -e 's/$/=/' | sort | uniq
ファイルからsecretsを登録する
gh auth login
gh secret set -f .secrets

GitHub hosted runnerのスペック
ソフトウェア
最大ジョブ数
context
GITHUB_TOKENのpermissions
permissionsの一覧
filter フィルターのパターン
usage
ワークフローコマンド
無料枠
デフォルト環境変数

pull_requestとpull_request_targetの違い
pull_request
- PRのマージコミットで実行される
- confllictがあると実行されない(pull_request_targetの場合は実行される)
- GITHUB_SHAはmergeコミットを指す
- forkされたリポジトリから実行された場合
- 「fork 先のリポジトリの設定で github actions が動く」
- つまりfork元のsecretsは提供されない、セキュリティのため
- GITHUB_TOKENは通常readonly https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token
pull_request_target
- PRのbase branchで実行される
- masterから派生したfeatureの場合、masterで実行される
- PRに含まれる悪意のあるコードが実行されたりsecretsが盗まれるのを防ぐため
- forkされたリポジトリから実行された場合
- 「fork 元のリポジトリの設定で github actions が動く」
- つまりsecretsにアクセスできる
- 用途
- fork先からのPRに対してlabelを付与したり
- labelが付与されたPRに対してCIを実行(labelを付与する権限が適切に管理されている前提)
- 次のような用途では使わない
- fork元のsecretにアクセスできるためPRからコードをビルドしたり実行しない(任意のコードからsecretにアクセスできるため)
- 補足
- permissionsを明示指定しない限りread/writeの権限が与えられる
- ワークフローはデフォルトブランチのものが使用される
共通
- 初回のcontributorからのPRに対してはメンテナーによる承認を必要とする(デフォルト設定の場合)
link

セキュリティ

構造化されたデータ(JSONなど)をそのままシークレットとして登録することは推奨されていない
To help ensure that GitHub redacts your secret in logs, avoid using structured data as the values of secrets. For example, avoid creating secrets that contain JSON or encoded Git blobs
バイナリの場合はbase64へ変換して登録、decodeしてファイルへ書き出す
JSONについてもkeyの単位で個別にsecretとして登録すべきという指摘もある、確実にマスクするため

Workflow内でGITHUB_TOKENを使ってイベントのトリガーを生成してもループしない
リポジトリGITHUB_TOKENを使用してタスクを実行する場合、 GITHUB_TOKEN によってworkflow_dispatchトリガーされるイベント (例外) と repository_dispatch、 は新しいワークフロー実行を作成しません。 これによって、予想外の再帰的なワークフローの実行が生じないようになります。 たとえば、ワークフロー実行でリポジトリの GITHUB_TOKEN を使用してコードがプッシュされた場合、push イベントの発生時に実行するように構成されたワークフローがリポジトリに含まれている場合でも、新しいワークフローは実行されません。
PAT(Personal Access Token)は例外
If you do want to trigger a workflow from within a workflow run, you can use a personal access token instead of GITHUB_TOKEN to trigger events that require a token. You'll need to create a personal access token and store it as a secret. To minimize your GitHub Actions usage costs, ensure that you don't create recursive or unintended workflow runs. For more information about creating a personal access token, see "Creating a personal access token." For more information about storing a personal access token as a secret, see "Creating and storing encrypted secrets."

steps.<step_id>.outcome とsteps.<step_id>.conclusion の違い

workflow_runは、他のワークフローのリクエストや完了時をトリガーにワークフローを実行することができます。

composit action
再利用可能なローカルアクションの作成
secretsは参照できない
シークレットはクレデンシャルなどの秘匿情報を管理する仕組みです。利用者が事前にGitHubへ登録して使用します。しかしComposite Actionでは、直接シークレットを参照できません。inputs経由で渡す必要があります。${{ secrets.ACCESS_KEY }}のような記述がComposite Actionにあるとエラーで落ちるため、ワークフローから切り出す際には書き換えが必要です。

workflowのテンプレートを作る
Creating starter workflows for your organization - GitHub Docs

emailに 41898282+github-actions[bot]@users.noreply.github.com を指定することで github-actions[bot] を利用する方法もある。
この方法はGitHub CommunityのGitHub Actions bot email address?というトピックで紹介されている。

jobを跨いで成果物を扱う方法
on: [push]
jobs:
first-job:
runs-on: ubuntu-latest
outputs:
value: ${{ steps.stepid.outputs.value }}
steps:
- id: stepid
run: echo "::set-output name=value::foobarbaz"
second-job:
runs-on: ubuntu-latest
needs: first-job
steps:
- run: echo ${{ needs.first-job.outputs.value }}
on: [push]
jobs:
first-job:
runs-on: ubuntu-latest
steps:
- run: echo 'foobarbaz' > ./value.txt
- uses: actions/upload-artifact@v3
with:
name: sample-artifact
path: value.txt
second-job:
runs-on: ubuntu-latest
needs: first-job
steps:
- uses: actions/download-artifact@v3
with:
name: sample-artifact
- run: cat ./value.txt

on:
pull_request:
はマージコミットで実行される
Bitriseは以下のオプションで挙動を切り替えられる

ワークフローの表示順序はascii codeではない

セルフホストで複数のランナーを実行(concurrency)

- ArtifactはStorageを使用する、無料枠は0.5GB

self-hostのログインユーザー名は runner

PR の CI をする場合は on: pull_request を使いましょう。
デフォルトは types: [ opened, synchronize, reopened ] なので PR 作成時だけでなく追加でプッシュしたときにも走ってくれます。
また、マージ先のブランチをマージした上で CI が実行されます。(GitHub が用意してくれる pull/:prNumber/merge ブランチで走ります)

tmpディレクトリを使う時は ${{ runner.temp }}
jobの実行単位でclearされる

gh actions-cache list | cut -f 1 | xargs -I% gh actions-cache delete % --confirm

name: 三項演算子
on:
push:
workflow_dispatch:
jobs:
env:
runs-on: ubuntu-latest
steps:
- run: echo ${{ (vars.FOOBAR == null && '') || 'test' }}
- run: echo ${{ (vars.FOOBAR != null && 'test') || '' }}

- uses: subosito/flutter-action@v2
with:
flutter-version: ${{ env.FLUTTER_VERSION }}
channel: "stable"
self-hostedでsubosito/flutter-actionを使う場合はcacheは使用しないほうがいい、save/restorでのネットワークが遅い、多分西海岸にある
1Gbyteのcacheのrestoreで5分以上かかる
self-hosted
Received 961829149 of 966023453 (99.6%), 2.7 MBs/sec
Received 961829149 of 966023453 (99.6%), 2.7 MBs/sec
Received 966023453 of 966023453 (100.0%), 2.7 MBs/sec
Cache Size: ~921 MB (966023453 B)
そもそもsubosito/flutter-actionはrunner.tool_cacheに永続的に保存されるのでcacheを利用する必要がない
GitHub-hostedは安定していないが速い
Run actions/cache@v3
Received 138412032 of 744062813 (18.6%), 131.3 MBs/sec
Received 402653184 of 744062813 (54.1%), 189.0 MBs/sec
Received 671088640 of 744062813 (90.2%), 207.8 MBs/sec
Received 744062813 of 744062813 (100.0%), 210.1 MBs/sec
Cache Size: ~710 MB (744062813 B)
Received 134217728 of 743721302 (18.0%), 122.0 MBs/sec
Received 285212672 of 743721302 (38.3%), 132.7 MBs/sec
Received 448790528 of 743721302 (60.3%), 140.4 MBs/sec
Received 616562688 of 743721302 (82.9%), 145.2 MBs/sec
Received 743721302 of 743721302 (100.0%), 142.6 MBs/sec
Cache Size: ~709 MB (743721302 B)
Received 964689920 of 976501383 (98.8%), 31.1 MBs/sec
Received 976501383 of 976501383 (100.0%), 30.9 MBs/sec
Cache Size: ~931 MB (976501383 B)

- ワークフローから別のワークフローを起動する場合はPATを利用する
- ワークフローを起動する必要がないならワークフローのトークン(
GITHUB_TOKEN
)を使う- 必要なPermissionはワークフロー内で定義する

${{ secrets.GITHUB_TOKEN }}
とは
github.token でも同じ

name: dump context
run-name: dump context
on: pull_request
permissions:
contents: read
jobs:
analyze:
runs-on: ubuntu-latest
steps:
- uses: actions/github-script@v6
with:
script: |
console.log(context)

Label関連
ファイルパスベース
ブランチ名ベース

GITHUB_TOKENでrest apiを使う場合のRate Limit
GITHUB_TOKEN を使用する場合、レート制限は、リポジトリごとに 1 時間あたり 1,000 要求です。

使用例
- name: Generate a token
id: generate_token
uses: actions/create-github-app-token@v1
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.PRIVATE_KEY }}
- name: create pull request
# env:
# GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
env:
GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
run: |
gh pr create ...

private repositoryのアクションを他のrepositoryと共有する

Xcodeのサポートポリシー
- only one major version of Xcode will be supported per macOS version
- all minor versions of the supported major version will be available
- beta and RC versions will be provided "as-is" in the latest available macOS image only no matter of beta/GA status of the image
- when a new patch version is released, the previous patch version will be replaced

キャッシュをサイズでソートして表示
gh api repos/:owner/:repo/actions/caches --paginate | jq '.actions_caches | sort_by(.size_in_bytes) | reverse'
gh api repos/:owner/:repo/actions/caches --paginate | jq '.actions_caches | sort_by(.size_in_bytes) | reverse | .[] | {
key: .key,
ref: .ref,
size: (
if .size_in_bytes > 1073741824 then
(.size_in_bytes/1073741824|floor|tostring) + " GB (" + (.size_in_bytes|tostring) + " bytes)"
elif .size_in_bytes > 1048576 then
(.size_in_bytes/1048576|floor|tostring) + " MB (" + (.size_in_bytes|tostring) + " bytes)"
elif .size_in_bytes > 1024 then
(.size_in_bytes/1024|floor|tostring) + " KB (" + (.size_in_bytes|tostring) + " bytes)"
else
(.size_in_bytes|tostring) + " bytes"
end
),
created_at: .created_at
}'

% gh repo list yorifuji --limit 200 --json name -q '.[].name' \
| xargs -I{} sh -c 'gh api -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" /repos/yorifuji/{}/actions/permissions | jq --arg repo {} ". + {repo: \$repo}"'

cooldown