Skip to content

Latest commit

 

History

History
341 lines (264 loc) · 8.9 KB

README.md

File metadata and controls

341 lines (264 loc) · 8.9 KB

Wait On Check Action

![RSpec Tests][rspec_shield]

Pause a workflow until a job in another workflow completes successfully.

This action uses the [Checks API][checks_api] to poll for check results. On success, the action exit allowing the workflow resume. Otherwise, the action will exit with status code 1 and fail the whole workflow.

This is a workaround to GitHub's limitation of non-interdependent workflows 🎉

You can run your workflows in parallel and pause a job until a job in another workflow completes successfully.

Minimal example

name: Test

on: [push]

jobs:
  test:
    name: Run tests
    runs-on: ubuntu-latest
      steps:
        ...
name: Publish

on: [push]

jobs:
  publish:
    name: Publish the package
    runs-on: ubuntu-latest
    steps:
      - name: Wait for tests to succeed
        uses: lewagon/[email protected]
        with:
          ref: ${{ github.ref }}
          check-name: 'Run tests'
          repo-token: ${{ secrets.GITHUB_TOKEN }}
          wait-interval: 10
      ...

GHE Support

For GHE support you just need to pass in api-endpoint as an input.

name: Publish

on: [push]

jobs:
  publish:
    name: Publish the package
    runs-on: ubuntu-latest
    steps:
      - name: Wait for tests to succeed
        uses: lewagon/[email protected]
        with:
          ref: ${{ github.ref }}
          check-name: 'Run tests'
          repo-token: ${{ secrets.GITHUB_TOKEN }}
          api-endpoint: YOUR_GHE_API_BASE_URL # Fed to https://octokit.github.io/octokit.rb/Octokit/Configurable.html#api_endpoint-instance_method
      ...

Alternatives

If you can keep the dependent jobs in a single workflow:

name: Test and publish

on: [push]

jobs:
  test:
    runs-on: ubuntu-latest
    steps: ...

  publish:
    runs-on: ubuntu-latest
    needs: test
    steps: ...

If you can run dependent jobs in a separate workflows in series:

name: Publish

on:
  workflow_run:
    workflows: ['Test']
    types:
      - completed

A real-world scenario

  • Pushes to master trigger a test job to be run against the application code.

  • Pushes to master also trigger a webhook that builds an image on external service such as Quay.

  • Once an image is built, a repository_dispatch hook is triggered from a third-party service. This triggers a deploy job.

  • We don't want the deploy job to start until the master branch passes its test job.

name: Trigger deployment on external event

on:
  # https://github.com/lewagon/quay-github-actions-dispatch
  repository_dispatch:
    types: [build_success]

jobs:
  deploy:
    if: startsWith(github.sha, github.event.client_payload.text)
    name: Deploy a new image
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2

      - name: Wait for tests to succeed
        uses: lewagon/[email protected]
        with:
          ref: master
          check-name: test
          repo-token: ${{ secrets.GITHUB_TOKEN }}
          wait-interval: 20

      - name: Save the DigitalOcean kubeconfig
        uses: digitalocean/action-doctl@master
        env:
          DIGITALOCEAN_ACCESS_TOKEN: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}
        with:
          args: kubernetes cluster kubeconfig show my-cluster > $GITHUB_WORKSPACE/.kubeconfig

      - name: Upgrade/install chart
        run: export KUBECONFIG=$GITHUB_WORKSPACE/.kubeconfig && make deploy latest_sha=$(echo $GITHUB_SHA | head -c7)}}

Parameters

Check name

Check name goes according to the jobs.<job_id>.name parameter.

In this case the job's name is 'test':

jobs:
  test:
    runs-on: ubuntu-latest
      steps:
      ...

In this case the name is 'Run tests':

jobs:
  test:
    name: Run tests
    runs-on: ubuntu-latest
      steps:
      ...

In this case the names will be:

  • Run tests (3.6)

  • Run tests (3.7)

jobs:
  test:
    name: Run tests
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python: [3.6, 3.7]

To inspect the names as they appear to the API:

curl -u username:$token \
https://api.github.com/repos/OWNER/REPO/commits/REF/check-runs \
-H 'Accept: application/vnd.github.antiope-preview+json' | jq '[.check_runs[].name]'

Running workflow name

If you would like to wait for all other checks to complete you may set running-workflow-name to the name of the current job and not set a check-name parameter.

name: Publish

on: [push]

jobs:
  publish:
    name: Publish the package
    runs-on: ubuntu-latest
    steps:
      - name: Wait for other checks to succeed
        uses: lewagon/[email protected]
        with:
          ref: ${{ github.ref }}
          running-workflow-name: 'Publish the package'
          repo-token: ${{ secrets.GITHUB_TOKEN }}
          wait-interval: 10
      ...

Using running workflow name in reusable workflows

Using this action in a reusable workflow means accepting a constraint that all calling jobs will have the same name. For example, all calling workflows must call their jobs caller (or some more relevant constant) so that if the reused workflow containing the job that uses this action to wait is called callee then the task can successfully wait on caller / callee. Working example follows.

.github/workflows/caller.yml

on:
  push:
jobs:
  caller:
    uses: ./.github/workflows/callee.yml

.github/workflows/callee.yml

on:
  workflow_call:
jobs:
  callee:
    runs-on: ubuntu-latest
    steps:
      - name: Wait for Other Workflows
        uses: lewagon/[email protected]
        with:
          ref: ${{ github.ref }}
          running-workflow-name: 'caller / callee'
          repo-token: ${{ secrets.GITHUB_TOKEN }}
          wait-interval: 10

Allowed conclusions

By default, checks that conclude with either success or skipped are allowed, and anything else is not. You may configure this with the allowed-conclusions option, which is a comma-separated list of conclusions.

name: Publish

on: [push]

jobs:
  publish:
    name: Publish the package
    runs-on: ubuntu-latest
    steps:
      - name: Wait for tests to succeed
        uses: lewagon/[email protected]
        with:
          ref: ${{ github.ref }}
          check-name: 'Run tests'
          repo-token: ${{ secrets.GITHUB_TOKEN }}
          wait-interval: 10
          allowed-conclusions: success,skipped,cancelled
      ...

Using check-regexp

Similar to the check-name parameter, this filters the checks to be waited but using a Regular Expression (aka regexp) to match the check name (jobs.<job_id>.name)

Example of use:

name: Wait using check-regexp
on:
  push:

jobs:
  wait-for-check-regexp:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2

      - name: Wait on tests
        uses: ./
        with:
          ref: ${{ github.sha }}
          repo-token: ${{ secrets.GITHUB_TOKEN }}
          running-workflow-name: wait-for-check-regexp
          check-regexp: .?-task

Ignore-checks

To selectively filter checks and ignore specific ones, you can specify the ignore-checks option with a list of comma-separated check names to be ignored. Example of use:

name: Wait using check-regexp
on:
  push:

jobs:
  wait-for-check-regexp:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2

      - name: Wait on tests
        uses: ./
        with:
          ref: ${{ github.sha }}
          repo-token: ${{ secrets.GITHUB_TOKEN }}
          running-workflow-name: wait-for-check-regexp
          ignore-checks: label1,label2

Wait interval (optional, default: 10)

As it could be seen in many examples, there's a parameter wait-interval, and sets a time in seconds to be waited between requests to the GitHub API. The default time is 10 seconds.

Verbose (optional, default: true)

If true, it prints some logs to help understanding the process (checks found, filtered, conclussions, etc.)

Auto-pagination

Since we are using Octokit for using GitHub API, we are subject to their limitations. One of them is the pagination max size: if we have more than 100 workflows running, the auto-pagination won't help. More about Octokit auto-pagination can be found here The solution would be to fetch all pages to gather all running workflows if they're more than 100, but it's still no implemented.

Tests

There are sample workflows in the .github/workflows directory. Two of them are logging tasks to emulate real-world actions being executed that have to be waited. The important workflows are the ones that use the wait-on-check-action.

A workflow named "wait_omitting-check-name" waits for the two simple-tasks, while the one named "wait_using_check-name" only waits for "simple-task".