tasktree 0.0.1__py3-none-any.whl → 0.0.2__py3-none-any.whl

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/cli.py CHANGED
@@ -236,13 +236,16 @@ def main(
236
236
  reset: Optional[bool] = typer.Option(
237
237
  None, "--reset", help="Remove state file (reset task cache)"
238
238
  ),
239
+ force: Optional[bool] = typer.Option(
240
+ None, "--force", "-f", help="Force re-run all tasks (ignore freshness)"
241
+ ),
239
242
  task_args: Optional[List[str]] = typer.Argument(
240
243
  None, help="Task name and arguments"
241
244
  ),
242
245
  ):
243
- """Task Tree - A task automation tool with intelligent incremental execution.
246
+ """Task Tree - A task automation tool with incremental execution.
244
247
 
245
- Run tasks defined in tasktree.yaml with intelligent dependency tracking
248
+ Run tasks defined in tasktree.yaml with dependency tracking
246
249
  and incremental execution.
247
250
 
248
251
  Examples:
@@ -284,7 +287,7 @@ def main(
284
287
 
285
288
  # Handle task execution
286
289
  if task_args:
287
- _execute_dynamic_task(task_args)
290
+ _execute_dynamic_task(task_args, force=force or False)
288
291
  else:
289
292
  # No arguments - show available tasks
290
293
  recipe = _get_recipe()
@@ -332,11 +335,12 @@ def _get_recipe() -> Recipe | None:
332
335
  raise typer.Exit(1)
333
336
 
334
337
 
335
- def _execute_dynamic_task(args: list[str]) -> None:
338
+ def _execute_dynamic_task(args: list[str], force: bool = False) -> None:
336
339
  """Execute a task specified by name with arguments.
337
340
 
338
341
  Args:
339
342
  args: Command line arguments (task name and task arguments)
343
+ force: If True, ignore freshness and re-run all tasks
340
344
  """
341
345
  if not args:
342
346
  return
@@ -373,7 +377,7 @@ def _execute_dynamic_task(args: list[str]) -> None:
373
377
  # Execute task
374
378
  executor = Executor(recipe, state)
375
379
  try:
376
- executor.execute_task(task_name, args_dict, dry_run=False)
380
+ executor.execute_task(task_name, args_dict, dry_run=False, force=force)
377
381
  console.print(f"[green]✓ Task '{task_name}' completed successfully[/green]")
378
382
  except Exception as e:
379
383
  console.print(f"[red]✗ Task '{task_name}' failed: {e}[/red]")
tasktree/executor.py CHANGED
@@ -51,25 +51,36 @@ class Executor:
51
51
  task: Task,
52
52
  args_dict: dict[str, Any],
53
53
  dep_statuses: dict[str, TaskStatus],
54
+ force: bool = False,
54
55
  ) -> TaskStatus:
55
56
  """Check if a task needs to run.
56
57
 
57
58
  A task executes if ANY of these conditions are met:
58
- 1. Task definition hash differs from cached state
59
- 2. Any explicit inputs have newer mtime than last_run
60
- 3. Any implicit inputs (from deps) have changed
61
- 4. No cached state exists for this task+args combination
62
- 5. Task has no inputs AND no outputs (always runs)
63
- 6. Different arguments than any cached execution
59
+ 1. Force flag is set (--force)
60
+ 2. Task definition hash differs from cached state
61
+ 3. Any explicit inputs have newer mtime than last_run
62
+ 4. Any implicit inputs (from deps) have changed
63
+ 5. No cached state exists for this task+args combination
64
+ 6. Task has no inputs AND no outputs (always runs)
65
+ 7. Different arguments than any cached execution
64
66
 
65
67
  Args:
66
68
  task: Task to check
67
69
  args_dict: Arguments for this task execution
68
70
  dep_statuses: Status of dependencies
71
+ force: If True, ignore freshness and force execution
69
72
 
70
73
  Returns:
71
74
  TaskStatus indicating whether task will run and why
72
75
  """
76
+ # If force flag is set, always run
77
+ if force:
78
+ return TaskStatus(
79
+ task_name=task.name,
80
+ will_run=True,
81
+ reason="forced",
82
+ )
83
+
73
84
  # Compute hashes
74
85
  task_hash = hash_task(task.cmd, task.outputs, task.working_dir, task.args)
75
86
  args_hash = hash_args(args_dict) if args_dict else None
@@ -136,6 +147,7 @@ class Executor:
136
147
  task_name: str,
137
148
  args_dict: dict[str, Any] | None = None,
138
149
  dry_run: bool = False,
150
+ force: bool = False,
139
151
  ) -> dict[str, TaskStatus]:
140
152
  """Execute a task and its dependencies.
141
153
 
@@ -143,6 +155,7 @@ class Executor:
143
155
  task_name: Name of task to execute
144
156
  args_dict: Arguments to pass to the task
145
157
  dry_run: If True, only check what would run without executing
158
+ force: If True, ignore freshness and re-run all tasks
146
159
 
147
160
  Returns:
148
161
  Dictionary of task names to their execution status
@@ -167,7 +180,7 @@ class Executor:
167
180
  # Determine task-specific args (only for target task)
168
181
  task_args = args_dict if name == task_name else {}
169
182
 
170
- status = self.check_task_status(task, task_args, dep_statuses)
183
+ status = self.check_task_status(task, task_args, dep_statuses, force=force)
171
184
  statuses[name] = status
172
185
 
173
186
  if dry_run:
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tasktree
3
- Version: 0.0.1
4
- Summary: A task automation tool with intelligent incremental execution
3
+ Version: 0.0.2
4
+ Summary: A task automation tool with incremental execution
5
5
  Requires-Python: >=3.11
6
6
  Requires-Dist: click>=8.1.0
7
7
  Requires-Dist: colorama>=0.4.6
@@ -14,9 +14,9 @@ Description-Content-Type: text/markdown
14
14
 
15
15
  # Task Tree (tt)
16
16
 
17
- [![Tests](https://github.com/kevinchannon/tasktree/actions/workflows/test.yml/badge.svg)](https://github.com/kevinchannon/tasktree/actions/workflows/test.yml)
17
+ [![Tests](https://github.com/kevinchannon/task-tree/actions/workflows/test.yml/badge.svg)](https://github.com/kevinchannon/task-tree/actions/workflows/test.yml)
18
18
 
19
- A task automation tool that combines simple command execution with intelligent dependency tracking and incremental execution.
19
+ A task automation tool that combines simple command execution with dependency tracking and incremental execution.
20
20
 
21
21
  ## Installation
22
22
 
@@ -31,13 +31,13 @@ pipx install tasktree
31
31
  For the latest unreleased version from GitHub:
32
32
 
33
33
  ```bash
34
- pipx install git+https://github.com/kevinchannon/tasktree.git
34
+ pipx install git+https://github.com/kevinchannon/task-tree.git
35
35
  ```
36
36
 
37
37
  Or to install from a local clone:
38
38
 
39
39
  ```bash
40
- git clone https://github.com/kevinchannon/tasktree.git
40
+ git clone https://github.com/kevinchannon/task-tree.git
41
41
  cd tasktree
42
42
  pipx install .
43
43
  ```
@@ -297,7 +297,7 @@ State file uses JSON format for simplicity and standard library compatibility.
297
297
 
298
298
  ```bash
299
299
  # Clone repository
300
- git clone https://github.com/kevinchannon/tasktree.git
300
+ git clone https://github.com/kevinchannon/task-tree.git
301
301
  cd tasktree
302
302
 
303
303
  # Install uv (if not already installed)
@@ -363,8 +363,8 @@ git push origin v1.0.0
363
363
  - Publish to PyPI
364
364
 
365
365
  4. Verify the release:
366
- - GitHub: https://github.com/kevinchannon/tasktree/releases
367
- - PyPI: https://pypi.org/project/tasktree/
366
+ - GitHub: https://github.com/kevinchannon/task-tree/releases
367
+ - PyPI: https://pypi.org/kevinchannon/tasktree/
368
368
  - Test: `pipx install --force tasktree`
369
369
 
370
370
  ### Version Numbering
@@ -372,16 +372,4 @@ git push origin v1.0.0
372
372
  Follow semantic versioning:
373
373
  - `v1.0.0` - Major release (breaking changes)
374
374
  - `v1.1.0` - Minor release (new features, backward compatible)
375
- - `v1.1.1` - Patch release (bug fixes)
376
-
377
- ### PyPI Trusted Publishing Setup
378
-
379
- Before the first release, configure trusted publishing on PyPI:
380
-
381
- 1. Go to https://pypi.org/manage/account/publishing/
382
- 2. Add a new publisher:
383
- - **PyPI Project Name**: `tasktree`
384
- - **Owner**: `kevinchannon`
385
- - **Repository name**: `tasktree`
386
- - **Workflow name**: `release.yml`
387
- - **Environment name**: (leave blank)
375
+ - `v1.1.1` - Patch release (bug fixes)
@@ -1,13 +1,13 @@
1
1
  tasktree/__init__.py,sha256=MVmdvKb3JdqLlo0x2_TPGMfgFC0HsDnP79HAzGnFnjI,1081
2
- tasktree/cli.py,sha256=hI9jqHE2YIb_6lYUjxVobLJOE88kOlunfAg52TsD1sQ,15681
3
- tasktree/executor.py,sha256=TH59xTR6MNBEek9Q8yjYhgC-h0H4mjNsP-yjAcVgS-E,11838
2
+ tasktree/cli.py,sha256=VZGB8FJ8glZLn_z2bjSLLbmGRfFZ5Zh4nc1cYDLjGck,15904
3
+ tasktree/executor.py,sha256=ZM-qEsgvjfRz77GEZzxF29L3I2d8Uz5W1ev7Mox9Vnc,12287
4
4
  tasktree/graph.py,sha256=9ngfg93y7EkOIN_lUQa0u-JhnwiMN1UdQQvIFw8RYCE,4181
5
5
  tasktree/hasher.py,sha256=jvXBvIfFH9g6AOBHHd012v8nG5JOgVnHH35mIEtVkwc,2133
6
6
  tasktree/parser.py,sha256=F2LbB84NinvBQT8zLONxn036R9Rued2y4XB3WGZ8PLk,9150
7
7
  tasktree/state.py,sha256=rxKtS3SbsPtAuraHbN807RGWfoYYkQ3pe8CxUstwo2k,3535
8
8
  tasktree/tasks.py,sha256=2QdQZtJAX2rSGbyXKG1z9VF_siz1DUzdvzCgPkykxtU,173
9
9
  tasktree/types.py,sha256=wrBzO-Z2ebCTRjWyOWNvuCjqAq-74Zyb9E4FQ4beF38,3751
10
- tasktree-0.0.1.dist-info/METADATA,sha256=aE9ihAgGTRvrNh7TarEA2vEFftKg3FV1DVlMAN0M9LU,9522
11
- tasktree-0.0.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
12
- tasktree-0.0.1.dist-info/entry_points.txt,sha256=lQINlvRYnimvteBbnhH84A9clTg8NnpEjCWqWkqg8KE,40
13
- tasktree-0.0.1.dist-info/RECORD,,
10
+ tasktree-0.0.2.dist-info/METADATA,sha256=yUoIhImEiwFND5rcCwzVdHosfW6BMvwbvdQgqF8EjnE,9145
11
+ tasktree-0.0.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
12
+ tasktree-0.0.2.dist-info/entry_points.txt,sha256=lQINlvRYnimvteBbnhH84A9clTg8NnpEjCWqWkqg8KE,40
13
+ tasktree-0.0.2.dist-info/RECORD,,