@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
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/******/ var __webpack_modules__ = ({
|
|
3
3
|
|
|
4
4
|
/***/ 48618:
|
|
5
|
-
/***/ ((__unused_webpack_module, exports) => {
|
|
5
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
6
6
|
|
|
7
7
|
"use strict";
|
|
8
8
|
|
|
@@ -11,6 +11,7 @@ Object.defineProperty(exports, "__esModule", ({
|
|
|
11
11
|
value: true
|
|
12
12
|
}));
|
|
13
13
|
exports.BaseContext = void 0;
|
|
14
|
+
const vaultManagerAccess_1 = __nccwpck_require__(37881);
|
|
14
15
|
/**
|
|
15
16
|
* Base class for CommandContext implementations.
|
|
16
17
|
* Handles caching, the `get()` method, and `promptDirect` delegation.
|
|
@@ -20,6 +21,10 @@ class BaseContext {
|
|
|
20
21
|
constructor(command) {
|
|
21
22
|
this.command = command;
|
|
22
23
|
this.cache = new Map();
|
|
24
|
+
this.vaultManagerGetter = (0, vaultManagerAccess_1.createVaultManagerGetter)(() => this);
|
|
25
|
+
}
|
|
26
|
+
getVaultManager() {
|
|
27
|
+
return this.vaultManagerGetter();
|
|
23
28
|
}
|
|
24
29
|
get(name) {
|
|
25
30
|
if (!this.cache.has(name)) {
|
|
@@ -91,6 +96,7 @@ Object.defineProperty(exports, "__esModule", ({
|
|
|
91
96
|
exports.createTerminalIO = exports.createTerminalContext = void 0;
|
|
92
97
|
const types_1 = __nccwpck_require__(92284);
|
|
93
98
|
const baseContext_1 = __nccwpck_require__(48618);
|
|
99
|
+
const vaultManagerAccess_1 = __nccwpck_require__(37881);
|
|
94
100
|
/**
|
|
95
101
|
* Resolve choices from a choices function.
|
|
96
102
|
*/
|
|
@@ -155,6 +161,10 @@ class TerminalContext extends baseContext_1.BaseContext {
|
|
|
155
161
|
super(command);
|
|
156
162
|
this.options = options;
|
|
157
163
|
}
|
|
164
|
+
get interactive() {
|
|
165
|
+
var _a;
|
|
166
|
+
return (_a = this.options.interactive) !== null && _a !== void 0 ? _a : process.stdin.isTTY === true;
|
|
167
|
+
}
|
|
158
168
|
log(message) {
|
|
159
169
|
console.log(message);
|
|
160
170
|
}
|
|
@@ -229,7 +239,10 @@ exports.createTerminalContext = createTerminalContext;
|
|
|
229
239
|
* Create a bare IO instance for terminal helper functions.
|
|
230
240
|
*/
|
|
231
241
|
function createTerminalIO(options = {}) {
|
|
232
|
-
|
|
242
|
+
var _a;
|
|
243
|
+
const io = {
|
|
244
|
+
interactive: (_a = options.interactive) !== null && _a !== void 0 ? _a : process.stdin.isTTY === true,
|
|
245
|
+
getVaultManager: (0, vaultManagerAccess_1.createVaultManagerGetter)(() => io),
|
|
233
246
|
log(message) {
|
|
234
247
|
console.log(message);
|
|
235
248
|
},
|
|
@@ -255,11 +268,45 @@ function createTerminalIO(options = {}) {
|
|
|
255
268
|
throw new types_1.MissingInputError(spec.name, spec.message);
|
|
256
269
|
}
|
|
257
270
|
};
|
|
271
|
+
return io;
|
|
258
272
|
}
|
|
259
273
|
exports.createTerminalIO = createTerminalIO;
|
|
260
274
|
|
|
261
275
|
/***/ }),
|
|
262
276
|
|
|
277
|
+
/***/ 37881:
|
|
278
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
279
|
+
|
|
280
|
+
"use strict";
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
Object.defineProperty(exports, "__esModule", ({
|
|
284
|
+
value: true
|
|
285
|
+
}));
|
|
286
|
+
exports.createVaultManagerGetter = void 0;
|
|
287
|
+
const getProjectConfig_1 = __nccwpck_require__(50001);
|
|
288
|
+
const VaultManager_1 = __nccwpck_require__(55771);
|
|
289
|
+
/**
|
|
290
|
+
* lazily creates the vault manager of a context (once per context),
|
|
291
|
+
* loading the project config on first use
|
|
292
|
+
*/
|
|
293
|
+
const createVaultManagerGetter = (io, options = {}) => {
|
|
294
|
+
let managerPromise;
|
|
295
|
+
return () => managerPromise !== null && managerPromise !== void 0 ? managerPromise : managerPromise = (async () => {
|
|
296
|
+
const config = await (0, getProjectConfig_1.getProjectConfig)();
|
|
297
|
+
if (!config) {
|
|
298
|
+
throw new Error("no catladder config found — the secrets vault needs a project config");
|
|
299
|
+
}
|
|
300
|
+
return new VaultManager_1.VaultManager(config, {
|
|
301
|
+
...options,
|
|
302
|
+
io: io()
|
|
303
|
+
});
|
|
304
|
+
})();
|
|
305
|
+
};
|
|
306
|
+
exports.createVaultManagerGetter = createVaultManagerGetter;
|
|
307
|
+
|
|
308
|
+
/***/ }),
|
|
309
|
+
|
|
263
310
|
/***/ 38365:
|
|
264
311
|
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
265
312
|
|
|
@@ -355,7 +402,9 @@ const pipeline_1 = __nccwpck_require__(60241);
|
|
|
355
402
|
const common_tags_1 = __nccwpck_require__(63779);
|
|
356
403
|
const lodash_es_1 = __nccwpck_require__(64284);
|
|
357
404
|
const getProjectConfig_1 = __nccwpck_require__(50001);
|
|
405
|
+
const commandSecretsSyncGithub_1 = __nccwpck_require__(50962);
|
|
358
406
|
const editAsFile_1 = __nccwpck_require__(82805);
|
|
407
|
+
const github_1 = __nccwpck_require__(18036);
|
|
359
408
|
const gitlab_1 = __nccwpck_require__(4508);
|
|
360
409
|
const promise_1 = __nccwpck_require__(51762);
|
|
361
410
|
/* for convenience, parse json objects. that makes it easier to edit secrets that are object */
|
|
@@ -433,21 +482,86 @@ const doItFor = async (instance, envAndComponents) => {
|
|
|
433
482
|
}
|
|
434
483
|
}
|
|
435
484
|
}
|
|
485
|
+
const config = await (0, getProjectConfig_1.getProjectConfig)();
|
|
486
|
+
if (!config) {
|
|
487
|
+
throw new Error("no catladder config found");
|
|
488
|
+
}
|
|
436
489
|
instance.log("");
|
|
437
|
-
instance.log("
|
|
490
|
+
instance.log("writing all secrets to the vault, please wait...");
|
|
438
491
|
instance.log("");
|
|
439
492
|
for (const [componentName, envs] of Object.entries(envAndComponents)) {
|
|
440
493
|
for (const env of envs) {
|
|
441
|
-
instance.log("
|
|
442
|
-
await (
|
|
494
|
+
instance.log("writing " + env + ":" + componentName + "...\n");
|
|
495
|
+
await (await instance.getVaultManager()).writeSecrets(env, componentName, valuesToEdit[componentName][env]);
|
|
443
496
|
instance.log("");
|
|
444
497
|
instance.log("✅ " + env + ":" + componentName);
|
|
445
498
|
instance.log("--------------------------------\n");
|
|
446
499
|
}
|
|
447
500
|
}
|
|
501
|
+
await mirrorSecretsToCiBackends(instance, config, envAndComponents, valuesToEdit);
|
|
448
502
|
instance.log("done! 😻");
|
|
449
503
|
instance.log("");
|
|
450
504
|
};
|
|
505
|
+
/**
|
|
506
|
+
* the vault is the source of truth; every enabled CI backend receives
|
|
507
|
+
* a mirrored copy of the edited secrets (gitlab variables, github
|
|
508
|
+
* secrets), so all CI systems stay in sync
|
|
509
|
+
*/
|
|
510
|
+
const mirrorSecretsToCiBackends = async (instance, config, envAndComponents, valuesToEdit) => {
|
|
511
|
+
const enabled = (0, pipeline_1.getEnabledPipelineTypes)(config);
|
|
512
|
+
// gitlab mirror (unless gitlab is the vault itself, then it is
|
|
513
|
+
// already written)
|
|
514
|
+
if ((0, pipeline_1.getVaultConfig)(config).type !== "gitlab" && enabled.includes("gitlab")) {
|
|
515
|
+
for (const [componentName, envs] of Object.entries(envAndComponents)) {
|
|
516
|
+
for (const env of envs) {
|
|
517
|
+
await (0, gitlab_1.upsertAllVariables)(instance, valuesToEdit[componentName][env], env, componentName);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
instance.log("✅ mirrored to gitlab");
|
|
521
|
+
}
|
|
522
|
+
if (!enabled.includes("github")) {
|
|
523
|
+
return;
|
|
524
|
+
}
|
|
525
|
+
const kinds = new Map();
|
|
526
|
+
for (const [componentName, envs] of Object.entries(envAndComponents)) {
|
|
527
|
+
for (const env of envs) {
|
|
528
|
+
const {
|
|
529
|
+
secretEnvVarKeys,
|
|
530
|
+
jobOnlyVars
|
|
531
|
+
} = await (0, getProjectConfig_1.getEnvironment)(env, componentName);
|
|
532
|
+
[...secretEnvVarKeys, ...jobOnlyVars.build.secretEnvVarKeys, ...jobOnlyVars.deploy.secretEnvVarKeys].forEach(({
|
|
533
|
+
key,
|
|
534
|
+
kind
|
|
535
|
+
}) => kinds.set((0, pipeline_1.getSecretVarName)(env, componentName, key), kind !== null && kind !== void 0 ? kind : "secret"));
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
const secrets = Object.entries(envAndComponents).flatMap(([componentName, envs]) => envs.flatMap(env => {
|
|
539
|
+
var _a;
|
|
540
|
+
return Object.entries((_a = valuesToEdit[componentName][env]) !== null && _a !== void 0 ? _a : {}).map(([key, value]) => {
|
|
541
|
+
var _a;
|
|
542
|
+
const name = (0, pipeline_1.getSecretVarName)(env, componentName, key);
|
|
543
|
+
return {
|
|
544
|
+
name,
|
|
545
|
+
value: typeof value === "string" ? value : JSON.stringify(value !== null && value !== void 0 ? value : ""),
|
|
546
|
+
kind: (_a = kinds.get(name)) !== null && _a !== void 0 ? _a : "secret"
|
|
547
|
+
};
|
|
548
|
+
});
|
|
549
|
+
}));
|
|
550
|
+
if (secrets.length === 0) {
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
553
|
+
if (!(await (0, github_1.isGhAuthenticated)())) {
|
|
554
|
+
instance.log("⚠️ github pipeline is enabled, but the github cli (gh) is not authenticated — run `project secrets-sync-github` later to mirror the secrets");
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
const repo = await (0, commandSecretsSyncGithub_1.getConfiguredGithubRepo)();
|
|
558
|
+
if (!repo) {
|
|
559
|
+
instance.log("⚠️ github pipeline is enabled, but no github repository was found — run `project secrets-sync-github` later to mirror the secrets");
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
562
|
+
instance.log(`mirroring ${secrets.length} secrets to github ('${repo}')...`);
|
|
563
|
+
await (0, commandSecretsSyncGithub_1.pushSecretsToGithub)(instance, repo, secrets);
|
|
564
|
+
};
|
|
451
565
|
const projectConfigSecrets = async (io, envComponent) => {
|
|
452
566
|
if (!envComponent) {
|
|
453
567
|
const allEnvAndcomponents = await (0, getProjectConfig_1.getAllComponentsWithAllEnvsHierarchical)();
|
|
@@ -1874,7 +1988,7 @@ exports.commandKubeStopPortforward = (0, defineCommand_1.defineCommand)({
|
|
|
1874
1988
|
Object.defineProperty(exports, "__esModule", ({
|
|
1875
1989
|
value: true
|
|
1876
1990
|
}));
|
|
1877
|
-
exports.commandStarwars = exports.commandDadjoke = exports.commandSecurityAuditCreate = exports.commandSecurityAuditEvaluate = exports.commandSecurityAuditCiJob = exports.commandRestoreDb = exports.commandMongoDestroyMember = exports.commandMongoPortForward = exports.commandMongoGetShell = exports.commandTriggerCronjobProject = exports.commandDeleteProject = exports.commandPauseProject = exports.commandDeletePods = exports.commandGetShell = exports.commandListPods = exports.commandNamespace = exports.commandSecurityEvaluate = exports.commandProjectRestoreDb = exports.commandCiJobLog = exports.commandCiJobOpen = exports.commandSetup = exports.commandGetMyTotalWorktime = exports.commandRenewToken = exports.commandTriggerCronjobGeneral = exports.commandOpenLogs = exports.commandSecretsClearBackups = exports.commandConfigSecrets = exports.commandCloudSqlProxy = exports.commandOpenGit = exports.commandOpenEnv = exports.commandPortForward = exports.commandEnvVars = exports.commandKubePortForward = exports.commandKubeGetShell = exports.commandKubeStopPortforward = exports.commandKubeListPods = exports.commandKubeListSecrets = exports.commandKubeListNamespaces = exports.commandKubeCurrentContext = void 0;
|
|
1991
|
+
exports.commandStarwars = exports.commandDadjoke = exports.commandSecurityAuditCreate = exports.commandSecurityAuditEvaluate = exports.commandSecurityAuditCiJob = exports.commandRestoreDb = exports.commandMongoDestroyMember = exports.commandMongoPortForward = exports.commandMongoGetShell = exports.commandTriggerCronjobProject = exports.commandDeleteProject = exports.commandPauseProject = exports.commandDeletePods = exports.commandGetShell = exports.commandListPods = exports.commandNamespace = exports.commandSecurityEvaluate = exports.commandProjectRestoreDb = exports.commandCiJobLog = exports.commandCiJobOpen = exports.commandSetup = exports.commandGetMyTotalWorktime = exports.commandRenewToken = exports.commandTriggerCronjobGeneral = exports.commandOpenLogs = exports.commandSecretsSyncGithub = exports.commandSecretsClearBackups = exports.commandConfigSecrets = exports.commandCloudSqlProxy = exports.commandOpenGit = exports.commandOpenEnv = exports.commandPortForward = exports.commandEnvVars = exports.commandKubePortForward = exports.commandKubeGetShell = exports.commandKubeStopPortforward = exports.commandKubeListPods = exports.commandKubeListSecrets = exports.commandKubeListNamespaces = exports.commandKubeCurrentContext = void 0;
|
|
1878
1992
|
// General commands
|
|
1879
1993
|
var commandKubeCurrentContext_1 = __nccwpck_require__(70243);
|
|
1880
1994
|
Object.defineProperty(exports, "commandKubeCurrentContext", ({
|
|
@@ -1975,6 +2089,13 @@ Object.defineProperty(exports, "commandSecretsClearBackups", ({
|
|
|
1975
2089
|
return commandSecretsClearBackups_1.commandSecretsClearBackups;
|
|
1976
2090
|
}
|
|
1977
2091
|
}));
|
|
2092
|
+
var commandSecretsSyncGithub_1 = __nccwpck_require__(50962);
|
|
2093
|
+
Object.defineProperty(exports, "commandSecretsSyncGithub", ({
|
|
2094
|
+
enumerable: true,
|
|
2095
|
+
get: function () {
|
|
2096
|
+
return commandSecretsSyncGithub_1.commandSecretsSyncGithub;
|
|
2097
|
+
}
|
|
2098
|
+
}));
|
|
1978
2099
|
var commandOpenLogs_1 = __nccwpck_require__(98720);
|
|
1979
2100
|
Object.defineProperty(exports, "commandOpenLogs", ({
|
|
1980
2101
|
enumerable: true,
|
|
@@ -3186,6 +3307,163 @@ exports.commandSecretsClearBackups = (0, defineCommand_1.defineCommand)({
|
|
|
3186
3307
|
|
|
3187
3308
|
/***/ }),
|
|
3188
3309
|
|
|
3310
|
+
/***/ 50962:
|
|
3311
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
3312
|
+
|
|
3313
|
+
"use strict";
|
|
3314
|
+
|
|
3315
|
+
|
|
3316
|
+
Object.defineProperty(exports, "__esModule", ({
|
|
3317
|
+
value: true
|
|
3318
|
+
}));
|
|
3319
|
+
exports.commandSecretsSyncGithub = exports.getConfiguredGithubRepo = exports.pushSecretsToGithub = exports.collectSecretsFromVault = void 0;
|
|
3320
|
+
const pipeline_1 = __nccwpck_require__(60241);
|
|
3321
|
+
const getProjectConfig_1 = __nccwpck_require__(50001);
|
|
3322
|
+
const defineCommand_1 = __nccwpck_require__(39489);
|
|
3323
|
+
const github_1 = __nccwpck_require__(18036);
|
|
3324
|
+
/**
|
|
3325
|
+
* all secrets declared in the config, with their values read from the
|
|
3326
|
+
* vault (github secrets are write-only and can never act as a source)
|
|
3327
|
+
*/
|
|
3328
|
+
const collectSecretsFromVault = async (io, envFilter) => {
|
|
3329
|
+
const envAndComponents = await (0, getProjectConfig_1.getAllComponentsWithAllEnvsHierarchical)();
|
|
3330
|
+
const kinds = new Map();
|
|
3331
|
+
for (const [componentName, envs] of Object.entries(envAndComponents)) {
|
|
3332
|
+
for (const env of envs) {
|
|
3333
|
+
if (envFilter && !envFilter.includes(env)) {
|
|
3334
|
+
continue;
|
|
3335
|
+
}
|
|
3336
|
+
const {
|
|
3337
|
+
secretEnvVarKeys,
|
|
3338
|
+
jobOnlyVars
|
|
3339
|
+
} = await (0, getProjectConfig_1.getEnvironment)(env, componentName);
|
|
3340
|
+
const keys = [...secretEnvVarKeys, ...jobOnlyVars.build.secretEnvVarKeys, ...jobOnlyVars.deploy.secretEnvVarKeys];
|
|
3341
|
+
keys.forEach(({
|
|
3342
|
+
key,
|
|
3343
|
+
kind
|
|
3344
|
+
}) => kinds.set((0, pipeline_1.getSecretVarName)(env, componentName, key), kind !== null && kind !== void 0 ? kind : "secret"));
|
|
3345
|
+
}
|
|
3346
|
+
}
|
|
3347
|
+
const names = [...kinds.keys()];
|
|
3348
|
+
const values = await (await io.getVaultManager()).readSecrets(names, io);
|
|
3349
|
+
const secrets = names.filter(name => values[name] !== undefined).map(name => {
|
|
3350
|
+
var _a;
|
|
3351
|
+
return {
|
|
3352
|
+
name,
|
|
3353
|
+
value: values[name],
|
|
3354
|
+
kind: (_a = kinds.get(name)) !== null && _a !== void 0 ? _a : "secret"
|
|
3355
|
+
};
|
|
3356
|
+
});
|
|
3357
|
+
const missing = names.filter(name => values[name] === undefined);
|
|
3358
|
+
return {
|
|
3359
|
+
secrets,
|
|
3360
|
+
missing
|
|
3361
|
+
};
|
|
3362
|
+
};
|
|
3363
|
+
exports.collectSecretsFromVault = collectSecretsFromVault;
|
|
3364
|
+
/**
|
|
3365
|
+
* pushes vault values to github via the gh cli: sensitive ones as repo
|
|
3366
|
+
* secrets (masked), "variable"-kind ones as repo variables (plain)
|
|
3367
|
+
*/
|
|
3368
|
+
const pushSecretsToGithub = async (io, repo, secrets) => {
|
|
3369
|
+
for (const {
|
|
3370
|
+
name,
|
|
3371
|
+
value,
|
|
3372
|
+
kind
|
|
3373
|
+
} of secrets) {
|
|
3374
|
+
if (kind === "variable") {
|
|
3375
|
+
await (0, github_1.setGithubVariable)(repo, name, value);
|
|
3376
|
+
io.log(`📖 ${name} (variable)`);
|
|
3377
|
+
} else {
|
|
3378
|
+
await (0, github_1.setGithubSecret)(repo, name, value);
|
|
3379
|
+
io.log(`✅ ${name}`);
|
|
3380
|
+
}
|
|
3381
|
+
}
|
|
3382
|
+
};
|
|
3383
|
+
exports.pushSecretsToGithub = pushSecretsToGithub;
|
|
3384
|
+
/**
|
|
3385
|
+
* resolves the github repository from the configured git remote
|
|
3386
|
+
* (`pipelines.github.gitRemote`, defaults to origin)
|
|
3387
|
+
*/
|
|
3388
|
+
const getConfiguredGithubRepo = async () => {
|
|
3389
|
+
const config = await (0, getProjectConfig_1.getProjectConfig)();
|
|
3390
|
+
if (!config) {
|
|
3391
|
+
return undefined;
|
|
3392
|
+
}
|
|
3393
|
+
return (0, github_1.getGithubRepoFromRemote)((0, pipeline_1.getPipelineGitRemote)(config, "github"));
|
|
3394
|
+
};
|
|
3395
|
+
exports.getConfiguredGithubRepo = getConfiguredGithubRepo;
|
|
3396
|
+
/**
|
|
3397
|
+
* copies the catladder secrets from the vault to github actions
|
|
3398
|
+
* repository secrets, keeping the exact same names, so the github
|
|
3399
|
+
* pipeline can reference them as ${{ secrets.<NAME> }}.
|
|
3400
|
+
*/
|
|
3401
|
+
exports.commandSecretsSyncGithub = (0, defineCommand_1.defineCommand)({
|
|
3402
|
+
name: "project secrets-sync-github",
|
|
3403
|
+
description: "copies all secrets from the vault to github repo secrets (same names), for the github pipeline",
|
|
3404
|
+
group: "project",
|
|
3405
|
+
inputs: {
|
|
3406
|
+
repo: {
|
|
3407
|
+
type: "string",
|
|
3408
|
+
message: "github repository (owner/name)",
|
|
3409
|
+
positional: true,
|
|
3410
|
+
required: false
|
|
3411
|
+
},
|
|
3412
|
+
env: {
|
|
3413
|
+
type: "string",
|
|
3414
|
+
message: "only sync these environments (comma-separated, e.g. review,dev) — github allows at most 100 repo secrets",
|
|
3415
|
+
positional: true,
|
|
3416
|
+
required: false
|
|
3417
|
+
}
|
|
3418
|
+
},
|
|
3419
|
+
execute: async ctx => {
|
|
3420
|
+
var _a, _b;
|
|
3421
|
+
const config = await (0, getProjectConfig_1.getProjectConfig)();
|
|
3422
|
+
if (!config) {
|
|
3423
|
+
throw new Error("no catladder config found");
|
|
3424
|
+
}
|
|
3425
|
+
const enabled = (0, pipeline_1.getEnabledPipelineTypes)(config);
|
|
3426
|
+
if (!enabled.includes("github")) {
|
|
3427
|
+
throw new Error("the github pipeline is not enabled in `pipelines` — nothing to sync to");
|
|
3428
|
+
}
|
|
3429
|
+
if (!(await (0, github_1.isGhAuthenticated)())) {
|
|
3430
|
+
throw new Error("the github cli (gh) is not installed or not authenticated — run `gh auth login` first");
|
|
3431
|
+
}
|
|
3432
|
+
const repo = (_a = await ctx.get("repo")) !== null && _a !== void 0 ? _a : await (0, exports.getConfiguredGithubRepo)();
|
|
3433
|
+
if (!repo) {
|
|
3434
|
+
throw new Error(`no github repository found on the '${(0, pipeline_1.getPipelineGitRemote)(config, "github")}' remote — pass it as owner/name or configure pipelines.github.gitRemote`);
|
|
3435
|
+
}
|
|
3436
|
+
const envFilter = (_b = await ctx.get("env")) === null || _b === void 0 ? void 0 : _b.split(",").map(e => e.trim());
|
|
3437
|
+
const {
|
|
3438
|
+
secrets,
|
|
3439
|
+
missing
|
|
3440
|
+
} = await (0, exports.collectSecretsFromVault)(ctx, envFilter);
|
|
3441
|
+
if (missing.length > 0) {
|
|
3442
|
+
ctx.log(`⚠️ ${missing.length} secrets are not set in the vault and will be skipped:`);
|
|
3443
|
+
missing.forEach(name => ctx.log(` - ${name}`));
|
|
3444
|
+
ctx.log("");
|
|
3445
|
+
}
|
|
3446
|
+
if (secrets.length === 0) {
|
|
3447
|
+
ctx.log("no secrets to sync 🤷");
|
|
3448
|
+
return;
|
|
3449
|
+
}
|
|
3450
|
+
ctx.log(`about to set ${secrets.length} secrets on '${repo}':`);
|
|
3451
|
+
secrets.forEach(({
|
|
3452
|
+
name
|
|
3453
|
+
}) => ctx.log(` - ${name}`));
|
|
3454
|
+
ctx.log("");
|
|
3455
|
+
const confirmed = await ctx.confirm("continue? 🤔");
|
|
3456
|
+
if (!confirmed) {
|
|
3457
|
+
throw new Error("abort");
|
|
3458
|
+
}
|
|
3459
|
+
await (0, exports.pushSecretsToGithub)(ctx, repo, secrets);
|
|
3460
|
+
ctx.log("");
|
|
3461
|
+
ctx.log("done! 😻 the github pipeline can use them as ${{ secrets.<NAME> }}");
|
|
3462
|
+
}
|
|
3463
|
+
});
|
|
3464
|
+
|
|
3465
|
+
/***/ }),
|
|
3466
|
+
|
|
3189
3467
|
/***/ 92494:
|
|
3190
3468
|
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
3191
3469
|
|
|
@@ -4179,14 +4457,24 @@ const getGitlabVar = async (io, env, componentName, variableName) => {
|
|
|
4179
4457
|
};
|
|
4180
4458
|
exports.getGitlabVar = getGitlabVar;
|
|
4181
4459
|
const resolveSecrets = async (io, varSets) => {
|
|
4182
|
-
|
|
4460
|
+
// the secret variables actually referenced by the env var values —
|
|
4461
|
+
// when they are all in the local cache, the vault is not contacted
|
|
4462
|
+
const referencedNames = [...new Set(varSets.flatMap(({
|
|
4463
|
+
envVars
|
|
4464
|
+
}) => Object.values(envVars).flatMap(value => {
|
|
4465
|
+
var _a;
|
|
4466
|
+
return (_a = `${value}`.match(/\$CL_\w+/g)) !== null && _a !== void 0 ? _a : [];
|
|
4467
|
+
})))].map(reference => reference.slice(1));
|
|
4468
|
+
const vaultManager = await io.getVaultManager();
|
|
4469
|
+
const secrets = await vaultManager.readSecrets(referencedNames, io);
|
|
4470
|
+
const secretEntries = Object.entries(secrets);
|
|
4183
4471
|
return Object.fromEntries(varSets.flatMap(({
|
|
4184
4472
|
envVars,
|
|
4185
4473
|
secretEnvVarKeys
|
|
4186
4474
|
}) => Object.entries(envVars).filter(([key, value]) => {
|
|
4187
4475
|
var _a;
|
|
4188
4476
|
return value !== undefined && value !== null && !((_a = secretEnvVarKeys.find(k => k.key === key)) === null || _a === void 0 ? void 0 : _a.hidden);
|
|
4189
|
-
}).map(([key, value]) => [key,
|
|
4477
|
+
}).map(([key, value]) => [key, secretEntries.reduce((acc, [name, secretValue]) => acc.replace(new RegExp("\\$" + name, "g"), secretValue), `${value}`)])));
|
|
4190
4478
|
};
|
|
4191
4479
|
const getEnvVarsResolved = async (io, env, componentName) => {
|
|
4192
4480
|
if (!componentName) {
|
|
@@ -4291,8 +4579,15 @@ exports.defineCommand = defineCommand;
|
|
|
4291
4579
|
Object.defineProperty(exports, "__esModule", ({
|
|
4292
4580
|
value: true
|
|
4293
4581
|
}));
|
|
4294
|
-
exports.MissingInputError = void 0;
|
|
4582
|
+
exports.MissingInputError = exports.NonInteractiveError = void 0;
|
|
4295
4583
|
// ─── Errors ──────────────────────────────────────────────────────────
|
|
4584
|
+
class NonInteractiveError extends Error {
|
|
4585
|
+
constructor(interaction) {
|
|
4586
|
+
super(`${interaction} requires an interactive terminal, but this context is not interactive`);
|
|
4587
|
+
this.name = "NonInteractiveError";
|
|
4588
|
+
}
|
|
4589
|
+
}
|
|
4590
|
+
exports.NonInteractiveError = NonInteractiveError;
|
|
4296
4591
|
class MissingInputError extends Error {
|
|
4297
4592
|
constructor(inputName, promptMessage) {
|
|
4298
4593
|
super(`Missing required input: "${inputName}" (${promptMessage}). ` + `Provide it via --${inputName}=<value> or --inputs='{"${inputName}": ...}'`);
|
|
@@ -4742,14 +5037,14 @@ exports.getProjectRootPath = getProjectRootPath;
|
|
|
4742
5037
|
/**
|
|
4743
5038
|
* Get the git remote hostname and project path from the git config.
|
|
4744
5039
|
*/
|
|
4745
|
-
const getGitRemoteHostAndPath = async () => {
|
|
5040
|
+
const getGitRemoteHostAndPath = async (remoteName = "origin") => {
|
|
4746
5041
|
var _a;
|
|
4747
|
-
const remoteUrl = await (0, gitConfig_1.gitConfigGet)(
|
|
5042
|
+
const remoteUrl = await (0, gitConfig_1.gitConfigGet)(`remote.${remoteName}.url`);
|
|
4748
5043
|
const remoteReg = /(https:\/\/|git@)([^:/]+)[:/]([^.]*)(\.git)?/;
|
|
4749
5044
|
const match = (_a = remoteUrl.match(remoteReg)) !== null && _a !== void 0 ? _a : [];
|
|
4750
5045
|
const [,, gitRemoteHost, gitRemotePath] = match;
|
|
4751
5046
|
if (!(gitRemoteHost === null || gitRemoteHost === void 0 ? void 0 : gitRemoteHost.length) || !(gitRemotePath === null || gitRemotePath === void 0 ? void 0 : gitRemotePath.length)) {
|
|
4752
|
-
throw new Error(`Failed to parse git remote hostname and path from git configs remote.
|
|
5047
|
+
throw new Error(`Failed to parse git remote hostname and path from git configs remote.${remoteName}.url! ${remoteUrl}`);
|
|
4753
5048
|
}
|
|
4754
5049
|
return {
|
|
4755
5050
|
gitRemoteHost,
|
|
@@ -5306,6 +5601,74 @@ exports["default"] = async () => {
|
|
|
5306
5601
|
|
|
5307
5602
|
/***/ }),
|
|
5308
5603
|
|
|
5604
|
+
/***/ 18036:
|
|
5605
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
5606
|
+
|
|
5607
|
+
"use strict";
|
|
5608
|
+
|
|
5609
|
+
|
|
5610
|
+
Object.defineProperty(exports, "__esModule", ({
|
|
5611
|
+
value: true
|
|
5612
|
+
}));
|
|
5613
|
+
exports.setGithubVariable = exports.setGithubSecret = exports.getGithubRepoFromRemote = exports.isGhAuthenticated = void 0;
|
|
5614
|
+
const child_process_1 = __nccwpck_require__(35317);
|
|
5615
|
+
const util_1 = __nccwpck_require__(39023);
|
|
5616
|
+
const execFile = (0, util_1.promisify)(child_process_1.execFile);
|
|
5617
|
+
/**
|
|
5618
|
+
* whether the github cli (gh) is installed and authenticated
|
|
5619
|
+
*/
|
|
5620
|
+
const isGhAuthenticated = async () => {
|
|
5621
|
+
try {
|
|
5622
|
+
await execFile("gh", ["auth", "status"]);
|
|
5623
|
+
return true;
|
|
5624
|
+
} catch (_a) {
|
|
5625
|
+
return false;
|
|
5626
|
+
}
|
|
5627
|
+
};
|
|
5628
|
+
exports.isGhAuthenticated = isGhAuthenticated;
|
|
5629
|
+
/**
|
|
5630
|
+
* the github repository (owner/name) a git remote points to.
|
|
5631
|
+
* Which remote belongs to github is configured per pipeline type
|
|
5632
|
+
* (`pipelines.github.gitRemote`, defaults to origin).
|
|
5633
|
+
*/
|
|
5634
|
+
const getGithubRepoFromRemote = async remoteName => {
|
|
5635
|
+
try {
|
|
5636
|
+
const {
|
|
5637
|
+
stdout
|
|
5638
|
+
} = await execFile("git", ["remote", "get-url", remoteName]);
|
|
5639
|
+
const match = stdout.match(/github\.com[:/]([\w.-]+\/[\w.-]+?)(\.git)?\s*$/);
|
|
5640
|
+
return match === null || match === void 0 ? void 0 : match[1];
|
|
5641
|
+
} catch (_a) {
|
|
5642
|
+
return undefined;
|
|
5643
|
+
}
|
|
5644
|
+
};
|
|
5645
|
+
exports.getGithubRepoFromRemote = getGithubRepoFromRemote;
|
|
5646
|
+
const ghSetViaStdin = (kind, repo, name, value) => new Promise((resolve, reject) => {
|
|
5647
|
+
var _a, _b;
|
|
5648
|
+
const child = (0, child_process_1.spawn)("gh", [kind, "set", name, "--repo", repo], {
|
|
5649
|
+
stdio: ["pipe", "ignore", "pipe"]
|
|
5650
|
+
});
|
|
5651
|
+
let stderr = "";
|
|
5652
|
+
(_a = child.stderr) === null || _a === void 0 ? void 0 : _a.on("data", data => stderr += data);
|
|
5653
|
+
child.on("error", reject);
|
|
5654
|
+
child.on("close", code => code === 0 ? resolve() : reject(new Error(`gh ${kind} set ${name} failed: ${stderr.trim()}`)));
|
|
5655
|
+
(_b = child.stdin) === null || _b === void 0 ? void 0 : _b.end(value);
|
|
5656
|
+
});
|
|
5657
|
+
/**
|
|
5658
|
+
* sets a github actions repository secret via the gh cli.
|
|
5659
|
+
* The value is passed via stdin so it never shows up in a process list.
|
|
5660
|
+
*/
|
|
5661
|
+
const setGithubSecret = async (repo, name, value) => ghSetViaStdin("secret", repo, name, value);
|
|
5662
|
+
exports.setGithubSecret = setGithubSecret;
|
|
5663
|
+
/**
|
|
5664
|
+
* sets a github actions repository variable (plain, unmasked) via the
|
|
5665
|
+
* gh cli — for vault values classified as not sensitive
|
|
5666
|
+
*/
|
|
5667
|
+
const setGithubVariable = async (repo, name, value) => ghSetViaStdin("variable", repo, name, value);
|
|
5668
|
+
exports.setGithubVariable = setGithubVariable;
|
|
5669
|
+
|
|
5670
|
+
/***/ }),
|
|
5671
|
+
|
|
5309
5672
|
/***/ 4508:
|
|
5310
5673
|
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
|
5311
5674
|
|
|
@@ -5845,6 +6208,445 @@ exports.getShell = getShell;
|
|
|
5845
6208
|
|
|
5846
6209
|
/***/ }),
|
|
5847
6210
|
|
|
6211
|
+
/***/ 63510:
|
|
6212
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
6213
|
+
|
|
6214
|
+
"use strict";
|
|
6215
|
+
|
|
6216
|
+
|
|
6217
|
+
Object.defineProperty(exports, "__esModule", ({
|
|
6218
|
+
value: true
|
|
6219
|
+
}));
|
|
6220
|
+
exports.BitwardenVault = void 0;
|
|
6221
|
+
const pipeline_1 = __nccwpck_require__(60241);
|
|
6222
|
+
const yaml_1 = __nccwpck_require__(6637);
|
|
6223
|
+
const bw_1 = __nccwpck_require__(52211);
|
|
6224
|
+
const DEFAULT_COLLECTION = "catladder";
|
|
6225
|
+
const SECURE_NOTE_TYPE = 2;
|
|
6226
|
+
/**
|
|
6227
|
+
* one yaml note per env and component:
|
|
6228
|
+
* `<customerName>/<appName>/<env>/<componentName>/secrets.yml`
|
|
6229
|
+
*/
|
|
6230
|
+
const itemName = (config, env, componentName) => `${config.customerName}/${config.appName}/${env}/${componentName}/secrets.yml`;
|
|
6231
|
+
const itemPrefix = config => `${config.customerName}/${config.appName}/`;
|
|
6232
|
+
/**
|
|
6233
|
+
* parses env and componentName back out of an item name
|
|
6234
|
+
*/
|
|
6235
|
+
const parseItemName = (config, name) => {
|
|
6236
|
+
const match = name.slice(itemPrefix(config).length).match(/^([^/]+)\/([^/]+)\/secrets\.yml$/);
|
|
6237
|
+
return match ? {
|
|
6238
|
+
env: match[1],
|
|
6239
|
+
componentName: match[2]
|
|
6240
|
+
} : null;
|
|
6241
|
+
};
|
|
6242
|
+
const findCollection = async (session, collectionName) => {
|
|
6243
|
+
const collections = await (0, bw_1.runBwJson)(session, ["list", "collections", "--search", collectionName]);
|
|
6244
|
+
const collection = collections.find(c => c.name === collectionName);
|
|
6245
|
+
if (!collection) {
|
|
6246
|
+
throw new Error(`bitwarden collection '${collectionName}' not found — create it and make sure you have access`);
|
|
6247
|
+
}
|
|
6248
|
+
return collection;
|
|
6249
|
+
};
|
|
6250
|
+
const encodePayload = payload => Buffer.from(JSON.stringify(payload), "utf-8").toString("base64");
|
|
6251
|
+
class BitwardenVault {
|
|
6252
|
+
constructor(config, options,
|
|
6253
|
+
/**
|
|
6254
|
+
* whether a locked bitwarden may be unlocked interactively
|
|
6255
|
+
* (false with catenv --vault-mode no-prompt)
|
|
6256
|
+
*/
|
|
6257
|
+
allowPrompt) {
|
|
6258
|
+
var _a;
|
|
6259
|
+
this.config = config;
|
|
6260
|
+
this.allowPrompt = allowPrompt;
|
|
6261
|
+
this.collectionName = (_a = options.collection) !== null && _a !== void 0 ? _a : DEFAULT_COLLECTION;
|
|
6262
|
+
this.id = `bitwarden:${this.collectionName}`;
|
|
6263
|
+
}
|
|
6264
|
+
session(io) {
|
|
6265
|
+
return (0, bw_1.getBwSession)(io, {
|
|
6266
|
+
allowPrompt: this.allowPrompt
|
|
6267
|
+
});
|
|
6268
|
+
}
|
|
6269
|
+
async readAllSecrets(io) {
|
|
6270
|
+
const {
|
|
6271
|
+
config,
|
|
6272
|
+
collectionName
|
|
6273
|
+
} = this;
|
|
6274
|
+
const bwSession = await this.session(io);
|
|
6275
|
+
const collection = await findCollection(bwSession, collectionName);
|
|
6276
|
+
const items = await (0, bw_1.runBwJson)(bwSession, ["list", "items", "--collectionid", collection.id]);
|
|
6277
|
+
const secrets = {};
|
|
6278
|
+
for (const item of items) {
|
|
6279
|
+
const parsed = parseItemName(config, item.name);
|
|
6280
|
+
if (!parsed || !item.notes) {
|
|
6281
|
+
continue;
|
|
6282
|
+
}
|
|
6283
|
+
const values = (0, yaml_1.parse)(item.notes);
|
|
6284
|
+
Object.entries(values !== null && values !== void 0 ? values : {}).forEach(([key, value]) => {
|
|
6285
|
+
secrets[(0, pipeline_1.getSecretVarName)(parsed.env, parsed.componentName, key)] = typeof value === "string" ? value : JSON.stringify(value);
|
|
6286
|
+
});
|
|
6287
|
+
}
|
|
6288
|
+
return secrets;
|
|
6289
|
+
}
|
|
6290
|
+
async writeSecrets(io, env, componentName, secrets) {
|
|
6291
|
+
const {
|
|
6292
|
+
config,
|
|
6293
|
+
collectionName
|
|
6294
|
+
} = this;
|
|
6295
|
+
const bwSession = await this.session(io);
|
|
6296
|
+
const collection = await findCollection(bwSession, collectionName);
|
|
6297
|
+
const name = itemName(config, env, componentName);
|
|
6298
|
+
const existing = (await (0, bw_1.runBwJson)(bwSession, ["list", "items", "--collectionid", collection.id, "--search", name])).find(item => item.name === name);
|
|
6299
|
+
const notes = (0, yaml_1.stringify)(secrets);
|
|
6300
|
+
if (existing) {
|
|
6301
|
+
await (0, bw_1.runBw)(bwSession, ["edit", "item", existing.id, encodePayload({
|
|
6302
|
+
...existing,
|
|
6303
|
+
notes
|
|
6304
|
+
})]);
|
|
6305
|
+
} else {
|
|
6306
|
+
await (0, bw_1.runBw)(bwSession, ["create", "item", encodePayload({
|
|
6307
|
+
type: SECURE_NOTE_TYPE,
|
|
6308
|
+
secureNote: {
|
|
6309
|
+
type: 0
|
|
6310
|
+
},
|
|
6311
|
+
name,
|
|
6312
|
+
notes,
|
|
6313
|
+
...(collection.organizationId ? {
|
|
6314
|
+
organizationId: collection.organizationId,
|
|
6315
|
+
collectionIds: [collection.id]
|
|
6316
|
+
} : {})
|
|
6317
|
+
})]);
|
|
6318
|
+
}
|
|
6319
|
+
}
|
|
6320
|
+
}
|
|
6321
|
+
exports.BitwardenVault = BitwardenVault;
|
|
6322
|
+
|
|
6323
|
+
/***/ }),
|
|
6324
|
+
|
|
6325
|
+
/***/ 31107:
|
|
6326
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
6327
|
+
|
|
6328
|
+
"use strict";
|
|
6329
|
+
|
|
6330
|
+
|
|
6331
|
+
Object.defineProperty(exports, "__esModule", ({
|
|
6332
|
+
value: true
|
|
6333
|
+
}));
|
|
6334
|
+
exports.GitlabVault = void 0;
|
|
6335
|
+
const gitlab_1 = __nccwpck_require__(4508);
|
|
6336
|
+
/**
|
|
6337
|
+
* the legacy (and default) vault: the gitlab project variables double
|
|
6338
|
+
* as the secret store
|
|
6339
|
+
*/
|
|
6340
|
+
class GitlabVault {
|
|
6341
|
+
constructor() {
|
|
6342
|
+
this.id = "gitlab";
|
|
6343
|
+
}
|
|
6344
|
+
async readAllSecrets(io) {
|
|
6345
|
+
const variables = await (0, gitlab_1.getAllVariables)(io);
|
|
6346
|
+
return Object.fromEntries(variables.map(v => [v.key, v.value]));
|
|
6347
|
+
}
|
|
6348
|
+
async writeSecrets(io, env, componentName, secrets) {
|
|
6349
|
+
await (0, gitlab_1.upsertAllVariables)(io, secrets, env, componentName);
|
|
6350
|
+
}
|
|
6351
|
+
}
|
|
6352
|
+
exports.GitlabVault = GitlabVault;
|
|
6353
|
+
|
|
6354
|
+
/***/ }),
|
|
6355
|
+
|
|
6356
|
+
/***/ 55771:
|
|
6357
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
6358
|
+
|
|
6359
|
+
"use strict";
|
|
6360
|
+
|
|
6361
|
+
|
|
6362
|
+
Object.defineProperty(exports, "__esModule", ({
|
|
6363
|
+
value: true
|
|
6364
|
+
}));
|
|
6365
|
+
exports.VaultManager = void 0;
|
|
6366
|
+
const pipeline_1 = __nccwpck_require__(60241);
|
|
6367
|
+
const BitwardenVault_1 = __nccwpck_require__(63510);
|
|
6368
|
+
const cache_1 = __nccwpck_require__(14236);
|
|
6369
|
+
const GitlabVault_1 = __nccwpck_require__(31107);
|
|
6370
|
+
/**
|
|
6371
|
+
* only secrets of this env are cached locally — the other envs'
|
|
6372
|
+
* secrets have no business sitting on developer machines
|
|
6373
|
+
*/
|
|
6374
|
+
const CACHED_ENV = "local";
|
|
6375
|
+
/**
|
|
6376
|
+
* owns the configured vault, the secrets mode and the local cache.
|
|
6377
|
+
* The vault is the readable source of truth for secrets; CI backends
|
|
6378
|
+
* only receive mirrored copies.
|
|
6379
|
+
*/
|
|
6380
|
+
class VaultManager {
|
|
6381
|
+
constructor(config, options = {}) {
|
|
6382
|
+
var _a, _b;
|
|
6383
|
+
this.config = config;
|
|
6384
|
+
/** refresh mode bypasses the cache only once per manager */
|
|
6385
|
+
this.refreshed = false;
|
|
6386
|
+
this.mode = (_a = options.mode) !== null && _a !== void 0 ? _a : "auto";
|
|
6387
|
+
this.io = (_b = options.io) !== null && _b !== void 0 ? _b : null;
|
|
6388
|
+
this.vault = this.createVault();
|
|
6389
|
+
}
|
|
6390
|
+
createVault() {
|
|
6391
|
+
const vaultConfig = (0, pipeline_1.getVaultConfig)(this.config);
|
|
6392
|
+
switch (vaultConfig.type) {
|
|
6393
|
+
case "gitlab":
|
|
6394
|
+
return new GitlabVault_1.GitlabVault();
|
|
6395
|
+
case "bitwarden":
|
|
6396
|
+
return new BitwardenVault_1.BitwardenVault(this.config, vaultConfig, this.mode === "auto" || this.mode === "refresh");
|
|
6397
|
+
}
|
|
6398
|
+
}
|
|
6399
|
+
/**
|
|
6400
|
+
* the vault secrets, served from the local cache when it contains
|
|
6401
|
+
* all required names; otherwise (depending on the mode) refreshed
|
|
6402
|
+
* from the vault. Only the "local" env is (re-)cached.
|
|
6403
|
+
*/
|
|
6404
|
+
async readSecrets(requiredNames, io = this.io) {
|
|
6405
|
+
const bypassCache = this.mode === "refresh" && !this.refreshed;
|
|
6406
|
+
const cache = bypassCache ? null : await (0, cache_1.readSecretsCache)();
|
|
6407
|
+
// known entries include recorded misses (null values), so declared
|
|
6408
|
+
// but intentionally unset secrets don't force a vault refresh
|
|
6409
|
+
const known = (cache === null || cache === void 0 ? void 0 : cache.vaultId) === this.vault.id ? flattenSecrets(cache.secrets) : undefined;
|
|
6410
|
+
const missing = requiredNames.filter(name => !(name in (known !== null && known !== void 0 ? known : {})));
|
|
6411
|
+
// nothing missing (or nothing required at all): don't touch the vault
|
|
6412
|
+
if (missing.length === 0 && (known || requiredNames.length === 0)) {
|
|
6413
|
+
return withoutMisses(known !== null && known !== void 0 ? known : {});
|
|
6414
|
+
}
|
|
6415
|
+
if (this.mode === "offline") {
|
|
6416
|
+
if (missing.length > 0) {
|
|
6417
|
+
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(", ")}`);
|
|
6418
|
+
}
|
|
6419
|
+
return withoutMisses(known !== null && known !== void 0 ? known : {});
|
|
6420
|
+
}
|
|
6421
|
+
const secrets = await this.vault.readAllSecrets(io);
|
|
6422
|
+
this.refreshed = true;
|
|
6423
|
+
await (0, cache_1.writeSecretsCache)(this.vault.id, await this.cacheableSubset(secrets));
|
|
6424
|
+
return secrets;
|
|
6425
|
+
}
|
|
6426
|
+
/**
|
|
6427
|
+
* writes secrets of one env/component to the vault and updates the
|
|
6428
|
+
* local cache (write-through, "local" env only)
|
|
6429
|
+
*/
|
|
6430
|
+
async writeSecrets(env, componentName, secrets, io = this.io) {
|
|
6431
|
+
if (!io) {
|
|
6432
|
+
throw new Error("writing to the vault requires an interactive context");
|
|
6433
|
+
}
|
|
6434
|
+
await this.vault.writeSecrets(io, env, componentName, secrets);
|
|
6435
|
+
if (env === CACHED_ENV) {
|
|
6436
|
+
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)])));
|
|
6437
|
+
}
|
|
6438
|
+
}
|
|
6439
|
+
/**
|
|
6440
|
+
* the subset of the vault secrets that may be cached: the declared
|
|
6441
|
+
* secrets of the "local" env, per component, as a hierarchy
|
|
6442
|
+
*/
|
|
6443
|
+
async cacheableSubset(flatSecrets) {
|
|
6444
|
+
const local = {};
|
|
6445
|
+
for (const componentName of Object.keys(this.config.components)) {
|
|
6446
|
+
const keys = await this.declaredSecretKeys(componentName);
|
|
6447
|
+
const values = Object.fromEntries(keys.map(key => {
|
|
6448
|
+
var _a;
|
|
6449
|
+
return [key,
|
|
6450
|
+
// null records "absent in the vault" (a known miss)
|
|
6451
|
+
(_a = flatSecrets[(0, pipeline_1.getSecretVarName)(CACHED_ENV, componentName, key)]) !== null && _a !== void 0 ? _a : null];
|
|
6452
|
+
}));
|
|
6453
|
+
if (Object.keys(values).length > 0) {
|
|
6454
|
+
local[componentName] = values;
|
|
6455
|
+
}
|
|
6456
|
+
}
|
|
6457
|
+
return Object.keys(local).length > 0 ? {
|
|
6458
|
+
[CACHED_ENV]: local
|
|
6459
|
+
} : {};
|
|
6460
|
+
}
|
|
6461
|
+
async declaredSecretKeys(componentName) {
|
|
6462
|
+
try {
|
|
6463
|
+
const {
|
|
6464
|
+
secretEnvVarKeys,
|
|
6465
|
+
jobOnlyVars
|
|
6466
|
+
} = await (0, pipeline_1.getEnvironment)({
|
|
6467
|
+
config: this.config,
|
|
6468
|
+
componentName,
|
|
6469
|
+
env: CACHED_ENV
|
|
6470
|
+
});
|
|
6471
|
+
return [...secretEnvVarKeys, ...jobOnlyVars.build.secretEnvVarKeys, ...jobOnlyVars.deploy.secretEnvVarKeys].map(({
|
|
6472
|
+
key
|
|
6473
|
+
}) => key);
|
|
6474
|
+
} catch (_a) {
|
|
6475
|
+
// components without a local env simply have nothing to cache
|
|
6476
|
+
return [];
|
|
6477
|
+
}
|
|
6478
|
+
}
|
|
6479
|
+
}
|
|
6480
|
+
exports.VaultManager = VaultManager;
|
|
6481
|
+
/**
|
|
6482
|
+
* the cache hierarchy as a flat map of raw secret variable names
|
|
6483
|
+
* (null values = recorded misses)
|
|
6484
|
+
*/
|
|
6485
|
+
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]))));
|
|
6486
|
+
/**
|
|
6487
|
+
* only actual values — recorded misses stay unresolved, like any other
|
|
6488
|
+
* unset variable
|
|
6489
|
+
*/
|
|
6490
|
+
const withoutMisses = known => Object.fromEntries(Object.entries(known).filter(entry => entry[1] !== null));
|
|
6491
|
+
|
|
6492
|
+
/***/ }),
|
|
6493
|
+
|
|
6494
|
+
/***/ 52211:
|
|
6495
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
6496
|
+
|
|
6497
|
+
"use strict";
|
|
6498
|
+
|
|
6499
|
+
|
|
6500
|
+
Object.defineProperty(exports, "__esModule", ({
|
|
6501
|
+
value: true
|
|
6502
|
+
}));
|
|
6503
|
+
exports.runBwJson = exports.runBw = exports.getBwSession = void 0;
|
|
6504
|
+
const child_process_1 = __nccwpck_require__(35317);
|
|
6505
|
+
const util_1 = __nccwpck_require__(39023);
|
|
6506
|
+
const preferences_1 = __nccwpck_require__(66261);
|
|
6507
|
+
const execFile = (0, util_1.promisify)(child_process_1.execFile);
|
|
6508
|
+
const SESSION_PREFERENCE = "bwsession";
|
|
6509
|
+
class BitwardenLockedError extends Error {
|
|
6510
|
+
constructor() {
|
|
6511
|
+
super("bitwarden is locked and prompting is disabled — run `bw unlock` or catenv without --vault-mode no-prompt");
|
|
6512
|
+
}
|
|
6513
|
+
}
|
|
6514
|
+
/**
|
|
6515
|
+
* runs an interactive bw command that prints a session key on stdout
|
|
6516
|
+
* (login/unlock) while the user types the password on the terminal
|
|
6517
|
+
*/
|
|
6518
|
+
const interactiveSessionCommand = args => new Promise((resolve, reject) => {
|
|
6519
|
+
var _a;
|
|
6520
|
+
const child = (0, child_process_1.spawn)("bw", [...args, "--raw"], {
|
|
6521
|
+
stdio: ["inherit", "pipe", "inherit"]
|
|
6522
|
+
});
|
|
6523
|
+
let session = "";
|
|
6524
|
+
(_a = child.stdout) === null || _a === void 0 ? void 0 : _a.on("data", data => session += data.toString("utf-8"));
|
|
6525
|
+
child.on("error", reject);
|
|
6526
|
+
child.on("close", code => code === 0 && session.trim() ? resolve(session.trim()) : reject(new Error(`bw ${args[0]} failed`)));
|
|
6527
|
+
});
|
|
6528
|
+
const getBwStatus = async session => {
|
|
6529
|
+
try {
|
|
6530
|
+
const {
|
|
6531
|
+
stdout
|
|
6532
|
+
} = await execFile("bw", ["status"], {
|
|
6533
|
+
env: {
|
|
6534
|
+
...process.env,
|
|
6535
|
+
...(session ? {
|
|
6536
|
+
BW_SESSION: session
|
|
6537
|
+
} : {})
|
|
6538
|
+
}
|
|
6539
|
+
});
|
|
6540
|
+
return JSON.parse(stdout).status;
|
|
6541
|
+
} catch (_a) {
|
|
6542
|
+
return "unauthenticated";
|
|
6543
|
+
}
|
|
6544
|
+
};
|
|
6545
|
+
/**
|
|
6546
|
+
* a working bw session: reuses the cached one, otherwise unlocks (or
|
|
6547
|
+
* logs in) interactively — unless prompting is disabled
|
|
6548
|
+
*/
|
|
6549
|
+
const getBwSession = async (io, {
|
|
6550
|
+
allowPrompt
|
|
6551
|
+
}) => {
|
|
6552
|
+
const cached = (await (0, preferences_1.hasPreference)(SESSION_PREFERENCE)) ? String(await (0, preferences_1.getPreference)(SESSION_PREFERENCE)) : null;
|
|
6553
|
+
const status = await getBwStatus(cached);
|
|
6554
|
+
if (status === "unlocked" && cached) {
|
|
6555
|
+
return cached;
|
|
6556
|
+
}
|
|
6557
|
+
if (!allowPrompt) {
|
|
6558
|
+
throw new BitwardenLockedError();
|
|
6559
|
+
}
|
|
6560
|
+
io === null || io === void 0 ? void 0 : io.log("");
|
|
6561
|
+
io === null || io === void 0 ? void 0 : io.log(status === "unauthenticated" ? "# Please login to Bitwarden:" : "# Bitwarden is locked, please unlock:");
|
|
6562
|
+
io === null || io === void 0 ? void 0 : io.log("");
|
|
6563
|
+
const session = await interactiveSessionCommand([status === "unauthenticated" ? "login" : "unlock"]);
|
|
6564
|
+
await (0, preferences_1.setPreference)(SESSION_PREFERENCE, session);
|
|
6565
|
+
await (0, exports.runBw)(session, ["sync"]);
|
|
6566
|
+
return session;
|
|
6567
|
+
};
|
|
6568
|
+
exports.getBwSession = getBwSession;
|
|
6569
|
+
/**
|
|
6570
|
+
* runs a bw command with the given session and returns stdout
|
|
6571
|
+
*/
|
|
6572
|
+
const runBw = async (session, args) => {
|
|
6573
|
+
const {
|
|
6574
|
+
stdout
|
|
6575
|
+
} = await execFile("bw", [...args, "--raw", "--nointeraction"], {
|
|
6576
|
+
env: {
|
|
6577
|
+
...process.env,
|
|
6578
|
+
BW_SESSION: session
|
|
6579
|
+
},
|
|
6580
|
+
maxBuffer: 50 * 1024 * 1024
|
|
6581
|
+
});
|
|
6582
|
+
return stdout;
|
|
6583
|
+
};
|
|
6584
|
+
exports.runBw = runBw;
|
|
6585
|
+
const runBwJson = async (session, args) => JSON.parse(await (0, exports.runBw)(session, args));
|
|
6586
|
+
exports.runBwJson = runBwJson;
|
|
6587
|
+
|
|
6588
|
+
/***/ }),
|
|
6589
|
+
|
|
6590
|
+
/***/ 14236:
|
|
6591
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
6592
|
+
|
|
6593
|
+
"use strict";
|
|
6594
|
+
|
|
6595
|
+
|
|
6596
|
+
Object.defineProperty(exports, "__esModule", ({
|
|
6597
|
+
value: true
|
|
6598
|
+
}));
|
|
6599
|
+
exports.updateSecretsCache = exports.writeSecretsCache = exports.readSecretsCache = void 0;
|
|
6600
|
+
const promises_1 = __nccwpck_require__(91943);
|
|
6601
|
+
const path_1 = __nccwpck_require__(16928);
|
|
6602
|
+
const gitProjectInformation_1 = __nccwpck_require__(21111);
|
|
6603
|
+
const getCacheFolder = async () => (0, path_1.join)(await (0, gitProjectInformation_1.getProjectRootPath)(), ".catladder");
|
|
6604
|
+
const getCachePath = async () => (0, path_1.join)(await getCacheFolder(), "secrets.json");
|
|
6605
|
+
const readSecretsCache = async () => {
|
|
6606
|
+
try {
|
|
6607
|
+
return JSON.parse(await (0, promises_1.readFile)(await getCachePath(), "utf-8"));
|
|
6608
|
+
} catch (_a) {
|
|
6609
|
+
return null;
|
|
6610
|
+
}
|
|
6611
|
+
};
|
|
6612
|
+
exports.readSecretsCache = readSecretsCache;
|
|
6613
|
+
const writeSecretsCache = async (vaultId, secrets) => {
|
|
6614
|
+
const folder = await getCacheFolder();
|
|
6615
|
+
await (0, promises_1.mkdir)(folder, {
|
|
6616
|
+
recursive: true
|
|
6617
|
+
});
|
|
6618
|
+
// the folder ignores itself, so the cache can never be committed
|
|
6619
|
+
await (0, promises_1.writeFile)((0, path_1.join)(folder, ".gitignore"), "*\n");
|
|
6620
|
+
const cache = {
|
|
6621
|
+
vaultId,
|
|
6622
|
+
updatedAt: new Date().toISOString(),
|
|
6623
|
+
secrets
|
|
6624
|
+
};
|
|
6625
|
+
await (0, promises_1.writeFile)(await getCachePath(), JSON.stringify(cache, null, 2));
|
|
6626
|
+
};
|
|
6627
|
+
exports.writeSecretsCache = writeSecretsCache;
|
|
6628
|
+
/**
|
|
6629
|
+
* merges freshly written secrets of one env/component into the cache
|
|
6630
|
+
* (write-through from config-secrets), so the next catenv run doesn't
|
|
6631
|
+
* need the vault
|
|
6632
|
+
*/
|
|
6633
|
+
const updateSecretsCache = async (vaultId, env, componentName, values) => {
|
|
6634
|
+
var _a;
|
|
6635
|
+
const existing = await (0, exports.readSecretsCache)();
|
|
6636
|
+
const secrets = (existing === null || existing === void 0 ? void 0 : existing.vaultId) === vaultId ? existing.secrets : {};
|
|
6637
|
+
secrets[env] = {
|
|
6638
|
+
...secrets[env],
|
|
6639
|
+
[componentName]: {
|
|
6640
|
+
...((_a = secrets[env]) === null || _a === void 0 ? void 0 : _a[componentName]),
|
|
6641
|
+
...values
|
|
6642
|
+
}
|
|
6643
|
+
};
|
|
6644
|
+
await (0, exports.writeSecretsCache)(vaultId, secrets);
|
|
6645
|
+
};
|
|
6646
|
+
exports.updateSecretsCache = updateSecretsCache;
|
|
6647
|
+
|
|
6648
|
+
/***/ }),
|
|
6649
|
+
|
|
5848
6650
|
/***/ 54038:
|
|
5849
6651
|
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
5850
6652
|
|
|
@@ -5861,7 +6663,11 @@ const createAllJobs_1 = __nccwpck_require__(83671);
|
|
|
5861
6663
|
const config_1 = __nccwpck_require__(96925);
|
|
5862
6664
|
const ciVariables_1 = __nccwpck_require__(25474);
|
|
5863
6665
|
const createGithubJobs_1 = __nccwpck_require__(14016);
|
|
6666
|
+
const jobImagesPlan_1 = __nccwpck_require__(11585);
|
|
6667
|
+
const scriptFunctions_1 = __nccwpck_require__(75759);
|
|
6668
|
+
const utils_1 = __nccwpck_require__(20595);
|
|
5864
6669
|
const githubReleaseJobs_1 = __nccwpck_require__(55611);
|
|
6670
|
+
const scriptFiles_1 = __nccwpck_require__(59189);
|
|
5865
6671
|
const WORKFLOWS_FOLDER = ".github/workflows";
|
|
5866
6672
|
/**
|
|
5867
6673
|
* generated workflow files are prefixed so that cleanup never touches
|
|
@@ -5906,18 +6712,29 @@ class GithubBackend {
|
|
|
5906
6712
|
async cleanup() {
|
|
5907
6713
|
const entries = await (0, promises_1.readdir)(WORKFLOWS_FOLDER).catch(() => []);
|
|
5908
6714
|
await Promise.all(entries.filter(file => file.startsWith(GENERATED_FILE_PREFIX)).map(file => (0, promises_1.unlink)((0, path_1.join)(WORKFLOWS_FOLDER, file))));
|
|
6715
|
+
await (0, promises_1.rm)(scriptFiles_1.GITHUB_SCRIPTS_FOLDER, {
|
|
6716
|
+
recursive: true,
|
|
6717
|
+
force: true
|
|
6718
|
+
});
|
|
5909
6719
|
}
|
|
5910
6720
|
async createFiles(config) {
|
|
5911
|
-
const
|
|
5912
|
-
|
|
6721
|
+
const images = this.createImagesPlan(config);
|
|
6722
|
+
const scripts = new scriptFiles_1.GithubScriptFiles();
|
|
6723
|
+
const workflows = await this.createWorkflows(config, images, scripts);
|
|
6724
|
+
return [...Object.entries(workflows).map(([fileName, workflow]) => ({
|
|
5913
6725
|
path: (0, path_1.join)(WORKFLOWS_FOLDER, fileName),
|
|
5914
6726
|
content: workflow
|
|
5915
|
-
}))
|
|
6727
|
+
})),
|
|
6728
|
+
// materialized job scripts and image definitions (repo mode)
|
|
6729
|
+
...scripts.getGeneratedFiles(), ...images.getGeneratedFiles()];
|
|
6730
|
+
}
|
|
6731
|
+
createImagesPlan(config) {
|
|
6732
|
+
return new jobImagesPlan_1.JobImagesPlan((0, jobImagesPlan_1.getJobImagesMode)(config, this.type), this.type);
|
|
5916
6733
|
}
|
|
5917
6734
|
/**
|
|
5918
6735
|
* all workflows keyed by file name, mainly for testing purposes
|
|
5919
6736
|
*/
|
|
5920
|
-
async createWorkflows(config) {
|
|
6737
|
+
async createWorkflows(config, images = this.createImagesPlan(config), scripts = new scriptFiles_1.GithubScriptFiles()) {
|
|
5921
6738
|
const workflows = {};
|
|
5922
6739
|
const reviewStopJobs = {};
|
|
5923
6740
|
const manualJobs = {};
|
|
@@ -5928,13 +6745,14 @@ class GithubBackend {
|
|
|
5928
6745
|
pipelineType: this.type
|
|
5929
6746
|
});
|
|
5930
6747
|
const uploadProviderIds = (0, createGithubJobs_1.getUploadProviderIds)(allJobs);
|
|
6748
|
+
const secretKinds = (0, createGithubJobs_1.collectSecretKinds)(allJobs);
|
|
5931
6749
|
const jobs = {};
|
|
5932
6750
|
// NOTE: agent jobs are gitlab-only and skipped on github
|
|
5933
6751
|
[...allJobs.workspaces, ...allJobs.components].forEach(({
|
|
5934
6752
|
context,
|
|
5935
6753
|
jobs: contextJobs
|
|
5936
6754
|
}) => contextJobs.forEach(job => {
|
|
5937
|
-
const [id, githubJob] = (0, createGithubJobs_1.makeGithubJob)(context, job, allJobs, uploadProviderIds);
|
|
6755
|
+
const [id, githubJob] = (0, createGithubJobs_1.makeGithubJob)(context, job, allJobs, uploadProviderIds, images, scripts, secretKinds);
|
|
5938
6756
|
if (isReviewStopJob(context, job)) {
|
|
5939
6757
|
reviewStopJobs[id] = githubJob;
|
|
5940
6758
|
} else if (isManualTaskJob(job)) {
|
|
@@ -5944,15 +6762,19 @@ class GithubBackend {
|
|
|
5944
6762
|
}
|
|
5945
6763
|
}));
|
|
5946
6764
|
if (trigger === "mainBranch") {
|
|
5947
|
-
const releaseJobs = (0, githubReleaseJobs_1.getGithubReleaseJobs)(config, Object.keys(jobs));
|
|
6765
|
+
const releaseJobs = (0, githubReleaseJobs_1.getGithubReleaseJobs)(config, Object.keys(jobs), images);
|
|
5948
6766
|
Object.assign(jobs, releaseJobs.main);
|
|
5949
6767
|
Object.assign(manualJobs, releaseJobs.manual);
|
|
5950
6768
|
}
|
|
5951
6769
|
if (Object.keys(jobs).length > 0) {
|
|
5952
6770
|
workflows[`${GENERATED_FILE_PREFIX}${workflowFileName(trigger)}`] = {
|
|
5953
6771
|
...TRIGGER_WORKFLOWS[trigger],
|
|
6772
|
+
...workflowPermissions(images),
|
|
5954
6773
|
env: ciVariables_1.GITHUB_INJECTED_WORKFLOW_ENV,
|
|
5955
|
-
jobs
|
|
6774
|
+
jobs: {
|
|
6775
|
+
...makeEnsureImageGithubJobs(images),
|
|
6776
|
+
...jobs
|
|
6777
|
+
}
|
|
5956
6778
|
};
|
|
5957
6779
|
}
|
|
5958
6780
|
}
|
|
@@ -5964,8 +6786,12 @@ class GithubBackend {
|
|
|
5964
6786
|
types: ["closed"]
|
|
5965
6787
|
}
|
|
5966
6788
|
},
|
|
6789
|
+
...workflowPermissions(images),
|
|
5967
6790
|
env: ciVariables_1.GITHUB_INJECTED_WORKFLOW_ENV,
|
|
5968
|
-
jobs:
|
|
6791
|
+
jobs: {
|
|
6792
|
+
...makeEnsureImageGithubJobs(images),
|
|
6793
|
+
...reviewStopJobs
|
|
6794
|
+
}
|
|
5969
6795
|
};
|
|
5970
6796
|
}
|
|
5971
6797
|
if (Object.keys(manualJobs).length > 0) {
|
|
@@ -5983,17 +6809,51 @@ class GithubBackend {
|
|
|
5983
6809
|
}
|
|
5984
6810
|
}
|
|
5985
6811
|
},
|
|
6812
|
+
...workflowPermissions(images),
|
|
5986
6813
|
env: ciVariables_1.GITHUB_INJECTED_WORKFLOW_ENV,
|
|
5987
|
-
jobs:
|
|
5988
|
-
...
|
|
5989
|
-
|
|
5990
|
-
|
|
6814
|
+
jobs: {
|
|
6815
|
+
...makeEnsureImageGithubJobs(images),
|
|
6816
|
+
...Object.fromEntries(Object.entries(manualJobs).map(([id, job]) => [id, {
|
|
6817
|
+
...job,
|
|
6818
|
+
if: `\${{ inputs.job == '${id}' }}`
|
|
6819
|
+
}]))
|
|
6820
|
+
}
|
|
5991
6821
|
};
|
|
5992
6822
|
}
|
|
5993
6823
|
return workflows;
|
|
5994
6824
|
}
|
|
5995
6825
|
}
|
|
5996
6826
|
exports.GithubBackend = GithubBackend;
|
|
6827
|
+
/**
|
|
6828
|
+
* repo mode needs packages:write for pushing job images to ghcr
|
|
6829
|
+
*/
|
|
6830
|
+
const workflowPermissions = images => images.mode === "repo" ? {
|
|
6831
|
+
permissions: {
|
|
6832
|
+
contents: "read",
|
|
6833
|
+
packages: "write"
|
|
6834
|
+
}
|
|
6835
|
+
} : {};
|
|
6836
|
+
/**
|
|
6837
|
+
* the image build jobs: always run (github has no server-side
|
|
6838
|
+
* changes-filter), the existence check makes unchanged runs fast.
|
|
6839
|
+
* Docker is native on github runners — no container, no dind.
|
|
6840
|
+
*/
|
|
6841
|
+
const makeEnsureImageGithubJobs = images => Object.fromEntries(images.getEnsureJobs().map(job => {
|
|
6842
|
+
var _a, _b;
|
|
6843
|
+
return [(0, createGithubJobs_1.githubGlobalJobId)(job.name), {
|
|
6844
|
+
name: job.name,
|
|
6845
|
+
"runs-on": "ubuntu-latest",
|
|
6846
|
+
steps: [{
|
|
6847
|
+
name: "Checkout",
|
|
6848
|
+
uses: "actions/checkout@v4"
|
|
6849
|
+
}, {
|
|
6850
|
+
name: job.name,
|
|
6851
|
+
id: "main",
|
|
6852
|
+
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"),
|
|
6853
|
+
shell: "bash"
|
|
6854
|
+
}]
|
|
6855
|
+
}];
|
|
6856
|
+
}));
|
|
5997
6857
|
const workflowFileName = trigger => {
|
|
5998
6858
|
switch (trigger) {
|
|
5999
6859
|
case "mr":
|
|
@@ -6044,7 +6904,8 @@ exports.GITHUB_CI_VARIABLES = {
|
|
|
6044
6904
|
jobToken: "CL_JOB_TOKEN",
|
|
6045
6905
|
jobImage: "CL_JOB_IMAGE",
|
|
6046
6906
|
registry: "CL_REGISTRY",
|
|
6047
|
-
registryImage: "CL_REGISTRY_IMAGE"
|
|
6907
|
+
registryImage: "CL_REGISTRY_IMAGE",
|
|
6908
|
+
registryUser: "CL_REGISTRY_USER"
|
|
6048
6909
|
};
|
|
6049
6910
|
/**
|
|
6050
6911
|
* the workflow-level env the backend injects to provide the CL_*
|
|
@@ -6054,6 +6915,7 @@ exports.GITHUB_INJECTED_WORKFLOW_ENV = {
|
|
|
6054
6915
|
CL_JOB_TOKEN: "${{ github.token }}",
|
|
6055
6916
|
CL_REGISTRY: "ghcr.io",
|
|
6056
6917
|
CL_REGISTRY_IMAGE: "ghcr.io/${{ github.repository }}",
|
|
6918
|
+
CL_REGISTRY_USER: "${{ github.actor }}",
|
|
6057
6919
|
// empty outside of pull request events
|
|
6058
6920
|
CL_PR_NUMBER: "${{ github.event.number }}"
|
|
6059
6921
|
};
|
|
@@ -6069,7 +6931,7 @@ exports.GITHUB_INJECTED_WORKFLOW_ENV = {
|
|
|
6069
6931
|
Object.defineProperty(exports, "__esModule", ({
|
|
6070
6932
|
value: true
|
|
6071
6933
|
}));
|
|
6072
|
-
exports.getUploadProviderIds = exports.makeGithubJob = exports.resolveGithubNeeds = exports.githubJobId = void 0;
|
|
6934
|
+
exports.getUploadProviderIds = exports.makeGithubJob = exports.collectSecretKinds = exports.resolveGithubNeeds = exports.githubGlobalJobId = exports.githubJobId = void 0;
|
|
6073
6935
|
const lodash_es_1 = __nccwpck_require__(64284);
|
|
6074
6936
|
const getInjectVarsScript_1 = __nccwpck_require__(90436);
|
|
6075
6937
|
const createJobCache_1 = __nccwpck_require__(65644);
|
|
@@ -6077,6 +6939,7 @@ const getEnvironmentVariables_1 = __nccwpck_require__(85855);
|
|
|
6077
6939
|
const utils_1 = __nccwpck_require__(20595);
|
|
6078
6940
|
const gitlab_1 = __nccwpck_require__(13468);
|
|
6079
6941
|
const scriptFunctions_1 = __nccwpck_require__(75759);
|
|
6942
|
+
const ciVariables_1 = __nccwpck_require__(25474);
|
|
6080
6943
|
/**
|
|
6081
6944
|
* runner variables that only make sense on gitlab runners and must not
|
|
6082
6945
|
* leak into github jobs (docker-in-docker daemon config, kubernetes
|
|
@@ -6095,6 +6958,9 @@ const slug = value => {
|
|
|
6095
6958
|
};
|
|
6096
6959
|
const githubJobId = (context, jobName) => slug(`${context.type === "workspace" ? "ws-" : ""}${context.name}-${jobName}-${context.env}`);
|
|
6097
6960
|
exports.githubJobId = githubJobId;
|
|
6961
|
+
/** id of a job without component/workspace context (e.g. image builds) */
|
|
6962
|
+
const githubGlobalJobId = jobName => slug(jobName);
|
|
6963
|
+
exports.githubGlobalJobId = githubGlobalJobId;
|
|
6098
6964
|
const githubJobName = (context, jobName) => `${context.name} ${jobName} | ${context.env}`;
|
|
6099
6965
|
const resolveNeed = (context, need, allJobs) => {
|
|
6100
6966
|
var _a;
|
|
@@ -6116,6 +6982,12 @@ const resolveNeed = (context, need, allJobs) => {
|
|
|
6116
6982
|
return (0, exports.githubJobId)(provider.context, jobName);
|
|
6117
6983
|
};
|
|
6118
6984
|
if ((0, lodash_es_1.isObject)(need)) {
|
|
6985
|
+
if ("global" in need && need.global) {
|
|
6986
|
+
return {
|
|
6987
|
+
id: (0, exports.githubGlobalJobId)(need.job),
|
|
6988
|
+
artifacts: need.artifacts
|
|
6989
|
+
};
|
|
6990
|
+
}
|
|
6119
6991
|
if ("workspaceName" in need && need.workspaceName) {
|
|
6120
6992
|
return {
|
|
6121
6993
|
id: findWorkspaceJob(need.workspaceName, need.job),
|
|
@@ -6133,9 +7005,9 @@ const resolveNeed = (context, need, allJobs) => {
|
|
|
6133
7005
|
artifacts: true
|
|
6134
7006
|
};
|
|
6135
7007
|
};
|
|
6136
|
-
const resolveGithubNeeds = (context, job, allJobs) => {
|
|
7008
|
+
const resolveGithubNeeds = (context, job, allJobs, extraNeeds = []) => {
|
|
6137
7009
|
var _a;
|
|
6138
|
-
const resolved = ((_a = job.needs) !== null && _a !== void 0 ? _a : []).map(need => resolveNeed(context, need, allJobs));
|
|
7010
|
+
const resolved = [...extraNeeds, ...((_a = job.needs) !== null && _a !== void 0 ? _a : [])].map(need => resolveNeed(context, need, allJobs));
|
|
6139
7011
|
// deduplicate by provider id, explicit entries win (they come last)
|
|
6140
7012
|
return [...new Map(resolved.map(n => [n.id, n])).values()].sort((a, b) => a.id.localeCompare(b.id));
|
|
6141
7013
|
};
|
|
@@ -6176,29 +7048,73 @@ const createCacheSteps = (context, job) => {
|
|
|
6176
7048
|
};
|
|
6177
7049
|
});
|
|
6178
7050
|
};
|
|
6179
|
-
|
|
7051
|
+
/**
|
|
7052
|
+
* how a vault-stored value reaches the job env: masked github secret,
|
|
7053
|
+
* or plain (unmasked) github variable for non-sensitive values — those
|
|
7054
|
+
* stay readable in logs and usable in environment urls
|
|
7055
|
+
*/
|
|
7056
|
+
const vaultValueExpression = (name, kinds) => kinds.get(name) === "variable" ? `\${{ vars.${name} }}` : `\${{ secrets.${name} }}`;
|
|
7057
|
+
/**
|
|
7058
|
+
* the kind of every vault-stored var of all components, keyed by its
|
|
7059
|
+
* CL_* name — the lookup for cross-component references
|
|
7060
|
+
*/
|
|
7061
|
+
const collectSecretKinds = allJobs => {
|
|
7062
|
+
const kinds = new Map();
|
|
7063
|
+
allJobs.components.forEach(({
|
|
7064
|
+
context
|
|
7065
|
+
}) => {
|
|
7066
|
+
var _a, _b;
|
|
7067
|
+
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 : [])];
|
|
7068
|
+
entries.forEach(({
|
|
7069
|
+
key,
|
|
7070
|
+
kind
|
|
7071
|
+
}) => kinds.set((0, getEnvironmentVariables_1.getSecretVarName)(context.env, context.name, key), kind !== null && kind !== void 0 ? kind : "secret"));
|
|
7072
|
+
});
|
|
7073
|
+
return kinds;
|
|
7074
|
+
};
|
|
7075
|
+
exports.collectSecretKinds = collectSecretKinds;
|
|
7076
|
+
const getSecretsEnv = (context, kinds) => {
|
|
6180
7077
|
var _a, _b;
|
|
6181
7078
|
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 : [])];
|
|
6182
7079
|
return Object.fromEntries(keys.map(({
|
|
6183
7080
|
key
|
|
6184
7081
|
}) => {
|
|
6185
7082
|
const name = (0, getEnvironmentVariables_1.getSecretVarName)(context.env, context.name, key);
|
|
6186
|
-
return [name,
|
|
7083
|
+
return [name, vaultValueExpression(name, kinds)];
|
|
6187
7084
|
}));
|
|
6188
7085
|
};
|
|
6189
|
-
|
|
7086
|
+
/**
|
|
7087
|
+
* every CL_* variable the job script reads must exist in the job env.
|
|
7088
|
+
* On gitlab all project variables are implicitly available in every
|
|
7089
|
+
* job — cross-component references (`${other-component:KEY}`) rely on
|
|
7090
|
+
* that. Github jobs only see what is injected explicitly, so the
|
|
7091
|
+
* script is scanned for the names it actually references.
|
|
7092
|
+
*/
|
|
7093
|
+
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)]));
|
|
7094
|
+
const makeGithubJob = (context, job, allJobs, uploadProviderIds, images, scripts, secretKinds = new Map()) => {
|
|
6190
7095
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
6191
7096
|
const id = (0, exports.githubJobId)(context, job.name);
|
|
6192
7097
|
const isComponent = context.type === "component";
|
|
6193
7098
|
const createsJobEnv = !!job.environment && isComponent && (!job.environment.action || job.environment.action === "start");
|
|
6194
7099
|
const skipCheckout = ((_a = job.runnerVariables) === null || _a === void 0 ? void 0 : _a.GIT_STRATEGY) === "none";
|
|
6195
|
-
const
|
|
6196
|
-
const
|
|
7100
|
+
const resolved = images.resolve(job.image);
|
|
7101
|
+
const needs = (0, exports.resolveGithubNeeds)(context, job, allJobs, resolved.need ? [resolved.need] : []);
|
|
7102
|
+
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;
|
|
6197
7103
|
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");
|
|
7104
|
+
// scripts live in committed files to keep workflows under github's
|
|
7105
|
+
// 512 KB limit. Two classes of jobs must keep their script inline:
|
|
7106
|
+
// jobs without a checkout have no repo files, and `${{ }}` expressions
|
|
7107
|
+
// are only interpolated inside the workflow file itself.
|
|
7108
|
+
const run = skipCheckout || runScript.includes("${{") ? runScript : scripts.add(id, runScript);
|
|
6198
7109
|
const artifactPaths = (_g = (_f = job.artifacts) === null || _f === void 0 ? void 0 : _f.paths) !== null && _g !== void 0 ? _g : [];
|
|
6199
|
-
const
|
|
7110
|
+
const declaredServices = ((_h = job.services) !== null && _h !== void 0 ? _h : []).map(service => typeof service === "string" ? {
|
|
6200
7111
|
name: service
|
|
6201
|
-
} : service)
|
|
7112
|
+
} : service);
|
|
7113
|
+
// docker runs natively on github runners, so gitlab's docker-in-docker
|
|
7114
|
+
// services are dropped. The job container stays: the runner mounts the
|
|
7115
|
+
// host's docker socket into it, and images like docker-build carry the
|
|
7116
|
+
// helper scripts (ensure*Dockerfile etc.) the job scripts rely on.
|
|
7117
|
+
const services = Object.fromEntries(declaredServices.filter(service => !isDindService(service.name)).map(service => [slug("alias" in service && service.alias ? service.alias : service.name), {
|
|
6202
7118
|
image: service.name,
|
|
6203
7119
|
...("variables" in service && service.variables ? {
|
|
6204
7120
|
env: service.variables
|
|
@@ -6206,7 +7122,8 @@ const makeGithubJob = (context, job, allJobs, uploadProviderIds) => {
|
|
|
6206
7122
|
}]));
|
|
6207
7123
|
const env = {
|
|
6208
7124
|
...Object.fromEntries(Object.entries((_j = job.runnerVariables) !== null && _j !== void 0 ? _j : {}).filter(([key]) => !GITLAB_ONLY_RUNNER_VARIABLES.has(key))),
|
|
6209
|
-
...(isComponent ? getSecretsEnv(context) : {}),
|
|
7125
|
+
...(isComponent ? getSecretsEnv(context, secretKinds) : {}),
|
|
7126
|
+
...getReferencedSecretsEnv(runScript, secretKinds),
|
|
6210
7127
|
CL_JOB_IMAGE: image !== null && image !== void 0 ? image : "runner"
|
|
6211
7128
|
};
|
|
6212
7129
|
const githubJob = {
|
|
@@ -6217,7 +7134,14 @@ const makeGithubJob = (context, job, allJobs, uploadProviderIds) => {
|
|
|
6217
7134
|
} : {}),
|
|
6218
7135
|
...(image ? {
|
|
6219
7136
|
container: {
|
|
6220
|
-
image
|
|
7137
|
+
image,
|
|
7138
|
+
// private images in the repo's registry need credentials
|
|
7139
|
+
...(resolved.fromRepoRegistry ? {
|
|
7140
|
+
credentials: {
|
|
7141
|
+
username: "${{ github.actor }}",
|
|
7142
|
+
password: "${{ github.token }}"
|
|
7143
|
+
}
|
|
7144
|
+
} : {})
|
|
6221
7145
|
}
|
|
6222
7146
|
} : {}),
|
|
6223
7147
|
...(Object.keys(services).length > 0 ? {
|
|
@@ -6244,7 +7168,7 @@ const makeGithubJob = (context, job, allJobs, uploadProviderIds) => {
|
|
|
6244
7168
|
})), {
|
|
6245
7169
|
name: job.name,
|
|
6246
7170
|
id: "main",
|
|
6247
|
-
run
|
|
7171
|
+
run,
|
|
6248
7172
|
shell: "bash"
|
|
6249
7173
|
}, ...(uploadProviderIds.has(id) || artifactPaths.length > 0 ? artifactPaths.length > 0 ? [{
|
|
6250
7174
|
name: "Upload artifacts",
|
|
@@ -6252,7 +7176,11 @@ const makeGithubJob = (context, job, allJobs, uploadProviderIds) => {
|
|
|
6252
7176
|
with: {
|
|
6253
7177
|
name: id,
|
|
6254
7178
|
path: artifactPaths.join("\n"),
|
|
6255
|
-
"if-no-files-found": "warn"
|
|
7179
|
+
"if-no-files-found": "warn",
|
|
7180
|
+
// gitlab artifacts include everything; upload-artifact
|
|
7181
|
+
// silently drops hidden files by default — which is
|
|
7182
|
+
// exactly where next.js builds live (.next)
|
|
7183
|
+
"include-hidden-files": true
|
|
6256
7184
|
}
|
|
6257
7185
|
}] : [] : [])]
|
|
6258
7186
|
};
|
|
@@ -6285,36 +7213,49 @@ Object.defineProperty(exports, "__esModule", ({
|
|
|
6285
7213
|
value: true
|
|
6286
7214
|
}));
|
|
6287
7215
|
exports.getGithubReleaseJobs = void 0;
|
|
6288
|
-
const
|
|
6289
|
-
const createReleaseJob = needs =>
|
|
6290
|
-
|
|
6291
|
-
|
|
6292
|
-
|
|
6293
|
-
|
|
6294
|
-
|
|
6295
|
-
|
|
6296
|
-
permissions: {
|
|
6297
|
-
contents: "write"
|
|
6298
|
-
},
|
|
6299
|
-
...(needs && needs.length > 0 ? {
|
|
6300
|
-
needs
|
|
6301
|
-
} : {}),
|
|
6302
|
-
env: {
|
|
6303
|
-
GITHUB_TOKEN: "${{ github.token }}"
|
|
6304
|
-
},
|
|
6305
|
-
steps: [{
|
|
6306
|
-
name: "Checkout",
|
|
6307
|
-
uses: "actions/checkout@v4",
|
|
6308
|
-
// semantic-release needs the full history to determine the version
|
|
6309
|
-
with: {
|
|
6310
|
-
"fetch-depth": 0
|
|
6311
|
-
}
|
|
6312
|
-
}, {
|
|
7216
|
+
const createGithubJobs_1 = __nccwpck_require__(14016);
|
|
7217
|
+
const createReleaseJob = (images, needs) => {
|
|
7218
|
+
const resolved = images.resolveRef({
|
|
7219
|
+
catladderImage: "semantic-release"
|
|
7220
|
+
});
|
|
7221
|
+
const imageNeeds = resolved.need && typeof resolved.need === "object" ? [(0, createGithubJobs_1.githubGlobalJobId)(resolved.need.job)] : [];
|
|
7222
|
+
const allNeeds = [...imageNeeds, ...(needs !== null && needs !== void 0 ? needs : [])];
|
|
7223
|
+
return {
|
|
6313
7224
|
name: "create release",
|
|
6314
|
-
|
|
6315
|
-
|
|
6316
|
-
|
|
6317
|
-
|
|
7225
|
+
"runs-on": "ubuntu-latest",
|
|
7226
|
+
container: {
|
|
7227
|
+
image: resolved.image,
|
|
7228
|
+
...(resolved.fromRepoRegistry ? {
|
|
7229
|
+
credentials: {
|
|
7230
|
+
username: "${{ github.actor }}",
|
|
7231
|
+
password: "${{ github.token }}"
|
|
7232
|
+
}
|
|
7233
|
+
} : {})
|
|
7234
|
+
},
|
|
7235
|
+
// semantic-release pushes the version tag and release commit
|
|
7236
|
+
permissions: {
|
|
7237
|
+
contents: "write"
|
|
7238
|
+
},
|
|
7239
|
+
...(allNeeds.length > 0 ? {
|
|
7240
|
+
needs: allNeeds
|
|
7241
|
+
} : {}),
|
|
7242
|
+
env: {
|
|
7243
|
+
GITHUB_TOKEN: "${{ github.token }}"
|
|
7244
|
+
},
|
|
7245
|
+
steps: [{
|
|
7246
|
+
name: "Checkout",
|
|
7247
|
+
uses: "actions/checkout@v4",
|
|
7248
|
+
// semantic-release needs the full history to determine the version
|
|
7249
|
+
with: {
|
|
7250
|
+
"fetch-depth": 0
|
|
7251
|
+
}
|
|
7252
|
+
}, {
|
|
7253
|
+
name: "create release",
|
|
7254
|
+
run: "semanticRelease",
|
|
7255
|
+
shell: "bash"
|
|
7256
|
+
}]
|
|
7257
|
+
};
|
|
7258
|
+
};
|
|
6318
7259
|
/**
|
|
6319
7260
|
* the release jobs for the github backend (the counterpart of the
|
|
6320
7261
|
* gitlab release jobs):
|
|
@@ -6324,22 +7265,22 @@ const createReleaseJob = needs => ({
|
|
|
6324
7265
|
* - otherwise (manual, the default): the release job goes to the
|
|
6325
7266
|
* manual tasks workflow
|
|
6326
7267
|
*/
|
|
6327
|
-
const getGithubReleaseJobs = (config, mainWorkflowJobIds) => {
|
|
7268
|
+
const getGithubReleaseJobs = (config, mainWorkflowJobIds, images) => {
|
|
6328
7269
|
var _a;
|
|
6329
7270
|
if (((_a = config.releases) === null || _a === void 0 ? void 0 : _a.when) === "auto") {
|
|
6330
7271
|
return {
|
|
6331
7272
|
main: {
|
|
6332
|
-
"create-release": createReleaseJob(mainWorkflowJobIds)
|
|
7273
|
+
"create-release": createReleaseJob(images, mainWorkflowJobIds)
|
|
6333
7274
|
},
|
|
6334
7275
|
manual: {
|
|
6335
|
-
"force-create-release": createReleaseJob()
|
|
7276
|
+
"force-create-release": createReleaseJob(images)
|
|
6336
7277
|
}
|
|
6337
7278
|
};
|
|
6338
7279
|
}
|
|
6339
7280
|
return {
|
|
6340
7281
|
main: {},
|
|
6341
7282
|
manual: {
|
|
6342
|
-
"create-release": createReleaseJob()
|
|
7283
|
+
"create-release": createReleaseJob(images)
|
|
6343
7284
|
}
|
|
6344
7285
|
};
|
|
6345
7286
|
};
|
|
@@ -6377,6 +7318,64 @@ Object.defineProperty(exports, "__esModule", ({
|
|
|
6377
7318
|
}));
|
|
6378
7319
|
__exportStar(__nccwpck_require__(54038), exports);
|
|
6379
7320
|
__exportStar(__nccwpck_require__(25474), exports);
|
|
7321
|
+
__exportStar(__nccwpck_require__(59189), exports);
|
|
7322
|
+
|
|
7323
|
+
/***/ }),
|
|
7324
|
+
|
|
7325
|
+
/***/ 59189:
|
|
7326
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
7327
|
+
|
|
7328
|
+
"use strict";
|
|
7329
|
+
|
|
7330
|
+
|
|
7331
|
+
Object.defineProperty(exports, "__esModule", ({
|
|
7332
|
+
value: true
|
|
7333
|
+
}));
|
|
7334
|
+
exports.GithubScriptFiles = exports.GITHUB_SCRIPTS_FOLDER = void 0;
|
|
7335
|
+
const path_1 = __nccwpck_require__(16928);
|
|
7336
|
+
/**
|
|
7337
|
+
* folder for job scripts materialized into the repository (committed,
|
|
7338
|
+
* like the image definitions). Owned entirely by the github backend.
|
|
7339
|
+
*/
|
|
7340
|
+
exports.GITHUB_SCRIPTS_FOLDER = ".catladder-generated/github/scripts";
|
|
7341
|
+
/**
|
|
7342
|
+
* github silently ignores workflow files larger than 512 KB — no run,
|
|
7343
|
+
* no check suite, no error. Inlining every job's bash script blows past
|
|
7344
|
+
* that limit on bigger projects, so job scripts are materialized into
|
|
7345
|
+
* committed files and the workflow step only invokes them.
|
|
7346
|
+
*
|
|
7347
|
+
* Scripts containing `${{ ... }}` expressions must stay inline: the
|
|
7348
|
+
* runner only interpolates expressions in the workflow file itself,
|
|
7349
|
+
* never in files read at runtime.
|
|
7350
|
+
*/
|
|
7351
|
+
class GithubScriptFiles {
|
|
7352
|
+
constructor() {
|
|
7353
|
+
this.files = new Map();
|
|
7354
|
+
}
|
|
7355
|
+
/**
|
|
7356
|
+
* materializes a job script into a committed file and returns the
|
|
7357
|
+
* step command invoking it
|
|
7358
|
+
*/
|
|
7359
|
+
add(jobId, script) {
|
|
7360
|
+
const path = (0, path_1.join)(exports.GITHUB_SCRIPTS_FOLDER, `${jobId}.sh`);
|
|
7361
|
+
// `shell: bash` steps run with `bash -eo pipefail`; the script file
|
|
7362
|
+
// must fail exactly like the inline version did
|
|
7363
|
+
const content = `#!/usr/bin/env bash\nset -eo pipefail\n\n${script}\n`;
|
|
7364
|
+
const existing = this.files.get(path);
|
|
7365
|
+
if (existing !== undefined && existing !== content) {
|
|
7366
|
+
throw new Error(`conflicting scripts for job id '${jobId}'`);
|
|
7367
|
+
}
|
|
7368
|
+
this.files.set(path, content);
|
|
7369
|
+
return `bash ${path}`;
|
|
7370
|
+
}
|
|
7371
|
+
getGeneratedFiles() {
|
|
7372
|
+
return [...this.files.entries()].map(([path, content]) => ({
|
|
7373
|
+
path,
|
|
7374
|
+
content
|
|
7375
|
+
}));
|
|
7376
|
+
}
|
|
7377
|
+
}
|
|
7378
|
+
exports.GithubScriptFiles = GithubScriptFiles;
|
|
6380
7379
|
|
|
6381
7380
|
/***/ }),
|
|
6382
7381
|
|
|
@@ -6431,6 +7430,7 @@ const promises_1 = __nccwpck_require__(91943);
|
|
|
6431
7430
|
const rules_1 = __nccwpck_require__(44565);
|
|
6432
7431
|
const config_1 = __nccwpck_require__(96925);
|
|
6433
7432
|
const createAllJobs_1 = __nccwpck_require__(83671);
|
|
7433
|
+
const jobImagesPlan_1 = __nccwpck_require__(11585);
|
|
6434
7434
|
const createGitlabJobs_1 = __nccwpck_require__(80512);
|
|
6435
7435
|
const createGitlabPipeline_1 = __nccwpck_require__(61862);
|
|
6436
7436
|
const gitlabReleaseJobs_1 = __nccwpck_require__(35531);
|
|
@@ -6450,31 +7450,38 @@ class GitlabBackend {
|
|
|
6450
7450
|
});
|
|
6451
7451
|
}
|
|
6452
7452
|
async createFiles(config) {
|
|
6453
|
-
const
|
|
7453
|
+
const images = this.createImagesPlan(config);
|
|
7454
|
+
const includes = await this.createIncludes(config, images);
|
|
6454
7455
|
const mainFile = {
|
|
6455
7456
|
path: ".gitlab-ci.yml",
|
|
6456
7457
|
content: {
|
|
6457
7458
|
include: includes.map(i => i.path)
|
|
6458
7459
|
}
|
|
6459
7460
|
};
|
|
6460
|
-
return [mainFile, ...includes
|
|
7461
|
+
return [mainFile, ...includes,
|
|
7462
|
+
// materialized image definitions (repo mode)
|
|
7463
|
+
...images.getGeneratedFiles()];
|
|
7464
|
+
}
|
|
7465
|
+
createImagesPlan(config) {
|
|
7466
|
+
return new jobImagesPlan_1.JobImagesPlan((0, jobImagesPlan_1.getJobImagesMode)(config, this.type), this.type);
|
|
6461
7467
|
}
|
|
6462
7468
|
/**
|
|
6463
7469
|
* the complete pipeline as one object (all includes merged into one),
|
|
6464
7470
|
* mainly for testing purposes
|
|
6465
7471
|
*/
|
|
6466
7472
|
async createCompletePipeline(config) {
|
|
6467
|
-
const includes = await this.createIncludes(config);
|
|
7473
|
+
const includes = await this.createIncludes(config, this.createImagesPlan(config));
|
|
6468
7474
|
return includes.reduce((acc, {
|
|
6469
7475
|
content
|
|
6470
7476
|
}) => {
|
|
6471
7477
|
return {
|
|
6472
7478
|
...acc,
|
|
7479
|
+
// includes are always yaml objects
|
|
6473
7480
|
...content // merge all includes into one object
|
|
6474
7481
|
};
|
|
6475
7482
|
}, {});
|
|
6476
7483
|
}
|
|
6477
|
-
async createIncludes(config) {
|
|
7484
|
+
async createIncludes(config, images) {
|
|
6478
7485
|
const {
|
|
6479
7486
|
jobs,
|
|
6480
7487
|
image,
|
|
@@ -6482,7 +7489,7 @@ class GitlabBackend {
|
|
|
6482
7489
|
variables,
|
|
6483
7490
|
workflow,
|
|
6484
7491
|
...pipelineRest
|
|
6485
|
-
} = await this.createPipeline(config);
|
|
7492
|
+
} = await this.createPipeline(config, images);
|
|
6486
7493
|
// we will create 1 include per component or workspace
|
|
6487
7494
|
// this is for better readability in git diffs and to avoid problems with yaml files beeing too large
|
|
6488
7495
|
// group by context
|
|
@@ -6515,14 +7522,14 @@ class GitlabBackend {
|
|
|
6515
7522
|
};
|
|
6516
7523
|
return [mainInclude, ...componentIncludes];
|
|
6517
7524
|
}
|
|
6518
|
-
async createPipeline(config) {
|
|
7525
|
+
async createPipeline(config, images) {
|
|
6519
7526
|
const stages = (0, getPipelineStages_1.getPipelineStages)(config);
|
|
6520
7527
|
// for all triggers create jobs and add base rules
|
|
6521
7528
|
const allJobsPerTrigger = await Promise.all(config_1.ALL_PIPELINE_TRIGGERS.map(async trigger => await (0, createGitlabJobs_1.createGitlabJobs)(await (0, createAllJobs_1.createAllJobs)({
|
|
6522
7529
|
config,
|
|
6523
7530
|
trigger,
|
|
6524
7531
|
pipelineType: this.type
|
|
6525
|
-
}), getGitlabRulesForTrigger(trigger)))).then(j => j.flat());
|
|
7532
|
+
}), images, getGitlabRulesForTrigger(trigger)))).then(j => j.flat());
|
|
6526
7533
|
const allWorkspaceJobs = allJobsPerTrigger.filter(j => {
|
|
6527
7534
|
var _a;
|
|
6528
7535
|
return ((_a = j.context) === null || _a === void 0 ? void 0 : _a.type) === "workspace";
|
|
@@ -6551,7 +7558,9 @@ class GitlabBackend {
|
|
|
6551
7558
|
var _a;
|
|
6552
7559
|
return ((_a = j.context) === null || _a === void 0 ? void 0 : _a.type) === "agent";
|
|
6553
7560
|
});
|
|
6554
|
-
|
|
7561
|
+
// context-less jobs (image build jobs)
|
|
7562
|
+
const allContextlessJobs = allJobsPerTrigger.filter(j => j.context === null);
|
|
7563
|
+
const allJobs = [...allContextlessJobs, ...allWorkspaceJobs, ...allComponentJobs, ...allGlobalJobs].reduce((acc, {
|
|
6555
7564
|
gitlabJob,
|
|
6556
7565
|
name,
|
|
6557
7566
|
context
|
|
@@ -6665,7 +7674,8 @@ exports.GITLAB_CI_VARIABLES = {
|
|
|
6665
7674
|
jobToken: "CI_JOB_TOKEN",
|
|
6666
7675
|
jobImage: "CI_JOB_IMAGE",
|
|
6667
7676
|
registry: "CI_REGISTRY",
|
|
6668
|
-
registryImage: "CI_REGISTRY_IMAGE"
|
|
7677
|
+
registryImage: "CI_REGISTRY_IMAGE",
|
|
7678
|
+
registryUser: "CI_REGISTRY_USER"
|
|
6669
7679
|
};
|
|
6670
7680
|
|
|
6671
7681
|
/***/ }),
|
|
@@ -6734,7 +7744,7 @@ const getFullReferencedJobNameFromWorkspace = (referencedJobName, workspaceName,
|
|
|
6734
7744
|
});
|
|
6735
7745
|
};
|
|
6736
7746
|
const getJobName = need => (0, lodash_es_1.isObject)(need) ? need.job : need;
|
|
6737
|
-
const makeGitlabJob = (context, job, allJobs, baseRules) => {
|
|
7747
|
+
const makeGitlabJob = (context, job, allJobs, images, baseRules) => {
|
|
6738
7748
|
var _a, _b;
|
|
6739
7749
|
const {
|
|
6740
7750
|
environment,
|
|
@@ -6752,8 +7762,14 @@ const makeGitlabJob = (context, job, allJobs, baseRules) => {
|
|
|
6752
7762
|
allow_failure: jobAllowFailure,
|
|
6753
7763
|
cache: jobCache,
|
|
6754
7764
|
caches,
|
|
7765
|
+
image: jobImage,
|
|
6755
7766
|
...rest
|
|
6756
7767
|
} = job;
|
|
7768
|
+
// catladder image references resolve according to the jobImages mode;
|
|
7769
|
+
// in repo mode the job additionally depends on the image build job
|
|
7770
|
+
const resolvedImage = images.resolve(jobImage);
|
|
7771
|
+
const image = resolvedImage.image;
|
|
7772
|
+
const imageNeeds = resolvedImage.need ? [resolvedImage.need] : [];
|
|
6757
7773
|
// the neutral `gate` translates to gitlab's when/allow_failure;
|
|
6758
7774
|
// explicitly set gitlab fields take precedence
|
|
6759
7775
|
const when = jobWhen !== null && jobWhen !== void 0 ? jobWhen : gate ? gate === "manual" ? "manual" : "on_success" : undefined;
|
|
@@ -6762,7 +7778,7 @@ const makeGitlabJob = (context, job, allJobs, baseRules) => {
|
|
|
6762
7778
|
// an explicitly set gitlab `cache` takes precedence
|
|
6763
7779
|
const cache = jobCache !== null && jobCache !== void 0 ? jobCache : caches && context.type !== "agent" ? (0, createJobCache_1.createJobCacheFromCacheConfigs)(context, caches) : undefined;
|
|
6764
7780
|
const stage = envMode === "stagePerEnv" && context.type !== "agent" ? `${job.stage} ${context.env}` : job.stage;
|
|
6765
|
-
const deduplicatedGitlabNeeds = getGitlabNeeds(context, job, allJobs);
|
|
7781
|
+
const deduplicatedGitlabNeeds = getGitlabNeeds(context, job, allJobs, imageNeeds);
|
|
6766
7782
|
const fullJobName = getFullJobName({
|
|
6767
7783
|
type: context.type,
|
|
6768
7784
|
name,
|
|
@@ -6791,6 +7807,7 @@ const makeGitlabJob = (context, job, allJobs, baseRules) => {
|
|
|
6791
7807
|
retry: defaults_1.BASE_RETRY,
|
|
6792
7808
|
interruptible: true,
|
|
6793
7809
|
...rest,
|
|
7810
|
+
image,
|
|
6794
7811
|
allow_failure,
|
|
6795
7812
|
cache: cache ? (0, cache_1.addCacheFallback)(cache, context) : undefined,
|
|
6796
7813
|
rules: rules.length > 0 ? rules : undefined,
|
|
@@ -6866,13 +7883,13 @@ const addGitlabEnvironment = (context, catladderJobEnvironment, job, allJobs) =>
|
|
|
6866
7883
|
script: [...((_b = job.script) !== null && _b !== void 0 ? _b : []), ...(createsJobEnv ? scriptToAdd : [])]
|
|
6867
7884
|
};
|
|
6868
7885
|
};
|
|
6869
|
-
const createGitlabJobs = async (allJobs, baseRules) => {
|
|
6870
|
-
|
|
7886
|
+
const createGitlabJobs = async (allJobs, images, baseRules) => {
|
|
7887
|
+
const contextualJobs = [...allJobs.workspaces, ...allJobs.components, ...allJobs.agents].flatMap(({
|
|
6871
7888
|
context,
|
|
6872
7889
|
jobs
|
|
6873
7890
|
}) => {
|
|
6874
7891
|
return jobs.map(job => {
|
|
6875
|
-
const [fullJobName, gitlabJob] = (0, exports.makeGitlabJob)(context, job, allJobs, baseRules);
|
|
7892
|
+
const [fullJobName, gitlabJob] = (0, exports.makeGitlabJob)(context, job, allJobs, images, baseRules);
|
|
6876
7893
|
return {
|
|
6877
7894
|
name: fullJobName,
|
|
6878
7895
|
gitlabJob,
|
|
@@ -6880,13 +7897,66 @@ const createGitlabJobs = async (allJobs, baseRules) => {
|
|
|
6880
7897
|
};
|
|
6881
7898
|
});
|
|
6882
7899
|
});
|
|
7900
|
+
// image build jobs (repo mode): no context, plain names, their
|
|
7901
|
+
// rules:changes combined with the trigger rules
|
|
7902
|
+
const imageJobs = images.getEnsureJobs().map(job => ({
|
|
7903
|
+
name: job.name,
|
|
7904
|
+
gitlabJob: makeEnsureImageGitlabJob(job, baseRules),
|
|
7905
|
+
context: null
|
|
7906
|
+
}));
|
|
7907
|
+
return [...imageJobs, ...contextualJobs];
|
|
6883
7908
|
};
|
|
6884
7909
|
exports.createGitlabJobs = createGitlabJobs;
|
|
6885
|
-
|
|
7910
|
+
/**
|
|
7911
|
+
* lowers an image build job: only runs when the (generated) image
|
|
7912
|
+
* definition changed, within the trigger's base rules
|
|
7913
|
+
*/
|
|
7914
|
+
const makeEnsureImageGitlabJob = (job, baseRules) => {
|
|
7915
|
+
var _a, _b, _c, _d;
|
|
7916
|
+
const changes = (_b = (_a = job.rules) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.changes;
|
|
7917
|
+
const rules = (baseRules !== null && baseRules !== void 0 ? baseRules : []).map(baseRule => baseRule.when === "never" ? baseRule : {
|
|
7918
|
+
...baseRule,
|
|
7919
|
+
changes
|
|
7920
|
+
});
|
|
7921
|
+
return (0, removeUndefined_1.removeUndefined)({
|
|
7922
|
+
retry: defaults_1.BASE_RETRY,
|
|
7923
|
+
interruptible: true,
|
|
7924
|
+
image: job.image,
|
|
7925
|
+
services: job.services,
|
|
7926
|
+
rules: rules.length > 0 ? rules : [{
|
|
7927
|
+
changes
|
|
7928
|
+
}],
|
|
7929
|
+
variables: job.runnerVariables,
|
|
7930
|
+
script: (_d = (_c = job.script) === null || _c === void 0 ? void 0 : _c.filter(utils_1.notNil)) !== null && _d !== void 0 ? _d : [],
|
|
7931
|
+
stage: job.stage,
|
|
7932
|
+
needs: []
|
|
7933
|
+
});
|
|
7934
|
+
};
|
|
7935
|
+
function getGitlabNeeds(context, job, allJobs, extraNeeds = []) {
|
|
6886
7936
|
var _a;
|
|
6887
|
-
const
|
|
7937
|
+
const jobWithExtraNeeds = extraNeeds.length > 0 ? {
|
|
7938
|
+
...job,
|
|
7939
|
+
needs: [...extraNeeds, ...((_a = job.needs) !== null && _a !== void 0 ? _a : [])]
|
|
7940
|
+
} : job;
|
|
7941
|
+
const needs = context.type === "workspace" ? getGitlabNeedsForWorkspaceJob(context, jobWithExtraNeeds, allJobs) : context.type === "agent" ? mapAgentNeeds(jobWithExtraNeeds.needs) : getGitlabNeedsForComponentJob(context, jobWithExtraNeeds, allJobs);
|
|
6888
7942
|
return needs ? deduplicateNeeds(needs) : undefined;
|
|
6889
7943
|
}
|
|
7944
|
+
/**
|
|
7945
|
+
* agent jobs use their needs as-is; global needs (image build jobs)
|
|
7946
|
+
* keep their plain name and optional flag
|
|
7947
|
+
*/
|
|
7948
|
+
function mapAgentNeeds(needs) {
|
|
7949
|
+
if (!needs) {
|
|
7950
|
+
return null;
|
|
7951
|
+
}
|
|
7952
|
+
return needs.map(n => (0, lodash_es_1.isObject)(n) && "global" in n && n.global ? {
|
|
7953
|
+
job: n.job,
|
|
7954
|
+
artifacts: n.artifacts,
|
|
7955
|
+
...(n.optional ? {
|
|
7956
|
+
optional: true
|
|
7957
|
+
} : {})
|
|
7958
|
+
} : n);
|
|
7959
|
+
}
|
|
6890
7960
|
function deduplicateNeeds(needs) {
|
|
6891
7961
|
return needs ? [...new Map(needs.map(n => [(0, lodash_es_1.isObject)(n) ? n.job : n, n])).values()] : undefined;
|
|
6892
7962
|
}
|
|
@@ -6895,11 +7965,19 @@ function getGitlabNeedsForComponentJob(context, {
|
|
|
6895
7965
|
}, allJobs) {
|
|
6896
7966
|
return (needs !== null && needs !== void 0 ? needs : []).map(n => {
|
|
6897
7967
|
var _a;
|
|
6898
|
-
return (0, lodash_es_1.isObject)(n) ? "
|
|
7968
|
+
return (0, lodash_es_1.isObject)(n) ? "global" in n && n.global ?
|
|
7969
|
+
// global jobs (e.g. image builds) keep their plain name
|
|
7970
|
+
{
|
|
7971
|
+
job: n.job,
|
|
7972
|
+
artifacts: n.artifacts,
|
|
7973
|
+
...(n.optional ? {
|
|
7974
|
+
optional: true
|
|
7975
|
+
} : {})
|
|
7976
|
+
} : "workspaceName" in n && n.workspaceName ? {
|
|
6899
7977
|
job: getFullReferencedJobNameFromWorkspace(n.job, n.workspaceName, context.env, allJobs),
|
|
6900
7978
|
artifacts: n.artifacts
|
|
6901
7979
|
} : {
|
|
6902
|
-
job: getFullReferencedJobNameFromComponent(n.job, (_a = n.componentName) !== null && _a !== void 0 ? _a : context.name, context.env, allJobs),
|
|
7980
|
+
job: getFullReferencedJobNameFromComponent(n.job, "componentName" in n ? (_a = n.componentName) !== null && _a !== void 0 ? _a : context.name : context.name, context.env, allJobs),
|
|
6903
7981
|
artifacts: n.artifacts
|
|
6904
7982
|
} : getFullReferencedJobNameFromComponent(n, context.name, context.env, allJobs);
|
|
6905
7983
|
}) // sort in a predictable manner for snapshot tests
|
|
@@ -6912,7 +7990,13 @@ function getGitlabNeedsForComponentJob(context, {
|
|
|
6912
7990
|
function getGitlabNeedsForWorkspaceJob(context, {
|
|
6913
7991
|
needs
|
|
6914
7992
|
}, allJobs) {
|
|
6915
|
-
return (needs !== null && needs !== void 0 ? needs : []).map(n => (0, lodash_es_1.isObject)(n) ? {
|
|
7993
|
+
return (needs !== null && needs !== void 0 ? needs : []).map(n => (0, lodash_es_1.isObject)(n) ? "global" in n && n.global ? {
|
|
7994
|
+
job: n.job,
|
|
7995
|
+
artifacts: n.artifacts,
|
|
7996
|
+
...(n.optional ? {
|
|
7997
|
+
optional: true
|
|
7998
|
+
} : {})
|
|
7999
|
+
} : {
|
|
6916
8000
|
job: getFullReferencedJobNameFromWorkspace(n.job, "workspaceName" in n && n.workspaceName ? n.workspaceName : context.name, context.env, allJobs),
|
|
6917
8001
|
artifacts: n.artifacts
|
|
6918
8002
|
} : getFullReferencedJobNameFromWorkspace(n, context.name, context.env, allJobs)) // sort in a predictable manner for snapshot tests
|
|
@@ -6941,7 +8025,7 @@ const createGitlabPipelineWithDefaults = ({
|
|
|
6941
8025
|
...config
|
|
6942
8026
|
}) => {
|
|
6943
8027
|
return {
|
|
6944
|
-
image: image !== null && image !== void 0 ? image : (0, runner_1.
|
|
8028
|
+
image: image !== null && image !== void 0 ? image : (0, runner_1.getCentralRunnerImageUrl)("jobs-default"),
|
|
6945
8029
|
// default image
|
|
6946
8030
|
variables: {
|
|
6947
8031
|
FF_USE_FASTZIP: "true",
|
|
@@ -7044,7 +8128,7 @@ const getGitlabReleaseJobs = config => {
|
|
|
7044
8128
|
return {
|
|
7045
8129
|
["create release"]: {
|
|
7046
8130
|
stage: "release",
|
|
7047
|
-
image: (0, runner_1.
|
|
8131
|
+
image: (0, runner_1.getCentralRunnerImageUrl)("semantic-release"),
|
|
7048
8132
|
script: ["semanticRelease"],
|
|
7049
8133
|
after_script: [EXPIRED_TOKEN_HELP],
|
|
7050
8134
|
rules: [...baseReleaseRules, {
|
|
@@ -7057,7 +8141,7 @@ const getGitlabReleaseJobs = config => {
|
|
|
7057
8141
|
},
|
|
7058
8142
|
["⚠️ force create release"]: {
|
|
7059
8143
|
stage: "release",
|
|
7060
|
-
image: (0, runner_1.
|
|
8144
|
+
image: (0, runner_1.getCentralRunnerImageUrl)("semantic-release"),
|
|
7061
8145
|
script: ["semanticRelease"],
|
|
7062
8146
|
after_script: [EXPIRED_TOKEN_HELP],
|
|
7063
8147
|
needs: [],
|
|
@@ -7163,7 +8247,7 @@ var __exportStar = this && this.__exportStar || function (m, exports) {
|
|
|
7163
8247
|
Object.defineProperty(exports, "__esModule", ({
|
|
7164
8248
|
value: true
|
|
7165
8249
|
}));
|
|
7166
|
-
exports.getEnabledPipelineTypes = exports.getPipelineBackend = void 0;
|
|
8250
|
+
exports.getEnabledPipelineTypes = exports.getVaultConfig = exports.getPipelineGitRemote = exports.getPipelineOptions = exports.getPipelineBackend = void 0;
|
|
7167
8251
|
const github_1 = __nccwpck_require__(99635);
|
|
7168
8252
|
const gitlab_1 = __nccwpck_require__(8475);
|
|
7169
8253
|
__exportStar(__nccwpck_require__(92474), exports);
|
|
@@ -7181,6 +8265,38 @@ const getPipelineBackend = type => {
|
|
|
7181
8265
|
return createBackend();
|
|
7182
8266
|
};
|
|
7183
8267
|
exports.getPipelineBackend = getPipelineBackend;
|
|
8268
|
+
/**
|
|
8269
|
+
* the options of an enabled pipeline type (empty object when enabled
|
|
8270
|
+
* with `true`)
|
|
8271
|
+
*/
|
|
8272
|
+
const getPipelineOptions = (config, type) => {
|
|
8273
|
+
var _a;
|
|
8274
|
+
const value = (_a = config.pipelines) === null || _a === void 0 ? void 0 : _a[type];
|
|
8275
|
+
return typeof value === "object" ? value : {};
|
|
8276
|
+
};
|
|
8277
|
+
exports.getPipelineOptions = getPipelineOptions;
|
|
8278
|
+
/**
|
|
8279
|
+
* the git remote pointing to the repository of this pipeline type's CI
|
|
8280
|
+
* system (e.g. during a migration, gitlab may be `origin` and github a
|
|
8281
|
+
* second remote)
|
|
8282
|
+
*/
|
|
8283
|
+
const getPipelineGitRemote = (config, type) => {
|
|
8284
|
+
var _a;
|
|
8285
|
+
return (_a = (0, exports.getPipelineOptions)(config, type).gitRemote) !== null && _a !== void 0 ? _a : "origin";
|
|
8286
|
+
};
|
|
8287
|
+
exports.getPipelineGitRemote = getPipelineGitRemote;
|
|
8288
|
+
/**
|
|
8289
|
+
* the normalized secrets vault of a config (string shorthands resolved
|
|
8290
|
+
* to their object form; defaults to the legacy gitlab store)
|
|
8291
|
+
*/
|
|
8292
|
+
const getVaultConfig = config => {
|
|
8293
|
+
var _a, _b;
|
|
8294
|
+
const vault = (_b = (_a = config.secrets) === null || _a === void 0 ? void 0 : _a.vault) !== null && _b !== void 0 ? _b : "gitlab";
|
|
8295
|
+
return typeof vault === "string" ? {
|
|
8296
|
+
type: vault
|
|
8297
|
+
} : vault;
|
|
8298
|
+
};
|
|
8299
|
+
exports.getVaultConfig = getVaultConfig;
|
|
7184
8300
|
/**
|
|
7185
8301
|
* the pipeline types enabled for this config. Multiple types can be
|
|
7186
8302
|
* enabled at once (parallel generation, e.g. during a CI migration).
|
|
@@ -8768,7 +9884,10 @@ const getYarnInstallCommand = async context => {
|
|
|
8768
9884
|
// inline builds make debugging easier as it prints it out in the logs, instead of writing it in temp files
|
|
8769
9885
|
return `yarn install --immutable --inline-builds`;
|
|
8770
9886
|
};
|
|
8771
|
-
const ensureNodeVersion = context => (0, gitlab_1.collapseableSection)("nodeinstall", "Ensure node version")([
|
|
9887
|
+
const ensureNodeVersion = context => (0, gitlab_1.collapseableSection)("nodeinstall", "Ensure node version")([
|
|
9888
|
+
// github actions overrides HOME in container jobs, so also look
|
|
9889
|
+
// for nvm where the catladder images install it (/root/.nvm)
|
|
9890
|
+
'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"]);
|
|
8772
9891
|
exports.ensureNodeVersion = ensureNodeVersion;
|
|
8773
9892
|
const getYarnInstall = async (context, options) => {
|
|
8774
9893
|
const postInstall = context.type !== "workspace" && context.build.type !== "disabled" && "postInstall" in context.build.config ? context.build.config.postInstall : null;
|
|
@@ -9147,7 +10266,7 @@ Object.defineProperty(exports, "__esModule", ({
|
|
|
9147
10266
|
value: true
|
|
9148
10267
|
}));
|
|
9149
10268
|
exports.DOCKER_REGISTRY = exports.PIPELINE_IMAGE_TAG = void 0;
|
|
9150
|
-
exports.PIPELINE_IMAGE_TAG = "next-
|
|
10269
|
+
exports.PIPELINE_IMAGE_TAG = "next-6a4450e0" || 0;
|
|
9151
10270
|
exports.DOCKER_REGISTRY = "git.panter.ch:5001/catladder/catladder" || 0;
|
|
9152
10271
|
|
|
9153
10272
|
/***/ }),
|
|
@@ -9559,7 +10678,7 @@ const getBasePredefinedVariables = ctx => {
|
|
|
9559
10678
|
};
|
|
9560
10679
|
};
|
|
9561
10680
|
const getEnvironmentVariables = async (ctx, options = {}) => {
|
|
9562
|
-
var _a, _b, _c, _d, _e, _f, _g
|
|
10681
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
9563
10682
|
const environmentContext = (0, getEnvironmentContext_1.getEnvironmentContext)(ctx);
|
|
9564
10683
|
const {
|
|
9565
10684
|
config,
|
|
@@ -9616,13 +10735,13 @@ const getEnvironmentVariables = async (ctx, options = {}) => {
|
|
|
9616
10735
|
}
|
|
9617
10736
|
const publicEnvVarsRaw = (_e = (_d = envConfigRaw.vars) === null || _d === void 0 ? void 0 : _d.public) !== null && _e !== void 0 ? _e : {};
|
|
9618
10737
|
const additionalSecretKeys = deployConfigRaw ? deploy_1.DEPLOY_TYPES[deployConfigRaw.type].additionalSecretKeys(environmentContext) : [];
|
|
9619
|
-
const secretEnvVarKeys = [...(0, envVars_1.
|
|
10738
|
+
const secretEnvVarKeys = [...(0, envVars_1.normalizeSecretVarsConfig)((_f = envConfigRaw.vars) === null || _f === void 0 ? void 0 : _f.secret), ...additionalSecretKeys];
|
|
9620
10739
|
const secretEnvVars = (0, envVars_1.makeSecretEnvVarMapping)(env, componentName, secretEnvVarKeys);
|
|
9621
10740
|
const publicEnvVarsRawSanitized = (0, envVars_1.stringifyValues)(publicEnvVarsRaw);
|
|
9622
10741
|
const publicEnvVarsUnresolved = Object.fromEntries(Object.entries(publicEnvVarsRawSanitized).map(([key, value]) => [key, (0, VariableValueContainingReferences_1.createVariableValueContainingReferencesFromString)(value, {
|
|
9623
10742
|
componentName: ctx.componentName
|
|
9624
10743
|
})]));
|
|
9625
|
-
const publicEnvVars = ((
|
|
10744
|
+
const publicEnvVars = ((_g = options.shouldResolveReferences) !== null && _g !== void 0 ? _g : true) ? await (0, resolveAllReferences_1.resolveAllReferences)(publicEnvVarsUnresolved, async otherComponentName => {
|
|
9626
10745
|
const {
|
|
9627
10746
|
envVars: otherEnvVars
|
|
9628
10747
|
} = await (0, exports.getEnvironmentVariables)({
|
|
@@ -9782,7 +10901,7 @@ const envVars_1 = __nccwpck_require__(94946);
|
|
|
9782
10901
|
* @returns
|
|
9783
10902
|
*/
|
|
9784
10903
|
const transformJobOnlyVars = async (env, componentName, vars) => {
|
|
9785
|
-
var _a
|
|
10904
|
+
var _a;
|
|
9786
10905
|
if (!vars) {
|
|
9787
10906
|
return {
|
|
9788
10907
|
envVars: {},
|
|
@@ -9790,7 +10909,7 @@ const transformJobOnlyVars = async (env, componentName, vars) => {
|
|
|
9790
10909
|
};
|
|
9791
10910
|
}
|
|
9792
10911
|
const publicVars = (0, envVars_1.stringifyValues)((_a = vars === null || vars === void 0 ? void 0 : vars.public) !== null && _a !== void 0 ? _a : {});
|
|
9793
|
-
const secretEnvVarKeys = (0, envVars_1.
|
|
10912
|
+
const secretEnvVarKeys = (0, envVars_1.normalizeSecretVarsConfig)(vars === null || vars === void 0 ? void 0 : vars.secret);
|
|
9794
10913
|
const deployJobOnlySecretEnvVars = (vars === null || vars === void 0 ? void 0 : vars.secret) ? (0, envVars_1.makeSecretEnvVarMapping)(env, componentName, secretEnvVarKeys) : {};
|
|
9795
10914
|
const envVars = {
|
|
9796
10915
|
...deployJobOnlySecretEnvVars,
|
|
@@ -9814,7 +10933,7 @@ exports.transformJobOnlyVars = transformJobOnlyVars;
|
|
|
9814
10933
|
Object.defineProperty(exports, "__esModule", ({
|
|
9815
10934
|
value: true
|
|
9816
10935
|
}));
|
|
9817
|
-
exports.makeSecretEnvVarMapping = exports.stringListToSecreteEnvVarList = exports.stringifyValues = void 0;
|
|
10936
|
+
exports.makeSecretEnvVarMapping = exports.normalizeSecretVarsConfig = exports.stringListToSecreteEnvVarList = exports.stringifyValues = void 0;
|
|
9818
10937
|
const lodash_es_1 = __nccwpck_require__(64284);
|
|
9819
10938
|
const getEnvironmentVariables_1 = __nccwpck_require__(85855);
|
|
9820
10939
|
const BashExpression_1 = __nccwpck_require__(25354);
|
|
@@ -9824,6 +10943,27 @@ const stringListToSecreteEnvVarList = keys => keys.map(key => ({
|
|
|
9824
10943
|
key
|
|
9825
10944
|
}));
|
|
9826
10945
|
exports.stringListToSecreteEnvVarList = stringListToSecreteEnvVarList;
|
|
10946
|
+
/**
|
|
10947
|
+
* normalizes both config forms of vault-stored env vars: the deprecated
|
|
10948
|
+
* plain string[] (all keys secret) and the record form carrying a kind
|
|
10949
|
+
* (or config object) per key
|
|
10950
|
+
*/
|
|
10951
|
+
const normalizeSecretVarsConfig = secret => {
|
|
10952
|
+
if (!secret) {
|
|
10953
|
+
return [];
|
|
10954
|
+
}
|
|
10955
|
+
if (Array.isArray(secret)) {
|
|
10956
|
+
return (0, exports.stringListToSecreteEnvVarList)(secret);
|
|
10957
|
+
}
|
|
10958
|
+
return Object.entries(secret).map(([key, config]) => typeof config === "string" ? {
|
|
10959
|
+
key,
|
|
10960
|
+
kind: config
|
|
10961
|
+
} : {
|
|
10962
|
+
key,
|
|
10963
|
+
...config
|
|
10964
|
+
});
|
|
10965
|
+
};
|
|
10966
|
+
exports.normalizeSecretVarsConfig = normalizeSecretVarsConfig;
|
|
9827
10967
|
const makeSecretEnvVarMapping = (env, componentName, secretEnvVars) => {
|
|
9828
10968
|
return Object.fromEntries(secretEnvVars.map(({
|
|
9829
10969
|
key
|
|
@@ -9833,6 +10973,330 @@ exports.makeSecretEnvVarMapping = makeSecretEnvVarMapping;
|
|
|
9833
10973
|
|
|
9834
10974
|
/***/ }),
|
|
9835
10975
|
|
|
10976
|
+
/***/ 53231:
|
|
10977
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
10978
|
+
|
|
10979
|
+
"use strict";
|
|
10980
|
+
|
|
10981
|
+
|
|
10982
|
+
Object.defineProperty(exports, "__esModule", ({
|
|
10983
|
+
value: true
|
|
10984
|
+
}));
|
|
10985
|
+
exports.computeCustomImageHash = void 0;
|
|
10986
|
+
const crypto_1 = __nccwpck_require__(76982);
|
|
10987
|
+
const fs_1 = __nccwpck_require__(79896);
|
|
10988
|
+
const path_1 = __nccwpck_require__(16928);
|
|
10989
|
+
const IGNORED_FILES = new Set([".DS_Store", "Thumbs.db"]);
|
|
10990
|
+
const isIgnoredFile = path => {
|
|
10991
|
+
var _a;
|
|
10992
|
+
return IGNORED_FILES.has((_a = path.split("/").pop()) !== null && _a !== void 0 ? _a : "");
|
|
10993
|
+
};
|
|
10994
|
+
function listFilesRecursive(dir) {
|
|
10995
|
+
const resolved = (0, path_1.resolve)(dir);
|
|
10996
|
+
const entries = (0, fs_1.readdirSync)(resolved, {
|
|
10997
|
+
recursive: true,
|
|
10998
|
+
encoding: "utf-8"
|
|
10999
|
+
});
|
|
11000
|
+
return entries.filter(entry => {
|
|
11001
|
+
if (isIgnoredFile(entry)) {
|
|
11002
|
+
// OS junk files exist locally but not in CI checkouts — they
|
|
11003
|
+
// must never influence the content hash
|
|
11004
|
+
return false;
|
|
11005
|
+
}
|
|
11006
|
+
const fullPath = (0, path_1.join)(resolved, entry);
|
|
11007
|
+
return (0, fs_1.statSync)(fullPath).isFile();
|
|
11008
|
+
}).sort();
|
|
11009
|
+
}
|
|
11010
|
+
function computeCustomImageHash(config) {
|
|
11011
|
+
var _a;
|
|
11012
|
+
const hash = (0, crypto_1.createHash)("sha256");
|
|
11013
|
+
const watchedPaths = [];
|
|
11014
|
+
// Hash all files in the dir (includes the Dockerfile and any context files)
|
|
11015
|
+
const dirFiles = listFilesRecursive(config.dir);
|
|
11016
|
+
for (const file of dirFiles) {
|
|
11017
|
+
const fullPath = (0, path_1.join)((0, path_1.resolve)(config.dir), file);
|
|
11018
|
+
hash.update(file); // include relative path for disambiguation
|
|
11019
|
+
hash.update((0, fs_1.readFileSync)(fullPath));
|
|
11020
|
+
}
|
|
11021
|
+
watchedPaths.push(`${config.dir}/**/*`);
|
|
11022
|
+
// extra dirs (e.g. included base image definitions)
|
|
11023
|
+
for (const extraDir of (_a = config.extraDirs) !== null && _a !== void 0 ? _a : []) {
|
|
11024
|
+
for (const file of listFilesRecursive(extraDir)) {
|
|
11025
|
+
hash.update(file);
|
|
11026
|
+
hash.update((0, fs_1.readFileSync)((0, path_1.join)((0, path_1.resolve)(extraDir), file)));
|
|
11027
|
+
}
|
|
11028
|
+
watchedPaths.push(`${extraDir}/**/*`);
|
|
11029
|
+
}
|
|
11030
|
+
// Hash extra paths (for files outside the dir)
|
|
11031
|
+
if (config.hashExtraPaths) {
|
|
11032
|
+
// Extra paths are literal file paths (not globs) for simplicity
|
|
11033
|
+
const extraFiles = [...config.hashExtraPaths].sort();
|
|
11034
|
+
for (const file of extraFiles) {
|
|
11035
|
+
hash.update(file);
|
|
11036
|
+
hash.update((0, fs_1.readFileSync)(file));
|
|
11037
|
+
}
|
|
11038
|
+
watchedPaths.push(...config.hashExtraPaths);
|
|
11039
|
+
}
|
|
11040
|
+
// Hash build args (sorted keys for determinism)
|
|
11041
|
+
if (config.buildArgs) {
|
|
11042
|
+
const sorted = Object.entries(config.buildArgs).sort(([a], [b]) => a.localeCompare(b));
|
|
11043
|
+
hash.update(JSON.stringify(sorted));
|
|
11044
|
+
}
|
|
11045
|
+
return {
|
|
11046
|
+
hash: hash.digest("hex").slice(0, 12),
|
|
11047
|
+
watchedPaths
|
|
11048
|
+
};
|
|
11049
|
+
}
|
|
11050
|
+
exports.computeCustomImageHash = computeCustomImageHash;
|
|
11051
|
+
|
|
11052
|
+
/***/ }),
|
|
11053
|
+
|
|
11054
|
+
/***/ 11585:
|
|
11055
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
11056
|
+
|
|
11057
|
+
"use strict";
|
|
11058
|
+
|
|
11059
|
+
|
|
11060
|
+
Object.defineProperty(exports, "__esModule", ({
|
|
11061
|
+
value: true
|
|
11062
|
+
}));
|
|
11063
|
+
exports.JobImagesPlan = exports.getJobImagesMode = exports.GENERATED_IMAGES_FOLDER = void 0;
|
|
11064
|
+
const fs_1 = __nccwpck_require__(79896);
|
|
11065
|
+
const path_1 = __nccwpck_require__(16928);
|
|
11066
|
+
const ciVariables_1 = __nccwpck_require__(14489);
|
|
11067
|
+
const docker_1 = __nccwpck_require__(12764);
|
|
11068
|
+
const constants_1 = __nccwpck_require__(43480);
|
|
11069
|
+
const runner_1 = __nccwpck_require__(92348);
|
|
11070
|
+
const gitlab_1 = __nccwpck_require__(13468);
|
|
11071
|
+
const hash_1 = __nccwpck_require__(53231);
|
|
11072
|
+
const shippedImages_1 = __nccwpck_require__(77734);
|
|
11073
|
+
exports.GENERATED_IMAGES_FOLDER = ".catladder-generated/images";
|
|
11074
|
+
/**
|
|
11075
|
+
* the official docker cli image used to build the job images — NOT a
|
|
11076
|
+
* catladder image, so building images never depends on one (bootstrap)
|
|
11077
|
+
*/
|
|
11078
|
+
const BUILDER_IMAGE = "docker.io/docker:29.5.1";
|
|
11079
|
+
const getJobImagesMode = (config, pipelineType) => {
|
|
11080
|
+
var _a;
|
|
11081
|
+
// the central registry is not reachable from github runners
|
|
11082
|
+
if (pipelineType === "github" && config.jobImages === "central") {
|
|
11083
|
+
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.`);
|
|
11084
|
+
}
|
|
11085
|
+
return (_a = config.jobImages) !== null && _a !== void 0 ? _a : pipelineType === "github" ? "repo" : "central";
|
|
11086
|
+
};
|
|
11087
|
+
exports.getJobImagesMode = getJobImagesMode;
|
|
11088
|
+
const ensureJobName = name => `🐳 job image ${name}`;
|
|
11089
|
+
/**
|
|
11090
|
+
* plans the catladder job images of one backend run: resolves image
|
|
11091
|
+
* references, and (in repo mode) collects the image build jobs and the
|
|
11092
|
+
* image definitions to materialize into the generated files.
|
|
11093
|
+
*
|
|
11094
|
+
* Reference-driven: only images actually used by a job are built.
|
|
11095
|
+
*/
|
|
11096
|
+
class JobImagesPlan {
|
|
11097
|
+
constructor(mode, pipelineType) {
|
|
11098
|
+
this.mode = mode;
|
|
11099
|
+
this.pipelineType = pipelineType;
|
|
11100
|
+
this.used = new Map();
|
|
11101
|
+
}
|
|
11102
|
+
/**
|
|
11103
|
+
* resolves a job image (marker or concrete) to a concrete image url
|
|
11104
|
+
* plus the build job dependency in repo mode
|
|
11105
|
+
*/
|
|
11106
|
+
resolve(image) {
|
|
11107
|
+
if (!(0, runner_1.isCatladderImageRef)(image)) {
|
|
11108
|
+
return {
|
|
11109
|
+
image
|
|
11110
|
+
};
|
|
11111
|
+
}
|
|
11112
|
+
return this.resolveRef(image);
|
|
11113
|
+
}
|
|
11114
|
+
resolveRef(ref) {
|
|
11115
|
+
const name = ref.catladderImage;
|
|
11116
|
+
if (this.mode === "central" || shippedImages_1.CENTRAL_ONLY_IMAGES.has(name)) {
|
|
11117
|
+
return {
|
|
11118
|
+
image: (0, runner_1.getCentralRunnerImageUrl)(name)
|
|
11119
|
+
};
|
|
11120
|
+
}
|
|
11121
|
+
const {
|
|
11122
|
+
hash
|
|
11123
|
+
} = this.use(name);
|
|
11124
|
+
return {
|
|
11125
|
+
image: `${this.registryImageRef()}/catladder/${name}:${hash}`,
|
|
11126
|
+
fromRepoRegistry: true,
|
|
11127
|
+
need: {
|
|
11128
|
+
job: ensureJobName(name),
|
|
11129
|
+
artifacts: false,
|
|
11130
|
+
optional: true,
|
|
11131
|
+
global: true
|
|
11132
|
+
}
|
|
11133
|
+
};
|
|
11134
|
+
}
|
|
11135
|
+
/**
|
|
11136
|
+
* the registry image prefix. On github, container images can't use
|
|
11137
|
+
* runtime env vars — the expression form is required.
|
|
11138
|
+
*/
|
|
11139
|
+
registryImageRef() {
|
|
11140
|
+
return this.pipelineType === "github" ? "ghcr.io/${{ github.repository }}" : `${(0, ciVariables_1.getCiVariable)({
|
|
11141
|
+
pipelineType: this.pipelineType
|
|
11142
|
+
}, "registryImage")}`;
|
|
11143
|
+
}
|
|
11144
|
+
use(name) {
|
|
11145
|
+
var _a;
|
|
11146
|
+
const existing = this.used.get(name);
|
|
11147
|
+
if (existing) {
|
|
11148
|
+
return existing;
|
|
11149
|
+
}
|
|
11150
|
+
const dependencies = (_a = shippedImages_1.RUNNER_IMAGE_DEPENDENCIES[name]) !== null && _a !== void 0 ? _a : [];
|
|
11151
|
+
// dependencies are materialized (and hashed) as part of this image,
|
|
11152
|
+
// but also usable standalone
|
|
11153
|
+
dependencies.forEach(dependency => this.use(dependency));
|
|
11154
|
+
const {
|
|
11155
|
+
hash
|
|
11156
|
+
} = (0, hash_1.computeCustomImageHash)({
|
|
11157
|
+
dir: (0, shippedImages_1.getShippedImageDir)(name),
|
|
11158
|
+
extraDirs: dependencies.map(dependency => (0, shippedImages_1.getShippedImageDir)(dependency))
|
|
11159
|
+
});
|
|
11160
|
+
const entry = {
|
|
11161
|
+
hash
|
|
11162
|
+
};
|
|
11163
|
+
this.used.set(name, entry);
|
|
11164
|
+
return entry;
|
|
11165
|
+
}
|
|
11166
|
+
/**
|
|
11167
|
+
* the image build jobs for all used images (repo mode; empty in
|
|
11168
|
+
* central mode)
|
|
11169
|
+
*/
|
|
11170
|
+
getEnsureJobs() {
|
|
11171
|
+
return [...this.used.entries()].map(([name, {
|
|
11172
|
+
hash
|
|
11173
|
+
}]) => this.createEnsureJob(name, hash));
|
|
11174
|
+
}
|
|
11175
|
+
createEnsureJob(name, hash) {
|
|
11176
|
+
var _a;
|
|
11177
|
+
const ctx = {
|
|
11178
|
+
pipelineType: this.pipelineType
|
|
11179
|
+
};
|
|
11180
|
+
const registryUser = (0, ciVariables_1.getCiVariable)(ctx, "registryUser");
|
|
11181
|
+
const jobToken = (0, ciVariables_1.getCiVariable)(ctx, "jobToken");
|
|
11182
|
+
const registry = (0, ciVariables_1.getCiVariable)(ctx, "registry");
|
|
11183
|
+
const imageRef = `${this.registryImageRef()}/catladder/${name}:${hash}`;
|
|
11184
|
+
const watchedDirs = [name, ...((_a = shippedImages_1.RUNNER_IMAGE_DEPENDENCIES[name]) !== null && _a !== void 0 ? _a : [])];
|
|
11185
|
+
const {
|
|
11186
|
+
services,
|
|
11187
|
+
runnerVariables
|
|
11188
|
+
} = (0, docker_1.getDockerJobBaseProps)();
|
|
11189
|
+
return {
|
|
11190
|
+
name: ensureJobName(name),
|
|
11191
|
+
stage: "setup",
|
|
11192
|
+
image: BUILDER_IMAGE,
|
|
11193
|
+
services,
|
|
11194
|
+
runnerVariables,
|
|
11195
|
+
needs: [],
|
|
11196
|
+
// gitlab: only run when the image definition changed; github has
|
|
11197
|
+
// no equivalent and always runs (the existence check is fast)
|
|
11198
|
+
rules: [{
|
|
11199
|
+
changes: watchedDirs.map(dir => `${exports.GENERATED_IMAGES_FOLDER}/${dir}/**/*`)
|
|
11200
|
+
}],
|
|
11201
|
+
variables: {},
|
|
11202
|
+
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}`])]
|
|
11203
|
+
};
|
|
11204
|
+
}
|
|
11205
|
+
/**
|
|
11206
|
+
* the image definitions of all used images, materialized into the
|
|
11207
|
+
* generated files (so pipelines build from committed, reviewable
|
|
11208
|
+
* files and gitlab's rules:changes can watch them)
|
|
11209
|
+
*/
|
|
11210
|
+
getGeneratedFiles() {
|
|
11211
|
+
return [...this.used.keys()].flatMap(name => {
|
|
11212
|
+
const dir = (0, shippedImages_1.getShippedImageDir)(name);
|
|
11213
|
+
return listFilesRecursive(dir).map(file => ({
|
|
11214
|
+
path: (0, path_1.join)(exports.GENERATED_IMAGES_FOLDER, name, file),
|
|
11215
|
+
content: (0, fs_1.readFileSync)((0, path_1.join)(dir, file), "utf-8")
|
|
11216
|
+
}));
|
|
11217
|
+
});
|
|
11218
|
+
}
|
|
11219
|
+
}
|
|
11220
|
+
exports.JobImagesPlan = JobImagesPlan;
|
|
11221
|
+
const IGNORED_FILES = new Set([".DS_Store", "Thumbs.db"]);
|
|
11222
|
+
const listFilesRecursive = dir => (0, fs_1.readdirSync)(dir, {
|
|
11223
|
+
recursive: true,
|
|
11224
|
+
encoding: "utf-8"
|
|
11225
|
+
}).filter(entry => {
|
|
11226
|
+
var _a;
|
|
11227
|
+
// OS junk files exist locally but not in CI checkouts
|
|
11228
|
+
return !IGNORED_FILES.has((_a = entry.split("/").pop()) !== null && _a !== void 0 ? _a : "") && (0, fs_1.statSync)((0, path_1.join)(dir, entry)).isFile();
|
|
11229
|
+
}).sort();
|
|
11230
|
+
|
|
11231
|
+
/***/ }),
|
|
11232
|
+
|
|
11233
|
+
/***/ 77734:
|
|
11234
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
11235
|
+
|
|
11236
|
+
"use strict";
|
|
11237
|
+
|
|
11238
|
+
|
|
11239
|
+
Object.defineProperty(exports, "__esModule", ({
|
|
11240
|
+
value: true
|
|
11241
|
+
}));
|
|
11242
|
+
exports.getShippedImageDir = exports.getShippedImagesDir = exports.RUNNER_IMAGE_BUILD_CONTEXT = exports.CENTRAL_ONLY_IMAGES = exports.RUNNER_IMAGE_DEPENDENCIES = void 0;
|
|
11243
|
+
const fs_1 = __nccwpck_require__(79896);
|
|
11244
|
+
const path_1 = __nccwpck_require__(16928);
|
|
11245
|
+
/**
|
|
11246
|
+
* images whose Dockerfile INCLUDEs another image's Dockerfile
|
|
11247
|
+
* (dockerfile-x/dockerfile-plus, resolved against the images root as
|
|
11248
|
+
* build context)
|
|
11249
|
+
*/
|
|
11250
|
+
exports.RUNNER_IMAGE_DEPENDENCIES = {
|
|
11251
|
+
"jobs-meteor": ["jobs-default"],
|
|
11252
|
+
"jobs-testing-chrome": ["jobs-default"]
|
|
11253
|
+
};
|
|
11254
|
+
/**
|
|
11255
|
+
* the docker build context of each image, mirroring the central image
|
|
11256
|
+
* builds: the jobs family builds from the images root (their
|
|
11257
|
+
* Dockerfiles INCLUDE sibling images), the others from their own dir
|
|
11258
|
+
* (their COPY paths are relative to it)
|
|
11259
|
+
*/
|
|
11260
|
+
/**
|
|
11261
|
+
* images that cannot be built from the shipped definitions and always
|
|
11262
|
+
* come from the central registry: semantic-release bakes catladder's
|
|
11263
|
+
* own cli sources into the image (repo-root build context).
|
|
11264
|
+
* TODO: make the semantic-release image self-contained.
|
|
11265
|
+
*/
|
|
11266
|
+
exports.CENTRAL_ONLY_IMAGES = new Set(["semantic-release"]);
|
|
11267
|
+
exports.RUNNER_IMAGE_BUILD_CONTEXT = {
|
|
11268
|
+
"jobs-default": "root",
|
|
11269
|
+
"jobs-meteor": "root",
|
|
11270
|
+
"jobs-testing-chrome": "root",
|
|
11271
|
+
kubernetes: "self",
|
|
11272
|
+
"docker-build": "self",
|
|
11273
|
+
gcloud: "self",
|
|
11274
|
+
"semantic-release": "self",
|
|
11275
|
+
"agent-claude": "self"
|
|
11276
|
+
};
|
|
11277
|
+
/**
|
|
11278
|
+
* the directory containing the image definitions shipped with the
|
|
11279
|
+
* package (copied into dist at build time; the repository layout is
|
|
11280
|
+
* the fallback for development and tests)
|
|
11281
|
+
*/
|
|
11282
|
+
const getShippedImagesDir = () => {
|
|
11283
|
+
const candidates = [
|
|
11284
|
+
// built package: dist/customImages -> dist/runner-images
|
|
11285
|
+
(0, path_1.join)(__dirname, "..", "runner-images"),
|
|
11286
|
+
// repository: pipeline/src/customImages -> <root>/runner-images
|
|
11287
|
+
(0, path_1.join)(__dirname, "..", "..", "..", "runner-images")];
|
|
11288
|
+
const found = candidates.find(candidate => (0, fs_1.existsSync)(candidate));
|
|
11289
|
+
if (!found) {
|
|
11290
|
+
throw new Error("shipped job image definitions not found");
|
|
11291
|
+
}
|
|
11292
|
+
return found;
|
|
11293
|
+
};
|
|
11294
|
+
exports.getShippedImagesDir = getShippedImagesDir;
|
|
11295
|
+
const getShippedImageDir = name => (0, path_1.join)((0, exports.getShippedImagesDir)(), name);
|
|
11296
|
+
exports.getShippedImageDir = getShippedImageDir;
|
|
11297
|
+
|
|
11298
|
+
/***/ }),
|
|
11299
|
+
|
|
9836
11300
|
/***/ 84628:
|
|
9837
11301
|
/***/ ((__unused_webpack_module, exports) => {
|
|
9838
11302
|
|
|
@@ -11052,13 +12516,18 @@ exports.GCLOUD_RUN_DEPLOY_TYPE = {
|
|
|
11052
12516
|
}
|
|
11053
12517
|
return {};
|
|
11054
12518
|
},
|
|
11055
|
-
additionalSecretKeys: ctx => [
|
|
12519
|
+
additionalSecretKeys: ctx => [
|
|
12520
|
+
// deploy-time credentials don't exist for the local env
|
|
12521
|
+
...(ctx.envType !== "local" ? [{
|
|
11056
12522
|
key: exports.GCLOUD_DEPLOY_CREDENTIALS_KEY,
|
|
11057
12523
|
hidden: true
|
|
11058
12524
|
}, {
|
|
11059
12525
|
key: exports.GCLOUD_RUN_CANONICAL_HOST_SUFFIX,
|
|
11060
|
-
hidden: true
|
|
11061
|
-
|
|
12526
|
+
hidden: true,
|
|
12527
|
+
// a public url fragment, not sensitive: masking it would
|
|
12528
|
+
// suppress environment urls on github and break log links
|
|
12529
|
+
kind: "variable"
|
|
12530
|
+
}] : []), ...(ctx.deployConfigRaw && ctx.deployConfigRaw.cloudSql ? [{
|
|
11062
12531
|
key: "DB_PASSWORD"
|
|
11063
12532
|
}] : [])],
|
|
11064
12533
|
getAdditionalEnvVars: ctx => {
|
|
@@ -11066,7 +12535,8 @@ exports.GCLOUD_RUN_DEPLOY_TYPE = {
|
|
|
11066
12535
|
fullName,
|
|
11067
12536
|
env,
|
|
11068
12537
|
componentName,
|
|
11069
|
-
deployConfigRaw
|
|
12538
|
+
deployConfigRaw,
|
|
12539
|
+
envType
|
|
11070
12540
|
} = ctx;
|
|
11071
12541
|
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();
|
|
11072
12542
|
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, {
|
|
@@ -11075,7 +12545,11 @@ exports.GCLOUD_RUN_DEPLOY_TYPE = {
|
|
|
11075
12545
|
region: deployConfigRaw.region
|
|
11076
12546
|
})])) : {};
|
|
11077
12547
|
return {
|
|
11078
|
-
|
|
12548
|
+
// references the canonical host suffix secret, which doesn't
|
|
12549
|
+
// exist for the local env
|
|
12550
|
+
...(envType !== "local" ? {
|
|
12551
|
+
HOSTNAME_INTERNAL
|
|
12552
|
+
} : {}),
|
|
11079
12553
|
...getCloudSqlVariables(ctx),
|
|
11080
12554
|
...jobTriggers,
|
|
11081
12555
|
DEPLOY_CLOUD_RUN_SERVICE_NAME: (0, getServiceName_1.getServiceNameForEnvContext)(ctx),
|
|
@@ -11168,7 +12642,10 @@ const getDatabaseDeleteScript = (context, deployConfig) => {
|
|
|
11168
12642
|
// unfortunatly the database cannot be deleted right after the service has stopped, as it might still have connections
|
|
11169
12643
|
// we have to repeate this process
|
|
11170
12644
|
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}`, {
|
|
11171
|
-
pauseInSeconds: 10
|
|
12645
|
+
pauseInSeconds: 10,
|
|
12646
|
+
// connections normally clear within 3-5min; anything beyond is
|
|
12647
|
+
// a permanent error (missing permission, wrong instance, ...)
|
|
12648
|
+
maxAttempts: 30
|
|
11172
12649
|
})];
|
|
11173
12650
|
};
|
|
11174
12651
|
exports.getDatabaseDeleteScript = getDatabaseDeleteScript;
|
|
@@ -12892,6 +14369,7 @@ const promises_1 = __nccwpck_require__(91943);
|
|
|
12892
14369
|
const path_1 = __nccwpck_require__(16928);
|
|
12893
14370
|
const backends_1 = __nccwpck_require__(93243);
|
|
12894
14371
|
const gitlab_1 = __nccwpck_require__(8475);
|
|
14372
|
+
const jobImagesPlan_1 = __nccwpck_require__(11585);
|
|
12895
14373
|
/**
|
|
12896
14374
|
* generates the pipeline files of all pipeline types enabled in the
|
|
12897
14375
|
* config (see `pipelines`). Pass an explicit `pipelineType` to generate
|
|
@@ -12899,6 +14377,16 @@ const gitlab_1 = __nccwpck_require__(8475);
|
|
|
12899
14377
|
*/
|
|
12900
14378
|
async function generatePipelineFiles(context, pipelineType) {
|
|
12901
14379
|
const pipelineTypes = pipelineType ? [pipelineType] : (0, backends_1.getEnabledPipelineTypes)(context.config);
|
|
14380
|
+
if (!pipelineType) {
|
|
14381
|
+
// the materialized image definitions are a union across all enabled
|
|
14382
|
+
// backends and no single backend may wipe them — cleaned once per
|
|
14383
|
+
// full generation, so images that fell out of use don't linger (and
|
|
14384
|
+
// keep triggering gitlab's rules:changes)
|
|
14385
|
+
await (0, promises_1.rm)(jobImagesPlan_1.GENERATED_IMAGES_FOLDER, {
|
|
14386
|
+
recursive: true,
|
|
14387
|
+
force: true
|
|
14388
|
+
});
|
|
14389
|
+
}
|
|
12902
14390
|
for (const type of pipelineTypes) {
|
|
12903
14391
|
await generatePipelineFilesForBackend(context, (0, backends_1.getPipelineBackend)(type));
|
|
12904
14392
|
}
|
|
@@ -12916,7 +14404,11 @@ async function generatePipelineFilesForBackend(context, backend) {
|
|
|
12916
14404
|
await (0, promises_1.mkdir)((0, path_1.dirname)(path), {
|
|
12917
14405
|
recursive: true
|
|
12918
14406
|
});
|
|
12919
|
-
|
|
14407
|
+
if (typeof content === "string") {
|
|
14408
|
+
await context.fileWriter.writeGeneratedFileRaw(path, content);
|
|
14409
|
+
} else {
|
|
14410
|
+
await context.fileWriter.writeYamlfile(path, content);
|
|
14411
|
+
}
|
|
12920
14412
|
}));
|
|
12921
14413
|
}
|
|
12922
14414
|
/**
|
|
@@ -13272,10 +14764,23 @@ exports.RULE_CONDITION_HOTFIX_BRANCH = "$CI_COMMIT_BRANCH =~ /^[0-9]+.([0-9]+|x)
|
|
|
13272
14764
|
Object.defineProperty(exports, "__esModule", ({
|
|
13273
14765
|
value: true
|
|
13274
14766
|
}));
|
|
13275
|
-
exports.getRunnerImage = void 0;
|
|
14767
|
+
exports.getCentralRunnerImageUrl = exports.getRunnerImage = exports.isCatladderImageRef = void 0;
|
|
13276
14768
|
const constants_1 = __nccwpck_require__(43480);
|
|
13277
|
-
const
|
|
14769
|
+
const isCatladderImageRef = value => typeof value === "object" && value !== null && "catladderImage" in value && typeof value.catladderImage === "string";
|
|
14770
|
+
exports.isCatladderImageRef = isCatladderImageRef;
|
|
14771
|
+
/**
|
|
14772
|
+
* job creators use this to reference a catladder-provided job image;
|
|
14773
|
+
* the backends resolve it to a concrete image url
|
|
14774
|
+
*/
|
|
14775
|
+
const getRunnerImage = imageName => ({
|
|
14776
|
+
catladderImage: imageName
|
|
14777
|
+
});
|
|
13278
14778
|
exports.getRunnerImage = getRunnerImage;
|
|
14779
|
+
/**
|
|
14780
|
+
* the image url in catladder's central registry (the classic behavior)
|
|
14781
|
+
*/
|
|
14782
|
+
const getCentralRunnerImageUrl = imageName => constants_1.DOCKER_REGISTRY + "/" + imageName + ":" + constants_1.PIPELINE_IMAGE_TAG;
|
|
14783
|
+
exports.getCentralRunnerImageUrl = getCentralRunnerImageUrl;
|
|
13279
14784
|
|
|
13280
14785
|
/***/ }),
|
|
13281
14786
|
|
|
@@ -13490,8 +14995,14 @@ const sanitizeForBashVariable = name => name.replace(/-/g, "_");
|
|
|
13490
14995
|
exports.sanitizeForBashVariable = sanitizeForBashVariable;
|
|
13491
14996
|
const repeatOnFailure = (command, options) => {
|
|
13492
14997
|
return `
|
|
14998
|
+
_attempt=0
|
|
13493
14999
|
until ${command}
|
|
13494
15000
|
do
|
|
15001
|
+
_attempt=$((_attempt+1))
|
|
15002
|
+
if [ "$_attempt" -ge ${options.maxAttempts} ]; then
|
|
15003
|
+
echo "giving up after ${options.maxAttempts} attempts"
|
|
15004
|
+
exit 1
|
|
15005
|
+
fi
|
|
13495
15006
|
echo "Trying again."
|
|
13496
15007
|
sleep ${options.pauseInSeconds}
|
|
13497
15008
|
done
|
|
@@ -13679,6 +15190,14 @@ class FileWriter {
|
|
|
13679
15190
|
extension: (_b = path.split(".").pop()) !== null && _b !== void 0 ? _b : ""
|
|
13680
15191
|
};
|
|
13681
15192
|
}
|
|
15193
|
+
/**
|
|
15194
|
+
* writes content verbatim (no auto-generated header) — e.g. for
|
|
15195
|
+
* materialized dockerfiles, where a leading comment would break
|
|
15196
|
+
* parser directives like `# syntax = ...`
|
|
15197
|
+
*/
|
|
15198
|
+
async writeGeneratedFileRaw(path, content) {
|
|
15199
|
+
await this.writeTheFile(path, content);
|
|
15200
|
+
}
|
|
13682
15201
|
async writeGeneratedFile(path, content, options) {
|
|
13683
15202
|
await this.writeTheFile(path, [this.getAutoGeneratedHeader(options.commentChar), content].join("\n"));
|
|
13684
15203
|
}
|