-
Notifications
You must be signed in to change notification settings - Fork 39
201 lines (168 loc) · 7.24 KB
/
Copy pathci.yml
File metadata and controls
201 lines (168 loc) · 7.24 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
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
name: CI
# Default behavior, on every push to master and every pull request: build the
# static site, and (on master) publish it to GitHub Pages. That is all that runs
# by default, because the full example/test/type/lint suite is already run on the
# local machine before pushing, and GitHub Actions can be slow.
#
# The full gates (examples match the Markdown, every example runs clean, pytest
# passes, ty-clean, ruff-clean) are opt-in, as are the prose checks (codespell
# spelling and Vale house style). Run them only when you want a second opinion
# in CI, in either of two ways:
# * From the Actions tab, choose this workflow and click "Run workflow"
# (the "run_gates" input defaults to true), or run
# gh workflow run ci.yml -f run_gates=true
# * Include the marker [full-ci] anywhere in a push commit message.
#
# Tooling is managed by uv.
on:
push:
branches: [master]
pull_request:
workflow_dispatch:
inputs:
run_gates:
description: "Run the full gates plus the spelling/house-style checks"
type: boolean
default: true
permissions:
contents: read
jobs:
# Default work: build the static site. Fast, because it skips running the
# examples, type-checking, and linting. On a push to master it hands the
# built site to the deploy job below.
site:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v6
with:
python-version: "3.15"
enable-cache: true
- name: Install pandoc
run: sudo apt-get update && sudo apt-get install -y pandoc
- name: Install tooling
run: uv sync --locked
- name: Build the static site
run: uv run python tools/build_site.py
# On master only, hand the built site to the deploy job below.
- name: Upload Pages artifact
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
uses: actions/upload-pages-artifact@v3
with:
path: build/site
# The full gates, opt-in only (manual dispatch with run_gates=true, or a push
# commit message containing [full-ci]). These run on the local machine on
# every change, so they are not part of the default CI path.
gates:
if: >-
(github.event_name == 'workflow_dispatch' && inputs.run_gates) ||
(github.event_name == 'push' &&
contains(github.event.head_commit.message, '[full-ci]'))
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v6
with:
python-version: "3.15"
enable-cache: true
- name: Install pandoc
run: sudo apt-get update && sudo apt-get install -y pandoc
- name: Install tooling
run: uv sync --locked
# Hard gate: the book's code blocks must match the committed Examples/
# tree (no drift, no conflicting duplicates).
- name: Check examples match the Markdown
run: uv run python tools/extract_examples.py
- name: Extract examples for running
run: uv run python tools/extract_examples.py --write
# Hard gate: every extracted example must run cleanly (the book is fully
# modernized, so the baseline is empty; use --baseline to gate only
# regressions during future bulk work).
- name: Run examples
run: uv run python tools/run_examples.py
# Hard gate: the book's pytest examples (test_*.py) must pass.
- name: Run the book's pytest examples
run: uv run pytest build/examples
# Hard gate: the examples must stay ty-clean (zero diagnostics).
- name: Type-check examples with ty
run: uv run ty check build/examples
# Hard gate: PEP 8 lint (naming, imports, modernization) must pass.
# See pyproject [tool.ruff]; deliberate exceptions live in
# per-file-ignores.
- name: Lint examples with ruff
run: uv run ruff check build/examples
# The same five checks, applied to Solutions/ (worked exercise
# answers), which go through a parallel extract/validate/ty/ruff/pytest
# pipeline (tools/extract_solutions.py). See tools/README.md.
- name: Check solutions match Solutions/*.md
run: uv run python tools/extract_solutions.py
- name: Extract solutions for running
run: uv run python tools/extract_solutions.py --write
- name: Verify solutions #: output markers
run: uv run python tools/validate_output.py --tree "$GITHUB_WORKSPACE/build/solutions" Solutions
- name: Type-check solutions with ty
run: uv run ty check build/solutions
- name: Lint solutions with ruff
run: uv run ruff check build/solutions
- name: Run the solutions' pytest examples
run: uv run pytest build/solutions
# Prose checks, opt-in only (same trigger as the gates job). codespell fails
# on spelling errors; Vale fails on em-dashes (an error-level rule) and prints
# the warning-level house-style findings. These also run locally via
# `make spell` and `make prose`.
prose:
if: >-
(github.event_name == 'workflow_dispatch' && inputs.run_gates) ||
(github.event_name == 'push' &&
contains(github.event.head_commit.message, '[full-ci]'))
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v6
with:
python-version: "3.15"
enable-cache: true
# Spelling: codespell is a uv-managed dev tool. Config lives in
# pyproject [tool.codespell]; the ignore list in tools/data/codespell-ignore.txt.
- name: Install tooling
run: uv sync --locked
- name: Spell-check prose with codespell
run: uv run codespell Chapters
# Vale is a standalone binary, not a Python package. Install the latest
# release; pin "version" below if you want fully reproducible runs.
- name: Install Vale
run: |
version=$(curl -fsSL https://api.github.com/repos/errata-ai/vale/releases/latest | grep -oP '"tag_name": "v\K[^"]+')
curl -fsSL "https://github.com/errata-ai/vale/releases/download/v${version}/vale_${version}_Linux_64-bit.tar.gz" | sudo tar -xz -C /usr/local/bin vale
vale --version
# Download the third-party styles referenced in .vale.ini (write-good,
# proselint). They are not committed, so CI fetches them each run.
- name: Sync Vale packages
run: vale sync
# House style: fails on em-dashes (error level); filler findings are
# warnings and do not fail the job. Config in .vale.ini.
- name: House-style lint with Vale
run: vale Chapters
# Publishes the site to GitHub Pages (bruceeckel.github.io/ThinkingInPython)
# on a push to master. It depends only on the site build, not on the opt-in
# gates, so publishing is not blocked by them.
deploy:
needs: site
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
runs-on: ubuntu-latest
permissions:
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deploy.outputs.page_url }}
concurrency:
group: pages
cancel-in-progress: true
steps:
- name: Deploy to GitHub Pages
id: deploy
uses: actions/deploy-pages@v4