Github Actions:检查步骤状态

51

在我的CI工作中,有一些步骤可能会出错。我不想在每个出错的步骤上重新启动工作流程,而是希望到达检查这些步骤的最后一步,并将此工作标记为失败。 但是我无法获取先前步骤的状态信息。

name: CI
on: [pull_request]
jobs:
  myjob:
    runs-on: ubuntu-latest
    steps:
      - name: Step 1
        id: hello
        run: <any> 
        continue-on-error: true
      - name: Step 2
        id: world
        run: <any> 
        continue-on-error: true
      - name: Check on failures
        if: job.steps.hello.status == failure() || job.steps.world.status == failure()
        run: exit 1
当我在“if”或“run”中使用下一个构造时,会得到:steps -> {},job.steps -> null。
如何获取状态信息?

我不理解这句话的意思:“当我在“if”或“run”中使用下一个结构时……”。您能否尝试重新表达一下? - rmunn
  • 名称:检查失败情况 运行:${{ toJson(steps) }} ${{ toJson(job.steps) }}然后我会得到{} null
- Maxim
5个回答

74

更新:现在steps上下文默认包含每个步骤的执行细节。使用每个步骤的outcome属性,我们可以检查其执行结果。

name: CI
on: [pull_request]
jobs:
  myjob:
    runs-on: ubuntu-latest
    steps:
      - name: Step 1
        id: hello
        run: <any> 
        continue-on-error: true
      - name: Step 2
        id: world
        run: <any> 
        continue-on-error: true
      - name: Check on failures
        if: steps.hello.outcome != 'success' || steps.world.outcome != 'success'
        run: exit 1

看一下步骤上下文的文档,它似乎并没有包含关于步骤的任何信息,除了outputs。这些必须由步骤明确定义。这就是为什么步骤上下文为空{}的原因。

https://help.github.com/en/articles/contexts-and-expression-syntax-for-github-actions#steps-context

很遗憾,据我所知,无法访问步骤的默认状态。解决方案是手动从每个步骤定义一个状态输出变量。

name: CI
on: [pull_request]
jobs:
  myjob:
    runs-on: ubuntu-latest
    steps:
      - name: Step 1
        id: hello
        run: echo ::set-output name=status::failure
        continue-on-error: true
      - name: Step 2
        id: world
        run: echo ::set-output name=status::success
        continue-on-error: true
      - name: Dump steps context
        env:
          STEPS_CONTEXT: ${{ toJson(steps) }}
        run: echo "$STEPS_CONTEXT"
      - name: Check on failures
        if: steps.hello.outputs.status == 'failure' || steps.world.outputs.status == 'failure'
        run: exit 1

这会生成以下上下文输出,导致作业失败。
{
  "hello": {
    "outputs": {
      "status": "failure"
    }
  },
  "world": {
     "outputs": {
      "status": "success"
    }
  }
}

https://help.github.com/en/articles/metadata-syntax-for-github-actions#outputs https://help.github.com/en/articles/development-tools-for-github-actions#set-an-output-parameter-set-output


1
对我来说不起作用。 “检查失败”未启动并转到下一步:完成此任务。当我禁用“if”时,此步骤运行,但变量未定义: - name: 检查失败 run: | echo hello - ${{ job.steps.hello.status }}! exit 1 => hello -!,进程以退出代码1完成 - Maxim
@Maxim 你是对的,抱歉。经过更多测试,目前看起来似乎不可能。我会更新这个答案。 - peterevans
谢谢你,@peterevans! 我简化了它,并在我的“run”结尾仅设置了“success”。 对我来说足够了: if: steps.hello.outputs.status!= 'success' || steps.world.outputs.status!= 'success' - Maxim
2
更新2020年: 正如其他答案所提到的,现在不再需要(如果曾经需要过,我不知道)显式设置输出。您只需要:1. 在步骤上设置一个“id”,2. 调用steps.<step id>.outcome。参考文献:https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#steps-context请@peterevans更新答案以添加此信息。 - fcole90
1
@fcole90 谢谢。已更新答案。原始答案是在 outcomeconclusion 可用之前编写的。 - peterevans
如果步骤被手动点击拒绝按钮拒绝了,会发生什么情况?在这种情况下,该步骤的状态将为“失败”。如何区分这种行为与真正的失败? - undefined

7

您可以使用steps.STEPNAME.outcome属性来获取状态,该属性与success()或failure()的检查相关联。

name: CI
on: [pull_request]
jobs:
  myjob:
    runs-on: ubuntu-latest
    steps:
      - name: Step 1
        id: hello
        run: <any> 
        continue-on-error: true
      - name: Step 2
        id: world
        run: <any> 
        continue-on-error: true
      - name: Check on failures
        if: (${{ success() }} || ${{ failure() }}) && (${{ steps.hello.outcome }} == 'failure' || ${{ steps.world.outcome }} == 'failure')
        run: exit 1

为什么需要这个:(${{ success() }} || ${{ failure() }}) - Enigmatic
需要运行该步骤,无论之前的步骤是否成功或出错。 - Nicolas Vuillamy
这与 always() 有什么不同吗? - Enigmatic
1
这是一个非常好的问题...当我发布我的答案时,可能always()函数还不存在,或者我不知道答案^^ - Nicolas Vuillamy
3
@BF99 always 在取消时也会运行。 - jerone

4
jobs:
  build:
    name: Build
    env:
      DOCKER_PASS: ${{ secrets.DOCKER_PASS }} 
    runs-on: ubuntu-latest
    steps:

    - name: script
      id: test1
      continue-on-error: true
      run: |
        ls -l sadasd
        
    - name: script
      id: sync
      continue-on-error: true
      run: |
        ls -l
    - name: Dump steps context
      env:
        STEPS_CONTEXT: ${{ toJson(steps) }}
      run: echo "$STEPS_CONTEXT"

输出结果

Run echo "$STEPS_CONTEXT"
{
  "test1": {
    "outputs": {},
    "outcome": "failure",
    "conclusion": "success"
  },
  "sync": {
    "outputs": {},
    "outcome": "success",
    "conclusion": "success"
  }
}

所以可以按照以下步骤进行:

    - name: sync run
      id: sync
      continue-on-error: true
      run: |
        .....
    - name: after_success
      run: |
        ...
      if: steps.sync.outcome  == 'success'
    - name: after_failure
      run: |
        ...
      if: steps.sync.outcome != 'success'

2

我正在使用与@peterevans之前建议的类似的方法,但利用命令的shell退出并设置set +e标志:

name: CI
on: [pull_request]
jobs:
  myjob:
    runs-on: ubuntu-latest
    steps:
      - name: Step 1
        id: hello
        run: |
          set +e
          ./my-script.sh
          echo ::set-output name=exit_status::failure
      - name: Step 2
        id: world
        run:
          set +e
          python3 ./my-script.py
          echo ::set-output name=exit_status::$?
      - name: Check on failures
        if: steps.hello.outputs.exit_status != 0 | steps.world.outputs.exit_status != 0
        run: exit 1

0

今天我遇到了同样的问题,通过使用条件语句解决了它:

name: CI
on: [pull_request]
jobs:
  myjob:
    runs-on: ubuntu-latest
    steps:
      - name: Step 1
        id: hello
        run: <any> 
        if: ${{ failure() ||  success() }}
      - name: Step 2
        id: world
        run: <any> 
        if: ${{ failure() ||  success() }}

最后:
  • 所有步骤都会被执行
  • 如果有任何步骤失败,作业myjob将会失败

这类似于Azure DevOps succeededOrFailed() condition

祝你的工作顺利!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接