@catladder/cli 1.105.1 → 1.106.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/apps/catenv/printVariables.js +1 -0
- package/dist/apps/catenv/printVariables.js.map +1 -1
- package/dist/apps/catenv/writeDotEnvFiles.js +1 -0
- package/dist/apps/catenv/writeDotEnvFiles.js.map +1 -1
- package/dist/apps/cli/commands/cloudSQL/commandRestoreDb.js +10 -22
- package/dist/apps/cli/commands/cloudSQL/commandRestoreDb.js.map +1 -1
- package/dist/apps/cli/commands/project/commandCloudSqlProxy.js +4 -4
- package/dist/apps/cli/commands/project/commandCloudSqlProxy.js.map +1 -1
- package/dist/bundles/catenv/index.js +3 -3
- package/dist/bundles/cli/index.js +2 -2
- package/dist/config/getProjectConfig.d.ts +2 -6
- package/dist/config/getProjectConfig.js +27 -24
- package/dist/config/getProjectConfig.js.map +1 -1
- package/dist/gcloud/cloudSql/startProxy.d.ts +10 -0
- package/dist/gcloud/cloudSql/startProxy.js +121 -0
- package/dist/gcloud/cloudSql/startProxy.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/apps/catenv/printVariables.ts +3 -1
- package/src/apps/catenv/writeDotEnvFiles.ts +1 -0
- package/src/apps/cli/commands/cloudSQL/commandRestoreDb.ts +14 -29
- package/src/apps/cli/commands/project/commandCloudSqlProxy.ts +6 -9
- package/src/config/getProjectConfig.ts +34 -20
- package/src/gcloud/cloudSql/startProxy.ts +74 -0
- package/src/types/child-process-promise.d.ts +2 -1
package/package.json
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"node": ">=12.0.0"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
"@catladder/pipeline": "1.
|
|
27
|
+
"@catladder/pipeline": "1.106.0",
|
|
28
28
|
"@kubernetes/client-node": "^0.16.2",
|
|
29
29
|
"@tsconfig/node14": "^1.0.1",
|
|
30
30
|
"@types/common-tags": "^1.8.0",
|
|
@@ -57,5 +57,5 @@
|
|
|
57
57
|
"typescript": "^4.5.4",
|
|
58
58
|
"vorpal": "^1.12.0"
|
|
59
59
|
},
|
|
60
|
-
"version": "1.
|
|
60
|
+
"version": "1.106.0"
|
|
61
61
|
}
|
|
@@ -13,7 +13,7 @@ const getAllVariablesToPrint = async (config: Config, choice?: Choice) => {
|
|
|
13
13
|
choice
|
|
14
14
|
);
|
|
15
15
|
|
|
16
|
-
let variables = {};
|
|
16
|
+
let variables: Record<string, string> = {};
|
|
17
17
|
if (currentComponent) {
|
|
18
18
|
variables = await getEnvVarsResolved(null, env, currentComponent);
|
|
19
19
|
} else {
|
|
@@ -23,6 +23,7 @@ const getAllVariablesToPrint = async (config: Config, choice?: Choice) => {
|
|
|
23
23
|
variables = await Object.keys(config.components).reduce(
|
|
24
24
|
async (acc, componentName) => {
|
|
25
25
|
const subappvars = await getEnvVarsResolved(null, env, componentName);
|
|
26
|
+
delete subappvars["_ALL_ENV_VAR_KEYS"];
|
|
26
27
|
return {
|
|
27
28
|
...(await acc),
|
|
28
29
|
...subappvars,
|
|
@@ -38,6 +39,7 @@ const getAllVariablesToPrint = async (config: Config, choice?: Choice) => {
|
|
|
38
39
|
{}
|
|
39
40
|
);
|
|
40
41
|
}
|
|
42
|
+
|
|
41
43
|
return variables;
|
|
42
44
|
};
|
|
43
45
|
|
|
@@ -32,6 +32,7 @@ export const writeDotEnvFiles = async (config: Config, choice?: Choice) => {
|
|
|
32
32
|
|
|
33
33
|
for (const componentName of componentsToActuallyWriteDotEnvNow) {
|
|
34
34
|
const variables = await getEnvVarsResolved(null, env, componentName);
|
|
35
|
+
delete variables["_ALL_ENV_VAR_KEYS"];
|
|
35
36
|
const componentDir = getComponentFullPath(gitRoot, config, componentName);
|
|
36
37
|
const filePath = join(componentDir, ".env");
|
|
37
38
|
// many .dotenv don't like multiline values, so we sanitize them here
|
|
@@ -1,29 +1,8 @@
|
|
|
1
1
|
import { spawn } from "child-process-promise";
|
|
2
|
-
import type Vorpal from "vorpal";
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
[],
|
|
8
|
-
{ shell: "bash" }
|
|
9
|
-
);
|
|
10
|
-
// wait until it starts
|
|
11
|
-
await spawn(
|
|
12
|
-
`echo -n "Waiting for proxy"
|
|
13
|
-
until echo > /dev/tcp/localhost/${port}; do
|
|
14
|
-
sleep 0.2
|
|
15
|
-
echo -n "."
|
|
16
|
-
done 2>/dev/null`,
|
|
17
|
-
[],
|
|
18
|
-
{ shell: "bash" }
|
|
19
|
-
);
|
|
20
|
-
const stop = () => proxy.childProcess.kill();
|
|
21
|
-
process.on("beforeExit", stop);
|
|
22
|
-
|
|
23
|
-
return {
|
|
24
|
-
stop,
|
|
25
|
-
};
|
|
26
|
-
};
|
|
3
|
+
import type Vorpal from "vorpal";
|
|
4
|
+
import type { CloudSqlBackgroundProxy } from "../../../../gcloud/cloudSql/startProxy";
|
|
5
|
+
import { startCloudSqlProxyInBackground } from "../../../../gcloud/cloudSql/startProxy";
|
|
27
6
|
|
|
28
7
|
export default async (vorpal: Vorpal) =>
|
|
29
8
|
vorpal
|
|
@@ -39,9 +18,9 @@ export default async (vorpal: Vorpal) =>
|
|
|
39
18
|
message: "Source instance (connection string or 'local')? 🤔 ",
|
|
40
19
|
});
|
|
41
20
|
|
|
42
|
-
let sourceProxy:
|
|
21
|
+
let sourceProxy: CloudSqlBackgroundProxy;
|
|
43
22
|
|
|
44
|
-
let targetProxy:
|
|
23
|
+
let targetProxy: CloudSqlBackgroundProxy;
|
|
45
24
|
|
|
46
25
|
let sourcePort: number;
|
|
47
26
|
let targetPort: number;
|
|
@@ -57,7 +36,10 @@ export default async (vorpal: Vorpal) =>
|
|
|
57
36
|
sourcePort = sourceLocalPort;
|
|
58
37
|
} else {
|
|
59
38
|
sourcePort = 54399;
|
|
60
|
-
sourceProxy = await
|
|
39
|
+
sourceProxy = await startCloudSqlProxyInBackground({
|
|
40
|
+
instanceName: sourceInstance,
|
|
41
|
+
localPort: sourcePort,
|
|
42
|
+
});
|
|
61
43
|
}
|
|
62
44
|
|
|
63
45
|
const { sourceUsername } = await this.prompt({
|
|
@@ -86,7 +68,7 @@ export default async (vorpal: Vorpal) =>
|
|
|
86
68
|
type: "input",
|
|
87
69
|
name: "targetInstance",
|
|
88
70
|
|
|
89
|
-
message: "
|
|
71
|
+
message: "Target INSTANCE (connection string or 'local')? 🤔 ",
|
|
90
72
|
});
|
|
91
73
|
|
|
92
74
|
if (targetInstance === "local") {
|
|
@@ -100,7 +82,10 @@ export default async (vorpal: Vorpal) =>
|
|
|
100
82
|
targetPort = targetLocalPort;
|
|
101
83
|
} else {
|
|
102
84
|
targetPort = 54499;
|
|
103
|
-
targetProxy = await
|
|
85
|
+
targetProxy = await startCloudSqlProxyInBackground({
|
|
86
|
+
instanceName: targetInstance,
|
|
87
|
+
localPort: targetPort,
|
|
88
|
+
});
|
|
104
89
|
}
|
|
105
90
|
|
|
106
91
|
const { targetUsername } = await this.prompt({
|
|
@@ -3,7 +3,6 @@ import {
|
|
|
3
3
|
createKubernetesCloudsqlBaseValues,
|
|
4
4
|
isOfDeployType,
|
|
5
5
|
} from "@catladder/pipeline";
|
|
6
|
-
import { spawn } from "child-process-promise";
|
|
7
6
|
import type Vorpal from "vorpal";
|
|
8
7
|
import type { CommandInstance } from "vorpal";
|
|
9
8
|
import {
|
|
@@ -12,6 +11,7 @@ import {
|
|
|
12
11
|
parseChoice,
|
|
13
12
|
} from "../../../../config/getProjectConfig";
|
|
14
13
|
import { envAndComponents } from "./utils/autocompletions";
|
|
14
|
+
import { startCloudSqlProxyInCurrentShell } from "../../../../gcloud/cloudSql/startProxy";
|
|
15
15
|
|
|
16
16
|
type ProxyInfo = {
|
|
17
17
|
instanceName: string;
|
|
@@ -70,14 +70,11 @@ export default async (vorpal: Vorpal) =>
|
|
|
70
70
|
`DATABASE_JDBC_URL=jdbc:postgresql://localhost:${localPort}/${DB_NAME}?schema=public&user=${DB_USER}&password=${DB_PASSWORD}`
|
|
71
71
|
);
|
|
72
72
|
this.log("");
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
shell: true,
|
|
79
|
-
}
|
|
80
|
-
);
|
|
73
|
+
|
|
74
|
+
await startCloudSqlProxyInCurrentShell({
|
|
75
|
+
instanceName,
|
|
76
|
+
localPort,
|
|
77
|
+
});
|
|
81
78
|
});
|
|
82
79
|
|
|
83
80
|
const getProxyInfoForKubernetes = async (
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Config } from "@catladder/pipeline";
|
|
1
|
+
import type { Config, EnvironmentEnvVars } from "@catladder/pipeline";
|
|
2
2
|
import {
|
|
3
3
|
readConfigSync,
|
|
4
4
|
getAllEnvs,
|
|
@@ -124,24 +124,32 @@ export const getGitlabVar = async (
|
|
|
124
124
|
|
|
125
125
|
const resolveSecrets = async (
|
|
126
126
|
vorpal: CommandInstance | null,
|
|
127
|
-
|
|
127
|
+
varSets: EnvironmentEnvVars[]
|
|
128
128
|
) => {
|
|
129
129
|
const allVariablesInGitlab = await getAllVariables(vorpal);
|
|
130
130
|
|
|
131
131
|
return Object.fromEntries(
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
132
|
+
varSets.flatMap((set) =>
|
|
133
|
+
Object.entries(set.envVars)
|
|
134
|
+
.map(([key, value]) => {
|
|
135
|
+
const secretKey = set.secretEnvVarKeys.find((k) => k.key === key);
|
|
136
|
+
|
|
137
|
+
if (secretKey) {
|
|
138
|
+
if (secretKey.hidden) {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
for (const variable of allVariablesInGitlab) {
|
|
142
|
+
value = value.replace(
|
|
143
|
+
new RegExp("\\$" + variable.key, "g"),
|
|
144
|
+
variable.value
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
return [key, value];
|
|
148
|
+
}
|
|
149
|
+
return [key, value];
|
|
150
|
+
})
|
|
151
|
+
.filter(Boolean)
|
|
152
|
+
)
|
|
145
153
|
);
|
|
146
154
|
};
|
|
147
155
|
|
|
@@ -155,9 +163,15 @@ export const getEnvVarsResolved = async (
|
|
|
155
163
|
}
|
|
156
164
|
try {
|
|
157
165
|
const envionment = await getEnvironment(env, componentName);
|
|
166
|
+
|
|
158
167
|
// in the pipeline the secrets alreadyy exists and bash will expand them
|
|
159
168
|
// but here we need to manually load them
|
|
160
|
-
return resolveSecrets(vorpal,
|
|
169
|
+
return resolveSecrets(vorpal, [
|
|
170
|
+
{
|
|
171
|
+
envVars: envionment.envVars,
|
|
172
|
+
secretEnvVarKeys: envionment.secretEnvVarKeys,
|
|
173
|
+
},
|
|
174
|
+
]);
|
|
161
175
|
} catch (e) {
|
|
162
176
|
// env is disabled
|
|
163
177
|
return {};
|
|
@@ -175,10 +189,10 @@ export const getJobOnlyEnvVarsResolved = async (
|
|
|
175
189
|
) => {
|
|
176
190
|
try {
|
|
177
191
|
const envionment = await getEnvironment(env, componentName);
|
|
178
|
-
return resolveSecrets(vorpal,
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
192
|
+
return resolveSecrets(vorpal, [
|
|
193
|
+
envionment.jobOnlyVars.build,
|
|
194
|
+
envionment.jobOnlyVars.deploy,
|
|
195
|
+
]);
|
|
182
196
|
} catch (e) {
|
|
183
197
|
// env is disabled
|
|
184
198
|
return {};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { spawn } from "child-process-promise";
|
|
2
|
+
import commandExists from "command-exists-promise";
|
|
3
|
+
|
|
4
|
+
export const ERROR_NOT_INSTALLED = "cloud-sql-proxy not installed";
|
|
5
|
+
|
|
6
|
+
export type CloudSqlBackgroundProxy = {
|
|
7
|
+
stop: () => void;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export type CloudSqlProxyOptions = {
|
|
11
|
+
instanceName: string;
|
|
12
|
+
localPort: number;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const getProxyCommandSpawnArgs = async ({
|
|
16
|
+
localPort,
|
|
17
|
+
instanceName,
|
|
18
|
+
}: CloudSqlProxyOptions) => {
|
|
19
|
+
const commandString = (await commandExists("cloud-sql-proxy"))
|
|
20
|
+
? `cloud-sql-proxy --port ${localPort} ${instanceName}`
|
|
21
|
+
: (await commandExists(
|
|
22
|
+
"cloud_sql_proxy" // v1
|
|
23
|
+
))
|
|
24
|
+
? `cloud_sql_proxy -instances ${instanceName}=tcp:${localPort}`
|
|
25
|
+
: null;
|
|
26
|
+
if (!commandString) {
|
|
27
|
+
throw new Error(ERROR_NOT_INSTALLED);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const [cmd, ...args] = commandString.split(" ");
|
|
31
|
+
return { cmd, args };
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const startCloudSqlProxyInCurrentShell = async (
|
|
35
|
+
opts: CloudSqlProxyOptions
|
|
36
|
+
) => {
|
|
37
|
+
const { cmd, args } = await getProxyCommandSpawnArgs(opts);
|
|
38
|
+
|
|
39
|
+
await spawn(cmd, args, {
|
|
40
|
+
stdio: "inherit",
|
|
41
|
+
shell: true,
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export const startCloudSqlProxyInBackground = async (
|
|
46
|
+
opts: CloudSqlProxyOptions
|
|
47
|
+
): Promise<CloudSqlBackgroundProxy> => {
|
|
48
|
+
const { cmd, args } = await getProxyCommandSpawnArgs(opts);
|
|
49
|
+
|
|
50
|
+
const proxyPromise = spawn(cmd, args, { shell: "bash" });
|
|
51
|
+
|
|
52
|
+
// wait until it starts
|
|
53
|
+
await spawn(
|
|
54
|
+
`echo -n "Waiting for proxy"
|
|
55
|
+
until echo > /dev/tcp/localhost/${opts.localPort}; do
|
|
56
|
+
sleep 0.2
|
|
57
|
+
echo -n "."
|
|
58
|
+
done 2>/dev/null`,
|
|
59
|
+
[],
|
|
60
|
+
{ shell: "bash" }
|
|
61
|
+
);
|
|
62
|
+
const stop = () => {
|
|
63
|
+
proxyPromise.catch(() => {
|
|
64
|
+
// ignore
|
|
65
|
+
});
|
|
66
|
+
proxyPromise.childProcess.kill();
|
|
67
|
+
};
|
|
68
|
+
// stop if catladder i stopped
|
|
69
|
+
process.on("beforeExit", stop);
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
stop,
|
|
73
|
+
};
|
|
74
|
+
};
|
|
@@ -13,7 +13,7 @@ declare module "child-process-promise" {
|
|
|
13
13
|
type Stdio = "inherit" | "pipe";
|
|
14
14
|
type SpawnOptions = {
|
|
15
15
|
stdio?: Stdio | Stdio[];
|
|
16
|
-
shell?: boolean;
|
|
16
|
+
shell?: boolean | string;
|
|
17
17
|
env?: Record<string, string>;
|
|
18
18
|
};
|
|
19
19
|
|
|
@@ -31,6 +31,7 @@ declare module "child-process-promise" {
|
|
|
31
31
|
): Promise<unknown> & {
|
|
32
32
|
childProcess: {
|
|
33
33
|
stdout: ReadStream;
|
|
34
|
+
kill: () => void;
|
|
34
35
|
};
|
|
35
36
|
};
|
|
36
37
|
}
|