@catladder/pipeline 0.0.7 → 1.0.2

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 (211) hide show
  1. package/babel-inline.json +11 -0
  2. package/bin/catladder-gitlab.js +3 -0
  3. package/dist/build/base/constants.d.ts +7 -0
  4. package/dist/build/base/constants.js +11 -0
  5. package/dist/build/base/createBuildJob.d.ts +5 -0
  6. package/dist/build/base/createBuildJob.js +99 -0
  7. package/dist/build/docker.d.ts +5 -0
  8. package/dist/build/docker.js +95 -0
  9. package/dist/build/index.d.ts +12 -0
  10. package/dist/build/index.js +63 -0
  11. package/dist/build/node/buildJob.d.ts +3 -0
  12. package/dist/build/node/buildJob.js +97 -0
  13. package/dist/build/node/cache.d.ts +4 -0
  14. package/dist/build/node/cache.js +67 -0
  15. package/dist/build/node/constants.d.ts +6 -0
  16. package/dist/build/node/constants.js +10 -0
  17. package/dist/build/node/index.d.ts +5 -0
  18. package/dist/build/node/index.js +63 -0
  19. package/dist/build/node/meteor.d.ts +3 -0
  20. package/dist/build/node/meteor.js +103 -0
  21. package/dist/build/node/testJob.d.ts +3 -0
  22. package/dist/build/node/testJob.js +112 -0
  23. package/dist/build/node/yarn.d.ts +2 -0
  24. package/dist/build/node/yarn.js +12 -0
  25. package/dist/build/tests/storybook.test.d.ts +1 -0
  26. package/dist/build/tests/storybook.test.js +221 -0
  27. package/dist/build/types.d.ts +63 -0
  28. package/dist/build/types.js +16 -0
  29. package/dist/catladder-gitlab.d.ts +1 -0
  30. package/dist/catladder-gitlab.js +44 -0
  31. package/dist/config/configruedEnvs.d.ts +4 -0
  32. package/dist/config/configruedEnvs.js +86 -0
  33. package/dist/config/configruedEnvs.test.d.ts +1 -0
  34. package/dist/config/configruedEnvs.test.js +103 -0
  35. package/dist/config/index.d.ts +2 -0
  36. package/dist/config/index.js +24 -0
  37. package/dist/config/readConfig.d.ts +2 -0
  38. package/dist/config/readConfig.js +47 -0
  39. package/dist/constants.d.ts +2 -0
  40. package/dist/constants.js +6 -0
  41. package/dist/context/index.d.ts +5 -0
  42. package/dist/context/index.js +211 -0
  43. package/dist/defaults/index.d.ts +2 -0
  44. package/dist/defaults/index.js +8 -0
  45. package/dist/deploy/base.d.ts +9 -0
  46. package/dist/deploy/base.js +94 -0
  47. package/dist/deploy/index.d.ts +11 -0
  48. package/dist/deploy/index.js +34 -0
  49. package/dist/deploy/kubernetes/cloudsql.d.ts +6 -0
  50. package/dist/deploy/kubernetes/cloudsql.js +16 -0
  51. package/dist/deploy/kubernetes/deployJob.d.ts +3 -0
  52. package/dist/deploy/kubernetes/deployJob.js +148 -0
  53. package/dist/deploy/kubernetes/index.d.ts +1 -0
  54. package/dist/deploy/kubernetes/index.js +22 -0
  55. package/dist/deploy/kubernetes/mongodb.d.ts +15 -0
  56. package/dist/deploy/kubernetes/mongodb.js +23 -0
  57. package/dist/deploy/types.d.ts +92 -0
  58. package/dist/deploy/types.js +16 -0
  59. package/dist/index.d.ts +8 -0
  60. package/dist/index.js +36 -0
  61. package/dist/pipeline/createChildPipeline.d.ts +9 -0
  62. package/dist/pipeline/createChildPipeline.js +266 -0
  63. package/dist/pipeline/createChildPipeline.test.d.ts +1 -0
  64. package/dist/pipeline/createChildPipeline.test.js +199 -0
  65. package/dist/pipeline/createJobs.d.ts +3 -0
  66. package/dist/pipeline/createJobs.js +331 -0
  67. package/dist/pipeline/index.d.ts +2 -0
  68. package/dist/pipeline/index.js +24 -0
  69. package/dist/pipeline/yarnInfo.d.ts +2 -0
  70. package/dist/pipeline/yarnInfo.js +296 -0
  71. package/dist/rules/index.d.ts +3 -0
  72. package/dist/rules/index.js +27 -0
  73. package/dist/runner/index.d.ts +3 -0
  74. package/dist/runner/index.js +12 -0
  75. package/dist/tsconfig.tsbuildinfo +1 -0
  76. package/dist/types/config.d.ts +73 -0
  77. package/dist/types/config.js +80 -0
  78. package/dist/types/context.d.ts +36 -0
  79. package/dist/types/context.js +3 -0
  80. package/dist/types/gitlab-types.d.ts +86 -0
  81. package/dist/types/gitlab-types.js +5 -0
  82. package/dist/{scripts/magic/types → types}/index.d.ts +1 -1
  83. package/dist/types/index.js +26 -0
  84. package/dist/utils/index.d.ts +2 -0
  85. package/dist/utils/index.js +18 -0
  86. package/package.json +30 -9
  87. package/src/build/base/constants.ts +7 -0
  88. package/src/build/base/createBuildJob.ts +46 -0
  89. package/{scripts/magic → src}/build/docker.ts +15 -2
  90. package/src/build/index.ts +42 -0
  91. package/src/build/node/buildJob.ts +54 -0
  92. package/src/build/node/cache.ts +36 -0
  93. package/src/build/node/constants.ts +6 -0
  94. package/src/build/node/index.ts +17 -0
  95. package/src/build/node/meteor.ts +75 -0
  96. package/src/build/node/testJob.ts +80 -0
  97. package/src/build/node/yarn.ts +8 -0
  98. package/src/build/tests/storybook.test.ts +46 -0
  99. package/src/build/types.ts +75 -0
  100. package/src/catladder-gitlab.ts +52 -0
  101. package/src/config/configruedEnvs.test.ts +97 -0
  102. package/src/config/configruedEnvs.ts +56 -0
  103. package/src/config/index.ts +2 -0
  104. package/src/config/readConfig.ts +36 -0
  105. package/src/constants.ts +2 -0
  106. package/src/context/index.ts +194 -0
  107. package/src/defaults/index.ts +6 -0
  108. package/src/deploy/base.ts +101 -0
  109. package/src/deploy/index.ts +19 -0
  110. package/src/deploy/kubernetes/cloudsql.ts +13 -0
  111. package/src/deploy/kubernetes/deployJob.ts +116 -0
  112. package/src/deploy/kubernetes/index.ts +1 -0
  113. package/src/deploy/kubernetes/mongodb.ts +20 -0
  114. package/src/deploy/types.ts +60 -0
  115. package/src/index.ts +8 -0
  116. package/{scripts/magic/tests/createPipeline.test.ts → src/pipeline/createChildPipeline.test.ts} +5 -4
  117. package/src/pipeline/createChildPipeline.ts +51 -0
  118. package/src/pipeline/createJobs.ts +158 -0
  119. package/src/pipeline/index.ts +2 -0
  120. package/src/pipeline/yarnInfo.ts +54 -0
  121. package/src/rules/index.ts +37 -0
  122. package/src/runner/index.ts +10 -0
  123. package/src/types/config.ts +88 -0
  124. package/src/types/context.ts +36 -0
  125. package/src/types/gitlab-types.ts +94 -0
  126. package/{scripts/magic → src}/types/index.ts +0 -0
  127. package/src/utils/index.ts +10 -0
  128. package/tsconfig.json +4 -2
  129. package/Dockerfile +0 -84
  130. package/dist/scripts/createSamplePipeline.d.ts +0 -2
  131. package/dist/scripts/createSamplePipeline.js +0 -14
  132. package/dist/scripts/magic/build/docker.d.ts +0 -2
  133. package/dist/scripts/magic/build/docker.js +0 -68
  134. package/dist/scripts/magic/build/index.d.ts +0 -9
  135. package/dist/scripts/magic/build/index.js +0 -12
  136. package/dist/scripts/magic/build/node.d.ts +0 -6
  137. package/dist/scripts/magic/build/node.js +0 -150
  138. package/dist/scripts/magic/build/types.d.ts +0 -18
  139. package/dist/scripts/magic/build/types.js +0 -7
  140. package/dist/scripts/magic/context/index.d.ts +0 -3
  141. package/dist/scripts/magic/context/index.js +0 -122
  142. package/dist/scripts/magic/createChildPipeline/index.d.ts +0 -3
  143. package/dist/scripts/magic/createChildPipeline/index.js +0 -68
  144. package/dist/scripts/magic/createPipeline.d.ts +0 -14
  145. package/dist/scripts/magic/createPipeline.js +0 -80
  146. package/dist/scripts/magic/deploy/index.d.ts +0 -9
  147. package/dist/scripts/magic/deploy/index.js +0 -12
  148. package/dist/scripts/magic/deploy/kubernetes.d.ts +0 -5
  149. package/dist/scripts/magic/deploy/kubernetes.js +0 -62
  150. package/dist/scripts/magic/deploy/types.d.ts +0 -41
  151. package/dist/scripts/magic/deploy/types.js +0 -7
  152. package/dist/scripts/magic/index.d.ts +0 -2
  153. package/dist/scripts/magic/index.js +0 -16
  154. package/dist/scripts/magic/sample-config.d.ts +0 -3
  155. package/dist/scripts/magic/sample-config.js +0 -77
  156. package/dist/scripts/magic/tests/createPipeline.test.d.ts +0 -1
  157. package/dist/scripts/magic/tests/createPipeline.test.js +0 -89
  158. package/dist/scripts/magic/types/config.d.ts +0 -49
  159. package/dist/scripts/magic/types/config.js +0 -17
  160. package/dist/scripts/magic/types/context.d.ts +0 -19
  161. package/dist/scripts/magic/types/context.js +0 -2
  162. package/dist/scripts/magic/types/gitlab-types.d.ts +0 -57
  163. package/dist/scripts/magic/types/gitlab-types.js +0 -2
  164. package/dist/scripts/magic/types/index.js +0 -15
  165. package/dist/scripts/magic.d.ts +0 -2
  166. package/dist/scripts/magic.js +0 -43
  167. package/dist/scripts/monorepoGenerate.d.ts +0 -2
  168. package/dist/scripts/monorepoGenerate.js +0 -164
  169. package/dist/scripts/printAllValues.d.ts +0 -2
  170. package/dist/scripts/printAllValues.js +0 -58
  171. package/dist/scripts/printBuildEnv.d.ts +0 -2
  172. package/dist/scripts/printBuildEnv.js +0 -77
  173. package/dist/scripts/utils/extractAllValues.d.ts +0 -1
  174. package/dist/scripts/utils/extractAllValues.js +0 -78
  175. package/dist/scripts/utils/extractBuildEnv.d.ts +0 -5
  176. package/dist/scripts/utils/extractBuildEnv.js +0 -152
  177. package/dist/scripts/utils/extractValuesFromEnvVars.d.ts +0 -2
  178. package/dist/scripts/utils/extractValuesFromEnvVars.js +0 -63
  179. package/dist/scripts/utils/extractValuesFromMr.d.ts +0 -2
  180. package/dist/scripts/utils/extractValuesFromMr.js +0 -86
  181. package/dist/tests/extractValuesFromMr.test.d.ts +0 -1
  182. package/dist/tests/extractValuesFromMr.test.js +0 -68
  183. package/scripts/createSamplePipeline.ts +0 -10
  184. package/scripts/getCommitInfo +0 -11
  185. package/scripts/kubernetesCreateSecret +0 -9
  186. package/scripts/kubernetesDelete +0 -4
  187. package/scripts/kubernetesDeploy +0 -55
  188. package/scripts/kubernetesEnsureNamespace +0 -3
  189. package/scripts/magic/build/index.ts +0 -18
  190. package/scripts/magic/build/node.ts +0 -143
  191. package/scripts/magic/build/types.ts +0 -21
  192. package/scripts/magic/context/index.ts +0 -127
  193. package/scripts/magic/createChildPipeline/index.ts +0 -60
  194. package/scripts/magic/createPipeline.ts +0 -52
  195. package/scripts/magic/deploy/index.ts +0 -19
  196. package/scripts/magic/deploy/kubernetes.ts +0 -65
  197. package/scripts/magic/deploy/types.ts +0 -29
  198. package/scripts/magic/index.ts +0 -2
  199. package/scripts/magic/sample-config.ts +0 -78
  200. package/scripts/magic/types/config.ts +0 -54
  201. package/scripts/magic/types/context.ts +0 -21
  202. package/scripts/magic/types/gitlab-types.ts +0 -69
  203. package/scripts/magic.ts +0 -51
  204. package/scripts/monorepoGenerate.ts +0 -104
  205. package/scripts/printAllValues.ts +0 -17
  206. package/scripts/printBuildEnv.ts +0 -22
  207. package/scripts/utils/extractAllValues.ts +0 -32
  208. package/scripts/utils/extractBuildEnv.ts +0 -94
  209. package/scripts/utils/extractValuesFromEnvVars.ts +0 -21
  210. package/scripts/utils/extractValuesFromMr.ts +0 -39
  211. package/tests/extractValuesFromMr.test.ts +0 -156
@@ -0,0 +1,116 @@
1
+ import { GitlabJobs } from "../../types/gitlab-types";
2
+ import { Context } from "../../types/context";
3
+ import { isOfDeployType } from "../types";
4
+ import { getRunnerImage } from "../../runner";
5
+ import { getBaseDeploymentJob, getBaseDeploymentStopJob } from "../base";
6
+ import { merge } from "lodash";
7
+ import { dump } from "js-yaml";
8
+ import { createMongodbBaseConfig } from "./mongodb";
9
+ import { createCloudsqlBaseConfig } from "./cloudsql";
10
+
11
+ export const createKubernetesDeployJobs = (context: Context): GitlabJobs => {
12
+ const deployConfig = context.componentConfig.deploy;
13
+ if (deployConfig === false) {
14
+ return [];
15
+ }
16
+ if (!isOfDeployType(deployConfig, "kubernetes")) {
17
+ // should not happen
18
+ throw new Error("deploy config is not kubernetes");
19
+ }
20
+
21
+ const allEnvVars = context.environment.envVars;
22
+ /**
23
+ * separate by secrets and public.
24
+ * we evalulate the actual values later, but want to store the secrets in kubernetes secrets
25
+ */
26
+ const env = Object.entries(allEnvVars).reduce<{
27
+ secret: Record<string, string>;
28
+ public: Record<string, string>;
29
+ }>(
30
+ (acc, [key, value]) => {
31
+ if (value?.startsWith("$CL_")) {
32
+ acc.secret = {
33
+ ...acc.secret,
34
+ [key]: value,
35
+ };
36
+ return acc;
37
+ }
38
+ acc.public = {
39
+ ...acc.public,
40
+ [key]: value,
41
+ };
42
+ return acc;
43
+ },
44
+ {
45
+ secret: {},
46
+ public: {},
47
+ }
48
+ );
49
+
50
+ const defaultKubeValues = {
51
+ application: {
52
+ hostname: context.environment.hostname,
53
+ command: context.componentConfig.build.startCommand,
54
+ },
55
+
56
+ env: env,
57
+ ...(deployConfig.values?.cloudsql?.enabled
58
+ ? createCloudsqlBaseConfig(context)
59
+ : {}),
60
+ ...(deployConfig.values?.mongodb?.enabled
61
+ ? createMongodbBaseConfig(context)
62
+ : {}),
63
+ };
64
+
65
+ const kubeValues = merge({}, defaultKubeValues, deployConfig.values);
66
+
67
+ const kubernetesEnvironment = {
68
+ namespace: context.environment.envVars.KUBE_NAMESPACE,
69
+ };
70
+ const shared = {
71
+ job: {
72
+ image: getRunnerImage("kubernetes"),
73
+ variables: {
74
+ ...context.environment.envVars,
75
+ HELM_EXPERIMENTAL_OCI: "1",
76
+ IMAGE_PULL_SECRET: `gitlab-registry-${context.componentName}`,
77
+ KUBE_VALUES: dump(kubeValues, {
78
+ lineWidth: -1,
79
+ quotingType: "'",
80
+ forceQuotes: true,
81
+ }),
82
+ HELM_GITLAB_CHART_NAME: "the-panter-chart",
83
+ HELM_ARGS: deployConfig.additionalHelmArgs,
84
+ COMPONENT_NAME: context.componentName,
85
+ // TODO: unify with docker build stage
86
+ IMAGE_TAG: "$CI_COMMIT_SHA",
87
+ },
88
+ },
89
+ };
90
+
91
+ const baseDeploymentJob = getBaseDeploymentJob(context);
92
+ const baseStopJob = getBaseDeploymentStopJob(context);
93
+
94
+ return [
95
+ merge({}, baseDeploymentJob, shared, {
96
+ job: {
97
+ script: [
98
+ "kubernetesEnsureNamespace",
99
+ "kubernetesCreateSecret",
100
+ "kubernetesDeploy",
101
+ ],
102
+ environment: {
103
+ kubernetes: kubernetesEnvironment,
104
+ },
105
+ },
106
+ }),
107
+ merge({}, baseStopJob, shared, {
108
+ job: {
109
+ script: ["kubernetesDelete"],
110
+ environment: {
111
+ kubernetes: kubernetesEnvironment,
112
+ },
113
+ },
114
+ }),
115
+ ];
116
+ };
@@ -0,0 +1 @@
1
+ export * from "./deployJob";
@@ -0,0 +1,20 @@
1
+ import { Context } from "../..";
2
+
3
+ export const createMongodbBaseConfig = (context: Context) => {
4
+ return {
5
+ mongodb: {
6
+ enabled: true,
7
+ backup: {
8
+ enabled: ["prod", "stage"].includes(context.environment.envType),
9
+ },
10
+ },
11
+ "mongodb-replicaset": {
12
+ replicas: 1,
13
+ persistentVolume: {
14
+ storageClass: ["prod", "stage"].includes(context.environment.envType)
15
+ ? "fast"
16
+ : "standard",
17
+ },
18
+ },
19
+ };
20
+ };
@@ -0,0 +1,60 @@
1
+ // eslint-disable-next-line @typescript-eslint/ban-types
2
+ export type DeployConfigBase = {};
3
+ type AllowUnknownProps<T extends Record<string, unknown>> = T &
4
+ Record<string, unknown>;
5
+ export type DeployConfigKubernetes = {
6
+ type: "kubernetes";
7
+ cluster?: string;
8
+ additionalHelmArgs?: string[];
9
+ values?: AllowUnknownProps<{
10
+ cloudsql?: {
11
+ enabled: boolean;
12
+ instanceId?: string;
13
+ projectId?: string;
14
+ region?: string;
15
+ };
16
+ mongodb?: AllowUnknownProps<{
17
+ enabled: boolean;
18
+ }>;
19
+ mailhog?: {
20
+ enabled: boolean;
21
+ };
22
+ jobs?: Record<string, AllowUnknownProps<{ command: string }>>;
23
+ cronjobs?: Record<
24
+ string,
25
+ AllowUnknownProps<{
26
+ schedule: string;
27
+ command: string;
28
+ concurrencyPolicy?: "Forbid" | "Allow" | "Replace";
29
+ }>
30
+ >;
31
+ application?: AllowUnknownProps<{
32
+ redirects?: AllowUnknownProps<{ host: string }>[];
33
+ replicas?: number;
34
+ resources?: {
35
+ limits?: {
36
+ cpu?: string;
37
+ memory?: string;
38
+ };
39
+ requests?: {
40
+ cpu?: string;
41
+ memory?: string;
42
+ };
43
+ };
44
+ }>;
45
+ }>;
46
+ } & DeployConfigBase;
47
+
48
+ type CustomDeployConfig = {
49
+ type: "custom";
50
+ script: string[];
51
+ };
52
+
53
+ export type DeployConfig = DeployConfigKubernetes;
54
+
55
+ export const isOfDeployType = <T extends Array<DeployConfig["type"]>>(
56
+ t: DeployConfig | false,
57
+ ...types: T
58
+ ): t is Extract<DeployConfig, { type: T[number] }> => {
59
+ return t && types.includes(t.type);
60
+ };
package/src/index.ts ADDED
@@ -0,0 +1,8 @@
1
+ export * from "./pipeline/";
2
+ export * from "./types";
3
+ export * from "./rules";
4
+ export * from "./runner";
5
+ export * from "./config";
6
+ export * from "./context";
7
+ export * from "./build";
8
+ export * from "./deploy";
@@ -1,7 +1,7 @@
1
1
  import { Config } from "../types";
2
- import { createPipeline } from "../createPipeline";
2
+ import { createChildPipeline } from "./createChildPipeline";
3
3
 
4
- describe("createPipeline", () => {
4
+ describe("createChildPipeline", () => {
5
5
  describe("node-app to kuberntes", () => {
6
6
  const config: Config = {
7
7
  appName: "test",
@@ -20,12 +20,12 @@ describe("createPipeline", () => {
20
20
  };
21
21
 
22
22
  it("creates a pipeline for a single app on the main branch", async () => {
23
- const { image, stages, workflow, ...jobs } = await createPipeline(
23
+ const { image, stages, workflow, ...jobs } = await createChildPipeline(
24
24
  "mainBranch",
25
25
  config
26
26
  );
27
27
  expect(image).toEqual(
28
- "git.panter.ch:5001/catladder/gitlab-ci/pipeline:$PIPELINE_IMAGE_TAG"
28
+ "git.panter.ch:5001/catladder/catladder/base-pipeline:"
29
29
  );
30
30
 
31
31
  expect(Object.keys(jobs)).toEqual([
@@ -35,6 +35,7 @@ describe("createPipeline", () => {
35
35
  "dev my-app app-build",
36
36
  "dev my-app docker-build",
37
37
  "dev my-app deploy-to-kubernetes",
38
+ "dev my-app kubernetes-stop",
38
39
  ]);
39
40
  });
40
41
  });
@@ -0,0 +1,51 @@
1
+ import { getAllEnvsByTrigger, getAllEnvsInAllComponents } from "../config";
2
+ import { createJobs } from "./createJobs";
3
+ import { RULES_ALWAYS } from "../rules";
4
+ import { getRunnerImage } from "../runner";
5
+ import { Config, PipelineTrigger } from "../types/config";
6
+ import { GitlabJobDef } from "../types/gitlab-types";
7
+ const baseStages = ["setup", "test", "build", "deploy", "verify", "stop"];
8
+ export const createChildPipeline = async (
9
+ trigger: PipelineTrigger,
10
+ config: Config
11
+ ) => {
12
+ const components = Object.keys(config.components);
13
+
14
+ // 2. write the triggering pipeline
15
+
16
+ const jobs = await components.reduce<Promise<Record<string, GitlabJobDef>>>(
17
+ async (acc, componentName) => {
18
+ const envs = getAllEnvsByTrigger(config, componentName, trigger);
19
+ return {
20
+ ...(await acc),
21
+ ...(await createJobs(envs, config, componentName, trigger)),
22
+ };
23
+ },
24
+ Promise.resolve({})
25
+ );
26
+
27
+ // while technically not required, we group different envs in its own stage
28
+ // each job from `createJobs` that is defined as `envMode: "stagePerEnv"` will have `deploy dev`, etc. instead of just `deploy`
29
+ // this is just so that it looks nicer in gitlab and makes running mutliple manual tasks more easy to use
30
+
31
+ const allEnvs = getAllEnvsInAllComponents(config);
32
+ const stages = baseStages.reduce<string[]>(
33
+ (acc, baseStage) => [
34
+ ...acc,
35
+ baseStage,
36
+ ...allEnvs.map((e) => `${baseStage} ${e}`),
37
+ ],
38
+ []
39
+ );
40
+
41
+ const childPipeline = {
42
+ image: getRunnerImage("jobs"), // default image
43
+ workflow: {
44
+ rules: RULES_ALWAYS,
45
+ },
46
+ stages,
47
+ ...jobs,
48
+ };
49
+
50
+ return childPipeline as typeof childPipeline & Record<string, GitlabJobDef>;
51
+ };
@@ -0,0 +1,158 @@
1
+ import { isObject } from "lodash";
2
+ import { BUILD_TYPES } from "../build";
3
+ import { createContext } from "../context";
4
+ import { DEPLOY_TYPES } from "../deploy";
5
+ import { Config, PipelineTrigger } from "../types/config";
6
+ import { Context, CommitInfo } from "../types/context";
7
+ import { GitlabJob, GitlabJobDef, GitlabJobs } from "../types/gitlab-types";
8
+ import { notNil } from "../utils";
9
+ import { getYarnInfo } from "./yarnInfo";
10
+
11
+ const createRawJobs = (context: Context): GitlabJobs => {
12
+ if (context.componentConfig.deploy === false) {
13
+ return [];
14
+ }
15
+ const buildJobs =
16
+ BUILD_TYPES[context.componentConfig.build.type].jobs(context);
17
+ const deployJobs =
18
+ DEPLOY_TYPES[context.componentConfig.deploy.type].jobs(context);
19
+
20
+ return [...buildJobs, ...deployJobs];
21
+ };
22
+ const getFullJobName = (
23
+ name: string,
24
+ componentName: string,
25
+ env?: string | null
26
+ ) => {
27
+ if (env) {
28
+ return `${componentName} ${name} | ${env} `;
29
+ }
30
+ return `${componentName} ${name}`;
31
+ };
32
+
33
+ const getFullReferencedJobName = (
34
+ referencedJobName: string,
35
+ componentName: string,
36
+ env: string,
37
+ allRawJobs: GitlabJobs
38
+ ) => {
39
+ const referencedJob = allRawJobs.find((j) => j.name === referencedJobName);
40
+ if (!referencedJob) {
41
+ throw new Error("unknown job referenced: " + referencedJobName);
42
+ }
43
+ const envToSet = referencedJob.envMode !== "none" ? env : null;
44
+ return getFullJobName(referencedJobName, componentName, envToSet);
45
+ };
46
+ // replaces references to other jobs with the full name
47
+ // the full name contains the componentname and the env name (if any)
48
+ const replaceReferences = (
49
+ job: GitlabJob,
50
+ componentName: string,
51
+ env: string,
52
+ allRawJobs: GitlabJobs
53
+ ): GitlabJobDef => {
54
+ const def = job.job;
55
+ const stage =
56
+ job.envMode === "stagePerEnv" ? `${def.stage} ${env}` : def.stage;
57
+ return {
58
+ ...def,
59
+ stage,
60
+ needs: def.needs?.map((n) =>
61
+ isObject(n)
62
+ ? {
63
+ job: getFullReferencedJobName(
64
+ n.job,
65
+ componentName,
66
+ env,
67
+ allRawJobs
68
+ ),
69
+ artifacts: n.artifacts,
70
+ }
71
+ : getFullReferencedJobName(n, componentName, env, allRawJobs)
72
+ ),
73
+ environment: def.environment?.on_stop
74
+ ? {
75
+ ...def.environment,
76
+ on_stop: getFullReferencedJobName(
77
+ def.environment.on_stop,
78
+ componentName,
79
+ env,
80
+ allRawJobs
81
+ ),
82
+ }
83
+ : def.environment,
84
+ dependencies: def.dependencies?.map((n) =>
85
+ getFullReferencedJobName(n, componentName, env, allRawJobs)
86
+ ),
87
+ };
88
+ };
89
+
90
+ // this can be removed once https://gitlab.com/gitlab-org/gitlab/-/issues/220758 is resolved
91
+ const addStageNeeds = (jobs: GitlabJobs): GitlabJobs => {
92
+ // when a job defines needsStages, we add these as needs
93
+ return jobs.map((job) => {
94
+ if (!job.needsStages || job.needsStages.length === 0) {
95
+ return job;
96
+ }
97
+
98
+ const neededJobs = jobs
99
+ .map((j) => {
100
+ const neededStage = job.needsStages?.find(
101
+ (s) => j.job.stage === s.stage
102
+ );
103
+ if (neededStage) {
104
+ return {
105
+ job: j.name,
106
+ artifacts: neededStage.artifacts ?? false,
107
+ };
108
+ }
109
+ })
110
+ .filter(notNil);
111
+ return {
112
+ ...job,
113
+ job: {
114
+ ...job.job,
115
+ needs: [...(job.job.needs ?? []), ...neededJobs],
116
+ },
117
+ };
118
+ });
119
+ };
120
+ export const createJobs = async (
121
+ envs: string[],
122
+ config: Config,
123
+ componentName: string,
124
+ trigger: PipelineTrigger
125
+ ): Promise<Record<string, GitlabJobDef>> => {
126
+ const commitInfo: CommitInfo = {
127
+ refName: process.env.CI_COMMIT_REF_NAME ?? "unknown",
128
+ refSlug: process.env.CI_COMMIT_REF_SLUG ?? "unknown",
129
+ trigger,
130
+ };
131
+
132
+ const yarnInfo = await getYarnInfo(config, componentName);
133
+
134
+ return envs.reduce((acc, env) => {
135
+ const context = createContext(
136
+ config,
137
+ componentName,
138
+ env,
139
+ commitInfo,
140
+ yarnInfo
141
+ );
142
+ const jobs = addStageNeeds(createRawJobs(context));
143
+
144
+ return {
145
+ ...acc,
146
+ ...jobs.reduce((acc, job) => {
147
+ return {
148
+ ...acc,
149
+ [getFullJobName(
150
+ job.name,
151
+ componentName,
152
+ job.envMode !== "none" ? env : undefined
153
+ )]: replaceReferences(job, componentName, env, jobs),
154
+ };
155
+ }, {}),
156
+ };
157
+ }, {});
158
+ };
@@ -0,0 +1,2 @@
1
+ export * from "./createChildPipeline";
2
+ export * from "./createJobs";
@@ -0,0 +1,54 @@
1
+ import { exec } from "child-process-promise";
2
+ import { Config, YarnInfo } from "../types";
3
+ import { pathEqual } from "path-equal";
4
+ import memoizee from "memoizee";
5
+
6
+ const execOrFail = async (cmd: string, onFail: string): Promise<string> => {
7
+ try {
8
+ return await exec(cmd).then((r) => r.stdout);
9
+ } catch (e) {
10
+ return onFail ?? null;
11
+ }
12
+ };
13
+
14
+ const getYarnVersion = memoizee(
15
+ async () => {
16
+ return await execOrFail("yarn --version", "");
17
+ },
18
+ { promise: true }
19
+ );
20
+
21
+ const getWorkspaces = memoizee(
22
+ async (isClassic: boolean): Promise<YarnInfo["workspaces"]> => {
23
+ return isClassic
24
+ ? Object.values(
25
+ JSON.parse(
26
+ JSON.parse(await execOrFail("yarn workspaces --json info", "{}"))
27
+ ?.data ?? "{}"
28
+ )
29
+ )
30
+ : JSON.parse(`[${await execOrFail("yarn workspaces list --json", "")}]`);
31
+ },
32
+ { promise: true }
33
+ );
34
+ export const getYarnInfo = async (
35
+ config: Config,
36
+ componentName: string
37
+ ): Promise<YarnInfo> => {
38
+ const version = await getYarnVersion();
39
+ if (!version) throw new Error("could not get yarn version");
40
+ const isClassic = version.startsWith("1");
41
+
42
+ const component = config.components[componentName];
43
+ const workspaces = await getWorkspaces(isClassic);
44
+ const componentIsInWorkspace = workspaces.some((w) =>
45
+ pathEqual(component.dir, w.location)
46
+ );
47
+
48
+ return {
49
+ workspaces,
50
+ version,
51
+ isClassic,
52
+ componentIsInWorkspace,
53
+ };
54
+ };
@@ -0,0 +1,37 @@
1
+ import { GitlabRule } from "../types";
2
+
3
+ const NEVER_ON_RELEASE_COMMIT: GitlabRule = {
4
+ if: "$CI_COMMIT_MESSAGE =~ /^chore\\(release\\).*/",
5
+ when: "never",
6
+ };
7
+ export const RULES_ALWAYS: GitlabRule[] = [
8
+ {
9
+ if: "$CI_COMMIT_TAG",
10
+ },
11
+ NEVER_ON_RELEASE_COMMIT,
12
+ {
13
+ if: "$CI_COMMIT_BRANCH =~ /^[0-9]+.([0-9]+|x).x$/",
14
+ },
15
+ {
16
+ if: "$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH",
17
+ },
18
+ {
19
+ if: "$CI_MERGE_REQUEST_ID",
20
+ },
21
+ ];
22
+
23
+ export const RULES_RELEASE: GitlabRule[] = [
24
+ NEVER_ON_RELEASE_COMMIT,
25
+ {
26
+ if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $AUTO_RELEASE == "true"',
27
+ when: "on_success",
28
+ },
29
+ {
30
+ if: "$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH",
31
+ when: "manual",
32
+ },
33
+ {
34
+ if: "$CI_COMMIT_BRANCH =~ /^[0-9]+.([0-9]+|x).x$/", // hotfix branches
35
+ when: "manual",
36
+ },
37
+ ];
@@ -0,0 +1,10 @@
1
+ import { PIPELINE_IMAGE_TAG, DOCKER_REGISTRY } from "../constants";
2
+
3
+ type RunnerImageName =
4
+ | "jobs"
5
+ | "kubernetes"
6
+ | "base-pipeline"
7
+ | "docker-build"
8
+ | "semantic-release";
9
+ export const getRunnerImage = (imageName: RunnerImageName) =>
10
+ DOCKER_REGISTRY + "/" + imageName + ":" + PIPELINE_IMAGE_TAG;
@@ -0,0 +1,88 @@
1
+ import { BuildConfig } from "../build/types";
2
+ import { DeployConfig } from "../deploy/types";
3
+ import { PartialDeep } from "type-fest";
4
+ export type PipelineTrigger = "mainBranch" | "mr" | "taggedRelease";
5
+
6
+ /**
7
+ * all env types with their trigger.
8
+ * Each env type has a default env with the same name which is always included
9
+ */
10
+ export const ENV_TYPES = {
11
+ dev: {
12
+ triggers: ["mainBranch", "taggedRelease"], // we also trigger dev on tagged release, so that the versions match
13
+ },
14
+ review: {
15
+ triggers: ["mr"],
16
+ },
17
+ stage: {
18
+ triggers: ["taggedRelease"],
19
+ },
20
+ prod: {
21
+ triggers: ["taggedRelease"],
22
+ },
23
+ local: {
24
+ triggers: [],
25
+ },
26
+ } as const;
27
+
28
+ /**
29
+ *
30
+ * @param trigger a trigger
31
+ * @returns array of env types for that trigger. this is also the list of default envs
32
+ */
33
+ export const getEnvTypesByTrigger = (trigger: PipelineTrigger) =>
34
+ Object.entries(ENV_TYPES)
35
+ .filter(([, e]) =>
36
+ (e.triggers as readonly PipelineTrigger[]).includes(trigger)
37
+ )
38
+ .map(([e]) => e as EnvType);
39
+
40
+ export const DEFAULT_ENVS = Object.keys(ENV_TYPES);
41
+ export const DEFAULT_ENV_TYPES = DEFAULT_ENVS as EnvType[];
42
+ export type EnvType = keyof typeof ENV_TYPES;
43
+
44
+ export const isKnowEnvType = (env: string): env is EnvType => {
45
+ return env in ENV_TYPES;
46
+ };
47
+
48
+ export type EnvVars = {
49
+ public?: Record<string, any>;
50
+ secret?: string[];
51
+ fromComponents?: {
52
+ [otherApp: string]: Record<string, string>;
53
+ };
54
+ };
55
+
56
+ export type DefaultEnvConfig = {
57
+ deploy: DeployConfig | false;
58
+ build: BuildConfig;
59
+ vars?: EnvVars;
60
+ };
61
+
62
+ export type DevLocalEnvConfig = {
63
+ vars?: EnvVars;
64
+ port?: number;
65
+ };
66
+ export type EnvConfig<E extends EnvType = EnvType> = {
67
+ type?: E;
68
+ hostname?: string;
69
+ } & PartialDeep<DefaultEnvConfig>;
70
+
71
+ export type Env = {
72
+ local?: DevLocalEnvConfig;
73
+ dev?: EnvConfig<"dev"> | false;
74
+ stage?: EnvConfig<"stage"> | false;
75
+ review?: EnvConfig<"review"> | false;
76
+ prod?: EnvConfig<"prod"> | false;
77
+ } & Record<string, EnvConfig | false>;
78
+
79
+ export type ComponentConfig = {
80
+ env?: Env;
81
+ dir: string;
82
+ } & DefaultEnvConfig;
83
+
84
+ export type Config = {
85
+ customerName: string;
86
+ appName: string;
87
+ components: Record<string, ComponentConfig>;
88
+ };
@@ -0,0 +1,36 @@
1
+ import { PipelineTrigger, ComponentConfig, Config, EnvType } from "./config";
2
+
3
+ export type Environment = {
4
+ hostname: string;
5
+ fullName: string;
6
+ shortName: string;
7
+ slug: string;
8
+ url: string;
9
+ /**
10
+ * env vars contain all build-time env vars. secrets have to be resolved (they are stored in gitlab)
11
+ */
12
+ envVars: Record<string, string>;
13
+ envType: EnvType;
14
+ secretEnvVarKeys: string[];
15
+ };
16
+
17
+ export type CommitInfo = {
18
+ refName: string;
19
+ refSlug: string;
20
+ trigger: PipelineTrigger;
21
+ };
22
+
23
+ export type YarnInfo = {
24
+ version: string;
25
+ workspaces: { location: string }[];
26
+ isClassic: boolean;
27
+ componentIsInWorkspace: boolean;
28
+ };
29
+ export type Context = {
30
+ componentName: string;
31
+ componentConfig: ComponentConfig;
32
+ fullConfig: Config;
33
+ environment: Environment;
34
+ commitInfo?: CommitInfo;
35
+ yarnInfo?: YarnInfo;
36
+ };