Skip to content

prose changes to /activate #984

prose changes to /activate

prose changes to /activate #984

Workflow file for this run

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