An open API service indexing awesome lists of open source software.

https://github.com/qltysh/stet

Run only the tests affected by your changes. Open-source selective test execution inspired by Stripe.
https://github.com/qltysh/stet

bun ci developer-tools python ruby rust selective-testing test-selection testing typescript

Last synced: about 15 hours ago
JSON representation

Run only the tests affected by your changes. Open-source selective test execution inspired by Stripe.

Awesome Lists containing this project

README

          

# stet

*stet* — "let it stand." A proofreading term meaning the original text is correct and should not be changed. In the same way, `stet` identifies the tests that can stand as-is, and reruns only the ones affected by your changes.

`stet` is an open-source implementation of the selective test execution system described in Stripe's blog post [*Fast CI for a 50M-Line Ruby Monorepo*](https://stripe.dev/blog/selective-test-execution-at-stripe-fast-ci-for-a-50m-line-ruby-monorepo). It traces which files each test opens, builds a dependency graph, and uses it to select just the tests impacted by your code changes. It works with Ruby/Minitest, Python/Pytest, and Bun on macOS and Linux.

> **Research preview.** `stet` is functional and tested but is not yet battle-tested in production. APIs, config format, and on-disk storage may change without notice. Feedback and contributions are welcome.

## How it works

1. **Record** — `stet` runs your test suite with a shared library injected via `DYLD_INSERT_LIBRARIES` (macOS) or `LD_PRELOAD` (Linux) that intercepts file-open syscalls. This produces a map of which source files each test depends on.

2. **Select** — When files change, `stet` diffs the repo inventory against the recorded dependency graph and identifies which tests are affected.

3. **Run** — `stet` executes only the affected tests, re-traces their dependencies, and updates the dependency graph for next time. No full re-record needed.

## Install

Using the [GitHub CLI](https://cli.github.com/):

```bash
# macOS (Apple Silicon)
gh release download --repo qltysh/stet --pattern 'stet-aarch64-apple-darwin.tar.gz'
tar xzf stet-aarch64-apple-darwin.tar.gz

# Linux (x86_64)
gh release download --repo qltysh/stet --pattern 'stet-x86_64-unknown-linux-gnu.tar.gz'
tar xzf stet-x86_64-unknown-linux-gnu.tar.gz
```

Then add the extracted directory to your PATH. The archive contains both the `stet` binary and the `libstet_interceptor` library.

### Build from source

Alternatively, build from source with the [Rust toolchain](https://rustup.rs/):

```bash
git clone https://github.com/qltysh/stet.git
cd stet
bash scripts/setup.sh
```

## Quick start

Run `stet init` from your project root to auto-detect your test runner and generate a config:

```bash
stet init
```

This scans your repo for dependency files (Gemfile, pyproject.toml, package.json/bun.lockb) and test directories, then writes a commented `stet.toml` with the right settings. Add `.stet/` to your `.gitignore`.

Then record a baseline and start running:

```bash
# Record the baseline (runs your full test suite once with tracing)
stet record

# Make a code change, then run just the affected tests
stet run
```

`stet init` accepts `--runner minitest|pytest|bun_test` to skip detection, `--force` to overwrite an existing config, and `--config ` for a custom output location.

### Manual configuration

If you prefer to create `stet.toml` by hand:

**Ruby/Minitest:**

```toml
test_runner = "minitest"
test_globs = ["test/**/*_test.rb"]
test_args = ["-Itest"]
inventory_excludes = [".git/**", ".stet/**", "tmp/**"]
```

**Python/Pytest:**

```toml
test_runner = "pytest"
test_globs = ["tests/test_*.py", "tests/**/*_test.py"]
test_args = ["-m", "pytest"]
inventory_excludes = [".git/**", ".stet/**", "__pycache__/**", ".pytest_cache/**"]
```

**Bun:**

```toml
test_runner = "bun_test"
test_globs = ["test/**/*.test.ts"]
test_args = ["test"]
inventory_excludes = [".git/**", ".stet/**", "node_modules/**"]
```

`state_dir` defaults to `.stet`. `runtime` is inferred from `test_runner` (`ruby`, `python3`, or `bun`) and resolved from PATH. Both can be overridden explicitly.

`stet` looks for `stet.toml` in the current directory and auto-discovers the interceptor library next to its own binary. Use `--config` and `--interceptor` to override.

## Commands

### `stet init`

Auto-detects the test runner from your repo contents and generates a commented `stet.toml`. Supports `--runner` to skip detection, `--force` to overwrite, and `--config` for a custom output path.

### `stet record`

Runs every test with tracing and publishes a new dependency baseline under `.stet/bases/`. Use this for initial setup or to force a full re-record.

### `stet select`

Reads the latest baseline, diffs current file hashes against it, and outputs the list of affected test units. Doesn't run anything.

### `stet run`

Selects affected tests, runs them with tracing, and updates the baseline. If no baseline exists, bootstraps by running the full suite. This is the steady-state command for day-to-day development.

## Advanced configuration

### Mandatory tests

Tests that should always run regardless of what changed:

```toml
mandatory_test_globs = ["test/health/**/*_test.rb"]
```

### Root preload

A script that runs before tests to generate shared artifacts (e.g., schema files). Changes to files opened by the root preload will select all tests:

```toml
root_args = ["-Itest", "test/root_preload.rb"]
```

### Tool routes

Run additional commands when specific files change:

```toml
[[tool_routes]]
name = "yaml-lint"
changed_file_globs = ["config/**/*.yml"]
command = ["{runtime}", "script/changed_file_yaml_lint.rb", "{changed_files...}"]
```

### Parallelism

```toml
max_workers = 8 # defaults to available CPU cores
```

## Development

Try the interactive demo:

```bash
bash scripts/demo-fixture.sh --fixture ruby
bash scripts/demo-fixture.sh --fixture python
bash scripts/demo-fixture.sh --fixture bun
```

Run the test suite:

```bash
bash scripts/setup.sh
cargo test --workspace
```

Run clippy and format checks:

```bash
cargo clippy --workspace --all-targets -- -D warnings
cargo fmt --check
```

Benchmark:

```bash
bash scripts/benchmark-fixture.sh --fixture ruby
bash scripts/benchmark-fixture.sh --fixture python
bash scripts/benchmark-fixture.sh --fixture bun
```

Linux validation (requires Docker):

```bash
bash scripts/validate-linux-docker.sh
```

## License

MIT