answer for the imports a renamed module leaves behind #655
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 | |
| permissions: {} | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| workflow_dispatch: | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.sha }} | |
| cancel-in-progress: true | |
| defaults: | |
| run: | |
| shell: bash | |
| env: | |
| CARGO_INCREMENTAL: 0 | |
| CARGO_NET_RETRY: 10 | |
| CARGO_TERM_COLOR: always | |
| RUSTUP_MAX_RETRIES: 10 | |
| PACKAGE_NAME: ruff | |
| PYTHON_VERSION: "3.14" | |
| NEXTEST_PROFILE: ci | |
| jobs: | |
| determine_changes: | |
| name: "Determine changes" | |
| runs-on: ubuntu-latest | |
| outputs: | |
| # Flag that is raised when any code that affects parser is changed | |
| parser: ${{ steps.check_parser.outputs.changed }} | |
| # Flag that is raised when any code that affects linter is changed | |
| linter: ${{ steps.check_linter.outputs.changed }} | |
| # Flag that is raised when any code that affects formatter is changed | |
| formatter: ${{ steps.check_formatter.outputs.changed }} | |
| # Flag that is raised when any code is changed | |
| # This is superset of the linter and formatter | |
| code: ${{ steps.check_code.outputs.changed }} | |
| # Flag that is raised when any code that affects the fuzzer is changed | |
| fuzz: ${{ steps.check_fuzzer.outputs.changed }} | |
| # Flag that is set to "true" when code related to ty changes. | |
| ty: ${{ steps.check_ty.outputs.changed }} | |
| # Flag that is set to "true" when code related to the py-fuzzer folder changes. | |
| py-fuzzer: ${{ steps.check_py_fuzzer.outputs.changed }} | |
| # Flag that is set to "true" when code related to the playground changes. | |
| playground: ${{ steps.check_playground.outputs.changed }} | |
| # Flag that is set to "true" when code related to the benchmarks changes. | |
| benchmarks: ${{ steps.check_benchmarks.outputs.changed }} | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| # Faster to do this separately than to use `fetch-depth: 0` with `actions/checkout` | |
| - name: Fetch full history without tags | |
| run: git fetch --no-tags --filter=blob:none --unshallow origin | |
| - name: Determine merge base | |
| id: merge_base | |
| env: | |
| BASE_REF: ${{ github.event.pull_request.base.ref || 'main' }} | |
| run: | | |
| sha=$(git merge-base HEAD "origin/${BASE_REF}") | |
| echo "sha=${sha}" >> "$GITHUB_OUTPUT" | |
| - name: Check if the parser code changed | |
| id: check_parser | |
| env: | |
| MERGE_BASE: ${{ steps.merge_base.outputs.sha }} | |
| run: | | |
| if git diff --quiet "${MERGE_BASE}...HEAD" -- \ | |
| ':Cargo.toml' \ | |
| ':Cargo.lock' \ | |
| ':rust-toolchain.toml' \ | |
| ':cargo/config.toml' \ | |
| ':crates/ruff_python_trivia/**' \ | |
| ':crates/ruff_source_file/**' \ | |
| ':crates/ruff_text_size/**' \ | |
| ':crates/ruff_python_ast/**' \ | |
| ':crates/ruff_python_parser/**' \ | |
| ':.github/workflows/ci.yaml' \ | |
| ; then | |
| echo "changed=false" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "changed=true" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Check if the linter code changed | |
| id: check_linter | |
| env: | |
| MERGE_BASE: ${{ steps.merge_base.outputs.sha }} | |
| run: | | |
| if git diff --quiet "${MERGE_BASE}...HEAD" -- ':Cargo.toml' \ | |
| ':Cargo.lock' \ | |
| ':rust-toolchain.toml' \ | |
| ':cargo/config.toml' \ | |
| ':crates/**' \ | |
| ':!crates/ty*/**' \ | |
| ':!crates/ruff_python_formatter/**' \ | |
| ':!crates/ruff_formatter/**' \ | |
| ':!crates/ruff_dev/**' \ | |
| ':!crates/ruff_benchmark/**' \ | |
| ':scripts/*' \ | |
| ':python/**' \ | |
| ':.github/workflows/ci.yaml' \ | |
| ; then | |
| echo "changed=false" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "changed=true" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Check if the formatter code changed | |
| id: check_formatter | |
| env: | |
| MERGE_BASE: ${{ steps.merge_base.outputs.sha }} | |
| run: | | |
| if git diff --quiet "${MERGE_BASE}...HEAD" -- ':Cargo.toml' \ | |
| ':Cargo.lock' \ | |
| ':rust-toolchain.toml' \ | |
| ':cargo/config.toml' \ | |
| ':crates/ruff_python_formatter/**' \ | |
| ':crates/ruff_formatter/**' \ | |
| ':crates/ruff_python_trivia/**' \ | |
| ':crates/ruff_python_ast/**' \ | |
| ':crates/ruff_source_file/**' \ | |
| ':crates/ruff_python_index/**' \ | |
| ':crates/ruff_python_index/**' \ | |
| ':crates/ruff_text_size/**' \ | |
| ':crates/ruff_python_parser/**' \ | |
| ':scripts/*' \ | |
| ':python/**' \ | |
| ':.github/workflows/ci.yaml' \ | |
| ; then | |
| echo "changed=false" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "changed=true" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Check if the fuzzer code changed | |
| id: check_fuzzer | |
| env: | |
| MERGE_BASE: ${{ steps.merge_base.outputs.sha }} | |
| run: | | |
| if git diff --quiet "${MERGE_BASE}...HEAD" -- ':Cargo.toml' \ | |
| ':Cargo.lock' \ | |
| ':rust-toolchain.toml' \ | |
| ':cargo/config.toml' \ | |
| ':fuzz/fuzz_targets/**' \ | |
| ':.github/workflows/ci.yaml' \ | |
| ; then | |
| echo "changed=false" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "changed=true" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Check if the py-fuzzer code changed | |
| id: check_py_fuzzer | |
| env: | |
| MERGE_BASE: ${{ steps.merge_base.outputs.sha }} | |
| run: | | |
| if git diff --quiet "${MERGE_BASE}...HEAD" -- 'python/py-fuzzer/**' \ | |
| ; then | |
| echo "changed=false" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "changed=true" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Check if there was any code related change | |
| id: check_code | |
| env: | |
| MERGE_BASE: ${{ steps.merge_base.outputs.sha }} | |
| run: | | |
| # NOTE: Do not exclude all Markdown files here, but rather use | |
| # specific exclude patterns like 'docs/**'), because tests for | |
| # 'ty' are written in Markdown. | |
| if git diff --quiet "${MERGE_BASE}...HEAD" -- \ | |
| ':!docs/**' \ | |
| ':!assets/**' \ | |
| ; then | |
| echo "changed=false" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "changed=true" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Check if there was any playground related change | |
| id: check_playground | |
| env: | |
| MERGE_BASE: ${{ steps.merge_base.outputs.sha }} | |
| run: | | |
| if git diff --quiet "${MERGE_BASE}...HEAD" -- \ | |
| ':playground/**' \ | |
| ; then | |
| echo "changed=false" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "changed=true" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Check if the ty code changed | |
| id: check_ty | |
| env: | |
| MERGE_BASE: ${{ steps.merge_base.outputs.sha }} | |
| run: | | |
| if git diff --quiet "${MERGE_BASE}...HEAD" -- \ | |
| ':Cargo.toml' \ | |
| ':Cargo.lock' \ | |
| ':rust-toolchain.toml' \ | |
| ':cargo/config.toml' \ | |
| ':crates/ty*/**' \ | |
| ':crates/ruff_db/**' \ | |
| ':crates/ruff_annotate_snippets/**' \ | |
| ':crates/ruff_python_ast/**' \ | |
| ':crates/ruff_python_parser/**' \ | |
| ':crates/ruff_python_trivia/**' \ | |
| ':crates/ruff_source_file/**' \ | |
| ':crates/ruff_text_size/**' \ | |
| ':.github/workflows/ci.yaml' \ | |
| ; then | |
| echo "changed=false" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "changed=true" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Check if the benchmark code changed | |
| id: check_benchmarks | |
| env: | |
| MERGE_BASE: ${{ steps.merge_base.outputs.sha }} | |
| run: | | |
| if git diff --quiet "${MERGE_BASE}...HEAD" -- \ | |
| ':Cargo.toml' \ | |
| ':Cargo.lock' \ | |
| ':rust-toolchain.toml' \ | |
| ':cargo/config.toml' \ | |
| ':crates/ruff_benchmark/**' \ | |
| ':.github/workflows/ci.yaml' \ | |
| ; then | |
| echo "changed=false" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "changed=true" >> "$GITHUB_OUTPUT" | |
| fi | |
| cargo-fmt: | |
| name: "cargo fmt" | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - name: "Install Rust toolchain" | |
| run: rustup component add rustfmt | |
| - run: cargo fmt --all --check | |
| shellcheck: | |
| name: "shellcheck" | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 | |
| with: | |
| go-version: "1.26.5" | |
| - name: "Run ShellCheck" | |
| env: | |
| GOSUMDB: sum.golang.org | |
| run: | | |
| files=() | |
| while IFS= read -r -d '' file; do | |
| files+=("${file}") | |
| done < <(git ls-files -z '*.sh') | |
| if ((${#files[@]} == 0)); then | |
| exit 0 | |
| fi | |
| go run github.com/wasilibs/go-shellcheck/cmd/shellcheck@v0.11.1 "${files[@]}" | |
| cargo-clippy: | |
| name: "cargo clippy" | |
| runs-on: ubuntu-latest | |
| needs: determine_changes | |
| if: ${{ needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main' }} | |
| timeout-minutes: 20 | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 | |
| with: | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - name: "Install Rust toolchain" | |
| run: | | |
| rustup component add clippy | |
| rustup target add wasm32-unknown-unknown | |
| - name: "Clippy" | |
| run: cargo clippy --workspace --all-targets --all-features --locked -- -D warnings | |
| - name: "Clippy (wasm)" | |
| run: cargo clippy -p ruff_wasm -p ty_wasm --target wasm32-unknown-unknown --all-features --locked -- -D warnings | |
| # upstream's `cargo-publish-dry-run` is dropped: the fork keeps ruff/ty crate | |
| # versions in lock-step with astral's published crates.io versions but modifies | |
| # their apis, so `cargo publish --dry-run` pulls the real published crate for a | |
| # transitive dep and fails on the api skew. the fork publishes only the | |
| # `basedpython` wheel to pypi, never these crates to crates.io | |
| # `by compile` builds against the running interpreter's headers, links its abi and has | |
| # to answer exactly as that interpreter does, so *which* interpreter is a first-class | |
| # variable and belongs in the workflow rather than in whatever a runner image ships. | |
| # | |
| # the supported set is python 3.13 and 3.14, each in its gil and its free-threaded | |
| # build. `PYTHON_VERSION` is the primary and `cargo test (linux)` runs the whole suite | |
| # against it; this job covers the other three. 3.12 is deliberately absent — it is | |
| # below the project's floor, and it was only ever reached because an image shipped it. | |
| # | |
| # only the version-sensitive targets run here, because only they start an interpreter: | |
| # * the six backend crates, which emit and then load real extension modules | |
| # * `by_transforms`' `*_runtime` tests, which transpile and then execute | |
| # * `ty`'s divergence and end-to-end tests, which do the same | |
| # the rest of the suite reads a vendored typeshed and a configured `python-version`, | |
| # so its answers do not move with the interpreter and repeating it buys nothing. | |
| # | |
| # a job of its own rather than steps on `cargo test (linux)`: as a step it pushed that | |
| # job past its budget and the doctest and dogfood steps after it never ran at all | |
| cargo-test-interpreter: | |
| name: "cargo test (python ${{ matrix.python }})" | |
| runs-on: ${{ github.repository == 'astral-sh/ruff' && 'depot-ubuntu-22.04-16' || 'ubuntu-latest' }} | |
| needs: determine_changes | |
| if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-test') && (needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main') }} | |
| timeout-minutes: 45 | |
| strategy: | |
| # one interpreter failing says nothing about the others, and which ones are green | |
| # is the whole answer this job exists to give | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - python: "3.13" | |
| backend_filter: "all()" | |
| # the free-threaded builds run the same tests, minus one that cannot be | |
| # observed there: `a_closure_does_not_leak_its_environment` asserts that | |
| # `sys.getrefcount` *rises* while a closure holds a string, and a | |
| # free-threaded interpreter reports the immortal sentinel for that string | |
| # (4294967295 on 3.13t, 3221225472 on 3.14t) whoever holds it. an ordinary | |
| # cpython closure fails the same assertion, so it measures the instrument | |
| # rather than the backend. the leak half of that test — the count is | |
| # unchanged after 20000 closures — runs and passes on both | |
| - python: "3.13t" | |
| backend_filter: "not test(=a_closure_does_not_leak_its_environment)" | |
| - python: "3.14t" | |
| backend_filter: "not test(=a_closure_does_not_leak_its_environment)" | |
| env: | |
| CARGO_PROFILE_DEV_DEBUG: line-tables-only | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 | |
| with: | |
| shared-key: ruff-linux-debug | |
| save-if: false | |
| - name: "Install Rust toolchain" | |
| run: rustup show | |
| - name: "Install mold" | |
| uses: rui314/setup-mold@9c9c13bf4c3f1adef0cc596abc155580bcb04444 # v1 | |
| - name: "Install cargo nextest" | |
| uses: taiki-e/install-action@43aecc8d72668fbcfe75c31400bc4f890f1c5853 # v2.83.2 | |
| with: | |
| tool: cargo-nextest | |
| - name: "Install uv" | |
| uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 | |
| with: | |
| version: "0.11.31" | |
| enable-cache: "true" | |
| # `PYTHON` is the load-bearing pin: every harness that starts an interpreter reads | |
| # it first. `PATH` is set as well because each of those harnesses falls back to a | |
| # bare name if the variable is ever unset, and `by_transforms` tries `python3.13` | |
| # *before* `python3` — so an unpinned run does not merely drift, it drifts towards | |
| # one particular version. uv's managed installs put a `python3` next to the | |
| # versioned name, and in a free-threaded install that `python3` is itself the | |
| # free-threaded build | |
| - name: "Pin the interpreter" | |
| env: | |
| PY: ${{ matrix.python }} | |
| run: | | |
| uv python install "$PY" | |
| python_path="$(uv python find "$PY")" | |
| echo "PYTHON=$python_path" >> "$GITHUB_ENV" | |
| dirname "$python_path" >> "$GITHUB_PATH" | |
| # a leg that silently resolved to a different interpreter would report a green that | |
| # belongs to some other version, which is the failure mode this whole job is about | |
| - name: "Verify the interpreter is the one asked for" | |
| env: | |
| PY: ${{ matrix.python }} | |
| run: | | |
| echo "PYTHON=$PYTHON" | |
| "$PYTHON" -VV | |
| echo "python3 on PATH: $(command -v python3)" | |
| # a free-threaded leg has to be genuinely free-threaded rather than a gil | |
| # build answering to a `t` name, so the probe reports both facts at once | |
| want_version="${PY%t}" | |
| want="$want_version false" | |
| if [ "$PY" != "$want_version" ]; then | |
| want="$want_version true" | |
| fi | |
| probe='import sys, sysconfig; print("%d.%d" % sys.version_info[:2], "true" if sysconfig.get_config_var("Py_GIL_DISABLED") else "false")' | |
| got=$("$PYTHON" -c "$probe") | |
| echo "PYTHON reports: $got (want: $want)" | |
| [ "$got" = "$want" ] || { echo "::error::PYTHON is not $PY"; exit 1; } | |
| # the harnesses fall back to a bare `python3` when the variable is unset, so | |
| # that has to be the same interpreter too | |
| got_path=$(python3 -c "$probe") | |
| echo "python3 reports: $got_path (want: $want)" | |
| [ "$got_path" = "$want" ] || { echo "::error::python3 on PATH is not $PY"; exit 1; } | |
| - name: "Run the native backend" | |
| env: | |
| BACKEND_FILTER: ${{ matrix.backend_filter }} | |
| run: | | |
| cargo nextest run \ | |
| -p by_build -p by_ir -p by_irbuild -p by_opt -p by_codegen_c -p by_rt \ | |
| -E "$BACKEND_FILTER" | |
| # a separate invocation on purpose: the backend's differential tests fork processes | |
| # and compile C, and sharing a run with `by_transforms`' ~1800 other tests starves | |
| # them into failures that pass on their own | |
| - name: "Run the transpiler's runtime tests" | |
| run: cargo nextest run -p by_transforms -E 'binary(/_runtime$/)' | |
| - name: "Run ty's divergence and end-to-end tests" | |
| run: | | |
| cargo nextest run -p ty \ | |
| -E 'binary(mdtest_divergence) + binary(by_e2e) + binary(django_lookup_runtime)' | |
| cargo-test-linux: | |
| name: "cargo test (linux)" | |
| runs-on: ${{ github.repository == 'astral-sh/ruff' && 'depot-ubuntu-22.04-16' || 'ubuntu-latest' }} | |
| needs: determine_changes | |
| if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-test') && (needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main') }} | |
| # the fork's `ubuntu-latest` runner is far slower than astral's 16-core depot | |
| # runner, so the full suite overruns the depot-tuned 20-minute budget | |
| # | |
| # 45 was in turn too tight: the job was already taking 34m32s on main, and runner speed | |
| # varies by more than the quarter of an hour that left. On 2026-08-13 the same commit range | |
| # ran its tests in 1603s, 1645s and then 1942s — the slow one reporting 1455 tests over the | |
| # one-second mark against 1263 for the fast one, which is a slower machine rather than more | |
| # work — and the 1942s run reached 45m mid-way through the dogfood steps and was killed. | |
| # Nextest's own total is the number to compare here: it stays flat across the merge, so the | |
| # budget is for the runner's variance, not for the suite growing. | |
| timeout-minutes: 75 | |
| env: | |
| # Line-tables-only debug info: faster builds, backtraces still work. | |
| CARGO_PROFILE_DEV_DEBUG: line-tables-only | |
| # Enable mdtests that require external dependencies. These `uv`-install real | |
| # packages and type-check against them — platform-independent behaviour, so | |
| # linux coverage suffices. Keeping them off the windows/macos jobs avoids the | |
| # fork's slow runners blowing the nextest deadlock timeout on heavy stubs | |
| # (django-stubs type-checks in ~8s locally but >180s unoptimised on the fork | |
| # windows runner's slow file I/O). | |
| MDTEST_EXTERNAL: "1" | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 | |
| with: | |
| shared-key: ruff-linux-debug | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - name: "Install Rust toolchain" | |
| run: rustup show | |
| - name: "Install mold" | |
| uses: rui314/setup-mold@9c9c13bf4c3f1adef0cc596abc155580bcb04444 # v1 | |
| - name: "Install cargo nextest and insta" | |
| uses: taiki-e/install-action@cb33e69fad06166ca28a42b2575e4dadabf62ee8 # v2.85.8 | |
| with: | |
| tool: | | |
| cargo-nextest | |
| cargo-insta | |
| - name: "Install uv" | |
| uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 | |
| with: | |
| version: "0.12.3" | |
| enable-cache: "true" | |
| - name: ty mdtests (GitHub annotations) | |
| if: ${{ needs.determine_changes.outputs.ty == 'true' }} | |
| env: | |
| NO_COLOR: 1 | |
| MDTEST_GITHUB_ANNOTATIONS_FORMAT: 1 | |
| # Ignore errors if this step fails; we want to continue to later steps in the workflow anyway. | |
| # This step is just to get nice GitHub annotations on the PR diff in the files-changed tab. | |
| run: cargo test -p ty_python_semantic --test mdtest || true | |
| # the tests that execute python run against whatever `python3` is first on `PATH`, | |
| # which without this is whichever interpreter the runner image happens to ship — | |
| # a 3.14 on macos and a 3.12 on linux, so the version under test moved with the | |
| # image rather than with the project. `by compile` builds against the running | |
| # interpreter's headers and has to answer as that interpreter does, so which one | |
| # it is belongs in the workflow. | |
| # | |
| # `PATH` as well as `PYTHON`: the harnesses all read the variable first, but each | |
| # falls back to a bare name when it is unset, and `by_transforms` tries | |
| # `python3.13` *before* `python3` — so a run that lost the variable would not | |
| # drift randomly, it would drift to one particular version. the rest of the | |
| # supported set is covered by `cargo test (python …)` | |
| - name: "Pin the interpreter the python-executing tests use" | |
| run: | | |
| uv python install "${PYTHON_VERSION}" | |
| python_path="$(uv python find "${PYTHON_VERSION}")" | |
| echo "PYTHON=$python_path" >> "$GITHUB_ENV" | |
| dirname "$python_path" >> "$GITHUB_PATH" | |
| - name: "Run tests" | |
| run: cargo insta test --all-features --unreferenced reject --test-runner nextest --disable-nextest-doctest | |
| - name: "Run doctests" | |
| run: cargo test --doc --all-features | |
| - name: Dogfood ty on py-fuzzer | |
| run: uv run --project=./python/py-fuzzer cargo run -p ty check --project=./python/py-fuzzer | |
| - name: Dogfood ty on the scripts directory | |
| run: uv run --project=./scripts cargo run -p ty check --project=./scripts | |
| - name: Dogfood ty on ty_benchmark | |
| run: uv run --project=./scripts/ty_benchmark cargo run -p ty check --project=./scripts/ty_benchmark | |
| # Check for broken links in the documentation. | |
| - run: cargo doc --all --no-deps | |
| env: | |
| RUSTDOCFLAGS: "-D warnings" | |
| # Use --document-private-items so that all our doc comments are kept in | |
| # sync, not just public items. Eventually we should do this for all | |
| # crates; for now add crates here as they are warning-clean to prevent | |
| # regression. | |
| - run: cargo doc --no-deps -p ty_python_semantic -p ty_python_core -p ty_module_resolver -p ty_site_packages -p ty_combine -p ty_project -p ty_ide -p ty_wasm -p ty_vendored -p ty_static -p ty -p ty_test -p ruff_db -p ruff_python_formatter --document-private-items | |
| env: | |
| # Setting RUSTDOCFLAGS because `cargo doc --check` isn't yet implemented (https://github.com/rust-lang/cargo/issues/10025). | |
| RUSTDOCFLAGS: "-D warnings" | |
| cargo-test-linux-release: | |
| name: "cargo test (linux, release)" | |
| # release-mode build + test times out on standard github runners, so this | |
| # needs depot's larger runners. gated to astral-sh/ruff so it skips on the | |
| # fork; adopt depot (see ROADMAP) then flip the predicate back to | |
| # 'KotlinIsland/basedpython' to re-enable | |
| runs-on: depot-ubuntu-22.04-16 | |
| needs: determine_changes | |
| if: | | |
| github.repository == 'astral-sh/ruff' && | |
| !contains(github.event.pull_request.labels.*.name, 'no-test') && | |
| (needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main') | |
| timeout-minutes: 20 | |
| env: | |
| # Line-tables-only debug info: faster builds, backtraces still work. | |
| CARGO_PROFILE_PROFILING_DEBUG: line-tables-only | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 | |
| with: | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - name: "Install Rust toolchain" | |
| run: rustup show | |
| - name: "Install mold" | |
| uses: rui314/setup-mold@9c9c13bf4c3f1adef0cc596abc155580bcb04444 # v1 | |
| - name: "Install cargo nextest" | |
| uses: taiki-e/install-action@cb33e69fad06166ca28a42b2575e4dadabf62ee8 # v2.85.8 | |
| with: | |
| tool: cargo-nextest | |
| - name: "Install uv" | |
| uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 | |
| with: | |
| version: "0.12.3" | |
| enable-cache: "true" | |
| - name: "Run tests" | |
| run: cargo nextest run --cargo-profile profiling --all-features | |
| - name: "Run doctests" | |
| run: cargo test --doc --profile profiling --all-features | |
| # these two used to take whatever interpreter the runner image shipped. that drift did | |
| # find real bugs — a 3.14 macos image surfaced six failures nobody was looking for — | |
| # but it found them as a red that named no version, and a green said nothing about | |
| # which version was covered. the same job could change answer between two reruns of | |
| # the same commit. so the interpreter is pinned here too, and the coverage the drift | |
| # used to buy by accident is bought on purpose by `cargo test (python …)` instead. | |
| # | |
| # the two platforms take different versions, so the platform axis and the version axis | |
| # are both covered without a third job: windows takes the newest because its toolchain | |
| # path is the most version-sensitive code in the backend (it has to name the | |
| # interpreter's import library, whose stem carries both the version and the | |
| # free-threaded `t`), and macos takes the floor version | |
| cargo-test-other: | |
| strategy: | |
| # each leg is now a distinct platform *and* version, so cancelling the other one | |
| # on the first failure throws away half the answer | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - platform: ${{ github.repository == 'astral-sh/ruff' && 'namespace-profile-windows-2022-x86-64-16x32' || 'windows-latest' }} | |
| python: "3.14" | |
| - platform: ${{ github.repository == 'astral-sh/ruff' && 'namespace-profile-macos-15' || 'macos-latest' }} | |
| python: "3.13" | |
| name: "cargo test (${{ matrix.platform }}, python ${{ matrix.python }})" | |
| runs-on: ${{ matrix.platform }} | |
| needs: determine_changes | |
| if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-test') && (needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main') }} | |
| # the fork's `windows-latest`/`macos-latest` runners are slower than astral's | |
| # depot runners, so the full suite overruns the depot-tuned 20-minute budget | |
| # | |
| # windows is the slow half of this matrix and came within two minutes of the previous | |
| # 45-minute budget on 2026-08-13 (42m54s, against 24m56s for macos on the same run), so it | |
| # gets the same headroom the linux job needed for the same reason | |
| timeout-minutes: 75 | |
| env: | |
| # Line-tables-only debug info: faster builds, backtraces still work. | |
| CARGO_PROFILE_DEV_DEBUG: line-tables-only | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 | |
| with: | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| # Fix for https://github.com/Swatinem/rust-cache/issues/341 | |
| cache-bin: "false" | |
| - name: "Install Rust toolchain" | |
| run: rustup show | |
| - name: "Install cargo nextest" | |
| uses: taiki-e/install-action@cb33e69fad06166ca28a42b2575e4dadabf62ee8 # v2.85.8 | |
| with: | |
| tool: cargo-nextest | |
| - name: "Install uv" | |
| uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 | |
| with: | |
| version: "0.12.3" | |
| enable-cache: "true" | |
| # `PATH` as well as `PYTHON`, for the fallback reason described on | |
| # `cargo test (python …)`. the interpreter reports its own directory rather than | |
| # `dirname` doing it: on windows this shell is git bash but `uv python find` answers | |
| # with a backslash-separated path, which `dirname` reads as a single component | |
| - name: "Pin the interpreter the python-executing tests use" | |
| env: | |
| PY: ${{ matrix.python }} | |
| run: | | |
| uv python install "$PY" | |
| python_path="$(uv python find "$PY")" | |
| echo "PYTHON=$python_path" >> "$GITHUB_ENV" | |
| "$python_path" -c 'import os, sys; print(os.path.dirname(sys.executable))' >> "$GITHUB_PATH" | |
| - name: "Run tests" | |
| run: | | |
| python3 -VV | |
| cargo nextest run --all-features --profile ci | |
| cargo test --all-features --doc | |
| cargo-test-wasm: | |
| name: "cargo test (wasm)" | |
| runs-on: ubuntu-latest | |
| needs: determine_changes | |
| if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-test') && (needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main') }} | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 | |
| with: | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - name: "Install Rust toolchain" | |
| run: rustup target add wasm32-unknown-unknown | |
| - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| node-version: 24 | |
| cache: "npm" | |
| cache-dependency-path: playground/package-lock.json | |
| - uses: jetli/wasm-pack-action@0d096b08b4e5a7de8c28de67e11e945404e9eefa # v0.4.0 | |
| with: | |
| version: v0.13.1 | |
| - name: "Test ruff_wasm" | |
| run: | | |
| cd crates/ruff_wasm | |
| wasm-pack test --node | |
| - name: "Test ty_wasm" | |
| run: | | |
| cd crates/ty_wasm | |
| wasm-pack test --node | |
| cargo-build-msrv: | |
| name: "cargo build (msrv)" | |
| runs-on: ${{ github.repository == 'astral-sh/ruff' && 'depot-ubuntu-24.04-8' || 'ubuntu-latest' }} | |
| needs: determine_changes | |
| if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-test') && (needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main') }} | |
| timeout-minutes: 20 | |
| env: | |
| # Line-tables-only debug info: faster builds, backtraces still work. | |
| CARGO_PROFILE_DEV_DEBUG: line-tables-only | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: SebRollen/toml-action@b1b3628f55fc3a28208d4203ada8b737e9687876 # v1.2.0 | |
| id: msrv | |
| with: | |
| file: "Cargo.toml" | |
| field: "workspace.package.rust-version" | |
| - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 | |
| with: | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - name: "Install Rust toolchain" | |
| env: | |
| MSRV: ${{ steps.msrv.outputs.value }} | |
| run: rustup default "${MSRV}" | |
| - name: "Install mold" | |
| uses: rui314/setup-mold@9c9c13bf4c3f1adef0cc596abc155580bcb04444 # v1 | |
| - name: "Build tests" | |
| env: | |
| MSRV: ${{ steps.msrv.outputs.value }} | |
| run: cargo "+${MSRV}" test --no-run --all-features | |
| # TODO: fork the fuzzer | |
| # cargo-fuzz-build: | |
| # name: "cargo fuzz build" | |
| # runs-on: ubuntu-latest | |
| # needs: determine_changes | |
| # if: ${{ github.ref == 'refs/heads/main' || needs.determine_changes.outputs.fuzz == 'true' || needs.determine_changes.outputs.code == 'true' }} | |
| # timeout-minutes: 10 | |
| # steps: | |
| # - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| # with: | |
| # persist-credentials: false | |
| # - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 | |
| # with: | |
| # workspaces: "fuzz -> target" | |
| # save-if: ${{ github.ref == 'refs/heads/main' }} | |
| # - name: "Install Rust toolchain" | |
| # run: rustup show | |
| # - name: "Install mold" | |
| # uses: rui314/setup-mold@9c9c13bf4c3f1adef0cc596abc155580bcb04444 # v1 | |
| # - name: "Install cargo-binstall" | |
| # uses: cargo-bins/cargo-binstall@dc19f1e48450eefe5a29b8da6c6b00a87d730b37 # v1.18.1 | |
| # - name: "Install cargo-fuzz" | |
| # # Download the latest version from quick install and not the github releases because github releases only has MUSL targets. | |
| # run: cargo binstall cargo-fuzz --force --disable-strategies crate-meta-data --no-confirm | |
| # - run: cargo fuzz build -s none | |
| fuzz-parser: | |
| name: "fuzz parser" | |
| runs-on: ubuntu-latest | |
| needs: determine_changes | |
| if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-test') && (needs.determine_changes.outputs.parser == 'true' || needs.determine_changes.outputs.py-fuzzer == 'true') }} | |
| timeout-minutes: 20 | |
| env: | |
| FORCE_COLOR: 1 | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 | |
| with: | |
| version: "0.12.3" | |
| - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 | |
| with: | |
| shared-key: ruff-linux-debug | |
| save-if: false | |
| - name: "Install Rust toolchain" | |
| run: rustup show | |
| - name: "Install mold" | |
| uses: rui314/setup-mold@9c9c13bf4c3f1adef0cc596abc155580bcb04444 # v1 | |
| - name: Build buff binary | |
| env: | |
| # Line-tables-only debug info: faster builds, backtraces still work. | |
| CARGO_PROFILE_DEV_DEBUG: line-tables-only | |
| # basedpython renames the `ruff` binary to `buff`. `--bin=ruff` below is | |
| # the py-fuzzer's tool-mode selector (an enum), not a binary name, so it | |
| # stays `ruff` | |
| run: cargo build --bin buff | |
| - name: Fuzz | |
| run: | | |
| ( | |
| uv run \ | |
| --python="${PYTHON_VERSION}" \ | |
| --project=./python/py-fuzzer \ | |
| --locked \ | |
| fuzz \ | |
| --test-executable=target/debug/buff \ | |
| --bin=ruff \ | |
| 0-500 | |
| ) | |
| scripts: | |
| name: "test scripts" | |
| runs-on: ubuntu-latest | |
| needs: determine_changes | |
| if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-test') && (needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main') }} | |
| timeout-minutes: 5 | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 | |
| with: | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 | |
| with: | |
| version: "0.12.3" | |
| - name: "Install Rust toolchain" | |
| run: rustup component add rustfmt | |
| # Run all code generation scripts, and verify that the current output is | |
| # already checked into git. | |
| - run: python crates/ruff_python_ast/generate.py | |
| - run: python crates/ruff_python_formatter/generate.py | |
| - run: test -z "$(git status --porcelain)" | |
| # Verify that adding a plugin or rule produces clean code. | |
| - run: ./scripts/add_rule.py --name DoTheThing --prefix F --code 999 --linter pyflakes | |
| - run: cargo check | |
| - run: | | |
| ./scripts/add_plugin.py test --url https://pypi.org/project/-test/0.1.0/ --prefix TST | |
| ./scripts/add_rule.py --name FirstRule --prefix TST --code 001 --linter test | |
| - run: cargo check | |
| # The round-trip report has to fit GitHub's comment size limit, and has to | |
| # not report a project as changed just because two binaries produced the | |
| # same failure. Both are only observable in a `pull_request` run, so they | |
| # are covered by unit tests instead. | |
| - run: uv run --no-project --with pytest pytest scripts/test_check_ecosystem_roundtrip.py | |
| # Lint/format/type-check py-fuzzer | |
| # (dogfooding with ty is done in a separate job) | |
| - run: uv run --directory=./python/py-fuzzer mypy | |
| - run: uv run --directory=./python/py-fuzzer ruff format --check | |
| - run: uv run --directory=./python/py-fuzzer ruff check | |
| ecosystem: | |
| name: "ecosystem" | |
| runs-on: ${{ github.repository == 'astral-sh/ruff' && 'depot-ubuntu-24.04-8' || 'ubuntu-latest' }} | |
| needs: determine_changes | |
| # Only runs on pull requests, since that is the only we way we can find the base version for comparison. | |
| # Ecosystem check needs linter and/or formatter changes. | |
| if: | | |
| !contains(github.event.pull_request.labels.*.name, 'no-test') && github.event_name == 'pull_request' && | |
| ( | |
| needs.determine_changes.outputs.linter == 'true' || | |
| needs.determine_changes.outputs.formatter == 'true' | |
| ) | |
| # max (6h): the fork runs on slow `ubuntu-latest`, not astral's depot | |
| # runners, so the 70-project ecosystem check overruns a tighter budget | |
| timeout-minutes: 360 | |
| env: | |
| # Line-tables-only debug info: faster builds, backtraces still work. | |
| CARGO_PROFILE_DEV_DEBUG: line-tables-only | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| ref: ${{ github.event.pull_request.base.ref }} | |
| persist-credentials: false | |
| - uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 | |
| with: | |
| python-version: ${{ env.PYTHON_VERSION }} | |
| activate-environment: true | |
| version: "0.12.3" | |
| - name: "Install Rust toolchain" | |
| run: rustup show | |
| - name: "Install mold" | |
| uses: rui314/setup-mold@9c9c13bf4c3f1adef0cc596abc155580bcb04444 # v1 | |
| - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 | |
| with: | |
| shared-key: ruff-linux-debug | |
| save-if: false | |
| - name: Build baseline version | |
| # basedpython renames the `ruff` binary to `buff` | |
| run: | | |
| cargo build --bin buff | |
| mv target/debug/buff target/debug/buff-baseline | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| clean: false | |
| - name: Build comparison version | |
| run: cargo build --bin buff | |
| - name: Install ruff-ecosystem | |
| run: | | |
| uv pip install ./python/ruff-ecosystem | |
| - name: Run `ruff check` stable ecosystem check | |
| if: ${{ needs.determine_changes.outputs.linter == 'true' }} | |
| run: | | |
| # Set pipefail to avoid hiding errors with tee | |
| set -eo pipefail | |
| ruff-ecosystem check ./target/debug/buff-baseline ./target/debug/buff --cache ./checkouts --output-format markdown | tee ecosystem-result-check-stable | |
| cat ecosystem-result-check-stable > "$GITHUB_STEP_SUMMARY" | |
| echo "### Linter (stable)" > ecosystem-result | |
| cat ecosystem-result-check-stable >> ecosystem-result | |
| echo "" >> ecosystem-result | |
| - name: Run `ruff check` preview ecosystem check | |
| if: ${{ needs.determine_changes.outputs.linter == 'true' }} | |
| run: | | |
| # Set pipefail to avoid hiding errors with tee | |
| set -eo pipefail | |
| ruff-ecosystem check ./target/debug/buff-baseline ./target/debug/buff --cache ./checkouts --output-format markdown --force-preview | tee ecosystem-result-check-preview | |
| cat ecosystem-result-check-preview > "$GITHUB_STEP_SUMMARY" | |
| echo "### Linter (preview)" >> ecosystem-result | |
| cat ecosystem-result-check-preview >> ecosystem-result | |
| echo "" >> ecosystem-result | |
| # `--max-parallelism 2`: the default (50) oversubscribes the fork's small | |
| # `ubuntu-latest` runner — dozens of concurrent multi-threaded `buff format` | |
| # walks plus git clone/reset churn make the parallel file walk intermittently | |
| # surface a transient `No such file or directory` on one large project (a | |
| # different one each run), which the "Fail on ecosystem errors" step turns | |
| # into a hard failure. astral's 32-core depot runner absorbs the load; ours | |
| # needs the concurrency capped. (format only — the read-only check runs are | |
| # unaffected.) | |
| - name: Run `ruff format` stable ecosystem check | |
| if: ${{ needs.determine_changes.outputs.formatter == 'true' }} | |
| run: | | |
| # Set pipefail to avoid hiding errors with tee | |
| set -eo pipefail | |
| ruff-ecosystem format ./target/debug/buff-baseline ./target/debug/buff --cache ./checkouts --output-format markdown --max-parallelism 2 | tee ecosystem-result-format-stable | |
| cat ecosystem-result-format-stable > "$GITHUB_STEP_SUMMARY" | |
| echo "### Formatter (stable)" >> ecosystem-result | |
| cat ecosystem-result-format-stable >> ecosystem-result | |
| echo "" >> ecosystem-result | |
| - name: Run `ruff format` preview ecosystem check | |
| if: ${{ needs.determine_changes.outputs.formatter == 'true' }} | |
| run: | | |
| # Set pipefail to avoid hiding errors with tee | |
| set -eo pipefail | |
| ruff-ecosystem format ./target/debug/buff-baseline ./target/debug/buff --cache ./checkouts --output-format markdown --force-preview --max-parallelism 2 | tee ecosystem-result-format-preview | |
| cat ecosystem-result-format-preview > "$GITHUB_STEP_SUMMARY" | |
| echo "### Formatter (preview)" >> ecosystem-result | |
| cat ecosystem-result-format-preview >> ecosystem-result | |
| echo "" >> ecosystem-result | |
| # `workflow_run` only populates `pull_requests` for same-repo PRs, so the | |
| # commenting workflow cannot recover the number for a fork PR on its own | |
| - name: Record PR number for the comment workflow | |
| run: echo "${{ github.event.pull_request.number }}" > pr-number.txt | |
| # NOTE: astral-sh-bot uses this artifact to post comments on PRs, and so | |
| # does the in-repo `ecosystem_comment` workflow. | |
| # Make sure to update both if you rename the artifact. | |
| - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| name: Upload Results | |
| with: | |
| name: ecosystem-result | |
| path: | | |
| ecosystem-result | |
| pr-number.txt | |
| if-no-files-found: "error" | |
| - name: Fail on ecosystem errors | |
| run: | | |
| if ! grep -q "project error" ecosystem-result; then | |
| echo "no ecosystem project errors" | |
| exit 0 | |
| fi | |
| # a project error is only a `grep` hit in the bare step otherwise, so | |
| # the maintainer can't tell a transient fork-runner `No such file or | |
| # directory` (see the parallelism note above) from a real regression | |
| # without downloading the artifact. surface the errored projects and | |
| # their messages straight into the step log. | |
| projects=$(grep -oE '">[^<]+</a> \(error\)' ecosystem-result \ | |
| | sed -E 's/">([^<]+)<\/a> \(error\)/\1/' | paste -sd', ' -) | |
| echo "::group::ecosystem project errors (${projects:-unknown})" | |
| grep -F "project error" ecosystem-result || true | |
| echo | |
| # print each errored project's section: its `(error)` summary line | |
| # through the closing </details>, which brackets the message body | |
| awk ' | |
| /\(error\)<\/summary>/ { show = 1 } | |
| show { print } | |
| /<\/details>/ && show { show = 0; print "" } | |
| ' ecosystem-result | |
| echo "::endgroup::" | |
| echo "::error title=ecosystem project errors::${projects:-see log} — full report in the ecosystem-result artifact" | |
| exit 1 | |
| fuzz-ty: | |
| name: "Fuzz for new ty panics" | |
| runs-on: ${{ github.repository == 'astral-sh/ruff' && 'depot-ubuntu-22.04-16' || 'ubuntu-latest' }} | |
| needs: | |
| - determine_changes | |
| # Only runs on pull requests, since that is the only we way we can find the base version for comparison. | |
| if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-test') && github.event_name == 'pull_request' && (needs.determine_changes.outputs.ty == 'true' || needs.determine_changes.outputs.py-fuzzer == 'true') }} | |
| # the fork's ubuntu-latest runners are far slower than astral's depot, and | |
| # basedpython parser changes give the fuzzer more to explore, so allow the | |
| # full budget rather than cancelling a healthy run | |
| timeout-minutes: ${{ github.repository == 'astral-sh/ruff' && 10 || 360 }} | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| # Faster to do this separately than to use `fetch-depth: 0` with `actions/checkout` | |
| - name: Fetch full history without tags | |
| run: git fetch --no-tags --filter=blob:none --unshallow origin | |
| - uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 | |
| with: | |
| version: "0.12.3" | |
| - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 | |
| with: | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - name: "Install Rust toolchain" | |
| run: rustup show | |
| - name: "Install mold" | |
| uses: rui314/setup-mold@9c9c13bf4c3f1adef0cc596abc155580bcb04444 # v1 | |
| - name: Fuzz | |
| env: | |
| FORCE_COLOR: 1 | |
| # Line-tables-only debug info: faster builds, backtraces still work. | |
| CARGO_PROFILE_PROFILING_DEBUG: line-tables-only | |
| run: | | |
| # basedpython renames the `ty` binary to `by`. `--bin=ty` passed to | |
| # the py-fuzzer below is its tool-mode selector (an enum), not a | |
| # binary name, so it stays `ty` | |
| echo "new commit" | |
| git rev-list --format=%s --max-count=1 "$GITHUB_SHA" | |
| cargo build --profile=profiling --bin=by | |
| mv target/profiling/by ty-new | |
| MERGE_BASE="$(git merge-base "$GITHUB_SHA" "origin/$GITHUB_BASE_REF")" | |
| git checkout -b old_commit "$MERGE_BASE" | |
| echo "old commit (merge base)" | |
| git rev-list --format=%s --max-count=1 old_commit | |
| cargo build --profile=profiling --bin=by | |
| mv target/profiling/by ty-old | |
| ( | |
| uv run \ | |
| --python="${PYTHON_VERSION}" \ | |
| --project=./python/py-fuzzer \ | |
| --locked \ | |
| fuzz \ | |
| --test-executable=ty-new \ | |
| --baseline-executable=ty-old \ | |
| --only-new-bugs \ | |
| --bin=ty \ | |
| 0-1000 | |
| ) | |
| cargo-shear: | |
| name: "cargo shear" | |
| runs-on: ubuntu-latest | |
| needs: determine_changes | |
| if: ${{ needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main' }} | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: cargo-bins/cargo-binstall@e00d2c94cc0067b77737821097a62d91c0301baa # v1.21.1 | |
| - run: cargo binstall --no-confirm cargo-shear@1.12.4 | |
| - run: cargo shear --deny-warnings | |
| ty-completion-evaluation: | |
| name: "ty completion evaluation" | |
| runs-on: ${{ github.repository == 'astral-sh/ruff' && 'depot-ubuntu-22.04-16' || 'ubuntu-latest' }} | |
| needs: determine_changes | |
| if: ${{ needs.determine_changes.outputs.ty == 'true' || github.ref == 'refs/heads/main' }} | |
| env: | |
| # Line-tables-only debug info: faster builds, backtraces still work. | |
| CARGO_PROFILE_PROFILING_DEBUG: line-tables-only | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 | |
| with: | |
| version: "0.12.3" | |
| - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 | |
| with: | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - name: "Install Rust toolchain" | |
| run: rustup show | |
| - name: "Install mold" | |
| uses: rui314/setup-mold@9c9c13bf4c3f1adef0cc596abc155580bcb04444 # v1 | |
| - name: "Run ty completion evaluation" | |
| run: cargo run --profile profiling --package ty_completion_eval -- all --threshold 0.4 --tasks /tmp/completion-evaluation-tasks.csv | |
| - name: "Ensure there are no changes" | |
| run: diff ./crates/ty_completion_eval/completion-evaluation-tasks.csv /tmp/completion-evaluation-tasks.csv | |
| python-package: | |
| name: "python package" | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-test') }} | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 | |
| with: | |
| python-version: ${{ env.PYTHON_VERSION }} | |
| architecture: x64 | |
| - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 | |
| with: | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - name: "Prep README.md" | |
| run: python scripts/transform_readme.py --target pypi | |
| - name: "Build wheels" | |
| uses: PyO3/maturin-action@e83996d129638aa358a18fbd1dfb82f0b0fb5d3b # v1.51.0 | |
| with: | |
| args: --out dist | |
| - name: "Test wheel" | |
| run: | | |
| pip install --force-reinstall --find-links dist "${PACKAGE_NAME}" | |
| ruff --help | |
| python -m ruff --help | |
| - name: "Remove wheels from cache" | |
| run: rm -rf target/wheels | |
| prek: | |
| name: "prek" | |
| runs-on: ${{ github.repository == 'astral-sh/ruff' && 'depot-ubuntu-22.04-16' || 'ubuntu-latest' }} | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 | |
| with: | |
| version: "0.12.3" | |
| - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| node-version: 24 | |
| - name: "Cache prek" | |
| uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 | |
| with: | |
| path: ~/.cache/prek | |
| key: prek-${{ hashFiles('.pre-commit-config.yaml') }} | |
| - name: "Run prek" | |
| run: | | |
| echo '```console' > "$GITHUB_STEP_SUMMARY" | |
| # Enable color output for prek and remove it for the summary | |
| # Use --hook-stage=manual to enable slower hooks that are skipped by default | |
| SKIP=rustfmt uv run --only-group dev --locked prek run --all-files --show-diff-on-failure --color always --hook-stage manual | \ | |
| tee >(sed -E 's/\x1B\[([0-9]{1,2}(;[0-9]{1,2})*)?[mGK]//g' >> "$GITHUB_STEP_SUMMARY") >&1 | |
| exit_code="${PIPESTATUS[0]}" | |
| echo '```' >> "$GITHUB_STEP_SUMMARY" | |
| exit "$exit_code" | |
| docs: | |
| name: "mkdocs" | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 | |
| with: | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - name: "Install Rust toolchain" | |
| run: rustup show | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 | |
| with: | |
| python-version: 3.13 | |
| activate-environment: true | |
| version: "0.12.3" | |
| - name: "Install dependencies" | |
| run: uv pip install -r docs/requirements.txt | |
| - name: "Update README File" | |
| run: python scripts/transform_readme.py --target mkdocs | |
| - name: "Generate docs" | |
| run: python scripts/generate_mkdocs.py | |
| - name: "Check docs formatting" | |
| run: python scripts/check_docs_formatted.py | |
| - name: "Build docs" | |
| run: mkdocs build --strict -f mkdocs.yml | |
| basedpython-docs: | |
| name: "zensical" | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| with: | |
| persist-credentials: false | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 | |
| with: | |
| python-version: 3.13 | |
| version: "0.11.31" | |
| enable-cache: true | |
| - name: "Install docs dependencies" | |
| run: uv sync --group docs --no-install-project --locked | |
| - name: "Build docs" | |
| run: uv run --no-sync zensical build --clean --strict | |
| check-formatter-instability-and-black-similarity: | |
| name: "formatter instabilities and black similarity" | |
| runs-on: ubuntu-latest | |
| needs: determine_changes | |
| if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-test') && (needs.determine_changes.outputs.formatter == 'true' || github.ref == 'refs/heads/main') }} | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 | |
| with: | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - name: "Install Rust toolchain" | |
| run: rustup show | |
| - name: "Run checks" | |
| run: scripts/formatter_ecosystem_checks.sh | |
| - name: "Github step summary" | |
| run: cat target/formatter-ecosystem/stats.txt > "$GITHUB_STEP_SUMMARY" | |
| - name: "Remove checkouts from cache" | |
| run: rm -r target/formatter-ecosystem | |
| # check-ruff-lsp: | |
| # name: "test ruff-lsp" | |
| # runs-on: ubuntu-latest | |
| # timeout-minutes: 5 | |
| # needs: determine_changes | |
| # if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-test') && (needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main') }} | |
| # env: | |
| # # Line-tables-only debug info: faster builds, backtraces still work. | |
| # CARGO_PROFILE_DEV_DEBUG: line-tables-only | |
| # steps: | |
| # - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| # name: "Checkout ruff source" | |
| # with: | |
| # persist-credentials: false | |
| # | |
| # - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 | |
| # with: | |
| # shared-key: ruff-linux-debug | |
| # save-if: false | |
| # | |
| # - name: "Install Rust toolchain" | |
| # run: rustup show | |
| # | |
| # - name: "Install mold" | |
| # uses: rui314/setup-mold@9c9c13bf4c3f1adef0cc596abc155580bcb04444 # v1 | |
| # | |
| # - name: Build Ruff binary | |
| # run: cargo build -p ruff --bin ruff | |
| # | |
| # - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| # name: "Checkout ruff-lsp source" | |
| # with: | |
| # persist-credentials: false | |
| # repository: "astral-sh/ruff-lsp" | |
| # path: ruff-lsp | |
| # | |
| # - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 | |
| # with: | |
| # # installation fails on 3.13 and newer | |
| # python-version: "3.12" | |
| # | |
| # - uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 | |
| # | |
| # - name: Install ruff-lsp dependencies | |
| # run: | | |
| # cd ruff-lsp | |
| # uv venv | |
| # uv pip install --no-deps -r requirements.txt | |
| # uv pip install --no-deps -r requirements-dev.txt | |
| # | |
| # - name: Run ruff-lsp tests | |
| # run: | | |
| # # Setup development binary | |
| # export PATH="${PWD}/target/debug:${PATH}" | |
| # ruff version | |
| # | |
| # cd ruff-lsp | |
| # uv pip uninstall ruff | |
| # uv run --no-sync pytest | |
| check-playground: | |
| name: "check playground" | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| needs: | |
| - determine_changes | |
| if: ${{ (needs.determine_changes.outputs.playground == 'true') }} | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - name: "Install Rust toolchain" | |
| run: rustup target add wasm32-unknown-unknown | |
| - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 | |
| with: | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| node-version: 24 | |
| cache: "npm" | |
| cache-dependency-path: playground/package-lock.json | |
| - uses: jetli/wasm-bindgen-action@20b33e20595891ab1a0ed73145d8a21fc96e7c29 # v0.2.0 | |
| - name: "Install Node dependencies" | |
| run: npm ci --ignore-scripts | |
| working-directory: playground | |
| - name: "Build playgrounds" | |
| run: npm run dev:wasm | |
| working-directory: playground | |
| - name: "Run TypeScript checks" | |
| run: npm run check | |
| working-directory: playground | |
| - name: "Check formatting" | |
| run: npm run fmt:check | |
| working-directory: playground | |
| benchmarks-instrumented-ruff: | |
| name: "benchmarks instrumented (ruff)" | |
| runs-on: ubuntu-24.04 | |
| needs: determine_changes | |
| # TODO(basedpython): enable benchmarks for the fork. requires: | |
| # 1. register KotlinIsland/basedpython at https://codspeed.io | |
| # (project must be created with OIDC auth enabled, or set the | |
| # CODSPEED_TOKEN repo secret and pass `token: ${{ secrets.CODSPEED_TOKEN }}` | |
| # to the CodSpeedHQ/action step below) | |
| # 2. flip the predicate below back to 'KotlinIsland/basedpython' | |
| # gated on astral-sh/ruff for now so the job skips on the fork; uploads | |
| # from KotlinIsland/basedpython otherwise fail OIDC auth with 401 | |
| if: | | |
| github.repository == 'astral-sh/ruff' && | |
| ( | |
| github.ref == 'refs/heads/main' || | |
| needs.determine_changes.outputs.formatter == 'true' || | |
| needs.determine_changes.outputs.linter == 'true' || | |
| needs.determine_changes.outputs.parser == 'true' || | |
| needs.determine_changes.outputs.benchmarks == 'true' | |
| ) | |
| timeout-minutes: 20 | |
| permissions: | |
| contents: read # required for actions/checkout | |
| id-token: write # required for OIDC authentication with CodSpeed | |
| steps: | |
| - name: "Checkout Branch" | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 | |
| with: | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 | |
| with: | |
| version: "0.12.3" | |
| - name: "Install Rust toolchain" | |
| run: rustup show | |
| - name: "Install codspeed" | |
| uses: taiki-e/install-action@cb33e69fad06166ca28a42b2575e4dadabf62ee8 # v2.85.8 | |
| with: | |
| tool: cargo-codspeed | |
| - name: "Build benchmarks" | |
| run: cargo codspeed build -m simulation -m memory --features "codspeed,ruff_instrumented" --profile profiling --no-default-features -p ruff_benchmark --bench formatter --bench lexer --bench linter --bench parser | |
| - name: "Run benchmarks" | |
| uses: CodSpeedHQ/action@0ca9cbbf4623b599a6c3ed4fc8a922942705d9f1 # v5.0.2 | |
| with: | |
| mode: "simulation,memory" | |
| run: cargo codspeed run | |
| benchmarks-instrumented-ty-build: | |
| name: "benchmarks instrumented ty (build)" | |
| runs-on: depot-ubuntu-24.04-4 | |
| needs: determine_changes | |
| # TODO(basedpython): see `benchmarks-instrumented-ruff` above for how to | |
| # enable benchmarks for the fork (register repo at codspeed.io, then flip | |
| # the predicate below back to 'KotlinIsland/basedpython') | |
| if: | | |
| github.repository == 'astral-sh/ruff' && | |
| ( | |
| github.ref == 'refs/heads/main' || | |
| needs.determine_changes.outputs.ty == 'true' || | |
| needs.determine_changes.outputs.benchmarks == 'true' | |
| ) | |
| timeout-minutes: 20 | |
| steps: | |
| - name: "Checkout Branch" | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 | |
| with: | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - name: "Install Rust toolchain" | |
| run: rustup show | |
| - name: "Install codspeed" | |
| uses: taiki-e/install-action@cb33e69fad06166ca28a42b2575e4dadabf62ee8 # v2.85.8 | |
| with: | |
| tool: cargo-codspeed | |
| - name: "Build benchmarks" | |
| run: cargo codspeed build -m simulation -m memory --features "codspeed,module_resolution,ty_instrumented" --profile profiling --no-default-features -p ruff_benchmark --bench module_resolution --bench ty --bench ty_constraint_set | |
| - name: "Upload benchmark binary" | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: benchmarks-instrumented-ty-binary | |
| compression-level: 1 | |
| path: target/codspeed | |
| if-no-files-found: "error" | |
| retention-days: 1 | |
| benchmarks-instrumented-ty-run: | |
| name: "benchmarks instrumented ty (${{ matrix.mode }}: ${{ matrix.name }})" | |
| runs-on: ubuntu-24.04 | |
| needs: benchmarks-instrumented-ty-build | |
| timeout-minutes: 20 | |
| permissions: | |
| contents: read # required for actions/checkout | |
| id-token: write # required for OIDC authentication with CodSpeed | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - name: micro | |
| target: ty | |
| filter: micro | |
| mode: simulation | |
| - name: micro | |
| target: ty | |
| filter: micro | |
| mode: memory | |
| - name: constraint_set | |
| target: ty_constraint_set | |
| filter: micro | |
| mode: simulation | |
| - name: constraint_set | |
| target: ty_constraint_set | |
| filter: micro | |
| mode: memory | |
| - name: projects | |
| target: ty | |
| filter: "check_file|anyio|attrs|hydra|datetype" | |
| mode: simulation | |
| - name: projects | |
| target: ty | |
| filter: "check_file|anyio|attrs|hydra|datetype" | |
| mode: memory | |
| - name: module_resolution | |
| target: module_resolution | |
| filter: ty_module_resolver | |
| mode: simulation | |
| steps: | |
| - name: "Checkout Branch" | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 | |
| with: | |
| version: "0.12.3" | |
| - name: "Install codspeed" | |
| uses: taiki-e/install-action@cb33e69fad06166ca28a42b2575e4dadabf62ee8 # v2.85.8 | |
| with: | |
| tool: cargo-codspeed | |
| - name: "Download benchmark binary" | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | |
| with: | |
| name: benchmarks-instrumented-ty-binary | |
| path: target/codspeed | |
| - name: "Restore binary permissions" | |
| # codspeed keeps changing the paths to the executable, so we have to be a bit more flexible | |
| run: find target/codspeed -type f -exec chmod +x {} + | |
| - name: "Run benchmarks" | |
| uses: CodSpeedHQ/action@0ca9cbbf4623b599a6c3ed4fc8a922942705d9f1 # v5.0.2 | |
| with: | |
| mode: ${{ matrix.mode }} | |
| run: cargo codspeed run --bench "${{ matrix.target }}" "${{ matrix.filter }}" | |
| benchmarks-walltime-build: | |
| name: "benchmarks walltime (build)" | |
| # depot runners hardcoded here are fine since the job is upstream-only. | |
| runs-on: depot-ubuntu-22.04-arm-4 | |
| needs: determine_changes | |
| # TODO(basedpython): see `benchmarks-instrumented-ruff` above for how to | |
| # enable benchmarks for the fork (register repo at codspeed.io, then flip | |
| # the predicate below back to 'KotlinIsland/basedpython') | |
| if: | | |
| github.repository == 'astral-sh/ruff' && | |
| ( | |
| !contains(github.event.pull_request.labels.*.name, 'no-test') && | |
| ( | |
| needs.determine_changes.outputs.ty == 'true' || | |
| needs.determine_changes.outputs.benchmarks == 'true' || | |
| github.ref == 'refs/heads/main' | |
| ) | |
| ) | |
| timeout-minutes: 20 | |
| steps: | |
| - name: "Checkout Branch" | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 | |
| with: | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 | |
| with: | |
| version: "0.12.3" | |
| - name: "Install Rust toolchain" | |
| run: rustup show | |
| - name: "Install codspeed" | |
| uses: taiki-e/install-action@cb33e69fad06166ca28a42b2575e4dadabf62ee8 # v2.85.8 | |
| with: | |
| tool: cargo-codspeed | |
| - name: "Build benchmarks" | |
| run: cargo codspeed build -m walltime --features "codspeed,ty_walltime" --profile profiling --no-default-features -p ruff_benchmark --bench ty_walltime | |
| - name: "Upload benchmark binary" | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: benchmarks-walltime-binary | |
| compression-level: 1 | |
| path: target/codspeed | |
| if-no-files-found: "error" | |
| retention-days: 1 | |
| benchmarks-walltime-run: | |
| name: "benchmarks walltime (${{ matrix.benchmark.name }})" | |
| runs-on: codspeed-macro | |
| needs: benchmarks-walltime-build | |
| timeout-minutes: 20 | |
| permissions: | |
| contents: read # required for actions/checkout | |
| id-token: write # required for OIDC authentication with CodSpeed | |
| strategy: | |
| matrix: | |
| benchmark: | |
| - name: sympy | |
| target: ty_walltime | |
| filter: sympy | |
| - name: "pandas|tanjun" | |
| target: ty_walltime | |
| filter: "pandas|tanjun" | |
| - name: "colour_science|static_frame" | |
| target: ty_walltime | |
| filter: "colour_science|static_frame" | |
| - name: "pydantic|freqtrade|multithreaded|altair" | |
| target: ty_walltime | |
| filter: "pydantic|freqtrade|multithreaded|altair" | |
| steps: | |
| - name: "Checkout Branch" | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 | |
| with: | |
| version: "0.12.3" | |
| - name: "Install codspeed" | |
| uses: taiki-e/install-action@cb33e69fad06166ca28a42b2575e4dadabf62ee8 # v2.85.8 | |
| with: | |
| tool: cargo-codspeed | |
| - name: "Download benchmark binary" | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | |
| with: | |
| name: benchmarks-walltime-binary | |
| path: target/codspeed | |
| - name: "Restore binary permissions" | |
| # codspeed keeps changing the paths to the executable, so we have to be a bit more flexible | |
| run: find target/codspeed -type f -exec chmod +x {} + | |
| - name: "Run benchmarks" | |
| uses: CodSpeedHQ/action@0ca9cbbf4623b599a6c3ed4fc8a922942705d9f1 # v5.0.2 | |
| env: | |
| # enabling walltime flamegraphs adds ~6 minutes to the CI time, and they don't | |
| # appear to provide much useful insight for our walltime benchmarks right now | |
| # (see https://github.com/astral-sh/ruff/pull/20419) | |
| CODSPEED_PERF_ENABLED: false | |
| with: | |
| mode: walltime | |
| run: cargo codspeed run --bench "${{ matrix.benchmark.target }}" -m walltime "${{ matrix.benchmark.filter }}" | |
| required-checks-passed: | |
| name: "all required checks passed" | |
| if: always() | |
| needs: | |
| - cargo-fmt | |
| - cargo-clippy | |
| - cargo-test-linux | |
| - cargo-test-interpreter | |
| - cargo-test-wasm | |
| - cargo-build-msrv | |
| - shellcheck | |
| - scripts | |
| - prek | |
| - docs | |
| - basedpython-docs | |
| - python-package | |
| runs-on: ubuntu-slim | |
| steps: | |
| - name: "Check required jobs passed" | |
| run: | | |
| failing=$(echo "$NEEDS_JSON" | jq -r 'to_entries[] | select(.value.result != "success" and .value.result != "skipped") | "\(.key): \(.value.result)"') | |
| if [ -n "$failing" ]; then | |
| echo "$failing" | |
| exit 1 | |
| fi | |
| env: | |
| NEEDS_JSON: ${{ toJSON(needs) }} |