tasktree 0.0.4__tar.gz → 0.0.6__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 (45) hide show
  1. {tasktree-0.0.4 → tasktree-0.0.6}/CLAUDE.md +9 -8
  2. {tasktree-0.0.4 → tasktree-0.0.6}/PKG-INFO +198 -111
  3. {tasktree-0.0.4 → tasktree-0.0.6}/README.md +197 -110
  4. tasktree-0.0.6/example/tasktree.yaml +16 -0
  5. {tasktree-0.0.4 → tasktree-0.0.6}/pyproject.toml +1 -1
  6. {tasktree-0.0.4 → tasktree-0.0.6}/requirements/implemented/shell-environment-requirements.md +37 -36
  7. tasktree-0.0.6/schema/README.md +118 -0
  8. tasktree-0.0.6/schema/tasktree-schema.json +163 -0
  9. tasktree-0.0.6/schema/vscode-settings-snippet.json +10 -0
  10. {tasktree-0.0.4 → tasktree-0.0.6}/src/tasktree/cli.py +85 -49
  11. {tasktree-0.0.4 → tasktree-0.0.6}/src/tasktree/parser.py +85 -14
  12. {tasktree-0.0.4 → tasktree-0.0.6}/tasktree.yaml +2 -0
  13. {tasktree-0.0.4 → tasktree-0.0.6}/tests/integration/test_clean_state.py +19 -15
  14. {tasktree-0.0.4 → tasktree-0.0.6}/tests/integration/test_cli_options.py +455 -81
  15. {tasktree-0.0.4 → tasktree-0.0.6}/tests/integration/test_dependency_execution.py +43 -40
  16. {tasktree-0.0.4 → tasktree-0.0.6}/tests/integration/test_end_to_end.py +8 -6
  17. {tasktree-0.0.4 → tasktree-0.0.6}/tests/integration/test_input_detection.py +15 -12
  18. {tasktree-0.0.4 → tasktree-0.0.6}/tests/integration/test_nested_imports.py +65 -55
  19. {tasktree-0.0.4 → tasktree-0.0.6}/tests/integration/test_state_persistence.py +14 -11
  20. {tasktree-0.0.4 → tasktree-0.0.6}/tests/integration/test_working_directory.py +51 -8
  21. {tasktree-0.0.4 → tasktree-0.0.6}/tests/unit/test_executor.py +13 -9
  22. {tasktree-0.0.4 → tasktree-0.0.6}/tests/unit/test_parser.py +397 -167
  23. tasktree-0.0.4/example/tasktree.yaml +0 -15
  24. {tasktree-0.0.4 → tasktree-0.0.6}/.github/workflows/release.yml +0 -0
  25. {tasktree-0.0.4 → tasktree-0.0.6}/.github/workflows/test.yml +0 -0
  26. {tasktree-0.0.4 → tasktree-0.0.6}/.gitignore +0 -0
  27. {tasktree-0.0.4 → tasktree-0.0.6}/.python-version +0 -0
  28. {tasktree-0.0.4 → tasktree-0.0.6}/example/source.txt +0 -0
  29. {tasktree-0.0.4 → tasktree-0.0.6}/requirements/future/docker-task-environments.md +0 -0
  30. {tasktree-0.0.4 → tasktree-0.0.6}/src/__init__.py +0 -0
  31. {tasktree-0.0.4 → tasktree-0.0.6}/src/tasktree/__init__.py +0 -0
  32. {tasktree-0.0.4 → tasktree-0.0.6}/src/tasktree/executor.py +0 -0
  33. {tasktree-0.0.4 → tasktree-0.0.6}/src/tasktree/graph.py +0 -0
  34. {tasktree-0.0.4 → tasktree-0.0.6}/src/tasktree/hasher.py +0 -0
  35. {tasktree-0.0.4 → tasktree-0.0.6}/src/tasktree/state.py +0 -0
  36. {tasktree-0.0.4 → tasktree-0.0.6}/src/tasktree/tasks.py +0 -0
  37. {tasktree-0.0.4 → tasktree-0.0.6}/src/tasktree/types.py +0 -0
  38. {tasktree-0.0.4 → tasktree-0.0.6}/tests/integration/test_missing_outputs.py +0 -0
  39. {tasktree-0.0.4 → tasktree-0.0.6}/tests/unit/test_cli.py +0 -0
  40. {tasktree-0.0.4 → tasktree-0.0.6}/tests/unit/test_graph.py +0 -0
  41. {tasktree-0.0.4 → tasktree-0.0.6}/tests/unit/test_hasher.py +0 -0
  42. {tasktree-0.0.4 → tasktree-0.0.6}/tests/unit/test_state.py +0 -0
  43. {tasktree-0.0.4 → tasktree-0.0.6}/tests/unit/test_tasks.py +0 -0
  44. {tasktree-0.0.4 → tasktree-0.0.6}/tests/unit/test_types.py +0 -0
  45. {tasktree-0.0.4 → tasktree-0.0.6}/uv.lock +0 -0
@@ -58,12 +58,13 @@ The project uses Python's built-in `unittest` framework with mocking via `unitte
58
58
 
59
59
  Tasks are defined in YAML with the following structure:
60
60
  ```yaml
61
- task-name:
62
- desc: Description (optional)
63
- deps: [dependency-tasks]
64
- inputs: [glob-patterns]
65
- outputs: [glob-patterns]
66
- working_dir: execution-directory
67
- args: [typed-parameters]
68
- cmd: shell-command
61
+ tasks:
62
+ task-name:
63
+ desc: Description (optional)
64
+ deps: [dependency-tasks]
65
+ inputs: [glob-patterns]
66
+ outputs: [glob-patterns]
67
+ working_dir: execution-directory
68
+ args: [typed-parameters]
69
+ cmd: shell-command
69
70
  ```
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tasktree
3
- Version: 0.0.4
3
+ Version: 0.0.6
4
4
  Summary: A task automation tool with incremental execution
5
5
  Requires-Python: >=3.11
6
6
  Requires-Dist: click>=8.1.0
@@ -70,33 +70,34 @@ Is this just whining and moaning? Should we just man up and revel in our own abi
70
70
 
71
71
  ... No. That's **a dumb idea**.
72
72
 
73
- Task Tree allows you to pile all the knowledge of **what** to run, **when** to run it, **where** to run it and **how** to run it into a single, readable place. Then you can delete all the scripts that no-one knows how to use and all the readme docs that lie to the few people that actually waste their time reading them.
73
+ Task Tree allows you to pile all the knowledge of **what** to run, **when** to run it, **where** to run it and **how** to run it into a single, readable place. Then you can delete all the scripts that no-one knows how to use and all the readme docs that lie to the few people that actually waste their time reading them.
74
74
 
75
75
  The tasks you need to perform to deliver your project become summarised in an executable file that looks like:
76
76
  ```yaml
77
- build:
78
- desc: Compile stuff
79
- outputs: [target/release/bin]
80
- cmd: cargo build --release
81
-
82
- package:
83
- desc: build installers
84
- deps: [build]
85
- outputs: [awesome.deb]
86
- cmd: |
87
- for bin in target/release/*; do
88
- if [[ -x "$bin" && ! -d "$bin" ]]; then
89
- install -Dm755 "$bin" "debian/awesome/usr/bin/$(basename "$bin")"
90
- fi
91
- done
92
-
93
- dpkg-buildpackage -us -uc
94
-
95
- test:
96
- desc: Run tests
97
- deps: [package]
98
- inputs: [tests/**/*.py]
99
- cmd: PYTHONPATH=src python3 -m pytest tests/ -v
77
+ tasks:
78
+ build:
79
+ desc: Compile stuff
80
+ outputs: [target/release/bin]
81
+ cmd: cargo build --release
82
+
83
+ package:
84
+ desc: build installers
85
+ deps: [build]
86
+ outputs: [awesome.deb]
87
+ cmd: |
88
+ for bin in target/release/*; do
89
+ if [[ -x "$bin" && ! -d "$bin" ]]; then
90
+ install -Dm755 "$bin" "debian/awesome/usr/bin/$(basename "$bin")"
91
+ fi
92
+ done
93
+
94
+ dpkg-buildpackage -us -uc
95
+
96
+ test:
97
+ desc: Run tests
98
+ deps: [package]
99
+ inputs: [tests/**/*.py]
100
+ cmd: PYTHONPATH=src python3 -m pytest tests/ -v
100
101
  ```
101
102
 
102
103
  If you want to run the tests then:
@@ -107,6 +108,52 @@ Boom! Done. `build` will always run, because there's no sensible way to know wha
107
108
 
108
109
  This is a toy example, but you can image how it plays out on a more complex project.
109
110
 
111
+ ## Migrating from v1.x to v2.0
112
+
113
+ Version 2.0 requires all task definitions to be under a top-level `tasks:` key.
114
+
115
+ ### Quick Migration
116
+
117
+ Wrap your existing tasks in a `tasks:` block:
118
+
119
+ ```yaml
120
+ # Before (v1.x)
121
+ build:
122
+ cmd: cargo build
123
+
124
+ # After (v2.0)
125
+ tasks:
126
+ build:
127
+ cmd: cargo build
128
+ ```
129
+
130
+ ### Why This Change?
131
+
132
+ 1. **Clearer structure**: Explicit separation of tasks from configuration
133
+ 2. **No naming conflicts**: You can now create tasks named "imports" or "environments"
134
+ 3. **Better error messages**: More helpful validation errors
135
+ 4. **Consistency**: All recipe files use the same format
136
+
137
+ ### Error Messages
138
+
139
+ If you forget to update, you'll see a clear error:
140
+
141
+ ```
142
+ Invalid recipe format in tasktree.yaml
143
+
144
+ Task definitions must be under a top-level "tasks:" key.
145
+
146
+ Found these keys at root level: build, test
147
+
148
+ Did you mean:
149
+
150
+ tasks:
151
+ build:
152
+ cmd: ...
153
+ test:
154
+ cmd: ...
155
+ ```
156
+
110
157
  ## Installation
111
158
 
112
159
  ### From PyPI (Recommended)
@@ -141,20 +188,52 @@ cd tasktree
141
188
  pipx install .
142
189
  ```
143
190
 
191
+ ## Editor Support
192
+
193
+ Task Tree includes a [JSON Schema](schema/tasktree-schema.json) that provides autocomplete, validation, and documentation in modern editors.
194
+
195
+ ### VS Code
196
+
197
+ Install the [YAML extension](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml), then add to your workspace `.vscode/settings.json`:
198
+
199
+ ```json
200
+ {
201
+ "yaml.schemas": {
202
+ "https://raw.githubusercontent.com/kevinchannon/tasktree/main/schema/tasktree-schema.json": [
203
+ "tasktree.yaml",
204
+ "tt.yaml"
205
+ ]
206
+ }
207
+ }
208
+ ```
209
+
210
+ Or add a comment at the top of your `tasktree.yaml`:
211
+
212
+ ```yaml
213
+ # yaml-language-server: $schema=https://raw.githubusercontent.com/kevinchannon/tasktree/main/schema/tasktree-schema.json
214
+
215
+ tasks:
216
+ build:
217
+ cmd: cargo build
218
+ ```
219
+
220
+ See [schema/README.md](schema/README.md) for IntelliJ/PyCharm and command-line validation.
221
+
144
222
  ## Quick Start
145
223
 
146
224
  Create a `tasktree.yaml` (or `tt.yaml`) in your project:
147
225
 
148
226
  ```yaml
149
- build:
150
- desc: Compile the application
151
- outputs: [target/release/bin]
152
- cmd: cargo build --release
227
+ tasks:
228
+ build:
229
+ desc: Compile the application
230
+ outputs: [target/release/bin]
231
+ cmd: cargo build --release
153
232
 
154
- test:
155
- desc: Run tests
156
- deps: [build]
157
- cmd: cargo test
233
+ test:
234
+ desc: Run tests
235
+ deps: [build]
236
+ cmd: cargo test
158
237
  ```
159
238
 
160
239
  Run tasks:
@@ -185,15 +264,16 @@ Task Tree only runs tasks when necessary. A task executes if:
185
264
  Tasks automatically inherit inputs from dependencies, eliminating redundant declarations:
186
265
 
187
266
  ```yaml
188
- build:
189
- outputs: [dist/app]
190
- cmd: go build -o dist/app
191
-
192
- package:
193
- deps: [build]
194
- outputs: [dist/app.tar.gz]
195
- cmd: tar czf dist/app.tar.gz dist/app
196
- # Automatically tracks dist/app as an input
267
+ tasks:
268
+ build:
269
+ outputs: [dist/app]
270
+ cmd: go build -o dist/app
271
+
272
+ package:
273
+ deps: [build]
274
+ outputs: [dist/app.tar.gz]
275
+ cmd: tar czf dist/app.tar.gz dist/app
276
+ # Automatically tracks dist/app as an input
197
277
  ```
198
278
 
199
279
  ### Single State File
@@ -205,15 +285,16 @@ All state lives in `.tasktree-state` at your project root. Stale entries are aut
205
285
  ### Basic Structure
206
286
 
207
287
  ```yaml
208
- task-name:
209
- desc: Human-readable description (optional)
210
- deps: [other-task] # Task dependencies
211
- inputs: [src/**/*.go] # Explicit input files (glob patterns)
212
- outputs: [dist/binary] # Output files (glob patterns)
213
- working_dir: subproject/ # Execution directory (default: project root)
214
- env: bash-strict # Execution environment (optional)
215
- args: [param1, param2:path=default] # Task parameters
216
- cmd: go build -o dist/binary # Command to execute
288
+ tasks:
289
+ task-name:
290
+ desc: Human-readable description (optional)
291
+ deps: [other-task] # Task dependencies
292
+ inputs: [src/**/*.go] # Explicit input files (glob patterns)
293
+ outputs: [dist/binary] # Output files (glob patterns)
294
+ working_dir: subproject/ # Execution directory (default: project root)
295
+ env: bash-strict # Execution environment (optional)
296
+ args: [param1, param2:path=default] # Task parameters
297
+ cmd: go build -o dist/binary # Command to execute
217
298
  ```
218
299
 
219
300
  ### Commands
@@ -221,18 +302,20 @@ task-name:
221
302
  **Single-line commands** are executed directly via the configured shell:
222
303
 
223
304
  ```yaml
224
- build:
225
- cmd: cargo build --release
305
+ tasks:
306
+ build:
307
+ cmd: cargo build --release
226
308
  ```
227
309
 
228
310
  **Multi-line commands** are written to temporary script files for proper execution:
229
311
 
230
312
  ```yaml
231
- deploy:
232
- cmd: |
233
- mkdir -p dist
234
- cp build/* dist/
235
- rsync -av dist/ server:/opt/app/
313
+ tasks:
314
+ deploy:
315
+ cmd: |
316
+ mkdir -p dist
317
+ cp build/* dist/
318
+ rsync -av dist/ server:/opt/app/
236
319
  ```
237
320
 
238
321
  Multi-line commands preserve shell syntax (line continuations, heredocs, etc.) and support shebangs on Unix/macOS.
@@ -240,12 +323,13 @@ Multi-line commands preserve shell syntax (line continuations, heredocs, etc.) a
240
323
  Or use folded blocks for long single-line commands:
241
324
 
242
325
  ```yaml
243
- compile:
244
- cmd: >
245
- gcc -o bin/app
246
- src/*.c
247
- -I include
248
- -L lib -lm
326
+ tasks:
327
+ compile:
328
+ cmd: >
329
+ gcc -o bin/app
330
+ src/*.c
331
+ -I include
332
+ -L lib -lm
249
333
  ```
250
334
 
251
335
  ### Execution Environments
@@ -305,12 +389,13 @@ tasks:
305
389
  Tasks can accept arguments with optional defaults:
306
390
 
307
391
  ```yaml
308
- deploy:
309
- args: [environment, region=eu-west-1]
310
- deps: [build]
311
- cmd: |
312
- aws s3 cp dist/app.zip s3://{{environment}}-{{region}}/
313
- aws lambda update-function-code --function-name app-{{environment}}
392
+ tasks:
393
+ deploy:
394
+ args: [environment, region=eu-west-1]
395
+ deps: [build]
396
+ cmd: |
397
+ aws s3 cp dist/app.zip s3://{{environment}}-{{region}}/
398
+ aws lambda update-function-code --function-name app-{{environment}}
314
399
  ```
315
400
 
316
401
  Invoke with: `tt deploy production` or `tt deploy staging us-east-1` or `tt deploy staging region=us-east-1`.
@@ -337,18 +422,19 @@ Split task definitions across multiple files for better organisation:
337
422
 
338
423
  ```yaml
339
424
  # tasktree.yaml
340
- import:
425
+ imports:
341
426
  - file: build/tasks.yml
342
427
  as: build
343
428
  - file: deploy/tasks.yml
344
429
  as: deploy
345
430
 
346
- test:
347
- deps: [build.compile, build.test-compile]
348
- cmd: ./run-tests.sh
431
+ tasks:
432
+ test:
433
+ deps: [build.compile, build.test-compile]
434
+ cmd: ./run-tests.sh
349
435
 
350
- ci:
351
- deps: [build.all, test, deploy.staging]
436
+ ci:
437
+ deps: [build.all, test, deploy.staging]
352
438
  ```
353
439
 
354
440
  Imported tasks are namespaced and can be referenced as dependencies. Each imported file is self-contained—it cannot depend on tasks in the importing file.
@@ -466,41 +552,42 @@ imports:
466
552
  - file: common/docker.yml
467
553
  as: docker
468
554
 
469
- compile:
470
- desc: Build application binaries
471
- outputs: [target/release/app]
472
- cmd: cargo build --release
473
-
474
- test-unit:
475
- desc: Run unit tests
476
- deps: [compile]
477
- cmd: cargo test
478
-
479
- package:
480
- desc: Create distribution archive
481
- deps: [compile]
482
- outputs: [dist/app-{{version}}.tar.gz]
483
- args: [version]
484
- cmd: |
485
- mkdir -p dist
486
- tar czf dist/app-{{version}}.tar.gz \
487
- target/release/app \
488
- config/ \
489
- migrations/
490
-
491
- deploy:
492
- desc: Deploy to environment
493
- deps: [package, docker.build-runtime]
494
- args: [environment, version]
495
- cmd: |
496
- scp dist/app-{{version}}.tar.gz {{environment}}:/opt/
497
- ssh {{environment}} /opt/deploy.sh {{version}}
498
-
499
- integration-test:
500
- desc: Run integration tests against deployed environment
501
- deps: [deploy]
502
- args: [environment, version]
503
- cmd: pytest tests/integration/ --env={{environment}}
555
+ tasks:
556
+ compile:
557
+ desc: Build application binaries
558
+ outputs: [target/release/app]
559
+ cmd: cargo build --release
560
+
561
+ test-unit:
562
+ desc: Run unit tests
563
+ deps: [compile]
564
+ cmd: cargo test
565
+
566
+ package:
567
+ desc: Create distribution archive
568
+ deps: [compile]
569
+ outputs: [dist/app-{{version}}.tar.gz]
570
+ args: [version]
571
+ cmd: |
572
+ mkdir -p dist
573
+ tar czf dist/app-{{version}}.tar.gz \
574
+ target/release/app \
575
+ config/ \
576
+ migrations/
577
+
578
+ deploy:
579
+ desc: Deploy to environment
580
+ deps: [package, docker.build-runtime]
581
+ args: [environment, version]
582
+ cmd: |
583
+ scp dist/app-{{version}}.tar.gz {{environment}}:/opt/
584
+ ssh {{environment}} /opt/deploy.sh {{version}}
585
+
586
+ integration-test:
587
+ desc: Run integration tests against deployed environment
588
+ deps: [deploy]
589
+ args: [environment, version]
590
+ cmd: pytest tests/integration/ --env={{environment}}
504
591
  ```
505
592
 
506
593
  Run the full pipeline: