@catladder/pipeline 1.170.1 → 2.0.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 (192) hide show
  1. package/dist/bash/BashExpression.d.ts +1 -6
  2. package/dist/bash/BashExpression.js +2 -15
  3. package/dist/bash/bashEscape.d.ts +34 -0
  4. package/dist/bash/bashEscape.js +114 -0
  5. package/dist/bash/bashYaml.js +25 -2
  6. package/dist/bash/getInjectVarsScript.js +4 -2
  7. package/dist/bash/index.d.ts +2 -0
  8. package/dist/bash/index.js +26 -0
  9. package/dist/build/base/createAppBuildJob.js +3 -3
  10. package/dist/build/base/writeDotEnv.js +6 -4
  11. package/dist/build/custom/testJob.js +12 -12
  12. package/dist/build/docker.d.ts +3 -3
  13. package/dist/build/node/buildJob.js +1 -1
  14. package/dist/build/node/cache.d.ts +2 -4
  15. package/dist/build/node/cache.js +3 -24
  16. package/dist/build/node/testJob.js +11 -11
  17. package/dist/build/rails/build.js +1 -1
  18. package/dist/build/rails/test.js +8 -8
  19. package/dist/build/types.d.ts +0 -10
  20. package/dist/constants.js +1 -1
  21. package/dist/context/createComponentContext.js +0 -1
  22. package/dist/context/getEnvConfig.js +2 -1
  23. package/dist/context/getEnvironment.js +1 -2
  24. package/dist/context/getEnvironmentVariables.d.ts +5 -6
  25. package/dist/context/getEnvironmentVariables.js +50 -38
  26. package/dist/deploy/base/deploy.js +3 -3
  27. package/dist/deploy/cloudRun/createJobs/getCloudRunDeployScripts.js +2 -2
  28. package/dist/deploy/cloudRun/index.js +2 -2
  29. package/dist/deploy/cloudRun/utils/getServiceName.d.ts +1 -1
  30. package/dist/deploy/kubernetes/cloudSql/index.d.ts +2 -2
  31. package/dist/deploy/kubernetes/cloudSql/index.js +3 -14
  32. package/dist/deploy/kubernetes/deployJob.js +1 -3
  33. package/dist/deploy/kubernetes/index.js +2 -2
  34. package/dist/deploy/kubernetes/kubeEnv.d.ts +3 -3
  35. package/dist/deploy/kubernetes/kubeValues.d.ts +3 -4
  36. package/dist/deploy/kubernetes/kubeValues.js +2 -3
  37. package/dist/deploy/types/base.d.ts +0 -6
  38. package/dist/deploy/types/kubernetes.d.ts +1 -34
  39. package/dist/globalScriptFunctions/index.d.ts +14 -0
  40. package/dist/globalScriptFunctions/index.js +37 -0
  41. package/dist/index.d.ts +3 -1
  42. package/dist/index.js +3 -1
  43. package/dist/pipeline/gitlab/createGitlabJobs.js +3 -5
  44. package/dist/pipeline/gitlab/createGitlabPipeline.d.ts +1 -0
  45. package/dist/pipeline/gitlab/createGitlabPipeline.js +38 -2
  46. package/dist/pipeline/packageManager.js +1 -1
  47. package/dist/runner/index.d.ts +1 -1
  48. package/dist/tsconfig.tsbuildinfo +1 -1
  49. package/dist/types/config.d.ts +6 -9
  50. package/dist/types/context.d.ts +2 -9
  51. package/dist/types/gitlab-types.d.ts +1 -0
  52. package/dist/types/jobs.d.ts +0 -8
  53. package/dist/utils/gitlab.js +4 -1
  54. package/dist/utils/writeFiles.js +1 -7
  55. package/dist/variables/VariableValue.d.ts +3 -0
  56. package/dist/variables/VariableValue.js +5 -0
  57. package/dist/variables/VariableValueContainingReferences.d.ts +24 -0
  58. package/dist/variables/VariableValueContainingReferences.js +97 -0
  59. package/dist/variables/__tests__/resolveAllReferences.test.js +219 -0
  60. package/dist/variables/__tests__/resolveAllReferencesOnce.test.d.ts +1 -0
  61. package/dist/variables/__tests__/resolveAllReferencesOnce.test.js +171 -0
  62. package/dist/variables/__tests__/resolveReferencesOnce.test.d.ts +1 -0
  63. package/dist/variables/__tests__/resolveReferencesOnce.test.js +202 -0
  64. package/dist/variables/__tests__/variableValue.test.d.ts +1 -0
  65. package/dist/variables/__tests__/variableValue.test.js +36 -0
  66. package/dist/variables/resolveAllReferences.d.ts +3 -0
  67. package/dist/{bash/replaceAsync.js → variables/resolveAllReferences.js} +60 -40
  68. package/dist/variables/resolveAllReferencesOnce.d.ts +5 -0
  69. package/dist/variables/resolveAllReferencesOnce.js +191 -0
  70. package/dist/variables/resolveReferencesOnce.d.ts +8 -0
  71. package/dist/variables/resolveReferencesOnce.js +22 -0
  72. package/examples/__snapshots__/cloud-run-http2.test.ts.snap +312 -238
  73. package/examples/__snapshots__/cloud-run-memory-limit.test.ts.snap +312 -238
  74. package/examples/__snapshots__/cloud-run-meteor-with-worker.test.ts.snap +312 -222
  75. package/examples/__snapshots__/cloud-run-nextjs.test.ts.snap +1436 -0
  76. package/examples/__snapshots__/cloud-run-no-cpu-throttling.test.ts.snap +312 -238
  77. package/examples/__snapshots__/cloud-run-no-service.test.ts.snap +316 -238
  78. package/examples/__snapshots__/cloud-run-non-public.test.ts.snap +312 -238
  79. package/examples/__snapshots__/cloud-run-post-stop-job.test.ts.snap +313 -238
  80. package/examples/__snapshots__/cloud-run-service-custom-vpc-connector.test.ts.snap +312 -238
  81. package/examples/__snapshots__/cloud-run-service-custom-vpc.test.ts.snap +312 -238
  82. package/examples/__snapshots__/cloud-run-service-gen2.test.ts.snap +312 -238
  83. package/examples/__snapshots__/cloud-run-service-increase-timout.test.ts.snap +312 -238
  84. package/examples/__snapshots__/cloud-run-service-with-volumes.test.ts.snap +316 -238
  85. package/examples/__snapshots__/cloud-run-storybook.test.ts.snap +294 -220
  86. package/examples/__snapshots__/cloud-run-with-ngnix.test.ts.snap +312 -238
  87. package/examples/__snapshots__/cloud-run-with-sql-reuse-db.test.ts.snap +652 -486
  88. package/examples/__snapshots__/cloud-run-with-sql.test.ts.snap +282 -288
  89. package/examples/__snapshots__/cloud-run-with-worker.test.ts.snap +312 -238
  90. package/examples/__snapshots__/custom-build-job-with-tests.test.ts.snap +284 -194
  91. package/examples/__snapshots__/custom-build-job.test.ts.snap +278 -188
  92. package/examples/__snapshots__/custom-deploy.test.ts.snap +220 -154
  93. package/examples/__snapshots__/custom-envs.test.ts.snap +216 -126
  94. package/examples/__snapshots__/custom-sbom-java.test.ts.snap +278 -188
  95. package/examples/__snapshots__/git-submodule.test.ts.snap +312 -238
  96. package/examples/__snapshots__/kubernetes-application-customization.test.ts.snap +231 -253
  97. package/examples/__snapshots__/kubernetes-with-cloud-sql.test.ts.snap +240 -262
  98. package/examples/__snapshots__/kubernetes-with-jobs.test.ts.snap +504 -506
  99. package/examples/__snapshots__/kubernetes-with-mongodb.test.ts.snap +239 -261
  100. package/examples/__snapshots__/local-dot-env.test.ts.snap +236 -238
  101. package/examples/__snapshots__/meteor-kubernetes.test.ts.snap +236 -242
  102. package/examples/__snapshots__/multiline-var.test.ts.snap +1355 -973
  103. package/examples/__snapshots__/native-app.test.ts.snap +438 -392
  104. package/examples/__snapshots__/node-build-with-custom-image.test.ts.snap +312 -238
  105. package/examples/__snapshots__/node-build-with-docker-additions.test.ts.snap +312 -238
  106. package/examples/__snapshots__/rails-k8s-with-worker-dockerfile.test.ts.snap +186 -188
  107. package/examples/__snapshots__/rails-k8s-with-worker.test.ts.snap +162 -164
  108. package/examples/__snapshots__/referencing-other-vars.test.ts.snap +971 -765
  109. package/examples/__snapshots__/wait-for-other-deploy.test.ts.snap +330 -228
  110. package/examples/__snapshots__/{workspace-api-www-custom-cache.test.ts.snap → workspace-api-www-turbo-cache.test.ts.snap} +457 -499
  111. package/examples/__snapshots__/workspace-api-www.test.ts.snap +452 -482
  112. package/examples/{workspace-api-www-custom-cache.test.ts → cloud-run-nextjs.test.ts} +2 -2
  113. package/examples/cloud-run-nextjs.ts +28 -0
  114. package/examples/cloud-run-with-sql.ts +0 -1
  115. package/examples/kubernetes-application-customization.ts +1 -0
  116. package/examples/kubernetes-with-cloud-sql.ts +1 -0
  117. package/examples/kubernetes-with-jobs.ts +1 -0
  118. package/examples/kubernetes-with-mongodb.ts +1 -0
  119. package/examples/meteor-kubernetes.ts +1 -1
  120. package/examples/native-app.ts +10 -7
  121. package/examples/rails-k8s-with-worker.ts +7 -1
  122. package/examples/{kubernetes-with-cloud-sql-legacy.test.ts → workspace-api-www-turbo-cache.test.ts} +2 -2
  123. package/examples/{workspace-api-www-custom-cache.ts → workspace-api-www-turbo-cache.ts} +4 -3
  124. package/examples/workspace-api-www.ts +3 -2
  125. package/package.json +2 -6
  126. package/src/bash/BashExpression.ts +0 -13
  127. package/src/bash/bashEscape.ts +158 -0
  128. package/src/bash/bashYaml.ts +36 -2
  129. package/src/bash/getInjectVarsScript.ts +11 -2
  130. package/src/bash/index.ts +2 -0
  131. package/src/build/base/createAppBuildJob.ts +0 -1
  132. package/src/build/base/writeDotEnv.ts +6 -6
  133. package/src/build/custom/testJob.ts +0 -1
  134. package/src/build/node/buildJob.ts +2 -2
  135. package/src/build/node/cache.ts +0 -29
  136. package/src/build/node/testJob.ts +0 -1
  137. package/src/build/rails/build.ts +0 -1
  138. package/src/build/rails/test.ts +0 -1
  139. package/src/build/types.ts +0 -13
  140. package/src/context/createComponentContext.ts +0 -1
  141. package/src/context/getEnvConfig.ts +2 -2
  142. package/src/context/getEnvironment.ts +1 -1
  143. package/src/context/getEnvironmentContext.ts +1 -1
  144. package/src/context/getEnvironmentVariables.ts +44 -51
  145. package/src/deploy/base/deploy.ts +1 -1
  146. package/src/deploy/cloudRun/createJobs/getCloudRunDeployScripts.ts +4 -12
  147. package/src/deploy/cloudRun/index.ts +2 -2
  148. package/src/deploy/kubernetes/cloudSql/index.ts +3 -16
  149. package/src/deploy/kubernetes/deployJob.ts +0 -2
  150. package/src/deploy/kubernetes/index.ts +2 -2
  151. package/src/deploy/kubernetes/kubeEnv.ts +3 -3
  152. package/src/deploy/kubernetes/kubeValues.ts +5 -8
  153. package/src/deploy/types/base.ts +0 -6
  154. package/src/deploy/types/kubernetes.ts +1 -36
  155. package/src/globalScriptFunctions/index.ts +30 -0
  156. package/src/index.ts +2 -0
  157. package/src/pipeline/gitlab/createGitlabJobs.ts +1 -4
  158. package/src/pipeline/gitlab/createGitlabPipeline.ts +8 -1
  159. package/src/pipeline/packageManager.ts +7 -5
  160. package/src/runner/index.ts +0 -1
  161. package/src/types/config.ts +6 -9
  162. package/src/types/context.ts +3 -9
  163. package/src/types/gitlab-types.ts +1 -0
  164. package/src/types/jobs.ts +0 -8
  165. package/src/utils/gitlab.ts +19 -2
  166. package/src/utils/writeFiles.ts +1 -2
  167. package/src/variables/VariableValue.ts +6 -0
  168. package/src/variables/VariableValueContainingReferences.ts +89 -0
  169. package/src/variables/__tests__/resolveAllReferences.test.ts +110 -0
  170. package/src/variables/__tests__/resolveAllReferencesOnce.test.ts +64 -0
  171. package/src/variables/__tests__/resolveReferencesOnce.test.ts +117 -0
  172. package/src/variables/__tests__/variableValue.test.ts +73 -0
  173. package/src/variables/resolveAllReferences.ts +46 -0
  174. package/src/variables/resolveAllReferencesOnce.ts +44 -0
  175. package/src/variables/resolveReferencesOnce.ts +29 -0
  176. package/bin/catladder-gitlab-dev.js +0 -3
  177. package/bin/catladder-gitlab.js +0 -3
  178. package/dist/bash/replaceAsync.d.ts +0 -2
  179. package/dist/bundles/catladder-gitlab/index.js +0 -15
  180. package/dist/context/__tests__/resolveReferences.test.js +0 -368
  181. package/dist/context/resolveReferences.d.ts +0 -6
  182. package/dist/context/resolveReferences.js +0 -286
  183. package/dist/deploy/kubernetes/processSecretsAsFiles.d.ts +0 -85
  184. package/dist/deploy/kubernetes/processSecretsAsFiles.js +0 -33
  185. package/examples/__snapshots__/kubernetes-with-cloud-sql-legacy.test.ts.snap +0 -1795
  186. package/examples/kubernetes-with-cloud-sql-legacy.ts +0 -35
  187. package/scripts/bundle +0 -2
  188. package/src/bash/replaceAsync.ts +0 -49
  189. package/src/context/__tests__/resolveReferences.test.ts +0 -148
  190. package/src/context/resolveReferences.ts +0 -93
  191. package/src/deploy/kubernetes/processSecretsAsFiles.ts +0 -35
  192. /package/dist/{context/__tests__/resolveReferences.test.d.ts → variables/__tests__/resolveAllReferences.test.d.ts} +0 -0
@@ -66,4 +66,5 @@ export interface GitlabPipeline extends Pick<JobTemplate, "variables"> {
66
66
  };
67
67
  stages: string[];
68
68
  jobs: Record<string, GitlabJobDef>;
69
+ before_script?: string[];
69
70
  }
package/src/types/jobs.ts CHANGED
@@ -70,14 +70,6 @@ export type CatladderJob<S = BaseStage> = {
70
70
  */
71
71
  needs?: Array<CatladderJobNeed>;
72
72
 
73
- /**
74
- * @deprecated set `componentName` to `needs` if you want to wait for a job from another component
75
- */
76
- needsOtherComponent?: Array<{
77
- componentName: string;
78
- job: string;
79
- artifacts: boolean;
80
- }>;
81
73
  /**
82
74
  * cache config, we use here the same shape as gitlab itself
83
75
  */
@@ -1,3 +1,5 @@
1
+ import { registerGlobalScriptFunction } from "../globalScriptFunctions";
2
+
1
3
  export const allowFailureInScripts = (script: string[]): string[] => [
2
4
  "set +e", // disable fail job on error
3
5
  ...script,
@@ -22,12 +24,27 @@ export const repeatOnFailure = (
22
24
  `;
23
25
  };
24
26
 
27
+ const start = registerGlobalScriptFunction(
28
+ "collapseable_section_start",
29
+ `local section_title="\${1}"
30
+ local section_description="\${2:-$section_title}"
31
+ echo -e "section_start:\`date +%s\`:\${section_title}[collapsed=true]\\r\\e[0K$\{section_description}"
32
+ `,
33
+ );
34
+
35
+ const end = registerGlobalScriptFunction(
36
+ "collapseable_section_end",
37
+ `local section_title="\${1}"
38
+ echo -e "section_end:\`date +%s\`:\${section_title}\\r\\e[0K"
39
+ `,
40
+ );
41
+
25
42
  export const collapseableSection =
26
43
  (name: string, header: string) =>
27
44
  (commands: string[]): string[] => {
28
45
  return [
29
- `echo -e "\\e[0Ksection_start:$(date +%s):${name}[collapsed=true]\\r\\e[0K${header}"`,
46
+ start.invoke(`"${name}"`, `"${header}"`),
30
47
  ...commands,
31
- `echo -e "\\e[0Ksection_end:$(date +%s):${name}\\r\\e[0K"`,
48
+ end.invoke(`"${name}"`),
32
49
  ];
33
50
  };
@@ -1,11 +1,10 @@
1
1
  import { writeFile } from "fs/promises";
2
2
  import { stringify } from "yaml";
3
- import packageInfos from "../packageInfos";
4
3
 
5
4
  export const getAutoGeneratedHeader = (commentChar: string) => {
6
5
  return [
7
6
  "-------------------------------------------------",
8
- `🐱 🔨 This file is generated by catladder v${packageInfos.version}`,
7
+ `🐱 🔨 This file is generated by catladder`,
9
8
  `🚨 Do not edit this file manually 🚨`,
10
9
  "-------------------------------------------------",
11
10
  ]
@@ -0,0 +1,6 @@
1
+ import type { BashExpression } from "../bash/BashExpression";
2
+ import type { VariableValueContainingReferences } from "./VariableValueContainingReferences";
3
+ export type VariableValue =
4
+ | VariableValueContainingReferences
5
+ | BashExpression
6
+ | string;
@@ -0,0 +1,89 @@
1
+ import { BashExpression } from "../bash/BashExpression";
2
+ import type { EscapeOptions } from "../bash/bashEscape";
3
+ import { escapeBashExpression, escapeString } from "../bash/bashEscape";
4
+
5
+ export class UnresolvableReference {
6
+ constructor(public reference: VariableReference) {}
7
+ public toString() {
8
+ return `Unresolvable reference: ${this.reference.toString()}`;
9
+ }
10
+ }
11
+ export class VariableReference {
12
+ public componentName: string;
13
+ public variableName: string;
14
+
15
+ constructor(componentName: string, variableName: string) {
16
+ this.componentName = componentName;
17
+ this.variableName = variableName;
18
+ }
19
+
20
+ public toString() {
21
+ return `\${${this.componentName}:${this.variableName}}`;
22
+ }
23
+ }
24
+
25
+ type VariableValuePart =
26
+ | string
27
+ | BashExpression
28
+ | VariableReference
29
+ | UnresolvableReference;
30
+
31
+ type MaybeArray<T> = T | T[];
32
+ export class VariableValueContainingReferences {
33
+ public parts: VariableValuePart[];
34
+ constructor(
35
+ parts: MaybeArray<VariableValuePart | VariableValueContainingReferences>,
36
+ ) {
37
+ this.parts = (Array.isArray(parts) ? parts : [parts]).flatMap((part) =>
38
+ part instanceof VariableValueContainingReferences
39
+ ? part.parts
40
+ : part === ""
41
+ ? []
42
+ : [part],
43
+ );
44
+ }
45
+
46
+ public toString(
47
+ options: EscapeOptions = {
48
+ quotes: false,
49
+ },
50
+ ) {
51
+ return this.parts
52
+ .map((part) => {
53
+ if (typeof part === "string") {
54
+ return escapeString(part, options);
55
+ } else if (part instanceof BashExpression) {
56
+ return escapeBashExpression(part, options);
57
+ } else {
58
+ return part.toString();
59
+ }
60
+ })
61
+ .join("");
62
+ }
63
+ }
64
+
65
+ // regex to resolve references in catladder variables
66
+ // those expressions have the pattern ${componentName:variableName}
67
+ const REGEX = /\$\{(([^:}]+):)?([^}]+)}/gm;
68
+ export const createVariableValueContainingReferencesFromString = (
69
+ value: string,
70
+ options: { componentName: string },
71
+ ) => {
72
+ const parts: Array<VariableValuePart> = [];
73
+ let match: any;
74
+ let lastIndex = 0;
75
+ while ((match = REGEX.exec(value)) !== null) {
76
+ const [fullMatch, _, otherComponentName, variableName] = match;
77
+
78
+ parts.push(value.slice(lastIndex, match.index));
79
+ parts.push(
80
+ new VariableReference(
81
+ otherComponentName || options.componentName,
82
+ variableName,
83
+ ),
84
+ );
85
+ lastIndex = REGEX.lastIndex;
86
+ }
87
+ parts.push(value.slice(lastIndex));
88
+ return new VariableValueContainingReferences(parts);
89
+ };
@@ -0,0 +1,110 @@
1
+ import {
2
+ VariableValueContainingReferences,
3
+ createVariableValueContainingReferencesFromString,
4
+ } from "../VariableValueContainingReferences";
5
+ import { resolveAllReferences } from "../resolveAllReferences";
6
+
7
+ describe("replaceAllReferences", () => {
8
+ it("should replace all references recursivly", async () => {
9
+ const values = {
10
+ myVar: createVariableValueContainingReferencesFromString(
11
+ "the 2nd component has ${component2:variable1} and self reference ${variable2}",
12
+ {
13
+ componentName: "component1",
14
+ },
15
+ ),
16
+ myOtherVar: createVariableValueContainingReferencesFromString(
17
+ "the third component has ${component3:variable1}, isn't that cool?",
18
+ {
19
+ componentName: "component1",
20
+ },
21
+ ),
22
+ myThirdVar: createVariableValueContainingReferencesFromString(
23
+ "value from component3: ${component3:variable3}",
24
+ {
25
+ componentName: "component1",
26
+ },
27
+ ),
28
+ };
29
+
30
+ const getEnvVars = async (componentName: string) => {
31
+ return {
32
+ variable1: createVariableValueContainingReferencesFromString(
33
+ `i am variable1 from ${componentName}`,
34
+ { componentName },
35
+ ),
36
+ variable2: createVariableValueContainingReferencesFromString(
37
+ `foo from ${componentName}`,
38
+ {
39
+ componentName,
40
+ },
41
+ ),
42
+ variable3: createVariableValueContainingReferencesFromString(
43
+ `i am referencing \${component1:variable1}`,
44
+ { componentName },
45
+ ),
46
+ };
47
+ };
48
+
49
+ const result = await resolveAllReferences(values, getEnvVars);
50
+ expect(result).toEqual({
51
+ myVar: new VariableValueContainingReferences([
52
+ "the 2nd component has ",
53
+ "i am variable1 from component2",
54
+ " and self reference ",
55
+ "foo from component1",
56
+ ]),
57
+ myOtherVar: new VariableValueContainingReferences([
58
+ "the third component has ",
59
+ "i am variable1 from component3",
60
+ ", isn't that cool?",
61
+ ]),
62
+ myThirdVar: new VariableValueContainingReferences([
63
+ "value from component3: ",
64
+ "i am referencing ",
65
+ "i am variable1 from component1",
66
+ ]),
67
+ });
68
+ });
69
+
70
+ it("detects infinte loop", async () => {
71
+ const values = {
72
+ myVar: createVariableValueContainingReferencesFromString(
73
+ "i am referencing ${component2:variable1}",
74
+ {
75
+ componentName: "component1",
76
+ },
77
+ ),
78
+ };
79
+
80
+ const getEnvVars = async (componentName: string) => {
81
+ if (componentName === "component2") {
82
+ return {
83
+ variable1: createVariableValueContainingReferencesFromString(
84
+ `i am referencing \${component3:variable1}`,
85
+ { componentName },
86
+ ),
87
+ };
88
+ } else if (componentName === "component3") {
89
+ return {
90
+ variable1: createVariableValueContainingReferencesFromString(
91
+ `i am referencing \${component1:variable1}`,
92
+ { componentName },
93
+ ),
94
+ };
95
+ } else {
96
+ return {
97
+ variable1: createVariableValueContainingReferencesFromString(
98
+ `i am referencing \${component2:variable1}`,
99
+ { componentName },
100
+ ),
101
+ };
102
+ }
103
+ };
104
+
105
+ // expect to throw an error
106
+ await expect(resolveAllReferences(values, getEnvVars)).rejects.toThrow(
107
+ "Infinite loop detected in these variables: myVar (last reference: ${component1:variable1})",
108
+ );
109
+ });
110
+ });
@@ -0,0 +1,64 @@
1
+ import {
2
+ VariableReference,
3
+ VariableValueContainingReferences,
4
+ createVariableValueContainingReferencesFromString,
5
+ } from "../VariableValueContainingReferences";
6
+ import { resolveAllReferencesOnce } from "../resolveAllReferencesOnce";
7
+
8
+ describe("resolveAllReferencesOnce", () => {
9
+ it("should replace all references", async () => {
10
+ const values = {
11
+ myVar: createVariableValueContainingReferencesFromString(
12
+ "the 2nd component has ${component2:variable1} and self reference ${variable2}",
13
+ { componentName: "component1" },
14
+ ),
15
+ myOtherVar: createVariableValueContainingReferencesFromString(
16
+ "the third component has ${component3:variable1}, isn't that cool?",
17
+ { componentName: "component1" },
18
+ ),
19
+ myThirdVar: createVariableValueContainingReferencesFromString(
20
+ "value from component3: ${component3:variable3}",
21
+ { componentName: "component1" },
22
+ ),
23
+ };
24
+
25
+ const getEnvVars = async (componentName: string) => {
26
+ return {
27
+ variable1: createVariableValueContainingReferencesFromString(
28
+ `i am variable1 from ${componentName}`,
29
+ { componentName },
30
+ ),
31
+ variable2: createVariableValueContainingReferencesFromString(
32
+ `foo from ${componentName}`,
33
+ {
34
+ componentName,
35
+ },
36
+ ),
37
+ variable3: createVariableValueContainingReferencesFromString(
38
+ `i am referencing \${component1:variable1}`,
39
+ { componentName },
40
+ ),
41
+ };
42
+ };
43
+
44
+ const result = await resolveAllReferencesOnce(values, getEnvVars);
45
+ expect(result).toEqual({
46
+ myVar: new VariableValueContainingReferences([
47
+ "the 2nd component has ",
48
+ "i am variable1 from component2",
49
+ " and self reference ",
50
+ "foo from component1",
51
+ ]),
52
+ myOtherVar: new VariableValueContainingReferences([
53
+ "the third component has ",
54
+ "i am variable1 from component3",
55
+ ", isn't that cool?",
56
+ ]),
57
+ myThirdVar: new VariableValueContainingReferences([
58
+ "value from component3: ",
59
+ "i am referencing ",
60
+ new VariableReference("component1", "variable1"),
61
+ ]),
62
+ });
63
+ });
64
+ });
@@ -0,0 +1,117 @@
1
+ import {
2
+ UnresolvableReference,
3
+ VariableReference,
4
+ createVariableValueContainingReferencesFromString,
5
+ } from "../VariableValueContainingReferences";
6
+ import { resolveReferencesOnce } from "../resolveReferencesOnce";
7
+
8
+ describe("resolveReferencesOnce", () => {
9
+ it("should replace a reference to another component", async () => {
10
+ const value = createVariableValueContainingReferencesFromString(
11
+ "the other component has ${otherComponent:variableName}, isn't that cool?",
12
+ {
13
+ componentName: "myComponent",
14
+ },
15
+ );
16
+
17
+ const result = resolveReferencesOnce(
18
+ value,
19
+ ({ componentName, variableName }) => {
20
+ return createVariableValueContainingReferencesFromString(
21
+ `replaced ${componentName}:${variableName}`,
22
+ { componentName },
23
+ );
24
+ },
25
+ );
26
+
27
+ expect(result.parts).toEqual([
28
+ "the other component has ",
29
+ "replaced otherComponent:variableName",
30
+ ", isn't that cool?",
31
+ ]);
32
+ });
33
+ it("should keep references in replacement", async () => {
34
+ const value = createVariableValueContainingReferencesFromString(
35
+ "the other component has ${otherComponent:variableName}, isn't that cool?",
36
+ {
37
+ componentName: "myComponent",
38
+ },
39
+ );
40
+
41
+ const result = resolveReferencesOnce(
42
+ value,
43
+ ({ componentName, variableName }) => {
44
+ return createVariableValueContainingReferencesFromString(
45
+ `replaced ${componentName}:${variableName}, contains reference to \${thirdComponent:x}`,
46
+ { componentName },
47
+ );
48
+ },
49
+ );
50
+
51
+ expect(result.parts).toEqual([
52
+ "the other component has ",
53
+
54
+ "replaced otherComponent:variableName, contains reference to ",
55
+ new VariableReference("thirdComponent", "x"),
56
+ ", isn't that cool?",
57
+ ]);
58
+ });
59
+
60
+ it("can be run multiple times", async () => {
61
+ const value = createVariableValueContainingReferencesFromString(
62
+ "the other component has ${otherComponent:variableName}, isn't that cool?",
63
+ {
64
+ componentName: "myComponent",
65
+ },
66
+ );
67
+ const replacer = ({
68
+ componentName,
69
+ variableName,
70
+ }: {
71
+ componentName: string;
72
+ variableName: string;
73
+ }) => {
74
+ return createVariableValueContainingReferencesFromString(
75
+ componentName === "thirdComponent"
76
+ ? "value from third component"
77
+ : `replaced ${componentName}:${variableName}, contains reference to \${thirdComponent:x}`,
78
+ { componentName },
79
+ );
80
+ };
81
+ const result = resolveReferencesOnce(
82
+ resolveReferencesOnce(value, replacer),
83
+ replacer,
84
+ );
85
+
86
+ expect(result.parts).toEqual([
87
+ "the other component has ",
88
+ "replaced otherComponent:variableName, contains reference to ",
89
+ "value from third component",
90
+ ", isn't that cool?",
91
+ ]);
92
+ });
93
+
94
+ it("flags unresolveable", async () => {
95
+ const value = createVariableValueContainingReferencesFromString(
96
+ "the other component has ${otherComponent:variableName}, isn't that cool?",
97
+ {
98
+ componentName: "myComponent",
99
+ },
100
+ );
101
+
102
+ const result = resolveReferencesOnce(
103
+ value,
104
+ ({ componentName, variableName }) => {
105
+ return null;
106
+ },
107
+ );
108
+
109
+ expect(result.parts).toEqual([
110
+ "the other component has ",
111
+ new UnresolvableReference(
112
+ new VariableReference("otherComponent", "variableName"),
113
+ ),
114
+ ", isn't that cool?",
115
+ ]);
116
+ });
117
+ });
@@ -0,0 +1,73 @@
1
+ import {
2
+ VariableReference,
3
+ createVariableValueContainingReferencesFromString,
4
+ } from "../VariableValueContainingReferences";
5
+
6
+ describe("createVarialeValueFromString", () => {
7
+ it("should create a VariableValue from a simple string", () => {
8
+ const stringValue = "hello world";
9
+
10
+ const result = createVariableValueContainingReferencesFromString(
11
+ stringValue,
12
+ {
13
+ componentName: "myComponent",
14
+ },
15
+ );
16
+
17
+ expect(result.parts).toEqual([stringValue]);
18
+ });
19
+
20
+ it("extracts references to other components", () => {
21
+ const stringValue =
22
+ "the other component has ${otherComponent:variableName}, isn't that cool?";
23
+
24
+ const result = createVariableValueContainingReferencesFromString(
25
+ stringValue,
26
+ {
27
+ componentName: "myComponent",
28
+ },
29
+ );
30
+
31
+ expect(result.parts).toEqual([
32
+ "the other component has ",
33
+ new VariableReference("otherComponent", "variableName"),
34
+ ", isn't that cool?",
35
+ ]);
36
+ });
37
+
38
+ it("extracts self references", () => {
39
+ const stringValue = "my component has ${variableName}!";
40
+
41
+ const result = createVariableValueContainingReferencesFromString(
42
+ stringValue,
43
+ {
44
+ componentName: "myComponent",
45
+ },
46
+ );
47
+
48
+ expect(result.parts).toEqual([
49
+ "my component has ",
50
+ new VariableReference("myComponent", "variableName"),
51
+ "!",
52
+ ]);
53
+ });
54
+ it("extracts multiple references", () => {
55
+ const stringValue =
56
+ "my component has ${variableName} and the other component has ${otherComponent:variableName}!";
57
+
58
+ const result = createVariableValueContainingReferencesFromString(
59
+ stringValue,
60
+ {
61
+ componentName: "myComponent",
62
+ },
63
+ );
64
+
65
+ expect(result.parts).toEqual([
66
+ "my component has ",
67
+ new VariableReference("myComponent", "variableName"),
68
+ " and the other component has ",
69
+ new VariableReference("otherComponent", "variableName"),
70
+ "!",
71
+ ]);
72
+ });
73
+ });
@@ -0,0 +1,46 @@
1
+ import type { VariableValue } from "./VariableValue";
2
+ import type { VariableValueContainingReferences } from "./VariableValueContainingReferences";
3
+ import { VariableReference } from "./VariableValueContainingReferences";
4
+ import { resolveAllReferencesOnce as resolveAllReferencesOnce } from "./resolveAllReferencesOnce";
5
+
6
+ export const resolveAllReferences = async (
7
+ values: Record<string, VariableValueContainingReferences>,
8
+ getEnvVars: (
9
+ componentName: string,
10
+ ) => Promise<Record<string, VariableValue | null | undefined>>,
11
+ ) => {
12
+ // replace until there aren't any references left
13
+ let result = values;
14
+
15
+ let i = 0;
16
+
17
+ while (
18
+ Object.values(result).some((value) =>
19
+ value.parts.some((part) => part instanceof VariableReference),
20
+ )
21
+ ) {
22
+ const replaced = await resolveAllReferencesOnce(result, getEnvVars);
23
+
24
+ result = replaced;
25
+ i++;
26
+ if (i > 1000) {
27
+ const unresolved = Object.entries(result).filter(([key, value]) =>
28
+ value.parts.some((part) => part instanceof VariableReference),
29
+ );
30
+
31
+ throw new Error(
32
+ "Infinite loop detected in these variables: " +
33
+ unresolved
34
+ .map(
35
+ ([key, value]) =>
36
+ `${key} (last reference: ${value.parts.find(
37
+ (part) => part instanceof VariableReference,
38
+ )})`,
39
+ )
40
+ .join(", "),
41
+ );
42
+ }
43
+ }
44
+
45
+ return result;
46
+ };
@@ -0,0 +1,44 @@
1
+ import type { VariableValue } from "./VariableValue";
2
+ import type { VariableValueContainingReferences } from "./VariableValueContainingReferences";
3
+ import { VariableReference } from "./VariableValueContainingReferences";
4
+ import { resolveReferencesOnce } from "./resolveReferencesOnce";
5
+
6
+ export const resolveAllReferencesOnce = async (
7
+ values: Record<string, VariableValueContainingReferences>,
8
+ getEnvVars: (
9
+ componentName: string,
10
+ ) => Promise<Record<string, VariableValue | undefined | null>>,
11
+ ) => {
12
+ const allReferences = Object.values(values).flatMap(
13
+ (value) =>
14
+ value?.parts.filter(
15
+ (part) => part instanceof VariableReference,
16
+ ) as VariableReference[],
17
+ );
18
+
19
+ const allComponentsUnique = Array.from(
20
+ new Set(allReferences.map((reference) => reference.componentName)),
21
+ );
22
+
23
+ const allEnvVarsInComponents = Object.fromEntries(
24
+ await Promise.all(
25
+ allComponentsUnique.map(async (componentName) => [
26
+ componentName,
27
+ await getEnvVars(componentName),
28
+ ]) as Array<
29
+ Promise<[string, Record<string, VariableValue | undefined | null>]>
30
+ >,
31
+ ),
32
+ );
33
+
34
+ return Object.fromEntries(
35
+ Object.entries(values).map(([key, value]) => [
36
+ key,
37
+ value !== null && value !== undefined
38
+ ? resolveReferencesOnce(value, ({ componentName, variableName }) => {
39
+ return allEnvVarsInComponents[componentName][variableName];
40
+ })
41
+ : value,
42
+ ]),
43
+ );
44
+ };
@@ -0,0 +1,29 @@
1
+ import type { VariableValue } from "./VariableValue";
2
+ import {
3
+ UnresolvableReference,
4
+ VariableReference,
5
+ VariableValueContainingReferences,
6
+ } from "./VariableValueContainingReferences";
7
+
8
+ type Resolver = (args: {
9
+ componentName: string;
10
+ variableName: string;
11
+ }) => VariableValue | null | undefined;
12
+ export const resolveReferencesOnce = (
13
+ value: VariableValueContainingReferences,
14
+ resolver: Resolver,
15
+ ) => {
16
+ const replacedParts = value.parts.map((part) => {
17
+ if (part instanceof VariableReference) {
18
+ const result = resolver({
19
+ componentName: part.componentName,
20
+ variableName: part.variableName,
21
+ });
22
+ return result ?? new UnresolvableReference(part);
23
+ } else {
24
+ return part;
25
+ }
26
+ });
27
+
28
+ return new VariableValueContainingReferences(replacedParts);
29
+ };
@@ -1,3 +0,0 @@
1
- #! /usr/bin/env node
2
-
3
- require("../dist/catladder-gitlab.js");
@@ -1,3 +0,0 @@
1
- #! /usr/bin/env node
2
-
3
- require("../dist/bundles/catladder-gitlab/index.js");
@@ -1,2 +0,0 @@
1
- import { BashExpression } from "./BashExpression";
2
- export default function replaceAsync(string: string | BashExpression, searchValue: any, replacer: (substring: string, ...args: any[]) => Promise<string | BashExpression>): Promise<any>;