chore: add CHANGELOG.md and enforce version consistency in CI #123
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| # Only maintainers can trigger CI (via PR approval or manual re-run). | |
| # Fork PRs require maintainer approval before workflows run. | |
| permissions: | |
| contents: read | |
| # A new push to a PR makes the in-flight run obsolete. | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| lint: | |
| name: Lint & types | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.12" | |
| # Pinned: an unpinned ruff silently disagrees with the contributor's | |
| # local version and fails CI on unrelated PRs (see chore/ruff-ci-fix). | |
| - name: Install tooling | |
| run: pip install "ruff==0.15.15" "mypy>=1.11,<2" | |
| - name: Ruff check | |
| run: ruff check . | |
| - name: Ruff format check | |
| run: ruff format --check . | |
| # Type checking is OS- and version-independent, so it belongs here and | |
| # runs once — not four times at the tail of every test matrix entry. | |
| - name: Type check | |
| run: mypy src/ scripts/ --ignore-missing-imports | |
| # The version is committed in five places. install.py stamps them from | |
| # src/__init__.py at install time, so drift never breaks an install and stays | |
| # invisible locally — it surfaces as a release that /plugin update declines to | |
| # fetch, because Claude Code keys its cache on .claude-plugin/plugin.json. | |
| versions: | |
| name: Version consistency | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.12" | |
| - name: Check version strings agree | |
| run: python scripts/check_versions.py | |
| test: | |
| name: Test (${{ matrix.os }}, Python ${{ matrix.python-version }}) | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest] | |
| python-version: ["3.10", "3.11", "3.12", "3.13"] | |
| include: | |
| # The installer and bin/token-saver have real per-OS branches; the | |
| # full Python sweep stays on Linux to keep the matrix affordable. | |
| - os: macos-latest | |
| python-version: "3.12" | |
| - os: windows-latest | |
| python-version: "3.12" | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - uses: actions/setup-python@v6 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Install dependencies | |
| run: pip install -e ".[dev]" | |
| - name: Run tests with coverage | |
| run: python -m pytest tests/ -v --cov=src --cov-report=xml --cov-report=term | |
| # Text I/O that omits `encoding=` decodes with the *locale* encoding — | |
| # cp1252 on Windows — which is how the first Windows run died: a fixture | |
| # containing "❌" was unreadable. Ruff's PLW1514 catches open() but not | |
| # subprocess(text=True), which is most of our exposure, so this flag is | |
| # the real guard. Linux-only: it is a property of the source, not the OS, | |
| # and one run is enough to fail the PR. | |
| - name: Check for locale-dependent text I/O | |
| if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.12' | |
| env: | |
| PYTHONWARNDEFAULTENCODING: "1" | |
| run: python -W error::EncodingWarning -m pytest tests/ -q | |
| - name: Upload coverage | |
| if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.12' | |
| uses: codecov/codecov-action@v6 | |
| with: | |
| files: coverage.xml | |
| fail_ci_if_error: false |