Open-Source Wikis

/

Ruff

/

How to contribute

/

Development workflow

astral-sh/ruff

Development workflow

A linear walkthrough of the inner loop for everyday changes.

1. Branch from main

git fetch origin
git checkout -b feature/<short-name> origin/main

The default branch is main. There are no long-lived release branches; releases are tagged off main (see CHANGELOG.md).

2. Build and run

Use debug builds. From the repo root:

cargo run -p ruff -- check path/to/file.py --no-cache
cargo run --bin ty -- check path/to/file.py

--no-cache is recommended while iterating, since cache hits will skip your new code path. The cache lives under .ruff_cache/ per-project (and is gitignored).

3. Add tests first

Every behavior change is testable:

  • Lint rules — add or extend a fixture under crates/ruff_linter/resources/test/fixtures/<plugin>/ and a snapshot test in the rule's module.
  • Formatter — add a Python file to crates/ruff_python_formatter/resources/test/fixtures/ and snapshot the output.
  • ty type checks — add an mdtest case under crates/ty_python_semantic/resources/mdtest/. Each .md file is parsed for code blocks and expected diagnostics; the format is documented in crates/mdtest/README.md.
  • LSP — add tests next to crates/ruff_server/tests/ or crates/ty_server/tests/.

4. Run tests

The full suite using nextest:

CARGO_PROFILE_DEV_OPT_LEVEL=1 \
INSTA_FORCE_PASS=1 INSTA_UPDATE=always \
CARGO_PROFILE_DEV_DEBUG="line-tables-only" \
MDTEST_UPDATE_SNAPSHOTS=1 \
cargo nextest run

Single crate while iterating:

cargo nextest run -p ruff_linter
cargo nextest run -p ty_python_semantic

A single mdtest file:

cargo nextest run -p ty_python_semantic -- mdtest::<relative/path/to.md>

A single mdtest case within a file (use a substring of the Markdown header):

MDTEST_TEST_FILTER="<filter>" cargo nextest run -p ty_python_semantic -- mdtest::<file.md>

5. Review snapshots

After the run, accept the deltas you intended:

cargo insta review     # interactive
cargo insta accept     # all

Always look at the diff. A subtle change in a rule can ripple through hundreds of fixture files. Reviewers will scrutinize unexpected snapshot churn.

6. Lint and format

cargo clippy --workspace --all-targets --all-features -- -D warnings
RUFF_UPDATE_SCHEMA=1 cargo test
uvx prek run -a

If you touched anything that has a generated artifact (rule registry, options, CLI arg metadata), regenerate explicitly:

cargo dev generate-all

This regenerates ruff.schema.json, ty.schema.json, the rules table in docs/, and the CLI reference page.

7. Commit and push

Conventional, small commits work well. PR titles should be descriptive; ty PRs must start with [ty].

git add -p
git commit -m "[F841] Detect unused walrus targets"
git push -u origin HEAD

8. Open the PR

A good PR description includes:

  • The issue link.
  • A 2–4 sentence summary of the change.
  • A "Test plan" section listing how you validated it.
  • Screenshots/before-after diagnostic output if user-visible.

CI runs cargo test, cargo clippy, uvx prek run -a, cargo dev generate-all (in check mode), the fuzz smoke tests, and the documentation build. Local pre-flight matches CI.

9. After review

If review feedback requires changes:

  • Make them as new commits (the team rebases at merge time).
  • Run uvx prek run -a again, every time you address comments.
  • Re-run snapshot tests if you touched output.

10. Merge

Maintainers squash-merge. The squashed commit message becomes part of the changelog.

Tips

  • Keep PRs focused. One rule, one bug, one option. Splitting is cheap.
  • cargo dev round-trip round-trips the parser through python/ corpora; useful for parser changes.
  • cargo dev format-dev runs the formatter against a curated corpus and reports stability.
  • cargo dev print-ast and cargo dev print-tokens are useful debugging helpers (see crates/ruff_dev/).

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Development workflow – Ruff wiki | Factory