GitHub Notesアクション
GitHub Notesアクションは、実行のノートをGitHubに投稿します。投稿先は、プルリクエストのコメント、GitHub Actionsのジョブのサマリー、Issueのいずれかです。
アクションは、ステップが通ったかどうかとは別に、人に向けたノートを残せます。後続のステップはそれをnotesとして読み、各ノートにはジョブとステップが付き、シークレットは隠されています。Probeはノートをどこにも投稿しません。投稿するのはこのアクションで、どのタイミングでどのノートを投稿するかはワークフローに書きます。このアクションはノートを投稿するためだけのもので、GitHub全般を操作するアクションではありません。
外部アクションとしてmozership/probe-github-notes で公開しています。ワークフローが初めて使うときにProbeがダウンロードし、固定したコミットのaction.ymlが示すSHA-256と一致する実行ファイルだけを実行します。notesコンテキストを持つ最初のバージョンであるProbe v1.32.0以降が必要です。
基本的な構文
ステップでは40文字のコミットSHAでアクションを固定します。各リリース のノートの先頭に、コピーして使うusesの行があります。このステップは最後のジョブに置き、そのジョブはalways付きでほかのジョブをneedsにします。こうすると、ほかのジョブがどう終わっても、すべて終わったあとに実行され、すべてのノートを読めます。
name: Shop
actions:
github-notes: github.com/mozership/probe-github-notes@76735813d682751a3b743a0dbce0ad49a8d372ad # v0.1.0
secrets:
- GITHUB_TOKEN
vars:
github_token: "{{GITHUB_TOKEN}}"
jobs:
# helloは受け取ったwithをそのままresとして返すので、
# ノートを残すアクションの代わりに使える
- name: Checkout
id: checkout
steps:
- name: A first-time shopper
uses: hello
with:
notes:
- level: critical
title: The checkout button is under the cookie banner
body: On a 390px wide screen the banner covers the button until it is closed.
- level: info
body: The search took 4s to show results.
- name: Notes
needs: [checkout]
always: true
steps:
- name: Put the notes on the pull request
uses: github-notes
with:
to: comment
token: "{{vars.github_token}}"
notes: "{{ notes }}"
test: status == 0ノートの投稿先
toで書き込む先を選びます。
to | 書き込む先 | 次の実行では | ノートがないとき |
|---|---|---|---|
comment | プルリクエストのコメント | 同じコメントを編集する | コメントがあれば、ノートがないことを書いて編集する。新しくは作らない |
summary | GitHub Actionsのジョブのサマリー | ジョブの実行ごとに別のサマリーになる | 何も書かない |
issue | labelsが付いたopenなIssue | openの間は同じIssueを編集する | openなIssueがあれば、ノートがないことを書いて編集し、クローズする。次にノートが出た実行で新しく作る |
コメントは、変更に対して実行するワークフローで、レビューする人に読んでもらうためのものです。サマリーはトークンが要らず、コメントするプルリクエストがない実行や、レビューする人に向けないノートに使います。Issueは、ステージング環境に対して毎晩実行するような定期実行のワークフローで、ノートを作業として追跡するためのものです。実行がノートを残す間はopenのままで、ノートを残さなかった最初の実行でクローズされます。
アクションはkeyごとにコメントかopenなIssueを1つ持ち、本文の先頭に<!-- probe-github-notes:<key> -->というマーカーを書きます。プルリクエストのコメント、またはlabelsが付いたopenなIssueから、マーカーで始まる最初のものを探して編集し、なければ新しく作ります。ノートの一部を別のコメントに投稿するには、別のkeyを使います。
- name: The critical notes, in a comment of their own
uses: github-notes
with:
to: comment
key: critical
token: "{{vars.github_token}}"
notes: "{{ filter(notes, .level == 'critical') }}"同じ場所に投稿する2つの実行が同時に走ると、どちらもコメントを見つけられずにそれぞれ作ることがあり、以降の実行は最初の1つだけを編集します。別々の実行の間をアクションが調整することはできないので、GitHub Actionsのconcurrencyなどで、ワークフローの実行が重ならないようにしてください。
パラメータ
| パラメータ | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
to | String | はい | - | comment、summary、issueのいずれか |
notes | Array | はい | - | "{{ notes }}"のような、notesコンテキストのエントリ。空のリストは、ノートを残さなかった実行として扱う |
body | String | いいえ | - | ノートの上に書くMarkdown |
timeout | Duration | いいえ | 30s | ステップの制限時間。10sのような形式か秒数で指定する |
token | String | comment、issue | - | リポジトリにコメントやIssueを書けるトークン |
repository | String | いいえ | GITHUB_REPOSITORY | owner/name形式のリポジトリ |
key | String | いいえ | probe | アクションが編集するコメントやIssueの名前。英数字、.、_、-を使える |
api_url | String | いいえ | GITHUB_API_URL、なければhttps://api.github.com | REST API。GitHub Enterprise Serverで使う |
number | Integer | いいえ | イベントのプルリクエスト | commentで、コメントするプルリクエストまたはIssue |
title | String | いいえ | Probe notes | issueのタイトル |
labels | Array | いいえ | [probe] | issueに付けるラベル。アクションはこのラベルでIssueを探す |
ほかのtoのためのパラメータは読まないので、ジョブのdefaultsで、どのtoのステップにもtokenを渡せます。どれにも当てはまらないキーは、ステップを失敗させます。action.ymlがこれらをparamsとして宣言しているので、probe checkはそのようなキーを行番号付きで報告します。
notesは、notesコンテキストと同じ形のエントリを受け取ります。levelがinfo、warning、criticalのいずれでもないエントリや、bodyのないエントリがあると、ステップは失敗します。手で書いたリストではなく、コンテキストそのもの、またはfilter(notes, .level != 'info')のようにその一部を渡してください。
to: commentでnumberがないときは、GitHub Actionsの実行を起動したイベントのプルリクエストにコメントします。イベントはGITHUB_EVENT_PATHから読み、pull_requestとpull_request_targetが対象です。ブランチへのpushなどそれ以外のイベントでは、何も投稿せずにステップを通し、res.postedはfalseになります。
GitHub Actionsの実行のトークンGITHUB_TOKENには、書き込みの権限が必要です。プルリクエストへのコメントにはpull-requests: write、IssueやIssueへのコメントにはissues: writeを付けます。Probeが出力の中で隠すように、トークンはsecretsに入れてください。
書き込む内容
先頭の1行でレベルごとのノートの件数を数え、そのあとにジョブとステップの名前の下にノートを並べます。ステップにはその状態と、repeatのジョブであれば何回目の実行かを添えます。ノートはレベルに応じたGitHubのアラートで書き、criticalはCAUTION、warningはWARNING、infoはNOTEです。タイトルと本文はそのまま書きます。
The run left 2 notes: 1 critical, 1 info.
### Checkout
**A first-time shopper** · passed
> [!CAUTION]
> **The checkout button is under the cookie banner**
>
> On a 390px wide screen the banner covers the button until it is closed.
> [!NOTE]
> The search took 4s to show results.
<sub>From [run 123456](https://github.com/owner/name/actions/runs/123456) of _Shop_.</sub>最後の行はGitHub Actionsの実行へのリンクで、GitHub Actionsの外では書きません。Probeが隠した値は、ノートの中では<secret:NAME>や<redacted>になっています。GitHubはこれをHTMLタグとみなして表示しないので、アクションはコードの外ではこれを文字として書きます。コードの中では、そのまま表示されます。
GitHubが受け付けるのは、コメントとIssueでは65536文字まで、ステップのサマリーでは1 MiBまでで、サマリーはそれまでに書かれた分も含みます。これより長いページでは末尾のノートを省き、省いた件数を1行で書きます。ノートをすべて省いても収まらないほどbodyが長いときは、ステップは失敗します。
レスポンスオブジェクト
| プロパティ | 型 | 説明 |
|---|---|---|
res.posted | Boolean | アクションが何かを書いたかどうか |
res.action | String | created、updated、closed(Issue)、written(サマリー)、noneのいずれか |
res.number | Integer | 投稿したプルリクエストかIssue、または投稿するものがなかったプルリクエスト。対象がないときとサマリーでは0 |
res.url | String | GitHub上のコメントかIssue。サマリーでは空 |
res.id | Integer | コメントかIssueのID |
res.code | Integer | GitHubへの最後のリクエストのステータスコード。サマリーでは0 |
req | Object | to、notesの件数、投稿先。トークンは含まない |
rt | Duration | ステップにかかった時間 |
status | Integer | 0 |
書き込めないトークンでの403や、存在しないプルリクエストへの404など、GitHubがエラーを返すと、ステップはGitHubのステータスとメッセージで失敗します。書き込みをGitHubが301や302でリダイレクトした場合も失敗します。そのまま従うと、書き込みが読み取りとして送り直されるためです。
アクションは、GitHubに投稿したノートをres.notesとして返しません。返すと、後続のステップに同じノートがもう一度残るためです。
ガードの下での動作
このアクションは実行のガードに従い、action.ymlでguard: [read-only, allow-host]を宣言しています。そのため、どちらのガードの下でも--allow-actionなしで実行します。拒否したステップは、リクエストを送る前に種類refusedで失敗します。
--read-onlyの下では、to: commentとto: issueはGitHubに書き込むので拒否します。to: summaryはジョブのページにだけ書くので実行します。--allow-hostの下では、api_urlのホストと、各リダイレクト先のホストが、実行が許可するものでなければなりません。GitHubであればapi.github.comです。ポートのないURLは、スキームの既定のポートとして扱います。
ガードを参照してください。