hammerkit 1.5.1 → 1.6.0-alpha.2

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 (480) hide show
  1. package/.agents/FEEDBACK.md +74 -0
  2. package/.agents/skills/before-commit/SKILL.md +101 -0
  3. package/.agents/skills/do-the-work/SKILL.md +64 -0
  4. package/.agents/skills/fix-ci/SKILL.md +98 -0
  5. package/.agents/skills/speckit-git-commit/SKILL.md +53 -0
  6. package/.agents/skills/speckit-git-feature/SKILL.md +72 -0
  7. package/.agents/skills/speckit-git-initialize/SKILL.md +54 -0
  8. package/.agents/skills/speckit-git-remote/SKILL.md +50 -0
  9. package/.agents/skills/speckit-git-validate/SKILL.md +54 -0
  10. package/.gitbook.yaml +5 -0
  11. package/.specify/extensions/.registry +37 -0
  12. package/.specify/extensions/git/README.md +100 -0
  13. package/.specify/extensions/git/commands/speckit.git.commit.md +48 -0
  14. package/.specify/extensions/git/commands/speckit.git.feature.md +67 -0
  15. package/.specify/extensions/git/commands/speckit.git.initialize.md +49 -0
  16. package/.specify/extensions/git/commands/speckit.git.remote.md +45 -0
  17. package/.specify/extensions/git/commands/speckit.git.validate.md +49 -0
  18. package/.specify/extensions/git/config-template.yml +62 -0
  19. package/.specify/extensions/git/extension.yml +140 -0
  20. package/.specify/extensions/git/git-config.yml +62 -0
  21. package/.specify/extensions.yml +149 -0
  22. package/.specify/feature.json +3 -0
  23. package/.specify/init-options.json +10 -0
  24. package/.specify/integration.json +15 -0
  25. package/.specify/integrations/claude.manifest.json +16 -0
  26. package/.specify/integrations/speckit.manifest.json +17 -0
  27. package/.specify/memory/constitution.md +162 -0
  28. package/.specify/templates/checklist-template.md +40 -0
  29. package/.specify/templates/constitution-template.md +50 -0
  30. package/.specify/templates/plan-template.md +113 -0
  31. package/.specify/templates/spec-template.md +131 -0
  32. package/.specify/templates/tasks-template.md +252 -0
  33. package/.specify/workflows/speckit/workflow.yml +77 -0
  34. package/.specify/workflows/workflow-registry.json +13 -0
  35. package/AGENTS.md +94 -0
  36. package/Dockerfile +3 -3
  37. package/FOLLOWUPS.md +34 -0
  38. package/README.md +9 -7
  39. package/SUMMARY.md +30 -5
  40. package/VALUES.md +53 -0
  41. package/build.schema.json +542 -408
  42. package/dist/cache/auto-pull.spec.js +123 -0
  43. package/dist/cache/backends/local-cache-backend.js +56 -0
  44. package/dist/cache/backends/local-cache-backend.spec.js +72 -0
  45. package/dist/cache/backends/s3-cache-backend.js +124 -0
  46. package/dist/cache/backends/s3-cache-backend.spec.js +118 -0
  47. package/dist/cache/cache-backend-registry.js +21 -0
  48. package/dist/cache/cache-backend-registry.spec.js +22 -0
  49. package/dist/cache/cache-backend.js +3 -0
  50. package/dist/cache/resolve-cache.js +60 -0
  51. package/dist/cache/resolve-cache.spec.js +52 -0
  52. package/dist/cli.js +112 -82
  53. package/dist/cli.spec.js +20 -2
  54. package/dist/console/get-logger.spec.js +23 -0
  55. package/dist/docker/get-default-platform.spec.js +29 -0
  56. package/dist/docker/longest-common-prefix.spec.js +26 -0
  57. package/dist/docker/package.js +283 -0
  58. package/dist/docker/package.spec.js +145 -0
  59. package/dist/docker/pull.js +4 -4
  60. package/dist/docker/remove-container.spec.js +32 -0
  61. package/dist/docker/stream.js +3 -3
  62. package/dist/docker/using-container.js +29 -11
  63. package/dist/docker/using-container.spec.js +90 -0
  64. package/dist/environment/merge-environment-variables.js +21 -0
  65. package/dist/environment/merge-environment-variables.spec.js +24 -0
  66. package/dist/environment/replace-env-variables.js +43 -10
  67. package/dist/environment/replace-env-variables.spec.js +47 -0
  68. package/dist/executer/abort.spec.js +18 -0
  69. package/dist/executer/await-completed-dependencies.js +56 -0
  70. package/dist/executer/cache-metadata.js +11 -0
  71. package/dist/executer/check-readiness.js +1 -1
  72. package/dist/{planner/work-node-port.js → executer/container-bind.js} +1 -1
  73. package/dist/executer/docker-service.js +110 -86
  74. package/dist/executer/docker-task.js +132 -0
  75. package/dist/executer/environment-mock.js +3 -4
  76. package/dist/executer/environment-mock.spec.js +22 -0
  77. package/dist/executer/event-cache.js +60 -127
  78. package/dist/executer/execute-command.js +4 -3
  79. package/dist/executer/execute-docker.js +32 -14
  80. package/dist/executer/execute-work-service.js +61 -0
  81. package/dist/executer/execute-work-task.js +107 -0
  82. package/dist/executer/execute-work-tree.js +27 -0
  83. package/dist/executer/execute.spec.js +14 -10
  84. package/dist/executer/execution-steps.js +47 -31
  85. package/dist/executer/get-container-binds.js +19 -0
  86. package/dist/executer/get-docker-executor.js +12 -12
  87. package/dist/executer/get-scheduler-down-result.js +12 -0
  88. package/dist/executer/get-scheduler-execute-result.js +28 -0
  89. package/dist/executer/get-scheduler-up-result.js +12 -0
  90. package/dist/executer/get-service-containers.js +14 -0
  91. package/dist/executer/get-service-containers.spec.js +59 -0
  92. package/dist/executer/get-service-env-hints.js +35 -0
  93. package/dist/executer/get-service-env-hints.spec.js +65 -0
  94. package/dist/executer/kubernetes-service.js +116 -48
  95. package/dist/executer/label-values.js +29 -46
  96. package/dist/executer/label-values.spec.js +61 -0
  97. package/dist/executer/lazy-resolver.js +16 -0
  98. package/dist/executer/lazy-resolver.spec.js +20 -0
  99. package/dist/executer/local-task.js +44 -0
  100. package/dist/executer/process-manager.js +16 -70
  101. package/dist/executer/process-manager.spec.js +39 -76
  102. package/dist/executer/reset-work-tree.js +30 -0
  103. package/dist/executer/scheduler/check-for-loop.js +17 -7
  104. package/dist/executer/scheduler/{scheduler-state.js → dependency-state.js} +1 -1
  105. package/dist/executer/scheduler/enqueue-next.js +83 -19
  106. package/dist/executer/scheduler/enqueue-next.spec.js +136 -0
  107. package/dist/executer/scheduler/{node-state.js → need-state.js} +1 -1
  108. package/dist/{parser/build-file.js → executer/scheduler/task-state.js} +1 -1
  109. package/dist/executer/set-user-permission.js +1 -1
  110. package/dist/executer/state-resolver.js +61 -0
  111. package/dist/executer/state-resolver.spec.js +37 -0
  112. package/dist/executer/state.js +37 -31
  113. package/dist/executer/state.spec.js +66 -0
  114. package/dist/executer/states.spec.js +14 -0
  115. package/dist/executer/watch-loop.js +68 -0
  116. package/dist/executer/watch-state-key.js +44 -0
  117. package/dist/executer/work-scope.js +1 -5
  118. package/dist/file/get-file-context.js +24 -3
  119. package/dist/file/get-file-context.spec.js +178 -0
  120. package/dist/file/move-files.js +2 -2
  121. package/dist/file/move-files.spec.js +48 -0
  122. package/dist/index.js +7 -8
  123. package/dist/json-schema.js +12 -0
  124. package/dist/kubernetes/apply.js +34 -0
  125. package/dist/kubernetes/await-running-state.js +71 -0
  126. package/dist/kubernetes/ensure-http-route.js +53 -0
  127. package/dist/kubernetes/ensure-http-route.spec.js +70 -0
  128. package/dist/kubernetes/ensure-ingress.js +54 -0
  129. package/dist/kubernetes/ensure-kubernetes-deployment-exists.js +105 -0
  130. package/dist/kubernetes/ensure-kubernetes-persistent-volume-claim-exists.js +40 -0
  131. package/dist/kubernetes/ensure-kubernetes-service-exists.js +36 -0
  132. package/dist/kubernetes/ensure-namespace.js +43 -0
  133. package/dist/kubernetes/ensure-namespace.spec.js +39 -0
  134. package/dist/kubernetes/ensure-persistent-data.js +158 -0
  135. package/dist/kubernetes/get-service-ip.js +11 -0
  136. package/dist/kubernetes/kubernetes-instance.js +48 -0
  137. package/dist/kubernetes/remove-persistent-data.js +19 -0
  138. package/dist/kubernetes/resolve-pod-name.js +42 -0
  139. package/dist/kubernetes/resolve-pod-name.spec.js +81 -0
  140. package/dist/kubernetes/resources.js +12 -0
  141. package/dist/kubernetes/restore-kubernetes-data.js +42 -0
  142. package/dist/kubernetes/store-kubernetes-data.js +39 -0
  143. package/dist/kubernetes/volumes.js +64 -0
  144. package/dist/log.js +69 -69
  145. package/dist/log.spec.js +131 -0
  146. package/dist/logging/grouped-logger.js +17 -15
  147. package/dist/logging/grouped-logger.spec.js +84 -0
  148. package/dist/logging/interactive-logger.js +1 -1
  149. package/dist/logging/interactive-logger.spec.js +57 -0
  150. package/dist/logging/live-logger.js +2 -2
  151. package/dist/logging/live-logger.spec.js +37 -0
  152. package/dist/logging/loggers.spec.js +154 -0
  153. package/dist/optimizer/calculate-checksum.spec.js +34 -0
  154. package/dist/optimizer/get-cache-directory.js +6 -6
  155. package/dist/optimizer/get-cache-directory.spec.js +59 -0
  156. package/dist/optimizer/get-work-cache-stats.js +53 -0
  157. package/dist/optimizer/get-work-cache-stats.spec.js +79 -0
  158. package/dist/{parser/build-file-task.js → optimizer/work-cache-stats.js} +1 -1
  159. package/dist/optimizer/work-task-cache-description.js +25 -0
  160. package/dist/optimizer/work-task-cache-description.spec.js +45 -0
  161. package/dist/parser/default-build-file.js +14 -7
  162. package/dist/parser/default-build-file.spec.js +48 -0
  163. package/dist/parser/parse-label-arguments.spec.js +27 -0
  164. package/dist/parser/read-build-file.js +2 -13
  165. package/dist/parser/read-build-file.spec.js +89 -0
  166. package/dist/parser/read-env-file.js +4 -5
  167. package/dist/parser/read-env-file.spec.js +42 -0
  168. package/dist/planner/utils/append-work-dependencies.js +55 -0
  169. package/dist/planner/utils/append-work-environment.js +22 -0
  170. package/dist/planner/utils/append-work-needs.js +18 -0
  171. package/dist/planner/utils/append-work-service.js +107 -0
  172. package/dist/planner/utils/append-work-service.spec.js +71 -0
  173. package/dist/planner/utils/append-work-task.js +81 -0
  174. package/dist/planner/utils/get-container-user.js +14 -0
  175. package/dist/planner/utils/get-container-user.spec.js +30 -0
  176. package/dist/planner/utils/get-default-kube-config.js +10 -0
  177. package/dist/planner/utils/get-default-kube-config.spec.js +11 -0
  178. package/dist/planner/utils/get-work-runtime.js +44 -0
  179. package/dist/planner/utils/normalize-path.js +1 -1
  180. package/dist/planner/utils/normalize-path.spec.js +24 -0
  181. package/dist/planner/utils/parse-work-command.js +80 -0
  182. package/dist/planner/utils/parse-work-command.spec.js +21 -0
  183. package/dist/planner/utils/parse-work-generate.js +38 -0
  184. package/dist/planner/utils/parse-work-generate.spec.js +45 -0
  185. package/dist/planner/utils/{parse-work-node-mount.js → parse-work-mount.js} +10 -7
  186. package/dist/planner/utils/{parse-work-node-mount.spec.js → parse-work-mount.spec.js} +14 -11
  187. package/dist/planner/utils/parse-work-mounts.js +13 -0
  188. package/dist/planner/utils/parse-work-mounts.spec.js +19 -0
  189. package/dist/planner/utils/{parse-work-node-port.js → parse-work-port.js} +11 -8
  190. package/dist/planner/utils/parse-work-port.spec.js +24 -0
  191. package/dist/planner/utils/parse-work-ports.js +10 -0
  192. package/dist/planner/utils/parse-work-ports.spec.js +24 -0
  193. package/dist/planner/utils/parse-work-source.js +72 -0
  194. package/dist/planner/utils/parse-work-source.spec.js +58 -0
  195. package/dist/planner/utils/parse-work-volume.js +45 -0
  196. package/dist/planner/utils/parse-work-volume.spec.js +18 -0
  197. package/dist/planner/utils/plan-work-tasks.js +41 -0
  198. package/dist/planner/utils/plan-work-tasks.spec.js +30 -0
  199. package/dist/planner/utils/plan-work-volume.js +1 -0
  200. package/dist/planner/utils/plan-work-volume.spec.js +33 -0
  201. package/dist/planner/utils/split-name.js +2 -2
  202. package/dist/planner/utils/split-name.spec.js +16 -0
  203. package/dist/planner/utils/template-value.js +1 -2
  204. package/dist/planner/utils/template-value.spec.js +14 -0
  205. package/dist/planner/validate.js +71 -38
  206. package/dist/planner/validate.spec.js +251 -0
  207. package/dist/planner/work-cache-id.js +12 -0
  208. package/dist/planner/work-cache-id.spec.js +173 -0
  209. package/dist/planner/work-command.js +3 -0
  210. package/dist/planner/work-environment.js +3 -0
  211. package/dist/planner/work-healthcheck.js +3 -0
  212. package/dist/planner/{work-node-status.js → work-item-status.js} +16 -62
  213. package/dist/{parser/build-file-service.js → planner/work-item-validation.js} +1 -1
  214. package/dist/planner/work-item.js +16 -0
  215. package/dist/{optimizer/work-node-cache-stats.js → planner/work-kubernetes-selector.js} +1 -1
  216. package/dist/planner/{work-nodes.js → work-port.js} +1 -1
  217. package/dist/planner/work-runtime-docker.js +224 -0
  218. package/dist/planner/work-runtime-kubernetes.js +264 -0
  219. package/dist/planner/work-runtime-local.js +109 -0
  220. package/dist/planner/work-runtime-local.spec.js +193 -0
  221. package/dist/planner/work-service-id.js +15 -5
  222. package/dist/planner/work-source.js +3 -0
  223. package/dist/planner/work-task.js +8 -0
  224. package/dist/program-commands.spec.js +84 -0
  225. package/dist/program.js +219 -73
  226. package/dist/program.spec.js +34 -11
  227. package/dist/run-program.js +28 -0
  228. package/dist/{executer/process.js → runtime/runtime.js} +1 -1
  229. package/dist/schema/build-file-base-task-schema.js +27 -0
  230. package/dist/schema/build-file-container-service-schema.js +28 -0
  231. package/dist/schema/build-file-container-task-schema.js +13 -0
  232. package/dist/schema/build-file-environment-schema-ingress.js +14 -0
  233. package/dist/schema/build-file-environment-schema.js +23 -0
  234. package/dist/schema/build-file-kubernetes-service-schema.js +17 -0
  235. package/dist/schema/build-file-kubernetes-service-selector-schema.js +9 -0
  236. package/dist/schema/build-file-local-platform-schema.js +9 -0
  237. package/dist/schema/build-file-local-task-schema.js +12 -0
  238. package/dist/schema/build-file-need-schema.js +12 -0
  239. package/dist/schema/build-file-schema.js +23 -0
  240. package/dist/schema/build-file-schema.spec.js +61 -0
  241. package/dist/schema/build-file-service-container-healthcheck.js +8 -0
  242. package/dist/schema/build-file-service-schema.js +15 -0
  243. package/dist/schema/build-file-task-command-schema.js +12 -0
  244. package/dist/schema/build-file-task-schema.js +12 -0
  245. package/dist/schema/build-file-volume-schema.js +14 -0
  246. package/dist/schema/cache-schema.js +31 -0
  247. package/dist/schema/doc-build-files.spec.js +223 -0
  248. package/dist/schema/envs-schema.js +6 -0
  249. package/dist/schema/labels-schema.js +6 -0
  250. package/dist/schema/parse-context.js +3 -0
  251. package/dist/schema/parse-error.js +12 -0
  252. package/dist/schema/parse-error.spec.js +18 -0
  253. package/dist/schema/reference-parser.js +209 -0
  254. package/dist/schema/reference-parser.spec.js +83 -0
  255. package/dist/schema/schema-parser.js +66 -0
  256. package/dist/schema/schema-parser.spec.js +80 -0
  257. package/dist/schema/type-guards.spec.js +23 -0
  258. package/dist/schema/work-scope-parser.js +77 -0
  259. package/dist/schema/work-scope-parser.spec.js +66 -0
  260. package/dist/service/update-service-status.js +11 -0
  261. package/dist/service/update-service-status.spec.js +27 -0
  262. package/dist/testing/ensure-local-registry.js +134 -0
  263. package/dist/testing/example-test-suite.js +16 -18
  264. package/dist/testing/expect.js +46 -22
  265. package/dist/testing/http-get.js +21 -0
  266. package/dist/testing/integration/cache.spec.js +13 -14
  267. package/dist/testing/integration/cancellation.spec.js +14 -9
  268. package/dist/testing/integration/clean.spec.js +14 -11
  269. package/dist/testing/integration/cmd.spec.js +1 -1
  270. package/dist/testing/integration/concurrency.spec.js +3 -3
  271. package/dist/testing/integration/docker-package-registry.spec.js +44 -0
  272. package/dist/testing/integration/docker-service-crash.spec.js +36 -0
  273. package/dist/testing/integration/docker.spec.js +4 -3
  274. package/dist/testing/integration/env.spec.js +9 -8
  275. package/dist/testing/integration/environment.spec.js +97 -0
  276. package/dist/testing/integration/error.spec.js +5 -4
  277. package/dist/testing/integration/export.spec.js +22 -0
  278. package/dist/testing/integration/extend.spec.js +9 -12
  279. package/dist/testing/integration/glob.spec.js +12 -20
  280. package/dist/testing/integration/include.spec.js +3 -3
  281. package/dist/testing/integration/invalid.spec.js +2 -3
  282. package/dist/testing/integration/invalid_loop.spec.js +49 -6
  283. package/dist/testing/integration/k8s-state-cache.spec.js +41 -0
  284. package/dist/testing/integration/kubernetes-service.spec.js +148 -0
  285. package/dist/testing/integration/kubernetes.spec.js +93 -9
  286. package/dist/testing/integration/labels.spec.js +6 -11
  287. package/dist/testing/integration/local.spec.js +1 -1
  288. package/dist/testing/integration/monorepo.spec.js +4 -4
  289. package/dist/testing/integration/multi-line.spec.js +3 -3
  290. package/dist/testing/integration/reference.spec.js +4 -5
  291. package/dist/testing/integration/services.spec.js +22 -4
  292. package/dist/testing/integration/store.spec.js +15 -16
  293. package/dist/testing/integration/unknown.spec.js +20 -18
  294. package/dist/testing/integration/validate.spec.js +143 -26
  295. package/dist/testing/integration/watch-dependency.spec.js +11 -8
  296. package/dist/testing/integration/watch.spec.js +15 -16
  297. package/dist/testing/requires-kubernetes.js +18 -0
  298. package/dist/testing/requires-linux-containers.js +18 -0
  299. package/dist/testing/requires-windows-containers.js +18 -0
  300. package/dist/testing/test-case.js +75 -0
  301. package/dist/testing/test-streams.js +28 -0
  302. package/dist/testing/testing-timeout.js +32 -0
  303. package/dist/utils/abort-event.js +10 -4
  304. package/dist/utils/abort-event.spec.js +46 -0
  305. package/dist/utils/buffer-context.js +44 -0
  306. package/dist/utils/buffer-context.spec.js +38 -0
  307. package/dist/utils/ci.spec.js +53 -0
  308. package/dist/utils/emitter.spec.js +34 -0
  309. package/dist/utils/empty-writable.spec.js +18 -0
  310. package/dist/utils/environment-config.js +4 -1
  311. package/dist/utils/environment-config.spec.js +26 -0
  312. package/dist/utils/fail-never.spec.js +9 -0
  313. package/dist/version.js +9 -0
  314. package/dist/version.spec.js +12 -0
  315. package/package.json +41 -23
  316. package/specs/build-file/caches/spec.md +114 -0
  317. package/specs/build-file/environment-variables/spec.md +82 -0
  318. package/specs/build-file/includes/spec.md +60 -0
  319. package/specs/build-file/references/spec.md +56 -0
  320. package/specs/build-file/spec.md +62 -0
  321. package/specs/cli/clean/spec.md +85 -0
  322. package/specs/cli/down/spec.md +85 -0
  323. package/specs/cli/execute/spec.md +101 -0
  324. package/specs/cli/init/spec.md +64 -0
  325. package/specs/cli/ls/spec.md +66 -0
  326. package/specs/cli/package/spec.md +110 -0
  327. package/specs/cli/spec.md +73 -0
  328. package/specs/cli/store-restore/spec.md +74 -0
  329. package/specs/cli/up/spec.md +80 -0
  330. package/specs/cli/validate/spec.md +70 -0
  331. package/specs/labels/spec.md +91 -0
  332. package/specs/service/container/spec.md +120 -0
  333. package/specs/service/kubernetes/spec.md +97 -0
  334. package/specs/service/spec.md +105 -0
  335. package/specs/task/caching/spec.md +107 -0
  336. package/specs/task/container/spec.md +118 -0
  337. package/specs/task/dependencies/spec.md +70 -0
  338. package/specs/task/extending/spec.md +74 -0
  339. package/specs/task/kubernetes/spec.md +125 -0
  340. package/specs/task/needs/spec.md +59 -0
  341. package/specs/task/spec.md +87 -0
  342. package/specs/task/watching/spec.md +69 -0
  343. package/dist/console/console-context-mock.js +0 -14
  344. package/dist/environment/get-process-env.js +0 -15
  345. package/dist/executer/create-scheduler-state.js +0 -32
  346. package/dist/executer/docker-node.js +0 -123
  347. package/dist/executer/hierarchy-scheduler.js +0 -94
  348. package/dist/executer/local-node.js +0 -57
  349. package/dist/executer/schedule.js +0 -137
  350. package/dist/executer/start-node.js +0 -67
  351. package/dist/executer/watch-node.js +0 -56
  352. package/dist/executer/watch-service.js +0 -54
  353. package/dist/file/get-file-context-mock.js +0 -187
  354. package/dist/file/get-file-context-mock.spec.js +0 -56
  355. package/dist/get-work-context.js +0 -29
  356. package/dist/optimizer/get-work-node-cache-stats.js +0 -104
  357. package/dist/optimizer/read-work-node-cache.js +0 -19
  358. package/dist/optimizer/work-node-cache-description.js +0 -32
  359. package/dist/optimizer/write-work-node-cache.js +0 -21
  360. package/dist/parser/build-file-task-command.js +0 -3
  361. package/dist/parser/build-file-task-platform.js +0 -3
  362. package/dist/parser/build-file-task-source.js +0 -3
  363. package/dist/parser/get-build-file.js +0 -9
  364. package/dist/parser/parse-boolean.js +0 -29
  365. package/dist/parser/parse-boolean.spec.js +0 -48
  366. package/dist/parser/parse-build-file-references.js +0 -35
  367. package/dist/parser/parse-build-file-services.js +0 -58
  368. package/dist/parser/parse-build-file-task-command.js +0 -36
  369. package/dist/parser/parse-build-file-task-source.js +0 -63
  370. package/dist/parser/parse-build-file.js +0 -125
  371. package/dist/parser/parse-context.js +0 -13
  372. package/dist/parser/parse-envs.js +0 -29
  373. package/dist/parser/parse-healthcheck.js +0 -28
  374. package/dist/parser/parse-service-selector.js +0 -39
  375. package/dist/parser/parse-string-array.js +0 -20
  376. package/dist/parser/parse-string-map.js +0 -30
  377. package/dist/parser/parse-string.js +0 -20
  378. package/dist/planner/utils/get-container-mounts.js +0 -24
  379. package/dist/planner/utils/parse-work-service-volume.js +0 -23
  380. package/dist/planner/utils/plan-work-command.js +0 -21
  381. package/dist/planner/utils/plan-work-dependency.js +0 -36
  382. package/dist/planner/utils/plan-work-node.js +0 -293
  383. package/dist/planner/utils/plan-work-nodes.js +0 -78
  384. package/dist/planner/utils/plan-work-tree.js +0 -15
  385. package/dist/planner/work-context.js +0 -23
  386. package/dist/planner/work-node-command.js +0 -3
  387. package/dist/planner/work-node-id.js +0 -12
  388. package/dist/planner/work-node-id.spec.js +0 -106
  389. package/dist/planner/work-node-path.js +0 -2
  390. package/dist/planner/work-node-source.js +0 -3
  391. package/dist/planner/work-node-validation.js +0 -3
  392. package/dist/planner/work-node.js +0 -8
  393. package/dist/planner/work-service-volume.js +0 -3
  394. package/dist/planner/work-services.js +0 -3
  395. package/dist/start-watch-processes.js +0 -28
  396. package/dist/testing/cli.js +0 -73
  397. package/dist/testing/create-build-file.js +0 -9
  398. package/dist/testing/get-logger.js +0 -23
  399. package/dist/testing/get-node.js +0 -12
  400. package/dist/testing/get-test-context.js +0 -19
  401. package/dist/testing/integration/program.spec.js +0 -25
  402. package/dist/testing/lazy.js +0 -17
  403. package/dist/testing/start-watch-processes.js +0 -29
  404. package/dist/testing/test-suite-options.js +0 -3
  405. package/dist/utils/abortable-function.js +0 -71
  406. package/logs/cache-console.log +0 -0
  407. package/logs/cache-status.log +0 -6
  408. package/logs/cache-stout.log +0 -0
  409. package/logs/cancellation-console.log +0 -0
  410. package/logs/cancellation-status.log +0 -3
  411. package/logs/cancellation-stout.log +0 -3
  412. package/logs/clean-console.log +0 -0
  413. package/logs/clean-status.log +0 -37
  414. package/logs/clean-stout.log +0 -95
  415. package/logs/cmd-console.log +0 -0
  416. package/logs/cmd-status.log +0 -8
  417. package/logs/cmd-stout.log +0 -9
  418. package/logs/concurrency-console.log +0 -0
  419. package/logs/concurrency-status.log +0 -14
  420. package/logs/concurrency-stout.log +0 -88
  421. package/logs/docker-console.log +0 -0
  422. package/logs/docker-status.log +0 -14
  423. package/logs/docker-stout.log +0 -39
  424. package/logs/env-console.log +0 -1
  425. package/logs/env-status.log +0 -1
  426. package/logs/env-stout.log +0 -0
  427. package/logs/error-console.log +0 -0
  428. package/logs/error-status.log +0 -10
  429. package/logs/error-stout.log +0 -36
  430. package/logs/extend-console.log +0 -0
  431. package/logs/extend-status.log +0 -1
  432. package/logs/extend-stout.log +0 -0
  433. package/logs/glob-console.log +0 -28
  434. package/logs/glob-status.log +0 -23
  435. package/logs/glob-stout.log +0 -52
  436. package/logs/hello-world-node-console.log +0 -0
  437. package/logs/hello-world-node-status.log +0 -37
  438. package/logs/hello-world-node-stout.log +0 -41
  439. package/logs/include-console.log +0 -0
  440. package/logs/include-status.log +0 -3
  441. package/logs/include-stout.log +0 -0
  442. package/logs/invalid-console.log +0 -0
  443. package/logs/invalid-status.log +0 -1
  444. package/logs/invalid-stout.log +0 -0
  445. package/logs/invalid_loop-console.log +0 -0
  446. package/logs/invalid_loop-status.log +0 -1
  447. package/logs/invalid_loop-stout.log +0 -11
  448. package/logs/labels-console.log +0 -0
  449. package/logs/labels-status.log +0 -1
  450. package/logs/labels-stout.log +0 -0
  451. package/logs/local-console.log +0 -0
  452. package/logs/local-status.log +0 -7
  453. package/logs/local-stout.log +0 -8
  454. package/logs/monorepo-console.log +0 -0
  455. package/logs/monorepo-status.log +0 -152
  456. package/logs/monorepo-stout.log +0 -2354
  457. package/logs/multi-line-console.log +0 -0
  458. package/logs/multi-line-status.log +0 -1
  459. package/logs/multi-line-stout.log +0 -0
  460. package/logs/reference-console.log +0 -0
  461. package/logs/reference-status.log +0 -5
  462. package/logs/reference-stout.log +0 -0
  463. package/logs/services-console.log +0 -0
  464. package/logs/services-status.log +0 -129
  465. package/logs/services-stout.log +0 -639
  466. package/logs/store-restore-console.log +0 -0
  467. package/logs/store-restore-status.log +0 -40
  468. package/logs/store-restore-stout.log +0 -97
  469. package/logs/unknown-console.log +0 -3
  470. package/logs/unknown-status.log +0 -1
  471. package/logs/unknown-stout.log +0 -0
  472. package/logs/validate-console.log +0 -0
  473. package/logs/validate-status.log +0 -2
  474. package/logs/validate-stout.log +0 -0
  475. package/logs/watch-console.log +0 -0
  476. package/logs/watch-dependency-console.log +0 -0
  477. package/logs/watch-dependency-status.log +0 -176
  478. package/logs/watch-dependency-stout.log +0 -779
  479. package/logs/watch-status.log +0 -100
  480. package/logs/watch-stout.log +0 -349
@@ -2,30 +2,31 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const expect_1 = require("../expect");
4
4
  const get_test_suite_1 = require("../get-test-suite");
5
+ const requires_linux_containers_1 = require("../requires-linux-containers");
5
6
  describe('env', () => {
6
7
  const suite = (0, get_test_suite_1.getTestSuite)('env', ['.hammerkit.yaml', '.env']);
7
8
  afterAll(() => suite.close());
8
9
  it('should use env from build file', async () => {
9
10
  const { cli, environment } = await suite.setup({ taskName: 'example' });
10
- const result = await cli.exec();
11
+ const result = await cli.runExec();
11
12
  await (0, expect_1.expectSuccessfulResult)(result, environment);
12
13
  await (0, expect_1.expectLog)(result, environment, `example`, '16.6.0');
13
14
  });
14
- it('should pass env to docker', async () => {
15
+ it('should pass env to docker', (0, requires_linux_containers_1.requiresLinuxContainers)(async () => {
15
16
  const { cli, environment } = await suite.setup({ taskName: 'example_docker' });
16
- const result = await cli.exec();
17
+ const result = await cli.runExec();
17
18
  await (0, expect_1.expectSuccessfulResult)(result, environment);
18
19
  await (0, expect_1.expectLog)(result, environment, `example_docker`, '16.6.0');
19
- });
20
+ }));
20
21
  it('should use env from task', async () => {
21
22
  const { cli, environment } = await suite.setup({ taskName: 'example_override' });
22
- const result = await cli.exec();
23
+ const result = await cli.runExec();
23
24
  await (0, expect_1.expectSuccessfulResult)(result, environment);
24
25
  await (0, expect_1.expectLog)(result, environment, `example_override`, '15.0.0');
25
26
  });
26
27
  it('should use env from .env', async () => {
27
28
  const { cli, environment } = await suite.setup({ taskName: 'example_with_dotenv' });
28
- const result = await cli.exec();
29
+ const result = await cli.runExec();
29
30
  await (0, expect_1.expectSuccessfulResult)(result, environment);
30
31
  await (0, expect_1.expectLog)(result, environment, `example_with_dotenv`, '123456');
31
32
  });
@@ -36,12 +37,12 @@ describe('env', () => {
36
37
  VERSION: '1.0.0',
37
38
  },
38
39
  });
39
- const result = await cli.exec();
40
+ const result = await cli.runExec();
40
41
  await (0, expect_1.expectSuccessfulResult)(result, environment);
41
42
  await (0, expect_1.expectLog)(result, environment, `example_with_shell_env`, '1.0.0');
42
43
  });
43
44
  it('should throw if process env is missing', async () => {
44
- await expect(suite.setup({ taskName: 'example_with_shell_env' })).rejects.toThrow('missing env $VERSION');
45
+ await expect(suite.setup({ taskName: 'example_with_shell_env' })).rejects.toThrow('missing environment variable VERSION');
45
46
  });
46
47
  });
47
48
  //# sourceMappingURL=env.spec.js.map
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const get_test_suite_1 = require("../get-test-suite");
4
+ const test_case_1 = require("../test-case");
5
+ const requires_kubernetes_1 = require("../requires-kubernetes");
6
+ const testing_timeout_1 = require("../testing-timeout");
7
+ describe('environment', () => {
8
+ const suite = (0, get_test_suite_1.getTestSuite)('error', ['.hammerkit.yaml']);
9
+ afterAll(() => suite.close());
10
+ it('should run on environment (kubernetes)', (0, requires_kubernetes_1.requiresKubernetes)(async () => {
11
+ const testCase = (0, test_case_1.createTestCase)('environment', {
12
+ '.hammerkit.yaml': {
13
+ tasks: {
14
+ install: {
15
+ image: 'node:18-alpine',
16
+ cmds: ['npm install'],
17
+ src: ['package.json'],
18
+ generates: ['node_modules'],
19
+ },
20
+ },
21
+ services: {
22
+ postgres: {
23
+ image: 'postgres:16-alpine',
24
+ envs: {
25
+ POSTGRES_USER: 'postgres',
26
+ POSTGRES_DB: 'demo',
27
+ POSTGRES_PASSWORD: '123456',
28
+ },
29
+ ports: [':5432'],
30
+ volumes: ['postgres-db:/var/lib/postgresql/data'],
31
+ },
32
+ api: {
33
+ deps: ['install'],
34
+ needs: ['postgres'],
35
+ image: 'node:16.6.0-alpine',
36
+ envs: {
37
+ DATABASE_URL: 'postgres://postgres:123456@postgres/demo',
38
+ },
39
+ cmd: 'node index.js',
40
+ src: ['index.js'],
41
+ ports: [':3000'],
42
+ },
43
+ },
44
+ environments: {
45
+ staging: {
46
+ kubernetes: {
47
+ namespace: `hammerkit-env-${(process.env.HAMMERKIT_TEST_RUN_ID ?? 'local').slice(0, 40)}`,
48
+ context: process.env.CLUSTER_NAME || 'docker-desktop',
49
+ ingresses: [
50
+ {
51
+ host: 'demo.bertschi.io',
52
+ service: 'api',
53
+ },
54
+ ],
55
+ },
56
+ },
57
+ },
58
+ },
59
+ 'package.json': '{ "dependencies": { "pg": "^8.7.1" } }',
60
+ 'index.js': `const { Client } = require('pg')
61
+ const { createServer } = require('http')
62
+
63
+ const client = new Client(process.env.DATABASE_URL)
64
+
65
+ const server = createServer(async (req, res) => {
66
+ const result = await client.query('SELECT $1::text as message', ['Hello world!'])
67
+ res.writeHead(200)
68
+ res.end(result.rows[0].message)
69
+ })
70
+
71
+ async function main() {
72
+ await client.connect()
73
+ server.listen(3000)
74
+ }
75
+
76
+ process.on('SIGINT', async function () {
77
+ server.close()
78
+ await client.end()
79
+ })
80
+
81
+ main().catch((err) => {
82
+ console.error(err)
83
+ process.exit(1)
84
+ })
85
+ `,
86
+ });
87
+ await testCase.cli({ environmentName: 'staging' }, async (cli) => {
88
+ try {
89
+ await (0, testing_timeout_1.testingTimeout)(cli.up({ daemon: true }));
90
+ }
91
+ finally {
92
+ await cli.runDown();
93
+ }
94
+ });
95
+ }));
96
+ });
97
+ //# sourceMappingURL=environment.spec.js.map
@@ -1,18 +1,19 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const get_test_suite_1 = require("../get-test-suite");
4
+ const requires_linux_containers_1 = require("../requires-linux-containers");
4
5
  describe('error', () => {
5
6
  const suite = (0, get_test_suite_1.getTestSuite)('error', ['.hammerkit.yaml']);
6
7
  afterAll(() => suite.close());
7
8
  it('should return error when local task failed', async () => {
8
9
  const { cli } = await suite.setup({ taskName: 'local_error' });
9
- const result = await cli.exec();
10
+ const result = await cli.runExec();
10
11
  expect(result.success).toBeFalsy();
11
12
  });
12
- it('should return error when docker task failed', async () => {
13
+ it('should return error when docker task failed', (0, requires_linux_containers_1.requiresLinuxContainers)(async () => {
13
14
  const { cli } = await suite.setup({ taskName: 'docker_error' });
14
- const result = await cli.exec();
15
+ const result = await cli.runExec();
15
16
  expect(result.success).toBeFalsy();
16
- });
17
+ }));
17
18
  });
18
19
  //# sourceMappingURL=error.spec.js.map
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const get_test_suite_1 = require("../get-test-suite");
4
+ const path_1 = require("path");
5
+ const requires_linux_containers_1 = require("../requires-linux-containers");
6
+ describe('export', () => {
7
+ const suite = (0, get_test_suite_1.getTestSuite)('export', ['.hammerkit.yaml']);
8
+ afterAll(() => suite.close());
9
+ it('should export created file', (0, requires_linux_containers_1.requiresLinuxContainers)(async () => {
10
+ const { cli, environment } = await suite.setup({ taskName: 'example_file' });
11
+ const result = await cli.runExec();
12
+ expect(result.success).toBeTruthy();
13
+ expect(await environment.file.read((0, path_1.join)(environment.cwd, 'test.txt'))).toEqual('hello\n');
14
+ }));
15
+ it('should export created directory', (0, requires_linux_containers_1.requiresLinuxContainers)(async () => {
16
+ const { cli, environment } = await suite.setup({ taskName: 'example_dir' });
17
+ const result = await cli.runExec();
18
+ expect(result.success).toBeTruthy();
19
+ expect(await environment.file.read((0, path_1.join)(environment.cwd, 'dist/test.txt'))).toEqual('hello\n');
20
+ }));
21
+ });
22
+ //# sourceMappingURL=export.spec.js.map
@@ -6,27 +6,24 @@ describe('extend', () => {
6
6
  afterAll(() => suite.close());
7
7
  it('should merge env variables', async () => {
8
8
  const { cli } = await suite.setup({ taskName: 'extend_env' });
9
- const node = await cli.node('extend_env');
10
- expect(node.envs).toContainEntries([
11
- ['NAME', 'base'],
12
- ['KEEP', 'value'],
13
- ]);
9
+ const task = await cli.task('extend_env');
10
+ expect(task.data.envs.variables).toMatchObject({ NAME: 'base', KEEP: 'value' });
14
11
  });
15
12
  it('should extend and override', async () => {
16
13
  const { cli } = await suite.setup({ taskName: 'extend_container_task' });
17
- const node = await cli.node('extend_container_task');
18
- expect(node.envs).toEqual({
14
+ const task = await cli.task('extend_container_task');
15
+ expect(task.data.envs.variables).toEqual({
19
16
  NAME: 'override',
20
17
  });
21
- expect(node.type).toBe('container');
22
- if (node.type === 'container') {
23
- expect(node.image).toBe('alpine:latest');
18
+ expect(task.data.type).toBe('container-task');
19
+ if (task.data.type === 'container-task') {
20
+ expect(task.data.image).toBe('alpine:latest');
24
21
  }
25
22
  });
26
23
  it('should merge deps', async () => {
27
24
  const { cli } = await suite.setup({ taskName: 'extend_dep' });
28
- const node = await cli.node('extend_dep');
29
- expect(node.deps.map((d) => d.name)).toIncludeSameMembers(['base_env', 'extend_env']);
25
+ const task = await cli.task('extend_dep');
26
+ expect(task.deps.map((d) => d.name).sort()).toEqual(['base_env', 'extend_env'].sort());
30
27
  });
31
28
  });
32
29
  //# sourceMappingURL=extend.spec.js.map
@@ -1,34 +1,26 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const get_test_suite_1 = require("../get-test-suite");
4
- const expect_1 = require("../expect");
4
+ const enqueue_next_1 = require("../../executer/scheduler/enqueue-next");
5
5
  describe('glob', () => {
6
6
  const suite = (0, get_test_suite_1.getTestSuite)('glob', ['.hammerkit.yaml', 'test.md', 'test.txt']);
7
7
  afterAll(() => suite.close());
8
8
  async function testCache(expectInvalidate, action) {
9
9
  const { cli, environment } = await suite.setup({ taskName: 'example' });
10
- const result1 = await cli.exec();
11
- await (0, expect_1.expectSuccessfulResult)(result1, environment);
12
- const node = cli.node('example');
13
- const nodeState1 = result1.state.node[node.id];
14
- expect(nodeState1.type).toEqual('completed');
15
- if (nodeState1.type === 'completed') {
16
- expect(nodeState1.duration).toBeGreaterThanOrEqual(100);
17
- }
10
+ const task = cli.task('example');
11
+ const cacheBefore = await (0, enqueue_next_1.checkCacheState)(task, 'checksum', environment);
12
+ expect(cacheBefore.stateKey).not.toBeNull();
18
13
  if (action) {
19
14
  await action(environment);
20
15
  }
21
- const result2 = await cli.exec();
22
- await (0, expect_1.expectSuccessfulResult)(result2, environment);
23
- const nodeState2 = result2.state.node[node.id];
24
- expect(nodeState2.type).toEqual('completed');
25
- if (nodeState2.type === 'completed') {
26
- if (expectInvalidate) {
27
- expect(nodeState2.cached).toBeFalsy();
28
- }
29
- else {
30
- expect(nodeState2.cached).toBeTruthy();
31
- }
16
+ const exampleAfter = cli.task('example');
17
+ const cacheAfter = await (0, enqueue_next_1.checkCacheState)(exampleAfter, 'checksum', environment);
18
+ expect(cacheAfter.stateKey).not.toBeNull();
19
+ if (expectInvalidate) {
20
+ expect(cacheAfter.stateKey).not.toEqual(cacheBefore.stateKey);
21
+ }
22
+ else {
23
+ expect(cacheAfter.stateKey).toEqual(cacheBefore.stateKey);
32
24
  }
33
25
  }
34
26
  it('should remove task after written cache', async () => {
@@ -7,13 +7,13 @@ describe('include', () => {
7
7
  afterAll(() => suite.close());
8
8
  it('should run included task', async () => {
9
9
  const { cli, environment } = await suite.setup({ taskName: 'example' });
10
- const result = await cli.exec();
10
+ const result = await cli.runExec();
11
11
  await (0, expect_1.expectSuccessfulResult)(result, environment);
12
12
  await (0, expect_1.expectLog)(result, environment, `foo:bar`, 'foobar');
13
13
  });
14
14
  it('should get name:example', async () => {
15
15
  const { cli, environment } = await suite.setup({ taskName: 'name:example' });
16
- const result = await cli.exec();
16
+ const result = await cli.runExec();
17
17
  await (0, expect_1.expectSuccessfulResult)(result, environment);
18
18
  });
19
19
  it('should get included task', async () => {
@@ -21,7 +21,7 @@ describe('include', () => {
21
21
  expect(cli.ls().map((n) => n.item.name)).toEqual(['foo:bar']);
22
22
  const item = cli.ls()[0];
23
23
  if (item.type === 'task') {
24
- expect(item.item.cwd).toBe(suite.path);
24
+ expect(item.item.data.cwd).toBe(suite.path);
25
25
  }
26
26
  else {
27
27
  expect(item.type).toBe('task');
@@ -1,17 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const get_test_suite_1 = require("../get-test-suite");
4
- const work_scope_1 = require("../../executer/work-scope");
5
4
  describe('invalid', () => {
6
5
  const suite = (0, get_test_suite_1.getTestSuite)('invalid', ['.hammerkit.yaml']);
7
6
  afterAll(() => suite.close());
8
7
  it('should throw on invalid yaml', async () => {
9
8
  try {
10
- await suite.setup((0, work_scope_1.emptyWorkLabelScope)());
9
+ await suite.setup({});
11
10
  expect.fail('should not be called');
12
11
  }
13
12
  catch (e) {
14
- expect(e.message).toStartWith('unable to parse');
13
+ expect(e.message.startsWith('unable to parse')).toBe(true);
15
14
  }
16
15
  });
17
16
  });
@@ -1,13 +1,56 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- const get_test_suite_1 = require("../get-test-suite");
3
+ const test_case_1 = require("../test-case");
4
4
  describe('invalid', () => {
5
- const suite = (0, get_test_suite_1.getTestSuite)('invalid_loop', ['.hammerkit.yaml']);
6
- afterAll(() => suite.close());
7
5
  it('should detect loop in execution', async () => {
8
- const { cli } = await suite.setup({ taskName: 'foo' });
9
- const result = await cli.exec();
10
- expect(result.success).toBeFalsy();
6
+ const testCase = (0, test_case_1.createTestCase)('invalid_loop', {
7
+ '.hammerkit.yaml': {
8
+ tasks: {
9
+ bar: {
10
+ deps: ['foo'],
11
+ cmds: ['echo bar'],
12
+ },
13
+ foo: {
14
+ deps: ['bar'],
15
+ cmds: ['echo foo'],
16
+ },
17
+ },
18
+ },
19
+ });
20
+ await testCase.cli({ taskName: 'foo' }, async (cli) => {
21
+ const result = await cli.runExec();
22
+ expect(result.success).toBeFalsy();
23
+ });
24
+ });
25
+ it('should detect loop in services', async () => {
26
+ const testCase = (0, test_case_1.createTestCase)('invalid_loop', {
27
+ '.hammerkit.yaml': {
28
+ services: {
29
+ foodb: {
30
+ image: 'postgres:12-alpine',
31
+ volumes: ['foo:/var/lib/postgresql/data'],
32
+ needs: ['bardb'],
33
+ ports: [':5432'],
34
+ },
35
+ bardb: {
36
+ image: 'postgres:12-alpine',
37
+ volumes: ['bar:/var/lib/postgresql/data'],
38
+ needs: ['foodb'],
39
+ ports: [':5432'],
40
+ },
41
+ },
42
+ tasks: {
43
+ example: {
44
+ needs: ['foodb'],
45
+ cmds: ['echo bar'],
46
+ },
47
+ },
48
+ },
49
+ });
50
+ await testCase.cli({ taskName: 'example' }, async (cli) => {
51
+ const result = await cli.runExec();
52
+ expect(result.success).toBeFalsy();
53
+ });
11
54
  });
12
55
  });
13
56
  //# sourceMappingURL=invalid_loop.spec.js.map
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const test_case_1 = require("../test-case");
4
+ const requires_kubernetes_1 = require("../requires-kubernetes");
5
+ /**
6
+ * Regression test for the k8s currentStateKey caching wired up in
7
+ * feature/shared-services. Running `up` twice with no input change should
8
+ * produce a cached second run, not redeploy.
9
+ */
10
+ describe('k8s deployment caches via hammerkit.dev/state label', () => {
11
+ const namespace = `hammerkit-cache-${(process.env.HAMMERKIT_TEST_RUN_ID ?? 'local').slice(0, 30)}`;
12
+ const suite = (0, test_case_1.createTestCase)('k8s-state-cache', {
13
+ '.hammerkit.yaml': {
14
+ services: {
15
+ redis: {
16
+ image: 'redis:7-alpine',
17
+ ports: [':6379'],
18
+ },
19
+ },
20
+ environments: {
21
+ default: {
22
+ kubernetes: {
23
+ namespace,
24
+ context: process.env.CLUSTER_NAME || 'docker-desktop',
25
+ },
26
+ },
27
+ },
28
+ },
29
+ });
30
+ it('second up() is a cache hit on the same state key', (0, requires_kubernetes_1.requiresKubernetes)(async () => {
31
+ await suite.cli({}, async (cli, env) => {
32
+ await cli.runUp({ daemon: true });
33
+ const firstKey = await cli.service('redis').runtime.currentStateKey(env);
34
+ expect(firstKey).not.toBeNull();
35
+ await cli.runUp({ daemon: true });
36
+ const secondKey = await cli.service('redis').runtime.currentStateKey(env);
37
+ expect(secondKey).toBe(firstKey);
38
+ });
39
+ }), 240000);
40
+ });
41
+ //# sourceMappingURL=k8s-state-cache.spec.js.map
@@ -0,0 +1,148 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const requires_kubernetes_1 = require("../requires-kubernetes");
4
+ const test_case_1 = require("../test-case");
5
+ const client_node_1 = require("@kubernetes/client-node");
6
+ const http_1 = require("http");
7
+ // Exercises src/executer/kubernetes-service.ts end-to-end: hammerkit's
8
+ // `kubernetes-service` type opens a local TCP server (one per published port)
9
+ // that tunnels via the k8s API to a pod. We deploy nginx directly with the k8s
10
+ // client, then point a hammerkit kubernetes-service at it, drive the lifecycle
11
+ // (load kubeconfig -> resolve pod -> listen -> state `running`) and actually
12
+ // HTTP-GET the forwarded port to prove data flows through to the pod.
13
+ const RUN_ID = (process.env.HAMMERKIT_TEST_RUN_ID ?? 'local').slice(0, 30);
14
+ const NS = `hammerkit-k8s-svc-${RUN_ID}`;
15
+ const CTX = process.env.CLUSTER_NAME || 'docker-desktop';
16
+ const HOST_PORT = 28080;
17
+ const DEPLOY_NAME = 'nginx';
18
+ function makeClients() {
19
+ const kc = new client_node_1.KubeConfig();
20
+ kc.loadFromDefault();
21
+ kc.setCurrentContext(CTX);
22
+ return {
23
+ coreApi: kc.makeApiClient(client_node_1.CoreV1Api),
24
+ appsApi: kc.makeApiClient(client_node_1.AppsV1Api),
25
+ };
26
+ }
27
+ async function ensureNamespace(coreApi) {
28
+ try {
29
+ await coreApi.readNamespace(NS);
30
+ return;
31
+ }
32
+ catch {
33
+ /* missing */
34
+ }
35
+ try {
36
+ await coreApi.createNamespace({ metadata: { name: NS } });
37
+ }
38
+ catch {
39
+ /* racing creator */
40
+ }
41
+ }
42
+ async function applyNginx(coreApi, appsApi) {
43
+ await appsApi.deleteNamespacedDeployment(DEPLOY_NAME, NS).catch(() => undefined);
44
+ await appsApi.createNamespacedDeployment(NS, {
45
+ metadata: { name: DEPLOY_NAME, labels: { app: DEPLOY_NAME } },
46
+ spec: {
47
+ replicas: 1,
48
+ selector: { matchLabels: { app: DEPLOY_NAME } },
49
+ template: {
50
+ metadata: { labels: { app: DEPLOY_NAME } },
51
+ spec: {
52
+ containers: [{ name: DEPLOY_NAME, image: 'nginx:1.25-alpine', ports: [{ containerPort: 80 }] }],
53
+ },
54
+ },
55
+ },
56
+ });
57
+ const deadline = Date.now() + 90000;
58
+ while (Date.now() < deadline) {
59
+ const pods = await coreApi.listNamespacedPod(NS, undefined, undefined, undefined, undefined, `app=${DEPLOY_NAME}`);
60
+ const ready = pods.body.items.some((p) => p.status?.conditions?.some((c) => c.type === 'Ready' && c.status === 'True'));
61
+ if (ready)
62
+ return;
63
+ await new Promise((r) => setTimeout(r, 1000));
64
+ }
65
+ throw new Error(`nginx pod in ${NS} did not become ready in time`);
66
+ }
67
+ async function waitFor(predicate, timeoutMs, intervalMs = 200) {
68
+ const deadline = Date.now() + timeoutMs;
69
+ while (Date.now() < deadline) {
70
+ if (predicate())
71
+ return;
72
+ await new Promise((r) => setTimeout(r, intervalMs));
73
+ }
74
+ throw new Error('waitFor: predicate never became true');
75
+ }
76
+ function httpGet(host, port, path) {
77
+ return new Promise((resolve, reject) => {
78
+ const req = (0, http_1.request)({ host, port, path, method: 'GET', timeout: 5000 }, (res) => {
79
+ let body = '';
80
+ res.on('data', (c) => (body += c));
81
+ res.on('end', () => resolve({ status: res.statusCode ?? 0, body }));
82
+ });
83
+ req.on('error', reject);
84
+ req.on('timeout', () => {
85
+ req.destroy();
86
+ reject(new Error('http timeout'));
87
+ });
88
+ req.end();
89
+ });
90
+ }
91
+ describe('kubernetes-service (port-forward)', () => {
92
+ const suite = (0, test_case_1.createTestCase)('k8s-service-forward', {
93
+ '.hammerkit.yaml': {
94
+ services: {
95
+ nginx: {
96
+ context: CTX,
97
+ namespace: NS,
98
+ selector: { type: 'deployment', name: DEPLOY_NAME },
99
+ ports: [`${HOST_PORT}:80`],
100
+ },
101
+ },
102
+ environments: {
103
+ default: {
104
+ kubernetes: { context: CTX, namespace: NS },
105
+ },
106
+ },
107
+ },
108
+ });
109
+ beforeAll((0, requires_kubernetes_1.requiresKubernetes)(async () => {
110
+ const { coreApi, appsApi } = makeClients();
111
+ await ensureNamespace(coreApi);
112
+ await applyNginx(coreApi, appsApi);
113
+ }), 120000);
114
+ afterAll(async () => {
115
+ try {
116
+ const { coreApi } = makeClients();
117
+ await coreApi.deleteNamespace(NS).catch(() => undefined);
118
+ }
119
+ catch {
120
+ /* no cluster available */
121
+ }
122
+ });
123
+ it('forwards a kubernetes-service to a pod and tears down on abort', (0, requires_kubernetes_1.requiresKubernetes)(async () => {
124
+ await suite.cli({}, async (cli, env) => {
125
+ const exec = cli.up({ logMode: 'live' });
126
+ const done = exec.start();
127
+ try {
128
+ // state transitions to `running` only after the forward server's
129
+ // listen() resolves — proves loadKubeConfig + resolvePodName + the
130
+ // TCP listener setup all completed against a live cluster.
131
+ await waitFor(() => exec.state.current.services['nginx']?.state.current.type === 'running', 30000);
132
+ // and an actual byte round-trip through the forward confirms the
133
+ // per-connection portForward path (createServer callback) works too.
134
+ const res = await httpGet('127.0.0.1', HOST_PORT, '/');
135
+ expect(res.status).toBe(200);
136
+ expect(res.body).toMatch(/nginx/i);
137
+ }
138
+ finally {
139
+ env.abortCtrl.abort();
140
+ await done;
141
+ }
142
+ // abort triggers the finally block in kubernetesService: forwards close,
143
+ // state advances to `end`.
144
+ expect(exec.state.current.services['nginx']?.state.current.type).toBe('end');
145
+ });
146
+ }), 120000);
147
+ });
148
+ //# sourceMappingURL=kubernetes-service.spec.js.map