@catladder/cli 0.0.0-refactor-untangle-gitlab-api-requests-from-vorpal-57cf3cf2 → 0.0.0-reference-database-url-1befbbee

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 (192) hide show
  1. package/dist/bundles/catenv/index.js +2146 -23675
  2. package/dist/bundles/cli/index.js +575 -1032
  3. package/dist/cli/src/apps/cli/commands/project/commandGitlabCi.d.ts +2 -5
  4. package/dist/cli/src/apps/cli/commands/project/commandGitlabCi.js +9 -26
  5. package/dist/cli/src/apps/cli/commands/project/commandGitlabCi.js.map +1 -1
  6. package/dist/cli/src/apps/cli/commands/project/commandSetup.js +5 -3
  7. package/dist/cli/src/apps/cli/commands/project/commandSetup.js.map +1 -1
  8. package/dist/cli/src/apps/cli/commands/project/setup/index.d.ts +1 -1
  9. package/dist/cli/src/apps/cli/commands/project/setup/index.js +6 -17
  10. package/dist/cli/src/apps/cli/commands/project/setup/index.js.map +1 -1
  11. package/dist/cli/src/apps/cli/commands/project/setup/setupAccessTokens.d.ts +1 -4
  12. package/dist/cli/src/apps/cli/commands/project/setup/setupAccessTokens.js +23 -35
  13. package/dist/cli/src/apps/cli/commands/project/setup/setupAccessTokens.js.map +1 -1
  14. package/dist/cli/src/apps/cli/commands/project/setup/setupKubernetes.d.ts +2 -5
  15. package/dist/cli/src/apps/cli/commands/project/setup/setupKubernetes.js +23 -38
  16. package/dist/cli/src/apps/cli/commands/project/setup/setupKubernetes.js.map +1 -1
  17. package/dist/cli/src/apps/cli/commands/project/setup/setupTopic.d.ts +1 -2
  18. package/dist/cli/src/apps/cli/commands/project/setup/setupTopic.js +4 -5
  19. package/dist/cli/src/apps/cli/commands/project/setup/setupTopic.js.map +1 -1
  20. package/dist/cli/src/apps/cli/commands/project/utils/autocompletions.d.ts +1 -0
  21. package/dist/cli/src/apps/cli/commands/project/utils/autocompletions.js +9 -1
  22. package/dist/cli/src/apps/cli/commands/project/utils/autocompletions.js.map +1 -1
  23. package/dist/cli/src/apps/cli/utils/getGoogleAuthUserNumber.d.ts +1 -1
  24. package/dist/cli/src/apps/cli/utils/getGoogleAuthUserNumber.js +11 -20
  25. package/dist/cli/src/apps/cli/utils/getGoogleAuthUserNumber.js.map +1 -1
  26. package/dist/cli/src/apps/cli/verify/index.js +5 -22
  27. package/dist/cli/src/apps/cli/verify/index.js.map +1 -1
  28. package/dist/cli/src/config/getProjectConfig.d.ts +1 -1
  29. package/dist/cli/src/config/getProjectConfig.js +10 -12
  30. package/dist/cli/src/config/getProjectConfig.js.map +1 -1
  31. package/dist/cli/src/git/gitProjectInformation.d.ts +1 -14
  32. package/dist/cli/src/git/gitProjectInformation.js +2 -29
  33. package/dist/cli/src/git/gitProjectInformation.js.map +1 -1
  34. package/dist/cli/src/utils/gitlab.d.ts +23 -17
  35. package/dist/cli/src/utils/gitlab.js +161 -120
  36. package/dist/cli/src/utils/gitlab.js.map +1 -1
  37. package/dist/cli/src/utils/log.d.ts +0 -15
  38. package/dist/cli/src/utils/log.js +1 -23
  39. package/dist/cli/src/utils/log.js.map +1 -1
  40. package/dist/cli/src/utils/preferences.d.ts +4 -0
  41. package/dist/cli/src/utils/preferences.js +58 -0
  42. package/dist/cli/src/utils/preferences.js.map +1 -0
  43. package/dist/pipeline/src/build/artifacts/createBuildJobArtifact.js +3 -1
  44. package/dist/pipeline/src/build/artifacts/createBuildJobArtifact.js.map +1 -1
  45. package/dist/pipeline/src/build/base/index.d.ts +2 -3
  46. package/dist/pipeline/src/build/base/index.js.map +1 -1
  47. package/dist/pipeline/src/build/cache/getAllCacheConfigsFromConfig.js +6 -4
  48. package/dist/pipeline/src/build/cache/getAllCacheConfigsFromConfig.js.map +1 -1
  49. package/dist/pipeline/src/build/custom/buildJob.d.ts +2 -2
  50. package/dist/pipeline/src/build/custom/buildJob.js.map +1 -1
  51. package/dist/pipeline/src/build/custom/index.d.ts +2 -2
  52. package/dist/pipeline/src/build/custom/index.js.map +1 -1
  53. package/dist/pipeline/src/build/custom/testJob.d.ts +2 -2
  54. package/dist/pipeline/src/build/custom/testJob.js.map +1 -1
  55. package/dist/pipeline/src/build/docker.d.ts +4 -4
  56. package/dist/pipeline/src/build/docker.js +1 -1
  57. package/dist/pipeline/src/build/docker.js.map +1 -1
  58. package/dist/pipeline/src/build/index.d.ts +2 -2
  59. package/dist/pipeline/src/build/index.js +2 -3
  60. package/dist/pipeline/src/build/index.js.map +1 -1
  61. package/dist/pipeline/src/build/node/buildJob.d.ts +5 -3
  62. package/dist/pipeline/src/build/node/buildJob.js.map +1 -1
  63. package/dist/pipeline/src/build/node/index.d.ts +4 -4
  64. package/dist/pipeline/src/build/node/index.js.map +1 -1
  65. package/dist/pipeline/src/build/node/meteor.d.ts +2 -2
  66. package/dist/pipeline/src/build/node/meteor.js.map +1 -1
  67. package/dist/pipeline/src/build/node/yarn.d.ts +1 -1
  68. package/dist/pipeline/src/build/node/yarn.js +3 -1
  69. package/dist/pipeline/src/build/node/yarn.js.map +1 -1
  70. package/dist/pipeline/src/build/rails/build.d.ts +2 -2
  71. package/dist/pipeline/src/build/rails/build.js +0 -1
  72. package/dist/pipeline/src/build/rails/build.js.map +1 -1
  73. package/dist/pipeline/src/build/rails/index.d.ts +2 -2
  74. package/dist/pipeline/src/build/rails/index.js.map +1 -1
  75. package/dist/pipeline/src/build/rails/test.js +18 -1
  76. package/dist/pipeline/src/build/rails/test.js.map +1 -1
  77. package/dist/pipeline/src/build/sbom.d.ts +2 -2
  78. package/dist/pipeline/src/build/sbom.js +4 -1
  79. package/dist/pipeline/src/build/sbom.js.map +1 -1
  80. package/dist/pipeline/src/build/types.d.ts +8 -0
  81. package/dist/pipeline/src/build/types.js.map +1 -1
  82. package/dist/pipeline/src/context/createComponentContext.js +17 -6
  83. package/dist/pipeline/src/context/createComponentContext.js.map +1 -1
  84. package/dist/pipeline/src/context/getLabels.js +3 -1
  85. package/dist/pipeline/src/context/getLabels.js.map +1 -1
  86. package/dist/pipeline/src/deploy/cloudRun/createJobs/cloudRunJobs.js +2 -2
  87. package/dist/pipeline/src/deploy/cloudRun/createJobs/cloudRunJobs.js.map +1 -1
  88. package/dist/pipeline/src/deploy/cloudRun/createJobs/cloudRunServices.js +32 -7
  89. package/dist/pipeline/src/deploy/cloudRun/createJobs/cloudRunServices.js.map +1 -1
  90. package/dist/pipeline/src/deploy/cloudRun/createJobs/execute/onDeploy.d.ts +1 -2
  91. package/dist/pipeline/src/deploy/cloudRun/createJobs/execute/onDeploy.js +3 -10
  92. package/dist/pipeline/src/deploy/cloudRun/createJobs/execute/onDeploy.js.map +1 -1
  93. package/dist/pipeline/src/deploy/cloudRun/createJobs/healthCheck.d.ts +5 -0
  94. package/dist/pipeline/src/deploy/cloudRun/createJobs/healthCheck.js +51 -0
  95. package/dist/pipeline/src/deploy/cloudRun/createJobs/healthCheck.js.map +1 -0
  96. package/dist/pipeline/src/deploy/cloudRun/index.js +7 -4
  97. package/dist/pipeline/src/deploy/cloudRun/index.js.map +1 -1
  98. package/dist/pipeline/src/deploy/cloudRun/utils/database.d.ts +21 -2
  99. package/dist/pipeline/src/deploy/cloudRun/utils/database.js +55 -6
  100. package/dist/pipeline/src/deploy/cloudRun/utils/database.js.map +1 -1
  101. package/dist/pipeline/src/deploy/cloudRun/utils/getJobOrServiceArgs.d.ts +2 -0
  102. package/dist/pipeline/src/deploy/cloudRun/utils/getJobOrServiceArgs.js +12 -0
  103. package/dist/pipeline/src/deploy/cloudRun/utils/getJobOrServiceArgs.js.map +1 -0
  104. package/dist/pipeline/src/deploy/kubernetes/kubeValues.d.ts +2 -2
  105. package/dist/pipeline/src/deploy/kubernetes/kubeValues.js +3 -1
  106. package/dist/pipeline/src/deploy/kubernetes/kubeValues.js.map +1 -1
  107. package/dist/pipeline/src/deploy/sbom.js +4 -3
  108. package/dist/pipeline/src/deploy/sbom.js.map +1 -1
  109. package/dist/pipeline/src/deploy/types/googleCloudRun.d.ts +100 -0
  110. package/dist/pipeline/src/deploy/types/googleCloudRun.js +16 -0
  111. package/dist/pipeline/src/deploy/types/googleCloudRun.js.map +1 -1
  112. package/dist/pipeline/src/pipeline/createJobsForComponent.js +3 -1
  113. package/dist/pipeline/src/pipeline/createJobsForComponent.js.map +1 -1
  114. package/dist/pipeline/src/types/config.d.ts +1 -1
  115. package/dist/pipeline/src/types/context.d.ts +6 -1
  116. package/dist/pipeline/src/types/context.js.map +1 -1
  117. package/dist/tsconfig.tsbuildinfo +1 -1
  118. package/package.json +1 -1
  119. package/src/apps/cli/commands/project/commandGitlabCi.ts +20 -58
  120. package/src/apps/cli/commands/project/commandSetup.ts +5 -3
  121. package/src/apps/cli/commands/project/setup/index.ts +9 -19
  122. package/src/apps/cli/commands/project/setup/setupAccessTokens.ts +45 -62
  123. package/src/apps/cli/commands/project/setup/setupKubernetes.ts +32 -53
  124. package/src/apps/cli/commands/project/setup/setupTopic.ts +12 -17
  125. package/src/apps/cli/commands/project/utils/autocompletions.ts +9 -0
  126. package/src/apps/cli/utils/getGoogleAuthUserNumber.ts +18 -28
  127. package/src/apps/cli/verify/index.ts +7 -25
  128. package/src/config/getProjectConfig.ts +21 -22
  129. package/src/git/gitProjectInformation.ts +1 -31
  130. package/src/utils/gitlab.ts +247 -200
  131. package/src/utils/log.ts +0 -26
  132. package/src/utils/preferences.ts +60 -0
  133. package/dist/cli/src/utils/gitlab-without-vorpal/FetchGitLabError.d.ts +0 -18
  134. package/dist/cli/src/utils/gitlab-without-vorpal/FetchGitLabError.js +0 -32
  135. package/dist/cli/src/utils/gitlab-without-vorpal/FetchGitLabError.js.map +0 -1
  136. package/dist/cli/src/utils/gitlab-without-vorpal/FetchMethod.d.ts +0 -1
  137. package/dist/cli/src/utils/gitlab-without-vorpal/FetchMethod.js +0 -3
  138. package/dist/cli/src/utils/gitlab-without-vorpal/FetchMethod.js.map +0 -1
  139. package/dist/cli/src/utils/gitlab-without-vorpal/GitLabApiDataOptional.d.ts +0 -14
  140. package/dist/cli/src/utils/gitlab-without-vorpal/GitLabApiDataOptional.js +0 -3
  141. package/dist/cli/src/utils/gitlab-without-vorpal/GitLabApiDataOptional.js.map +0 -1
  142. package/dist/cli/src/utils/gitlab-without-vorpal/GitLabTokenMissingError.d.ts +0 -4
  143. package/dist/cli/src/utils/gitlab-without-vorpal/GitLabTokenMissingError.js +0 -12
  144. package/dist/cli/src/utils/gitlab-without-vorpal/GitLabTokenMissingError.js.map +0 -1
  145. package/dist/cli/src/utils/gitlab-without-vorpal/fetchGitLabApi.d.ts +0 -8
  146. package/dist/cli/src/utils/gitlab-without-vorpal/fetchGitLabApi.js +0 -47
  147. package/dist/cli/src/utils/gitlab-without-vorpal/fetchGitLabApi.js.map +0 -1
  148. package/dist/cli/src/utils/gitlab-without-vorpal/getGitlabHostPathToken.d.ts +0 -20
  149. package/dist/cli/src/utils/gitlab-without-vorpal/getGitlabHostPathToken.js +0 -15
  150. package/dist/cli/src/utils/gitlab-without-vorpal/getGitlabHostPathToken.js.map +0 -1
  151. package/dist/cli/src/utils/gitlab-without-vorpal/gitLabProjectByGitPath.d.ts +0 -23
  152. package/dist/cli/src/utils/gitlab-without-vorpal/gitLabProjectByGitPath.js +0 -30
  153. package/dist/cli/src/utils/gitlab-without-vorpal/gitLabProjectByGitPath.js.map +0 -1
  154. package/dist/cli/src/utils/gitlab-without-vorpal/gitLabVariables.d.ts +0 -66
  155. package/dist/cli/src/utils/gitlab-without-vorpal/gitLabVariables.js +0 -129
  156. package/dist/cli/src/utils/gitlab-without-vorpal/gitLabVariables.js.map +0 -1
  157. package/dist/cli/src/utils/gitlab-without-vorpal/index.d.ts +0 -12
  158. package/dist/cli/src/utils/gitlab-without-vorpal/index.js +0 -29
  159. package/dist/cli/src/utils/gitlab-without-vorpal/index.js.map +0 -1
  160. package/dist/cli/src/utils/gitlab-without-vorpal/insertProjectTopics.d.ts +0 -5
  161. package/dist/cli/src/utils/gitlab-without-vorpal/insertProjectTopics.js +0 -23
  162. package/dist/cli/src/utils/gitlab-without-vorpal/insertProjectTopics.js.map +0 -1
  163. package/dist/cli/src/utils/gitlab-without-vorpal/loadGitLabToken.d.ts +0 -2
  164. package/dist/cli/src/utils/gitlab-without-vorpal/loadGitLabToken.js +0 -27
  165. package/dist/cli/src/utils/gitlab-without-vorpal/loadGitLabToken.js.map +0 -1
  166. package/dist/cli/src/utils/gitlab-without-vorpal/projectAccessToken.d.ts +0 -29
  167. package/dist/cli/src/utils/gitlab-without-vorpal/projectAccessToken.js +0 -24
  168. package/dist/cli/src/utils/gitlab-without-vorpal/projectAccessToken.js.map +0 -1
  169. package/dist/cli/src/utils/gitlab-without-vorpal/storeGitLabToken.d.ts +0 -3
  170. package/dist/cli/src/utils/gitlab-without-vorpal/storeGitLabToken.js +0 -19
  171. package/dist/cli/src/utils/gitlab-without-vorpal/storeGitLabToken.js.map +0 -1
  172. package/dist/cli/src/utils/preferences/CatladderPreferences.d.ts +0 -27
  173. package/dist/cli/src/utils/preferences/CatladderPreferences.js +0 -34
  174. package/dist/cli/src/utils/preferences/CatladderPreferences.js.map +0 -1
  175. package/dist/cli/src/utils/preferences/index.d.ts +0 -11
  176. package/dist/cli/src/utils/preferences/index.js +0 -79
  177. package/dist/cli/src/utils/preferences/index.js.map +0 -1
  178. package/src/utils/gitlab-without-vorpal/FetchGitLabError.ts +0 -57
  179. package/src/utils/gitlab-without-vorpal/FetchMethod.ts +0 -1
  180. package/src/utils/gitlab-without-vorpal/GitLabApiDataOptional.ts +0 -14
  181. package/src/utils/gitlab-without-vorpal/GitLabTokenMissingError.ts +0 -7
  182. package/src/utils/gitlab-without-vorpal/fetchGitLabApi.ts +0 -74
  183. package/src/utils/gitlab-without-vorpal/getGitlabHostPathToken.ts +0 -31
  184. package/src/utils/gitlab-without-vorpal/gitLabProjectByGitPath.ts +0 -57
  185. package/src/utils/gitlab-without-vorpal/gitLabVariables.ts +0 -290
  186. package/src/utils/gitlab-without-vorpal/index.ts +0 -12
  187. package/src/utils/gitlab-without-vorpal/insertProjectTopics.ts +0 -35
  188. package/src/utils/gitlab-without-vorpal/loadGitLabToken.ts +0 -29
  189. package/src/utils/gitlab-without-vorpal/projectAccessToken.ts +0 -86
  190. package/src/utils/gitlab-without-vorpal/storeGitLabToken.ts +0 -23
  191. package/src/utils/preferences/CatladderPreferences.ts +0 -51
  192. package/src/utils/preferences/index.ts +0 -103
@@ -1,5 +1,8 @@
1
- import { watch } from "fs";
2
- import type { Config, EnvironmentEnvVars } from "@catladder/pipeline";
1
+ import type {
2
+ Config,
3
+ EnvironmentEnvVars,
4
+ VariableValue,
5
+ } from "@catladder/pipeline";
3
6
  import {
4
7
  readConfig,
5
8
  getAllEnvs,
@@ -9,14 +12,11 @@ import {
9
12
  } from "@catladder/pipeline";
10
13
 
11
14
  import type { CommandInstance } from "vorpal";
12
- import { getGitlabToken, getVariableValueByRawName } from "../utils/gitlab";
15
+ import { getAllVariables, getVariableValueByRawName } from "../utils/gitlab";
13
16
 
14
17
  import { getGitRoot } from "../utils/projects";
15
- import {
16
- getGitLabHostPathToken,
17
- gitLabVariable,
18
- type GitLabApiDataOptional,
19
- } from "../utils/gitlab-without-vorpal";
18
+
19
+ import { watch } from "fs";
20
20
 
21
21
  export { parseChoice } from "./parseChoice";
22
22
 
@@ -94,10 +94,21 @@ export const getAllComponentsWithAllEnvsHierarchical = async (): Promise<{
94
94
  );
95
95
  };
96
96
 
97
- export const getAllPipelineContexts = async () => {
97
+ export const getAllPipelineContexts = async (
98
+ onlyComponent?: string | string[],
99
+ ) => {
100
+ const onlyComponentsArray = onlyComponent
101
+ ? Array.isArray(onlyComponent)
102
+ ? onlyComponent
103
+ : [onlyComponent]
104
+ : null;
98
105
  return Promise.all(
99
106
  (await getAllComponentsWithAllEnvsFlat())
100
107
  .filter((c) => c.env !== "local")
108
+ .filter(
109
+ (c) =>
110
+ !onlyComponentsArray || onlyComponentsArray.includes(c.componentName),
111
+ )
101
112
  .map(({ env, componentName }) =>
102
113
  getPipelineContextByChoice(env, componentName),
103
114
  ),
@@ -123,20 +134,8 @@ export const getGitlabVar = async (
123
134
  const resolveSecrets = async (
124
135
  vorpal: CommandInstance | null,
125
136
  varSets: EnvironmentEnvVars[],
126
- existing: GitLabApiDataOptional = {},
127
137
  ): Promise<Record<string, string>> => {
128
- const {
129
- host,
130
- path,
131
- token: inputToken,
132
- } = await getGitLabHostPathToken(existing, vorpal);
133
- const token = inputToken || (await getGitlabToken(vorpal, host));
134
- const allVariablesInGitlab = await gitLabVariable.getAll({
135
- logger: vorpal,
136
- token,
137
- host,
138
- path,
139
- });
138
+ const allVariablesInGitlab = await getAllVariables(vorpal);
140
139
 
141
140
  return Object.fromEntries(
142
141
  varSets.flatMap(({ envVars, secretEnvVarKeys }) =>
@@ -12,16 +12,10 @@ export const getProjectRootPath = async (): Promise<string> => {
12
12
  /**
13
13
  * Get the git remote hostname and project path from the git config.
14
14
  */
15
- export const getGitRemoteHostAndPath = async ({
16
- host,
17
- path,
18
- }: { host?: string; path?: string } = {}): Promise<{
15
+ export const getGitRemoteHostAndPath = async (): Promise<{
19
16
  gitRemoteHost: string;
20
17
  gitRemotePath: string;
21
18
  }> => {
22
- if (host?.length && path?.length) {
23
- return { gitRemoteHost: host, gitRemotePath: path };
24
- }
25
19
  const remoteUrl = await gitConfigGet("remote.origin.url");
26
20
  const remoteReg = /(https:\/\/|git@)([^:/]+)[:/]([^.]*)(\.git)?/;
27
21
  const match = remoteUrl.match(remoteReg) ?? [];
@@ -44,27 +38,3 @@ export const gitProjectInformation = async () => {
44
38
  projectRootPath,
45
39
  };
46
40
  };
47
-
48
- /**
49
- * Get the git remote hostname.
50
- * Will only run a shell execution when hostnamePresent is nil or empty.
51
- */
52
- export const getGitRemoteHost = async (hostnamePresent?: string) => {
53
- if (hostnamePresent?.length) {
54
- return hostnamePresent;
55
- }
56
- const { gitRemoteHost } = await getGitRemoteHostAndPath();
57
- return gitRemoteHost;
58
- };
59
-
60
- /**
61
- * Get the git remote path.
62
- * Will only run a shell execution when pathPresent is nil or empty.
63
- */
64
- export const getGitRemotePath = async (pathPresent?: string) => {
65
- if (pathPresent?.length) {
66
- return pathPresent;
67
- }
68
- const { gitRemotePath } = await getGitRemoteHostAndPath();
69
- return gitRemotePath;
70
- };
@@ -1,186 +1,272 @@
1
+ import { getSecretVarName } from "@catladder/pipeline";
1
2
  import { has, isObject } from "lodash";
3
+ import memoizee from "memoizee";
4
+ import fetch from "node-fetch";
2
5
  import open from "open";
3
6
  import type { CommandInstance } from "vorpal";
7
+ import { getPreference, hasPreference, setPreference } from "./preferences";
8
+ import { getGitRemoteHostAndPath } from "../git/gitProjectInformation";
4
9
 
5
- import { getSecretVarName } from "@catladder/pipeline";
6
- import { getGitRemoteHost } from "../git/gitProjectInformation";
7
- import { logError, logNotice, logLines } from "./log";
8
- import {
9
- type FetchMethod,
10
- type GitLabApiDataOptional,
11
- fetchGitLabApi,
12
- GitLabTokenMissingError,
13
- loadGitLabToken,
14
- storeGitLabToken,
15
- gitLabVariable,
16
- getGitLabHostPathToken,
17
- getGitLabProjectId,
18
- } from "./gitlab-without-vorpal";
19
-
20
- export const setupGitlabToken = async (
21
- vorpal: CommandInstance,
22
- host?: string,
23
- ) => {
24
- logNotice(
25
- vorpal,
26
- "In order to access the API, you need your personal access token.",
27
- "It's best to create a specific token for CatLadder.",
28
- );
29
-
30
- const gitRemoteHost = await getGitRemoteHost(host);
31
- const accessTokenSettingsUrl = `https://${gitRemoteHost}/-/user_settings/personal_access_tokens`;
32
- logNotice(
33
- vorpal,
34
- "We'll open up the GitLab settings page in your browser for you!",
35
- accessTokenSettingsUrl,
36
- );
10
+ const TOKEN_KEY = "gitlab-personal-access-token";
37
11
 
38
- const { shouldContinue } = await vorpal.prompt({
39
- default: true,
40
- message: "Ok",
41
- name: "shouldContinue",
42
- type: "prompt",
43
- });
12
+ export const hasGitlabToken = async () => await hasPreference(TOKEN_KEY);
13
+ export const setupGitlabToken = async (vorpal: CommandInstance) => {
14
+ vorpal.log("");
15
+ vorpal.log("☝ in order to access the api, we need a personal access token");
16
+ vorpal.log("Its best to create one specifically for catladder");
17
+ vorpal.log("Scopes needed: api");
18
+ vorpal.log("");
19
+ vorpal.log("☝ we open up the settings page for you!");
20
+ vorpal.log("");
21
+ const [{ shouldContinue }, { gitRemoteHost }] = await Promise.all([
22
+ vorpal.prompt({
23
+ default: true,
24
+ message: "Ok",
25
+ name: "shouldContinue",
26
+ type: "prompt",
27
+ }),
28
+ getGitRemoteHostAndPath(),
29
+ ]);
44
30
 
45
- open(accessTokenSettingsUrl);
31
+ open(`https://${gitRemoteHost}/-/user_settings/personal_access_tokens`);
46
32
 
47
- logLines(vorpal, "Please enter GitLab's personal access token.");
33
+ vorpal.log("Please type in gitlab's personal access token");
48
34
 
49
- const { personalToken: token } = await vorpal.prompt({
35
+ const { personalToken } = await vorpal.prompt({
50
36
  type: "string",
51
37
  name: "personalToken",
52
38
  default: "",
53
39
  message: "Your personal access token ",
54
40
  });
55
- try {
56
- return storeGitLabToken({ token, host }, vorpal);
57
- } catch (error) {
58
- if (error instanceof GitLabTokenMissingError) {
59
- logError(vorpal, "Token missing", "Please run catladder again");
41
+ if (personalToken) {
42
+ await setPreference(TOKEN_KEY, personalToken);
43
+ }
44
+ };
45
+ export const getGitlabToken = async (vorpal: CommandInstance | null) => {
46
+ if (!(await hasGitlabToken())) {
47
+ if (!vorpal) {
48
+ console.error(
49
+ "⚠️ gitlab token missing, please run catladder to set it up",
50
+ );
60
51
  process.exit(1);
61
- } else {
62
- throw error;
63
52
  }
53
+ await setupGitlabToken(vorpal);
64
54
  }
55
+ return getPreference(TOKEN_KEY);
65
56
  };
66
57
 
67
- export const getGitlabToken = async (
58
+ type Method = "GET" | "PUT" | "POST" | "DELETE";
59
+ export const doGitlabRequest = async <T = any>(
68
60
  vorpal: CommandInstance | null,
69
- host?: string,
70
- ) => {
71
- const gitRemoteHost = await getGitRemoteHost(host);
72
- try {
73
- return loadGitLabToken(gitRemoteHost, vorpal);
74
- } catch (error) {
75
- if (!(error instanceof GitLabTokenMissingError)) throw error;
76
- if (vorpal) {
77
- return setupGitlabToken(vorpal, gitRemoteHost);
61
+ path: string,
62
+ data: any = undefined,
63
+ method: Method = "GET",
64
+ ): Promise<T> => {
65
+ const [rootToken, { gitRemoteHost }] = await Promise.all([
66
+ getGitlabToken(vorpal),
67
+ getGitRemoteHostAndPath(),
68
+ ]);
69
+
70
+ //const method = data ? (update ? "PUT" : "POST") : "GET";
71
+
72
+ const result = await fetch(`https://${gitRemoteHost}/api/v4/${path}`, {
73
+ method,
74
+ headers: {
75
+ "Content-Type": "application/json",
76
+ "Private-Token": rootToken,
77
+ },
78
+ body: data ? JSON.stringify(data) : undefined,
79
+ });
80
+
81
+ if (result.status >= 200 && result.status < 400) {
82
+ if (result.headers.get("content-type") === "application/json") {
83
+ return result.json();
78
84
  }
79
- logError(
80
- console,
81
- "GitLab token missing!",
82
- "Please run catladder to set it up",
83
- );
84
- process.exit(1);
85
+ return null;
86
+ }
87
+ if (result.status === 404) {
88
+ throw new Error("not found");
85
89
  }
90
+
91
+ throw new Error(
92
+ `Could not send request to gitlab api ${path}: ${result.status} "${
93
+ result.statusText
94
+ }".\nResponse: ${JSON.stringify(await result.json(), null, 2)}`,
95
+ );
86
96
  };
87
97
 
88
- export const doGitlabRequest = async <T = any>(
98
+ export const getProjectInfo = async (
89
99
  vorpal: CommandInstance | null,
90
- {
91
- path: resourcePath,
92
- ...args
93
- }: {
94
- path: string;
95
- data?: any;
96
- method?: FetchMethod;
97
- host?: string;
98
- token?: string;
100
+ ): Promise<{ id: string; web_url: string }> => {
101
+ const { gitRemotePath } = await getGitRemoteHostAndPath();
102
+ const project = await doGitlabRequest(
103
+ vorpal,
104
+ `projects/${encodeURIComponent(gitRemotePath)}`,
105
+ );
106
+ return project;
107
+ };
108
+
109
+ type GitlabVariable = {
110
+ variable_type: string;
111
+ key: string;
112
+ value: string;
113
+ protected: boolean;
114
+ masked: boolean;
115
+ environment_scope: string;
116
+ };
117
+ export const getAllVariables = memoizee(
118
+ async (
119
+ vorpal: CommandInstance | null,
120
+ n = 5, // how many requests to do in parallel, 5 seems a good value for many projects, ideally we would do one request in parallel per component
121
+ ): Promise<Array<GitlabVariable>> => {
122
+ const { id } = await getProjectInfo(vorpal);
123
+
124
+ let all: Array<GitlabVariable> = [];
125
+ let result: Array<Array<GitlabVariable>> = [];
126
+ let page = 1;
127
+
128
+ do {
129
+ // Create an array of promises for N pages
130
+ const promises = Array.from({ length: n }, (_, i) => {
131
+ return doGitlabRequest(
132
+ vorpal,
133
+ `projects/${id}/variables?per_page=100&page=${page + i}`,
134
+ );
135
+ });
136
+
137
+ // Wait for all promises to resolve
138
+ result = await Promise.all(promises);
139
+
140
+ // Increment the page by N
141
+ page += n;
142
+
143
+ // Flatten the result array and add it to 'all'
144
+ all = [...all, ...result.flat()];
145
+ // Continue only if the last page had results
146
+ } while (result.length > 0 && result[result.length - 1].length > 0);
147
+
148
+ return all;
99
149
  },
100
- ): Promise<T> => fetchGitLabApi<T>({ resourcePath, ...args }, vorpal);
150
+ { promise: true },
151
+ );
101
152
 
102
153
  export const getVariableValueByRawName = async (
103
154
  vorpal: CommandInstance,
104
155
  rawName: string,
105
- {
106
- projectId,
107
- ...existing
108
- }: GitLabApiDataOptional & { projectId?: number | string } = {},
109
156
  ) => {
110
- const {
111
- host,
112
- path,
113
- token: inputToken,
114
- } = await getGitLabHostPathToken(existing, vorpal);
115
- const token = inputToken || (await getGitlabToken(vorpal, host));
116
- const id =
117
- projectId || (await getGitLabProjectId({ host, path, token }, vorpal));
118
- const allVariables = await gitLabVariable.getAll({
119
- logger: vorpal,
120
- host,
121
- path,
122
- token,
123
- projectId: id,
124
- });
157
+ const allVariables = await getAllVariables(vorpal);
125
158
  return allVariables.find((v) => v.key === rawName)?.value;
126
159
  };
127
160
 
128
- const getAllCatladderEnvVarsInGitlab = async (
161
+ const maskableRegex = new RegExp("^[a-zA-Z0-9_+=/@:.~-]{8,}$"); // SEE https://gitlab.com/gitlab-org/gitlab-foss/-/blob/master/spec/frontend/ci_variable_list/components/ci_variable_modal_spec.js#L20
162
+ const isMaskable = (value: string): boolean => maskableRegex.test(value);
163
+
164
+ const createVariable = async (
129
165
  vorpal: CommandInstance,
130
- {
131
- projectId,
132
- ...existing
133
- }: GitLabApiDataOptional & { projectId?: string | number } = {},
166
+ projectId: string,
167
+ key: string,
168
+ value: string,
169
+ masked = true,
170
+ environment_scope = "*",
134
171
  ) => {
135
- const {
136
- host,
137
- path,
138
- token: inputToken,
139
- } = await getGitLabHostPathToken(existing, vorpal);
140
- const token = inputToken || (await getGitlabToken(vorpal, host));
141
- const id =
142
- projectId || (await getGitLabProjectId({ host, path, token }, vorpal));
143
- return gitLabVariable.getAllCatladder({
144
- logger: vorpal,
145
- host,
146
- path,
147
- token,
148
- projectId: id,
149
- });
172
+ return await doGitlabRequest(
173
+ vorpal,
174
+ `projects/${projectId}/variables`,
175
+ {
176
+ key,
177
+ value,
178
+ masked: masked && isMaskable(value),
179
+ environment_scope,
180
+ },
181
+ "POST",
182
+ );
150
183
  };
151
184
 
152
- const getBackupKey = (fullKey: string, timestamp: number) =>
153
- `${fullKey}_backup_${timestamp}`;
185
+ const updateVariable = async (
186
+ vorpal: CommandInstance,
187
+ projectId: string,
188
+ key: string,
189
+ value: string,
190
+ masked = true,
191
+ ) => {
192
+ return await doGitlabRequest(
193
+ vorpal,
194
+ `projects/${projectId}/variables/${key}`,
195
+ {
196
+ value,
197
+ masked: masked && isMaskable(value),
198
+ },
199
+ "PUT",
200
+ );
201
+ };
154
202
 
155
- export const clearBackups = async (
203
+ const deleteVariable = async (
156
204
  vorpal: CommandInstance,
157
- keep: number,
158
- existing: GitLabApiDataOptional = {},
205
+ projectId: string,
206
+ key: string,
159
207
  ) => {
160
- const {
161
- host,
162
- path,
163
- token: inputToken,
164
- } = await getGitLabHostPathToken(existing, vorpal);
165
- const token = inputToken || (await getGitlabToken(vorpal, host));
166
- const id = await getGitLabProjectId({ host, path, token }, vorpal);
167
-
168
- const existingVariables = await getAllCatladderEnvVarsInGitlab(vorpal, {
169
- projectId: id,
170
- host,
171
- path,
172
- token,
173
- });
208
+ return await doGitlabRequest(
209
+ vorpal,
210
+ `projects/${projectId}/variables/${key}`,
211
+ undefined,
212
+ "DELETE",
213
+ );
214
+ };
215
+
216
+ const getAllCatladderEnvVarsInGitlab = async (vorpal: CommandInstance) => {
217
+ const allVariables = await getAllVariables(vorpal).then((v) =>
218
+ v.reduce<{
219
+ [key: string]: {
220
+ value?: string;
221
+ backups: number[];
222
+ };
223
+ }>((acc, variable) => {
224
+ const { key } = variable;
225
+
226
+ if (key.startsWith("CL_")) {
227
+ const matchBackup = key.match(/(CL_.*)_backup_([0-9]+)/);
228
+
229
+ if (matchBackup) {
230
+ const key = matchBackup[1];
231
+ const timestamp = Number(matchBackup[2]);
232
+ const backups = [...(acc[key]?.backups ?? []), timestamp];
233
+ return {
234
+ ...acc,
235
+ [key]: {
236
+ ...(acc[key] ?? {}), // add value
237
+ backups,
238
+ },
239
+ };
240
+ }
241
+
242
+ return {
243
+ ...acc,
244
+ [key]: {
245
+ backups: [],
246
+ ...(acc[key] ?? {}), // may add backups
247
+ value: variable.value,
248
+ },
249
+ };
250
+ }
251
+
252
+ return acc;
253
+ }, {}),
254
+ );
255
+ return allVariables;
256
+ };
257
+
258
+ const getBackupKey = (fullKey: string, timestamp: number) =>
259
+ `${fullKey}_backup_${timestamp}`;
260
+ export const clearBackups = async (vorpal: CommandInstance, keep: number) => {
261
+ const existingVariables = await getAllCatladderEnvVarsInGitlab(vorpal);
262
+ const { id } = await getProjectInfo(vorpal);
174
263
  for (const [key, { backups }] of Object.entries(existingVariables)) {
175
264
  const backupsSorted = backups.sort((a, b) => b - a);
176
265
  //const toKeep = backupsSorted.slice(0, keep);
177
266
  const toDelete = backupsSorted.slice(keep);
178
267
 
179
268
  for (const timestamp of toDelete) {
180
- await gitLabVariable.delete(
181
- { projectId: id, key: getBackupKey(key, timestamp), token, host },
182
- vorpal,
183
- );
269
+ await deleteVariable(vorpal, id, getBackupKey(key, timestamp));
184
270
  }
185
271
  }
186
272
  };
@@ -192,27 +278,11 @@ export const upsertAllVariables = async (
192
278
  componentName: string,
193
279
  backup = true,
194
280
  masked = true, // FIXME: would be better to have this per variable
195
- {
196
- projectId,
197
- ...existing
198
- }: GitLabApiDataOptional & { projectId?: number | string } = {},
199
281
  ): Promise<void> => {
200
- const {
201
- host,
202
- path,
203
- token: inputToken,
204
- } = await getGitLabHostPathToken(existing, vorpal);
205
- const token = inputToken || (await getGitlabToken(vorpal, host));
206
- const id =
207
- projectId || (await getGitLabProjectId({ host, path, token }, vorpal));
282
+ const { id } = await getProjectInfo(vorpal);
208
283
 
209
284
  // we list all existing variables. We also gather backup versions, but its currently unused
210
- const existingVariables = await getAllCatladderEnvVarsInGitlab(vorpal, {
211
- projectId: id,
212
- host,
213
- path,
214
- token,
215
- });
285
+ const existingVariables = await getAllCatladderEnvVarsInGitlab(vorpal);
216
286
  for (const [key, value] of Object.entries(variables ?? {})) {
217
287
  const fullKey = getSecretVarName(env, componentName, key);
218
288
  const valueSanitized = isObject(value) ? JSON.stringify(value) : `${value}`;
@@ -220,52 +290,29 @@ export const upsertAllVariables = async (
220
290
  const exists = has(existingVariables, fullKey);
221
291
  const oldValue = existingVariables[fullKey]?.value;
222
292
  const changed = oldValue !== valueSanitized;
223
- if (!changed) {
293
+ if (changed) {
294
+ if (exists) {
295
+ vorpal.log(`changed: ${key}`);
296
+
297
+ await updateVariable(vorpal, id, fullKey, valueSanitized, masked);
298
+ // write backup
299
+ if (backup) {
300
+ await createVariable(
301
+ vorpal,
302
+ id,
303
+ getBackupKey(fullKey, new Date().getTime()),
304
+ oldValue,
305
+ masked,
306
+ "_backup",
307
+ );
308
+ }
309
+ } else {
310
+ vorpal.log(`new : ${key}`);
311
+ await createVariable(vorpal, id, fullKey, valueSanitized, masked);
312
+ }
313
+ } else {
224
314
  vorpal.log(`skip : ${key}`);
225
- continue;
226
- }
227
- if (!exists) {
228
- vorpal.log(`new : ${key}`);
229
- await gitLabVariable.create(
230
- {
231
- projectId: id,
232
- key: fullKey,
233
- value: valueSanitized,
234
- masked,
235
- host,
236
- token,
237
- },
238
- vorpal,
239
- );
240
- continue;
241
- }
242
- vorpal.log(`changed: ${key}`);
243
-
244
- await gitLabVariable.update(
245
- {
246
- projectId: id,
247
- key: fullKey,
248
- value: valueSanitized,
249
- masked,
250
- host,
251
- token,
252
- },
253
- vorpal,
254
- );
255
- // write backup
256
- if (backup) {
257
- await gitLabVariable.create(
258
- {
259
- projectId: id,
260
- key: getBackupKey(fullKey, new Date().getTime()),
261
- value: oldValue,
262
- masked,
263
- host,
264
- token,
265
- },
266
- vorpal,
267
- );
268
315
  }
269
316
  }
270
- gitLabVariable.getAll.clear();
317
+ getAllVariables.clear();
271
318
  };
package/src/utils/log.ts CHANGED
@@ -111,29 +111,3 @@ export const logWarning = (
111
111
  }
112
112
  logLines(cmd, "");
113
113
  };
114
-
115
- /**
116
- * Logs a notification message using the log method of the provided {@link LoggerCmdInstance}.
117
- *
118
- * Line items that are `null` or `undefined` are logged as empty lines.
119
- *
120
- * @example
121
- * ```ts
122
- * logNotice(cmd, "Message");
123
- * logNotice(cmd, "Message", "Additional message");
124
- * logNotice(cmd, "Message", "Additional message", "Another additional message line");
125
- * logNotice(cmd, "Message", ...additionalMessages); // arrays can be spread into the function
126
- * logNotice(cmd, "Message", additionalMessages); // but it will flatten the plain array for convenience
127
- * ```
128
- */
129
- export const logNotice = (
130
- cmd: LoggerCmdInstance = console,
131
- message: string,
132
- ...additionalMessages: LinesArg[]
133
- ) => {
134
- logLines(cmd, "", `[NOTICE] ☝ : ${message}`);
135
- if (additionalMessages?.length) {
136
- logLines(cmd, ...additionalMessages.flat());
137
- }
138
- logLines(cmd, "");
139
- };