@catladder/pipeline 4.6.4 → 4.7.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/constants.js +1 -1
- package/dist/deploy/cloudRun/index.js +12 -0
- package/dist/deploy/index.d.ts +5 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/pipeline/createJobsForComponent.js +5 -4
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/config.d.ts +8 -0
- package/dist/verify/createVerifyJobs.d.ts +4 -0
- package/dist/verify/createVerifyJobs.js +229 -0
- package/dist/verify/index.d.ts +2 -0
- package/dist/verify/index.js +26 -0
- package/dist/verify/types.d.ts +16 -0
- package/dist/verify/types.js +5 -0
- package/examples/__snapshots__/cloud-run-verify.test.ts.snap +3061 -0
- package/examples/cloud-run-verify.test.ts +12 -0
- package/examples/cloud-run-verify.ts +50 -0
- package/package.json +1 -1
- package/src/deploy/cloudRun/index.ts +23 -1
- package/src/deploy/index.ts +5 -0
- package/src/index.ts +1 -0
- package/src/pipeline/createJobsForComponent.ts +4 -2
- package/src/types/config.ts +9 -0
- package/src/verify/createVerifyJobs.ts +81 -0
- package/src/verify/index.ts +2 -0
- package/src/verify/types.ts +18 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { it, expect } from "vitest";
|
|
2
|
+
import { createYamlLocalPipeline } from "./__utils__/helpers";
|
|
3
|
+
import config from "./cloud-run-verify";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* This test is auto-generated.
|
|
7
|
+
* Modifications will be overwritten on every `yarn test` run!
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
it("matches snapshot for cloud-run-verify local pipeline YAML", async () => {
|
|
11
|
+
expect(await createYamlLocalPipeline(config)).toMatchSnapshot();
|
|
12
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { Config } from "../src";
|
|
2
|
+
|
|
3
|
+
const config = {
|
|
4
|
+
appName: "test-app",
|
|
5
|
+
customerName: "pan",
|
|
6
|
+
components: {
|
|
7
|
+
db: {
|
|
8
|
+
dir: "db",
|
|
9
|
+
build: {
|
|
10
|
+
type: "node",
|
|
11
|
+
},
|
|
12
|
+
deploy: {
|
|
13
|
+
type: "google-cloudrun",
|
|
14
|
+
projectId: "asdf",
|
|
15
|
+
region: "asia-east1",
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
api: {
|
|
19
|
+
dir: "api",
|
|
20
|
+
build: {
|
|
21
|
+
type: "node",
|
|
22
|
+
},
|
|
23
|
+
deploy: {
|
|
24
|
+
type: "google-cloudrun",
|
|
25
|
+
projectId: "asdf",
|
|
26
|
+
region: "asia-east1",
|
|
27
|
+
service: {
|
|
28
|
+
allowUnauthenticated: false,
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
verify: {
|
|
32
|
+
command: "yarn e2e",
|
|
33
|
+
waitFor: ["db"],
|
|
34
|
+
},
|
|
35
|
+
env: {
|
|
36
|
+
prod: {
|
|
37
|
+
verify: false,
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
} satisfies Config;
|
|
43
|
+
|
|
44
|
+
export default config;
|
|
45
|
+
|
|
46
|
+
export const information = {
|
|
47
|
+
title: "Cloud Run: Post-deploy verify",
|
|
48
|
+
description:
|
|
49
|
+
"Runs an e2e suite in the verify stage after each deploy. The verify job waits for the db component's deploy, authenticates via application default credentials because the service is non-public, and is disabled for prod.",
|
|
50
|
+
};
|
package/package.json
CHANGED
|
@@ -6,7 +6,10 @@ import {
|
|
|
6
6
|
import type { BuildConfig } from "../../build";
|
|
7
7
|
import { getSecretVarName } from "../../context";
|
|
8
8
|
import type { EnvironmentContext } from "../../types/environmentContext";
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
collapseableSection,
|
|
11
|
+
sanitizeForBashVariable,
|
|
12
|
+
} from "../../utils/gitlab";
|
|
10
13
|
import { getFullDbName } from "../cloudSql/utils";
|
|
11
14
|
import { createGoogleCloudRunDeployJobs } from "./createJobs";
|
|
12
15
|
import { getCloudRunJobExecuteUrl } from "./utils/cloudRunExecutionUrl";
|
|
@@ -137,4 +140,23 @@ export const GCLOUD_RUN_DEPLOY_TYPE: DeployTypeDefinition<DeployConfigCloudRun>
|
|
|
137
140
|
: undefined,
|
|
138
141
|
};
|
|
139
142
|
},
|
|
143
|
+
verifyJobSetupScript: (context) => {
|
|
144
|
+
const deployConfig = context.deploy?.config as
|
|
145
|
+
| DeployConfigCloudRun
|
|
146
|
+
| undefined;
|
|
147
|
+
const service = deployConfig?.service;
|
|
148
|
+
const serviceConfig = typeof service === "object" ? service : undefined;
|
|
149
|
+
if (serviceConfig?.allowUnauthenticated !== false) {
|
|
150
|
+
return [];
|
|
151
|
+
}
|
|
152
|
+
// the service requires IAM auth: provide application default credentials
|
|
153
|
+
// so the verify command can fetch identity tokens for the deployed service
|
|
154
|
+
return collapseableSection(
|
|
155
|
+
"verifygcloudauth",
|
|
156
|
+
"Setup google application credentials",
|
|
157
|
+
)([
|
|
158
|
+
`echo "$${GCLOUD_DEPLOY_CREDENTIALS_KEY}" > "$CI_PROJECT_DIR/.gcloud-sa.json"`,
|
|
159
|
+
`export GOOGLE_APPLICATION_CREDENTIALS="$CI_PROJECT_DIR/.gcloud-sa.json"`,
|
|
160
|
+
]);
|
|
161
|
+
},
|
|
140
162
|
};
|
package/src/deploy/index.ts
CHANGED
|
@@ -27,6 +27,11 @@ export type DeployTypeDefinition<D extends DeployConfig> = {
|
|
|
27
27
|
getAdditionalEnvVars: (
|
|
28
28
|
envContext: EnvironmentContext<BuildConfig, D>,
|
|
29
29
|
) => Record<string, string | BashExpression | undefined | null>;
|
|
30
|
+
/**
|
|
31
|
+
* script lines the deploy type contributes to the start of the verify job,
|
|
32
|
+
* e.g. to authenticate against a non-public service
|
|
33
|
+
*/
|
|
34
|
+
verifyJobSetupScript?: (context: ComponentContext) => string[];
|
|
30
35
|
};
|
|
31
36
|
export type DeployTypes = {
|
|
32
37
|
[T in DeployConfigType]: DeployTypeDefinition<DeployConfigGeneric<T>>;
|
package/src/index.ts
CHANGED
|
@@ -5,6 +5,7 @@ import type {
|
|
|
5
5
|
ComponentContextWithBuild,
|
|
6
6
|
} from "../types/context";
|
|
7
7
|
import type { CatladderJob } from "../types/jobs";
|
|
8
|
+
import { createVerifyJobs } from "../verify/createVerifyJobs";
|
|
8
9
|
|
|
9
10
|
const injectDefaultVarsInCustomJobs = (
|
|
10
11
|
context: ComponentContext,
|
|
@@ -27,7 +28,7 @@ const getCustomJobs = (context: ComponentContext) => {
|
|
|
27
28
|
export const createJobsForComponentContext = async (
|
|
28
29
|
context: ComponentContext,
|
|
29
30
|
): Promise<CatladderJob[]> => {
|
|
30
|
-
const [buildJobs, deployJobs] = await Promise.all([
|
|
31
|
+
const [buildJobs, deployJobs, verifyJobs] = await Promise.all([
|
|
31
32
|
context.build.type !== "disabled"
|
|
32
33
|
? BUILD_TYPES[context.build.buildType].jobs(
|
|
33
34
|
context as ComponentContextWithBuild,
|
|
@@ -36,9 +37,10 @@ export const createJobsForComponentContext = async (
|
|
|
36
37
|
context.componentConfig.deploy !== false
|
|
37
38
|
? DEPLOY_TYPES[context.componentConfig.deploy.type].jobs(context)
|
|
38
39
|
: [],
|
|
40
|
+
createVerifyJobs(context),
|
|
39
41
|
]);
|
|
40
42
|
|
|
41
43
|
const customJobs = getCustomJobs(context);
|
|
42
44
|
|
|
43
|
-
return [...buildJobs, ...deployJobs, ...customJobs];
|
|
45
|
+
return [...buildJobs, ...deployJobs, ...verifyJobs, ...customJobs];
|
|
44
46
|
};
|
package/src/types/config.ts
CHANGED
|
@@ -8,6 +8,7 @@ import type { PipelineType, WorkspaceBuildConfig } from "..";
|
|
|
8
8
|
import type { AgentConfig } from "./agent";
|
|
9
9
|
import type { Hooks } from "./hooks";
|
|
10
10
|
import type { ReleaseConfig } from "./release";
|
|
11
|
+
import type { VerifyConfig } from "../verify/types";
|
|
11
12
|
|
|
12
13
|
export const ALL_PIPELINE_TRIGGERS = [
|
|
13
14
|
"mainBranch",
|
|
@@ -91,6 +92,14 @@ export type DefaultEnvConfig = {
|
|
|
91
92
|
* environment variables
|
|
92
93
|
*/
|
|
93
94
|
vars?: EnvVars;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* post-deploy verification: runs a job in the `verify` stage after the deploy,
|
|
98
|
+
* e.g. an e2e test suite against the freshly deployed environment.
|
|
99
|
+
*
|
|
100
|
+
* Runs in all deployed envs by default, disable per env with `verify: false`
|
|
101
|
+
*/
|
|
102
|
+
verify?: VerifyConfig | false;
|
|
94
103
|
};
|
|
95
104
|
|
|
96
105
|
export type DevLocalEnvConfig = {
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { createArtifactsConfig } from "../build/base/createArtifactsConfig";
|
|
2
|
+
import { createJobCacheFromCacheConfigs } from "../build/cache/createJobCache";
|
|
3
|
+
import { getNodeCache } from "../build/node/cache";
|
|
4
|
+
import { NODE_RUNNER_BUILD_VARIABLES } from "../build/node/constants";
|
|
5
|
+
import { ensureNodeVersion, getYarnInstall } from "../build/node/yarn";
|
|
6
|
+
import { DEPLOY_TYPES } from "../deploy";
|
|
7
|
+
import { DEPLOY_JOB_NAME } from "../deploy/base/deploy";
|
|
8
|
+
import { getRunnerImage } from "../runner";
|
|
9
|
+
import type { ComponentContext } from "../types/context";
|
|
10
|
+
import type { CatladderJob } from "../types/jobs";
|
|
11
|
+
import { ensureArray } from "../utils";
|
|
12
|
+
|
|
13
|
+
export const VERIFY_JOB_NAME = "🔍 verify";
|
|
14
|
+
|
|
15
|
+
export const createVerifyJobs = async (
|
|
16
|
+
context: ComponentContext,
|
|
17
|
+
): Promise<CatladderJob[]> => {
|
|
18
|
+
const verifyConfig = context.componentConfig.verify;
|
|
19
|
+
if (!verifyConfig) {
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const deployConfig = context.deploy?.config;
|
|
24
|
+
if (!deployConfig) {
|
|
25
|
+
// nothing is deployed, so there is nothing to verify
|
|
26
|
+
return [];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const isNodeBuild =
|
|
30
|
+
context.build.type !== "disabled" && context.build.buildType === "node";
|
|
31
|
+
|
|
32
|
+
const [yarnInstall, nodeCache] = isNodeBuild
|
|
33
|
+
? await Promise.all([
|
|
34
|
+
getYarnInstall(context),
|
|
35
|
+
getNodeCache(context, "pull"),
|
|
36
|
+
])
|
|
37
|
+
: [null, null];
|
|
38
|
+
|
|
39
|
+
const setupScript =
|
|
40
|
+
DEPLOY_TYPES[deployConfig.type].verifyJobSetupScript?.(context) ?? [];
|
|
41
|
+
|
|
42
|
+
return [
|
|
43
|
+
{
|
|
44
|
+
name: VERIFY_JOB_NAME,
|
|
45
|
+
stage: "verify",
|
|
46
|
+
envMode: "stagePerEnv",
|
|
47
|
+
// wait for this component's own deploy
|
|
48
|
+
needsStages: [{ stage: "deploy", artifacts: false }],
|
|
49
|
+
// ...and for the deploys of the components listed in waitFor
|
|
50
|
+
needs: (verifyConfig.waitFor ?? []).map((componentName) => ({
|
|
51
|
+
job: DEPLOY_JOB_NAME,
|
|
52
|
+
componentName,
|
|
53
|
+
artifacts: false,
|
|
54
|
+
})),
|
|
55
|
+
image: verifyConfig.jobImage ?? getRunnerImage("jobs-testing-chrome"),
|
|
56
|
+
cache: nodeCache
|
|
57
|
+
? createJobCacheFromCacheConfigs(context, nodeCache)
|
|
58
|
+
: undefined,
|
|
59
|
+
variables: {
|
|
60
|
+
...context.environment.envVars,
|
|
61
|
+
},
|
|
62
|
+
runnerVariables: {
|
|
63
|
+
...NODE_RUNNER_BUILD_VARIABLES,
|
|
64
|
+
...(verifyConfig.runnerVariables ?? {}),
|
|
65
|
+
},
|
|
66
|
+
script: [
|
|
67
|
+
...setupScript,
|
|
68
|
+
...(yarnInstall ? ensureNodeVersion(context) : []),
|
|
69
|
+
`cd ${context.build.dir}`,
|
|
70
|
+
...(yarnInstall ?? []),
|
|
71
|
+
...ensureArray(verifyConfig.command),
|
|
72
|
+
],
|
|
73
|
+
allow_failure: verifyConfig.allowFailure,
|
|
74
|
+
...createArtifactsConfig(
|
|
75
|
+
context.build.dir,
|
|
76
|
+
verifyConfig.artifactsReports,
|
|
77
|
+
verifyConfig.artifacts,
|
|
78
|
+
),
|
|
79
|
+
},
|
|
80
|
+
];
|
|
81
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { TestJobCustom } from "../build/types";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* post-deploy verification job configuration
|
|
5
|
+
*/
|
|
6
|
+
export type VerifyConfig = TestJobCustom & {
|
|
7
|
+
/**
|
|
8
|
+
* command(s) to run against the deployed environment (e.g. `yarn e2e`).
|
|
9
|
+
* Runs in the component's directory.
|
|
10
|
+
*/
|
|
11
|
+
command: string | string[];
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* names of other components whose deploy must finish before this verify job runs
|
|
15
|
+
* (in addition to this component's own deploy, which is always awaited)
|
|
16
|
+
*/
|
|
17
|
+
waitFor?: string[];
|
|
18
|
+
};
|