Contributing
Issues and pull requests are welcome. For anything larger than a fix, open an issue first so the design can be agreed before the code; ROADMAP.md says where the project is going. Security problems go through SECURITY.md, never a public issue. Everyone taking part follows the Code of Conduct.
The CI gates
A pull request must pass what CI runs (.github/workflows/ci.yml and docs.yml). From the repository root:
uv sync --all-extras
uv run ruff format --check .
uv run ruff check .
uv run ty check
uv run pytest -n auto
uv sync --all-extras --group docs && uv run great-docs build # the documentationTests skip what the machine cannot run rather than fail: the jj-parametrized tests need jj on PATH (CI installs the release binary), and the publish / import tests need PostgreSQL’s pg_ctl (see the README’s “Development”).
A change to the native scanner in native/, or to what it mirrors in tether.backends.file, also has to pass CI’s native job. That needs rustup, which installs the Rust that native/rust-toolchain.toml pins on first use:
(cd native && cargo fmt --check && cargo clippy --all-targets --features python -- -D warnings && cargo test)
uv sync --all-extras --group native # builds tether-vcs-native into the environment
uv run pytest # the file backend now scans through ittests/test_native.py runs both scanners on the same trees and requires the same states, listings, cache file and errors; TETHER_NATIVE=0 puts the whole suite back on the Python scanner.
Every wheel ships native/THIRD-PARTY-NOTICES: the licenses of the crates compiled into it. When a crate comes, goes or changes its license text, the native job fails until the file is regenerated with cargo-about 0.9.2 (cargo install --locked cargo-about@0.9.2):
(cd native && cargo fetch --locked && cargo about generate --features python --frozen --fail about.hbs -o THIRD-PARTY-NOTICES)Changelog
Every user-visible change gets an entry under [Unreleased] in CHANGELOG.md (Keep a Changelog), saying what changed and what a user has to do about it. Mark breaking changes breaking; before 1.0 they can land in any release.