@vaharoni/devops 1.1.6 → 1.1.8

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 (50) hide show
  1. package/README.md +5 -1
  2. package/dist/cli/cloudrun.d.ts +11 -0
  3. package/dist/cli/cloudrun.d.ts.map +1 -0
  4. package/dist/cli/cloudrun.js +121 -0
  5. package/dist/cli/common.d.ts +10 -12
  6. package/dist/cli/common.d.ts.map +1 -1
  7. package/dist/cli/common.js +28 -22
  8. package/dist/cli/env.js +2 -2
  9. package/dist/cli/prep-build.d.ts.map +1 -1
  10. package/dist/cli/prep-build.js +35 -6
  11. package/dist/cli/registry.d.ts.map +1 -1
  12. package/dist/cli/registry.js +12 -3
  13. package/dist/devops.js +3 -1
  14. package/dist/libs/cloudrun-helpers.d.ts +16 -0
  15. package/dist/libs/cloudrun-helpers.d.ts.map +1 -0
  16. package/dist/libs/cloudrun-helpers.js +79 -0
  17. package/dist/libs/discovery/process-common.js +1 -1
  18. package/dist/libs/k8s-constants.d.ts +1 -0
  19. package/dist/libs/k8s-constants.d.ts.map +1 -1
  20. package/dist/libs/k8s-constants.js +35 -10
  21. package/dist/libs/k8s-generate.d.ts +1 -1
  22. package/dist/libs/k8s-generate.d.ts.map +1 -1
  23. package/dist/libs/k8s-generate.js +4 -2
  24. package/dist/libs/k8s-secrets-manager.d.ts +2 -1
  25. package/dist/libs/k8s-secrets-manager.d.ts.map +1 -1
  26. package/dist/libs/k8s-secrets-manager.js +8 -5
  27. package/dist/types/index.d.ts +19 -8
  28. package/dist/types/index.d.ts.map +1 -1
  29. package/dist/types/index.js +3 -1
  30. package/package.json +1 -1
  31. package/src/cli/cloudrun.ts +133 -0
  32. package/src/cli/common.ts +46 -38
  33. package/src/cli/db.ts +1 -1
  34. package/src/cli/dml.ts +1 -1
  35. package/src/cli/env.ts +2 -2
  36. package/src/cli/exec.ts +1 -1
  37. package/src/cli/job.ts +1 -1
  38. package/src/cli/prep-build.ts +34 -6
  39. package/src/cli/redis.ts +1 -1
  40. package/src/cli/registry.ts +12 -3
  41. package/src/devops.ts +3 -1
  42. package/src/libs/cloudrun-helpers.ts +118 -0
  43. package/src/libs/discovery/process-common.ts +1 -1
  44. package/src/libs/k8s-constants.ts +36 -12
  45. package/src/libs/k8s-generate.ts +3 -2
  46. package/src/libs/k8s-secrets-manager.ts +9 -5
  47. package/src/target-templates/lang-variants-common/python/.devops/config/images.yaml +3 -1
  48. package/src/target-templates/lang-variants-common/typescript/.devops/docker-images/cloudrun.Dockerfile +31 -0
  49. package/src/target-templates/lang-variants-common/typescript/.github/actions/deploy-image@v1/action.yaml +4 -0
  50. package/src/types/index.ts +3 -1
package/README.md CHANGED
@@ -29,7 +29,6 @@ Currently, the repo works with `bun` as the package manager for node and `uv` fo
29
29
  Run this in your local copy of the devops folder:
30
30
  ```shell
31
31
  bun link
32
- bun run build
33
32
  ```
34
33
 
35
34
  Run this in a local package using the project for testing:
@@ -37,6 +36,11 @@ Run this in a local package using the project for testing:
37
36
  bun link @vaharoni/devops
38
37
  ```
39
38
 
39
+ After changes you make in this local repo, run:
40
+ ```shell
41
+ bun run build
42
+ ```
43
+
40
44
  When done:
41
45
  ```shell
42
46
  # In the local copy of this repo
@@ -0,0 +1,11 @@
1
+ import { CLICommandParser } from "./common";
2
+ declare function run(cmdObj: CLICommandParser): Promise<void>;
3
+ declare const _default: {
4
+ cloudrun: {
5
+ oneLiner: string;
6
+ keyExamples: string;
7
+ run: typeof run;
8
+ };
9
+ };
10
+ export default _default;
11
+ //# sourceMappingURL=cloudrun.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudrun.d.ts","sourceRoot":"","sources":["../../src/cli/cloudrun.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAmC,MAAM,UAAU,CAAC;AA6E7E,iBAAe,GAAG,CAAC,MAAM,EAAE,gBAAgB,iBAmD1C;;;;;;;;AAED,wBAEE"}
@@ -0,0 +1,121 @@
1
+ import { CLICommandParser, printUsageAndExit, StrongParams } from "./common";
2
+ import { buildDev, deploy } from "../libs/cloudrun-helpers";
3
+ const oneLiner = "Supports cloudrun images";
4
+ const keyExamples = `
5
+ $ devops cloudrun deploy cloudrun-image SHA --env staging --region us-central1 [--forward-env ENV1,ENV2 --allow-unauthenticated]
6
+ $ devops cloudrun build-dev cloudrun-image
7
+ `.trim();
8
+ const usage = `
9
+ ${oneLiner}
10
+
11
+ USAGE
12
+ Configuration prerequisites:
13
+ - The image should be defined in images.yaml with:
14
+ cloudrun: true
15
+ - The artifact registry URL should be set in config/constants.yaml:
16
+ cloudrun-artifact-registry-repo-path: REGION-docker.pkg.dev/PROJECT_ID/REPO
17
+
18
+ Deploy a cloudrun image to Cloud Run:
19
+ devops cloudrun deploy <image> <sha> --env <env> --region <region> [options]
20
+
21
+ Options:
22
+ --forward-env ENV1,ENV2 Comma-separated env var names to forward into the service
23
+ --allow-unauthenticated Allow unauthenticated access
24
+ --cpu <cpu> CPU, e.g. 0.25, 0.5, 1
25
+ --memory <mem> Memory, e.g. 256Mi, 512Mi, 1Gi
26
+ --min-instances <n> Minimum instances
27
+ --max-instances <n> Maximum instances
28
+ --timeout <time> Request timeout, e.g. 60s
29
+ -- Pass through additional args to gcloud (e.g. -- --ingress internal)
30
+
31
+ Notes:
32
+ - The image must already be pushed to the artifact registry.
33
+ - <env> also supports local environments (e.g. development).
34
+ - For remote monorepo environments, variables specified in --forward-env that
35
+ are not present in the current process's env are fetched from the cluster.
36
+
37
+ Build a cloudrun image locally in development environment:
38
+ devops cloudrun build-dev cloudrun-image
39
+
40
+ This command builds the image locally with a random SHA and pushes it to the artifact registry.
41
+
42
+ EXAMPLES
43
+ ${keyExamples}
44
+ `;
45
+ const handlers = {
46
+ "build-dev": (opts) => {
47
+ buildDev(opts.required("image"));
48
+ },
49
+ _deploy: (opts) => {
50
+ const rawForwardEnv = opts.optional("forwardEnv");
51
+ const forwardEnv = rawForwardEnv
52
+ ? rawForwardEnv.split(",").map(v => v.trim()).filter(Boolean)
53
+ : [];
54
+ const minInstancesStr = opts.optional("minInstances");
55
+ const maxInstancesStr = opts.optional("maxInstances");
56
+ deploy({
57
+ image: opts.required("image"),
58
+ env: opts.required("env"),
59
+ sha: opts.required("sha"),
60
+ region: opts.required("region"),
61
+ forwardEnv,
62
+ allowUnauthenticated: opts.optional("allowUnauthenticated") === "true",
63
+ cpu: opts.optional("cpu"),
64
+ memory: opts.optional("memory"),
65
+ minInstances: minInstancesStr ? Number(minInstancesStr) : undefined,
66
+ maxInstances: maxInstancesStr ? Number(maxInstancesStr) : undefined,
67
+ timeout: opts.optional("timeout"),
68
+ extraArgs: opts.optional("extraArgs"),
69
+ });
70
+ },
71
+ };
72
+ async function run(cmdObj) {
73
+ if (cmdObj.help || cmdObj.args.length === 0)
74
+ printUsageAndExit(usage);
75
+ const parsed = cmdObj.parseOptions({
76
+ params: [
77
+ "--keep-last",
78
+ "--forward-env",
79
+ "--region",
80
+ "--cpu",
81
+ "--memory",
82
+ "--min-instances",
83
+ "--max-instances",
84
+ "--timeout",
85
+ "--sha",
86
+ ],
87
+ booleans: ["--allow-unauthenticated"],
88
+ passthroughArgs: true,
89
+ });
90
+ const [subcommand, image, sha] = parsed.args;
91
+ // Inject env variables as forwarding is needed
92
+ if (subcommand === "deploy") {
93
+ cmdObj.executorFromEnv(`devops cloudrun _deploy ${cmdObj.args.slice(1).join(" ")}`, { checkEnvYaml: false }).spawn();
94
+ return;
95
+ }
96
+ const handler = handlers[subcommand];
97
+ if (!handler) {
98
+ console.error(`Unknown subcommand: ${subcommand}`);
99
+ printUsageAndExit(usage);
100
+ }
101
+ const params = new StrongParams(usage, {
102
+ env: cmdObj.env,
103
+ subcommand,
104
+ image,
105
+ sha,
106
+ keepLast: parsed.options["--keep-last"],
107
+ forwardEnv: parsed.options["--forward-env"],
108
+ region: parsed.options["--region"],
109
+ allowUnauthenticated: parsed.options["--allow-unauthenticated"] ? "true" : undefined,
110
+ cpu: parsed.options["--cpu"],
111
+ memory: parsed.options["--memory"],
112
+ minInstances: parsed.options["--min-instances"],
113
+ maxInstances: parsed.options["--max-instances"],
114
+ timeout: parsed.options["--timeout"],
115
+ extraArgs: parsed.passthrough ? parsed.passthrough.join(" ") : undefined,
116
+ });
117
+ handler(params);
118
+ }
119
+ export default {
120
+ cloudrun: { oneLiner, keyExamples, run },
121
+ };
@@ -1,9 +1,7 @@
1
- type ParsedArgs = {
1
+ type ParsedArgs<TBoolKeys extends readonly string[], TParamKeys extends readonly string[]> = {
2
2
  args: string[];
3
3
  argsStr: string;
4
- options: {
5
- [key: string]: string | boolean;
6
- };
4
+ options: Partial<Record<TBoolKeys[number], true>> & Partial<Record<TParamKeys[number], string>>;
7
5
  passthrough?: string[];
8
6
  };
9
7
  export declare class CLICommandParser {
@@ -15,20 +13,20 @@ export declare class CLICommandParser {
15
13
  skipEnvCheck: boolean;
16
14
  constructor(cmdArray: string[]);
17
15
  executorFromEnv(commandStr: string, options?: Omit<CommandExecutorOptions, "env">): CommandExecutor;
18
- parseOptions({ params, booleans, passthroughArgs, }?: {
16
+ parseOptions<const TBoolKeys extends readonly string[], const TParamKeys extends readonly string[]>({ params, booleans, passthroughArgs, }?: {
19
17
  /** Param is used like so: --param value */
20
- params?: string[];
18
+ params?: TParamKeys;
21
19
  /** Boolean flag is used like so: --flag */
22
- booleans?: string[];
20
+ booleans?: TBoolKeys;
23
21
  /** Pass through args are used like so: -- arg1 arg2 */
24
22
  passthroughArgs?: boolean;
25
- }): ParsedArgs;
23
+ }): ParsedArgs<TBoolKeys, TParamKeys>;
26
24
  _validateEnv(env: string): boolean;
27
- _separateOptions(args: string[], { params, booleans, passthroughArgs, }?: {
28
- params?: string[];
29
- booleans?: string[];
25
+ _separateOptions<const TBoolKeys extends readonly string[], const TParamKeys extends readonly string[]>(args: string[], { params, booleans, passthroughArgs, }?: {
26
+ params?: TParamKeys;
27
+ booleans?: TBoolKeys;
30
28
  passthroughArgs?: boolean;
31
- }): ParsedArgs;
29
+ }): ParsedArgs<TBoolKeys, TParamKeys>;
32
30
  }
33
31
  type CommandExecutorOptions = {
34
32
  env?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../src/cli/common.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../src/cli/common.ts"],"names":[],"mappings":"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"}
@@ -47,7 +47,7 @@ export class CLICommandParser {
47
47
  // # => { args: ['arg1'], options: { '--some-flag': true, '--in': 'workspace' } }
48
48
  //
49
49
  // Note that the global param --env is already extracted and can be accessed with cmd.env
50
- parseOptions({ params = [], booleans = [], passthroughArgs = false, } = {}) {
50
+ parseOptions({ params, booleans, passthroughArgs = false, } = {}) {
51
51
  return this._separateOptions(this.args, {
52
52
  params,
53
53
  booleans,
@@ -63,36 +63,42 @@ export class CLICommandParser {
63
63
  }
64
64
  return true;
65
65
  }
66
- _separateOptions(args, { params = [], booleans = [], passthroughArgs = false, } = {}) {
67
- const results = {
68
- args: [],
69
- argsStr: "",
70
- options: {},
71
- ...(passthroughArgs ? { passthrough: [] } : {}),
72
- };
73
- const paramsLookup = Object.fromEntries(params.map((x) => [x, true]));
74
- const booleansLookup = Object.fromEntries(booleans.map((x) => [x, true]));
66
+ _separateOptions(args, { params, booleans, passthroughArgs = false, } = {}) {
67
+ const paramsLookup = new Set(params ?? []);
68
+ const booleansLookup = new Set(booleans ?? []);
69
+ const isParam = (arg) => paramsLookup.has(arg);
70
+ const isBoolean = (arg) => booleansLookup.has(arg);
75
71
  const passthroughArgsStart = passthroughArgs ? args.indexOf("--") : -1;
72
+ // prettier-ignore
76
73
  const numArgsToProcess = passthroughArgsStart === -1 ? args.length : passthroughArgsStart;
74
+ const getResPassthrough = () => {
75
+ if (!passthroughArgs || passthroughArgsStart < 0)
76
+ return { passthrough: [] };
77
+ return { passthrough: args.slice(passthroughArgsStart + 1) };
78
+ };
79
+ const resArgs = [];
80
+ const resParams = {};
81
+ const resOptions = {};
77
82
  for (let i = 0; i < numArgsToProcess; ++i) {
78
83
  const curr = args[i];
79
- if (paramsLookup[curr]) {
84
+ if (isParam(curr)) {
80
85
  const next = args[i + 1];
81
- results.options[curr] = next;
86
+ resParams[curr] = next;
82
87
  ++i;
83
88
  }
84
- else if (booleansLookup[curr]) {
85
- results.options[curr] = true;
89
+ else if (isBoolean(curr)) {
90
+ resOptions[curr] = true;
86
91
  }
87
92
  else {
88
- results.args.push(curr);
93
+ resArgs.push(curr);
89
94
  }
90
95
  }
91
- results.argsStr = results.args.join(" ");
92
- if (passthroughArgs && passthroughArgsStart >= 0) {
93
- results.passthrough = args.slice(passthroughArgsStart + 1);
94
- }
95
- return results;
96
+ return {
97
+ args: resArgs,
98
+ argsStr: resArgs.join(" "),
99
+ options: { ...resOptions, ...resParams },
100
+ ...getResPassthrough(),
101
+ };
96
102
  }
97
103
  }
98
104
  export class CommandExecutor {
@@ -144,10 +150,10 @@ export class CommandExecutor {
144
150
  const envToUse = this._getProcessEnv(env);
145
151
  return new Promise((resolve) => {
146
152
  try {
147
- const [cmd, ...args] = fullCommand.split(" ").filter(Boolean);
148
- const childProcess = spawn(cmd, args, {
153
+ const childProcess = spawn(fullCommand, {
149
154
  stdio: "inherit",
150
155
  env: envToUse,
156
+ shell: true,
151
157
  });
152
158
  childProcess.on("close", (code) => {
153
159
  if (code !== 0) {
package/dist/cli/env.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { globSync } from "glob";
2
- import { deleteMonorepoSecret, getMonorepoSecret, setMonorepoSecret, } from "../libs/k8s-secrets-manager";
2
+ import { deleteMonorepoSecret, getMonorepoSecretStr, setMonorepoSecret, } from "../libs/k8s-secrets-manager";
3
3
  import { CombinedEnvValidator } from "../libs/validate-env";
4
4
  import { CLICommandParser, dotEnvFilesForEnv, printUsageAndExit, } from "./common";
5
5
  const oneLiner = "Commands to manipulate env variables";
@@ -46,7 +46,7 @@ function run(cmdObj) {
46
46
  break;
47
47
  }
48
48
  case "get": {
49
- console.log(getMonorepoSecret(cmdObj.env, rest));
49
+ console.log(getMonorepoSecretStr(cmdObj.env, rest));
50
50
  break;
51
51
  }
52
52
  case "set": {
@@ -1 +1 @@
1
- {"version":3,"file":"prep-build.d.ts","sourceRoot":"","sources":["../../src/cli/prep-build.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAqB,MAAM,UAAU,CAAC;AAqB/D,iBAAe,GAAG,CAAC,MAAM,EAAE,gBAAgB,iBAmE1C;;;;;;;;AAED,wBAEE"}
1
+ {"version":3,"file":"prep-build.d.ts","sourceRoot":"","sources":["../../src/cli/prep-build.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAqB,MAAM,UAAU,CAAC;AA0B/D,iBAAe,GAAG,CAAC,MAAM,EAAE,gBAAgB,iBA0F1C;;;;;;;;AAED,wBAEE"}
@@ -3,8 +3,10 @@ import os from "os";
3
3
  import path from "path";
4
4
  import { CLICommandParser, printUsageAndExit } from "./common";
5
5
  import { getImageData, getTemplateData } from "../libs/config";
6
- import { getMonorepoSecret } from "../libs/k8s-secrets-manager";
6
+ import { getMonorepoSecretStr } from "../libs/k8s-secrets-manager";
7
7
  import { getImageDescendentData } from "../libs/discovery/images";
8
+ import { isLocalOrRemoteEnv } from "../libs/k8s-constants";
9
+ import chalk from "chalk";
8
10
  const oneLiner = "Copies all dependencies of an image to a temporary folder in preparation for a Docker build";
9
11
  const keyExamples = `
10
12
  $ devops prep-build main-node
@@ -13,7 +15,10 @@ const usage = `
13
15
  ${oneLiner}
14
16
 
15
17
  USAGE
16
- devops prep-build <image>
18
+ devops prep-build <image> --env <env>
19
+
20
+ If <env> is a remote environment (e.g. staging, production), the environment variables are
21
+ fetched from the cluster and injected in case they are needed during the build process.
17
22
 
18
23
  EXAMPLES
19
24
  ${keyExamples}
@@ -52,16 +57,40 @@ async function run(cmdObj) {
52
57
  console.warn(`COPYING Docker common`);
53
58
  fs.copySync(dockerCommonPayloadPath, destFolder);
54
59
  }
55
- console.warn(`COPYING Docker image payload`);
56
- fs.copySync(dockerImagePayloadPath, destFolder);
60
+ if (fs.existsSync(dockerImagePayloadPath)) {
61
+ console.warn(`COPYING Docker image payload`);
62
+ fs.copySync(dockerImagePayloadPath, destFolder);
63
+ }
57
64
  console.warn(`COPYING .devops/config`);
58
65
  fs.mkdirSync(path.join(destFolder, ".devops"));
59
66
  fs.copySync(".devops/config", path.join(destFolder, ".devops/config"));
60
67
  // Create config directory. It should be deleted by the docker image so that it can be mounted as a volume when the pod is run
61
68
  console.warn(`CREATING config for the build process`);
62
69
  fs.mkdirSync(path.join(destFolder, "config"));
63
- const envFileData = getMonorepoSecret(cmdObj.env);
64
- fs.writeFileSync(path.join(destFolder, `config/.env.global`), envFileData);
70
+ const destGlobalEnvPath = path.join(destFolder, "config/.env.global");
71
+ if (isLocalOrRemoteEnv(cmdObj.env) === "remote") {
72
+ const envFileData = getMonorepoSecretStr(cmdObj.env);
73
+ fs.writeFileSync(destGlobalEnvPath, envFileData);
74
+ }
75
+ else {
76
+ let anyCopied = false;
77
+ const localGlobalEnvPath = "config/.env.global";
78
+ const localEnvPath = `config/.env.${cmdObj.env}`;
79
+ const destEnvPath = path.join(destFolder, `config/.env.${cmdObj.env}`);
80
+ if (fs.existsSync(localGlobalEnvPath)) {
81
+ console.warn(`COPYING ${localGlobalEnvPath} to ${destGlobalEnvPath}`);
82
+ fs.copyFileSync(localGlobalEnvPath, destGlobalEnvPath);
83
+ anyCopied = true;
84
+ }
85
+ if (fs.existsSync(localEnvPath)) {
86
+ console.warn(`COPYING ${localEnvPath} to ${destEnvPath}`);
87
+ fs.copyFileSync(localEnvPath, destEnvPath);
88
+ anyCopied = true;
89
+ }
90
+ if (!anyCopied) {
91
+ console.warn(chalk.red(`\nWarning: local environment ${cmdObj.env} has no .env files. Environment variables will not be injected.\n`));
92
+ }
93
+ }
65
94
  // Copy all dependencies
66
95
  getImageDescendentData(image).forEach((project) => {
67
96
  console.warn(`COPYING ${project.rootPath}`);
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/cli/registry.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,gBAAgB,EAAmC,MAAM,UAAU,CAAC;AAoD7E,iBAAS,GAAG,CAAC,MAAM,EAAE,gBAAgB,QAYpC;;;;;;;;AAED,wBAEE"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/cli/registry.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,gBAAgB,EAAmC,MAAM,UAAU,CAAC;AA6D7E,iBAAS,GAAG,CAAC,MAAM,EAAE,gBAAgB,QAYpC;;;;;;;;AAED,wBAEE"}
@@ -6,20 +6,26 @@ const oneLiner = "Manage container repositories";
6
6
  const keyExamples = `
7
7
  $ devops registry server-url
8
8
  $ devops registry reg-url
9
- $ devops registry repo-url my-image sha
10
- $ devops registry prune my-image
9
+ $ devops registry repo-url my-image sha
10
+ $ devops registry image-name my-image
11
+ $ devops registry prune my-image
11
12
  `.trim();
12
13
  const usage = `
13
14
  ${oneLiner}
14
15
 
15
16
  USAGE
16
- Get base URLs
17
+ Get base URLs for the container registry of the cluster:
17
18
  devops registry server-url
18
19
  devops registry reg-url
19
20
 
21
+ Note: for cloudrun images these URLs are not relevant.
22
+
20
23
  Gets the URL of an image in the container registry:
21
24
  devops registry repo-url <image> <sha> --env <env>
22
25
 
26
+ Gets the image name in the container registry:
27
+ devops registry image-name <image> --env <env>
28
+
23
29
  Prunes the repository of old images to enforce the "image-versions-to-keep" constant in config/constants.yaml:
24
30
  devops registry prune <image> --env <env>
25
31
 
@@ -34,6 +40,9 @@ const handlers = {
34
40
  "repo-url": (opts) => {
35
41
  console.log(containerRegistryRepoPath(opts.required("image"), opts.required("env"), opts.required("sha")));
36
42
  },
43
+ "image-name": (opts) => {
44
+ console.log(containerRegistryImageName(opts.required("image"), opts.required("env")));
45
+ },
37
46
  prune: (opts) => {
38
47
  const regName = containerRegistryPath();
39
48
  const repoName = containerRegistryImageName(opts.required("image"), opts.required("env"));
package/dist/devops.js CHANGED
@@ -22,6 +22,7 @@ import namespace from "./cli/namespace";
22
22
  import image from "./cli/image";
23
23
  import template from "./cli/template";
24
24
  import job from "./cli/job";
25
+ import cloudrun from "./cli/cloudrun";
25
26
  const [_node, _scriptPath, ...commandArgs] = process.argv;
26
27
  const allImports = [
27
28
  // day-to-day
@@ -43,11 +44,12 @@ const allImports = [
43
44
  job,
44
45
  //= Deployment
45
46
  prepBuild,
47
+ cloudrun,
46
48
  affected,
47
49
  constant,
48
50
  registry,
49
51
  internalCurl,
50
- jwt
52
+ jwt,
51
53
  ];
52
54
  const commands = {};
53
55
  allImports.forEach((imported) => {
@@ -0,0 +1,16 @@
1
+ export declare function buildDev(image: string): Promise<void>;
2
+ export declare function deploy({ image, env, sha, region, forwardEnv, allowUnauthenticated, cpu, memory, minInstances, maxInstances, timeout, extraArgs, }: {
3
+ image: string;
4
+ env: string;
5
+ sha: string;
6
+ region: string;
7
+ forwardEnv?: string[];
8
+ allowUnauthenticated?: boolean;
9
+ cpu?: string;
10
+ memory?: string;
11
+ minInstances?: number;
12
+ maxInstances?: number;
13
+ timeout?: string;
14
+ extraArgs?: string;
15
+ }): Promise<void>;
16
+ //# sourceMappingURL=cloudrun-helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudrun-helpers.d.ts","sourceRoot":"","sources":["../../src/libs/cloudrun-helpers.ts"],"names":[],"mappings":"AA0CA,wBAAsB,QAAQ,CAAC,KAAK,EAAE,MAAM,iBAyB3C;AAED,wBAAsB,MAAM,CAAC,EAC3B,KAAK,EACL,GAAG,EACH,GAAG,EACH,MAAM,EACN,UAAe,EACf,oBAA4B,EAC5B,GAAY,EACZ,MAAgB,EAChB,YAAgB,EAChB,YAAgB,EAChB,OAAe,EACf,SAAc,GACf,EAAE;IACD,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,iBAsBA"}
@@ -0,0 +1,79 @@
1
+ import { randomBytes } from "crypto";
2
+ import { CommandExecutor } from "../cli/common";
3
+ import { containerRegistryRepoPath, isLocalOrRemoteEnv } from "./k8s-constants";
4
+ import { getImageData } from "./config";
5
+ import { getMonorepoSecretObject } from "./k8s-secrets-manager";
6
+ import chalk from "chalk";
7
+ function verifyCloudrunImage(image) {
8
+ const imageData = getImageData(image);
9
+ if (!imageData["cloudrun"]) {
10
+ console.error(`Image ${image} is not a cloudrun image. Add "cloudrun: true" in images.yaml`);
11
+ process.exit(1);
12
+ }
13
+ }
14
+ function getEnvValuesToForward(env, forwardEnv) {
15
+ if (!forwardEnv.length)
16
+ return {};
17
+ let envValues = {};
18
+ const missingValues = new Set();
19
+ for (const key of forwardEnv) {
20
+ const value = process.env[key];
21
+ if (value) {
22
+ envValues[key] = value;
23
+ }
24
+ else {
25
+ missingValues.add(key);
26
+ }
27
+ }
28
+ if (missingValues.size > 0 && isLocalOrRemoteEnv(env) === "remote") {
29
+ const secretsFromCluster = getMonorepoSecretObject(env, Array.from(missingValues));
30
+ for (const key of Object.keys(secretsFromCluster)) {
31
+ envValues[key] = secretsFromCluster[key];
32
+ missingValues.delete(key);
33
+ }
34
+ }
35
+ if (missingValues.size > 0) {
36
+ console.error(`Some forwardEnv variables are missing: ${Array.from(missingValues).join(", ")}`);
37
+ process.exit(1);
38
+ }
39
+ return envValues;
40
+ }
41
+ export async function buildDev(image) {
42
+ verifyCloudrunImage(image);
43
+ const env = "development";
44
+ const sha = randomBytes(12).toString("hex");
45
+ const buildDir = new CommandExecutor(`devops prep-build ${image}`, {
46
+ env,
47
+ }).exec().trim();
48
+ const tag = containerRegistryRepoPath(image, env, sha);
49
+ console.warn(`Building ${tag} from ${buildDir}`);
50
+ await new CommandExecutor(`docker build --platform linux/amd64 -t ${tag} ${buildDir} --build-arg MONOREPO_ENV=${env}`, { env }).spawn();
51
+ console.warn(`Pushing ${tag}`);
52
+ await new CommandExecutor(`docker push ${tag}`, { env }).spawn();
53
+ console.warn(`\n✅ Built and pushed ${tag}\n`);
54
+ console.warn('Run "devops cloudrun deploy" next. For example:');
55
+ console.warn(chalk.blue(`./devops cloudrun deploy ${image} ${sha} --env ${env} --allow-unauthenticated --region us-east1 --forward-env ENV1,ENV2`));
56
+ console.warn();
57
+ console.log(tag);
58
+ }
59
+ export async function deploy({ image, env, sha, region, forwardEnv = [], allowUnauthenticated = false, cpu = "0.25", memory = "256Mi", minInstances = 0, maxInstances = 1, timeout = "60s", extraArgs = "", }) {
60
+ verifyCloudrunImage(image);
61
+ const repoPath = containerRegistryRepoPath(image, env, sha);
62
+ const envValues = getEnvValuesToForward(env, forwardEnv);
63
+ const envValuesCsv = Object.entries(envValues).map(([key, value]) => `${key}="${value}"`).join(",");
64
+ const serviceName = `${image}-${env}`;
65
+ const cmd = `
66
+ gcloud run deploy ${serviceName}
67
+ --image ${repoPath}
68
+ ${Object.keys(envValues).length > 0 ? `--set-env-vars ${envValuesCsv}` : ""}
69
+ ${allowUnauthenticated ? "--allow-unauthenticated" : ""}
70
+ --region ${region}
71
+ --cpu ${cpu}
72
+ --memory ${memory}
73
+ --min-instances ${minInstances}
74
+ --max-instances ${maxInstances}
75
+ --timeout ${timeout}
76
+ ${extraArgs}
77
+ `.trim().replace(/\s+/g, " ");
78
+ await new CommandExecutor(cmd, { env }).spawn();
79
+ }
@@ -21,7 +21,7 @@ export class PackageDataProcessor {
21
21
  console.error(`Error parsing ${packageFilePath}: ${parsedRes.error}`);
22
22
  process.exit(1);
23
23
  }
24
- const rootDir = path.dirname(packageFilePath);
24
+ const rootDir = path.relative(process.cwd(), path.dirname(packageFilePath));
25
25
  const name = this.nameExtractor(parsedRes.data);
26
26
  this.workspaceNames.add(name);
27
27
  this.loadedFiles[rootDir] = { name, data: parsedRes.data };
@@ -1,5 +1,6 @@
1
1
  export declare const MISSING_DOMAIN_KEY_ERROR = "$$$MISSING_DOMAIN_KEY$$$";
2
2
  export declare function allSupportedEnvs(): string[];
3
+ export declare function isLocalOrRemoteEnv(monorepoEnv: string): "local" | "remote";
3
4
  export declare function envToNamespace(monorepoEnv?: string): string;
4
5
  export declare function secretName(): string;
5
6
  export declare function imageDebugName(image: string): string;
@@ -1 +1 @@
1
- {"version":3,"file":"k8s-constants.d.ts","sourceRoot":"","sources":["../../src/libs/k8s-constants.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,wBAAwB,6BAA6B,CAAA;AAoBlE,wBAAgB,gBAAgB,aAE/B;AAYD,wBAAgB,cAAc,CAAC,WAAW,CAAC,EAAE,MAAM,UAGlD;AAED,wBAAgB,UAAU,WAEzB;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,UAE3C;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,UAE3C;AAED,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,UAG5E;AAED,wBAAgB,qBAAqB,WAEpC;AAED,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,UAOf;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,UAIlE;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,UAE9C"}
1
+ {"version":3,"file":"k8s-constants.d.ts","sourceRoot":"","sources":["../../src/libs/k8s-constants.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,wBAAwB,6BAA6B,CAAA;AAoBlE,wBAAgB,gBAAgB,aAE/B;AAED,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,CAI1E;AAqBD,wBAAgB,cAAc,CAAC,WAAW,CAAC,EAAE,MAAM,UAGlD;AAED,wBAAgB,UAAU,WAEzB;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,UAE3C;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,UAE3C;AAED,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,UAG5E;AAED,wBAAgB,qBAAqB,WAEpC;AAED,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,UAgBf;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,UAIlE;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,UAE9C"}
@@ -21,12 +21,27 @@ function localSupportedEnvs() {
21
21
  export function allSupportedEnvs() {
22
22
  return [...remoteSupportedEnvs(), ...localSupportedEnvs()];
23
23
  }
24
- function validateEnv(monorepoEnv) {
24
+ export function isLocalOrRemoteEnv(monorepoEnv) {
25
+ if (remoteSupportedEnvs().includes(monorepoEnv))
26
+ return "remote";
27
+ if (localSupportedEnvs().includes(monorepoEnv))
28
+ return "local";
29
+ throw new Error(`Unsupported environment: ${monorepoEnv}`);
30
+ }
31
+ function validateEnv(monorepoEnv, { allowLocal = false } = {}) {
25
32
  if (!monorepoEnv)
26
33
  throw new Error("MONOREPO_ENV cannot be empty");
27
- if (!remoteSupportedEnvs().includes(monorepoEnv)) {
28
- console.error(`MONOREPO_ENV must be one of: ${remoteSupportedEnvs().join(", ")}. Can be set using --env flag.`);
29
- process.exit(1);
34
+ if (allowLocal) {
35
+ if (!allSupportedEnvs().includes(monorepoEnv)) {
36
+ console.error(`MONOREPO_ENV must be one of: ${allSupportedEnvs().join(", ")}. Can be set using --env flag.`);
37
+ process.exit(1);
38
+ }
39
+ }
40
+ else {
41
+ if (!remoteSupportedEnvs().includes(monorepoEnv)) {
42
+ console.error(`MONOREPO_ENV must be one of: ${remoteSupportedEnvs().join(", ")}. Can be set using --env flag.`);
43
+ process.exit(1);
44
+ }
30
45
  }
31
46
  }
32
47
  export function envToNamespace(monorepoEnv) {
@@ -43,18 +58,28 @@ export function imageConfigMap(image) {
43
58
  return `image-config-${image}`;
44
59
  }
45
60
  export function containerRegistryImageName(image, monorepoEnv) {
46
- validateEnv(monorepoEnv);
61
+ validateEnv(monorepoEnv, { allowLocal: true });
47
62
  return `${getConst("project-name")}-${monorepoEnv}-${image}`;
48
63
  }
49
64
  export function containerRegistryPath() {
50
65
  return [getConst("registry-base-url"), getConst("registry-image-path-prefix", { ignoreIfInvalid: true })].filter(Boolean).join("/");
51
66
  }
52
67
  export function containerRegistryRepoPath(image, monorepoEnv, gitSha) {
53
- return [
54
- getConst("registry-base-url"),
55
- getConst("registry-image-path-prefix", { ignoreIfInvalid: true }),
56
- [containerRegistryImageName(image, monorepoEnv), gitSha].join(":"),
57
- ].filter(Boolean).join("/");
68
+ const imageNameAndTag = [containerRegistryImageName(image, monorepoEnv), gitSha].join(":");
69
+ const imageData = getImageData(image);
70
+ if (imageData["cloudrun"]) {
71
+ return [
72
+ getConst("cloudrun-artifact-registry-repo-path"),
73
+ imageNameAndTag,
74
+ ].join("/");
75
+ }
76
+ else {
77
+ return [
78
+ getConst("registry-base-url"),
79
+ getConst("registry-image-path-prefix", { ignoreIfInvalid: true }),
80
+ imageNameAndTag,
81
+ ].filter(Boolean).join("/");
82
+ }
58
83
  }
59
84
  export function domainNameForEnv(image, monorepoEnv) {
60
85
  const imageData = getImageData(image);