Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/PUBLISHING.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ version number can never be reused once published.

1. Bump `__version__` in [`src/legaldown/__init__.py`](../src/legaldown/__init__.py) — it is the single
source of truth; `pyproject.toml` reads it via `[tool.hatch.version]`.
2. Commit, then publish a GitHub Release with the tag `vX.Y.Z`. Its notes are where this
2. Commit and run **CI** on it (*Actions → CI → Run workflow*; it runs only on demand, or with the `ci` label on a pull request), then publish a
GitHub Release with the tag `vX.Y.Z`. Its notes are where this
project records what changed in a release.

The workflow builds the sdist and wheel, runs `twine check --strict`, **verifies the tag matches
Expand Down
98 changes: 47 additions & 51 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,22 @@
name: CI

# On demand only, in either of two ways:
# - Actions → CI → Run workflow, on the branch you pick;
# - the `ci` label on a pull request: adding it runs CI, and CI then runs again
# on each push to that pull request until the label is removed.
# One job on one Python, the one the release is built with, so a run costs one
# runner's setup rather than six: lint, the tests (with the specification fixtures
# corpus unless switched off), and the build with its metadata check.

on:
push:
branches: [main]
pull_request:
types: [labeled, synchronize, reopened]
workflow_dispatch:
inputs:
conformance:
description: "Also run the specification fixtures corpus (checks out ForLegalAI/LegalDown)"
type: boolean
default: true

permissions:
contents: read
Expand All @@ -13,76 +26,59 @@ concurrency:
cancel-in-progress: true

jobs:
lint:
name: Lint (ruff)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: pip
- run: pip install ruff
- run: ruff check .

test:
name: Tests (Python ${{ matrix.python-version }})
check:
name: Lint, test, build
# A push or a reopening of a pull request runs it only while the pull request has
# the `ci` label; adding some other label does not.
if: >-
github.event_name == 'workflow_dispatch' ||
(contains(github.event.pull_request.labels.*.name, 'ci') &&
(github.event.action != 'labeled' || github.event.label.name == 'ci'))
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.11", "3.12", "3.13"]
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: pip
- run: pip install -e ".[dev]"
- run: pytest -q

conformance:
name: Specification conformance
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check out the LegalDown specification (fixtures corpus)
# The corpus is checked out and run for a pull request, and for a manual run
# unless its `conformance` input is off.
- name: Check out the LegalDown specification (fixtures corpus only)
if: github.event_name != 'workflow_dispatch' || inputs.conformance
uses: actions/checkout@v4
with:
repository: ForLegalAI/LegalDown
ref: v0.2
path: .legaldown-spec
sparse-checkout: fixtures
# A private specification repository needs a token with read access;
# GITHUB_TOKEN cannot read another repository.
token: ${{ secrets.SPEC_REPO_TOKEN || github.token }}

- uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: pip
cache-dependency-path: pyproject.toml

# The dev extra holds pytest, ruff, build and twine: one install for every step.
- run: pip install -e ".[dev]"
- name: Validate against the fixtures corpus

- run: ruff check .

- name: Tests and specification conformance
if: github.event_name != 'workflow_dispatch' || inputs.conformance
env:
LEGALDOWN_FIXTURES_DIR: .legaldown-spec/fixtures
# Cases for unimplemented rules are skipped and named, so a failure
# here is a regression against a rule this implementation claims.
run: pytest tests/conformance -q
# Cases for unimplemented rules are skipped and named, so a failure in
# tests/conformance is a regression against a rule this implementation claims.
run: pytest -q

- name: Tests
if: github.event_name == 'workflow_dispatch' && !inputs.conformance
run: pytest -q

build:
name: Build distribution
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: pip
- run: pip install build twine
- run: python -m build

- name: Check package metadata
# --strict matches the publish workflow, so a metadata problem fails
# here on the pull request rather than at release time.
# here rather than at release time.
run: twine check --strict dist/*
- uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
2 changes: 1 addition & 1 deletion CONFORMANCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ and 38 skipped: eight of the other skips are the implemented rules named above,
case, which is marked Full (fixtures README, step 4) — `tests/test_assembly.py` assembles it with
a loader instead. Cases that need the final option run with it; cases that need an answers set
are assembled with it, and each assembly case is compared byte for byte with its expected output.
CI runs this on every push and pull request.
CI runs this on demand (Actions → CI → Run workflow with the `conformance` input on, or the `ci` label on a pull request).

## Assembly (§15.7, §17.6)

Expand Down
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -604,9 +604,17 @@ checks it does not perform, so those are listed in
git clone https://github.com/ForLegalAI/legaldown-validator
cd legaldown-validator
pip install -e ".[dev]"
ruff check .
pytest
```

**CI** runs on demand only, as one job on Python 3.12 (the version releases are built with): lint,
the tests with the specification fixtures corpus, and the build with its metadata check. Start it
with *Actions → CI → Run workflow* on the branch you pick (the `conformance` input switches the
corpus off for a quicker run), or by adding the **`ci` label** to a pull request: it then runs again
on each push to that pull request until the label is removed. Nothing else triggers it, so run it
before merging and before a release.

### Conformance suite

The fixtures corpus lives in the specification repository, so point the harness at a checkout:
Expand All @@ -618,7 +626,7 @@ LEGALDOWN_FIXTURES_DIR=../LegalDown/fixtures pytest tests/conformance -q

Cases for rules outside Core are skipped and named, so the run doubles as the coverage ledger in
[CONFORMANCE.md](https://github.com/ForLegalAI/legaldown-validator/blob/main/CONFORMANCE.md),
which accounts for every skip. CI runs it on every push and pull request.
which accounts for every skip. CI runs it with the rest of the checks, on demand (below).

Bug reports and pull requests are welcome in
[Issues](https://github.com/ForLegalAI/legaldown-validator/issues); questions about the format
Expand Down
Loading