From 60d2d4ed752b88f12143948bce04e8ab748f14f0 Mon Sep 17 00:00:00 2001 From: Eliah Kagan Date: Thu, 24 Apr 2025 20:48:57 -0400 Subject: [PATCH 1/2] Add and validate a dependent job for branch protection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GitHub branch protection rules requiring CI checks currently only support listing individual checks as required. This adds an `all-pass` job that depends on all other jobs, to simplify this. `all-pass` can thus be made a required check, in lieu of numerous others, which it takes care to ensure are treated as effectively required. This also adds an `all-pass-meta` job that checks that the `all-pass` job really depends on all intended other jobs, which currently is all other jobs in the workflow. It is intentional at this time that neither CodeQL (configured via the "default" setup) nor the Markdown links check shall be blocking. The `all-pass` job is based on the `tests-pass` job in `gitoxide`, introduced in https://github.com/GitoxideLabs/gitoxide/pull/1551 by Jiahao XU (https://github.com/NobodyXu), moderately edited since, and further moderately edited in the form it appars here. In view of... - (de minimis) the small size of the code, other than the list of jobs it depends on, which is not duplicated since the jobs here differ including in their names, *and* - how widespread that specific technique appears to be, based in part on searching GitHub and examining results with the exact string `"contains(needs.*.result, 'cancelled')"`, *and* - (scènes à faire) the limited number of reasonable feasible ways the technique can be expressed ...it seems to me that that continued resemblance of fragments of the code here to the code there does not raise copyright or related problems, in the `all-pass` job. Separately, the `all-pass-meta` job is is a direct copy of the `check-blocking` job in `gitoxide`, introduced among other changes in https://github.com/GitoxideLabs/gitoxide/pull/1668. The `all-pass-meta` job is a near-complete copy of `check-blocking`, with only minimal changes, and even keeps the comments naerly unchanged. Although `check-blocking` is less important than `tests-pass`, it is also significantly longer and more complex. But unlike `tests-pass`, I contributed the `check-blocking` job in `gitoxide` (without copying from a previous work to do so; and licensing it nonexclusively, with no transfer or assignment of copyright). So that specific code is fine for me to reuse here. More broadly, I intend that anyone be allowed to reuse the code of the `all-pass-meta` job (as it appears here), anywhere, with no restrictions. See the 0BSD license file that accompanies this (algorithms-python) project. Note that the code of `check-blocking` in `gitoxide` may receive modifications authored by others, may be renamed, and some other job may be renamed to it, or it might be removed and some other job with that name may arise later, etc. Such code may still only be used under the terms that it is offered; these more permissive terms do *not* apply to such code, especially if it is written by others. --- .github/workflows/test.yml | 62 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a189ec2..5c9ffa4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -191,3 +191,65 @@ jobs: - name: Analyze shell scripts uses: bewuethr/shellcheck-action@v2 + + # Check that only jobs intended not to block PR auto-merge are omitted as + # dependencies of the `all-pass` job below, so that whenever a job is added, + # a decision is made about whether it must pass for PRs to merge. + all-pass-meta: + runs-on: ubuntu-latest + + env: + # List all jobs that are intended NOT to block PR auto-merge here. + EXPECTED_NONBLOCKING_JOBS: |- + all-pass + + defaults: + run: + shell: bash + + steps: + - name: Find this workflow + run: | + relative_workflow_with_ref="${GITHUB_WORKFLOW_REF#"$GITHUB_REPOSITORY/"}" + echo "WORKFLOW_PATH=${relative_workflow_with_ref%@*}" >> "$GITHUB_ENV" + + - uses: actions/checkout@v4 + with: + sparse-checkout: ${{ env.WORKFLOW_PATH }} + + - name: Get all jobs + run: yq '.jobs | keys.[]' -- "$WORKFLOW_PATH" | sort | tee all-jobs.txt + + - name: Get blocking jobs + run: yq '.jobs.all-pass.needs.[]' -- "$WORKFLOW_PATH" | sort | tee blocking-jobs.txt + + - name: Get jobs we intend do not block + run: sort <<<"$EXPECTED_NONBLOCKING_JOBS" | tee expected-nonblocking-jobs.txt + + - name: Each job must block PRs or be declared not to + run: | + sort -m blocking-jobs.txt expected-nonblocking-jobs.txt | + diff --color=always -U1000 - all-jobs.txt + + all-pass: + name: All tests pass + + needs: + - pytest-conda + - pytest-pipenv-lock + - pytest-pipenv + - lint + - shellcheck + - all-pass-meta + + runs-on: ubuntu-latest + + steps: + - name: Some failed + if: contains(needs.*.result, 'cancelled') || contains(needs.*.result, 'failure') + run: | + false + + - name: All passed + run: | + true From 766b934861eba39b65a595a1d11d58cd6601bae2 Mon Sep 17 00:00:00 2001 From: Eliah Kagan Date: Thu, 24 Apr 2025 22:39:36 -0400 Subject: [PATCH 2/2] Specify explicit `contents: read` workflow permissions This resolves a CodeQL check and is also just a good idea. See https://github.com/GitoxideLabs/prodash/pull/36. --- .github/workflows/markdown-links.yml | 3 +++ .github/workflows/test.yml | 3 +++ 2 files changed, 6 insertions(+) diff --git a/.github/workflows/markdown-links.yml b/.github/workflows/markdown-links.yml index 30ce7d7..96dd262 100644 --- a/.github/workflows/markdown-links.yml +++ b/.github/workflows/markdown-links.yml @@ -6,6 +6,9 @@ on: schedule: - cron: '15 0,12 * * *' +permissions: + contents: read + jobs: markdown-link-check: runs-on: ubuntu-latest diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5c9ffa4..f336d1e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -2,6 +2,9 @@ name: Test on: [push, pull_request] +permissions: + contents: read + jobs: pytest-conda: name: pytest (conda)