hammerkit 1.5.0 → 1.6.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/FEEDBACK.md +74 -0
- package/.agents/skills/before-commit/SKILL.md +101 -0
- package/.agents/skills/do-the-work/SKILL.md +64 -0
- package/.agents/skills/fix-ci/SKILL.md +98 -0
- package/.agents/skills/speckit-git-commit/SKILL.md +53 -0
- package/.agents/skills/speckit-git-feature/SKILL.md +72 -0
- package/.agents/skills/speckit-git-initialize/SKILL.md +54 -0
- package/.agents/skills/speckit-git-remote/SKILL.md +50 -0
- package/.agents/skills/speckit-git-validate/SKILL.md +54 -0
- package/.gitbook.yaml +5 -0
- package/.specify/extensions/.registry +37 -0
- package/.specify/extensions/git/README.md +100 -0
- package/.specify/extensions/git/commands/speckit.git.commit.md +48 -0
- package/.specify/extensions/git/commands/speckit.git.feature.md +67 -0
- package/.specify/extensions/git/commands/speckit.git.initialize.md +49 -0
- package/.specify/extensions/git/commands/speckit.git.remote.md +45 -0
- package/.specify/extensions/git/commands/speckit.git.validate.md +49 -0
- package/.specify/extensions/git/config-template.yml +62 -0
- package/.specify/extensions/git/extension.yml +140 -0
- package/.specify/extensions/git/git-config.yml +62 -0
- package/.specify/extensions.yml +149 -0
- package/.specify/feature.json +3 -0
- package/.specify/init-options.json +10 -0
- package/.specify/integration.json +15 -0
- package/.specify/integrations/claude.manifest.json +16 -0
- package/.specify/integrations/speckit.manifest.json +17 -0
- package/.specify/memory/constitution.md +162 -0
- package/.specify/templates/checklist-template.md +40 -0
- package/.specify/templates/constitution-template.md +50 -0
- package/.specify/templates/plan-template.md +113 -0
- package/.specify/templates/spec-template.md +131 -0
- package/.specify/templates/tasks-template.md +252 -0
- package/.specify/workflows/speckit/workflow.yml +77 -0
- package/.specify/workflows/workflow-registry.json +13 -0
- package/AGENTS.md +94 -0
- package/Dockerfile +3 -3
- package/FOLLOWUPS.md +34 -0
- package/README.md +9 -7
- package/SUMMARY.md +30 -5
- package/VALUES.md +53 -0
- package/build.schema.json +542 -408
- package/dist/cache/auto-pull.spec.js +123 -0
- package/dist/cache/backends/local-cache-backend.js +56 -0
- package/dist/cache/backends/local-cache-backend.spec.js +72 -0
- package/dist/cache/backends/s3-cache-backend.js +124 -0
- package/dist/cache/backends/s3-cache-backend.spec.js +118 -0
- package/dist/cache/cache-backend-registry.js +21 -0
- package/dist/cache/cache-backend-registry.spec.js +22 -0
- package/dist/cache/cache-backend.js +3 -0
- package/dist/cache/resolve-cache.js +60 -0
- package/dist/cache/resolve-cache.spec.js +52 -0
- package/dist/cli.js +112 -82
- package/dist/cli.spec.js +20 -2
- package/dist/console/get-logger.spec.js +23 -0
- package/dist/docker/get-default-platform.spec.js +29 -0
- package/dist/docker/longest-common-prefix.spec.js +26 -0
- package/dist/docker/package.js +283 -0
- package/dist/docker/package.spec.js +145 -0
- package/dist/docker/pull.js +4 -4
- package/dist/docker/remove-container.spec.js +32 -0
- package/dist/docker/stream.js +3 -3
- package/dist/docker/using-container.js +29 -11
- package/dist/docker/using-container.spec.js +90 -0
- package/dist/environment/merge-environment-variables.js +21 -0
- package/dist/environment/merge-environment-variables.spec.js +24 -0
- package/dist/environment/replace-env-variables.js +43 -10
- package/dist/environment/replace-env-variables.spec.js +47 -0
- package/dist/executer/abort.spec.js +18 -0
- package/dist/executer/await-completed-dependencies.js +56 -0
- package/dist/executer/cache-metadata.js +11 -0
- package/dist/executer/check-readiness.js +1 -1
- package/dist/{planner/work-node-port.js → executer/container-bind.js} +1 -1
- package/dist/executer/docker-service.js +110 -86
- package/dist/executer/docker-task.js +132 -0
- package/dist/executer/environment-mock.js +3 -4
- package/dist/executer/environment-mock.spec.js +22 -0
- package/dist/executer/event-cache.js +60 -127
- package/dist/executer/execute-command.js +4 -3
- package/dist/executer/execute-docker.js +32 -14
- package/dist/executer/execute-work-service.js +61 -0
- package/dist/executer/execute-work-task.js +107 -0
- package/dist/executer/execute-work-tree.js +27 -0
- package/dist/executer/execute.spec.js +14 -10
- package/dist/executer/execution-steps.js +47 -31
- package/dist/executer/get-container-binds.js +19 -0
- package/dist/executer/get-docker-executor.js +12 -12
- package/dist/executer/get-scheduler-down-result.js +12 -0
- package/dist/executer/get-scheduler-execute-result.js +28 -0
- package/dist/executer/get-scheduler-up-result.js +12 -0
- package/dist/executer/get-service-containers.js +14 -0
- package/dist/executer/get-service-containers.spec.js +59 -0
- package/dist/executer/get-service-env-hints.js +35 -0
- package/dist/executer/get-service-env-hints.spec.js +65 -0
- package/dist/executer/kubernetes-service.js +116 -48
- package/dist/executer/label-values.js +29 -46
- package/dist/executer/label-values.spec.js +61 -0
- package/dist/executer/lazy-resolver.js +16 -0
- package/dist/executer/lazy-resolver.spec.js +20 -0
- package/dist/executer/local-task.js +44 -0
- package/dist/executer/process-manager.js +16 -70
- package/dist/executer/process-manager.spec.js +39 -76
- package/dist/executer/reset-work-tree.js +30 -0
- package/dist/executer/scheduler/check-for-loop.js +17 -7
- package/dist/executer/scheduler/{scheduler-state.js → dependency-state.js} +1 -1
- package/dist/executer/scheduler/enqueue-next.js +83 -19
- package/dist/executer/scheduler/enqueue-next.spec.js +136 -0
- package/dist/executer/scheduler/{node-state.js → need-state.js} +1 -1
- package/dist/{parser/build-file.js → executer/scheduler/task-state.js} +1 -1
- package/dist/executer/set-user-permission.js +1 -1
- package/dist/executer/state-resolver.js +61 -0
- package/dist/executer/state-resolver.spec.js +37 -0
- package/dist/executer/state.js +37 -31
- package/dist/executer/state.spec.js +66 -0
- package/dist/executer/states.spec.js +14 -0
- package/dist/executer/watch-loop.js +68 -0
- package/dist/executer/watch-state-key.js +44 -0
- package/dist/executer/work-scope.js +1 -5
- package/dist/file/get-file-context.js +24 -3
- package/dist/file/get-file-context.spec.js +178 -0
- package/dist/file/move-files.js +2 -2
- package/dist/file/move-files.spec.js +48 -0
- package/dist/index.js +7 -8
- package/dist/json-schema.js +12 -0
- package/dist/kubernetes/apply.js +34 -0
- package/dist/kubernetes/await-running-state.js +71 -0
- package/dist/kubernetes/ensure-http-route.js +53 -0
- package/dist/kubernetes/ensure-http-route.spec.js +70 -0
- package/dist/kubernetes/ensure-ingress.js +54 -0
- package/dist/kubernetes/ensure-kubernetes-deployment-exists.js +105 -0
- package/dist/kubernetes/ensure-kubernetes-persistent-volume-claim-exists.js +40 -0
- package/dist/kubernetes/ensure-kubernetes-service-exists.js +36 -0
- package/dist/kubernetes/ensure-namespace.js +43 -0
- package/dist/kubernetes/ensure-namespace.spec.js +39 -0
- package/dist/kubernetes/ensure-persistent-data.js +158 -0
- package/dist/kubernetes/get-service-ip.js +11 -0
- package/dist/kubernetes/kubernetes-instance.js +48 -0
- package/dist/kubernetes/remove-persistent-data.js +19 -0
- package/dist/kubernetes/resolve-pod-name.js +42 -0
- package/dist/kubernetes/resolve-pod-name.spec.js +81 -0
- package/dist/kubernetes/resources.js +12 -0
- package/dist/kubernetes/restore-kubernetes-data.js +42 -0
- package/dist/kubernetes/store-kubernetes-data.js +39 -0
- package/dist/kubernetes/volumes.js +64 -0
- package/dist/log.js +69 -69
- package/dist/log.spec.js +131 -0
- package/dist/logging/grouped-logger.js +17 -15
- package/dist/logging/grouped-logger.spec.js +84 -0
- package/dist/logging/interactive-logger.js +1 -1
- package/dist/logging/interactive-logger.spec.js +57 -0
- package/dist/logging/live-logger.js +2 -2
- package/dist/logging/live-logger.spec.js +37 -0
- package/dist/logging/loggers.spec.js +154 -0
- package/dist/optimizer/calculate-checksum.spec.js +34 -0
- package/dist/optimizer/get-cache-directory.js +6 -6
- package/dist/optimizer/get-cache-directory.spec.js +59 -0
- package/dist/optimizer/get-work-cache-stats.js +53 -0
- package/dist/optimizer/get-work-cache-stats.spec.js +79 -0
- package/dist/{parser/build-file-task.js → optimizer/work-cache-stats.js} +1 -1
- package/dist/optimizer/work-task-cache-description.js +25 -0
- package/dist/optimizer/work-task-cache-description.spec.js +45 -0
- package/dist/parser/default-build-file.js +14 -7
- package/dist/parser/default-build-file.spec.js +48 -0
- package/dist/parser/parse-label-arguments.spec.js +27 -0
- package/dist/parser/read-build-file.js +2 -13
- package/dist/parser/read-build-file.spec.js +89 -0
- package/dist/parser/read-env-file.js +4 -5
- package/dist/parser/read-env-file.spec.js +42 -0
- package/dist/planner/utils/append-work-dependencies.js +55 -0
- package/dist/planner/utils/append-work-environment.js +22 -0
- package/dist/planner/utils/append-work-needs.js +18 -0
- package/dist/planner/utils/append-work-service.js +107 -0
- package/dist/planner/utils/append-work-service.spec.js +71 -0
- package/dist/planner/utils/append-work-task.js +81 -0
- package/dist/planner/utils/get-container-user.js +14 -0
- package/dist/planner/utils/get-container-user.spec.js +30 -0
- package/dist/planner/utils/get-default-kube-config.js +10 -0
- package/dist/planner/utils/get-default-kube-config.spec.js +11 -0
- package/dist/planner/utils/get-work-runtime.js +44 -0
- package/dist/planner/utils/normalize-path.js +1 -1
- package/dist/planner/utils/normalize-path.spec.js +24 -0
- package/dist/planner/utils/parse-work-command.js +80 -0
- package/dist/planner/utils/parse-work-command.spec.js +21 -0
- package/dist/planner/utils/parse-work-generate.js +38 -0
- package/dist/planner/utils/parse-work-generate.spec.js +45 -0
- package/dist/planner/utils/{parse-work-node-mount.js → parse-work-mount.js} +10 -7
- package/dist/planner/utils/{parse-work-node-mount.spec.js → parse-work-mount.spec.js} +14 -11
- package/dist/planner/utils/parse-work-mounts.js +13 -0
- package/dist/planner/utils/parse-work-mounts.spec.js +19 -0
- package/dist/planner/utils/{parse-work-node-port.js → parse-work-port.js} +11 -8
- package/dist/planner/utils/parse-work-port.spec.js +24 -0
- package/dist/planner/utils/parse-work-ports.js +10 -0
- package/dist/planner/utils/parse-work-ports.spec.js +24 -0
- package/dist/planner/utils/parse-work-source.js +72 -0
- package/dist/planner/utils/parse-work-source.spec.js +58 -0
- package/dist/planner/utils/parse-work-volume.js +45 -0
- package/dist/planner/utils/parse-work-volume.spec.js +18 -0
- package/dist/planner/utils/plan-work-tasks.js +41 -0
- package/dist/planner/utils/plan-work-tasks.spec.js +30 -0
- package/dist/planner/utils/plan-work-volume.js +1 -0
- package/dist/planner/utils/plan-work-volume.spec.js +33 -0
- package/dist/planner/utils/split-name.js +2 -2
- package/dist/planner/utils/split-name.spec.js +16 -0
- package/dist/planner/utils/template-value.js +1 -2
- package/dist/planner/utils/template-value.spec.js +14 -0
- package/dist/planner/validate.js +71 -38
- package/dist/planner/validate.spec.js +251 -0
- package/dist/planner/work-cache-id.js +12 -0
- package/dist/planner/work-cache-id.spec.js +173 -0
- package/dist/planner/work-command.js +3 -0
- package/dist/planner/work-environment.js +3 -0
- package/dist/planner/work-healthcheck.js +3 -0
- package/dist/planner/{work-node-status.js → work-item-status.js} +16 -62
- package/dist/{parser/build-file-service.js → planner/work-item-validation.js} +1 -1
- package/dist/planner/work-item.js +16 -0
- package/dist/{optimizer/work-node-cache-stats.js → planner/work-kubernetes-selector.js} +1 -1
- package/dist/planner/{work-nodes.js → work-port.js} +1 -1
- package/dist/planner/work-runtime-docker.js +224 -0
- package/dist/planner/work-runtime-kubernetes.js +264 -0
- package/dist/planner/work-runtime-local.js +109 -0
- package/dist/planner/work-runtime-local.spec.js +193 -0
- package/dist/planner/work-service-id.js +15 -5
- package/dist/planner/work-source.js +3 -0
- package/dist/planner/work-task.js +8 -0
- package/dist/program-commands.spec.js +84 -0
- package/dist/program.js +219 -73
- package/dist/program.spec.js +34 -11
- package/dist/run-program.js +28 -0
- package/dist/{executer/process.js → runtime/runtime.js} +1 -1
- package/dist/schema/build-file-base-task-schema.js +27 -0
- package/dist/schema/build-file-container-service-schema.js +28 -0
- package/dist/schema/build-file-container-task-schema.js +13 -0
- package/dist/schema/build-file-environment-schema-ingress.js +14 -0
- package/dist/schema/build-file-environment-schema.js +23 -0
- package/dist/schema/build-file-kubernetes-service-schema.js +17 -0
- package/dist/schema/build-file-kubernetes-service-selector-schema.js +9 -0
- package/dist/schema/build-file-local-platform-schema.js +9 -0
- package/dist/schema/build-file-local-task-schema.js +12 -0
- package/dist/schema/build-file-need-schema.js +12 -0
- package/dist/schema/build-file-schema.js +23 -0
- package/dist/schema/build-file-schema.spec.js +61 -0
- package/dist/schema/build-file-service-container-healthcheck.js +8 -0
- package/dist/schema/build-file-service-schema.js +15 -0
- package/dist/schema/build-file-task-command-schema.js +12 -0
- package/dist/schema/build-file-task-schema.js +12 -0
- package/dist/schema/build-file-volume-schema.js +14 -0
- package/dist/schema/cache-schema.js +31 -0
- package/dist/schema/doc-build-files.spec.js +223 -0
- package/dist/schema/envs-schema.js +6 -0
- package/dist/schema/labels-schema.js +6 -0
- package/dist/schema/parse-context.js +3 -0
- package/dist/schema/parse-error.js +12 -0
- package/dist/schema/parse-error.spec.js +18 -0
- package/dist/schema/reference-parser.js +209 -0
- package/dist/schema/reference-parser.spec.js +83 -0
- package/dist/schema/schema-parser.js +66 -0
- package/dist/schema/schema-parser.spec.js +80 -0
- package/dist/schema/type-guards.spec.js +23 -0
- package/dist/schema/work-scope-parser.js +77 -0
- package/dist/schema/work-scope-parser.spec.js +66 -0
- package/dist/service/update-service-status.js +11 -0
- package/dist/service/update-service-status.spec.js +27 -0
- package/dist/testing/ensure-local-registry.js +134 -0
- package/dist/testing/example-test-suite.js +16 -18
- package/dist/testing/expect.js +46 -22
- package/dist/testing/http-get.js +21 -0
- package/dist/testing/integration/cache.spec.js +13 -14
- package/dist/testing/integration/cancellation.spec.js +14 -9
- package/dist/testing/integration/clean.spec.js +14 -11
- package/dist/testing/integration/cmd.spec.js +1 -1
- package/dist/testing/integration/concurrency.spec.js +3 -3
- package/dist/testing/integration/docker-package-registry.spec.js +44 -0
- package/dist/testing/integration/docker-service-crash.spec.js +36 -0
- package/dist/testing/integration/docker.spec.js +4 -3
- package/dist/testing/integration/env.spec.js +9 -8
- package/dist/testing/integration/environment.spec.js +97 -0
- package/dist/testing/integration/error.spec.js +5 -4
- package/dist/testing/integration/export.spec.js +22 -0
- package/dist/testing/integration/extend.spec.js +9 -12
- package/dist/testing/integration/glob.spec.js +12 -20
- package/dist/testing/integration/include.spec.js +3 -3
- package/dist/testing/integration/invalid.spec.js +2 -3
- package/dist/testing/integration/invalid_loop.spec.js +49 -6
- package/dist/testing/integration/k8s-state-cache.spec.js +41 -0
- package/dist/testing/integration/kubernetes-service.spec.js +148 -0
- package/dist/testing/integration/kubernetes.spec.js +93 -9
- package/dist/testing/integration/labels.spec.js +6 -11
- package/dist/testing/integration/local.spec.js +1 -1
- package/dist/testing/integration/monorepo.spec.js +4 -4
- package/dist/testing/integration/multi-line.spec.js +3 -3
- package/dist/testing/integration/reference.spec.js +4 -5
- package/dist/testing/integration/services.spec.js +22 -4
- package/dist/testing/integration/store.spec.js +15 -16
- package/dist/testing/integration/unknown.spec.js +20 -18
- package/dist/testing/integration/validate.spec.js +143 -26
- package/dist/testing/integration/watch-dependency.spec.js +11 -8
- package/dist/testing/integration/watch.spec.js +15 -16
- package/dist/testing/requires-kubernetes.js +18 -0
- package/dist/testing/requires-linux-containers.js +18 -0
- package/dist/testing/requires-windows-containers.js +18 -0
- package/dist/testing/test-case.js +75 -0
- package/dist/testing/test-streams.js +28 -0
- package/dist/testing/testing-timeout.js +32 -0
- package/dist/utils/abort-event.js +10 -4
- package/dist/utils/abort-event.spec.js +46 -0
- package/dist/utils/buffer-context.js +44 -0
- package/dist/utils/buffer-context.spec.js +38 -0
- package/dist/utils/ci.spec.js +53 -0
- package/dist/utils/emitter.spec.js +34 -0
- package/dist/utils/empty-writable.spec.js +18 -0
- package/dist/utils/environment-config.js +4 -1
- package/dist/utils/environment-config.spec.js +26 -0
- package/dist/utils/fail-never.spec.js +9 -0
- package/dist/version.js +9 -0
- package/dist/version.spec.js +12 -0
- package/package.json +41 -23
- package/specs/build-file/caches/spec.md +114 -0
- package/specs/build-file/environment-variables/spec.md +82 -0
- package/specs/build-file/includes/spec.md +60 -0
- package/specs/build-file/references/spec.md +56 -0
- package/specs/build-file/spec.md +62 -0
- package/specs/cli/clean/spec.md +85 -0
- package/specs/cli/down/spec.md +85 -0
- package/specs/cli/execute/spec.md +101 -0
- package/specs/cli/init/spec.md +64 -0
- package/specs/cli/ls/spec.md +66 -0
- package/specs/cli/package/spec.md +110 -0
- package/specs/cli/spec.md +73 -0
- package/specs/cli/store-restore/spec.md +74 -0
- package/specs/cli/up/spec.md +80 -0
- package/specs/cli/validate/spec.md +70 -0
- package/specs/labels/spec.md +91 -0
- package/specs/service/container/spec.md +120 -0
- package/specs/service/kubernetes/spec.md +97 -0
- package/specs/service/spec.md +105 -0
- package/specs/task/caching/spec.md +107 -0
- package/specs/task/container/spec.md +118 -0
- package/specs/task/dependencies/spec.md +70 -0
- package/specs/task/extending/spec.md +74 -0
- package/specs/task/kubernetes/spec.md +125 -0
- package/specs/task/needs/spec.md +59 -0
- package/specs/task/spec.md +87 -0
- package/specs/task/watching/spec.md +69 -0
- package/dist/console/console-context-mock.js +0 -14
- package/dist/environment/get-process-env.js +0 -15
- package/dist/executer/create-scheduler-state.js +0 -32
- package/dist/executer/docker-node.js +0 -123
- package/dist/executer/hierarchy-scheduler.js +0 -94
- package/dist/executer/local-node.js +0 -57
- package/dist/executer/schedule.js +0 -137
- package/dist/executer/start-node.js +0 -67
- package/dist/executer/watch-node.js +0 -56
- package/dist/executer/watch-service.js +0 -54
- package/dist/file/get-file-context-mock.js +0 -187
- package/dist/file/get-file-context-mock.spec.js +0 -56
- package/dist/get-work-context.js +0 -29
- package/dist/optimizer/get-work-node-cache-stats.js +0 -104
- package/dist/optimizer/read-work-node-cache.js +0 -19
- package/dist/optimizer/work-node-cache-description.js +0 -32
- package/dist/optimizer/write-work-node-cache.js +0 -21
- package/dist/parser/build-file-task-command.js +0 -3
- package/dist/parser/build-file-task-platform.js +0 -3
- package/dist/parser/build-file-task-source.js +0 -3
- package/dist/parser/get-build-file.js +0 -9
- package/dist/parser/parse-boolean.js +0 -29
- package/dist/parser/parse-boolean.spec.js +0 -48
- package/dist/parser/parse-build-file-references.js +0 -35
- package/dist/parser/parse-build-file-services.js +0 -58
- package/dist/parser/parse-build-file-task-command.js +0 -36
- package/dist/parser/parse-build-file-task-source.js +0 -63
- package/dist/parser/parse-build-file.js +0 -125
- package/dist/parser/parse-context.js +0 -13
- package/dist/parser/parse-envs.js +0 -29
- package/dist/parser/parse-healthcheck.js +0 -28
- package/dist/parser/parse-service-selector.js +0 -39
- package/dist/parser/parse-string-array.js +0 -20
- package/dist/parser/parse-string-map.js +0 -30
- package/dist/parser/parse-string.js +0 -20
- package/dist/planner/utils/get-container-mounts.js +0 -24
- package/dist/planner/utils/parse-work-service-volume.js +0 -23
- package/dist/planner/utils/plan-work-command.js +0 -21
- package/dist/planner/utils/plan-work-dependency.js +0 -36
- package/dist/planner/utils/plan-work-node.js +0 -293
- package/dist/planner/utils/plan-work-nodes.js +0 -78
- package/dist/planner/utils/plan-work-tree.js +0 -15
- package/dist/planner/work-context.js +0 -23
- package/dist/planner/work-node-command.js +0 -3
- package/dist/planner/work-node-id.js +0 -12
- package/dist/planner/work-node-id.spec.js +0 -106
- package/dist/planner/work-node-path.js +0 -2
- package/dist/planner/work-node-source.js +0 -3
- package/dist/planner/work-node-validation.js +0 -3
- package/dist/planner/work-node.js +0 -8
- package/dist/planner/work-service-volume.js +0 -3
- package/dist/planner/work-services.js +0 -3
- package/dist/start-watch-processes.js +0 -28
- package/dist/testing/cli.js +0 -73
- package/dist/testing/create-build-file.js +0 -9
- package/dist/testing/get-logger.js +0 -23
- package/dist/testing/get-node.js +0 -12
- package/dist/testing/get-test-context.js +0 -19
- package/dist/testing/integration/program.spec.js +0 -25
- package/dist/testing/lazy.js +0 -17
- package/dist/testing/start-watch-processes.js +0 -29
- package/dist/testing/test-suite-options.js +0 -3
- package/dist/utils/abortable-function.js +0 -71
- package/logs/cache-console.log +0 -0
- package/logs/cache-status.log +0 -6
- package/logs/cache-stout.log +0 -0
- package/logs/cancellation-console.log +0 -0
- package/logs/cancellation-status.log +0 -3
- package/logs/cancellation-stout.log +0 -3
- package/logs/clean-console.log +0 -0
- package/logs/clean-status.log +0 -37
- package/logs/clean-stout.log +0 -95
- package/logs/cmd-console.log +0 -0
- package/logs/cmd-status.log +0 -8
- package/logs/cmd-stout.log +0 -9
- package/logs/concurrency-console.log +0 -0
- package/logs/concurrency-status.log +0 -14
- package/logs/concurrency-stout.log +0 -88
- package/logs/docker-console.log +0 -0
- package/logs/docker-status.log +0 -14
- package/logs/docker-stout.log +0 -39
- package/logs/env-console.log +0 -1
- package/logs/env-status.log +0 -1
- package/logs/env-stout.log +0 -0
- package/logs/error-console.log +0 -0
- package/logs/error-status.log +0 -10
- package/logs/error-stout.log +0 -36
- package/logs/extend-console.log +0 -0
- package/logs/extend-status.log +0 -1
- package/logs/extend-stout.log +0 -0
- package/logs/glob-console.log +0 -28
- package/logs/glob-status.log +0 -23
- package/logs/glob-stout.log +0 -52
- package/logs/hello-world-node-console.log +0 -0
- package/logs/hello-world-node-status.log +0 -37
- package/logs/hello-world-node-stout.log +0 -41
- package/logs/include-console.log +0 -0
- package/logs/include-status.log +0 -3
- package/logs/include-stout.log +0 -0
- package/logs/invalid-console.log +0 -0
- package/logs/invalid-status.log +0 -1
- package/logs/invalid-stout.log +0 -0
- package/logs/invalid_loop-console.log +0 -0
- package/logs/invalid_loop-status.log +0 -1
- package/logs/invalid_loop-stout.log +0 -11
- package/logs/labels-console.log +0 -0
- package/logs/labels-status.log +0 -1
- package/logs/labels-stout.log +0 -0
- package/logs/local-console.log +0 -0
- package/logs/local-status.log +0 -7
- package/logs/local-stout.log +0 -8
- package/logs/monorepo-console.log +0 -0
- package/logs/monorepo-status.log +0 -152
- package/logs/monorepo-stout.log +0 -2354
- package/logs/multi-line-console.log +0 -0
- package/logs/multi-line-status.log +0 -1
- package/logs/multi-line-stout.log +0 -0
- package/logs/reference-console.log +0 -0
- package/logs/reference-status.log +0 -5
- package/logs/reference-stout.log +0 -0
- package/logs/services-console.log +0 -0
- package/logs/services-status.log +0 -129
- package/logs/services-stout.log +0 -639
- package/logs/store-restore-console.log +0 -0
- package/logs/store-restore-status.log +0 -40
- package/logs/store-restore-stout.log +0 -97
- package/logs/unknown-console.log +0 -3
- package/logs/unknown-status.log +0 -1
- package/logs/unknown-stout.log +0 -0
- package/logs/validate-console.log +0 -0
- package/logs/validate-status.log +0 -2
- package/logs/validate-stout.log +0 -0
- package/logs/watch-console.log +0 -0
- package/logs/watch-dependency-console.log +0 -0
- package/logs/watch-dependency-status.log +0 -176
- package/logs/watch-dependency-stout.log +0 -779
- package/logs/watch-status.log +0 -100
- package/logs/watch-stout.log +0 -349
|
@@ -1,90 +1,53 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const process_manager_1 = require("./process-manager");
|
|
4
|
-
const
|
|
5
|
-
const
|
|
4
|
+
const work_item_status_1 = require("../planner/work-item-status");
|
|
5
|
+
const empty_writable_1 = require("../utils/empty-writable");
|
|
6
6
|
describe('process-manager', () => {
|
|
7
|
+
function fakeWorkItem(id) {
|
|
8
|
+
return {
|
|
9
|
+
id: () => '',
|
|
10
|
+
status: (0, work_item_status_1.statusConsole)((0, empty_writable_1.emptyWritable)()).context((0, work_item_status_1.logContext)('task', { name: id })),
|
|
11
|
+
deps: [],
|
|
12
|
+
aliases: [id],
|
|
13
|
+
needs: [],
|
|
14
|
+
requiredBy: [],
|
|
15
|
+
name: id,
|
|
16
|
+
data: null,
|
|
17
|
+
state: null,
|
|
18
|
+
runtime: null,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
7
21
|
it('should complete on success', async () => {
|
|
8
|
-
const manager = new process_manager_1.ProcessManager(
|
|
9
|
-
let
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
await manager.onComplete();
|
|
16
|
-
expect(currentIndex).toBe(2);
|
|
22
|
+
const manager = new process_manager_1.ProcessManager(0);
|
|
23
|
+
let called = false;
|
|
24
|
+
await manager.task(fakeWorkItem('a'), () => new Promise((resolve) => setTimeout(() => {
|
|
25
|
+
called = true;
|
|
26
|
+
resolve();
|
|
27
|
+
}, 100)));
|
|
28
|
+
expect(called).toBeTruthy();
|
|
17
29
|
});
|
|
18
|
-
it('should
|
|
19
|
-
const manager = new process_manager_1.ProcessManager(
|
|
20
|
-
|
|
21
|
-
const expectedEvents = ['started', 'ended'];
|
|
22
|
-
manager.on((evt) => {
|
|
23
|
-
expect(evt.type).toBe(expectedEvents[currentIndex++]);
|
|
24
|
-
});
|
|
25
|
-
manager.task({ type: 'task', name: 'test-error', id: 'a' }, () => new Promise((resolve, reject) => setTimeout(() => reject(new Error('3')), 100)));
|
|
26
|
-
await manager.onComplete();
|
|
27
|
-
expect(currentIndex).toBe(2);
|
|
30
|
+
it('should throw error', async () => {
|
|
31
|
+
const manager = new process_manager_1.ProcessManager(0);
|
|
32
|
+
await expect(manager.task(fakeWorkItem('a'), () => new Promise((resolve, reject) => setTimeout(() => reject(new Error('3')), 100)))).rejects.toThrow('3');
|
|
28
33
|
});
|
|
29
34
|
it('should not start more than worker count', async () => {
|
|
30
|
-
const manager = new process_manager_1.ProcessManager(
|
|
31
|
-
const processes = [];
|
|
32
|
-
let concurrencyCount = 0;
|
|
33
|
-
let hasOversteppedLimits = false;
|
|
34
|
-
manager.on((evt) => {
|
|
35
|
-
if (evt.type === 'started') {
|
|
36
|
-
concurrencyCount++;
|
|
37
|
-
}
|
|
38
|
-
else if (evt.type === 'ended') {
|
|
39
|
-
concurrencyCount--;
|
|
40
|
-
processes.push(evt.context.id);
|
|
41
|
-
}
|
|
42
|
-
if (concurrencyCount > 1) {
|
|
43
|
-
hasOversteppedLimits = true;
|
|
44
|
-
}
|
|
45
|
-
});
|
|
46
|
-
manager.task({ type: 'task', name: 'test-success', id: 'a' }, () => new Promise((resolve) => setTimeout(() => resolve(), 100)));
|
|
47
|
-
manager.task({ type: 'task', name: 'test-success', id: 'b' }, () => new Promise((resolve) => setTimeout(() => resolve(), 100)));
|
|
48
|
-
manager.task({ type: 'task', name: 'test-success', id: 'c' }, () => new Promise((resolve) => setTimeout(() => resolve(), 100)));
|
|
49
|
-
await manager.onComplete();
|
|
50
|
-
expect(processes).toEqual(['a', 'b', 'c']);
|
|
51
|
-
expect(hasOversteppedLimits).toBeFalsy();
|
|
52
|
-
expect(concurrencyCount).toBe(0);
|
|
53
|
-
});
|
|
54
|
-
it('should terminate on abort', async () => {
|
|
55
|
-
const env = (0, environment_mock_1.environmentMock)(process.cwd());
|
|
56
|
-
const manager = new process_manager_1.ProcessManager(env, 0);
|
|
57
|
-
manager.task({ type: 'task', name: 'test-success', id: 'a' }, (abort) => new Promise((resolve) => {
|
|
58
|
-
(0, abort_event_1.listenOnAbort)(abort.signal, resolve);
|
|
59
|
-
}));
|
|
60
|
-
setTimeout(() => {
|
|
61
|
-
env.abortCtrl.abort();
|
|
62
|
-
}, 200);
|
|
63
|
-
await manager.onComplete();
|
|
64
|
-
});
|
|
65
|
-
it('should abort if task with same id is already started', async () => {
|
|
66
|
-
const manager = new process_manager_1.ProcessManager((0, environment_mock_1.environmentMock)(process.cwd()), 0);
|
|
67
|
-
const processes = [];
|
|
35
|
+
const manager = new process_manager_1.ProcessManager(1);
|
|
68
36
|
let concurrencyCount = 0;
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
else if (evt.type === 'ended') {
|
|
37
|
+
const fakeAction = () => new Promise((resolve) => {
|
|
38
|
+
expect(concurrencyCount).toBe(0);
|
|
39
|
+
concurrencyCount++;
|
|
40
|
+
setTimeout(() => {
|
|
41
|
+
expect(concurrencyCount).toBe(1);
|
|
75
42
|
concurrencyCount--;
|
|
76
|
-
|
|
77
|
-
}
|
|
78
|
-
if (concurrencyCount > 1) {
|
|
79
|
-
hasOversteppedLimits = true;
|
|
80
|
-
}
|
|
43
|
+
resolve();
|
|
44
|
+
}, 100);
|
|
81
45
|
});
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
expect(hasOversteppedLimits).toBeFalsy();
|
|
46
|
+
await Promise.all([
|
|
47
|
+
manager.task(fakeWorkItem('a'), fakeAction),
|
|
48
|
+
manager.task(fakeWorkItem('b'), fakeAction),
|
|
49
|
+
manager.task(fakeWorkItem('c'), fakeAction),
|
|
50
|
+
]);
|
|
88
51
|
expect(concurrencyCount).toBe(0);
|
|
89
52
|
});
|
|
90
53
|
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resetWorkTree = void 0;
|
|
4
|
+
const state_1 = require("./state");
|
|
5
|
+
function resetWorkTree(workTree, type) {
|
|
6
|
+
return {
|
|
7
|
+
tasks: Object.entries(workTree.tasks).reduce((tasks, [key, task]) => {
|
|
8
|
+
task.state = new state_1.State({
|
|
9
|
+
type: 'pending',
|
|
10
|
+
stateKey: null,
|
|
11
|
+
});
|
|
12
|
+
tasks[key] = task;
|
|
13
|
+
return tasks;
|
|
14
|
+
}, {}),
|
|
15
|
+
services: Object.entries(workTree.services).reduce((services, [key, service]) => {
|
|
16
|
+
if (type === 'execute' && service.requiredBy.length === 0) {
|
|
17
|
+
return services;
|
|
18
|
+
}
|
|
19
|
+
service.state = new state_1.State({
|
|
20
|
+
type: 'pending',
|
|
21
|
+
stateKey: null,
|
|
22
|
+
});
|
|
23
|
+
services[key] = service;
|
|
24
|
+
return services;
|
|
25
|
+
}, {}),
|
|
26
|
+
environment: workTree.environment,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
exports.resetWorkTree = resetWorkTree;
|
|
30
|
+
//# sourceMappingURL=reset-work-tree.js.map
|
|
@@ -1,19 +1,29 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.checkForLoop = void 0;
|
|
4
|
-
const
|
|
4
|
+
const plan_work_tasks_1 = require("../../planner/utils/plan-work-tasks");
|
|
5
5
|
const validate_1 = require("../../planner/validate");
|
|
6
|
-
function checkForLoop(
|
|
7
|
-
for (const
|
|
8
|
-
const cyclePath = (0, validate_1.
|
|
6
|
+
function checkForLoop(workTree) {
|
|
7
|
+
for (const task of (0, plan_work_tasks_1.iterateWorkTasks)(workTree)) {
|
|
8
|
+
const cyclePath = (0, validate_1.hasDependencyCycle)(task, []) ?? (0, validate_1.hasMixedCycle)(task, []);
|
|
9
9
|
if (cyclePath && cyclePath.length > 0) {
|
|
10
10
|
const errorMessage = `task cycle detected ${cyclePath.map((n) => n.name).join(' -> ')}`;
|
|
11
|
-
state.
|
|
11
|
+
task.state.set({
|
|
12
12
|
type: 'error',
|
|
13
|
-
node: nodeState.node,
|
|
14
13
|
stateKey: null,
|
|
15
14
|
errorMessage,
|
|
16
|
-
};
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
for (const service of (0, plan_work_tasks_1.iterateWorkServices)(workTree)) {
|
|
19
|
+
const cyclePath = (0, validate_1.hasNeedCycle)(service, []) ?? (0, validate_1.hasMixedCycle)(service, []);
|
|
20
|
+
if (cyclePath && cyclePath.length > 0) {
|
|
21
|
+
const errorMessage = `service cycle detected ${cyclePath.map((n) => n.name).join(' -> ')}`;
|
|
22
|
+
service.state.set({
|
|
23
|
+
type: 'error',
|
|
24
|
+
stateKey: null,
|
|
25
|
+
errorMessage,
|
|
26
|
+
});
|
|
17
27
|
}
|
|
18
28
|
}
|
|
19
29
|
}
|
|
@@ -1,27 +1,91 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.checkCacheState = void 0;
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
4
|
+
const get_work_cache_stats_1 = require("../../optimizer/get-work-cache-stats");
|
|
5
|
+
const work_item_1 = require("../../planner/work-item");
|
|
6
|
+
const get_cache_directory_1 = require("../../optimizer/get-cache-directory");
|
|
7
|
+
const cache_metadata_1 = require("../cache-metadata");
|
|
8
|
+
const work_task_cache_description_1 = require("../../optimizer/work-task-cache-description");
|
|
9
|
+
const log_1 = require("../../log");
|
|
10
|
+
const crypto_1 = require("crypto");
|
|
11
|
+
function resolveEffective(item, fallbackMethod) {
|
|
12
|
+
const declared = item.data.caching;
|
|
13
|
+
if (declared.implicit) {
|
|
14
|
+
return { ...declared, method: fallbackMethod };
|
|
14
15
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
return declared;
|
|
17
|
+
}
|
|
18
|
+
// Fold a task's own state key together with the state keys of its dependencies.
|
|
19
|
+
// A change anywhere in the dependency subtree must change the resulting key, so
|
|
20
|
+
// that a downstream task is invalidated when an upstream source changes — even
|
|
21
|
+
// if the downstream task's own sources are untouched.
|
|
22
|
+
function combineStateKeys(ownKey, depKeys) {
|
|
23
|
+
if (depKeys.length === 0) {
|
|
24
|
+
return ownKey;
|
|
25
|
+
}
|
|
26
|
+
// Sort so the key is independent of dependency declaration order.
|
|
27
|
+
const sorted = [...depKeys].sort();
|
|
28
|
+
return (0, crypto_1.createHash)('md5')
|
|
29
|
+
.update([ownKey, ...sorted].join(','))
|
|
30
|
+
.digest('hex');
|
|
31
|
+
}
|
|
32
|
+
// Compute an item's effective state key from its source files plus the effective
|
|
33
|
+
// state keys of its dependencies, recursively. This is derived purely from the
|
|
34
|
+
// work tree and the filesystem, so it does not depend on scheduler/run state —
|
|
35
|
+
// important because checkCacheState runs before dependencies are awaited.
|
|
36
|
+
async function resolveEffectiveStateKey(item, defaultCacheMethod, environment, memo) {
|
|
37
|
+
const existing = memo.get(item.id());
|
|
38
|
+
if (existing !== undefined) {
|
|
39
|
+
return existing;
|
|
40
|
+
}
|
|
41
|
+
const resolved = resolveEffective(item, defaultCacheMethod);
|
|
42
|
+
// Always hash with a concrete method; `none` only disables the cache *check*
|
|
43
|
+
// for that task, its sources still influence what depends on it.
|
|
44
|
+
const method = resolved.method === 'none' ? defaultCacheMethod : resolved.method;
|
|
45
|
+
const stats = await (0, get_work_cache_stats_1.getWorkCacheStats)(item.data, environment);
|
|
46
|
+
const ownKey = (0, get_work_cache_stats_1.getStateKey)(stats, method);
|
|
47
|
+
const depKeys = [];
|
|
48
|
+
for (const dep of item.deps) {
|
|
49
|
+
depKeys.push(await resolveEffectiveStateKey(dep, defaultCacheMethod, environment, memo));
|
|
50
|
+
}
|
|
51
|
+
const combined = combineStateKeys(ownKey, depKeys);
|
|
52
|
+
memo.set(item.id(), combined);
|
|
53
|
+
return combined;
|
|
54
|
+
}
|
|
55
|
+
async function checkCacheState(item, defaultCacheMethod, environment) {
|
|
56
|
+
const resolved = resolveEffective(item, defaultCacheMethod);
|
|
57
|
+
const currentStats = await (0, get_work_cache_stats_1.getWorkCacheStats)(item.data, environment);
|
|
58
|
+
const ownKey = (0, get_work_cache_stats_1.getStateKey)(currentStats, resolved.method === 'none' ? defaultCacheMethod : resolved.method);
|
|
59
|
+
const memo = new Map();
|
|
60
|
+
const depKeys = [];
|
|
61
|
+
for (const dep of item.deps) {
|
|
62
|
+
depKeys.push(await resolveEffectiveStateKey(dep, defaultCacheMethod, environment, memo));
|
|
63
|
+
}
|
|
64
|
+
const stateKey = combineStateKeys(ownKey, depKeys);
|
|
65
|
+
if (resolved.method === 'none') {
|
|
66
|
+
item.status.write('debug', `${item.name} is skipping cache check, because caching is disabled`);
|
|
67
|
+
return { cached: false, stateKey, resolved };
|
|
68
|
+
}
|
|
69
|
+
if ((0, work_item_1.isWorkTaskItem)(item)) {
|
|
70
|
+
const runtimeStateKey = await item.runtime.currentStateKey(environment);
|
|
71
|
+
if (runtimeStateKey === stateKey) {
|
|
72
|
+
return { cached: true, stateKey, resolved };
|
|
73
|
+
}
|
|
74
|
+
try {
|
|
75
|
+
const cacheDir = (0, get_cache_directory_1.getCacheDirectory)(item.id());
|
|
76
|
+
const pulled = await resolved.backend.pull(item.id(), stateKey, cacheDir, environment);
|
|
77
|
+
if (pulled) {
|
|
78
|
+
item.status.write('info', `${item.name} pulled from cache "${resolved.name}" (${resolved.backend.type})`);
|
|
79
|
+
await item.runtime.restore(environment, cacheDir);
|
|
80
|
+
await (0, cache_metadata_1.writeCacheMetadata)(environment, item.id(), currentStats, (0, work_task_cache_description_1.getWorkTaskCacheDescription)(item.data));
|
|
81
|
+
return { cached: true, stateKey, resolved };
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch (e) {
|
|
85
|
+
item.status.write('warn', `${item.name} failed to pull from cache "${resolved.name}": ${(0, log_1.getErrorMessage)(e)} — continuing with local execution`);
|
|
86
|
+
}
|
|
19
87
|
}
|
|
20
|
-
|
|
21
|
-
return {
|
|
22
|
-
cached: cacheKey === stateKey,
|
|
23
|
-
stateKey,
|
|
24
|
-
};
|
|
88
|
+
return { cached: false, stateKey, resolved };
|
|
25
89
|
}
|
|
26
90
|
exports.checkCacheState = checkCacheState;
|
|
27
91
|
//# sourceMappingURL=enqueue-next.js.map
|
|
@@ -0,0 +1,136 @@
|
|
|
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("../environment-mock");
|
|
7
|
+
const enqueue_next_1 = require("./enqueue-next");
|
|
8
|
+
const local_cache_backend_1 = require("../../cache/backends/local-cache-backend");
|
|
9
|
+
const state_1 = require("../state");
|
|
10
|
+
describe('checkCacheState', () => {
|
|
11
|
+
let scratch;
|
|
12
|
+
let remoteDir;
|
|
13
|
+
let machineHome;
|
|
14
|
+
let originalHome;
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
scratch = (0, fs_1.mkdtempSync)((0, path_1.join)((0, os_1.tmpdir)(), 'hammerkit-enqueue-'));
|
|
17
|
+
remoteDir = (0, fs_1.mkdtempSync)((0, path_1.join)((0, os_1.tmpdir)(), 'hammerkit-remote-'));
|
|
18
|
+
machineHome = (0, fs_1.mkdtempSync)((0, path_1.join)((0, os_1.tmpdir)(), 'hammerkit-home-'));
|
|
19
|
+
originalHome = process.env.HOME;
|
|
20
|
+
if (process.platform === 'win32') {
|
|
21
|
+
process.env.APPDATA = machineHome;
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
process.env.HOME = machineHome;
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
afterEach(() => {
|
|
28
|
+
(0, fs_1.rmSync)(scratch, { recursive: true, force: true });
|
|
29
|
+
(0, fs_1.rmSync)(remoteDir, { recursive: true, force: true });
|
|
30
|
+
(0, fs_1.rmSync)(machineHome, { recursive: true, force: true });
|
|
31
|
+
if (originalHome !== undefined) {
|
|
32
|
+
process.env.HOME = originalHome;
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
delete process.env.HOME;
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
// empty remote → backend.pull always misses, so a key mismatch yields cached:false
|
|
39
|
+
function makeResolved(method) {
|
|
40
|
+
return {
|
|
41
|
+
name: 'remote',
|
|
42
|
+
method,
|
|
43
|
+
backend: (0, local_cache_backend_1.createLocalCacheBackend)({ type: 'local', path: remoteDir }),
|
|
44
|
+
implicit: false,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function makeTask(id, options) {
|
|
48
|
+
const storedStateKey = options.storedStateKey ?? null;
|
|
49
|
+
return {
|
|
50
|
+
id: () => id,
|
|
51
|
+
name: id,
|
|
52
|
+
status: { write: vi.fn() },
|
|
53
|
+
data: {
|
|
54
|
+
type: 'local-task',
|
|
55
|
+
name: id,
|
|
56
|
+
cwd: scratch,
|
|
57
|
+
cmds: [],
|
|
58
|
+
generates: [],
|
|
59
|
+
src: (options.srcFiles ?? []).map((absolutePath) => ({
|
|
60
|
+
absolutePath,
|
|
61
|
+
source: absolutePath,
|
|
62
|
+
matcher: () => true,
|
|
63
|
+
inherited: null,
|
|
64
|
+
isFile: true,
|
|
65
|
+
})),
|
|
66
|
+
envs: { variables: {}, replacements: [] },
|
|
67
|
+
labels: {},
|
|
68
|
+
shell: '/bin/sh',
|
|
69
|
+
caching: options.resolved,
|
|
70
|
+
description: null,
|
|
71
|
+
scope: {},
|
|
72
|
+
},
|
|
73
|
+
needs: [],
|
|
74
|
+
deps: options.deps ?? [],
|
|
75
|
+
requiredBy: [],
|
|
76
|
+
state: new state_1.State({ type: 'pending', stateKey: null }),
|
|
77
|
+
runtime: {
|
|
78
|
+
async initialize() { },
|
|
79
|
+
async remove() { },
|
|
80
|
+
async execute() { },
|
|
81
|
+
async stop() { },
|
|
82
|
+
async archive() { },
|
|
83
|
+
async restore() { },
|
|
84
|
+
async currentStateKey() {
|
|
85
|
+
return storedStateKey;
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
it('reports cached:false when caching method is none', async () => {
|
|
91
|
+
const env = (0, environment_mock_1.environmentMock)(scratch);
|
|
92
|
+
const task = makeTask('none-task', { resolved: makeResolved('none') });
|
|
93
|
+
const result = await (0, enqueue_next_1.checkCacheState)(task, 'checksum', env);
|
|
94
|
+
expect(result.cached).toBe(false);
|
|
95
|
+
});
|
|
96
|
+
it('reports cached:true when the stored key matches the effective key', async () => {
|
|
97
|
+
const env = (0, environment_mock_1.environmentMock)(scratch);
|
|
98
|
+
const probe = makeTask('hit-task', { resolved: makeResolved('checksum') });
|
|
99
|
+
const { stateKey } = await (0, enqueue_next_1.checkCacheState)(probe, 'checksum', env);
|
|
100
|
+
const task = makeTask('hit-task', { resolved: makeResolved('checksum'), storedStateKey: stateKey });
|
|
101
|
+
const result = await (0, enqueue_next_1.checkCacheState)(task, 'checksum', env);
|
|
102
|
+
expect(result.cached).toBe(true);
|
|
103
|
+
expect(result.stateKey).toBe(stateKey);
|
|
104
|
+
});
|
|
105
|
+
it('invalidates a downstream task when an upstream dependency source changes', async () => {
|
|
106
|
+
const env = (0, environment_mock_1.environmentMock)(scratch);
|
|
107
|
+
const upstreamSrc = (0, path_1.join)(scratch, 'upstream.txt');
|
|
108
|
+
(0, fs_1.writeFileSync)(upstreamSrc, 'v1');
|
|
109
|
+
const makeUpstream = () => makeTask('upstream', { resolved: makeResolved('checksum'), srcFiles: [upstreamSrc] });
|
|
110
|
+
const makeDownstream = (storedStateKey) => makeTask('downstream', { resolved: makeResolved('checksum'), deps: [makeUpstream()], storedStateKey });
|
|
111
|
+
// First pass: capture the downstream effective key and pretend it was stored.
|
|
112
|
+
const keyBefore = (await (0, enqueue_next_1.checkCacheState)(makeDownstream(null), 'checksum', env)).stateKey;
|
|
113
|
+
const cachedHit = await (0, enqueue_next_1.checkCacheState)(makeDownstream(keyBefore), 'checksum', env);
|
|
114
|
+
expect(cachedHit.cached).toBe(true);
|
|
115
|
+
// Change ONLY the upstream source — downstream's own sources are untouched.
|
|
116
|
+
(0, fs_1.writeFileSync)(upstreamSrc, 'v2-changed');
|
|
117
|
+
const afterChange = await (0, enqueue_next_1.checkCacheState)(makeDownstream(keyBefore), 'checksum', env);
|
|
118
|
+
expect(afterChange.stateKey).not.toBe(keyBefore);
|
|
119
|
+
expect(afterChange.cached).toBe(false);
|
|
120
|
+
});
|
|
121
|
+
it('produces a stable key regardless of dependency declaration order', async () => {
|
|
122
|
+
const env = (0, environment_mock_1.environmentMock)(scratch);
|
|
123
|
+
const aSrc = (0, path_1.join)(scratch, 'a.txt');
|
|
124
|
+
const bSrc = (0, path_1.join)(scratch, 'b.txt');
|
|
125
|
+
(0, fs_1.writeFileSync)(aSrc, 'a');
|
|
126
|
+
(0, fs_1.writeFileSync)(bSrc, 'b');
|
|
127
|
+
const depA = () => makeTask('dep-a', { resolved: makeResolved('checksum'), srcFiles: [aSrc] });
|
|
128
|
+
const depB = () => makeTask('dep-b', { resolved: makeResolved('checksum'), srcFiles: [bSrc] });
|
|
129
|
+
const forward = makeTask('root', { resolved: makeResolved('checksum'), deps: [depA(), depB()] });
|
|
130
|
+
const reversed = makeTask('root', { resolved: makeResolved('checksum'), deps: [depB(), depA()] });
|
|
131
|
+
const keyForward = (await (0, enqueue_next_1.checkCacheState)(forward, 'checksum', env)).stateKey;
|
|
132
|
+
const keyReversed = (await (0, enqueue_next_1.checkCacheState)(reversed, 'checksum', env)).stateKey;
|
|
133
|
+
expect(keyForward).toBe(keyReversed);
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
//# sourceMappingURL=enqueue-next.spec.js.map
|
|
@@ -4,7 +4,7 @@ exports.setUserPermission = void 0;
|
|
|
4
4
|
const execute_docker_1 = require("./execute-docker");
|
|
5
5
|
async function setUserPermission(directory, status, environment, container, user) {
|
|
6
6
|
status.write('debug', `set permission on ${directory}`);
|
|
7
|
-
const result = await (0, execute_docker_1.execCommand)(status, environment, container, '/', ['chown', user, directory], null, undefined,
|
|
7
|
+
const result = await (0, execute_docker_1.execCommand)(status, environment, container, '/', ['chown', user, directory], null, undefined, new AbortController().signal);
|
|
8
8
|
if (result.type === 'canceled') {
|
|
9
9
|
return;
|
|
10
10
|
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.awaitState = exports.isState = exports.untilChanged = void 0;
|
|
4
|
+
const abort_event_1 = require("../utils/abort-event");
|
|
5
|
+
const abort_1 = require("./abort");
|
|
6
|
+
function untilChanged(key, state, abort) {
|
|
7
|
+
return new Promise((resolve, reject) => {
|
|
8
|
+
const handle = state.on(key, (value) => {
|
|
9
|
+
handle.close();
|
|
10
|
+
abortListener.close();
|
|
11
|
+
resolve(value);
|
|
12
|
+
});
|
|
13
|
+
const abortListener = (0, abort_event_1.listenOnAbort)(abort, () => {
|
|
14
|
+
handle.close();
|
|
15
|
+
reject(new abort_1.AbortError());
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
exports.untilChanged = untilChanged;
|
|
20
|
+
function isState(key, state, condition, abort) {
|
|
21
|
+
if (condition(state.current)) {
|
|
22
|
+
return Promise.resolve(state.current);
|
|
23
|
+
}
|
|
24
|
+
return new Promise((resolve, reject) => {
|
|
25
|
+
const listener = state.on(key, (value) => {
|
|
26
|
+
if (!condition(value)) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
abortListener.close();
|
|
30
|
+
resolve(value);
|
|
31
|
+
listener.close();
|
|
32
|
+
});
|
|
33
|
+
const abortListener = (0, abort_event_1.listenOnAbort)(abort, () => {
|
|
34
|
+
listener.close();
|
|
35
|
+
reject(new abort_1.AbortError());
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
exports.isState = isState;
|
|
40
|
+
function awaitState(key, state, condition, abort) {
|
|
41
|
+
return new Promise((resolve, reject) => {
|
|
42
|
+
if (condition(state.current)) {
|
|
43
|
+
resolve();
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const listener = state.on(key, (value) => {
|
|
47
|
+
if (!condition(value)) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
listener.close();
|
|
51
|
+
abortListener.close();
|
|
52
|
+
resolve();
|
|
53
|
+
});
|
|
54
|
+
const abortListener = (0, abort_event_1.listenOnAbort)(abort, () => {
|
|
55
|
+
listener.close();
|
|
56
|
+
reject(new abort_1.AbortError());
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
exports.awaitState = awaitState;
|
|
61
|
+
//# sourceMappingURL=state-resolver.js.map
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const state_resolver_1 = require("./state-resolver");
|
|
4
|
+
const state_1 = require("./state");
|
|
5
|
+
const abort_1 = require("./abort");
|
|
6
|
+
describe('state-resolver', () => {
|
|
7
|
+
it('should resolve state', async () => {
|
|
8
|
+
const state = new state_1.State('a');
|
|
9
|
+
const isB = (val) => val === 'b';
|
|
10
|
+
const result = (0, state_resolver_1.isState)('test-state', state, isB, new AbortController().signal);
|
|
11
|
+
state.set('c');
|
|
12
|
+
state.set('a');
|
|
13
|
+
state.set('b');
|
|
14
|
+
await result;
|
|
15
|
+
});
|
|
16
|
+
it('should resolve state if already in', async () => {
|
|
17
|
+
const state = new state_1.State('b');
|
|
18
|
+
const isB = (val) => val === 'b';
|
|
19
|
+
await (0, state_resolver_1.isState)('test-state', state, isB, new AbortController().signal);
|
|
20
|
+
});
|
|
21
|
+
it('isState rejects with AbortError when aborted before the condition is met', async () => {
|
|
22
|
+
const state = new state_1.State('a');
|
|
23
|
+
const isB = (val) => val === 'b';
|
|
24
|
+
const abort = new AbortController();
|
|
25
|
+
const result = (0, state_resolver_1.isState)('test-state', state, isB, abort.signal);
|
|
26
|
+
abort.abort();
|
|
27
|
+
await expect(result).rejects.toBeInstanceOf(abort_1.AbortError);
|
|
28
|
+
});
|
|
29
|
+
it('awaitState rejects with AbortError when aborted before the condition is met', async () => {
|
|
30
|
+
const state = new state_1.State('a');
|
|
31
|
+
const abort = new AbortController();
|
|
32
|
+
const result = (0, state_resolver_1.awaitState)('test-state', state, (val) => val === 'b', abort.signal);
|
|
33
|
+
abort.abort();
|
|
34
|
+
await expect(result).rejects.toBeInstanceOf(abort_1.AbortError);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
//# sourceMappingURL=state-resolver.spec.js.map
|
package/dist/executer/state.js
CHANGED
|
@@ -2,46 +2,52 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.State = void 0;
|
|
4
4
|
class State {
|
|
5
|
-
constructor(current) {
|
|
5
|
+
constructor(current, options) {
|
|
6
6
|
this.current = current;
|
|
7
|
+
this.options = options;
|
|
7
8
|
this.listeners = [];
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const newKeys = Object.keys(newValue);
|
|
12
|
-
const keysToRemove = currentKeys.filter((k) => newKeys.indexOf(k) === -1);
|
|
13
|
-
for (const key of keysToRemove) {
|
|
14
|
-
delete state[key];
|
|
15
|
-
}
|
|
16
|
-
for (const key of newKeys) {
|
|
17
|
-
state[key] = newValue[key];
|
|
9
|
+
this.handles = [];
|
|
10
|
+
if (this.options?.subStates) {
|
|
11
|
+
this.attachToStores(this.options.subStates);
|
|
18
12
|
}
|
|
19
13
|
}
|
|
20
|
-
|
|
21
|
-
const state
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
patchNode(newState, stateKey) {
|
|
27
|
-
const state = this.current.node[newState.node.id];
|
|
28
|
-
if (state.stateKey === stateKey) {
|
|
29
|
-
this.assignState(state, newState);
|
|
30
|
-
this.notifyListeners(this.current);
|
|
14
|
+
attachToStores(subStates) {
|
|
15
|
+
for (const state of subStates) {
|
|
16
|
+
this.handles.push(state.on('sub-state-forward', () => {
|
|
17
|
+
this.notifyListeners(this.current);
|
|
18
|
+
}));
|
|
31
19
|
}
|
|
32
|
-
return state;
|
|
33
20
|
}
|
|
34
|
-
|
|
35
|
-
this.
|
|
36
|
-
this.notifyListeners(
|
|
21
|
+
set(newState) {
|
|
22
|
+
this.current = newState;
|
|
23
|
+
this.notifyListeners(newState);
|
|
24
|
+
return this.current;
|
|
37
25
|
}
|
|
38
|
-
on(listener) {
|
|
39
|
-
this.listeners.push(listener);
|
|
40
|
-
|
|
26
|
+
on(key, listener) {
|
|
27
|
+
this.listeners.push({ key, listener });
|
|
28
|
+
return {
|
|
29
|
+
close: () => {
|
|
30
|
+
const index = this.listeners.findIndex((l) => l.key === key && l.listener === listener);
|
|
31
|
+
if (index >= 0) {
|
|
32
|
+
this.listeners.splice(index, 1);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
// TODO warn
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
};
|
|
41
39
|
}
|
|
42
40
|
notifyListeners(evt) {
|
|
43
|
-
for (const listener of this.listeners) {
|
|
44
|
-
listener(evt);
|
|
41
|
+
for (const listener of [...this.listeners]) {
|
|
42
|
+
listener.listener(evt);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
close() {
|
|
46
|
+
for (const handle of this.handles) {
|
|
47
|
+
handle.close();
|
|
48
|
+
}
|
|
49
|
+
if (this.options?.onDestroy) {
|
|
50
|
+
this.options?.onDestroy();
|
|
45
51
|
}
|
|
46
52
|
}
|
|
47
53
|
}
|