Skip to content

Commit

Permalink
CI: Add a verify-success reusable workflow to use for required checks (
Browse files Browse the repository at this point in the history
…#3320)

* CI: Add a verify success job to use in required checks

* Limit line length in verify-success.yml and Python Code Quality workflow

* CI: Use pipx to run tools in python-code-quality.yml, cache pip

* CI: Add verify success for pytest workflow

* CI: Add verify-success to Ubuntu

* Update .github/workflows/python-code-quality.yml
  • Loading branch information
echoix committed Jan 5, 2024
1 parent 3a9db16 commit 16ebff9
Show file tree
Hide file tree
Showing 4 changed files with 193 additions and 12 deletions.
8 changes: 8 additions & 0 deletions .github/workflows/pytest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,11 @@ jobs:
- name: Print installed versions
if: always()
run: .github/workflows/print_versions.sh
pytest-success:
name: pytest Result
needs:
- pytest
if: ${{ always() }}
uses: ./.github/workflows/verify-success.yml
with:
needs_context: ${{ toJson(needs) }}
30 changes: 20 additions & 10 deletions .github/workflows/python-code-quality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@ on:

jobs:
python-checks:
name: Python Code Quality
name: Python Code Quality Checks

concurrency:
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.sha }}-${{
matrix.pylint-version }}
group: ${{ github.workflow }}-${{ github.job }}-${{
github.event_name == 'pull_request' &&
github.head_ref || github.sha }}-${{ matrix.pylint-version }}
cancel-in-progress: true

# Using matrix just to get variables which are not environmental variables
Expand All @@ -26,11 +27,11 @@ jobs:
matrix:
include:
- os: ubuntu-22.04
python-version: '3.10'
min-python-version: '3.7'
black-version: '23.1.0'
flake8-version: '3.9.2'
pylint-version: '2.12.2'
python-version: "3.10"
min-python-version: "3.7"
black-version: "23.1.0"
flake8-version: "3.9.2"
pylint-version: "2.12.2"

runs-on: ${{ matrix.os }}

Expand All @@ -39,7 +40,7 @@ jobs:
run: |
echo OS: ${{ matrix.os }}
echo Python: ${{ matrix.python-version }}
echo Minimimal Python version: ${{ matrix.min-python-version }}
echo Minimal Python version: ${{ matrix.min-python-version }}
echo Black: ${{ matrix.black-version }}
echo Flake8: ${{ matrix.flake8-version }}
echo Pylint: ${{ matrix.pylint-version }}
Expand All @@ -50,13 +51,14 @@ jobs:
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: pip

- name: Install non-Python dependencies
run: |
sudo apt-get update -y
sudo apt-get install -y wget git gawk findutils
xargs -a <(awk '! /^ *(#|$)/' ".github/workflows/apt.txt") -r -- \
sudo apt-get install -y --no-install-recommends --no-install-suggests
sudo apt-get install -y --no-install-recommends --no-install-suggests
- name: Install Python dependencies
run: |
Expand Down Expand Up @@ -146,3 +148,11 @@ jobs:
name: sphinx-grass
path: sphinx-grass
retention-days: 3
python-success:
name: Python Code Quality Result
needs:
- python-checks
if: ${{ always() }}
uses: ./.github/workflows/verify-success.yml
with:
needs_context: ${{ toJson(needs) }}
12 changes: 10 additions & 2 deletions .github/workflows/ubuntu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ on:
- releasebranch_*

jobs:
build-and-test:
ubuntu:
name: ${{ matrix.name }} tests

concurrency:
Expand All @@ -26,7 +26,7 @@ jobs:
strategy:
matrix:
include:
- name: '22.04'
- name: "22.04"
os: ubuntu-22.04
config: ubuntu-22.04
# This is without optional things but it still keeps things useful,
Expand Down Expand Up @@ -95,3 +95,11 @@ jobs:
- name: Print installed versions
if: always()
run: .github/workflows/print_versions.sh
build-and-test-success:
name: Build & Test Result
needs:
- ubuntu
if: ${{ always() }}
uses: ./.github/workflows/verify-success.yml
with:
needs_context: ${{ toJson(needs) }}
155 changes: 155 additions & 0 deletions .github/workflows/verify-success.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
---
name: Verify Success reusable workflow

# Use this reusable workflow as a job of workflow to check that
# all jobs, including ones ran through a matrix, were successful.
# This job can then be used as a required status check in the
# repo's rulesets, that allows to change the required jobs or
# the matrix values of a required job without needing to change
# the rulesets settings. In the future, GitHub might have a
# solution to this natively.

# This reusable workflow has inputs to change what is required
# to have this workflow pass. It handles the cases were there were
# skipped jobs, and no successful jobs.

# The jobs to check must set as the `needs` for the job calling this
# reusable workflow. This also means that the job ids should be in the
# same workflow file. The calling job must be set to always run to be
# triggered when jobs are skipped or cancelled.
# Then, set the `needs_context` input like:
# `needs_context: ${{ toJson(needs) }}`

# Example usage, as a job inside a workflow:
# ```
# jobs:
# a-job-id:
# ...
# another-job-id:
# ...
# some-job-success:
# name: Some Job Result
# needs:
# - a-job-id
# - another-job-id
# if: ${{ always() }}
# uses: ./.github/workflows/verify-success.yml
# with:
# needs_context: ${{ toJson(needs) }}
# ```

on:
workflow_call:
inputs:
needs_context:
type: string
required: true
# Can't escape the handlebars in the description
description:
In the calling job that defines all the needed jobs,
send `toJson(needs)` inside `$` followed by `{{ }}`
fail_if_failure:
type: boolean
default: true
description:
If true, this workflow will fail if any job from 'needs_context was
failed
fail_if_cancelled:
type: boolean
default: true
description:
If true, this workflow will fail if any job from 'needs_context' was
cancelled
fail_if_skipped:
type: boolean
default: false
description:
If true, this workflow will fail if any job from 'needs_context' was
skipped
require_success:
type: boolean
default: true
description:
If true, this workflow will fail if no job from 'needs_context' was
successful

jobs:
verify-success:
name: Success
runs-on: ubuntu-latest
continue-on-error: true
steps:
- name: Set outputs for each job result type
id: has-result
run: |
echo "failure=${{
contains(env.NEEDS_RESULT, 'failure') }}" >> "$GITHUB_OUTPUT"
echo "cancelled=${{
contains(env.NEEDS_RESULT, 'cancelled') }}" >> "$GITHUB_OUTPUT"
echo "skipped=${{
contains(env.NEEDS_RESULT, 'skipped') }}" >> "$GITHUB_OUTPUT"
echo "success=${{
contains(env.NEEDS_RESULT, 'success') }}" >> "$GITHUB_OUTPUT"
env:
NEEDS_RESULT: ${{ toJson(fromJson(inputs.needs_context).*.result) }}
- name: Set exit codes for each job result type
id: exit-code
run: |
echo "failure=${{ inputs.fail_if_failure &&
fromJson(steps.has-result.outputs.failure) && 1 || 0
}}" >> "$GITHUB_OUTPUT"
echo "cancelled=${{ inputs.fail_if_cancelled &&
fromJson(steps.has-result.outputs.cancelled) && 1 || 0
}}" >> "$GITHUB_OUTPUT"
echo "skipped=${{ inputs.fail_if_skipped &&
fromJson(steps.has-result.outputs.skipped) && 1 || 0
}}" >> "$GITHUB_OUTPUT"
echo "success=${{ inputs.require_success &&
!fromJson(steps.has-result.outputs.success) && 1 || 0
}}" >> "$GITHUB_OUTPUT"
- name: Set messages for each job result type
id: message
run: |
echo "failure=${{ format('{0}{1} were failed',
(steps.exit-code.outputs.failure == 1) && env.P1 || env.P2,
(steps.has-result.outputs.failure == 'true') && env.M1 || env.M2)
}}" >> "$GITHUB_OUTPUT"
echo "cancelled=${{ format('{0}{1} were cancelled',
(steps.exit-code.outputs.cancelled == 1) && env.P1 || env.P2,
(steps.has-result.outputs.cancelled == 'true') && env.M1 || env.M2)
}}" >> "$GITHUB_OUTPUT"
echo "skipped=${{ format('{0}{1} were skipped',
(steps.exit-code.outputs.skipped == 1) && env.P1 || env.P2,
(steps.has-result.outputs.skipped == 'true') && env.M1 || env.M2)
}}" >> "$GITHUB_OUTPUT"
echo "success=${{ format('{0}{1} were successful',
(steps.exit-code.outputs.success == 1) && env.P1 || env.P2,
(steps.has-result.outputs.success == 'true') && env.M1 || env.M2)
}}" >> "$GITHUB_OUTPUT"
env:
P1: "::error ::" # Common message prefix if step will fail
P2: "" # Common message prefix if step will not fail
M1: "Some jobs" # Common message if result is true
M2: "No jobs" # Common message if result is false

- name: Check for failed jobs
run: |
echo "${{ steps.message.outputs.failure }}"
exit ${{ steps.exit-code.outputs.failure }}
- name: Check for cancelled jobs
run: |
echo "${{ steps.message.outputs.cancelled }}"
exit ${{ steps.exit-code.outputs.cancelled }}
- name: Check for skipped jobs
run: |
echo "${{ steps.message.outputs.skipped }}"
exit ${{ steps.exit-code.outputs.skipped }}
- name: Check for successful jobs
run: |
echo "${{ steps.message.outputs.success }}"
exit ${{ steps.exit-code.outputs.success }}
- run: echo "Checks passed successfully"
if: ${{ success() }}
- run: echo "Checks failed"
if: ${{ !success() }}

0 comments on commit 16ebff9

Please sign in to comment.