tempest-cli 0.2.0__tar.gz → 0.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. {tempest_cli-0.2.0 → tempest_cli-0.4.0}/CHANGELOG.md +76 -0
  2. {tempest_cli-0.2.0 → tempest_cli-0.4.0}/PKG-INFO +38 -17
  3. {tempest_cli-0.2.0 → tempest_cli-0.4.0}/README.md +35 -15
  4. {tempest_cli-0.2.0 → tempest_cli-0.4.0}/docs/changelog.en.md +42 -0
  5. {tempest_cli-0.2.0 → tempest_cli-0.4.0}/docs/changelog.md +41 -0
  6. tempest_cli-0.4.0/docs/commands.en.md +159 -0
  7. tempest_cli-0.4.0/docs/commands.md +156 -0
  8. {tempest_cli-0.2.0 → tempest_cli-0.4.0}/docs/configuration.en.md +6 -0
  9. {tempest_cli-0.2.0 → tempest_cli-0.4.0}/docs/configuration.md +6 -0
  10. {tempest_cli-0.2.0 → tempest_cli-0.4.0}/docs/index.en.md +6 -1
  11. {tempest_cli-0.2.0 → tempest_cli-0.4.0}/docs/index.md +6 -1
  12. tempest_cli-0.4.0/docs/installation.en.md +112 -0
  13. tempest_cli-0.4.0/docs/installation.md +112 -0
  14. {tempest_cli-0.2.0 → tempest_cli-0.4.0}/docs/library.en.md +1 -0
  15. {tempest_cli-0.2.0 → tempest_cli-0.4.0}/docs/library.md +1 -0
  16. tempest_cli-0.4.0/docs/rules.en.md +252 -0
  17. tempest_cli-0.4.0/docs/rules.md +249 -0
  18. {tempest_cli-0.2.0 → tempest_cli-0.4.0}/mkdocs.yml +3 -0
  19. {tempest_cli-0.2.0 → tempest_cli-0.4.0}/pyproject.toml +17 -6
  20. {tempest_cli-0.2.0 → tempest_cli-0.4.0}/tempest_cli/__init__.py +6 -4
  21. {tempest_cli-0.2.0 → tempest_cli-0.4.0}/tempest_cli/lint.py +246 -15
  22. {tempest_cli-0.2.0 → tempest_cli-0.4.0}/tempest_cli/main.py +121 -4
  23. tempest_cli-0.4.0/tests/test_fast.py +388 -0
  24. {tempest_cli-0.2.0 → tempest_cli-0.4.0}/tests/test_lint_runners.py +25 -4
  25. {tempest_cli-0.2.0 → tempest_cli-0.4.0}/uv.lock +29 -3
  26. tempest_cli-0.2.0/docs/commands.en.md +0 -82
  27. tempest_cli-0.2.0/docs/commands.md +0 -81
  28. tempest_cli-0.2.0/docs/installation.en.md +0 -90
  29. tempest_cli-0.2.0/docs/installation.md +0 -89
  30. {tempest_cli-0.2.0 → tempest_cli-0.4.0}/.github/workflows/ci.yml +0 -0
  31. {tempest_cli-0.2.0 → tempest_cli-0.4.0}/.github/workflows/docs.yml +0 -0
  32. {tempest_cli-0.2.0 → tempest_cli-0.4.0}/.github/workflows/release-pypi.yml +0 -0
  33. {tempest_cli-0.2.0 → tempest_cli-0.4.0}/.gitignore +0 -0
  34. {tempest_cli-0.2.0 → tempest_cli-0.4.0}/LICENSE +0 -0
  35. {tempest_cli-0.2.0 → tempest_cli-0.4.0}/Makefile +0 -0
  36. {tempest_cli-0.2.0 → tempest_cli-0.4.0}/docs/pr-prompt.en.md +0 -0
  37. {tempest_cli-0.2.0 → tempest_cli-0.4.0}/docs/pr-prompt.md +0 -0
  38. {tempest_cli-0.2.0 → tempest_cli-0.4.0}/docs/reference.en.md +0 -0
  39. {tempest_cli-0.2.0 → tempest_cli-0.4.0}/docs/reference.md +0 -0
  40. {tempest_cli-0.2.0 → tempest_cli-0.4.0}/tempest_cli/_templates/pull_request_template.en-US.md +0 -0
  41. {tempest_cli-0.2.0 → tempest_cli-0.4.0}/tempest_cli/_templates/pull_request_template.pt-BR.md +0 -0
  42. {tempest_cli-0.2.0 → tempest_cli-0.4.0}/tempest_cli/config.py +0 -0
  43. {tempest_cli-0.2.0 → tempest_cli-0.4.0}/tempest_cli/pr_prompt.py +0 -0
  44. {tempest_cli-0.2.0 → tempest_cli-0.4.0}/tempest_cli/py.typed +0 -0
  45. {tempest_cli-0.2.0 → tempest_cli-0.4.0}/tests/__init__.py +0 -0
  46. {tempest_cli-0.2.0 → tempest_cli-0.4.0}/tests/test_cli.py +0 -0
  47. {tempest_cli-0.2.0 → tempest_cli-0.4.0}/tests/test_config.py +0 -0
  48. {tempest_cli-0.2.0 → tempest_cli-0.4.0}/tests/test_lint_strictness.py +0 -0
  49. {tempest_cli-0.2.0 → tempest_cli-0.4.0}/tests/test_pr_prompt.py +0 -0
@@ -5,6 +5,82 @@ All notable changes to **tempest-cli** are listed below.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.4.0] — 2026-09-27
9
+
10
+ ### Added
11
+
12
+ - **`test --fast` and `check --fast`: the suite in parallel.** `--fast`
13
+ runs pytest as `pytest -n <workers> -p no:cacheprovider [target]`, with
14
+ pytest-xdist spreading the suite across the cores; `--workers` / `-w`
15
+ takes what `pytest -n` takes (an integer, `auto` — the default — or
16
+ `logical`) and is a usage error (exit 2) without `--fast`. The cache
17
+ plugin is off because several workers writing `.pytest_cache` at once
18
+ is a race that buys nothing. The target is forwarded and pytest's exit
19
+ code comes straight back, as in the serial run. It is a flag rather
20
+ than a `test fast` subcommand because `test` already takes a
21
+ positional path: `test fast` keeps meaning the `fast/` folder.
22
+ Requested in mauriciobenjamin700/tempest-fastapi-sdk#328.
23
+
24
+ Measured on a machine with 6 physical cores / 12 threads. On this
25
+ package's own suite (100 tests, warm environment, three runs each)
26
+ `tempest-cli test` took 2.2 s and `tempest-cli test --fast` 1.6–1.7 s
27
+ (12 workers: no `psutil` here, so `auto` counts logical CPUs) — worker
28
+ start-up is most of the fast run at this size. On the
29
+ tempest-fastapi-sdk suite (10 218 tests, one run each, same
30
+ invocation), pytest reported 2127 s serial and 411 s with `--fast`
31
+ (`auto` → 6 workers, since `psutil` is installed there), about 5.2x;
32
+ both runs ended with the same 10 failures, all from `ruff` being a dead
33
+ pyenv shim on that `PATH`.
34
+
35
+ `auto` is pytest-xdist's rule, not ours: physical cores when `psutil`
36
+ is importable, logical CPUs otherwise. `-w logical` asks for the
37
+ threads explicitly.
38
+
39
+ - **A missing pytest-xdist is a sentence, not `unrecognized arguments:
40
+ -n`.** Before spawning, `--fast` asks the interpreter pytest will run
41
+ under — read from the pytest script's shebang, its sibling `python`,
42
+ or the same `uv run --with pytest` overlay — whether it can import
43
+ `xdist`. When it cannot, the message names `pytest-xdist`,
44
+ `tempest-cli[tools]` and `tempest-fastapi-sdk[tests]`, and the exit code
45
+ is 127, with no traceback. `check --fast` makes that check before its
46
+ first step. A probe that cannot run at all is not taken as "missing":
47
+ the run proceeds and pytest reports for itself.
48
+
49
+ - **`run_pytest(..., fast=, workers=)` and `run_full_check(..., fast=,
50
+ workers=)`** for library callers — keyword-only, defaulting to the
51
+ serial run, so every existing call is unchanged. `DEFAULT_FAST_WORKERS`,
52
+ `XDIST_MODULE` and `MISSING_TOOL_EXIT_CODE` are exported from
53
+ `tempest_cli.lint`.
54
+
55
+ ### Changed
56
+
57
+ - **`[tools]` now carries `pytest-xdist>=3.8.0`** next to mypy and pytest,
58
+ so the bundle is enough for `--fast`. Its `requires-dist`
59
+ (`execnet>=2.1`, `pytest>=7.0.0`) has no upper bound.
60
+
61
+ ## [0.3.0] — 2026-08-15
62
+
63
+ ### Changed
64
+
65
+ - **`ruff` now ships with the package.** It moved from the `[tools]`
66
+ extra into the runtime dependencies, so `uv add --dev tempest-cli` is
67
+ enough for `lint`, `fix`, `format` and `fmt-check` to run — no second
68
+ install, and no dependency on `uv` being around to fetch one. The cost
69
+ is nil: ruff is a static binary wheel with no Python dependencies of
70
+ its own, so no bound of its reaches a consumer's resolution.
71
+
72
+ `mypy` and `pytest` stay out on purpose. A mypy bump changes which
73
+ errors a codebase reports and pytest has to match the suite and its
74
+ plugins — those are the project's call. `[tools]` now installs exactly
75
+ those two.
76
+
77
+ - **The project's environment is searched before the CLI's own.** With
78
+ ruff bundled, the CLI's environment always has one; looking there
79
+ first would silently override a version the project pinned whenever
80
+ `tempest-cli` is installed apart from it (`uv tool install`, pipx).
81
+ The order is now `$VIRTUAL_ENV` → nearest `.venv` → the CLI's own
82
+ environment → `PATH` → `uv run --with`.
83
+
8
84
  ## [0.2.0] — 2026-08-15
9
85
 
10
86
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: tempest-cli
3
- Version: 0.2.0
3
+ Version: 0.4.0
4
4
  Summary: Framework-agnostic quality gate for Python projects: ruff + mypy + pytest behind one command, with a typing-strictness dial and a PR-description prompt generator.
5
5
  Project-URL: Homepage, https://github.com/mauriciobenjamin700/tempest-cli
6
6
  Project-URL: Repository, https://github.com/mauriciobenjamin700/tempest-cli
@@ -22,11 +22,12 @@ Classifier: Topic :: Software Development :: Quality Assurance
22
22
  Classifier: Topic :: Utilities
23
23
  Classifier: Typing :: Typed
24
24
  Requires-Python: >=3.11
25
+ Requires-Dist: ruff>=0.8.0
25
26
  Requires-Dist: typer>=0.12.0
26
27
  Provides-Extra: tools
27
28
  Requires-Dist: mypy>=1.13.0; extra == 'tools'
29
+ Requires-Dist: pytest-xdist>=3.8.0; extra == 'tools'
28
30
  Requires-Dist: pytest>=8.3.3; extra == 'tools'
29
- Requires-Dist: ruff>=0.8.0; extra == 'tools'
30
31
  Description-Content-Type: text/markdown
31
32
 
32
33
  # tempest-cli
@@ -42,7 +43,8 @@ One command for the quality gate of any Python project — `ruff` +
42
43
  `pyproject.toml` instead of in four different Makefile targets.
43
44
 
44
45
  Framework-agnostic on purpose: Django, Flask, Litestar, FastAPI, a
45
- library, a script. The only runtime dependency is `typer`.
46
+ library, a script. It brings `ruff` along, so the gate runs the moment
47
+ you install it; `typer` is the only other runtime dependency.
46
48
 
47
49
  ```bash
48
50
  uv add --dev tempest-cli
@@ -72,8 +74,8 @@ remembered to pass.
72
74
  | `tempest-cli format` | `ruff format` (writes) |
73
75
  | `tempest-cli fmt-check` | `ruff format --check` (read-only) |
74
76
  | `tempest-cli type` | `mypy` |
75
- | `tempest-cli test` | `pytest` |
76
- | `tempest-cli check` | all four, in order, stopping at the first failure |
77
+ | `tempest-cli test` | `pytest` (`--fast` spreads it across cores with pytest-xdist: `-n auto -p no:cacheprovider`, `-w N` to choose) |
78
+ | `tempest-cli check` | all four, in order, stopping at the first failure (`--fast` runs the test step in parallel) |
77
79
  | `tempest-cli pr-prompt` | builds the prompt that makes an AI write this branch's PR description |
78
80
 
79
81
  Every command takes an optional path (`tempest-cli lint src/`) and
@@ -103,6 +105,13 @@ they avoid `Any`.
103
105
  Override per run with `--strictness` / `-s`. Absent config means
104
106
  `standard`.
105
107
 
108
+ Everything that is *not* typing — silencing an untyped library, skipping
109
+ generated code, dropping a rule that does not fit your framework — is
110
+ ordinary `[tool.ruff]` / `[tool.mypy]` configuration. The recipes,
111
+ including the one that takes a legacy Django project to a green gate,
112
+ are in **[Tuning the rules](https://mauriciobenjamin700.github.io/tempest-cli/rules/)**
113
+ ([EN](https://mauriciobenjamin700.github.io/tempest-cli/en/rules/)).
114
+
106
115
  ## PR descriptions from the branch itself
107
116
 
108
117
  ```bash
@@ -141,24 +150,36 @@ cli: typer.Typer = typer.Typer(name="mytool")
141
150
  register_commands(cli)
142
151
  ```
143
152
 
144
- ## Installing the tools
145
-
146
- `tempest-cli` shells out to whatever `ruff`, `mypy` and `pytest` it
147
- finds — it does not pin them, so your project chooses the versions. The
148
- lookup runs in this order:
153
+ ## Where the tools come from
149
154
 
150
- 1. the environments of the run — the interpreter's own directory, then
151
- `$VIRTUAL_ENV`, then the nearest `.venv` up the tree;
152
- 2. `PATH`, skipping a pyenv/asdf shim that dispatches nowhere (the one
153
- that answers `pyenv: ruff: command not found`);
154
- 3. `uv run --with <tool> <tool>`, when `uv` is available.
155
+ **`ruff` comes with the package** — six of the eight commands are ruff,
156
+ so `lint`, `fix`, `format` and `fmt-check` work straight after
157
+ `uv add --dev tempest-cli`, with nothing else to install. It is a static
158
+ binary wheel with no Python dependencies of its own, so nothing of its
159
+ propagates into your resolution.
155
160
 
156
- To install the three alongside it:
161
+ `mypy` and `pytest` are deliberately left to you — a mypy bump changes
162
+ which errors your code reports, and pytest has to match your plugins and
163
+ your suite. Add them yourself, or take the bundle:
157
164
 
158
165
  ```bash
159
- uv add --dev "tempest-cli[tools]"
166
+ uv add --dev "tempest-cli[tools]" # mypy + pytest + pytest-xdist
160
167
  ```
161
168
 
169
+ `pytest-xdist` is what `test --fast` runs the suite with; its
170
+ `requires-dist` (`execnet>=2.1`, `pytest>=7.0.0`) carries no upper bound.
171
+
172
+ Whatever you pin wins over the bundled ruff. The lookup runs in this
173
+ order:
174
+
175
+ 1. the project's environment — `$VIRTUAL_ENV`, then the nearest `.venv`
176
+ up the tree;
177
+ 2. the environment `tempest-cli` itself runs from (where the bundled
178
+ ruff lives);
179
+ 3. `PATH`, skipping a pyenv/asdf shim that dispatches nowhere (the one
180
+ that answers `pyenv: ruff: command not found`);
181
+ 4. `uv run --with <tool> <tool>`, when `uv` is available.
182
+
162
183
  ## Relationship with tempest-fastapi-sdk
163
184
 
164
185
  This package was extracted from
@@ -11,7 +11,8 @@ One command for the quality gate of any Python project — `ruff` +
11
11
  `pyproject.toml` instead of in four different Makefile targets.
12
12
 
13
13
  Framework-agnostic on purpose: Django, Flask, Litestar, FastAPI, a
14
- library, a script. The only runtime dependency is `typer`.
14
+ library, a script. It brings `ruff` along, so the gate runs the moment
15
+ you install it; `typer` is the only other runtime dependency.
15
16
 
16
17
  ```bash
17
18
  uv add --dev tempest-cli
@@ -41,8 +42,8 @@ remembered to pass.
41
42
  | `tempest-cli format` | `ruff format` (writes) |
42
43
  | `tempest-cli fmt-check` | `ruff format --check` (read-only) |
43
44
  | `tempest-cli type` | `mypy` |
44
- | `tempest-cli test` | `pytest` |
45
- | `tempest-cli check` | all four, in order, stopping at the first failure |
45
+ | `tempest-cli test` | `pytest` (`--fast` spreads it across cores with pytest-xdist: `-n auto -p no:cacheprovider`, `-w N` to choose) |
46
+ | `tempest-cli check` | all four, in order, stopping at the first failure (`--fast` runs the test step in parallel) |
46
47
  | `tempest-cli pr-prompt` | builds the prompt that makes an AI write this branch's PR description |
47
48
 
48
49
  Every command takes an optional path (`tempest-cli lint src/`) and
@@ -72,6 +73,13 @@ they avoid `Any`.
72
73
  Override per run with `--strictness` / `-s`. Absent config means
73
74
  `standard`.
74
75
 
76
+ Everything that is *not* typing — silencing an untyped library, skipping
77
+ generated code, dropping a rule that does not fit your framework — is
78
+ ordinary `[tool.ruff]` / `[tool.mypy]` configuration. The recipes,
79
+ including the one that takes a legacy Django project to a green gate,
80
+ are in **[Tuning the rules](https://mauriciobenjamin700.github.io/tempest-cli/rules/)**
81
+ ([EN](https://mauriciobenjamin700.github.io/tempest-cli/en/rules/)).
82
+
75
83
  ## PR descriptions from the branch itself
76
84
 
77
85
  ```bash
@@ -110,24 +118,36 @@ cli: typer.Typer = typer.Typer(name="mytool")
110
118
  register_commands(cli)
111
119
  ```
112
120
 
113
- ## Installing the tools
114
-
115
- `tempest-cli` shells out to whatever `ruff`, `mypy` and `pytest` it
116
- finds — it does not pin them, so your project chooses the versions. The
117
- lookup runs in this order:
121
+ ## Where the tools come from
118
122
 
119
- 1. the environments of the run — the interpreter's own directory, then
120
- `$VIRTUAL_ENV`, then the nearest `.venv` up the tree;
121
- 2. `PATH`, skipping a pyenv/asdf shim that dispatches nowhere (the one
122
- that answers `pyenv: ruff: command not found`);
123
- 3. `uv run --with <tool> <tool>`, when `uv` is available.
123
+ **`ruff` comes with the package** — six of the eight commands are ruff,
124
+ so `lint`, `fix`, `format` and `fmt-check` work straight after
125
+ `uv add --dev tempest-cli`, with nothing else to install. It is a static
126
+ binary wheel with no Python dependencies of its own, so nothing of its
127
+ propagates into your resolution.
124
128
 
125
- To install the three alongside it:
129
+ `mypy` and `pytest` are deliberately left to you — a mypy bump changes
130
+ which errors your code reports, and pytest has to match your plugins and
131
+ your suite. Add them yourself, or take the bundle:
126
132
 
127
133
  ```bash
128
- uv add --dev "tempest-cli[tools]"
134
+ uv add --dev "tempest-cli[tools]" # mypy + pytest + pytest-xdist
129
135
  ```
130
136
 
137
+ `pytest-xdist` is what `test --fast` runs the suite with; its
138
+ `requires-dist` (`execnet>=2.1`, `pytest>=7.0.0`) carries no upper bound.
139
+
140
+ Whatever you pin wins over the bundled ruff. The lookup runs in this
141
+ order:
142
+
143
+ 1. the project's environment — `$VIRTUAL_ENV`, then the nearest `.venv`
144
+ up the tree;
145
+ 2. the environment `tempest-cli` itself runs from (where the bundled
146
+ ruff lives);
147
+ 3. `PATH`, skipping a pyenv/asdf shim that dispatches nowhere (the one
148
+ that answers `pyenv: ruff: command not found`);
149
+ 4. `uv run --with <tool> <tool>`, when `uv` is available.
150
+
131
151
  ## Relationship with tempest-fastapi-sdk
132
152
 
133
153
  This package was extracted from
@@ -3,6 +3,48 @@
3
3
  The full history lives in the repository's
4
4
  [`CHANGELOG.md`](https://github.com/mauriciobenjamin700/tempest-cli/blob/main/CHANGELOG.md).
5
5
 
6
+ ## [0.4.0] — 2026-09-27
7
+
8
+ ### Added
9
+
10
+ - **`test --fast` and `check --fast`: the suite in parallel.** Runs
11
+ `pytest -n <workers> -p no:cacheprovider [target]` with pytest-xdist;
12
+ `--workers` / `-w` takes what `pytest -n` takes (an integer, `auto` —
13
+ the default — or `logical`) and is a usage error without `--fast`. The
14
+ target is forwarded and pytest's exit code comes back untranslated. It
15
+ is a flag, not a subcommand, because `test fast` keeps meaning the
16
+ `fast/` folder. [Details](commands.md#the-suite-in-parallel-fast).
17
+ - **A missing pytest-xdist is a sentence, not `unrecognized arguments:
18
+ -n`.** `--fast` asks the interpreter that will run pytest whether it
19
+ can import `xdist`; when it cannot, the message names the package and
20
+ the extras (`tempest-cli[tools]`, `tempest-fastapi-sdk[tests]`) and the
21
+ exit code is 127, with no traceback. Under `check --fast` the check
22
+ comes before the first step.
23
+ - **`run_pytest` / `run_full_check` gain `fast=` and `workers=`**,
24
+ keyword-only, serial by default.
25
+
26
+ ### Changed
27
+
28
+ - **`[tools]` now carries `pytest-xdist>=3.8.0`.** No upper bound in its
29
+ `requires-dist` (`execnet>=2.1`, `pytest>=7.0.0`).
30
+
31
+ ## [0.3.0] — 2026-08-15
32
+
33
+ ### Changed
34
+
35
+ - **`ruff` now ships with the package.** It left the `[tools]` extra for
36
+ the runtime dependencies, so `uv add --dev tempest-cli` is enough for
37
+ `lint`, `fix`, `format` and `fmt-check` to run. The cost is nil: ruff
38
+ is a static binary wheel with no Python dependencies of its own, so no
39
+ bound of its reaches a consumer's resolution. `mypy` and `pytest` stay
40
+ out on purpose; `[tools]` now installs exactly those two.
41
+ - **The project's environment is searched before the CLI's own.** With
42
+ ruff bundled, the CLI's environment always has one — looking there
43
+ first would silently override a version the project pinned whenever
44
+ `tempest-cli` lives apart from it (`uv tool install`, pipx). The order
45
+ is now `$VIRTUAL_ENV` → nearest `.venv` → the CLI's environment →
46
+ `PATH` → `uv run --with`.
47
+
6
48
  ## [0.2.0] — 2026-08-15
7
49
 
8
50
  ### Added
@@ -4,6 +4,47 @@ O histórico completo vive no
4
4
  [`CHANGELOG.md`](https://github.com/mauriciobenjamin700/tempest-cli/blob/main/CHANGELOG.md)
5
5
  do repositório.
6
6
 
7
+ ## [0.4.0] — 2026-09-27
8
+
9
+ ### Adicionado
10
+
11
+ - **`test --fast` e `check --fast`: a suíte em paralelo.** Roda
12
+ `pytest -n <workers> -p no:cacheprovider [alvo]` com o pytest-xdist;
13
+ `--workers` / `-w` aceita o que o `pytest -n` aceita (inteiro, `auto` —
14
+ o padrão — ou `logical`) e é erro de uso sem `--fast`. O alvo é
15
+ repassado e o código de saída do pytest volta sem tradução. É flag, e
16
+ não subcomando, porque `test fast` continua significando a pasta
17
+ `fast/`. [Detalhes](commands.md#a-suite-em-paralelo-fast).
18
+ - **pytest-xdist ausente vira frase, não `unrecognized arguments: -n`.**
19
+ O `--fast` pergunta ao interpretador que vai rodar o pytest se ele
20
+ importa o `xdist`; faltando, a mensagem nomeia o pacote e os extras
21
+ (`tempest-cli[tools]`, `tempest-fastapi-sdk[tests]`) e a saída é 127,
22
+ sem traceback. No `check --fast` a checagem vem antes do primeiro passo.
23
+ - **`run_pytest` / `run_full_check` ganham `fast=` e `workers=`**
24
+ keyword-only, com default serial.
25
+
26
+ ### Mudado
27
+
28
+ - **O `[tools]` agora leva `pytest-xdist>=3.8.0`.** Sem teto no
29
+ `requires-dist` (`execnet>=2.1`, `pytest>=7.0.0`).
30
+
31
+ ## [0.3.0] — 2026-08-15
32
+
33
+ ### Mudado
34
+
35
+ - **O `ruff` agora vem junto com o pacote.** Saiu do extra `[tools]` e
36
+ virou dependência: `uv add --dev tempest-cli` já basta para `lint`,
37
+ `fix`, `format` e `fmt-check` rodarem. Custo zero — o ruff é binário
38
+ estático, sem dependência Python, então nenhum limite dele entra na
39
+ resolução de quem instala. `mypy` e `pytest` continuam de fora de
40
+ propósito; `[tools]` agora instala exatamente esses dois.
41
+ - **O ambiente do projeto passa a ser procurado antes do da CLI.** Com o
42
+ ruff embutido, o ambiente da CLI sempre tem um — procurar ali primeiro
43
+ sobrescreveria em silêncio a versão que o projeto fixou quando o
44
+ `tempest-cli` mora fora dele (`uv tool install`, pipx). A ordem agora é
45
+ `$VIRTUAL_ENV` → `.venv` mais próximo → ambiente da CLI → `PATH` →
46
+ `uv run --with`.
47
+
7
48
  ## [0.2.0] — 2026-08-15
8
49
 
9
50
  ### Adicionado
@@ -0,0 +1,159 @@
1
+ # Commands
2
+
3
+ Eight commands. All take an optional path and return the underlying
4
+ tool's exit code.
5
+
6
+ | Command | Runs |
7
+ | --- | --- |
8
+ | `lint` | `ruff check` |
9
+ | `fix` | `ruff check --fix` then `ruff format` |
10
+ | `format` | `ruff format` (writes) |
11
+ | `fmt-check` | `ruff format --check` (read-only) |
12
+ | `type` | `mypy` |
13
+ | `test` | `pytest` |
14
+ | `check` | the four above, in order, stopping at the first failure |
15
+ | `pr-prompt` | builds the PR-description prompt — [its own page](pr-prompt.md) |
16
+
17
+ !!! tip "`tc` is the short form"
18
+ The package installs `tempest-cli` and `tc` pointing at the same
19
+ program. The examples use the long name; `tc check`, `tc fix` and
20
+ `tc type -s strict` work exactly the same.
21
+
22
+ ## The full gate
23
+
24
+ ```bash
25
+ tempest-cli check # the whole project
26
+ tempest-cli check src/ # a single path
27
+ tempest-cli check -s strict # with raised typing strictness for this run
28
+ ```
29
+
30
+ The order is deliberate: **lint → formatting → types → tests**. What
31
+ fails fastest and is cheapest to fix comes first, and the run stops at
32
+ the first failure — there is no point running the whole suite when the
33
+ imports are unsorted.
34
+
35
+ ## Fixing what can be fixed
36
+
37
+ ```bash
38
+ tempest-cli fix # safe autofixes + formatting
39
+ tempest-cli fix --unsafe # also ruff's risky autofixes
40
+ ```
41
+
42
+ `fix` makes two passes: `ruff check --fix` (sorts and dedupes imports,
43
+ drops unused ones, normalizes quotes) and then `ruff format`
44
+ (indentation, line length, blank lines).
45
+
46
+ !!! warning "`--unsafe` can change behavior"
47
+ Ruff's "unsafe" autofixes are the ones that may alter semantics.
48
+ They are off by default. Turned them on? Read the `git diff` before
49
+ committing.
50
+
51
+ ## One at a time
52
+
53
+ ```bash
54
+ tempest-cli lint src/
55
+ tempest-cli fmt-check
56
+ tempest-cli type mypackage
57
+ tempest-cli test tests/unit
58
+ ```
59
+
60
+ `test` forwards the path to pytest as a filter; with no argument it runs
61
+ the whole suite.
62
+
63
+ ## The suite in parallel: `--fast`
64
+
65
+ A suite whose tests are already isolated (a database per test, no global
66
+ state) pays the serial time and buys nothing for it. `--fast` spreads the
67
+ suite across the cores with
68
+ [pytest-xdist](https://pytest-xdist.readthedocs.io/):
69
+
70
+ ```bash
71
+ tempest-cli test --fast # -n auto: one worker per core
72
+ tempest-cli test --fast -w 4 # four workers
73
+ tempest-cli test tests/unit --fast # the target is still forwarded
74
+ tempest-cli check --fast # the full gate, with the test step in parallel
75
+ ```
76
+
77
+ Underneath it becomes `pytest -n <workers> -p no:cacheprovider [target]`.
78
+ `-p no:cacheprovider` is there because several workers writing
79
+ `.pytest_cache` at once is a race that buys nothing — and that cache is
80
+ what `--lf` / `--ff` read, so those two remain a serial-run affair.
81
+
82
+ `--workers` (`-w`) takes what `pytest -n` takes: an integer, `auto` (the
83
+ default) or `logical`. Without `--fast` it is a usage error (exit 2)
84
+ instead of being silently ignored.
85
+
86
+ !!! info "`auto` counts physical cores when `psutil` is installed"
87
+ pytest-xdist decides: with `psutil` importable, `auto` is the number of
88
+ **physical** cores; without it, the number of logical CPUs. On a machine
89
+ with 6 cores and 12 threads, with `psutil` in the environment, `auto`
90
+ started `created: 6/6 workers`. Want the 12 threads? `-w logical` or
91
+ `-w 12`.
92
+
93
+ !!! note "Why a flag, not `tempest-cli test fast`"
94
+ `test` already takes a positional path. `test fast` keeps meaning
95
+ "run pytest on the `fast/` folder" — a subcommand by that name would
96
+ break anyone who has one.
97
+
98
+ ### Without pytest-xdist
99
+
100
+ Before running anything, the CLI asks **the very interpreter that will
101
+ run pytest** whether it can import `xdist` — not the CLI's own
102
+ interpreter, which under `uv tool install` or pipx lives in a different
103
+ environment. When it is missing, the message names what to install and
104
+ the exit code is **127**, with no traceback:
105
+
106
+ ```console
107
+ $ tempest-cli test --fast
108
+ error: --fast needs pytest-xdist, which is not installed in the environment pytest runs in (.venv/bin/pytest). Install it with 'uv add --dev pytest-xdist' — or a bundle that carries it, 'uv add --dev "tempest-cli[tools]"' or 'uv add --dev "tempest-fastapi-sdk[tests]"' — and retry, or drop --fast to run the suite serially.
109
+ $ echo $?
110
+ 127
111
+ ```
112
+
113
+ Under `check --fast` the check happens **before** the first step: there
114
+ is no point waiting for lint and mypy to finish to learn the tests will
115
+ not run.
116
+
117
+ ### A test that fails only in parallel
118
+
119
+ Parallelism exposes tests that depend on order or on an idle machine:
120
+ two tests writing the same file, the same port, a module-level global, a
121
+ fixed `sleep` waiting for something that takes longer once every core is
122
+ busy. Before treating the failure as a regression, run the test **alone
123
+ and serially**:
124
+
125
+ ```bash
126
+ tempest-cli test "tests/test_scheduler.py::test_lease_expires"
127
+ ```
128
+
129
+ - **It passes alone**: the defect is the test's isolation, not the change
130
+ under review. Fix the test (a file under `tmp_path`, a free port, wait
131
+ on a condition instead of a `sleep`).
132
+ - **It fails alone too**: it is a real regression.
133
+
134
+ ## What each returns
135
+
136
+ The exit code is the tool's own, untranslated:
137
+
138
+ ```bash
139
+ tempest-cli lint; echo "exited $?"
140
+ ```
141
+
142
+ There is exactly one code of its own: **127**, when the tool is in none
143
+ of the places the CLI looks — the run's environment, `PATH`, `uv run
144
+ --with` — and the message then names what was missing and how to install
145
+ it. The lookup order is in
146
+ [Installation](installation.md#where-ruff-mypy-and-pytest-come-from).
147
+ The same 127 comes out of `--fast` when pytest-xdist is not in pytest's
148
+ environment.
149
+
150
+ ## Recap
151
+
152
+ - `check` is lint + fmt-check + type + test, in order, stopping at the
153
+ first failure.
154
+ - `fix` is the pass that repairs; `--unsafe` only when you will review.
155
+ - `test --fast` / `check --fast` run the suite with pytest-xdist
156
+ (`-n auto`, `-w N` to choose); a test that fails only in parallel is
157
+ checked by running it alone.
158
+ - Exit codes are the tools'; 127 means a missing tool (or the
159
+ pytest-xdist `--fast` needs).