@catladder/pipeline 1.45.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.
- package/dist/bundles/catladder-gitlab/index.js +1 -1
- package/dist/constants.js +1 -1
- package/dist/context/getEnvironment.d.ts +5 -0
- package/dist/context/getEnvironment.js +374 -0
- package/dist/context/index.d.ts +2 -4
- package/dist/context/index.js +17 -218
- package/dist/deploy/base.js +4 -17
- package/dist/deploy/cloudRun/deployJob.js +1 -1
- package/dist/deploy/kubernetes/deployJob.js +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/context.d.ts +9 -1
- package/package.json +1 -1
- package/src/context/getEnvironment.ts +206 -0
- package/src/context/index.ts +5 -206
- package/src/deploy/base.ts +7 -18
- package/src/deploy/cloudRun/deployJob.ts +1 -1
- package/src/deploy/kubernetes/deployJob.ts +1 -0
- package/src/types/context.ts +14 -2
package/src/context/index.ts
CHANGED
|
@@ -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 {
|
|
12
|
-
import type {
|
|
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
|
-
|
|
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,
|
package/src/deploy/base.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getDockerImageVariables, requiresDockerBuild } from "../build/docker";
|
|
2
2
|
import type { Context } from "../types";
|
|
3
3
|
import type { CatladderJob } from "../types/jobs";
|
|
4
|
+
import { isOfDeployType } from "./types";
|
|
4
5
|
import { contextIsStoppable } from "./utils";
|
|
5
6
|
|
|
6
7
|
export const DEPLOY_JOB_NAME = "🚀 Deploy";
|
|
@@ -15,20 +16,16 @@ const DEPLOY_RUNNER_VARIABLES = {
|
|
|
15
16
|
};
|
|
16
17
|
type JobWithoutScript = Omit<CatladderJob, "script">;
|
|
17
18
|
export const getBaseDeploymentJob = (context: Context): JobWithoutScript => {
|
|
18
|
-
const environment = {
|
|
19
|
-
name: context.environment.fullName,
|
|
20
|
-
url: context.environment.url,
|
|
21
|
-
};
|
|
22
|
-
|
|
23
19
|
const hasDocker = requiresDockerBuild(context);
|
|
24
20
|
const isStoppable = contextIsStoppable(context);
|
|
25
21
|
|
|
26
22
|
const autoStop =
|
|
27
23
|
context.environment.envType === "review"
|
|
28
|
-
? "
|
|
24
|
+
? "2 week"
|
|
29
25
|
: context.environment.envType === "dev"
|
|
30
|
-
? "
|
|
26
|
+
? "4 weeks"
|
|
31
27
|
: undefined;
|
|
28
|
+
|
|
32
29
|
// if auto or manual is configured explicitly, use that
|
|
33
30
|
const whenDeployDefined =
|
|
34
31
|
context.componentConfig.deploy && context.componentConfig.deploy.when
|
|
@@ -82,7 +79,7 @@ export const getBaseDeploymentJob = (context: Context): JobWithoutScript => {
|
|
|
82
79
|
...(hasDocker ? getDockerImageVariables(context) : {}),
|
|
83
80
|
},
|
|
84
81
|
environment: {
|
|
85
|
-
...environment,
|
|
82
|
+
...context.environment.gitlabEnvironment,
|
|
86
83
|
...(isStoppable
|
|
87
84
|
? {
|
|
88
85
|
on_stop: STOP_JOB_NAME,
|
|
@@ -96,10 +93,6 @@ export const getBaseDeploymentJob = (context: Context): JobWithoutScript => {
|
|
|
96
93
|
export const getBaseDeploymentStopJob = (
|
|
97
94
|
context: Context
|
|
98
95
|
): JobWithoutScript => {
|
|
99
|
-
const environment = {
|
|
100
|
-
name: context.environment.fullName,
|
|
101
|
-
url: context.environment.url,
|
|
102
|
-
};
|
|
103
96
|
return {
|
|
104
97
|
name: STOP_JOB_NAME,
|
|
105
98
|
envMode: "stagePerEnv", // makes it easier to run manual tasks er env
|
|
@@ -122,17 +115,13 @@ export const getBaseDeploymentStopJob = (
|
|
|
122
115
|
},
|
|
123
116
|
stage: "stop",
|
|
124
117
|
environment: {
|
|
125
|
-
...environment,
|
|
118
|
+
...context.environment.gitlabEnvironment,
|
|
126
119
|
action: "stop",
|
|
127
120
|
},
|
|
128
121
|
};
|
|
129
122
|
};
|
|
130
123
|
|
|
131
124
|
export const getBaseRollbackJob = (context: Context): JobWithoutScript => {
|
|
132
|
-
const environment = {
|
|
133
|
-
name: context.environment.fullName,
|
|
134
|
-
url: context.environment.url,
|
|
135
|
-
};
|
|
136
125
|
return {
|
|
137
126
|
name: ROLLBACK_JOB_NAME,
|
|
138
127
|
envMode: "stagePerEnv", // makes it easier to run manual tasks er env
|
|
@@ -149,7 +138,7 @@ export const getBaseRollbackJob = (context: Context): JobWithoutScript => {
|
|
|
149
138
|
},
|
|
150
139
|
stage: "rollback",
|
|
151
140
|
environment: {
|
|
152
|
-
...environment,
|
|
141
|
+
...context.environment.gitlabEnvironment,
|
|
153
142
|
action: "access",
|
|
154
143
|
},
|
|
155
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.
|
|
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, {
|
package/src/types/context.ts
CHANGED
|
@@ -1,11 +1,23 @@
|
|
|
1
|
-
import type {
|
|
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
|
*/
|