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,114 +0,0 @@
|
|
|
1
|
-
# Feature Specification: Build File: Caches
|
|
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/build-file/caches.md`
|
|
10
|
-
|
|
11
|
-
## User Scenarios & Testing *(mandatory)*
|
|
12
|
-
|
|
13
|
-
### User Story 1 - Skip unchanged tasks using the default local cache (Priority: P1)
|
|
14
|
-
|
|
15
|
-
A developer runs hammerkit for the first time. Results are stored in the local cache (`~/.hammerkit/remote-cache`). On subsequent runs, hammerkit compares source file checksums and skips tasks whose inputs have not changed, saving build time without any configuration.
|
|
16
|
-
|
|
17
|
-
**Why this priority**: Local caching is the out-of-the-box experience for every hammerkit user; it is always active.
|
|
18
|
-
|
|
19
|
-
**Independent Test**: Run a task twice without modifying source files. Confirm the second run skips execution. Modify a source file and confirm the task runs again.
|
|
20
|
-
|
|
21
|
-
**Acceptance Scenarios**:
|
|
22
|
-
|
|
23
|
-
1. **Given** a task with `src:` files that have not changed since the last run, **When** the task is invoked, **Then** hammerkit skips execution and reports the task as up-to-date.
|
|
24
|
-
2. **Given** a task with `src:` files where at least one has changed, **When** the task is invoked, **Then** hammerkit executes the task commands.
|
|
25
|
-
|
|
26
|
-
### User Story 2 - Share build results across machines via a remote cache (Priority: P1)
|
|
27
|
-
|
|
28
|
-
A team uses an S3 bucket as a shared cache. When a developer or CI job completes a task, the result is pushed to S3. The next machine to request the same task pulls the cached result and skips execution, dramatically reducing CI time.
|
|
29
|
-
|
|
30
|
-
**Why this priority**: Remote caching is the primary new capability in 1.6.0 and a key differentiator for team and CI workflows.
|
|
31
|
-
|
|
32
|
-
**Independent Test**: Declare an S3-backed cache, run a task on machine A and confirm the result is pushed. On machine B (with empty local cache), run the same task and confirm it is pulled and skipped.
|
|
33
|
-
|
|
34
|
-
**Acceptance Scenarios**:
|
|
35
|
-
|
|
36
|
-
1. **Given** a named cache with `type: s3` is declared and a task references it, **When** a task completes successfully, **Then** the result is pushed to the configured S3 bucket.
|
|
37
|
-
2. **Given** the S3 bucket contains a cached result for the current source checksum, **When** the task is invoked on a machine without a local result, **Then** hammerkit pulls from the bucket and skips task execution.
|
|
38
|
-
3. **Given** the S3 backend is unreachable, **When** a task runs, **Then** hammerkit emits a warning and continues — the pull or push failure does NOT fail the build.
|
|
39
|
-
|
|
40
|
-
### User Story 3 - Override the default cache for all tasks (Priority: P2)
|
|
41
|
-
|
|
42
|
-
A team wants all tasks to use a remote S3 bucket without modifying each task individually. They declare a `caches.default` entry in the build file, redirecting the implicit default cache to their S3 bucket.
|
|
43
|
-
|
|
44
|
-
**Why this priority**: This is the recommended way to enable remote caching for an entire project with a single configuration change.
|
|
45
|
-
|
|
46
|
-
**Independent Test**: Declare `caches.default` pointing to S3, run several tasks that do not explicitly reference any cache, and confirm each pushes results to the S3 bucket.
|
|
47
|
-
|
|
48
|
-
**Acceptance Scenarios**:
|
|
49
|
-
|
|
50
|
-
1. **Given** `caches.default` is declared with an S3 backend, **When** a task that does not reference any named cache runs and succeeds, **Then** its result is pushed to the S3 bucket specified in `caches.default`.
|
|
51
|
-
|
|
52
|
-
### User Story 4 - Choose a change-detection method for a cache (Priority: P2)
|
|
53
|
-
|
|
54
|
-
A developer with a large source tree wants faster change detection. They configure a named cache to use `modify-date` instead of `checksum`. A CI workflow that must always rebuild configures a cache with `none` method.
|
|
55
|
-
|
|
56
|
-
**Why this priority**: Method selection lets users trade precision for speed or disable skipping entirely for correctness-critical pipelines.
|
|
57
|
-
|
|
58
|
-
**Independent Test**: Configure a task with `method: none`; run it twice and confirm it always executes. Configure a task with `method: modify-date`; run it twice without touching files and confirm it is skipped.
|
|
59
|
-
|
|
60
|
-
**Acceptance Scenarios**:
|
|
61
|
-
|
|
62
|
-
1. **Given** a cache with `method: none`, **When** any task using that cache is invoked, **Then** the task always executes, regardless of source file state.
|
|
63
|
-
2. **Given** a cache with `method: checksum` (default), **When** source file content is identical to the previous run, **Then** the task is skipped.
|
|
64
|
-
3. **Given** a cache with `method: modify-date`, **When** source file modification timestamps are unchanged, **Then** the task is skipped without computing checksums.
|
|
65
|
-
|
|
66
|
-
### Edge Cases
|
|
67
|
-
|
|
68
|
-
- Two built-in caches are always available: `default` (local backend, checksum method) and `none` (disables skipping).
|
|
69
|
-
- Declaring `caches.default` overrides the built-in `default` cache for all tasks that do not explicitly reference a cache.
|
|
70
|
-
- The `--cache` CLI flag overrides the method for implicit (non-explicitly-referenced) tasks at runtime and takes precedence over what `caches.default` declares for the method.
|
|
71
|
-
- S3 credentials are never stored in the build file; they are read from the AWS SDK credential chain.
|
|
72
|
-
- Azure Blob Storage is explicitly unsupported through the built-in `s3` backend.
|
|
73
|
-
- Any S3-compatible service (MinIO, Cloudflare R2, GCS via HMAC keys) can be used via the `endpoint` field.
|
|
74
|
-
- `forcePathStyle` defaults to `true` when a custom `endpoint` is set.
|
|
75
|
-
|
|
76
|
-
## Requirements *(mandatory)*
|
|
77
|
-
|
|
78
|
-
### Functional Requirements
|
|
79
|
-
|
|
80
|
-
- **FR-001**: The build file MUST support a top-level `caches:` map where each entry declares a named cache with a `method` and a `backend`.
|
|
81
|
-
- **FR-002**: Each cache entry MUST support a `method` field with values `checksum` (default), `modify-date`, or `none`.
|
|
82
|
-
- **FR-003**: Each cache entry MUST support a `backend` field specifying the storage backend type (`local` or `s3`).
|
|
83
|
-
- **FR-004**: The `local` backend MUST accept an optional `path` field; when omitted it MUST default to `~/.hammerkit/remote-cache`.
|
|
84
|
-
- **FR-005**: The `s3` backend MUST require a `bucket` field and accept optional `region`, `endpoint`, `prefix`, and `forcePathStyle` fields.
|
|
85
|
-
- **FR-006**: S3 credentials MUST be sourced from the AWS SDK credential chain and MUST NOT be stored in the build file.
|
|
86
|
-
- **FR-007**: Before a task runs, the system MUST attempt to pull a cached result from the backend if no local result is present; if the sources are unchanged, the task MUST be skipped.
|
|
87
|
-
- **FR-008**: After a task completes successfully, the system MUST push the result to the configured backend.
|
|
88
|
-
- **FR-009**: Backend errors during pull or push MUST emit a warning and MUST NOT cause the build to fail.
|
|
89
|
-
- **FR-010**: Declaring `caches.default` MUST override the built-in default cache for all tasks that do not explicitly reference a named cache.
|
|
90
|
-
- **FR-011**: A built-in `none` cache MUST always be available, which disables task skipping entirely.
|
|
91
|
-
- **FR-012**: A task MUST be able to reference a named cache by setting `cache.name` in its task configuration.
|
|
92
|
-
|
|
93
|
-
### Key Entities
|
|
94
|
-
|
|
95
|
-
- **Cache**: A named entry in the `caches:` map; contains a `method` (change detection strategy) and a `backend` (storage configuration).
|
|
96
|
-
- **Local Backend**: Stores cache entries on the local filesystem; configurable via a `path` field.
|
|
97
|
-
- **S3 Backend**: Stores cache entries in an S3-compatible bucket; configurable via `bucket`, `region`, `endpoint`, `prefix`, and `forcePathStyle`.
|
|
98
|
-
|
|
99
|
-
## Success Criteria *(mandatory)*
|
|
100
|
-
|
|
101
|
-
### Measurable Outcomes
|
|
102
|
-
|
|
103
|
-
- **SC-001**: An unchanged task is skipped on the second invocation when using the default local cache with `checksum` method.
|
|
104
|
-
- **SC-002**: A task result pushed from one machine is pulled and skips execution on a second machine using the same S3-backed cache configuration.
|
|
105
|
-
- **SC-003**: A build completes successfully even when the configured S3 backend is unreachable, with a warning visible in the output.
|
|
106
|
-
- **SC-004**: Declaring `caches.default` with an S3 backend causes all tasks (that do not explicitly reference a different cache) to push their results to that S3 bucket.
|
|
107
|
-
- **SC-005**: A task using `method: none` executes on every invocation regardless of whether source files have changed.
|
|
108
|
-
|
|
109
|
-
## Assumptions
|
|
110
|
-
|
|
111
|
-
- The `cache.name` field on a task (referencing a named cache) is the task-level hook into this feature; full task-level caching options are covered by the task/caching spec page.
|
|
112
|
-
- The `--cache` CLI flag controls the method for tasks using the implicit default cache; it does not affect tasks that explicitly reference a named cache by name.
|
|
113
|
-
- "Pulling" a cached result means restoring the task's `generates:` outputs so downstream tasks can use them without re-running the producing task.
|
|
114
|
-
- The `checksum` method hashes file content; `modify-date` compares filesystem mtime; both apply to the files listed in the task's `src:` field.
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
# Feature Specification: Build File: Environment Variables
|
|
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/build-file/environment-variables.md`
|
|
10
|
-
|
|
11
|
-
## User Scenarios & Testing *(mandatory)*
|
|
12
|
-
|
|
13
|
-
### User Story 1 - Pass shell environment variables into a task (Priority: P1)
|
|
14
|
-
|
|
15
|
-
A developer needs a task to use a variable (e.g. `VERSION`) that is set in the shell before running hammerkit. They declare the variable in the task's `envs:` block referencing the shell value (`$VERSION`). Hammerkit validates the variable is set and injects it into the task execution environment.
|
|
16
|
-
|
|
17
|
-
**Why this priority**: This is the most common env-var pattern; it prevents silent failures from unset variables.
|
|
18
|
-
|
|
19
|
-
**Independent Test**: Export a variable in the shell, declare it in the task `envs:`, run the task, and confirm the command receives the correct value. Then unset the variable and confirm hammerkit throws an error rather than passing an empty value.
|
|
20
|
-
|
|
21
|
-
**Acceptance Scenarios**:
|
|
22
|
-
|
|
23
|
-
1. **Given** a shell variable `VERSION=1.0.0` is exported, **When** a task declares `VERSION: $VERSION` in its `envs:` and runs `echo $VERSION`, **Then** the output is `1.0.0`.
|
|
24
|
-
2. **Given** a task declares `VERSION: $VERSION` but the shell variable is not set, **When** the task is invoked, **Then** hammerkit throws an error before executing any commands.
|
|
25
|
-
|
|
26
|
-
### User Story 2 - Use .env file for secret values (Priority: P2)
|
|
27
|
-
|
|
28
|
-
A developer stores sensitive credentials (e.g. `NPM_TOKEN`) in a `.env` file that is excluded from version control. The task `envs:` block references the variable using the `$NPM_TOKEN` syntax. Hammerkit reads the `.env` file and makes the value available to the task.
|
|
29
|
-
|
|
30
|
-
**Why this priority**: Keeps secrets out of the build file and version history while still being available during task execution.
|
|
31
|
-
|
|
32
|
-
**Independent Test**: Create a `.env` file with `NPM_TOKEN=abc`, declare it in the task `envs:`, run the task, and confirm the token is available to the command.
|
|
33
|
-
|
|
34
|
-
**Acceptance Scenarios**:
|
|
35
|
-
|
|
36
|
-
1. **Given** a `.env` file containing `NPM_TOKEN=abc`, **When** a task declares `NPM_TOKEN: $NPM_TOKEN` in its `envs:` and is executed, **Then** the command receives `NPM_TOKEN=abc`.
|
|
37
|
-
|
|
38
|
-
### User Story 3 - Define environment variables in the build file (Priority: P2)
|
|
39
|
-
|
|
40
|
-
A developer defines default values for environment variables at the top-level `envs:` block or within a specific task's `envs:` block. Task-level declarations override the file-level defaults for that task only.
|
|
41
|
-
|
|
42
|
-
**Why this priority**: Centralises configuration that does not change per-developer while allowing per-task overrides.
|
|
43
|
-
|
|
44
|
-
**Independent Test**: Declare `NODE_VERSION: 14.16.0` at the top level and `NODE_VERSION: 14.0.0` inside one task's `envs:`. Run each task and verify each receives the correct version string.
|
|
45
|
-
|
|
46
|
-
**Acceptance Scenarios**:
|
|
47
|
-
|
|
48
|
-
1. **Given** `NODE_VERSION: 14.16.0` is declared in the top-level `envs:`, **When** a task that does not override it runs `echo $NODE_VERSION`, **Then** the output is `14.16.0`.
|
|
49
|
-
2. **Given** a task declares `NODE_VERSION: 14.0.0` in its own `envs:`, **When** that task runs, **Then** its value (`14.0.0`) takes precedence over the top-level value.
|
|
50
|
-
3. **Given** top-level `envs:` are declared in file A, **When** a task from a referenced or included build file B runs, **Then** it does NOT have access to file A's top-level env vars.
|
|
51
|
-
|
|
52
|
-
### Edge Cases
|
|
53
|
-
|
|
54
|
-
- Referencing an undefined shell variable that is not in `.env` causes a hard error before task execution begins.
|
|
55
|
-
- Variables declared in a build file's top-level `envs:` are scoped to that file; they do not leak into referenced or included build files.
|
|
56
|
-
- The `.env` file is loaded relative to the project directory containing the build file.
|
|
57
|
-
|
|
58
|
-
## Requirements *(mandatory)*
|
|
59
|
-
|
|
60
|
-
### Functional Requirements
|
|
61
|
-
|
|
62
|
-
- **FR-001**: The system MUST support declaring environment variables in the top-level `envs:` map of a build file, making them available to all tasks in that file.
|
|
63
|
-
- **FR-002**: The system MUST support declaring environment variables in a task-level `envs:` map, overriding any same-named top-level declaration for that task.
|
|
64
|
-
- **FR-003**: The system MUST resolve `$VAR` references in `envs:` values from the shell environment at the time the task is executed.
|
|
65
|
-
- **FR-004**: The system MUST read environment variable values from a `.env` file in the project directory and make them available for `$VAR` resolution.
|
|
66
|
-
- **FR-005**: The system MUST throw an error if an `envs:` entry references a shell or `.env` variable that is not defined, rather than passing an empty or undefined value to the task.
|
|
67
|
-
- **FR-006**: Top-level `envs:` declarations MUST be scoped to the build file in which they are defined and MUST NOT be visible to referenced or included build files.
|
|
68
|
-
|
|
69
|
-
## Success Criteria *(mandatory)*
|
|
70
|
-
|
|
71
|
-
### Measurable Outcomes
|
|
72
|
-
|
|
73
|
-
- **SC-001**: A task that declares a shell-sourced env var receives the correct value when the variable is set, and hammerkit exits with a non-zero code and an error message when the variable is unset.
|
|
74
|
-
- **SC-002**: A task that sources a value from `.env` receives the correct value without the secret appearing in the build file.
|
|
75
|
-
- **SC-003**: A task-level `envs:` declaration overrides a file-level declaration for the same variable name within that task only.
|
|
76
|
-
- **SC-004**: Tasks in a referenced or included build file do not inherit top-level env vars from the including build file.
|
|
77
|
-
|
|
78
|
-
## Assumptions
|
|
79
|
-
|
|
80
|
-
- `.env` file loading is automatic; no explicit declaration in the build file is needed beyond the `$VAR` reference in `envs:`.
|
|
81
|
-
- Variables defined as literal values in `envs:` (not using `$VAR` syntax) are always available and require no shell validation.
|
|
82
|
-
- The precedence order (most specific wins) is: task-level `envs:` > top-level `envs:` > `.env` file > shell environment, though the docs do not enumerate this explicitly; this assumption is recorded here for review.
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
# Feature Specification: Build File: Includes
|
|
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/build-file/includes.md`
|
|
10
|
-
|
|
11
|
-
## User Scenarios & Testing *(mandatory)*
|
|
12
|
-
|
|
13
|
-
### User Story 1 - Reuse a shared task definition across multiple projects (Priority: P1)
|
|
14
|
-
|
|
15
|
-
In a monorepo with multiple packages that each have a `package.json`, a developer extracts the common `npm install` task into a shared `build.npm.yaml` file at the repo root. Each package's build file declares an `includes:` entry pointing to that shared file under the alias `npm`. The `npm:install` task is then available as a dependency in each package and executes with the working directory set to the package that included it — not the location of the shared file.
|
|
16
|
-
|
|
17
|
-
**Why this priority**: Includes are the canonical way to eliminate duplicated task definitions in monorepos; getting the working directory right is the core value proposition.
|
|
18
|
-
|
|
19
|
-
**Independent Test**: Create a shared build file with a task that writes a file. Include it in two different package build files. Run `hammerkit npm:install` from each package context and confirm the output file is written to the respective package directory, not the shared file's directory.
|
|
20
|
-
|
|
21
|
-
**Acceptance Scenarios**:
|
|
22
|
-
|
|
23
|
-
1. **Given** `build.npm.yaml` at the repo root defines task `install`, and `packages/a/.hammerkit.yaml` declares `includes: { npm: ../../build.npm.yaml }`, **When** the user runs `npm:install` in the context of package `a`, **Then** the task executes with the working directory set to `packages/a/`.
|
|
24
|
-
2. **Given** the same shared file is included in `packages/b/.hammerkit.yaml`, **When** `npm:install` runs in package `b`'s context, **Then** the working directory is `packages/b/`, independent of package `a`.
|
|
25
|
-
3. **Given** `packages/b/.hammerkit.yaml` declares `deps: [npm:install, a:build]`, **When** the build task runs, **Then** `npm:install` runs in `packages/b/`'s working directory and `a:build` runs as a reference with `packages/a/`'s working directory.
|
|
26
|
-
|
|
27
|
-
### Edge Cases
|
|
28
|
-
|
|
29
|
-
- Includes differ from references in that the working directory is the location of the including build file, not the location of the included file.
|
|
30
|
-
- Top-level `envs:` from the including build file are not visible to tasks in the included build file.
|
|
31
|
-
- An included file can itself declare further references, mixing the two mechanisms as shown in the monorepo example.
|
|
32
|
-
|
|
33
|
-
## Requirements *(mandatory)*
|
|
34
|
-
|
|
35
|
-
### Functional Requirements
|
|
36
|
-
|
|
37
|
-
- **FR-001**: The build file MUST support a top-level `includes:` map where each key is an alias and each value is a path to a shared build YAML file.
|
|
38
|
-
- **FR-002**: Tasks from an included build file MUST be addressable using the `<alias>:<task-name>` notation from the CLI and in task `deps:` lists.
|
|
39
|
-
- **FR-003**: When a task from an included build file executes, the working directory MUST be the directory of the build file that declared the `includes:` entry, NOT the directory of the included file.
|
|
40
|
-
- **FR-004**: The same shared build file MAY be included by multiple build files, with each inclusion using the working directory of the including file independently.
|
|
41
|
-
- **FR-005**: Includes and references MAY be combined in the same build file, allowing tasks from included files to coexist with tasks from referenced sub-projects as dependencies.
|
|
42
|
-
|
|
43
|
-
### Key Entities
|
|
44
|
-
|
|
45
|
-
- **Include**: A named entry in the `includes:` map; the key is the alias used to prefix task names, the value is the relative path to the shared build YAML file.
|
|
46
|
-
|
|
47
|
-
## Success Criteria *(mandatory)*
|
|
48
|
-
|
|
49
|
-
### Measurable Outcomes
|
|
50
|
-
|
|
51
|
-
- **SC-001**: A task sourced from an included build file runs with the working directory of the including project, not the directory where the shared file resides.
|
|
52
|
-
- **SC-002**: The same shared task file included by two different packages produces independent executions, each in their own package directory.
|
|
53
|
-
- **SC-003**: A build file that combines `includes:` and `references:` correctly resolves both sets of task namespaces and executes each with the correct working directory.
|
|
54
|
-
|
|
55
|
-
## Assumptions
|
|
56
|
-
|
|
57
|
-
- Include paths are relative to the directory of the build file containing the `includes:` block.
|
|
58
|
-
- Included files are standard hammerkit build YAML files and may contain any valid build file content (`tasks:`, `envs:`, etc.).
|
|
59
|
-
- The working-directory rule applies to all task types within an included file (container tasks and local tasks alike), though the docs only illustrate local tasks.
|
|
60
|
-
- Unlike references, includes do not require the target path to be a directory — they point directly to a `.yaml` file.
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
# Feature Specification: Build File: References
|
|
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/build-file/references.md`
|
|
10
|
-
|
|
11
|
-
## User Scenarios & Testing *(mandatory)*
|
|
12
|
-
|
|
13
|
-
### User Story 1 - Run a task from a referenced sub-project (Priority: P1)
|
|
14
|
-
|
|
15
|
-
A developer has a monorepo with multiple sub-directories, each containing its own build file. They declare a `references:` map in the root build file, giving each sub-project a short alias. They can then invoke tasks in those sub-projects from the CLI using the `<alias>:<task>` syntax, or declare them as dependencies in root tasks.
|
|
16
|
-
|
|
17
|
-
**Why this priority**: References are the primary mechanism for composing multi-project builds from a single entry-point build file.
|
|
18
|
-
|
|
19
|
-
**Independent Test**: Create a root build file with a reference to a sub-directory build file. Run `hammerkit <alias>:<task>` and confirm the task in the sub-project executes.
|
|
20
|
-
|
|
21
|
-
**Acceptance Scenarios**:
|
|
22
|
-
|
|
23
|
-
1. **Given** a root build file declares `references: { foo: project/foo }`, and `project/foo/.hammerkit.yaml` contains a task named `example`, **When** the user runs `hammerkit foo:example`, **Then** the `example` task from `project/foo` executes.
|
|
24
|
-
2. **Given** a root task declares `foo:example` in its `deps:`, **When** that root task runs, **Then** `foo:example` is executed as a prerequisite with the working directory fixed to `project/foo`.
|
|
25
|
-
|
|
26
|
-
### Edge Cases
|
|
27
|
-
|
|
28
|
-
- The working directory for tasks in a referenced build file is fixed to the directory where the referenced build file resides, not the directory of the referencing build file.
|
|
29
|
-
- Top-level `envs:` from the referencing build file are not visible to tasks in the referenced build file.
|
|
30
|
-
- Circular references (A references B which references A) are not discussed in the docs; behavior is assumed to be an error or undefined.
|
|
31
|
-
|
|
32
|
-
## Requirements *(mandatory)*
|
|
33
|
-
|
|
34
|
-
### Functional Requirements
|
|
35
|
-
|
|
36
|
-
- **FR-001**: The build file MUST support a top-level `references:` map where each key is an alias and each value is a path to another project directory containing a build file.
|
|
37
|
-
- **FR-002**: Tasks from a referenced build file MUST be addressable using the `<alias>:<task-name>` notation from the CLI.
|
|
38
|
-
- **FR-003**: Tasks from a referenced build file MUST be usable as dependency entries in the referencing build file's task `deps:` list using the `<alias>:<task-name>` notation.
|
|
39
|
-
- **FR-004**: The working directory for tasks executing in a referenced build file MUST be the directory of that referenced build file, not the directory of the referencing file.
|
|
40
|
-
|
|
41
|
-
### Key Entities
|
|
42
|
-
|
|
43
|
-
- **Reference**: A named entry in the `references:` map; the key is the alias used to prefix task names, the value is the relative path to the sub-project directory.
|
|
44
|
-
|
|
45
|
-
## Success Criteria *(mandatory)*
|
|
46
|
-
|
|
47
|
-
### Measurable Outcomes
|
|
48
|
-
|
|
49
|
-
- **SC-001**: A task in a referenced build file is successfully invoked via `hammerkit <alias>:<task>` and executes with the working directory set to the referenced project directory.
|
|
50
|
-
- **SC-002**: A task in the root build file that lists `<alias>:<task>` as a dependency causes that referenced task to run before the root task's commands execute.
|
|
51
|
-
|
|
52
|
-
## Assumptions
|
|
53
|
-
|
|
54
|
-
- The path in the `references:` value points to a directory, and hammerkit locates the build file (`build.yaml` or `.hammerkit.yaml`) within that directory automatically.
|
|
55
|
-
- Reference paths are relative to the directory of the build file containing the `references:` block.
|
|
56
|
-
- Deeply nested references (a reference to a build file that itself references another) are assumed to be supported, though not explicitly documented.
|
package/specs/build-file/spec.md
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
# Feature Specification: Build File: 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/build-file/README.md`
|
|
10
|
-
|
|
11
|
-
## User Scenarios & Testing *(mandatory)*
|
|
12
|
-
|
|
13
|
-
### User Story 1 - Define a project build file (Priority: P1)
|
|
14
|
-
|
|
15
|
-
A developer creates a `build.yaml` (or `.hammerkit.yaml`) file at the root of their project directory. They declare top-level environment variables, one or more named tasks, references to sub-projects, and includes for shared task files. They then invoke tasks by name via the hammerkit CLI.
|
|
16
|
-
|
|
17
|
-
**Why this priority**: The build file is the central configuration artifact; all other hammerkit features depend on it.
|
|
18
|
-
|
|
19
|
-
**Independent Test**: Create a minimal build file with a single task and verify `hammerkit <task>` executes it.
|
|
20
|
-
|
|
21
|
-
**Acceptance Scenarios**:
|
|
22
|
-
|
|
23
|
-
1. **Given** a project directory, **When** a `build.yaml` file is placed there with a valid `tasks:` block, **Then** hammerkit discovers and executes named tasks from that file via the CLI.
|
|
24
|
-
2. **Given** a build file with a top-level `envs:` block, **When** a task is run, **Then** the declared environment variables are available to the task commands.
|
|
25
|
-
3. **Given** a build file with `references:` and `includes:` blocks, **When** hammerkit starts, **Then** it loads the referenced and included build files and makes their tasks available under the appropriate namespaced names.
|
|
26
|
-
|
|
27
|
-
### Edge Cases
|
|
28
|
-
|
|
29
|
-
- A build file with no `tasks:` block is valid but produces no executable targets.
|
|
30
|
-
- The filename may be `build.yaml` or `.hammerkit.yaml`; behavior is identical.
|
|
31
|
-
- Top-level `envs:` are scoped to the build file where they are declared and do not propagate to referenced or included files.
|
|
32
|
-
|
|
33
|
-
## Requirements *(mandatory)*
|
|
34
|
-
|
|
35
|
-
### Functional Requirements
|
|
36
|
-
|
|
37
|
-
- **FR-001**: The system MUST read build configuration from a YAML file named `build.yaml` or `.hammerkit.yaml` located in the project directory.
|
|
38
|
-
- **FR-002**: The build file MUST support a top-level `envs:` map for declaring environment variables shared across all tasks in that file.
|
|
39
|
-
- **FR-003**: The build file MUST support a top-level `tasks:` map where each key is a task name and the value is the task configuration.
|
|
40
|
-
- **FR-004**: The build file MUST support a top-level `references:` map pointing to other build files in sub-directories.
|
|
41
|
-
- **FR-005**: The build file MUST support a top-level `includes:` map pointing to shared build files whose tasks are merged under a namespace.
|
|
42
|
-
- **FR-006**: Tasks declared in a build file MUST be invocable by name via the hammerkit CLI.
|
|
43
|
-
|
|
44
|
-
### Key Entities
|
|
45
|
-
|
|
46
|
-
- **Build File**: A YAML file (`build.yaml` / `.hammerkit.yaml`) containing `envs`, `tasks`, `references`, and `includes` top-level keys.
|
|
47
|
-
- **Task**: A named unit of work inside the `tasks:` map; may declare commands, dependencies, source files, and generated outputs.
|
|
48
|
-
- **Reference**: A named pointer to another project directory containing its own build file.
|
|
49
|
-
- **Include**: A named pointer to a shared build YAML file whose tasks are reused with the working directory of the including file.
|
|
50
|
-
|
|
51
|
-
## Success Criteria *(mandatory)*
|
|
52
|
-
|
|
53
|
-
### Measurable Outcomes
|
|
54
|
-
|
|
55
|
-
- **SC-001**: A build file with all four top-level sections (`envs`, `tasks`, `references`, `includes`) loads without errors and all tasks are accessible via the CLI.
|
|
56
|
-
- **SC-002**: Environment variables defined in the top-level `envs:` block are resolved correctly within tasks in the same file and are not visible in referenced or included files.
|
|
57
|
-
|
|
58
|
-
## Assumptions
|
|
59
|
-
|
|
60
|
-
- The primary filename used in examples is `.hammerkit.yaml`; `build.yaml` is also accepted based on the docs description.
|
|
61
|
-
- The `caches:` top-level key (introduced in 1.6.0) exists in the build file schema but is covered by its own spec page.
|
|
62
|
-
- Task-level details (image, cmds, deps, src, generates) are covered by the Task spec pages, not this overview.
|
package/specs/cli/clean/spec.md
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
# Feature Specification: CLI: clean
|
|
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/cli/clean.md`
|
|
10
|
-
|
|
11
|
-
## User Scenarios & Testing *(mandatory)*
|
|
12
|
-
|
|
13
|
-
### User Story 1 - Remove generated outputs and local cache state for a clean rebuild (Priority: P1)
|
|
14
|
-
|
|
15
|
-
A developer suspects their build is producing stale results due to a previous cached state. They run `hammerkit clean` to delete all generated directories and files as well as hammerkit's per-task cache state for the current checkout, then re-run tasks to verify everything builds from scratch.
|
|
16
|
-
|
|
17
|
-
**Why this priority**: The primary purpose of `clean` is to reset local state so that builds are fully reproducible without prior artifacts.
|
|
18
|
-
|
|
19
|
-
**Independent Test**: Run a task that produces a `generates` output. Run `hammerkit clean`. Confirm the generated output no longer exists and that hammerkit re-executes the task on the next run regardless of unchanged inputs.
|
|
20
|
-
|
|
21
|
-
**Acceptance Scenarios**:
|
|
22
|
-
|
|
23
|
-
1. **Given** tasks have been run and generated outputs and cache state exist, **When** `hammerkit clean` is run, **Then** all generated outputs and per-task local cache state are removed.
|
|
24
|
-
|
|
25
|
-
2. **Given** `hammerkit clean` has completed, **When** a task is run again with unchanged inputs, **Then** hammerkit re-executes the task because the local cache state is absent.
|
|
26
|
-
|
|
27
|
-
### User Story 2 - Drop stored remote/backend cache results to force a full rebuild (Priority: P2)
|
|
28
|
-
|
|
29
|
-
A developer encounters a persistent caching issue and needs to force the next run to rebuild from scratch even against a configured cache backend (local result store or remote, e.g. S3). They run `hammerkit clean --cache` to also purge stored results from the backend.
|
|
30
|
-
|
|
31
|
-
**Why this priority**: The `--cache` flag addresses a deeper reset need when the standard clean is insufficient due to a populated cache backend.
|
|
32
|
-
|
|
33
|
-
**Independent Test**: Configure a cache backend. Run tasks so results are stored in the backend. Run `hammerkit clean --cache`. Confirm the backend has no stored results for the project and that the next run rebuilds all tasks.
|
|
34
|
-
|
|
35
|
-
**Acceptance Scenarios**:
|
|
36
|
-
|
|
37
|
-
1. **Given** a configured cache backend with stored task results, **When** `hammerkit clean --cache` is run, **Then** the stored results in the backend (local `~/.hammerkit/remote-cache` or remote) are deleted in addition to generated outputs and local cache state.
|
|
38
|
-
|
|
39
|
-
2. **Given** `--cache` is omitted, **When** `hammerkit clean` is run, **Then** stored results in the cache backend are preserved; only local generated outputs and per-task cache state are removed.
|
|
40
|
-
|
|
41
|
-
### User Story 3 - Clean a subset of tasks and services using label filters (Priority: P2)
|
|
42
|
-
|
|
43
|
-
A developer wants to clean only a specific subset of tasks without affecting others. They use `--filter` or `--exclude` with label selectors to target or omit specific tasks and services.
|
|
44
|
-
|
|
45
|
-
**Why this priority**: Label-scoped clean reduces disruption to unrelated tasks in large build files.
|
|
46
|
-
|
|
47
|
-
**Independent Test**: Tag two tasks with different labels. Run both. Run `hammerkit clean --filter <label>`. Confirm only the filtered task's outputs and cache state are removed while the other task's outputs remain.
|
|
48
|
-
|
|
49
|
-
**Acceptance Scenarios**:
|
|
50
|
-
|
|
51
|
-
1. **Given** tasks are labeled, **When** `hammerkit clean --filter <label>` is run, **Then** only the tasks and services matching the label are cleaned.
|
|
52
|
-
|
|
53
|
-
2. **Given** tasks are labeled, **When** `hammerkit clean --exclude <label>` is run, **Then** tasks and services matching the label are skipped and all others are cleaned.
|
|
54
|
-
|
|
55
|
-
### Edge Cases
|
|
56
|
-
|
|
57
|
-
- Running `hammerkit clean` when no tasks have been run (no generated outputs, no cache state) should complete without error.
|
|
58
|
-
- `hammerkit clean --cache` removes the local result store at `~/.hammerkit/remote-cache` or a configured remote backend, not just the per-checkout cache state.
|
|
59
|
-
- Label filters apply to both tasks and services, consistent with their behavior in other commands.
|
|
60
|
-
|
|
61
|
-
## Requirements *(mandatory)*
|
|
62
|
-
|
|
63
|
-
### Functional Requirements
|
|
64
|
-
|
|
65
|
-
- **FR-001**: System MUST remove all generated outputs (files and directories declared via `generates`) for all tasks and services in the current checkout when `hammerkit clean` is run.
|
|
66
|
-
- **FR-002**: System MUST remove the per-task local cache state for the current checkout when `hammerkit clean` is run.
|
|
67
|
-
- **FR-003**: When `--cache` is supplied, system MUST additionally delete stored results from the configured cache backend (defaulting to `~/.hammerkit/remote-cache` for local backends).
|
|
68
|
-
- **FR-004**: System MUST support `-f`/`--filter` and `-e`/`--exclude` label options to restrict which tasks and services are cleaned.
|
|
69
|
-
- **FR-005**: System MUST complete without error when there are no generated outputs or cache state to remove.
|
|
70
|
-
|
|
71
|
-
## Success Criteria *(mandatory)*
|
|
72
|
-
|
|
73
|
-
### Measurable Outcomes
|
|
74
|
-
|
|
75
|
-
- **SC-001**: After `hammerkit clean`, no generated output directories or files from any task's `generates` field exist in the working tree.
|
|
76
|
-
- **SC-002**: After `hammerkit clean`, running any task re-executes it fully regardless of whether its inputs have changed.
|
|
77
|
-
- **SC-003**: After `hammerkit clean --cache`, the cache backend contains no stored results for the project and the next run rebuilds all tasks from source.
|
|
78
|
-
- **SC-004**: After `hammerkit clean --filter <label>`, only tasks matching the label have their outputs and cache state removed; all other task outputs remain intact.
|
|
79
|
-
|
|
80
|
-
## Assumptions
|
|
81
|
-
|
|
82
|
-
- "Per-task cache state" refers to the hammerkit-internal tracking of input hashes used to determine whether a task is up to date; this is distinct from stored build results in the cache backend.
|
|
83
|
-
- The `--cache` flag targets whatever backend is configured in the build file's `caches` section, defaulting to the local result store at `~/.hammerkit/remote-cache`.
|
|
84
|
-
- The `clean` command does not prompt for confirmation; it is destructive by design.
|
|
85
|
-
- There is no `--dry-run` option documented; the command always performs the deletion.
|
package/specs/cli/down/spec.md
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
# Feature Specification: CLI: down
|
|
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/cli/down.md`
|
|
10
|
-
|
|
11
|
-
## User Scenarios & Testing *(mandatory)*
|
|
12
|
-
|
|
13
|
-
### User Story 1 - Stopping all running services (Priority: P1)
|
|
14
|
-
|
|
15
|
-
A developer has finished their work session and wants to free the resources held by services that were started with `hammerkit up` (foreground or daemon). They run `hammerkit down` and all services defined in the build file are stopped.
|
|
16
|
-
|
|
17
|
-
**Why this priority**: `down` is the natural complement to `up` and the primary way to cleanly release containerized service resources.
|
|
18
|
-
|
|
19
|
-
**Independent Test**: Start services with `hammerkit up --daemon`, then run `hammerkit down` and verify that all service containers are no longer running.
|
|
20
|
-
|
|
21
|
-
**Acceptance Scenarios**:
|
|
22
|
-
|
|
23
|
-
1. **Given** services started with `hammerkit up --daemon`, **When** the user runs `hammerkit down`, **Then** all services defined in the build file are stopped and exit cleanly.
|
|
24
|
-
|
|
25
|
-
2. **Given** services started with `hammerkit up` (foreground, now interrupted), **When** the user runs `hammerkit down`, **Then** any remaining service containers are stopped.
|
|
26
|
-
|
|
27
|
-
3. **Given** no services currently running, **When** the user runs `hammerkit down`, **Then** the command exits with code 0 without error.
|
|
28
|
-
|
|
29
|
-
### User Story 2 - Stopping a subset of services by label (Priority: P2)
|
|
30
|
-
|
|
31
|
-
A developer is running multiple services and wants to stop only a specific subset without affecting others. They use `--filter` or `--exclude` to target the relevant services.
|
|
32
|
-
|
|
33
|
-
**Why this priority**: Label filtering is consistent across all service-related commands and supports fine-grained lifecycle control in complex builds.
|
|
34
|
-
|
|
35
|
-
**Independent Test**: Start two labeled services, run `hammerkit down -f <label>` matching only one, and verify the other remains running.
|
|
36
|
-
|
|
37
|
-
**Acceptance Scenarios**:
|
|
38
|
-
|
|
39
|
-
1. **Given** multiple services with different labels, **When** the user runs `hammerkit down -f <label>`, **Then** only services matching the label are stopped; others remain running.
|
|
40
|
-
|
|
41
|
-
2. **Given** multiple services with different labels, **When** the user runs `hammerkit down -e <label>`, **Then** services matching the excluded label are not stopped; all others are stopped.
|
|
42
|
-
|
|
43
|
-
### User Story 3 - Stopping services in a named environment (Priority: P3)
|
|
44
|
-
|
|
45
|
-
A developer has services running in a Kubernetes environment and wants to stop them without affecting local Docker services. They pass `--env <name>` to target that environment.
|
|
46
|
-
|
|
47
|
-
**Why this priority**: Multi-environment support is consistent with `up` but is a power-user scenario.
|
|
48
|
-
|
|
49
|
-
**Independent Test**: Given services running in a named Kubernetes environment, run `hammerkit down --env <name>` and verify those services stop while local Docker services are unaffected.
|
|
50
|
-
|
|
51
|
-
**Acceptance Scenarios**:
|
|
52
|
-
|
|
53
|
-
1. **Given** services running in a named environment, **When** the user runs `hammerkit down --env <name>`, **Then** services in that environment are stopped.
|
|
54
|
-
|
|
55
|
-
### Edge Cases
|
|
56
|
-
|
|
57
|
-
- `hammerkit down` with no running services must not error.
|
|
58
|
-
- `hammerkit down -f <label>` where no services match the label must exit with code 0 without affecting other services.
|
|
59
|
-
- `--filter` and `--exclude` used together must apply both constraints; services matching both conditions are excluded.
|
|
60
|
-
|
|
61
|
-
## Requirements *(mandatory)*
|
|
62
|
-
|
|
63
|
-
### Functional Requirements
|
|
64
|
-
|
|
65
|
-
- **FR-001**: System MUST stop all services defined in the build file when `hammerkit down` is run without filter options.
|
|
66
|
-
- **FR-002**: System MUST support label-based inclusion filtering via `-f / --filter <key=value>` to stop only matching services.
|
|
67
|
-
- **FR-003**: System MUST support label-based exclusion filtering via `-e / --exclude <key=value>` to skip stopping matching services.
|
|
68
|
-
- **FR-004**: System MUST support an `--env <name>` option to stop services in a configured named environment.
|
|
69
|
-
- **FR-005**: System MUST exit with code 0 when no services are running (idempotent stop).
|
|
70
|
-
|
|
71
|
-
## Success Criteria *(mandatory)*
|
|
72
|
-
|
|
73
|
-
### Measurable Outcomes
|
|
74
|
-
|
|
75
|
-
- **SC-001**: After `hammerkit down`, no service containers defined in the build file remain in a running state.
|
|
76
|
-
- **SC-002**: `hammerkit down` exits with code 0 regardless of whether services were running before the command.
|
|
77
|
-
- **SC-003**: With `-f <label>`, only services bearing that label are stopped; services with other labels continue running.
|
|
78
|
-
- **SC-004**: With `--env <name>`, only services in the named environment are stopped; services in other environments are unaffected.
|
|
79
|
-
|
|
80
|
-
## Assumptions
|
|
81
|
-
|
|
82
|
-
- `hammerkit down` targets the same set of services as the corresponding `hammerkit up` invocation when no filters are applied.
|
|
83
|
-
- The command does not require that services were started specifically via `hammerkit up`; it stops matching service containers regardless of how they were started.
|
|
84
|
-
- `down` has no `--daemon`, `--concurrency`, `--watch`, `--log`, or `--cache` options (these do not appear in the documented option list).
|
|
85
|
-
- Stopping a service that is not running is treated as a success (idempotent), consistent with the "no error on empty" edge case documented implicitly.
|