-
Notifications
You must be signed in to change notification settings - Fork 32
180 lines (164 loc) · 7.14 KB
/
Copy pathpython-tests.yaml
File metadata and controls
180 lines (164 loc) · 7.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
name: Python Tests
on:
workflow_dispatch:
push:
branches:
- main
- release-*
pull_request:
merge_group:
permissions:
contents: read
pull-requests: read
jobs:
changes:
if: github.repository_owner == 'jumpstarter-dev'
runs-on: ubuntu-latest
outputs:
should_run: ${{ steps.filter.outputs.python }}
renode_driver: ${{ steps.filter.outputs.renode_driver }}
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
fetch-depth: 0
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4
id: filter
with:
base: ${{ github.base_ref || github.event.merge_group.base_ref || 'main' }}
filters: |
python:
- 'python/**'
- '!python/docs/**'
- '!python/**/*.md'
- '.github/workflows/python-tests.yaml'
renode_driver:
- 'python/packages/jumpstarter-driver-renode/**'
pytest-matrix:
needs: changes
if: needs.changes.outputs.should_run == 'true' || github.event_name == 'workflow_dispatch'
runs-on: ${{ matrix.runs-on }}
strategy:
fail-fast: false
matrix:
runs-on: [arc-runner-kubevirt-small, macos-15]
# Floor: oldest Python in supported platforms (RHEL 9 appstream)
# Ceiling: newest Python in latest Fedora
# Review on each RHEL/Fedora release
python-version: ["3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
fetch-depth: 0
- id: uv
run: echo "version=$(cat .uv-version)" >> "$GITHUB_OUTPUT"
- name: Install uv
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
with:
version: ${{ steps.uv.outputs.version }}
python-version: ${{ matrix.python-version }}
- name: Setup Linux dependencies
if: runner.os == 'Linux'
run: |
# udev rules and kernel modules (idempotent)
echo <<EOF | sudo tee /etc/udev/rules.d/99-kvm.rules
KERNEL=="kvm", GROUP="kvm", MODE="0666"
KERNEL=="vhost-vsock", GROUP="kvm", MODE="0666"
KERNEL=="vhost-net", GROUP="kvm", MODE="0666"
EOF
sudo udevadm control --reload-rules
for mod in vhost_vsock vhost_net veth bridge nf_nat nf_conntrack nft_masq nft_nat nft_chain_nat; do
sudo modprobe "$mod" 2>/dev/null || true
done
sudo chmod 0666 /dev/kvm /dev/vhost-vsock /dev/vhost-net 2>/dev/null || true
# collect missing packages
pkgs=()
command -v qemu-system-arm &>/dev/null || pkgs+=(qemu-system-arm)
command -v qemu-system-x86_64 &>/dev/null || pkgs+=(qemu-system-x86)
dpkg -s libgpiod-dev &>/dev/null || pkgs+=(libgpiod-dev)
dpkg -s liblgpio-dev &>/dev/null || pkgs+=(liblgpio-dev)
command -v nft &>/dev/null || pkgs+=(nftables)
command -v dnsmasq &>/dev/null || pkgs+=(dnsmasq-base)
command -v dhclient &>/dev/null || pkgs+=(isc-dhcp-client)
command -v dig &>/dev/null || pkgs+=(dnsutils)
command -v renode &>/dev/null || pkgs+=(renode)
command -v rpm2cpio &>/dev/null || pkgs+=(rpm2cpio)
command -v cpio &>/dev/null || pkgs+=(cpio)
if [ ${#pkgs[@]} -gt 0 ]; then
# add renode repo if needed
if [[ " ${pkgs[*]} " == *" renode "* ]]; then
wget -qO /tmp/renode.deb https://github.com/renode/renode/releases/download/v1.16.1/renode_1.16.1_amd64.deb
pkgs=("${pkgs[@]/renode//tmp/renode.deb}")
fi
sudo apt-get update
sudo apt-get install -y "${pkgs[@]}"
fi
- name: Install Qemu (macOS)
if: runner.os == 'macOS'
run: |
brew install qemu
# Homebrew Renode is slow (~5+ minutes per job). Install on macOS only when this run
# touches the Renode driver, or on workflow_dispatch (full manual run). Linux still
# installs Renode from the .deb in all jobs (fast).
- name: Install Renode (macOS)
if: >-
runner.os == 'macOS'
&& (needs.changes.outputs.renode_driver == 'true'
|| github.event_name == 'workflow_dispatch')
run: |
brew install renode/tap/renode
- name: Cache Fedora Cloud images
id: cache-fedora-cloud-images
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
with:
path: python/packages/jumpstarter-driver-qemu/images
key: fedora-cloud-43-1.6
- name: Download Fedora Cloud images
if: steps.cache-fedora-cloud-images.outputs.cache-hit != 'true'
run: |
for arch in aarch64 x86_64; do
curl -L --fail --output "python/packages/jumpstarter-driver-qemu/images/Fedora-Cloud-Base-Generic-43-1.6.${arch}.qcow2" \
"https://iad.mirror.rackspace.com/fedora/releases/43/Cloud/${arch}/images/Fedora-Cloud-Base-Generic-43-1.6.${arch}.qcow2"
done
- name: Run pytest
working-directory: python
env:
PYTEST_ADDOPTS: "--cov-report=xml --log-level=CRITICAL --log-cli-level=CRITICAL"
run: |
make test -j4 LOGS_DIR=${{ runner.temp }}/test-logs
- name: Upload test logs
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: test-logs-${{ matrix.runs-on }}-py${{ matrix.python-version }}
path: ${{ runner.temp }}/test-logs/
if-no-files-found: ignore
retention-days: 7
# Diff-coverage is only checked on Linux. Several packages (e.g.
# jumpstarter-driver-dut-network) are Linux-only, so their tests are
# entirely skipped on macOS, making all changed lines appear uncovered
# and dragging diff-coverage below the threshold. Linux runners already
# enforce the 80% gate, so nothing is lost.
- name: Check coverage on changed lines
if: github.event_name == 'pull_request' && runner.os == 'Linux'
working-directory: python
run: |
coverage_files=$(find packages docs/source/reference -name coverage.xml 2>/dev/null | sort)
if [ -z "$coverage_files" ]; then
echo "::error::No coverage.xml files found"
exit 1
fi
uv run diff-cover $coverage_files --compare-branch=origin/${{ github.base_ref }} --fail-under=80 --exclude '*_pb2.py' '*_pb2_grpc.py' '**/conftest.py' '**/test_*.py' '**/*_test.py'
# https://github.com/orgs/community/discussions/26822
pytest:
runs-on: ubuntu-latest
needs: [changes, pytest-matrix]
if: ${{ always() }}
steps:
- run: exit 1
# Fail on failures or cancellations, but allow skips when no relevant changes
if: >-
${{
contains(needs.*.result, 'failure')
|| contains(needs.*.result, 'cancelled')
|| (contains(needs.*.result, 'skipped') && needs.changes.outputs.should_run == 'true')
}}