hammerkit 1.4.0 → 1.5.0-alpha.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.
Files changed (177) hide show
  1. package/.devcontainer/Dockerfile +5 -0
  2. package/.devcontainer/devcontainer.json +40 -0
  3. package/README.md +13 -86
  4. package/SUMMARY.md +43 -0
  5. package/build.schema.json +56 -2
  6. package/dist/cli.js +97 -0
  7. package/dist/cli.spec.js +5 -0
  8. package/dist/console/console-context-mock.js +11 -0
  9. package/dist/console/get-logger.js +23 -0
  10. package/dist/docker/pull.js +5 -5
  11. package/dist/docker/remove-container.js +21 -0
  12. package/dist/docker/stream.js +14 -10
  13. package/dist/docker/using-container.js +28 -0
  14. package/dist/environment/get-process-env.js +4 -4
  15. package/dist/environment/replace-env-variables.js +2 -3
  16. package/dist/executer/abort.js +13 -0
  17. package/dist/executer/check-readiness.js +25 -0
  18. package/dist/executer/create-scheduler-state.js +32 -0
  19. package/dist/executer/docker-node.js +123 -0
  20. package/dist/executer/docker-service.js +113 -0
  21. package/dist/executer/environment-mock.js +17 -0
  22. package/dist/executer/event-cache.js +165 -0
  23. package/dist/executer/execute-command.js +42 -0
  24. package/dist/executer/execute-docker.js +58 -194
  25. package/dist/executer/execute.spec.js +37 -37
  26. package/dist/executer/execution-steps.js +57 -0
  27. package/dist/executer/get-docker-executor.js +6 -100
  28. package/dist/executer/hierarchy-scheduler.js +94 -0
  29. package/dist/executer/kubernetes-service.js +64 -0
  30. package/dist/executer/label-values.js +65 -0
  31. package/dist/executer/local-node.js +57 -0
  32. package/dist/executer/print-container-options.js +17 -0
  33. package/dist/{logging/log-strategy.js → executer/process-item.js} +1 -1
  34. package/dist/executer/process-listener.js +3 -0
  35. package/dist/executer/process-manager.js +111 -0
  36. package/dist/executer/process-manager.spec.js +91 -0
  37. package/dist/executer/{executor.js → process.js} +1 -1
  38. package/dist/executer/{execute-result.js → readonly-state.js} +1 -1
  39. package/dist/executer/schedule.js +139 -0
  40. package/dist/executer/scheduler/check-for-loop.js +21 -0
  41. package/dist/executer/scheduler/enqueue-next.js +27 -0
  42. package/dist/{testing/test-context.js → executer/scheduler/node-state.js} +1 -1
  43. package/dist/executer/scheduler/scheduler-result.js +3 -0
  44. package/dist/executer/scheduler/scheduler-state.js +3 -0
  45. package/dist/executer/scheduler/service-state.js +3 -0
  46. package/dist/executer/service-dns.js +6 -0
  47. package/dist/executer/set-user-permission.js +16 -0
  48. package/dist/executer/start-node.js +59 -0
  49. package/dist/executer/state-listener.js +3 -0
  50. package/dist/executer/state.js +49 -0
  51. package/dist/executer/states.js +4 -159
  52. package/dist/executer/watch-node.js +57 -0
  53. package/dist/executer/watch-service.js +54 -0
  54. package/dist/executer/work-scope.js +10 -0
  55. package/dist/file/get-file-context-mock.spec.js +5 -5
  56. package/dist/file/get-file-context.js +41 -18
  57. package/dist/file/move-files.js +1 -1
  58. package/dist/get-work-context.js +29 -0
  59. package/dist/index.js +8 -4
  60. package/dist/log.js +192 -50
  61. package/dist/logging/grouped-logger.js +31 -19
  62. package/dist/logging/interactive-logger.js +20 -23
  63. package/dist/logging/live-logger.js +7 -17
  64. package/dist/optimizer/calculate-checksum.js +1 -1
  65. package/dist/optimizer/get-cache-directory.js +8 -13
  66. package/dist/optimizer/get-work-node-cache-stats.js +68 -21
  67. package/dist/optimizer/read-work-node-cache.js +2 -2
  68. package/dist/optimizer/work-node-cache-description.js +12 -11
  69. package/dist/optimizer/write-work-node-cache.js +9 -8
  70. package/dist/{executer/execution-context.js → parser/build-file-service.js} +1 -1
  71. package/dist/{optimizer → parser}/cache-method.js +0 -0
  72. package/dist/parser/get-build-file.js +1 -1
  73. package/dist/parser/parse-boolean.js +29 -0
  74. package/dist/parser/parse-boolean.spec.js +48 -0
  75. package/dist/parser/parse-build-file-references.js +2 -2
  76. package/dist/parser/parse-build-file-services.js +58 -0
  77. package/dist/parser/parse-build-file-task-command.js +6 -5
  78. package/dist/parser/parse-build-file-task-source.js +5 -5
  79. package/dist/parser/parse-build-file.js +27 -15
  80. package/dist/parser/parse-context.js +13 -0
  81. package/dist/parser/parse-envs.js +4 -3
  82. package/dist/parser/parse-healthcheck.js +28 -0
  83. package/dist/parser/parse-label-arguments.js +23 -0
  84. package/dist/parser/parse-service-selector.js +39 -0
  85. package/dist/parser/parse-string-array.js +6 -5
  86. package/dist/parser/parse-string-map.js +30 -0
  87. package/dist/parser/parse-string.js +20 -0
  88. package/dist/parser/read-build-file.js +16 -5
  89. package/dist/parser/read-env-file.js +3 -3
  90. package/dist/planner/utils/get-container-mounts.js +24 -0
  91. package/dist/planner/utils/normalize-path.js +17 -0
  92. package/dist/planner/utils/parse-work-node-mount.js +3 -14
  93. package/dist/planner/utils/parse-work-node-mount.spec.js +10 -10
  94. package/dist/planner/utils/parse-work-service-volume.js +21 -0
  95. package/dist/planner/utils/plan-work-command.js +1 -1
  96. package/dist/planner/utils/plan-work-dependency.js +17 -5
  97. package/dist/planner/utils/plan-work-node.js +203 -128
  98. package/dist/planner/utils/plan-work-nodes.js +59 -14
  99. package/dist/planner/utils/plan-work-tree.js +8 -4
  100. package/dist/planner/utils/plan-work-volume.js +25 -0
  101. package/dist/planner/validate.js +56 -8
  102. package/dist/planner/work-context.js +20 -0
  103. package/dist/planner/work-mount.js +3 -0
  104. package/dist/planner/work-node-id.js +4 -4
  105. package/dist/planner/work-node-id.spec.js +11 -8
  106. package/dist/planner/work-node-path.js +0 -1
  107. package/dist/planner/work-node-status.js +121 -18
  108. package/dist/planner/work-node.js +3 -3
  109. package/dist/planner/work-service-id.js +13 -0
  110. package/dist/planner/work-service-volume.js +3 -0
  111. package/dist/planner/work-service.js +6 -0
  112. package/dist/planner/work-services.js +3 -0
  113. package/dist/planner/work-volume.js +3 -0
  114. package/dist/program.js +155 -90
  115. package/dist/program.spec.js +20 -0
  116. package/dist/start-watch-processes.js +28 -0
  117. package/dist/testing/cli.js +73 -0
  118. package/dist/testing/create-build-file.js +1 -1
  119. package/dist/testing/example-test-suite.js +54 -0
  120. package/dist/testing/expect.js +30 -18
  121. package/dist/testing/get-logger.js +23 -0
  122. package/dist/testing/get-node.js +2 -2
  123. package/dist/testing/get-test-context.js +5 -3
  124. package/dist/testing/get-test-suite.js +2 -50
  125. package/dist/testing/integration/cache.spec.js +25 -28
  126. package/dist/testing/integration/cancellation.spec.js +19 -21
  127. package/dist/testing/integration/clean.spec.js +25 -28
  128. package/dist/testing/integration/cmd.spec.js +5 -8
  129. package/dist/testing/integration/concurrency.spec.js +8 -17
  130. package/dist/testing/integration/docker.spec.js +6 -9
  131. package/dist/testing/integration/env.spec.js +27 -34
  132. package/dist/testing/integration/error.spec.js +5 -9
  133. package/dist/testing/integration/extend.spec.js +32 -0
  134. package/dist/testing/integration/glob.spec.js +35 -28
  135. package/dist/testing/integration/include.spec.js +17 -16
  136. package/dist/testing/integration/invalid.spec.js +3 -2
  137. package/dist/testing/integration/invalid_loop.spec.js +13 -0
  138. package/dist/testing/integration/kubernetes.spec.js +15 -0
  139. package/dist/testing/integration/labels.spec.js +47 -0
  140. package/dist/testing/integration/local.spec.js +4 -7
  141. package/dist/testing/integration/monorepo.spec.js +5 -9
  142. package/dist/testing/integration/multi-line.spec.js +4 -4
  143. package/dist/testing/integration/program.spec.js +3 -10
  144. package/dist/testing/integration/reference.spec.js +10 -13
  145. package/dist/testing/integration/services.spec.js +14 -0
  146. package/dist/testing/integration/store.spec.js +42 -38
  147. package/dist/testing/integration/unknown.spec.js +4 -4
  148. package/dist/testing/integration/validate.spec.js +4 -4
  149. package/dist/testing/integration/watch.spec.js +34 -33
  150. package/dist/testing/lazy.js +17 -0
  151. package/dist/testing/start-watch-processes.js +29 -0
  152. package/dist/testing/test-suite-setup.js +3 -0
  153. package/dist/utils/abort-event.js +14 -1
  154. package/dist/utils/abortable-function.js +71 -0
  155. package/dist/utils/debouncer.spec.js +8 -8
  156. package/dist/utils/environment-config.js +13 -0
  157. package/dist/utils/fail-never.js +1 -1
  158. package/dist/utils/sleep.spec.js +3 -3
  159. package/package.json +24 -21
  160. package/dist/console/get-console-context-mock.js +0 -33
  161. package/dist/executer/clean.js +0 -17
  162. package/dist/executer/execute-local.js +0 -59
  163. package/dist/executer/execute.js +0 -139
  164. package/dist/executer/execution-context-event.js +0 -3
  165. package/dist/executer/execution-context-mock.js +0 -3
  166. package/dist/executer/executor-mock.js +0 -61
  167. package/dist/executer/get-environment-mock.js +0 -16
  168. package/dist/executer/get-execution-context-mock.js +0 -18
  169. package/dist/executer/get-local-executor.js +0 -56
  170. package/dist/executer/restore.js +0 -19
  171. package/dist/executer/store.js +0 -19
  172. package/dist/logging/get-logger.js +0 -23
  173. package/dist/logging/message-to-console.js +0 -16
  174. package/dist/optimizer/optimize.js +0 -32
  175. package/dist/optimizer/work-node-description.js +0 -12
  176. package/dist/planner/utils/find-build-task.js +0 -18
  177. package/dist/testing/create-work-tree.js +0 -11
@@ -1,145 +1,162 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.planWorkNode = exports.getMergedBuildTask = void 0;
3
+ exports.getAbsolutePaths = exports.mapSource = exports.parseWorkNodeNeeds = exports.parseContainerWorkNodePorts = exports.mapLabels = exports.getWorkNode = exports.findBuildTask = exports.planTask = void 0;
4
+ const work_context_1 = require("../work-context");
4
5
  const template_value_1 = require("./template-value");
5
6
  const plan_work_command_1 = require("./plan-work-command");
6
7
  const split_name_1 = require("./split-name");
7
- const find_build_task_1 = require("./find-build-task");
8
8
  const parse_work_node_mount_1 = require("./parse-work-node-mount");
9
9
  const plan_work_dependency_1 = require("./plan-work-dependency");
10
10
  const path_1 = require("path");
11
- const work_node_status_1 = require("../work-node-status");
12
11
  const work_node_id_1 = require("../work-node-id");
13
12
  const parse_work_node_port_1 = require("./parse-work-node-port");
14
- function getMergedBuildTask(build, task) {
13
+ const work_service_id_1 = require("../work-service-id");
14
+ const os_1 = require("os");
15
+ const parse_work_service_volume_1 = require("./parse-work-service-volume");
16
+ const plan_work_volume_1 = require("./plan-work-volume");
17
+ const get_container_mounts_1 = require("./get-container-mounts");
18
+ function planTask(workContext, buildTaskResult) {
19
+ let extendedTask = null;
20
+ if (buildTaskResult.task.extend) {
21
+ extendedTask = findBuildTask(workContext, { taskName: buildTaskResult.task.extend });
22
+ if (extendedTask.task.extend) {
23
+ throw new Error(`nested extend ${extendedTask.name} is not allowed for task ${buildTaskResult.name}`);
24
+ }
25
+ }
15
26
  const envs = {
16
- ...build.envs,
17
- ...(task.envs || {}),
27
+ ...(extendedTask?.task?.envs || {}),
28
+ ...buildTaskResult.context.build.envs,
29
+ ...(buildTaskResult.task.envs || {}),
18
30
  };
19
- if (task.extend) {
20
- const extend = find_build_task_1.findBuildTask(build, task.extend);
21
- const extendEnvs = {
22
- ...extend.task.envs,
23
- ...envs,
24
- };
25
- return {
26
- task: {
27
- image: task.image || extend.task.image,
28
- envs: extendEnvs,
29
- ports: task.ports || extend.task.ports || [],
30
- cmds: task.cmds || extend.task.cmds || [],
31
- description: task.description || extend.task.description,
32
- shell: task.shell || extend.task.shell,
33
- continuous: task.continuous || extend.task.continuous || false,
34
- unknownProps: task.unknownProps,
35
- src: [...(extend.task.src || []), ...(task.src || [])],
36
- mounts: [...(extend.task.mounts || []), ...(task.mounts || [])],
37
- generates: [...(extend.task.generates || []), ...(task.generates || [])],
38
- },
39
- deps: [
40
- ...(extend.task.deps || []).map((d) => ({ name: d, build: extend.build })),
41
- ...(task.deps || []).map((d) => ({ name: d, build: build })),
42
- ],
43
- };
44
- }
45
- else {
46
- return {
47
- task: {
48
- image: task.image,
49
- src: task.src || [],
50
- cmds: task.cmds || [],
51
- continuous: task.continuous || false,
52
- generates: task.generates || [],
53
- description: task.description,
54
- shell: task.shell,
55
- ports: task.ports || [],
56
- unknownProps: task.unknownProps,
57
- mounts: task.mounts || [],
58
- envs,
59
- },
60
- deps: [...(task.deps || []).map((d) => ({ name: d, build: build }))],
61
- };
62
- }
63
- }
64
- exports.getMergedBuildTask = getMergedBuildTask;
65
- function planWorkNode(build, taskName, nodes, context) {
66
- if (build.tasks[taskName]) {
67
- const { task, deps } = getMergedBuildTask(build, build.tasks[taskName]);
68
- const id = work_node_id_1.getWorkNodeId(context.currentWorkdir, task, deps);
69
- if (nodes[id]) {
70
- return nodes[id];
31
+ const getReferences = (task, prop) => {
32
+ if (!task) {
33
+ return [];
71
34
  }
72
- const name = [...context.namePrefix, taskName].join(':');
73
- const node = parseWorkNode({
74
- envs: task.envs,
75
- id,
76
- continuous: task.continuous,
77
- description: template_value_1.templateValue(task.description, task.envs),
78
- name,
79
- cwd: context.currentWorkdir,
80
- cmds: parseWorkNodeCommand(task, context, task.envs),
81
- deps: [],
82
- unknownProps: task.unknownProps,
83
- buildFile: build,
84
- taskName: taskName,
85
- src: parseLocalWorkNodeSource(task, context, task.envs),
86
- generates: parseLocalWorkNodeGenerate(task, context, task.envs),
87
- mergedDeps: deps,
88
- mergedTask: task,
89
- status: {
90
- name,
91
- state: { type: 'pending', pendingDependencies: {} },
92
- defer: new AbortController(),
93
- console: work_node_status_1.nodeConsole(),
94
- },
95
- }, task, context);
96
- nodes[id] = node;
97
- const depNodes = deps.map((dep) => {
98
- const depName = template_value_1.templateValue(dep.name, dep.build.envs);
99
- const depNode = planWorkNode(dep.build, depName, nodes, {
100
- ...context,
101
- idPrefix: null,
102
- });
103
- if (!depNode) {
104
- throw new Error(`unable to find dependency ${dep} for task ${taskName} in ${dep.build.path}`);
105
- }
106
- return depNode;
107
- });
108
- plan_work_dependency_1.planWorkDependency(depNodes, node, taskName, nodes, context);
109
- return node;
35
+ const value = task.task[prop];
36
+ if (!value) {
37
+ return [];
38
+ }
39
+ return value.map((d) => ({
40
+ name: d,
41
+ build: buildTaskResult.context.build,
42
+ context: task.context,
43
+ }));
44
+ };
45
+ const mergeReferences = (first, second) => {
46
+ return [...first, ...second];
47
+ };
48
+ return {
49
+ buildTask: buildTaskResult.task,
50
+ build: buildTaskResult.context.build,
51
+ name: buildTaskResult.name,
52
+ cache: buildTaskResult.task.cache ?? extendedTask?.task?.cache ?? null,
53
+ description: buildTaskResult.task.description ?? extendedTask?.task?.description ?? null,
54
+ cwd: workContext.cwd,
55
+ image: buildTaskResult.task.image ?? extendedTask?.task?.image ?? null,
56
+ platform: buildTaskResult.task.platform ?? extendedTask?.task?.platform ?? null,
57
+ mounts: buildTaskResult.task.mounts || extendedTask?.task?.mounts || [],
58
+ generates: buildTaskResult.task.generates || extendedTask?.task?.generates || [],
59
+ shell: buildTaskResult.task.shell ?? extendedTask?.task?.shell ?? null,
60
+ ports: buildTaskResult.task.ports || extendedTask?.task?.ports || [],
61
+ src: buildTaskResult.task.src || extendedTask?.task?.src || [],
62
+ cmds: buildTaskResult.task.cmds || extendedTask?.task?.cmds || [],
63
+ continuous: buildTaskResult.task.continuous ?? extendedTask?.task?.continuous ?? false,
64
+ labels: {
65
+ ...(extendedTask?.task?.labels || {}),
66
+ ...(buildTaskResult.task.labels || {}),
67
+ },
68
+ envs,
69
+ deps: mergeReferences(getReferences(extendedTask, 'deps'), getReferences(buildTaskResult, 'deps')),
70
+ needs: mergeReferences(getReferences(extendedTask, 'needs'), getReferences(buildTaskResult, 'needs')),
71
+ };
72
+ }
73
+ exports.planTask = planTask;
74
+ function findBuildTask(context, selector) {
75
+ if (context.build.tasks[selector.taskName]) {
76
+ return { task: context.build.tasks[selector.taskName], context, name: selector.taskName };
110
77
  }
111
78
  else {
112
- const ref = split_name_1.splitName(taskName);
79
+ const ref = (0, split_name_1.splitName)(selector.taskName);
113
80
  if (ref.prefix) {
114
- if (build.references[ref.prefix]) {
115
- return planWorkNode(build.references[ref.prefix], ref.taskName, nodes, {
116
- ...context,
117
- currentWorkdir: build.references[ref.prefix].path,
118
- idPrefix: null,
119
- namePrefix: [...context.namePrefix, ref.prefix],
120
- });
81
+ if (context.build.references[ref.prefix]) {
82
+ return findBuildTask((0, work_context_1.createSubWorkContext)(context, {
83
+ name: ref.prefix,
84
+ type: 'references',
85
+ }), { taskName: ref.taskName });
121
86
  }
122
- else if (build.includes[ref.prefix]) {
123
- return planWorkNode(build.includes[ref.prefix], ref.taskName, nodes, {
124
- ...context,
125
- idPrefix: ref.prefix,
126
- namePrefix: [...context.namePrefix, ref.prefix],
87
+ else if (context.build.includes[ref.prefix]) {
88
+ return findBuildTask((0, work_context_1.createSubWorkContext)(context, {
89
+ name: ref.prefix,
90
+ type: 'includes',
91
+ }), {
92
+ taskName: ref.taskName,
127
93
  });
128
94
  }
129
95
  }
130
- throw new Error(`unable to find ${taskName} in ${build.path}`);
96
+ throw new Error(`unable to find ${selector.taskName} in ${context.build.path}`);
97
+ }
98
+ }
99
+ exports.findBuildTask = findBuildTask;
100
+ function getWorkNode(context, selector) {
101
+ const rootNode = findBuildTask(context, selector);
102
+ const plannedTask = planTask(rootNode.context, rootNode);
103
+ const id = (0, work_node_id_1.getWorkNodeId)(plannedTask);
104
+ if (context.workTree.nodes[id]) {
105
+ return context.workTree.nodes[id];
106
+ }
107
+ const node = parseWorkNode(id, plannedTask, rootNode.context);
108
+ context.workTree.nodes[id] = node;
109
+ const depNodes = [];
110
+ for (const plannedDep of plannedTask.deps) {
111
+ const depName = (0, template_value_1.templateValue)(plannedDep.name, plannedDep.build.envs);
112
+ const depNode = getWorkNode(plannedDep.context, { taskName: depName });
113
+ if (!depNodes.some((d) => d.id === depNode.id)) {
114
+ depNodes.push(depNode);
115
+ }
131
116
  }
117
+ (0, plan_work_dependency_1.planWorkDependency)(depNodes, node);
118
+ return node;
132
119
  }
133
- exports.planWorkNode = planWorkNode;
134
- function parseWorkNode(baseWorkNode, task, context) {
120
+ exports.getWorkNode = getWorkNode;
121
+ function mapLabels(labels) {
122
+ const result = {};
123
+ for (const [key, value] of Object.entries(labels)) {
124
+ result[key] = [value];
125
+ }
126
+ return result;
127
+ }
128
+ exports.mapLabels = mapLabels;
129
+ function parseWorkNode(id, task, context) {
130
+ const name = [...context.namePrefix, task.name].join(':');
131
+ const baseWorkNode = {
132
+ envs: task.envs,
133
+ id,
134
+ description: (0, template_value_1.templateValue)(task.description, task.envs),
135
+ continuous: task.continuous,
136
+ name,
137
+ cwd: task.cwd,
138
+ cmds: parseWorkNodeCommand(task, context, task.envs),
139
+ deps: [],
140
+ buildFile: task.build,
141
+ taskName: task.name,
142
+ src: parseLocalWorkNodeSource(task, context, task.envs),
143
+ generates: parseLocalWorkNodeGenerate(task, context, task.envs),
144
+ plannedTask: task,
145
+ needs: parseWorkNodeNeeds(task.needs, context),
146
+ labels: mapLabels(task.labels),
147
+ caching: task.cache ?? null,
148
+ };
135
149
  if (task.image) {
150
+ const mounts = parseContainerWorkNodeMount(task, context, task.envs);
136
151
  return {
137
152
  ...baseWorkNode,
138
153
  type: 'container',
139
- image: template_value_1.templateValue(task.image, task.envs),
140
- shell: template_value_1.templateValue(task.shell, task.envs) || '/bin/sh',
141
- mounts: parseContainerWorkNodeMount(task, context, task.envs),
154
+ user: getContainerUser(),
155
+ image: (0, template_value_1.templateValue)(task.image, task.envs),
156
+ shell: (0, template_value_1.templateValue)(task.shell, task.envs) || '/bin/sh',
157
+ mounts: (0, get_container_mounts_1.getContainerMounts)(baseWorkNode, mounts),
142
158
  ports: parseContainerWorkNodePorts(task, context, task.envs),
159
+ volumes: (0, plan_work_volume_1.getContainerVolumes)(baseWorkNode),
143
160
  };
144
161
  }
145
162
  else {
@@ -150,48 +167,106 @@ function parseWorkNode(baseWorkNode, task, context) {
150
167
  }
151
168
  }
152
169
  function parseContainerWorkNodePorts(task, context, envs) {
153
- return task.ports.map((m) => template_value_1.templateValue(m, envs)).map((m) => parse_work_node_port_1.parseWorkNodePort(m));
170
+ return task.ports.map((m) => (0, template_value_1.templateValue)(m, envs)).map((m) => (0, parse_work_node_port_1.parseWorkNodePort)(m));
154
171
  }
172
+ exports.parseContainerWorkNodePorts = parseContainerWorkNodePorts;
155
173
  function parseContainerWorkNodeMount(task, context, envs) {
156
- return task.mounts.map((m) => template_value_1.templateValue(m, envs)).map((m) => parse_work_node_mount_1.parseWorkNodeMount(context.currentWorkdir, m));
174
+ return task.mounts.map((m) => (0, template_value_1.templateValue)(m, envs)).map((m) => (0, parse_work_node_mount_1.parseWorkNodeMount)(context.cwd, m));
157
175
  }
158
176
  function parseLocalWorkNodeGenerate(task, context, envs) {
159
- return getAbsolutePaths(task.generates, context.currentWorkdir)
160
- .map((g) => template_value_1.templateValue(g, envs))
177
+ return getAbsolutePaths(task.generates, context.cwd)
178
+ .map((g) => (0, template_value_1.templateValue)(g, envs))
161
179
  .map((path) => ({ path, inherited: false }));
162
180
  }
163
181
  function parseLocalWorkNodeSource(task, context, envs) {
164
182
  return task.src
165
183
  .map((src) => ({
166
- relativePath: template_value_1.templateValue(src.relativePath, envs),
184
+ relativePath: (0, template_value_1.templateValue)(src.relativePath, envs),
167
185
  matcher: src.matcher,
168
186
  }))
169
- .map((src) => mapSource(src, context.currentWorkdir));
187
+ .map((src) => mapSource(src, context.cwd));
188
+ }
189
+ function getContainerUser() {
190
+ return (0, os_1.platform)() === 'linux' || (0, os_1.platform)() === 'freebsd' || (0, os_1.platform)() === 'openbsd' || (0, os_1.platform)() === 'sunos'
191
+ ? `${process.getuid()}:${process.getgid()}`
192
+ : null;
193
+ }
194
+ function parseWorkNodeNeeds(needs, context) {
195
+ const result = [];
196
+ for (const need of needs) {
197
+ const service = need.build.services[need.name];
198
+ const id = (0, work_service_id_1.getWorkServiceId)(need.build, service);
199
+ if (!context.workTree.services[id]) {
200
+ const workService = {
201
+ id,
202
+ buildService: service,
203
+ name: need.name,
204
+ description: service.description,
205
+ ports: (service.ports || []).map((m) => (0, template_value_1.templateValue)(m, service.envs)).map((m) => (0, parse_work_node_port_1.parseWorkNodePort)(m)),
206
+ };
207
+ if (service.image) {
208
+ context.workTree.services[id] = {
209
+ ...workService,
210
+ type: 'container-service',
211
+ cmd: service.cmd,
212
+ envs: service.envs || {},
213
+ image: service.image,
214
+ // user: getContainerUser(),
215
+ healthcheck: service.healthcheck,
216
+ mounts: (service.mounts || [])
217
+ .map((m) => (0, template_value_1.templateValue)(m, service.envs))
218
+ .map((m) => (0, parse_work_node_mount_1.parseWorkNodeMount)(need.build.path, m)),
219
+ volumes: (service.volumes || [])
220
+ .map((m) => (0, template_value_1.templateValue)(m, service.envs))
221
+ .map((m) => (0, parse_work_service_volume_1.parseWorkServiceVolume)(need.build.path, m)),
222
+ };
223
+ }
224
+ else if (!!service.context && !!service.selector) {
225
+ context.workTree.services[id] = {
226
+ ...workService,
227
+ context: service.context,
228
+ selector: service.selector,
229
+ kubeconfig: service.kubeconfig ?? getDefaultKubeConfig(),
230
+ type: 'kubernetes-service',
231
+ };
232
+ }
233
+ }
234
+ if (!result.some((s) => s.id === id)) {
235
+ result.push(context.workTree.services[id]);
236
+ }
237
+ }
238
+ return result;
239
+ }
240
+ exports.parseWorkNodeNeeds = parseWorkNodeNeeds;
241
+ function getDefaultKubeConfig() {
242
+ return (0, path_1.join)((0, os_1.homedir)(), '.kube/config');
170
243
  }
171
244
  function parseWorkNodeCommand(task, context, envs) {
172
- return plan_work_command_1.planWorkCommand(task.cmds.map((cmd) => {
245
+ return (0, plan_work_command_1.planWorkCommand)(task.cmds.map((cmd) => {
173
246
  if (typeof cmd === 'string') {
174
- return template_value_1.templateValue(cmd, envs);
247
+ return (0, template_value_1.templateValue)(cmd, envs);
175
248
  }
176
249
  else {
177
250
  return {
178
- cmd: template_value_1.templateValue(cmd.cmd, envs),
179
- path: template_value_1.templateValue(cmd.path, envs),
251
+ cmd: (0, template_value_1.templateValue)(cmd.cmd, envs),
252
+ path: (0, template_value_1.templateValue)(cmd.path, envs),
180
253
  type: cmd.type,
181
254
  };
182
255
  }
183
- }), context.currentWorkdir);
256
+ }), context.cwd);
184
257
  }
185
258
  function mapSource(src, workDir) {
186
259
  return {
187
260
  matcher: src.matcher,
188
- absolutePath: path_1.join(workDir, src.relativePath),
261
+ absolutePath: (0, path_1.join)(workDir, src.relativePath),
189
262
  };
190
263
  }
264
+ exports.mapSource = mapSource;
191
265
  function getAbsolutePaths(dirs, workingDir) {
192
266
  if (!dirs) {
193
267
  return [];
194
268
  }
195
- return dirs.map((dir) => path_1.join(workingDir, dir));
269
+ return dirs.map((dir) => (0, path_1.join)(workingDir, dir));
196
270
  }
271
+ exports.getAbsolutePaths = getAbsolutePaths;
197
272
  //# sourceMappingURL=plan-work-node.js.map
@@ -1,13 +1,58 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.iterateWorkNodes = exports.planWorkNodes = void 0;
3
+ exports.iterateWorkNodes = exports.iterateWorkServices = exports.planWorkNodes = void 0;
4
4
  const plan_work_node_1 = require("./plan-work-node");
5
- function planWorkNodes(build) {
6
- const nodes = {};
7
- addWorkNodes(build, nodes, [], []);
8
- return nodes;
5
+ const work_context_1 = require("../work-context");
6
+ const label_values_1 = require("../../executer/label-values");
7
+ function planWorkNodes(build, options) {
8
+ const context = (0, work_context_1.createWorkContext)(build);
9
+ addWorkNodes(context, []);
10
+ const nodesIdsToRemove = [];
11
+ for (const [nodeId, node] of Object.entries(context.workTree.nodes)) {
12
+ if (!(0, label_values_1.matchesAllLabels)(options.filterLabels, node, context.workTree.nodes) ||
13
+ (0, label_values_1.matchesAnyLabel)(options.excludeLabels, node)) {
14
+ nodesIdsToRemove.push(nodeId);
15
+ }
16
+ }
17
+ for (const nodeId of nodesIdsToRemove) {
18
+ removeNode(nodeId, context.workTree);
19
+ }
20
+ removeUnusedServices(context.workTree);
21
+ return context.workTree;
9
22
  }
10
23
  exports.planWorkNodes = planWorkNodes;
24
+ function removeUnusedServices(workTree) {
25
+ const needs = new Set();
26
+ for (const node of Object.values(workTree.nodes)) {
27
+ for (const need of node.needs) {
28
+ needs.add(need.id);
29
+ }
30
+ }
31
+ const services = Object.values(workTree.services);
32
+ for (const service of services) {
33
+ if (!needs.has(service.id)) {
34
+ delete workTree.services[service.id];
35
+ }
36
+ }
37
+ }
38
+ function removeNode(nodeId, workTree) {
39
+ const node = workTree.nodes[nodeId];
40
+ if (node) {
41
+ delete workTree.nodes[nodeId];
42
+ for (const node of Object.values(workTree.nodes)) {
43
+ if (node.deps.some((d) => d.id === nodeId)) {
44
+ removeNode(node.id, workTree);
45
+ }
46
+ }
47
+ }
48
+ }
49
+ function* iterateWorkServices(services) {
50
+ for (const serviceId of Object.keys(services)) {
51
+ const service = services[serviceId];
52
+ yield service;
53
+ }
54
+ }
55
+ exports.iterateWorkServices = iterateWorkServices;
11
56
  function* iterateWorkNodes(nodes) {
12
57
  for (const nodeId of Object.keys(nodes)) {
13
58
  const node = nodes[nodeId];
@@ -15,19 +60,19 @@ function* iterateWorkNodes(nodes) {
15
60
  }
16
61
  }
17
62
  exports.iterateWorkNodes = iterateWorkNodes;
18
- function addWorkNodes(build, nodes, files, namePrefix) {
19
- if (files.indexOf(build.fileName) !== -1) {
63
+ function addWorkNodes(context, files) {
64
+ if (files.indexOf(context.build.fileName) !== -1) {
20
65
  return;
21
66
  }
22
- files.push(build.fileName);
23
- for (const taskId of Object.keys(build.tasks)) {
24
- plan_work_node_1.planWorkNode(build, taskId, nodes, { currentWorkdir: build.path, idPrefix: null, namePrefix: namePrefix });
67
+ files.push(context.build.fileName);
68
+ for (const taskName of Object.keys(context.build.tasks)) {
69
+ (0, plan_work_node_1.getWorkNode)(context, { taskName });
25
70
  }
26
- for (const key of Object.keys(build.references)) {
27
- addWorkNodes(build.references[key], nodes, files, [...namePrefix, key]);
71
+ for (const name of Object.keys(context.build.references)) {
72
+ addWorkNodes((0, work_context_1.createSubWorkContext)(context, { type: 'references', name }), files);
28
73
  }
29
- for (const key of Object.keys(build.includes)) {
30
- addWorkNodes(build.includes[key], nodes, files, [...namePrefix, key]);
74
+ for (const name of Object.keys(context.build.includes)) {
75
+ addWorkNodes((0, work_context_1.createSubWorkContext)(context, { type: 'includes', name }), files);
31
76
  }
32
77
  }
33
78
  //# sourceMappingURL=plan-work-nodes.js.map
@@ -2,10 +2,14 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.planWorkTree = void 0;
4
4
  const plan_work_node_1 = require("./plan-work-node");
5
- function planWorkTree(build, taskName) {
6
- const nodes = {};
7
- const rootNode = plan_work_node_1.planWorkNode(build, taskName, nodes, { currentWorkdir: build.path, idPrefix: null, namePrefix: [] });
8
- return { nodes, rootNode };
5
+ const work_context_1 = require("../work-context");
6
+ function planWorkTree(build, options) {
7
+ const context = (0, work_context_1.createWorkContext)(build);
8
+ const result = (0, plan_work_node_1.getWorkNode)(context, { taskName: options.taskName });
9
+ return {
10
+ ...context.workTree,
11
+ rootNode: result,
12
+ };
9
13
  }
10
14
  exports.planWorkTree = planWorkTree;
11
15
  //# sourceMappingURL=plan-work-tree.js.map
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getContainerVolumes = exports.getVolumeName = exports.generateId = void 0;
4
+ const crypto_1 = require("crypto");
5
+ function generateId(generate) {
6
+ return (0, crypto_1.createHash)('sha1').update(generate).digest('hex');
7
+ }
8
+ exports.generateId = generateId;
9
+ function getVolumeName(generate) {
10
+ return `hammerkit-${generateId(generate)}`;
11
+ }
12
+ exports.getVolumeName = getVolumeName;
13
+ function getContainerVolumes(task) {
14
+ const volumes = [];
15
+ for (const generate of task.generates) {
16
+ const name = getVolumeName(generate.path);
17
+ volumes.push({
18
+ name,
19
+ containerPath: generate.path,
20
+ });
21
+ }
22
+ return volumes;
23
+ }
24
+ exports.getContainerVolumes = getContainerVolumes;
25
+ //# sourceMappingURL=plan-work-volume.js.map
@@ -1,13 +1,52 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.validate = void 0;
4
- const plan_work_nodes_1 = require("../planner/utils/plan-work-nodes");
5
- const plan_work_tree_1 = require("../planner/utils/plan-work-tree");
6
- async function* validate(buildFile, context, name) {
7
- const tree = name ? plan_work_tree_1.planWorkTree(buildFile, name).nodes : plan_work_nodes_1.planWorkNodes(buildFile);
3
+ exports.checkIfContextExists = exports.hasCycle = exports.validate = void 0;
4
+ const read_build_file_1 = require("../parser/read-build-file");
5
+ async function* validate(workTree, context) {
8
6
  const cycleNodes = [];
9
- for (const key of Object.keys(tree)) {
10
- const node = tree[key];
7
+ for (const service of Object.values(workTree.services)) {
8
+ if (!service.description) {
9
+ yield { type: 'warn', message: `missing description`, node: service };
10
+ }
11
+ if (service.type === 'container-service') {
12
+ if (!service.healthcheck) {
13
+ yield { type: 'warn', message: 'missing healthcheck', node: service };
14
+ }
15
+ for (const mount of service.mounts) {
16
+ if (!(await context.file.exists(mount.localPath))) {
17
+ yield {
18
+ type: 'warn',
19
+ message: `mount ${mount.localPath} does not exist`,
20
+ node: service,
21
+ };
22
+ }
23
+ }
24
+ }
25
+ else {
26
+ if (!(await context.file.exists(service.kubeconfig))) {
27
+ yield {
28
+ type: 'warn',
29
+ message: `kubeconfig ${service.kubeconfig} does not exist`,
30
+ node: service,
31
+ };
32
+ }
33
+ else if (!(await checkIfContextExists(service, context))) {
34
+ yield {
35
+ type: 'warn',
36
+ message: `context ${service.context} does not exist in kubeconfig ${service.kubeconfig}`,
37
+ node: service,
38
+ };
39
+ }
40
+ }
41
+ for (const key of Object.keys(service.buildService.unknownProps)) {
42
+ yield {
43
+ type: 'warn',
44
+ message: `${key} is an unknown configuration`,
45
+ node: service,
46
+ };
47
+ }
48
+ }
49
+ for (const node of Object.values(workTree.nodes)) {
11
50
  if (!node.description) {
12
51
  yield { type: 'warn', message: `missing description`, node: node };
13
52
  }
@@ -23,7 +62,7 @@ async function* validate(buildFile, context, name) {
23
62
  };
24
63
  }
25
64
  }
26
- for (const key of Object.keys(node.unknownProps)) {
65
+ for (const key of Object.keys(node.plannedTask.buildTask.unknownProps)) {
27
66
  yield {
28
67
  type: 'warn',
29
68
  message: `${key} is an unknown configuration`,
@@ -52,4 +91,13 @@ function hasCycle(node, currentPath) {
52
91
  }
53
92
  return null;
54
93
  }
94
+ exports.hasCycle = hasCycle;
95
+ async function checkIfContextExists(service, context) {
96
+ const kubeconfig = await (0, read_build_file_1.read)(service.kubeconfig, context);
97
+ if (kubeconfig.contexts && kubeconfig.contexts instanceof Array) {
98
+ return kubeconfig.contexts.some((c) => c['name'] === service.context);
99
+ }
100
+ return false;
101
+ }
102
+ exports.checkIfContextExists = checkIfContextExists;
55
103
  //# sourceMappingURL=validate.js.map
@@ -1,3 +1,23 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createSubWorkContext = exports.createWorkContext = void 0;
4
+ function createWorkContext(build) {
5
+ return {
6
+ cwd: build.path,
7
+ namePrefix: [],
8
+ build,
9
+ workTree: { nodes: {}, services: {} },
10
+ };
11
+ }
12
+ exports.createWorkContext = createWorkContext;
13
+ function createSubWorkContext(context, options) {
14
+ const subBuildFile = context.build[options.type][options.name];
15
+ return {
16
+ build: subBuildFile,
17
+ workTree: context.workTree,
18
+ cwd: options.type === 'references' ? subBuildFile.path : context.cwd,
19
+ namePrefix: [...context.namePrefix, options.name],
20
+ };
21
+ }
22
+ exports.createSubWorkContext = createSubWorkContext;
3
23
  //# sourceMappingURL=work-context.js.map
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=work-mount.js.map