GitHub Actions で jq を使って json の input を検証する
GitHub Actions の input の制限
GitHub Actions の Custom actions、Reusable workflows において、input の型には制限があります。
Custom actions では string のみ 1 、Reusable workflow では string
、number
、boolean
から選びます。
JSON のような複雑な構造を定義出来ないため、input で扱う場合は JSON 文字列として渡すしかないです。 JSON 文字列を jq でパースして必要な値を取り出して Action の処理を開始すれば良いだけの話ではありますが、処理の前に入力値検証をしたくなるのは当然ですね?
jq のフィルター結果に従って --exit-status
でコマンドを失敗させることが出来るので、jq の入力値検証でコケさせる方法を確認しようと思います。
string
型のフィールド
「string
型の name
フィールドを持つ JSON」の配列かどうかを確認します。
// TypeScript で書くとこんな感じ
type JsonArray = {
name: string;
}[];
all(generator; condition)
で配列内の全ての要素が true かどうかを検証します。
要素の期待値は「name
フィールドがstring
型」なので、.[]."name"
でフィールドを取り出して、type == "string"
かどうかを確認しました。
JSON_ARRAY1='[
{ "name": "kotori" },
{ "name": "honoka" }
]'
echo $JSON_ARRAY1 | jq --exit-status 'all(.[]."name"; type == "string")'
true # valid
JSON_ARRAY2='[
{ "name": "kotori" },
{ "name": true }
]'
echo $JSON_ARRAY2 | jq --exit-status 'all(.[]."name"; type == "string")'
false # invalid
Optional なフィールド
「optional な string
型の school
フィールドを持つ JSON」の配列かどうかを確認します。
// TypeScript で書くとこんな感じ
type JsonArray = {
name: string;
school?: string;
}[];
or
operator で 条件を増やします。
has(key)
で school
フィールドがあるかを確認しつつ、not
operator で結果を反転させます。
つまり「school
フィールドがない」を確認をする。
JSON_ARRAY1='[
{ "name": "kotori", "school": "otonoki-zaka" },
{ "name": "alpaca" }
]'
echo $JSON_ARRAY1 | jq --exit-status 'all(.[]; (."school" | type == "string") or (has("school") | not))'
true # valid
JSON_ARRAY2='[
{ "name": "kotori", "school": 1 },
{ "name": "alpaca" }
]'
echo $JSON_ARRAY2 | jq --exit-status 'all(.[]; (."school" | type == "string") or (has("school") | not))'
false # invalid
フィールドの値が重複しない
.[]."name"
で name
フィールドの値を取り出してから、再度 [ ]
で囲って配列にします。
配列に対して、length
で取得した要素数と
unique
で重複排除した配列の要素数
を比較して、同じ数字なら重複がないことが分かります。
pipe した値が (length)
と (unique | length)
両方に渡るのが、ちょっと不思議な感覚…(pipe に慣れていないだけ?)
JSON_ARRAY1='[
{ "name": "kotori" },
{ "name": "honoka" }
]'
echo $JSON_ARRAY1 | jq --exit-status '[.[]."name"] | (length) == (unique | length)'
true # valid
JSON_ARRAY2='[
{ "name": "kotori" },
{ "name": "kotori" }
]'
echo $JSON_ARRAY2 | jq --exit-status '[.[]."name"] | (length) == (unique | length)'
false # valid
Footnotes
-
正確には custom actions では input の型を設定することが出来ないです。 環境変数で値の受け渡しを実現しているので必ず string になっています。 ↩