hammerkit 1.6.0 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -7
- package/build.schema.json +59 -15
- package/dist/cache/backends/local-cache-backend.js +58 -1
- package/dist/cache/backends/registry/registry-client.js +264 -0
- package/dist/cache/backends/registry/registry-credentials.js +81 -0
- package/dist/cache/backends/registry/registry-reference.js +36 -0
- package/dist/cache/backends/registry-cache-backend.js +145 -0
- package/dist/cache/backends/s3-cache-backend.js +99 -46
- package/dist/cache/cache-backend-registry.js +2 -0
- package/dist/cache/cache-inventory.js +84 -0
- package/dist/cache/cache-sync.js +77 -0
- package/dist/cache/explain.js +214 -0
- package/dist/cache/last-resolved.js +48 -0
- package/dist/cache/read-only.js +15 -0
- package/dist/cache/retention.js +61 -0
- package/dist/cli.js +43 -0
- package/dist/docker/using-container.js +17 -1
- package/dist/executer/archive-task-entry.js +21 -0
- package/dist/executer/await-completed-dependencies.js +32 -14
- package/dist/executer/cache-metadata.js +9 -2
- package/dist/executer/docker-service.js +2 -1
- package/dist/executer/docker-task.js +18 -3
- package/dist/executer/dry-run.js +73 -0
- package/dist/executer/event-cache.js +6 -5
- package/dist/executer/execute-command.js +21 -3
- package/dist/executer/execute-docker.js +18 -2
- package/dist/executer/execute-work-service.js +10 -1
- package/dist/executer/execute-work-task.js +111 -26
- package/dist/executer/execute-work-tree.js +26 -1
- package/dist/executer/execution-steps.js +3 -8
- package/dist/executer/get-container-binds.js +13 -1
- package/dist/executer/get-scheduler-execute-result.js +4 -1
- package/dist/executer/lazy-resolver.js +15 -3
- package/dist/executer/reset-work-tree.js +2 -0
- package/dist/executer/run-summary.js +102 -0
- package/dist/executer/scheduler/enqueue-next.js +15 -60
- package/dist/executer/scheduler/state-key.js +78 -0
- package/dist/index.js +14 -1
- package/dist/kubernetes/apply.js +6 -7
- package/dist/kubernetes/await-running-state.js +100 -60
- package/dist/kubernetes/ensure-http-route.js +7 -10
- package/dist/kubernetes/ensure-namespace.js +9 -10
- package/dist/kubernetes/ensure-persistent-data.js +6 -5
- package/dist/kubernetes/get-service-ip.js +2 -2
- package/dist/kubernetes/kubernetes-instance.js +0 -4
- package/dist/kubernetes/remove-persistent-data.js +16 -6
- package/dist/kubernetes/resolve-pod-name.js +7 -7
- package/dist/log.js +16 -6
- package/dist/logging/live-logger.js +2 -1
- package/dist/optimizer/calculate-checksum.js +8 -2
- package/dist/optimizer/get-work-cache-stats.js +66 -16
- package/dist/optimizer/work-task-cache-description.js +34 -5
- package/dist/planner/project-root.js +26 -0
- package/dist/planner/utils/append-work-environment.js +1 -1
- package/dist/planner/utils/append-work-service.js +2 -1
- package/dist/planner/utils/append-work-task.js +7 -1
- package/dist/planner/utils/get-outputs-to-reset.js +20 -0
- package/dist/planner/utils/parse-work-generate.js +2 -2
- package/dist/planner/utils/parse-work-source.js +35 -30
- package/dist/planner/utils/portable-path.js +30 -0
- package/dist/planner/work-cache-id.js +2 -2
- package/dist/planner/work-graph-serializer.js +103 -0
- package/dist/planner/work-instance-id.js +15 -0
- package/dist/planner/work-runtime-docker.js +58 -15
- package/dist/planner/work-runtime-kubernetes.js +95 -45
- package/dist/planner/work-runtime-local.js +31 -8
- package/dist/planner/work-service-id.js +16 -4
- package/dist/program.js +235 -1
- package/dist/schema/build-file-base-task-schema.js +4 -0
- package/dist/schema/build-file-environment-schema-http-route.js +15 -0
- package/dist/schema/build-file-environment-schema.js +8 -2
- package/dist/schema/build-file-schema.js +1 -1
- package/dist/schema/cache-schema.js +21 -2
- package/dist/schema/duration-schema.js +18 -0
- package/dist/schema/envs-schema.js +1 -1
- package/dist/schema/reference-parser.js +3 -0
- package/dist/schema/size-schema.js +18 -0
- package/dist/schema/work-scope-parser.js +15 -2
- package/dist/utils/units.js +87 -0
- package/package.json +20 -9
- package/.agents/FEEDBACK.md +0 -74
- package/.agents/skills/before-commit/SKILL.md +0 -101
- package/.agents/skills/do-the-work/SKILL.md +0 -64
- package/.agents/skills/fix-ci/SKILL.md +0 -98
- package/.agents/skills/speckit-git-commit/SKILL.md +0 -53
- package/.agents/skills/speckit-git-feature/SKILL.md +0 -72
- package/.agents/skills/speckit-git-initialize/SKILL.md +0 -54
- package/.agents/skills/speckit-git-remote/SKILL.md +0 -50
- package/.agents/skills/speckit-git-validate/SKILL.md +0 -54
- package/.devcontainer/Dockerfile +0 -5
- package/.devcontainer/devcontainer.json +0 -40
- package/.gitbook.yaml +0 -5
- package/.specify/extensions/.registry +0 -37
- package/.specify/extensions/git/README.md +0 -100
- package/.specify/extensions/git/commands/speckit.git.commit.md +0 -48
- package/.specify/extensions/git/commands/speckit.git.feature.md +0 -67
- package/.specify/extensions/git/commands/speckit.git.initialize.md +0 -49
- package/.specify/extensions/git/commands/speckit.git.remote.md +0 -45
- package/.specify/extensions/git/commands/speckit.git.validate.md +0 -49
- package/.specify/extensions/git/config-template.yml +0 -62
- package/.specify/extensions/git/extension.yml +0 -140
- package/.specify/extensions/git/git-config.yml +0 -62
- package/.specify/extensions.yml +0 -149
- package/.specify/feature.json +0 -3
- package/.specify/init-options.json +0 -10
- package/.specify/integration.json +0 -15
- package/.specify/integrations/claude.manifest.json +0 -16
- package/.specify/integrations/speckit.manifest.json +0 -17
- package/.specify/memory/constitution.md +0 -162
- package/.specify/templates/checklist-template.md +0 -40
- package/.specify/templates/constitution-template.md +0 -50
- package/.specify/templates/plan-template.md +0 -113
- package/.specify/templates/spec-template.md +0 -131
- package/.specify/templates/tasks-template.md +0 -252
- package/.specify/workflows/speckit/workflow.yml +0 -77
- package/.specify/workflows/workflow-registry.json +0 -13
- package/AGENTS.md +0 -94
- package/Dockerfile +0 -32
- package/FOLLOWUPS.md +0 -34
- package/SUMMARY.md +0 -68
- package/VALUES.md +0 -53
- package/dist/cache/auto-pull.spec.js +0 -123
- package/dist/cache/backends/local-cache-backend.spec.js +0 -72
- package/dist/cache/backends/s3-cache-backend.spec.js +0 -118
- package/dist/cache/cache-backend-registry.spec.js +0 -22
- package/dist/cache/resolve-cache.spec.js +0 -52
- package/dist/cli.spec.js +0 -23
- package/dist/console/get-logger.spec.js +0 -23
- package/dist/docker/get-default-platform.spec.js +0 -29
- package/dist/docker/longest-common-prefix.spec.js +0 -26
- package/dist/docker/package.spec.js +0 -145
- package/dist/docker/remove-container.spec.js +0 -32
- package/dist/docker/using-container.spec.js +0 -90
- package/dist/environment/merge-environment-variables.spec.js +0 -24
- package/dist/environment/replace-env-variables.spec.js +0 -47
- package/dist/executer/abort.spec.js +0 -18
- package/dist/executer/environment-mock.spec.js +0 -22
- package/dist/executer/execute.spec.js +0 -51
- package/dist/executer/get-service-containers.spec.js +0 -59
- package/dist/executer/get-service-env-hints.spec.js +0 -65
- package/dist/executer/label-values.spec.js +0 -61
- package/dist/executer/lazy-resolver.spec.js +0 -20
- package/dist/executer/process-manager.spec.js +0 -54
- package/dist/executer/scheduler/enqueue-next.spec.js +0 -136
- package/dist/executer/state-resolver.spec.js +0 -37
- package/dist/executer/state.spec.js +0 -66
- package/dist/executer/states.spec.js +0 -14
- package/dist/file/get-file-context.spec.js +0 -178
- package/dist/file/move-files.spec.js +0 -48
- package/dist/kubernetes/ensure-http-route.spec.js +0 -70
- package/dist/kubernetes/ensure-ingress.js +0 -54
- package/dist/kubernetes/ensure-namespace.spec.js +0 -39
- package/dist/kubernetes/resolve-pod-name.spec.js +0 -81
- package/dist/log.spec.js +0 -131
- package/dist/logging/grouped-logger.spec.js +0 -84
- package/dist/logging/interactive-logger.spec.js +0 -57
- package/dist/logging/live-logger.spec.js +0 -37
- package/dist/logging/loggers.spec.js +0 -154
- package/dist/optimizer/calculate-checksum.spec.js +0 -34
- package/dist/optimizer/get-cache-directory.spec.js +0 -59
- package/dist/optimizer/get-work-cache-stats.spec.js +0 -79
- package/dist/optimizer/work-task-cache-description.spec.js +0 -45
- package/dist/parser/default-build-file.spec.js +0 -48
- package/dist/parser/parse-label-arguments.spec.js +0 -27
- package/dist/parser/read-build-file.spec.js +0 -89
- package/dist/parser/read-env-file.spec.js +0 -42
- package/dist/planner/utils/append-work-service.spec.js +0 -71
- package/dist/planner/utils/get-container-user.spec.js +0 -30
- package/dist/planner/utils/get-default-kube-config.spec.js +0 -11
- package/dist/planner/utils/normalize-path.spec.js +0 -24
- package/dist/planner/utils/parse-work-command.spec.js +0 -21
- package/dist/planner/utils/parse-work-generate.spec.js +0 -45
- package/dist/planner/utils/parse-work-mount.spec.js +0 -62
- package/dist/planner/utils/parse-work-mounts.spec.js +0 -19
- package/dist/planner/utils/parse-work-port.spec.js +0 -24
- package/dist/planner/utils/parse-work-ports.spec.js +0 -24
- package/dist/planner/utils/parse-work-source.spec.js +0 -58
- package/dist/planner/utils/parse-work-volume.spec.js +0 -18
- package/dist/planner/utils/plan-work-tasks.spec.js +0 -30
- package/dist/planner/utils/plan-work-volume.spec.js +0 -33
- package/dist/planner/utils/split-name.spec.js +0 -16
- package/dist/planner/utils/template-value.spec.js +0 -14
- package/dist/planner/validate.spec.js +0 -251
- package/dist/planner/work-cache-id.spec.js +0 -173
- package/dist/planner/work-runtime-local.spec.js +0 -193
- package/dist/program-commands.spec.js +0 -84
- package/dist/program.spec.js +0 -43
- package/dist/schema/build-file-environment-schema-ingress.js +0 -14
- package/dist/schema/build-file-schema.spec.js +0 -61
- package/dist/schema/doc-build-files.spec.js +0 -223
- package/dist/schema/parse-error.spec.js +0 -18
- package/dist/schema/reference-parser.spec.js +0 -83
- package/dist/schema/schema-parser.spec.js +0 -80
- package/dist/schema/type-guards.spec.js +0 -23
- package/dist/schema/work-scope-parser.spec.js +0 -66
- package/dist/service/update-service-status.spec.js +0 -27
- package/dist/testing/ensure-local-registry.js +0 -134
- package/dist/testing/example-test-suite.js +0 -63
- package/dist/testing/expect.js +0 -82
- package/dist/testing/get-test-suite.js +0 -9
- package/dist/testing/http-get.js +0 -21
- package/dist/testing/integration/cache.spec.js +0 -49
- package/dist/testing/integration/cancellation.spec.js +0 -45
- package/dist/testing/integration/clean.spec.js +0 -43
- package/dist/testing/integration/cmd.spec.js +0 -15
- package/dist/testing/integration/concurrency.spec.js +0 -19
- package/dist/testing/integration/docker-package-registry.spec.js +0 -44
- package/dist/testing/integration/docker-service-crash.spec.js +0 -36
- package/dist/testing/integration/docker.spec.js +0 -18
- package/dist/testing/integration/env.spec.js +0 -48
- package/dist/testing/integration/environment.spec.js +0 -97
- package/dist/testing/integration/error.spec.js +0 -19
- package/dist/testing/integration/export.spec.js +0 -22
- package/dist/testing/integration/extend.spec.js +0 -29
- package/dist/testing/integration/glob.spec.js +0 -40
- package/dist/testing/integration/include.spec.js +0 -31
- package/dist/testing/integration/invalid.spec.js +0 -17
- package/dist/testing/integration/invalid_loop.spec.js +0 -56
- package/dist/testing/integration/k8s-state-cache.spec.js +0 -41
- package/dist/testing/integration/kubernetes-service.spec.js +0 -148
- package/dist/testing/integration/kubernetes.spec.js +0 -99
- package/dist/testing/integration/labels.spec.js +0 -42
- package/dist/testing/integration/local.spec.js +0 -14
- package/dist/testing/integration/monorepo.spec.js +0 -15
- package/dist/testing/integration/multi-line.spec.js +0 -17
- package/dist/testing/integration/reference.spec.js +0 -21
- package/dist/testing/integration/services.spec.js +0 -38
- package/dist/testing/integration/store.spec.js +0 -52
- package/dist/testing/integration/unknown.spec.js +0 -28
- package/dist/testing/integration/validate.spec.js +0 -160
- package/dist/testing/integration/watch-dependency.spec.js +0 -33
- package/dist/testing/integration/watch.spec.js +0 -45
- package/dist/testing/requires-kubernetes.js +0 -18
- package/dist/testing/requires-linux-containers.js +0 -18
- package/dist/testing/requires-windows-containers.js +0 -18
- package/dist/testing/test-case.js +0 -75
- package/dist/testing/test-streams.js +0 -28
- package/dist/testing/test-suite-setup.js +0 -3
- package/dist/testing/test-suite.js +0 -3
- package/dist/testing/testing-timeout.js +0 -32
- package/dist/utils/abort-event.spec.js +0 -46
- package/dist/utils/buffer-context.spec.js +0 -38
- package/dist/utils/ci.spec.js +0 -53
- package/dist/utils/debouncer.spec.js +0 -58
- package/dist/utils/emitter.spec.js +0 -34
- package/dist/utils/empty-writable.spec.js +0 -18
- package/dist/utils/environment-config.spec.js +0 -26
- package/dist/utils/fail-never.spec.js +0 -9
- package/dist/utils/sleep.spec.js +0 -22
- package/dist/version.spec.js +0 -12
- package/specs/build-file/caches/spec.md +0 -114
- package/specs/build-file/environment-variables/spec.md +0 -82
- package/specs/build-file/includes/spec.md +0 -60
- package/specs/build-file/references/spec.md +0 -56
- package/specs/build-file/spec.md +0 -62
- package/specs/cli/clean/spec.md +0 -85
- package/specs/cli/down/spec.md +0 -85
- package/specs/cli/execute/spec.md +0 -101
- package/specs/cli/init/spec.md +0 -64
- package/specs/cli/ls/spec.md +0 -66
- package/specs/cli/package/spec.md +0 -110
- package/specs/cli/spec.md +0 -73
- package/specs/cli/store-restore/spec.md +0 -74
- package/specs/cli/up/spec.md +0 -80
- package/specs/cli/validate/spec.md +0 -70
- package/specs/labels/spec.md +0 -91
- package/specs/service/container/spec.md +0 -120
- package/specs/service/kubernetes/spec.md +0 -97
- package/specs/service/spec.md +0 -105
- package/specs/task/caching/spec.md +0 -107
- package/specs/task/container/spec.md +0 -118
- package/specs/task/dependencies/spec.md +0 -70
- package/specs/task/extending/spec.md +0 -74
- package/specs/task/kubernetes/spec.md +0 -125
- package/specs/task/needs/spec.md +0 -59
- package/specs/task/spec.md +0 -87
- package/specs/task/watching/spec.md +0 -69
package/dist/program.js
CHANGED
|
@@ -10,6 +10,10 @@ const ci_1 = require("./utils/ci");
|
|
|
10
10
|
const parse_label_arguments_1 = require("./parser/parse-label-arguments");
|
|
11
11
|
const cli_1 = require("./cli");
|
|
12
12
|
const log_1 = require("./log");
|
|
13
|
+
const empty_writable_1 = require("./utils/empty-writable");
|
|
14
|
+
const explain_1 = require("./cache/explain");
|
|
15
|
+
const run_summary_1 = require("./executer/run-summary");
|
|
16
|
+
const dry_run_1 = require("./executer/dry-run");
|
|
13
17
|
const label_values_1 = require("./executer/label-values");
|
|
14
18
|
const default_build_file_1 = require("./parser/default-build-file");
|
|
15
19
|
const schema_parser_1 = require("./schema/schema-parser");
|
|
@@ -17,6 +21,9 @@ const work_scope_parser_1 = require("./schema/work-scope-parser");
|
|
|
17
21
|
const reference_parser_1 = require("./schema/reference-parser");
|
|
18
22
|
const colors_1 = __importDefault(require("colors"));
|
|
19
23
|
const version_1 = require("./version");
|
|
24
|
+
const read_only_1 = require("./cache/read-only");
|
|
25
|
+
const units_1 = require("./utils/units");
|
|
26
|
+
const cache_inventory_1 = require("./cache/cache-inventory");
|
|
20
27
|
async function createCli(fileName, environment, workScope) {
|
|
21
28
|
const { ctx, scope } = await (0, schema_parser_1.createParseContext)(fileName, environment);
|
|
22
29
|
const referencedScope = await (0, reference_parser_1.parseReferences)(ctx, scope, environment);
|
|
@@ -233,6 +240,179 @@ async function getProgram(environment, argv) {
|
|
|
233
240
|
program.error('Detected errors in the hammerkit configuration', { exitCode: 1 });
|
|
234
241
|
}
|
|
235
242
|
});
|
|
243
|
+
program
|
|
244
|
+
.command('graph [task]')
|
|
245
|
+
.description('serialize the build graph (tasks, services, deps/needs edges) as mermaid or dot')
|
|
246
|
+
.addOption(new commander_1.Option('-f, --filter <labels...>', 'filter task and services with labels'))
|
|
247
|
+
.addOption(new commander_1.Option('-e, --exclude <labels...>', 'exclude task and services with labels'))
|
|
248
|
+
.addOption(new commander_1.Option('--env <name>', 'environment'))
|
|
249
|
+
.addOption(new commander_1.Option('--format <format>', 'output format').default('mermaid').choices(['mermaid', 'dot']))
|
|
250
|
+
.action(async (task, options) => {
|
|
251
|
+
try {
|
|
252
|
+
const cli = await createCli(fileName, environment, task ? { taskName: task, environmentName: options.env ?? null } : parseWorkLabelScope(options));
|
|
253
|
+
const serialization = cli.graph(options.format);
|
|
254
|
+
environment.stdout.write(`${serialization.output}\n`);
|
|
255
|
+
if (serialization.cycle) {
|
|
256
|
+
environment.console.warn(`cycle detected: ${serialization.cycle.join(' -> ')}`);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
catch (e) {
|
|
260
|
+
if (e instanceof commander_1.CommanderError) {
|
|
261
|
+
throw e;
|
|
262
|
+
}
|
|
263
|
+
environment.console.error((0, log_1.getErrorMessage)(e));
|
|
264
|
+
program.error('Graph was not successful', { exitCode: 1 });
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
program
|
|
268
|
+
.command('explain [task]')
|
|
269
|
+
.description('explain whether tasks would be a cache hit or miss, without running them')
|
|
270
|
+
.addOption(new commander_1.Option('-f, --filter <labels...>', 'filter task and services with labels'))
|
|
271
|
+
.addOption(new commander_1.Option('-e, --exclude <labels...>', 'exclude task and services with labels'))
|
|
272
|
+
.addOption(new commander_1.Option('--env <name>', 'environment'))
|
|
273
|
+
.addOption(new commander_1.Option('--cache <method>', 'caching method to compare')
|
|
274
|
+
.default('checksum')
|
|
275
|
+
.choices(['checksum', 'modify-date', 'none']))
|
|
276
|
+
.addOption(new commander_1.Option('--json', 'emit the explanation as JSON').default(false))
|
|
277
|
+
.action(async (task, options) => {
|
|
278
|
+
try {
|
|
279
|
+
const cli = await createCli(fileName, environment, task ? { taskName: task, environmentName: options.env ?? null } : parseWorkLabelScope(options));
|
|
280
|
+
const explanations = await cli.explain({ cacheDefault: options.cache });
|
|
281
|
+
if (options.json) {
|
|
282
|
+
environment.stdout.write(`${JSON.stringify(explanations, null, 2)}\n`);
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
for (const explanation of explanations) {
|
|
286
|
+
const label = explanation.status === 'hit'
|
|
287
|
+
? colors_1.default.green('cache hit')
|
|
288
|
+
: explanation.status === 'uncacheable'
|
|
289
|
+
? colors_1.default.grey('uncacheable')
|
|
290
|
+
: colors_1.default.yellow('cache miss');
|
|
291
|
+
environment.stdout.write(`• ${explanation.taskName}: ${label}\n`);
|
|
292
|
+
for (const cause of explanation.causes) {
|
|
293
|
+
(0, log_1.printProperty)(environment, 'cause', (0, explain_1.describeCause)(cause));
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
catch (e) {
|
|
298
|
+
if (e instanceof commander_1.CommanderError) {
|
|
299
|
+
throw e;
|
|
300
|
+
}
|
|
301
|
+
environment.console.error((0, log_1.getErrorMessage)(e));
|
|
302
|
+
program.error('Explain was not successful', { exitCode: 1 });
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
const cacheCommand = program.command('cache').description('inspect, prune and move cache entries');
|
|
306
|
+
for (const direction of ['pull', 'push']) {
|
|
307
|
+
cacheCommand
|
|
308
|
+
.command(`${direction} [task]`)
|
|
309
|
+
.description(direction === 'pull'
|
|
310
|
+
? 'fetch the cache entries of the current state from a remote cache, without running tasks'
|
|
311
|
+
: 'upload the locally cached entries of the current state to a remote cache, without running tasks')
|
|
312
|
+
.addOption(new commander_1.Option('--remote <name>', 'remote cache declared in the caches block').makeOptionMandatory())
|
|
313
|
+
.addOption(new commander_1.Option('-f, --filter <labels...>', 'filter task and services with labels'))
|
|
314
|
+
.addOption(new commander_1.Option('-e, --exclude <labels...>', 'exclude task and services with labels'))
|
|
315
|
+
.addOption(new commander_1.Option('--env <name>', 'environment'))
|
|
316
|
+
.addOption(new commander_1.Option('--cache <method>', 'caching method to compare')
|
|
317
|
+
.default('checksum')
|
|
318
|
+
.choices(['checksum', 'modify-date', 'none']))
|
|
319
|
+
.action(async (task, options) => {
|
|
320
|
+
try {
|
|
321
|
+
if (direction === 'push' && (0, read_only_1.isCacheReadOnly)(false, environment.processEnvs)) {
|
|
322
|
+
program.error(`cache is read-only (${read_only_1.CACHE_READ_ONLY_ENV} is set), refusing to push`, { exitCode: 1 });
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
const cli = await createCli(fileName, environment, task ? { taskName: task, environmentName: options.env ?? null } : parseWorkLabelScope(options));
|
|
326
|
+
const results = await cli.syncCache({ direction, remote: options.remote, cacheDefault: options.cache });
|
|
327
|
+
const labels = {
|
|
328
|
+
transferred: colors_1.default.green(direction === 'pull' ? 'pulled' : 'pushed'),
|
|
329
|
+
present: colors_1.default.grey('already present'),
|
|
330
|
+
missing: colors_1.default.yellow(direction === 'pull' ? 'not in remote' : 'not in local cache'),
|
|
331
|
+
skipped: colors_1.default.grey('skipped'),
|
|
332
|
+
};
|
|
333
|
+
for (const result of results) {
|
|
334
|
+
environment.stdout.write(`• ${result.taskName}: ${labels[result.status]}\n`);
|
|
335
|
+
}
|
|
336
|
+
const moved = results.filter((r) => r.status === 'transferred').length;
|
|
337
|
+
environment.stdout.write(`${moved}/${results.length} entries ${direction === 'pull' ? 'pulled' : 'pushed'}\n`);
|
|
338
|
+
}
|
|
339
|
+
catch (e) {
|
|
340
|
+
if (e instanceof commander_1.CommanderError) {
|
|
341
|
+
throw e;
|
|
342
|
+
}
|
|
343
|
+
environment.console.error((0, log_1.getErrorMessage)(e));
|
|
344
|
+
program.error(`Cache ${direction} was not successful: ${(0, log_1.getErrorMessage)(e)}`, { exitCode: 1 });
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
const describeEntry = (entry) => `${entry.taskName ?? colors_1.default.grey(entry.taskId.substring(0, 12))} ${colors_1.default.grey(entry.stateKey.substring(0, 12))} ` +
|
|
349
|
+
`${entry.size === null ? '?' : (0, units_1.formatSize)(entry.size)}` +
|
|
350
|
+
(entry.lastAccessedAt ?? entry.createdAt
|
|
351
|
+
? colors_1.default.grey(` last used ${(0, units_1.formatDuration)(Date.now() - (entry.lastAccessedAt ?? entry.createdAt ?? 0))} ago`)
|
|
352
|
+
: '');
|
|
353
|
+
const totalSize = (entries) => (0, units_1.formatSize)(entries.reduce((sum, entry) => sum + (entry.size ?? 0), 0));
|
|
354
|
+
const countOf = (count) => `${count} ${count === 1 ? 'entry' : 'entries'}`;
|
|
355
|
+
cacheCommand
|
|
356
|
+
.command('ls')
|
|
357
|
+
.description('list the entries of a cache (default: the local default cache)')
|
|
358
|
+
.addOption(new commander_1.Option('--remote <name>', 'cache declared in the caches block to list'))
|
|
359
|
+
.addOption(new commander_1.Option('--json', 'emit the entries as JSON').default(false))
|
|
360
|
+
.action(async (options) => {
|
|
361
|
+
try {
|
|
362
|
+
const cli = await createCli(fileName, environment, parseWorkLabelScope({}));
|
|
363
|
+
const entries = await cli.listCache(options.remote);
|
|
364
|
+
if (options.json) {
|
|
365
|
+
environment.stdout.write(`${JSON.stringify(entries, null, 2)}\n`);
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
for (const entry of entries) {
|
|
369
|
+
environment.stdout.write(`• ${describeEntry(entry)}\n`);
|
|
370
|
+
}
|
|
371
|
+
environment.stdout.write(`${countOf(entries.length)}, ${totalSize(entries)} total\n`);
|
|
372
|
+
}
|
|
373
|
+
catch (e) {
|
|
374
|
+
if (e instanceof commander_1.CommanderError) {
|
|
375
|
+
throw e;
|
|
376
|
+
}
|
|
377
|
+
program.error(`Cache ls was not successful: ${(0, log_1.getErrorMessage)(e)}`, { exitCode: 1 });
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
cacheCommand
|
|
381
|
+
.command('prune')
|
|
382
|
+
.description('remove cache entries by retention policy (default: the local default cache)')
|
|
383
|
+
.addOption(new commander_1.Option('--remote <name>', 'cache declared in the caches block to prune'))
|
|
384
|
+
.addOption(new commander_1.Option('--max-age <duration>', 'remove entries not used within this long (e.g. 30d)').argParser(units_1.parseDuration))
|
|
385
|
+
.addOption(new commander_1.Option('--max-size <size>', 'remove least recently used entries above this size (e.g. 5Gi)').argParser(units_1.parseSize))
|
|
386
|
+
.addOption(new commander_1.Option('--keep <count>', 'keep only the newest versions per task').argParser((v) => parseInt(v, 10)))
|
|
387
|
+
.addOption(new commander_1.Option('--dry-run', 'show what would be removed without removing it').default(false))
|
|
388
|
+
.action(async (options) => {
|
|
389
|
+
try {
|
|
390
|
+
const cli = await createCli(fileName, environment, parseWorkLabelScope({}));
|
|
391
|
+
const policy = cli.retentionPolicy(options.remote, {
|
|
392
|
+
maxAge: options.maxAge,
|
|
393
|
+
maxSize: options.maxSize,
|
|
394
|
+
keepPerTask: options.keep,
|
|
395
|
+
});
|
|
396
|
+
if (!(0, cache_inventory_1.hasPolicy)(policy)) {
|
|
397
|
+
program.error('no retention policy: pass --max-age, --max-size or --keep, or declare retention on the cache', { exitCode: 1 });
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
const plan = await cli.pruneCache(options.remote, policy, options.dryRun);
|
|
401
|
+
for (const entry of plan.evict) {
|
|
402
|
+
environment.stdout.write(`• ${options.dryRun ? 'would remove' : 'removed'} ${describeEntry(entry)}\n`);
|
|
403
|
+
}
|
|
404
|
+
for (const note of plan.unavailable) {
|
|
405
|
+
environment.console.warn(note);
|
|
406
|
+
}
|
|
407
|
+
environment.stdout.write(`${options.dryRun ? 'would remove' : 'removed'} ${countOf(plan.evict.length)} (${totalSize(plan.evict)}), ` + `kept ${countOf(plan.keep.length)} (${totalSize(plan.keep)})\n`);
|
|
408
|
+
}
|
|
409
|
+
catch (e) {
|
|
410
|
+
if (e instanceof commander_1.CommanderError) {
|
|
411
|
+
throw e;
|
|
412
|
+
}
|
|
413
|
+
program.error(`Cache prune was not successful: ${(0, log_1.getErrorMessage)(e)}`, { exitCode: 1 });
|
|
414
|
+
}
|
|
415
|
+
});
|
|
236
416
|
program
|
|
237
417
|
.command('up')
|
|
238
418
|
.description('start services(s)')
|
|
@@ -248,6 +428,8 @@ async function getProgram(environment, argv) {
|
|
|
248
428
|
.addOption(new commander_1.Option('--cache <method>', 'caching method to compare')
|
|
249
429
|
.default('checksum')
|
|
250
430
|
.choices(['checksum', 'modify-date', 'none']))
|
|
431
|
+
.addOption(new commander_1.Option('--cache-read-only', `restore from cache backends but never push to them (or set ${read_only_1.CACHE_READ_ONLY_ENV}=1)`).default(false))
|
|
432
|
+
.addOption(new commander_1.Option('--timeout <duration>', 'fail tasks without their own timeout after this long (e.g. 10m)').argParser(units_1.parseDuration))
|
|
251
433
|
.action(async (options) => {
|
|
252
434
|
try {
|
|
253
435
|
const scope = parseWorkLabelScope(options);
|
|
@@ -258,6 +440,8 @@ async function getProgram(environment, argv) {
|
|
|
258
440
|
workers: options.concurrency,
|
|
259
441
|
logMode: options.log,
|
|
260
442
|
daemon: options.daemon,
|
|
443
|
+
cacheReadOnly: (0, read_only_1.isCacheReadOnly)(options.cacheReadOnly, environment.processEnvs),
|
|
444
|
+
timeout: options.timeout ?? null,
|
|
261
445
|
});
|
|
262
446
|
if (!result.success) {
|
|
263
447
|
program.error('Up was not successful', { exitCode: 1 });
|
|
@@ -311,22 +495,72 @@ async function getProgram(environment, argv) {
|
|
|
311
495
|
.addOption(new commander_1.Option('--cache <method>', 'caching method to compare')
|
|
312
496
|
.default('checksum')
|
|
313
497
|
.choices(['checksum', 'modify-date', 'none']))
|
|
498
|
+
.addOption(new commander_1.Option('--no-summary', 'do not print the end-of-run summary'))
|
|
499
|
+
.addOption(new commander_1.Option('--summary-json', 'emit the end-of-run summary as JSON').default(false))
|
|
500
|
+
.addOption(new commander_1.Option('--explain', 'print the cache-miss cause when a task rebuilds').default(false))
|
|
501
|
+
.addOption(new commander_1.Option('--dry-run', 'print the execution plan with predicted cache hits/misses without running').default(false))
|
|
502
|
+
.addOption(new commander_1.Option('--cache-read-only', `restore from cache backends but never push to them (or set ${read_only_1.CACHE_READ_ONLY_ENV}=1)`).default(false))
|
|
503
|
+
.addOption(new commander_1.Option('--timeout <duration>', 'fail tasks without their own timeout after this long (e.g. 10m)').argParser(units_1.parseDuration))
|
|
504
|
+
.addOption(new commander_1.Option('--no-skip-deps', 'run dependencies even when every task needing them is a cache hit'))
|
|
314
505
|
.action(async (task, options) => {
|
|
315
506
|
try {
|
|
316
|
-
|
|
507
|
+
// For machine-readable JSON, suppress the human progress logger (which
|
|
508
|
+
// also writes to stdout) so the only thing on stdout is the JSON.
|
|
509
|
+
const runEnvironment = options.summaryJson
|
|
510
|
+
? { ...environment, stdout: (0, empty_writable_1.emptyWritable)(), console: (0, log_1.consoleContext)((0, empty_writable_1.emptyWritable)()) }
|
|
511
|
+
: environment;
|
|
512
|
+
const cli = await createCli(fileName, runEnvironment, task ? { taskName: task, environmentName: options.env } : parseWorkLabelScope(options));
|
|
317
513
|
if (cli.tasks().length === 0) {
|
|
318
514
|
program.error('No tasks found', { exitCode: 127 });
|
|
319
515
|
return;
|
|
320
516
|
}
|
|
517
|
+
if (options.dryRun) {
|
|
518
|
+
const plan = await cli.dryRun({ cacheDefault: options.cache });
|
|
519
|
+
if (plan.cycle) {
|
|
520
|
+
program.error(`task cycle detected ${plan.cycle.join(' -> ')}`, { exitCode: 1 });
|
|
521
|
+
return;
|
|
522
|
+
}
|
|
523
|
+
(0, dry_run_1.printDryRun)(environment, plan);
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
const runStart = Date.now();
|
|
321
527
|
const result = await cli.runExec({
|
|
322
528
|
cacheDefault: options.cache,
|
|
323
529
|
watch: options.watch,
|
|
324
530
|
workers: options.concurrency,
|
|
325
531
|
logMode: options.log,
|
|
532
|
+
explain: options.explain,
|
|
533
|
+
cacheReadOnly: (0, read_only_1.isCacheReadOnly)(options.cacheReadOnly, environment.processEnvs),
|
|
534
|
+
timeout: options.timeout ?? null,
|
|
535
|
+
skipDeps: options.skipDeps !== false,
|
|
326
536
|
});
|
|
537
|
+
// Reporting only: the summary never changes the exit code or behavior.
|
|
538
|
+
if (!options.watch) {
|
|
539
|
+
const summary = (0, run_summary_1.summarizeRun)(result.state, Date.now() - runStart);
|
|
540
|
+
if (options.summaryJson) {
|
|
541
|
+
environment.stdout.write(`${JSON.stringify(summary, null, 2)}\n`);
|
|
542
|
+
}
|
|
543
|
+
else if (options.summary !== false) {
|
|
544
|
+
(0, run_summary_1.printRunSummary)(environment, summary);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
327
547
|
if (!result.success) {
|
|
328
548
|
program.error('Execution was not successful', { exitCode: 1 });
|
|
329
549
|
}
|
|
550
|
+
// Declared retention keeps local caches bounded without anyone having
|
|
551
|
+
// to remember `cache prune`. Never on remotes, never in read-only mode.
|
|
552
|
+
if (!options.watch && !(0, read_only_1.isCacheReadOnly)(options.cacheReadOnly, environment.processEnvs)) {
|
|
553
|
+
try {
|
|
554
|
+
for (const { cacheName, plan } of await cli.autoPrune()) {
|
|
555
|
+
if (plan.evict.length > 0) {
|
|
556
|
+
runEnvironment.console.info(`pruned ${plan.evict.length} old ${plan.evict.length === 1 ? 'entry' : 'entries'} from cache "${cacheName}"`);
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
catch (e) {
|
|
561
|
+
runEnvironment.console.warn(`automatic cache prune failed: ${(0, log_1.getErrorMessage)(e)}`);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
330
564
|
}
|
|
331
565
|
catch (e) {
|
|
332
566
|
if (e instanceof commander_1.CommanderError) {
|
|
@@ -8,6 +8,7 @@ const labels_schema_1 = require("./labels-schema");
|
|
|
8
8
|
const cache_schema_1 = require("./cache-schema");
|
|
9
9
|
const build_file_task_command_schema_1 = require("./build-file-task-command-schema");
|
|
10
10
|
const build_file_volume_schema_1 = require("./build-file-volume-schema");
|
|
11
|
+
const duration_schema_1 = require("./duration-schema");
|
|
11
12
|
exports.buildFileBaseTaskSchema = (0, zod_1.object)({
|
|
12
13
|
deps: (0, zod_1.array)((0, zod_1.string)()).optional(),
|
|
13
14
|
needs: (0, zod_1.array)(build_file_need_schema_1.buildFileNeedSchema).optional(),
|
|
@@ -23,5 +24,8 @@ exports.buildFileBaseTaskSchema = (0, zod_1.object)({
|
|
|
23
24
|
// A task that watches its own sources and restarts itself (e.g. `ng serve`,
|
|
24
25
|
// `tsc -w`). In watch mode hammerkit then does not watch/restart it itself.
|
|
25
26
|
continuous: (0, zod_1.boolean)().optional(),
|
|
27
|
+
// Maximum execution time, e.g. `30s`, `10m`, `1h30m`. The task fails when it
|
|
28
|
+
// runs longer. Does not affect the cache key (ADR-0002).
|
|
29
|
+
timeout: duration_schema_1.durationSchema.optional(),
|
|
26
30
|
});
|
|
27
31
|
//# sourceMappingURL=build-file-base-task-schema.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildFileEnvironmentSchemaHttpRoute = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
// A Gateway API HTTPRoute exposing a service of the environment under a hostname.
|
|
6
|
+
exports.buildFileEnvironmentSchemaHttpRoute = (0, zod_1.object)({
|
|
7
|
+
host: (0, zod_1.string)(),
|
|
8
|
+
service: (0, zod_1.string)(),
|
|
9
|
+
servicePort: (0, zod_1.number)().optional(),
|
|
10
|
+
path: (0, zod_1.string)().optional(),
|
|
11
|
+
// the parent Gateway the route attaches to
|
|
12
|
+
gateway: (0, zod_1.string)(),
|
|
13
|
+
gatewayNamespace: (0, zod_1.string)().optional(),
|
|
14
|
+
}).strict();
|
|
15
|
+
//# sourceMappingURL=build-file-environment-schema-http-route.js.map
|
|
@@ -2,12 +2,18 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.buildFileEnvironmentSchema = exports.buildFileDockerEnvironmentSchema = exports.buildFileKubernetesEnvironmentSchema = void 0;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
|
-
const
|
|
5
|
+
const build_file_environment_schema_http_route_1 = require("./build-file-environment-schema-http-route");
|
|
6
6
|
exports.buildFileKubernetesEnvironmentSchema = (0, zod_1.object)({
|
|
7
7
|
namespace: (0, zod_1.string)().optional(),
|
|
8
8
|
context: (0, zod_1.string)(),
|
|
9
9
|
kubeconfig: (0, zod_1.string)().optional(),
|
|
10
|
-
|
|
10
|
+
httpRoutes: (0, zod_1.array)(build_file_environment_schema_http_route_1.buildFileEnvironmentSchemaHttpRoute).optional(),
|
|
11
|
+
// Ingress support was removed in 1.8.0. Fail instead of dropping the routes.
|
|
12
|
+
ingresses: (0, zod_1.never)({
|
|
13
|
+
errorMap: () => ({
|
|
14
|
+
message: 'ingresses were removed in 1.8.0: declare Gateway API routes under httpRoutes, each with a gateway',
|
|
15
|
+
}),
|
|
16
|
+
}).optional(),
|
|
11
17
|
});
|
|
12
18
|
exports.buildFileDockerEnvironmentSchema = (0, zod_1.object)({
|
|
13
19
|
host: (0, zod_1.string)().optional(),
|
|
@@ -19,5 +19,5 @@ exports.buildFileSchema = (0, zod_1.object)({
|
|
|
19
19
|
labels: labels_schema_1.labelsSchema.optional(),
|
|
20
20
|
})
|
|
21
21
|
.strict()
|
|
22
|
-
.describe('Build file with support for containerization\nhttps://
|
|
22
|
+
.describe('Build file with support for containerization\nhttps://hammerkit.dev/docs/build-file');
|
|
23
23
|
//# sourceMappingURL=build-file-schema.js.map
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.cacheSchema = exports.taskCacheRefSchema = exports.buildFileCacheSchema = exports.cacheBackendSchema = exports.cacheBackendS3Schema = exports.cacheBackendLocalSchema = exports.cacheMethodSchema = void 0;
|
|
3
|
+
exports.cacheSchema = exports.taskCacheRefSchema = exports.buildFileCacheSchema = exports.cacheRetentionSchema = exports.cacheBackendSchema = exports.cacheBackendRegistrySchema = exports.cacheBackendS3Schema = exports.cacheBackendLocalSchema = exports.cacheMethodSchema = void 0;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
|
+
const duration_schema_1 = require("./duration-schema");
|
|
6
|
+
const size_schema_1 = require("./size-schema");
|
|
5
7
|
exports.cacheMethodSchema = (0, zod_1.union)([(0, zod_1.literal)('checksum'), (0, zod_1.literal)('modify-date'), (0, zod_1.literal)('none')]);
|
|
6
8
|
exports.cacheBackendLocalSchema = (0, zod_1.object)({
|
|
7
9
|
type: (0, zod_1.literal)('local'),
|
|
@@ -15,10 +17,27 @@ exports.cacheBackendS3Schema = (0, zod_1.object)({
|
|
|
15
17
|
prefix: (0, zod_1.string)().optional(),
|
|
16
18
|
forcePathStyle: zod_1.z.boolean().optional(),
|
|
17
19
|
}).strict();
|
|
18
|
-
exports.
|
|
20
|
+
exports.cacheBackendRegistrySchema = (0, zod_1.object)({
|
|
21
|
+
type: (0, zod_1.literal)('registry'),
|
|
22
|
+
// repository to store entries in, e.g. `ghcr.io/org/hammerkit-cache`
|
|
23
|
+
repository: (0, zod_1.string)(),
|
|
24
|
+
// talk plain http (defaults to true only for localhost registries)
|
|
25
|
+
insecure: zod_1.z.boolean().optional(),
|
|
26
|
+
}).strict();
|
|
27
|
+
exports.cacheBackendSchema = (0, zod_1.union)([exports.cacheBackendLocalSchema, exports.cacheBackendS3Schema, exports.cacheBackendRegistrySchema]);
|
|
28
|
+
exports.cacheRetentionSchema = (0, zod_1.object)({
|
|
29
|
+
// evict entries not used within this long, e.g. `30d`
|
|
30
|
+
maxAge: duration_schema_1.durationSchema.optional(),
|
|
31
|
+
// evict least recently used entries until the cache is at most this big, e.g. `5Gi`
|
|
32
|
+
maxSize: size_schema_1.sizeSchema.optional(),
|
|
33
|
+
// keep only the newest N versions per task
|
|
34
|
+
keepPerTask: zod_1.z.number().int().positive().optional(),
|
|
35
|
+
}).strict();
|
|
19
36
|
exports.buildFileCacheSchema = (0, zod_1.object)({
|
|
20
37
|
method: exports.cacheMethodSchema,
|
|
21
38
|
backend: exports.cacheBackendSchema,
|
|
39
|
+
// applied by `cache prune`, and automatically after a run for local caches
|
|
40
|
+
retention: exports.cacheRetentionSchema.optional(),
|
|
22
41
|
}).strict();
|
|
23
42
|
exports.taskCacheRefSchema = (0, zod_1.union)([
|
|
24
43
|
exports.cacheMethodSchema,
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.durationSchema = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const units_1 = require("../utils/units");
|
|
6
|
+
function isDuration(value) {
|
|
7
|
+
try {
|
|
8
|
+
(0, units_1.parseDuration)(value);
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
exports.durationSchema = (0, zod_1.string)().refine(isDuration, (value) => ({
|
|
16
|
+
message: `invalid duration "${value}", expected e.g. 30s, 5m, 1h30m or 30d`,
|
|
17
|
+
}));
|
|
18
|
+
//# sourceMappingURL=duration-schema.js.map
|
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.envsSchema = void 0;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
|
-
exports.envsSchema = (0, zod_1.record)((0, zod_1.union)([(0, zod_1.string)(), (0, zod_1.number)()])).describe('Environment values for the current build task\nhttps://
|
|
5
|
+
exports.envsSchema = (0, zod_1.record)((0, zod_1.union)([(0, zod_1.string)(), (0, zod_1.number)()])).describe('Environment values for the current build task\nhttps://hammerkit.dev/docs/build-file/environment-variables');
|
|
6
6
|
//# sourceMappingURL=envs-schema.js.map
|
|
@@ -8,6 +8,7 @@ const read_env_file_1 = require("../parser/read-env-file");
|
|
|
8
8
|
const label_values_1 = require("../executer/label-values");
|
|
9
9
|
const merge_environment_variables_1 = require("../environment/merge-environment-variables");
|
|
10
10
|
const resolve_cache_1 = require("../cache/resolve-cache");
|
|
11
|
+
const project_root_1 = require("../planner/project-root");
|
|
11
12
|
function combinePath(namePrefix, name) {
|
|
12
13
|
return namePrefix.length > 0 ? `${namePrefix}:${name}` : name;
|
|
13
14
|
}
|
|
@@ -20,6 +21,7 @@ async function parseReferences(ctx, mainScope, environment) {
|
|
|
20
21
|
envFiles: {},
|
|
21
22
|
environments: {},
|
|
22
23
|
caches: {},
|
|
24
|
+
projectRoot: await (0, project_root_1.findProjectRoot)(mainScope.cwd, environment),
|
|
23
25
|
};
|
|
24
26
|
for (const file of Object.values(ctx.files)) {
|
|
25
27
|
if (!reference.envFiles[file.cwd]) {
|
|
@@ -97,6 +99,7 @@ function applySchemaExtension(reference, task) {
|
|
|
97
99
|
applySchemaExtension(reference, extend);
|
|
98
100
|
task.schema.shell = task.schema.shell ?? extend.schema.shell;
|
|
99
101
|
task.schema.cache = task.schema.cache ?? extend.schema.cache;
|
|
102
|
+
task.schema.timeout = task.schema.timeout ?? extend.schema.timeout;
|
|
100
103
|
task.schema.cmds = extendArray(task.schema.cmds, extend.schema.cmds);
|
|
101
104
|
task.schema.src = extendArray(task.schema.src, extend.schema.src);
|
|
102
105
|
task.schema.generates = extendArray(task.schema.generates, extend.schema.generates);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sizeSchema = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const units_1 = require("../utils/units");
|
|
6
|
+
function isSize(value) {
|
|
7
|
+
try {
|
|
8
|
+
(0, units_1.parseSize)(value);
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
exports.sizeSchema = (0, zod_1.string)().refine(isSize, (value) => ({
|
|
16
|
+
message: `invalid size "${value}", expected e.g. 500Mi, 5Gi or 2G`,
|
|
17
|
+
}));
|
|
18
|
+
//# sourceMappingURL=size-schema.js.map
|
|
@@ -17,8 +17,20 @@ function defaultEnvironment(context) {
|
|
|
17
17
|
}
|
|
18
18
|
exports.defaultEnvironment = defaultEnvironment;
|
|
19
19
|
function getWorkContext(context, scope, environment) {
|
|
20
|
-
const workTree = {
|
|
21
|
-
|
|
20
|
+
const workTree = {
|
|
21
|
+
services: {},
|
|
22
|
+
environment: defaultEnvironment(context),
|
|
23
|
+
tasks: {},
|
|
24
|
+
caches: context.caches,
|
|
25
|
+
};
|
|
26
|
+
const filteredWorkTree = {
|
|
27
|
+
services: {},
|
|
28
|
+
environment: defaultEnvironment(context),
|
|
29
|
+
tasks: {},
|
|
30
|
+
caches: context.caches,
|
|
31
|
+
};
|
|
32
|
+
const requested = [];
|
|
33
|
+
filteredWorkTree.requested = requested;
|
|
22
34
|
for (const [envName, env] of Object.entries(context.environments)) {
|
|
23
35
|
if (envName === scope.environmentName) {
|
|
24
36
|
filteredWorkTree.environment = (0, append_work_environment_1.appendWorkEnvironment)(env);
|
|
@@ -28,6 +40,7 @@ function getWorkContext(context, scope, environment) {
|
|
|
28
40
|
for (const task of Object.values(context.tasks)) {
|
|
29
41
|
const item = (0, append_work_task_1.appendWorkTask)(workTree, task.cwd, task, environment, context);
|
|
30
42
|
if (matchesTaskWorkScope(item, scope)) {
|
|
43
|
+
requested.push(item.name);
|
|
31
44
|
applyTask(filteredWorkTree, item);
|
|
32
45
|
}
|
|
33
46
|
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formatSize = exports.parseSize = exports.formatDuration = exports.parseDuration = void 0;
|
|
4
|
+
const DURATION_UNITS = {
|
|
5
|
+
ms: 1,
|
|
6
|
+
s: 1000,
|
|
7
|
+
m: 60000,
|
|
8
|
+
h: 3600000,
|
|
9
|
+
d: 86400000,
|
|
10
|
+
};
|
|
11
|
+
// Parse a duration such as `500ms`, `30s`, `5m`, `1h30m` or `30d` into
|
|
12
|
+
// milliseconds. Every component needs a unit, and the total must be positive.
|
|
13
|
+
function parseDuration(value) {
|
|
14
|
+
const pattern = /(\d+(?:\.\d+)?)(ms|s|m|h|d)/y;
|
|
15
|
+
let total = 0;
|
|
16
|
+
let offset = 0;
|
|
17
|
+
while (offset < value.length) {
|
|
18
|
+
pattern.lastIndex = offset;
|
|
19
|
+
const match = pattern.exec(value);
|
|
20
|
+
if (!match) {
|
|
21
|
+
throw new Error(`invalid duration "${value}", expected e.g. 30s, 5m, 1h30m or 30d`);
|
|
22
|
+
}
|
|
23
|
+
total += parseFloat(match[1]) * DURATION_UNITS[match[2]];
|
|
24
|
+
offset = pattern.lastIndex;
|
|
25
|
+
}
|
|
26
|
+
if (total <= 0) {
|
|
27
|
+
throw new Error(`invalid duration "${value}", expected e.g. 30s, 5m, 1h30m or 30d`);
|
|
28
|
+
}
|
|
29
|
+
return Math.round(total);
|
|
30
|
+
}
|
|
31
|
+
exports.parseDuration = parseDuration;
|
|
32
|
+
function formatDuration(ms) {
|
|
33
|
+
if (ms < 1000) {
|
|
34
|
+
return `${ms}ms`;
|
|
35
|
+
}
|
|
36
|
+
let remaining = Math.round(ms / 1000);
|
|
37
|
+
const parts = [];
|
|
38
|
+
for (const [unit, seconds] of [
|
|
39
|
+
['d', 86400],
|
|
40
|
+
['h', 3600],
|
|
41
|
+
['m', 60],
|
|
42
|
+
['s', 1],
|
|
43
|
+
]) {
|
|
44
|
+
if (remaining >= seconds) {
|
|
45
|
+
parts.push(`${Math.floor(remaining / seconds)}${unit}`);
|
|
46
|
+
remaining %= seconds;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return parts.join('');
|
|
50
|
+
}
|
|
51
|
+
exports.formatDuration = formatDuration;
|
|
52
|
+
const SIZE_UNITS = {
|
|
53
|
+
'': 1,
|
|
54
|
+
K: 1000,
|
|
55
|
+
M: 1000 ** 2,
|
|
56
|
+
G: 1000 ** 3,
|
|
57
|
+
T: 1000 ** 4,
|
|
58
|
+
Ki: 1024,
|
|
59
|
+
Mi: 1024 ** 2,
|
|
60
|
+
Gi: 1024 ** 3,
|
|
61
|
+
Ti: 1024 ** 4,
|
|
62
|
+
};
|
|
63
|
+
// Parse a size such as `500Mi`, `5Gi` or `2G` (Kubernetes-style suffixes;
|
|
64
|
+
// binary `Ki/Mi/Gi/Ti`, decimal `K/M/G/T`, none for bytes) into bytes.
|
|
65
|
+
function parseSize(value) {
|
|
66
|
+
const match = /^(\d+(?:\.\d+)?)(Ki|Mi|Gi|Ti|K|M|G|T)?$/.exec(value);
|
|
67
|
+
if (!match) {
|
|
68
|
+
throw new Error(`invalid size "${value}", expected e.g. 500Mi, 5Gi or 2G`);
|
|
69
|
+
}
|
|
70
|
+
return Math.round(parseFloat(match[1]) * SIZE_UNITS[match[2] ?? '']);
|
|
71
|
+
}
|
|
72
|
+
exports.parseSize = parseSize;
|
|
73
|
+
function formatSize(bytes) {
|
|
74
|
+
for (const [unit, factor] of [
|
|
75
|
+
['Ti', 1024 ** 4],
|
|
76
|
+
['Gi', 1024 ** 3],
|
|
77
|
+
['Mi', 1024 ** 2],
|
|
78
|
+
['Ki', 1024],
|
|
79
|
+
]) {
|
|
80
|
+
if (bytes >= factor) {
|
|
81
|
+
return `${(bytes / factor).toFixed(1).replace(/\.0$/, '')}${unit}`;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return `${bytes}B`;
|
|
85
|
+
}
|
|
86
|
+
exports.formatSize = formatSize;
|
|
87
|
+
//# sourceMappingURL=units.js.map
|