Lambdaカクテル

京都在住Webエンジニアの日記です

Invite link for Scalaわいわいランド

GitHub ActionsでJSONを組み立てるのは actions/github-script 経由が一番早そう

GitHub Actionsでworkflowを組んでいると、外部ツールと組合わせるために、JSONを組み立てなければならないことがある。Actionに直接渡すだけだとJSONの出る幕はあまりないが、外部サービスになんかするといった時にはすぐJSONが必要になりがち。

二重の苦労

従来は頑張ってJSON="{\"foo\": \"$BAR\"}"みたいに素朴に文字列を組み立てていたけれど、これがすんなりいく訳もなく、大抵3回は変数の展開に失敗する。bashでは変数展開をしたければdouble quotationでくくる必要があるけれど、JSONのオブジェクト表記におけるフィールド名もdouble quotationでくくる必要があるので、ネスト地獄が発生する。また、これを渡すときも大変で、ファイルで渡したければ<(cat $JSON)と書いてfile substitutionを使う必要がある。

  • 二重の苦労
    • 組み立てるのに苦労
      • 変数展開が大変
      • double quotationがネストする
    • 渡すときに苦労
      • ファイルで渡したいときどうする
      • ちなみにnode.jsはfile substitutionに非対応なので一旦ファイルに置く必要がある

ちなみにcat <<EOF > data.jsonなどのようにして一旦ファイルに置くとnode.jsのようなfile substitutionに非対応のコマンドなどでも使えるけれど、けっこう不毛な感じになってしまう。

渡すときの苦労はファイルに置くことで(なんか不毛だけど)大抵の場合はなんとかなるのでこれで納得している。

actions/github-script で組み立てを簡単にする

JSONを組み立てるときは、色々試した結果、actions/github-script@v6でオブジェクトを組み立てて、JSON.stringify()を用いて文字列をゲットし、それをそのステップのoutputとして出力すると便利。

例えば、次に示すのはCIの実行時間をMackerelにポストするといった例。

      - uses: actions/github-script@v6
        id: create-body
        with:
          result-encoding: string // 文字列で受け取れる
          script: |
            const time = Date.now() / 1000
            // ${{}} による変数展開も可能
            const start = ${{ needs.recordstarttime.outputs.ci_start_epoch }}
            const end = ${{ needs.recordendtime.outputs.ci_end_epoch }}
            const body = [
              {
                name: 'ci.ciyaml.elapsed_sec.sec',
                time: time,
                value: end - start
              }
            ]
            return JSON.stringify(body)
      - name: Post Mackerel
        uses: yutailang0119/action-mackerel-api@v3
        with:
          api-key: ${{ secrets.MACKEREL_API_KEY }}
          http-method: POST
          path: services/うんたらかんたら/tsdb
          body: ${{ steps.create-body.outputs.result }}

苦行から解放された。便利。

★記事をRTしてもらえると喜びます
Webアプリケーション開発関連の記事を投稿しています.読者になってみませんか?