gd-tools-cli 0.5.0__tar.gz → 0.7.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 (91) hide show
  1. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/PKG-INFO +146 -66
  2. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/README.md +145 -65
  3. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/pyproject.toml +8 -3
  4. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/addons/gd-tools-coverage/coverage.gd +266 -1
  5. gd_tools_cli-0.7.0/src/gd_tools/addons/gd-tools-editor/coverage_overlay.gd +213 -0
  6. gd_tools_cli-0.7.0/src/gd_tools/addons/gd-tools-editor/dock.gd +313 -0
  7. gd_tools_cli-0.7.0/src/gd_tools/addons/gd-tools-editor/plugin.cfg +7 -0
  8. gd_tools_cli-0.7.0/src/gd_tools/addons/gd-tools-editor/plugin.gd +39 -0
  9. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/addons/gd-tools-test/gd_tools_mock.gd +50 -3
  10. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/addons/gd-tools-test/gd_tools_native_coverage.gd +108 -1
  11. gd_tools_cli-0.7.0/src/gd_tools/addons/gd-tools-test/gd_tools_snapshot_serializer.gd +153 -0
  12. gd_tools_cli-0.7.0/src/gd_tools/addons/gd-tools-test/gd_tools_snapshot_store.gd +132 -0
  13. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/addons/gd-tools-test/gd_tools_test.gd +659 -4
  14. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/addons/gd-tools-test/gd_tools_test_preflight.gd +2 -2
  15. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/addons/gd-tools-test/gd_tools_test_runner.gd +118 -8
  16. gd_tools_cli-0.7.0/src/gd_tools/atomic_io.py +78 -0
  17. gd_tools_cli-0.7.0/src/gd_tools/changes.py +117 -0
  18. gd_tools_cli-0.7.0/src/gd_tools/clean.py +269 -0
  19. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/cli.py +601 -85
  20. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/config.py +100 -74
  21. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/coverage/diff_reporter.py +2 -2
  22. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/coverage/orchestrator.py +62 -10
  23. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/coverage/plan_generator.py +319 -9
  24. gd_tools_cli-0.7.0/src/gd_tools/coverage/playtest.py +257 -0
  25. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/coverage/reporter.py +194 -16
  26. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/doctor.py +85 -190
  27. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/errors.py +30 -6
  28. gd_tools_cli-0.7.0/src/gd_tools/gh_annotations.py +36 -0
  29. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/godot.py +3 -39
  30. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/init.py +93 -341
  31. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/lint_runner.py +44 -0
  32. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/migration/reporter.py +11 -8
  33. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/native_test/artifacts.py +2 -1
  34. gd_tools_cli-0.7.0/src/gd_tools/native_test/bridge_scan.py +49 -0
  35. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/native_test/command.py +180 -35
  36. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/native_test/discovery.py +29 -16
  37. gd_tools_cli-0.7.0/src/gd_tools/native_test/import_cache.py +185 -0
  38. gd_tools_cli-0.7.0/src/gd_tools/native_test/orchestrator.py +782 -0
  39. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/native_test/preflight.py +3 -3
  40. gd_tools_cli-0.7.0/src/gd_tools/native_test/preflight_cache.py +239 -0
  41. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/native_test/protocol.py +11 -35
  42. gd_tools_cli-0.7.0/src/gd_tools/pre_commit.py +283 -0
  43. gd_tools_cli-0.7.0/src/gd_tools/schema.py +59 -0
  44. gd_tools_cli-0.7.0/src/gd_tools/test_results.py +353 -0
  45. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/version.py +4 -12
  46. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/watch/loop.py +5 -18
  47. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/watch/mapping.py +36 -1
  48. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/watch/session.py +12 -1
  49. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools_cli.egg-info/PKG-INFO +146 -66
  50. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools_cli.egg-info/SOURCES.txt +16 -4
  51. gd_tools_cli-0.5.0/src/gd_tools/addons/gd-tools-coverage/post_run_hook.gd +0 -116
  52. gd_tools_cli-0.5.0/src/gd_tools/addons/gd-tools-coverage/pre_run_hook.gd +0 -10
  53. gd_tools_cli-0.5.0/src/gd_tools/addons/gd-tools-test/gd_tools_gut_bridge.gd +0 -770
  54. gd_tools_cli-0.5.0/src/gd_tools/native_test/bridge_scan.py +0 -141
  55. gd_tools_cli-0.5.0/src/gd_tools/native_test/orchestrator.py +0 -504
  56. gd_tools_cli-0.5.0/src/gd_tools/test_runner.py +0 -175
  57. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/setup.cfg +0 -0
  58. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/__init__.py +0 -0
  59. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/__main__.py +0 -0
  60. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/addon_check.py +0 -0
  61. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/addons/__init__.py +0 -0
  62. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/addons/gd-tools-test/gd_tools_parameter_naming.gd +0 -0
  63. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/addons/gd-tools-test/gd_tools_test_context.gd +0 -0
  64. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/coverage/__init__.py +0 -0
  65. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/coverage/cobertura_reporter.py +0 -0
  66. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/coverage/html_reporter.py +0 -0
  67. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/coverage/lcov_reporter.py +0 -0
  68. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/coverage/omissions.py +0 -0
  69. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/coverage/templates/file.html +0 -0
  70. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/coverage/templates/index.html +0 -0
  71. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/coverage/terminal_reporter.py +0 -0
  72. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/file_discovery.py +0 -0
  73. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/format_runner.py +0 -0
  74. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/migration/__init__.py +0 -0
  75. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/migration/apply.py +0 -0
  76. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/migration/gutconfig.py +0 -0
  77. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/migration/rewrite.py +0 -0
  78. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/migration/scan.py +0 -0
  79. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/migration/translate.py +0 -0
  80. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/native_test/__init__.py +0 -0
  81. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/output.py +0 -0
  82. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/update_check.py +0 -0
  83. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/verbosity.py +0 -0
  84. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/watch/__init__.py +0 -0
  85. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/watch/coalescer.py +0 -0
  86. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/watch/observer.py +0 -0
  87. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools/watch/scope.py +0 -0
  88. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools_cli.egg-info/dependency_links.txt +0 -0
  89. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools_cli.egg-info/entry_points.txt +0 -0
  90. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools_cli.egg-info/requires.txt +0 -0
  91. {gd_tools_cli-0.5.0 → gd_tools_cli-0.7.0}/src/gd_tools_cli.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gd-tools-cli
3
- Version: 0.5.0
3
+ Version: 0.7.0
4
4
  Summary: A modern development workflow CLI for GDScript projects in Godot 4.5+
5
5
  Author-email: mansyar <m.ansyarafi@gmail.com>
6
6
  License: MIT
@@ -63,9 +63,9 @@ coverage for GDScript that no existing tool provides.
63
63
  Tests are written against `GdToolsTest`, a native GDScript base class that runs
64
64
  inside your Godot project, so a test can touch the real scene tree, await real
65
65
  signals, and assert on real engine objects without leaving the engine. Existing
66
- suites that `extend GutTest` run through the built-in compatibility bridge --
67
- no GUT addon required -- while projects migrate. The bridge is deprecated as of
68
- v0.5.0 and will be removed in v0.6.0.
66
+ suites that `extend GutTest` are no longer runnable -- the GUT compatibility
67
+ bridge was removed in v0.6.0; run `gd-tools migrate` to move them onto
68
+ `GdToolsTest`.
69
69
 
70
70
  One install, one config, one mental model.
71
71
 
@@ -74,10 +74,11 @@ One install, one config, one mental model.
74
74
  | Feature | Description |
75
75
  |---------|-------------|
76
76
  | **Unified workflow** | One install, one config (`gd-tools.toml`), one mental model for test, lint, format, and coverage. Consistent terminal output with colored markers and summary footers across all commands. |
77
- | **Native test runtime** | Tests extend `GdToolsTest` and run inside Godot itself. Scene and resource integration tests reach the real scene tree through an explicit context object rather than a proxy. |
78
- | **Zero-friction bootstrap** | `gd-tools init` gets a project fully set up in under a minute -- native test and coverage addons deployed, configs generated. Existing `GutTest` suites run through the built-in compatibility bridge with no addon install. |
79
- | **Coverage gap-filling** | Production-quality line and branch coverage for GDScript -- HTML, LCOV, and Cobertura reports that integrate with CI and code review tools. `# gd-tools: no cover` annotations exclude debug-only code from the numbers. |
80
- | **CI/CD friendly** | Exit codes, `--check` flags, machine-readable output (JSON, JUnit XML, LCOV, Cobertura), no interactive prompts in CI mode. |
77
+ | **Native test runtime** | Tests extend `GdToolsTest` and run inside Godot itself. Scene and resource integration tests reach the real scene tree through an explicit context object rather than a proxy. Doubles, partial doubles, and stubbing isolate collaborators; spy assertions cover calls, argument wildcards, call order, and property values. |
78
+ | **Snapshot testing** | `assert_snapshot(value)` pins rendered values -- including object property dumps and node trees -- against versioned, diffable `.snap` files. First run writes and passes; mismatches fail with a unified diff, and `--snapshot-update` accepts the new output. |
79
+ | **Zero-friction bootstrap** | `gd-tools init` gets a project fully set up in under a minute -- native test and coverage addons deployed, configs generated. |
80
+ | **Coverage gap-filling** | Production-quality line and branch coverage for GDScript -- HTML, LCOV, Cobertura, and JSON reports, plus GitHub Actions annotations that surface failures inline on pull requests. Independent line (`--min`) and branch (`--min-branch`) gates. `# gd-tools: no cover` annotations exclude debug-only code from the numbers. `coverage run` collects coverage during manual playtest sessions, not just automated tests. |
81
+ | **CI/CD friendly** | Exit codes, `--check` flags, machine-readable output (JSON, JUnit XML, LCOV, Cobertura), and GitHub Actions annotations for lint violations and coverage gates. No interactive prompts in CI mode. |
81
82
  | **Standalone compatibility** | gdlint and gdformat continue to work if invoked directly. `gd-tools` is a layer on top, not a lock-in. |
82
83
 
83
84
  ## 3. Installation
@@ -119,11 +120,11 @@ directory. The command is idempotent -- safe to re-run. If you've modified
119
120
  coverage addon files, they are automatically backed up to
120
121
  `addons/gd-tools-coverage/.backups/` before being overwritten.
121
122
 
122
- The legacy GUT runtime has been replaced by the built-in compatibility bridge:
123
- suites extending `GutTest` run on the native runtime with no GUT addon
124
- installed. The bridge is deprecated as of v0.5.0 and will be removed in
125
- v0.6.0. See the [migration guide](./docs/gut-migration.md) for the
126
- supported subset and the steps to move fully onto `GdToolsTest`.
123
+ The GUT compatibility bridge was removed in v0.6.0: suites extending `GutTest`
124
+ are no longer runnable -- `gd-tools test` rejects them with exit 2 and
125
+ migration guidance. Run `gd-tools migrate` and see the
126
+ [migration guide](./docs/gut-migration.md) for the steps to move fully onto
127
+ `GdToolsTest`.
127
128
 
128
129
  A test suite is any class extending `GdToolsTest`:
129
130
 
@@ -139,14 +140,14 @@ func test_health_starts_at_full() -> void:
139
140
  | Command | Description |
140
141
  |---------|-------------|
141
142
  | `gd-tools init` | Bootstrap a Godot project -- deploy the native test and coverage addons, generate configs. |
142
- | `gd-tools doctor` | Diagnose the development environment -- Godot, native test addon, bridge-eligible GUT suites, coverage addon, tooling. |
143
- | `gd-tools test` | Run tests with optional coverage, thresholds, and JUnit XML output. Suites extending `GdToolsTest` and `GutTest` are detected and routed automatically (`GutTest` suites run through the compatibility bridge). Accepts optional path arguments to override configured test directories. `--watch` re-runs affected suites on `.gd` file changes. Every run publishes a machine-readable artifact index under `.gd-tools/artifacts/<run_id>/`. |
143
+ | `gd-tools doctor` | Diagnose the development environment -- Godot, native test addon, coverage addon, tooling; reports legacy GUT artifacts as migration advice. |
144
+ | `gd-tools test` | Run tests with optional coverage, thresholds, and JUnit XML output. Suites must extend `GdToolsTest`; `GutTest` suites are rejected with exit 2 and migration guidance. Accepts optional path arguments to override configured test directories. `--parallel N` runs suites through a bounded worker pool. `--changed` runs only the suites mapped from git-changed files. `--watch` re-runs affected suites on `.gd` file changes. `--durations N` reports the N slowest tests after the run. Every run publishes a machine-readable artifact index under `.gd-tools/artifacts/<run_id>/`. |
144
145
  | `gd-tools migrate` | Guided GUT-to-native migration. Default: read-only report with unsupported-construct inventory and proposed base-class rewrites. `--apply` renames clean suites to `GdToolsTest` and translates `.gutconfig.json` into `gd-tools.toml` (merge, never clobber). `--config-only` translates config only. |
145
- | `gd-tools lint` | Lint GDScript files using gdlint with text or JSON output. Accepts one or more file or directory paths. |
146
+ | `gd-tools lint` | Lint GDScript files using gdlint with text, JSON, or GitHub Actions annotation output. Accepts one or more file or directory paths. |
146
147
  | `gd-tools format` | Format GDScript files using gdformat with check and diff modes. Accepts one or more file or directory paths. |
147
- | `gd-tools coverage` | Coverage subcommands -- `report`, `merge`, `show`, `save-baseline`, and `diff` (baseline comparison for CI regression gates). |
148
- | `gd-tools config` | Configuration management -- `show` (display resolved config), `validate` (check config validity). |
149
- | `gd-tools version` | Display versions of all gd-tools components (gd-tools, Godot, gdtoolkit, Python, and GUT when installed) in a table or JSON. |
148
+ | `gd-tools coverage` | Coverage subcommands -- `report`, `merge`, `show`, `save-baseline`, `diff` (baseline comparison for CI regression gates), and `run` (collect coverage during a manual playtest session). |
149
+ | `gd-tools config` | Configuration management -- `show` (display resolved config), `validate` (check config validity), `schema` (print or write the JSON Schema for `gd-tools.toml`). |
150
+ | `gd-tools version` | Display versions of all gd-tools components (gd-tools, Godot, gdtoolkit, Python) in a table or JSON. |
150
151
  | `gd-tools completion` | Generate shell completion scripts for bash, zsh, fish, or PowerShell. |
151
152
 
152
153
  ### Selecting and Filtering Tests
@@ -157,10 +158,47 @@ gd-tools test --suite PlayerTests # one suite, by class name
157
158
  gd-tools test --test test_takes_damage # one test method
158
159
  gd-tools test --tag smoke # suites with that class-level tag
159
160
  gd-tools test --test-timeout 30 # per-test timeout, in seconds
161
+ gd-tools test --parallel 4 # run suites with 4 concurrent workers
162
+ gd-tools test --durations 10 # report the 10 slowest tests
163
+ gd-tools test --changed # only suites mapped from git-changed files
164
+ gd-tools test --changed --base main # PR/CI mode: diff from merge-base with main
160
165
  ```
161
166
 
162
167
  `--tag` is repeatable, and `--test-timeout` (per test) is separate from
163
- `--timeout` (per suite process).
168
+ `--timeout` (per suite process). `--parallel` dispatches suites to a bounded
169
+ worker pool (1-32 workers; bare `--parallel` means 4) while keeping results,
170
+ JUnit XML, and merged coverage identical to a sequential run. Persist the
171
+ choice with `parallel = 4` under `[test]` in `gd-tools.toml`.
172
+
173
+ `--durations N` prints a "Slowest Tests" table after the run, sorted
174
+ slowest-first, covering pass, fail, and skip outcomes. Bare `--durations`
175
+ means 10; `--durations 0` lists every executed test (pytest parity). Persist
176
+ the choice with `durations = 10` under `[test]` in `gd-tools.toml`; the flag
177
+ overrides the config for one invocation. The table renders identically under
178
+ `--watch` re-runs and `--parallel` runs.
179
+
180
+ `--changed` selects suites from git instead of running everything: uncommitted
181
+ changes (staged, unstaged, and untracked) map to suites by the same
182
+ file→suite convention as `--watch` — `src/enemy.gd` selects
183
+ `tests/test_enemy.gd` or `tests/enemy_test.gd`. A change that maps to no
184
+ suite (e.g. `project.godot` or a scene file) falls back to the full suite
185
+ with an explicit notice, so the selection is safe for CI. The summary line
186
+ reports how many suites were selected; per-file mapping detail prints under
187
+ `--verbose`. Add `--base <ref>` to diff committed changes from
188
+ `merge-base(<ref>, HEAD)` instead of the working tree — the form to use on
189
+ pull-request CI. `--changed` composes with `--parallel`, `--coverage`, and
190
+ the `--suite`/`--test`/`--tag` filters (the active filters bound the
191
+ mapping domain); an empty change set exits 0 without launching Godot.
192
+
193
+ Repeat runs are faster: the `godot --headless --import` step is cached under
194
+ `.gd-tools/native/import-cache/` and skipped when `project.godot`, any
195
+ project source/resource file (scripts, scenes, import sidecars, addons), or
196
+ the Godot version is unchanged. The integration preflight is likewise cached
197
+ under `.gd-tools/native/preflight-cache/` and skipped when the suites, test
198
+ files, `project.godot`, Godot version, and bundled addons are unchanged. Cache
199
+ hit/miss reasons are reported under `--verbose`; `--no-cache` bypasses the
200
+ import, preflight, and coverage plan caches, and `gd-tools clean --cache`
201
+ removes the cache directory.
164
202
 
165
203
  Each run writes a machine-readable artifact index under
166
204
  `.gd-tools/artifacts/<run_id>/`, listing the manifest, result, event stream,
@@ -182,49 +220,33 @@ suite by convention — `src/enemy.gd` re-runs `tests/test_enemy.gd` or
182
220
  `tests/enemy_test.gd` — with a full-suite fallback (announced explicitly)
183
221
  when no suite matches. Rapid successive saves are coalesced into a single
184
222
  re-run, and a save during a running suite queues exactly one follow-up run.
223
+ The same file→suite mapping powers the non-interactive `gd-tools test
224
+ --changed` selection (see [Selecting and Filtering
225
+ Tests](#selecting-and-filtering-tests)).
185
226
 
186
227
  - Native runtime only: the removed legacy GUT runtime (`--runtime gut`) is
187
- rejected with exit 2; `GutTest` suites run through the compatibility bridge.
228
+ rejected with exit 2; `GutTest` suites must be migrated (`gd-tools migrate`).
188
229
  - Interactive only: `--watch` combined with `CI=true` exits 2.
189
230
  - The terminal is cleared between runs; the banner shows how many files are
190
- watched, and `Ctrl+C` always exits 0.
231
+ watched. While idle, `Ctrl+C` exits 0; interrupting an in-flight run kills
232
+ its Godot processes and exits 130.
191
233
  - Positional path arguments are not supported with `--watch`; the watched
192
234
  scope is the project root minus standard excludes (`.godot/`, `.gd-tools/`,
193
235
  `.git/`, and the gd-tools addons).
194
236
 
195
- ### Native Runtime vs. GUT Compatibility Bridge
196
-
197
- The native runtime is the default and the forward path. Suites extending
198
- `GutTest` run through the built-in compatibility bridge on the same native
199
- runner; the bridge is deprecated as of v0.5.0 and will be removed in v0.6.0.
200
-
201
- | Capability | Native runtime (`GdToolsTest`) | Bridge (`GutTest`) |
202
- |------------|----------------|--------------|
203
- | Base class | `GdToolsTest` extends `Node` | `GutTest`, provided by gd-tools (no GUT addon) |
204
- | Discovery | `test_*` methods, by directory or exact file selector | Same; routed automatically per file |
205
- | Lifecycle hooks | `before_all`, `after_all`, `before_each`, `after_each` | Same, plus `prerun_setup` and `postrun_teardown` |
206
- | Assertions | Full native assertion set plus `fail()`, `skip_test()`, `pending_test()` | Documented GUT core subset -- unsupported constructs fail at preflight |
207
- | Async waits | `wait_process_frame`, `wait_physics_frames`, `wait_seconds`, `wait_for_signal(signal, timeout)` | GUT helper family, incl. `wait_until`, `wait_while`, `yield_*` |
208
- | Tags | Class-level tags, filtered with `--tag` | Same |
209
- | Test selectors | `--suite`, `--test`, `--test-timeout` | Same |
210
- | Scene and resource integration | `const INTEGRATION` plus `GdToolsTestContext` for scene root, node lookup, named resources, and bounded signal waits | Not wired into the bridge shim |
211
- | Retries | Configurable per test (`[test].retries`) | Same |
212
- | Line and branch coverage | Yes | Yes |
213
- | JUnit XML output | Yes | Yes |
214
- | Mocking and stubbing | `double()`, `partial_double()`, `stub()` (`.to_return`/`.to_call_super`), `assert_called*` family | Same -- inherited from `GdToolsTest` with identical semantics |
215
- | Parameterized tests | `parameterize()` in `before_all`, values injected via `use_parameters` | Not supported -- preflight rejects `parameterize()` |
216
- | Skipping a test at runtime | `skip_test()` and `pending_test()` | Yes |
217
- | Parallel execution | Not yet -- suites run sequentially | Same |
218
- | Editor plugin | Not yet | Not applicable |
219
-
220
- **Known limitations.** Parameterized tests are native-only -- the bridge
221
- deliberately refuses `parameterize()` at preflight rather than mis-running
222
- them, so such suites must migrate to `GdToolsTest`. Suites run sequentially;
223
- parallel execution is planned but not yet available. The bridge itself is
224
- deprecated as of v0.5.0 and will be removed in v0.6.0. See the
225
- [migration guide](./docs/gut-migration.md) for the bridge's supported subset,
226
- [User Guide](./docs/USER_GUIDE.md#34-test) for the full flag reference, and
227
- [Roadmap](./docs/ROADMAP.md#8-temporary-native-test-runtime-migration-roadmap)
237
+ ### Migrating Legacy GUT Suites
238
+
239
+ The GUT compatibility bridge was removed in v0.6.0; the native runtime
240
+ (`GdToolsTest`) is the only supported runtime. Suites extending `GutTest` are
241
+ rejected by `gd-tools test` with exit 2 and migration guidance, and
242
+ `--runtime gut` is rejected the same way. Run `gd-tools migrate` and see the
243
+ [migration guide](./docs/gut-migration.md) to move legacy suites onto the
244
+ native runtime.
245
+
246
+ **Known limitations.** Parallel execution is opt-in and off by default
247
+ (`--parallel N` / `[test].parallel`); suites run sequentially without it. See
248
+ the [User Guide](./docs/USER_GUIDE.md#34-test) for the full flag reference and
249
+ [Roadmap](./docs/ROADMAP.md#native-runtime-transition-completed-foundation)
228
250
  for what is planned.
229
251
 
230
252
  ### Verbosity Control
@@ -306,7 +328,41 @@ eval "$(gd-tools)"
306
328
  See the [User Guide](./docs/USER_GUIDE.md) for detailed per-shell
307
329
  instructions.
308
330
 
309
- ## 7. Configuration
331
+ ## 7. Pre-commit Hooks
332
+
333
+ Wire gd-tools into the [pre-commit](https://pre-commit.com) framework so
334
+ every commit runs your format check, lint, and (optionally) your test suite:
335
+
336
+ ```bash
337
+ gd-tools install-hooks
338
+ ```
339
+
340
+ The command generates `.pre-commit-hooks.yaml` and merges a `repos: local:`
341
+ entry into `.pre-commit-config.yaml`. Existing hooks — including your own —
342
+ are preserved; re-runs update only the gd-tools entries in place.
343
+
344
+ Interactive by default: confirm each hook (`format`, `lint`, `test`). For
345
+ scripted or CI use, pass flags instead:
346
+
347
+ ```bash
348
+ gd-tools install-hooks --non-interactive # format + lint (defaults)
349
+ gd-tools install-hooks --all # format + lint + test
350
+ gd-tools install-hooks --hooks format,lint # explicit selection
351
+ ```
352
+
353
+ | Flag | Behavior |
354
+ |---|---|
355
+ | `--all` | Enable every hook (format, lint, test). |
356
+ | `--hooks HOOKS` | Comma-separated selection, e.g. `--hooks format,lint`. |
357
+ | `--non-interactive` | Never prompt; use defaults or explicit flags. |
358
+
359
+ Exit codes follow the gd-tools convention: `0` installed, `1` nothing to do,
360
+ `2` config/environment error.
361
+
362
+ See the [User Guide](./docs/USER_GUIDE.md#8-pre-commit-hooks) for the
363
+ generated file contents and per-hook details.
364
+
365
+ ## 8. Configuration
310
366
 
311
367
  `gd-tools` uses a single `gd-tools.toml` file as the source of truth for
312
368
  all tool configuration. `gd-tools init` generates this file with sensible
@@ -320,10 +376,10 @@ binary = "" # Optional -- auto-detected if unset
320
376
  test_dirs = ["test", "tests"]
321
377
  prefix = "test_"
322
378
  suffix = ".gd"
323
- gutconfig = ".gutconfig.json" # legacy; not read by the native runtime or the bridge
324
379
  runtime = "native" # native (default); "gut" is no longer a runnable runtime
325
380
  timeout_seconds = 5.0 # default per-test timeout for async native tests
326
381
  retries = 0 # opt-in retries per native test
382
+ # parallel = 4 # opt-in parallel suite execution (1-32; unset runs sequentially)
327
383
  tags = [] # native suite tag filters
328
384
 
329
385
  [lint]
@@ -341,10 +397,36 @@ exclude = ["addons", ".godot", ".gd-tools", ".git"]
341
397
  test_dirs = ["test", "tests"]
342
398
  ```
343
399
 
400
+ ### Editor Autocomplete & Validation
401
+
402
+ `gd-tools` publishes a JSON Schema for `gd-tools.toml` at
403
+ [`docs/gd-tools.schema.json`](./docs/gd-tools.schema.json). Add a
404
+ `"$schema"` key to your config to enable autocomplete and inline
405
+ validation in editors that support TOML schemas:
406
+
407
+ ```toml
408
+ "$schema" = "https://raw.githubusercontent.com/mansyar/gd-tools/main/docs/gd-tools.schema.json"
409
+ ```
410
+
411
+ The key is accepted and ignored by the CLI — it carries no runtime
412
+ meaning.
413
+
414
+ - **VS Code** (with [Even Better TOML](https://marketplace.visualstudio.com/items?itemName=tamasfe.even-better-toml)):
415
+ the `"$schema"` key above is picked up automatically. Alternatively,
416
+ associate the schema by filename in your settings:
417
+ `"even-better-toml.schema.associations": {"gd-tools.toml": "https://raw.githubusercontent.com/mansyar/gd-tools/main/docs/gd-tools.schema.json"}`
418
+ - **taplo** (CLI / LSP): the `"$schema"` key works out of the box, or
419
+ add a `schema` entry to your `taplo.toml` pointing at the URL above.
420
+
421
+ The schema is regenerated with
422
+ `gd-tools config schema --output docs/gd-tools.schema.json`;
423
+ a unit test keeps the checked-in snapshot in sync with the installed
424
+ version's config model.
425
+
344
426
  See the [User Guide](./docs/USER_GUIDE.md) for a full configuration reference
345
427
  with all keys, defaults, and examples.
346
428
 
347
- ## 8. Documentation
429
+ ## 9. Documentation
348
430
 
349
431
  | Document | Description |
350
432
  |----------|-------------|
@@ -355,7 +437,7 @@ with all keys, defaults, and examples.
355
437
  | [Roadmap](./docs/ROADMAP.md) | Release phases and milestones. |
356
438
  | [Testing Strategy](./docs/TESTING_STRATEGY.md) | Test pyramid, coverage targets, and CI integration. |
357
439
 
358
- ## 9. Development
440
+ ## 10. Development
359
441
 
360
442
  ```bash
361
443
  # Clone and install in editable mode with dev dependencies
@@ -385,20 +467,18 @@ See [Testing Strategy](./docs/TESTING_STRATEGY.md) for the full testing
385
467
  guide and [Contributing Guide](./docs/CONTRIBUTING.md) for development
386
468
  setup details.
387
469
 
388
- ## 10. License
470
+ ## 11. License
389
471
 
390
472
  MIT
391
473
 
392
- ## 11. Acknowledgements
474
+ ## 12. Acknowledgements
393
475
 
394
- `gd-tools` stands on the shoulders of two excellent community tools. It
395
- wraps them; it does not replace them. Full credit to their authors for the
396
- hard parts.
476
+ `gd-tools` stands on the shoulders of excellent community tools, past and
477
+ present. Full credit to their authors for the hard parts.
397
478
 
398
479
  - **[GUT (Godot Unit Test)](https://github.com/bitwes/Gut)** by
399
480
  [bitwes](https://github.com/bitwes): the GDScript test framework whose
400
- core API the built-in compatibility bridge reproduces while projects
401
- migrate to the native runtime.
481
+ core API informed the native runtime's assertion surface.
402
482
  - **[gdtoolkit](https://github.com/Scony/godot-gdscript-toolkit)** by
403
483
  [Scony](https://github.com/Scony): provides `gdlint` and `gdformat`, which
404
484
  `gd-tools lint` and `gd-tools format` wrap.