我有一个Python脚本,它在创建拉请求时运行.该脚本对repo中的文件执行一些判断,并打印结果以及退出代码(如果文件看起来正常,则为0;如果文件有问题,则为1).然后,我希望捕获脚本的输出,并使用结果对拉请求进行自动注释.

对于未通过判断的脚本(退出代码为1),我可以捕获输出或让退出代码使步骤失败,但不能两者兼而有之.将多行输出捕获为$GITHUB_OUTPUT似乎忽略了Python脚本的退出代码.

这是我的工作流程(自动注释步骤目前是一个占位符,直到我可以运行运行脚本步骤)

name: Test Data

on:
  pull_request

jobs:
  check_data:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout Repository
        uses: actions/checkout@v4

      - name: Get branch name
        shell: bash
        run: echo "BRANCH=${{ github.event.pull_request.head.ref }}" >> "$GITHUB_ENV"

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.10'

      - name: Install dependencies
        run: pip install pandas

      - name: Run script
        id: check_data
        shell: bash
        run: |
          {
            echo "results<<EOF"
            echo "$(python tools/check_data.py $BRANCH)"
            echo "EOF"
          } >> "$GITHUB_OUTPUT"

      - name: Auto comment
        shell: bash
        run: echo "${{ steps.check_data.outputs.results }}"

如果Python脚本以1退出,我希望Run script步失败.在以下情况下可以很好地工作:

- name: Run script
        run: python tools/check_data.py $BRANCH

但这显然不会捕获标准输出以供下一步使用.

有没有人想到,如果脚本失败,我如何既能捕获输出,又能在失败后退出步骤?我可以有两个步骤,然后运行脚本两次,但效率不是很高.

推荐答案

下面是你如何做到这一点;我还添加了一个注释操作:

name: Check Data and Show Message in PR

on:
  push:
    branches: [main, develop]
  pull_request:

env:
  PYTHON_VERSION: "3.10"

permissions:
  # perms required by the marocchino/sticky-pull-request-comment action
  contents: read
  pull-requests: write

jobs:
  check-data:
    runs-on: ubuntu-latest
    timeout-minutes: 20
    env:
      # see https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#good-practices-for-mitigating-script-injection-attacks for why we use an env and not templating
      # see https://laurentsenta.com/digital-garden/programming/github-actions-tips/ for why I picked this value (I use a push trigger too)
      BRANCH: ${{ github.head_ref || github.ref_name }}
    steps:
      - name: Checkout Repository
        uses: actions/checkout@v4
      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: ${{ env.PYTHON_VERSION }}
      # - name: Install dependencies
      #   run: pip install pandas
      - name: Run script
        id: check_data
        shell: bash
        # We use a file instead of an HEREDOC, see https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#multiline-strings
        run: |
          python tools/exit_and_output.py 1 10 | tee comment.txt
      - uses: marocchino/sticky-pull-request-comment@331f8f5b4215f0445d3c07b4967662a32a2d3e31 # v2.9.0
        # on failure and success and if it's a PR -- this is different from `if: always()`
        if: (success() || failure()) && github.event.pull_request
        with:
          recreate: true
          header: check-data
          path: comment.txt
      - if: (success() || failure()) && !github.event.pull_request
        run: |
          cat comment.txt >> "${GITHUB_STEP_SUMMARY}"

以下是需要注意的几点:

我使用了一个声明式的env而不是你的echo BRANCH=.... > GITHUB_ENV脚本. 我觉得这个更明确,它通常是safer.

我使用${{ github.head_ref || github.ref_name }}来获取分支机构名称,只是因为我也想在从push到Main的过程中触发此工作流.但你没必要这么做.

我使用文件而不是HEREDOC(<< EOF),我发现这更易于维护:您不必纠结于管道故障、退出代码等等.此外,例如,如果您的输出包含"GEOFFray",则可以避免奇怪的错误.Doc

我添加了一个 comments 操作;我喜欢这个操作;它会自动更新.

我使用if: (success() || failure()),它在作业(job)取消时停止(而不是always()),这使得判断的其余部分更具可读性.

最后,为了完整起见,我还在Push to Main和Development上输出了一个作业(job)摘要(您可以在this GitHub job上看到结果).

如果您想要查看输出:PRthe results for many different cases,我在演示资源库中进行了设置.

Python相关问答推荐

如何根据另一列值用字典中的值替换列值

Pandas实际上如何对基于自定义的索引(integer和非integer)执行索引

Python json.转储包含一些UTF-8字符的二元组,要么失败,要么转换它们.我希望编码字符按原样保留

不理解Value错误:在Python中使用迭代对象设置时必须具有相等的len键和值

Python中绕y轴曲线的旋转

为什么以这种方式调用pd.ExcelWriter会创建无效的文件格式或扩展名?

如何在Python脚本中附加一个Google tab(已经打开)

如何调整QscrollArea以正确显示内部正在变化的Qgridlayout?

在vscode上使用Python虚拟环境时((env))

Django REST Framework:无法正确地将值注释到多对多模型,不断得到错误字段名称字段对模型无效'<><>

UNIQUE约束失败:customuser. username

如何合并两个列表,并获得每个索引值最高的列表名称?

旋转多边形而不改变内部空间关系

如何创建引用列表并分配值的Systemrame列

使用Openpyxl从Excel中的折线图更改图表样式

在Python中从嵌套的for循环中获取插值

正在try 让Python读取特定的CSV文件

Django更新视图未更新

如何让PYTHON上的Selify连接到现有的Firefox实例-我无法连接到Marionette端口

为什么这个正则表达式没有捕获最后一次输入?