YAML設定リファレンス
Probeがワークフローファイルから読み取るキー、式が評価されるコンテキスト、バリデーションの規則をまとめます。
ワークフローの構造
以下の雛形は、ワークフローファイルに書けるプロパティと、それぞれの位置を示しています。
name: string # 必須: ワークフロー名
description: string # 任意: ワークフローの説明
vars: # 任意: ワークフロー変数
key: value
secrets: # 任意: 出力で伏せる環境変数
- NAME
defaults: # 任意: すべてのジョブに効く、アクションごとの with の既定値
http:
url: string
actions: # 任意: 外部アクションに付ける名前
name: string
jobs: # 必須: ジョブのリスト
- name: string # 必須: ジョブ名
id: string # 任意: ジョブ ID。needs から参照する
needs: [job-id, ...] # 任意: 依存するジョブ
always: boolean # 任意: 依存先のジョブが失敗しても実行する
skipif: expression # 任意: 真ならジョブをスキップ
fail_fast: boolean # 任意: 失敗したステップより後のステップをスキップ
defaults: # 任意: アクションごとの with の既定値
http:
url: string
repeat: # 任意: ジョブを繰り返す
count: integer
interval: duration
async: boolean
warmup: integer
test: expression # 任意: 全回に対するアサーション
baseline_test: expression # 任意: 以前の実行と比べるアサーション
steps: # 必須: ステップのリスト
- name: string # 任意: ステップ名
id: string # 任意: ステップ ID。outputs をこの ID から読める
uses: string # 必須: アクション名、または actions で付けた名前
with: # 任意: アクション引数
key: value
test: expression # 任意: アサーション
echo: string # 任意: レポートに出力する文字列
vars: # 任意: ステップ変数
key: value
outputs: # 任意: 後続へ渡す値
key: expression
skipif: expression # 任意: 真ならステップをスキップ
wait: duration # 任意: 実行前の待機
timeout: duration # 任意: ステップのタイムアウト
iteration: # 任意: 要素ごとにステップを繰り返す。
- key: value # リスト、またはリストになるテンプレート
retry: # 任意: 失敗時のリトライ
max_attempts: integer
interval: duration
initial_delay: durationjobsはリストです。ジョブIDをキーにしたマップで書くと読み込みに失敗します。
トップレベルのenvはありません。環境変数はvarsを通して読みます。
トップレベルのプロパティ
ワークフローファイルのルートには、jobsのほかに6つのプロパティを置きます。名前、説明、開始時点の値、そのうち表示してはいけない値、ステップが共有するwithの値、そして外部アクションに付ける名前です。
name
型: String(必須) 説明: ワークフロー名。レポートの先頭に表示されます。
name: "API Health Check"description
型: String(任意) 説明: ワークフローの説明。
description: |
本番 API を確認します。
- エンドポイントの死活
- レスポンスタイムvars
型: Object(任意)
説明: すべてのジョブとステップからvars.<name>で参照できる変数です。
環境変数が見えるのはvarsの中だけで、変数名をそのまま書いて参照します。値は最初のジョブが始まる前に一度だけ評価されます。
vars:
# 環境変数を読む
api_url: "{{API_URL}}"
# デフォルト付き
timeout: "{{REQUEST_TIMEOUT ?? '30s'}}"
# 読み込み時に計算する
run_id: "{{random_str(8)}}"
# ネストした値も書ける
auth:
user: "{{API_USER}}"varは、probe --var api_url=http://localhost:8080 workflow.ymlのようにワークフローの実行時に与えることもできます。与えた値はここに書いた値の代わりにそのまま使われ、それを読む他のvarもその値を読みます。--varと、環境にない変数をファイルから読む--env-fileを参照してください。
ステップの式から環境変数を直接読むことはできません。式のコンテキストにenvは存在しないため、varsに置いてvars.<name>で参照します。
ある変数から別の変数をvars.<name>で参照できます。参照先がブロックのどこに書かれていても構いません。各変数は参照している変数の後に評価されるため、ランダムなパスワードのように一度だけ計算される値は、それを使って組み立てたどの変数でも同じになります。
vars:
http_port: "{{HTTP_PORT ?? '18080'}}"
base: "http://localhost:{{vars.http_port}}"
password: "{{PASSWORD ?? random_str(24)}}"
basic_auth: "Basic {{encode_base64('alice:' + vars.password)}}"直接または他の変数を経由して自分自身を参照する変数があると、最初のジョブが始まる前にvars: circular reference: a -> b -> aのように経路を示すエラーでワークフローが止まります。変数でない名前は nil として読まれるので、vars.<name> ?? 'default'はデフォルト値になります。vars[KEY]のように実行時に決まるキーでvarsを読む変数は、他のすべての変数の後に評価されます。テンプレートファイルから作る変数のようにtemplateを呼ぶ変数は、テンプレートが何を読むかが実行するまで分からないため、templateを呼ばないすべての変数の後に評価されます。テンプレートが、templateを呼ぶ別の変数のうちまだ評価していないものを読む場合は、その変数を先に評価します。両者の参照が循環していれば、ほかの変数の循環と同じくワークフローを止めます。
リストの中のテンプレートも、マップと同じくどの深さでも評価されます。ports: ["{{vars.http_port}}"]はポート番号を持ちます。
nil のフィールドを読む{{nothing.here}}のように評価できないテンプレートを持つ変数があると、最初のジョブが始まる前に終了ステータス2でワークフローが止まります。エラーにはvars.a: {{nothing.here}}: cannot fetch here from <nil>のように変数とテンプレートが示されます。評価できなかった変数を参照する変数は評価しないため、同じエラーが重ねて出ることはありません。
secrets
型: 文字列の配列(任意) 説明: Probeが表示・書き出すものに、値を出してはいけない環境変数の名前です。
secrets:
- API_TOKEN
- DB_PASSWORD
vars:
api_token: "{{API_TOKEN}}"
db_password: "{{DB_PASSWORD}}"列挙した変数の値が現れる箇所には、代わりに<secret:NAME>と書きます。対象は、端末のレポート、ステップ名、echo、失敗したステップについて表示するリクエストとレスポンス、--verboseの出力、アクション自身のログ、--reportで書き出すファイルです。エラーメッセージで引用符に囲まれたときやJSONに埋め込まれたときのエスケープされた形も伏せます。ステップ、テスト、outputsは本来の値をそのまま使い、変わるのは表示だけです。
設定されていない名前や空文字列の名前は、伏せる値が無いので無視します。短い値は現れるたびに置き換えるため、1のような値を指定すると出力中のすべての1が伏せられます。
secretsとは別に、Authorization、Proxy-Authorization、Cookie、Set-Cookieヘッダの値は常に<redacted>と表示します。ログインのステップが返し、後のリクエストで送るトークンのように、実行中に得た値はsecretsに書けませんが、これらのヘッダのどれかで送られます。Probeはアクションがこれらの値を送る直前と受け取った時点で値を記録し、以降はアクション自身のログも含めて伏せます。
アクションに渡す資格情報も同じです。withのどの階層にあってもpassword、key_passphrase、secret_access_key、session_tokenの値は<redacted>と表示します。dsnやurlに書いたredis://user:password@hostのようなURLは、パスワードの部分だけを伏せ、それ以外はそのまま表示します。そのため、ステップに直接書いたパスワードは、secretsに書かなくても--verboseの出力やアクションのログに出ません。こうした値のテンプレートを評価できなかった場合、エラーにはwith.passwordのように値の場所を示しますが、理由は示しません。テンプレートにもエラーの文面にも資格情報が含まれうるためです。urlがこの扱いになるのは、redis://app:{{vars.pw}}@hostのようにテンプレートがユーザー情報の部分にある場合だけです。urlのそれ以外の場所にあるテンプレートのエラーは表示します。
defaults
型: Object(任意)
説明: すべてのジョブのステップに効くwithの既定値です。ジョブのdefaultsと同じく、アクションをキーにして書きます。
ベースURLやDSNのようにどのジョブも使う接続先は、ジョブごとではなくここに一度だけ書きます:
defaults:
db:
dsn: "postgres://{{vars.user}}@{{vars.host}}/app"
http:
url: "{{vars.api_url}}"
headers:
accept: application/json
jobs:
- name: Rows
steps:
- name: Count users
uses: db
with:
query: SELECT count(*) AS n FROM users
test: res.rows[0].n > 0
- name: API
defaults:
http:
headers:
authorization: "Bearer {{vars.token}}"
steps:
- name: List users # 既定の url に、両方のヘッダーを付けて送る
uses: http
with:
get: /users
test: res.code == 200もっとも近くに書いた値が優先されます。ステップがwithに書いた値、そのジョブのdefaults、ワークフローのdefaultsの順です。オブジェクトはキーごとにマージされるので、上のステップはワークフローのacceptヘッダーとジョブのauthorizationヘッダーの両方を送ります。既定値の中のテンプレートは、ステップの実行時に、そのステップのvarsとoutputsで評価されます。
ワークフローのdefaultsは、embeddedアクションで実行するジョブファイルには適用されません。ジョブファイルは独立したファイルで、自身のdefaultsを持ちます。
actions
型: 文字列のオブジェクト(任意)
説明: ワークフローが使う外部アクションに付ける名前です。ステップのusesと、ジョブやワークフローのdefaultsのキーに、リポジトリとコミットの代わりにこの名前を書けます。
actions:
graphql: github.com/mozership/probe-graphql@41e4ffa222db58c63c7169117c919e6d252bdbf9 # v0.2.0
jobs:
- name: Countries API
defaults:
graphql:
url: https://countries.trevorblades.com/graphql
steps:
- name: Look up Japan
uses: graphql
with:
query: '{ country(code: "JP") { capital } }'
test: res.data.country.capital == "Tokyo"アクションを固定するコミットを書く場所が1か所になるので、新しいリリースへの更新は1行の変更で済みます。
- 名前に使えるのは英数字、
_、-で、先頭は英数字です。 httpやshellのようなProbeのアクションの名前は付けられません。uses: httpが何を実行するかは、ワークフローによって変わらないようにするためです。そのような名前を付けたワークフローは読み込みに失敗します。- 値は
usesと同じ形式で外部アクションを指定します。40文字のコミットSHAを付けたgithub.com/<owner>/<repo>[/<dir>]@<commit>か、./、../、/で始まるローカルのパスです。テンプレートは書けず、別の名前を指すこともできません。 - ステップでアクションを完全な形で書くこともでき、名前で書いた
defaultsはそのステップにも適用されます。1つのdefaultsに、名前とそれが指すアクションの両方を書くことはできません。
Probeはワークフローを読み込む時点で名前をアクションに置き換えるので、それ以降の処理はすべて完全な形のアクションを扱います。特に--allow-actionには、名前ではなくアクションを指定します。名前で許可すると、その名前が指すアクションをワークフローの側で変えられてしまうためです。
embeddedアクションで実行するジョブファイルは、埋め込む側のワークフローの名前で読まれるので、そのステップとdefaultsでも名前を使えます。名前を付けた外部アクションを参照してください。
ジョブ
jobsはジョブ名からジョブ定義へのマップです。ジョブは順に実行するステップをまとめ、依存先を宣言します。
ジョブのプロパティ
ジョブの定義では以下のプロパティを指定します。
| プロパティ | 型 | 必須 | 説明 |
|---|---|---|---|
name | String | 必須 | ジョブ名。テンプレート式が使えます |
id | String | 任意 | 他ジョブのneedsから参照する識別子。省略時は自動採番されます |
needs | Array | 任意 | 先に完了している必要があるジョブのID |
always | Boolean | 任意 | needsのジョブが失敗していても、それらが終わり次第実行する |
steps | Array | 必須 | 実行するステップ |
skipif | Expression | 任意 | 真ならジョブ全体をスキップ |
fail_fast | Boolean | 任意 | 失敗したステップより後のステップをスキップ |
defaults | Object | 任意 | アクション名をキーとしたwithの既定値 |
repeat | Object | 任意 | ジョブを繰り返す |
ジョブにif、continue_on_error、timeoutはありません。失敗の後にも実行したいジョブにはalwaysを付けます。
needs
依存のないジョブは並列に開始します。needsが参照するのはジョブのIDなので、依存される側には明示的なidが必要です。
jobs:
- id: setup
name: Setup
steps:
- name: Prepare
uses: hello
echo: "ready"
- name: Test
needs: [setup]
steps:
- name: Run
uses: hello
echo: "testing"always
ジョブは、needsに書いたジョブが失敗したとき、または同じ理由でスキップされたときにスキップされます。always: trueを付けたジョブは、needsのジョブがどう終わったかにかかわらず、すべてが終わり次第実行されます。他のジョブが作ったものを片付けるジョブに必要な動作です。これがないと、失敗した実行はテスト用のデータベースやファイルを残し、次の実行はそれらが残っているために失敗します。
jobs:
- id: setup
name: Setup
steps:
- name: Create the test database
uses: db
with:
dsn: "{{vars.admin_dsn}}"
query: CREATE DATABASE probe_test
test: res.code == 0
- id: tests
name: Tests
needs: [setup]
steps:
- name: Count users
uses: db
with:
dsn: "{{vars.test_dsn}}"
query: SELECT count(*) AS n FROM users
test: res.rows[0].n > 0
- name: Cleanup
needs: [setup, tests]
always: true
steps:
- name: Drop the test database
uses: db
with:
dsn: "{{vars.admin_dsn}}"
query: DROP DATABASE IF EXISTS probe_test
test: res.code == 0- このジョブも
needsのすべてのジョブを待ちます。繰り返すジョブは全回の実行を待ちます。片付ける対象を作るジョブはすべてneedsに書き、それらと並行して走らないようにします。 - 実行全体の成否は変わりません。
alwaysが変えるのはどのジョブが走るかであり、終了ステータスではありません。 - 失敗またはスキップされたジョブが公開しなかったoutputはnilとして読まれます。
DROP DATABASE IF EXISTSのように、それがなくても動くステップを書きます。 alwaysを付けたジョブをneedsに書いたジョブは、他のジョブに対してと同じく、そのジョブの結果に従います。skipifは引き続き有効です。両方を書いたジョブは、式が真ならスキップされます。
skipif
ブール式です。真と評価されるとジョブをスキップします。
jobs:
- name: Production only
skipif: vars.environment != "production"
steps:
- name: Check
uses: http
with:
url: "{{vars.api_url}}/health"
method: GETfail_fast
ジョブのステップは順番に実行され、前のステップが失敗していても次のステップは実行されます。これは、それぞれが別のことを確かめていて、レポートに1行ずつ残す価値があるステップに向いています。一方、後のステップが前のステップの作ったものを使う場合、後のステップは前の失敗が原因で失敗し、本当に見るべき1つの失敗が、そこから派生した失敗に紛れて見分けにくくなります。fail_fast: trueを付けると、失敗したステップより後のステップは実行されず、スキップとして報告されます:
jobs:
- name: Orders
fail_fast: true
steps:
- name: Create the table
uses: db
with:
query: CREATE TABLE orders (id INTEGER PRIMARY KEY, total INTEGER)
test: res.code == 0
- name: Insert an order # テーブルを作れなかったときはスキップ
uses: db
with:
query: INSERT INTO orders (total) VALUES (?)
params: [100]
test: res.rows_affected == 1- ステップが失敗するのは、
testが偽のとき、アクションがエラーを返したとき、レスポンスが契約に違反したときです。testがなく何にも検査されないステップは失敗しないので、何も止めません。 - スキップされたステップは
waitを待たず、outputsも公開しません。 iterationの残りのエントリも、どれかが失敗した時点でスキップされます。repeatを付けたジョブは、実行のたびにやり直します。失敗によってスキップされるのは、その回の残りのステップだけです。ステップが実行されなかった回は、そのステップの成功にも失敗にも数えず、1/3 success (33.3%), 2 skippedのように別に示します。- 他のジョブには影響しません。失敗したジョブ一般と同じく、
needsを通した影響だけがあります。後片付けのように失敗の後にも実行したいステップは、alwaysを付けたジョブに書きます。
defaults
ジョブ内の該当アクションを使うステップのwithにマージされる既定値です。ステップ側の指定が優先され、ここでの指定は、すべてのジョブが共有するワークフローのdefaultsより優先されます。キーはステップがusesに書くものです。組み込みアクションの名前、完全な形の外部アクション、actionsで付けた名前のどれかです。
jobs:
- name: API checks
defaults:
http:
url: "{{vars.api_url}}"
headers:
authorization: "Bearer {{vars.token}}"
accept: application/json
steps:
- name: Health
uses: http
with:
get: /health # 既定の url からの相対パス
test: res.code == 200httpアクションはメソッドの指定が必須です。methodを明示するか、get / post / put / delete / patchといった省略記法を使います。省略記法の値は完全なURLか、urlからの相対パスです。
- name: Explicit method
uses: http
with:
url: "{{vars.api_url}}/health"
method: GETrepeat
repeatはジョブ全体を一定の間隔で繰り返します。この指定でテストを繰り返し実行すると、監視として使えます。
| プロパティ | 型 | 必須 | 説明 |
|---|---|---|---|
count | Integer | 必須 | 実行回数。上限はPROBE_MAX_REPEAT_COUNT(既定10000) |
interval | Duration | 任意 | 1回の実行が終わってから次を始めるまでの待ち時間。asyncのときは、1回の実行を始めてから次を始めるまでの間隔で、必須 |
async | Boolean | 任意 | 前の実行の終わりを待たずに次の実行を始める |
warmup | Integer | 任意 | countの前に行う実行の回数。どの集計にも含めない。countとの合計がPROBE_MAX_REPEAT_COUNTの上限を受ける |
test | Expression | 任意 | すべての回が終わった後に、各ステップの回の集計に対して評価する。指定した場合は、これだけでジョブの成否が決まる。全回に対するテストを参照 |
baseline_test | Expression | 任意 | すべての回が終わった後に、各ステップの回の集計と、--baselineで指定した実行の集計に対して評価する。指定がなければスキップする。以前の実行と比べるテストを参照 |
jobs:
- name: Poll until ready
repeat:
count: 10
interval: 5s
steps:
- name: Check
uses: http
with:
url: "{{vars.api_url}}/status"
method: GET
test: res.code == 200warmupの回は最初に行います。intervalとasyncも含めてほかの回と同じように実行しますが、結果には含めません。ステップが失敗してもジョブは失敗しません。ただし、名前を評価できないなどジョブを開始できない場合は、ほかの回と同じくwarmupの回でも失敗します。成否の回数と応答時間は、その後のcount回について数えます。計測する回の前に、サービスがキャッシュやコネクションプールを満たす時間を取るためのものです。
各回のステップは、同じ回の前のステップが公開した出力を読みます。asyncで複数の回が同時に動く場合も同じです。後続のジョブは、それぞれの出力について、最後にそれを公開した回の値を読みます。そのため、最後の回が飛ばしたステップの出力は、その前の回の値になります。
全回に対するテスト
repeat.testがなければ、ステップが失敗した回が1回でもあるとジョブは失敗します。repeat.testは、すべての回が終わった後に各ステップの回の集計に対して評価され、これだけでジョブの成否が決まります。
jobs:
- name: Search
repeat:
count: 100
interval: 100ms
warmup: 5
test: steps.search.success_rate >= 0.99 && steps.search.rt.p95 < 0.3
steps:
- name: Search by keyword
id: search
uses: http
with:
url: "{{vars.api_url}}"
get: /search?q=probe
test: res.code == 200式からは、ワークフローの変数varsと、ジョブの各ステップの回の集計stepsを読めます。stepsのキーはステップのidで、idのないステップはstep_0のように番号で指定します。
| フィールド | 型 | 説明 |
|---|---|---|
runs | Integer | 数えた回数。success、failure、skippedの合計 |
success | Integer | ステップが成功した回数。ステップ自身のskipifでスキップされた回を含む |
failure | Integer | テストが失敗した回数と、アクションがエラーを返した回数の合計 |
skipped | Integer | ステップが実行されなかった回数。fail_fastのジョブで前のステップが失敗した回と、iterationに要素がなかった回 |
success_rate | Float | successをrunsで割った値。0から1 |
rt | Object | アクションが時間を返した回の所要時間。rt.secと同じく秒単位で、min、mean、p50、p90、p95、p99、maxを持つ。時間を返した回がなければnil |
パーセンタイルは、レポートの応答時間と同じく最近接順位法によるものです。warmupの回はどれにも数えません。iterationのあるステップは、すべての要素の回をまとめて数えます。
repeat.testを指定すると、各回の結果は数えるだけになり、それ自体では何も失敗させません。
- ステップが失敗した回があってもジョブは失敗しません。ステップは成功として報告し、失敗した回は
repeatの回数に数えます。 - テストが真ならジョブは成功し、偽のとき、評価できないとき、真偽値でないときは失敗します。偽のときは、ステップのテストと同じく、どの条件が偽だったかと、比べた値を示します。
- 終了ステータスはテストの結果で決まります。テストが失敗すれば、各回が何で失敗したかに関係なく1です。
- 数える回をすべて
skipifがスキップしたジョブはスキップとなり、テストは評価しません。一部の回だけをスキップした場合は、実行した回に対してテストを評価します。
以前の実行と比べるテスト
repeat.baseline_testは、各回を以前の実行(--baselineで指定したレポート)と比べます。すべての回が終わった後、repeat.testの次に評価します。repeat.testが読めるものに加えて、baseline.stepsの下で、以前の実行における同じジョブのステップをidで読めます。
jobs:
- name: Search
repeat:
count: 100
warmup: 5
test: steps.search.success_rate >= 0.99
baseline_test: steps.search.rt.p95 < baseline.steps.search.rt.p95 * 1.2
steps:
- name: Search by keyword
id: search
uses: http
with:
url: "{{vars.api_url}}"
get: /search?q=probe
test: res.code == 200レポートに記録される項目が少ないので、baseline.stepsの下のステップはstepsの下より少ないフィールドを持ちます。
| フィールド | 型 | 説明 |
|---|---|---|
runs | Integer | 数えた回数 |
success | Integer | ステップが成功した回数 |
success_rate | Float | successをrunsで割った値。0から1 |
rt | Object | ステップの所要時間。レポートの応答時間から取り、秒単位でstepsの下と同じフィールドを持つ。時間がなければnil |
ジョブはidが同じジョブと、ステップはidが同じステップと対応させます。iterationのあるステップは、レポートでは同じidの複数のステップになります。runsとsuccessはそれらの合計ですが、時間はパーセンタイルからまとめられないので、rtはnilになります。
--baselineを指定しなかったとき、テストがbaseline.stepsの下で読むステップが以前の実行にないとき、rtの下で読む時間がないときは、テストをスキップし、ジョブはこのテストでは失敗しません。そのため、同じワークフローを--baselineの有無にかかわらずそのまま実行できます。スキップしたときは、skipped: the baseline has no step searchのように理由を示します。以前の実行にテストが読むものがあるかを実行前に判断できるのは、ステップとフィールドが式に直接書かれているときだけです。そのため、baseline.steps[vars.id]のように実行時に決まるキーでステップやフィールドを読むテストは、ワークフローを読み込む時点で拒否し、終了ステータス2で終わります。
評価した場合は、テストが成り立つときだけジョブは成功し、終了ステータスはrepeat.testと同じくテストの結果で決まります。各回の失敗の扱いは変えません。repeat.testがなければ、ステップが失敗した回があるとジョブは失敗します。baselineを読めるのはこのテストだけです。baseline.stepsにないステップやフィールドを読むbaseline_testは、probe checkが報告します。
ステップ
ステップは1回のアクション呼び出しと、その周辺の指定から成ります。実行するかを決める条件、成功したかを決めるテスト、後続のステップに残す出力です。
ステップのプロパティ
ステップの定義では以下のプロパティを指定します。
| プロパティ | 型 | 必須 | 説明 |
|---|---|---|---|
uses | String | 必須 | 実行するアクション。http、shellなどの組み込みアクションか、外部アクション |
name | String | 任意 | ステップ名 |
id | String | 任意 | このステップのoutputsの名前空間になる識別子 |
with | Object | 任意 | アクション引数 |
test | Expression | 任意 | アサーション。偽ならステップは失敗します |
echo | String | 任意 | レポートに出力する文字列 |
vars | Object | 任意 | ステップ内だけの変数 |
outputs | Object | 任意 | 後続のステップやジョブへ渡す値 |
skipif | Expression | 任意 | 真ならステップをスキップ |
wait | Duration | 任意 | 実行前の待機時間 |
timeout | Duration | 任意 | ステップのタイムアウト(既定5m)。その時点で実行中のアクションは停止され、ステップは失敗する |
iteration | Array またはテンプレート | 任意 | 要素ごとにステップを繰り返す。値はvarsから参照します |
retry | Object | 任意 | 失敗時のリトライ |
キーはactionではなくuses、条件はifではなくskipifです。
outputs
後続のステップやジョブへ渡す値です。outputs.tokenのように名前で読めます。ステップにidがあれば、outputs.auth.tokenのようにidからも読めます。ほかのステップが同じ名前を公開する場合は、それぞれの値を読めるようにステップにidを付けてください。
値はテンプレートではなく式なので、波カッコは書きません。
steps:
- name: Log in
id: auth
uses: http
with:
url: "{{vars.api_url}}/login"
method: POST
test: res.code == 200
outputs:
token: res.body.access_token
user_id: res.body.user.id後続からはステップIDで名前空間を指定するか、出力名だけで参照します。
headers:
Authorization: "Bearer {{outputs.auth.token}}"
X-User: "{{outputs.user_id}}"ハイフンを含むIDは式の識別子として解釈できないため、ブラケットで参照します。
echo: "{{outputs['create-user'].user_id}}"retry
retryは、テストが通るか試行回数を使い切るまで、そのステップだけを繰り返します。
| プロパティ | 型 | 必須 | 説明 |
|---|---|---|---|
max_attempts | Integer | 必須 | 試行回数。1以上で、上限はPROBE_MAX_ATTEMPTS(既定10000) |
interval | Duration | 任意 | 試行間隔 |
initial_delay | Duration | 任意 | 最初の試行前の待機 |
steps:
- name: Flaky endpoint
uses: http
with:
url: "{{vars.api_url}}/slow"
method: GET
test: res.code == 200
retry:
max_attempts: 3
interval: 2siteration
要素ごとにステップを繰り返します。各要素のキーはvarsから参照できます。
steps:
- name: Check {{vars.path}}
uses: http
iteration:
- path: /health
- path: /metrics
- path: /version
with:
url: "{{vars.api_url}}{{vars.path}}"
method: GET
test: res.code == 200iterationには、ワークフローに書いたリストの代わりに、オブジェクトのリストになるテンプレートを1つ書けます。テンプレートはステップに到達した時点で、ワークフローとステップのvars、それまでに公開されたoutputsを使って評価されます。そのため、ファイルに置いたケースや、前のステップで取得した値を要素にできます:
steps:
# ファイルのケースごとに1回実行。ケースはワークフローを変えずに増やせる
- name: "{{vars.name}} can sign in"
uses: http
iteration: "{{ parse_json(file('testdata/users.json')) }}"
with:
post: /login
body:
user: "{{vars.name}}"
password: "{{vars.password}}"
test: res.code == 200
- name: List orders
id: orders
uses: db
with:
query: SELECT id, total FROM orders WHERE status = 'open'
test: res.code == 0
outputs:
rows: res.rows
# 上のステップが読んだ行ごとに1回実行
- name: "Order {{vars.id}} has a total"
uses: http
iteration: "{{ outputs.orders.rows }}"
with:
get: "/orders/{{vars.id}}"
test: res.body.total == vars.total- 値は
{{ }}のテンプレート1つだけです。前後に文字があるもの、テンプレートが2つあるものは文字列になってしまうため、ワークフローの読み込みに失敗します。 - 各要素はオブジェクトで、そのキーをステップが
varsとして読みます。文字列のリストなど、それ以外のリストはステップを失敗させます。"{{ map(vars.paths, ({path: #})) }}"のようにmapでオブジェクトに変換してください。 - 評価できないテンプレート、リストにならないテンプレートは、ステップを実行せずに失敗させます。
- 要素のないリストはステップをスキップし、スキップとして報告します。実行に使う値がないためです。空のリスト
[]として書いたiterationは、iterationのないステップと同じく1回実行します。 - 要素はそのまま使われます。要素の値に書いた
{{ }}は評価されません。ステップ自身のvarsは、テンプレートのために評価され、さらに要素ごとにも評価されます。ワークフローに書いたリストの要素ごとに評価されるのと同じです。random_strを呼ぶvarは、そのたびに別の値になります。 iterationが受け取れる要素は1,048,576個までです。それより長いリストはステップを失敗させます。repeatを付けたジョブでは、テンプレートは回ごとに評価され、回によって要素数が変わることがあります。各要素はリスト内の位置ごとに集計され、後続のステップはそれぞれ自身として集計されます。リストに要素がなかった回は、fail_fastのジョブで実行されなかった回と同じく、そのステップの成功にも失敗にも数えません。
式のコンテキスト
ステップの式から見えるのは次の名前だけです。
| 名前 | 型 | 説明 |
|---|---|---|
vars | Object | ワークフローの変数にステップのvarsをマージしたもの |
res | Object | アクションのレスポンス |
req | Object | 送信したリクエスト |
rt | Object | レスポンスタイム。rt.duration(文字列)とrt.sec(秒、浮動小数点数) |
status | Integer | アクションの終了ステータス。成功は0 |
outputs | Object | 先行ステップが公開した値 |
repeat_index | Integer | ジョブ繰り返し時の現在のインデックス。0から始まり、warmupの回も数える |
このコンテキストにenv、jobs、stepsはありません。
httpのres
resの内容はアクションごとに異なります。httpでは以下が入ります。
| フィールド | 型 | 説明 |
|---|---|---|
res.code | Integer | ステータスコード(例: 200) |
res.status | String | ステータス行(例: "200 OK") |
res.headers | Object | レスポンスヘッダー。キーはContent-Typeのような正規形 |
res.body | Any | レスポンスボディ。JSONならオブジェクトや配列に解析され、それ以外は文字列 |
res.rawbody | String | 解析前のボディ。JSONとして解析したときに入ります |
test: |
res.code == 200 &&
res.headers["Content-Type"] contains "application/json" &&
res.body.status == "ok" &&
rt.sec < 1他のアクションのresはアクションリファレンスを参照してください。
データ型
ワークフローファイルの値のうち、独自の書き方を持つものが2つあります。時間の長さと、コンテキストを参照する式やテンプレートです。
Duration
Goのduration文字列か、秒数の数値で指定します。
timeout: "30s"
timeout: "5m"
interval: 10 # 10 秒式とテンプレート
テンプレート式は文字列の中に書き、評価結果で置き換わります。
url: "{{vars.api_url}}/users/{{outputs.auth.user_id}}"ブール式は波カッコなしでそのまま書きます。
test: res.code == 200 && rt.sec < 2
skipif: vars.environment == "local"outputsの値も式なので、波カッコは書きません。
評価できないテンプレートはエラーになり、エラーの文面が値に入ることはありません。定義されていない名前は nil として読まれエラーになりませんが、nil のフィールドを読むことや、構文として解釈できない式はエラーです。
| テンプレートの場所 | 起きること |
|---|---|
ステップのwith、vars、name | ステップは種類templateで失敗し、アクションは実行されません。エラーにはwith.headers.authorizationのように値の場所が示されます |
ワークフローのvars | 最初のジョブの前に終了ステータス2でワークフローが止まります |
ジョブのname | ジョブが失敗し、終了ステータスは2です |
ステップのecho | 本文の代わりにエラーを表示し、ステップの結果は変わりません |
# 先行するステップが outputs.login を出力していなければ、ステップは失敗する
headers:
authorization: "Bearer {{outputs.login.token}}"
# 代わりの値を使う
headers:
authorization: "Bearer {{outputs.login?.token ?? 'none'}}"式の中で使える関数は組み込み関数を参照してください。
バリデーション規則
- ワークフローには
nameが必要で、jobsは空でないリストである必要があります - 各ジョブには
nameと1つ以上のステップが必要です - 各ステップには
usesが必要で、アクションを指している必要があります。Probeのアクション、外部アクション、actionsで付けた名前のいずれかです。どれでもない場合は、スキップされるステップであっても、最初のジョブの前に終了ステータス2で実行が止まります actionsの名前はProbeのアクションの名前であってはならず、コミットで固定した外部アクションかローカルのパスを指す必要がありますneedsは存在するジョブIDを指し、依存関係は循環していない必要がありますrepeat.countとrepeat.warmupは0以上、retry.max_attemptsは1以上である必要があります
probe checkは、受け付けないキー、解析できない式、公開される前に読む出力とあわせて、これらをワークフローを実行せずに報告します。CLIリファレンスを参照してください。
ファイルのマージ
複数のファイルをカンマ区切りで渡すと順に連結されます。複数回定義されたトップレベルのキーは、最後のファイルの値になります。
probe base.yml,production.ymlマージの規則はファイルマージを参照してください。