@catladder/pipeline 1.46.0 → 1.47.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.
@@ -1,214 +1,13 @@
1
- import { isObject, merge } from "lodash";
2
- import slugify from "slugify";
3
1
  import { BUILD_TYPES } from "../build";
4
2
  import type { BuildConfig } from "../build/types";
5
- import {
6
- GCLOUD_RUN_CANONICAL_HOST_SUFFIX,
7
- DEPLOY_TYPES,
8
- getKubernetesNamespace,
9
- } from "../deploy";
3
+ import { DEPLOY_TYPES } from "../deploy";
10
4
  import type { DeployConfig } from "../deploy/types";
11
- import { isOfDeployType } from "../deploy/types";
12
- import type { Config, DevLocalEnvConfig } from "../types/config";
13
- import { isKnowEnvType } from "../types/config";
14
- import type {
15
- CommitInfo,
16
- Context,
17
- Environment,
18
- PackageManagerInfo,
19
- } from "../types/context";
5
+ import type { Config } from "../types/config";
6
+ import type { CommitInfo, Context, PackageManagerInfo } from "../types/context";
20
7
  import { mergeWithMergingArrays } from "../utils";
21
- import {
22
- resolveReferences,
23
- translateLegacyFromComponents,
24
- } from "./resolveReferences";
8
+ import { getEnvironment } from "./getEnvironment";
25
9
 
26
- const sanitizeForEnVar = (s: string) => s.replace(/-/g, "_");
27
- export const getSecretVarName = (
28
- env: string,
29
- componentName: string,
30
- key: string
31
- ) => `CL_${sanitizeForEnVar(env)}_${sanitizeForEnVar(componentName)}_${key}`; // remove dash from component name
32
-
33
- const addIndexVar = (vars: Record<string, unknown>) => ({
34
- ...vars,
35
- _ALL_ENV_VAR_KEYS: JSON.stringify(Object.keys(vars)),
36
- });
37
-
38
- export const getSecretVarNameForContext = (context: Context, key: string) =>
39
- getSecretVarName(context.environment.shortName, context.componentName, key);
40
- export const getEnvironment = async (
41
- config: Config,
42
- componentName: string,
43
- env: string,
44
- commitInfo?: CommitInfo,
45
- alreadyVisited: Record<string, Record<string, boolean>> = {} // to prevent endless loop
46
- ): Promise<Environment> => {
47
- const defaultConfig = config.components[componentName];
48
- if (!defaultConfig) {
49
- throw new Error("unknown component " + componentName);
50
- }
51
-
52
- const envConfig = defaultConfig.env?.[env] ?? {};
53
- if (envConfig === false) {
54
- throw new Error("env is disabled: " + env);
55
- }
56
-
57
- const mergedConfig = mergeWithMergingArrays(defaultConfig, envConfig);
58
-
59
- // env type: if its set manually, use that, otherwise use the known env types
60
-
61
- const envType = envConfig?.type ?? (isKnowEnvType(env) ? env : null);
62
-
63
- if (!envType) {
64
- throw new Error(
65
- "Missing type in environment " + env + " in component " + componentName
66
- );
67
- }
68
-
69
- const basePredefinedVariables = {
70
- ENV_SHORT: env,
71
- APP_DIR: mergedConfig.dir,
72
- ENV_TYPE: envType,
73
- };
74
-
75
- const environmentName =
76
- envType === "review" && commitInfo
77
- ? `${env}/${commitInfo.refName}/${componentName}`
78
- : `${env}/${componentName}`;
79
-
80
- const environmentSlug =
81
- envType === "review" && commitInfo
82
- ? `${env}-${commitInfo.reviewSlug}-${componentName}`
83
- : `${env}-${componentName}`;
84
-
85
- let predefinedVariables: Record<string, string>;
86
- let host: string;
87
- let url: string;
88
- if (envType === "local") {
89
- const devLocalConfig: DevLocalEnvConfig = mergedConfig;
90
- const port = devLocalConfig.port ?? 3000;
91
- host = "localhost:" + port;
92
- url = "http://" + host;
93
- predefinedVariables = {
94
- ENV_SHORT: "local",
95
- ROOT_URL: url,
96
- PORT: port.toString(),
97
- };
98
- } else {
99
- const RELEASE_NAME = `${config.customerName}-${config.appName}-${environmentSlug}`;
100
-
101
- const componentSlug = slugify(componentName);
102
- const envInUrl =
103
- envType === "review" && commitInfo
104
- ? `${commitInfo.reviewSlug}.${env}`
105
- : env;
106
-
107
- const domainCanonical =
108
- (mergedConfig?.deploy &&
109
- mergedConfig?.deploy.type === "kubernetes" &&
110
- mergedConfig.deploy.cluster?.domainCanonical) || // for convenience, we allow clusters to define a canonical domain, because a cluster has a fixed ip and you will usually have a domain pointing to that cluster
111
- config.domainCanonical ||
112
- "panter.cloud";
113
-
114
- const HOST_CANONICAL = isOfDeployType(mergedConfig.deploy, "kubernetes")
115
- ? `${componentSlug}.${envInUrl}.${config.appName}.${config.customerName}.${domainCanonical}`
116
- : isOfDeployType(mergedConfig.deploy, "google-cloudrun")
117
- ? environmentSlug +
118
- "-" +
119
- process.env[
120
- getSecretVarName(env, componentName, GCLOUD_RUN_CANONICAL_HOST_SUFFIX)
121
- ]
122
- : "";
123
- host = mergedConfig?.host ?? HOST_CANONICAL;
124
- const url = `https://${host}`;
125
-
126
- // FIXME: move to kube specific jobs
127
- const KUBE_APP_NAME_PREFIX =
128
- envType === "review" && commitInfo ? `${commitInfo.reviewSlug}-` : "";
129
-
130
- const KUBE_APP_NAME = `${KUBE_APP_NAME_PREFIX}${componentName}`;
131
- const KUBE_NAMESPACE = getKubernetesNamespace(config, env);
132
-
133
- predefinedVariables = {
134
- ...basePredefinedVariables,
135
- HOST_CANONICAL,
136
- HOST: host,
137
- ROOT_URL: url,
138
- KUBE_NAMESPACE,
139
- KUBE_APP_NAME,
140
- KUBE_APP_NAME_PREFIX,
141
- RELEASE_NAME,
142
- };
143
- }
144
- const publicEnvVarsRaw = mergedConfig.vars?.public ?? {};
145
-
146
- const additionalSecretKeys = mergedConfig.deploy
147
- ? DEPLOY_TYPES[mergedConfig.deploy.type].additionalSecretKeys(
148
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
149
- mergedConfig.deploy as any
150
- )
151
- : [];
152
-
153
- const secretEnvVarKeys = [
154
- ...(mergedConfig.vars?.secret ?? []),
155
- ...additionalSecretKeys,
156
- ];
157
- const secretEnvVars = Object.fromEntries(
158
- secretEnvVarKeys.map((key) => [
159
- key,
160
- `$${getSecretVarName(env, componentName, key)}`,
161
- ])
162
- );
163
-
164
- // this is deprecated, we now support: $componentname:FOO
165
- const legacyFromComponents = mergedConfig.vars?.fromComponents ?? {};
166
- const publicEnvVarsRawWithLegasyFromComponents = merge(
167
- {},
168
- translateLegacyFromComponents(legacyFromComponents),
169
- publicEnvVarsRaw
170
- );
171
-
172
- const publicEnvVarsRawSanitized = Object.fromEntries(
173
- Object.entries(publicEnvVarsRawWithLegasyFromComponents).map(
174
- ([key, value]) => [
175
- key,
176
- isObject(value) ? JSON.stringify(value) : `${value}`,
177
- ]
178
- )
179
- );
180
-
181
- const envVarsRaw = addIndexVar({
182
- ...predefinedVariables,
183
- ...secretEnvVars,
184
- ...publicEnvVarsRawSanitized,
185
- });
186
-
187
- const envVars = await resolveReferences(
188
- envVarsRaw,
189
- async (componentName, variableName, alreadyVisited) => {
190
- const { envVars } = await getEnvironment(
191
- config,
192
- componentName,
193
- env,
194
- commitInfo,
195
- alreadyVisited
196
- );
197
- return envVars[variableName];
198
- },
199
- alreadyVisited
200
- );
201
- return {
202
- envType,
203
- host,
204
- fullName: environmentName,
205
- slug: environmentSlug,
206
- shortName: env,
207
- url: predefinedVariables.ROOT_URL,
208
- envVars,
209
- secretEnvVarKeys,
210
- };
211
- };
10
+ export * from "./getEnvironment";
212
11
 
213
12
  export const createContext = async (
214
13
  config: Config,
@@ -16,11 +16,6 @@ const DEPLOY_RUNNER_VARIABLES = {
16
16
  };
17
17
  type JobWithoutScript = Omit<CatladderJob, "script">;
18
18
  export const getBaseDeploymentJob = (context: Context): JobWithoutScript => {
19
- const environment = {
20
- name: context.environment.fullName,
21
- url: context.environment.url,
22
- };
23
-
24
19
  const hasDocker = requiresDockerBuild(context);
25
20
  const isStoppable = contextIsStoppable(context);
26
21
 
@@ -84,7 +79,7 @@ export const getBaseDeploymentJob = (context: Context): JobWithoutScript => {
84
79
  ...(hasDocker ? getDockerImageVariables(context) : {}),
85
80
  },
86
81
  environment: {
87
- ...environment,
82
+ ...context.environment.gitlabEnvironment,
88
83
  ...(isStoppable
89
84
  ? {
90
85
  on_stop: STOP_JOB_NAME,
@@ -98,10 +93,6 @@ export const getBaseDeploymentJob = (context: Context): JobWithoutScript => {
98
93
  export const getBaseDeploymentStopJob = (
99
94
  context: Context
100
95
  ): JobWithoutScript => {
101
- const environment = {
102
- name: context.environment.fullName,
103
- url: context.environment.url,
104
- };
105
96
  return {
106
97
  name: STOP_JOB_NAME,
107
98
  envMode: "stagePerEnv", // makes it easier to run manual tasks er env
@@ -124,17 +115,13 @@ export const getBaseDeploymentStopJob = (
124
115
  },
125
116
  stage: "stop",
126
117
  environment: {
127
- ...environment,
118
+ ...context.environment.gitlabEnvironment,
128
119
  action: "stop",
129
120
  },
130
121
  };
131
122
  };
132
123
 
133
124
  export const getBaseRollbackJob = (context: Context): JobWithoutScript => {
134
- const environment = {
135
- name: context.environment.fullName,
136
- url: context.environment.url,
137
- };
138
125
  return {
139
126
  name: ROLLBACK_JOB_NAME,
140
127
  envMode: "stagePerEnv", // makes it easier to run manual tasks er env
@@ -151,7 +138,7 @@ export const getBaseRollbackJob = (context: Context): JobWithoutScript => {
151
138
  },
152
139
  stage: "rollback",
153
140
  environment: {
154
- ...environment,
141
+ ...context.environment.gitlabEnvironment,
155
142
  action: "access",
156
143
  },
157
144
  };
@@ -39,7 +39,7 @@ export const createDeployJob = (context: Context): CatladderJob[] => {
39
39
  GCLOUD_DEPLOY_CREDENTIALS_KEY
40
40
  );
41
41
 
42
- const serviceName = context.environment.slug;
42
+ const serviceName = context.environment.fullName;
43
43
 
44
44
  const labelsString = Object.entries(getLabels(context))
45
45
  .map(([key, value]) => `${key}=${value}`)
@@ -32,6 +32,7 @@ export const createKubernetesDeployJobs = (
32
32
  image: getRunnerImage("kubernetes"),
33
33
  variables: {
34
34
  ...context.environment.envVars,
35
+ RELEASE_NAME: context.environment.fullName,
35
36
  HELM_EXPERIMENTAL_OCI: "1",
36
37
  KUBE_DOCKER_IMAGE_PULL_SECRET: `gitlab-registry-${context.componentName}`,
37
38
  KUBE_VALUES: dump(kubeValues, {
@@ -1,11 +1,23 @@
1
- import type { PipelineTrigger, ComponentConfig, Config, EnvType } from "./config";
1
+ import type {
2
+ PipelineTrigger,
3
+ ComponentConfig,
4
+ Config,
5
+ EnvType,
6
+ } from "./config";
2
7
 
3
8
  export type Environment = {
4
9
  host: string;
10
+ url: string;
11
+ /**
12
+ * the full name of the app. We use this as RELEASE_NAME in kubernetes and the service name in google cloud run
13
+ */
5
14
  fullName: string;
15
+ gitlabEnvironment: {
16
+ name: string;
17
+ url: string;
18
+ };
6
19
  shortName: string;
7
20
  slug: string;
8
- url: string;
9
21
  /**
10
22
  * env vars contain all build-time env vars. secrets have to be resolved (they are stored in gitlab)
11
23
  */