Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plan output not properly formatted #21

Open
2 tasks done
Mmasson-01 opened this issue Sep 2, 2023 · 11 comments
Open
2 tasks done

Plan output not properly formatted #21

Mmasson-01 opened this issue Sep 2, 2023 · 11 comments
Assignees
Labels
bug Something isn't working

Comments

@Mmasson-01
Copy link

Describe the bug
Capturing the terragrunt plan output to use it into a comment is not properly formatted.
The plan output is on a single line.

image

To Reproduce
Steps to reproduce the behavior, code snippets and examples which can be used to reproduce the issue.

    - name: Check terragrunt HCL
      uses: gruntwork-io/terragrunt-action@v1
      id: fmt
      with:
        tf_version: ${{ inputs.tf_version }}
        tg_version: ${{ inputs.tg_version }}
        tg_dir: ${{ inputs.workdir }}
        tg_command: 'hclfmt --terragrunt-check --terragrunt-diff'

    - name: Plan
      id: plan
      uses: gruntwork-io/terragrunt-action@v1
      with:
        tg_comment: 1
        tf_version: ${{ inputs.tf_version }}
        tg_version: ${{ inputs.tg_version }}
        tg_dir: ${{ inputs.workdir }}
        tg_command: 'plan'

    - uses: actions/github-script@v6
      if: github.event_name == 'pull_request'
      env:
        PLAN: "terraform\n${{ steps.plan.outputs.tg_action_output }}"
      with:
        github-token: ${{ inputs.GITHUB_TOKEN }}
        script: |
          // 1. Retrieve existing bot comments for the PR
          const { data: comments } = await github.rest.issues.listComments({
            owner: context.repo.owner,
            repo: context.repo.repo,
            issue_number: context.issue.number,
          })
          const botComment = comments.find(comment => {
            return comment.user.type === 'Bot' && comment.body.includes('Terragrunt Format and Style')
          })

          // 2. Prepare format of the comment
          const output = `#### Terragrunt Format and Style 🖌\`${{ steps.fmt.outcome }}\`

          #### Terragrunt Plan 📖\`${{ steps.plan.outcome }}\`

          <details><summary>Show Plan</summary>

          \`\`\`\n
          ${{ steps.plan.outputs.tg_action_output }}
          \`\`\`

          </details>

          *Pusher: @${{ github.actor }}, Action: \`${{ github.event_name }}\`, Workflow: \`${{ github.workflow }}\`*`;

          // 3. If we have a comment, update it, otherwise create a new one
          if (botComment) {
            github.rest.issues.updateComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              comment_id: botComment.id,
              body: output
            })
          } else {
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: output
            })
          }

Expected behavior
Should output the plan formatted as shown in the action log:

image

Nice to have

  • Terminal output
  • Screenshots

Versions

  • Terragrunt Action version: v1
  • Environment details (Terragrunt version, Terraform version, etc.):
    • tg version: 0.46.3
    • tf version: 1.5.6

Additional context
I've tried a few things to output in the proper format but no luck so far.

@Mmasson-01 Mmasson-01 added the bug Something isn't working label Sep 2, 2023
@denis256 denis256 self-assigned this Sep 4, 2023
@denis256 denis256 moved this to To do in Terragrunt Roadmap Sep 4, 2023
@denis256 denis256 moved this from To do to In progress in Terragrunt Roadmap Sep 5, 2023
@denis256 denis256 moved this from In progress to To do in Terragrunt Roadmap Sep 11, 2023
@vorotech
Copy link

vorotech commented Oct 2, 2023

@Mmasson-01 @denis256 Was having similar problem with terraform, and it was solved but reformatting the plan output. I think it should work here too

      # Sed is taking all lines that begin with one or more spaces followed by a `+` or `-`.
      # It stores the amount of spaces in `\1` and the +/- in `\2`.
      # Then replace that portion of the line with `\2\1` (+/- followed by the number of matched spaces).
      # cat is used instead of echo to avoid issues with quotes.
      # plan is limited initially to 65300 characters as its the GitHub env variable limit
      - name: Reformat Plan
        if: steps.plan.outcome == 'success'
        run: |
          plan=$(cat <<'EOF'
          ${{ format('{0}{1}', steps.plan.outputs.stdout, steps.plan.outputs.stderr) }}
          EOF
          )
          echo "PLAN<<EOF" >> $GITHUB_ENV
          echo "${plan:0:65300}" | sed -E 's/^([[:space:]]+)([-+])/\2\1/g' | grep -v 'Refreshing state' >> $GITHUB_ENV
          echo "EOF" >> $GITHUB_ENV

@aiell0
Copy link

aiell0 commented Oct 4, 2023

@vorotech I attempted to use the code you pasted and am getting the following error:

Error: Process completed with exit code 1.
Error: Unable to process file command 'env' successfully.
Error: Invalid value. Matching delimiter not found 'EOF'

The code I am using is the following:

      - name: Reformat Plan
        if: steps.plan.outcome == 'success'
        run: |
          plan=$(cat <<'EOF'
          ${{ format('{0}', steps.plan.outputs.tg_action_output) }}
          EOF
          )
          echo "PLAN<<EOF" >> $GITHUB_ENV
          echo "${plan:0:65300}" | sed -E 's/^([[:space:]]+)([-+])/\2\1/g' | grep -v 'Refreshing state' >> $GITHUB_ENV
          echo "EOF" >> $GITHUB_ENV


      - uses: actions/github-script@v6
        with:
          script: |
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: "${{ env.PLAN }}"
            })

Unless I am doing something glaringly stupid (possible since I am sleep deprived) it looks like it will have to be modified a bit. I have been looking for an excuse to learn sed so I can take it on when I have time. Just an FYI.

@vorotech
Copy link

vorotech commented Oct 4, 2023

@aiell0 I haven't tested myself. I mentioned that this is a code I'm using with terraform, not terrugrunt yet. And to be precise my previous step with plan looks like. Maybe the show command does slightly different output than plan.

      - name: Plan Terraform
        id: plan
        continue-on-error: true
        run: |
          cd ${{ inputs.TF_PATH }}
          terraform plan -input=false -no-color -out=tfplan \
          && terraform show -no-color tfplan

I will give it a try and update here.

@yiskaneto
Copy link

yiskaneto commented Oct 9, 2023

Yo! in case you still have the same issue, here's my current workaround for this:

Note 1: I use a matrix to iterate through several project
Note 2: For commenting the PR I use if: always() as I want to get the result regardless if the plan fails or not.

    - name: Terragrunt Check HCL Formatting
      id: terragrunt_fmt
      uses: ./.github/actions/terragrunt
      with:
        TG_COMMAND: 'hclfmt --terragrunt-check --terragrunt-diff'
        TG_VERSION: ${{ env.TG_VERSION }}
        TG_DIR:     ${{ matrix.tg_dirs }}
        TF_VERSION: ${{ env.TF_VERSION }}

    - name: Terraform ${{ env.TG_COMMAND }}
      uses: gruntwork-io/terragrunt-action@v1
      id: tg_action
      with:
        tg_command: ${{ env.TG_COMMAND }}
        tf_version: ${{ env.TF_VERSION }}
        tg_version: ${{ env.TG_VERSION }}
        tg_dir:     ${{ matrix.tg_dirs }}

    - name: Update result icon
      if: always()
      run: |
        if [[ ${{ steps.terragrunt_fmt.outcome }} == "success" ]] ; then echo "RESULT_VALIDATE_ICON=$(echo ✅)" >> $GITHUB_ENV  ; else echo "RESULT_VALIDATE_ICON=$(echo ❌)" >> $GITHUB_ENV ; fi
          if [[ ${{ steps.tg_action.outcome }} == "success" ]] ; then echo "RESULT_ACTION_ICON=$(echo ✅)" >> $GITHUB_ENV  ; else echo "RESULT_ACTION_ICON=$(echo ❌)" >> $GITHUB_ENV ; fi

    - name: Output Cleaning
      if: always()
      run: |
        TG_OUT=$(echo "${{ steps.tg_action.outputs.tg_action_output }}" | sed 's|%0A|\n|g')
        echo "TG_PLAN_OUTPUT<<EOF" >> $GITHUB_ENV
        echo "$TG_OUT" >> $GITHUB_ENV
        echo "EOF" >> $GITHUB_ENV

    - name: Comment PR
      uses: actions/github-script@v6
      if: always()
      with:
        script: |
          github.rest.issues.createComment({
            issue_number: context.issue.number,
            owner: context.repo.owner,
            repo: context.repo.repo,
            body: `### *${{ github.workflow }}* Action ([Run #${{ github.run_number }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})) Summary 🚀
            #### Target directory: ${{ matrix.tg_dirs }}
            #### Terragrunt Format and Style 🖌️ ${{ steps.terragrunt_fmt.outcome }} ${{ env.RESULT_VALIDATE_ICON }}
            #### Terraform Plan 📖 **${{ steps.tg_action.outcome }}** ${{ env.RESULT_PLAN_ICON }}

            <details><summary>Show Plan</summary>

            \`\`\`\n
            ${{ env.TG_PLAN_OUTPUT }}
            \`\`\`

            </details>

            Pusher: *@${{ github.actor }}*, Action: *${{ github.event_name }}*`
          })

@kamontat
Copy link

@escanoru I would suggest add ${TG_OUT:0:65300} on your output cleaning step to avoid argument too long error from GitHub script.

@aiell0
Copy link

aiell0 commented Oct 13, 2023

@escanoru I ended up needing to clarify the statement a bit but got this working:

      - name: Output Cleaning
        id: clean
        run: |
          TG_OUT=$(echo '${{ steps.plan.outputs.tg_action_output }}' | sed 's|%0A|\n|g ; s|%3C|<|g')
          echo "TG_PLAN_OUTPUT<<EOF" >> $GITHUB_ENV
          echo "${TG_OUT:0:65300}" >> $GITHUB_ENV
          echo "EOF" >> $GITHUB_ENV

Thanks so much to everyone in here!

@kamontat
Copy link

This is still fix problem on the surface.
The real solution should fix within Terragrunt action script.

@aiell0
Copy link

aiell0 commented Oct 20, 2023

Found a bug here....if the plan fails, it doesn't show up. Will look into a fix.

@yiskaneto
Copy link

yiskaneto commented Oct 28, 2023

@escanoru I would suggest add ${TG_OUT:0:65300} on your output cleaning step to avoid argument too long error from GitHub script.

Thanks for the tip @kamontat, I didn't know about the Github action character limitation.

@yiskaneto
Copy link

yiskaneto commented Oct 28, 2023

Found a bug here....if the plan fails, it doesn't show up. Will look into a fix.

I came across this today, the reason why this happening is because I forgot to add if: always() condition on the 'Output Cleaning' step, after adding this, I caused an error on purpose and was able to get the fail plan. Hope this helps you.

Cheers!

@YuriGusev
Copy link

YuriGusev commented Jul 28, 2024

If you look in the action code, it escapes the plan so it can be passed as the action output.

You can find how it is done here: clean_multiline_text.

To make it multiline again you can unescape it in your script:

`
....
const multiline_plan = unescape('${{ inputs.terragrunt_plan_output }}');
....
Show plan

${multiline_plan}

....
`

It would be nicer if the output could be formatted as JSON instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
Status: To do
Development

No branches or pull requests

7 participants