ci: one reduced build job on draft pull requests and manual runs (#1986)

* ci: one reduced build job on draft pull requests and manual runs

* ci: reject manual runs on tags

* ci: reduced job by job condition, tests only when selected

* ci: test selection and retries in scripts/ci/run-tests.sh

* ci: guide to reduced builds and test selection
This commit is contained in:
Evgeny @ SimpleX Chat authored and GitHub committed 2026-10-26 10:25:15 +00:00
1 parent 3818284007
commit f23f2ac53e
3 files changed
+137 -24

No files matched your search

+49 -24
View File
@@ -8,6 +8,13 @@ on:
tags:
- "v*"
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
workflow_dispatch:
inputs:
tests:
description: "hspec match patterns, one per line; / runs all tests, empty runs none"
type: string
default: ""
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
@@ -24,7 +31,15 @@ jobs:
maybe-release:
runs-on: ubuntu-latest
outputs:
reduced: ${{ github.event_name == 'workflow_dispatch' || github.event.pull_request.draft == true }}
steps:
- name: Reject a manual run on a tag
if: github.event_name == 'workflow_dispatch' && github.ref_type == 'tag'
run: |
echo "::error::A manual run starts on a branch; to retry a release, re-run the jobs of its tag push."
exit 1
- name: Clone project
if: startsWith(github.ref, 'refs/tags/v')
uses: actions/checkout@v3
@@ -66,21 +81,22 @@ jobs:
build:
name: "ubuntu-${{ matrix.os }}-${{ matrix.arch }}, GHC: ${{ matrix.ghc }}"
needs: maybe-release
if: needs.maybe-release.outputs.reduced != 'true'
permissions:
contents: write
packages: write
env:
env: &build-env
apps: "smp-server xftp-server ntf-server xftp"
opt: ${{ github.event_name == 'pull_request' && 'O0' || 'O2' }}
ghc_options: ${{ github.event_name == 'pull_request' && '--ghc-options=-O0' || '' }}
opt: ${{ github.event_name == 'push' && 'O2' || 'O0' }}
ghc_options: ${{ github.event_name != 'push' && '--ghc-options=-O0' || '' }}
release: ${{ startsWith(github.ref, 'refs/tags/v') }}
postgres_dist: ${{ startsWith(github.ref, 'refs/tags/v') && 'dist-newstyle' || 'dist-postgres' }}
branch: ${{ github.base_ref || github.ref_name }}
cache_o0: ${{ github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/stable') }}
image_cache: ghcr.io/simplex-chat/simplexmq-build-cache:${{ matrix.os }}-${{ matrix.arch }}-ghc${{ matrix.ghc }}
image_cache: ghcr.io/${{ github.repository_owner }}/simplexmq-build-cache:${{ matrix.os }}-${{ matrix.arch }}-ghc${{ matrix.ghc }}
source_hashes: dist-newstyle/sources.sha256
runs-on: ${{ matrix.runner }}
services:
services: &build-services
postgres:
image: postgres:15
env:
@@ -127,7 +143,7 @@ jobs:
runner: "ubuntu-24.04-arm"
ghc: "9.6.3"
should_run: true
steps:
steps: &build-steps
- name: Clone project
if: matrix.should_run == true
uses: actions/checkout@v3
@@ -291,7 +307,7 @@ jobs:
- name: Build everything else (standard)
id: build-standard
if: matrix.should_run == true
if: matrix.should_run == true && needs.maybe-release.outputs.reduced != 'true'
shell: docker exec -t builder sh -eu {0}
run: |
cabal build --jobs=$(nproc) ${{ env.ghc_options }}
@@ -394,23 +410,11 @@ jobs:
shell: bash
env:
PGHOST: localhost
run: |
i=1
attempts=1
${{ (github.ref == 'refs/heads/stable' || startsWith(github.ref, 'refs/tags/v')) }} && attempts=3
while [ "$i" -le "$attempts" ]; do
if ./simplexmq-test; then
break
else
echo "Attempt $i failed, retrying..."
i=$((i + 1))
sleep 1
fi
done
if [ "$i" -gt "$attempts" ]; then
echo "All "$attempts" attempts failed."
exit 1
fi
REDUCED: ${{ needs.maybe-release.outputs.reduced }}
TESTS: ${{ github.event_name == 'workflow_dispatch' && inputs.tests || '' }}
PR_BODY: ${{ github.event.pull_request.draft == true && github.event.pull_request.body || '' }}
ATTEMPTS: ${{ (github.ref == 'refs/heads/stable' || startsWith(github.ref, 'refs/tags/v')) && 3 || 1 }}
run: scripts/ci/run-tests.sh ./simplexmq-test
- name: Remove -O2 build directories
id: remove-o2
@@ -458,6 +462,27 @@ jobs:
dist-postgres
key: ${{ steps.keys.outputs.dist }}-O0-${{ env.branch }}-${{ github.sha }}
build-reduced:
name: "ubuntu-${{ matrix.os }}-${{ matrix.arch }}, GHC: ${{ matrix.ghc }}"
needs: maybe-release
if: needs.maybe-release.outputs.reduced == 'true'
permissions:
contents: write
packages: write
env: *build-env
runs-on: ${{ matrix.runner }}
services: *build-services
strategy:
matrix:
include:
- os: 24.04
os_underscore: 24_04
arch: x86-64
runner: "ubuntu-24.04"
ghc: "9.6.3"
should_run: true
steps: *build-steps
# =============================
# Resolver test job
# =============================
+50
View File
@@ -0,0 +1,50 @@
# CI on GitHub's runners
## Builds
`build.yml` runs one of two builds:
| Trigger | Build | Jobs |
|---|---|---|
| a push to a draft pull request<br>a manual run (workflow_dispatch) | reduced | build-reduced: ubuntu-24.04 x86-64, GHC 9.6.3, at -O0, without the standard build |
| a pull request marked ready for review, and later pushes to it<br>a push to master or stable<br>a push of a v* tag | full | build: 5 entries (GHC 8.10.7 and 9.6.3, x86-64 and aarch64), at -O0 on pull requests and -O2 on pushes |
Both builds also run maybe-release and resolver (python). Tests run on the x86-64 entries. The reduced build restores the -O0 build caches saved by master pushes; the Docker image cache is tagged by ISO week, so the first run of a week rebuilds the image.
## Test selection
- Draft pull request: a fenced block with the info string `ci-tests` in the description, one hspec match pattern per line. The block is read at each push; an edit applies from the next push.
- Manual run: input `tests`, one pattern per line.
- `/` runs all tests. With no pattern, a reduced build runs no tests. A full build runs all tests and ignores the selection.
- Each pattern is passed as `-m <pattern>`. With at least one pattern, `--fail-on=empty` is added, so a pattern that matches nothing fails the run.
- A pattern matches the item path `/group/subgroup/item/` as a substring. Group names are the `describe` names in tests/Test.hs.
Example block:
````
```ci-tests
/Core tests/Encoding tests/
SMP proxy
```
````
## Manual run
```sh
curl -fsS -X POST \
-H "Authorization: Bearer $GH_TOKEN" \
-H "Accept: application/vnd.github+json" \
https://api.github.com/repos/<owner>/simplexmq/actions/workflows/build.yml/dispatches \
-d '{"ref": "<branch>", "inputs": {"tests": "/Core tests/Encoding tests/\nSMP proxy"}}'
```
A manual run starts on a branch; a release is retried by re-running the jobs of its tag push.
## Local run
scripts/ci/run-tests.sh runs the selection as in CI: it appends the patterns of `TESTS` to the test command.
```sh
cabal build --enable-tests --ghc-options=-O0 simplexmq-test
TESTS='/Core tests/Encoding tests/' scripts/ci/run-tests.sh "$(cabal list-bin simplexmq-test --ghc-options=-O0)"
```
+38
View File
@@ -0,0 +1,38 @@
#!/bin/bash
set -euo pipefail
if [ "$#" -eq 0 ]; then
echo "usage: $0 <test command>" >&2
exit 1
fi
if [ -n "${PR_BODY:-}" ]; then
TESTS=$(printf '%s\n' "$PR_BODY" | tr -d '\r' | awk '/^```ci-tests[ \t]*$/ {f = 1; next} /^```[ \t]*$/ {f = 0} f')
fi
args=()
while read -r p; do
if [ -n "$p" ]; then args+=(-m "$p"); fi
done <<< "${TESTS:-}"
if [ "${#args[@]}" -gt 0 ]; then
args+=(--fail-on=empty)
elif [ "${REDUCED:-}" = true ]; then
echo "No tests selected"
exit 0
fi
i=1
attempts=${ATTEMPTS:-1}
while [ "$i" -le "$attempts" ]; do
if "$@" "${args[@]}"; then
break
else
echo "Attempt $i failed, retrying..."
i=$((i + 1))
sleep 1
fi
done
if [ "$i" -gt "$attempts" ]; then
echo "All $attempts attempts failed."
exit 1
fi