v0.1.0 — zero known bugs (first minor release) #1907
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] | |
| jobs: | |
| test: | |
| permissions: | |
| contents: read | |
| strategy: | |
| # #848: don't let one failed combo cancel the other 11 — a single | |
| # flaky test cancelled two otherwise-green matrices on PR #846. | |
| # Full per-run results also make real cross-platform breakage | |
| # (one OS red, others green) legible at a glance. | |
| fail-fast: false | |
| matrix: | |
| # Explicit macOS pins (not `macos-latest`) so we don't silently | |
| # migrate when GitHub flips the `-latest` alias. See README §Supported | |
| # platforms for the policy. `macos-15` (Sequoia) is currently | |
| # `macos-latest` (May 2026) and the most common single non-current | |
| # version among real users (~24% of macOS install base per | |
| # https://telemetrydeck.com/survey/apple/macOS/versions/); `macos-26` | |
| # (Tahoe) is current and dominant (~75%). | |
| os: [ubuntu-latest, macos-15, macos-26, windows-latest] | |
| python-version: ["3.11", "3.12", "3.13"] | |
| name: test (${{ matrix.os }}, ${{ matrix.python-version }})${{ matrix.python-version == '3.12' && matrix.os == 'ubuntu-latest' && ' + coverage' || '' }} | |
| runs-on: ${{ matrix.os }} | |
| # No PYTHONUTF8 env: #645 made text I/O UTF-8 without the PEP-540 backstop | |
| # (#641). Every text-mode open()/read_text()/write_text() and every | |
| # subprocess text=True capture passes an explicit encoding="utf-8" (enforced | |
| # by scripts/check_explicit_encoding.py), and the `vera` CLI reconfigures its | |
| # stdout/stderr to UTF-8 at startup — so a Vera program printing `→` / `—` is | |
| # UTF-8 on every runner regardless of locale, cp1252 Windows included. | |
| steps: | |
| - uses: actions/checkout@v7 | |
| with: | |
| persist-credentials: false | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Install dependencies | |
| run: pip install -e ".[dev]" | |
| # Two mutually-exclusive run-test steps so the gating cell | |
| # (3.12 / ubuntu) does coverage in the SAME pytest invocation | |
| # rather than running the full suite twice. -n auto runs tests | |
| # in parallel across CPU cores via pytest-xdist; the coverage | |
| # cell takes the longest because instrumentation adds overhead, | |
| # so it sets the wall time and gets parallelised too. | |
| - name: Run tests | |
| if: ${{ !(matrix.python-version == '3.12' && matrix.os == 'ubuntu-latest') }} | |
| run: pytest -v -n auto | |
| - name: Run tests with coverage | |
| if: matrix.python-version == '3.12' && matrix.os == 'ubuntu-latest' | |
| run: pytest -v -n auto --cov=vera --cov-report=term-missing --cov-report=xml --cov-fail-under=80 | |
| - name: Upload coverage to Codecov | |
| if: matrix.python-version == '3.12' && matrix.os == 'ubuntu-latest' | |
| uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0 | |
| with: | |
| token: ${{ secrets.CODECOV_TOKEN }} | |
| files: coverage.xml | |
| flags: python | |
| fail_ci_if_error: false | |
| typecheck: | |
| permissions: | |
| contents: read | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| with: | |
| persist-credentials: false | |
| - name: Set up Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.12" | |
| - name: Install dependencies | |
| run: pip install -e ".[dev]" | |
| - name: Run mypy | |
| run: mypy vera/ | |
| lint: | |
| permissions: | |
| contents: read | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| with: | |
| # Full history so check_changelog_updated.py can diff against | |
| # origin/main. Other lint checks work fine without it. | |
| fetch-depth: 0 | |
| persist-credentials: false | |
| - name: Set up Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.12" | |
| - name: Install dependencies | |
| run: pip install -e ".[dev]" | |
| - name: Check CHANGELOG updated for substantive changes | |
| # PR-level escape hatch: adding the "skip-changelog" label | |
| # skips this step for PRs that legitimately don't need an entry | |
| # (e.g., a typo fix in a code comment). The step always runs | |
| # for push events on main. | |
| if: github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'skip-changelog') | |
| run: python scripts/check_changelog_updated.py | |
| - name: Check conformance suite | |
| run: python scripts/check_conformance.py | |
| - name: Check all examples type-check and verify cleanly | |
| run: python scripts/check_examples.py | |
| - name: Check vera run commands in examples/README.md are valid | |
| run: python scripts/check_examples_readme.py | |
| - name: Check version numbers are in sync | |
| run: python scripts/check_version_sync.py | |
| - name: Check spec code blocks parse correctly | |
| run: python scripts/check_spec_examples.py | |
| - name: Check README code blocks parse correctly | |
| run: python scripts/check_readme_examples.py | |
| - name: Check SKILL.md code blocks parse correctly | |
| run: python scripts/check_skill_examples.py | |
| - name: Check FAQ code blocks parse correctly | |
| run: python scripts/check_faq_examples.py | |
| - name: Check HTML code blocks parse, check, and verify | |
| run: python scripts/check_html_examples.py | |
| - name: Check no doc example redefines a built-in (E151) | |
| run: python scripts/check_doc_builtin_shadowing.py | |
| - name: Check no unexpected [E602]/[E604] silent skips (Layer 1 of #626) | |
| run: python scripts/check_e602_clean.py | |
| - name: Check every diagnostic carries rationale/fix/spec_ref (#682) | |
| run: python scripts/check_diagnostic_fields.py | |
| - name: Check text-mode file I/O passes explicit encoding (#645) | |
| run: python scripts/check_explicit_encoding.py | |
| - name: Check site assets are up-to-date | |
| run: python scripts/check_site_assets.py | |
| - name: Check license compliance | |
| run: python scripts/check_licenses.py | |
| - name: Check documentation counts are consistent | |
| run: python scripts/check_doc_counts.py | |
| - name: Check limitation tables are in sync | |
| run: python scripts/check_limitations_sync.py | |
| - name: Lint (ruff) | |
| run: ruff check . | |
| - name: Security lint (ruff S rules) | |
| run: ruff check --select S vera/ | |
| - name: Verify uv.lock is up to date | |
| run: | | |
| pip install "uv>=0.5,<2" | |
| uv lock --check | |
| security: | |
| permissions: | |
| contents: read | |
| security-events: write | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| with: | |
| fetch-depth: 0 | |
| persist-credentials: false | |
| - name: Gitleaks | |
| uses: gitleaks/gitleaks-action@v3 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| dependency-audit: | |
| permissions: | |
| contents: read | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| with: | |
| persist-credentials: false | |
| - name: Set up Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.12" | |
| - name: Install dependencies and pip-audit | |
| # `pip install --upgrade pip` first: actions/setup-python@v6 bakes | |
| # pip 26.0.1 into its toolchain, which is flagged for CVE-2026-3219 | |
| # (archive-handling, fixed in pip 26.1 via pypa/pip#13870). Without | |
| # the upgrade, pip-audit reports the runner's own pip as vulnerable | |
| # even though the fix is shipped on PyPI. Drop the `--upgrade pip` | |
| # once the runner image picks up pip 26.1 natively. Tracked in #537, | |
| # listed in the "CI workarounds" section of KNOWN_ISSUES.md. | |
| run: pip install --upgrade pip && pip install -e . && pip install pip-audit | |
| - name: Audit dependencies for known CVEs | |
| # --skip-editable: vera itself is a local editable install, not on PyPI | |
| # --ignore-vuln CVE-2026-4539: pygments 2.19.2 (transitive via pytest/rich); | |
| # no fix release exists yet — revisit when pygments >2.19.2 ships | |
| run: pip-audit --skip-editable --ignore-vuln CVE-2026-4539 | |
| wheel-preflight: | |
| # Structural backstop for #691-class regressions: if an upstream dep | |
| # bumps its platform-tag baseline (e.g. z3-solver going from | |
| # macosx_13_0_arm64 to macosx_15_0_arm64 between 4.15.4 and 4.15.5), | |
| # this job fails fast in CI rather than letting users discover the | |
| # regression at install time on their machine. Pairs with the | |
| # README §Supported platforms policy; the script enforces what the | |
| # README documents. | |
| permissions: | |
| contents: read | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| with: | |
| persist-credentials: false | |
| - name: Set up Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.12" | |
| - name: Check wheel availability across supported platforms | |
| run: python scripts/check_wheel_availability.py | |
| sbom: | |
| permissions: | |
| contents: read | |
| runs-on: ubuntu-latest | |
| # Generate an SBOM on every push to main (i.e. each release merge). | |
| # PRs get the artifact too, useful for reviewing dependency changes. | |
| steps: | |
| - uses: actions/checkout@v7 | |
| with: | |
| persist-credentials: false | |
| - name: Set up Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.12" | |
| - name: Install vera and CycloneDX tooling | |
| run: pip install -e . && pip install cyclonedx-bom | |
| - name: Generate CycloneDX SBOM | |
| run: cyclonedx-py environment --of JSON -o sbom.json | |
| - name: Upload SBOM artifact | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: sbom | |
| path: sbom.json | |
| retention-days: 90 | |
| browser-parity: | |
| permissions: | |
| contents: read | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| with: | |
| persist-credentials: false | |
| - name: Set up Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.12" | |
| - name: Set up Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: "22" | |
| - name: Install dependencies | |
| run: pip install -e ".[dev]" | |
| - name: Run browser parity tests | |
| run: pytest tests/test_browser.py -v | |
| env: | |
| NODE_V8_COVERAGE: ${{ runner.temp }}/v8-coverage | |
| - name: Generate JS coverage report | |
| if: always() | |
| run: npx c8 report --temp-directory="${{ runner.temp }}/v8-coverage" --reporter=lcov --report-dir=./js-coverage --src=vera/browser/ | |
| - name: Upload JS coverage to Codecov | |
| if: always() | |
| uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0 | |
| with: | |
| token: ${{ secrets.CODECOV_TOKEN }} | |
| files: js-coverage/lcov.info | |
| flags: javascript | |
| fail_ci_if_error: false |