@catladder/pipeline 2.9.3 → 2.10.1
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/bash/bashEscape.d.ts +4 -1
- package/dist/bash/bashEscape.js +7 -2
- package/dist/constants.js +1 -1
- package/dist/deploy/cloudRun/createJobs/cloudRunJobs.d.ts +5 -3
- package/dist/deploy/cloudRun/createJobs/cloudRunJobs.js +17 -101
- package/dist/deploy/cloudRun/createJobs/execute/onDeploy.d.ts +4 -0
- package/dist/deploy/cloudRun/createJobs/execute/onDeploy.js +120 -0
- package/dist/deploy/cloudRun/createJobs/execute/schedules.d.ts +3 -0
- package/dist/deploy/cloudRun/createJobs/execute/schedules.js +173 -0
- package/dist/deploy/cloudRun/createJobs/getCloudRunDeployScripts.js +4 -2
- package/dist/deploy/cloudRun/createJobs/getCloudRunStopScripts.js +4 -2
- package/dist/deploy/cloudRun/index.js +6 -2
- package/dist/deploy/cloudRun/utils/cloudRunExecutionUrl.d.ts +10 -0
- package/dist/deploy/cloudRun/utils/cloudRunExecutionUrl.js +16 -0
- package/dist/deploy/cloudRun/utils/jobName.d.ts +5 -1
- package/dist/deploy/cloudRun/utils/jobName.js +14 -2
- package/dist/deploy/types/googleCloudRun.d.ts +95 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/examples/__snapshots__/cloud-run-with-sql-legacy-jobs.test.ts.snap +1697 -0
- package/examples/__snapshots__/cloud-run-with-sql.test.ts.snap +133 -70
- package/examples/cloud-run-no-service.ts +6 -0
- package/examples/cloud-run-post-stop-job.ts +7 -0
- package/examples/cloud-run-service-custom-vpc-connector.ts +0 -1
- package/examples/cloud-run-service-custom-vpc.ts +0 -1
- package/examples/cloud-run-service-with-volumes.ts +9 -1
- package/examples/cloud-run-with-sql-legacy-jobs.test.ts +11 -0
- package/examples/cloud-run-with-sql-legacy-jobs.ts +49 -0
- package/examples/cloud-run-with-sql.ts +38 -4
- package/package.json +1 -1
- package/src/bash/bashEscape.ts +7 -1
- package/src/deploy/cloudRun/createJobs/cloudRunJobs.ts +16 -155
- package/src/deploy/cloudRun/createJobs/execute/onDeploy.ts +112 -0
- package/src/deploy/cloudRun/createJobs/execute/schedules.ts +186 -0
- package/src/deploy/cloudRun/createJobs/getCloudRunDeployScripts.ts +6 -8
- package/src/deploy/cloudRun/createJobs/getCloudRunStopScripts.ts +6 -8
- package/src/deploy/cloudRun/index.ts +6 -6
- package/src/deploy/cloudRun/utils/cloudRunExecutionUrl.ts +20 -0
- package/src/deploy/cloudRun/utils/jobName.ts +16 -1
- package/src/deploy/types/googleCloudRun.ts +123 -1
|
@@ -18,6 +18,7 @@ const config: Config = {
|
|
|
18
18
|
review: {
|
|
19
19
|
deploy: {
|
|
20
20
|
jobs: {
|
|
21
|
+
// in this example we only declare the job on the review environment.
|
|
21
22
|
["drop-db"]: {
|
|
22
23
|
command: [
|
|
23
24
|
"/bin/sh",
|
|
@@ -25,6 +26,12 @@ const config: Config = {
|
|
|
25
26
|
"mongosh \\$MONGO_URL --eval 'db.dropDatabase()'",
|
|
26
27
|
],
|
|
27
28
|
image: "rtsp/mongosh:latest",
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
execute: {
|
|
32
|
+
["drop-db"]: {
|
|
33
|
+
type: "job",
|
|
34
|
+
job: "drop-db",
|
|
28
35
|
when: "postStop",
|
|
29
36
|
},
|
|
30
37
|
},
|
|
@@ -34,7 +34,7 @@ const config: Config = {
|
|
|
34
34
|
jobs: {
|
|
35
35
|
migrate: {
|
|
36
36
|
command: "migrate",
|
|
37
|
-
|
|
37
|
+
|
|
38
38
|
volumes: {
|
|
39
39
|
myMount: {
|
|
40
40
|
type: "cloud-storage",
|
|
@@ -44,6 +44,14 @@ const config: Config = {
|
|
|
44
44
|
},
|
|
45
45
|
},
|
|
46
46
|
},
|
|
47
|
+
|
|
48
|
+
execute: {
|
|
49
|
+
migrate: {
|
|
50
|
+
type: "job",
|
|
51
|
+
job: "migrate",
|
|
52
|
+
when: "postDeploy",
|
|
53
|
+
},
|
|
54
|
+
},
|
|
47
55
|
},
|
|
48
56
|
},
|
|
49
57
|
},
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createYamlLocalPipeline } from "./__utils__/helpers";
|
|
2
|
+
import config from "./cloud-run-with-sql-legacy-jobs";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* This test is auto-generated.
|
|
6
|
+
* Modifications will be overwritten on every `yarn test` run!
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
it("matches snapshot for cloud-run-with-sql-legacy-jobs local pipeline YAML", async () => {
|
|
10
|
+
expect(await createYamlLocalPipeline(config)).toMatchSnapshot();
|
|
11
|
+
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { Config } from "../src";
|
|
2
|
+
|
|
3
|
+
const config: Config = {
|
|
4
|
+
appName: "test-app",
|
|
5
|
+
customerName: "pan",
|
|
6
|
+
components: {
|
|
7
|
+
api: {
|
|
8
|
+
dir: "api",
|
|
9
|
+
build: {
|
|
10
|
+
type: "node",
|
|
11
|
+
},
|
|
12
|
+
deploy: {
|
|
13
|
+
type: "google-cloudrun",
|
|
14
|
+
projectId: "google-project-id",
|
|
15
|
+
region: "europe-west6",
|
|
16
|
+
// optional, set min and max instances
|
|
17
|
+
// defaults to 0-100
|
|
18
|
+
service: {
|
|
19
|
+
minInstances: 0,
|
|
20
|
+
maxInstances: 5,
|
|
21
|
+
},
|
|
22
|
+
cloudSql: {
|
|
23
|
+
type: "unmanaged",
|
|
24
|
+
instanceConnectionName: "projectId:region:instancename",
|
|
25
|
+
dbUser: "my-user",
|
|
26
|
+
},
|
|
27
|
+
jobs: {
|
|
28
|
+
migration: {
|
|
29
|
+
when: "preDeploy",
|
|
30
|
+
command: "yarn migrate",
|
|
31
|
+
waitForCompletion: true,
|
|
32
|
+
},
|
|
33
|
+
["send-reminders"]: {
|
|
34
|
+
when: "schedule",
|
|
35
|
+
command: "yarn job:send-reminders",
|
|
36
|
+
schedule: "0 * * * *",
|
|
37
|
+
timeout: "15m",
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export default config;
|
|
46
|
+
|
|
47
|
+
export const information = {
|
|
48
|
+
title: "Cloud Run: With SQL",
|
|
49
|
+
};
|
|
@@ -25,16 +25,50 @@ const config: Config = {
|
|
|
25
25
|
dbUser: "my-user",
|
|
26
26
|
},
|
|
27
27
|
jobs: {
|
|
28
|
-
|
|
29
|
-
when: "preDeploy",
|
|
28
|
+
migrate: {
|
|
30
29
|
command: "yarn migrate",
|
|
30
|
+
},
|
|
31
|
+
["send-reminders"]: {
|
|
32
|
+
command: "yarn job:send-reminders",
|
|
33
|
+
args: ["--verbose=false"],
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
execute: {
|
|
37
|
+
migrate: {
|
|
38
|
+
type: "job",
|
|
39
|
+
job: "migrate",
|
|
40
|
+
when: "preDeploy",
|
|
31
41
|
waitForCompletion: true,
|
|
42
|
+
args: ["--verbose=true", "--create-db"],
|
|
43
|
+
},
|
|
44
|
+
["send-reminders-admins"]: {
|
|
45
|
+
type: "job",
|
|
46
|
+
when: "schedule",
|
|
47
|
+
job: "send-reminders",
|
|
48
|
+
args: ["--only-admins", "--verbose=true"],
|
|
49
|
+
schedule: "0 * * * *",
|
|
32
50
|
},
|
|
33
51
|
["send-reminders"]: {
|
|
52
|
+
type: "job",
|
|
53
|
+
when: "schedule",
|
|
54
|
+
job: "send-reminders",
|
|
55
|
+
schedule: "0 * * * *",
|
|
56
|
+
},
|
|
57
|
+
["call-http-endpoint"]: {
|
|
58
|
+
type: "http",
|
|
59
|
+
url: "${ROOT_URL}/myEndpoint",
|
|
34
60
|
when: "schedule",
|
|
35
|
-
command: "yarn job:send-reminders",
|
|
36
61
|
schedule: "0 * * * *",
|
|
37
|
-
|
|
62
|
+
method: "GET",
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
env: {
|
|
67
|
+
review: {
|
|
68
|
+
deploy: {
|
|
69
|
+
execute: {
|
|
70
|
+
"send-reminders": null, // disable on this env
|
|
71
|
+
},
|
|
38
72
|
},
|
|
39
73
|
},
|
|
40
74
|
},
|
package/package.json
CHANGED
package/src/bash/bashEscape.ts
CHANGED
|
@@ -57,6 +57,9 @@ export const escapeDoubleQuotes = (value: string | null | undefined) =>
|
|
|
57
57
|
export const escapeSingleQuotes = (value: string | null | undefined) =>
|
|
58
58
|
value?.toString().replace(/'/g, "\\'");
|
|
59
59
|
|
|
60
|
+
export type EscapeForDotEnvOptions = {
|
|
61
|
+
quoteMode: "auto" | "always";
|
|
62
|
+
};
|
|
60
63
|
/**
|
|
61
64
|
*
|
|
62
65
|
* escape env vars for .env files.
|
|
@@ -75,6 +78,9 @@ export const escapeSingleQuotes = (value: string | null | undefined) =>
|
|
|
75
78
|
*/
|
|
76
79
|
export const escapeForDotEnv = (
|
|
77
80
|
value: VariableValue | undefined | null,
|
|
81
|
+
options: EscapeForDotEnvOptions = {
|
|
82
|
+
quoteMode: "auto",
|
|
83
|
+
},
|
|
78
84
|
): string => {
|
|
79
85
|
if (value === undefined || value === null) {
|
|
80
86
|
return "";
|
|
@@ -82,7 +88,7 @@ export const escapeForDotEnv = (
|
|
|
82
88
|
if (typeof value === "string") {
|
|
83
89
|
// if string contains newlines, we need to wrap it in quotes
|
|
84
90
|
// we additionaly escape newlines, that give best compatibility
|
|
85
|
-
if (value.includes("\n")) {
|
|
91
|
+
if (options.quoteMode === "always" || value.includes("\n")) {
|
|
86
92
|
const newlinesReplaces = value.replace(/\n/g, "\\n");
|
|
87
93
|
|
|
88
94
|
// default to ", but if this is not possible, we try to use ' or `
|
|
@@ -1,90 +1,36 @@
|
|
|
1
1
|
import type { ComponentContext } from "../../../types/context";
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
} from "../../types/googleCloudRun";
|
|
3
|
+
import { getLabels } from "../../../context/getLabels";
|
|
4
|
+
import { notNil } from "../../../utils";
|
|
5
|
+
import type { DeployConfigCloudRunJob } from "../../types/googleCloudRun";
|
|
7
6
|
import { createArgsString } from "../utils/createArgsString";
|
|
8
|
-
import {
|
|
7
|
+
import { getFullJobName } from "../utils/jobName";
|
|
9
8
|
import {
|
|
10
9
|
gcloudRunCmd,
|
|
11
|
-
gcloudSchedulerCmd,
|
|
12
10
|
getCloudRunDeployConfig,
|
|
13
11
|
getCommonCloudRunArgs,
|
|
14
12
|
getCommonDeployArgs,
|
|
15
13
|
makeLabelString,
|
|
16
14
|
} from "./common";
|
|
17
|
-
import { getLabels } from "../../../context/getLabels";
|
|
18
|
-
import { createVolumeConfig } from "./volumes";
|
|
19
|
-
import type {
|
|
20
|
-
BashExpression,
|
|
21
|
-
StringOrBashExpression,
|
|
22
|
-
} from "../../../bash/BashExpression";
|
|
23
15
|
import { ENV_VARS_FILENAME } from "./constants";
|
|
24
|
-
import {
|
|
25
|
-
|
|
26
|
-
const getJobRunScriptForJob = (
|
|
27
|
-
context: ComponentContext,
|
|
28
|
-
jobName: StringOrBashExpression,
|
|
29
|
-
wait: boolean,
|
|
30
|
-
) => {
|
|
31
|
-
const commonArgs = getCommonCloudRunArgs(context);
|
|
32
|
-
|
|
33
|
-
const commonArgsString = createArgsString(commonArgs);
|
|
34
|
-
return `${gcloudRunCmd()} jobs execute ${jobName.toString()} ${commonArgsString}${
|
|
35
|
-
wait ? " --wait" : ""
|
|
36
|
-
}`;
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
export const getDeleteSchedulesScripts = (context: ComponentContext) => {
|
|
40
|
-
const deployConfig = getCloudRunDeployConfig(context);
|
|
41
|
-
const schedules = getSchedules(context);
|
|
42
|
-
const argsString = createArgsString({
|
|
43
|
-
project: deployConfig.projectId,
|
|
44
|
-
location: deployConfig.region,
|
|
45
|
-
});
|
|
46
|
-
return schedules
|
|
47
|
-
.map(({ name }) => {
|
|
48
|
-
return [`${gcloudSchedulerCmd()} jobs delete ${name} ${argsString}`];
|
|
49
|
-
})
|
|
50
|
-
.flat();
|
|
51
|
-
};
|
|
16
|
+
import { createVolumeConfig } from "./volumes";
|
|
17
|
+
import { getCloudRunJobArgsArg } from "./execute/onDeploy";
|
|
52
18
|
|
|
53
19
|
export const getDeleteJobsScripts = (context: ComponentContext) => {
|
|
54
20
|
const commonArgs = getCommonCloudRunArgs(context);
|
|
55
21
|
const commonArgsString = createArgsString(commonArgs);
|
|
56
22
|
const jobsWithNames = getCloudRunJobsWithNames(context);
|
|
57
23
|
|
|
58
|
-
return jobsWithNames.flatMap(({
|
|
24
|
+
return jobsWithNames.flatMap(({ fullJobName }) => [
|
|
59
25
|
// first delete all job executions. Otherwise delete might fail if one of those is still running
|
|
60
|
-
`${gcloudRunCmd()} jobs executions list ${commonArgsString} --job ${
|
|
61
|
-
`${gcloudRunCmd()} jobs delete ${
|
|
26
|
+
`${gcloudRunCmd()} jobs executions list ${commonArgsString} --job ${fullJobName} --format="value(name)" | xargs -I {} ${gcloudRunCmd()} jobs executions delete {} --quiet ${commonArgsString}`,
|
|
27
|
+
`${gcloudRunCmd()} jobs delete ${fullJobName} ${commonArgsString}`,
|
|
62
28
|
]);
|
|
63
29
|
};
|
|
64
30
|
|
|
65
|
-
export const getJobRunScripts = (
|
|
66
|
-
context: ComponentContext,
|
|
67
|
-
when: DeployConfigCloudRunJob["when"],
|
|
68
|
-
) => {
|
|
69
|
-
const jobsWithNames = getCloudRunJobsWithNames(context);
|
|
70
|
-
|
|
71
|
-
return jobsWithNames
|
|
72
|
-
.filter(({ job }) => job.when === when)
|
|
73
|
-
.map(({ jobName, job }) => {
|
|
74
|
-
// always wait for completion for preStop and postStop jobs
|
|
75
|
-
// since stop will delete the jobs afterwards, so they will fail
|
|
76
|
-
const waitForCompletion = ["preStop", "postStop"].includes(when)
|
|
77
|
-
? true
|
|
78
|
-
: "waitForCompletion" in job
|
|
79
|
-
? (job.waitForCompletion ?? false)
|
|
80
|
-
: false;
|
|
81
|
-
return getJobRunScriptForJob(context, jobName, waitForCompletion);
|
|
82
|
-
});
|
|
83
|
-
};
|
|
84
|
-
|
|
85
31
|
export const getJobCreateScripts = (context: ComponentContext): string[] =>
|
|
86
32
|
getCloudRunJobsWithNames(context).map(
|
|
87
|
-
({ job,
|
|
33
|
+
({ job, fullJobName }, jobIndex): string => {
|
|
88
34
|
const commandArray = Array.isArray(job.command)
|
|
89
35
|
? job.command
|
|
90
36
|
: job.command.split(" ");
|
|
@@ -98,6 +44,7 @@ export const getJobCreateScripts = (context: ComponentContext): string[] =>
|
|
|
98
44
|
const commonDeployArgsString = createArgsString(
|
|
99
45
|
{
|
|
100
46
|
command: `"${commandArray.join(",")}"`,
|
|
47
|
+
args: getCloudRunJobArgsArg(job.args),
|
|
101
48
|
labels: `"${makeLabelString(getLabels(context))},cloud-run-job-name=$current_job_name"`,
|
|
102
49
|
image: `"${job.image ?? commonImage}"`,
|
|
103
50
|
project,
|
|
@@ -125,7 +72,7 @@ export const getJobCreateScripts = (context: ComponentContext): string[] =>
|
|
|
125
72
|
jobIndex === 0
|
|
126
73
|
? `exist_job_names="$(\n ${gcloudRunCmd()} jobs list --filter='metadata.name ~ ${context.env}.*${context.name}' --format='value(name)' --limit=999 --project='${project}' --region='${region}'\n)"`
|
|
127
74
|
: null,
|
|
128
|
-
`current_job_name="${
|
|
75
|
+
`current_job_name="${fullJobName}"`,
|
|
129
76
|
'if grep "$current_job_name" <<<"$exist_job_names" >/dev/null; then',
|
|
130
77
|
` ${gcloudRunCmd()} jobs update "$current_job_name" ${commonDeployArgsString}`,
|
|
131
78
|
"else",
|
|
@@ -137,104 +84,18 @@ export const getJobCreateScripts = (context: ComponentContext): string[] =>
|
|
|
137
84
|
},
|
|
138
85
|
);
|
|
139
86
|
|
|
140
|
-
export const
|
|
141
|
-
context: ComponentContext,
|
|
142
|
-
): string[] => {
|
|
143
|
-
const schedules = getSchedules(context);
|
|
144
|
-
const { region: location, projectId: project } =
|
|
145
|
-
getCloudRunDeployConfig(context);
|
|
146
|
-
|
|
147
|
-
return schedules.map((scheduler, jobIndex): string => {
|
|
148
|
-
const uri = getSchedulerUrl(scheduler, context);
|
|
149
|
-
|
|
150
|
-
const argsString = createArgsString({
|
|
151
|
-
project,
|
|
152
|
-
location,
|
|
153
|
-
uri: `"$current_job_uri"`,
|
|
154
|
-
"http-method": "POST",
|
|
155
|
-
"oauth-service-account-email": `"$GCLOUD_PROJECT_NUMBER-compute@developer.gserviceaccount.com"`,
|
|
156
|
-
schedule: `"${scheduler.schedule}"`,
|
|
157
|
-
"max-retry-attempts": scheduler.maxRetryAttempts ?? 0,
|
|
158
|
-
});
|
|
159
|
-
return [
|
|
160
|
-
jobIndex === 0
|
|
161
|
-
? `exist_scheduler_names="$(\n ${gcloudSchedulerCmd()} jobs list --filter='httpTarget.uri ~ ${context.env}.*${context.name}' --format='value(name)' --limit=999 --location='${location}' --project='${project}'\n)"`
|
|
162
|
-
: null,
|
|
163
|
-
`current_job_uri="${uri}"`,
|
|
164
|
-
`current_scheduler_name="${scheduler.name}"`,
|
|
165
|
-
`if grep "$current_scheduler_name" <<<"$exist_scheduler_names" >/dev/null; then`,
|
|
166
|
-
` ${gcloudSchedulerCmd()} jobs update http "$current_scheduler_name" ${argsString}`,
|
|
167
|
-
`else`,
|
|
168
|
-
` ${gcloudSchedulerCmd()} jobs create http "$current_scheduler_name" ${argsString}`,
|
|
169
|
-
`fi`,
|
|
170
|
-
]
|
|
171
|
-
.filter(notNil)
|
|
172
|
-
.join("\n");
|
|
173
|
-
});
|
|
174
|
-
};
|
|
175
|
-
|
|
176
|
-
type Scheduler = {
|
|
177
|
-
name: StringOrBashExpression;
|
|
178
|
-
maxRetryAttempts?: number;
|
|
179
|
-
schedule: string;
|
|
180
|
-
} & {
|
|
181
|
-
type: "cloudRunJob";
|
|
182
|
-
jobName: StringOrBashExpression;
|
|
183
|
-
};
|
|
184
|
-
|
|
185
|
-
const getSchedulerUrl = (scheduler: Scheduler, context: ComponentContext) => {
|
|
186
|
-
if (scheduler.type === "cloudRunJob") {
|
|
187
|
-
const { region: location, projectId: project } =
|
|
188
|
-
getCloudRunDeployConfig(context);
|
|
189
|
-
|
|
190
|
-
const uriBase = `https://${location}-run.googleapis.com/apis/run.googleapis.com/v1/namespaces/${project}/jobs`;
|
|
191
|
-
|
|
192
|
-
return `${uriBase}/${scheduler.jobName}:run`;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
throw new Error(`Unknown scheduler type: ${scheduler.type}`);
|
|
196
|
-
};
|
|
197
|
-
|
|
198
|
-
const getSchedules = (context: ComponentContext): Scheduler[] => {
|
|
199
|
-
const jobsWithNames = getCloudRunJobsWithNames(context);
|
|
200
|
-
|
|
201
|
-
return jobsWithNames
|
|
202
|
-
.filter(
|
|
203
|
-
(
|
|
204
|
-
entry,
|
|
205
|
-
): entry is {
|
|
206
|
-
jobName: BashExpression;
|
|
207
|
-
job: DeployConfigCloudRunJobWithSchedule;
|
|
208
|
-
jobKey: string;
|
|
209
|
-
} => entry.job.when === "schedule",
|
|
210
|
-
)
|
|
211
|
-
.map(({ job: { maxRetryAttempts, schedule }, jobName }) => {
|
|
212
|
-
const schedulerName = jobName.concat("-scheduler");
|
|
213
|
-
return {
|
|
214
|
-
name: schedulerName,
|
|
215
|
-
maxRetryAttempts,
|
|
216
|
-
schedule,
|
|
217
|
-
type: "cloudRunJob",
|
|
218
|
-
jobName,
|
|
219
|
-
};
|
|
220
|
-
});
|
|
221
|
-
};
|
|
222
|
-
|
|
223
|
-
const getCloudRunJobsWithNames = (context: ComponentContext) => {
|
|
87
|
+
export const getCloudRunJobsWithNames = (context: ComponentContext) => {
|
|
224
88
|
const deployConfig = getCloudRunDeployConfig(context);
|
|
225
89
|
|
|
226
|
-
const getFullJobName = (name: string) =>
|
|
227
|
-
getCloudRunJobName(context.environment.fullName, name);
|
|
228
|
-
|
|
229
90
|
const jobsWithNames = Object.entries(deployConfig.jobs ?? {})
|
|
230
91
|
// filter out disabled jobs
|
|
231
92
|
.filter((entry): entry is [string, DeployConfigCloudRunJob] =>
|
|
232
93
|
Boolean(entry[1]),
|
|
233
94
|
)
|
|
234
|
-
.map(([
|
|
235
|
-
|
|
95
|
+
.map(([jobName, job]) => ({
|
|
96
|
+
fullJobName: getFullJobName(context, jobName),
|
|
236
97
|
job,
|
|
237
|
-
|
|
98
|
+
jobName,
|
|
238
99
|
}));
|
|
239
100
|
return jobsWithNames;
|
|
240
101
|
};
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import type { StringOrBashExpression } from "../../../../bash";
|
|
2
|
+
import type { ComponentContext } from "../../../../types/context";
|
|
3
|
+
import type {
|
|
4
|
+
DeployConfigCloudRunExecuteOnDeploy,
|
|
5
|
+
DeployConfigCloudRunJob,
|
|
6
|
+
} from "../../../types/googleCloudRun";
|
|
7
|
+
import { createArgsString } from "../../utils/createArgsString";
|
|
8
|
+
import { getFullJobName } from "../../utils/jobName";
|
|
9
|
+
import { getCloudRunJobsWithNames } from "../cloudRunJobs";
|
|
10
|
+
import {
|
|
11
|
+
gcloudRunCmd,
|
|
12
|
+
getCloudRunDeployConfig,
|
|
13
|
+
getCommonCloudRunArgs,
|
|
14
|
+
} from "../common";
|
|
15
|
+
|
|
16
|
+
type Execute = {
|
|
17
|
+
jobName: StringOrBashExpression;
|
|
18
|
+
config: DeployConfigCloudRunExecuteOnDeploy;
|
|
19
|
+
};
|
|
20
|
+
export const getOnDeployExecuteScript = (
|
|
21
|
+
context: ComponentContext,
|
|
22
|
+
when: DeployConfigCloudRunExecuteOnDeploy["when"],
|
|
23
|
+
) => {
|
|
24
|
+
const executes = getExecutes(context);
|
|
25
|
+
|
|
26
|
+
return executes
|
|
27
|
+
.filter(({ config }) => config.when === when)
|
|
28
|
+
.map((execute) => {
|
|
29
|
+
return getJobRunScriptForExecute(context, execute);
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const getExecutes = (context: ComponentContext): Execute[] => {
|
|
34
|
+
const deployConfig = getCloudRunDeployConfig(context);
|
|
35
|
+
return [
|
|
36
|
+
...getLegacyExecutes(context),
|
|
37
|
+
...Object.entries(deployConfig.execute ?? {}).flatMap(([key, value]) => {
|
|
38
|
+
if (!value || (value.when !== "schedule" && value.type !== "job")) {
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
return [
|
|
42
|
+
{
|
|
43
|
+
jobName: key,
|
|
44
|
+
config: value,
|
|
45
|
+
} as Execute,
|
|
46
|
+
];
|
|
47
|
+
}),
|
|
48
|
+
];
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const getLegacyExecutes = (context: ComponentContext): Execute[] => {
|
|
52
|
+
const jobsWithNames = getCloudRunJobsWithNames(context);
|
|
53
|
+
|
|
54
|
+
return jobsWithNames.flatMap(({ jobName, job }) => {
|
|
55
|
+
if (
|
|
56
|
+
!job.when ||
|
|
57
|
+
!["preDeploy", "postDeploy", "preStop", "postStop"].includes(job.when)
|
|
58
|
+
) {
|
|
59
|
+
return [];
|
|
60
|
+
}
|
|
61
|
+
return [
|
|
62
|
+
{
|
|
63
|
+
jobName,
|
|
64
|
+
config: {
|
|
65
|
+
job: jobName,
|
|
66
|
+
type: "job",
|
|
67
|
+
when: job.when,
|
|
68
|
+
...(job.when === "preDeploy" || job.when === "postDeploy"
|
|
69
|
+
? {
|
|
70
|
+
waitForCompletion: job.waitForCompletion,
|
|
71
|
+
}
|
|
72
|
+
: {}),
|
|
73
|
+
} as Execute["config"],
|
|
74
|
+
},
|
|
75
|
+
];
|
|
76
|
+
});
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const getJobRunScriptForExecute = (
|
|
80
|
+
context: ComponentContext,
|
|
81
|
+
{ jobName, config }: Execute,
|
|
82
|
+
) => {
|
|
83
|
+
const commonArgs = getCommonCloudRunArgs(context);
|
|
84
|
+
|
|
85
|
+
// always wait for completion for preStop and postStop jobs
|
|
86
|
+
// since stop will delete the jobs afterwards, so they will fail
|
|
87
|
+
const waitForCompletion = ["preStop", "postStop"].includes(config.when)
|
|
88
|
+
? true // always
|
|
89
|
+
: "waitForCompletion" in config
|
|
90
|
+
? (config.waitForCompletion ?? false) // depends on config
|
|
91
|
+
: false;
|
|
92
|
+
|
|
93
|
+
const argString = createArgsString({
|
|
94
|
+
...commonArgs,
|
|
95
|
+
wait: waitForCompletion === true ? true : undefined,
|
|
96
|
+
args: getCloudRunJobArgsArg(config.args),
|
|
97
|
+
});
|
|
98
|
+
const fullJobName = getFullJobName(context, jobName);
|
|
99
|
+
return `${gcloudRunCmd()} jobs execute ${fullJobName.toString()} ${argString}`;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
export const getCloudRunJobArgsArg = (
|
|
103
|
+
args:
|
|
104
|
+
| DeployConfigCloudRunExecuteOnDeploy["args"]
|
|
105
|
+
| DeployConfigCloudRunJob["args"],
|
|
106
|
+
) => {
|
|
107
|
+
return args !== undefined
|
|
108
|
+
? args.length > 0
|
|
109
|
+
? args?.map((arg) => `"${arg}"`).join(",")
|
|
110
|
+
: ""
|
|
111
|
+
: undefined;
|
|
112
|
+
};
|