@catladder/pipeline 1.10.2 → 1.13.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 (79) hide show
  1. package/dist/build/base/constants.js +1 -1
  2. package/dist/build/base/createBuildJob.d.ts +4 -2
  3. package/dist/build/base/createBuildJob.js +13 -18
  4. package/dist/build/docker.d.ts +6 -3
  5. package/dist/build/docker.js +24 -9
  6. package/dist/build/index.d.ts +2 -2
  7. package/dist/build/node/buildJob.d.ts +2 -2
  8. package/dist/build/node/buildJob.js +26 -13
  9. package/dist/build/node/cache.d.ts +3 -1
  10. package/dist/build/node/cache.js +33 -5
  11. package/dist/build/node/constants.js +2 -2
  12. package/dist/build/node/index.d.ts +4 -4
  13. package/dist/build/node/meteor.d.ts +2 -2
  14. package/dist/build/node/meteor.js +4 -23
  15. package/dist/build/node/testJob.d.ts +2 -2
  16. package/dist/build/node/testJob.js +20 -29
  17. package/dist/build/node/yarn.d.ts +4 -0
  18. package/dist/build/node/yarn.js +10 -3
  19. package/dist/build/tests/storybook.test.js +10 -23
  20. package/dist/build/types.d.ts +6 -0
  21. package/dist/catladder-gitlab.js +33 -2
  22. package/dist/constants.js +1 -1
  23. package/dist/context/index.d.ts +2 -2
  24. package/dist/context/index.js +2 -2
  25. package/dist/deploy/base.d.ts +3 -4
  26. package/dist/deploy/base.js +27 -33
  27. package/dist/deploy/index.d.ts +2 -2
  28. package/dist/deploy/kubernetes/deployJob.d.ts +2 -2
  29. package/dist/deploy/kubernetes/deployJob.js +32 -38
  30. package/dist/pipeline/createChildPipeline.d.ts +2 -11
  31. package/dist/pipeline/createChildPipeline.js +24 -18
  32. package/dist/pipeline/createChildPipeline.test.js +3 -14
  33. package/dist/pipeline/createJobs.d.ts +2 -2
  34. package/dist/pipeline/createJobs.js +29 -23
  35. package/dist/pipeline/gitlab/makeGitlabJob.d.ts +8 -0
  36. package/dist/pipeline/gitlab/makeGitlabJob.js +45 -0
  37. package/dist/pipeline/packageManager.d.ts +2 -0
  38. package/dist/pipeline/{yarnInfo.js → packageManager.js} +69 -8
  39. package/dist/tsconfig.tsbuildinfo +1 -1
  40. package/dist/types/context.d.ts +15 -6
  41. package/dist/types/gitlab-types.d.ts +10 -22
  42. package/dist/types/gitlab-types.js +1 -3
  43. package/dist/types/index.d.ts +2 -1
  44. package/dist/types/index.js +3 -1
  45. package/dist/types/jobs.d.ts +75 -0
  46. package/dist/types/jobs.js +5 -0
  47. package/dist/types/pipeline.d.ts +4 -0
  48. package/dist/types/pipeline.js +3 -0
  49. package/package.json +1 -1
  50. package/src/build/base/constants.ts +1 -1
  51. package/src/build/base/createBuildJob.ts +29 -31
  52. package/src/build/docker.ts +50 -45
  53. package/src/build/index.ts +3 -2
  54. package/src/build/node/buildJob.ts +35 -25
  55. package/src/build/node/cache.ts +30 -5
  56. package/src/build/node/constants.ts +2 -2
  57. package/src/build/node/index.ts +4 -4
  58. package/src/build/node/meteor.ts +10 -18
  59. package/src/build/node/testJob.ts +31 -40
  60. package/src/build/node/yarn.ts +20 -3
  61. package/src/build/tests/storybook.test.ts +4 -2
  62. package/src/build/types.ts +6 -0
  63. package/src/catladder-gitlab.ts +9 -5
  64. package/src/context/index.ts +8 -4
  65. package/src/deploy/base.ts +40 -45
  66. package/src/deploy/index.ts +2 -2
  67. package/src/deploy/kubernetes/deployJob.ts +43 -48
  68. package/src/pipeline/createChildPipeline.test.ts +2 -1
  69. package/src/pipeline/createChildPipeline.ts +23 -21
  70. package/src/pipeline/createJobs.ts +50 -41
  71. package/src/pipeline/gitlab/makeGitlabJob.ts +16 -0
  72. package/src/pipeline/packageManager.ts +99 -0
  73. package/src/types/context.ts +14 -3
  74. package/src/types/gitlab-types.ts +10 -30
  75. package/src/types/index.ts +1 -0
  76. package/src/types/jobs.ts +88 -0
  77. package/src/types/pipeline.ts +11 -0
  78. package/dist/pipeline/yarnInfo.d.ts +0 -2
  79. package/src/pipeline/yarnInfo.ts +0 -54
@@ -1,11 +1,15 @@
1
- import { merge, mergeWith } from "lodash";
2
1
  import slugify from "slugify";
3
2
  import { BUILD_TYPES } from "../build";
4
3
  import { BuildConfig } from "../build/types";
5
4
  import { DEPLOY_TYPES, getKubernetesNamespace } from "../deploy";
6
5
  import { DeployConfig } from "../deploy/types";
7
6
  import { Config, isKnowEnvType, DevLocalEnvConfig } from "../types/config";
8
- import { CommitInfo, Context, Environment, YarnInfo } from "../types/context";
7
+ import {
8
+ CommitInfo,
9
+ Context,
10
+ Environment,
11
+ PackageManagerInfo,
12
+ } from "../types/context";
9
13
  import { mergeWithMergingArrays } from "../utils";
10
14
 
11
15
  const sanitizeForEnVar = (s: string) => s.replace(/-/g, "_");
@@ -164,7 +168,7 @@ export const createContext = (
164
168
  componentName: string,
165
169
  env: string,
166
170
  commitInfo?: CommitInfo,
167
- yarnInfo?: YarnInfo
171
+ packageManagerInfo?: PackageManagerInfo
168
172
  ): Context => {
169
173
  if (!/^[a-z0-9-]+$/.test(componentName)) {
170
174
  throw new Error(
@@ -208,6 +212,6 @@ export const createContext = (
208
212
  componentName,
209
213
  environment: getEnvironment(config, componentName, env, commitInfo),
210
214
  commitInfo,
211
- yarnInfo,
215
+ packageManagerInfo,
212
216
  };
213
217
  };
@@ -1,4 +1,5 @@
1
- import { GitlabJob, Context, GitlabJobDef } from "../types";
1
+ import { Context } from "../types";
2
+ import { CatladderJob } from "../types/jobs";
2
3
 
3
4
  export const DEPLOY_JOB_NAME = "🚀 Deploy";
4
5
  export const STOP_JOB_NAME = "🛑 Stop ⚠️";
@@ -9,9 +10,7 @@ const DEPLOY_RUNNER_VARIABLES = {
9
10
  KUBERNETES_MEMORY_REQUEST: "200Mi",
10
11
  KUBERNETES_MEMORY_LIMIT: "500Mi",
11
12
  };
12
- type JobWithoutScript = Omit<GitlabJob, "job"> & {
13
- job: Omit<GitlabJobDef, "script">;
14
- };
13
+ type JobWithoutScript = Omit<CatladderJob, "script">;
15
14
  export const getBaseDeploymentJob = (context: Context): JobWithoutScript => {
16
15
  const environment = {
17
16
  name: context.environment.fullName,
@@ -45,26 +44,24 @@ export const getBaseDeploymentJob = (context: Context): JobWithoutScript => {
45
44
  artifacts: false,
46
45
  },
47
46
  ], // workaround for https://gitlab.com/gitlab-org/gitlab/-/issues/220758
48
- job: {
49
- rules: [
50
- autoDeploy
51
- ? {
52
- when: "on_success",
53
- }
54
- : {
55
- when: "manual",
56
- },
57
- ],
58
- stage: "deploy",
59
- dependencies: [],
60
- variables: {
61
- ...DEPLOY_RUNNER_VARIABLES,
62
- },
63
- environment: {
64
- ...environment,
65
- on_stop: STOP_JOB_NAME,
66
- auto_stop_in: autoStop,
67
- },
47
+
48
+ rules: [
49
+ autoDeploy
50
+ ? {
51
+ when: "on_success",
52
+ }
53
+ : {
54
+ when: "manual",
55
+ },
56
+ ],
57
+ stage: "deploy",
58
+ variables: {
59
+ ...DEPLOY_RUNNER_VARIABLES,
60
+ },
61
+ environment: {
62
+ ...environment,
63
+ on_stop: STOP_JOB_NAME,
64
+ auto_stop_in: autoStop,
68
65
  },
69
66
  };
70
67
  };
@@ -79,29 +76,27 @@ export const getBaseDeploymentStopJob = (
79
76
  return {
80
77
  name: STOP_JOB_NAME,
81
78
  envMode: "stagePerEnv", // makes it easier to run manual tasks er env
82
- job: {
83
- needs: [DEPLOY_JOB_NAME],
84
- rules: [
85
- {
86
- if: "$CI_COMMIT_BRANCH =~ /^[0-9]+\\.([0-9]+|x)\\.x$/", // automatic on hotfix branches
87
- when: "on_success",
88
- allow_failure: true,
89
- },
90
- {
91
- when: "manual",
92
- allow_failure: true,
93
- },
94
- ],
95
- variables: {
96
- ...DEPLOY_RUNNER_VARIABLES,
97
- GIT_STRATEGY: "none",
79
+
80
+ needs: [DEPLOY_JOB_NAME],
81
+ rules: [
82
+ {
83
+ if: "$CI_COMMIT_BRANCH =~ /^[0-9]+\\.([0-9]+|x)\\.x$/", // automatic on hotfix branches
84
+ when: "on_success",
85
+ allow_failure: true,
98
86
  },
99
- stage: "stop",
100
- dependencies: [],
101
- environment: {
102
- ...environment,
103
- action: "stop",
87
+ {
88
+ when: "manual",
89
+ allow_failure: true,
104
90
  },
91
+ ],
92
+ variables: {
93
+ ...DEPLOY_RUNNER_VARIABLES,
94
+ GIT_STRATEGY: "none",
95
+ },
96
+ stage: "stop",
97
+ environment: {
98
+ ...environment,
99
+ action: "stop",
105
100
  },
106
101
  };
107
102
  };
@@ -1,5 +1,5 @@
1
- import { GitlabJobs } from "../types/gitlab-types";
2
1
  import { Context } from "../types/context";
2
+ import { CatladderJob } from "../types/jobs";
3
3
  import { createKubernetesDeployJobs } from "./kubernetes";
4
4
  import { DeployConfig } from "./types";
5
5
  export * from "./kubernetes";
@@ -7,7 +7,7 @@ export * from "./types";
7
7
  export * from "./utils";
8
8
  export type DeployTypes = {
9
9
  [type in DeployConfig["type"]]: {
10
- jobs: (context: Context) => GitlabJobs;
10
+ jobs: (context: Context) => CatladderJob[];
11
11
  defaults: () => Partial<Extract<DeployConfig, { type: type }>>;
12
12
  };
13
13
  };
@@ -1,18 +1,19 @@
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
1
  import { dump } from "js-yaml";
8
- import { createMongodbBaseConfig } from "./mongodb";
9
- import { createCloudsqlBaseConfig } from "./cloudsql";
2
+ import { merge } from "lodash";
3
+ import { DeployConfigKubernetesValues } from "..";
10
4
  import { getSecretVarNameForContext } from "../..";
5
+ import { getRunnerImage } from "../../runner";
6
+ import { Context } from "../../types/context";
7
+ import { CatladderJob } from "../../types/jobs";
11
8
  import { mergeWithMergingArrays } from "../../utils";
12
- import { DeployConfigKubernetesValues } from "..";
13
- import { PartialDeep } from "type-fest";
9
+ import { getBaseDeploymentJob, getBaseDeploymentStopJob } from "../base";
10
+ import { isOfDeployType } from "../types";
11
+ import { createCloudsqlBaseConfig } from "./cloudsql";
12
+ import { createMongodbBaseConfig } from "./mongodb";
14
13
 
15
- export const createKubernetesDeployJobs = (context: Context): GitlabJobs => {
14
+ export const createKubernetesDeployJobs = (
15
+ context: Context
16
+ ): CatladderJob[] => {
16
17
  const deployConfig = context.componentConfig.deploy;
17
18
  if (deployConfig === false) {
18
19
  return [];
@@ -91,28 +92,26 @@ export const createKubernetesDeployJobs = (context: Context): GitlabJobs => {
91
92
  namespace: context.environment.envVars.KUBE_NAMESPACE,
92
93
  };
93
94
  const shared = {
94
- job: {
95
- image: getRunnerImage("kubernetes"),
96
- variables: {
97
- ...context.environment.envVars,
98
- HELM_EXPERIMENTAL_OCI: "1",
99
- IMAGE_PULL_SECRET: `gitlab-registry-${context.componentName}`,
100
- KUBE_VALUES: dump(kubeValues, {
101
- lineWidth: -1,
102
- quotingType: "'",
103
- forceQuotes: true,
104
- }),
105
- HELM_GITLAB_CHART_NAME: "the-panter-chart",
106
- HELM_ARGS: [
107
- ...(deployConfig.debug ? ["--debug"] : []),
108
- ...(deployConfig.additionalHelmArgs ?? []),
109
- ].join(" "),
110
- COMPONENT_NAME: context.componentName,
111
- BUILD_ID: context.commitInfo?.buildId,
112
- // TODO: unify with docker build stage
113
- IMAGE_NAME: context.environment.shortName + "/" + context.componentName,
114
- IMAGE_TAG: "$CI_COMMIT_SHA",
115
- },
95
+ image: getRunnerImage("kubernetes"),
96
+ variables: {
97
+ ...context.environment.envVars,
98
+ HELM_EXPERIMENTAL_OCI: "1",
99
+ IMAGE_PULL_SECRET: `gitlab-registry-${context.componentName}`,
100
+ KUBE_VALUES: dump(kubeValues, {
101
+ lineWidth: -1,
102
+ quotingType: "'",
103
+ forceQuotes: true,
104
+ }),
105
+ HELM_GITLAB_CHART_NAME: "the-panter-chart",
106
+ HELM_ARGS: [
107
+ ...(deployConfig.debug ? ["--debug"] : []),
108
+ ...(deployConfig.additionalHelmArgs ?? []),
109
+ ].join(" "),
110
+ COMPONENT_NAME: context.componentName,
111
+ BUILD_ID: context.commitInfo?.buildId,
112
+ // TODO: unify with docker build stage
113
+ IMAGE_NAME: context.environment.shortName + "/" + context.componentName,
114
+ IMAGE_TAG: "$CI_COMMIT_SHA",
116
115
  },
117
116
  };
118
117
 
@@ -136,24 +135,20 @@ export const createKubernetesDeployJobs = (context: Context): GitlabJobs => {
136
135
  ];
137
136
  return [
138
137
  merge({}, baseDeploymentJob, shared, {
139
- job: {
140
- script: [
141
- ...connectContext,
142
- "kubernetesCreateSecret",
143
- "kubernetesDeploy",
144
- "echo deployment successful 😻",
145
- ],
146
- environment: {
147
- kubernetes: kubernetesEnvironment,
148
- },
138
+ script: [
139
+ ...connectContext,
140
+ "kubernetesCreateSecret",
141
+ "kubernetesDeploy",
142
+ "echo deployment successful 😻",
143
+ ],
144
+ environment: {
145
+ kubernetes: kubernetesEnvironment,
149
146
  },
150
147
  }),
151
148
  merge({}, baseStopJob, shared, {
152
- job: {
153
- script: [...connectContext, "kubernetesDelete"],
154
- environment: {
155
- kubernetes: kubernetesEnvironment,
156
- },
149
+ script: [...connectContext, "kubernetesDelete"],
150
+ environment: {
151
+ kubernetes: kubernetesEnvironment,
157
152
  },
158
153
  }),
159
154
  ];
@@ -26,7 +26,8 @@ describe("createChildPipeline", () => {
26
26
  };
27
27
 
28
28
  it("creates a pipeline for a single app on the main branch", async () => {
29
- const { image, stages, workflow, ...jobs } = await createChildPipeline(
29
+ const { image, jobs } = await createChildPipeline(
30
+ "gitlab",
30
31
  "mainBranch",
31
32
  config
32
33
  );
@@ -1,24 +1,25 @@
1
1
  import { getAllEnvsByTrigger, getAllEnvsInAllComponents } from "../config";
2
- import { createJobs } from "./createJobs";
3
2
  import { RULES_ALWAYS } from "../rules";
4
3
  import { getRunnerImage } from "../runner";
4
+ import { GitlabPipeline, Pipeline, PipelineJob, PipelineType } from "../types";
5
5
  import { Config, PipelineTrigger } from "../types/config";
6
- import { GitlabJobDef } from "../types/gitlab-types";
6
+ import { createJobs } from "./createJobs";
7
+
7
8
  const baseStages = ["setup", "test", "build", "deploy", "verify", "stop"];
8
- export const createChildPipeline = async (
9
+ export const createChildPipeline = async <T extends PipelineType>(
10
+ type: T,
9
11
  trigger: PipelineTrigger,
10
12
  config: Config
11
- ) => {
13
+ ): Promise<Pipeline<T>> => {
12
14
  const components = Object.keys(config.components);
13
15
 
14
16
  // 2. write the triggering pipeline
15
-
16
- const jobs = await components.reduce<Promise<Record<string, GitlabJobDef>>>(
17
+ const jobs = await components.reduce<Promise<Record<string, PipelineJob<T>>>>(
17
18
  async (acc, componentName) => {
18
19
  const envs = getAllEnvsByTrigger(config, componentName, trigger);
19
20
  return {
20
21
  ...(await acc),
21
- ...(await createJobs(envs, config, componentName, trigger)),
22
+ ...(await createJobs(type, envs, config, componentName, trigger)),
22
23
  };
23
24
  },
24
25
  Promise.resolve({})
@@ -37,18 +38,19 @@ export const createChildPipeline = async (
37
38
  ],
38
39
  []
39
40
  );
40
-
41
- const childPipeline = {
42
- image: getRunnerImage("jobs-default"), // default image
43
- variables: {
44
- FF_USE_FASTZIP: "true",
45
- },
46
- workflow: {
47
- rules: RULES_ALWAYS,
48
- },
49
- stages,
50
- ...jobs,
51
- };
52
-
53
- return childPipeline as typeof childPipeline & Record<string, GitlabJobDef>;
41
+ if (type === "gitlab") {
42
+ const pipeline: GitlabPipeline = {
43
+ image: getRunnerImage("jobs-default"), // default image
44
+ variables: {
45
+ FF_USE_FASTZIP: "true",
46
+ },
47
+ workflow: {
48
+ rules: RULES_ALWAYS,
49
+ },
50
+ stages,
51
+ jobs,
52
+ };
53
+ return pipeline as Pipeline<T>;
54
+ }
55
+ throw new Error(`${type} is not supported`);
54
56
  };
@@ -3,13 +3,15 @@ import { isObject } from "lodash";
3
3
  import { BUILD_TYPES } from "../build";
4
4
  import { createContext } from "../context";
5
5
  import { DEPLOY_TYPES } from "../deploy";
6
+ import { PipelineJob, PipelineType } from "../types";
6
7
  import { Config, PipelineTrigger } from "../types/config";
7
- import { Context, CommitInfo } from "../types/context";
8
- import { GitlabJob, GitlabJobDef, GitlabJobs } from "../types/gitlab-types";
8
+ import { CommitInfo, Context } from "../types/context";
9
+ import { CatladderJob } from "../types/jobs";
9
10
  import { notNil } from "../utils";
10
- import { getYarnInfo } from "./yarnInfo";
11
+ import { makeGitlabJob } from "./gitlab/makeGitlabJob";
12
+ import { getPackageManagerInfo } from "./packageManager";
11
13
 
12
- const createRawJobs = (context: Context): GitlabJobs => {
14
+ const createRawJobs = (context: Context): CatladderJob[] => {
13
15
  if (context.componentConfig.deploy === false) {
14
16
  return [];
15
17
  }
@@ -35,7 +37,7 @@ const getFullReferencedJobName = (
35
37
  referencedJobName: string,
36
38
  componentName: string,
37
39
  env: string,
38
- allRawJobs: GitlabJobs
40
+ allRawJobs: CatladderJob[]
39
41
  ) => {
40
42
  const referencedJob = allRawJobs.find((j) => j.name === referencedJobName);
41
43
  if (!referencedJob) {
@@ -47,18 +49,17 @@ const getFullReferencedJobName = (
47
49
  // replaces references to other jobs with the full name
48
50
  // the full name contains the componentname and the env name (if any)
49
51
  const replaceReferences = (
50
- job: GitlabJob,
52
+ job: CatladderJob,
51
53
  componentName: string,
52
54
  env: string,
53
- allRawJobs: GitlabJobs
54
- ): GitlabJobDef => {
55
- const def = job.job;
55
+ allRawJobs: CatladderJob[]
56
+ ): CatladderJob<string> => {
56
57
  const stage =
57
- job.envMode === "stagePerEnv" ? `${def.stage} ${env}` : def.stage;
58
+ job.envMode === "stagePerEnv" ? `${job.stage} ${env}` : job.stage;
58
59
  return {
59
- ...def,
60
+ ...job,
60
61
  stage,
61
- needs: def.needs?.map((n) =>
62
+ needs: job.needs?.map((n) =>
62
63
  isObject(n)
63
64
  ? {
64
65
  job: getFullReferencedJobName(
@@ -71,25 +72,22 @@ const replaceReferences = (
71
72
  }
72
73
  : getFullReferencedJobName(n, componentName, env, allRawJobs)
73
74
  ),
74
- environment: def.environment?.on_stop
75
+ environment: job.environment?.on_stop
75
76
  ? {
76
- ...def.environment,
77
+ ...job.environment,
77
78
  on_stop: getFullReferencedJobName(
78
- def.environment.on_stop,
79
+ job.environment.on_stop,
79
80
  componentName,
80
81
  env,
81
82
  allRawJobs
82
83
  ),
83
84
  }
84
- : def.environment,
85
- dependencies: def.dependencies?.map((n) =>
86
- getFullReferencedJobName(n, componentName, env, allRawJobs)
87
- ),
85
+ : job.environment,
88
86
  };
89
87
  };
90
88
 
91
89
  // this can be removed once https://gitlab.com/gitlab-org/gitlab/-/issues/220758 is resolved
92
- const addStageNeeds = (jobs: GitlabJobs): GitlabJobs => {
90
+ const addStageNeeds = (jobs: CatladderJob[]): CatladderJob[] => {
93
91
  // when a job defines needsStages, we add these as needs
94
92
  return jobs.map((job) => {
95
93
  if (!job.needsStages || job.needsStages.length === 0) {
@@ -98,9 +96,7 @@ const addStageNeeds = (jobs: GitlabJobs): GitlabJobs => {
98
96
 
99
97
  const neededJobs = jobs
100
98
  .map((j) => {
101
- const neededStage = job.needsStages?.find(
102
- (s) => j.job.stage === s.stage
103
- );
99
+ const neededStage = job.needsStages?.find((s) => j.stage === s.stage);
104
100
  if (neededStage) {
105
101
  return {
106
102
  job: j.name,
@@ -111,19 +107,19 @@ const addStageNeeds = (jobs: GitlabJobs): GitlabJobs => {
111
107
  .filter(notNil);
112
108
  return {
113
109
  ...job,
114
- job: {
115
- ...job.job,
116
- needs: [...(job.job.needs ?? []), ...neededJobs],
117
- },
110
+
111
+ needs: [...(job.needs ?? []), ...neededJobs],
118
112
  };
119
113
  });
120
114
  };
121
- export const createJobs = async (
115
+
116
+ export const createJobs = async <T extends PipelineType>(
117
+ type: T,
122
118
  envs: string[],
123
119
  config: Config,
124
120
  componentName: string,
125
121
  trigger: PipelineTrigger
126
- ): Promise<Record<string, GitlabJobDef>> => {
122
+ ): Promise<Record<string, PipelineJob<T>>> => {
127
123
  const commitInfo: CommitInfo = {
128
124
  refName: process.env.CI_COMMIT_REF_NAME ?? "unknown",
129
125
  refSlug: process.env.CI_COMMIT_REF_SLUG ?? "unknown",
@@ -134,7 +130,7 @@ export const createJobs = async (
134
130
  trigger,
135
131
  };
136
132
 
137
- const yarnInfo = await getYarnInfo(config, componentName);
133
+ const packageManagerInfo = await getPackageManagerInfo(config, componentName);
138
134
 
139
135
  return envs.reduce((acc, env) => {
140
136
  const context = createContext(
@@ -142,22 +138,35 @@ export const createJobs = async (
142
138
  componentName,
143
139
  env,
144
140
  commitInfo,
145
- yarnInfo
141
+ packageManagerInfo
146
142
  );
147
143
  const jobs = addStageNeeds(createRawJobs(context));
148
144
 
149
- return {
145
+ const result = {
150
146
  ...acc,
151
- ...jobs.reduce((acc, job) => {
152
- return {
153
- ...acc,
154
- [getFullJobName(
155
- job.name,
156
- componentName,
157
- job.envMode !== "none" ? env : undefined
158
- )]: replaceReferences(job, componentName, env, jobs),
159
- };
147
+ ...jobs.reduce<Record<string, PipelineJob<T>>>((acc, job) => {
148
+ const jobWithResolvedReferences = replaceReferences(
149
+ job,
150
+ componentName,
151
+ env,
152
+ jobs
153
+ );
154
+ const jobName = getFullJobName(
155
+ job.name,
156
+ componentName,
157
+ job.envMode !== "none" ? env : undefined
158
+ );
159
+ if (type === "gitlab") {
160
+ return {
161
+ ...acc,
162
+ [jobName]: makeGitlabJob(
163
+ jobWithResolvedReferences
164
+ ) as PipelineJob<T>,
165
+ };
166
+ }
167
+ throw new Error("not supported");
160
168
  }, {}),
161
169
  };
170
+ return result;
162
171
  }, {});
163
172
  };
@@ -0,0 +1,16 @@
1
+ import { BASE_RETRY } from "../../defaults";
2
+ import { GitlabJobDef } from "../../types";
3
+ import { CatladderJob } from "../../types/jobs";
4
+
5
+ export const makeGitlabJob = ({
6
+ envMode,
7
+ needsStages,
8
+ name,
9
+ ...rest
10
+ }: CatladderJob<string>): GitlabJobDef => {
11
+ return {
12
+ ...rest,
13
+ retry: BASE_RETRY,
14
+ interruptible: true,
15
+ };
16
+ };
@@ -0,0 +1,99 @@
1
+ import { exec } from "child-process-promise";
2
+ import { Config, PackageManagerInfo } from "../types";
3
+ import { pathEqual } from "path-equal";
4
+ import memoizee from "memoizee";
5
+ import { join } from "path";
6
+ import { existsSync } from "fs";
7
+
8
+ const execOrFail = async (cmd: string, onFail: string): Promise<string> => {
9
+ try {
10
+ return await exec(cmd).then((r) => r.stdout);
11
+ } catch (e) {
12
+ return onFail ?? null;
13
+ }
14
+ };
15
+
16
+ const getYarnVersion = memoizee(
17
+ async () => {
18
+ return await execOrFail("yarn --version", "");
19
+ },
20
+ { promise: true }
21
+ );
22
+
23
+ const getWorkspaces = memoizee(
24
+ async (isClassic: boolean): Promise<PackageManagerInfo["workspaces"]> => {
25
+ return isClassic
26
+ ? Object.values(
27
+ JSON.parse(
28
+ JSON.parse(await execOrFail("yarn workspaces --json info", "{}"))
29
+ ?.data ?? "{}"
30
+ )
31
+ )
32
+ : JSON.parse(
33
+ `[${(await execOrFail("yarn workspaces list --json --verbose", ""))
34
+ .trim()
35
+ .split("\n")
36
+ .join(",")}]`
37
+ );
38
+ },
39
+ { promise: true }
40
+ );
41
+ export const getPackageManagerInfo = async (
42
+ config: Config,
43
+ componentName: string
44
+ ): Promise<PackageManagerInfo> => {
45
+ // currently only supports yarn
46
+ const version = await getYarnVersion();
47
+ if (!version) throw new Error("could not get yarn version");
48
+ const isClassic = version.startsWith("1");
49
+
50
+ const component = config.components[componentName];
51
+ const workspaces = await getWorkspaces(isClassic);
52
+ const currentWorkspace = workspaces.find((w) =>
53
+ pathEqual(component.dir, w.location)
54
+ );
55
+ const componentIsInWorkspace = Boolean(currentWorkspace);
56
+ const workspaceRoot = "."; // currently we assume the root folder, later on we might support nested workspaces
57
+ const packageJson = join(component.dir, "package.json");
58
+ const workspacePackageJson = componentIsInWorkspace
59
+ ? join(workspaceRoot, "package.json")
60
+ : null;
61
+
62
+ const lockFile = componentIsInWorkspace
63
+ ? join(workspaceRoot, "yarn.lock")
64
+ : join(component.dir, "yarn.lock");
65
+ const configFiles = [".yarnrc", ".yarnrc.yml", ".npmrc", ".yarn"]; // ".yarn" is yarn 2 folder
66
+ const rcFiles = (
67
+ componentIsInWorkspace
68
+ ? configFiles
69
+ : configFiles.map((f) => join(component.dir, f))
70
+ ).filter((f) => existsSync(f));
71
+
72
+ // get all folders that this workspace depend on
73
+ // we will later copy them into the docker build
74
+ const workspaceDependencies = currentWorkspace
75
+ ? ([
76
+ ...currentWorkspace.workspaceDependencies,
77
+ ...currentWorkspace.mismatchedWorkspaceDependencies,
78
+ ]
79
+ .map((name) => workspaces.find((w) => w.name === name)?.location)
80
+ .filter(Boolean) as string[])
81
+ : [];
82
+
83
+ const pathsToCopyInDocker = [
84
+ packageJson,
85
+ ...(workspacePackageJson ? [workspacePackageJson] : []),
86
+ lockFile,
87
+ ...rcFiles,
88
+ ...workspaceDependencies,
89
+ ];
90
+ return {
91
+ type: "yarn",
92
+ workspaces,
93
+ version,
94
+ isClassic,
95
+ currentWorkspace,
96
+ componentIsInWorkspace,
97
+ pathsToCopyInDocker,
98
+ };
99
+ };