Repository navigation
162 lines (151 loc) · 6.4 KB
/
Copy pathcode-test.yaml
File metadata and controls
162 lines (151 loc) · 6.4 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
name: code tests
on:
push:
branches:
- main
paths:
- "python/**"
- ".github/workflows/code-test.yaml"
pull_request:
paths:
- "python/**"
- ".github/workflows/code-test.yaml"
workflow_dispatch:
merge_group:
types: [checks_requested]
# limit rapid succession from pushes
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
env:
OPENSTACK_VERSION: "2026.1"
jobs:
discover:
runs-on: ubuntu-latest
outputs:
projects: ${{ steps.set-projects.outputs.projects }}
steps:
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
- name: Find all projects with pyproject.toml
id: set-projects
run: |
# grabs all paths with pyproject.toml, snips the 2nd dir, grabs only unique ones, makes a JSON list
projects=$(find python -mindepth 2 ! -wholename 'python/understack-tests/*' -name pyproject.toml | awk -F/ '{print $2}' | sort -u | jq -R -s -c 'split("\n")[:-1]')
echo "projects=$projects" >> "$GITHUB_OUTPUT"
uv:
needs: [discover]
runs-on: ubuntu-latest
strategy:
matrix:
project: ${{ fromJson(needs.discover.outputs.projects) }}
defaults:
run:
working-directory: ./python/${{ matrix.project }}
steps:
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
- uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7
with:
python-version-file: python/${{ matrix.project }}/pyproject.toml
- name: Install locked dependencies
if: ${{ hashFiles(format('python/{0}/uv.lock', matrix.project)) != '' }}
run: uv sync
- name: Install with OpenStack upper-constraints
if: ${{ hashFiles(format('python/{0}/uv.lock', matrix.project)) == '' }}
run: |
curl -fsSL -o "$RUNNER_TEMP/upper-constraints.txt" \
"https://releases.openstack.org/constraints/upper/${OPENSTACK_VERSION}"
# neutron-lib is installed from our fork (see [tool.uv.sources]), the
# same exclusion containers/neutron/Dockerfile makes.
grep -v '^neutron-lib===' "$RUNNER_TEMP/upper-constraints.txt" > "$RUNNER_TEMP/constraints.txt"
uv venv
uv pip install --constraint "$RUNNER_TEMP/constraints.txt" --group test -e .
# uv run must use this environment as-is, not lock and re-sync it.
echo "UV_NO_SYNC=1" >> "$GITHUB_ENV"
- run: uv build --wheel
- run: |
set -e
if [ -e .stestr.conf ]; then
uv run stestr run
else
uv run pytest --cov --cov-report xml:coverage.xml --junitxml=junit.xml
fi
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
with:
name: coverage-${{ matrix.project }}
path: python/${{ matrix.project }}/coverage.xml
retention-days: 1
# Publish the ML2 scenario traceability matrix (scenario ID -> status) to
# the job summary and keep the JUnit as an artifact. neutron-understack
# only: its scenario tests tag each JUnit case with a `scenario` property.
- name: ML2 scenario traceability report
if: ${{ always() && matrix.project == 'neutron-understack' }}
run: |
if [ -f junit.xml ]; then
uv run python ../../scripts/scenario-report.py \
--catalog neutron_understack/tests/scenarios/SCENARIOS.md \
--junit junit.xml >> "$GITHUB_STEP_SUMMARY"
else
echo "No junit.xml produced (tests did not run)." >> "$GITHUB_STEP_SUMMARY"
fi
# Keep each project's JUnit for the consolidated publish-test-results job.
# if-no-files-found=ignore: stestr projects don't emit junit.xml.
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
if: ${{ always() }}
with:
name: junit-${{ matrix.project }}
path: python/${{ matrix.project }}/junit.xml
if-no-files-found: ignore
retention-days: 1
coverage-upload:
needs: [uv]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
# No merge-multiple: each project's coverage.xml has the same filename, so
# flattening would overwrite them. Download each artifact into its own
# coverage-reports/<artifact-name>/ subdirectory instead.
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
with:
pattern: coverage-*
path: coverage-reports
# Merge every project's coverage.xml into one report. This used to call
# the `cobertura-merge-globby` npm package, which uses `util.isString()`
# (removed in Node 24) and now crashes on the runner. A stdlib Python
# script does the same job with no npm/Node dependency.
- run: |
shopt -s globstar nullglob
files=(coverage-reports/**/coverage.xml)
if [ ${#files[@]} -eq 0 ]; then
echo "No coverage.xml artifacts found to merge" >&2
exit 1
fi
python3 scripts/merge-cobertura.py -o coverage.xml "${files[@]}"
shell: bash
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
with:
name: coverage.xml
path: coverage.xml
retention-days: 1
# Consolidated pass/fail/skip report from every project's JUnit, posted as a
# PR comment + check. Same-repo PRs only get write permissions; fork PRs would
# need a separate workflow_run-triggered workflow (not wired up here).
publish-test-results:
needs: [uv]
# Skip on fork PRs: the token is read-only there, so the action cannot post
# the check/comment. Forks would need a separate workflow_run workflow.
if: ${{ always() && github.event.pull_request.head.repo.fork != true }}
runs-on: ubuntu-latest
permissions:
checks: write
pull-requests: write
contents: read
steps:
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
with:
pattern: junit-*
merge-multiple: true
path: junit
- uses: EnricoMi/publish-unit-test-result-action@7622c5bf3d112a72ab4fa3951c2aa5723d8ab92d # v2.25.0
with:
check_name: Python test results
junit_files: junit/**/*.xml