Open51

GitHub Actions

ピン留めされたアイテム
yorifujiyorifuji

全レポジトリの 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

ピン留めされたアイテム
yorifujiyorifuji

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
ピン留めされたアイテム
yorifujiyorifuji

pull_requestとpull_request_targetの違い

pull_request

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にアクセスできるため)
  • 補足

共通

https://pankona.github.io/blog/2021/03/29/github-actions-pull-request-target/

https://zenn.dev/shunsuke_suzuki/articles/secure-github-actions-by-pull-request-target

https://zenn.dev/koji_1009/articles/93ed9db1896c5d

ピン留めされたアイテム
yorifujiyorifuji

構造化されたデータ(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

https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions#naming-your-secrets

バイナリの場合はbase64へ変換して登録、decodeしてファイルへ書き出す

https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions#storing-base64-binary-blobs-as-secrets

JSONについてもkeyの単位で個別にsecretとして登録すべきという指摘もある、確実にマスクするため

https://engineering.mercari.com/blog/entry/20230609-github-actions-guideline/

yorifujiyorifuji

Workflow内でGITHUB_TOKENを使ってイベントのトリガーを生成してもループしない
https://docs.github.com/ja/enterprise-cloud@latest/actions/using-workflows/triggering-a-workflow

リポジトリ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."

yorifujiyorifuji

composit action

再利用可能なローカルアクションの作成
https://docs.github.com/en/actions/creating-actions/creating-a-composite-action

https://zenn.dev/tmrekk/articles/5fef57be891040

secretsは参照できない
https://zenn.dev/tmknom/books/pragmatic-composite-action/viewer/implementation

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

yorifujiyorifuji

jobを跨いで成果物を扱う方法

https://qiita.com/dr666m1/items/9c19b323e8c4e837827c#artifactとして渡すドキュメント

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
yorifujiyorifuji

https://zenn.dev/link/comments/022608025daf21

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

yorifujiyorifuji
      - 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)
yorifujiyorifuji
yorifujiyorifuji
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)
yorifujiyorifuji

https://github.com/actions/create-github-app-token

使用例

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

Xcodeのサポートポリシー
https://github.com/actions/runner-images?tab=readme-ov-file#support-policy

  • 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
yorifujiyorifuji

キャッシュをサイズでソートして表示

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
}'