hammerkit 1.6.0 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/build.schema.json +49 -2
- package/dist/cache/backends/local-cache-backend.js +58 -1
- package/dist/cache/backends/registry/registry-client.js +264 -0
- package/dist/cache/backends/registry/registry-credentials.js +81 -0
- package/dist/cache/backends/registry/registry-reference.js +36 -0
- package/dist/cache/backends/registry-cache-backend.js +145 -0
- package/dist/cache/backends/s3-cache-backend.js +99 -46
- package/dist/cache/cache-backend-registry.js +2 -0
- package/dist/cache/cache-inventory.js +84 -0
- package/dist/cache/cache-sync.js +77 -0
- package/dist/cache/explain.js +214 -0
- package/dist/cache/last-resolved.js +48 -0
- package/dist/cache/read-only.js +15 -0
- package/dist/cache/retention.js +61 -0
- package/dist/cli.js +43 -0
- package/dist/docker/using-container.js +5 -1
- package/dist/executer/archive-task-entry.js +21 -0
- package/dist/executer/await-completed-dependencies.js +32 -14
- package/dist/executer/cache-metadata.js +9 -2
- package/dist/executer/docker-service.js +2 -1
- package/dist/executer/docker-task.js +2 -1
- package/dist/executer/dry-run.js +73 -0
- package/dist/executer/event-cache.js +6 -5
- package/dist/executer/execute-command.js +21 -3
- package/dist/executer/execute-work-service.js +10 -1
- package/dist/executer/execute-work-task.js +95 -25
- package/dist/executer/execute-work-tree.js +26 -1
- package/dist/executer/get-scheduler-execute-result.js +4 -1
- package/dist/executer/lazy-resolver.js +15 -3
- package/dist/executer/reset-work-tree.js +2 -0
- package/dist/executer/run-summary.js +102 -0
- package/dist/executer/scheduler/enqueue-next.js +15 -60
- package/dist/executer/scheduler/state-key.js +78 -0
- package/dist/kubernetes/await-running-state.js +73 -19
- package/dist/log.js +16 -6
- package/dist/logging/live-logger.js +2 -1
- package/dist/optimizer/calculate-checksum.js +8 -2
- package/dist/optimizer/get-work-cache-stats.js +66 -16
- package/dist/optimizer/work-task-cache-description.js +34 -5
- package/dist/planner/project-root.js +26 -0
- package/dist/planner/utils/append-work-service.js +2 -1
- package/dist/planner/utils/append-work-task.js +7 -1
- package/dist/planner/utils/parse-work-source.js +35 -30
- package/dist/planner/utils/portable-path.js +30 -0
- package/dist/planner/work-cache-id.js +2 -2
- package/dist/planner/work-graph-serializer.js +103 -0
- package/dist/planner/work-instance-id.js +15 -0
- package/dist/planner/work-runtime-docker.js +53 -15
- package/dist/planner/work-runtime-kubernetes.js +35 -3
- package/dist/planner/work-runtime-local.js +9 -3
- package/dist/planner/work-service-id.js +16 -4
- package/dist/program.js +235 -1
- package/dist/schema/build-file-base-task-schema.js +4 -0
- package/dist/schema/cache-schema.js +21 -2
- package/dist/schema/duration-schema.js +18 -0
- package/dist/schema/reference-parser.js +3 -0
- package/dist/schema/size-schema.js +18 -0
- package/dist/schema/work-scope-parser.js +15 -2
- package/dist/utils/units.js +87 -0
- package/package.json +12 -1
- package/.agents/FEEDBACK.md +0 -74
- package/.agents/skills/before-commit/SKILL.md +0 -101
- package/.agents/skills/do-the-work/SKILL.md +0 -64
- package/.agents/skills/fix-ci/SKILL.md +0 -98
- package/.agents/skills/speckit-git-commit/SKILL.md +0 -53
- package/.agents/skills/speckit-git-feature/SKILL.md +0 -72
- package/.agents/skills/speckit-git-initialize/SKILL.md +0 -54
- package/.agents/skills/speckit-git-remote/SKILL.md +0 -50
- package/.agents/skills/speckit-git-validate/SKILL.md +0 -54
- package/.devcontainer/Dockerfile +0 -5
- package/.devcontainer/devcontainer.json +0 -40
- package/.gitbook.yaml +0 -5
- package/.specify/extensions/.registry +0 -37
- package/.specify/extensions/git/README.md +0 -100
- package/.specify/extensions/git/commands/speckit.git.commit.md +0 -48
- package/.specify/extensions/git/commands/speckit.git.feature.md +0 -67
- package/.specify/extensions/git/commands/speckit.git.initialize.md +0 -49
- package/.specify/extensions/git/commands/speckit.git.remote.md +0 -45
- package/.specify/extensions/git/commands/speckit.git.validate.md +0 -49
- package/.specify/extensions/git/config-template.yml +0 -62
- package/.specify/extensions/git/extension.yml +0 -140
- package/.specify/extensions/git/git-config.yml +0 -62
- package/.specify/extensions.yml +0 -149
- package/.specify/feature.json +0 -3
- package/.specify/init-options.json +0 -10
- package/.specify/integration.json +0 -15
- package/.specify/integrations/claude.manifest.json +0 -16
- package/.specify/integrations/speckit.manifest.json +0 -17
- package/.specify/memory/constitution.md +0 -162
- package/.specify/templates/checklist-template.md +0 -40
- package/.specify/templates/constitution-template.md +0 -50
- package/.specify/templates/plan-template.md +0 -113
- package/.specify/templates/spec-template.md +0 -131
- package/.specify/templates/tasks-template.md +0 -252
- package/.specify/workflows/speckit/workflow.yml +0 -77
- package/.specify/workflows/workflow-registry.json +0 -13
- package/AGENTS.md +0 -94
- package/Dockerfile +0 -32
- package/FOLLOWUPS.md +0 -34
- package/SUMMARY.md +0 -68
- package/VALUES.md +0 -53
- package/dist/cache/auto-pull.spec.js +0 -123
- package/dist/cache/backends/local-cache-backend.spec.js +0 -72
- package/dist/cache/backends/s3-cache-backend.spec.js +0 -118
- package/dist/cache/cache-backend-registry.spec.js +0 -22
- package/dist/cache/resolve-cache.spec.js +0 -52
- package/dist/cli.spec.js +0 -23
- package/dist/console/get-logger.spec.js +0 -23
- package/dist/docker/get-default-platform.spec.js +0 -29
- package/dist/docker/longest-common-prefix.spec.js +0 -26
- package/dist/docker/package.spec.js +0 -145
- package/dist/docker/remove-container.spec.js +0 -32
- package/dist/docker/using-container.spec.js +0 -90
- package/dist/environment/merge-environment-variables.spec.js +0 -24
- package/dist/environment/replace-env-variables.spec.js +0 -47
- package/dist/executer/abort.spec.js +0 -18
- package/dist/executer/environment-mock.spec.js +0 -22
- package/dist/executer/execute.spec.js +0 -51
- package/dist/executer/get-service-containers.spec.js +0 -59
- package/dist/executer/get-service-env-hints.spec.js +0 -65
- package/dist/executer/label-values.spec.js +0 -61
- package/dist/executer/lazy-resolver.spec.js +0 -20
- package/dist/executer/process-manager.spec.js +0 -54
- package/dist/executer/scheduler/enqueue-next.spec.js +0 -136
- package/dist/executer/state-resolver.spec.js +0 -37
- package/dist/executer/state.spec.js +0 -66
- package/dist/executer/states.spec.js +0 -14
- package/dist/file/get-file-context.spec.js +0 -178
- package/dist/file/move-files.spec.js +0 -48
- package/dist/kubernetes/ensure-http-route.spec.js +0 -70
- package/dist/kubernetes/ensure-namespace.spec.js +0 -39
- package/dist/kubernetes/resolve-pod-name.spec.js +0 -81
- package/dist/log.spec.js +0 -131
- package/dist/logging/grouped-logger.spec.js +0 -84
- package/dist/logging/interactive-logger.spec.js +0 -57
- package/dist/logging/live-logger.spec.js +0 -37
- package/dist/logging/loggers.spec.js +0 -154
- package/dist/optimizer/calculate-checksum.spec.js +0 -34
- package/dist/optimizer/get-cache-directory.spec.js +0 -59
- package/dist/optimizer/get-work-cache-stats.spec.js +0 -79
- package/dist/optimizer/work-task-cache-description.spec.js +0 -45
- package/dist/parser/default-build-file.spec.js +0 -48
- package/dist/parser/parse-label-arguments.spec.js +0 -27
- package/dist/parser/read-build-file.spec.js +0 -89
- package/dist/parser/read-env-file.spec.js +0 -42
- package/dist/planner/utils/append-work-service.spec.js +0 -71
- package/dist/planner/utils/get-container-user.spec.js +0 -30
- package/dist/planner/utils/get-default-kube-config.spec.js +0 -11
- package/dist/planner/utils/normalize-path.spec.js +0 -24
- package/dist/planner/utils/parse-work-command.spec.js +0 -21
- package/dist/planner/utils/parse-work-generate.spec.js +0 -45
- package/dist/planner/utils/parse-work-mount.spec.js +0 -62
- package/dist/planner/utils/parse-work-mounts.spec.js +0 -19
- package/dist/planner/utils/parse-work-port.spec.js +0 -24
- package/dist/planner/utils/parse-work-ports.spec.js +0 -24
- package/dist/planner/utils/parse-work-source.spec.js +0 -58
- package/dist/planner/utils/parse-work-volume.spec.js +0 -18
- package/dist/planner/utils/plan-work-tasks.spec.js +0 -30
- package/dist/planner/utils/plan-work-volume.spec.js +0 -33
- package/dist/planner/utils/split-name.spec.js +0 -16
- package/dist/planner/utils/template-value.spec.js +0 -14
- package/dist/planner/validate.spec.js +0 -251
- package/dist/planner/work-cache-id.spec.js +0 -173
- package/dist/planner/work-runtime-local.spec.js +0 -193
- package/dist/program-commands.spec.js +0 -84
- package/dist/program.spec.js +0 -43
- package/dist/schema/build-file-schema.spec.js +0 -61
- package/dist/schema/doc-build-files.spec.js +0 -223
- package/dist/schema/parse-error.spec.js +0 -18
- package/dist/schema/reference-parser.spec.js +0 -83
- package/dist/schema/schema-parser.spec.js +0 -80
- package/dist/schema/type-guards.spec.js +0 -23
- package/dist/schema/work-scope-parser.spec.js +0 -66
- package/dist/service/update-service-status.spec.js +0 -27
- package/dist/testing/ensure-local-registry.js +0 -134
- package/dist/testing/example-test-suite.js +0 -63
- package/dist/testing/expect.js +0 -82
- package/dist/testing/get-test-suite.js +0 -9
- package/dist/testing/http-get.js +0 -21
- package/dist/testing/integration/cache.spec.js +0 -49
- package/dist/testing/integration/cancellation.spec.js +0 -45
- package/dist/testing/integration/clean.spec.js +0 -43
- package/dist/testing/integration/cmd.spec.js +0 -15
- package/dist/testing/integration/concurrency.spec.js +0 -19
- package/dist/testing/integration/docker-package-registry.spec.js +0 -44
- package/dist/testing/integration/docker-service-crash.spec.js +0 -36
- package/dist/testing/integration/docker.spec.js +0 -18
- package/dist/testing/integration/env.spec.js +0 -48
- package/dist/testing/integration/environment.spec.js +0 -97
- package/dist/testing/integration/error.spec.js +0 -19
- package/dist/testing/integration/export.spec.js +0 -22
- package/dist/testing/integration/extend.spec.js +0 -29
- package/dist/testing/integration/glob.spec.js +0 -40
- package/dist/testing/integration/include.spec.js +0 -31
- package/dist/testing/integration/invalid.spec.js +0 -17
- package/dist/testing/integration/invalid_loop.spec.js +0 -56
- package/dist/testing/integration/k8s-state-cache.spec.js +0 -41
- package/dist/testing/integration/kubernetes-service.spec.js +0 -148
- package/dist/testing/integration/kubernetes.spec.js +0 -99
- package/dist/testing/integration/labels.spec.js +0 -42
- package/dist/testing/integration/local.spec.js +0 -14
- package/dist/testing/integration/monorepo.spec.js +0 -15
- package/dist/testing/integration/multi-line.spec.js +0 -17
- package/dist/testing/integration/reference.spec.js +0 -21
- package/dist/testing/integration/services.spec.js +0 -38
- package/dist/testing/integration/store.spec.js +0 -52
- package/dist/testing/integration/unknown.spec.js +0 -28
- package/dist/testing/integration/validate.spec.js +0 -160
- package/dist/testing/integration/watch-dependency.spec.js +0 -33
- package/dist/testing/integration/watch.spec.js +0 -45
- package/dist/testing/requires-kubernetes.js +0 -18
- package/dist/testing/requires-linux-containers.js +0 -18
- package/dist/testing/requires-windows-containers.js +0 -18
- package/dist/testing/test-case.js +0 -75
- package/dist/testing/test-streams.js +0 -28
- package/dist/testing/test-suite-setup.js +0 -3
- package/dist/testing/test-suite.js +0 -3
- package/dist/testing/testing-timeout.js +0 -32
- package/dist/utils/abort-event.spec.js +0 -46
- package/dist/utils/buffer-context.spec.js +0 -38
- package/dist/utils/ci.spec.js +0 -53
- package/dist/utils/debouncer.spec.js +0 -58
- package/dist/utils/emitter.spec.js +0 -34
- package/dist/utils/empty-writable.spec.js +0 -18
- package/dist/utils/environment-config.spec.js +0 -26
- package/dist/utils/fail-never.spec.js +0 -9
- package/dist/utils/sleep.spec.js +0 -22
- package/dist/version.spec.js +0 -12
- package/specs/build-file/caches/spec.md +0 -114
- package/specs/build-file/environment-variables/spec.md +0 -82
- package/specs/build-file/includes/spec.md +0 -60
- package/specs/build-file/references/spec.md +0 -56
- package/specs/build-file/spec.md +0 -62
- package/specs/cli/clean/spec.md +0 -85
- package/specs/cli/down/spec.md +0 -85
- package/specs/cli/execute/spec.md +0 -101
- package/specs/cli/init/spec.md +0 -64
- package/specs/cli/ls/spec.md +0 -66
- package/specs/cli/package/spec.md +0 -110
- package/specs/cli/spec.md +0 -73
- package/specs/cli/store-restore/spec.md +0 -74
- package/specs/cli/up/spec.md +0 -80
- package/specs/cli/validate/spec.md +0 -70
- package/specs/labels/spec.md +0 -91
- package/specs/service/container/spec.md +0 -120
- package/specs/service/kubernetes/spec.md +0 -97
- package/specs/service/spec.md +0 -105
- package/specs/task/caching/spec.md +0 -107
- package/specs/task/container/spec.md +0 -118
- package/specs/task/dependencies/spec.md +0 -70
- package/specs/task/extending/spec.md +0 -74
- package/specs/task/kubernetes/spec.md +0 -125
- package/specs/task/needs/spec.md +0 -59
- package/specs/task/spec.md +0 -87
- package/specs/task/watching/spec.md +0 -69
|
@@ -1,193 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const path_1 = require("path");
|
|
4
|
-
const os_1 = require("os");
|
|
5
|
-
const fs_1 = require("fs");
|
|
6
|
-
const work_runtime_local_1 = require("./work-runtime-local");
|
|
7
|
-
const environment_mock_1 = require("../executer/environment-mock");
|
|
8
|
-
const state_1 = require("../executer/state");
|
|
9
|
-
const mockFindProcess = vi.hoisted(() => vi.fn());
|
|
10
|
-
vi.mock('find-process', () => ({
|
|
11
|
-
__esModule: true,
|
|
12
|
-
default: (...args) => mockFindProcess(...args),
|
|
13
|
-
}));
|
|
14
|
-
vi.mock('../executer/local-task', () => ({
|
|
15
|
-
localTask: vi.fn().mockResolvedValue(undefined),
|
|
16
|
-
}));
|
|
17
|
-
function makeTask(cwd) {
|
|
18
|
-
return {
|
|
19
|
-
id: () => 'task-1',
|
|
20
|
-
name: 'task-1',
|
|
21
|
-
status: { write: vi.fn() },
|
|
22
|
-
data: {
|
|
23
|
-
type: 'local-task',
|
|
24
|
-
name: 'task-1',
|
|
25
|
-
cwd,
|
|
26
|
-
cmds: [],
|
|
27
|
-
generates: [],
|
|
28
|
-
src: [],
|
|
29
|
-
envs: { variables: {}, processEnvs: {} },
|
|
30
|
-
labels: {},
|
|
31
|
-
shell: '/bin/sh',
|
|
32
|
-
continuous: false,
|
|
33
|
-
caching: {
|
|
34
|
-
name: 'none',
|
|
35
|
-
method: 'none',
|
|
36
|
-
backend: {
|
|
37
|
-
type: 'local',
|
|
38
|
-
has: async () => false,
|
|
39
|
-
pull: async () => false,
|
|
40
|
-
push: async () => { },
|
|
41
|
-
clear: async () => { },
|
|
42
|
-
},
|
|
43
|
-
implicit: true,
|
|
44
|
-
},
|
|
45
|
-
description: null,
|
|
46
|
-
scope: {},
|
|
47
|
-
},
|
|
48
|
-
needs: [],
|
|
49
|
-
deps: [],
|
|
50
|
-
requiredBy: [],
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
describe('local task pidfile', () => {
|
|
54
|
-
let cwd;
|
|
55
|
-
beforeEach(() => {
|
|
56
|
-
cwd = (0, fs_1.mkdtempSync)((0, path_1.join)((0, os_1.tmpdir)(), 'hammerkit-pidfile-'));
|
|
57
|
-
mockFindProcess.mockReset();
|
|
58
|
-
});
|
|
59
|
-
afterEach(() => {
|
|
60
|
-
(0, fs_1.rmSync)(cwd, { recursive: true, force: true });
|
|
61
|
-
});
|
|
62
|
-
it('writes pidfile during execute and cleans up after', async () => {
|
|
63
|
-
const task = makeTask(cwd);
|
|
64
|
-
const runtime = (0, work_runtime_local_1.getLocalWorkRuntime)(task);
|
|
65
|
-
const env = (0, environment_mock_1.environmentMock)(cwd);
|
|
66
|
-
const state = new state_1.State({ type: 'pending', stateKey: null });
|
|
67
|
-
await runtime.execute(env, {
|
|
68
|
-
stateKey: 'state-1',
|
|
69
|
-
abort: new AbortController().signal,
|
|
70
|
-
state,
|
|
71
|
-
cache: {
|
|
72
|
-
cached: false,
|
|
73
|
-
stateKey: 'state-x',
|
|
74
|
-
resolved: {
|
|
75
|
-
name: 'none',
|
|
76
|
-
method: 'none',
|
|
77
|
-
backend: {
|
|
78
|
-
type: 'local',
|
|
79
|
-
has: async () => false,
|
|
80
|
-
pull: async () => false,
|
|
81
|
-
push: async () => { },
|
|
82
|
-
clear: async () => { },
|
|
83
|
-
},
|
|
84
|
-
implicit: true,
|
|
85
|
-
},
|
|
86
|
-
},
|
|
87
|
-
daemon: false,
|
|
88
|
-
});
|
|
89
|
-
expect(await env.file.exists((0, path_1.join)(cwd, '.hammerkit', 'task-1.pid'))).toBe(false);
|
|
90
|
-
expect(await env.file.exists((0, path_1.join)(cwd, '.hammerkit', 'task-1'))).toBe(true);
|
|
91
|
-
});
|
|
92
|
-
it('removes a stale pidfile when the process is not alive', async () => {
|
|
93
|
-
const task = makeTask(cwd);
|
|
94
|
-
const runtime = (0, work_runtime_local_1.getLocalWorkRuntime)(task);
|
|
95
|
-
const env = (0, environment_mock_1.environmentMock)(cwd);
|
|
96
|
-
const state = new state_1.State({ type: 'pending', stateKey: null });
|
|
97
|
-
await env.file.createDirectory((0, path_1.join)(cwd, '.hammerkit'));
|
|
98
|
-
(0, fs_1.writeFileSync)((0, path_1.join)(cwd, '.hammerkit', 'task-1.pid'), '999999');
|
|
99
|
-
mockFindProcess.mockResolvedValueOnce([]);
|
|
100
|
-
await runtime.execute(env, {
|
|
101
|
-
stateKey: 'state-2',
|
|
102
|
-
abort: new AbortController().signal,
|
|
103
|
-
state,
|
|
104
|
-
cache: {
|
|
105
|
-
cached: false,
|
|
106
|
-
stateKey: 'state-x',
|
|
107
|
-
resolved: {
|
|
108
|
-
name: 'none',
|
|
109
|
-
method: 'none',
|
|
110
|
-
backend: {
|
|
111
|
-
type: 'local',
|
|
112
|
-
has: async () => false,
|
|
113
|
-
pull: async () => false,
|
|
114
|
-
push: async () => { },
|
|
115
|
-
clear: async () => { },
|
|
116
|
-
},
|
|
117
|
-
implicit: true,
|
|
118
|
-
},
|
|
119
|
-
},
|
|
120
|
-
daemon: false,
|
|
121
|
-
});
|
|
122
|
-
expect(state.current.type).not.toBe('error');
|
|
123
|
-
expect(mockFindProcess).toHaveBeenCalledWith('pid', 999999);
|
|
124
|
-
});
|
|
125
|
-
it('refuses to run when the pidfile points at a live process', async () => {
|
|
126
|
-
const task = makeTask(cwd);
|
|
127
|
-
const runtime = (0, work_runtime_local_1.getLocalWorkRuntime)(task);
|
|
128
|
-
const env = (0, environment_mock_1.environmentMock)(cwd);
|
|
129
|
-
const state = new state_1.State({ type: 'pending', stateKey: null });
|
|
130
|
-
await env.file.createDirectory((0, path_1.join)(cwd, '.hammerkit'));
|
|
131
|
-
(0, fs_1.writeFileSync)((0, path_1.join)(cwd, '.hammerkit', 'task-1.pid'), '12345');
|
|
132
|
-
mockFindProcess.mockResolvedValueOnce([{ pid: 12345, name: 'node' }]);
|
|
133
|
-
await runtime.execute(env, {
|
|
134
|
-
stateKey: 'state-3',
|
|
135
|
-
abort: new AbortController().signal,
|
|
136
|
-
state,
|
|
137
|
-
cache: {
|
|
138
|
-
cached: false,
|
|
139
|
-
stateKey: 'state-x',
|
|
140
|
-
resolved: {
|
|
141
|
-
name: 'none',
|
|
142
|
-
method: 'none',
|
|
143
|
-
backend: {
|
|
144
|
-
type: 'local',
|
|
145
|
-
has: async () => false,
|
|
146
|
-
pull: async () => false,
|
|
147
|
-
push: async () => { },
|
|
148
|
-
clear: async () => { },
|
|
149
|
-
},
|
|
150
|
-
implicit: true,
|
|
151
|
-
},
|
|
152
|
-
},
|
|
153
|
-
daemon: false,
|
|
154
|
-
});
|
|
155
|
-
expect(state.current.type).toBe('error');
|
|
156
|
-
if (state.current.type === 'error') {
|
|
157
|
-
expect(state.current.errorMessage).toMatch(/already running.*12345/);
|
|
158
|
-
}
|
|
159
|
-
});
|
|
160
|
-
it('does not block when the pidfile contains our own pid', async () => {
|
|
161
|
-
const task = makeTask(cwd);
|
|
162
|
-
const runtime = (0, work_runtime_local_1.getLocalWorkRuntime)(task);
|
|
163
|
-
const env = (0, environment_mock_1.environmentMock)(cwd);
|
|
164
|
-
const state = new state_1.State({ type: 'pending', stateKey: null });
|
|
165
|
-
await env.file.createDirectory((0, path_1.join)(cwd, '.hammerkit'));
|
|
166
|
-
(0, fs_1.writeFileSync)((0, path_1.join)(cwd, '.hammerkit', 'task-1.pid'), `${process.pid}`);
|
|
167
|
-
await runtime.execute(env, {
|
|
168
|
-
stateKey: 'state-4',
|
|
169
|
-
abort: new AbortController().signal,
|
|
170
|
-
state,
|
|
171
|
-
cache: {
|
|
172
|
-
cached: false,
|
|
173
|
-
stateKey: 'state-x',
|
|
174
|
-
resolved: {
|
|
175
|
-
name: 'none',
|
|
176
|
-
method: 'none',
|
|
177
|
-
backend: {
|
|
178
|
-
type: 'local',
|
|
179
|
-
has: async () => false,
|
|
180
|
-
pull: async () => false,
|
|
181
|
-
push: async () => { },
|
|
182
|
-
clear: async () => { },
|
|
183
|
-
},
|
|
184
|
-
implicit: true,
|
|
185
|
-
},
|
|
186
|
-
},
|
|
187
|
-
daemon: false,
|
|
188
|
-
});
|
|
189
|
-
expect(state.current.type).not.toBe('error');
|
|
190
|
-
expect(mockFindProcess).not.toHaveBeenCalled();
|
|
191
|
-
});
|
|
192
|
-
});
|
|
193
|
-
//# sourceMappingURL=work-runtime-local.spec.js.map
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const test_case_1 = require("./testing/test-case");
|
|
4
|
-
// Fast unit-suite coverage for program.ts: every command that does not actually
|
|
5
|
-
// run a container (ls, validate, clean --cache, init, --file, unknown task).
|
|
6
|
-
// The slow container-running cases (run, package, up/down) live in
|
|
7
|
-
// `program.spec.ts` and run in the integration suite.
|
|
8
|
-
//
|
|
9
|
-
// shell() forwards args to commander via `[env.cwd, ...args]`, and commander's
|
|
10
|
-
// default `from: 'node'` consumes the first two slots as node+script. So args
|
|
11
|
-
// must start with a script-name placeholder (matching how production receives
|
|
12
|
-
// process.argv); the real command starts at index 1.
|
|
13
|
-
const HK = 'hammerkit';
|
|
14
|
-
describe('program commands (fast)', () => {
|
|
15
|
-
it('ls lists tasks and services without running them', async () => {
|
|
16
|
-
const t = (0, test_case_1.createTestCase)('cmd-ls', {
|
|
17
|
-
'.hammerkit.yaml': {
|
|
18
|
-
services: { api: { image: 'nginx', ports: [] } },
|
|
19
|
-
tasks: {
|
|
20
|
-
build: { cmds: ['true'], description: 'build it', labels: { tier: 'backend' } },
|
|
21
|
-
},
|
|
22
|
-
},
|
|
23
|
-
});
|
|
24
|
-
await t.shell([HK, 'ls']);
|
|
25
|
-
});
|
|
26
|
-
it('ls --filter narrows by label', async () => {
|
|
27
|
-
const t = (0, test_case_1.createTestCase)('cmd-ls-filter', {
|
|
28
|
-
'.hammerkit.yaml': {
|
|
29
|
-
tasks: {
|
|
30
|
-
build: { cmds: ['true'], labels: { app: 'web' } },
|
|
31
|
-
lint: { cmds: ['true'], labels: { app: 'tool' } },
|
|
32
|
-
},
|
|
33
|
-
},
|
|
34
|
-
});
|
|
35
|
-
await t.shell([HK, 'ls', '--filter', 'app=web']);
|
|
36
|
-
});
|
|
37
|
-
it('validate returns cleanly for a healthy build file', async () => {
|
|
38
|
-
const t = (0, test_case_1.createTestCase)('cmd-validate-ok', {
|
|
39
|
-
'.hammerkit.yaml': {
|
|
40
|
-
tasks: { build: { description: 'build it', cmds: ['true'] } },
|
|
41
|
-
},
|
|
42
|
-
});
|
|
43
|
-
await t.shell([HK, 'validate']);
|
|
44
|
-
});
|
|
45
|
-
it('validate exits non-zero when a cycle is detected', async () => {
|
|
46
|
-
const t = (0, test_case_1.createTestCase)('cmd-validate-cycle', {
|
|
47
|
-
'.hammerkit.yaml': {
|
|
48
|
-
tasks: {
|
|
49
|
-
a: { description: 'a', cmds: ['true'], deps: ['b'] },
|
|
50
|
-
b: { description: 'b', cmds: ['true'], deps: ['a'] },
|
|
51
|
-
},
|
|
52
|
-
},
|
|
53
|
-
});
|
|
54
|
-
await expect(t.shell([HK, 'validate'])).rejects.toThrow('Detected errors');
|
|
55
|
-
});
|
|
56
|
-
it('clean --cache clears the backend cache (no container ops)', async () => {
|
|
57
|
-
const t = (0, test_case_1.createTestCase)('cmd-clean-cache', {
|
|
58
|
-
'.hammerkit.yaml': {
|
|
59
|
-
tasks: { build: { cmds: ['true'] } },
|
|
60
|
-
},
|
|
61
|
-
});
|
|
62
|
-
await t.shell([HK, 'clean', '--cache']);
|
|
63
|
-
});
|
|
64
|
-
it('init writes a default .hammerkit.yaml when none exists', async () => {
|
|
65
|
-
// empty fixture so getBuildFilename finds nothing; only the `init` command is registered then
|
|
66
|
-
const t = (0, test_case_1.createTestCase)('cmd-init', {});
|
|
67
|
-
await t.shell([HK, 'init']);
|
|
68
|
-
});
|
|
69
|
-
it('errors when the requested task does not exist', async () => {
|
|
70
|
-
const t = (0, test_case_1.createTestCase)('cmd-unknown-task', {
|
|
71
|
-
'.hammerkit.yaml': { tasks: { example: { cmds: ['true'] } } },
|
|
72
|
-
});
|
|
73
|
-
await expect(t.shell([HK, 'run', 'no-such-task'])).rejects.toThrow('No tasks found');
|
|
74
|
-
});
|
|
75
|
-
it('--file selects a non-default build file', async () => {
|
|
76
|
-
const t = (0, test_case_1.createTestCase)('cmd-file-arg', {
|
|
77
|
-
'custom.yaml': {
|
|
78
|
-
tasks: { only: { description: 'only', cmds: ['true'] } },
|
|
79
|
-
},
|
|
80
|
-
});
|
|
81
|
-
await t.shell([HK, '--file', 'custom.yaml', 'ls']);
|
|
82
|
-
});
|
|
83
|
-
});
|
|
84
|
-
//# sourceMappingURL=program-commands.spec.js.map
|
package/dist/program.spec.js
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const test_case_1 = require("./testing/test-case");
|
|
4
|
-
describe('program', () => {
|
|
5
|
-
it('should run when cache is up to date and --no-cache arg is passed', async () => {
|
|
6
|
-
const testCase = (0, test_case_1.createTestCase)('no-cache', {
|
|
7
|
-
'package.json': '{ "dependencies": { "hammerkit": "^1.5.0" } }',
|
|
8
|
-
'.hammerkit.yaml': {
|
|
9
|
-
tasks: {
|
|
10
|
-
example: {
|
|
11
|
-
description: 'install npm packages',
|
|
12
|
-
image: 'node:16.6.0-alpine',
|
|
13
|
-
// On linux hammerkit runs the container as the host uid:gid (see
|
|
14
|
-
// get-container-user) so generated files aren't root-owned. That uid
|
|
15
|
-
// has no home dir in the image, so npm falls back to the unwritable
|
|
16
|
-
// /.npm and fails with EACCES. Point HOME at a writable dir — what a
|
|
17
|
-
// real non-root user would do — so the task works regardless of uid
|
|
18
|
-
// (it only "passed" elsewhere because those ran the container as root).
|
|
19
|
-
envs: { HOME: '/tmp' },
|
|
20
|
-
src: ['package.json'],
|
|
21
|
-
generates: ['node_modules'],
|
|
22
|
-
cmds: ['npm install'],
|
|
23
|
-
},
|
|
24
|
-
},
|
|
25
|
-
},
|
|
26
|
-
});
|
|
27
|
-
await testCase.shell(['run', 'example', '--cache', 'none']);
|
|
28
|
-
}, 120000);
|
|
29
|
-
it('should warn about invalid task name', async () => {
|
|
30
|
-
const testCase = (0, test_case_1.createTestCase)('wrong-name', {
|
|
31
|
-
'.hammerkit.yaml': {
|
|
32
|
-
tasks: {
|
|
33
|
-
example: {
|
|
34
|
-
image: 'node:16.6.0-alpine',
|
|
35
|
-
cmds: ['npm ci'],
|
|
36
|
-
},
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
});
|
|
40
|
-
await expect(testCase.shell(['run', 'example2'])).rejects.toThrow('No tasks found');
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
//# sourceMappingURL=program.spec.js.map
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const build_file_schema_1 = require("./build-file-schema");
|
|
4
|
-
function parse(input) {
|
|
5
|
-
return build_file_schema_1.buildFileSchema.safeParseAsync(input);
|
|
6
|
-
}
|
|
7
|
-
describe('buildFileSchema', () => {
|
|
8
|
-
describe('container services', () => {
|
|
9
|
-
it('accepts a service without ports (reachable via needs/DNS)', async () => {
|
|
10
|
-
const result = await parse({
|
|
11
|
-
services: { postgres: { image: 'postgres:12-alpine', healthcheck: { cmd: 'pg_isready -U postgres' } } },
|
|
12
|
-
});
|
|
13
|
-
expect(result.success).toBe(true);
|
|
14
|
-
});
|
|
15
|
-
it('accepts a service with numeric and string ports', async () => {
|
|
16
|
-
const result = await parse({ services: { api: { image: 'node:alpine', ports: [':3000', 8080] } } });
|
|
17
|
-
expect(result.success).toBe(true);
|
|
18
|
-
});
|
|
19
|
-
it('rejects a service that is neither a container nor a kubernetes service', async () => {
|
|
20
|
-
const result = await parse({ services: { broken: { ports: [80] } } });
|
|
21
|
-
expect(result.success).toBe(false);
|
|
22
|
-
});
|
|
23
|
-
});
|
|
24
|
-
describe('kubernetes services', () => {
|
|
25
|
-
it('accepts a service with a selector', async () => {
|
|
26
|
-
const result = await parse({
|
|
27
|
-
services: { db: { selector: { type: 'deployment', name: 'db' }, ports: [5432] } },
|
|
28
|
-
});
|
|
29
|
-
expect(result.success).toBe(true);
|
|
30
|
-
});
|
|
31
|
-
});
|
|
32
|
-
describe('continuous tasks', () => {
|
|
33
|
-
it('accepts a container task marked continuous', async () => {
|
|
34
|
-
const result = await parse({ tasks: { serve: { image: 'node:16', continuous: true, cmds: ['ng serve'] } } });
|
|
35
|
-
expect(result.success).toBe(true);
|
|
36
|
-
});
|
|
37
|
-
it('accepts a local task marked continuous', async () => {
|
|
38
|
-
const result = await parse({ tasks: { serve: { continuous: true, cmds: ['ng serve'] } } });
|
|
39
|
-
expect(result.success).toBe(true);
|
|
40
|
-
});
|
|
41
|
-
it('rejects a non-boolean continuous', async () => {
|
|
42
|
-
const result = await parse({ tasks: { serve: { continuous: 'yes', cmds: ['x'] } } });
|
|
43
|
-
expect(result.success).toBe(false);
|
|
44
|
-
});
|
|
45
|
-
});
|
|
46
|
-
describe('strictness', () => {
|
|
47
|
-
it('rejects unknown top-level keys', async () => {
|
|
48
|
-
const result = await parse({ bogus: true });
|
|
49
|
-
expect(result.success).toBe(false);
|
|
50
|
-
});
|
|
51
|
-
it('rejects unknown task keys', async () => {
|
|
52
|
-
const result = await parse({ tasks: { build: { cmds: ['x'], bogus: 1 } } });
|
|
53
|
-
expect(result.success).toBe(false);
|
|
54
|
-
});
|
|
55
|
-
it('accepts an empty build file', async () => {
|
|
56
|
-
const result = await parse({});
|
|
57
|
-
expect(result.success).toBe(true);
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
|
-
});
|
|
61
|
-
//# sourceMappingURL=build-file-schema.spec.js.map
|
|
@@ -1,223 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const fs_1 = require("fs");
|
|
4
|
-
const path_1 = require("path");
|
|
5
|
-
const yaml_1 = require("yaml");
|
|
6
|
-
const build_file_schema_1 = require("./build-file-schema");
|
|
7
|
-
/*
|
|
8
|
-
* Documentation coverage: every hammerkit build-file example that ships in the
|
|
9
|
-
* docs must stay valid against the real schema, so the docs cannot silently
|
|
10
|
-
* drift to config the tool would reject.
|
|
11
|
-
*
|
|
12
|
-
* The harness is self-discovering: it walks docs/ at collection time and turns
|
|
13
|
-
* every fenced ```yaml block into its own assertion. A block is treated as a
|
|
14
|
-
* hammerkit build file when it parses to an object whose top-level keys are all
|
|
15
|
-
* part of the schema (envs/tasks/services/...). Anything else (a GitLab/GitHub
|
|
16
|
-
* CI snippet, a design-doc proposal) is "foreign" and must be listed in
|
|
17
|
-
* FOREIGN_BLOCKS with a reason — a foreign block that is NOT listed fails the
|
|
18
|
-
* audit, so a new build-file example is validated rather than quietly ignored,
|
|
19
|
-
* and a typo'd example (unknown key) is surfaced instead of skipped.
|
|
20
|
-
*/
|
|
21
|
-
const repoRoot = (0, path_1.join)(__dirname, '..', '..');
|
|
22
|
-
const docsDir = (0, path_1.join)(repoRoot, 'docs');
|
|
23
|
-
const bestPracticesDir = (0, path_1.join)(repoRoot, 'best-practices');
|
|
24
|
-
// Top-level keys the build-file schema understands. Mirrors buildFileSchema's
|
|
25
|
-
// shape; kept here only to classify "is this block a hammerkit build file at all".
|
|
26
|
-
const KNOWN_TOP_KEYS = new Set([
|
|
27
|
-
'envs',
|
|
28
|
-
'tasks',
|
|
29
|
-
'services',
|
|
30
|
-
'references',
|
|
31
|
-
'includes',
|
|
32
|
-
'environments',
|
|
33
|
-
'caches',
|
|
34
|
-
'labels',
|
|
35
|
-
]);
|
|
36
|
-
// A doc block can declare itself intentionally invalid by putting this comment
|
|
37
|
-
// on its first line; the harness then asserts the schema REJECTS it.
|
|
38
|
-
const EXPECT_INVALID = '# hammerkit:expect-invalid';
|
|
39
|
-
// Directories that document a specific past version, not the current build-file
|
|
40
|
-
// reference. Their snippets are expected to use the syntax of their release and
|
|
41
|
-
// must not be validated against today's schema.
|
|
42
|
-
const HISTORICAL_DIRS = ['release-blog', 'change-log'];
|
|
43
|
-
// yaml blocks in docs/ that are deliberately NOT hammerkit build files. Each is
|
|
44
|
-
// matched by a unique snippet of its body. Keep the reason — these are the only
|
|
45
|
-
// blocks allowed to be unrecognized.
|
|
46
|
-
const FOREIGN_BLOCKS = [
|
|
47
|
-
{
|
|
48
|
-
file: (0, path_1.join)('installation.md'),
|
|
49
|
-
snippet: 'DOCKER_DRIVER',
|
|
50
|
-
reason: 'GitLab CI (.gitlab-ci.yml) example, not a hammerkit build file',
|
|
51
|
-
},
|
|
52
|
-
{
|
|
53
|
-
file: (0, path_1.join)('installation.md'),
|
|
54
|
-
snippet: 'no0dles/hammerkit-github-action',
|
|
55
|
-
reason: 'GitHub Actions workflow example, not a hammerkit build file',
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
file: (0, path_1.join)('cli', 'store-restore.md'),
|
|
59
|
-
snippet: 'before_script',
|
|
60
|
-
reason: 'GitLab CI (gitlab-ci.yml) caching example, not a hammerkit build file',
|
|
61
|
-
},
|
|
62
|
-
{
|
|
63
|
-
file: (0, path_1.join)('guides', 'ci-caching.md'),
|
|
64
|
-
snippet: 'actions/cache@v4',
|
|
65
|
-
reason: 'GitHub Actions workflow example, not a hammerkit build file',
|
|
66
|
-
},
|
|
67
|
-
{
|
|
68
|
-
file: (0, path_1.join)('contribution', 'secret-managers.md'),
|
|
69
|
-
snippet: 'secret://vault',
|
|
70
|
-
reason: 'design-doc proposal for an unimplemented secrets: provider; not valid against the current schema',
|
|
71
|
-
},
|
|
72
|
-
];
|
|
73
|
-
function walkMarkdown(dir) {
|
|
74
|
-
const out = [];
|
|
75
|
-
for (const entry of (0, fs_1.readdirSync)(dir, { withFileTypes: true })) {
|
|
76
|
-
const full = (0, path_1.join)(dir, entry.name);
|
|
77
|
-
if (entry.isDirectory()) {
|
|
78
|
-
out.push(...walkMarkdown(full));
|
|
79
|
-
}
|
|
80
|
-
else if (entry.name.endsWith('.md')) {
|
|
81
|
-
out.push(full);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
return out;
|
|
85
|
-
}
|
|
86
|
-
// Extract the body of every fenced ```yaml / ```yml block. GitBook's
|
|
87
|
-
// `{% code %}` wrappers and `{% hint %}`/`{% tabs %}` around a block are
|
|
88
|
-
// irrelevant — only the fence matters.
|
|
89
|
-
function extractYamlBlocks(content) {
|
|
90
|
-
const lines = content.split(/\r?\n/);
|
|
91
|
-
const blocks = [];
|
|
92
|
-
for (let i = 0; i < lines.length; i++) {
|
|
93
|
-
if (!/^\s*```ya?ml\s*$/.test(lines[i])) {
|
|
94
|
-
continue;
|
|
95
|
-
}
|
|
96
|
-
const start = i + 1;
|
|
97
|
-
const body = [];
|
|
98
|
-
let j = start;
|
|
99
|
-
while (j < lines.length && !/^\s*```\s*$/.test(lines[j])) {
|
|
100
|
-
body.push(lines[j]);
|
|
101
|
-
j++;
|
|
102
|
-
}
|
|
103
|
-
blocks.push({ body: body.join('\n'), startLine: start + 1 });
|
|
104
|
-
i = j;
|
|
105
|
-
}
|
|
106
|
-
return blocks;
|
|
107
|
-
}
|
|
108
|
-
function firstNonEmptyLine(body) {
|
|
109
|
-
for (const line of body.split(/\r?\n/)) {
|
|
110
|
-
if (line.trim() !== '') {
|
|
111
|
-
return line.trim();
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
return '';
|
|
115
|
-
}
|
|
116
|
-
// A block is a hammerkit build file when it parses to a non-empty object whose
|
|
117
|
-
// top-level keys are all part of the schema.
|
|
118
|
-
function isBuildFileShaped(parsed) {
|
|
119
|
-
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
120
|
-
return false;
|
|
121
|
-
}
|
|
122
|
-
const keys = Object.keys(parsed);
|
|
123
|
-
return keys.length > 0 && keys.every((k) => KNOWN_TOP_KEYS.has(k));
|
|
124
|
-
}
|
|
125
|
-
const docFiles = walkMarkdown(docsDir).sort();
|
|
126
|
-
const allBlocks = [];
|
|
127
|
-
for (const file of docFiles) {
|
|
128
|
-
const relFile = (0, path_1.relative)(docsDir, file);
|
|
129
|
-
const topDir = relFile.split(/[\\/]/)[0];
|
|
130
|
-
if (HISTORICAL_DIRS.includes(topDir)) {
|
|
131
|
-
continue;
|
|
132
|
-
}
|
|
133
|
-
extractYamlBlocks((0, fs_1.readFileSync)(file, 'utf8')).forEach((block, index) => {
|
|
134
|
-
allBlocks.push({ ...block, relFile, index });
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
const foreignMatches = new Set();
|
|
138
|
-
let buildFileBlockCount = 0;
|
|
139
|
-
describe('docs build-file examples', () => {
|
|
140
|
-
// Group assertions per doc file for readable failures.
|
|
141
|
-
const byFile = new Map();
|
|
142
|
-
for (const block of allBlocks) {
|
|
143
|
-
const list = byFile.get(block.relFile) ?? [];
|
|
144
|
-
list.push(block);
|
|
145
|
-
byFile.set(block.relFile, list);
|
|
146
|
-
}
|
|
147
|
-
for (const [relFile, blocks] of byFile) {
|
|
148
|
-
describe(relFile, () => {
|
|
149
|
-
blocks.forEach((block) => {
|
|
150
|
-
const label = `yaml block at line ${block.startLine}`;
|
|
151
|
-
const foreignIndex = FOREIGN_BLOCKS.findIndex((f) => f.file === relFile && block.body.includes(f.snippet));
|
|
152
|
-
if (foreignIndex >= 0) {
|
|
153
|
-
foreignMatches.add(foreignIndex);
|
|
154
|
-
it(`${label} is a documented non-hammerkit block`, () => {
|
|
155
|
-
// Listed in FOREIGN_BLOCKS with a reason — nothing to validate.
|
|
156
|
-
expect(FOREIGN_BLOCKS[foreignIndex].reason).toBeTruthy();
|
|
157
|
-
});
|
|
158
|
-
return;
|
|
159
|
-
}
|
|
160
|
-
if (firstNonEmptyLine(block.body) === EXPECT_INVALID) {
|
|
161
|
-
it(`${label} is rejected by the schema (marked expect-invalid)`, async () => {
|
|
162
|
-
const parsed = (0, yaml_1.parse)(block.body);
|
|
163
|
-
const result = await build_file_schema_1.buildFileSchema.safeParseAsync(parsed);
|
|
164
|
-
expect(result.success).toBe(false);
|
|
165
|
-
});
|
|
166
|
-
buildFileBlockCount++;
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
it(`${label} is a valid build file`, async () => {
|
|
170
|
-
let parsed;
|
|
171
|
-
try {
|
|
172
|
-
parsed = (0, yaml_1.parse)(block.body);
|
|
173
|
-
}
|
|
174
|
-
catch (e) {
|
|
175
|
-
throw new Error(`${relFile}:${block.startLine} is not valid YAML: ${e.message}`);
|
|
176
|
-
}
|
|
177
|
-
if (!isBuildFileShaped(parsed)) {
|
|
178
|
-
const keys = parsed && typeof parsed === 'object' && !Array.isArray(parsed)
|
|
179
|
-
? Object.keys(parsed).join(', ')
|
|
180
|
-
: typeof parsed;
|
|
181
|
-
throw new Error(`${relFile}:${block.startLine} is not a recognized hammerkit build file (top-level: ${keys}).\n` +
|
|
182
|
-
`If this is intentionally foreign yaml (a CI config, a proposal), add it to FOREIGN_BLOCKS with a reason.\n` +
|
|
183
|
-
`Otherwise fix the example so its top-level keys are one of: ${[...KNOWN_TOP_KEYS].join(', ')}.`);
|
|
184
|
-
}
|
|
185
|
-
const result = await build_file_schema_1.buildFileSchema.safeParseAsync(parsed);
|
|
186
|
-
if (!result.success) {
|
|
187
|
-
throw new Error(`${relFile}:${block.startLine} fails the build-file schema:\n` +
|
|
188
|
-
result.error.issues.map((iss) => ` - ${iss.path.join('.')}: ${iss.message}`).join('\n'));
|
|
189
|
-
}
|
|
190
|
-
});
|
|
191
|
-
buildFileBlockCount++;
|
|
192
|
-
});
|
|
193
|
-
});
|
|
194
|
-
}
|
|
195
|
-
// Guard against a regex/discovery regression silently matching nothing, and
|
|
196
|
-
// against a build-file example dropping out of validation unnoticed.
|
|
197
|
-
it('discovers the documented build-file examples', () => {
|
|
198
|
-
expect(buildFileBlockCount).toBeGreaterThanOrEqual(60);
|
|
199
|
-
});
|
|
200
|
-
// Every documented exclusion must still match a real block, so stale entries
|
|
201
|
-
// are removed when the doc changes.
|
|
202
|
-
it('has no stale FOREIGN_BLOCKS entries', () => {
|
|
203
|
-
const unmatched = FOREIGN_BLOCKS.filter((_, i) => !foreignMatches.has(i)).map((f) => `${f.file} (${f.snippet})`);
|
|
204
|
-
expect(unmatched).toEqual([]);
|
|
205
|
-
});
|
|
206
|
-
});
|
|
207
|
-
describe('best-practices build configs', () => {
|
|
208
|
-
const files = (0, fs_1.readdirSync)(bestPracticesDir)
|
|
209
|
-
.filter((f) => f.endsWith('.yaml') || f.endsWith('.yml'))
|
|
210
|
-
.sort();
|
|
211
|
-
it('finds the best-practices templates', () => {
|
|
212
|
-
expect(files.length).toBeGreaterThanOrEqual(10);
|
|
213
|
-
});
|
|
214
|
-
it.each(files)('%s is a valid build file', async (name) => {
|
|
215
|
-
const parsed = (0, yaml_1.parse)((0, fs_1.readFileSync)((0, path_1.join)(bestPracticesDir, name), 'utf8'));
|
|
216
|
-
const result = await build_file_schema_1.buildFileSchema.safeParseAsync(parsed);
|
|
217
|
-
if (!result.success) {
|
|
218
|
-
throw new Error(`best-practices/${name} fails the build-file schema:\n` +
|
|
219
|
-
result.error.issues.map((iss) => ` - ${iss.path.join('.')}: ${iss.message}`).join('\n'));
|
|
220
|
-
}
|
|
221
|
-
});
|
|
222
|
-
});
|
|
223
|
-
//# sourceMappingURL=doc-build-files.spec.js.map
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const zod_1 = require("zod");
|
|
4
|
-
const parse_error_1 = require("./parse-error");
|
|
5
|
-
describe('ParseError', () => {
|
|
6
|
-
it('wraps a ZodError with the offending build-file path', () => {
|
|
7
|
-
const result = zod_1.z.object({ name: zod_1.z.string() }).safeParse({});
|
|
8
|
-
if (result.success) {
|
|
9
|
-
throw new Error('precondition: expected the safeParse to fail');
|
|
10
|
-
}
|
|
11
|
-
const err = new parse_error_1.ParseError(result.error, '/work/.hammerkit.yaml');
|
|
12
|
-
expect(err).toBeInstanceOf(Error);
|
|
13
|
-
expect(err.zod).toBe(result.error);
|
|
14
|
-
expect(err.buildFilePath).toBe('/work/.hammerkit.yaml');
|
|
15
|
-
expect(err.message).toBe('parse error');
|
|
16
|
-
});
|
|
17
|
-
});
|
|
18
|
-
//# sourceMappingURL=parse-error.spec.js.map
|