Nova Kwok's Awesome Blog

将 GitHub Actions 的 Step 输出评论到对应 PR 上

这个只是一个简单的记录和分享,没啥技术含量

在 CI 中我们会大量使用 GitHub Actions “作为质量门进行把关”,一般在 PR 中我们会设置 PR 必须跑过测试才能点 Merge,我们的 GitHub Actions Workflow 一般会这么写:

on:
  pull_request:
    branches:
      - master

然后我们就可以通过 CI 是否通过来判断是否可以考虑合并 PR,但是要手动点开看日志有的时候也太烦了,所以就有了类似 GitOps (注意,这里并不是 GitOps)的玩法,直接把某个步骤的结果输出到对应的 PR 评论上,例如,最近挺火的 Infracost,只要这样写:

- name: Terraform plan
  run: terraform plan -out tfplan.binary
  working-directory: ${{ env.working-directory }}

- name: Terraform show
  run: terraform show -json tfplan.binary > plan.json
  working-directory: ${{ env.working-directory }}

- name: Setup Infracost
  uses: infracost/actions/setup@v1
  with:
    api-key: ${{ secrets.INFRACOST_API_KEY }}

- name: Generate Infracost JSON
  run: infracost breakdown --path plan.json --format json --out-file /tmp/infracost.json
  working-directory: ${{ env.working-directory }}

- name: Post Infracost comment
  run: |
    infracost comment github --path /tmp/infracost.json \
                              --repo $GITHUB_REPOSITORY \
                              --github-token ${{github.token}} \
                              --pull-request ${{github.event.pull_request.number}} \
                              --behavior update    

就可以配合 Terraform 在每次 PR 中修改了一些基础设施之后评论 PR 分别告诉我们这个 PR 会修改哪些基础设施,同时告诉我们这么修改了之后会对费用有什么影响:

非常的直观,这样在每个 PR 的时候所有开发人员都可以知道这么个 PR 到底会不会给自己钱包开个窟窿了。

但是有的时候我们希望一些别的内容也可以有类似的输出该怎么操作呢?

一般来说网上会建议我们按照:

echo ::set-output name=docker_tag::$(echo ${GITHUB_REF} | cut -d'/' -f3)-${GITHUB_SHA}

类似这种蛇形走位的方式在某个 Step 中设置一个 output ,然后在后续 Step 中通过 ${{ steps.vars.outputs.docker_tag }} 这种方式来获取。

(然而很多场景下这个方法得到的 outputs 都是空的,非常诡异)

这里简单记录一个可用的例子,希望可以帮到和我一样不想蛇形走位且希望简单方便的用法,例子如下:

- name: Scan for CVE
  uses: mathiasvr/command-output@v1
  id: trivy
  with:
    run: |
      trivy image --no-progress --severity "HIGH,CRITICAL" ghcr.io/${{ steps.ghcr_string.outputs.lowercase }}      

- name: Comment PR
  uses: thollander/actions-comment-pull-request@v1
  with:
    message: |
      ```
      ${{ steps.trivy.outputs.stdout }}
      ```      
    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

将自己需要执行的所有指令放在 mathiasvr/command-output@v1 下,并设置一个 id,这样所有的输出结果都会被重定向到 stdout 中,在后续步骤中就可以使用 ${{ steps.<step_id>.outputs.stdout }} 这种方式直接获取到了,同时使用 thollander/actions-comment-pull-request@v1 方法打印到对应的 PR 中,这里的例子是使用 trivy 这个工具对每次 PR 构建的镜像进行安全扫描,并自动把扫描结果打印到 PR 记录中,对应的实际案例可以看这个 PR: Print all CVE results to PR comment by n0vad3v · Pull Request #130 · webp-sh/webp_server_go

是不是很方便,比去买什么国字头 XX 安全公司的 Java 编写的 XX 安全产品是不是看上去正经多了?

Have Fun,以上。

#Chinese #GitHub Actions