hammerkit 1.6.0 → 1.8.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.
Files changed (277) hide show
  1. package/README.md +7 -7
  2. package/build.schema.json +59 -15
  3. package/dist/cache/backends/local-cache-backend.js +58 -1
  4. package/dist/cache/backends/registry/registry-client.js +264 -0
  5. package/dist/cache/backends/registry/registry-credentials.js +81 -0
  6. package/dist/cache/backends/registry/registry-reference.js +36 -0
  7. package/dist/cache/backends/registry-cache-backend.js +145 -0
  8. package/dist/cache/backends/s3-cache-backend.js +99 -46
  9. package/dist/cache/cache-backend-registry.js +2 -0
  10. package/dist/cache/cache-inventory.js +84 -0
  11. package/dist/cache/cache-sync.js +77 -0
  12. package/dist/cache/explain.js +214 -0
  13. package/dist/cache/last-resolved.js +48 -0
  14. package/dist/cache/read-only.js +15 -0
  15. package/dist/cache/retention.js +61 -0
  16. package/dist/cli.js +43 -0
  17. package/dist/docker/using-container.js +17 -1
  18. package/dist/executer/archive-task-entry.js +21 -0
  19. package/dist/executer/await-completed-dependencies.js +32 -14
  20. package/dist/executer/cache-metadata.js +9 -2
  21. package/dist/executer/docker-service.js +2 -1
  22. package/dist/executer/docker-task.js +18 -3
  23. package/dist/executer/dry-run.js +73 -0
  24. package/dist/executer/event-cache.js +6 -5
  25. package/dist/executer/execute-command.js +21 -3
  26. package/dist/executer/execute-docker.js +18 -2
  27. package/dist/executer/execute-work-service.js +10 -1
  28. package/dist/executer/execute-work-task.js +111 -26
  29. package/dist/executer/execute-work-tree.js +26 -1
  30. package/dist/executer/execution-steps.js +3 -8
  31. package/dist/executer/get-container-binds.js +13 -1
  32. package/dist/executer/get-scheduler-execute-result.js +4 -1
  33. package/dist/executer/lazy-resolver.js +15 -3
  34. package/dist/executer/reset-work-tree.js +2 -0
  35. package/dist/executer/run-summary.js +102 -0
  36. package/dist/executer/scheduler/enqueue-next.js +15 -60
  37. package/dist/executer/scheduler/state-key.js +78 -0
  38. package/dist/index.js +14 -1
  39. package/dist/kubernetes/apply.js +6 -7
  40. package/dist/kubernetes/await-running-state.js +100 -60
  41. package/dist/kubernetes/ensure-http-route.js +7 -10
  42. package/dist/kubernetes/ensure-namespace.js +9 -10
  43. package/dist/kubernetes/ensure-persistent-data.js +6 -5
  44. package/dist/kubernetes/get-service-ip.js +2 -2
  45. package/dist/kubernetes/kubernetes-instance.js +0 -4
  46. package/dist/kubernetes/remove-persistent-data.js +16 -6
  47. package/dist/kubernetes/resolve-pod-name.js +7 -7
  48. package/dist/log.js +16 -6
  49. package/dist/logging/live-logger.js +2 -1
  50. package/dist/optimizer/calculate-checksum.js +8 -2
  51. package/dist/optimizer/get-work-cache-stats.js +66 -16
  52. package/dist/optimizer/work-task-cache-description.js +34 -5
  53. package/dist/planner/project-root.js +26 -0
  54. package/dist/planner/utils/append-work-environment.js +1 -1
  55. package/dist/planner/utils/append-work-service.js +2 -1
  56. package/dist/planner/utils/append-work-task.js +7 -1
  57. package/dist/planner/utils/get-outputs-to-reset.js +20 -0
  58. package/dist/planner/utils/parse-work-generate.js +2 -2
  59. package/dist/planner/utils/parse-work-source.js +35 -30
  60. package/dist/planner/utils/portable-path.js +30 -0
  61. package/dist/planner/work-cache-id.js +2 -2
  62. package/dist/planner/work-graph-serializer.js +103 -0
  63. package/dist/planner/work-instance-id.js +15 -0
  64. package/dist/planner/work-runtime-docker.js +58 -15
  65. package/dist/planner/work-runtime-kubernetes.js +95 -45
  66. package/dist/planner/work-runtime-local.js +31 -8
  67. package/dist/planner/work-service-id.js +16 -4
  68. package/dist/program.js +235 -1
  69. package/dist/schema/build-file-base-task-schema.js +4 -0
  70. package/dist/schema/build-file-environment-schema-http-route.js +15 -0
  71. package/dist/schema/build-file-environment-schema.js +8 -2
  72. package/dist/schema/build-file-schema.js +1 -1
  73. package/dist/schema/cache-schema.js +21 -2
  74. package/dist/schema/duration-schema.js +18 -0
  75. package/dist/schema/envs-schema.js +1 -1
  76. package/dist/schema/reference-parser.js +3 -0
  77. package/dist/schema/size-schema.js +18 -0
  78. package/dist/schema/work-scope-parser.js +15 -2
  79. package/dist/utils/units.js +87 -0
  80. package/package.json +20 -9
  81. package/.agents/FEEDBACK.md +0 -74
  82. package/.agents/skills/before-commit/SKILL.md +0 -101
  83. package/.agents/skills/do-the-work/SKILL.md +0 -64
  84. package/.agents/skills/fix-ci/SKILL.md +0 -98
  85. package/.agents/skills/speckit-git-commit/SKILL.md +0 -53
  86. package/.agents/skills/speckit-git-feature/SKILL.md +0 -72
  87. package/.agents/skills/speckit-git-initialize/SKILL.md +0 -54
  88. package/.agents/skills/speckit-git-remote/SKILL.md +0 -50
  89. package/.agents/skills/speckit-git-validate/SKILL.md +0 -54
  90. package/.devcontainer/Dockerfile +0 -5
  91. package/.devcontainer/devcontainer.json +0 -40
  92. package/.gitbook.yaml +0 -5
  93. package/.specify/extensions/.registry +0 -37
  94. package/.specify/extensions/git/README.md +0 -100
  95. package/.specify/extensions/git/commands/speckit.git.commit.md +0 -48
  96. package/.specify/extensions/git/commands/speckit.git.feature.md +0 -67
  97. package/.specify/extensions/git/commands/speckit.git.initialize.md +0 -49
  98. package/.specify/extensions/git/commands/speckit.git.remote.md +0 -45
  99. package/.specify/extensions/git/commands/speckit.git.validate.md +0 -49
  100. package/.specify/extensions/git/config-template.yml +0 -62
  101. package/.specify/extensions/git/extension.yml +0 -140
  102. package/.specify/extensions/git/git-config.yml +0 -62
  103. package/.specify/extensions.yml +0 -149
  104. package/.specify/feature.json +0 -3
  105. package/.specify/init-options.json +0 -10
  106. package/.specify/integration.json +0 -15
  107. package/.specify/integrations/claude.manifest.json +0 -16
  108. package/.specify/integrations/speckit.manifest.json +0 -17
  109. package/.specify/memory/constitution.md +0 -162
  110. package/.specify/templates/checklist-template.md +0 -40
  111. package/.specify/templates/constitution-template.md +0 -50
  112. package/.specify/templates/plan-template.md +0 -113
  113. package/.specify/templates/spec-template.md +0 -131
  114. package/.specify/templates/tasks-template.md +0 -252
  115. package/.specify/workflows/speckit/workflow.yml +0 -77
  116. package/.specify/workflows/workflow-registry.json +0 -13
  117. package/AGENTS.md +0 -94
  118. package/Dockerfile +0 -32
  119. package/FOLLOWUPS.md +0 -34
  120. package/SUMMARY.md +0 -68
  121. package/VALUES.md +0 -53
  122. package/dist/cache/auto-pull.spec.js +0 -123
  123. package/dist/cache/backends/local-cache-backend.spec.js +0 -72
  124. package/dist/cache/backends/s3-cache-backend.spec.js +0 -118
  125. package/dist/cache/cache-backend-registry.spec.js +0 -22
  126. package/dist/cache/resolve-cache.spec.js +0 -52
  127. package/dist/cli.spec.js +0 -23
  128. package/dist/console/get-logger.spec.js +0 -23
  129. package/dist/docker/get-default-platform.spec.js +0 -29
  130. package/dist/docker/longest-common-prefix.spec.js +0 -26
  131. package/dist/docker/package.spec.js +0 -145
  132. package/dist/docker/remove-container.spec.js +0 -32
  133. package/dist/docker/using-container.spec.js +0 -90
  134. package/dist/environment/merge-environment-variables.spec.js +0 -24
  135. package/dist/environment/replace-env-variables.spec.js +0 -47
  136. package/dist/executer/abort.spec.js +0 -18
  137. package/dist/executer/environment-mock.spec.js +0 -22
  138. package/dist/executer/execute.spec.js +0 -51
  139. package/dist/executer/get-service-containers.spec.js +0 -59
  140. package/dist/executer/get-service-env-hints.spec.js +0 -65
  141. package/dist/executer/label-values.spec.js +0 -61
  142. package/dist/executer/lazy-resolver.spec.js +0 -20
  143. package/dist/executer/process-manager.spec.js +0 -54
  144. package/dist/executer/scheduler/enqueue-next.spec.js +0 -136
  145. package/dist/executer/state-resolver.spec.js +0 -37
  146. package/dist/executer/state.spec.js +0 -66
  147. package/dist/executer/states.spec.js +0 -14
  148. package/dist/file/get-file-context.spec.js +0 -178
  149. package/dist/file/move-files.spec.js +0 -48
  150. package/dist/kubernetes/ensure-http-route.spec.js +0 -70
  151. package/dist/kubernetes/ensure-ingress.js +0 -54
  152. package/dist/kubernetes/ensure-namespace.spec.js +0 -39
  153. package/dist/kubernetes/resolve-pod-name.spec.js +0 -81
  154. package/dist/log.spec.js +0 -131
  155. package/dist/logging/grouped-logger.spec.js +0 -84
  156. package/dist/logging/interactive-logger.spec.js +0 -57
  157. package/dist/logging/live-logger.spec.js +0 -37
  158. package/dist/logging/loggers.spec.js +0 -154
  159. package/dist/optimizer/calculate-checksum.spec.js +0 -34
  160. package/dist/optimizer/get-cache-directory.spec.js +0 -59
  161. package/dist/optimizer/get-work-cache-stats.spec.js +0 -79
  162. package/dist/optimizer/work-task-cache-description.spec.js +0 -45
  163. package/dist/parser/default-build-file.spec.js +0 -48
  164. package/dist/parser/parse-label-arguments.spec.js +0 -27
  165. package/dist/parser/read-build-file.spec.js +0 -89
  166. package/dist/parser/read-env-file.spec.js +0 -42
  167. package/dist/planner/utils/append-work-service.spec.js +0 -71
  168. package/dist/planner/utils/get-container-user.spec.js +0 -30
  169. package/dist/planner/utils/get-default-kube-config.spec.js +0 -11
  170. package/dist/planner/utils/normalize-path.spec.js +0 -24
  171. package/dist/planner/utils/parse-work-command.spec.js +0 -21
  172. package/dist/planner/utils/parse-work-generate.spec.js +0 -45
  173. package/dist/planner/utils/parse-work-mount.spec.js +0 -62
  174. package/dist/planner/utils/parse-work-mounts.spec.js +0 -19
  175. package/dist/planner/utils/parse-work-port.spec.js +0 -24
  176. package/dist/planner/utils/parse-work-ports.spec.js +0 -24
  177. package/dist/planner/utils/parse-work-source.spec.js +0 -58
  178. package/dist/planner/utils/parse-work-volume.spec.js +0 -18
  179. package/dist/planner/utils/plan-work-tasks.spec.js +0 -30
  180. package/dist/planner/utils/plan-work-volume.spec.js +0 -33
  181. package/dist/planner/utils/split-name.spec.js +0 -16
  182. package/dist/planner/utils/template-value.spec.js +0 -14
  183. package/dist/planner/validate.spec.js +0 -251
  184. package/dist/planner/work-cache-id.spec.js +0 -173
  185. package/dist/planner/work-runtime-local.spec.js +0 -193
  186. package/dist/program-commands.spec.js +0 -84
  187. package/dist/program.spec.js +0 -43
  188. package/dist/schema/build-file-environment-schema-ingress.js +0 -14
  189. package/dist/schema/build-file-schema.spec.js +0 -61
  190. package/dist/schema/doc-build-files.spec.js +0 -223
  191. package/dist/schema/parse-error.spec.js +0 -18
  192. package/dist/schema/reference-parser.spec.js +0 -83
  193. package/dist/schema/schema-parser.spec.js +0 -80
  194. package/dist/schema/type-guards.spec.js +0 -23
  195. package/dist/schema/work-scope-parser.spec.js +0 -66
  196. package/dist/service/update-service-status.spec.js +0 -27
  197. package/dist/testing/ensure-local-registry.js +0 -134
  198. package/dist/testing/example-test-suite.js +0 -63
  199. package/dist/testing/expect.js +0 -82
  200. package/dist/testing/get-test-suite.js +0 -9
  201. package/dist/testing/http-get.js +0 -21
  202. package/dist/testing/integration/cache.spec.js +0 -49
  203. package/dist/testing/integration/cancellation.spec.js +0 -45
  204. package/dist/testing/integration/clean.spec.js +0 -43
  205. package/dist/testing/integration/cmd.spec.js +0 -15
  206. package/dist/testing/integration/concurrency.spec.js +0 -19
  207. package/dist/testing/integration/docker-package-registry.spec.js +0 -44
  208. package/dist/testing/integration/docker-service-crash.spec.js +0 -36
  209. package/dist/testing/integration/docker.spec.js +0 -18
  210. package/dist/testing/integration/env.spec.js +0 -48
  211. package/dist/testing/integration/environment.spec.js +0 -97
  212. package/dist/testing/integration/error.spec.js +0 -19
  213. package/dist/testing/integration/export.spec.js +0 -22
  214. package/dist/testing/integration/extend.spec.js +0 -29
  215. package/dist/testing/integration/glob.spec.js +0 -40
  216. package/dist/testing/integration/include.spec.js +0 -31
  217. package/dist/testing/integration/invalid.spec.js +0 -17
  218. package/dist/testing/integration/invalid_loop.spec.js +0 -56
  219. package/dist/testing/integration/k8s-state-cache.spec.js +0 -41
  220. package/dist/testing/integration/kubernetes-service.spec.js +0 -148
  221. package/dist/testing/integration/kubernetes.spec.js +0 -99
  222. package/dist/testing/integration/labels.spec.js +0 -42
  223. package/dist/testing/integration/local.spec.js +0 -14
  224. package/dist/testing/integration/monorepo.spec.js +0 -15
  225. package/dist/testing/integration/multi-line.spec.js +0 -17
  226. package/dist/testing/integration/reference.spec.js +0 -21
  227. package/dist/testing/integration/services.spec.js +0 -38
  228. package/dist/testing/integration/store.spec.js +0 -52
  229. package/dist/testing/integration/unknown.spec.js +0 -28
  230. package/dist/testing/integration/validate.spec.js +0 -160
  231. package/dist/testing/integration/watch-dependency.spec.js +0 -33
  232. package/dist/testing/integration/watch.spec.js +0 -45
  233. package/dist/testing/requires-kubernetes.js +0 -18
  234. package/dist/testing/requires-linux-containers.js +0 -18
  235. package/dist/testing/requires-windows-containers.js +0 -18
  236. package/dist/testing/test-case.js +0 -75
  237. package/dist/testing/test-streams.js +0 -28
  238. package/dist/testing/test-suite-setup.js +0 -3
  239. package/dist/testing/test-suite.js +0 -3
  240. package/dist/testing/testing-timeout.js +0 -32
  241. package/dist/utils/abort-event.spec.js +0 -46
  242. package/dist/utils/buffer-context.spec.js +0 -38
  243. package/dist/utils/ci.spec.js +0 -53
  244. package/dist/utils/debouncer.spec.js +0 -58
  245. package/dist/utils/emitter.spec.js +0 -34
  246. package/dist/utils/empty-writable.spec.js +0 -18
  247. package/dist/utils/environment-config.spec.js +0 -26
  248. package/dist/utils/fail-never.spec.js +0 -9
  249. package/dist/utils/sleep.spec.js +0 -22
  250. package/dist/version.spec.js +0 -12
  251. package/specs/build-file/caches/spec.md +0 -114
  252. package/specs/build-file/environment-variables/spec.md +0 -82
  253. package/specs/build-file/includes/spec.md +0 -60
  254. package/specs/build-file/references/spec.md +0 -56
  255. package/specs/build-file/spec.md +0 -62
  256. package/specs/cli/clean/spec.md +0 -85
  257. package/specs/cli/down/spec.md +0 -85
  258. package/specs/cli/execute/spec.md +0 -101
  259. package/specs/cli/init/spec.md +0 -64
  260. package/specs/cli/ls/spec.md +0 -66
  261. package/specs/cli/package/spec.md +0 -110
  262. package/specs/cli/spec.md +0 -73
  263. package/specs/cli/store-restore/spec.md +0 -74
  264. package/specs/cli/up/spec.md +0 -80
  265. package/specs/cli/validate/spec.md +0 -70
  266. package/specs/labels/spec.md +0 -91
  267. package/specs/service/container/spec.md +0 -120
  268. package/specs/service/kubernetes/spec.md +0 -97
  269. package/specs/service/spec.md +0 -105
  270. package/specs/task/caching/spec.md +0 -107
  271. package/specs/task/container/spec.md +0 -118
  272. package/specs/task/dependencies/spec.md +0 -70
  273. package/specs/task/extending/spec.md +0 -74
  274. package/specs/task/kubernetes/spec.md +0 -125
  275. package/specs/task/needs/spec.md +0 -59
  276. package/specs/task/spec.md +0 -87
  277. package/specs/task/watching/spec.md +0 -69
package/Dockerfile DELETED
@@ -1,32 +0,0 @@
1
- FROM node:24-alpine AS build
2
-
3
- ARG TARGETPLATFORM
4
-
5
- WORKDIR /app
6
-
7
- # install dependencies
8
- COPY package.json .
9
- COPY package-lock.json .
10
- RUN npm ci
11
-
12
- # build source code
13
- COPY tsconfig.json .
14
- COPY src src
15
- RUN node_modules/.bin/tsc -b
16
- RUN export ARCH=$(echo $TARGETPLATFORM | cut -c7-11)
17
- RUN node_modules/.bin/pkg . --targets "node24-alpine-$ARCH" --compress Brotli
18
-
19
- ######################################
20
- # Minimal runtime: hammerkit talks to the daemon via dockerode and to k8s via
21
- # @kubernetes/client-node — both bundled into the binary — so it needs only a
22
- # shell, CA certs and libstdc++ (for the embedded node), not the full
23
- # docker-cli image with buildx/compose. docker-cli is kept for users who exec
24
- # into the image. Cuts the image roughly in half vs docker:*-cli-alpine.
25
- FROM alpine:3.21
26
-
27
- RUN apk add --no-cache docker-cli ca-certificates libstdc++
28
-
29
- WORKDIR /app
30
- COPY --from=build /app/hammerkit /usr/local/bin/hammerkit
31
-
32
- ENTRYPOINT ["hammerkit"]
package/FOLLOWUPS.md DELETED
@@ -1,34 +0,0 @@
1
- # Runtime follow-ups
2
-
3
- Tracking what's done on `feature/runtime-followups` and what remains. The integration-test work is tracked separately in [INTEGRATION-TESTS.md](INTEGRATION-TESTS.md).
4
-
5
- ## Done on this branch
6
-
7
- - [x] **Cross-cycle validation** — new `hasMixedCycle` walks deps and needs together; wired into both [validate.ts](src/planner/validate.ts) and [check-for-loop.ts](src/executer/scheduler/check-for-loop.ts). Tests in [validate.spec.ts](src/planner/validate.spec.ts).
8
- - [x] **Local task pidfile** — [work-runtime-local.ts](src/planner/work-runtime-local.ts) writes `.hammerkit/<id>.pid` for the duration of `execute()`. A live PID (`find-process`) blocks re-entry with an `error` state; a stale PID is silently swept. Tests in [work-runtime-local.spec.ts](src/planner/work-runtime-local.spec.ts).
9
- - [x] **Docker service crash detection** — [docker-service.ts](src/executer/docker-service.ts) now races `container.wait()` against `abort`. A container that exits before abort is reported as `{ type: 'end', reason: 'crash' }` instead of `terminated`.
10
- - [x] **Service env hints for local tasks** — [get-service-env-hints.ts](src/executer/get-service-env-hints.ts) emits `HAMMERKIT_<NAME>_HOST` / `_PORT` / `_PORT_<containerPort>` for each running need. Merged into the local task's command env in [local-task.ts](src/executer/local-task.ts). Tests in [get-service-env-hints.spec.ts](src/executer/get-service-env-hints.spec.ts).
11
- - [x] **K8s deployment healthcheck** — `service.data.healthcheck.cmd` is translated to an `exec` `readinessProbe`/`livenessProbe` in [ensure-kubernetes-deployment-exists.ts](src/kubernetes/ensure-kubernetes-deployment-exists.ts). No more silently-ignored healthchecks on k8s.
12
- - [x] **Kubernetes port-forward without `kubectl`** — [kubernetes-service.ts](src/executer/kubernetes-service.ts) now uses `@kubernetes/client-node`'s `PortForward` class with a local `net.createServer` listener per port. Selector → pod resolution lives in [resolve-pod-name.ts](src/kubernetes/resolve-pod-name.ts) and supports `service`, `deployment`, and `pod` selectors. A new optional `namespace` field on the `kubernetes-service` schema (defaults to `'default'`) makes per-job namespace isolation possible from a build file.
13
-
14
- ## Done in 1.6.0 hardening (branch `hardening/1.6.0`)
15
-
16
- - [x] **Transitive dependency cache invalidation** — `checkCacheState` now folds each task's own state key together with the recursively-computed state keys of its dependencies ([src/executer/scheduler/enqueue-next.ts](src/executer/scheduler/enqueue-next.ts) `combineStateKeys`/`resolveEffectiveStateKey`). A change to an upstream source now invalidates downstream tasks even when their own sources are unchanged. Because `currentStateKey` reads back the stored key, the round-trip stays consistent (one expected cache miss on first run after upgrade). Tests in [enqueue-next.spec.ts](src/executer/scheduler/enqueue-next.spec.ts).
17
- - [x] **K8s stale upload/download pod cleanup** — `getPodForPersistence` force-deletes and waits for any leftover pod of the same name before scheduling a fresh one ([src/kubernetes/ensure-persistent-data.ts](src/kubernetes/ensure-persistent-data.ts) `removeStalePod`), so a pod leaked by a crashed run no longer gets patched in place and stuck. `statusCodeOf` is now shared from [apply.ts](src/kubernetes/apply.ts).
18
-
19
- ## Open
20
-
21
- **Release triage (1.6.0):** none of the items below block the 1.6.0 release — they
22
- are tracked as post-1.6.0 cleanup. They are error-message, code-placement, and
23
- operational-efficiency improvements (no longer any known correctness gap that
24
- yields wrong build outputs).
25
-
26
- ### Smaller TODOs (lower priority)
27
-
28
- - [src/planner/utils/append-work-dependencies.ts:39](src/planner/utils/append-work-dependencies.ts) — `// TODO check if thats correct` (skipping `isFile` generates when inheriting).
29
- - **K8s persistence dedupe + real matcher/stateKey** — [src/kubernetes/ensure-persistent-data.ts](src/kubernetes/ensure-persistent-data.ts) and [src/kubernetes/volumes.ts:89](src/kubernetes/volumes.ts) `:91`. Skipping re-upload when the persisted state already matches needs an in-cluster state marker per volume, and the `matcher: () => true` / `stateKey: ''` placeholders must be replaced with the work item's real source matcher/key. Deferred deliberately: it is a new in-cluster-state feature (not a localized fix) and the k8s persistence path is only exercisable on the self-hosted integration runner, so it was kept out of the release-hardening pass to keep 1.6.0 verifiable. Until then uploads include the full source path (over-upload, still correct).
30
- - [src/schema/reference-parser.ts:276](src/schema/reference-parser.ts) `:305` — generic "unable to find" errors should include resolution path.
31
- - [src/executer/event-cache.ts:15](src/executer/event-cache.ts) `:28` — clean/store logic ought to live in the local runtime, not the cache module.
32
- - [src/executer/state.ts:41](src/executer/state.ts) — emit a warn when removing a listener that isn't registered.
33
- - [src/planner/work-item-status.ts:33](src/planner/work-item-status.ts) `:50` `:58` — `LogContext` should replace with `WorkItem` reference; two `cleanup` markers.
34
- - [src/kubernetes/await-running-state.ts:66](src/kubernetes/await-running-state.ts) — `awaitDeployRunningState` has a confusing `(... && obj.status?.readyReplicas) ?? 0 > 0` operator-precedence expression. It happens to behave correctly (resolves only when `readyReplicas` is truthy) but reads as a bug; rewrite as `((obj.status?.readyReplicas ?? 0) > 0)`. Cosmetic — left untouched in 1.6.0 to avoid changing the k8s path that is only exercised on the integration runner.
package/SUMMARY.md DELETED
@@ -1,68 +0,0 @@
1
- # Table of contents
2
-
3
- * [About](README.md)
4
- * [Why hammerkit](docs/why-hammerkit.md)
5
- * [Installation](docs/installation.md)
6
- * [Getting started](docs/getting-started.md)
7
- * [Tutorial](docs/tutorial.md)
8
- * [Concepts](docs/concepts.md)
9
- * [Build file](docs/build-file/README.md)
10
- * [Environment Variables](docs/build-file/environment-variables.md)
11
- * [References](docs/build-file/references.md)
12
- * [Includes](docs/build-file/includes.md)
13
- * [Caches](docs/build-file/caches.md)
14
- * [Reference](docs/build-file/reference.md)
15
- * [Task](docs/task/README.md)
16
- * [Dependencies](docs/task/dependencies.md)
17
- * [Needs](docs/task/needs.md)
18
- * [Caching](docs/task/caching.md)
19
- * [Run task in a container](docs/task/container.md)
20
- * [Run task on Kubernetes](docs/task/kubernetes.md)
21
- * [Watching](docs/task/watching.md)
22
- * [Extending](docs/task/extending.md)
23
- * [Service](docs/service/README.md)
24
- * [Container service](docs/service/container.md)
25
- * [Kubernetes service](docs/service/kubernetes.md)
26
- * [Labels](docs/labels/README.md)
27
- * [Guides](docs/guides/local-vs-container.md)
28
- * [Local vs container tasks](docs/guides/local-vs-container.md)
29
- * [Caching strategy in CI](docs/guides/ci-caching.md)
30
- * [Services & networking](docs/guides/services-networking.md)
31
- * [Monorepo layout](docs/guides/monorepo.md)
32
- * [Development workflow](docs/guides/development-workflow.md)
33
- * [CLI](docs/cli/README.md)
34
- * [Init](docs/cli/init.md)
35
- * [ls](docs/cli/ls.md)
36
- * [Execute](docs/cli/execute.md)
37
- * [Up](docs/cli/up.md)
38
- * [Down](docs/cli/down.md)
39
- * [Store / Restore](docs/cli/store-restore.md)
40
- * [Package](docs/cli/package.md)
41
- * [Clean](docs/cli/clean.md)
42
- * [Validate](docs/cli/validate.md)
43
- * [Recipes](docs/recipes.md)
44
- * [FAQ & Troubleshooting](docs/faq.md)
45
-
46
- ## External Links
47
-
48
- * [Docker Hub](https://hub.docker.com/r/no0dles/hammerkit)
49
- * [Homebrew Repository](https://github.com/no0dles/homebrew-hammerkit)
50
-
51
- ## Release Blog
52
-
53
- * [Release 1.4.0](docs/release-blog/release-1.4.0.md)
54
- * [Release 1.5.0](docs/release-blog/release-1.5.0.md)
55
- * [Release 1.6.0](docs/release-blog/release-1.6.0.md)
56
-
57
- ## Change Log
58
-
59
- * [Changelog 1.4.0](docs/change-log/change-log-1.4.0.md)
60
- * [Changelog 1.5.0](docs/change-log/change-log-1.5.0.md)
61
- * [Changelog 1.6.0](docs/change-log/change-log-1.6.0.md)
62
-
63
- ## Contribution
64
-
65
- * [Roadmap](docs/contribution/roadmap.md)
66
- * [Secret managers (planned)](docs/contribution/secret-managers.md)
67
- * [Publishing](docs/contribution/publish.md)
68
- * [Self-hosted runner](docs/contribution/self-hosted-runner.md)
package/VALUES.md DELETED
@@ -1,53 +0,0 @@
1
- # Values
2
-
3
- This file is the canonical statement of what hammerkit optimizes for and the conventions that follow from it. Contributors and AI agents should read it before non-trivial work. Day-to-day agent operating rules live in [AGENTS.md](AGENTS.md); durable corrections live in [.agents/FEEDBACK.md](.agents/FEEDBACK.md).
4
-
5
- ## Product values
6
-
7
- ### Local-first
8
-
9
- Hammerkit must be usable on a developer's laptop, not only in CI. A build tool that only runs on CI is broken.
10
-
11
- ### Platform-agnostic
12
-
13
- No coupling to GitHub Actions, GitLab CI, or any single provider. The same build runs anywhere a container does.
14
-
15
- ### One config, many tools
16
-
17
- A single hammerkit build file replaces N tool-specific configs. Reducing config sprawl is a feature, not a side effect.
18
-
19
- ### Caching reduces waste, not just time
20
-
21
- Smart, distributed caching saves compute — that matters for cost and footprint, not only build speed.
22
-
23
- ## Engineering values
24
-
25
- ### Stable foundation
26
-
27
- The CLI and build-file schema are contracts. Breaking them is a deliberate, versioned decision — never a refactor side effect.
28
-
29
- ### Simplicity & composability
30
-
31
- Prefer small, composable pieces over clever abstractions. If two features can be one, make them one.
32
-
33
- ### Pragmatic typing
34
-
35
- TS strict is on; `any` is permitted where it pulls its weight. Type purity is a means, not the goal.
36
-
37
- ### Tests carry their weight
38
-
39
- Quality and coverage are non-negotiable. Slow integration tests are accepted because they buy real confidence.
40
-
41
- ## Decision heuristics
42
-
43
- ### Fix root causes, not symptoms
44
-
45
- A red check is fixed by repairing what's broken — not by removing, muting, or weakening the check.
46
-
47
- ### Real integrations over mocks
48
-
49
- Where feasible, exercise real Docker / real registries / real Kubernetes. Mocks are a last resort, not a default.
50
-
51
- ### Add nothing speculative
52
-
53
- Features, abstractions, and config knobs land when a concrete need exists — not for hypothetical futures.
@@ -1,123 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const path_1 = require("path");
4
- const os_1 = require("os");
5
- const fs_1 = require("fs");
6
- const environment_mock_1 = require("../executer/environment-mock");
7
- const enqueue_next_1 = require("../executer/scheduler/enqueue-next");
8
- const local_cache_backend_1 = require("./backends/local-cache-backend");
9
- const state_1 = require("../executer/state");
10
- const cache_metadata_1 = require("../executer/cache-metadata");
11
- const get_cache_directory_1 = require("../optimizer/get-cache-directory");
12
- const get_work_cache_stats_1 = require("../optimizer/get-work-cache-stats");
13
- const work_task_cache_description_1 = require("../optimizer/work-task-cache-description");
14
- describe('checkCacheState auto-pull', () => {
15
- let remoteDir;
16
- let machineHome;
17
- let originalHome;
18
- beforeEach(() => {
19
- remoteDir = (0, fs_1.mkdtempSync)((0, path_1.join)((0, os_1.tmpdir)(), 'hammerkit-remote-'));
20
- machineHome = (0, fs_1.mkdtempSync)((0, path_1.join)((0, os_1.tmpdir)(), 'hammerkit-home-'));
21
- originalHome = process.env.HOME;
22
- if (process.platform === 'darwin') {
23
- // getHammerkitDirectory uses Library/Application Support on macOS
24
- process.env.HOME = machineHome;
25
- }
26
- else if (process.platform === 'win32') {
27
- process.env.APPDATA = machineHome;
28
- }
29
- else {
30
- process.env.HOME = machineHome;
31
- }
32
- });
33
- afterEach(() => {
34
- (0, fs_1.rmSync)(remoteDir, { recursive: true, force: true });
35
- (0, fs_1.rmSync)(machineHome, { recursive: true, force: true });
36
- if (originalHome !== undefined) {
37
- process.env.HOME = originalHome;
38
- }
39
- else {
40
- delete process.env.HOME;
41
- }
42
- });
43
- function makeBackend() {
44
- return (0, local_cache_backend_1.createLocalCacheBackend)({ type: 'local', path: remoteDir });
45
- }
46
- function makeWorkItem(cwd, resolved) {
47
- const storedStateKey = null;
48
- return {
49
- id: () => 'demo-task',
50
- name: 'demo-task',
51
- status: { write: vi.fn() },
52
- data: {
53
- type: 'local-task',
54
- name: 'demo-task',
55
- cwd,
56
- cmds: [],
57
- generates: [],
58
- src: [],
59
- envs: { variables: {}, replacements: [] },
60
- labels: {},
61
- shell: '/bin/sh',
62
- continuous: false,
63
- caching: resolved,
64
- description: null,
65
- scope: {},
66
- },
67
- needs: [],
68
- deps: [],
69
- requiredBy: [],
70
- state: new state_1.State({ type: 'pending', stateKey: null }),
71
- runtime: {
72
- async initialize() { },
73
- async remove() { },
74
- async execute() { },
75
- async stop() { },
76
- async archive() { },
77
- async restore() {
78
- // simulate a successful artifact restore
79
- },
80
- async currentStateKey() {
81
- return storedStateKey;
82
- },
83
- },
84
- };
85
- }
86
- it('reports cached:true on the second machine after the first pushed', async () => {
87
- // Machine A: produce cache + push to remote
88
- const machineAScratch = (0, fs_1.mkdtempSync)((0, path_1.join)((0, os_1.tmpdir)(), 'hammerkit-machine-a-'));
89
- const envA = (0, environment_mock_1.environmentMock)(machineAScratch);
90
- const backend = makeBackend();
91
- const resolved = { name: 'remote', method: 'checksum', backend, implicit: false };
92
- const itemA = makeWorkItem(machineAScratch, resolved);
93
- const stats = await (0, get_work_cache_stats_1.getWorkCacheStats)(itemA.data, envA);
94
- const stateKey = (0, get_work_cache_stats_1.getStateKey)(stats, 'checksum');
95
- await (0, cache_metadata_1.writeCacheMetadata)(envA, itemA.id(), stats, (0, work_task_cache_description_1.getWorkTaskCacheDescription)(itemA.data));
96
- const cacheDir = (0, get_cache_directory_1.getCacheDirectory)(itemA.id());
97
- await backend.push(itemA.id(), stateKey, cacheDir, envA);
98
- (0, fs_1.rmSync)(machineAScratch, { recursive: true, force: true });
99
- // Machine B (different HOME = fresh local cache): same task, same sources → same stateKey
100
- const machineBScratch = (0, fs_1.mkdtempSync)((0, path_1.join)((0, os_1.tmpdir)(), 'hammerkit-machine-b-'));
101
- const envB = (0, environment_mock_1.environmentMock)(machineBScratch);
102
- // simulate a *different* machine: reset the HOME again
103
- const machineBHome = (0, fs_1.mkdtempSync)((0, path_1.join)((0, os_1.tmpdir)(), 'hammerkit-home-b-'));
104
- process.env.HOME = machineBHome;
105
- const itemB = makeWorkItem(machineBScratch, resolved);
106
- const cacheState = await (0, enqueue_next_1.checkCacheState)(itemB, 'checksum', envB);
107
- expect(cacheState.stateKey).toBe(stateKey);
108
- expect(cacheState.cached).toBe(true);
109
- (0, fs_1.rmSync)(machineBScratch, { recursive: true, force: true });
110
- (0, fs_1.rmSync)(machineBHome, { recursive: true, force: true });
111
- });
112
- it('reports cached:false when remote has nothing', async () => {
113
- const scratch = (0, fs_1.mkdtempSync)((0, path_1.join)((0, os_1.tmpdir)(), 'hammerkit-machine-c-'));
114
- const env = (0, environment_mock_1.environmentMock)(scratch);
115
- const backend = makeBackend();
116
- const resolved = { name: 'remote', method: 'checksum', backend, implicit: false };
117
- const item = makeWorkItem(scratch, resolved);
118
- const cacheState = await (0, enqueue_next_1.checkCacheState)(item, 'checksum', env);
119
- expect(cacheState.cached).toBe(false);
120
- (0, fs_1.rmSync)(scratch, { recursive: true, force: true });
121
- });
122
- });
123
- //# sourceMappingURL=auto-pull.spec.js.map
@@ -1,72 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const path_1 = require("path");
4
- const os_1 = require("os");
5
- const fs_1 = require("fs");
6
- const local_cache_backend_1 = require("./local-cache-backend");
7
- const environment_mock_1 = require("../../executer/environment-mock");
8
- describe('local cache backend', () => {
9
- let root;
10
- let scratch;
11
- beforeEach(() => {
12
- root = (0, fs_1.mkdtempSync)((0, path_1.join)((0, os_1.tmpdir)(), 'hammerkit-local-cache-'));
13
- scratch = (0, fs_1.mkdtempSync)((0, path_1.join)((0, os_1.tmpdir)(), 'hammerkit-local-cache-scratch-'));
14
- });
15
- afterEach(() => {
16
- (0, fs_1.rmSync)(root, { recursive: true, force: true });
17
- (0, fs_1.rmSync)(scratch, { recursive: true, force: true });
18
- });
19
- it('reports no hit when nothing pushed yet', async () => {
20
- const env = (0, environment_mock_1.environmentMock)(scratch);
21
- const backend = (0, local_cache_backend_1.createLocalCacheBackend)({ type: 'local', path: root });
22
- expect(await backend.has('taskA', 'key1', env)).toBe(false);
23
- expect(await backend.pull('taskA', 'key1', (0, path_1.join)(scratch, 'pull'), env)).toBe(false);
24
- });
25
- it('round-trips a task through push and pull', async () => {
26
- const env = (0, environment_mock_1.environmentMock)(scratch);
27
- const backend = (0, local_cache_backend_1.createLocalCacheBackend)({ type: 'local', path: root });
28
- const sourceDir = (0, path_1.join)(scratch, 'src');
29
- await env.file.createDirectory(sourceDir);
30
- await env.file.writeFile((0, path_1.join)(sourceDir, 'stats.json'), '{"files":{}}');
31
- await env.file.writeFile((0, path_1.join)(sourceDir, 'description.json'), '{}');
32
- await env.file.writeFile((0, path_1.join)(sourceDir, 'dist-generates.tgz'), 'tarball-bytes');
33
- await backend.push('taskA', 'key1', sourceDir, env);
34
- expect(await backend.has('taskA', 'key1', env)).toBe(true);
35
- const into = (0, path_1.join)(scratch, 'pull');
36
- const ok = await backend.pull('taskA', 'key1', into, env);
37
- expect(ok).toBe(true);
38
- expect(await env.file.exists((0, path_1.join)(into, 'stats.json'))).toBe(true);
39
- expect(await env.file.exists((0, path_1.join)(into, 'description.json'))).toBe(true);
40
- expect(await env.file.exists((0, path_1.join)(into, 'dist-generates.tgz'))).toBe(true);
41
- expect(await env.file.read((0, path_1.join)(into, 'dist-generates.tgz'))).toBe('tarball-bytes');
42
- });
43
- it('isolates entries by stateKey', async () => {
44
- const env = (0, environment_mock_1.environmentMock)(scratch);
45
- const backend = (0, local_cache_backend_1.createLocalCacheBackend)({ type: 'local', path: root });
46
- const sourceDir = (0, path_1.join)(scratch, 'src');
47
- await env.file.createDirectory(sourceDir);
48
- await env.file.writeFile((0, path_1.join)(sourceDir, 'stats.json'), '{}');
49
- await backend.push('taskA', 'key1', sourceDir, env);
50
- expect(await backend.has('taskA', 'key2', env)).toBe(false);
51
- });
52
- it('clear removes every state key of a task without touching others', async () => {
53
- const env = (0, environment_mock_1.environmentMock)(scratch);
54
- const backend = (0, local_cache_backend_1.createLocalCacheBackend)({ type: 'local', path: root });
55
- const sourceDir = (0, path_1.join)(scratch, 'src');
56
- await env.file.createDirectory(sourceDir);
57
- await env.file.writeFile((0, path_1.join)(sourceDir, 'stats.json'), '{}');
58
- await backend.push('taskA', 'key1', sourceDir, env);
59
- await backend.push('taskA', 'key2', sourceDir, env);
60
- await backend.push('taskB', 'key1', sourceDir, env);
61
- await backend.clear('taskA', env);
62
- expect(await backend.has('taskA', 'key1', env)).toBe(false);
63
- expect(await backend.has('taskA', 'key2', env)).toBe(false);
64
- expect(await backend.has('taskB', 'key1', env)).toBe(true);
65
- });
66
- it('clear is a no-op when the task has nothing cached', async () => {
67
- const env = (0, environment_mock_1.environmentMock)(scratch);
68
- const backend = (0, local_cache_backend_1.createLocalCacheBackend)({ type: 'local', path: root });
69
- await expect(backend.clear('missing', env)).resolves.toBeUndefined();
70
- });
71
- });
72
- //# sourceMappingURL=local-cache-backend.spec.js.map
@@ -1,118 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const stream_1 = require("stream");
4
- // vi.hoisted: vi.mock is hoisted above this file's top-level code, so the factory
5
- // below can only reference variables that are themselves hoisted.
6
- const { sendMock } = vi.hoisted(() => ({ sendMock: vi.fn() }));
7
- vi.mock('@aws-sdk/client-s3', () => {
8
- class S3ClientMock {
9
- constructor() {
10
- this.send = sendMock;
11
- }
12
- }
13
- class GetObjectCommand {
14
- constructor(input) {
15
- this.input = input;
16
- }
17
- }
18
- class PutObjectCommand {
19
- constructor(input) {
20
- this.input = input;
21
- }
22
- }
23
- class HeadObjectCommand {
24
- constructor(input) {
25
- this.input = input;
26
- }
27
- }
28
- class ListObjectsV2Command {
29
- constructor(input) {
30
- this.input = input;
31
- }
32
- }
33
- return {
34
- S3Client: S3ClientMock,
35
- GetObjectCommand,
36
- PutObjectCommand,
37
- HeadObjectCommand,
38
- ListObjectsV2Command,
39
- };
40
- });
41
- const s3_cache_backend_1 = require("./s3-cache-backend");
42
- const fs_1 = require("fs");
43
- const os_1 = require("os");
44
- const path_1 = require("path");
45
- const environment_mock_1 = require("../../executer/environment-mock");
46
- describe('s3 cache backend', () => {
47
- let scratch;
48
- beforeEach(() => {
49
- sendMock.mockReset();
50
- scratch = (0, fs_1.mkdtempSync)((0, path_1.join)((0, os_1.tmpdir)(), 'hammerkit-s3-spec-'));
51
- });
52
- afterEach(() => {
53
- (0, fs_1.rmSync)(scratch, { recursive: true, force: true });
54
- });
55
- it('returns false from has() when HeadObject rejects', async () => {
56
- sendMock.mockRejectedValueOnce(new Error('not found'));
57
- const backend = (0, s3_cache_backend_1.createS3CacheBackend)({ type: 's3', bucket: 'b', region: 'us-east-1' });
58
- const env = (0, environment_mock_1.environmentMock)(scratch);
59
- expect(await backend.has('task', 'state', env)).toBe(false);
60
- });
61
- it('returns true when HeadObject resolves', async () => {
62
- sendMock.mockResolvedValueOnce({});
63
- const backend = (0, s3_cache_backend_1.createS3CacheBackend)({ type: 's3', bucket: 'b', region: 'us-east-1' });
64
- const env = (0, environment_mock_1.environmentMock)(scratch);
65
- expect(await backend.has('task', 'state', env)).toBe(true);
66
- });
67
- it('uploads files via PutObject with prefix + task + stateKey path', async () => {
68
- sendMock.mockResolvedValue({});
69
- const backend = (0, s3_cache_backend_1.createS3CacheBackend)({ type: 's3', bucket: 'b', prefix: 'p/', region: 'us-east-1' });
70
- const env = (0, environment_mock_1.environmentMock)(scratch);
71
- await env.file.writeFile((0, path_1.join)(scratch, 'stats.json'), '{}');
72
- await env.file.writeFile((0, path_1.join)(scratch, 'description.json'), '{}');
73
- await env.file.writeFile((0, path_1.join)(scratch, 'a-generates.tgz'), 'bytes');
74
- await backend.push('task1', 'key1', scratch, env);
75
- const keys = sendMock.mock.calls.map(([cmd]) => cmd.input.Key);
76
- expect(keys).toContain('p/task1/key1/a-generates.tgz');
77
- expect(keys).toContain('p/task1/key1/description.json');
78
- expect(keys).toContain('p/task1/key1/stats.json');
79
- // stats.json must be uploaded last so a partial push is invisible to has()/pull()
80
- expect(keys[keys.length - 1]).toBe('p/task1/key1/stats.json');
81
- });
82
- it('downloads files into the local cache dir on pull', async () => {
83
- const backend = (0, s3_cache_backend_1.createS3CacheBackend)({ type: 's3', bucket: 'b', region: 'us-east-1' });
84
- const env = (0, environment_mock_1.environmentMock)(scratch);
85
- // Order: Head, then List, then a Get per object
86
- sendMock.mockResolvedValueOnce({}); // head
87
- sendMock.mockResolvedValueOnce({
88
- Contents: [{ Key: 'task/state/stats.json' }, { Key: 'task/state/dist.tgz' }],
89
- });
90
- sendMock.mockResolvedValueOnce({ Body: stream_1.Readable.from(['{}']) });
91
- sendMock.mockResolvedValueOnce({ Body: stream_1.Readable.from(['tarball']) });
92
- const into = (0, path_1.join)(scratch, 'pulled');
93
- const ok = await backend.pull('task', 'state', into, env);
94
- expect(ok).toBe(true);
95
- expect(await env.file.exists((0, path_1.join)(into, 'stats.json'))).toBe(true);
96
- expect(await env.file.exists((0, path_1.join)(into, 'dist.tgz'))).toBe(true);
97
- });
98
- it('does not write objects whose key escapes the restore dir on pull', async () => {
99
- const backend = (0, s3_cache_backend_1.createS3CacheBackend)({ type: 's3', bucket: 'b', region: 'us-east-1' });
100
- const env = (0, environment_mock_1.environmentMock)(scratch);
101
- sendMock.mockResolvedValueOnce({}); // head
102
- sendMock.mockResolvedValueOnce({
103
- // a poisoned bucket can list a key whose suffix traverses out of the dir
104
- Contents: [{ Key: 'task/state/../escape.txt' }, { Key: 'task/state/safe.txt' }],
105
- });
106
- // only the safe object should be fetched; the traversal entry is skipped before Get
107
- sendMock.mockResolvedValueOnce({ Body: stream_1.Readable.from(['ok']) });
108
- const into = (0, path_1.join)(scratch, 'pulled');
109
- const ok = await backend.pull('task', 'state', into, env);
110
- expect(ok).toBe(true);
111
- expect(await env.file.exists((0, path_1.join)(into, 'safe.txt'))).toBe(true);
112
- // ../escape.txt would resolve to scratch/escape.txt, outside `into`
113
- expect(await env.file.exists((0, path_1.join)(scratch, 'escape.txt'))).toBe(false);
114
- // the traversal entry must not trigger a GetObject (head + list + 1 get = 3)
115
- expect(sendMock).toHaveBeenCalledTimes(3);
116
- });
117
- });
118
- //# sourceMappingURL=s3-cache-backend.spec.js.map
@@ -1,22 +0,0 @@
1
- "use strict";
2
- // The factory registry registers `local` and `s3` at import time. We can
3
- // exercise createCacheBackend for both registered types and the unknown-type
4
- // failure without needing the AWS SDK at runtime (`local` is real; for `s3`
5
- // we register a fake under a fresh type name).
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- const cache_backend_registry_1 = require("./cache-backend-registry");
8
- describe('createCacheBackend', () => {
9
- it('builds a local backend from a {type:"local"} spec', () => {
10
- const backend = (0, cache_backend_registry_1.createCacheBackend)({ type: 'local' });
11
- expect(backend.type).toBe('local');
12
- });
13
- it('throws on an unknown backend type', () => {
14
- expect(() => (0, cache_backend_registry_1.createCacheBackend)({ type: 'unknown-backend-xyz' })).toThrow(/unknown cache backend type: unknown-backend-xyz/);
15
- });
16
- it('dispatches to a registered custom factory', () => {
17
- const fakeBackend = { type: 'fake' };
18
- (0, cache_backend_registry_1.registerCacheBackend)('fake-backend', () => fakeBackend);
19
- expect((0, cache_backend_registry_1.createCacheBackend)({ type: 'fake-backend' })).toBe(fakeBackend);
20
- });
21
- });
22
- //# sourceMappingURL=cache-backend-registry.spec.js.map
@@ -1,52 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const resolve_cache_1 = require("./resolve-cache");
4
- describe('resolveCache', () => {
5
- const catalog = (0, resolve_cache_1.withBuiltinCaches)({
6
- s3: { method: 'modify-date', backend: { type: 'local', path: '/tmp/fake' } },
7
- });
8
- it('uses the default cache when no ref is given', () => {
9
- const r = (0, resolve_cache_1.resolveCache)(undefined, catalog, 'taskA');
10
- expect(r.name).toBe('default');
11
- expect(r.method).toBe('checksum');
12
- expect(r.backend.type).toBe('local');
13
- expect(r.implicit).toBe(true);
14
- });
15
- it('treats a string ref as a method override on default', () => {
16
- const r = (0, resolve_cache_1.resolveCache)('modify-date', catalog, 'taskA');
17
- expect(r.name).toBe('default');
18
- expect(r.method).toBe('modify-date');
19
- expect(r.backend.type).toBe('local');
20
- expect(r.implicit).toBe(false);
21
- });
22
- it('uses none method when "none" string shorthand is used', () => {
23
- const r = (0, resolve_cache_1.resolveCache)('none', catalog, 'taskA');
24
- expect(r.method).toBe('none');
25
- });
26
- it('resolves a named reference and keeps its declared method', () => {
27
- const r = (0, resolve_cache_1.resolveCache)({ name: 's3' }, catalog, 'taskA');
28
- expect(r.name).toBe('s3');
29
- expect(r.method).toBe('modify-date');
30
- });
31
- it('overrides the named cache method when the task sets one', () => {
32
- const r = (0, resolve_cache_1.resolveCache)({ name: 's3', method: 'checksum' }, catalog, 'taskA');
33
- expect(r.name).toBe('s3');
34
- expect(r.method).toBe('checksum');
35
- });
36
- it('throws when an unknown name is referenced', () => {
37
- expect(() => (0, resolve_cache_1.resolveCache)({ name: 'missing' }, catalog, 'taskA')).toThrow(/cache "missing" referenced by task "taskA"/);
38
- });
39
- it('seeds default and none even when nothing is declared', () => {
40
- const empty = (0, resolve_cache_1.withBuiltinCaches)(undefined);
41
- expect(empty.default.backend.type).toBe('local');
42
- expect(empty.none.backend.type).toBe('local');
43
- });
44
- it('lets the user override the built-in default', () => {
45
- const cat = (0, resolve_cache_1.withBuiltinCaches)({
46
- default: { method: 'modify-date', backend: { type: 'local', path: '/tmp/x' } },
47
- });
48
- const r = (0, resolve_cache_1.resolveCache)(undefined, cat, 'taskA');
49
- expect(r.method).toBe('modify-date');
50
- });
51
- });
52
- //# sourceMappingURL=resolve-cache.spec.js.map
package/dist/cli.spec.js DELETED
@@ -1,23 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const path_1 = require("path");
4
- const test_case_1 = require("./testing/test-case");
5
- const program_1 = require("./program");
6
- // Drives the real parse pipeline (createCli) over an in-memory build file and
7
- // then exercises Cli lookups against the resulting work tree — a real "not
8
- // found" situation, no mocking.
9
- describe('Cli', () => {
10
- it('service() throws for an unknown service name', async () => {
11
- const testCase = (0, test_case_1.createTestCase)('cli-service', {
12
- '.hammerkit.yaml': {
13
- services: { api: { image: 'nginx', ports: [] } },
14
- tasks: { build: { cmds: ['tsc'], needs: ['api'] } },
15
- },
16
- });
17
- await testCase.setup(async (cwd, environment) => {
18
- const cli = await (0, program_1.createCli)((0, path_1.join)(cwd, '.hammerkit.yaml'), environment, { taskName: 'build' });
19
- expect(() => cli.service('missing')).toThrow('unable to find service missing');
20
- });
21
- });
22
- });
23
- //# sourceMappingURL=cli.spec.js.map
@@ -1,23 +0,0 @@
1
- "use strict";
2
- // Verifies getLogger dispatches to the right logger by name and rejects an
3
- // unknown mode via failNever — the actual loggers are tested elsewhere.
4
- Object.defineProperty(exports, "__esModule", { value: true });
5
- vi.mock('../logging/grouped-logger', () => ({ groupedLogger: vi.fn(() => 'grouped-instance') }));
6
- vi.mock('../logging/live-logger', () => ({ liveLogger: vi.fn(() => 'live-instance') }));
7
- vi.mock('../logging/interactive-logger', () => ({ interactiveLogger: vi.fn(() => 'interactive-instance') }));
8
- const get_logger_1 = require("./get-logger");
9
- describe('getLogger', () => {
10
- it('returns the grouped logger for mode "grouped"', () => {
11
- expect((0, get_logger_1.getLogger)('grouped', {}, {})).toBe('grouped-instance');
12
- });
13
- it('returns the live logger for mode "live"', () => {
14
- expect((0, get_logger_1.getLogger)('live', {}, {})).toBe('live-instance');
15
- });
16
- it('returns the interactive logger for mode "interactive"', () => {
17
- expect((0, get_logger_1.getLogger)('interactive', {}, {})).toBe('interactive-instance');
18
- });
19
- it('throws on an unknown mode (failNever)', () => {
20
- expect(() => (0, get_logger_1.getLogger)('bogus', {}, {})).toThrow();
21
- });
22
- });
23
- //# sourceMappingURL=get-logger.spec.js.map