@catladder/cli 0.0.0-fix-config-move-not-working-again-bf012644 → 0.0.0-fix-handle-missing-cloud-sql-proxy-command-error-and-show-nice-4dbbecce

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 (49) hide show
  1. package/dist/bundles/catenv/index.js +327 -124
  2. package/dist/bundles/cli/index.js +470 -181
  3. package/dist/cli/src/apps/catenv/printVariables.js +4 -1
  4. package/dist/cli/src/apps/catenv/printVariables.js.map +1 -1
  5. package/dist/cli/src/apps/catenv/utils.d.ts +6 -2
  6. package/dist/cli/src/apps/catenv/utils.js +4 -2
  7. package/dist/cli/src/apps/catenv/utils.js.map +1 -1
  8. package/dist/cli/src/apps/cli/commands/project/commandCloudSqlProxy.js +84 -51
  9. package/dist/cli/src/apps/cli/commands/project/commandCloudSqlProxy.js.map +1 -1
  10. package/dist/cli/src/utils/log.d.ts +65 -1
  11. package/dist/cli/src/utils/log.js +66 -8
  12. package/dist/cli/src/utils/log.js.map +1 -1
  13. package/dist/pipeline/src/bash/bashEscape.d.ts +4 -1
  14. package/dist/pipeline/src/bash/bashEscape.js +4 -2
  15. package/dist/pipeline/src/bash/bashEscape.js.map +1 -1
  16. package/dist/pipeline/src/context/getEnvConfig.js +14 -2
  17. package/dist/pipeline/src/context/getEnvConfig.js.map +1 -1
  18. package/dist/pipeline/src/deploy/cloudRun/createJobs/cloudRunJobs.d.ts +5 -3
  19. package/dist/pipeline/src/deploy/cloudRun/createJobs/cloudRunJobs.js +18 -107
  20. package/dist/pipeline/src/deploy/cloudRun/createJobs/cloudRunJobs.js.map +1 -1
  21. package/dist/pipeline/src/deploy/cloudRun/createJobs/execute/onDeploy.d.ts +4 -0
  22. package/dist/pipeline/src/deploy/cloudRun/createJobs/execute/onDeploy.js +85 -0
  23. package/dist/pipeline/src/deploy/cloudRun/createJobs/execute/onDeploy.js.map +1 -0
  24. package/dist/pipeline/src/deploy/cloudRun/createJobs/execute/schedules.d.ts +3 -0
  25. package/dist/pipeline/src/deploy/cloudRun/createJobs/execute/schedules.js +136 -0
  26. package/dist/pipeline/src/deploy/cloudRun/createJobs/execute/schedules.js.map +1 -0
  27. package/dist/pipeline/src/deploy/cloudRun/createJobs/getCloudRunDeployScripts.js +5 -3
  28. package/dist/pipeline/src/deploy/cloudRun/createJobs/getCloudRunDeployScripts.js.map +1 -1
  29. package/dist/pipeline/src/deploy/cloudRun/createJobs/getCloudRunStopScripts.js +5 -3
  30. package/dist/pipeline/src/deploy/cloudRun/createJobs/getCloudRunStopScripts.js.map +1 -1
  31. package/dist/pipeline/src/deploy/cloudRun/index.js +6 -2
  32. package/dist/pipeline/src/deploy/cloudRun/index.js.map +1 -1
  33. package/dist/pipeline/src/deploy/cloudRun/utils/cloudRunExecutionUrl.d.ts +6 -0
  34. package/dist/pipeline/src/deploy/cloudRun/utils/cloudRunExecutionUrl.js +11 -0
  35. package/dist/pipeline/src/deploy/cloudRun/utils/cloudRunExecutionUrl.js.map +1 -0
  36. package/dist/pipeline/src/deploy/cloudRun/utils/jobName.d.ts +5 -1
  37. package/dist/pipeline/src/deploy/cloudRun/utils/jobName.js +7 -1
  38. package/dist/pipeline/src/deploy/cloudRun/utils/jobName.js.map +1 -1
  39. package/dist/pipeline/src/deploy/types/googleCloudRun.d.ts +99 -1
  40. package/dist/pipeline/src/deploy/types/index.d.ts +1 -0
  41. package/dist/pipeline/src/deploy/types/index.js +7 -1
  42. package/dist/pipeline/src/deploy/types/index.js.map +1 -1
  43. package/dist/pipeline/src/types/config.d.ts +11 -6
  44. package/dist/tsconfig.tsbuildinfo +1 -1
  45. package/package.json +1 -1
  46. package/src/apps/catenv/printVariables.ts +4 -1
  47. package/src/apps/catenv/utils.ts +12 -3
  48. package/src/apps/cli/commands/project/commandCloudSqlProxy.ts +130 -66
  49. package/src/utils/log.ts +104 -8
package/package.json CHANGED
@@ -53,7 +53,7 @@
53
53
  }
54
54
  ],
55
55
  "license": "MIT",
56
- "version": "0.0.0-fix-config-move-not-working-again-bf012644",
56
+ "version": "0.0.0-fix-handle-missing-cloud-sql-proxy-command-error-and-show-nice-4dbbecce",
57
57
  "scripts": {
58
58
  "lint": "eslint \"src/**/*.ts\"",
59
59
  "lint:fix": "eslint \"src/**/*.ts\" --fix",
@@ -55,4 +55,7 @@ export const printVariables = async (config: Config, choice?: Choice) => {
55
55
  };
56
56
 
57
57
  const makeExportKeyValuestring = (variables: Record<string, string>) =>
58
- makeKeyValueString(variables, "export ");
58
+ makeKeyValueString(variables, {
59
+ keyPrefix: "export ",
60
+ escapeOptions: { quoteMode: "always" },
61
+ });
@@ -1,4 +1,4 @@
1
- import type { Config } from "@catladder/pipeline";
1
+ import type { Config, EscapeForDotEnvOptions } from "@catladder/pipeline";
2
2
  import { join } from "path";
3
3
  import { getGitRoot } from "../../utils/projects";
4
4
  import type { Choice } from "./types";
@@ -32,13 +32,22 @@ export const getCurrentComponentAndEnvFromChoice = async (
32
32
  };
33
33
  };
34
34
 
35
+ export type MakeKeyValueStringOptions = {
36
+ keyPrefix?: string;
37
+ escapeOptions?: EscapeForDotEnvOptions;
38
+ };
35
39
  export const makeKeyValueString = (
36
40
  variables: Record<string, string>,
37
- keyPrefix = "",
41
+ { keyPrefix, escapeOptions }: MakeKeyValueStringOptions = {
42
+ keyPrefix: "",
43
+ },
38
44
  ) =>
39
45
  Object.entries(variables)
40
46
  // quotes are important, otherwise line breaks don't work properly
41
- .map(([key, value]) => `${keyPrefix}${key}=${escapeForDotEnv(value)}`)
47
+ .map(
48
+ ([key, value]) =>
49
+ `${keyPrefix}${key}=${escapeForDotEnv(value, escapeOptions)}`,
50
+ )
42
51
  .join("\n");
43
52
 
44
53
  export const sanitizeEnvVarName = (name: string) =>
@@ -1,17 +1,23 @@
1
1
  import type { ComponentContext } from "@catladder/pipeline";
2
2
  import {
3
3
  createKubernetesCloudsqlBaseValues,
4
+ getDeployConfigType,
4
5
  isOfDeployType,
5
6
  } from "@catladder/pipeline";
6
7
  import type Vorpal from "vorpal";
7
8
  import type { CommandInstance } from "vorpal";
9
+ import clipboard from "clipboardy";
8
10
  import {
9
11
  getEnvVarsResolved,
10
12
  getPipelineContextByChoice,
11
13
  parseChoice,
12
14
  } from "../../../../config/getProjectConfig";
13
15
  import { envAndComponents } from "./utils/autocompletions";
14
- import { startCloudSqlProxyInCurrentShell } from "../../../../gcloud/cloudSql/startProxy";
16
+ import {
17
+ ERROR_NOT_INSTALLED,
18
+ startCloudSqlProxyInCurrentShell,
19
+ } from "../../../../gcloud/cloudSql/startProxy";
20
+ import { logError, logLines, logWarning } from "../../../../utils/log";
15
21
 
16
22
  type ProxyInfo = {
17
23
  instanceName: string;
@@ -19,61 +25,15 @@ type ProxyInfo = {
19
25
  DB_PASSWORD: string;
20
26
  DB_USER: string;
21
27
  };
22
- export default async (vorpal: Vorpal) =>
23
- vorpal
24
- .command("project-cloud-sql-proxy <envComponent>", "proxy to cloud sql db")
25
- .autocomplete(await envAndComponents())
26
- .action(async function ({ envComponent }) {
27
- const { env, componentName } = parseChoice(envComponent);
28
- if (!componentName) {
29
- this.log("need componentName");
30
- return;
31
- }
32
-
33
- const context = await getPipelineContextByChoice(env, componentName);
34
- let proxyInfo: ProxyInfo;
35
-
36
- if (env === "review") {
37
- vorpal.log(
38
- "⚠️ connection string does not include mr information on review environments",
39
- );
40
- }
41
- if (isOfDeployType(context.deploy?.config, "kubernetes")) {
42
- proxyInfo = await getProxyInfoForKubernetes(this, context);
43
- } else if (isOfDeployType(context.deploy?.config, "google-cloudrun")) {
44
- proxyInfo = await getProxyInfoForCloudRun(this, context);
45
- } else {
46
- throw new Error("unsupported environment");
47
- }
48
-
49
- // skynet-164509:europe-west6:pvl-cyclomania-review=tcp:5432
50
- const { DB_PASSWORD, DB_NAME, DB_USER, instanceName } = proxyInfo;
51
- const { localPort } = await this.prompt({
52
- type: "number",
53
- name: "localPort",
54
- default: "54320",
55
- message: "Local port: ",
56
- });
57
-
58
- this.log("");
59
- this.log(`postgres-PW: ${DB_PASSWORD}`);
60
- this.log("");
61
- this.log("connection strings:");
62
- this.log("");
63
- this.log(
64
- `DATABASE_URL=postgresql://${DB_USER}:${DB_PASSWORD}@localhost:${localPort}/${DB_NAME}?schema=public`,
65
- );
66
- this.log("");
67
- this.log(
68
- `DATABASE_JDBC_URL=jdbc:postgresql://localhost:${localPort}/${DB_NAME}?schema=public&user=${DB_USER}&password=${DB_PASSWORD}`,
69
- );
70
- this.log("");
71
28
 
72
- await startCloudSqlProxyInCurrentShell({
73
- instanceName,
74
- localPort,
75
- });
76
- });
29
+ const getProxyInfo = (context: ComponentContext) => {
30
+ if (isOfDeployType(context.deploy?.config, "kubernetes")) {
31
+ return getProxyInfoForKubernetes(this, context);
32
+ } else if (isOfDeployType(context.deploy?.config, "google-cloudrun")) {
33
+ return getProxyInfoForCloudRun(this, context);
34
+ }
35
+ throw new Error(`unsupported environment: ${context.deploy?.config?.type}`);
36
+ };
77
37
 
78
38
  const getProxyInfoForKubernetes = async (
79
39
  vorpal: CommandInstance,
@@ -111,20 +71,124 @@ const getProxyInfoForCloudRun = async (
111
71
  !isOfDeployType(context.deploy?.config, "google-cloudrun") ||
112
72
  !context.deploy?.config.cloudSql
113
73
  ) {
114
- throw new Error("unsupported");
74
+ const deployType = getDeployConfigType(context.deploy?.config);
75
+ const errorMessage =
76
+ deployType === "google-cloudrun"
77
+ ? `DeployConfig is missing the cloudSql property`
78
+ : `Unsupported DeployConfig type: ${deployType}`;
79
+ logError(vorpal, errorMessage);
80
+ throw new Error(errorMessage);
115
81
  }
116
-
117
82
  const envVars = await getEnvVarsResolved(vorpal, context.env, context.name);
118
-
119
- const DB_PASSWORD = envVars?.DB_PASSWORD?.toString();
120
- const DB_USER = envVars?.DB_USER?.toString();
121
-
122
- const DB_NAME = context.environment.envVars.DB_NAME.toString();
123
-
124
83
  return {
125
84
  instanceName: context.deploy?.config.cloudSql.instanceConnectionName,
126
- DB_PASSWORD,
127
- DB_NAME,
128
- DB_USER,
85
+ DB_PASSWORD: envVars?.DB_PASSWORD?.toString(),
86
+ DB_NAME: context.environment.envVars.DB_NAME.toString(),
87
+ DB_USER: envVars?.DB_USER?.toString(),
129
88
  };
130
89
  };
90
+
91
+ const getDbUrl = (
92
+ { DB_PASSWORD, DB_NAME, DB_USER }: ProxyInfo,
93
+ localPort: string,
94
+ additional: string = "",
95
+ ) =>
96
+ `DATABASE_URL="postgresql://${DB_USER}:${DB_PASSWORD}@localhost:${localPort}/${DB_NAME}${additional}"`;
97
+
98
+ const getJdbcUrl = (
99
+ { DB_PASSWORD, DB_NAME, DB_USER }: ProxyInfo,
100
+ localPort: string,
101
+ ) =>
102
+ `DATABASE_JDBC_URL="jdbc:postgresql://localhost:${localPort}/${DB_NAME}?schema=public&user=${DB_USER}&password=${DB_PASSWORD}"`;
103
+
104
+ export default async (vorpal: Vorpal) =>
105
+ vorpal
106
+ .command("project-cloud-sql-proxy <envComponent>", "proxy to cloud sql db")
107
+ .autocomplete(await envAndComponents())
108
+ .action(async function ({ envComponent }) {
109
+ const { env, componentName } = parseChoice(envComponent);
110
+ if (!componentName) {
111
+ logWarning(this, "need componentName");
112
+ return;
113
+ }
114
+
115
+ const context = await getPipelineContextByChoice(env, componentName);
116
+
117
+ if (env === "review") {
118
+ logWarning(
119
+ this,
120
+ "connection string does not include mr information on review environments",
121
+ );
122
+ }
123
+
124
+ const { localPort } = await this.prompt({
125
+ type: "number",
126
+ name: "localPort",
127
+ default: "54320",
128
+ message: "Local port: ",
129
+ });
130
+
131
+ const proxyInfo = await getProxyInfo(context);
132
+
133
+ /**
134
+ * Env variables for libpq (e.g. psql client)
135
+ * https://www.postgresql.org/docs/current/libpq-envars.html#LIBPQ-ENVARS
136
+ */
137
+ const psqlEnvVars = {
138
+ PGPASSWORD: proxyInfo.DB_PASSWORD,
139
+ PGUSER: proxyInfo.DB_USER,
140
+ PGDATABASE: proxyInfo.DB_NAME,
141
+ PGHOST: "localhost",
142
+ PGPORT: localPort,
143
+ };
144
+ const lipbqEnvVarDeclarations = Object.entries(psqlEnvVars).map(
145
+ ([key, value]) => `${key}="${value}"`,
146
+ );
147
+ const dbUrl = getDbUrl(proxyInfo, localPort);
148
+ const jdbcUrl = getJdbcUrl(proxyInfo, localPort);
149
+
150
+ clipboard.writeSync(
151
+ [
152
+ "",
153
+ "## CloudSQL proxy connection .env variables",
154
+ dbUrl,
155
+ jdbcUrl,
156
+ "## DATABASE_URL with schema=public parameter (e. g. Prisma requires this):",
157
+ `# ${getDbUrl(proxyInfo, localPort, `?schema=public`)}`,
158
+ "## Env variables for libpq (e.g. psql client https://www.postgresql.org/docs/current/libpq-envars.html#LIBPQ-ENVARS)",
159
+ ...lipbqEnvVarDeclarations,
160
+ "",
161
+ ].join("\n"),
162
+ );
163
+
164
+ logLines(
165
+ this,
166
+ null,
167
+ "Connection strings env variables DATABASE_URL and those for the 'psql' client (copied to your clipboard for .env file):",
168
+ dbUrl,
169
+ jdbcUrl,
170
+ ...lipbqEnvVarDeclarations,
171
+ null,
172
+ "DATABASE_URL with schema=public parameter (e. g. Prisma requires this):",
173
+ getDbUrl(proxyInfo, localPort, `?schema=public`),
174
+ null,
175
+ );
176
+
177
+ try {
178
+ await startCloudSqlProxyInCurrentShell({
179
+ instanceName: proxyInfo.instanceName,
180
+ localPort,
181
+ });
182
+ } catch (error) {
183
+ if (!(error instanceof Error)) throw error;
184
+ if (error.message !== ERROR_NOT_INSTALLED) throw error;
185
+ logError(
186
+ this,
187
+ error.message,
188
+ null,
189
+ "Please install the Cloud SQL Auth Proxy from:",
190
+ `https://cloud.google.com/sql/docs/postgres/connect-auth-proxy#install`,
191
+ null,
192
+ );
193
+ }
194
+ });
package/src/utils/log.ts CHANGED
@@ -1,13 +1,109 @@
1
+ import type { CommandInstance } from "vorpal";
2
+
3
+ type AnyMessagesFn = (message?: any, ...optionalParams: any[]) => void;
4
+ type StringMessagesFn = (message?: string, ...optionalParams: string[]) => void;
5
+ type AnyMessageFn = (message?: any) => void;
6
+ type StringMessageFn = (message?: string) => void;
7
+ type StringMessageSpreadFn = (...message: string[]) => void;
8
+ type AnyMessageSpreadFn = (...message: any[]) => void;
9
+ type SomeKindOfLogFn =
10
+ | AnyMessagesFn
11
+ | StringMessagesFn
12
+ | AnyMessageFn
13
+ | StringMessageFn
14
+ | StringMessageSpreadFn
15
+ | AnyMessageSpreadFn;
16
+ type HasSomeKindOfLogMethod = { log: SomeKindOfLogFn };
17
+
18
+ /**
19
+ * Something that has a .log method taking a string argument.
20
+ *
21
+ * null and undefined will fall back to console.log.
22
+ */
23
+ export type LoggerCmdInstance =
24
+ | CommandInstance
25
+ | Console
26
+ | HasSomeKindOfLogMethod
27
+ | null
28
+ | undefined;
29
+
30
+ type LinesArgItem = string | null | undefined;
31
+ type LinesArg = LinesArgItem | LinesArgItem[];
32
+
33
+ /**
34
+ * Logs multiple lines using the log method of the provided {@link LoggerCmdInstance}.
35
+ *
36
+ * Line items that are `null` or `undefined` are logged as empty lines.
37
+ *
38
+ * @param cmd - The logger instance to use. If `null` or `undefined`, `console` will be used.
39
+ *
40
+ * @example
41
+ * ```ts
42
+ * logLines(cmd, "line 1", "line 2", null, "line 3");
43
+ * logLines(cmd, ...linesArray); // arrays can be spread into the function
44
+ * logLines(cmd, linesArray); // but it will flatten the plain array for convenience
45
+ * ```
46
+ */
47
+ export function logLines(
48
+ cmd: LoggerCmdInstance = console,
49
+ ...lines: LinesArg[]
50
+ ) {
51
+ const logger = cmd ?? console;
52
+ for (const line of lines.flat()) {
53
+ if (line === null || line === undefined) {
54
+ logger.log("");
55
+ } else {
56
+ logger.log(line);
57
+ }
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Logs an error message using the log method of the provided {@link LoggerCmdInstance}.
63
+ *
64
+ * Line items that are `null` or `undefined` are logged as empty lines.
65
+ *
66
+ * @example
67
+ * ```ts
68
+ * logError(cmd, "Message");
69
+ * logError(cmd, "Message", "Additional message");
70
+ * logError(cmd, "Message", "Additional message", "Another additional message line");
71
+ * logError(cmd, "Message", ...additionalMessages); // arrays can be spread into the function
72
+ * logError(cmd, "Message", additionalMessages); // but it will flatten the plain array for convenience
73
+ * ```
74
+ */
1
75
  export const logError = (
2
- cmd: any,
76
+ cmd: LoggerCmdInstance = console,
77
+ message: string,
78
+ ...additionalMessages: LinesArg[]
79
+ ) => {
80
+ logLines(cmd, null, `[ERROR] 🙀 :${message}`, null);
81
+ if (additionalMessages?.length) {
82
+ logLines(cmd, ...additionalMessages.flat(), null);
83
+ }
84
+ };
85
+
86
+ /**
87
+ * Logs a warning message using the log method of the provided {@link LoggerCmdInstance}.
88
+ *
89
+ * Line items that are `null` or `undefined` are logged as empty lines.
90
+ *
91
+ * @example
92
+ * ```ts
93
+ * logWarning(cmd, "Message");
94
+ * logWarning(cmd, "Message", "Additional message");
95
+ * logWarning(cmd, "Message", "Additional message", "Another additional message line");
96
+ * logWarning(cmd, "Message", ...additionalMessages); // arrays can be spread into the function
97
+ * logWarning(cmd, "Message", additionalMessages); // but it will flatten the plain array for convenience
98
+ * ```
99
+ */
100
+ export const logWarning = (
101
+ cmd: LoggerCmdInstance = console,
3
102
  message: string,
4
- additionalMessage?: any,
103
+ ...additionalMessages: LinesArg[]
5
104
  ) => {
6
- cmd.log("");
7
- cmd.log(`[ERROR] 🙀 :${message}`);
8
- cmd.log("");
9
- if (additionalMessage) {
10
- cmd.log(additionalMessage);
11
- cmd.log("");
105
+ logLines(cmd, `[WARNING] ⚠️ : ${message}`);
106
+ if (additionalMessages?.length) {
107
+ logLines(cmd, ...additionalMessages.flat(), null);
12
108
  }
13
109
  };