Hatchling's default sdist is everything git does not ignore, which packed the Claude skills, the GitHub configuration, the PyInstaller spec, the device-side scripts and the developer environment template into an archive whose only job is to build and test the wheel. An exclude list keeps the package, the tests and their fixture, the manual and the files a build reads. The build backend floor is hatchling 1.26, the first to write the PEP 639 licence fields into the metadata; an older one built a wheel that said nothing about the licence. Workflow comments that reasoned from a private repo's metered minutes are reworded for the public one, a skill's usage line stops naming one machine's venv, and the scheduler's lock file is ignored in the tree rather than only in one clone's info/exclude. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
118 lines
4.2 KiB
YAML
118 lines
4.2 KiB
YAML
# The three commands CONTRIBUTING.md asks a contributor to run, run for them.
|
|
#
|
|
# Split in two on purpose. Style is a property of the source, not of the machine, so
|
|
# `lint` runs once and its failure is unambiguous. Behaviour is a property of the
|
|
# machine, so `test` runs everywhere we claim to work — the description promises
|
|
# Windows, macOS and Linux, and until this file existed that promise had only ever been
|
|
# checked on one of them.
|
|
name: CI
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
pull_request:
|
|
workflow_dispatch:
|
|
|
|
# Nothing here writes to the repository; say so rather than inherit the default.
|
|
permissions:
|
|
contents: read
|
|
|
|
# A second push while the first is still running makes the first answer obsolete.
|
|
# Cancel it — a run on a stale commit is a queue slot and a wait spent on nothing.
|
|
concurrency:
|
|
group: ci-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
jobs:
|
|
lint:
|
|
name: lint
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 10
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- uses: actions/setup-python@v5
|
|
with:
|
|
python-version: "3.10"
|
|
cache: pip
|
|
cache-dependency-path: pyproject.toml
|
|
|
|
- run: pip install -e ".[dev]"
|
|
|
|
# Both gates, and the second runs even when the first fails: they report
|
|
# different things and seeing only the earlier one wastes a round trip.
|
|
- run: ruff check .
|
|
- if: ${{ !cancelled() }}
|
|
run: ruff format --check .
|
|
|
|
test:
|
|
name: test ${{ matrix.os }} py${{ matrix.python }}
|
|
runs-on: ${{ matrix.os }}
|
|
timeout-minutes: 15
|
|
strategy:
|
|
# Let every leg finish. The point of a run is the whole picture of what broke,
|
|
# and one red leg cancelling its siblings hides the rest until the next push.
|
|
fail-fast: false
|
|
matrix:
|
|
# Linux carries the full Python range and the slower-to-schedule runners
|
|
# cover the ends of it, which is where a version-dependent break actually
|
|
# shows up. It was shaped this way when the repository was private and
|
|
# minutes were metered; on a public one they are not, so this can widen to
|
|
# every OS times every version whenever the wait for a full run is worth it.
|
|
include:
|
|
- { os: ubuntu-latest, python: "3.10" }
|
|
- { os: ubuntu-latest, python: "3.11" }
|
|
- { os: ubuntu-latest, python: "3.12" }
|
|
- { os: ubuntu-latest, python: "3.13" }
|
|
- { os: windows-latest, python: "3.10" }
|
|
- { os: windows-latest, python: "3.13" }
|
|
- { os: macos-latest, python: "3.13" }
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- uses: actions/setup-python@v5
|
|
with:
|
|
python-version: ${{ matrix.python }}
|
|
cache: pip
|
|
cache-dependency-path: pyproject.toml
|
|
|
|
- run: pip install -e ".[dev]"
|
|
|
|
# Includes tests/test_gallery.py, the dual-platform readability gate: every
|
|
# screen has to stay readable at 72 columns regular and 53 on the PicoCalc, and
|
|
# every PicoCalc case is a hard failure rather than a warning.
|
|
- run: python -m pytest -q
|
|
|
|
# Builds the distributions and checks them the way PyPI would, publishing nothing.
|
|
# Worth its minute: packaging breaks silently and is otherwise only discovered on
|
|
# the one day you least want to discover it. The wheel is installed into a clean
|
|
# environment and the command run from outside the source tree, because "it built"
|
|
# and "it works when installed" are different claims.
|
|
build:
|
|
name: build
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 10
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- uses: actions/setup-python@v5
|
|
with:
|
|
python-version: "3.12"
|
|
|
|
- run: pip install build twine
|
|
|
|
- run: python -m build
|
|
|
|
- run: twine check dist/*
|
|
|
|
- name: Install the wheel clean and run the command
|
|
run: |
|
|
python -m venv /tmp/fresh
|
|
/tmp/fresh/bin/pip install --quiet dist/*.whl
|
|
cd /tmp
|
|
/tmp/fresh/bin/meshterm --help > /dev/null
|
|
# A tool-provided subcommand, not just --help: the tools are discovered at
|
|
# runtime, so a broken package still answers --help perfectly well.
|
|
/tmp/fresh/bin/meshterm contacts --help > /dev/null
|
|
echo "the wheel installs, the console script runs, and its tools registered"
|