Repository navigation
143 lines (137 loc) · 6.36 KB
/
Copy pathtests.yml
File metadata and controls
143 lines (137 loc) · 6.36 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
name: Tests
# Every push and every pull request, whatever its base branch (stacked pull requests are checked too).
# pages.yml calls this workflow as well and deploys only after it passes.
on:
push:
pull_request:
workflow_call:
permissions:
contents: read
defaults:
run:
shell: bash
jobs:
checks:
name: Offline checks
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- name: Checkout
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
with:
persist-credentials: false
- name: Install dependencies
id: install
run: |
python3 -m venv "$RUNNER_TEMP/venv"
"$RUNNER_TEMP/venv/bin/python" -m pip install --quiet -r requirements.txt -r requirements-lint.txt
# The remaining checks run even when an earlier one fails, so one run reports every failure.
- name: Unit tests (every tests/test_*.py, under coverage)
# coverage.py measures scripts/ while each test file runs, including every script a test starts as a
# subprocess ([tool.coverage] in pyproject.toml); each process writes its own data file, combined below.
if: ${{ !cancelled() && steps.install.outcome == 'success' }}
env:
COVERAGE_FILE: ${{ runner.temp }}/coverage/.coverage
run: |
mkdir -p "$RUNNER_TEMP/coverage"
failed=()
for test in tests/test_*.py; do
echo "::group::$test"
"$RUNNER_TEMP/venv/bin/python" -I -m coverage run "$test" || failed+=("$test")
echo "::endgroup::"
done
for test in "${failed[@]}"; do
echo "::error file=$test::$test failed"
done
[ "${#failed[@]}" -eq 0 ]
- name: Coverage of scripts/ by the unit tests (fails below fail_under in pyproject.toml)
if: ${{ !cancelled() && steps.install.outcome == 'success' }}
env:
COVERAGE_FILE: ${{ runner.temp }}/coverage/.coverage
run: |
"$RUNNER_TEMP/venv/bin/python" -I -m coverage combine --quiet "$RUNNER_TEMP/coverage"
{
echo "### Coverage of scripts/ by the unit tests"
"$RUNNER_TEMP/venv/bin/python" -I -m coverage report --format=markdown --fail-under=0
} >> "$GITHUB_STEP_SUMMARY"
"$RUNNER_TEMP/venv/bin/python" -I -m coverage report
- name: Generated files match their sources
if: ${{ !cancelled() && steps.install.outcome == 'success' }}
run: '"$RUNNER_TEMP/venv/bin/python" scripts/build_catalog.py --verify --check'
- name: Inherited files keep their bytes
if: ${{ !cancelled() && steps.install.outcome == 'success' }}
run: '"$RUNNER_TEMP/venv/bin/python" scripts/build_legacy_inventory.py'
- name: Archive manifest matches its files
if: ${{ !cancelled() && steps.install.outcome == 'success' }}
run: '"$RUNNER_TEMP/venv/bin/python" -I scripts/fetch_archives.py --verify'
browser:
name: Browser smoke test
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
with:
persist-credentials: false
- name: Install dependencies
# Playwright drives the runner's preinstalled Google Chrome; no browser is downloaded.
run: |
python3 -m venv "$RUNNER_TEMP/venv"
"$RUNNER_TEMP/venv/bin/python" -m pip install --quiet -r requirements-dev.txt
- name: Smoke-test both pages in headless Chrome
run: |
"$RUNNER_TEMP/venv/bin/python" -I -m http.server 8765 --bind 127.0.0.1 > "$RUNNER_TEMP/http-server.log" 2>&1 &
server=$!
trap 'kill "$server"' EXIT
for _ in $(seq 50); do
curl --silent --fail --output /dev/null http://127.0.0.1:8765/archive.html && break
sleep 0.2
done
"$RUNNER_TEMP/venv/bin/python" -I tests/browser_smoke.py --base http://127.0.0.1:8765 --browser "$(command -v google-chrome)"
lint:
# Every hook of .pre-commit-config.yaml on every file, as `pre-commit run --all-files` runs them locally:
# whitespace and file checks, ruff, mypy, actionlint and ESLint (check only), each one pinned. A hook that has to
# rewrite a file fails the run and shows the diff; the byte-pinned and generated files are excluded from them all.
name: Lint, format and type checks
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
with:
persist-credentials: false
- name: Install the pinned lint tools
id: install
# pre-commit, ruff and mypy from requirements-lint.txt; ESLint exactly as package-lock.json pins it, without
# running any package's install scripts.
run: |
python3 -m venv "$RUNNER_TEMP/venv"
"$RUNNER_TEMP/venv/bin/python" -m pip install --quiet -r requirements-lint.txt
node_version="$(node --version)"
echo "Node.js $node_version"
major=0 minor=0
if [[ "$node_version" =~ ^v([0-9]+)\.([0-9]+)\.[0-9]+$ ]]; then
major="${BASH_REMATCH[1]}" minor="${BASH_REMATCH[2]}"
fi
if ! (( (major == 20 && minor >= 19) || (major == 22 && minor >= 13) || major >= 24 )); then
echo "::error::Node.js $node_version does not satisfy ^20.19.0 || ^22.13.0 || >=24 (engines in package.json), which the pinned ESLint needs."
exit 1
fi
npm ci --ignore-scripts --no-audit --no-fund
- name: Run every pre-commit hook on every file
if: ${{ !cancelled() && steps.install.outcome == 'success' }}
env:
PRE_COMMIT_HOME: ${{ runner.temp }}/pre-commit
run: '"$RUNNER_TEMP/venv/bin/python" -I -m pre_commit run --all-files --show-diff-on-failure'
- name: Lint left the checkout unchanged
# Catches a hook or tool that rewrote or added a file; caches and node_modules/ are in .gitignore.
if: ${{ !cancelled() }}
run: |
changed="$(git status --porcelain --untracked-files=all)"
if [ -n "$changed" ]; then
echo "::error::Linting changed or added these files. Run pre-commit run --all-files locally and commit the reviewed result."
printf '%s\n' "$changed"
exit 1
fi