tasktree 0.0.4__tar.gz → 0.0.5__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 (42) hide show
  1. {tasktree-0.0.4 → tasktree-0.0.5}/CLAUDE.md +9 -8
  2. {tasktree-0.0.4 → tasktree-0.0.5}/PKG-INFO +167 -111
  3. {tasktree-0.0.4 → tasktree-0.0.5}/README.md +166 -110
  4. tasktree-0.0.5/example/tasktree.yaml +16 -0
  5. {tasktree-0.0.4 → tasktree-0.0.5}/pyproject.toml +1 -1
  6. {tasktree-0.0.4 → tasktree-0.0.5}/requirements/implemented/shell-environment-requirements.md +37 -36
  7. {tasktree-0.0.4 → tasktree-0.0.5}/src/tasktree/cli.py +19 -18
  8. {tasktree-0.0.4 → tasktree-0.0.5}/src/tasktree/parser.py +41 -7
  9. {tasktree-0.0.4 → tasktree-0.0.5}/tests/integration/test_clean_state.py +19 -15
  10. {tasktree-0.0.4 → tasktree-0.0.5}/tests/integration/test_cli_options.py +233 -81
  11. {tasktree-0.0.4 → tasktree-0.0.5}/tests/integration/test_dependency_execution.py +43 -40
  12. {tasktree-0.0.4 → tasktree-0.0.5}/tests/integration/test_end_to_end.py +8 -6
  13. {tasktree-0.0.4 → tasktree-0.0.5}/tests/integration/test_input_detection.py +15 -12
  14. {tasktree-0.0.4 → tasktree-0.0.5}/tests/integration/test_nested_imports.py +65 -55
  15. {tasktree-0.0.4 → tasktree-0.0.5}/tests/integration/test_state_persistence.py +14 -11
  16. {tasktree-0.0.4 → tasktree-0.0.5}/tests/integration/test_working_directory.py +10 -8
  17. {tasktree-0.0.4 → tasktree-0.0.5}/tests/unit/test_executor.py +13 -9
  18. {tasktree-0.0.4 → tasktree-0.0.5}/tests/unit/test_parser.py +349 -164
  19. tasktree-0.0.4/example/tasktree.yaml +0 -15
  20. {tasktree-0.0.4 → tasktree-0.0.5}/.github/workflows/release.yml +0 -0
  21. {tasktree-0.0.4 → tasktree-0.0.5}/.github/workflows/test.yml +0 -0
  22. {tasktree-0.0.4 → tasktree-0.0.5}/.gitignore +0 -0
  23. {tasktree-0.0.4 → tasktree-0.0.5}/.python-version +0 -0
  24. {tasktree-0.0.4 → tasktree-0.0.5}/example/source.txt +0 -0
  25. {tasktree-0.0.4 → tasktree-0.0.5}/requirements/future/docker-task-environments.md +0 -0
  26. {tasktree-0.0.4 → tasktree-0.0.5}/src/__init__.py +0 -0
  27. {tasktree-0.0.4 → tasktree-0.0.5}/src/tasktree/__init__.py +0 -0
  28. {tasktree-0.0.4 → tasktree-0.0.5}/src/tasktree/executor.py +0 -0
  29. {tasktree-0.0.4 → tasktree-0.0.5}/src/tasktree/graph.py +0 -0
  30. {tasktree-0.0.4 → tasktree-0.0.5}/src/tasktree/hasher.py +0 -0
  31. {tasktree-0.0.4 → tasktree-0.0.5}/src/tasktree/state.py +0 -0
  32. {tasktree-0.0.4 → tasktree-0.0.5}/src/tasktree/tasks.py +0 -0
  33. {tasktree-0.0.4 → tasktree-0.0.5}/src/tasktree/types.py +0 -0
  34. {tasktree-0.0.4 → tasktree-0.0.5}/tasktree.yaml +0 -0
  35. {tasktree-0.0.4 → tasktree-0.0.5}/tests/integration/test_missing_outputs.py +0 -0
  36. {tasktree-0.0.4 → tasktree-0.0.5}/tests/unit/test_cli.py +0 -0
  37. {tasktree-0.0.4 → tasktree-0.0.5}/tests/unit/test_graph.py +0 -0
  38. {tasktree-0.0.4 → tasktree-0.0.5}/tests/unit/test_hasher.py +0 -0
  39. {tasktree-0.0.4 → tasktree-0.0.5}/tests/unit/test_state.py +0 -0
  40. {tasktree-0.0.4 → tasktree-0.0.5}/tests/unit/test_tasks.py +0 -0
  41. {tasktree-0.0.4 → tasktree-0.0.5}/tests/unit/test_types.py +0 -0
  42. {tasktree-0.0.4 → tasktree-0.0.5}/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.5
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)
@@ -146,15 +193,16 @@ pipx install .
146
193
  Create a `tasktree.yaml` (or `tt.yaml`) in your project:
147
194
 
148
195
  ```yaml
149
- build:
150
- desc: Compile the application
151
- outputs: [target/release/bin]
152
- cmd: cargo build --release
196
+ tasks:
197
+ build:
198
+ desc: Compile the application
199
+ outputs: [target/release/bin]
200
+ cmd: cargo build --release
153
201
 
154
- test:
155
- desc: Run tests
156
- deps: [build]
157
- cmd: cargo test
202
+ test:
203
+ desc: Run tests
204
+ deps: [build]
205
+ cmd: cargo test
158
206
  ```
159
207
 
160
208
  Run tasks:
@@ -185,15 +233,16 @@ Task Tree only runs tasks when necessary. A task executes if:
185
233
  Tasks automatically inherit inputs from dependencies, eliminating redundant declarations:
186
234
 
187
235
  ```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
236
+ tasks:
237
+ build:
238
+ outputs: [dist/app]
239
+ cmd: go build -o dist/app
240
+
241
+ package:
242
+ deps: [build]
243
+ outputs: [dist/app.tar.gz]
244
+ cmd: tar czf dist/app.tar.gz dist/app
245
+ # Automatically tracks dist/app as an input
197
246
  ```
198
247
 
199
248
  ### Single State File
@@ -205,15 +254,16 @@ All state lives in `.tasktree-state` at your project root. Stale entries are aut
205
254
  ### Basic Structure
206
255
 
207
256
  ```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
257
+ tasks:
258
+ task-name:
259
+ desc: Human-readable description (optional)
260
+ deps: [other-task] # Task dependencies
261
+ inputs: [src/**/*.go] # Explicit input files (glob patterns)
262
+ outputs: [dist/binary] # Output files (glob patterns)
263
+ working_dir: subproject/ # Execution directory (default: project root)
264
+ env: bash-strict # Execution environment (optional)
265
+ args: [param1, param2:path=default] # Task parameters
266
+ cmd: go build -o dist/binary # Command to execute
217
267
  ```
218
268
 
219
269
  ### Commands
@@ -221,18 +271,20 @@ task-name:
221
271
  **Single-line commands** are executed directly via the configured shell:
222
272
 
223
273
  ```yaml
224
- build:
225
- cmd: cargo build --release
274
+ tasks:
275
+ build:
276
+ cmd: cargo build --release
226
277
  ```
227
278
 
228
279
  **Multi-line commands** are written to temporary script files for proper execution:
229
280
 
230
281
  ```yaml
231
- deploy:
232
- cmd: |
233
- mkdir -p dist
234
- cp build/* dist/
235
- rsync -av dist/ server:/opt/app/
282
+ tasks:
283
+ deploy:
284
+ cmd: |
285
+ mkdir -p dist
286
+ cp build/* dist/
287
+ rsync -av dist/ server:/opt/app/
236
288
  ```
237
289
 
238
290
  Multi-line commands preserve shell syntax (line continuations, heredocs, etc.) and support shebangs on Unix/macOS.
@@ -240,12 +292,13 @@ Multi-line commands preserve shell syntax (line continuations, heredocs, etc.) a
240
292
  Or use folded blocks for long single-line commands:
241
293
 
242
294
  ```yaml
243
- compile:
244
- cmd: >
245
- gcc -o bin/app
246
- src/*.c
247
- -I include
248
- -L lib -lm
295
+ tasks:
296
+ compile:
297
+ cmd: >
298
+ gcc -o bin/app
299
+ src/*.c
300
+ -I include
301
+ -L lib -lm
249
302
  ```
250
303
 
251
304
  ### Execution Environments
@@ -305,12 +358,13 @@ tasks:
305
358
  Tasks can accept arguments with optional defaults:
306
359
 
307
360
  ```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}}
361
+ tasks:
362
+ deploy:
363
+ args: [environment, region=eu-west-1]
364
+ deps: [build]
365
+ cmd: |
366
+ aws s3 cp dist/app.zip s3://{{environment}}-{{region}}/
367
+ aws lambda update-function-code --function-name app-{{environment}}
314
368
  ```
315
369
 
316
370
  Invoke with: `tt deploy production` or `tt deploy staging us-east-1` or `tt deploy staging region=us-east-1`.
@@ -337,18 +391,19 @@ Split task definitions across multiple files for better organisation:
337
391
 
338
392
  ```yaml
339
393
  # tasktree.yaml
340
- import:
394
+ imports:
341
395
  - file: build/tasks.yml
342
396
  as: build
343
397
  - file: deploy/tasks.yml
344
398
  as: deploy
345
399
 
346
- test:
347
- deps: [build.compile, build.test-compile]
348
- cmd: ./run-tests.sh
400
+ tasks:
401
+ test:
402
+ deps: [build.compile, build.test-compile]
403
+ cmd: ./run-tests.sh
349
404
 
350
- ci:
351
- deps: [build.all, test, deploy.staging]
405
+ ci:
406
+ deps: [build.all, test, deploy.staging]
352
407
  ```
353
408
 
354
409
  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 +521,42 @@ imports:
466
521
  - file: common/docker.yml
467
522
  as: docker
468
523
 
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}}
524
+ tasks:
525
+ compile:
526
+ desc: Build application binaries
527
+ outputs: [target/release/app]
528
+ cmd: cargo build --release
529
+
530
+ test-unit:
531
+ desc: Run unit tests
532
+ deps: [compile]
533
+ cmd: cargo test
534
+
535
+ package:
536
+ desc: Create distribution archive
537
+ deps: [compile]
538
+ outputs: [dist/app-{{version}}.tar.gz]
539
+ args: [version]
540
+ cmd: |
541
+ mkdir -p dist
542
+ tar czf dist/app-{{version}}.tar.gz \
543
+ target/release/app \
544
+ config/ \
545
+ migrations/
546
+
547
+ deploy:
548
+ desc: Deploy to environment
549
+ deps: [package, docker.build-runtime]
550
+ args: [environment, version]
551
+ cmd: |
552
+ scp dist/app-{{version}}.tar.gz {{environment}}:/opt/
553
+ ssh {{environment}} /opt/deploy.sh {{version}}
554
+
555
+ integration-test:
556
+ desc: Run integration tests against deployed environment
557
+ deps: [deploy]
558
+ args: [environment, version]
559
+ cmd: pytest tests/integration/ --env={{environment}}
504
560
  ```
505
561
 
506
562
  Run the full pipeline: