hammerkit 1.6.0 → 1.7.0
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.
- package/README.md +4 -4
- package/build.schema.json +49 -2
- package/dist/cache/backends/local-cache-backend.js +58 -1
- package/dist/cache/backends/registry/registry-client.js +264 -0
- package/dist/cache/backends/registry/registry-credentials.js +81 -0
- package/dist/cache/backends/registry/registry-reference.js +36 -0
- package/dist/cache/backends/registry-cache-backend.js +145 -0
- package/dist/cache/backends/s3-cache-backend.js +99 -46
- package/dist/cache/cache-backend-registry.js +2 -0
- package/dist/cache/cache-inventory.js +84 -0
- package/dist/cache/cache-sync.js +77 -0
- package/dist/cache/explain.js +214 -0
- package/dist/cache/last-resolved.js +48 -0
- package/dist/cache/read-only.js +15 -0
- package/dist/cache/retention.js +61 -0
- package/dist/cli.js +43 -0
- package/dist/docker/using-container.js +5 -1
- package/dist/executer/archive-task-entry.js +21 -0
- package/dist/executer/await-completed-dependencies.js +32 -14
- package/dist/executer/cache-metadata.js +9 -2
- package/dist/executer/docker-service.js +2 -1
- package/dist/executer/docker-task.js +2 -1
- package/dist/executer/dry-run.js +73 -0
- package/dist/executer/event-cache.js +6 -5
- package/dist/executer/execute-command.js +21 -3
- package/dist/executer/execute-work-service.js +10 -1
- package/dist/executer/execute-work-task.js +95 -25
- package/dist/executer/execute-work-tree.js +26 -1
- package/dist/executer/get-scheduler-execute-result.js +4 -1
- package/dist/executer/lazy-resolver.js +15 -3
- package/dist/executer/reset-work-tree.js +2 -0
- package/dist/executer/run-summary.js +102 -0
- package/dist/executer/scheduler/enqueue-next.js +15 -60
- package/dist/executer/scheduler/state-key.js +78 -0
- package/dist/kubernetes/await-running-state.js +73 -19
- package/dist/log.js +16 -6
- package/dist/logging/live-logger.js +2 -1
- package/dist/optimizer/calculate-checksum.js +8 -2
- package/dist/optimizer/get-work-cache-stats.js +66 -16
- package/dist/optimizer/work-task-cache-description.js +34 -5
- package/dist/planner/project-root.js +26 -0
- package/dist/planner/utils/append-work-service.js +2 -1
- package/dist/planner/utils/append-work-task.js +7 -1
- package/dist/planner/utils/parse-work-source.js +35 -30
- package/dist/planner/utils/portable-path.js +30 -0
- package/dist/planner/work-cache-id.js +2 -2
- package/dist/planner/work-graph-serializer.js +103 -0
- package/dist/planner/work-instance-id.js +15 -0
- package/dist/planner/work-runtime-docker.js +53 -15
- package/dist/planner/work-runtime-kubernetes.js +35 -3
- package/dist/planner/work-runtime-local.js +9 -3
- package/dist/planner/work-service-id.js +16 -4
- package/dist/program.js +235 -1
- package/dist/schema/build-file-base-task-schema.js +4 -0
- package/dist/schema/cache-schema.js +21 -2
- package/dist/schema/duration-schema.js +18 -0
- package/dist/schema/reference-parser.js +3 -0
- package/dist/schema/size-schema.js +18 -0
- package/dist/schema/work-scope-parser.js +15 -2
- package/dist/utils/units.js +87 -0
- package/package.json +12 -1
- package/.agents/FEEDBACK.md +0 -74
- package/.agents/skills/before-commit/SKILL.md +0 -101
- package/.agents/skills/do-the-work/SKILL.md +0 -64
- package/.agents/skills/fix-ci/SKILL.md +0 -98
- package/.agents/skills/speckit-git-commit/SKILL.md +0 -53
- package/.agents/skills/speckit-git-feature/SKILL.md +0 -72
- package/.agents/skills/speckit-git-initialize/SKILL.md +0 -54
- package/.agents/skills/speckit-git-remote/SKILL.md +0 -50
- package/.agents/skills/speckit-git-validate/SKILL.md +0 -54
- package/.devcontainer/Dockerfile +0 -5
- package/.devcontainer/devcontainer.json +0 -40
- package/.gitbook.yaml +0 -5
- package/.specify/extensions/.registry +0 -37
- package/.specify/extensions/git/README.md +0 -100
- package/.specify/extensions/git/commands/speckit.git.commit.md +0 -48
- package/.specify/extensions/git/commands/speckit.git.feature.md +0 -67
- package/.specify/extensions/git/commands/speckit.git.initialize.md +0 -49
- package/.specify/extensions/git/commands/speckit.git.remote.md +0 -45
- package/.specify/extensions/git/commands/speckit.git.validate.md +0 -49
- package/.specify/extensions/git/config-template.yml +0 -62
- package/.specify/extensions/git/extension.yml +0 -140
- package/.specify/extensions/git/git-config.yml +0 -62
- package/.specify/extensions.yml +0 -149
- package/.specify/feature.json +0 -3
- package/.specify/init-options.json +0 -10
- package/.specify/integration.json +0 -15
- package/.specify/integrations/claude.manifest.json +0 -16
- package/.specify/integrations/speckit.manifest.json +0 -17
- package/.specify/memory/constitution.md +0 -162
- package/.specify/templates/checklist-template.md +0 -40
- package/.specify/templates/constitution-template.md +0 -50
- package/.specify/templates/plan-template.md +0 -113
- package/.specify/templates/spec-template.md +0 -131
- package/.specify/templates/tasks-template.md +0 -252
- package/.specify/workflows/speckit/workflow.yml +0 -77
- package/.specify/workflows/workflow-registry.json +0 -13
- package/AGENTS.md +0 -94
- package/Dockerfile +0 -32
- package/FOLLOWUPS.md +0 -34
- package/SUMMARY.md +0 -68
- package/VALUES.md +0 -53
- package/dist/cache/auto-pull.spec.js +0 -123
- package/dist/cache/backends/local-cache-backend.spec.js +0 -72
- package/dist/cache/backends/s3-cache-backend.spec.js +0 -118
- package/dist/cache/cache-backend-registry.spec.js +0 -22
- package/dist/cache/resolve-cache.spec.js +0 -52
- package/dist/cli.spec.js +0 -23
- package/dist/console/get-logger.spec.js +0 -23
- package/dist/docker/get-default-platform.spec.js +0 -29
- package/dist/docker/longest-common-prefix.spec.js +0 -26
- package/dist/docker/package.spec.js +0 -145
- package/dist/docker/remove-container.spec.js +0 -32
- package/dist/docker/using-container.spec.js +0 -90
- package/dist/environment/merge-environment-variables.spec.js +0 -24
- package/dist/environment/replace-env-variables.spec.js +0 -47
- package/dist/executer/abort.spec.js +0 -18
- package/dist/executer/environment-mock.spec.js +0 -22
- package/dist/executer/execute.spec.js +0 -51
- package/dist/executer/get-service-containers.spec.js +0 -59
- package/dist/executer/get-service-env-hints.spec.js +0 -65
- package/dist/executer/label-values.spec.js +0 -61
- package/dist/executer/lazy-resolver.spec.js +0 -20
- package/dist/executer/process-manager.spec.js +0 -54
- package/dist/executer/scheduler/enqueue-next.spec.js +0 -136
- package/dist/executer/state-resolver.spec.js +0 -37
- package/dist/executer/state.spec.js +0 -66
- package/dist/executer/states.spec.js +0 -14
- package/dist/file/get-file-context.spec.js +0 -178
- package/dist/file/move-files.spec.js +0 -48
- package/dist/kubernetes/ensure-http-route.spec.js +0 -70
- package/dist/kubernetes/ensure-namespace.spec.js +0 -39
- package/dist/kubernetes/resolve-pod-name.spec.js +0 -81
- package/dist/log.spec.js +0 -131
- package/dist/logging/grouped-logger.spec.js +0 -84
- package/dist/logging/interactive-logger.spec.js +0 -57
- package/dist/logging/live-logger.spec.js +0 -37
- package/dist/logging/loggers.spec.js +0 -154
- package/dist/optimizer/calculate-checksum.spec.js +0 -34
- package/dist/optimizer/get-cache-directory.spec.js +0 -59
- package/dist/optimizer/get-work-cache-stats.spec.js +0 -79
- package/dist/optimizer/work-task-cache-description.spec.js +0 -45
- package/dist/parser/default-build-file.spec.js +0 -48
- package/dist/parser/parse-label-arguments.spec.js +0 -27
- package/dist/parser/read-build-file.spec.js +0 -89
- package/dist/parser/read-env-file.spec.js +0 -42
- package/dist/planner/utils/append-work-service.spec.js +0 -71
- package/dist/planner/utils/get-container-user.spec.js +0 -30
- package/dist/planner/utils/get-default-kube-config.spec.js +0 -11
- package/dist/planner/utils/normalize-path.spec.js +0 -24
- package/dist/planner/utils/parse-work-command.spec.js +0 -21
- package/dist/planner/utils/parse-work-generate.spec.js +0 -45
- package/dist/planner/utils/parse-work-mount.spec.js +0 -62
- package/dist/planner/utils/parse-work-mounts.spec.js +0 -19
- package/dist/planner/utils/parse-work-port.spec.js +0 -24
- package/dist/planner/utils/parse-work-ports.spec.js +0 -24
- package/dist/planner/utils/parse-work-source.spec.js +0 -58
- package/dist/planner/utils/parse-work-volume.spec.js +0 -18
- package/dist/planner/utils/plan-work-tasks.spec.js +0 -30
- package/dist/planner/utils/plan-work-volume.spec.js +0 -33
- package/dist/planner/utils/split-name.spec.js +0 -16
- package/dist/planner/utils/template-value.spec.js +0 -14
- package/dist/planner/validate.spec.js +0 -251
- package/dist/planner/work-cache-id.spec.js +0 -173
- package/dist/planner/work-runtime-local.spec.js +0 -193
- package/dist/program-commands.spec.js +0 -84
- package/dist/program.spec.js +0 -43
- package/dist/schema/build-file-schema.spec.js +0 -61
- package/dist/schema/doc-build-files.spec.js +0 -223
- package/dist/schema/parse-error.spec.js +0 -18
- package/dist/schema/reference-parser.spec.js +0 -83
- package/dist/schema/schema-parser.spec.js +0 -80
- package/dist/schema/type-guards.spec.js +0 -23
- package/dist/schema/work-scope-parser.spec.js +0 -66
- package/dist/service/update-service-status.spec.js +0 -27
- package/dist/testing/ensure-local-registry.js +0 -134
- package/dist/testing/example-test-suite.js +0 -63
- package/dist/testing/expect.js +0 -82
- package/dist/testing/get-test-suite.js +0 -9
- package/dist/testing/http-get.js +0 -21
- package/dist/testing/integration/cache.spec.js +0 -49
- package/dist/testing/integration/cancellation.spec.js +0 -45
- package/dist/testing/integration/clean.spec.js +0 -43
- package/dist/testing/integration/cmd.spec.js +0 -15
- package/dist/testing/integration/concurrency.spec.js +0 -19
- package/dist/testing/integration/docker-package-registry.spec.js +0 -44
- package/dist/testing/integration/docker-service-crash.spec.js +0 -36
- package/dist/testing/integration/docker.spec.js +0 -18
- package/dist/testing/integration/env.spec.js +0 -48
- package/dist/testing/integration/environment.spec.js +0 -97
- package/dist/testing/integration/error.spec.js +0 -19
- package/dist/testing/integration/export.spec.js +0 -22
- package/dist/testing/integration/extend.spec.js +0 -29
- package/dist/testing/integration/glob.spec.js +0 -40
- package/dist/testing/integration/include.spec.js +0 -31
- package/dist/testing/integration/invalid.spec.js +0 -17
- package/dist/testing/integration/invalid_loop.spec.js +0 -56
- package/dist/testing/integration/k8s-state-cache.spec.js +0 -41
- package/dist/testing/integration/kubernetes-service.spec.js +0 -148
- package/dist/testing/integration/kubernetes.spec.js +0 -99
- package/dist/testing/integration/labels.spec.js +0 -42
- package/dist/testing/integration/local.spec.js +0 -14
- package/dist/testing/integration/monorepo.spec.js +0 -15
- package/dist/testing/integration/multi-line.spec.js +0 -17
- package/dist/testing/integration/reference.spec.js +0 -21
- package/dist/testing/integration/services.spec.js +0 -38
- package/dist/testing/integration/store.spec.js +0 -52
- package/dist/testing/integration/unknown.spec.js +0 -28
- package/dist/testing/integration/validate.spec.js +0 -160
- package/dist/testing/integration/watch-dependency.spec.js +0 -33
- package/dist/testing/integration/watch.spec.js +0 -45
- package/dist/testing/requires-kubernetes.js +0 -18
- package/dist/testing/requires-linux-containers.js +0 -18
- package/dist/testing/requires-windows-containers.js +0 -18
- package/dist/testing/test-case.js +0 -75
- package/dist/testing/test-streams.js +0 -28
- package/dist/testing/test-suite-setup.js +0 -3
- package/dist/testing/test-suite.js +0 -3
- package/dist/testing/testing-timeout.js +0 -32
- package/dist/utils/abort-event.spec.js +0 -46
- package/dist/utils/buffer-context.spec.js +0 -38
- package/dist/utils/ci.spec.js +0 -53
- package/dist/utils/debouncer.spec.js +0 -58
- package/dist/utils/emitter.spec.js +0 -34
- package/dist/utils/empty-writable.spec.js +0 -18
- package/dist/utils/environment-config.spec.js +0 -26
- package/dist/utils/fail-never.spec.js +0 -9
- package/dist/utils/sleep.spec.js +0 -22
- package/dist/version.spec.js +0 -12
- package/specs/build-file/caches/spec.md +0 -114
- package/specs/build-file/environment-variables/spec.md +0 -82
- package/specs/build-file/includes/spec.md +0 -60
- package/specs/build-file/references/spec.md +0 -56
- package/specs/build-file/spec.md +0 -62
- package/specs/cli/clean/spec.md +0 -85
- package/specs/cli/down/spec.md +0 -85
- package/specs/cli/execute/spec.md +0 -101
- package/specs/cli/init/spec.md +0 -64
- package/specs/cli/ls/spec.md +0 -66
- package/specs/cli/package/spec.md +0 -110
- package/specs/cli/spec.md +0 -73
- package/specs/cli/store-restore/spec.md +0 -74
- package/specs/cli/up/spec.md +0 -80
- package/specs/cli/validate/spec.md +0 -70
- package/specs/labels/spec.md +0 -91
- package/specs/service/container/spec.md +0 -120
- package/specs/service/kubernetes/spec.md +0 -97
- package/specs/service/spec.md +0 -105
- package/specs/task/caching/spec.md +0 -107
- package/specs/task/container/spec.md +0 -118
- package/specs/task/dependencies/spec.md +0 -70
- package/specs/task/extending/spec.md +0 -74
- package/specs/task/kubernetes/spec.md +0 -125
- package/specs/task/needs/spec.md +0 -59
- package/specs/task/spec.md +0 -87
- package/specs/task/watching/spec.md +0 -69
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
# Feature Specification: Task: Container
|
|
2
|
-
|
|
3
|
-
**Feature Branch**: `001-current-state-specs`
|
|
4
|
-
|
|
5
|
-
**Created**: 2026-05-30
|
|
6
|
-
|
|
7
|
-
**Status**: Current State (reverse-specified from docs, hammerkit 1.6.0)
|
|
8
|
-
|
|
9
|
-
**Input**: Existing behavior documented in `docs/task/container.md`
|
|
10
|
-
|
|
11
|
-
## User Scenarios & Testing *(mandatory)*
|
|
12
|
-
|
|
13
|
-
### User Story 1 - Run a task inside a container image (Priority: P1)
|
|
14
|
-
|
|
15
|
-
A developer wants to build their project without installing Node.js locally. They add `image: node:14.16.0` to the task definition and hammerkit executes the task's commands inside a container using that image.
|
|
16
|
-
|
|
17
|
-
**Why this priority**: Container execution is the core cross-platform isolation feature of hammerkit.
|
|
18
|
-
|
|
19
|
-
**Independent Test**: Define a task with `image` set and a command that prints the Node version; verify the output matches the version in the image, not any locally installed Node.
|
|
20
|
-
|
|
21
|
-
**Acceptance Scenarios**:
|
|
22
|
-
|
|
23
|
-
1. **Given** a task with an `image` property, **When** the task is run, **Then** all commands execute inside a container created from that image.
|
|
24
|
-
2. **Given** a task with `image` but no `src` or `mounts`, **When** the task runs, **Then** the container has no access to host files.
|
|
25
|
-
|
|
26
|
-
### User Story 2 - Make source files available inside the container (Priority: P1)
|
|
27
|
-
|
|
28
|
-
A developer's container task needs to read project files. They declare those files and folders in `src`; hammerkit mounts them into the container automatically so commands can access them.
|
|
29
|
-
|
|
30
|
-
**Why this priority**: Without file access the container task cannot read inputs and is not useful.
|
|
31
|
-
|
|
32
|
-
**Independent Test**: Add `src` files to a container task and verify a command inside the container can read those files.
|
|
33
|
-
|
|
34
|
-
**Acceptance Scenarios**:
|
|
35
|
-
|
|
36
|
-
1. **Given** a container task with `src` files listed, **When** the task executes, **Then** those files are accessible at their expected paths inside the container.
|
|
37
|
-
2. **Given** a container task whose dependency task declares `src` and `generates`, **When** the dependent task executes, **Then** those dependency paths are also mounted automatically without being listed again.
|
|
38
|
-
|
|
39
|
-
### User Story 3 - Persist output files across runs using generates (Priority: P2)
|
|
40
|
-
|
|
41
|
-
A developer's container task produces `node_modules`. They declare `node_modules` under `generates` so hammerkit persists it in a container volume between runs, enabling caching of the installed packages.
|
|
42
|
-
|
|
43
|
-
**Why this priority**: Without `generates`, outputs are lost when the container exits; re-runs would redo all work.
|
|
44
|
-
|
|
45
|
-
**Independent Test**: Run an install task in a container with `node_modules` in `generates`; stop hammerkit and run again — the second run should be cached and `node_modules` should still be present.
|
|
46
|
-
|
|
47
|
-
**Acceptance Scenarios**:
|
|
48
|
-
|
|
49
|
-
1. **Given** a container task with a path in `generates`, **When** the task completes, **Then** the output is preserved in a container volume for the next run.
|
|
50
|
-
2. **Given** a container task with `generates` and `export: true`, **When** the task completes, **Then** the generated files are also copied to the host workspace.
|
|
51
|
-
|
|
52
|
-
### User Story 4 - Mount additional files and directories (Priority: P2)
|
|
53
|
-
|
|
54
|
-
A developer needs to give the container access to files that are neither source inputs nor generated outputs (e.g., a credential file or a shared cache directory). They use `mounts` with relative paths, absolute paths, or `$PWD`-relative expressions.
|
|
55
|
-
|
|
56
|
-
**Why this priority**: Not all container inputs fit the source/generate model; mounts fill that gap.
|
|
57
|
-
|
|
58
|
-
**Independent Test**: Add a mount to a container task and verify the mounted path is accessible inside the container.
|
|
59
|
-
|
|
60
|
-
**Acceptance Scenarios**:
|
|
61
|
-
|
|
62
|
-
1. **Given** a container task with a relative `mounts` entry, **When** the task runs, **Then** the relative path is mounted into the container.
|
|
63
|
-
2. **Given** a container task with an absolute `mounts` entry, **When** the task runs, **Then** the absolute path is mounted into the container.
|
|
64
|
-
3. **Given** a container task with a `$PWD`-style `mounts` entry (e.g., `$PWD/.npm:/.npm`), **When** the task runs, **Then** the path is expanded and mounted at the specified target path.
|
|
65
|
-
|
|
66
|
-
### User Story 5 - Override the execution shell (Priority: P3)
|
|
67
|
-
|
|
68
|
-
A developer's commands require bash-specific syntax. They set `shell: bash` on the task and commands are invoked with bash instead of the default `sh`.
|
|
69
|
-
|
|
70
|
-
**Why this priority**: Some commands or scripts require a specific shell; the default `sh` is too restrictive for some use cases.
|
|
71
|
-
|
|
72
|
-
**Independent Test**: Set `shell: bash` and use a bash-only feature (`$RANDOM`); verify the command succeeds inside the container.
|
|
73
|
-
|
|
74
|
-
**Acceptance Scenarios**:
|
|
75
|
-
|
|
76
|
-
1. **Given** a container task with `shell: bash`, **When** a command uses bash-specific syntax, **Then** it executes successfully.
|
|
77
|
-
2. **Given** a container task without a `shell` property, **When** commands run, **Then** they are executed with `sh`.
|
|
78
|
-
|
|
79
|
-
### Edge Cases
|
|
80
|
-
|
|
81
|
-
- A container task with no `src`, `generates`, or `mounts` can still run but has no access to host files.
|
|
82
|
-
- File permissions: commands in a container run with the same UID/GID as the local user; hammerkit sets the owner of the working directory and all mounts to that UID/GID before each task run.
|
|
83
|
-
- Sources and generates of all dependency tasks are automatically mounted; this reduces the need for explicit `mounts` entries.
|
|
84
|
-
|
|
85
|
-
## Requirements *(mandatory)*
|
|
86
|
-
|
|
87
|
-
### Functional Requirements
|
|
88
|
-
|
|
89
|
-
- **FR-001**: The system MUST accept an `image` property on a task and execute all `cmds` inside a container created from that image.
|
|
90
|
-
- **FR-002**: The system MUST mount all `src` files and directories into the container at task startup so they are accessible inside the container.
|
|
91
|
-
- **FR-003**: The system MUST persist paths listed in `generates` in a container volume across runs.
|
|
92
|
-
- **FR-004**: The system MUST automatically mount the `src` and `generates` paths of all dependency tasks into a dependent container task.
|
|
93
|
-
- **FR-005**: The system MUST accept a `mounts` list supporting relative paths, absolute paths, and `$PWD`-prefixed expressions with optional target path suffixes.
|
|
94
|
-
- **FR-006**: The system MUST default to `sh` as the command execution shell for container tasks.
|
|
95
|
-
- **FR-007**: The system MUST accept a `shell` property on a task to override the execution shell.
|
|
96
|
-
- **FR-008**: The system MUST run container commands with the same UID/GID as the host user and set ownership of the working directory and mounts accordingly before each run.
|
|
97
|
-
|
|
98
|
-
### Key Entities
|
|
99
|
-
|
|
100
|
-
- **Container task**: A task with an `image` property. Additional attributes: `shell` (optional), `mounts` (optional list), `src` (optional), `generates` (optional).
|
|
101
|
-
- **Mount entry**: A string specifying a host path (relative, absolute, or `$PWD`-prefixed) optionally followed by `:` and a container target path.
|
|
102
|
-
|
|
103
|
-
## Success Criteria *(mandatory)*
|
|
104
|
-
|
|
105
|
-
### Measurable Outcomes
|
|
106
|
-
|
|
107
|
-
- **SC-001**: A container task command that prints the runtime version outputs the version from the declared image, not the host.
|
|
108
|
-
- **SC-002**: Files listed in `src` are readable inside the container during task execution.
|
|
109
|
-
- **SC-003**: A path listed in `generates` persists between separate hammerkit invocations without requiring re-installation.
|
|
110
|
-
- **SC-004**: A container task with `export: true` on a generate path results in that directory appearing on the host filesystem after the run.
|
|
111
|
-
- **SC-005**: Files created inside the container are owned by the host user's UID/GID on the host filesystem.
|
|
112
|
-
|
|
113
|
-
## Assumptions
|
|
114
|
-
|
|
115
|
-
- Container execution uses the local Docker daemon unless an environment is selected (see kubernetes.md).
|
|
116
|
-
- The working directory inside the container mirrors the host project directory structure.
|
|
117
|
-
- `$PWD` in mount expressions is expanded to the host working directory at task execution time.
|
|
118
|
-
- The `export` and `resetOnChange` flags on generate entries are described on the Task Overview page and apply equally to container tasks.
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
# Feature Specification: Task: Dependencies
|
|
2
|
-
|
|
3
|
-
**Feature Branch**: `001-current-state-specs`
|
|
4
|
-
|
|
5
|
-
**Created**: 2026-05-30
|
|
6
|
-
|
|
7
|
-
**Status**: Current State (reverse-specified from docs, hammerkit 1.6.0)
|
|
8
|
-
|
|
9
|
-
**Input**: Existing behavior documented in `docs/task/dependencies.md`
|
|
10
|
-
|
|
11
|
-
## User Scenarios & Testing *(mandatory)*
|
|
12
|
-
|
|
13
|
-
### User Story 1 - Chain tasks with dependencies (Priority: P1)
|
|
14
|
-
|
|
15
|
-
A developer has three tasks — `install`, `build`, and `publish` — where each step must complete before the next starts. They declare `deps` on each downstream task. When running `hammerkit publish`, hammerkit resolves the full chain and executes each task in dependency order.
|
|
16
|
-
|
|
17
|
-
**Why this priority**: Dependency ordering is the foundational orchestration primitive; without it users must run tasks manually in sequence.
|
|
18
|
-
|
|
19
|
-
**Independent Test**: Define a three-task chain and run the last one; observe that all three execute in correct order.
|
|
20
|
-
|
|
21
|
-
**Acceptance Scenarios**:
|
|
22
|
-
|
|
23
|
-
1. **Given** tasks A, B, C where B depends on A and C depends on B, **When** the user runs `hammerkit C`, **Then** A executes first, then B, then C.
|
|
24
|
-
2. **Given** a dependency chain where task A fails, **When** the user runs `hammerkit C`, **Then** B and C are not executed and the run aborts with a failure.
|
|
25
|
-
3. **Given** a dependency is already cached (sources unchanged), **When** the user runs a downstream task, **Then** the cached dependency is skipped and the downstream task still runs.
|
|
26
|
-
|
|
27
|
-
### User Story 2 - Deep dependency chains (Priority: P2)
|
|
28
|
-
|
|
29
|
-
A developer in a monorepo builds deeply nested dependency graphs. Hammerkit resolves chains of arbitrary depth as long as there are no cycles.
|
|
30
|
-
|
|
31
|
-
**Why this priority**: Monorepos commonly have multi-level dependency trees.
|
|
32
|
-
|
|
33
|
-
**Independent Test**: Create a 5-level dependency chain and confirm all levels execute in the correct order.
|
|
34
|
-
|
|
35
|
-
**Acceptance Scenarios**:
|
|
36
|
-
|
|
37
|
-
1. **Given** a dependency graph N levels deep with no cycles, **When** the leaf task is invoked, **Then** all ancestors execute in topological order.
|
|
38
|
-
2. **Given** a build file where task A depends on task B and task B depends on task A, **When** any task in the cycle is invoked, **Then** hammerkit reports an error and does not execute any task.
|
|
39
|
-
|
|
40
|
-
### Edge Cases
|
|
41
|
-
|
|
42
|
-
- A task with an empty `deps: []` list is treated the same as a task with no `deps` field.
|
|
43
|
-
- If any dependency in the chain fails, all pending downstream tasks are aborted.
|
|
44
|
-
- Circular dependency graphs (loops) are explicitly prohibited and must be detected at parse/plan time.
|
|
45
|
-
|
|
46
|
-
## Requirements *(mandatory)*
|
|
47
|
-
|
|
48
|
-
### Functional Requirements
|
|
49
|
-
|
|
50
|
-
- **FR-001**: The system MUST accept a `deps` list of task names on any task.
|
|
51
|
-
- **FR-002**: The system MUST execute all tasks listed in `deps` before executing the dependent task.
|
|
52
|
-
- **FR-003**: The system MUST abort execution of all pending tasks when any dependency task fails.
|
|
53
|
-
- **FR-004**: The system MUST support arbitrarily deep dependency chains.
|
|
54
|
-
- **FR-005**: The system MUST detect and reject cyclic dependency graphs (loops).
|
|
55
|
-
- **FR-006**: A dependency task that is cached (all sources unchanged) MUST be skipped without re-executing, and downstream tasks that still need to run MUST continue normally.
|
|
56
|
-
|
|
57
|
-
## Success Criteria *(mandatory)*
|
|
58
|
-
|
|
59
|
-
### Measurable Outcomes
|
|
60
|
-
|
|
61
|
-
- **SC-001**: Running a task with a two-level dependency chain results in the dependency executing first, followed by the requested task.
|
|
62
|
-
- **SC-002**: When a dependency fails, no tasks that depend on it (directly or transitively) are executed.
|
|
63
|
-
- **SC-003**: Cyclic dependencies cause hammerkit to exit with an error before executing any command.
|
|
64
|
-
- **SC-004**: A cached dependency does not re-execute; its downstream task still executes if needed.
|
|
65
|
-
|
|
66
|
-
## Assumptions
|
|
67
|
-
|
|
68
|
-
- `deps` values must reference tasks defined within the same build file or an included build file; cross-build-file references follow the include/namespace conventions described elsewhere.
|
|
69
|
-
- Dependency resolution is eager: all dependencies of a task are resolved before that task starts, not lazily during execution.
|
|
70
|
-
- Parallel execution of independent siblings within a dependency graph is outside the scope of this page and is not specified here.
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
# Feature Specification: Task: Extending
|
|
2
|
-
|
|
3
|
-
**Feature Branch**: `001-current-state-specs`
|
|
4
|
-
|
|
5
|
-
**Created**: 2026-05-30
|
|
6
|
-
|
|
7
|
-
**Status**: Current State (reverse-specified from docs, hammerkit 1.6.0)
|
|
8
|
-
|
|
9
|
-
**Input**: Existing behavior documented in `docs/task/extending.md`
|
|
10
|
-
|
|
11
|
-
## User Scenarios & Testing *(mandatory)*
|
|
12
|
-
|
|
13
|
-
### User Story 1 - Inherit a task from another build file (Priority: P1)
|
|
14
|
-
|
|
15
|
-
A developer in a monorepo has a shared `build.tsc.yaml` that defines standard `install` and `build` tasks. In each package's `.hammerkit.yaml` they write a task with `extend: tsc:build` to inherit all properties of the base task (sources, generates, commands, dependencies) with the working directory of the current file. This eliminates copy-pasting task definitions across packages.
|
|
16
|
-
|
|
17
|
-
**Why this priority**: Reducing duplication is the primary motivation for the extending feature and directly affects maintainability in larger projects.
|
|
18
|
-
|
|
19
|
-
**Independent Test**: Define a base task in an included file and a task that extends it with no overrides; run the extending task and verify it behaves identically to the base task.
|
|
20
|
-
|
|
21
|
-
**Acceptance Scenarios**:
|
|
22
|
-
|
|
23
|
-
1. **Given** a task with `extend: <namespace>:<task>` and no additional properties, **When** the task is run, **Then** it executes with all properties of the base task and the working directory of the current build file.
|
|
24
|
-
2. **Given** a task that extends a base task, **When** the base task defines `src`, `generates`, `deps`, and `cmds`, **Then** the extending task inherits all of those properties.
|
|
25
|
-
|
|
26
|
-
### User Story 2 - Override properties in an extended task (Priority: P1)
|
|
27
|
-
|
|
28
|
-
A developer extends a base task but needs to adjust specific properties — for example clearing all dependencies so the task runs standalone. They declare the overriding property alongside `extend`; the declared value replaces the inherited one.
|
|
29
|
-
|
|
30
|
-
**Why this priority**: Inheritance without override capability would force developers to extend-and-copy, defeating the purpose.
|
|
31
|
-
|
|
32
|
-
**Independent Test**: Extend a task that has `deps: [install]` and override with `deps: []`; run and verify the install task does not execute.
|
|
33
|
-
|
|
34
|
-
**Acceptance Scenarios**:
|
|
35
|
-
|
|
36
|
-
1. **Given** a task that extends a base task and declares `deps: []`, **When** the task is run, **Then** it runs without any dependency tasks, overriding the base `deps`.
|
|
37
|
-
2. **Given** a task that extends a base task and declares a new `cmds` list, **When** the task is run, **Then** the overriding commands execute, not the base commands.
|
|
38
|
-
3. **Given** a task that extends a base task and overrides only one property, **When** the task is run, **Then** all other properties are still inherited from the base task.
|
|
39
|
-
|
|
40
|
-
### Edge Cases
|
|
41
|
-
|
|
42
|
-
- The `extend` reference uses the `<namespace>:<task>` format where `namespace` matches an entry in the `includes` block of the same build file.
|
|
43
|
-
- Extending a task that itself extends another task (multi-level extend) is not described in the docs; behavior is not specified here.
|
|
44
|
-
- If the referenced base task or namespace does not exist, hammerkit should report an error at parse/plan time.
|
|
45
|
-
|
|
46
|
-
## Requirements *(mandatory)*
|
|
47
|
-
|
|
48
|
-
### Functional Requirements
|
|
49
|
-
|
|
50
|
-
- **FR-001**: The system MUST accept an `extend` field on a task whose value is a `<namespace>:<taskName>` reference to a task in an included build file.
|
|
51
|
-
- **FR-002**: A task with `extend` MUST inherit all properties of the referenced base task by default.
|
|
52
|
-
- **FR-003**: The working directory of an extending task MUST be the directory of the current build file, not the included file.
|
|
53
|
-
- **FR-004**: Any property declared on the extending task alongside `extend` MUST override the corresponding inherited property from the base task.
|
|
54
|
-
- **FR-005**: Properties not overridden on the extending task MUST retain their inherited values from the base task.
|
|
55
|
-
|
|
56
|
-
### Key Entities
|
|
57
|
-
|
|
58
|
-
- **Base task**: A task defined in an included build file that serves as a template.
|
|
59
|
-
- **Extending task**: A task in the current build file that references a base task via `extend` and optionally overrides specific properties.
|
|
60
|
-
- **Include**: A top-level `includes` entry mapping a namespace to a build file path, enabling the `<namespace>:<task>` reference syntax.
|
|
61
|
-
|
|
62
|
-
## Success Criteria *(mandatory)*
|
|
63
|
-
|
|
64
|
-
### Measurable Outcomes
|
|
65
|
-
|
|
66
|
-
- **SC-001**: An extending task with no overrides produces the same observable behavior as running the base task directly, using the current file's working directory.
|
|
67
|
-
- **SC-002**: An extending task with `deps: []` runs without executing any dependency tasks, even when the base task declares dependencies.
|
|
68
|
-
- **SC-003**: An extending task that overrides one property inherits all other properties unchanged from the base task.
|
|
69
|
-
|
|
70
|
-
## Assumptions
|
|
71
|
-
|
|
72
|
-
- The `includes` block is required to bring the base file into scope under a namespace; the `extend` syntax `<namespace>:<task>` must match an entry in `includes`.
|
|
73
|
-
- Only a single level of extension is documented; chained extension (a base that itself extends another) is treated as out of scope for this spec.
|
|
74
|
-
- Property merging is a full replacement, not a deep merge — for example, overriding `deps` replaces the entire list, not appends to it.
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
# Feature Specification: Task: Kubernetes
|
|
2
|
-
|
|
3
|
-
**Feature Branch**: `001-current-state-specs`
|
|
4
|
-
|
|
5
|
-
**Created**: 2026-05-30
|
|
6
|
-
|
|
7
|
-
**Status**: Current State (reverse-specified from docs, hammerkit 1.6.0)
|
|
8
|
-
|
|
9
|
-
**Input**: Existing behavior documented in `docs/task/kubernetes.md`
|
|
10
|
-
|
|
11
|
-
## User Scenarios & Testing *(mandatory)*
|
|
12
|
-
|
|
13
|
-
### User Story 1 - Run tasks on a Kubernetes cluster (Priority: P1)
|
|
14
|
-
|
|
15
|
-
A developer wants to run their hammerkit tasks on a Kubernetes cluster rather than the local Docker daemon. They declare an environment with a `kubernetes` target in the build file and pass `--env <name>` when running a task. Tasks execute as Kubernetes jobs, services run as deployments, and caching works identically to local runs.
|
|
16
|
-
|
|
17
|
-
**Why this priority**: This is the headline feature introduced in 1.6.0; it enables cloud-based and reproducible remote execution from the same build file.
|
|
18
|
-
|
|
19
|
-
**Independent Test**: Declare a kubernetes environment pointing to a reachable cluster context, run `hammerkit <task> --env <name>`, and verify the task pod appears in the cluster and the task completes successfully.
|
|
20
|
-
|
|
21
|
-
**Acceptance Scenarios**:
|
|
22
|
-
|
|
23
|
-
1. **Given** an `environments` block with a kubernetes target, **When** the user runs `hammerkit <task> --env <name>`, **Then** the task executes as a Kubernetes job in the specified cluster context.
|
|
24
|
-
2. **Given** a service referenced by a task via `needs`, **When** the environment is kubernetes, **Then** the service runs as a Kubernetes deployment and its healthcheck is translated into readiness/liveness probes.
|
|
25
|
-
3. **Given** no `--env` flag is passed, **When** the user runs a task, **Then** hammerkit uses the local Docker daemon regardless of declared environments.
|
|
26
|
-
|
|
27
|
-
### User Story 2 - Configure the cluster connection (Priority: P1)
|
|
28
|
-
|
|
29
|
-
An operator needs to specify which cluster context, namespace, and kubeconfig file to use. They fill in the kubernetes target fields; `context` is required and the rest default to sensible values.
|
|
30
|
-
|
|
31
|
-
**Why this priority**: Without correct cluster targeting, tasks would run on the wrong cluster or fail to authenticate.
|
|
32
|
-
|
|
33
|
-
**Independent Test**: Declare an environment with a specific `namespace`; run a task and verify the resulting job is created in that namespace.
|
|
34
|
-
|
|
35
|
-
**Acceptance Scenarios**:
|
|
36
|
-
|
|
37
|
-
1. **Given** a kubernetes target with only `context` set, **When** a task runs in that environment, **Then** hammerkit uses `$HOME/.kube/config` and the default namespace.
|
|
38
|
-
2. **Given** a kubernetes target with `kubeconfig` and `namespace` set, **When** a task runs, **Then** the specified kubeconfig file and namespace are used.
|
|
39
|
-
|
|
40
|
-
### User Story 3 - Expose services via ingresses (Priority: P2)
|
|
41
|
-
|
|
42
|
-
An operator wants a deployed service to be reachable from outside the cluster. They add an `ingresses` entry under the kubernetes target with a hostname and service name. Hammerkit creates an Ingress (or Gateway API HTTPRoute) resource pointing to the service.
|
|
43
|
-
|
|
44
|
-
**Why this priority**: Ingress configuration enables integration testing and end-to-end workflows that require external access to deployed services.
|
|
45
|
-
|
|
46
|
-
**Independent Test**: Declare an ingress entry for a service, run in the kubernetes environment, and verify an Ingress resource with the correct host and service reference is created in the cluster.
|
|
47
|
-
|
|
48
|
-
**Acceptance Scenarios**:
|
|
49
|
-
|
|
50
|
-
1. **Given** an ingress entry with `host`, `service`, and `servicePort`, **When** the environment is activated, **Then** hammerkit creates a Kubernetes Ingress resource routing that host to the service.
|
|
51
|
-
2. **Given** an ingress entry with `kind: httproute` and a `gateway` name, **When** the environment is activated, **Then** hammerkit creates a Gateway API HTTPRoute resource attached to the named Gateway.
|
|
52
|
-
3. **Given** an ingress entry with both `ingress` and `httproute` kinds in the same list, **When** the environment is activated, **Then** both resource types are created.
|
|
53
|
-
|
|
54
|
-
### User Story 4 - Target a remote Docker daemon (Priority: P3)
|
|
55
|
-
|
|
56
|
-
A developer wants to run tasks against a remote Docker daemon instead of the local one. They declare an environment with a `docker` target and optionally supply a `host` address.
|
|
57
|
-
|
|
58
|
-
**Why this priority**: Remote Docker is an alternative execution target that shares the environment declaration mechanism.
|
|
59
|
-
|
|
60
|
-
**Independent Test**: Declare a docker environment with a `host` pointing to a remote daemon; run a task with `--env <name>` and verify it executes on the remote daemon.
|
|
61
|
-
|
|
62
|
-
**Acceptance Scenarios**:
|
|
63
|
-
|
|
64
|
-
1. **Given** a docker environment target with a `host` address, **When** `hammerkit <task> --env <name>` is run, **Then** the task executes against the remote Docker daemon at that address.
|
|
65
|
-
|
|
66
|
-
### User Story 5 - Use `--env` with store and restore commands (Priority: P2)
|
|
67
|
-
|
|
68
|
-
A CI engineer stores build cache from a cluster run and restores it on another machine. The `--env` flag is available on the store and restore CLI commands, not just execute.
|
|
69
|
-
|
|
70
|
-
**Why this priority**: Remote cache round-tripping requires environment selection at storage time to address the right cluster outputs.
|
|
71
|
-
|
|
72
|
-
**Independent Test**: Run `hammerkit store --env <name>` after a cluster-based build and verify the result is stored correctly.
|
|
73
|
-
|
|
74
|
-
**Acceptance Scenarios**:
|
|
75
|
-
|
|
76
|
-
1. **Given** a completed kubernetes-environment task run, **When** the user runs `hammerkit store --env <name>`, **Then** the task results from the cluster are stored.
|
|
77
|
-
2. **Given** stored results from a cluster, **When** the user runs `hammerkit restore --env <name>`, **Then** the results are restored into the cluster environment.
|
|
78
|
-
|
|
79
|
-
### Edge Cases
|
|
80
|
-
|
|
81
|
-
- `context` is required for a kubernetes target; omitting it should cause a validation error.
|
|
82
|
-
- `kind: httproute` requires Gateway API CRDs and a `Gateway` resource to be installed in the cluster; hammerkit does not install these prerequisites.
|
|
83
|
-
- The `gateway` field is required when `kind: httproute` is used; `gatewayNamespace` is optional.
|
|
84
|
-
- The same environment declaration supplies cluster connection details for port-forward Kubernetes services (described in the service/kubernetes page), avoiding repetition.
|
|
85
|
-
|
|
86
|
-
## Requirements *(mandatory)*
|
|
87
|
-
|
|
88
|
-
### Functional Requirements
|
|
89
|
-
|
|
90
|
-
- **FR-001**: The system MUST accept a top-level `environments` block where each entry targets either `kubernetes` or `docker`.
|
|
91
|
-
- **FR-002**: The system MUST accept a `--env <name>` CLI flag on the execute, store, and restore commands.
|
|
92
|
-
- **FR-003**: When `--env` is not supplied, the system MUST use the local Docker daemon.
|
|
93
|
-
- **FR-004**: A kubernetes target MUST require a `context` field identifying the kube context (cluster + user).
|
|
94
|
-
- **FR-005**: A kubernetes target MUST support optional `namespace`, `kubeconfig`, and `ingresses` fields.
|
|
95
|
-
- **FR-006**: When `kubeconfig` is not specified, the system MUST default to `$HOME/.kube/config`.
|
|
96
|
-
- **FR-007**: The system MUST execute tasks as Kubernetes jobs and container services as Kubernetes deployments when running in a kubernetes environment.
|
|
97
|
-
- **FR-008**: A service healthcheck MUST be translated into Kubernetes readiness and liveness probes on the corresponding deployment.
|
|
98
|
-
- **FR-009**: The system MUST support an `ingresses` list on a kubernetes target, creating either an Ingress or a Gateway API HTTPRoute resource per entry.
|
|
99
|
-
- **FR-010**: An ingress entry MUST require `host` and `service` fields; `kind` (default `ingress`), `servicePort`, and `path` are optional.
|
|
100
|
-
- **FR-011**: An `httproute` ingress entry MUST require a `gateway` field; `gatewayNamespace` is optional.
|
|
101
|
-
- **FR-012**: A docker environment target MUST support an optional `host` field for a remote Docker daemon address.
|
|
102
|
-
- **FR-013**: Task caching MUST function identically in kubernetes environments as in local docker runs.
|
|
103
|
-
|
|
104
|
-
### Key Entities
|
|
105
|
-
|
|
106
|
-
- **Environment**: A named entry in `environments` specifying either a `kubernetes` or `docker` execution target.
|
|
107
|
-
- **Kubernetes target**: Configuration for cluster execution: `context` (required), `namespace`, `kubeconfig`, `ingresses`.
|
|
108
|
-
- **Docker target**: Configuration for docker execution: `host` (optional).
|
|
109
|
-
- **Ingress entry**: Route configuration with `kind`, `host`, `service`, `servicePort`, `path`, `gateway`, `gatewayNamespace`.
|
|
110
|
-
|
|
111
|
-
## Success Criteria *(mandatory)*
|
|
112
|
-
|
|
113
|
-
### Measurable Outcomes
|
|
114
|
-
|
|
115
|
-
- **SC-001**: A task run with `--env <kubernetes-env>` creates a job in the target cluster and produces the same output as a local run.
|
|
116
|
-
- **SC-002**: A service with a healthcheck deployed via a kubernetes environment has readiness and liveness probes on its deployment.
|
|
117
|
-
- **SC-003**: An ingress entry with `kind: ingress` creates a Kubernetes Ingress resource with the correct host and backend service.
|
|
118
|
-
- **SC-004**: An ingress entry with `kind: httproute` creates a Gateway API HTTPRoute resource attached to the specified Gateway.
|
|
119
|
-
- **SC-005**: Without `--env`, tasks run on the local Docker daemon regardless of declared environments.
|
|
120
|
-
|
|
121
|
-
## Assumptions
|
|
122
|
-
|
|
123
|
-
- "Same caching behavior" means checksum/modify-date/none methods and remote backends all work the same way in a kubernetes environment as locally.
|
|
124
|
-
- The kubernetes environment feature was introduced in hammerkit 1.6.0; earlier versions do not support it.
|
|
125
|
-
- Port-forward Kubernetes services (described separately in service/kubernetes.md) can reuse the cluster connection declared in an environment via `--env`, but this page does not specify that detail further.
|
package/specs/task/needs/spec.md
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
# Feature Specification: Task: Needs
|
|
2
|
-
|
|
3
|
-
**Feature Branch**: `001-current-state-specs`
|
|
4
|
-
|
|
5
|
-
**Created**: 2026-05-30
|
|
6
|
-
|
|
7
|
-
**Status**: Current State (reverse-specified from docs, hammerkit 1.6.0)
|
|
8
|
-
|
|
9
|
-
**Input**: Existing behavior documented in `docs/task/needs.md`
|
|
10
|
-
|
|
11
|
-
## User Scenarios & Testing *(mandatory)*
|
|
12
|
-
|
|
13
|
-
### User Story 1 - Start a service before a task (Priority: P1)
|
|
14
|
-
|
|
15
|
-
A developer has a task that requires a database to be running. They declare the database service in the `services` block with a healthcheck command and reference it in the task's `needs` list. When the task is executed, hammerkit starts the service automatically and waits until the healthcheck passes before running any task commands.
|
|
16
|
-
|
|
17
|
-
**Why this priority**: Tasks that depend on services would fail silently or non-deterministically without this coordination mechanism.
|
|
18
|
-
|
|
19
|
-
**Independent Test**: Define a service with a healthcheck and a task with `needs: [<service>]`; run the task and verify the service is reachable before the first command executes.
|
|
20
|
-
|
|
21
|
-
**Acceptance Scenarios**:
|
|
22
|
-
|
|
23
|
-
1. **Given** a service with a healthcheck and a task that lists that service in `needs`, **When** the user runs the task, **Then** hammerkit starts the service and waits for the healthcheck to pass before executing the task's commands.
|
|
24
|
-
2. **Given** a task with `needs: [postgres]` and a postgres service whose healthcheck fails continuously, **When** the task is run, **Then** the task does not start and hammerkit reports that the service is not ready.
|
|
25
|
-
3. **Given** multiple tasks that each list the same service in `needs`, **When** those tasks run together, **Then** the service is started once and shared rather than started per-task.
|
|
26
|
-
|
|
27
|
-
### Edge Cases
|
|
28
|
-
|
|
29
|
-
- A service referenced in `needs` but not defined in the `services` block should cause an error at parse/plan time.
|
|
30
|
-
- If no healthcheck is defined on a service, hammerkit starts the task immediately after launching the service container without readiness gating.
|
|
31
|
-
- A task with an empty `needs: []` list is treated the same as a task with no `needs` field.
|
|
32
|
-
|
|
33
|
-
## Requirements *(mandatory)*
|
|
34
|
-
|
|
35
|
-
### Functional Requirements
|
|
36
|
-
|
|
37
|
-
- **FR-001**: The system MUST accept a `needs` list of service names on any task.
|
|
38
|
-
- **FR-002**: The system MUST start every service listed in a task's `needs` before executing that task's commands.
|
|
39
|
-
- **FR-003**: When a service declares a `healthcheck`, the system MUST wait for the healthcheck to succeed before the dependent task starts.
|
|
40
|
-
- **FR-004**: The system MUST NOT start a task whose `needs` services have not yet passed their healthchecks.
|
|
41
|
-
|
|
42
|
-
### Key Entities
|
|
43
|
-
|
|
44
|
-
- **Service**: A long-running container process declared in the top-level `services` block. Key attributes: `image`, `healthcheck` (optional, with `cmd`).
|
|
45
|
-
- **Needs**: A list of service names on a task that declares runtime dependencies on those services.
|
|
46
|
-
|
|
47
|
-
## Success Criteria *(mandatory)*
|
|
48
|
-
|
|
49
|
-
### Measurable Outcomes
|
|
50
|
-
|
|
51
|
-
- **SC-001**: A task with `needs: [postgres]` does not execute its first command until the postgres service's healthcheck returns success.
|
|
52
|
-
- **SC-002**: When a service healthcheck never passes, the dependent task never starts and hammerkit reports a failure.
|
|
53
|
-
- **SC-003**: A service listed in `needs` by multiple tasks is started exactly once per run.
|
|
54
|
-
|
|
55
|
-
## Assumptions
|
|
56
|
-
|
|
57
|
-
- `needs` expresses a runtime service dependency, distinct from `deps` which expresses a task execution dependency.
|
|
58
|
-
- Healthcheck polling interval and timeout are implementation details not specified in the docs; they are assumed to be reasonable defaults.
|
|
59
|
-
- Services are stopped by hammerkit after all tasks that need them have completed, though the exact lifecycle is not described on this page.
|
package/specs/task/spec.md
DELETED
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
# Feature Specification: Task: Overview
|
|
2
|
-
|
|
3
|
-
**Feature Branch**: `001-current-state-specs`
|
|
4
|
-
|
|
5
|
-
**Created**: 2026-05-30
|
|
6
|
-
|
|
7
|
-
**Status**: Current State (reverse-specified from docs, hammerkit 1.6.0)
|
|
8
|
-
|
|
9
|
-
**Input**: Existing behavior documented in `docs/task/README.md`
|
|
10
|
-
|
|
11
|
-
## User Scenarios & Testing *(mandatory)*
|
|
12
|
-
|
|
13
|
-
### User Story 1 - Run a minimal task (Priority: P1)
|
|
14
|
-
|
|
15
|
-
A developer defines a task with only a list of commands in `.hammerkit.yaml` and runs it. Hammerkit executes each command in sequence. No source or output declarations are required for the most basic use case.
|
|
16
|
-
|
|
17
|
-
**Why this priority**: This is the entry-point experience; every other feature builds on it.
|
|
18
|
-
|
|
19
|
-
**Independent Test**: Create a `.hammerkit.yaml` with a single `echo` command task and run it — the output should appear in the terminal.
|
|
20
|
-
|
|
21
|
-
**Acceptance Scenarios**:
|
|
22
|
-
|
|
23
|
-
1. **Given** a `.hammerkit.yaml` with a task containing only `cmds`, **When** the user runs `hammerkit <task>`, **Then** each command executes in order and the process exits with the command's exit code.
|
|
24
|
-
|
|
25
|
-
### User Story 2 - Declare source files to enable caching (Priority: P1)
|
|
26
|
-
|
|
27
|
-
A developer adds a `src` list to a task. On subsequent runs where none of the listed files have changed, hammerkit skips execution entirely and reports the task as cached.
|
|
28
|
-
|
|
29
|
-
**Why this priority**: Source-based caching is the primary performance mechanism for incremental builds.
|
|
30
|
-
|
|
31
|
-
**Independent Test**: Run the task twice with no file changes; the second run must be skipped/cached.
|
|
32
|
-
|
|
33
|
-
**Acceptance Scenarios**:
|
|
34
|
-
|
|
35
|
-
1. **Given** a task with `src` files defined, **When** those files are unchanged since the last successful run, **Then** the task is skipped.
|
|
36
|
-
2. **Given** a task with `src` files defined, **When** one source file changes, **Then** the task re-executes.
|
|
37
|
-
|
|
38
|
-
### User Story 3 - Declare generated output files (Priority: P2)
|
|
39
|
-
|
|
40
|
-
A developer adds a `generates` list so hammerkit knows which output directories a task produces. Generated files can optionally be exported back to the workspace or reset before each run.
|
|
41
|
-
|
|
42
|
-
**Why this priority**: Tracking outputs enables archiving/restore and correct incremental behaviour.
|
|
43
|
-
|
|
44
|
-
**Independent Test**: Run a container task with `export: true` on a generate path and verify the directory appears in the host workspace after the run.
|
|
45
|
-
|
|
46
|
-
**Acceptance Scenarios**:
|
|
47
|
-
|
|
48
|
-
1. **Given** a container task with `generates` and `export: true`, **When** the task completes, **Then** the generated directory is copied into the host workspace.
|
|
49
|
-
2. **Given** a task with `generates` and `resetOnChange: true`, **When** the task re-runs after a source change, **Then** the output directory is wiped before execution begins.
|
|
50
|
-
3. **Given** a container task with `generates` but no `export` flag, **When** the task completes, **Then** the output stays inside the container volume and is not copied to the host.
|
|
51
|
-
|
|
52
|
-
### Edge Cases
|
|
53
|
-
|
|
54
|
-
- A task with no `src` declaration is always executed (never skipped by caching).
|
|
55
|
-
- `resetOnChange: true` only wipes the directory when the task actually re-runs (i.e. cache miss); it has no effect when the task is skipped.
|
|
56
|
-
- `export: true` is only meaningful for container tasks; for local tasks outputs are already on the host filesystem.
|
|
57
|
-
|
|
58
|
-
## Requirements *(mandatory)*
|
|
59
|
-
|
|
60
|
-
### Functional Requirements
|
|
61
|
-
|
|
62
|
-
- **FR-001**: The system MUST execute the commands of a task in the order they are declared under `cmds`.
|
|
63
|
-
- **FR-002**: The system MUST accept a `src` list of files, directories, or glob patterns on a task and use it to determine whether the task can be skipped.
|
|
64
|
-
- **FR-003**: The system MUST accept a `generates` list on a task that identifies output files or directories produced by the task.
|
|
65
|
-
- **FR-004**: When a generate entry carries `export: true`, the system MUST copy that path from the container volume into the host workspace after the task succeeds.
|
|
66
|
-
- **FR-005**: When a generate entry carries `resetOnChange: true`, the system MUST wipe that output directory before re-executing the task.
|
|
67
|
-
- **FR-006**: The system MUST support an optional `description` field on a task for human-readable documentation.
|
|
68
|
-
|
|
69
|
-
### Key Entities
|
|
70
|
-
|
|
71
|
-
- **Task**: The primary unit of work. Key attributes: `cmds` (required), `src` (optional), `generates` (optional), `description` (optional).
|
|
72
|
-
- **Generate entry**: An output path, optionally decorated with `export` (boolean) and `resetOnChange` (boolean).
|
|
73
|
-
|
|
74
|
-
## Success Criteria *(mandatory)*
|
|
75
|
-
|
|
76
|
-
### Measurable Outcomes
|
|
77
|
-
|
|
78
|
-
- **SC-001**: A task with no `src` always runs when invoked.
|
|
79
|
-
- **SC-002**: A task with unchanged `src` files is skipped on the second run without executing any command.
|
|
80
|
-
- **SC-003**: After a container task with `export: true` completes, the generated path exists on the host filesystem.
|
|
81
|
-
- **SC-004**: After a container task with `resetOnChange: true` re-runs, no files from a previous run remain in the output directory before the new commands execute.
|
|
82
|
-
|
|
83
|
-
## Assumptions
|
|
84
|
-
|
|
85
|
-
- The minimal task form (only `cmds`) is always a local (non-container) task unless an `image` is specified.
|
|
86
|
-
- "Generates" store output inside a container volume by default; the `export` flag is only relevant for container tasks.
|
|
87
|
-
- The `description` field is display-only and does not affect execution.
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
# Feature Specification: Task: Watching
|
|
2
|
-
|
|
3
|
-
**Feature Branch**: `001-current-state-specs`
|
|
4
|
-
|
|
5
|
-
**Created**: 2026-05-30
|
|
6
|
-
|
|
7
|
-
**Status**: Current State (reverse-specified from docs, hammerkit 1.6.0)
|
|
8
|
-
|
|
9
|
-
**Input**: Existing behavior documented in `docs/task/watching.md`
|
|
10
|
-
|
|
11
|
-
## User Scenarios & Testing *(mandatory)*
|
|
12
|
-
|
|
13
|
-
### User Story 1 - Restart a task automatically on source file changes (Priority: P1)
|
|
14
|
-
|
|
15
|
-
A developer runs an API server task and wants it to restart whenever the source code changes. They run `hammerkit <task> --watch`. Hammerkit watches the task's declared `src` files and folders; when a change is detected it restarts the task.
|
|
16
|
-
|
|
17
|
-
**Why this priority**: Watch mode is the primary developer-experience feature for iterative development workflows.
|
|
18
|
-
|
|
19
|
-
**Independent Test**: Start a task with `--watch` and a `src` folder; modify a file in the folder and observe that the task process is terminated and restarted.
|
|
20
|
-
|
|
21
|
-
**Acceptance Scenarios**:
|
|
22
|
-
|
|
23
|
-
1. **Given** a task with `src` defined and the `--watch` flag, **When** a file in `src` changes, **Then** hammerkit terminates the running task and restarts it.
|
|
24
|
-
2. **Given** a task with `src` defined and the `--watch` flag, **When** no files change, **Then** the task continues running without interruption.
|
|
25
|
-
|
|
26
|
-
### User Story 2 - Mark a self-managing task as continuous (Priority: P2)
|
|
27
|
-
|
|
28
|
-
A developer uses Angular CLI's `ng serve` which handles its own file watching and incremental rebuilding internally. They mark the task with `continuous: true`. When watch mode is active, hammerkit does not watch the `src` directory for that task, allowing the tool to manage its own restart cycle.
|
|
29
|
-
|
|
30
|
-
**Why this priority**: Self-managing tasks (Angular, webpack --watch, etc.) would otherwise be redundantly restarted by hammerkit on top of their own internal watching, causing conflicts.
|
|
31
|
-
|
|
32
|
-
**Independent Test**: Mark a task `continuous: true` and run with `--watch`; modify a source file and verify hammerkit does NOT restart the task process (the task handles its own reload).
|
|
33
|
-
|
|
34
|
-
**Acceptance Scenarios**:
|
|
35
|
-
|
|
36
|
-
1. **Given** a task with `continuous: true` and the `--watch` flag, **When** a file in `src` changes, **Then** hammerkit does NOT restart the task process.
|
|
37
|
-
2. **Given** a task with `continuous: true` but WITHOUT `--watch`, **When** the task is run normally, **Then** the `continuous` flag has no visible effect on single-run behavior.
|
|
38
|
-
3. **Given** a mix of continuous and non-continuous tasks in watch mode, **When** a source file for the non-continuous task changes, **Then** only the non-continuous task is restarted.
|
|
39
|
-
|
|
40
|
-
### Edge Cases
|
|
41
|
-
|
|
42
|
-
- A task without `src` declared has nothing to watch; behavior with `--watch` and no `src` is not specified (assumed to run once and stay alive without restart triggers).
|
|
43
|
-
- `continuous: true` only suppresses hammerkit-level file watching; it does not affect how the task's process itself behaves.
|
|
44
|
-
- Watch mode with a container task follows the same restart semantics as a local task.
|
|
45
|
-
|
|
46
|
-
## Requirements *(mandatory)*
|
|
47
|
-
|
|
48
|
-
### Functional Requirements
|
|
49
|
-
|
|
50
|
-
- **FR-001**: The system MUST support a `--watch` CLI flag on the execute command.
|
|
51
|
-
- **FR-002**: When `--watch` is active, the system MUST monitor the `src` files and folders of a task for changes.
|
|
52
|
-
- **FR-003**: When a change is detected in watched sources, the system MUST terminate the running task process and restart it.
|
|
53
|
-
- **FR-004**: The system MUST accept a `continuous: true` field on a task.
|
|
54
|
-
- **FR-005**: When a task has `continuous: true` and watch mode is active, the system MUST NOT watch the task's `src` for changes or restart it.
|
|
55
|
-
|
|
56
|
-
## Success Criteria *(mandatory)*
|
|
57
|
-
|
|
58
|
-
### Measurable Outcomes
|
|
59
|
-
|
|
60
|
-
- **SC-001**: Modifying a source file of a watched non-continuous task causes the task to restart within a reasonable detection window.
|
|
61
|
-
- **SC-002**: Modifying a source file of a watched continuous task does NOT cause hammerkit to restart that task process.
|
|
62
|
-
- **SC-003**: A task without `continuous: true` runs and restarts under `--watch` as expected.
|
|
63
|
-
|
|
64
|
-
## Assumptions
|
|
65
|
-
|
|
66
|
-
- Watch mode monitors the same `src` paths used for caching; the two features share source declarations.
|
|
67
|
-
- The file-system polling or event mechanism used for watching is an implementation detail not described in the docs.
|
|
68
|
-
- `continuous: true` is intended for tasks that have their own internal watch loop (e.g., webpack, ng serve, jest --watch).
|
|
69
|
-
- Watch mode operates for the lifetime of the hammerkit process; Ctrl-C stops watching and terminates all running tasks.
|