GitHub ActionsでJson fileを作成/更新する方法を確認してみた

2022.05.10

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、CX事業本部 IoT事業部の若槻です。

今回は、GitHub ActionsでJson fileを作成および更新する実装をする機会があり、方法を探してみると何パターンか見つかったため、比較のためそれぞれ試してみました。

確認してみた

次のようなPull Request作成を行うWorkflow configで、Json fileを作成および更新してみます。

.github/workflows/init-post.yml

on:
  issues:
    types:
      - assigned

jobs:
  create_pr:
    runs-on: ubuntu-latest
    env:
      REPO: ${{ github.repository }}
      ISSUE_NUM: ${{ github.event.issue.number }}
      ISSUE_TITLE: ${{ github.event.issue.title }}
      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
    steps:
      - name: Get open linked PR
        id: get_open_linked_pr
        run: |
          open_linked_pr_length=$(\
            gh pr list \
              --repo $REPO \
              --state open \
              --search "close #$ISSUE_NUM in:body" \
              --json number | jq '. | length'\
          )
          echo "::set-output name=open_linked_pr_length::$open_linked_pr_length"

      - name: Check open linked pr length
        if: steps.get_open_linked_pr.outputs.open_linked_pr_length != 0
        run: |
          echo "Unclosed pull request is existing."
          exit 1

      - name: Checkout
        uses: actions/checkout@v3

      - name: Get merged linked PR
        id: get_merged_linked_pr
        run: |
          merged_linked_pr_length=$(\
            gh pr list \
              --repo $REPO \
              --state merged \
              --search "close #$ISSUE_NUM in:body" \
              --json  number | jq '. | length'\
          )
          echo "::set-output name=merged_linked_pr_length::$merged_linked_pr_length"

      - name: Make directory
        if: steps.get_merged_linked_pr.outputs.merged_linked_pr_length == 0
        run: |
          mkdir $ISSUE_NUM

      - name: Get current date time
        id: get_current_date_time
        run: |
          current_date_time=$(TZ=UTC-9 date '+%Y/%m/%dT%H:%M:%S')
          echo "::set-output name=current_date_time::$current_date_time"

      # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
      # ここで .json ファイルの操作を行う
      # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

      - name: Reopen issue
        if: ${{ github.event.issue.state }} == "closed"
        run: gh issue reopen $ISSUE_NUM

      - name: Define new branch name
        id: define_new_branch_name
        run: |
          new_branch_name=$(echo "${ISSUE_NUM}-$(TZ=UTC-9 date '+%Y%m%d')")
          echo "::set-output name=new_branch_name::$new_branch_name"

      - name: Create branch
        uses: EndBug/add-and-commit@v9
        with:
          new_branch: ${{ steps.define_new_branch_name.outputs.new_branch_name }}

      - name: Create PR
        run: |
          gh pr create \
            --head $NEW_BRANCH_NAME \
            --base $BASE_BRANCH_NAME \
            --title "$ISSUE_TITLE" \
            --body "close #${ISSUE_NUM}"
        env:
          NEW_BRANCH_NAME: ${{ steps.define_new_branch_name.outputs.new_branch_name }}
          BASE_BRANCH_NAME: ${{ github.event.repository.default_branch }}

59行目あたりにjsonファイル操作処理を入れてみます。

echoコマンド

標準コマンドのechoコマンドを使用する方法です。

この方法には次のような特徴があります。

  • actionを使う必要が無く、標準コマンドだけで実現可能。
  • Jsonを整形したい場合は改行コード(\n)やスペース()を使う必要があり、データの可視性が悪くなる。

実際にWorkflowで使用してみます。

.github/workflows/init-post.yml

      - name: Create config.json
        if: steps.get_merged_linked_pr.outputs.merged_linked_pr_length == 0
        run: |
          echo -e "{\n  \"createdAt\": \"${{ env.CURRENT_DATE_TIME }}\",\n  \"updatedAt\": \"${{ env.CURRENT_DATE_TIME }}\"\n}" \
            > $ISSUE_NUM/config.json
        env: 
          CURRENT_DATE_TIME: ${{ steps.get_current_date_time.outputs.current_date_time }}

Workflowを実行すると、Json fileを新規作成できました。

jossef/action-set-json-field action

jossef/action-set-json-field actionを使用する方法です。

この方法には次のような特徴があります。

  • Json fileの新規作成のみ可能。
  • ファイル内容のJsonは整形されない。echoコマンドと同様、改行コードやスペースを指定する必要がある。

実際にWorkflowで使用してみます。

.github/workflows/init-post.yml

      - name: Create config.json
        if: steps.get_merged_linked_pr.outputs.merged_linked_pr_length == 0
        uses: jsdaniell/create-json@1.1.2
        with:
          name: config.json
          json: '{"createdAt":"${{ env.CURRENT_DATE_TIME }}", "updatedAt":"${{ env.CURRENT_DATE_TIME }}"}'
          dir: ${{ env.ISSUE_NUM }}/
        env: 
          CURRENT_DATE_TIME: ${{ steps.get_current_date_time.outputs.current_date_time }}

Workflowを実行すると、Json fileを新規作成できました。

jsdaniell/create-json action

jsdaniell/create-json actionを使用する方法です。

この方法には次のような特徴があります。

  • フィールドの追加および更新が可能。
  • Json fileは事前に作成されている必要がある。(ファイル内容は最低限{}とあれば良い)
  • フィールドの新規追加および更新のいずれでも、Jsonの整形が行われる。
  • 操作したいフィールド毎にactionを分ける必要がある。

実際にWorkflowで使用してみます。

.github/workflows/init-post.yml

      - name: Create config file
        if: steps.get_merged_linked_pr.outputs.merged_linked_pr_length == 0
        run: |
          echo -e "{}" >> $ISSUE_NUM/config.json

      - name: Update createdAt config.json
        if: steps.get_merged_linked_pr.outputs.merged_linked_pr_length == 0
        uses: jossef/action-set-json-field@v1
        with:
          file: ${{ env.ISSUE_NUM }}/config.json
          field: createdAt
          value: ${{ steps.get_current_date_time.outputs.current_date_time }}

      - name: Update updatedAt config.json
        uses: jossef/action-set-json-field@v1
        with:
          file: ${{ env.ISSUE_NUM }}/config.json
          field: updatedAt
          value:  ${{ steps.get_current_date_time.outputs.current_date_time }}

Workflowを実行すると、Json fileへフィールドを新規追加することができました。

またJson fileが作成済みおよびフィールドが追加済みの場合、更新することができました。

所感

GitHub ActionsでJson fileを作成および更新する方法をいくつか確認してみました。

個人的には、行数は増えやすいが可読性の高くなる3つ目のjsdaniell/create-json actionが使いやすいと思いました。単一のステップでフィールドの新規追加および更新のいずれにも対応させたい場合にも、難なく対応させることができます。ただ、フィールド数が非常に多くWorkflowのパフォーマンスに影響を与えかねない場合は1つ目または2つ目の方法を検討することになると思います。

以上