Skip to content

Commit 47e9139

Browse files
committed
CI: run only sanity check on limited OSes when changes are trivial
The commit uses some heuristics to determine the triviality of a PR. It runs "quick" CI (i.e., only use sanity.run on fewer OSes) if (explicity required by user): - the *last* commit message contains a line 'ZFS-CI-Type: quick', or if (by heuristics): - the files changed are not in the list of specified directory, and - all commit messages does not contain 'ZFS-CI-Type: full'. It runs "full" CI otherwise. See: #16561 (comment) Signed-off-by: Shengqi Chen <[email protected]>
1 parent d40d409 commit 47e9139

File tree

4 files changed

+149
-2
lines changed

4 files changed

+149
-2
lines changed

.github/CONTRIBUTING.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,9 @@ Any required reviews can then be finalized and the pull request merged.
147147
#### Tests and Benchmarks
148148
* Every pull request is tested using a GitHub Actions workflow on multiple platforms by running the [zfs-tests.sh and zloop.sh](
149149
https://openzfs.github.io/openzfs-docs/Developer%20Resources/Building%20ZFS.html#running-zloop-sh-and-zfs-tests-sh) test suites.
150+
`.github/workflows/scripts/generate-ci-type.py` is used to determine whether the pull request is "trivial", i.e., not initroducing behavior changes of any code, configuration or tests. If so, the CI will run on fewer platforms and only essential sanity tsets will run. You can control its behaviour by adding `ZFS-CI-Type` line to your commit message:
151+
* If your last commit (or `HEAD` in git terms) contains a line `ZFS-CI-Type: quick`, quick mode is forced regardless of what files are changed.
152+
* Otherwise, if any commit in a PR contains a line `ZFS-CI-Type: full`, full mode is forced.
150153
* To verify your changes conform to the [style guidelines](
151154
https://github.com/openzfs/zfs/blob/master/.github/CONTRIBUTING.md#style-guides
152155
), please run `make checkstyle` and resolve any warnings.
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
#!/usr/bin/env python3
2+
3+
"""
4+
Determine the CI type based on the change list and commit message.
5+
6+
Prints "quick" if (explicity required by user):
7+
- the *last* commit message contains 'ZFS-CI-Type: quick'
8+
or if (heuristics):
9+
- the files changed are not in the list of specified directory, and
10+
- all commit messages does not contain 'ZFS-CI-Type: full'
11+
12+
Otherwise prints "full".
13+
"""
14+
15+
import sys
16+
import subprocess
17+
import re
18+
19+
"""
20+
Patterns of files that are not considered to trigger full CI.
21+
"""
22+
FULL_RUN_IGNORE_REGEX = list(map(re.compile, [
23+
r'.*\.md',
24+
r'.*\.gitignore'
25+
]))
26+
27+
"""
28+
Patterns of files that are considered to trigger full CI.
29+
"""
30+
FULL_RUN_REGEX = list(map(re.compile, [
31+
r'cmd.*',
32+
r'configs/.*',
33+
r'META',
34+
r'.*\.am',
35+
r'.*\.m4',
36+
r'autogen\.sh',
37+
r'configure\.ac',
38+
r'copy-builtin',
39+
r'contrib',
40+
r'etc',
41+
r'include',
42+
r'lib/.*',
43+
r'module/.*',
44+
r'scripts/.*',
45+
r'tests/.*',
46+
r'udev/.*'
47+
]))
48+
49+
if __name__ == '__main__':
50+
51+
prog = sys.argv[0]
52+
53+
if len(sys.argv) != 3:
54+
print(f'Usage: {prog} <head_ref> <base_ref>')
55+
sys.exit(1)
56+
57+
head, base = sys.argv[1:3]
58+
59+
def output_type(type, reason):
60+
print(f'{prog}: will run {type} CI: {reason}', file=sys.stderr)
61+
print(type)
62+
sys.exit(0)
63+
64+
# check last (HEAD) commit message
65+
last_commit_message_raw = subprocess.run([
66+
'git', 'show', '-s', '--format=%B', 'HEAD'
67+
], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
68+
69+
for line in last_commit_message_raw.stdout.decode().splitlines():
70+
if line.strip().lower() == 'zfs-ci-type: quick':
71+
output_type('quick', f'explicitly requested by HEAD commit {head}')
72+
73+
# check all commit messages
74+
all_commit_message_raw = subprocess.run([
75+
'git', 'show', '-s',
76+
'--format=ZFS-CI-Commit: %H%n%B', f'{head}...{base}'
77+
], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
78+
all_commit_message = all_commit_message_raw.stdout.decode().splitlines()
79+
80+
commit_ref = head
81+
for line in all_commit_message:
82+
if line.startswith('ZFS-CI-Commit:'):
83+
commit_ref = line.lstrip('ZFS-CI-Commit:').rstrip()
84+
if line.strip().lower() == 'zfs-ci-type: full':
85+
output_type('full', f'explicitly requested by commit {commit_ref}')
86+
87+
# check changed files
88+
changed_files_raw = subprocess.run([
89+
'git', 'diff', '--name-only', head, base
90+
], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
91+
changed_files = changed_files_raw.stdout.decode().splitlines()
92+
93+
for f in changed_files:
94+
for r in FULL_RUN_IGNORE_REGEX:
95+
if r.match(f):
96+
break
97+
else:
98+
for r in FULL_RUN_REGEX:
99+
if r.match(f):
100+
output_type(
101+
'full',
102+
f'changed file "{f}" matches pattern "{r.pattern}"'
103+
)
104+
105+
# catch-all
106+
output_type('quick', 'no changed file matches full CI patterns')

.github/workflows/scripts/qemu-6-tests.sh

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ if [ -z ${1:-} ]; then
4848
for i in $(seq 1 $VMs); do
4949
IP="192.168.122.1$i"
5050
daemonize -c /var/tmp -p vm${i}.pid -o vm${i}log.txt -- \
51-
$SSH zfs@$IP $TESTS $OS $i $VMs
51+
$SSH zfs@$IP $TESTS $OS $i $VMs $CI_TYPE
5252
# handly line by line and add info prefix
5353
stdbuf -oL tail -fq vm${i}log.txt \
5454
| while read -r line; do prefix "$i" "$line"; done &
@@ -91,6 +91,9 @@ esac
9191
# run functional testings and save exitcode
9292
cd /var/tmp
9393
TAGS=$2/$3
94+
if [ "$4" == "quick" ]; then
95+
export RUNFILES="sanity.run"
96+
fi
9497
sudo dmesg -c > dmesg-prerun.txt
9598
mount > mount.txt
9699
df -h > df-prerun.txt

.github/workflows/zfs-qemu.yml

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,48 @@ on:
66

77
jobs:
88

9+
test-config:
10+
name: Generate configuration for QEMU test
11+
runs-on: ubuntu-24.04
12+
outputs:
13+
test_os: ${{ steps.os.outputs.os }}
14+
ci_type: ${{ steps.os.outputs.ci_type }}
15+
steps:
16+
- uses: actions/checkout@v4
17+
with:
18+
fetch-depth: 0
19+
- name: Generate OS config and CI type
20+
id: os
21+
run: |
22+
FULL_OS='["almalinux8", "almalinux9", "centos-stream9", "debian11", "debian12", "fedora39", "fedora40", "freebsd13", "freebsd13r", "freebsd14", "freebsd14r", "ubuntu20", "ubuntu22", "ubuntu24"]'
23+
QUICK_OS='["almalinux8", "almalinux9", "debian12", "freebsd13", "freebsd14", "ubuntu22"]'
24+
# determine CI type when running on PR
25+
ci_type="full"
26+
if ${{ github.event_name == 'pull_request' }}; then
27+
head=${{ github.event.pull_request.head.sha }}
28+
base=${{ github.event.pull_request.base.sha }}
29+
ci_type=$(python3 .github/workflows/scripts/generate-ci-type.py $head $base)
30+
fi
31+
if [ "$ci_type" == "quick" ]; then
32+
os_selection="$QUICK_OS"
33+
else
34+
os_selection="$FULL_OS"
35+
fi
36+
os_json=$(echo ${os_selection} | jq -c)
37+
echo "os=$os_json" >> $GITHUB_OUTPUT
38+
echo "ci_type=$ci_type" >> $GITHUB_OUTPUT
39+
940
qemu-vm:
1041
name: qemu-x86
42+
needs: [ test-config ]
1143
strategy:
1244
fail-fast: false
1345
matrix:
1446
# all:
1547
# os: [almalinux8, almalinux9, archlinux, centos-stream9, fedora39, fedora40, debian11, debian12, freebsd13, freebsd13r, freebsd14, freebsd14r, freebsd15, ubuntu20, ubuntu22, ubuntu24]
1648
# openzfs:
17-
os: [almalinux8, almalinux9, centos-stream9, debian11, debian12, fedora39, fedora40, freebsd13, freebsd13r, freebsd14, freebsd14r, ubuntu20, ubuntu22, ubuntu24]
49+
# os: [almalinux8, almalinux9, centos-stream9, debian11, debian12, fedora39, fedora40, freebsd13, freebsd13r, freebsd14, freebsd14r, ubuntu20, ubuntu22, ubuntu24]
50+
os: ${{ fromJson(needs.test-config.outputs.test_os) }}
1851
runs-on: ubuntu-24.04
1952
steps:
2053
- uses: actions/checkout@v4
@@ -64,6 +97,8 @@ jobs:
6497
- name: Run tests
6598
timeout-minutes: 270
6699
run: .github/workflows/scripts/qemu-6-tests.sh
100+
env:
101+
CI_TYPE: ${{ needs.test-config.outputs.ci_type }}
67102

68103
- name: Prepare artifacts
69104
if: always()

0 commit comments

Comments
 (0)