@catladder/cli 0.0.0-next-b3e567e8 → 0.0.0-next-dccc0a36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/bundles/catenv/index.js +244 -67
  2. package/dist/bundles/cli/index.js +244 -67
  3. package/dist/bundles/skills/catladder-builds/SKILL.md +49 -2
  4. package/dist/bundles/skills/catladder-builds/references/build-types.md +2 -2
  5. package/dist/bundles/skills/catladder-pipelines/SKILL.md +13 -3
  6. package/dist/packages/pipeline/src/backends/github/GithubBackend.js +4 -4
  7. package/dist/packages/pipeline/src/backends/github/GithubBackend.js.map +1 -1
  8. package/dist/packages/pipeline/src/backends/gitlab/GitlabBackend.js +4 -4
  9. package/dist/packages/pipeline/src/backends/gitlab/GitlabBackend.js.map +1 -1
  10. package/dist/packages/pipeline/src/build/types.d.ts +6 -5
  11. package/dist/packages/pipeline/src/build/types.js.map +1 -1
  12. package/dist/packages/pipeline/src/customImages/hash.d.ts +9 -0
  13. package/dist/packages/pipeline/src/customImages/hash.js +41 -16
  14. package/dist/packages/pipeline/src/customImages/hash.js.map +1 -1
  15. package/dist/packages/pipeline/src/customImages/jobImagesPlan.d.ts +23 -5
  16. package/dist/packages/pipeline/src/customImages/jobImagesPlan.js +177 -43
  17. package/dist/packages/pipeline/src/customImages/jobImagesPlan.js.map +1 -1
  18. package/dist/packages/pipeline/src/customImages/projectImages.d.ts +67 -0
  19. package/dist/packages/pipeline/src/customImages/projectImages.js +9 -0
  20. package/dist/packages/pipeline/src/customImages/projectImages.js.map +1 -0
  21. package/dist/packages/pipeline/src/deploy/types/custom.d.ts +2 -2
  22. package/dist/packages/pipeline/src/deploy/types/index.d.ts +4 -4
  23. package/dist/packages/pipeline/src/deploy/types/pages.d.ts +2 -2
  24. package/dist/packages/pipeline/src/index.d.ts +2 -0
  25. package/dist/packages/pipeline/src/index.js +2 -0
  26. package/dist/packages/pipeline/src/index.js.map +1 -1
  27. package/dist/packages/pipeline/src/types/config.d.ts +8 -0
  28. package/dist/packages/pipeline/src/types/config.js.map +1 -1
  29. package/dist/packages/pipeline/src/types/jobs.d.ts +2 -1
  30. package/dist/packages/pipeline/src/types/jobs.js.map +1 -1
  31. package/dist/skills/catladder-builds/SKILL.md +49 -2
  32. package/dist/skills/catladder-builds/references/build-types.md +2 -2
  33. package/dist/skills/catladder-pipelines/SKILL.md +13 -3
  34. package/dist/tsconfig.tsbuildinfo +1 -1
  35. package/package.json +1 -1
@@ -2321,7 +2321,7 @@ class GithubBackend {
2321
2321
  await (0, promises_1.rm)(scriptFiles_1.GITHUB_SCRIPTS_FOLDER, { recursive: true, force: true });
2322
2322
  }
2323
2323
  async createFiles(config) {
2324
- const images = this.createImagesPlan();
2324
+ const images = this.createImagesPlan(config);
2325
2325
  const scripts = new scriptFiles_1.GithubScriptFiles();
2326
2326
  const workflows = await this.createWorkflows(config, images, scripts);
2327
2327
  return [
@@ -2336,13 +2336,13 @@ class GithubBackend {
2336
2336
  ...(0, shippedCatci_1.getCatciGeneratedFiles)(),
2337
2337
  ];
2338
2338
  }
2339
- createImagesPlan() {
2340
- return new jobImagesPlan_1.JobImagesPlan(this.type);
2339
+ createImagesPlan(config) {
2340
+ return new jobImagesPlan_1.JobImagesPlan(this.type, config.images);
2341
2341
  }
2342
2342
  /**
2343
2343
  * all workflows keyed by file name, mainly for testing purposes
2344
2344
  */
2345
- async createWorkflows(config, images = this.createImagesPlan(), scripts = new scriptFiles_1.GithubScriptFiles()) {
2345
+ async createWorkflows(config, images = this.createImagesPlan(config), scripts = new scriptFiles_1.GithubScriptFiles()) {
2346
2346
  var _a, _b, _c, _d;
2347
2347
  const workflows = {};
2348
2348
  // per-pipeline-type variables (pipelines.github.runnerVariables);
@@ -3311,7 +3311,7 @@ class GitlabBackend {
3311
3311
  await (0, promises_1.rm)(this.generatedFolder, { force: true, recursive: true });
3312
3312
  }
3313
3313
  async createFiles(config) {
3314
- const images = this.createImagesPlan();
3314
+ const images = this.createImagesPlan(config);
3315
3315
  const includes = await this.createIncludes(config, images);
3316
3316
  const mainFile = {
3317
3317
  path: ".gitlab-ci.yml",
@@ -3328,15 +3328,15 @@ class GitlabBackend {
3328
3328
  ...(0, shippedCatci_1.getCatciGeneratedFiles)(),
3329
3329
  ];
3330
3330
  }
3331
- createImagesPlan() {
3332
- return new jobImagesPlan_1.JobImagesPlan(this.type);
3331
+ createImagesPlan(config) {
3332
+ return new jobImagesPlan_1.JobImagesPlan(this.type, config.images);
3333
3333
  }
3334
3334
  /**
3335
3335
  * the complete pipeline as one object (all includes merged into one),
3336
3336
  * mainly for testing purposes
3337
3337
  */
3338
3338
  async createCompletePipeline(config) {
3339
- const includes = await this.createIncludes(config, this.createImagesPlan());
3339
+ const includes = await this.createIncludes(config, this.createImagesPlan(config));
3340
3340
  return includes.reduce((acc, { content }) => {
3341
3341
  return {
3342
3342
  ...acc,
@@ -6981,7 +6981,7 @@ exports.makeSecretEnvVarMapping = makeSecretEnvVarMapping;
6981
6981
  "use strict";
6982
6982
 
6983
6983
  Object.defineProperty(exports, "__esModule", ({ value: true }));
6984
- exports.computeCustomImageHash = void 0;
6984
+ exports.computeInlineImageHash = exports.computeCustomImageHash = void 0;
6985
6985
  const crypto_1 = __nccwpck_require__(76982);
6986
6986
  const fs_1 = __nccwpck_require__(79896);
6987
6987
  const path_1 = __nccwpck_require__(16928);
@@ -7002,6 +7002,29 @@ function listFilesRecursive(dir) {
7002
7002
  })
7003
7003
  .sort();
7004
7004
  }
7005
+ /**
7006
+ * the parts every image definition hashes on top of its content:
7007
+ * files outside the definition, and the build args
7008
+ */
7009
+ function hashExtras(hash, config) {
7010
+ const watchedPaths = [];
7011
+ // Hash extra paths (for files outside the dir)
7012
+ if (config.hashExtraPaths) {
7013
+ // Extra paths are literal file paths (not globs) for simplicity
7014
+ const extraFiles = [...config.hashExtraPaths].sort();
7015
+ for (const file of extraFiles) {
7016
+ hash.update(file);
7017
+ hash.update((0, fs_1.readFileSync)(file));
7018
+ }
7019
+ watchedPaths.push(...config.hashExtraPaths);
7020
+ }
7021
+ // Hash build args (sorted keys for determinism)
7022
+ if (config.buildArgs) {
7023
+ const sorted = Object.entries(config.buildArgs).sort(([a], [b]) => a.localeCompare(b));
7024
+ hash.update(JSON.stringify(sorted));
7025
+ }
7026
+ return watchedPaths;
7027
+ }
7005
7028
  function computeCustomImageHash(config) {
7006
7029
  var _a;
7007
7030
  const hash = (0, crypto_1.createHash)("sha256");
@@ -7022,27 +7045,29 @@ function computeCustomImageHash(config) {
7022
7045
  }
7023
7046
  watchedPaths.push(`${extraDir}/**/*`);
7024
7047
  }
7025
- // Hash extra paths (for files outside the dir)
7026
- if (config.hashExtraPaths) {
7027
- // Extra paths are literal file paths (not globs) for simplicity
7028
- const extraFiles = [...config.hashExtraPaths].sort();
7029
- for (const file of extraFiles) {
7030
- hash.update(file);
7031
- hash.update((0, fs_1.readFileSync)(file));
7032
- }
7033
- watchedPaths.push(...config.hashExtraPaths);
7034
- }
7035
- // Hash build args (sorted keys for determinism)
7036
- if (config.buildArgs) {
7037
- const sorted = Object.entries(config.buildArgs).sort(([a], [b]) => a.localeCompare(b));
7038
- hash.update(JSON.stringify(sorted));
7039
- }
7048
+ watchedPaths.push(...hashExtras(hash, config));
7040
7049
  return {
7041
7050
  hash: hash.digest("hex").slice(0, 12),
7042
7051
  watchedPaths,
7043
7052
  };
7044
7053
  }
7045
7054
  exports.computeCustomImageHash = computeCustomImageHash;
7055
+ /**
7056
+ * the hash of an image defined by an inline Dockerfile: its content
7057
+ * stands in for the definition dir. The build context is deliberately
7058
+ * NOT hashed (it may be the whole repository) — `hashExtraPaths` is how
7059
+ * context files opt into the hash.
7060
+ */
7061
+ function computeInlineImageHash(config) {
7062
+ const hash = (0, crypto_1.createHash)("sha256");
7063
+ hash.update(config.dockerfileContent);
7064
+ const watchedPaths = hashExtras(hash, config);
7065
+ return {
7066
+ hash: hash.digest("hex").slice(0, 12),
7067
+ watchedPaths,
7068
+ };
7069
+ }
7070
+ exports.computeInlineImageHash = computeInlineImageHash;
7046
7071
  //# sourceMappingURL=hash.js.map
7047
7072
 
7048
7073
  /***/ }),
@@ -7053,7 +7078,7 @@ exports.computeCustomImageHash = computeCustomImageHash;
7053
7078
  "use strict";
7054
7079
 
7055
7080
  Object.defineProperty(exports, "__esModule", ({ value: true }));
7056
- exports.JobImagesPlan = exports.GENERATED_IMAGES_FOLDER = void 0;
7081
+ exports.JobImagesPlan = exports.PROJECT_IMAGES_FOLDER = exports.GENERATED_IMAGES_FOLDER = void 0;
7057
7082
  const fs_1 = __nccwpck_require__(79896);
7058
7083
  const path_1 = __nccwpck_require__(16928);
7059
7084
  const ciVariables_1 = __nccwpck_require__(72700);
@@ -7061,6 +7086,7 @@ const docker_1 = __nccwpck_require__(83777);
7061
7086
  const runner_1 = __nccwpck_require__(71065);
7062
7087
  const gitlab_1 = __nccwpck_require__(37393);
7063
7088
  const hash_1 = __nccwpck_require__(34092);
7089
+ const projectImages_1 = __nccwpck_require__(55537);
7064
7090
  const shippedImages_1 = __nccwpck_require__(28687);
7065
7091
  exports.GENERATED_IMAGES_FOLDER = ".catladder-generated/images";
7066
7092
  /**
@@ -7068,7 +7094,44 @@ exports.GENERATED_IMAGES_FOLDER = ".catladder-generated/images";
7068
7094
  * catladder image, so building images never depends on one (bootstrap)
7069
7095
  */
7070
7096
  const BUILDER_IMAGE = "docker.io/docker:29.5.1";
7071
- const ensureJobName = (name) => `🐳 job image ${name}`;
7097
+ /**
7098
+ * every planned image is consumed the same way: its url, plus an
7099
+ * optional dependency on its build job
7100
+ */
7101
+ const toResolvedJobImage = ({ imageRef, jobName, }) => ({
7102
+ image: imageRef,
7103
+ fromRepoRegistry: true,
7104
+ need: {
7105
+ job: jobName,
7106
+ artifacts: false,
7107
+ optional: true,
7108
+ global: true,
7109
+ },
7110
+ });
7111
+ /**
7112
+ * materializes an image definition directory into the generated files
7113
+ * (used for the definitions catladder ships)
7114
+ */
7115
+ const materializeDir = (sourceDir, targetDir) => listFilesRecursive(sourceDir).map((file) => ({
7116
+ path: (0, path_1.join)(targetDir, file),
7117
+ content: (0, fs_1.readFileSync)((0, path_1.join)(sourceDir, file), "utf-8"),
7118
+ }));
7119
+ // built-in (catladder-shipped) images carry the catladder marker in
7120
+ // their job name; project-declared images get the short plain name
7121
+ const ensureJobName = (name) => `🐳 catladder image ${name}`;
7122
+ const projectEnsureJobName = (name) => `🐳 image ${name}`;
7123
+ /**
7124
+ * the config file whose content feeds the project image hashes
7125
+ * (`buildArgs`, `hashExtraPaths`): the gitlab change detection has to
7126
+ * watch it, because a config-only change alters the image tag without
7127
+ * touching the image dir
7128
+ */
7129
+ const CONFIG_FILE = "catladder.ts";
7130
+ /**
7131
+ * where inline project Dockerfiles are materialized — a subfolder, so a
7132
+ * project image can carry the same name as a shipped one
7133
+ */
7134
+ exports.PROJECT_IMAGES_FOLDER = `${exports.GENERATED_IMAGES_FOLDER}/project`;
7072
7135
  /**
7073
7136
  * plans the catladder job images of one backend run: resolves image
7074
7137
  * references, collects the image build jobs, and the image definitions
@@ -7079,33 +7142,30 @@ const ensureJobName = (name) => `🐳 job image ${name}`;
7079
7142
  * Reference-driven: only images actually used by a job are built.
7080
7143
  */
7081
7144
  class JobImagesPlan {
7082
- constructor(pipelineType) {
7145
+ constructor(pipelineType, projectImages = {}) {
7083
7146
  this.pipelineType = pipelineType;
7147
+ this.projectImages = projectImages;
7084
7148
  this.used = new Map();
7149
+ this.usedProject = new Map();
7085
7150
  }
7086
7151
  /**
7087
7152
  * resolves a job image (marker or concrete) to a concrete image url
7088
7153
  * plus the build job dependency
7089
7154
  */
7090
7155
  resolve(image) {
7091
- if (!(0, runner_1.isCatladderImageRef)(image)) {
7092
- return { image };
7156
+ if ((0, runner_1.isCatladderImageRef)(image)) {
7157
+ return this.resolveRef(image);
7158
+ }
7159
+ if ((0, projectImages_1.isProjectImageRef)(image)) {
7160
+ return this.resolveProjectRef(image);
7093
7161
  }
7094
- return this.resolveRef(image);
7162
+ return { image };
7095
7163
  }
7096
7164
  resolveRef(ref) {
7097
- const name = ref.catladderImage;
7098
- const { hash } = this.use(name);
7099
- return {
7100
- image: `${this.registryImageRef()}/catladder/${name}:${hash}`,
7101
- fromRepoRegistry: true,
7102
- need: {
7103
- job: ensureJobName(name),
7104
- artifacts: false,
7105
- optional: true,
7106
- global: true,
7107
- },
7108
- };
7165
+ return toResolvedJobImage(this.use(ref.catladderImage));
7166
+ }
7167
+ resolveProjectRef(ref) {
7168
+ return toResolvedJobImage(this.useProject(ref.image));
7109
7169
  }
7110
7170
  /**
7111
7171
  * the registry image prefix. On github, container images can't use
@@ -7116,6 +7176,85 @@ class JobImagesPlan {
7116
7176
  ? "ghcr.io/${{ github.repository }}"
7117
7177
  : `${(0, ciVariables_1.getCiVariable)({ pipelineType: this.pipelineType }, "registryImage")}`;
7118
7178
  }
7179
+ useProject(name) {
7180
+ const existing = this.usedProject.get(name);
7181
+ if (existing) {
7182
+ return existing;
7183
+ }
7184
+ const imageConfig = this.projectImages[name];
7185
+ if (!imageConfig) {
7186
+ const declared = Object.keys(this.projectImages);
7187
+ throw new Error(`unknown job image "${name}" — ${declared.length > 0
7188
+ ? `images declared in config.images: ${declared.join(", ")}`
7189
+ : "no images are declared in config.images"}`);
7190
+ }
7191
+ const source = this.planProjectSource(name, imageConfig);
7192
+ const planned = {
7193
+ ...source,
7194
+ jobName: projectEnsureJobName(name),
7195
+ buildArgs: imageConfig.buildArgs,
7196
+ // `job-images/` keeps the project's job images apart from its
7197
+ // deployable component images (registry root) and build caches
7198
+ imageRef: `${this.registryImageRef()}/job-images/${name}:${source.hash}`,
7199
+ };
7200
+ this.usedProject.set(name, planned);
7201
+ return planned;
7202
+ }
7203
+ /**
7204
+ * the source-dependent half of a project image: an inline Dockerfile
7205
+ * is materialized into the generated files and hashed by its content,
7206
+ * a directory is hashed and watched in place
7207
+ */
7208
+ planProjectSource(name, imageConfig) {
7209
+ var _a, _b;
7210
+ if (imageConfig.dockerfile !== undefined) {
7211
+ const content = toDockerfileContent(imageConfig.dockerfile);
7212
+ const dockerfilePath = `${exports.PROJECT_IMAGES_FOLDER}/${name}/Dockerfile`;
7213
+ const { hash, watchedPaths } = (0, hash_1.computeInlineImageHash)({
7214
+ dockerfileContent: content,
7215
+ hashExtraPaths: imageConfig.hashExtraPaths,
7216
+ buildArgs: imageConfig.buildArgs,
7217
+ });
7218
+ return {
7219
+ hash,
7220
+ dockerfilePath,
7221
+ // an inline definition carries no directory of its own — the
7222
+ // repository root is the sensible default context
7223
+ contextDir: (_a = imageConfig.context) !== null && _a !== void 0 ? _a : ".",
7224
+ watchedPaths: [
7225
+ `${exports.PROJECT_IMAGES_FOLDER}/${name}/**/*`,
7226
+ ...watchedPaths,
7227
+ CONFIG_FILE,
7228
+ ],
7229
+ files: [{ path: dockerfilePath, content }],
7230
+ };
7231
+ }
7232
+ const dir = imageConfig.dir;
7233
+ // fail at generation time with the offending image named: an
7234
+ // unreadable dir would otherwise surface as a bare fs ENOENT, and a
7235
+ // missing Dockerfile only as a docker build failure in CI
7236
+ if (!(0, fs_1.existsSync)(dir)) {
7237
+ throw new Error(`job image "${name}": the directory "${dir}" does not exist (config.images.${name}.dir, relative to the repository root)`);
7238
+ }
7239
+ if (!(0, fs_1.existsSync)((0, path_1.join)(dir, "Dockerfile"))) {
7240
+ throw new Error(`job image "${name}": no Dockerfile in "${dir}" (config.images.${name}.dir)`);
7241
+ }
7242
+ const { hash, watchedPaths } = (0, hash_1.computeCustomImageHash)({
7243
+ dir,
7244
+ hashExtraPaths: imageConfig.hashExtraPaths,
7245
+ buildArgs: imageConfig.buildArgs,
7246
+ });
7247
+ return {
7248
+ hash,
7249
+ dockerfilePath: `${dir}/Dockerfile`,
7250
+ contextDir: (_b = imageConfig.context) !== null && _b !== void 0 ? _b : dir,
7251
+ // the dir is committed in the project — watched in place, nothing
7252
+ // is materialized. The config file is watched too: buildArgs /
7253
+ // hashExtraPaths changes alter the tag without touching the dir
7254
+ watchedPaths: [...watchedPaths, CONFIG_FILE],
7255
+ files: [],
7256
+ };
7257
+ }
7119
7258
  use(name) {
7120
7259
  var _a;
7121
7260
  const existing = this.used.get(name);
@@ -7130,27 +7269,43 @@ class JobImagesPlan {
7130
7269
  dir: (0, shippedImages_1.getShippedImageDir)(name),
7131
7270
  extraDirs: dependencies.map((dependency) => (0, shippedImages_1.getShippedImageDir)(dependency)),
7132
7271
  });
7133
- const entry = { hash };
7134
- this.used.set(name, entry);
7135
- return entry;
7272
+ const targetDir = `${exports.GENERATED_IMAGES_FOLDER}/${name}`;
7273
+ const planned = {
7274
+ hash,
7275
+ jobName: ensureJobName(name),
7276
+ imageRef: `${this.registryImageRef()}/catladder/${name}:${hash}`,
7277
+ dockerfilePath: `${targetDir}/Dockerfile`,
7278
+ // the jobs family INCLUDEs sibling images, so it builds from the
7279
+ // images root; the others from their own dir
7280
+ contextDir: shippedImages_1.RUNNER_IMAGE_BUILD_CONTEXT[name] === "root"
7281
+ ? exports.GENERATED_IMAGES_FOLDER
7282
+ : targetDir,
7283
+ watchedPaths: [name, ...dependencies].map((dir) => `${exports.GENERATED_IMAGES_FOLDER}/${dir}/**/*`),
7284
+ // pipelines build from committed, reviewable files (and gitlab's
7285
+ // rules:changes can watch them)
7286
+ files: materializeDir((0, shippedImages_1.getShippedImageDir)(name), targetDir),
7287
+ };
7288
+ this.used.set(name, planned);
7289
+ return planned;
7136
7290
  }
7137
7291
  /**
7138
7292
  * the image build jobs for all used images
7139
7293
  */
7140
7294
  getEnsureJobs() {
7141
- return [...this.used.entries()].map(([name, { hash }]) => this.createEnsureJob(name, hash));
7295
+ return [...this.used.values(), ...this.usedProject.values()].map((planned) => this.createImageBuildJob(planned));
7142
7296
  }
7143
- createEnsureJob(name, hash) {
7144
- var _a;
7297
+ createImageBuildJob({ jobName, imageRef, watchedPaths, dockerfilePath, contextDir, buildArgs, }) {
7298
+ const buildArgFlags = Object.entries(buildArgs !== null && buildArgs !== void 0 ? buildArgs : {})
7299
+ .map(([key, value]) => ` --build-arg '${key}=${value}'`)
7300
+ .join("");
7301
+ const buildCommand = `DOCKER_BUILDKIT=1 docker build -t ${imageRef}${buildArgFlags} -f ${dockerfilePath} ${contextDir}`;
7145
7302
  const ctx = { pipelineType: this.pipelineType };
7146
7303
  const registryUser = (0, ciVariables_1.getCiVariable)(ctx, "registryUser");
7147
7304
  const jobToken = (0, ciVariables_1.getCiVariable)(ctx, "jobToken");
7148
7305
  const registry = (0, ciVariables_1.getCiVariable)(ctx, "registry");
7149
- const imageRef = `${this.registryImageRef()}/catladder/${name}:${hash}`;
7150
- const watchedDirs = [name, ...((_a = shippedImages_1.RUNNER_IMAGE_DEPENDENCIES[name]) !== null && _a !== void 0 ? _a : [])];
7151
7306
  const { services, runnerVariables } = (0, docker_1.getDockerJobBaseProps)();
7152
7307
  return {
7153
- name: ensureJobName(name),
7308
+ name: jobName,
7154
7309
  stage: "setup",
7155
7310
  image: BUILDER_IMAGE,
7156
7311
  services,
@@ -7160,7 +7315,9 @@ class JobImagesPlan {
7160
7315
  // no equivalent and always runs (the existence check is fast)
7161
7316
  rules: [
7162
7317
  {
7163
- changes: watchedDirs.map((dir) => `${exports.GENERATED_IMAGES_FOLDER}/${dir}/**/*`),
7318
+ // a fresh array per job: the yaml serializer anchors repeated
7319
+ // objects, and a shared reference would reshuffle anchors
7320
+ changes: [...watchedPaths],
7164
7321
  },
7165
7322
  ],
7166
7323
  variables: {},
@@ -7174,31 +7331,33 @@ class JobImagesPlan {
7174
7331
  ` exit 0`,
7175
7332
  `fi`,
7176
7333
  ]),
7177
- ...(0, gitlab_1.collapseableSection)("docker-build", "Building image")([
7178
- `DOCKER_BUILDKIT=1 docker build -t ${imageRef} -f ${exports.GENERATED_IMAGES_FOLDER}/${name}/Dockerfile ${shippedImages_1.RUNNER_IMAGE_BUILD_CONTEXT[name] === "root"
7179
- ? exports.GENERATED_IMAGES_FOLDER
7180
- : `${exports.GENERATED_IMAGES_FOLDER}/${name}`}`,
7181
- ]),
7334
+ ...(0, gitlab_1.collapseableSection)("docker-build", "Building image")([buildCommand]),
7182
7335
  ...(0, gitlab_1.collapseableSection)("docker-push", "Pushing image")([`docker push ${imageRef}`]),
7183
7336
  ],
7184
7337
  };
7185
7338
  }
7186
7339
  /**
7187
- * the image definitions of all used images, materialized into the
7188
- * generated files (so pipelines build from committed, reviewable
7189
- * files and gitlab's rules:changes can watch them)
7340
+ * the image definitions to materialize into the generated files (so
7341
+ * pipelines build from committed, reviewable files and gitlab's
7342
+ * rules:changes can watch them): the definitions catladder ships and
7343
+ * the project's inline Dockerfiles. A project image directory is
7344
+ * already committed and contributes nothing.
7190
7345
  */
7191
7346
  getGeneratedFiles() {
7192
- return [...this.used.keys()].flatMap((name) => {
7193
- const dir = (0, shippedImages_1.getShippedImageDir)(name);
7194
- return listFilesRecursive(dir).map((file) => ({
7195
- path: (0, path_1.join)(exports.GENERATED_IMAGES_FOLDER, name, file),
7196
- content: (0, fs_1.readFileSync)((0, path_1.join)(dir, file), "utf-8"),
7197
- }));
7198
- });
7347
+ return [...this.used.values(), ...this.usedProject.values()].flatMap(({ files }) => files);
7199
7348
  }
7200
7349
  }
7201
7350
  exports.JobImagesPlan = JobImagesPlan;
7351
+ /**
7352
+ * an inline Dockerfile is written as given — as one string, or as lines
7353
+ * joined with newlines (always newline-terminated)
7354
+ */
7355
+ const toDockerfileContent = (dockerfile) => {
7356
+ const content = Array.isArray(dockerfile)
7357
+ ? dockerfile.join("\n")
7358
+ : dockerfile;
7359
+ return content.endsWith("\n") ? content : `${content}\n`;
7360
+ };
7202
7361
  const IGNORED_FILES = new Set([".DS_Store", "Thumbs.db"]);
7203
7362
  const listFilesRecursive = (dir) => (0, fs_1.readdirSync)(dir, { recursive: true, encoding: "utf-8" })
7204
7363
  .filter((entry) => {
@@ -7212,6 +7371,22 @@ const listFilesRecursive = (dir) => (0, fs_1.readdirSync)(dir, { recursive: true
7212
7371
 
7213
7372
  /***/ }),
7214
7373
 
7374
+ /***/ 55537:
7375
+ /***/ ((__unused_webpack_module, exports) => {
7376
+
7377
+ "use strict";
7378
+
7379
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
7380
+ exports.isProjectImageRef = void 0;
7381
+ const isProjectImageRef = (value) => typeof value === "object" &&
7382
+ value !== null &&
7383
+ "image" in value &&
7384
+ typeof value.image === "string";
7385
+ exports.isProjectImageRef = isProjectImageRef;
7386
+ //# sourceMappingURL=projectImages.js.map
7387
+
7388
+ /***/ }),
7389
+
7215
7390
  /***/ 28687:
7216
7391
  /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
7217
7392
 
@@ -9925,6 +10100,8 @@ __exportStar(__nccwpck_require__(68906), exports);
9925
10100
  __exportStar(__nccwpck_require__(23040), exports);
9926
10101
  __exportStar(__nccwpck_require__(35086), exports);
9927
10102
  __exportStar(__nccwpck_require__(71065), exports);
10103
+ __exportStar(__nccwpck_require__(55537), exports);
10104
+ __exportStar(__nccwpck_require__(47864), exports);
9928
10105
  __exportStar(__nccwpck_require__(80769), exports);
9929
10106
  __exportStar(__nccwpck_require__(7732), exports);
9930
10107
  __exportStar(__nccwpck_require__(66526), exports);