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,83 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const test_case_1 = require("../testing/test-case");
|
|
4
|
-
const program_1 = require("../program");
|
|
5
|
-
const path_1 = require("path");
|
|
6
|
-
// Drive the full parse pipeline (schema-parser -> parseReferences -> getWorkContext)
|
|
7
|
-
// over an in-memory build file and assert on the resulting work tree. This exercises
|
|
8
|
-
// reference resolution: deps, needs, label merging and schema `extend`.
|
|
9
|
-
async function withCli(buildFile, scope, fn) {
|
|
10
|
-
const testCase = (0, test_case_1.createTestCase)('reference-parser', { '.hammerkit.yaml': buildFile });
|
|
11
|
-
await testCase.setup(async (cwd, environment) => {
|
|
12
|
-
const cli = await (0, program_1.createCli)((0, path_1.join)(cwd, '.hammerkit.yaml'), environment, scope);
|
|
13
|
-
await fn(cli);
|
|
14
|
-
});
|
|
15
|
-
}
|
|
16
|
-
describe('reference-parser', () => {
|
|
17
|
-
it('resolves task dependencies', async () => {
|
|
18
|
-
await withCli({
|
|
19
|
-
tasks: {
|
|
20
|
-
install: { cmds: ['npm install'] },
|
|
21
|
-
build: { cmds: ['tsc'], deps: ['install'] },
|
|
22
|
-
},
|
|
23
|
-
}, { taskName: 'build' }, (cli) => {
|
|
24
|
-
const build = cli.task('build');
|
|
25
|
-
expect(build.deps.map((d) => d.name)).toEqual(['install']);
|
|
26
|
-
});
|
|
27
|
-
});
|
|
28
|
-
it('resolves service needs', async () => {
|
|
29
|
-
await withCli({
|
|
30
|
-
services: {
|
|
31
|
-
api: { image: 'nginx', ports: [] },
|
|
32
|
-
},
|
|
33
|
-
tasks: {
|
|
34
|
-
build: { cmds: ['tsc'], needs: ['api'] },
|
|
35
|
-
},
|
|
36
|
-
}, { taskName: 'build' }, (cli) => {
|
|
37
|
-
const build = cli.task('build');
|
|
38
|
-
expect(build.needs.map((n) => n.service.name)).toEqual(['api']);
|
|
39
|
-
});
|
|
40
|
-
});
|
|
41
|
-
it('merges build-file labels with task labels', async () => {
|
|
42
|
-
await withCli({
|
|
43
|
-
labels: { app: 'web' },
|
|
44
|
-
tasks: {
|
|
45
|
-
build: { cmds: ['tsc'], labels: { tier: 'backend' } },
|
|
46
|
-
},
|
|
47
|
-
}, { taskName: 'build' }, (cli) => {
|
|
48
|
-
expect(cli.task('build').data.labels).toEqual({ app: ['web'], tier: ['backend'] });
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
it('applies schema extend (image, cmds, labels)', async () => {
|
|
52
|
-
await withCli({
|
|
53
|
-
tasks: {
|
|
54
|
-
base: { image: 'node', cmds: ['a'] },
|
|
55
|
-
child: { extend: 'base', cmds: ['b'] },
|
|
56
|
-
},
|
|
57
|
-
}, { taskName: 'child' }, (cli) => {
|
|
58
|
-
const child = cli.task('child').data;
|
|
59
|
-
// child inherits the base image and is therefore a container task
|
|
60
|
-
expect(child.type).toBe('container-task');
|
|
61
|
-
expect(child.image).toBe('node');
|
|
62
|
-
// extendArray prepends the extended task's cmds before the child's own
|
|
63
|
-
expect(child.cmds).toHaveLength(2);
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
it('throws when a dependency cannot be found', async () => {
|
|
67
|
-
const testCase = (0, test_case_1.createTestCase)('reference-parser', {
|
|
68
|
-
'.hammerkit.yaml': { tasks: { build: { cmds: ['tsc'], deps: ['missing'] } } },
|
|
69
|
-
});
|
|
70
|
-
await testCase.setup(async (cwd, environment) => {
|
|
71
|
-
await expect((0, program_1.createCli)((0, path_1.join)(cwd, '.hammerkit.yaml'), environment, { taskName: 'build' })).rejects.toThrow('unable to find missing');
|
|
72
|
-
});
|
|
73
|
-
});
|
|
74
|
-
it('throws when a needed service cannot be found', async () => {
|
|
75
|
-
const testCase = (0, test_case_1.createTestCase)('reference-parser', {
|
|
76
|
-
'.hammerkit.yaml': { tasks: { build: { cmds: ['tsc'], needs: ['missingsvc'] } } },
|
|
77
|
-
});
|
|
78
|
-
await testCase.setup(async (cwd, environment) => {
|
|
79
|
-
await expect((0, program_1.createCli)((0, path_1.join)(cwd, '.hammerkit.yaml'), environment, { taskName: 'build' })).rejects.toThrow('unable to find missingsvc');
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
});
|
|
83
|
-
//# sourceMappingURL=reference-parser.spec.js.map
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const path_1 = require("path");
|
|
4
|
-
const os_1 = require("os");
|
|
5
|
-
const fs_1 = require("fs");
|
|
6
|
-
const environment_mock_1 = require("../executer/environment-mock");
|
|
7
|
-
const schema_parser_1 = require("./schema-parser");
|
|
8
|
-
const parse_error_1 = require("./parse-error");
|
|
9
|
-
describe('createParseContext', () => {
|
|
10
|
-
let scratch;
|
|
11
|
-
beforeEach(() => {
|
|
12
|
-
scratch = (0, fs_1.mkdtempSync)((0, path_1.join)((0, os_1.tmpdir)(), 'hammerkit-schema-'));
|
|
13
|
-
});
|
|
14
|
-
afterEach(() => {
|
|
15
|
-
(0, fs_1.rmSync)(scratch, { recursive: true, force: true });
|
|
16
|
-
});
|
|
17
|
-
function writeBuildFile(content) {
|
|
18
|
-
const file = (0, path_1.join)(scratch, '.hammerkit.yaml');
|
|
19
|
-
(0, fs_1.writeFileSync)(file, content);
|
|
20
|
-
return file;
|
|
21
|
-
}
|
|
22
|
-
it('parses a valid build file', async () => {
|
|
23
|
-
const env = (0, environment_mock_1.environmentMock)(scratch);
|
|
24
|
-
const file = writeBuildFile('tasks:\n build:\n cmds:\n - echo hi\n');
|
|
25
|
-
const { scope } = await (0, schema_parser_1.createParseContext)(file, env);
|
|
26
|
-
expect(scope.schema.tasks?.build).toBeDefined();
|
|
27
|
-
});
|
|
28
|
-
it('rejects an unknown top-level key (strict schema)', async () => {
|
|
29
|
-
const env = (0, environment_mock_1.environmentMock)(scratch);
|
|
30
|
-
const file = writeBuildFile('bogus: true\ntasks:\n build:\n cmds:\n - echo hi\n');
|
|
31
|
-
await expect((0, schema_parser_1.createParseContext)(file, env)).rejects.toBeInstanceOf(parse_error_1.ParseError);
|
|
32
|
-
});
|
|
33
|
-
it('rejects a task with an invalid command shape', async () => {
|
|
34
|
-
const env = (0, environment_mock_1.environmentMock)(scratch);
|
|
35
|
-
const file = writeBuildFile('tasks:\n build:\n cmds: 42\n');
|
|
36
|
-
await expect((0, schema_parser_1.createParseContext)(file, env)).rejects.toBeInstanceOf(parse_error_1.ParseError);
|
|
37
|
-
});
|
|
38
|
-
it('resolves a reference to another build file', async () => {
|
|
39
|
-
const env = (0, environment_mock_1.environmentMock)(scratch);
|
|
40
|
-
const sub = (0, path_1.join)(scratch, 'sub');
|
|
41
|
-
(0, fs_1.writeFileSync)((0, path_1.join)(scratch, '.hammerkit.yaml'), 'references:\n lib: sub\ntasks:\n build:\n cmds:\n - echo root\n');
|
|
42
|
-
// create the referenced build file
|
|
43
|
-
(0, fs_1.mkdirSync)(sub);
|
|
44
|
-
(0, fs_1.writeFileSync)((0, path_1.join)(sub, '.hammerkit.yaml'), 'tasks:\n lib-build:\n cmds:\n - echo lib\n');
|
|
45
|
-
const { scope } = await (0, schema_parser_1.createParseContext)((0, path_1.join)(scratch, '.hammerkit.yaml'), env);
|
|
46
|
-
expect(scope.references['lib']).toBeDefined();
|
|
47
|
-
expect(scope.references['lib'].scope.schema.tasks?.['lib-build']).toBeDefined();
|
|
48
|
-
});
|
|
49
|
-
it('resolves an include (sibling build file merged under a name)', async () => {
|
|
50
|
-
const env = (0, environment_mock_1.environmentMock)(scratch);
|
|
51
|
-
(0, fs_1.writeFileSync)((0, path_1.join)(scratch, 'common.yaml'), 'tasks:\n shared:\n cmds:\n - echo s\n');
|
|
52
|
-
(0, fs_1.writeFileSync)((0, path_1.join)(scratch, '.hammerkit.yaml'), 'includes:\n npm: common.yaml\n');
|
|
53
|
-
const { scope } = await (0, schema_parser_1.createParseContext)((0, path_1.join)(scratch, '.hammerkit.yaml'), env);
|
|
54
|
-
expect(scope.references['npm']).toBeDefined();
|
|
55
|
-
expect(scope.references['npm'].type).toBe('include');
|
|
56
|
-
expect(scope.references['npm'].scope.schema.tasks?.['shared']).toBeDefined();
|
|
57
|
-
});
|
|
58
|
-
it('throws when an include and a reference share the same name', async () => {
|
|
59
|
-
const env = (0, environment_mock_1.environmentMock)(scratch);
|
|
60
|
-
const sub = (0, path_1.join)(scratch, 'sub');
|
|
61
|
-
(0, fs_1.mkdirSync)(sub);
|
|
62
|
-
(0, fs_1.writeFileSync)((0, path_1.join)(sub, '.hammerkit.yaml'), 'tasks:\n x:\n cmds:\n - echo x\n');
|
|
63
|
-
(0, fs_1.writeFileSync)((0, path_1.join)(scratch, 'inc.yaml'), 'tasks:\n y:\n cmds:\n - echo y\n');
|
|
64
|
-
(0, fs_1.writeFileSync)((0, path_1.join)(scratch, '.hammerkit.yaml'), 'references:\n lib: sub\nincludes:\n lib: inc.yaml\n');
|
|
65
|
-
await expect((0, schema_parser_1.createParseContext)((0, path_1.join)(scratch, '.hammerkit.yaml'), env)).rejects.toThrow(/lib already exists/);
|
|
66
|
-
});
|
|
67
|
-
it('reuses an already-parsed build file when reached again (cache hit)', async () => {
|
|
68
|
-
const env = (0, environment_mock_1.environmentMock)(scratch);
|
|
69
|
-
const sub = (0, path_1.join)(scratch, 'sub');
|
|
70
|
-
(0, fs_1.mkdirSync)(sub);
|
|
71
|
-
(0, fs_1.writeFileSync)((0, path_1.join)(sub, '.hammerkit.yaml'), 'tasks:\n s:\n cmds:\n - echo s\n');
|
|
72
|
-
(0, fs_1.writeFileSync)((0, path_1.join)(scratch, '.hammerkit.yaml'), 'references:\n a: sub\n b: sub\n');
|
|
73
|
-
const { ctx, scope } = await (0, schema_parser_1.createParseContext)((0, path_1.join)(scratch, '.hammerkit.yaml'), env);
|
|
74
|
-
// Both references point at sub/.hammerkit.yaml and must end up at the same
|
|
75
|
-
// parsed ParseScope (the second appendBuildFile hits the ctx.files cache).
|
|
76
|
-
expect(scope.references['a'].scope).toBe(scope.references['b'].scope);
|
|
77
|
-
expect(Object.keys(ctx.files)).toHaveLength(2); // root + sub (sub cached on second visit)
|
|
78
|
-
});
|
|
79
|
-
});
|
|
80
|
-
//# sourceMappingURL=schema-parser.spec.js.map
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const build_file_service_schema_1 = require("./build-file-service-schema");
|
|
4
|
-
const build_file_task_schema_1 = require("./build-file-task-schema");
|
|
5
|
-
describe('service/task type guards', () => {
|
|
6
|
-
it('isBuildFileContainerSchema discriminates by `image` presence', () => {
|
|
7
|
-
expect((0, build_file_service_schema_1.isBuildFileContainerSchema)({ image: 'node' })).toBe(true);
|
|
8
|
-
expect((0, build_file_service_schema_1.isBuildFileContainerSchema)({ selector: { name: 'n', type: 't' } })).toBe(false);
|
|
9
|
-
});
|
|
10
|
-
it('isBuildFileKubernetesServiceSchema discriminates by `selector` presence', () => {
|
|
11
|
-
expect((0, build_file_service_schema_1.isBuildFileKubernetesServiceSchema)({ selector: { name: 'n', type: 't' } })).toBe(true);
|
|
12
|
-
expect((0, build_file_service_schema_1.isBuildFileKubernetesServiceSchema)({ image: 'node' })).toBe(false);
|
|
13
|
-
});
|
|
14
|
-
it('isBuildFileContainerTaskSchema returns true iff the task has an image', () => {
|
|
15
|
-
expect((0, build_file_task_schema_1.isBuildFileContainerTaskSchema)({ image: 'node' })).toBe(true);
|
|
16
|
-
expect((0, build_file_task_schema_1.isBuildFileContainerTaskSchema)({ cmds: ['x'] })).toBe(false);
|
|
17
|
-
});
|
|
18
|
-
it('isBuildFileLocalTaskSchema returns true iff the task has no image', () => {
|
|
19
|
-
expect((0, build_file_task_schema_1.isBuildFileLocalTaskSchema)({ cmds: ['x'] })).toBe(true);
|
|
20
|
-
expect((0, build_file_task_schema_1.isBuildFileLocalTaskSchema)({ image: 'node' })).toBe(false);
|
|
21
|
-
});
|
|
22
|
-
});
|
|
23
|
-
//# sourceMappingURL=type-guards.spec.js.map
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const work_scope_parser_1 = require("./work-scope-parser");
|
|
4
|
-
const test_case_1 = require("../testing/test-case");
|
|
5
|
-
const program_1 = require("../program");
|
|
6
|
-
const path_1 = require("path");
|
|
7
|
-
async function withCli(buildFile, scope, fn) {
|
|
8
|
-
const testCase = (0, test_case_1.createTestCase)('work-scope-parser', { '.hammerkit.yaml': buildFile });
|
|
9
|
-
await testCase.setup(async (cwd, environment) => {
|
|
10
|
-
const cli = await (0, program_1.createCli)((0, path_1.join)(cwd, '.hammerkit.yaml'), environment, scope);
|
|
11
|
-
await fn(cli);
|
|
12
|
-
});
|
|
13
|
-
}
|
|
14
|
-
describe('work-scope-parser', () => {
|
|
15
|
-
describe('defaultEnvironment', () => {
|
|
16
|
-
it('falls back to docker when no default environment is declared', () => {
|
|
17
|
-
expect((0, work_scope_parser_1.defaultEnvironment)({ environments: {} })).toEqual({ type: 'docker' });
|
|
18
|
-
});
|
|
19
|
-
it('uses a declared docker default environment', () => {
|
|
20
|
-
const context = {
|
|
21
|
-
environments: { default: { schema: { docker: { host: 'tcp://remote:2375' } } } },
|
|
22
|
-
};
|
|
23
|
-
expect((0, work_scope_parser_1.defaultEnvironment)(context)).toEqual({ type: 'docker', host: 'tcp://remote:2375' });
|
|
24
|
-
});
|
|
25
|
-
it('uses a declared kubernetes default environment', () => {
|
|
26
|
-
const context = {
|
|
27
|
-
environments: { default: { schema: { kubernetes: { context: 'prod' } } } },
|
|
28
|
-
};
|
|
29
|
-
expect((0, work_scope_parser_1.defaultEnvironment)(context)).toEqual({
|
|
30
|
-
type: 'kubernetes',
|
|
31
|
-
context: 'prod',
|
|
32
|
-
ingresses: [],
|
|
33
|
-
namespace: 'default',
|
|
34
|
-
});
|
|
35
|
-
});
|
|
36
|
-
});
|
|
37
|
-
describe('getWorkContext (via createCli)', () => {
|
|
38
|
-
it('includes only the requested task and its dependencies', async () => {
|
|
39
|
-
await withCli({
|
|
40
|
-
tasks: {
|
|
41
|
-
install: { cmds: ['npm install'] },
|
|
42
|
-
build: { cmds: ['tsc'], deps: ['install'] },
|
|
43
|
-
lint: { cmds: ['eslint'] },
|
|
44
|
-
},
|
|
45
|
-
}, { taskName: 'build' }, (cli) => {
|
|
46
|
-
const names = cli
|
|
47
|
-
.tasks()
|
|
48
|
-
.map((t) => t.item.name)
|
|
49
|
-
.sort();
|
|
50
|
-
expect(names).toEqual(['build', 'install']);
|
|
51
|
-
expect(() => cli.task('lint')).toThrow('unable to find task lint');
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
it('filters tasks by label', async () => {
|
|
55
|
-
await withCli({
|
|
56
|
-
tasks: {
|
|
57
|
-
build: { cmds: ['tsc'], labels: { app: 'web' } },
|
|
58
|
-
lint: { cmds: ['eslint'], labels: { app: 'tool' } },
|
|
59
|
-
},
|
|
60
|
-
}, { filterLabels: { app: ['web'] } }, (cli) => {
|
|
61
|
-
expect(cli.tasks().map((t) => t.item.name)).toEqual(['build']);
|
|
62
|
-
});
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
//# sourceMappingURL=work-scope-parser.spec.js.map
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const update_service_status_1 = require("./update-service-status");
|
|
4
|
-
function fakeService(initialize) {
|
|
5
|
-
return {
|
|
6
|
-
state: { current: { type: 'pending' } },
|
|
7
|
-
runtime: { initialize },
|
|
8
|
-
};
|
|
9
|
-
}
|
|
10
|
-
describe('updateServiceStatus', () => {
|
|
11
|
-
it('calls initialize(state) on every service runtime', async () => {
|
|
12
|
-
const a = vi.fn().mockResolvedValue(undefined);
|
|
13
|
-
const b = vi.fn().mockResolvedValue(undefined);
|
|
14
|
-
const workTree = {
|
|
15
|
-
services: { svcA: fakeService(a), svcB: fakeService(b) },
|
|
16
|
-
tasks: {},
|
|
17
|
-
};
|
|
18
|
-
await (0, update_service_status_1.updateServiceStatus)(workTree);
|
|
19
|
-
expect(a).toHaveBeenCalledTimes(1);
|
|
20
|
-
expect(b).toHaveBeenCalledTimes(1);
|
|
21
|
-
});
|
|
22
|
-
it('is a no-op when the work tree has no services', async () => {
|
|
23
|
-
const workTree = { services: {}, tasks: {} };
|
|
24
|
-
await expect((0, update_service_status_1.updateServiceStatus)(workTree)).resolves.toBeUndefined();
|
|
25
|
-
});
|
|
26
|
-
});
|
|
27
|
-
//# sourceMappingURL=update-service-status.spec.js.map
|
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.ensureLocalRegistry = void 0;
|
|
7
|
-
const dockerode_1 = __importDefault(require("dockerode"));
|
|
8
|
-
const REGISTRY_NAME = 'hammerkit-test-registry';
|
|
9
|
-
const REGISTRY_IMAGE = 'registry:2';
|
|
10
|
-
// Small image with busybox wget, used to talk to the registry from the daemon's
|
|
11
|
-
// network (see why below). alpine is already pulled by the package suites.
|
|
12
|
-
const PROBE_IMAGE = 'alpine:3.19';
|
|
13
|
-
const MANAGED_PORT = Number(process.env.HAMMERKIT_TEST_REGISTRY_PORT) || 5000;
|
|
14
|
-
function registryAddressFromEnv() {
|
|
15
|
-
const fromEnv = process.env.REGISTRY;
|
|
16
|
-
if (!fromEnv) {
|
|
17
|
-
return null;
|
|
18
|
-
}
|
|
19
|
-
const match = /^([^:]+):(\d+)$/.exec(fromEnv);
|
|
20
|
-
if (!match) {
|
|
21
|
-
throw new Error(`REGISTRY must be of the form host:port (got "${fromEnv}")`);
|
|
22
|
-
}
|
|
23
|
-
return { host: match[1], hostPort: parseInt(match[2], 10) };
|
|
24
|
-
}
|
|
25
|
-
async function ensureImage(docker, image) {
|
|
26
|
-
try {
|
|
27
|
-
await docker.getImage(image).inspect();
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
catch {
|
|
31
|
-
// not present locally — pull it below
|
|
32
|
-
}
|
|
33
|
-
await new Promise((resolve, reject) => {
|
|
34
|
-
docker.pull(image, (err, stream) => {
|
|
35
|
-
if (err || !stream) {
|
|
36
|
-
reject(err ?? new Error('no pull stream'));
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
docker.modem.followProgress(stream, (e) => (e ? reject(e) : resolve()));
|
|
40
|
-
});
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
// Run a throwaway container on the *host* network and return its exit code.
|
|
44
|
-
// The registry is reachable at 127.0.0.1:<port> from the daemon's network (see
|
|
45
|
-
// ensureLocalRegistry), but not necessarily from this (host) process — on Docker
|
|
46
|
-
// Desktop the daemon is in a VM — so registry HTTP is done from here instead.
|
|
47
|
-
async function runOnHostNet(docker, shellCmd) {
|
|
48
|
-
await ensureImage(docker, PROBE_IMAGE);
|
|
49
|
-
const container = await docker.createContainer({
|
|
50
|
-
Image: PROBE_IMAGE,
|
|
51
|
-
Cmd: ['sh', '-c', shellCmd],
|
|
52
|
-
HostConfig: { NetworkMode: 'host', AutoRemove: false },
|
|
53
|
-
});
|
|
54
|
-
try {
|
|
55
|
-
await container.start();
|
|
56
|
-
const res = await container.wait();
|
|
57
|
-
return res.StatusCode ?? 1;
|
|
58
|
-
}
|
|
59
|
-
finally {
|
|
60
|
-
await container.remove({ force: true }).catch(() => undefined);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* Returns a docker registry suitable for `cli.package({ registry, push: true, ... })`.
|
|
65
|
-
*
|
|
66
|
-
* Resolution order:
|
|
67
|
-
* 1. `REGISTRY=host:port` env var (used by CI; just probed for liveness, never managed).
|
|
68
|
-
* 2. A managed `registry:2` container on the daemon's own network (host networking).
|
|
69
|
-
*
|
|
70
|
-
* Host networking matters: the daemon performs the push, and an HTTP push needs a
|
|
71
|
-
* `127.0.0.1`/`localhost` address (the only registries docker treats as insecure
|
|
72
|
-
* without daemon config). On Docker Desktop the daemon runs in a VM, so a
|
|
73
|
-
* host-*published* port is not reachable from it via 127.0.0.1 (`docker push
|
|
74
|
-
* 127.0.0.1:<published>` → connection refused). Putting the registry on the
|
|
75
|
-
* daemon's network makes 127.0.0.1:<port> resolve to it. Because this process
|
|
76
|
-
* (on the host) then can't see the registry, liveness and tag lookups run inside
|
|
77
|
-
* a throwaway container on the same network — see `listsTag`.
|
|
78
|
-
*
|
|
79
|
-
* Callers must invoke `cleanup()`. For the env-var case it is a no-op.
|
|
80
|
-
*/
|
|
81
|
-
async function ensureLocalRegistry(docker) {
|
|
82
|
-
const d = docker ?? new dockerode_1.default();
|
|
83
|
-
const fromEnv = registryAddressFromEnv();
|
|
84
|
-
let host;
|
|
85
|
-
let hostPort;
|
|
86
|
-
let cleanup = async () => undefined;
|
|
87
|
-
if (fromEnv) {
|
|
88
|
-
host = fromEnv.host;
|
|
89
|
-
hostPort = fromEnv.hostPort;
|
|
90
|
-
}
|
|
91
|
-
else {
|
|
92
|
-
host = '127.0.0.1';
|
|
93
|
-
hostPort = MANAGED_PORT;
|
|
94
|
-
await ensureImage(d, REGISTRY_IMAGE);
|
|
95
|
-
const existing = await d.listContainers({ all: true, filters: { name: [REGISTRY_NAME] } });
|
|
96
|
-
if (existing.length === 0) {
|
|
97
|
-
const container = await d.createContainer({
|
|
98
|
-
Image: REGISTRY_IMAGE,
|
|
99
|
-
name: REGISTRY_NAME,
|
|
100
|
-
Env: [`REGISTRY_HTTP_ADDR=0.0.0.0:${MANAGED_PORT}`],
|
|
101
|
-
HostConfig: { AutoRemove: true, NetworkMode: 'host' },
|
|
102
|
-
});
|
|
103
|
-
await container.start();
|
|
104
|
-
}
|
|
105
|
-
else if (existing[0].State !== 'running') {
|
|
106
|
-
await d.getContainer(existing[0].Id).start();
|
|
107
|
-
}
|
|
108
|
-
cleanup = async () => {
|
|
109
|
-
const c = (await d.listContainers({ all: true, filters: { name: [REGISTRY_NAME] } }))[0];
|
|
110
|
-
if (c) {
|
|
111
|
-
await d
|
|
112
|
-
.getContainer(c.Id)
|
|
113
|
-
.remove({ force: true })
|
|
114
|
-
.catch(() => undefined);
|
|
115
|
-
}
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
const base = `http://${host}:${hostPort}`;
|
|
119
|
-
const reachable = await runOnHostNet(d, `for i in $(seq 1 60); do wget -q -O /dev/null ${base}/v2/ && exit 0; sleep 1; done; exit 1`);
|
|
120
|
-
if (reachable !== 0) {
|
|
121
|
-
throw new Error(`docker registry at ${host}:${hostPort} did not become reachable in time`);
|
|
122
|
-
}
|
|
123
|
-
return {
|
|
124
|
-
host,
|
|
125
|
-
hostPort,
|
|
126
|
-
cleanup,
|
|
127
|
-
async listsTag(repository, tag) {
|
|
128
|
-
const code = await runOnHostNet(d, `wget -qO- ${base}/v2/${repository}/tags/list | grep -q '"${tag}"'`);
|
|
129
|
-
return code === 0;
|
|
130
|
-
},
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
exports.ensureLocalRegistry = ensureLocalRegistry;
|
|
134
|
-
//# sourceMappingURL=ensure-local-registry.js.map
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ExampleTestSuite = void 0;
|
|
4
|
-
const path_1 = require("path");
|
|
5
|
-
const get_file_context_1 = require("../file/get-file-context");
|
|
6
|
-
const work_item_status_1 = require("../planner/work-item-status");
|
|
7
|
-
const program_1 = require("../program");
|
|
8
|
-
const log_1 = require("../log");
|
|
9
|
-
const test_streams_1 = require("./test-streams");
|
|
10
|
-
class ExampleTestSuite {
|
|
11
|
-
constructor(exampleName, files) {
|
|
12
|
-
this.files = files;
|
|
13
|
-
this.tests = [];
|
|
14
|
-
this.exampleDirectory = (0, path_1.join)(__dirname, '../../examples/', exampleName);
|
|
15
|
-
this.path = (0, path_1.join)(process.cwd(), 'temp', exampleName);
|
|
16
|
-
this.file = (0, get_file_context_1.getFileContext)(this.path);
|
|
17
|
-
}
|
|
18
|
-
async close() {
|
|
19
|
-
for (const test of this.tests) {
|
|
20
|
-
test.close();
|
|
21
|
-
await this.file.remove(test.cwd);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
async setup(scope) {
|
|
25
|
-
await this.file.remove(this.path);
|
|
26
|
-
await this.file.createDirectory(this.path);
|
|
27
|
-
const statusStream = (0, test_streams_1.memoryStream)();
|
|
28
|
-
const environment = {
|
|
29
|
-
processEnvs: { ...process.env, ...(scope.envs ?? {}) },
|
|
30
|
-
abortCtrl: new AbortController(),
|
|
31
|
-
cwd: this.path,
|
|
32
|
-
file: this.file,
|
|
33
|
-
console: (0, log_1.consoleContext)((0, test_streams_1.emptyStream)()),
|
|
34
|
-
status: (0, work_item_status_1.statusConsole)(statusStream.stream),
|
|
35
|
-
stdout: (0, test_streams_1.emptyStream)(),
|
|
36
|
-
stderr: (0, test_streams_1.emptyStream)(),
|
|
37
|
-
stdoutColumns: 80,
|
|
38
|
-
};
|
|
39
|
-
for (const file of this.files) {
|
|
40
|
-
await this.file.copy((0, path_1.join)(this.exampleDirectory, file), (0, path_1.join)(this.path, file));
|
|
41
|
-
}
|
|
42
|
-
const fileName = (0, path_1.join)(this.path, '.hammerkit.yaml');
|
|
43
|
-
this.tests.push({
|
|
44
|
-
cwd: this.path,
|
|
45
|
-
close() {
|
|
46
|
-
environment.abortCtrl.abort();
|
|
47
|
-
},
|
|
48
|
-
});
|
|
49
|
-
const cli = await (0, program_1.createCli)(fileName, environment, scope);
|
|
50
|
-
// clear the backend cache too: the default `local` backend persists under
|
|
51
|
-
// ~/.hammerkit/remote-cache outside the test's temp dir, so without this a
|
|
52
|
-
// prior run's result would leak in and make cache assertions flaky.
|
|
53
|
-
await cli.clean({ cache: true });
|
|
54
|
-
// reset cli clean stats
|
|
55
|
-
environment.status = (0, work_item_status_1.statusConsole)(statusStream.stream);
|
|
56
|
-
return {
|
|
57
|
-
cli,
|
|
58
|
-
environment,
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
exports.ExampleTestSuite = ExampleTestSuite;
|
|
63
|
-
//# sourceMappingURL=example-test-suite.js.map
|
package/dist/testing/expect.js
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.expectContainsLog = exports.expectLog = exports.expectSuccessfulResult = exports.expectSuccessfulExecution = void 0;
|
|
4
|
-
const plan_work_tasks_1 = require("../planner/utils/plan-work-tasks");
|
|
5
|
-
const get_scheduler_execute_result_1 = require("../executer/get-scheduler-execute-result");
|
|
6
|
-
const testing_timeout_1 = require("./testing-timeout");
|
|
7
|
-
async function expectSuccessfulExecution(exec, env) {
|
|
8
|
-
const badResult = new Promise((resolve) => {
|
|
9
|
-
exec.state.on('expected-status', (workTree) => {
|
|
10
|
-
if (env.abortCtrl.signal.aborted) {
|
|
11
|
-
return;
|
|
12
|
-
}
|
|
13
|
-
const hasErrorTask = Object.values(workTree.tasks).some((n) => n.state.current.type === 'error' || n.state.current.type === 'crash');
|
|
14
|
-
const hasErrorService = Object.values(workTree.services).some((n) => n.state.current.type === 'error' || n.state.current.type === 'end');
|
|
15
|
-
if (!hasErrorTask && !hasErrorService) {
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
18
|
-
const stateResult = (0, get_scheduler_execute_result_1.getSchedulerExecuteResult)(workTree);
|
|
19
|
-
if (!stateResult.success) {
|
|
20
|
-
resolve(stateResult);
|
|
21
|
-
env.abortCtrl.abort();
|
|
22
|
-
}
|
|
23
|
-
});
|
|
24
|
-
});
|
|
25
|
-
const result = await Promise.race([badResult, (0, testing_timeout_1.testingTimeout)(exec)]);
|
|
26
|
-
await expectSuccessfulResult(result, env);
|
|
27
|
-
}
|
|
28
|
-
exports.expectSuccessfulExecution = expectSuccessfulExecution;
|
|
29
|
-
async function expectSuccessfulResult(result, env) {
|
|
30
|
-
if (!result.success) {
|
|
31
|
-
for (const task of (0, plan_work_tasks_1.iterateWorkTasks)(result.state)) {
|
|
32
|
-
if (task.state.current.type !== 'completed') {
|
|
33
|
-
expect({
|
|
34
|
-
cacheId: task.id(),
|
|
35
|
-
status: task.state.current.type,
|
|
36
|
-
updates: Array.from(task.status.read()).map((s) => `${s.level}: ${s.message}`),
|
|
37
|
-
logs: Array.from(task.status.logs()).map((l) => `${l.console}: ${l.message}`),
|
|
38
|
-
errorMessage: task.state.current.type === 'error' ? task.state.current.errorMessage : undefined,
|
|
39
|
-
needs: task.needs.map((need) => ({
|
|
40
|
-
name: need.name,
|
|
41
|
-
updates: Array.from(need.service.status.read()).map((s) => `${s.level}: ${s.message}`),
|
|
42
|
-
logs: Array.from(need.service.status.logs()).map((l) => `${l.console}: ${l.message}`),
|
|
43
|
-
})),
|
|
44
|
-
}).toEqual({
|
|
45
|
-
cacheId: task.id(),
|
|
46
|
-
status: 'completed',
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
const status = Array.from(env.status.read());
|
|
52
|
-
const errorStatus = status
|
|
53
|
-
.filter((s) => s.level === 'warn' || s.level === 'error')
|
|
54
|
-
.map((s) => `${s.context.type}:${s.context.name} - ${s.level} ${s.message}`);
|
|
55
|
-
expect(errorStatus).toEqual([]);
|
|
56
|
-
}
|
|
57
|
-
exports.expectSuccessfulResult = expectSuccessfulResult;
|
|
58
|
-
function getTaskState(state, name) {
|
|
59
|
-
const tasks = Object.values(state.tasks).find((n) => n.name === name);
|
|
60
|
-
if (!tasks) {
|
|
61
|
-
throw new Error(`could not find task ${name}`);
|
|
62
|
-
}
|
|
63
|
-
return tasks;
|
|
64
|
-
}
|
|
65
|
-
async function expectLog(result, env, name, message) {
|
|
66
|
-
const state = getTaskState(result.state, name);
|
|
67
|
-
const logs = Array.from(state.status.logs()).map((n) => n.message);
|
|
68
|
-
expect(logs).toContain(message);
|
|
69
|
-
}
|
|
70
|
-
exports.expectLog = expectLog;
|
|
71
|
-
async function expectContainsLog(result, env, name, message) {
|
|
72
|
-
const state = getTaskState(result.state, name);
|
|
73
|
-
const logs = state.status.logs();
|
|
74
|
-
for (const log of logs) {
|
|
75
|
-
if (log.message.indexOf(message) >= 0) {
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
expect(Array.from(logs)).toContain(message);
|
|
80
|
-
}
|
|
81
|
-
exports.expectContainsLog = expectContainsLog;
|
|
82
|
-
//# sourceMappingURL=expect.js.map
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getTestSuite = void 0;
|
|
4
|
-
const example_test_suite_1 = require("./example-test-suite");
|
|
5
|
-
function getTestSuite(exampleName, files) {
|
|
6
|
-
return new example_test_suite_1.ExampleTestSuite(exampleName, files);
|
|
7
|
-
}
|
|
8
|
-
exports.getTestSuite = getTestSuite;
|
|
9
|
-
//# sourceMappingURL=get-test-suite.js.map
|
package/dist/testing/http-get.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.httpGet = void 0;
|
|
4
|
-
const http_1 = require("http");
|
|
5
|
-
function httpGet(host, port, path, timeoutMs = 10000) {
|
|
6
|
-
return new Promise((resolve, reject) => {
|
|
7
|
-
const req = (0, http_1.request)({ host, port, path, method: 'GET', timeout: timeoutMs }, (res) => {
|
|
8
|
-
const chunks = [];
|
|
9
|
-
res.on('data', (chunk) => chunks.push(chunk));
|
|
10
|
-
res.on('end', () => resolve({ status: res.statusCode ?? 0, body: Buffer.concat(chunks).toString('utf8') }));
|
|
11
|
-
res.on('error', reject);
|
|
12
|
-
});
|
|
13
|
-
req.on('error', reject);
|
|
14
|
-
req.on('timeout', () => {
|
|
15
|
-
req.destroy(new Error(`timeout after ${timeoutMs}ms`));
|
|
16
|
-
});
|
|
17
|
-
req.end();
|
|
18
|
-
});
|
|
19
|
-
}
|
|
20
|
-
exports.httpGet = httpGet;
|
|
21
|
-
//# sourceMappingURL=http-get.js.map
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const expect_1 = require("../expect");
|
|
4
|
-
const get_test_suite_1 = require("../get-test-suite");
|
|
5
|
-
const path_1 = require("path");
|
|
6
|
-
const enqueue_next_1 = require("../../executer/scheduler/enqueue-next");
|
|
7
|
-
const read_build_file_1 = require("../../parser/read-build-file");
|
|
8
|
-
const requires_linux_containers_1 = require("../requires-linux-containers");
|
|
9
|
-
describe('cache', () => {
|
|
10
|
-
const suite = (0, get_test_suite_1.getTestSuite)('cache', ['.hammerkit.yaml', 'package.json', 'package-lock.json']);
|
|
11
|
-
afterAll(() => suite.close());
|
|
12
|
-
async function testCache(action, expectInvalidate) {
|
|
13
|
-
const setupBefore = await suite.setup({ taskName: 'example' });
|
|
14
|
-
const result = await setupBefore.cli.exec().start();
|
|
15
|
-
await (0, expect_1.expectSuccessfulResult)(result, setupBefore.environment);
|
|
16
|
-
await action(setupBefore.environment);
|
|
17
|
-
const setupAfter = await suite.setup({ taskName: 'example' });
|
|
18
|
-
const task = setupAfter.cli.task('example');
|
|
19
|
-
const checksumUpToDate = await (0, enqueue_next_1.checkCacheState)(task, 'checksum', setupAfter.environment);
|
|
20
|
-
const modifyDateUpToDate = await (0, enqueue_next_1.checkCacheState)(task, 'modify-date', setupAfter.environment);
|
|
21
|
-
if (expectInvalidate) {
|
|
22
|
-
expect(checksumUpToDate.cached).toBeFalsy();
|
|
23
|
-
expect(modifyDateUpToDate.cached).toBeFalsy();
|
|
24
|
-
}
|
|
25
|
-
else {
|
|
26
|
-
expect(checksumUpToDate.cached).toBeTruthy();
|
|
27
|
-
expect(modifyDateUpToDate.cached).toBeTruthy();
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
it('should run invalid cache on src file change', (0, requires_linux_containers_1.requiresLinuxContainers)(async () => {
|
|
31
|
-
await testCache(async (environment) => {
|
|
32
|
-
await environment.file.appendFile((0, path_1.join)(environment.cwd, 'package.json'), '\n');
|
|
33
|
-
}, true);
|
|
34
|
-
}));
|
|
35
|
-
it('should mount generations of dependant tasks', (0, requires_linux_containers_1.requiresLinuxContainers)(async () => {
|
|
36
|
-
const { cli, environment } = await suite.setup({ taskName: 'dependant' });
|
|
37
|
-
const result = await cli.runExec();
|
|
38
|
-
await (0, expect_1.expectSuccessfulResult)(result, environment);
|
|
39
|
-
await (0, expect_1.expectLog)(result, environment, `dependant`, 'node_modules');
|
|
40
|
-
}));
|
|
41
|
-
it('should invalid cache on image change', (0, requires_linux_containers_1.requiresLinuxContainers)(async () => {
|
|
42
|
-
await testCache(async (environment) => {
|
|
43
|
-
const buildFile = await (0, read_build_file_1.read)('.hammerkit.yaml', environment);
|
|
44
|
-
buildFile.tasks['example'].image = '15.0.0';
|
|
45
|
-
await (0, read_build_file_1.write)('.hammerkit.yaml', buildFile, environment);
|
|
46
|
-
}, true);
|
|
47
|
-
}));
|
|
48
|
-
});
|
|
49
|
-
//# sourceMappingURL=cache.spec.js.map
|