@catladder/cli 0.0.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/.nvmrc +1 -0
- package/CONTRIBUTING.md +83 -0
- package/README.md +31 -0
- package/bin/catenv.sh +1 -0
- package/bin/catladder +3 -0
- package/includes/envrc +35 -0
- package/package.json +65 -0
- package/src/apps/catenv/catenv.ts +41 -0
- package/src/apps/shell/commands/general/index.ts +132 -0
- package/src/apps/shell/commands/general/namespaceAutoCompletion.ts +7 -0
- package/src/apps/shell/commands/general/portForward.ts +47 -0
- package/src/apps/shell/commands/mongodb/index.ts +10 -0
- package/src/apps/shell/commands/mongodb/projectMongoDestroyMember.ts +134 -0
- package/src/apps/shell/commands/mongodb/projectMongoGetShell.ts +41 -0
- package/src/apps/shell/commands/mongodb/projectMongoPortForward.ts +42 -0
- package/src/apps/shell/commands/mongodb/utils/index.ts +84 -0
- package/src/apps/shell/commands/project/commandCloudSqlProxy.ts +65 -0
- package/src/apps/shell/commands/project/commandConfigSecrets.ts +245 -0
- package/src/apps/shell/commands/project/commandCopyDB.ts +93 -0
- package/src/apps/shell/commands/project/commandDeletePods.ts +50 -0
- package/src/apps/shell/commands/project/commandDeleteProject.ts +34 -0
- package/src/apps/shell/commands/project/commandEnvVars.ts +17 -0
- package/src/apps/shell/commands/project/commandGetMyTotalWorktime.ts +14 -0
- package/src/apps/shell/commands/project/commandGetShell.ts +35 -0
- package/src/apps/shell/commands/project/commandGitlabCi.ts +114 -0
- package/src/apps/shell/commands/project/commandInitGitlab.ts +157 -0
- package/src/apps/shell/commands/project/commandInitProject.ts +282 -0
- package/src/apps/shell/commands/project/commandListPods.ts +21 -0
- package/src/apps/shell/commands/project/commandMigrateHelm3.ts +53 -0
- package/src/apps/shell/commands/project/commandNamespace.ts +12 -0
- package/src/apps/shell/commands/project/commandOpenCostDashboard.ts +29 -0
- package/src/apps/shell/commands/project/commandOpenDashboard.ts +27 -0
- package/src/apps/shell/commands/project/commandOpenEnv.ts +18 -0
- package/src/apps/shell/commands/project/commandOpenGit.ts +12 -0
- package/src/apps/shell/commands/project/commandOpenGrafana.ts +31 -0
- package/src/apps/shell/commands/project/commandOpenGrafanaPod.ts +46 -0
- package/src/apps/shell/commands/project/commandOpenLogs.ts +23 -0
- package/src/apps/shell/commands/project/commandPauseProject.ts +31 -0
- package/src/apps/shell/commands/project/commandPortForward.ts +45 -0
- package/src/apps/shell/commands/project/commandTriggerCronjob.ts +61 -0
- package/src/apps/shell/commands/project/commandVariables.ts +13 -0
- package/src/apps/shell/commands/project/index.ts +62 -0
- package/src/apps/shell/commands/project/utils/autocompletions.ts +7 -0
- package/src/apps/shell/commands/project/utils/ensureCluster.ts +31 -0
- package/src/apps/shell/commands/project/utils/ensureNamespace.ts +32 -0
- package/src/apps/shell/commands/project/utils/monorepo.ts +45 -0
- package/src/apps/shell/commands/shared/index.ts +31 -0
- package/src/apps/shell/commands/theStuffThatReallyMatters/index.ts +51 -0
- package/src/apps/shell/shell.ts +30 -0
- package/src/apps/shell/utils/getGoogleAuthUserNumber.ts +23 -0
- package/src/config/clusters.ts +45 -0
- package/src/config/constants.ts +5 -0
- package/src/index.ts +17 -0
- package/src/k8sApi/index.ts +17 -0
- package/src/packageInfos.ts +4 -0
- package/src/types/child-process-promise.d.ts +1 -0
- package/src/types/command-exists-promise.d.ts +1 -0
- package/src/types/git-repo-name.d.ts +1 -0
- package/src/types/types.ts +20 -0
- package/src/types/yawn-yaml.d.ts +1 -0
- package/src/utils/cluster.ts +21 -0
- package/src/utils/dashboardToken.ts +20 -0
- package/src/utils/files.ts +18 -0
- package/src/utils/formatEnvVars.ts +7 -0
- package/src/utils/getEditor.ts +16 -0
- package/src/utils/gitlab.ts +80 -0
- package/src/utils/log.ts +13 -0
- package/src/utils/passwordstore/index.ts +192 -0
- package/src/utils/portForward.ts +52 -0
- package/src/utils/preferences/index.ts +33 -0
- package/src/utils/projects/index.ts +171 -0
- package/src/utils/promise.ts +11 -0
- package/src/utils/shell.ts +20 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { exec } from "child-process-promise";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
import k8sApi from "../../k8sApi";
|
|
4
|
+
import { Env, ISecrets, IValueFile } from "../../types/types";
|
|
5
|
+
import { readFileOrError, readYaml } from "../files";
|
|
6
|
+
import formatEnvVars from "../formatEnvVars";
|
|
7
|
+
import { hasBitwarden, readPassEnvVars, syncBitwarden } from "../passwordstore";
|
|
8
|
+
import { filter } from "../promise";
|
|
9
|
+
|
|
10
|
+
import { merge } from "lodash";
|
|
11
|
+
|
|
12
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
13
|
+
const YAWN = require("yawn-yaml/cjs");
|
|
14
|
+
|
|
15
|
+
export const getGitRoot = async () => {
|
|
16
|
+
return (await exec("git rev-parse --show-toplevel")).stdout?.trim();
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const getRootGitlabCiFile = async () => {
|
|
20
|
+
const gitRoot = await getGitRoot();
|
|
21
|
+
return join(gitRoot, ".gitlab-ci.yml");
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const readRootGitlabCiFile = async () =>
|
|
25
|
+
readFileOrError(await getRootGitlabCiFile());
|
|
26
|
+
|
|
27
|
+
export const hasGitlabCiFile = async () => {
|
|
28
|
+
const [error, file] = await readRootGitlabCiFile();
|
|
29
|
+
if (error) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
return true;
|
|
33
|
+
};
|
|
34
|
+
export const getLocalProjectVariables = async () => {
|
|
35
|
+
const [error, file] = await readRootGitlabCiFile();
|
|
36
|
+
if (error) {
|
|
37
|
+
throw new Error("there is no '.gitlab-ci.yml' in the current project");
|
|
38
|
+
}
|
|
39
|
+
// yawn allows to modify yaml while keeping comments!
|
|
40
|
+
const yawn = new YAWN(file);
|
|
41
|
+
const { variables } = yawn.json;
|
|
42
|
+
if (!variables) {
|
|
43
|
+
throw new Error("your '.gitlab-ci.yml' does not define `variables`");
|
|
44
|
+
}
|
|
45
|
+
const defaults = {
|
|
46
|
+
CLUSTER_NAME: "production",
|
|
47
|
+
};
|
|
48
|
+
return {
|
|
49
|
+
...defaults,
|
|
50
|
+
...variables,
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export const getProjectNamespace = async (env: Env) => {
|
|
55
|
+
const { CUSTOMER_NAME, APP_NAME } = await getLocalProjectVariables();
|
|
56
|
+
return `${CUSTOMER_NAME}-${APP_NAME}-${env}`;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export const getProjectHelmReleaseName = async (env: Env) => {
|
|
60
|
+
// can't properly get the release name for review as it contains an additional branch slug
|
|
61
|
+
if (env === "review" || env === "dev-local") {
|
|
62
|
+
throw new Error(`can't get helm release name for ${env}`);
|
|
63
|
+
}
|
|
64
|
+
const {
|
|
65
|
+
CUSTOMER_NAME,
|
|
66
|
+
APP_NAME,
|
|
67
|
+
COMPONENT_NAME = "web",
|
|
68
|
+
} = await getLocalProjectVariables();
|
|
69
|
+
return `${CUSTOMER_NAME}-${APP_NAME}-${env}-${COMPONENT_NAME}`;
|
|
70
|
+
};
|
|
71
|
+
export const getProjectPods = async (env: Env) => {
|
|
72
|
+
const namespace = await getProjectNamespace(env);
|
|
73
|
+
const res = await k8sApi.listNamespacedPod(namespace);
|
|
74
|
+
|
|
75
|
+
return res.body.items;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export const getProjectPvcs = async (env: Env) => {
|
|
79
|
+
const namespace = await getProjectNamespace(env);
|
|
80
|
+
const res = await k8sApi.listNamespacedPersistentVolumeClaim(namespace);
|
|
81
|
+
|
|
82
|
+
return res.body.items;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export const getProjectPodNames = async (env: Env) => {
|
|
86
|
+
const pods = await getProjectPods(env);
|
|
87
|
+
return pods.map((n) => n.metadata.name);
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export const getPassPath = async (env: Env) => {
|
|
91
|
+
const { CUSTOMER_NAME, APP_NAME } = await getLocalProjectVariables();
|
|
92
|
+
return `${CUSTOMER_NAME}/${APP_NAME}/${env}/secrets.yml`;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export const getProjectValuesFiles = async (env: Env, subApp?: string) => {
|
|
96
|
+
const gitRoot = await getGitRoot();
|
|
97
|
+
const possibleFiles = ["values.yml", `values-${env}.yml`].map((file) =>
|
|
98
|
+
subApp ? join(gitRoot, subApp, file) : join(gitRoot, file)
|
|
99
|
+
);
|
|
100
|
+
return filter(possibleFiles, async (file) => {
|
|
101
|
+
const [error] = await readFileOrError(file);
|
|
102
|
+
return !error;
|
|
103
|
+
});
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export const getAllValues = async (env: Env, subApp?: string) => {
|
|
107
|
+
const valuesFilePaths = await getProjectValuesFiles(env, subApp);
|
|
108
|
+
return Promise.all(
|
|
109
|
+
valuesFilePaths.map(async (file) => (await readYaml(file)) as IValueFile)
|
|
110
|
+
);
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
export const getProjectValues = async (env: Env, subApp?: string) => {
|
|
114
|
+
const values = await getAllValues(env, subApp);
|
|
115
|
+
return merge({}, ...values) as IValueFile;
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
export const getAllPublicEnvVars = async (env: Env, subApp?: string) => {
|
|
119
|
+
return formatEnvVars(
|
|
120
|
+
(await getAllValues(env, subApp)).reduce<ISecrets>((acc, value) => {
|
|
121
|
+
if (value.env && value.env.public) {
|
|
122
|
+
return {
|
|
123
|
+
...acc,
|
|
124
|
+
...value.env.public,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
return acc;
|
|
128
|
+
}, {})
|
|
129
|
+
);
|
|
130
|
+
};
|
|
131
|
+
export const getAllSecretsEnvVarsMapping = async (
|
|
132
|
+
env: Env,
|
|
133
|
+
subApp?: string
|
|
134
|
+
) => {
|
|
135
|
+
return (await getAllValues(env, subApp)).reduce<ISecrets>((acc, value) => {
|
|
136
|
+
if (value.env && value.env.secret) {
|
|
137
|
+
return {
|
|
138
|
+
...acc,
|
|
139
|
+
...value.env.secret,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
return acc;
|
|
143
|
+
}, {});
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
export const hasSecrets = async (env: Env, subApp?: string) => {
|
|
147
|
+
return Object.keys(await getAllSecretsEnvVarsMapping(env, subApp)).length > 0;
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
export const getAllEnvVars = async (
|
|
151
|
+
env: Env,
|
|
152
|
+
subApp?: string
|
|
153
|
+
): Promise<Record<string, string>> => {
|
|
154
|
+
return {
|
|
155
|
+
...(await getAllPublicEnvVars(env, subApp)),
|
|
156
|
+
...(await getAllSecretEnvVars(env, subApp)),
|
|
157
|
+
};
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
export const getAllSecretEnvVars = async (env: Env, subApp?: string) => {
|
|
161
|
+
if (!(await hasSecrets(env, subApp))) {
|
|
162
|
+
return {};
|
|
163
|
+
}
|
|
164
|
+
if (await hasBitwarden()) {
|
|
165
|
+
await syncBitwarden(false /* do not force sync */);
|
|
166
|
+
const passPath = await getPassPath(env);
|
|
167
|
+
return readPassEnvVars(passPath);
|
|
168
|
+
} else {
|
|
169
|
+
return {};
|
|
170
|
+
}
|
|
171
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export async function filter<T>(
|
|
2
|
+
arr: T[],
|
|
3
|
+
iterator: (item: T) => Promise<boolean>
|
|
4
|
+
) {
|
|
5
|
+
const fail = Symbol("fail");
|
|
6
|
+
return ((await Promise.all(
|
|
7
|
+
arr.map(async item => ((await iterator(item)) ? item : fail))
|
|
8
|
+
)).filter(i => i !== fail) as any) as Promise<T[]>;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const delay = (ms: number) => new Promise(res => setTimeout(res, ms));
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { spawn } from "child-process-promise";
|
|
2
|
+
|
|
3
|
+
export const getShell = async (namespace: string, podName: string) => {
|
|
4
|
+
const command = `kubectl exec -it ${podName} -n ${namespace} -- /bin/sh -xc 'bash||sh'`;
|
|
5
|
+
try {
|
|
6
|
+
await spawn(command, {
|
|
7
|
+
stdio: "inherit",
|
|
8
|
+
shell: true,
|
|
9
|
+
env: {
|
|
10
|
+
...process.env,
|
|
11
|
+
DEBUG: "",
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
} catch (e) {
|
|
15
|
+
// tslint:disable-next-line:no-console
|
|
16
|
+
if (e.code !== 130) {
|
|
17
|
+
console.log(e);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
};
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "@tsconfig/node14/tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"module": "CommonJS",
|
|
5
|
+
"declaration": true,
|
|
6
|
+
"noImplicitAny": true,
|
|
7
|
+
"moduleResolution": "node",
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"sourceMap": true,
|
|
10
|
+
"outDir": "dist",
|
|
11
|
+
"strict": false,
|
|
12
|
+
"baseUrl": ".",
|
|
13
|
+
"incremental": true,
|
|
14
|
+
"resolveJsonModule": true,
|
|
15
|
+
"paths": {
|
|
16
|
+
"*": ["node_modules/*", "src/types/*"]
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"include": ["src/**/*"]
|
|
20
|
+
}
|