tasktree 0.0.2__tar.gz → 0.0.4__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.
- {tasktree-0.0.2 → tasktree-0.0.4}/.github/workflows/test.yml +1 -1
- {tasktree-0.0.2 → tasktree-0.0.4}/.gitignore +0 -3
- tasktree-0.0.4/.python-version +1 -0
- {tasktree-0.0.2 → tasktree-0.0.4}/PKG-INFO +251 -14
- tasktree-0.0.4/README.md +598 -0
- {tasktree-0.0.2 → tasktree-0.0.4}/pyproject.toml +1 -1
- tasktree-0.0.4/requirements/future/docker-task-environments.md +1002 -0
- tasktree-0.0.4/requirements/implemented/shell-environment-requirements.md +392 -0
- {tasktree-0.0.2 → tasktree-0.0.4}/src/tasktree/cli.py +43 -138
- {tasktree-0.0.2 → tasktree-0.0.4}/src/tasktree/executor.py +202 -16
- tasktree-0.0.4/src/tasktree/hasher.py +27 -0
- {tasktree-0.0.2 → tasktree-0.0.4}/src/tasktree/parser.py +108 -5
- {tasktree-0.0.2 → tasktree-0.0.4}/src/tasktree/types.py +7 -7
- tasktree-0.0.4/tasktree.yaml +48 -0
- {tasktree-0.0.2 → tasktree-0.0.4}/tests/integration/test_cli_options.py +149 -1
- {tasktree-0.0.2 → tasktree-0.0.4}/tests/integration/test_dependency_execution.py +4 -4
- {tasktree-0.0.2 → tasktree-0.0.4}/tests/integration/test_missing_outputs.py +7 -7
- {tasktree-0.0.2 → tasktree-0.0.4}/tests/integration/test_working_directory.py +1 -1
- {tasktree-0.0.2 → tasktree-0.0.4}/tests/unit/test_executor.py +375 -5
- {tasktree-0.0.2 → tasktree-0.0.4}/tests/unit/test_parser.py +90 -0
- tasktree-0.0.2/README.md +0 -361
- tasktree-0.0.2/src/tasktree/hasher.py +0 -74
- tasktree-0.0.2/tasktree.yaml +0 -48
- {tasktree-0.0.2 → tasktree-0.0.4}/.github/workflows/release.yml +0 -0
- {tasktree-0.0.2 → tasktree-0.0.4}/CLAUDE.md +0 -0
- {tasktree-0.0.2 → tasktree-0.0.4}/example/source.txt +0 -0
- {tasktree-0.0.2 → tasktree-0.0.4}/example/tasktree.yaml +0 -0
- {tasktree-0.0.2 → tasktree-0.0.4}/src/__init__.py +0 -0
- {tasktree-0.0.2 → tasktree-0.0.4}/src/tasktree/__init__.py +0 -0
- {tasktree-0.0.2 → tasktree-0.0.4}/src/tasktree/graph.py +0 -0
- {tasktree-0.0.2 → tasktree-0.0.4}/src/tasktree/state.py +0 -0
- {tasktree-0.0.2 → tasktree-0.0.4}/src/tasktree/tasks.py +0 -0
- {tasktree-0.0.2 → tasktree-0.0.4}/tests/integration/test_clean_state.py +0 -0
- {tasktree-0.0.2 → tasktree-0.0.4}/tests/integration/test_end_to_end.py +0 -0
- {tasktree-0.0.2 → tasktree-0.0.4}/tests/integration/test_input_detection.py +0 -0
- {tasktree-0.0.2 → tasktree-0.0.4}/tests/integration/test_nested_imports.py +0 -0
- {tasktree-0.0.2 → tasktree-0.0.4}/tests/integration/test_state_persistence.py +0 -0
- {tasktree-0.0.2 → tasktree-0.0.4}/tests/unit/test_cli.py +0 -0
- {tasktree-0.0.2 → tasktree-0.0.4}/tests/unit/test_graph.py +0 -0
- {tasktree-0.0.2 → tasktree-0.0.4}/tests/unit/test_hasher.py +0 -0
- {tasktree-0.0.2 → tasktree-0.0.4}/tests/unit/test_state.py +0 -0
- {tasktree-0.0.2 → tasktree-0.0.4}/tests/unit/test_tasks.py +0 -0
- {tasktree-0.0.2 → tasktree-0.0.4}/tests/unit/test_types.py +0 -0
- {tasktree-0.0.2 → tasktree-0.0.4}/uv.lock +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.12
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tasktree
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.4
|
|
4
4
|
Summary: A task automation tool with incremental execution
|
|
5
5
|
Requires-Python: >=3.11
|
|
6
6
|
Requires-Dist: click>=8.1.0
|
|
@@ -18,6 +18,95 @@ Description-Content-Type: text/markdown
|
|
|
18
18
|
|
|
19
19
|
A task automation tool that combines simple command execution with dependency tracking and incremental execution.
|
|
20
20
|
|
|
21
|
+
## Motivation
|
|
22
|
+
In any project of even moderate size, various scripts inevitably come into being along the way. These scripts often must be run in a particular order, or at a particular time. For historical reasons, this almost certainly a problem if your project is developed in a Linux environment; in Windows, an IDE like Visual Studio may be taking care of a significant proportion of your build, packaging and deployment tasks. Then again, it may not...
|
|
23
|
+
|
|
24
|
+
The various incantations that have to be issued to build, package, test and deploy a project can build up and then all of a sudden there's only a few people that remember which to invoke and when and then people start making helpful readme guides on what to do with the scripts and then those become out of date and start telling lies about things and so on.
|
|
25
|
+
|
|
26
|
+
Then there's the scripts themselves. In Linux, they're probably a big pile of Bash and Python, or something (Ruby, Perl, you name it). You can bet the house on people solving the problem of passing parameters to their scripts in a whole bunch of different and inconsistent ways.
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
#!/usr/bin/env bash
|
|
30
|
+
# It's an environment variable defined.... somewhere?
|
|
31
|
+
echo "FOO is: $FOO"
|
|
32
|
+
```
|
|
33
|
+
```bash
|
|
34
|
+
#!/usr/bin/env bash
|
|
35
|
+
# Using simple positional arguments... guess what means what when you're invoking it!
|
|
36
|
+
echo "First: $1, Second: $2"
|
|
37
|
+
```
|
|
38
|
+
```bash
|
|
39
|
+
#!/usr/bin/env bash
|
|
40
|
+
# Oooooh fancy "make me look like a proper app" named option parsing... don't try and do --foo=bar though!
|
|
41
|
+
FOO=""
|
|
42
|
+
while [[ $# -gt 0 ]]; do
|
|
43
|
+
case "$1" in
|
|
44
|
+
--foo) FOO=$2; shift ;;
|
|
45
|
+
--) break ;;
|
|
46
|
+
*) echo "Unknown: $1";;
|
|
47
|
+
esac
|
|
48
|
+
shift
|
|
49
|
+
done
|
|
50
|
+
```
|
|
51
|
+
```bash
|
|
52
|
+
#!/usr/bin/env bash
|
|
53
|
+
# This thing...
|
|
54
|
+
ARGS=$(getopt -o f:b --long foo:,bar: -n 'myscript' -- "$@")
|
|
55
|
+
eval set -- "$ARGS"
|
|
56
|
+
while true; do
|
|
57
|
+
case "$1" in
|
|
58
|
+
-b|--bar) echo "Bar: $2"; shift 2 ;;
|
|
59
|
+
-f|--foo) echo "Foo: $2"; shift 2 ;;
|
|
60
|
+
--) shift; break ;;
|
|
61
|
+
*) break ;;
|
|
62
|
+
esac
|
|
63
|
+
done
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
What about help info? Who has time to wire that in?
|
|
67
|
+
|
|
68
|
+
### The point
|
|
69
|
+
Is this just whining and moaning? Should we just man up and revel in our own ability to memorize all the right incantations like some kind of scripting shaman?
|
|
70
|
+
|
|
71
|
+
... No. That's **a dumb idea**.
|
|
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.
|
|
74
|
+
|
|
75
|
+
The tasks you need to perform to deliver your project become summarised in an executable file that looks like:
|
|
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
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
If you want to run the tests then:
|
|
103
|
+
```bash
|
|
104
|
+
tt test
|
|
105
|
+
```
|
|
106
|
+
Boom! Done. `build` will always run, because there's no sensible way to know what Cargo did. However, if Cargo decided that nothing needed to be done and didn't touch the binaries, then `package` will realize that and not do anything. Then `test` will just run with the new tests that you just wrote. If you then immediately run `test` again, then `test` will figure out that none of the dependencies did anything and that none of the test files have changed and then just _do nothing_ - as it should.
|
|
107
|
+
|
|
108
|
+
This is a toy example, but you can image how it plays out on a more complex project.
|
|
109
|
+
|
|
21
110
|
## Installation
|
|
22
111
|
|
|
23
112
|
### From PyPI (Recommended)
|
|
@@ -26,6 +115,16 @@ A task automation tool that combines simple command execution with dependency tr
|
|
|
26
115
|
pipx install tasktree
|
|
27
116
|
```
|
|
28
117
|
|
|
118
|
+
If you have multiple Python interpreter versions installed, and the _default_ interpreter is a version <3.11, then you can use `pipx`'s `--python` option to specify an interpreter with a version >=3.11:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
# If the target version is on the PATH
|
|
122
|
+
pipx install --python python3.12 tasktree
|
|
123
|
+
|
|
124
|
+
# With a path to an interpreter
|
|
125
|
+
pipx install --python /path/to/python3.12 tasktree
|
|
126
|
+
```
|
|
127
|
+
|
|
29
128
|
### From Source
|
|
30
129
|
|
|
31
130
|
For the latest unreleased version from GitHub:
|
|
@@ -61,9 +160,11 @@ test:
|
|
|
61
160
|
Run tasks:
|
|
62
161
|
|
|
63
162
|
```bash
|
|
64
|
-
tt
|
|
65
|
-
tt
|
|
163
|
+
tt # Print the help
|
|
164
|
+
tt --help # ...also print the help
|
|
66
165
|
tt --list # Show all available tasks
|
|
166
|
+
tt build # Build the application (assuming this is in your tasktree.yaml)
|
|
167
|
+
tt test # Run tests (builds first if needed)
|
|
67
168
|
```
|
|
68
169
|
|
|
69
170
|
## Core Concepts
|
|
@@ -72,11 +173,12 @@ tt --list # Show all available tasks
|
|
|
72
173
|
|
|
73
174
|
Task Tree only runs tasks when necessary. A task executes if:
|
|
74
175
|
|
|
75
|
-
- Its definition (command, outputs, working directory) has changed
|
|
176
|
+
- Its definition (command, outputs, working directory, environment) has changed
|
|
76
177
|
- Any input files have changed since the last run
|
|
77
178
|
- Any dependencies have re-run
|
|
78
179
|
- It has never been executed before
|
|
79
180
|
- It has no inputs or outputs (always runs)
|
|
181
|
+
- The execution environment has changed (CLI override or environment config change)
|
|
80
182
|
|
|
81
183
|
### Automatic Input Inheritance
|
|
82
184
|
|
|
@@ -105,17 +207,25 @@ All state lives in `.tasktree-state` at your project root. Stale entries are aut
|
|
|
105
207
|
```yaml
|
|
106
208
|
task-name:
|
|
107
209
|
desc: Human-readable description (optional)
|
|
108
|
-
deps: [other-task]
|
|
109
|
-
inputs: [src/**/*.go]
|
|
110
|
-
outputs: [dist/binary]
|
|
111
|
-
working_dir: subproject/
|
|
112
|
-
|
|
113
|
-
|
|
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
|
|
114
217
|
```
|
|
115
218
|
|
|
116
219
|
### Commands
|
|
117
220
|
|
|
118
|
-
|
|
221
|
+
**Single-line commands** are executed directly via the configured shell:
|
|
222
|
+
|
|
223
|
+
```yaml
|
|
224
|
+
build:
|
|
225
|
+
cmd: cargo build --release
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
**Multi-line commands** are written to temporary script files for proper execution:
|
|
119
229
|
|
|
120
230
|
```yaml
|
|
121
231
|
deploy:
|
|
@@ -125,7 +235,9 @@ deploy:
|
|
|
125
235
|
rsync -av dist/ server:/opt/app/
|
|
126
236
|
```
|
|
127
237
|
|
|
128
|
-
|
|
238
|
+
Multi-line commands preserve shell syntax (line continuations, heredocs, etc.) and support shebangs on Unix/macOS.
|
|
239
|
+
|
|
240
|
+
Or use folded blocks for long single-line commands:
|
|
129
241
|
|
|
130
242
|
```yaml
|
|
131
243
|
compile:
|
|
@@ -136,6 +248,58 @@ compile:
|
|
|
136
248
|
-L lib -lm
|
|
137
249
|
```
|
|
138
250
|
|
|
251
|
+
### Execution Environments
|
|
252
|
+
|
|
253
|
+
Configure custom shell environments for task execution:
|
|
254
|
+
|
|
255
|
+
```yaml
|
|
256
|
+
environments:
|
|
257
|
+
default: bash-strict
|
|
258
|
+
|
|
259
|
+
bash-strict:
|
|
260
|
+
shell: bash
|
|
261
|
+
args: ['-c'] # For single-line: bash -c "command"
|
|
262
|
+
preamble: | # For multi-line: prepended to script
|
|
263
|
+
set -euo pipefail
|
|
264
|
+
|
|
265
|
+
python:
|
|
266
|
+
shell: python
|
|
267
|
+
args: ['-c']
|
|
268
|
+
|
|
269
|
+
powershell:
|
|
270
|
+
shell: powershell
|
|
271
|
+
args: ['-ExecutionPolicy', 'Bypass', '-Command']
|
|
272
|
+
preamble: |
|
|
273
|
+
$ErrorActionPreference = 'Stop'
|
|
274
|
+
|
|
275
|
+
tasks:
|
|
276
|
+
build:
|
|
277
|
+
# Uses 'default' environment (bash-strict)
|
|
278
|
+
cmd: cargo build --release
|
|
279
|
+
|
|
280
|
+
analyze:
|
|
281
|
+
env: python
|
|
282
|
+
cmd: |
|
|
283
|
+
import sys
|
|
284
|
+
print(f"Analyzing with Python {sys.version}")
|
|
285
|
+
# ... analysis code ...
|
|
286
|
+
|
|
287
|
+
windows-task:
|
|
288
|
+
env: powershell
|
|
289
|
+
cmd: |
|
|
290
|
+
Compress-Archive -Path dist/* -DestinationPath package.zip
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
**Environment resolution priority:**
|
|
294
|
+
1. CLI override: `tt --env python build`
|
|
295
|
+
2. Task's `env` field
|
|
296
|
+
3. Recipe's `default` environment
|
|
297
|
+
4. Platform default (bash on Unix, cmd on Windows)
|
|
298
|
+
|
|
299
|
+
**Platform defaults** when no environments are configured:
|
|
300
|
+
- **Unix/macOS**: bash with `-c` args
|
|
301
|
+
- **Windows**: cmd with `/c` args
|
|
302
|
+
|
|
139
303
|
### Parameterised Tasks
|
|
140
304
|
|
|
141
305
|
Tasks can accept arguments with optional defaults:
|
|
@@ -202,12 +366,19 @@ Input and output patterns support standard glob syntax:
|
|
|
202
366
|
|
|
203
367
|
### How State Works
|
|
204
368
|
|
|
205
|
-
Each task is identified by a hash of its definition
|
|
369
|
+
Each task is identified by a hash of its definition. The hash includes:
|
|
370
|
+
|
|
371
|
+
- Command to execute
|
|
372
|
+
- Output patterns
|
|
373
|
+
- Working directory
|
|
374
|
+
- Argument definitions
|
|
375
|
+
- Execution environment
|
|
206
376
|
|
|
377
|
+
State tracks:
|
|
207
378
|
- When the task last ran
|
|
208
379
|
- Timestamps of input files at that time
|
|
209
380
|
|
|
210
|
-
Tasks are re-run when their definition changes
|
|
381
|
+
Tasks are re-run when their definition changes, inputs are newer than the last run, or the environment changes.
|
|
211
382
|
|
|
212
383
|
### What's Not In The Hash
|
|
213
384
|
|
|
@@ -222,6 +393,72 @@ Changes to these don't invalidate cached state:
|
|
|
222
393
|
|
|
223
394
|
At the start of each invocation, state is checked for invalid task hashes and non-existent ones are automatically removed. Delete a task from your recipe file and its state disappears the next time you run `tt <cmd>`
|
|
224
395
|
|
|
396
|
+
## Command-Line Options
|
|
397
|
+
|
|
398
|
+
Task Tree provides several command-line options for controlling task execution:
|
|
399
|
+
|
|
400
|
+
### Execution Control
|
|
401
|
+
|
|
402
|
+
```bash
|
|
403
|
+
# Force re-run (ignore freshness checks)
|
|
404
|
+
tt --force build
|
|
405
|
+
tt -f build
|
|
406
|
+
|
|
407
|
+
# Run only the specified task, skip dependencies (implies --force)
|
|
408
|
+
tt --only deploy
|
|
409
|
+
tt -o deploy
|
|
410
|
+
|
|
411
|
+
# Override environment for all tasks
|
|
412
|
+
tt --env python analyze
|
|
413
|
+
tt -e powershell build
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
### Information Commands
|
|
417
|
+
|
|
418
|
+
```bash
|
|
419
|
+
# List all available tasks
|
|
420
|
+
tt --list
|
|
421
|
+
tt -l
|
|
422
|
+
|
|
423
|
+
# Show detailed task definition
|
|
424
|
+
tt --show build
|
|
425
|
+
|
|
426
|
+
# Show dependency tree (without execution)
|
|
427
|
+
tt --tree deploy
|
|
428
|
+
|
|
429
|
+
# Show version
|
|
430
|
+
tt --version
|
|
431
|
+
tt -v
|
|
432
|
+
|
|
433
|
+
# Create a blank recipe file
|
|
434
|
+
tt --init
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
### State Management
|
|
438
|
+
|
|
439
|
+
```bash
|
|
440
|
+
# Remove state file (reset task cache)
|
|
441
|
+
tt --clean
|
|
442
|
+
tt --clean-state
|
|
443
|
+
tt --reset
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
### Common Workflows
|
|
447
|
+
|
|
448
|
+
```bash
|
|
449
|
+
# Fresh build of everything
|
|
450
|
+
tt --force build
|
|
451
|
+
|
|
452
|
+
# Run a task without rebuilding dependencies
|
|
453
|
+
tt --only test
|
|
454
|
+
|
|
455
|
+
# Test with a different shell/environment
|
|
456
|
+
tt --env python test
|
|
457
|
+
|
|
458
|
+
# Force rebuild and deploy
|
|
459
|
+
tt --force deploy production
|
|
460
|
+
```
|
|
461
|
+
|
|
225
462
|
## Example: Full Build Pipeline
|
|
226
463
|
|
|
227
464
|
```yaml
|