@catladder/cli 0.0.0-next-4e7c6848 → 0.0.0-next-6a4450e0
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/bundles/catenv/index.js +1392 -116
- package/dist/bundles/cli/index.js +1631 -112
- package/dist/cli/src/adapters/baseContext.d.ts +4 -0
- package/dist/cli/src/adapters/baseContext.js +5 -0
- package/dist/cli/src/adapters/baseContext.js.map +1 -1
- package/dist/cli/src/adapters/nonInteractive.d.ts +9 -0
- package/dist/cli/src/adapters/nonInteractive.js +32 -0
- package/dist/cli/src/adapters/nonInteractive.js.map +1 -0
- package/dist/cli/src/adapters/programmatic.d.ts +1 -0
- package/dist/cli/src/adapters/programmatic.js +6 -1
- package/dist/cli/src/adapters/programmatic.js.map +1 -1
- package/dist/cli/src/adapters/terminal.d.ts +1 -0
- package/dist/cli/src/adapters/terminal.js +10 -1
- package/dist/cli/src/adapters/terminal.js.map +1 -1
- package/dist/cli/src/adapters/vaultManagerAccess.d.ts +8 -0
- package/dist/cli/src/adapters/vaultManagerAccess.js +26 -0
- package/dist/cli/src/adapters/vaultManagerAccess.js.map +1 -0
- package/dist/cli/src/apps/catenv/catenv.d.ts +2 -0
- package/dist/cli/src/apps/catenv/catenv.js +8 -1
- package/dist/cli/src/apps/catenv/catenv.js.map +1 -1
- package/dist/cli/src/apps/catenv/printVariables.d.ts +2 -2
- package/dist/cli/src/apps/catenv/printVariables.js +4 -4
- package/dist/cli/src/apps/catenv/printVariables.js.map +1 -1
- package/dist/cli/src/apps/catenv/types.d.ts +9 -0
- package/dist/cli/src/apps/catenv/writeDotEnvFiles.d.ts +2 -2
- package/dist/cli/src/apps/catenv/writeDotEnvFiles.js +1 -1
- package/dist/cli/src/apps/catenv/writeDotEnvFiles.js.map +1 -1
- package/dist/cli/src/apps/cli/commands/project/commandConfigSecrets.js +70 -3
- package/dist/cli/src/apps/cli/commands/project/commandConfigSecrets.js.map +1 -1
- package/dist/cli/src/catenv.js +3 -2
- package/dist/cli/src/catenv.js.map +1 -1
- package/dist/cli/src/commands/index.d.ts +1 -0
- package/dist/cli/src/commands/index.js +8 -1
- package/dist/cli/src/commands/index.js.map +1 -1
- package/dist/cli/src/commands/project/commandSecretsSyncGithub.d.ts +46 -0
- package/dist/cli/src/commands/project/commandSecretsSyncGithub.js +150 -0
- package/dist/cli/src/commands/project/commandSecretsSyncGithub.js.map +1 -0
- package/dist/cli/src/config/getProjectConfig.d.ts +1 -1
- package/dist/cli/src/config/getProjectConfig.js +12 -2
- package/dist/cli/src/config/getProjectConfig.js.map +1 -1
- package/dist/cli/src/core/types.d.ts +15 -0
- package/dist/cli/src/core/types.js +8 -1
- package/dist/cli/src/core/types.js.map +1 -1
- package/dist/cli/src/git/gitProjectInformation.d.ts +1 -1
- package/dist/cli/src/git/gitProjectInformation.js +3 -3
- package/dist/cli/src/git/gitProjectInformation.js.map +1 -1
- package/dist/cli/src/utils/github.d.ts +20 -0
- package/dist/cli/src/utils/github.js +61 -0
- package/dist/cli/src/utils/github.js.map +1 -0
- package/dist/cli/src/vault/BitwardenVault.d.ts +24 -0
- package/dist/cli/src/vault/BitwardenVault.js +107 -0
- package/dist/cli/src/vault/BitwardenVault.js.map +1 -0
- package/dist/cli/src/vault/GitlabVault.d.ts +11 -0
- package/dist/cli/src/vault/GitlabVault.js +24 -0
- package/dist/cli/src/vault/GitlabVault.js.map +1 -0
- package/dist/cli/src/vault/VaultManager.d.ts +43 -0
- package/dist/cli/src/vault/VaultManager.js +131 -0
- package/dist/cli/src/vault/VaultManager.js.map +1 -0
- package/dist/cli/src/vault/bw.d.ts +15 -0
- package/dist/cli/src/vault/bw.js +89 -0
- package/dist/cli/src/vault/bw.js.map +1 -0
- package/dist/cli/src/vault/cache.d.ts +38 -0
- package/dist/cli/src/vault/cache.js +53 -0
- package/dist/cli/src/vault/cache.js.map +1 -0
- package/dist/cli/src/vault/index.d.ts +5 -0
- package/dist/cli/src/vault/index.js +48 -0
- package/dist/cli/src/vault/index.js.map +1 -0
- package/dist/cli/src/vault/types.d.ts +33 -0
- package/dist/cli/src/vault/types.js +5 -0
- package/dist/cli/src/vault/types.js.map +1 -0
- package/dist/pipeline/src/backends/github/GithubBackend.d.ts +4 -1
- package/dist/pipeline/src/backends/github/GithubBackend.js +70 -12
- package/dist/pipeline/src/backends/github/GithubBackend.js.map +1 -1
- package/dist/pipeline/src/backends/github/ciVariables.js +3 -1
- package/dist/pipeline/src/backends/github/ciVariables.js.map +1 -1
- package/dist/pipeline/src/backends/github/createGithubJobs.d.ts +13 -3
- package/dist/pipeline/src/backends/github/createGithubJobs.js +80 -14
- package/dist/pipeline/src/backends/github/createGithubJobs.js.map +1 -1
- package/dist/pipeline/src/backends/github/githubReleaseJobs.d.ts +2 -1
- package/dist/pipeline/src/backends/github/githubReleaseJobs.js +46 -33
- package/dist/pipeline/src/backends/github/githubReleaseJobs.js.map +1 -1
- package/dist/pipeline/src/backends/github/index.d.ts +2 -1
- package/dist/pipeline/src/backends/github/index.js +2 -1
- package/dist/pipeline/src/backends/github/index.js.map +1 -1
- package/dist/pipeline/src/backends/github/scriptFiles.d.ts +25 -0
- package/dist/pipeline/src/backends/github/scriptFiles.js +50 -0
- package/dist/pipeline/src/backends/github/scriptFiles.js.map +1 -0
- package/dist/pipeline/src/backends/gitlab/GitlabBackend.d.ts +1 -0
- package/dist/pipeline/src/backends/gitlab/GitlabBackend.js +18 -8
- package/dist/pipeline/src/backends/gitlab/GitlabBackend.js.map +1 -1
- package/dist/pipeline/src/backends/gitlab/ciVariables.js +2 -1
- package/dist/pipeline/src/backends/gitlab/ciVariables.js.map +1 -1
- package/dist/pipeline/src/backends/gitlab/createGitlabJobs.d.ts +3 -2
- package/dist/pipeline/src/backends/gitlab/createGitlabJobs.js +84 -10
- package/dist/pipeline/src/backends/gitlab/createGitlabJobs.js.map +1 -1
- package/dist/pipeline/src/backends/gitlab/createGitlabPipeline.js +1 -1
- package/dist/pipeline/src/backends/gitlab/createGitlabPipeline.js.map +1 -1
- package/dist/pipeline/src/backends/gitlab/gitlabReleaseJobs.js +2 -2
- package/dist/pipeline/src/backends/gitlab/gitlabReleaseJobs.js.map +1 -1
- package/dist/pipeline/src/backends/index.d.ts +17 -1
- package/dist/pipeline/src/backends/index.js +33 -1
- package/dist/pipeline/src/backends/index.js.map +1 -1
- package/dist/pipeline/src/backends/types.d.ts +2 -1
- package/dist/pipeline/src/bash/ciVariables.d.ts +1 -1
- package/dist/pipeline/src/bash/ciVariables.js.map +1 -1
- package/dist/pipeline/src/build/node/yarn.js +4 -1
- package/dist/pipeline/src/build/node/yarn.js.map +1 -1
- package/dist/pipeline/src/build/types.d.ts +1 -1
- package/dist/pipeline/src/constants.js +1 -1
- package/dist/pipeline/src/context/getEnvironmentVariables.d.ts +8 -0
- package/dist/pipeline/src/context/getEnvironmentVariables.js +3 -3
- package/dist/pipeline/src/context/getEnvironmentVariables.js.map +1 -1
- package/dist/pipeline/src/context/transformJobOnlyVars.js +2 -2
- package/dist/pipeline/src/context/transformJobOnlyVars.js.map +1 -1
- package/dist/pipeline/src/context/utils/envVars.d.ts +7 -0
- package/dist/pipeline/src/context/utils/envVars.js +22 -1
- package/dist/pipeline/src/context/utils/envVars.js.map +1 -1
- package/dist/pipeline/src/customImages/hash.d.ts +15 -0
- package/dist/pipeline/src/customImages/hash.js +71 -0
- package/dist/pipeline/src/customImages/hash.js.map +1 -0
- package/dist/pipeline/src/customImages/jobImagesPlan.d.ts +59 -0
- package/dist/pipeline/src/customImages/jobImagesPlan.js +172 -0
- package/dist/pipeline/src/customImages/jobImagesPlan.js.map +1 -0
- package/dist/pipeline/src/customImages/shippedImages.d.ts +28 -0
- package/dist/pipeline/src/customImages/shippedImages.js +60 -0
- package/dist/pipeline/src/customImages/shippedImages.js.map +1 -0
- package/dist/pipeline/src/deploy/cloudRun/index.js +15 -5
- package/dist/pipeline/src/deploy/cloudRun/index.js.map +1 -1
- package/dist/pipeline/src/deploy/cloudRun/utils/database.js +4 -1
- package/dist/pipeline/src/deploy/cloudRun/utils/database.js.map +1 -1
- package/dist/pipeline/src/pipeline/generatePipelineFiles.js +16 -1
- package/dist/pipeline/src/pipeline/generatePipelineFiles.js.map +1 -1
- package/dist/pipeline/src/runner/index.d.ts +20 -1
- package/dist/pipeline/src/runner/index.js +16 -3
- package/dist/pipeline/src/runner/index.js.map +1 -1
- package/dist/pipeline/src/types/config.d.ts +63 -5
- package/dist/pipeline/src/types/github-types.d.ts +5 -0
- package/dist/pipeline/src/types/jobs.d.ts +10 -2
- package/dist/pipeline/src/types/jobs.js.map +1 -1
- package/dist/pipeline/src/utils/gitlab.d.ts +5 -0
- package/dist/pipeline/src/utils/gitlab.js +6 -0
- package/dist/pipeline/src/utils/gitlab.js.map +1 -1
- package/dist/pipeline/src/utils/writeFiles.d.ts +6 -0
- package/dist/pipeline/src/utils/writeFiles.js +8 -0
- package/dist/pipeline/src/utils/writeFiles.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/adapters/baseContext.ts +10 -0
- package/src/adapters/nonInteractive.ts +30 -0
- package/src/adapters/programmatic.ts +7 -1
- package/src/adapters/terminal.ts +9 -1
- package/src/adapters/vaultManagerAccess.ts +25 -0
- package/src/apps/catenv/catenv.ts +5 -1
- package/src/apps/catenv/printVariables.ts +16 -6
- package/src/apps/catenv/types.ts +9 -0
- package/src/apps/catenv/writeDotEnvFiles.ts +3 -3
- package/src/apps/cli/commands/project/commandConfigSecrets.ts +114 -9
- package/src/catenv.ts +22 -2
- package/src/commands/index.ts +1 -0
- package/src/commands/project/commandSecretsSyncGithub.ts +172 -0
- package/src/config/getProjectConfig.ts +21 -7
- package/src/core/types.ts +23 -0
- package/src/git/gitProjectInformation.ts +5 -3
- package/src/utils/github.ts +76 -0
- package/src/vault/BitwardenVault.ts +161 -0
- package/src/vault/GitlabVault.ts +25 -0
- package/src/vault/VaultManager.ts +211 -0
- package/src/vault/bw.ts +110 -0
- package/src/vault/cache.ts +80 -0
- package/src/vault/index.ts +5 -0
- package/src/vault/types.ts +42 -0
|
@@ -1,6 +1,78 @@
|
|
|
1
1
|
/******/ (() => { // webpackBootstrap
|
|
2
2
|
/******/ var __webpack_modules__ = ({
|
|
3
3
|
|
|
4
|
+
/***/ 1917:
|
|
5
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
6
|
+
|
|
7
|
+
"use strict";
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
Object.defineProperty(exports, "__esModule", ({
|
|
11
|
+
value: true
|
|
12
|
+
}));
|
|
13
|
+
exports.createNonInteractiveIO = void 0;
|
|
14
|
+
const types_1 = __nccwpck_require__(2284);
|
|
15
|
+
const vaultManagerAccess_1 = __nccwpck_require__(7881);
|
|
16
|
+
/**
|
|
17
|
+
* the context of non-interactive runs (catenv via direnv): logging
|
|
18
|
+
* goes to stderr, any required interaction fails with a clear error.
|
|
19
|
+
*/
|
|
20
|
+
function createNonInteractiveIO(options = {}) {
|
|
21
|
+
const io = {
|
|
22
|
+
interactive: false,
|
|
23
|
+
getVaultManager: (0, vaultManagerAccess_1.createVaultManagerGetter)(() => io, {
|
|
24
|
+
mode: options.vaultMode
|
|
25
|
+
}),
|
|
26
|
+
log(message) {
|
|
27
|
+
// stderr: stdout may be evaluated (direnv)
|
|
28
|
+
console.error(message);
|
|
29
|
+
},
|
|
30
|
+
async confirm(message) {
|
|
31
|
+
throw new types_1.NonInteractiveError(`confirmation ("${message}")`);
|
|
32
|
+
},
|
|
33
|
+
async promptDirect(spec) {
|
|
34
|
+
throw new types_1.NonInteractiveError(`input "${spec.name}"`);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
return io;
|
|
38
|
+
}
|
|
39
|
+
exports.createNonInteractiveIO = createNonInteractiveIO;
|
|
40
|
+
|
|
41
|
+
/***/ }),
|
|
42
|
+
|
|
43
|
+
/***/ 7881:
|
|
44
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
45
|
+
|
|
46
|
+
"use strict";
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
Object.defineProperty(exports, "__esModule", ({
|
|
50
|
+
value: true
|
|
51
|
+
}));
|
|
52
|
+
exports.createVaultManagerGetter = void 0;
|
|
53
|
+
const getProjectConfig_1 = __nccwpck_require__(1);
|
|
54
|
+
const VaultManager_1 = __nccwpck_require__(5771);
|
|
55
|
+
/**
|
|
56
|
+
* lazily creates the vault manager of a context (once per context),
|
|
57
|
+
* loading the project config on first use
|
|
58
|
+
*/
|
|
59
|
+
const createVaultManagerGetter = (io, options = {}) => {
|
|
60
|
+
let managerPromise;
|
|
61
|
+
return () => managerPromise !== null && managerPromise !== void 0 ? managerPromise : managerPromise = (async () => {
|
|
62
|
+
const config = await (0, getProjectConfig_1.getProjectConfig)();
|
|
63
|
+
if (!config) {
|
|
64
|
+
throw new Error("no catladder config found — the secrets vault needs a project config");
|
|
65
|
+
}
|
|
66
|
+
return new VaultManager_1.VaultManager(config, {
|
|
67
|
+
...options,
|
|
68
|
+
io: io()
|
|
69
|
+
});
|
|
70
|
+
})();
|
|
71
|
+
};
|
|
72
|
+
exports.createVaultManagerGetter = createVaultManagerGetter;
|
|
73
|
+
|
|
74
|
+
/***/ }),
|
|
75
|
+
|
|
4
76
|
/***/ 6057:
|
|
5
77
|
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
6
78
|
|
|
@@ -16,12 +88,19 @@ const verboseBanner_1 = __nccwpck_require__(5472);
|
|
|
16
88
|
const writeDotEnvFiles_1 = __nccwpck_require__(5614);
|
|
17
89
|
const writeEnvDTs_1 = __nccwpck_require__(8832);
|
|
18
90
|
const pipeline_1 = __nccwpck_require__(241);
|
|
91
|
+
const nonInteractive_1 = __nccwpck_require__(1917);
|
|
19
92
|
exports["default"] = async (choice, options) => {
|
|
20
93
|
const config = await (0, getProjectConfig_1.getProjectConfig)();
|
|
21
94
|
if (!config) {
|
|
22
95
|
return;
|
|
23
96
|
}
|
|
24
|
-
const
|
|
97
|
+
const io = (0, nonInteractive_1.createNonInteractiveIO)({
|
|
98
|
+
vaultMode: options === null || options === void 0 ? void 0 : options.vaultMode
|
|
99
|
+
});
|
|
100
|
+
const context = {
|
|
101
|
+
...(0, pipeline_1.createCatenvContext)(config),
|
|
102
|
+
io
|
|
103
|
+
};
|
|
25
104
|
if (options === null || options === void 0 ? void 0 : options.verbose) {
|
|
26
105
|
(0, verboseBanner_1.printVerboseBanner)();
|
|
27
106
|
}
|
|
@@ -42,19 +121,19 @@ Object.defineProperty(exports, "__esModule", ({
|
|
|
42
121
|
exports.printVariables = void 0;
|
|
43
122
|
const getProjectConfig_1 = __nccwpck_require__(1);
|
|
44
123
|
const utils_1 = __nccwpck_require__(1909);
|
|
45
|
-
const getAllVariablesToPrint = async (config, choice) => {
|
|
124
|
+
const getAllVariablesToPrint = async (io, config, choice) => {
|
|
46
125
|
const {
|
|
47
126
|
env,
|
|
48
127
|
currentComponent
|
|
49
128
|
} = await (0, utils_1.getCurrentComponentAndEnvFromChoice)(config, choice);
|
|
50
129
|
if (currentComponent) {
|
|
51
|
-
return await (0, getProjectConfig_1.getEnvVarsResolved)(
|
|
130
|
+
return await (0, getProjectConfig_1.getEnvVarsResolved)(io, env, currentComponent);
|
|
52
131
|
} else {
|
|
53
132
|
// when in a monorep and not in a subapp, merge all env vars.
|
|
54
133
|
// this is not 100% correct, but better than not exporting any vars at all
|
|
55
134
|
// so we also add prefixed variants
|
|
56
135
|
return await Object.keys(config.components).reduce(async (acc, componentName) => {
|
|
57
|
-
const subappvars = await (0, getProjectConfig_1.getEnvVarsResolved)(
|
|
136
|
+
const subappvars = await (0, getProjectConfig_1.getEnvVarsResolved)(io, env, componentName);
|
|
58
137
|
delete subappvars["_ALL_ENV_VAR_KEYS"];
|
|
59
138
|
return {
|
|
60
139
|
...(await acc),
|
|
@@ -66,7 +145,7 @@ const getAllVariablesToPrint = async (config, choice) => {
|
|
|
66
145
|
}
|
|
67
146
|
};
|
|
68
147
|
const printVariables = async (context, choice) => {
|
|
69
|
-
const variables = await getAllVariablesToPrint(context.config, choice);
|
|
148
|
+
const variables = await getAllVariablesToPrint(context.io, context.config, choice);
|
|
70
149
|
console.log(makeExportKeyValuestring(variables));
|
|
71
150
|
};
|
|
72
151
|
exports.printVariables = printVariables;
|
|
@@ -185,7 +264,7 @@ const writeDotEnvFiles = async (context, choice) => {
|
|
|
185
264
|
const componentsToActuallyWriteDotEnvNow = currentComponent ? componentsWithEnabledDotEnvWrite.includes(currentComponent) ? [currentComponent] : [] : componentsWithEnabledDotEnvWrite;
|
|
186
265
|
const gitRoot = await (0, projects_1.getGitRoot)();
|
|
187
266
|
for (const componentName of componentsToActuallyWriteDotEnvNow) {
|
|
188
|
-
const variables = await (0, getProjectConfig_1.getEnvVarsResolved)(
|
|
267
|
+
const variables = await (0, getProjectConfig_1.getEnvVarsResolved)(context.io, env, componentName);
|
|
189
268
|
delete variables["_ALL_ENV_VAR_KEYS"];
|
|
190
269
|
const componentDir = (0, utils_1.getComponentFullPath)(gitRoot, context.config, componentName);
|
|
191
270
|
const filePath = (0, path_1.join)(componentDir, ".env");
|
|
@@ -279,11 +358,12 @@ const catenv_1 = __importDefault(__nccwpck_require__(6057));
|
|
|
279
358
|
const parseChoice_1 = __nccwpck_require__(4272);
|
|
280
359
|
const packageInfos_1 = __importDefault(__nccwpck_require__(3568));
|
|
281
360
|
const program = new commander_1.Command();
|
|
282
|
-
program.name("catenv").description("Environment variable and pipeline generation via direnv").version(packageInfos_1.default.version).argument("[envComponent]", "env or env:component").option("-v, --verbose", "verbose output").option("-p, --print-variables", "print variables").action((envComponent, opts) => {
|
|
361
|
+
program.name("catenv").description("Environment variable and pipeline generation via direnv").version(packageInfos_1.default.version).argument("[envComponent]", "env or env:component").option("-v, --verbose", "verbose output").option("-p, --print-variables", "print variables").addOption(new commander_1.Option("--vault-mode <mode>", ["how to interact with the secrets vault:", "auto: contact the vault when cached secrets are missing (may prompt to unlock)", "no-prompt: like auto, but fail instead of prompting", "offline: never contact the vault, use only locally cached secrets", "refresh: ignore the local cache once and refresh it from the vault"].join("\n")).choices(["auto", "no-prompt", "offline", "refresh"]).default("auto")).action((envComponent, opts) => {
|
|
283
362
|
var _a, _b;
|
|
284
363
|
(0, catenv_1.default)(envComponent ? (0, parseChoice_1.parseChoice)(envComponent) : null, {
|
|
285
364
|
verbose: (_a = opts.verbose) !== null && _a !== void 0 ? _a : false,
|
|
286
|
-
printVariables: (_b = opts.printVariables) !== null && _b !== void 0 ? _b : false
|
|
365
|
+
printVariables: (_b = opts.printVariables) !== null && _b !== void 0 ? _b : false,
|
|
366
|
+
vaultMode: opts.vaultMode
|
|
287
367
|
}).then(() => {
|
|
288
368
|
// we have to exit manually, because we have some file watches
|
|
289
369
|
process.exit();
|
|
@@ -403,14 +483,24 @@ const getGitlabVar = async (io, env, componentName, variableName) => {
|
|
|
403
483
|
};
|
|
404
484
|
exports.getGitlabVar = getGitlabVar;
|
|
405
485
|
const resolveSecrets = async (io, varSets) => {
|
|
406
|
-
|
|
486
|
+
// the secret variables actually referenced by the env var values —
|
|
487
|
+
// when they are all in the local cache, the vault is not contacted
|
|
488
|
+
const referencedNames = [...new Set(varSets.flatMap(({
|
|
489
|
+
envVars
|
|
490
|
+
}) => Object.values(envVars).flatMap(value => {
|
|
491
|
+
var _a;
|
|
492
|
+
return (_a = `${value}`.match(/\$CL_\w+/g)) !== null && _a !== void 0 ? _a : [];
|
|
493
|
+
})))].map(reference => reference.slice(1));
|
|
494
|
+
const vaultManager = await io.getVaultManager();
|
|
495
|
+
const secrets = await vaultManager.readSecrets(referencedNames, io);
|
|
496
|
+
const secretEntries = Object.entries(secrets);
|
|
407
497
|
return Object.fromEntries(varSets.flatMap(({
|
|
408
498
|
envVars,
|
|
409
499
|
secretEnvVarKeys
|
|
410
500
|
}) => Object.entries(envVars).filter(([key, value]) => {
|
|
411
501
|
var _a;
|
|
412
502
|
return value !== undefined && value !== null && !((_a = secretEnvVarKeys.find(k => k.key === key)) === null || _a === void 0 ? void 0 : _a.hidden);
|
|
413
|
-
}).map(([key, value]) => [key,
|
|
503
|
+
}).map(([key, value]) => [key, secretEntries.reduce((acc, [name, secretValue]) => acc.replace(new RegExp("\\$" + name, "g"), secretValue), `${value}`)])));
|
|
414
504
|
};
|
|
415
505
|
const getEnvVarsResolved = async (io, env, componentName) => {
|
|
416
506
|
if (!componentName) {
|
|
@@ -464,6 +554,36 @@ exports.parseChoice = parseChoice;
|
|
|
464
554
|
|
|
465
555
|
/***/ }),
|
|
466
556
|
|
|
557
|
+
/***/ 2284:
|
|
558
|
+
/***/ ((__unused_webpack_module, exports) => {
|
|
559
|
+
|
|
560
|
+
"use strict";
|
|
561
|
+
|
|
562
|
+
|
|
563
|
+
Object.defineProperty(exports, "__esModule", ({
|
|
564
|
+
value: true
|
|
565
|
+
}));
|
|
566
|
+
exports.MissingInputError = exports.NonInteractiveError = void 0;
|
|
567
|
+
// ─── Errors ──────────────────────────────────────────────────────────
|
|
568
|
+
class NonInteractiveError extends Error {
|
|
569
|
+
constructor(interaction) {
|
|
570
|
+
super(`${interaction} requires an interactive terminal, but this context is not interactive`);
|
|
571
|
+
this.name = "NonInteractiveError";
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
exports.NonInteractiveError = NonInteractiveError;
|
|
575
|
+
class MissingInputError extends Error {
|
|
576
|
+
constructor(inputName, promptMessage) {
|
|
577
|
+
super(`Missing required input: "${inputName}" (${promptMessage}). ` + `Provide it via --${inputName}=<value> or --inputs='{"${inputName}": ...}'`);
|
|
578
|
+
this.inputName = inputName;
|
|
579
|
+
this.promptMessage = promptMessage;
|
|
580
|
+
this.name = "MissingInputError";
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
exports.MissingInputError = MissingInputError;
|
|
584
|
+
|
|
585
|
+
/***/ }),
|
|
586
|
+
|
|
467
587
|
/***/ 6636:
|
|
468
588
|
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
469
589
|
|
|
@@ -518,14 +638,14 @@ exports.getProjectRootPath = getProjectRootPath;
|
|
|
518
638
|
/**
|
|
519
639
|
* Get the git remote hostname and project path from the git config.
|
|
520
640
|
*/
|
|
521
|
-
const getGitRemoteHostAndPath = async () => {
|
|
641
|
+
const getGitRemoteHostAndPath = async (remoteName = "origin") => {
|
|
522
642
|
var _a;
|
|
523
|
-
const remoteUrl = await (0, gitConfig_1.gitConfigGet)(
|
|
643
|
+
const remoteUrl = await (0, gitConfig_1.gitConfigGet)(`remote.${remoteName}.url`);
|
|
524
644
|
const remoteReg = /(https:\/\/|git@)([^:/]+)[:/]([^.]*)(\.git)?/;
|
|
525
645
|
const match = (_a = remoteUrl.match(remoteReg)) !== null && _a !== void 0 ? _a : [];
|
|
526
646
|
const [,, gitRemoteHost, gitRemotePath] = match;
|
|
527
647
|
if (!(gitRemoteHost === null || gitRemoteHost === void 0 ? void 0 : gitRemoteHost.length) || !(gitRemotePath === null || gitRemotePath === void 0 ? void 0 : gitRemotePath.length)) {
|
|
528
|
-
throw new Error(`Failed to parse git remote hostname and path from git configs remote.
|
|
648
|
+
throw new Error(`Failed to parse git remote hostname and path from git configs remote.${remoteName}.url! ${remoteUrl}`);
|
|
529
649
|
}
|
|
530
650
|
return {
|
|
531
651
|
gitRemoteHost,
|
|
@@ -947,6 +1067,445 @@ exports.getProjectNamespace = getProjectNamespace;
|
|
|
947
1067
|
|
|
948
1068
|
/***/ }),
|
|
949
1069
|
|
|
1070
|
+
/***/ 3510:
|
|
1071
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
1072
|
+
|
|
1073
|
+
"use strict";
|
|
1074
|
+
|
|
1075
|
+
|
|
1076
|
+
Object.defineProperty(exports, "__esModule", ({
|
|
1077
|
+
value: true
|
|
1078
|
+
}));
|
|
1079
|
+
exports.BitwardenVault = void 0;
|
|
1080
|
+
const pipeline_1 = __nccwpck_require__(241);
|
|
1081
|
+
const yaml_1 = __nccwpck_require__(6637);
|
|
1082
|
+
const bw_1 = __nccwpck_require__(2211);
|
|
1083
|
+
const DEFAULT_COLLECTION = "catladder";
|
|
1084
|
+
const SECURE_NOTE_TYPE = 2;
|
|
1085
|
+
/**
|
|
1086
|
+
* one yaml note per env and component:
|
|
1087
|
+
* `<customerName>/<appName>/<env>/<componentName>/secrets.yml`
|
|
1088
|
+
*/
|
|
1089
|
+
const itemName = (config, env, componentName) => `${config.customerName}/${config.appName}/${env}/${componentName}/secrets.yml`;
|
|
1090
|
+
const itemPrefix = config => `${config.customerName}/${config.appName}/`;
|
|
1091
|
+
/**
|
|
1092
|
+
* parses env and componentName back out of an item name
|
|
1093
|
+
*/
|
|
1094
|
+
const parseItemName = (config, name) => {
|
|
1095
|
+
const match = name.slice(itemPrefix(config).length).match(/^([^/]+)\/([^/]+)\/secrets\.yml$/);
|
|
1096
|
+
return match ? {
|
|
1097
|
+
env: match[1],
|
|
1098
|
+
componentName: match[2]
|
|
1099
|
+
} : null;
|
|
1100
|
+
};
|
|
1101
|
+
const findCollection = async (session, collectionName) => {
|
|
1102
|
+
const collections = await (0, bw_1.runBwJson)(session, ["list", "collections", "--search", collectionName]);
|
|
1103
|
+
const collection = collections.find(c => c.name === collectionName);
|
|
1104
|
+
if (!collection) {
|
|
1105
|
+
throw new Error(`bitwarden collection '${collectionName}' not found — create it and make sure you have access`);
|
|
1106
|
+
}
|
|
1107
|
+
return collection;
|
|
1108
|
+
};
|
|
1109
|
+
const encodePayload = payload => Buffer.from(JSON.stringify(payload), "utf-8").toString("base64");
|
|
1110
|
+
class BitwardenVault {
|
|
1111
|
+
constructor(config, options,
|
|
1112
|
+
/**
|
|
1113
|
+
* whether a locked bitwarden may be unlocked interactively
|
|
1114
|
+
* (false with catenv --vault-mode no-prompt)
|
|
1115
|
+
*/
|
|
1116
|
+
allowPrompt) {
|
|
1117
|
+
var _a;
|
|
1118
|
+
this.config = config;
|
|
1119
|
+
this.allowPrompt = allowPrompt;
|
|
1120
|
+
this.collectionName = (_a = options.collection) !== null && _a !== void 0 ? _a : DEFAULT_COLLECTION;
|
|
1121
|
+
this.id = `bitwarden:${this.collectionName}`;
|
|
1122
|
+
}
|
|
1123
|
+
session(io) {
|
|
1124
|
+
return (0, bw_1.getBwSession)(io, {
|
|
1125
|
+
allowPrompt: this.allowPrompt
|
|
1126
|
+
});
|
|
1127
|
+
}
|
|
1128
|
+
async readAllSecrets(io) {
|
|
1129
|
+
const {
|
|
1130
|
+
config,
|
|
1131
|
+
collectionName
|
|
1132
|
+
} = this;
|
|
1133
|
+
const bwSession = await this.session(io);
|
|
1134
|
+
const collection = await findCollection(bwSession, collectionName);
|
|
1135
|
+
const items = await (0, bw_1.runBwJson)(bwSession, ["list", "items", "--collectionid", collection.id]);
|
|
1136
|
+
const secrets = {};
|
|
1137
|
+
for (const item of items) {
|
|
1138
|
+
const parsed = parseItemName(config, item.name);
|
|
1139
|
+
if (!parsed || !item.notes) {
|
|
1140
|
+
continue;
|
|
1141
|
+
}
|
|
1142
|
+
const values = (0, yaml_1.parse)(item.notes);
|
|
1143
|
+
Object.entries(values !== null && values !== void 0 ? values : {}).forEach(([key, value]) => {
|
|
1144
|
+
secrets[(0, pipeline_1.getSecretVarName)(parsed.env, parsed.componentName, key)] = typeof value === "string" ? value : JSON.stringify(value);
|
|
1145
|
+
});
|
|
1146
|
+
}
|
|
1147
|
+
return secrets;
|
|
1148
|
+
}
|
|
1149
|
+
async writeSecrets(io, env, componentName, secrets) {
|
|
1150
|
+
const {
|
|
1151
|
+
config,
|
|
1152
|
+
collectionName
|
|
1153
|
+
} = this;
|
|
1154
|
+
const bwSession = await this.session(io);
|
|
1155
|
+
const collection = await findCollection(bwSession, collectionName);
|
|
1156
|
+
const name = itemName(config, env, componentName);
|
|
1157
|
+
const existing = (await (0, bw_1.runBwJson)(bwSession, ["list", "items", "--collectionid", collection.id, "--search", name])).find(item => item.name === name);
|
|
1158
|
+
const notes = (0, yaml_1.stringify)(secrets);
|
|
1159
|
+
if (existing) {
|
|
1160
|
+
await (0, bw_1.runBw)(bwSession, ["edit", "item", existing.id, encodePayload({
|
|
1161
|
+
...existing,
|
|
1162
|
+
notes
|
|
1163
|
+
})]);
|
|
1164
|
+
} else {
|
|
1165
|
+
await (0, bw_1.runBw)(bwSession, ["create", "item", encodePayload({
|
|
1166
|
+
type: SECURE_NOTE_TYPE,
|
|
1167
|
+
secureNote: {
|
|
1168
|
+
type: 0
|
|
1169
|
+
},
|
|
1170
|
+
name,
|
|
1171
|
+
notes,
|
|
1172
|
+
...(collection.organizationId ? {
|
|
1173
|
+
organizationId: collection.organizationId,
|
|
1174
|
+
collectionIds: [collection.id]
|
|
1175
|
+
} : {})
|
|
1176
|
+
})]);
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
exports.BitwardenVault = BitwardenVault;
|
|
1181
|
+
|
|
1182
|
+
/***/ }),
|
|
1183
|
+
|
|
1184
|
+
/***/ 1107:
|
|
1185
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
1186
|
+
|
|
1187
|
+
"use strict";
|
|
1188
|
+
|
|
1189
|
+
|
|
1190
|
+
Object.defineProperty(exports, "__esModule", ({
|
|
1191
|
+
value: true
|
|
1192
|
+
}));
|
|
1193
|
+
exports.GitlabVault = void 0;
|
|
1194
|
+
const gitlab_1 = __nccwpck_require__(4508);
|
|
1195
|
+
/**
|
|
1196
|
+
* the legacy (and default) vault: the gitlab project variables double
|
|
1197
|
+
* as the secret store
|
|
1198
|
+
*/
|
|
1199
|
+
class GitlabVault {
|
|
1200
|
+
constructor() {
|
|
1201
|
+
this.id = "gitlab";
|
|
1202
|
+
}
|
|
1203
|
+
async readAllSecrets(io) {
|
|
1204
|
+
const variables = await (0, gitlab_1.getAllVariables)(io);
|
|
1205
|
+
return Object.fromEntries(variables.map(v => [v.key, v.value]));
|
|
1206
|
+
}
|
|
1207
|
+
async writeSecrets(io, env, componentName, secrets) {
|
|
1208
|
+
await (0, gitlab_1.upsertAllVariables)(io, secrets, env, componentName);
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
exports.GitlabVault = GitlabVault;
|
|
1212
|
+
|
|
1213
|
+
/***/ }),
|
|
1214
|
+
|
|
1215
|
+
/***/ 5771:
|
|
1216
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
1217
|
+
|
|
1218
|
+
"use strict";
|
|
1219
|
+
|
|
1220
|
+
|
|
1221
|
+
Object.defineProperty(exports, "__esModule", ({
|
|
1222
|
+
value: true
|
|
1223
|
+
}));
|
|
1224
|
+
exports.VaultManager = void 0;
|
|
1225
|
+
const pipeline_1 = __nccwpck_require__(241);
|
|
1226
|
+
const BitwardenVault_1 = __nccwpck_require__(3510);
|
|
1227
|
+
const cache_1 = __nccwpck_require__(4236);
|
|
1228
|
+
const GitlabVault_1 = __nccwpck_require__(1107);
|
|
1229
|
+
/**
|
|
1230
|
+
* only secrets of this env are cached locally — the other envs'
|
|
1231
|
+
* secrets have no business sitting on developer machines
|
|
1232
|
+
*/
|
|
1233
|
+
const CACHED_ENV = "local";
|
|
1234
|
+
/**
|
|
1235
|
+
* owns the configured vault, the secrets mode and the local cache.
|
|
1236
|
+
* The vault is the readable source of truth for secrets; CI backends
|
|
1237
|
+
* only receive mirrored copies.
|
|
1238
|
+
*/
|
|
1239
|
+
class VaultManager {
|
|
1240
|
+
constructor(config, options = {}) {
|
|
1241
|
+
var _a, _b;
|
|
1242
|
+
this.config = config;
|
|
1243
|
+
/** refresh mode bypasses the cache only once per manager */
|
|
1244
|
+
this.refreshed = false;
|
|
1245
|
+
this.mode = (_a = options.mode) !== null && _a !== void 0 ? _a : "auto";
|
|
1246
|
+
this.io = (_b = options.io) !== null && _b !== void 0 ? _b : null;
|
|
1247
|
+
this.vault = this.createVault();
|
|
1248
|
+
}
|
|
1249
|
+
createVault() {
|
|
1250
|
+
const vaultConfig = (0, pipeline_1.getVaultConfig)(this.config);
|
|
1251
|
+
switch (vaultConfig.type) {
|
|
1252
|
+
case "gitlab":
|
|
1253
|
+
return new GitlabVault_1.GitlabVault();
|
|
1254
|
+
case "bitwarden":
|
|
1255
|
+
return new BitwardenVault_1.BitwardenVault(this.config, vaultConfig, this.mode === "auto" || this.mode === "refresh");
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
/**
|
|
1259
|
+
* the vault secrets, served from the local cache when it contains
|
|
1260
|
+
* all required names; otherwise (depending on the mode) refreshed
|
|
1261
|
+
* from the vault. Only the "local" env is (re-)cached.
|
|
1262
|
+
*/
|
|
1263
|
+
async readSecrets(requiredNames, io = this.io) {
|
|
1264
|
+
const bypassCache = this.mode === "refresh" && !this.refreshed;
|
|
1265
|
+
const cache = bypassCache ? null : await (0, cache_1.readSecretsCache)();
|
|
1266
|
+
// known entries include recorded misses (null values), so declared
|
|
1267
|
+
// but intentionally unset secrets don't force a vault refresh
|
|
1268
|
+
const known = (cache === null || cache === void 0 ? void 0 : cache.vaultId) === this.vault.id ? flattenSecrets(cache.secrets) : undefined;
|
|
1269
|
+
const missing = requiredNames.filter(name => !(name in (known !== null && known !== void 0 ? known : {})));
|
|
1270
|
+
// nothing missing (or nothing required at all): don't touch the vault
|
|
1271
|
+
if (missing.length === 0 && (known || requiredNames.length === 0)) {
|
|
1272
|
+
return withoutMisses(known !== null && known !== void 0 ? known : {});
|
|
1273
|
+
}
|
|
1274
|
+
if (this.mode === "offline") {
|
|
1275
|
+
if (missing.length > 0) {
|
|
1276
|
+
io === null || io === void 0 ? void 0 : io.log(`⚠️ vault is offline (--vault-mode offline) and ${missing.length} secrets are not in the local cache: ${missing.join(", ")}`);
|
|
1277
|
+
}
|
|
1278
|
+
return withoutMisses(known !== null && known !== void 0 ? known : {});
|
|
1279
|
+
}
|
|
1280
|
+
const secrets = await this.vault.readAllSecrets(io);
|
|
1281
|
+
this.refreshed = true;
|
|
1282
|
+
await (0, cache_1.writeSecretsCache)(this.vault.id, await this.cacheableSubset(secrets));
|
|
1283
|
+
return secrets;
|
|
1284
|
+
}
|
|
1285
|
+
/**
|
|
1286
|
+
* writes secrets of one env/component to the vault and updates the
|
|
1287
|
+
* local cache (write-through, "local" env only)
|
|
1288
|
+
*/
|
|
1289
|
+
async writeSecrets(env, componentName, secrets, io = this.io) {
|
|
1290
|
+
if (!io) {
|
|
1291
|
+
throw new Error("writing to the vault requires an interactive context");
|
|
1292
|
+
}
|
|
1293
|
+
await this.vault.writeSecrets(io, env, componentName, secrets);
|
|
1294
|
+
if (env === CACHED_ENV) {
|
|
1295
|
+
await (0, cache_1.updateSecretsCache)(this.vault.id, env, componentName, Object.fromEntries(Object.entries(secrets).map(([key, value]) => [key, typeof value === "string" ? value : JSON.stringify(value)])));
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
/**
|
|
1299
|
+
* the subset of the vault secrets that may be cached: the declared
|
|
1300
|
+
* secrets of the "local" env, per component, as a hierarchy
|
|
1301
|
+
*/
|
|
1302
|
+
async cacheableSubset(flatSecrets) {
|
|
1303
|
+
const local = {};
|
|
1304
|
+
for (const componentName of Object.keys(this.config.components)) {
|
|
1305
|
+
const keys = await this.declaredSecretKeys(componentName);
|
|
1306
|
+
const values = Object.fromEntries(keys.map(key => {
|
|
1307
|
+
var _a;
|
|
1308
|
+
return [key,
|
|
1309
|
+
// null records "absent in the vault" (a known miss)
|
|
1310
|
+
(_a = flatSecrets[(0, pipeline_1.getSecretVarName)(CACHED_ENV, componentName, key)]) !== null && _a !== void 0 ? _a : null];
|
|
1311
|
+
}));
|
|
1312
|
+
if (Object.keys(values).length > 0) {
|
|
1313
|
+
local[componentName] = values;
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
return Object.keys(local).length > 0 ? {
|
|
1317
|
+
[CACHED_ENV]: local
|
|
1318
|
+
} : {};
|
|
1319
|
+
}
|
|
1320
|
+
async declaredSecretKeys(componentName) {
|
|
1321
|
+
try {
|
|
1322
|
+
const {
|
|
1323
|
+
secretEnvVarKeys,
|
|
1324
|
+
jobOnlyVars
|
|
1325
|
+
} = await (0, pipeline_1.getEnvironment)({
|
|
1326
|
+
config: this.config,
|
|
1327
|
+
componentName,
|
|
1328
|
+
env: CACHED_ENV
|
|
1329
|
+
});
|
|
1330
|
+
return [...secretEnvVarKeys, ...jobOnlyVars.build.secretEnvVarKeys, ...jobOnlyVars.deploy.secretEnvVarKeys].map(({
|
|
1331
|
+
key
|
|
1332
|
+
}) => key);
|
|
1333
|
+
} catch (_a) {
|
|
1334
|
+
// components without a local env simply have nothing to cache
|
|
1335
|
+
return [];
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
exports.VaultManager = VaultManager;
|
|
1340
|
+
/**
|
|
1341
|
+
* the cache hierarchy as a flat map of raw secret variable names
|
|
1342
|
+
* (null values = recorded misses)
|
|
1343
|
+
*/
|
|
1344
|
+
const flattenSecrets = secrets => Object.fromEntries(Object.entries(secrets).flatMap(([env, components]) => Object.entries(components).flatMap(([componentName, values]) => Object.entries(values).map(([key, value]) => [(0, pipeline_1.getSecretVarName)(env, componentName, key), value]))));
|
|
1345
|
+
/**
|
|
1346
|
+
* only actual values — recorded misses stay unresolved, like any other
|
|
1347
|
+
* unset variable
|
|
1348
|
+
*/
|
|
1349
|
+
const withoutMisses = known => Object.fromEntries(Object.entries(known).filter(entry => entry[1] !== null));
|
|
1350
|
+
|
|
1351
|
+
/***/ }),
|
|
1352
|
+
|
|
1353
|
+
/***/ 2211:
|
|
1354
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
1355
|
+
|
|
1356
|
+
"use strict";
|
|
1357
|
+
|
|
1358
|
+
|
|
1359
|
+
Object.defineProperty(exports, "__esModule", ({
|
|
1360
|
+
value: true
|
|
1361
|
+
}));
|
|
1362
|
+
exports.runBwJson = exports.runBw = exports.getBwSession = void 0;
|
|
1363
|
+
const child_process_1 = __nccwpck_require__(5317);
|
|
1364
|
+
const util_1 = __nccwpck_require__(9023);
|
|
1365
|
+
const preferences_1 = __nccwpck_require__(6261);
|
|
1366
|
+
const execFile = (0, util_1.promisify)(child_process_1.execFile);
|
|
1367
|
+
const SESSION_PREFERENCE = "bwsession";
|
|
1368
|
+
class BitwardenLockedError extends Error {
|
|
1369
|
+
constructor() {
|
|
1370
|
+
super("bitwarden is locked and prompting is disabled — run `bw unlock` or catenv without --vault-mode no-prompt");
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
/**
|
|
1374
|
+
* runs an interactive bw command that prints a session key on stdout
|
|
1375
|
+
* (login/unlock) while the user types the password on the terminal
|
|
1376
|
+
*/
|
|
1377
|
+
const interactiveSessionCommand = args => new Promise((resolve, reject) => {
|
|
1378
|
+
var _a;
|
|
1379
|
+
const child = (0, child_process_1.spawn)("bw", [...args, "--raw"], {
|
|
1380
|
+
stdio: ["inherit", "pipe", "inherit"]
|
|
1381
|
+
});
|
|
1382
|
+
let session = "";
|
|
1383
|
+
(_a = child.stdout) === null || _a === void 0 ? void 0 : _a.on("data", data => session += data.toString("utf-8"));
|
|
1384
|
+
child.on("error", reject);
|
|
1385
|
+
child.on("close", code => code === 0 && session.trim() ? resolve(session.trim()) : reject(new Error(`bw ${args[0]} failed`)));
|
|
1386
|
+
});
|
|
1387
|
+
const getBwStatus = async session => {
|
|
1388
|
+
try {
|
|
1389
|
+
const {
|
|
1390
|
+
stdout
|
|
1391
|
+
} = await execFile("bw", ["status"], {
|
|
1392
|
+
env: {
|
|
1393
|
+
...process.env,
|
|
1394
|
+
...(session ? {
|
|
1395
|
+
BW_SESSION: session
|
|
1396
|
+
} : {})
|
|
1397
|
+
}
|
|
1398
|
+
});
|
|
1399
|
+
return JSON.parse(stdout).status;
|
|
1400
|
+
} catch (_a) {
|
|
1401
|
+
return "unauthenticated";
|
|
1402
|
+
}
|
|
1403
|
+
};
|
|
1404
|
+
/**
|
|
1405
|
+
* a working bw session: reuses the cached one, otherwise unlocks (or
|
|
1406
|
+
* logs in) interactively — unless prompting is disabled
|
|
1407
|
+
*/
|
|
1408
|
+
const getBwSession = async (io, {
|
|
1409
|
+
allowPrompt
|
|
1410
|
+
}) => {
|
|
1411
|
+
const cached = (await (0, preferences_1.hasPreference)(SESSION_PREFERENCE)) ? String(await (0, preferences_1.getPreference)(SESSION_PREFERENCE)) : null;
|
|
1412
|
+
const status = await getBwStatus(cached);
|
|
1413
|
+
if (status === "unlocked" && cached) {
|
|
1414
|
+
return cached;
|
|
1415
|
+
}
|
|
1416
|
+
if (!allowPrompt) {
|
|
1417
|
+
throw new BitwardenLockedError();
|
|
1418
|
+
}
|
|
1419
|
+
io === null || io === void 0 ? void 0 : io.log("");
|
|
1420
|
+
io === null || io === void 0 ? void 0 : io.log(status === "unauthenticated" ? "# Please login to Bitwarden:" : "# Bitwarden is locked, please unlock:");
|
|
1421
|
+
io === null || io === void 0 ? void 0 : io.log("");
|
|
1422
|
+
const session = await interactiveSessionCommand([status === "unauthenticated" ? "login" : "unlock"]);
|
|
1423
|
+
await (0, preferences_1.setPreference)(SESSION_PREFERENCE, session);
|
|
1424
|
+
await (0, exports.runBw)(session, ["sync"]);
|
|
1425
|
+
return session;
|
|
1426
|
+
};
|
|
1427
|
+
exports.getBwSession = getBwSession;
|
|
1428
|
+
/**
|
|
1429
|
+
* runs a bw command with the given session and returns stdout
|
|
1430
|
+
*/
|
|
1431
|
+
const runBw = async (session, args) => {
|
|
1432
|
+
const {
|
|
1433
|
+
stdout
|
|
1434
|
+
} = await execFile("bw", [...args, "--raw", "--nointeraction"], {
|
|
1435
|
+
env: {
|
|
1436
|
+
...process.env,
|
|
1437
|
+
BW_SESSION: session
|
|
1438
|
+
},
|
|
1439
|
+
maxBuffer: 50 * 1024 * 1024
|
|
1440
|
+
});
|
|
1441
|
+
return stdout;
|
|
1442
|
+
};
|
|
1443
|
+
exports.runBw = runBw;
|
|
1444
|
+
const runBwJson = async (session, args) => JSON.parse(await (0, exports.runBw)(session, args));
|
|
1445
|
+
exports.runBwJson = runBwJson;
|
|
1446
|
+
|
|
1447
|
+
/***/ }),
|
|
1448
|
+
|
|
1449
|
+
/***/ 4236:
|
|
1450
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
1451
|
+
|
|
1452
|
+
"use strict";
|
|
1453
|
+
|
|
1454
|
+
|
|
1455
|
+
Object.defineProperty(exports, "__esModule", ({
|
|
1456
|
+
value: true
|
|
1457
|
+
}));
|
|
1458
|
+
exports.updateSecretsCache = exports.writeSecretsCache = exports.readSecretsCache = void 0;
|
|
1459
|
+
const promises_1 = __nccwpck_require__(1943);
|
|
1460
|
+
const path_1 = __nccwpck_require__(6928);
|
|
1461
|
+
const gitProjectInformation_1 = __nccwpck_require__(1111);
|
|
1462
|
+
const getCacheFolder = async () => (0, path_1.join)(await (0, gitProjectInformation_1.getProjectRootPath)(), ".catladder");
|
|
1463
|
+
const getCachePath = async () => (0, path_1.join)(await getCacheFolder(), "secrets.json");
|
|
1464
|
+
const readSecretsCache = async () => {
|
|
1465
|
+
try {
|
|
1466
|
+
return JSON.parse(await (0, promises_1.readFile)(await getCachePath(), "utf-8"));
|
|
1467
|
+
} catch (_a) {
|
|
1468
|
+
return null;
|
|
1469
|
+
}
|
|
1470
|
+
};
|
|
1471
|
+
exports.readSecretsCache = readSecretsCache;
|
|
1472
|
+
const writeSecretsCache = async (vaultId, secrets) => {
|
|
1473
|
+
const folder = await getCacheFolder();
|
|
1474
|
+
await (0, promises_1.mkdir)(folder, {
|
|
1475
|
+
recursive: true
|
|
1476
|
+
});
|
|
1477
|
+
// the folder ignores itself, so the cache can never be committed
|
|
1478
|
+
await (0, promises_1.writeFile)((0, path_1.join)(folder, ".gitignore"), "*\n");
|
|
1479
|
+
const cache = {
|
|
1480
|
+
vaultId,
|
|
1481
|
+
updatedAt: new Date().toISOString(),
|
|
1482
|
+
secrets
|
|
1483
|
+
};
|
|
1484
|
+
await (0, promises_1.writeFile)(await getCachePath(), JSON.stringify(cache, null, 2));
|
|
1485
|
+
};
|
|
1486
|
+
exports.writeSecretsCache = writeSecretsCache;
|
|
1487
|
+
/**
|
|
1488
|
+
* merges freshly written secrets of one env/component into the cache
|
|
1489
|
+
* (write-through from config-secrets), so the next catenv run doesn't
|
|
1490
|
+
* need the vault
|
|
1491
|
+
*/
|
|
1492
|
+
const updateSecretsCache = async (vaultId, env, componentName, values) => {
|
|
1493
|
+
var _a;
|
|
1494
|
+
const existing = await (0, exports.readSecretsCache)();
|
|
1495
|
+
const secrets = (existing === null || existing === void 0 ? void 0 : existing.vaultId) === vaultId ? existing.secrets : {};
|
|
1496
|
+
secrets[env] = {
|
|
1497
|
+
...secrets[env],
|
|
1498
|
+
[componentName]: {
|
|
1499
|
+
...((_a = secrets[env]) === null || _a === void 0 ? void 0 : _a[componentName]),
|
|
1500
|
+
...values
|
|
1501
|
+
}
|
|
1502
|
+
};
|
|
1503
|
+
await (0, exports.writeSecretsCache)(vaultId, secrets);
|
|
1504
|
+
};
|
|
1505
|
+
exports.updateSecretsCache = updateSecretsCache;
|
|
1506
|
+
|
|
1507
|
+
/***/ }),
|
|
1508
|
+
|
|
950
1509
|
/***/ 4038:
|
|
951
1510
|
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
952
1511
|
|
|
@@ -963,7 +1522,11 @@ const createAllJobs_1 = __nccwpck_require__(3671);
|
|
|
963
1522
|
const config_1 = __nccwpck_require__(6925);
|
|
964
1523
|
const ciVariables_1 = __nccwpck_require__(3093);
|
|
965
1524
|
const createGithubJobs_1 = __nccwpck_require__(4016);
|
|
1525
|
+
const jobImagesPlan_1 = __nccwpck_require__(1585);
|
|
1526
|
+
const scriptFunctions_1 = __nccwpck_require__(5759);
|
|
1527
|
+
const utils_1 = __nccwpck_require__(595);
|
|
966
1528
|
const githubReleaseJobs_1 = __nccwpck_require__(5611);
|
|
1529
|
+
const scriptFiles_1 = __nccwpck_require__(9189);
|
|
967
1530
|
const WORKFLOWS_FOLDER = ".github/workflows";
|
|
968
1531
|
/**
|
|
969
1532
|
* generated workflow files are prefixed so that cleanup never touches
|
|
@@ -1008,18 +1571,29 @@ class GithubBackend {
|
|
|
1008
1571
|
async cleanup() {
|
|
1009
1572
|
const entries = await (0, promises_1.readdir)(WORKFLOWS_FOLDER).catch(() => []);
|
|
1010
1573
|
await Promise.all(entries.filter(file => file.startsWith(GENERATED_FILE_PREFIX)).map(file => (0, promises_1.unlink)((0, path_1.join)(WORKFLOWS_FOLDER, file))));
|
|
1574
|
+
await (0, promises_1.rm)(scriptFiles_1.GITHUB_SCRIPTS_FOLDER, {
|
|
1575
|
+
recursive: true,
|
|
1576
|
+
force: true
|
|
1577
|
+
});
|
|
1011
1578
|
}
|
|
1012
1579
|
async createFiles(config) {
|
|
1013
|
-
const
|
|
1014
|
-
|
|
1580
|
+
const images = this.createImagesPlan(config);
|
|
1581
|
+
const scripts = new scriptFiles_1.GithubScriptFiles();
|
|
1582
|
+
const workflows = await this.createWorkflows(config, images, scripts);
|
|
1583
|
+
return [...Object.entries(workflows).map(([fileName, workflow]) => ({
|
|
1015
1584
|
path: (0, path_1.join)(WORKFLOWS_FOLDER, fileName),
|
|
1016
1585
|
content: workflow
|
|
1017
|
-
}))
|
|
1586
|
+
})),
|
|
1587
|
+
// materialized job scripts and image definitions (repo mode)
|
|
1588
|
+
...scripts.getGeneratedFiles(), ...images.getGeneratedFiles()];
|
|
1589
|
+
}
|
|
1590
|
+
createImagesPlan(config) {
|
|
1591
|
+
return new jobImagesPlan_1.JobImagesPlan((0, jobImagesPlan_1.getJobImagesMode)(config, this.type), this.type);
|
|
1018
1592
|
}
|
|
1019
1593
|
/**
|
|
1020
1594
|
* all workflows keyed by file name, mainly for testing purposes
|
|
1021
1595
|
*/
|
|
1022
|
-
async createWorkflows(config) {
|
|
1596
|
+
async createWorkflows(config, images = this.createImagesPlan(config), scripts = new scriptFiles_1.GithubScriptFiles()) {
|
|
1023
1597
|
const workflows = {};
|
|
1024
1598
|
const reviewStopJobs = {};
|
|
1025
1599
|
const manualJobs = {};
|
|
@@ -1030,13 +1604,14 @@ class GithubBackend {
|
|
|
1030
1604
|
pipelineType: this.type
|
|
1031
1605
|
});
|
|
1032
1606
|
const uploadProviderIds = (0, createGithubJobs_1.getUploadProviderIds)(allJobs);
|
|
1607
|
+
const secretKinds = (0, createGithubJobs_1.collectSecretKinds)(allJobs);
|
|
1033
1608
|
const jobs = {};
|
|
1034
1609
|
// NOTE: agent jobs are gitlab-only and skipped on github
|
|
1035
1610
|
[...allJobs.workspaces, ...allJobs.components].forEach(({
|
|
1036
1611
|
context,
|
|
1037
1612
|
jobs: contextJobs
|
|
1038
1613
|
}) => contextJobs.forEach(job => {
|
|
1039
|
-
const [id, githubJob] = (0, createGithubJobs_1.makeGithubJob)(context, job, allJobs, uploadProviderIds);
|
|
1614
|
+
const [id, githubJob] = (0, createGithubJobs_1.makeGithubJob)(context, job, allJobs, uploadProviderIds, images, scripts, secretKinds);
|
|
1040
1615
|
if (isReviewStopJob(context, job)) {
|
|
1041
1616
|
reviewStopJobs[id] = githubJob;
|
|
1042
1617
|
} else if (isManualTaskJob(job)) {
|
|
@@ -1046,15 +1621,19 @@ class GithubBackend {
|
|
|
1046
1621
|
}
|
|
1047
1622
|
}));
|
|
1048
1623
|
if (trigger === "mainBranch") {
|
|
1049
|
-
const releaseJobs = (0, githubReleaseJobs_1.getGithubReleaseJobs)(config, Object.keys(jobs));
|
|
1624
|
+
const releaseJobs = (0, githubReleaseJobs_1.getGithubReleaseJobs)(config, Object.keys(jobs), images);
|
|
1050
1625
|
Object.assign(jobs, releaseJobs.main);
|
|
1051
1626
|
Object.assign(manualJobs, releaseJobs.manual);
|
|
1052
1627
|
}
|
|
1053
1628
|
if (Object.keys(jobs).length > 0) {
|
|
1054
1629
|
workflows[`${GENERATED_FILE_PREFIX}${workflowFileName(trigger)}`] = {
|
|
1055
1630
|
...TRIGGER_WORKFLOWS[trigger],
|
|
1631
|
+
...workflowPermissions(images),
|
|
1056
1632
|
env: ciVariables_1.GITHUB_INJECTED_WORKFLOW_ENV,
|
|
1057
|
-
jobs
|
|
1633
|
+
jobs: {
|
|
1634
|
+
...makeEnsureImageGithubJobs(images),
|
|
1635
|
+
...jobs
|
|
1636
|
+
}
|
|
1058
1637
|
};
|
|
1059
1638
|
}
|
|
1060
1639
|
}
|
|
@@ -1066,8 +1645,12 @@ class GithubBackend {
|
|
|
1066
1645
|
types: ["closed"]
|
|
1067
1646
|
}
|
|
1068
1647
|
},
|
|
1648
|
+
...workflowPermissions(images),
|
|
1069
1649
|
env: ciVariables_1.GITHUB_INJECTED_WORKFLOW_ENV,
|
|
1070
|
-
jobs:
|
|
1650
|
+
jobs: {
|
|
1651
|
+
...makeEnsureImageGithubJobs(images),
|
|
1652
|
+
...reviewStopJobs
|
|
1653
|
+
}
|
|
1071
1654
|
};
|
|
1072
1655
|
}
|
|
1073
1656
|
if (Object.keys(manualJobs).length > 0) {
|
|
@@ -1085,17 +1668,51 @@ class GithubBackend {
|
|
|
1085
1668
|
}
|
|
1086
1669
|
}
|
|
1087
1670
|
},
|
|
1671
|
+
...workflowPermissions(images),
|
|
1088
1672
|
env: ciVariables_1.GITHUB_INJECTED_WORKFLOW_ENV,
|
|
1089
|
-
jobs:
|
|
1090
|
-
...
|
|
1091
|
-
|
|
1092
|
-
|
|
1673
|
+
jobs: {
|
|
1674
|
+
...makeEnsureImageGithubJobs(images),
|
|
1675
|
+
...Object.fromEntries(Object.entries(manualJobs).map(([id, job]) => [id, {
|
|
1676
|
+
...job,
|
|
1677
|
+
if: `\${{ inputs.job == '${id}' }}`
|
|
1678
|
+
}]))
|
|
1679
|
+
}
|
|
1093
1680
|
};
|
|
1094
1681
|
}
|
|
1095
1682
|
return workflows;
|
|
1096
1683
|
}
|
|
1097
1684
|
}
|
|
1098
1685
|
exports.GithubBackend = GithubBackend;
|
|
1686
|
+
/**
|
|
1687
|
+
* repo mode needs packages:write for pushing job images to ghcr
|
|
1688
|
+
*/
|
|
1689
|
+
const workflowPermissions = images => images.mode === "repo" ? {
|
|
1690
|
+
permissions: {
|
|
1691
|
+
contents: "read",
|
|
1692
|
+
packages: "write"
|
|
1693
|
+
}
|
|
1694
|
+
} : {};
|
|
1695
|
+
/**
|
|
1696
|
+
* the image build jobs: always run (github has no server-side
|
|
1697
|
+
* changes-filter), the existence check makes unchanged runs fast.
|
|
1698
|
+
* Docker is native on github runners — no container, no dind.
|
|
1699
|
+
*/
|
|
1700
|
+
const makeEnsureImageGithubJobs = images => Object.fromEntries(images.getEnsureJobs().map(job => {
|
|
1701
|
+
var _a, _b;
|
|
1702
|
+
return [(0, createGithubJobs_1.githubGlobalJobId)(job.name), {
|
|
1703
|
+
name: job.name,
|
|
1704
|
+
"runs-on": "ubuntu-latest",
|
|
1705
|
+
steps: [{
|
|
1706
|
+
name: "Checkout",
|
|
1707
|
+
uses: "actions/checkout@v4"
|
|
1708
|
+
}, {
|
|
1709
|
+
name: job.name,
|
|
1710
|
+
id: "main",
|
|
1711
|
+
run: [...(0, scriptFunctions_1.getGithubScriptFunctionDefinitions)(), ...((_b = (_a = job.script) === null || _a === void 0 ? void 0 : _a.filter(utils_1.notNil)) !== null && _b !== void 0 ? _b : [])].join("\n"),
|
|
1712
|
+
shell: "bash"
|
|
1713
|
+
}]
|
|
1714
|
+
}];
|
|
1715
|
+
}));
|
|
1099
1716
|
const workflowFileName = trigger => {
|
|
1100
1717
|
switch (trigger) {
|
|
1101
1718
|
case "mr":
|
|
@@ -1146,7 +1763,8 @@ exports.GITHUB_CI_VARIABLES = {
|
|
|
1146
1763
|
jobToken: "CL_JOB_TOKEN",
|
|
1147
1764
|
jobImage: "CL_JOB_IMAGE",
|
|
1148
1765
|
registry: "CL_REGISTRY",
|
|
1149
|
-
registryImage: "CL_REGISTRY_IMAGE"
|
|
1766
|
+
registryImage: "CL_REGISTRY_IMAGE",
|
|
1767
|
+
registryUser: "CL_REGISTRY_USER"
|
|
1150
1768
|
};
|
|
1151
1769
|
/**
|
|
1152
1770
|
* the workflow-level env the backend injects to provide the CL_*
|
|
@@ -1156,6 +1774,7 @@ exports.GITHUB_INJECTED_WORKFLOW_ENV = {
|
|
|
1156
1774
|
CL_JOB_TOKEN: "${{ github.token }}",
|
|
1157
1775
|
CL_REGISTRY: "ghcr.io",
|
|
1158
1776
|
CL_REGISTRY_IMAGE: "ghcr.io/${{ github.repository }}",
|
|
1777
|
+
CL_REGISTRY_USER: "${{ github.actor }}",
|
|
1159
1778
|
// empty outside of pull request events
|
|
1160
1779
|
CL_PR_NUMBER: "${{ github.event.number }}"
|
|
1161
1780
|
};
|
|
@@ -1171,7 +1790,7 @@ exports.GITHUB_INJECTED_WORKFLOW_ENV = {
|
|
|
1171
1790
|
Object.defineProperty(exports, "__esModule", ({
|
|
1172
1791
|
value: true
|
|
1173
1792
|
}));
|
|
1174
|
-
exports.getUploadProviderIds = exports.makeGithubJob = exports.resolveGithubNeeds = exports.githubJobId = void 0;
|
|
1793
|
+
exports.getUploadProviderIds = exports.makeGithubJob = exports.collectSecretKinds = exports.resolveGithubNeeds = exports.githubGlobalJobId = exports.githubJobId = void 0;
|
|
1175
1794
|
const lodash_es_1 = __nccwpck_require__(4284);
|
|
1176
1795
|
const getInjectVarsScript_1 = __nccwpck_require__(436);
|
|
1177
1796
|
const createJobCache_1 = __nccwpck_require__(5644);
|
|
@@ -1179,6 +1798,7 @@ const getEnvironmentVariables_1 = __nccwpck_require__(5855);
|
|
|
1179
1798
|
const utils_1 = __nccwpck_require__(595);
|
|
1180
1799
|
const gitlab_1 = __nccwpck_require__(3468);
|
|
1181
1800
|
const scriptFunctions_1 = __nccwpck_require__(5759);
|
|
1801
|
+
const ciVariables_1 = __nccwpck_require__(3093);
|
|
1182
1802
|
/**
|
|
1183
1803
|
* runner variables that only make sense on gitlab runners and must not
|
|
1184
1804
|
* leak into github jobs (docker-in-docker daemon config, kubernetes
|
|
@@ -1197,6 +1817,9 @@ const slug = value => {
|
|
|
1197
1817
|
};
|
|
1198
1818
|
const githubJobId = (context, jobName) => slug(`${context.type === "workspace" ? "ws-" : ""}${context.name}-${jobName}-${context.env}`);
|
|
1199
1819
|
exports.githubJobId = githubJobId;
|
|
1820
|
+
/** id of a job without component/workspace context (e.g. image builds) */
|
|
1821
|
+
const githubGlobalJobId = jobName => slug(jobName);
|
|
1822
|
+
exports.githubGlobalJobId = githubGlobalJobId;
|
|
1200
1823
|
const githubJobName = (context, jobName) => `${context.name} ${jobName} | ${context.env}`;
|
|
1201
1824
|
const resolveNeed = (context, need, allJobs) => {
|
|
1202
1825
|
var _a;
|
|
@@ -1215,9 +1838,15 @@ const resolveNeed = (context, need, allJobs) => {
|
|
|
1215
1838
|
if (!provider || !job) {
|
|
1216
1839
|
throw new Error(`unknown job referenced: '${jobName}' from workspace '${env}:${workspaceName}'`);
|
|
1217
1840
|
}
|
|
1218
|
-
return (0, exports.githubJobId)(provider.context, jobName);
|
|
1219
|
-
};
|
|
1220
|
-
if ((0, lodash_es_1.isObject)(need)) {
|
|
1841
|
+
return (0, exports.githubJobId)(provider.context, jobName);
|
|
1842
|
+
};
|
|
1843
|
+
if ((0, lodash_es_1.isObject)(need)) {
|
|
1844
|
+
if ("global" in need && need.global) {
|
|
1845
|
+
return {
|
|
1846
|
+
id: (0, exports.githubGlobalJobId)(need.job),
|
|
1847
|
+
artifacts: need.artifacts
|
|
1848
|
+
};
|
|
1849
|
+
}
|
|
1221
1850
|
if ("workspaceName" in need && need.workspaceName) {
|
|
1222
1851
|
return {
|
|
1223
1852
|
id: findWorkspaceJob(need.workspaceName, need.job),
|
|
@@ -1235,9 +1864,9 @@ const resolveNeed = (context, need, allJobs) => {
|
|
|
1235
1864
|
artifacts: true
|
|
1236
1865
|
};
|
|
1237
1866
|
};
|
|
1238
|
-
const resolveGithubNeeds = (context, job, allJobs) => {
|
|
1867
|
+
const resolveGithubNeeds = (context, job, allJobs, extraNeeds = []) => {
|
|
1239
1868
|
var _a;
|
|
1240
|
-
const resolved = ((_a = job.needs) !== null && _a !== void 0 ? _a : []).map(need => resolveNeed(context, need, allJobs));
|
|
1869
|
+
const resolved = [...extraNeeds, ...((_a = job.needs) !== null && _a !== void 0 ? _a : [])].map(need => resolveNeed(context, need, allJobs));
|
|
1241
1870
|
// deduplicate by provider id, explicit entries win (they come last)
|
|
1242
1871
|
return [...new Map(resolved.map(n => [n.id, n])).values()].sort((a, b) => a.id.localeCompare(b.id));
|
|
1243
1872
|
};
|
|
@@ -1278,29 +1907,73 @@ const createCacheSteps = (context, job) => {
|
|
|
1278
1907
|
};
|
|
1279
1908
|
});
|
|
1280
1909
|
};
|
|
1281
|
-
|
|
1910
|
+
/**
|
|
1911
|
+
* how a vault-stored value reaches the job env: masked github secret,
|
|
1912
|
+
* or plain (unmasked) github variable for non-sensitive values — those
|
|
1913
|
+
* stay readable in logs and usable in environment urls
|
|
1914
|
+
*/
|
|
1915
|
+
const vaultValueExpression = (name, kinds) => kinds.get(name) === "variable" ? `\${{ vars.${name} }}` : `\${{ secrets.${name} }}`;
|
|
1916
|
+
/**
|
|
1917
|
+
* the kind of every vault-stored var of all components, keyed by its
|
|
1918
|
+
* CL_* name — the lookup for cross-component references
|
|
1919
|
+
*/
|
|
1920
|
+
const collectSecretKinds = allJobs => {
|
|
1921
|
+
const kinds = new Map();
|
|
1922
|
+
allJobs.components.forEach(({
|
|
1923
|
+
context
|
|
1924
|
+
}) => {
|
|
1925
|
+
var _a, _b;
|
|
1926
|
+
const entries = [...context.environment.secretEnvVarKeys, ...((_a = context.environment.jobOnlyVars.build.secretEnvVarKeys) !== null && _a !== void 0 ? _a : []), ...((_b = context.environment.jobOnlyVars.deploy.secretEnvVarKeys) !== null && _b !== void 0 ? _b : [])];
|
|
1927
|
+
entries.forEach(({
|
|
1928
|
+
key,
|
|
1929
|
+
kind
|
|
1930
|
+
}) => kinds.set((0, getEnvironmentVariables_1.getSecretVarName)(context.env, context.name, key), kind !== null && kind !== void 0 ? kind : "secret"));
|
|
1931
|
+
});
|
|
1932
|
+
return kinds;
|
|
1933
|
+
};
|
|
1934
|
+
exports.collectSecretKinds = collectSecretKinds;
|
|
1935
|
+
const getSecretsEnv = (context, kinds) => {
|
|
1282
1936
|
var _a, _b;
|
|
1283
1937
|
const keys = [...context.environment.secretEnvVarKeys, ...((_a = context.environment.jobOnlyVars.build.secretEnvVarKeys) !== null && _a !== void 0 ? _a : []), ...((_b = context.environment.jobOnlyVars.deploy.secretEnvVarKeys) !== null && _b !== void 0 ? _b : [])];
|
|
1284
1938
|
return Object.fromEntries(keys.map(({
|
|
1285
1939
|
key
|
|
1286
1940
|
}) => {
|
|
1287
1941
|
const name = (0, getEnvironmentVariables_1.getSecretVarName)(context.env, context.name, key);
|
|
1288
|
-
return [name,
|
|
1942
|
+
return [name, vaultValueExpression(name, kinds)];
|
|
1289
1943
|
}));
|
|
1290
1944
|
};
|
|
1291
|
-
|
|
1945
|
+
/**
|
|
1946
|
+
* every CL_* variable the job script reads must exist in the job env.
|
|
1947
|
+
* On gitlab all project variables are implicitly available in every
|
|
1948
|
+
* job — cross-component references (`${other-component:KEY}`) rely on
|
|
1949
|
+
* that. Github jobs only see what is injected explicitly, so the
|
|
1950
|
+
* script is scanned for the names it actually references.
|
|
1951
|
+
*/
|
|
1952
|
+
const getReferencedSecretsEnv = (script, kinds) => Object.fromEntries([...script.matchAll(/\$\{?(CL_[A-Za-z0-9_]+)\}?/g)].map(match => match[1]).filter(name => !(name in ciVariables_1.GITHUB_INJECTED_WORKFLOW_ENV)).map(name => [name, vaultValueExpression(name, kinds)]));
|
|
1953
|
+
const makeGithubJob = (context, job, allJobs, uploadProviderIds, images, scripts, secretKinds = new Map()) => {
|
|
1292
1954
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
1293
1955
|
const id = (0, exports.githubJobId)(context, job.name);
|
|
1294
1956
|
const isComponent = context.type === "component";
|
|
1295
1957
|
const createsJobEnv = !!job.environment && isComponent && (!job.environment.action || job.environment.action === "start");
|
|
1296
1958
|
const skipCheckout = ((_a = job.runnerVariables) === null || _a === void 0 ? void 0 : _a.GIT_STRATEGY) === "none";
|
|
1297
|
-
const
|
|
1298
|
-
const
|
|
1959
|
+
const resolved = images.resolve(job.image);
|
|
1960
|
+
const needs = (0, exports.resolveGithubNeeds)(context, job, allJobs, resolved.need ? [resolved.need] : []);
|
|
1961
|
+
const image = typeof resolved.image === "string" ? resolved.image : Array.isArray(resolved.image) ? resolved.image[0] : (_b = resolved.image) === null || _b === void 0 ? void 0 : _b.name;
|
|
1299
1962
|
const runScript = [...(0, scriptFunctions_1.getGithubScriptFunctionDefinitions)(), ...(0, gitlab_1.collapseableSection)("injectvars", "Injecting variables")((0, getInjectVarsScript_1.getInjectVarsScript)((_c = job.variables) !== null && _c !== void 0 ? _c : {})), ...((_e = (_d = job.script) === null || _d === void 0 ? void 0 : _d.filter(utils_1.notNil)) !== null && _e !== void 0 ? _e : []), ...(createsJobEnv ? [`echo "url=$ROOT_URL" >> "$GITHUB_OUTPUT"`] : [])].join("\n");
|
|
1963
|
+
// scripts live in committed files to keep workflows under github's
|
|
1964
|
+
// 512 KB limit. Two classes of jobs must keep their script inline:
|
|
1965
|
+
// jobs without a checkout have no repo files, and `${{ }}` expressions
|
|
1966
|
+
// are only interpolated inside the workflow file itself.
|
|
1967
|
+
const run = skipCheckout || runScript.includes("${{") ? runScript : scripts.add(id, runScript);
|
|
1300
1968
|
const artifactPaths = (_g = (_f = job.artifacts) === null || _f === void 0 ? void 0 : _f.paths) !== null && _g !== void 0 ? _g : [];
|
|
1301
|
-
const
|
|
1969
|
+
const declaredServices = ((_h = job.services) !== null && _h !== void 0 ? _h : []).map(service => typeof service === "string" ? {
|
|
1302
1970
|
name: service
|
|
1303
|
-
} : service)
|
|
1971
|
+
} : service);
|
|
1972
|
+
// docker runs natively on github runners, so gitlab's docker-in-docker
|
|
1973
|
+
// services are dropped. The job container stays: the runner mounts the
|
|
1974
|
+
// host's docker socket into it, and images like docker-build carry the
|
|
1975
|
+
// helper scripts (ensure*Dockerfile etc.) the job scripts rely on.
|
|
1976
|
+
const services = Object.fromEntries(declaredServices.filter(service => !isDindService(service.name)).map(service => [slug("alias" in service && service.alias ? service.alias : service.name), {
|
|
1304
1977
|
image: service.name,
|
|
1305
1978
|
...("variables" in service && service.variables ? {
|
|
1306
1979
|
env: service.variables
|
|
@@ -1308,7 +1981,8 @@ const makeGithubJob = (context, job, allJobs, uploadProviderIds) => {
|
|
|
1308
1981
|
}]));
|
|
1309
1982
|
const env = {
|
|
1310
1983
|
...Object.fromEntries(Object.entries((_j = job.runnerVariables) !== null && _j !== void 0 ? _j : {}).filter(([key]) => !GITLAB_ONLY_RUNNER_VARIABLES.has(key))),
|
|
1311
|
-
...(isComponent ? getSecretsEnv(context) : {}),
|
|
1984
|
+
...(isComponent ? getSecretsEnv(context, secretKinds) : {}),
|
|
1985
|
+
...getReferencedSecretsEnv(runScript, secretKinds),
|
|
1312
1986
|
CL_JOB_IMAGE: image !== null && image !== void 0 ? image : "runner"
|
|
1313
1987
|
};
|
|
1314
1988
|
const githubJob = {
|
|
@@ -1319,7 +1993,14 @@ const makeGithubJob = (context, job, allJobs, uploadProviderIds) => {
|
|
|
1319
1993
|
} : {}),
|
|
1320
1994
|
...(image ? {
|
|
1321
1995
|
container: {
|
|
1322
|
-
image
|
|
1996
|
+
image,
|
|
1997
|
+
// private images in the repo's registry need credentials
|
|
1998
|
+
...(resolved.fromRepoRegistry ? {
|
|
1999
|
+
credentials: {
|
|
2000
|
+
username: "${{ github.actor }}",
|
|
2001
|
+
password: "${{ github.token }}"
|
|
2002
|
+
}
|
|
2003
|
+
} : {})
|
|
1323
2004
|
}
|
|
1324
2005
|
} : {}),
|
|
1325
2006
|
...(Object.keys(services).length > 0 ? {
|
|
@@ -1346,7 +2027,7 @@ const makeGithubJob = (context, job, allJobs, uploadProviderIds) => {
|
|
|
1346
2027
|
})), {
|
|
1347
2028
|
name: job.name,
|
|
1348
2029
|
id: "main",
|
|
1349
|
-
run
|
|
2030
|
+
run,
|
|
1350
2031
|
shell: "bash"
|
|
1351
2032
|
}, ...(uploadProviderIds.has(id) || artifactPaths.length > 0 ? artifactPaths.length > 0 ? [{
|
|
1352
2033
|
name: "Upload artifacts",
|
|
@@ -1354,7 +2035,11 @@ const makeGithubJob = (context, job, allJobs, uploadProviderIds) => {
|
|
|
1354
2035
|
with: {
|
|
1355
2036
|
name: id,
|
|
1356
2037
|
path: artifactPaths.join("\n"),
|
|
1357
|
-
"if-no-files-found": "warn"
|
|
2038
|
+
"if-no-files-found": "warn",
|
|
2039
|
+
// gitlab artifacts include everything; upload-artifact
|
|
2040
|
+
// silently drops hidden files by default — which is
|
|
2041
|
+
// exactly where next.js builds live (.next)
|
|
2042
|
+
"include-hidden-files": true
|
|
1358
2043
|
}
|
|
1359
2044
|
}] : [] : [])]
|
|
1360
2045
|
};
|
|
@@ -1387,36 +2072,49 @@ Object.defineProperty(exports, "__esModule", ({
|
|
|
1387
2072
|
value: true
|
|
1388
2073
|
}));
|
|
1389
2074
|
exports.getGithubReleaseJobs = void 0;
|
|
1390
|
-
const
|
|
1391
|
-
const createReleaseJob = needs =>
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
permissions: {
|
|
1399
|
-
contents: "write"
|
|
1400
|
-
},
|
|
1401
|
-
...(needs && needs.length > 0 ? {
|
|
1402
|
-
needs
|
|
1403
|
-
} : {}),
|
|
1404
|
-
env: {
|
|
1405
|
-
GITHUB_TOKEN: "${{ github.token }}"
|
|
1406
|
-
},
|
|
1407
|
-
steps: [{
|
|
1408
|
-
name: "Checkout",
|
|
1409
|
-
uses: "actions/checkout@v4",
|
|
1410
|
-
// semantic-release needs the full history to determine the version
|
|
1411
|
-
with: {
|
|
1412
|
-
"fetch-depth": 0
|
|
1413
|
-
}
|
|
1414
|
-
}, {
|
|
2075
|
+
const createGithubJobs_1 = __nccwpck_require__(4016);
|
|
2076
|
+
const createReleaseJob = (images, needs) => {
|
|
2077
|
+
const resolved = images.resolveRef({
|
|
2078
|
+
catladderImage: "semantic-release"
|
|
2079
|
+
});
|
|
2080
|
+
const imageNeeds = resolved.need && typeof resolved.need === "object" ? [(0, createGithubJobs_1.githubGlobalJobId)(resolved.need.job)] : [];
|
|
2081
|
+
const allNeeds = [...imageNeeds, ...(needs !== null && needs !== void 0 ? needs : [])];
|
|
2082
|
+
return {
|
|
1415
2083
|
name: "create release",
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
2084
|
+
"runs-on": "ubuntu-latest",
|
|
2085
|
+
container: {
|
|
2086
|
+
image: resolved.image,
|
|
2087
|
+
...(resolved.fromRepoRegistry ? {
|
|
2088
|
+
credentials: {
|
|
2089
|
+
username: "${{ github.actor }}",
|
|
2090
|
+
password: "${{ github.token }}"
|
|
2091
|
+
}
|
|
2092
|
+
} : {})
|
|
2093
|
+
},
|
|
2094
|
+
// semantic-release pushes the version tag and release commit
|
|
2095
|
+
permissions: {
|
|
2096
|
+
contents: "write"
|
|
2097
|
+
},
|
|
2098
|
+
...(allNeeds.length > 0 ? {
|
|
2099
|
+
needs: allNeeds
|
|
2100
|
+
} : {}),
|
|
2101
|
+
env: {
|
|
2102
|
+
GITHUB_TOKEN: "${{ github.token }}"
|
|
2103
|
+
},
|
|
2104
|
+
steps: [{
|
|
2105
|
+
name: "Checkout",
|
|
2106
|
+
uses: "actions/checkout@v4",
|
|
2107
|
+
// semantic-release needs the full history to determine the version
|
|
2108
|
+
with: {
|
|
2109
|
+
"fetch-depth": 0
|
|
2110
|
+
}
|
|
2111
|
+
}, {
|
|
2112
|
+
name: "create release",
|
|
2113
|
+
run: "semanticRelease",
|
|
2114
|
+
shell: "bash"
|
|
2115
|
+
}]
|
|
2116
|
+
};
|
|
2117
|
+
};
|
|
1420
2118
|
/**
|
|
1421
2119
|
* the release jobs for the github backend (the counterpart of the
|
|
1422
2120
|
* gitlab release jobs):
|
|
@@ -1426,22 +2124,22 @@ const createReleaseJob = needs => ({
|
|
|
1426
2124
|
* - otherwise (manual, the default): the release job goes to the
|
|
1427
2125
|
* manual tasks workflow
|
|
1428
2126
|
*/
|
|
1429
|
-
const getGithubReleaseJobs = (config, mainWorkflowJobIds) => {
|
|
2127
|
+
const getGithubReleaseJobs = (config, mainWorkflowJobIds, images) => {
|
|
1430
2128
|
var _a;
|
|
1431
2129
|
if (((_a = config.releases) === null || _a === void 0 ? void 0 : _a.when) === "auto") {
|
|
1432
2130
|
return {
|
|
1433
2131
|
main: {
|
|
1434
|
-
"create-release": createReleaseJob(mainWorkflowJobIds)
|
|
2132
|
+
"create-release": createReleaseJob(images, mainWorkflowJobIds)
|
|
1435
2133
|
},
|
|
1436
2134
|
manual: {
|
|
1437
|
-
"force-create-release": createReleaseJob()
|
|
2135
|
+
"force-create-release": createReleaseJob(images)
|
|
1438
2136
|
}
|
|
1439
2137
|
};
|
|
1440
2138
|
}
|
|
1441
2139
|
return {
|
|
1442
2140
|
main: {},
|
|
1443
2141
|
manual: {
|
|
1444
|
-
"create-release": createReleaseJob()
|
|
2142
|
+
"create-release": createReleaseJob(images)
|
|
1445
2143
|
}
|
|
1446
2144
|
};
|
|
1447
2145
|
};
|
|
@@ -1479,6 +2177,64 @@ Object.defineProperty(exports, "__esModule", ({
|
|
|
1479
2177
|
}));
|
|
1480
2178
|
__exportStar(__nccwpck_require__(4038), exports);
|
|
1481
2179
|
__exportStar(__nccwpck_require__(3093), exports);
|
|
2180
|
+
__exportStar(__nccwpck_require__(9189), exports);
|
|
2181
|
+
|
|
2182
|
+
/***/ }),
|
|
2183
|
+
|
|
2184
|
+
/***/ 9189:
|
|
2185
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
2186
|
+
|
|
2187
|
+
"use strict";
|
|
2188
|
+
|
|
2189
|
+
|
|
2190
|
+
Object.defineProperty(exports, "__esModule", ({
|
|
2191
|
+
value: true
|
|
2192
|
+
}));
|
|
2193
|
+
exports.GithubScriptFiles = exports.GITHUB_SCRIPTS_FOLDER = void 0;
|
|
2194
|
+
const path_1 = __nccwpck_require__(6928);
|
|
2195
|
+
/**
|
|
2196
|
+
* folder for job scripts materialized into the repository (committed,
|
|
2197
|
+
* like the image definitions). Owned entirely by the github backend.
|
|
2198
|
+
*/
|
|
2199
|
+
exports.GITHUB_SCRIPTS_FOLDER = ".catladder-generated/github/scripts";
|
|
2200
|
+
/**
|
|
2201
|
+
* github silently ignores workflow files larger than 512 KB — no run,
|
|
2202
|
+
* no check suite, no error. Inlining every job's bash script blows past
|
|
2203
|
+
* that limit on bigger projects, so job scripts are materialized into
|
|
2204
|
+
* committed files and the workflow step only invokes them.
|
|
2205
|
+
*
|
|
2206
|
+
* Scripts containing `${{ ... }}` expressions must stay inline: the
|
|
2207
|
+
* runner only interpolates expressions in the workflow file itself,
|
|
2208
|
+
* never in files read at runtime.
|
|
2209
|
+
*/
|
|
2210
|
+
class GithubScriptFiles {
|
|
2211
|
+
constructor() {
|
|
2212
|
+
this.files = new Map();
|
|
2213
|
+
}
|
|
2214
|
+
/**
|
|
2215
|
+
* materializes a job script into a committed file and returns the
|
|
2216
|
+
* step command invoking it
|
|
2217
|
+
*/
|
|
2218
|
+
add(jobId, script) {
|
|
2219
|
+
const path = (0, path_1.join)(exports.GITHUB_SCRIPTS_FOLDER, `${jobId}.sh`);
|
|
2220
|
+
// `shell: bash` steps run with `bash -eo pipefail`; the script file
|
|
2221
|
+
// must fail exactly like the inline version did
|
|
2222
|
+
const content = `#!/usr/bin/env bash\nset -eo pipefail\n\n${script}\n`;
|
|
2223
|
+
const existing = this.files.get(path);
|
|
2224
|
+
if (existing !== undefined && existing !== content) {
|
|
2225
|
+
throw new Error(`conflicting scripts for job id '${jobId}'`);
|
|
2226
|
+
}
|
|
2227
|
+
this.files.set(path, content);
|
|
2228
|
+
return `bash ${path}`;
|
|
2229
|
+
}
|
|
2230
|
+
getGeneratedFiles() {
|
|
2231
|
+
return [...this.files.entries()].map(([path, content]) => ({
|
|
2232
|
+
path,
|
|
2233
|
+
content
|
|
2234
|
+
}));
|
|
2235
|
+
}
|
|
2236
|
+
}
|
|
2237
|
+
exports.GithubScriptFiles = GithubScriptFiles;
|
|
1482
2238
|
|
|
1483
2239
|
/***/ }),
|
|
1484
2240
|
|
|
@@ -1533,6 +2289,7 @@ const promises_1 = __nccwpck_require__(1943);
|
|
|
1533
2289
|
const rules_1 = __nccwpck_require__(4565);
|
|
1534
2290
|
const config_1 = __nccwpck_require__(6925);
|
|
1535
2291
|
const createAllJobs_1 = __nccwpck_require__(3671);
|
|
2292
|
+
const jobImagesPlan_1 = __nccwpck_require__(1585);
|
|
1536
2293
|
const createGitlabJobs_1 = __nccwpck_require__(512);
|
|
1537
2294
|
const createGitlabPipeline_1 = __nccwpck_require__(1862);
|
|
1538
2295
|
const gitlabReleaseJobs_1 = __nccwpck_require__(5531);
|
|
@@ -1552,31 +2309,38 @@ class GitlabBackend {
|
|
|
1552
2309
|
});
|
|
1553
2310
|
}
|
|
1554
2311
|
async createFiles(config) {
|
|
1555
|
-
const
|
|
2312
|
+
const images = this.createImagesPlan(config);
|
|
2313
|
+
const includes = await this.createIncludes(config, images);
|
|
1556
2314
|
const mainFile = {
|
|
1557
2315
|
path: ".gitlab-ci.yml",
|
|
1558
2316
|
content: {
|
|
1559
2317
|
include: includes.map(i => i.path)
|
|
1560
2318
|
}
|
|
1561
2319
|
};
|
|
1562
|
-
return [mainFile, ...includes
|
|
2320
|
+
return [mainFile, ...includes,
|
|
2321
|
+
// materialized image definitions (repo mode)
|
|
2322
|
+
...images.getGeneratedFiles()];
|
|
2323
|
+
}
|
|
2324
|
+
createImagesPlan(config) {
|
|
2325
|
+
return new jobImagesPlan_1.JobImagesPlan((0, jobImagesPlan_1.getJobImagesMode)(config, this.type), this.type);
|
|
1563
2326
|
}
|
|
1564
2327
|
/**
|
|
1565
2328
|
* the complete pipeline as one object (all includes merged into one),
|
|
1566
2329
|
* mainly for testing purposes
|
|
1567
2330
|
*/
|
|
1568
2331
|
async createCompletePipeline(config) {
|
|
1569
|
-
const includes = await this.createIncludes(config);
|
|
2332
|
+
const includes = await this.createIncludes(config, this.createImagesPlan(config));
|
|
1570
2333
|
return includes.reduce((acc, {
|
|
1571
2334
|
content
|
|
1572
2335
|
}) => {
|
|
1573
2336
|
return {
|
|
1574
2337
|
...acc,
|
|
2338
|
+
// includes are always yaml objects
|
|
1575
2339
|
...content // merge all includes into one object
|
|
1576
2340
|
};
|
|
1577
2341
|
}, {});
|
|
1578
2342
|
}
|
|
1579
|
-
async createIncludes(config) {
|
|
2343
|
+
async createIncludes(config, images) {
|
|
1580
2344
|
const {
|
|
1581
2345
|
jobs,
|
|
1582
2346
|
image,
|
|
@@ -1584,7 +2348,7 @@ class GitlabBackend {
|
|
|
1584
2348
|
variables,
|
|
1585
2349
|
workflow,
|
|
1586
2350
|
...pipelineRest
|
|
1587
|
-
} = await this.createPipeline(config);
|
|
2351
|
+
} = await this.createPipeline(config, images);
|
|
1588
2352
|
// we will create 1 include per component or workspace
|
|
1589
2353
|
// this is for better readability in git diffs and to avoid problems with yaml files beeing too large
|
|
1590
2354
|
// group by context
|
|
@@ -1617,14 +2381,14 @@ class GitlabBackend {
|
|
|
1617
2381
|
};
|
|
1618
2382
|
return [mainInclude, ...componentIncludes];
|
|
1619
2383
|
}
|
|
1620
|
-
async createPipeline(config) {
|
|
2384
|
+
async createPipeline(config, images) {
|
|
1621
2385
|
const stages = (0, getPipelineStages_1.getPipelineStages)(config);
|
|
1622
2386
|
// for all triggers create jobs and add base rules
|
|
1623
2387
|
const allJobsPerTrigger = await Promise.all(config_1.ALL_PIPELINE_TRIGGERS.map(async trigger => await (0, createGitlabJobs_1.createGitlabJobs)(await (0, createAllJobs_1.createAllJobs)({
|
|
1624
2388
|
config,
|
|
1625
2389
|
trigger,
|
|
1626
2390
|
pipelineType: this.type
|
|
1627
|
-
}), getGitlabRulesForTrigger(trigger)))).then(j => j.flat());
|
|
2391
|
+
}), images, getGitlabRulesForTrigger(trigger)))).then(j => j.flat());
|
|
1628
2392
|
const allWorkspaceJobs = allJobsPerTrigger.filter(j => {
|
|
1629
2393
|
var _a;
|
|
1630
2394
|
return ((_a = j.context) === null || _a === void 0 ? void 0 : _a.type) === "workspace";
|
|
@@ -1653,7 +2417,9 @@ class GitlabBackend {
|
|
|
1653
2417
|
var _a;
|
|
1654
2418
|
return ((_a = j.context) === null || _a === void 0 ? void 0 : _a.type) === "agent";
|
|
1655
2419
|
});
|
|
1656
|
-
|
|
2420
|
+
// context-less jobs (image build jobs)
|
|
2421
|
+
const allContextlessJobs = allJobsPerTrigger.filter(j => j.context === null);
|
|
2422
|
+
const allJobs = [...allContextlessJobs, ...allWorkspaceJobs, ...allComponentJobs, ...allGlobalJobs].reduce((acc, {
|
|
1657
2423
|
gitlabJob,
|
|
1658
2424
|
name,
|
|
1659
2425
|
context
|
|
@@ -1767,7 +2533,8 @@ exports.GITLAB_CI_VARIABLES = {
|
|
|
1767
2533
|
jobToken: "CI_JOB_TOKEN",
|
|
1768
2534
|
jobImage: "CI_JOB_IMAGE",
|
|
1769
2535
|
registry: "CI_REGISTRY",
|
|
1770
|
-
registryImage: "CI_REGISTRY_IMAGE"
|
|
2536
|
+
registryImage: "CI_REGISTRY_IMAGE",
|
|
2537
|
+
registryUser: "CI_REGISTRY_USER"
|
|
1771
2538
|
};
|
|
1772
2539
|
|
|
1773
2540
|
/***/ }),
|
|
@@ -1836,7 +2603,7 @@ const getFullReferencedJobNameFromWorkspace = (referencedJobName, workspaceName,
|
|
|
1836
2603
|
});
|
|
1837
2604
|
};
|
|
1838
2605
|
const getJobName = need => (0, lodash_es_1.isObject)(need) ? need.job : need;
|
|
1839
|
-
const makeGitlabJob = (context, job, allJobs, baseRules) => {
|
|
2606
|
+
const makeGitlabJob = (context, job, allJobs, images, baseRules) => {
|
|
1840
2607
|
var _a, _b;
|
|
1841
2608
|
const {
|
|
1842
2609
|
environment,
|
|
@@ -1854,8 +2621,14 @@ const makeGitlabJob = (context, job, allJobs, baseRules) => {
|
|
|
1854
2621
|
allow_failure: jobAllowFailure,
|
|
1855
2622
|
cache: jobCache,
|
|
1856
2623
|
caches,
|
|
2624
|
+
image: jobImage,
|
|
1857
2625
|
...rest
|
|
1858
2626
|
} = job;
|
|
2627
|
+
// catladder image references resolve according to the jobImages mode;
|
|
2628
|
+
// in repo mode the job additionally depends on the image build job
|
|
2629
|
+
const resolvedImage = images.resolve(jobImage);
|
|
2630
|
+
const image = resolvedImage.image;
|
|
2631
|
+
const imageNeeds = resolvedImage.need ? [resolvedImage.need] : [];
|
|
1859
2632
|
// the neutral `gate` translates to gitlab's when/allow_failure;
|
|
1860
2633
|
// explicitly set gitlab fields take precedence
|
|
1861
2634
|
const when = jobWhen !== null && jobWhen !== void 0 ? jobWhen : gate ? gate === "manual" ? "manual" : "on_success" : undefined;
|
|
@@ -1864,7 +2637,7 @@ const makeGitlabJob = (context, job, allJobs, baseRules) => {
|
|
|
1864
2637
|
// an explicitly set gitlab `cache` takes precedence
|
|
1865
2638
|
const cache = jobCache !== null && jobCache !== void 0 ? jobCache : caches && context.type !== "agent" ? (0, createJobCache_1.createJobCacheFromCacheConfigs)(context, caches) : undefined;
|
|
1866
2639
|
const stage = envMode === "stagePerEnv" && context.type !== "agent" ? `${job.stage} ${context.env}` : job.stage;
|
|
1867
|
-
const deduplicatedGitlabNeeds = getGitlabNeeds(context, job, allJobs);
|
|
2640
|
+
const deduplicatedGitlabNeeds = getGitlabNeeds(context, job, allJobs, imageNeeds);
|
|
1868
2641
|
const fullJobName = getFullJobName({
|
|
1869
2642
|
type: context.type,
|
|
1870
2643
|
name,
|
|
@@ -1893,6 +2666,7 @@ const makeGitlabJob = (context, job, allJobs, baseRules) => {
|
|
|
1893
2666
|
retry: defaults_1.BASE_RETRY,
|
|
1894
2667
|
interruptible: true,
|
|
1895
2668
|
...rest,
|
|
2669
|
+
image,
|
|
1896
2670
|
allow_failure,
|
|
1897
2671
|
cache: cache ? (0, cache_1.addCacheFallback)(cache, context) : undefined,
|
|
1898
2672
|
rules: rules.length > 0 ? rules : undefined,
|
|
@@ -1968,13 +2742,13 @@ const addGitlabEnvironment = (context, catladderJobEnvironment, job, allJobs) =>
|
|
|
1968
2742
|
script: [...((_b = job.script) !== null && _b !== void 0 ? _b : []), ...(createsJobEnv ? scriptToAdd : [])]
|
|
1969
2743
|
};
|
|
1970
2744
|
};
|
|
1971
|
-
const createGitlabJobs = async (allJobs, baseRules) => {
|
|
1972
|
-
|
|
2745
|
+
const createGitlabJobs = async (allJobs, images, baseRules) => {
|
|
2746
|
+
const contextualJobs = [...allJobs.workspaces, ...allJobs.components, ...allJobs.agents].flatMap(({
|
|
1973
2747
|
context,
|
|
1974
2748
|
jobs
|
|
1975
2749
|
}) => {
|
|
1976
2750
|
return jobs.map(job => {
|
|
1977
|
-
const [fullJobName, gitlabJob] = (0, exports.makeGitlabJob)(context, job, allJobs, baseRules);
|
|
2751
|
+
const [fullJobName, gitlabJob] = (0, exports.makeGitlabJob)(context, job, allJobs, images, baseRules);
|
|
1978
2752
|
return {
|
|
1979
2753
|
name: fullJobName,
|
|
1980
2754
|
gitlabJob,
|
|
@@ -1982,13 +2756,66 @@ const createGitlabJobs = async (allJobs, baseRules) => {
|
|
|
1982
2756
|
};
|
|
1983
2757
|
});
|
|
1984
2758
|
});
|
|
2759
|
+
// image build jobs (repo mode): no context, plain names, their
|
|
2760
|
+
// rules:changes combined with the trigger rules
|
|
2761
|
+
const imageJobs = images.getEnsureJobs().map(job => ({
|
|
2762
|
+
name: job.name,
|
|
2763
|
+
gitlabJob: makeEnsureImageGitlabJob(job, baseRules),
|
|
2764
|
+
context: null
|
|
2765
|
+
}));
|
|
2766
|
+
return [...imageJobs, ...contextualJobs];
|
|
1985
2767
|
};
|
|
1986
2768
|
exports.createGitlabJobs = createGitlabJobs;
|
|
1987
|
-
|
|
2769
|
+
/**
|
|
2770
|
+
* lowers an image build job: only runs when the (generated) image
|
|
2771
|
+
* definition changed, within the trigger's base rules
|
|
2772
|
+
*/
|
|
2773
|
+
const makeEnsureImageGitlabJob = (job, baseRules) => {
|
|
2774
|
+
var _a, _b, _c, _d;
|
|
2775
|
+
const changes = (_b = (_a = job.rules) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.changes;
|
|
2776
|
+
const rules = (baseRules !== null && baseRules !== void 0 ? baseRules : []).map(baseRule => baseRule.when === "never" ? baseRule : {
|
|
2777
|
+
...baseRule,
|
|
2778
|
+
changes
|
|
2779
|
+
});
|
|
2780
|
+
return (0, removeUndefined_1.removeUndefined)({
|
|
2781
|
+
retry: defaults_1.BASE_RETRY,
|
|
2782
|
+
interruptible: true,
|
|
2783
|
+
image: job.image,
|
|
2784
|
+
services: job.services,
|
|
2785
|
+
rules: rules.length > 0 ? rules : [{
|
|
2786
|
+
changes
|
|
2787
|
+
}],
|
|
2788
|
+
variables: job.runnerVariables,
|
|
2789
|
+
script: (_d = (_c = job.script) === null || _c === void 0 ? void 0 : _c.filter(utils_1.notNil)) !== null && _d !== void 0 ? _d : [],
|
|
2790
|
+
stage: job.stage,
|
|
2791
|
+
needs: []
|
|
2792
|
+
});
|
|
2793
|
+
};
|
|
2794
|
+
function getGitlabNeeds(context, job, allJobs, extraNeeds = []) {
|
|
1988
2795
|
var _a;
|
|
1989
|
-
const
|
|
2796
|
+
const jobWithExtraNeeds = extraNeeds.length > 0 ? {
|
|
2797
|
+
...job,
|
|
2798
|
+
needs: [...extraNeeds, ...((_a = job.needs) !== null && _a !== void 0 ? _a : [])]
|
|
2799
|
+
} : job;
|
|
2800
|
+
const needs = context.type === "workspace" ? getGitlabNeedsForWorkspaceJob(context, jobWithExtraNeeds, allJobs) : context.type === "agent" ? mapAgentNeeds(jobWithExtraNeeds.needs) : getGitlabNeedsForComponentJob(context, jobWithExtraNeeds, allJobs);
|
|
1990
2801
|
return needs ? deduplicateNeeds(needs) : undefined;
|
|
1991
2802
|
}
|
|
2803
|
+
/**
|
|
2804
|
+
* agent jobs use their needs as-is; global needs (image build jobs)
|
|
2805
|
+
* keep their plain name and optional flag
|
|
2806
|
+
*/
|
|
2807
|
+
function mapAgentNeeds(needs) {
|
|
2808
|
+
if (!needs) {
|
|
2809
|
+
return null;
|
|
2810
|
+
}
|
|
2811
|
+
return needs.map(n => (0, lodash_es_1.isObject)(n) && "global" in n && n.global ? {
|
|
2812
|
+
job: n.job,
|
|
2813
|
+
artifacts: n.artifacts,
|
|
2814
|
+
...(n.optional ? {
|
|
2815
|
+
optional: true
|
|
2816
|
+
} : {})
|
|
2817
|
+
} : n);
|
|
2818
|
+
}
|
|
1992
2819
|
function deduplicateNeeds(needs) {
|
|
1993
2820
|
return needs ? [...new Map(needs.map(n => [(0, lodash_es_1.isObject)(n) ? n.job : n, n])).values()] : undefined;
|
|
1994
2821
|
}
|
|
@@ -1997,11 +2824,19 @@ function getGitlabNeedsForComponentJob(context, {
|
|
|
1997
2824
|
}, allJobs) {
|
|
1998
2825
|
return (needs !== null && needs !== void 0 ? needs : []).map(n => {
|
|
1999
2826
|
var _a;
|
|
2000
|
-
return (0, lodash_es_1.isObject)(n) ? "
|
|
2827
|
+
return (0, lodash_es_1.isObject)(n) ? "global" in n && n.global ?
|
|
2828
|
+
// global jobs (e.g. image builds) keep their plain name
|
|
2829
|
+
{
|
|
2830
|
+
job: n.job,
|
|
2831
|
+
artifacts: n.artifacts,
|
|
2832
|
+
...(n.optional ? {
|
|
2833
|
+
optional: true
|
|
2834
|
+
} : {})
|
|
2835
|
+
} : "workspaceName" in n && n.workspaceName ? {
|
|
2001
2836
|
job: getFullReferencedJobNameFromWorkspace(n.job, n.workspaceName, context.env, allJobs),
|
|
2002
2837
|
artifacts: n.artifacts
|
|
2003
2838
|
} : {
|
|
2004
|
-
job: getFullReferencedJobNameFromComponent(n.job, (_a = n.componentName) !== null && _a !== void 0 ? _a : context.name, context.env, allJobs),
|
|
2839
|
+
job: getFullReferencedJobNameFromComponent(n.job, "componentName" in n ? (_a = n.componentName) !== null && _a !== void 0 ? _a : context.name : context.name, context.env, allJobs),
|
|
2005
2840
|
artifacts: n.artifacts
|
|
2006
2841
|
} : getFullReferencedJobNameFromComponent(n, context.name, context.env, allJobs);
|
|
2007
2842
|
}) // sort in a predictable manner for snapshot tests
|
|
@@ -2014,7 +2849,13 @@ function getGitlabNeedsForComponentJob(context, {
|
|
|
2014
2849
|
function getGitlabNeedsForWorkspaceJob(context, {
|
|
2015
2850
|
needs
|
|
2016
2851
|
}, allJobs) {
|
|
2017
|
-
return (needs !== null && needs !== void 0 ? needs : []).map(n => (0, lodash_es_1.isObject)(n) ? {
|
|
2852
|
+
return (needs !== null && needs !== void 0 ? needs : []).map(n => (0, lodash_es_1.isObject)(n) ? "global" in n && n.global ? {
|
|
2853
|
+
job: n.job,
|
|
2854
|
+
artifacts: n.artifacts,
|
|
2855
|
+
...(n.optional ? {
|
|
2856
|
+
optional: true
|
|
2857
|
+
} : {})
|
|
2858
|
+
} : {
|
|
2018
2859
|
job: getFullReferencedJobNameFromWorkspace(n.job, "workspaceName" in n && n.workspaceName ? n.workspaceName : context.name, context.env, allJobs),
|
|
2019
2860
|
artifacts: n.artifacts
|
|
2020
2861
|
} : getFullReferencedJobNameFromWorkspace(n, context.name, context.env, allJobs)) // sort in a predictable manner for snapshot tests
|
|
@@ -2043,7 +2884,7 @@ const createGitlabPipelineWithDefaults = ({
|
|
|
2043
2884
|
...config
|
|
2044
2885
|
}) => {
|
|
2045
2886
|
return {
|
|
2046
|
-
image: image !== null && image !== void 0 ? image : (0, runner_1.
|
|
2887
|
+
image: image !== null && image !== void 0 ? image : (0, runner_1.getCentralRunnerImageUrl)("jobs-default"),
|
|
2047
2888
|
// default image
|
|
2048
2889
|
variables: {
|
|
2049
2890
|
FF_USE_FASTZIP: "true",
|
|
@@ -2146,7 +2987,7 @@ const getGitlabReleaseJobs = config => {
|
|
|
2146
2987
|
return {
|
|
2147
2988
|
["create release"]: {
|
|
2148
2989
|
stage: "release",
|
|
2149
|
-
image: (0, runner_1.
|
|
2990
|
+
image: (0, runner_1.getCentralRunnerImageUrl)("semantic-release"),
|
|
2150
2991
|
script: ["semanticRelease"],
|
|
2151
2992
|
after_script: [EXPIRED_TOKEN_HELP],
|
|
2152
2993
|
rules: [...baseReleaseRules, {
|
|
@@ -2159,7 +3000,7 @@ const getGitlabReleaseJobs = config => {
|
|
|
2159
3000
|
},
|
|
2160
3001
|
["⚠️ force create release"]: {
|
|
2161
3002
|
stage: "release",
|
|
2162
|
-
image: (0, runner_1.
|
|
3003
|
+
image: (0, runner_1.getCentralRunnerImageUrl)("semantic-release"),
|
|
2163
3004
|
script: ["semanticRelease"],
|
|
2164
3005
|
after_script: [EXPIRED_TOKEN_HELP],
|
|
2165
3006
|
needs: [],
|
|
@@ -2265,7 +3106,7 @@ var __exportStar = this && this.__exportStar || function (m, exports) {
|
|
|
2265
3106
|
Object.defineProperty(exports, "__esModule", ({
|
|
2266
3107
|
value: true
|
|
2267
3108
|
}));
|
|
2268
|
-
exports.getEnabledPipelineTypes = exports.getPipelineBackend = void 0;
|
|
3109
|
+
exports.getEnabledPipelineTypes = exports.getVaultConfig = exports.getPipelineGitRemote = exports.getPipelineOptions = exports.getPipelineBackend = void 0;
|
|
2269
3110
|
const github_1 = __nccwpck_require__(9635);
|
|
2270
3111
|
const gitlab_1 = __nccwpck_require__(8475);
|
|
2271
3112
|
__exportStar(__nccwpck_require__(2474), exports);
|
|
@@ -2283,6 +3124,38 @@ const getPipelineBackend = type => {
|
|
|
2283
3124
|
return createBackend();
|
|
2284
3125
|
};
|
|
2285
3126
|
exports.getPipelineBackend = getPipelineBackend;
|
|
3127
|
+
/**
|
|
3128
|
+
* the options of an enabled pipeline type (empty object when enabled
|
|
3129
|
+
* with `true`)
|
|
3130
|
+
*/
|
|
3131
|
+
const getPipelineOptions = (config, type) => {
|
|
3132
|
+
var _a;
|
|
3133
|
+
const value = (_a = config.pipelines) === null || _a === void 0 ? void 0 : _a[type];
|
|
3134
|
+
return typeof value === "object" ? value : {};
|
|
3135
|
+
};
|
|
3136
|
+
exports.getPipelineOptions = getPipelineOptions;
|
|
3137
|
+
/**
|
|
3138
|
+
* the git remote pointing to the repository of this pipeline type's CI
|
|
3139
|
+
* system (e.g. during a migration, gitlab may be `origin` and github a
|
|
3140
|
+
* second remote)
|
|
3141
|
+
*/
|
|
3142
|
+
const getPipelineGitRemote = (config, type) => {
|
|
3143
|
+
var _a;
|
|
3144
|
+
return (_a = (0, exports.getPipelineOptions)(config, type).gitRemote) !== null && _a !== void 0 ? _a : "origin";
|
|
3145
|
+
};
|
|
3146
|
+
exports.getPipelineGitRemote = getPipelineGitRemote;
|
|
3147
|
+
/**
|
|
3148
|
+
* the normalized secrets vault of a config (string shorthands resolved
|
|
3149
|
+
* to their object form; defaults to the legacy gitlab store)
|
|
3150
|
+
*/
|
|
3151
|
+
const getVaultConfig = config => {
|
|
3152
|
+
var _a, _b;
|
|
3153
|
+
const vault = (_b = (_a = config.secrets) === null || _a === void 0 ? void 0 : _a.vault) !== null && _b !== void 0 ? _b : "gitlab";
|
|
3154
|
+
return typeof vault === "string" ? {
|
|
3155
|
+
type: vault
|
|
3156
|
+
} : vault;
|
|
3157
|
+
};
|
|
3158
|
+
exports.getVaultConfig = getVaultConfig;
|
|
2286
3159
|
/**
|
|
2287
3160
|
* the pipeline types enabled for this config. Multiple types can be
|
|
2288
3161
|
* enabled at once (parallel generation, e.g. during a CI migration).
|
|
@@ -3870,7 +4743,10 @@ const getYarnInstallCommand = async context => {
|
|
|
3870
4743
|
// inline builds make debugging easier as it prints it out in the logs, instead of writing it in temp files
|
|
3871
4744
|
return `yarn install --immutable --inline-builds`;
|
|
3872
4745
|
};
|
|
3873
|
-
const ensureNodeVersion = context => (0, gitlab_1.collapseableSection)("nodeinstall", "Ensure node version")([
|
|
4746
|
+
const ensureNodeVersion = context => (0, gitlab_1.collapseableSection)("nodeinstall", "Ensure node version")([
|
|
4747
|
+
// github actions overrides HOME in container jobs, so also look
|
|
4748
|
+
// for nvm where the catladder images install it (/root/.nvm)
|
|
4749
|
+
'if [ -f "$HOME/.nvm/nvm.sh" ]; then source "$HOME/.nvm/nvm.sh"; elif [ -f /root/.nvm/nvm.sh ]; then export NVM_DIR=/root/.nvm; source /root/.nvm/nvm.sh; fi', "if command -v nvm &> /dev/null && [ -f ./.nvmrc ]; then nvm install; fi"]);
|
|
3874
4750
|
exports.ensureNodeVersion = ensureNodeVersion;
|
|
3875
4751
|
const getYarnInstall = async (context, options) => {
|
|
3876
4752
|
const postInstall = context.type !== "workspace" && context.build.type !== "disabled" && "postInstall" in context.build.config ? context.build.config.postInstall : null;
|
|
@@ -4249,7 +5125,7 @@ Object.defineProperty(exports, "__esModule", ({
|
|
|
4249
5125
|
value: true
|
|
4250
5126
|
}));
|
|
4251
5127
|
exports.DOCKER_REGISTRY = exports.PIPELINE_IMAGE_TAG = void 0;
|
|
4252
|
-
exports.PIPELINE_IMAGE_TAG = "next-
|
|
5128
|
+
exports.PIPELINE_IMAGE_TAG = "next-6a4450e0" || 0;
|
|
4253
5129
|
exports.DOCKER_REGISTRY = "git.panter.ch:5001/catladder/catladder" || 0;
|
|
4254
5130
|
|
|
4255
5131
|
/***/ }),
|
|
@@ -4661,7 +5537,7 @@ const getBasePredefinedVariables = ctx => {
|
|
|
4661
5537
|
};
|
|
4662
5538
|
};
|
|
4663
5539
|
const getEnvironmentVariables = async (ctx, options = {}) => {
|
|
4664
|
-
var _a, _b, _c, _d, _e, _f, _g
|
|
5540
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
4665
5541
|
const environmentContext = (0, getEnvironmentContext_1.getEnvironmentContext)(ctx);
|
|
4666
5542
|
const {
|
|
4667
5543
|
config,
|
|
@@ -4718,13 +5594,13 @@ const getEnvironmentVariables = async (ctx, options = {}) => {
|
|
|
4718
5594
|
}
|
|
4719
5595
|
const publicEnvVarsRaw = (_e = (_d = envConfigRaw.vars) === null || _d === void 0 ? void 0 : _d.public) !== null && _e !== void 0 ? _e : {};
|
|
4720
5596
|
const additionalSecretKeys = deployConfigRaw ? deploy_1.DEPLOY_TYPES[deployConfigRaw.type].additionalSecretKeys(environmentContext) : [];
|
|
4721
|
-
const secretEnvVarKeys = [...(0, envVars_1.
|
|
5597
|
+
const secretEnvVarKeys = [...(0, envVars_1.normalizeSecretVarsConfig)((_f = envConfigRaw.vars) === null || _f === void 0 ? void 0 : _f.secret), ...additionalSecretKeys];
|
|
4722
5598
|
const secretEnvVars = (0, envVars_1.makeSecretEnvVarMapping)(env, componentName, secretEnvVarKeys);
|
|
4723
5599
|
const publicEnvVarsRawSanitized = (0, envVars_1.stringifyValues)(publicEnvVarsRaw);
|
|
4724
5600
|
const publicEnvVarsUnresolved = Object.fromEntries(Object.entries(publicEnvVarsRawSanitized).map(([key, value]) => [key, (0, VariableValueContainingReferences_1.createVariableValueContainingReferencesFromString)(value, {
|
|
4725
5601
|
componentName: ctx.componentName
|
|
4726
5602
|
})]));
|
|
4727
|
-
const publicEnvVars = ((
|
|
5603
|
+
const publicEnvVars = ((_g = options.shouldResolveReferences) !== null && _g !== void 0 ? _g : true) ? await (0, resolveAllReferences_1.resolveAllReferences)(publicEnvVarsUnresolved, async otherComponentName => {
|
|
4728
5604
|
const {
|
|
4729
5605
|
envVars: otherEnvVars
|
|
4730
5606
|
} = await (0, exports.getEnvironmentVariables)({
|
|
@@ -4884,7 +5760,7 @@ const envVars_1 = __nccwpck_require__(4946);
|
|
|
4884
5760
|
* @returns
|
|
4885
5761
|
*/
|
|
4886
5762
|
const transformJobOnlyVars = async (env, componentName, vars) => {
|
|
4887
|
-
var _a
|
|
5763
|
+
var _a;
|
|
4888
5764
|
if (!vars) {
|
|
4889
5765
|
return {
|
|
4890
5766
|
envVars: {},
|
|
@@ -4892,7 +5768,7 @@ const transformJobOnlyVars = async (env, componentName, vars) => {
|
|
|
4892
5768
|
};
|
|
4893
5769
|
}
|
|
4894
5770
|
const publicVars = (0, envVars_1.stringifyValues)((_a = vars === null || vars === void 0 ? void 0 : vars.public) !== null && _a !== void 0 ? _a : {});
|
|
4895
|
-
const secretEnvVarKeys = (0, envVars_1.
|
|
5771
|
+
const secretEnvVarKeys = (0, envVars_1.normalizeSecretVarsConfig)(vars === null || vars === void 0 ? void 0 : vars.secret);
|
|
4896
5772
|
const deployJobOnlySecretEnvVars = (vars === null || vars === void 0 ? void 0 : vars.secret) ? (0, envVars_1.makeSecretEnvVarMapping)(env, componentName, secretEnvVarKeys) : {};
|
|
4897
5773
|
const envVars = {
|
|
4898
5774
|
...deployJobOnlySecretEnvVars,
|
|
@@ -4916,7 +5792,7 @@ exports.transformJobOnlyVars = transformJobOnlyVars;
|
|
|
4916
5792
|
Object.defineProperty(exports, "__esModule", ({
|
|
4917
5793
|
value: true
|
|
4918
5794
|
}));
|
|
4919
|
-
exports.makeSecretEnvVarMapping = exports.stringListToSecreteEnvVarList = exports.stringifyValues = void 0;
|
|
5795
|
+
exports.makeSecretEnvVarMapping = exports.normalizeSecretVarsConfig = exports.stringListToSecreteEnvVarList = exports.stringifyValues = void 0;
|
|
4920
5796
|
const lodash_es_1 = __nccwpck_require__(4284);
|
|
4921
5797
|
const getEnvironmentVariables_1 = __nccwpck_require__(5855);
|
|
4922
5798
|
const BashExpression_1 = __nccwpck_require__(5354);
|
|
@@ -4926,6 +5802,27 @@ const stringListToSecreteEnvVarList = keys => keys.map(key => ({
|
|
|
4926
5802
|
key
|
|
4927
5803
|
}));
|
|
4928
5804
|
exports.stringListToSecreteEnvVarList = stringListToSecreteEnvVarList;
|
|
5805
|
+
/**
|
|
5806
|
+
* normalizes both config forms of vault-stored env vars: the deprecated
|
|
5807
|
+
* plain string[] (all keys secret) and the record form carrying a kind
|
|
5808
|
+
* (or config object) per key
|
|
5809
|
+
*/
|
|
5810
|
+
const normalizeSecretVarsConfig = secret => {
|
|
5811
|
+
if (!secret) {
|
|
5812
|
+
return [];
|
|
5813
|
+
}
|
|
5814
|
+
if (Array.isArray(secret)) {
|
|
5815
|
+
return (0, exports.stringListToSecreteEnvVarList)(secret);
|
|
5816
|
+
}
|
|
5817
|
+
return Object.entries(secret).map(([key, config]) => typeof config === "string" ? {
|
|
5818
|
+
key,
|
|
5819
|
+
kind: config
|
|
5820
|
+
} : {
|
|
5821
|
+
key,
|
|
5822
|
+
...config
|
|
5823
|
+
});
|
|
5824
|
+
};
|
|
5825
|
+
exports.normalizeSecretVarsConfig = normalizeSecretVarsConfig;
|
|
4929
5826
|
const makeSecretEnvVarMapping = (env, componentName, secretEnvVars) => {
|
|
4930
5827
|
return Object.fromEntries(secretEnvVars.map(({
|
|
4931
5828
|
key
|
|
@@ -4935,6 +5832,330 @@ exports.makeSecretEnvVarMapping = makeSecretEnvVarMapping;
|
|
|
4935
5832
|
|
|
4936
5833
|
/***/ }),
|
|
4937
5834
|
|
|
5835
|
+
/***/ 3231:
|
|
5836
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
5837
|
+
|
|
5838
|
+
"use strict";
|
|
5839
|
+
|
|
5840
|
+
|
|
5841
|
+
Object.defineProperty(exports, "__esModule", ({
|
|
5842
|
+
value: true
|
|
5843
|
+
}));
|
|
5844
|
+
exports.computeCustomImageHash = void 0;
|
|
5845
|
+
const crypto_1 = __nccwpck_require__(6982);
|
|
5846
|
+
const fs_1 = __nccwpck_require__(9896);
|
|
5847
|
+
const path_1 = __nccwpck_require__(6928);
|
|
5848
|
+
const IGNORED_FILES = new Set([".DS_Store", "Thumbs.db"]);
|
|
5849
|
+
const isIgnoredFile = path => {
|
|
5850
|
+
var _a;
|
|
5851
|
+
return IGNORED_FILES.has((_a = path.split("/").pop()) !== null && _a !== void 0 ? _a : "");
|
|
5852
|
+
};
|
|
5853
|
+
function listFilesRecursive(dir) {
|
|
5854
|
+
const resolved = (0, path_1.resolve)(dir);
|
|
5855
|
+
const entries = (0, fs_1.readdirSync)(resolved, {
|
|
5856
|
+
recursive: true,
|
|
5857
|
+
encoding: "utf-8"
|
|
5858
|
+
});
|
|
5859
|
+
return entries.filter(entry => {
|
|
5860
|
+
if (isIgnoredFile(entry)) {
|
|
5861
|
+
// OS junk files exist locally but not in CI checkouts — they
|
|
5862
|
+
// must never influence the content hash
|
|
5863
|
+
return false;
|
|
5864
|
+
}
|
|
5865
|
+
const fullPath = (0, path_1.join)(resolved, entry);
|
|
5866
|
+
return (0, fs_1.statSync)(fullPath).isFile();
|
|
5867
|
+
}).sort();
|
|
5868
|
+
}
|
|
5869
|
+
function computeCustomImageHash(config) {
|
|
5870
|
+
var _a;
|
|
5871
|
+
const hash = (0, crypto_1.createHash)("sha256");
|
|
5872
|
+
const watchedPaths = [];
|
|
5873
|
+
// Hash all files in the dir (includes the Dockerfile and any context files)
|
|
5874
|
+
const dirFiles = listFilesRecursive(config.dir);
|
|
5875
|
+
for (const file of dirFiles) {
|
|
5876
|
+
const fullPath = (0, path_1.join)((0, path_1.resolve)(config.dir), file);
|
|
5877
|
+
hash.update(file); // include relative path for disambiguation
|
|
5878
|
+
hash.update((0, fs_1.readFileSync)(fullPath));
|
|
5879
|
+
}
|
|
5880
|
+
watchedPaths.push(`${config.dir}/**/*`);
|
|
5881
|
+
// extra dirs (e.g. included base image definitions)
|
|
5882
|
+
for (const extraDir of (_a = config.extraDirs) !== null && _a !== void 0 ? _a : []) {
|
|
5883
|
+
for (const file of listFilesRecursive(extraDir)) {
|
|
5884
|
+
hash.update(file);
|
|
5885
|
+
hash.update((0, fs_1.readFileSync)((0, path_1.join)((0, path_1.resolve)(extraDir), file)));
|
|
5886
|
+
}
|
|
5887
|
+
watchedPaths.push(`${extraDir}/**/*`);
|
|
5888
|
+
}
|
|
5889
|
+
// Hash extra paths (for files outside the dir)
|
|
5890
|
+
if (config.hashExtraPaths) {
|
|
5891
|
+
// Extra paths are literal file paths (not globs) for simplicity
|
|
5892
|
+
const extraFiles = [...config.hashExtraPaths].sort();
|
|
5893
|
+
for (const file of extraFiles) {
|
|
5894
|
+
hash.update(file);
|
|
5895
|
+
hash.update((0, fs_1.readFileSync)(file));
|
|
5896
|
+
}
|
|
5897
|
+
watchedPaths.push(...config.hashExtraPaths);
|
|
5898
|
+
}
|
|
5899
|
+
// Hash build args (sorted keys for determinism)
|
|
5900
|
+
if (config.buildArgs) {
|
|
5901
|
+
const sorted = Object.entries(config.buildArgs).sort(([a], [b]) => a.localeCompare(b));
|
|
5902
|
+
hash.update(JSON.stringify(sorted));
|
|
5903
|
+
}
|
|
5904
|
+
return {
|
|
5905
|
+
hash: hash.digest("hex").slice(0, 12),
|
|
5906
|
+
watchedPaths
|
|
5907
|
+
};
|
|
5908
|
+
}
|
|
5909
|
+
exports.computeCustomImageHash = computeCustomImageHash;
|
|
5910
|
+
|
|
5911
|
+
/***/ }),
|
|
5912
|
+
|
|
5913
|
+
/***/ 1585:
|
|
5914
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
5915
|
+
|
|
5916
|
+
"use strict";
|
|
5917
|
+
|
|
5918
|
+
|
|
5919
|
+
Object.defineProperty(exports, "__esModule", ({
|
|
5920
|
+
value: true
|
|
5921
|
+
}));
|
|
5922
|
+
exports.JobImagesPlan = exports.getJobImagesMode = exports.GENERATED_IMAGES_FOLDER = void 0;
|
|
5923
|
+
const fs_1 = __nccwpck_require__(9896);
|
|
5924
|
+
const path_1 = __nccwpck_require__(6928);
|
|
5925
|
+
const ciVariables_1 = __nccwpck_require__(4489);
|
|
5926
|
+
const docker_1 = __nccwpck_require__(2764);
|
|
5927
|
+
const constants_1 = __nccwpck_require__(3480);
|
|
5928
|
+
const runner_1 = __nccwpck_require__(2348);
|
|
5929
|
+
const gitlab_1 = __nccwpck_require__(3468);
|
|
5930
|
+
const hash_1 = __nccwpck_require__(3231);
|
|
5931
|
+
const shippedImages_1 = __nccwpck_require__(7734);
|
|
5932
|
+
exports.GENERATED_IMAGES_FOLDER = ".catladder-generated/images";
|
|
5933
|
+
/**
|
|
5934
|
+
* the official docker cli image used to build the job images — NOT a
|
|
5935
|
+
* catladder image, so building images never depends on one (bootstrap)
|
|
5936
|
+
*/
|
|
5937
|
+
const BUILDER_IMAGE = "docker.io/docker:29.5.1";
|
|
5938
|
+
const getJobImagesMode = (config, pipelineType) => {
|
|
5939
|
+
var _a;
|
|
5940
|
+
// the central registry is not reachable from github runners
|
|
5941
|
+
if (pipelineType === "github" && config.jobImages === "central") {
|
|
5942
|
+
throw new Error(`jobImages: "central" is not supported on github: catladder's central registry (${constants_1.DOCKER_REGISTRY}) is unreachable from github runners. Use "repo" (the default) instead.`);
|
|
5943
|
+
}
|
|
5944
|
+
return (_a = config.jobImages) !== null && _a !== void 0 ? _a : pipelineType === "github" ? "repo" : "central";
|
|
5945
|
+
};
|
|
5946
|
+
exports.getJobImagesMode = getJobImagesMode;
|
|
5947
|
+
const ensureJobName = name => `🐳 job image ${name}`;
|
|
5948
|
+
/**
|
|
5949
|
+
* plans the catladder job images of one backend run: resolves image
|
|
5950
|
+
* references, and (in repo mode) collects the image build jobs and the
|
|
5951
|
+
* image definitions to materialize into the generated files.
|
|
5952
|
+
*
|
|
5953
|
+
* Reference-driven: only images actually used by a job are built.
|
|
5954
|
+
*/
|
|
5955
|
+
class JobImagesPlan {
|
|
5956
|
+
constructor(mode, pipelineType) {
|
|
5957
|
+
this.mode = mode;
|
|
5958
|
+
this.pipelineType = pipelineType;
|
|
5959
|
+
this.used = new Map();
|
|
5960
|
+
}
|
|
5961
|
+
/**
|
|
5962
|
+
* resolves a job image (marker or concrete) to a concrete image url
|
|
5963
|
+
* plus the build job dependency in repo mode
|
|
5964
|
+
*/
|
|
5965
|
+
resolve(image) {
|
|
5966
|
+
if (!(0, runner_1.isCatladderImageRef)(image)) {
|
|
5967
|
+
return {
|
|
5968
|
+
image
|
|
5969
|
+
};
|
|
5970
|
+
}
|
|
5971
|
+
return this.resolveRef(image);
|
|
5972
|
+
}
|
|
5973
|
+
resolveRef(ref) {
|
|
5974
|
+
const name = ref.catladderImage;
|
|
5975
|
+
if (this.mode === "central" || shippedImages_1.CENTRAL_ONLY_IMAGES.has(name)) {
|
|
5976
|
+
return {
|
|
5977
|
+
image: (0, runner_1.getCentralRunnerImageUrl)(name)
|
|
5978
|
+
};
|
|
5979
|
+
}
|
|
5980
|
+
const {
|
|
5981
|
+
hash
|
|
5982
|
+
} = this.use(name);
|
|
5983
|
+
return {
|
|
5984
|
+
image: `${this.registryImageRef()}/catladder/${name}:${hash}`,
|
|
5985
|
+
fromRepoRegistry: true,
|
|
5986
|
+
need: {
|
|
5987
|
+
job: ensureJobName(name),
|
|
5988
|
+
artifacts: false,
|
|
5989
|
+
optional: true,
|
|
5990
|
+
global: true
|
|
5991
|
+
}
|
|
5992
|
+
};
|
|
5993
|
+
}
|
|
5994
|
+
/**
|
|
5995
|
+
* the registry image prefix. On github, container images can't use
|
|
5996
|
+
* runtime env vars — the expression form is required.
|
|
5997
|
+
*/
|
|
5998
|
+
registryImageRef() {
|
|
5999
|
+
return this.pipelineType === "github" ? "ghcr.io/${{ github.repository }}" : `${(0, ciVariables_1.getCiVariable)({
|
|
6000
|
+
pipelineType: this.pipelineType
|
|
6001
|
+
}, "registryImage")}`;
|
|
6002
|
+
}
|
|
6003
|
+
use(name) {
|
|
6004
|
+
var _a;
|
|
6005
|
+
const existing = this.used.get(name);
|
|
6006
|
+
if (existing) {
|
|
6007
|
+
return existing;
|
|
6008
|
+
}
|
|
6009
|
+
const dependencies = (_a = shippedImages_1.RUNNER_IMAGE_DEPENDENCIES[name]) !== null && _a !== void 0 ? _a : [];
|
|
6010
|
+
// dependencies are materialized (and hashed) as part of this image,
|
|
6011
|
+
// but also usable standalone
|
|
6012
|
+
dependencies.forEach(dependency => this.use(dependency));
|
|
6013
|
+
const {
|
|
6014
|
+
hash
|
|
6015
|
+
} = (0, hash_1.computeCustomImageHash)({
|
|
6016
|
+
dir: (0, shippedImages_1.getShippedImageDir)(name),
|
|
6017
|
+
extraDirs: dependencies.map(dependency => (0, shippedImages_1.getShippedImageDir)(dependency))
|
|
6018
|
+
});
|
|
6019
|
+
const entry = {
|
|
6020
|
+
hash
|
|
6021
|
+
};
|
|
6022
|
+
this.used.set(name, entry);
|
|
6023
|
+
return entry;
|
|
6024
|
+
}
|
|
6025
|
+
/**
|
|
6026
|
+
* the image build jobs for all used images (repo mode; empty in
|
|
6027
|
+
* central mode)
|
|
6028
|
+
*/
|
|
6029
|
+
getEnsureJobs() {
|
|
6030
|
+
return [...this.used.entries()].map(([name, {
|
|
6031
|
+
hash
|
|
6032
|
+
}]) => this.createEnsureJob(name, hash));
|
|
6033
|
+
}
|
|
6034
|
+
createEnsureJob(name, hash) {
|
|
6035
|
+
var _a;
|
|
6036
|
+
const ctx = {
|
|
6037
|
+
pipelineType: this.pipelineType
|
|
6038
|
+
};
|
|
6039
|
+
const registryUser = (0, ciVariables_1.getCiVariable)(ctx, "registryUser");
|
|
6040
|
+
const jobToken = (0, ciVariables_1.getCiVariable)(ctx, "jobToken");
|
|
6041
|
+
const registry = (0, ciVariables_1.getCiVariable)(ctx, "registry");
|
|
6042
|
+
const imageRef = `${this.registryImageRef()}/catladder/${name}:${hash}`;
|
|
6043
|
+
const watchedDirs = [name, ...((_a = shippedImages_1.RUNNER_IMAGE_DEPENDENCIES[name]) !== null && _a !== void 0 ? _a : [])];
|
|
6044
|
+
const {
|
|
6045
|
+
services,
|
|
6046
|
+
runnerVariables
|
|
6047
|
+
} = (0, docker_1.getDockerJobBaseProps)();
|
|
6048
|
+
return {
|
|
6049
|
+
name: ensureJobName(name),
|
|
6050
|
+
stage: "setup",
|
|
6051
|
+
image: BUILDER_IMAGE,
|
|
6052
|
+
services,
|
|
6053
|
+
runnerVariables,
|
|
6054
|
+
needs: [],
|
|
6055
|
+
// gitlab: only run when the image definition changed; github has
|
|
6056
|
+
// no equivalent and always runs (the existence check is fast)
|
|
6057
|
+
rules: [{
|
|
6058
|
+
changes: watchedDirs.map(dir => `${exports.GENERATED_IMAGES_FOLDER}/${dir}/**/*`)
|
|
6059
|
+
}],
|
|
6060
|
+
variables: {},
|
|
6061
|
+
script: [...(0, gitlab_1.collapseableSection)("docker-login", "Docker Login")([`docker login --username ${registryUser} --password ${jobToken} ${registry}`]), ...(0, gitlab_1.collapseableSection)("check-image", "Checking if image exists")([`if docker manifest inspect ${imageRef} > /dev/null 2>&1; then`, ` echo "Image ${imageRef} already exists, skipping build"`, ` exit 0`, `fi`]), ...(0, gitlab_1.collapseableSection)("docker-build", "Building image")([`DOCKER_BUILDKIT=1 docker build -t ${imageRef} -f ${exports.GENERATED_IMAGES_FOLDER}/${name}/Dockerfile ${shippedImages_1.RUNNER_IMAGE_BUILD_CONTEXT[name] === "root" ? exports.GENERATED_IMAGES_FOLDER : `${exports.GENERATED_IMAGES_FOLDER}/${name}`}`]), ...(0, gitlab_1.collapseableSection)("docker-push", "Pushing image")([`docker push ${imageRef}`])]
|
|
6062
|
+
};
|
|
6063
|
+
}
|
|
6064
|
+
/**
|
|
6065
|
+
* the image definitions of all used images, materialized into the
|
|
6066
|
+
* generated files (so pipelines build from committed, reviewable
|
|
6067
|
+
* files and gitlab's rules:changes can watch them)
|
|
6068
|
+
*/
|
|
6069
|
+
getGeneratedFiles() {
|
|
6070
|
+
return [...this.used.keys()].flatMap(name => {
|
|
6071
|
+
const dir = (0, shippedImages_1.getShippedImageDir)(name);
|
|
6072
|
+
return listFilesRecursive(dir).map(file => ({
|
|
6073
|
+
path: (0, path_1.join)(exports.GENERATED_IMAGES_FOLDER, name, file),
|
|
6074
|
+
content: (0, fs_1.readFileSync)((0, path_1.join)(dir, file), "utf-8")
|
|
6075
|
+
}));
|
|
6076
|
+
});
|
|
6077
|
+
}
|
|
6078
|
+
}
|
|
6079
|
+
exports.JobImagesPlan = JobImagesPlan;
|
|
6080
|
+
const IGNORED_FILES = new Set([".DS_Store", "Thumbs.db"]);
|
|
6081
|
+
const listFilesRecursive = dir => (0, fs_1.readdirSync)(dir, {
|
|
6082
|
+
recursive: true,
|
|
6083
|
+
encoding: "utf-8"
|
|
6084
|
+
}).filter(entry => {
|
|
6085
|
+
var _a;
|
|
6086
|
+
// OS junk files exist locally but not in CI checkouts
|
|
6087
|
+
return !IGNORED_FILES.has((_a = entry.split("/").pop()) !== null && _a !== void 0 ? _a : "") && (0, fs_1.statSync)((0, path_1.join)(dir, entry)).isFile();
|
|
6088
|
+
}).sort();
|
|
6089
|
+
|
|
6090
|
+
/***/ }),
|
|
6091
|
+
|
|
6092
|
+
/***/ 7734:
|
|
6093
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
6094
|
+
|
|
6095
|
+
"use strict";
|
|
6096
|
+
|
|
6097
|
+
|
|
6098
|
+
Object.defineProperty(exports, "__esModule", ({
|
|
6099
|
+
value: true
|
|
6100
|
+
}));
|
|
6101
|
+
exports.getShippedImageDir = exports.getShippedImagesDir = exports.RUNNER_IMAGE_BUILD_CONTEXT = exports.CENTRAL_ONLY_IMAGES = exports.RUNNER_IMAGE_DEPENDENCIES = void 0;
|
|
6102
|
+
const fs_1 = __nccwpck_require__(9896);
|
|
6103
|
+
const path_1 = __nccwpck_require__(6928);
|
|
6104
|
+
/**
|
|
6105
|
+
* images whose Dockerfile INCLUDEs another image's Dockerfile
|
|
6106
|
+
* (dockerfile-x/dockerfile-plus, resolved against the images root as
|
|
6107
|
+
* build context)
|
|
6108
|
+
*/
|
|
6109
|
+
exports.RUNNER_IMAGE_DEPENDENCIES = {
|
|
6110
|
+
"jobs-meteor": ["jobs-default"],
|
|
6111
|
+
"jobs-testing-chrome": ["jobs-default"]
|
|
6112
|
+
};
|
|
6113
|
+
/**
|
|
6114
|
+
* the docker build context of each image, mirroring the central image
|
|
6115
|
+
* builds: the jobs family builds from the images root (their
|
|
6116
|
+
* Dockerfiles INCLUDE sibling images), the others from their own dir
|
|
6117
|
+
* (their COPY paths are relative to it)
|
|
6118
|
+
*/
|
|
6119
|
+
/**
|
|
6120
|
+
* images that cannot be built from the shipped definitions and always
|
|
6121
|
+
* come from the central registry: semantic-release bakes catladder's
|
|
6122
|
+
* own cli sources into the image (repo-root build context).
|
|
6123
|
+
* TODO: make the semantic-release image self-contained.
|
|
6124
|
+
*/
|
|
6125
|
+
exports.CENTRAL_ONLY_IMAGES = new Set(["semantic-release"]);
|
|
6126
|
+
exports.RUNNER_IMAGE_BUILD_CONTEXT = {
|
|
6127
|
+
"jobs-default": "root",
|
|
6128
|
+
"jobs-meteor": "root",
|
|
6129
|
+
"jobs-testing-chrome": "root",
|
|
6130
|
+
kubernetes: "self",
|
|
6131
|
+
"docker-build": "self",
|
|
6132
|
+
gcloud: "self",
|
|
6133
|
+
"semantic-release": "self",
|
|
6134
|
+
"agent-claude": "self"
|
|
6135
|
+
};
|
|
6136
|
+
/**
|
|
6137
|
+
* the directory containing the image definitions shipped with the
|
|
6138
|
+
* package (copied into dist at build time; the repository layout is
|
|
6139
|
+
* the fallback for development and tests)
|
|
6140
|
+
*/
|
|
6141
|
+
const getShippedImagesDir = () => {
|
|
6142
|
+
const candidates = [
|
|
6143
|
+
// built package: dist/customImages -> dist/runner-images
|
|
6144
|
+
(0, path_1.join)(__dirname, "..", "runner-images"),
|
|
6145
|
+
// repository: pipeline/src/customImages -> <root>/runner-images
|
|
6146
|
+
(0, path_1.join)(__dirname, "..", "..", "..", "runner-images")];
|
|
6147
|
+
const found = candidates.find(candidate => (0, fs_1.existsSync)(candidate));
|
|
6148
|
+
if (!found) {
|
|
6149
|
+
throw new Error("shipped job image definitions not found");
|
|
6150
|
+
}
|
|
6151
|
+
return found;
|
|
6152
|
+
};
|
|
6153
|
+
exports.getShippedImagesDir = getShippedImagesDir;
|
|
6154
|
+
const getShippedImageDir = name => (0, path_1.join)((0, exports.getShippedImagesDir)(), name);
|
|
6155
|
+
exports.getShippedImageDir = getShippedImageDir;
|
|
6156
|
+
|
|
6157
|
+
/***/ }),
|
|
6158
|
+
|
|
4938
6159
|
/***/ 4628:
|
|
4939
6160
|
/***/ ((__unused_webpack_module, exports) => {
|
|
4940
6161
|
|
|
@@ -6154,13 +7375,18 @@ exports.GCLOUD_RUN_DEPLOY_TYPE = {
|
|
|
6154
7375
|
}
|
|
6155
7376
|
return {};
|
|
6156
7377
|
},
|
|
6157
|
-
additionalSecretKeys: ctx => [
|
|
7378
|
+
additionalSecretKeys: ctx => [
|
|
7379
|
+
// deploy-time credentials don't exist for the local env
|
|
7380
|
+
...(ctx.envType !== "local" ? [{
|
|
6158
7381
|
key: exports.GCLOUD_DEPLOY_CREDENTIALS_KEY,
|
|
6159
7382
|
hidden: true
|
|
6160
7383
|
}, {
|
|
6161
7384
|
key: exports.GCLOUD_RUN_CANONICAL_HOST_SUFFIX,
|
|
6162
|
-
hidden: true
|
|
6163
|
-
|
|
7385
|
+
hidden: true,
|
|
7386
|
+
// a public url fragment, not sensitive: masking it would
|
|
7387
|
+
// suppress environment urls on github and break log links
|
|
7388
|
+
kind: "variable"
|
|
7389
|
+
}] : []), ...(ctx.deployConfigRaw && ctx.deployConfigRaw.cloudSql ? [{
|
|
6164
7390
|
key: "DB_PASSWORD"
|
|
6165
7391
|
}] : [])],
|
|
6166
7392
|
getAdditionalEnvVars: ctx => {
|
|
@@ -6168,7 +7394,8 @@ exports.GCLOUD_RUN_DEPLOY_TYPE = {
|
|
|
6168
7394
|
fullName,
|
|
6169
7395
|
env,
|
|
6170
7396
|
componentName,
|
|
6171
|
-
deployConfigRaw
|
|
7397
|
+
deployConfigRaw,
|
|
7398
|
+
envType
|
|
6172
7399
|
} = ctx;
|
|
6173
7400
|
const HOSTNAME_INTERNAL = (0, BashExpression_1.joinBashExpressions)([fullName, (0, BashExpression_1.getBashVariable)((0, context_1.getSecretVarName)(env, componentName, exports.GCLOUD_RUN_CANONICAL_HOST_SUFFIX))], "-").toLowerCase();
|
|
6174
7401
|
const jobTriggers = deployConfigRaw && deployConfigRaw.jobs ? Object.fromEntries(Object.entries(deployConfigRaw.jobs).filter(([name, job]) => Boolean(job)).map(([name, job]) => ["CLOUD_RUN_JOB_TRIGGER_URL_" + (0, gitlab_1.sanitizeForBashVariable)(name), (0, cloudRunExecutionUrl_1.getCloudRunJobExecuteUrl)(name, {
|
|
@@ -6177,7 +7404,11 @@ exports.GCLOUD_RUN_DEPLOY_TYPE = {
|
|
|
6177
7404
|
region: deployConfigRaw.region
|
|
6178
7405
|
})])) : {};
|
|
6179
7406
|
return {
|
|
6180
|
-
|
|
7407
|
+
// references the canonical host suffix secret, which doesn't
|
|
7408
|
+
// exist for the local env
|
|
7409
|
+
...(envType !== "local" ? {
|
|
7410
|
+
HOSTNAME_INTERNAL
|
|
7411
|
+
} : {}),
|
|
6181
7412
|
...getCloudSqlVariables(ctx),
|
|
6182
7413
|
...jobTriggers,
|
|
6183
7414
|
DEPLOY_CLOUD_RUN_SERVICE_NAME: (0, getServiceName_1.getServiceNameForEnvContext)(ctx),
|
|
@@ -6270,7 +7501,10 @@ const getDatabaseDeleteScript = (context, deployConfig) => {
|
|
|
6270
7501
|
// unfortunatly the database cannot be deleted right after the service has stopped, as it might still have connections
|
|
6271
7502
|
// we have to repeate this process
|
|
6272
7503
|
return [`echo "deleting database ${DB_NAME}..."`, `echo "👆 this can take multiple attemps (3-5min), because google cloud run may still have a connection to the database after the cloud run service is shut down"`, (0, gitlab_1.repeatOnFailure)(`gcloud sql databases delete ${DB_NAME} --instance=${instanceId} --project ${projectId}`, {
|
|
6273
|
-
pauseInSeconds: 10
|
|
7504
|
+
pauseInSeconds: 10,
|
|
7505
|
+
// connections normally clear within 3-5min; anything beyond is
|
|
7506
|
+
// a permanent error (missing permission, wrong instance, ...)
|
|
7507
|
+
maxAttempts: 30
|
|
6274
7508
|
})];
|
|
6275
7509
|
};
|
|
6276
7510
|
exports.getDatabaseDeleteScript = getDatabaseDeleteScript;
|
|
@@ -7994,6 +9228,7 @@ const promises_1 = __nccwpck_require__(1943);
|
|
|
7994
9228
|
const path_1 = __nccwpck_require__(6928);
|
|
7995
9229
|
const backends_1 = __nccwpck_require__(3243);
|
|
7996
9230
|
const gitlab_1 = __nccwpck_require__(8475);
|
|
9231
|
+
const jobImagesPlan_1 = __nccwpck_require__(1585);
|
|
7997
9232
|
/**
|
|
7998
9233
|
* generates the pipeline files of all pipeline types enabled in the
|
|
7999
9234
|
* config (see `pipelines`). Pass an explicit `pipelineType` to generate
|
|
@@ -8001,6 +9236,16 @@ const gitlab_1 = __nccwpck_require__(8475);
|
|
|
8001
9236
|
*/
|
|
8002
9237
|
async function generatePipelineFiles(context, pipelineType) {
|
|
8003
9238
|
const pipelineTypes = pipelineType ? [pipelineType] : (0, backends_1.getEnabledPipelineTypes)(context.config);
|
|
9239
|
+
if (!pipelineType) {
|
|
9240
|
+
// the materialized image definitions are a union across all enabled
|
|
9241
|
+
// backends and no single backend may wipe them — cleaned once per
|
|
9242
|
+
// full generation, so images that fell out of use don't linger (and
|
|
9243
|
+
// keep triggering gitlab's rules:changes)
|
|
9244
|
+
await (0, promises_1.rm)(jobImagesPlan_1.GENERATED_IMAGES_FOLDER, {
|
|
9245
|
+
recursive: true,
|
|
9246
|
+
force: true
|
|
9247
|
+
});
|
|
9248
|
+
}
|
|
8004
9249
|
for (const type of pipelineTypes) {
|
|
8005
9250
|
await generatePipelineFilesForBackend(context, (0, backends_1.getPipelineBackend)(type));
|
|
8006
9251
|
}
|
|
@@ -8018,7 +9263,11 @@ async function generatePipelineFilesForBackend(context, backend) {
|
|
|
8018
9263
|
await (0, promises_1.mkdir)((0, path_1.dirname)(path), {
|
|
8019
9264
|
recursive: true
|
|
8020
9265
|
});
|
|
8021
|
-
|
|
9266
|
+
if (typeof content === "string") {
|
|
9267
|
+
await context.fileWriter.writeGeneratedFileRaw(path, content);
|
|
9268
|
+
} else {
|
|
9269
|
+
await context.fileWriter.writeYamlfile(path, content);
|
|
9270
|
+
}
|
|
8022
9271
|
}));
|
|
8023
9272
|
}
|
|
8024
9273
|
/**
|
|
@@ -8374,10 +9623,23 @@ exports.RULE_CONDITION_HOTFIX_BRANCH = "$CI_COMMIT_BRANCH =~ /^[0-9]+.([0-9]+|x)
|
|
|
8374
9623
|
Object.defineProperty(exports, "__esModule", ({
|
|
8375
9624
|
value: true
|
|
8376
9625
|
}));
|
|
8377
|
-
exports.getRunnerImage = void 0;
|
|
9626
|
+
exports.getCentralRunnerImageUrl = exports.getRunnerImage = exports.isCatladderImageRef = void 0;
|
|
8378
9627
|
const constants_1 = __nccwpck_require__(3480);
|
|
8379
|
-
const
|
|
9628
|
+
const isCatladderImageRef = value => typeof value === "object" && value !== null && "catladderImage" in value && typeof value.catladderImage === "string";
|
|
9629
|
+
exports.isCatladderImageRef = isCatladderImageRef;
|
|
9630
|
+
/**
|
|
9631
|
+
* job creators use this to reference a catladder-provided job image;
|
|
9632
|
+
* the backends resolve it to a concrete image url
|
|
9633
|
+
*/
|
|
9634
|
+
const getRunnerImage = imageName => ({
|
|
9635
|
+
catladderImage: imageName
|
|
9636
|
+
});
|
|
8380
9637
|
exports.getRunnerImage = getRunnerImage;
|
|
9638
|
+
/**
|
|
9639
|
+
* the image url in catladder's central registry (the classic behavior)
|
|
9640
|
+
*/
|
|
9641
|
+
const getCentralRunnerImageUrl = imageName => constants_1.DOCKER_REGISTRY + "/" + imageName + ":" + constants_1.PIPELINE_IMAGE_TAG;
|
|
9642
|
+
exports.getCentralRunnerImageUrl = getCentralRunnerImageUrl;
|
|
8381
9643
|
|
|
8382
9644
|
/***/ }),
|
|
8383
9645
|
|
|
@@ -8592,8 +9854,14 @@ const sanitizeForBashVariable = name => name.replace(/-/g, "_");
|
|
|
8592
9854
|
exports.sanitizeForBashVariable = sanitizeForBashVariable;
|
|
8593
9855
|
const repeatOnFailure = (command, options) => {
|
|
8594
9856
|
return `
|
|
9857
|
+
_attempt=0
|
|
8595
9858
|
until ${command}
|
|
8596
9859
|
do
|
|
9860
|
+
_attempt=$((_attempt+1))
|
|
9861
|
+
if [ "$_attempt" -ge ${options.maxAttempts} ]; then
|
|
9862
|
+
echo "giving up after ${options.maxAttempts} attempts"
|
|
9863
|
+
exit 1
|
|
9864
|
+
fi
|
|
8597
9865
|
echo "Trying again."
|
|
8598
9866
|
sleep ${options.pauseInSeconds}
|
|
8599
9867
|
done
|
|
@@ -8781,6 +10049,14 @@ class FileWriter {
|
|
|
8781
10049
|
extension: (_b = path.split(".").pop()) !== null && _b !== void 0 ? _b : ""
|
|
8782
10050
|
};
|
|
8783
10051
|
}
|
|
10052
|
+
/**
|
|
10053
|
+
* writes content verbatim (no auto-generated header) — e.g. for
|
|
10054
|
+
* materialized dockerfiles, where a leading comment would break
|
|
10055
|
+
* parser directives like `# syntax = ...`
|
|
10056
|
+
*/
|
|
10057
|
+
async writeGeneratedFileRaw(path, content) {
|
|
10058
|
+
await this.writeTheFile(path, content);
|
|
10059
|
+
}
|
|
8784
10060
|
async writeGeneratedFile(path, content, options) {
|
|
8785
10061
|
await this.writeTheFile(path, [this.getAutoGeneratedHeader(options.commentChar), content].join("\n"));
|
|
8786
10062
|
}
|