@catladder/cli 0.0.0-next-89bce6d0 → 0.0.0-next-d13ff46d

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/apps/cli/src/release/changesetsReleaseJob.js +4 -0
  2. package/dist/apps/cli/src/release/changesetsReleaseJob.js.map +1 -1
  3. package/dist/apps/cli/src/release/githubQueuedRelease.js +22 -3
  4. package/dist/apps/cli/src/release/githubQueuedRelease.js.map +1 -1
  5. package/dist/apps/cli/src/release/stepSummary.d.ts +6 -0
  6. package/dist/apps/cli/src/release/stepSummary.js +32 -0
  7. package/dist/apps/cli/src/release/stepSummary.js.map +1 -0
  8. package/dist/bundles/catci/index.js +3 -3
  9. package/dist/bundles/catenv/index.js +216 -109
  10. package/dist/bundles/cli/index.js +216 -109
  11. package/dist/bundles/skills/catladder-config/SKILL.md +4 -0
  12. package/dist/bundles/skills/catladder-migrate-ci-backend/SKILL.md +249 -0
  13. package/dist/bundles/skills/catladder-migrate-release-method/SKILL.md +233 -0
  14. package/dist/bundles/skills/catladder-pipelines/SKILL.md +10 -1
  15. package/dist/bundles/skills/catladder-releases/SKILL.md +20 -10
  16. package/dist/bundles/skills/catladder-secrets/SKILL.md +2 -0
  17. package/dist/packages/pipeline/src/backends/github/GithubBackend.js +93 -72
  18. package/dist/packages/pipeline/src/backends/github/GithubBackend.js.map +1 -1
  19. package/dist/packages/pipeline/src/backends/github/ensureImageJobs.d.ts +12 -0
  20. package/dist/packages/pipeline/src/backends/github/ensureImageJobs.js +40 -0
  21. package/dist/packages/pipeline/src/backends/github/ensureImageJobs.js.map +1 -0
  22. package/dist/packages/pipeline/src/backends/github/githubReleaseJobs.d.ts +17 -14
  23. package/dist/packages/pipeline/src/backends/github/githubReleaseJobs.js +76 -37
  24. package/dist/packages/pipeline/src/backends/github/githubReleaseJobs.js.map +1 -1
  25. package/dist/skills/catladder-config/SKILL.md +4 -0
  26. package/dist/skills/catladder-migrate-ci-backend/SKILL.md +249 -0
  27. package/dist/skills/catladder-migrate-release-method/SKILL.md +233 -0
  28. package/dist/skills/catladder-pipelines/SKILL.md +10 -1
  29. package/dist/skills/catladder-releases/SKILL.md +20 -10
  30. package/dist/skills/catladder-secrets/SKILL.md +2 -0
  31. package/dist/tsconfig.tsbuildinfo +1 -1
  32. package/package.json +1 -1
  33. package/src/release/changesetsReleaseJob.ts +6 -0
  34. package/src/release/githubQueuedRelease.ts +37 -3
  35. package/src/release/stepSummary.ts +27 -0
@@ -8281,9 +8281,8 @@ const ciVariables_1 = __nccwpck_require__(88393);
8281
8281
  const index_1 = __nccwpck_require__(68906);
8282
8282
  const createGithubJobs_1 = __nccwpck_require__(57877);
8283
8283
  const jobImagesPlan_1 = __nccwpck_require__(47864);
8284
- const scriptFunctions_1 = __nccwpck_require__(79252);
8284
+ const ensureImageJobs_1 = __nccwpck_require__(70051);
8285
8285
  const shippedCatci_1 = __nccwpck_require__(79024);
8286
- const utils_1 = __nccwpck_require__(24516);
8287
8286
  const githubReleaseJobs_1 = __nccwpck_require__(89800);
8288
8287
  const scriptFiles_1 = __nccwpck_require__(30966);
8289
8288
  const WORKFLOWS_FOLDER = ".github/workflows";
@@ -8292,9 +8291,13 @@ const WORKFLOWS_FOLDER = ".github/workflows";
8292
8291
  * user-maintained workflows in the same folder
8293
8292
  */
8294
8293
  const GENERATED_FILE_PREFIX = "catladder-";
8294
+ // NOTE on the emoji prefixes: github sorts the Actions sidebar by raw
8295
+ // code point, so the đŸ› ī¸ (U+1F6E0) prefix makes the pipeline workflows
8296
+ // sort BELOW the triggerable action workflows (â†Šī¸ âšī¸ â–ļī¸ 🚀, all lower
8297
+ // code points) — the things a human clicks come first.
8295
8298
  const TRIGGER_WORKFLOWS = {
8296
8299
  mr: {
8297
- name: "catladder review",
8300
+ name: "đŸ› ī¸ catladder review",
8298
8301
  on: { pull_request: { types: ["opened", "synchronize", "reopened"] } },
8299
8302
  concurrency: {
8300
8303
  group: "catladder-review-${{ github.event.number }}",
@@ -8302,12 +8305,12 @@ const TRIGGER_WORKFLOWS = {
8302
8305
  },
8303
8306
  },
8304
8307
  mainBranch: {
8305
- name: "catladder main",
8308
+ name: "đŸ› ī¸ catladder main",
8306
8309
  // TODO: make the default branch configurable
8307
8310
  on: { push: { branches: ["main"] } },
8308
8311
  },
8309
8312
  taggedRelease: {
8310
- name: "catladder release",
8313
+ name: "đŸ› ī¸ catladder release",
8311
8314
  // tags pushed with the default GITHUB_TOKEN (as the release job
8312
8315
  // does) don't trigger `on: push: tags` — the release job therefore
8313
8316
  // also dispatches this workflow explicitly for the new tag
@@ -8357,15 +8360,18 @@ class GithubBackend {
8357
8360
  ...(0, index_1.getPipelineOptions)(config, this.type).runnerVariables,
8358
8361
  };
8359
8362
  const reviewStopJobs = {};
8360
- // jobs routed to the workflow_dispatch "manual tasks" workflow. A
8361
- // manual job and its build closure live here instead of an automatic
8362
- // workflow; `manualJobConditions` is the `if` that selects each one
8363
- // from the dispatch input, `manualDispatchOptions` the leaf jobs that
8364
- // become dropdown choices (closure jobs run because their leaf was
8365
- // chosen, not on their own).
8366
- const manualJobs = {};
8367
- const manualJobConditions = {};
8368
- const manualDispatchOptions = [];
8363
+ // jobs routed to the per-kind workflow_dispatch workflows (deploy /
8364
+ // stop / rollback). A manual job and its build closure live there
8365
+ // instead of an automatic workflow; `conditions` is the `if` that
8366
+ // selects each one from the dispatch input, `options` the leaf jobs
8367
+ // that become dropdown choices (closure jobs run because their leaf
8368
+ // was chosen, not on their own). A closure job serving leaves of
8369
+ // several kinds is duplicated into each kind's workflow.
8370
+ const manualKindBuckets = {
8371
+ deploy: { jobs: {}, conditions: {}, options: [], envTypes: [] },
8372
+ stop: { jobs: {}, conditions: {}, options: [], envTypes: [] },
8373
+ rollback: { jobs: {}, conditions: {}, options: [], envTypes: [] },
8374
+ };
8369
8375
  for (const trigger of config_1.ALL_PIPELINE_TRIGGERS) {
8370
8376
  const allJobs = await (0, createAllJobs_1.createAllJobs)({
8371
8377
  config,
@@ -8442,32 +8448,46 @@ class GithubBackend {
8442
8448
  }
8443
8449
  }
8444
8450
  }
8451
+ const kindOfLeaf = new Map(leafIds.map((id) => [id, manualKind(triggerJobs.get(id).job)]));
8445
8452
  const jobs = {};
8446
8453
  for (const [id, { githubJob }] of triggerJobs) {
8447
8454
  const leaves = servesLeaves.get(id);
8448
8455
  if (leaves) {
8449
- manualJobs[id] = githubJob;
8450
- manualJobConditions[id] = [...leaves]
8451
- .sort()
8452
- .map((leaf) => `inputs.job == '${leaf}'`)
8453
- .join(" || ");
8456
+ // one entry per kind the job serves — restricted to that
8457
+ // kind's leaves, so the `if` only references its own inputs
8458
+ for (const kind of new Set([...leaves].map((leaf) => kindOfLeaf.get(leaf)))) {
8459
+ const bucket = manualKindBuckets[kind];
8460
+ bucket.jobs[id] = githubJob;
8461
+ bucket.conditions[id] = [...leaves]
8462
+ .filter((leaf) => kindOfLeaf.get(leaf) === kind)
8463
+ .sort()
8464
+ .map((leaf) => `inputs.job == '${leaf}'`)
8465
+ .join(" || ");
8466
+ }
8454
8467
  }
8455
8468
  else {
8456
8469
  jobs[id] = githubJob;
8457
8470
  }
8458
8471
  }
8459
- manualDispatchOptions.push(...leafIds);
8472
+ for (const id of leafIds) {
8473
+ const bucket = manualKindBuckets[kindOfLeaf.get(id)];
8474
+ bucket.options.push(id);
8475
+ const context = triggerJobs.get(id).context;
8476
+ if (context.type === "component") {
8477
+ bucket.envTypes.push(context.environment.envType);
8478
+ }
8479
+ }
8460
8480
  if (trigger === "mr") {
8461
8481
  Object.assign(jobs, (0, githubReleaseJobs_1.getGithubReleaseCheckJobs)(config, images));
8462
8482
  }
8463
8483
  if (trigger === "mainBranch") {
8464
- const releaseJobs = (0, githubReleaseJobs_1.getGithubReleaseJobs)(config, Object.keys(jobs), images);
8465
- Object.assign(jobs, releaseJobs.main);
8466
- for (const [id, job] of Object.entries(releaseJobs.manual)) {
8467
- manualJobs[id] = job;
8468
- manualJobConditions[id] = `inputs.job == '${id}'`;
8469
- manualDispatchOptions.push(id);
8470
- }
8484
+ // auto release mode: the release job runs at the end of the
8485
+ // main workflow itself
8486
+ Object.assign(jobs, (0, githubReleaseJobs_1.getGithubReleaseJobs)(config, Object.keys(jobs), images));
8487
+ // the dispatch workflow to trigger a release by hand (with a
8488
+ // force checkbox where the method distinguishes it)
8489
+ workflows[`${GENERATED_FILE_PREFIX}create-release.yml`] =
8490
+ (0, githubReleaseJobs_1.getGithubCreateReleaseWorkflow)(config, images, workflowEnv);
8471
8491
  // manual release mode: the workflow that runs a queued release
8472
8492
  // once the main workflow completed green
8473
8493
  const releaseOnGreen = (0, githubReleaseJobs_1.getGithubReleaseOnGreenWorkflow)(config, images, TRIGGER_WORKFLOWS.mainBranch.name, workflowEnv);
@@ -8481,41 +8501,59 @@ class GithubBackend {
8481
8501
  ...TRIGGER_WORKFLOWS[trigger],
8482
8502
  ...workflowPermissions(images),
8483
8503
  env: workflowEnv,
8484
- jobs: { ...makeEnsureImageGithubJobs(images), ...jobs },
8504
+ jobs: { ...(0, ensureImageJobs_1.makeEnsureImageGithubJobs)(images), ...jobs },
8485
8505
  };
8486
8506
  }
8487
8507
  }
8488
8508
  if (Object.keys(reviewStopJobs).length > 0) {
8489
8509
  workflows[`${GENERATED_FILE_PREFIX}review-stop.yml`] = {
8490
- name: "catladder review stop",
8510
+ name: "đŸ› ī¸ catladder review stop",
8491
8511
  on: { pull_request: { types: ["closed"] } },
8492
8512
  ...workflowPermissions(images),
8493
8513
  env: workflowEnv,
8494
- jobs: { ...makeEnsureImageGithubJobs(images), ...reviewStopJobs },
8514
+ jobs: { ...(0, ensureImageJobs_1.makeEnsureImageGithubJobs)(images), ...reviewStopJobs },
8495
8515
  };
8496
8516
  }
8497
- if (Object.keys(manualJobs).length > 0) {
8498
- workflows[`${GENERATED_FILE_PREFIX}manual.yml`] = {
8499
- name: "catladder manual tasks",
8517
+ for (const [kind, bucket] of Object.entries(manualKindBuckets)) {
8518
+ if (Object.keys(bucket.jobs).length === 0) {
8519
+ continue;
8520
+ }
8521
+ const options = [...new Set(bucket.options)];
8522
+ // a single candidate needs no dropdown — the dispatch just runs it
8523
+ const singleTask = options.length === 1;
8524
+ // one common env across the kind's tasks → carry it in the name
8525
+ // ("â–ļī¸ catladder deploy prod"); mixed envs keep the generic name
8526
+ // and the dropdown distinguishes
8527
+ const envTypes = [...new Set(bucket.envTypes)];
8528
+ const envSuffix = envTypes.length === 1 &&
8529
+ bucket.envTypes.length === bucket.options.length
8530
+ ? ` ${envTypes[0]}`
8531
+ : "";
8532
+ workflows[`${GENERATED_FILE_PREFIX}${kind}.yml`] = {
8533
+ name: `${MANUAL_KIND_WORKFLOW_NAMES[kind]}${envSuffix}`,
8500
8534
  on: {
8501
- workflow_dispatch: {
8502
- inputs: {
8503
- job: {
8504
- description: "the task to run",
8505
- required: true,
8506
- type: "choice",
8507
- options: [...new Set(manualDispatchOptions)],
8535
+ workflow_dispatch: singleTask
8536
+ ? {}
8537
+ : {
8538
+ inputs: {
8539
+ job: {
8540
+ description: "the task to run",
8541
+ required: true,
8542
+ type: "choice",
8543
+ options,
8544
+ },
8508
8545
  },
8509
8546
  },
8510
- },
8511
8547
  },
8512
8548
  ...workflowPermissions(images),
8513
8549
  env: workflowEnv,
8514
8550
  jobs: {
8515
- ...makeEnsureImageGithubJobs(images),
8516
- ...Object.fromEntries(Object.entries(manualJobs).map(([id, job]) => [
8551
+ ...(0, ensureImageJobs_1.makeEnsureImageGithubJobs)(images),
8552
+ ...Object.fromEntries(Object.entries(bucket.jobs).map(([id, job]) => [
8517
8553
  id,
8518
- { ...job, if: `\${{ ${manualJobConditions[id]} }}` },
8554
+ singleTask
8555
+ ? job
8556
+ : { ...job, if: `\${{ ${bucket.conditions[id]} }}` },
8519
8557
  ])),
8520
8558
  },
8521
8559
  };
@@ -8530,33 +8568,6 @@ exports.GithubBackend = GithubBackend;
8530
8568
  const workflowPermissions = (_images) => ({
8531
8569
  permissions: { contents: "read", packages: "write" },
8532
8570
  });
8533
- /**
8534
- * the image build jobs: always run (github has no server-side
8535
- * changes-filter), the existence check makes unchanged runs fast.
8536
- * Docker is native on github runners — no container, no dind.
8537
- */
8538
- const makeEnsureImageGithubJobs = (images) => Object.fromEntries(images.getEnsureJobs().map((job) => {
8539
- var _a, _b;
8540
- return [
8541
- (0, createGithubJobs_1.githubGlobalJobId)(job.name),
8542
- {
8543
- name: job.name,
8544
- "runs-on": "ubuntu-latest",
8545
- steps: [
8546
- { name: "Checkout", uses: "actions/checkout@v4" },
8547
- {
8548
- name: job.name,
8549
- id: "main",
8550
- run: [
8551
- ...(0, scriptFunctions_1.getGithubScriptFunctionDefinitions)(),
8552
- ...((_b = (_a = job.script) === null || _a === void 0 ? void 0 : _a.filter(utils_1.notNil)) !== null && _b !== void 0 ? _b : []),
8553
- ].join("\n"),
8554
- shell: "bash",
8555
- },
8556
- ],
8557
- },
8558
- ];
8559
- }));
8560
8571
  const workflowFileName = (trigger) => {
8561
8572
  switch (trigger) {
8562
8573
  case "mr":
@@ -8580,10 +8591,20 @@ const isReviewStopJob = (context, job) => {
8580
8591
  };
8581
8592
  /**
8582
8593
  * stop/rollback jobs of non-review environments have no automatic
8583
- * trigger; they are collected in a workflow_dispatch workflow
8594
+ * trigger; they are collected in workflow_dispatch workflows
8584
8595
  * (gitlab runs them as manual jobs inside the pipeline)
8585
8596
  */
8586
8597
  const isManualTaskJob = (job) => job.stage === "stop" || job.stage === "rollback";
8598
+ const MANUAL_KIND_WORKFLOW_NAMES = {
8599
+ deploy: "â–ļī¸ catladder deploy",
8600
+ stop: "âšī¸ catladder stop",
8601
+ rollback: "â†Šī¸ catladder rollback",
8602
+ };
8603
+ const manualKind = (job) => job.stage === "stop"
8604
+ ? "stop"
8605
+ : job.stage === "rollback"
8606
+ ? "rollback"
8607
+ : "deploy";
8587
8608
  //# sourceMappingURL=GithubBackend.js.map
8588
8609
 
8589
8610
  /***/ }),
@@ -9013,17 +9034,78 @@ exports.getUploadProviderIds = getUploadProviderIds;
9013
9034
 
9014
9035
  /***/ }),
9015
9036
 
9037
+ /***/ 70051:
9038
+ /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
9039
+
9040
+ "use strict";
9041
+
9042
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
9043
+ exports.makeEnsureImageGithubJobs = void 0;
9044
+ const createGithubJobs_1 = __nccwpck_require__(57877);
9045
+ const scriptFunctions_1 = __nccwpck_require__(79252);
9046
+ const utils_1 = __nccwpck_require__(24516);
9047
+ /**
9048
+ * the image build jobs: always run (github has no server-side
9049
+ * changes-filter), the existence check makes unchanged runs fast.
9050
+ * Docker is native on github runners — no container, no dind.
9051
+ * `only` restricts to the named images (e.g. the create-release
9052
+ * workflow needs just the release image).
9053
+ */
9054
+ const makeEnsureImageGithubJobs = (images, options = {}) => Object.fromEntries(images
9055
+ .getEnsureJobs()
9056
+ .filter((job) => !options.only || options.only.includes(job.name))
9057
+ .map((job) => {
9058
+ var _a, _b;
9059
+ return [
9060
+ (0, createGithubJobs_1.githubGlobalJobId)(job.name),
9061
+ {
9062
+ name: job.name,
9063
+ "runs-on": "ubuntu-latest",
9064
+ steps: [
9065
+ { name: "Checkout", uses: "actions/checkout@v4" },
9066
+ {
9067
+ name: job.name,
9068
+ id: "main",
9069
+ run: [
9070
+ ...(0, scriptFunctions_1.getGithubScriptFunctionDefinitions)(),
9071
+ ...((_b = (_a = job.script) === null || _a === void 0 ? void 0 : _a.filter(utils_1.notNil)) !== null && _b !== void 0 ? _b : []),
9072
+ ].join("\n"),
9073
+ shell: "bash",
9074
+ },
9075
+ ],
9076
+ },
9077
+ ];
9078
+ }));
9079
+ exports.makeEnsureImageGithubJobs = makeEnsureImageGithubJobs;
9080
+ //# sourceMappingURL=ensureImageJobs.js.map
9081
+
9082
+ /***/ }),
9083
+
9016
9084
  /***/ 89800:
9017
9085
  /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
9018
9086
 
9019
9087
  "use strict";
9020
9088
 
9021
9089
  Object.defineProperty(exports, "__esModule", ({ value: true }));
9022
- exports.getGithubReleaseCheckJobs = exports.getGithubReleaseOnGreenWorkflow = exports.getGithubReleaseJobs = void 0;
9090
+ exports.getGithubReleaseCheckJobs = exports.getGithubReleaseOnGreenWorkflow = exports.getGithubCreateReleaseWorkflow = exports.getGithubReleaseJobs = void 0;
9023
9091
  const createGithubJobs_1 = __nccwpck_require__(57877);
9092
+ const ensureImageJobs_1 = __nccwpck_require__(70051);
9024
9093
  const release_1 = __nccwpck_require__(38904);
9025
9094
  const shippedCatci_1 = __nccwpck_require__(79024);
9026
9095
  const CATCI = `${shippedCatci_1.GENERATED_CATCI_FOLDER}/index.js`;
9096
+ /**
9097
+ * the build job of the release image only — the create-release
9098
+ * dispatch workflow needs no other image (empty for external images)
9099
+ */
9100
+ const makeReleaseImageEnsureJobs = (config, images) => {
9101
+ const resolved = images.resolveRef({
9102
+ catladderImage: (0, release_1.getReleaseMethod)(config).image,
9103
+ });
9104
+ if (!resolved.need || typeof resolved.need !== "object") {
9105
+ return {};
9106
+ }
9107
+ return (0, ensureImageJobs_1.makeEnsureImageGithubJobs)(images, { only: [resolved.need.job] });
9108
+ };
9027
9109
  const createReleaseJob = (config, images, options = {}) => {
9028
9110
  var _a;
9029
9111
  const method = (0, release_1.getReleaseMethod)(config);
@@ -9077,6 +9159,7 @@ const createReleaseJob = (config, images, options = {}) => {
9077
9159
  {
9078
9160
  name: "check main workflow",
9079
9161
  id: "queue",
9162
+ ...(options.queueCheckIf ? { if: options.queueCheckIf } : {}),
9080
9163
  run: `node ${CATCI} release github-queue-check`,
9081
9164
  shell: "bash",
9082
9165
  },
@@ -9094,51 +9177,75 @@ const createReleaseJob = (config, images, options = {}) => {
9094
9177
  };
9095
9178
  };
9096
9179
  /**
9097
- * the release jobs for the github backend (the counterpart of the
9098
- * gitlab release jobs):
9099
- * - releases.when === "auto": the release job runs in the main-branch
9100
- * workflow after all other jobs; a force variant goes to the manual
9101
- * tasks workflow
9102
- * - otherwise (manual, the default): the release job goes to the
9103
- * manual tasks workflow. Its queue-check step releases right away on
9104
- * a green main run and otherwise queues the release for the
9105
- * release-on-green workflow (see getGithubReleaseOnGreenWorkflow) —
9106
- * the counterpart of gitlab's queue button + executor pair.
9180
+ * the release jobs of the main-branch workflow: with releases.when ===
9181
+ * "auto" the release runs at the end of every main workflow run.
9182
+ * Manual releasing happens via the create-release dispatch workflow
9183
+ * (see getGithubCreateReleaseWorkflow) instead.
9107
9184
  */
9108
9185
  const getGithubReleaseJobs = (config, mainWorkflowJobIds, images) => {
9109
9186
  var _a;
9110
- const method = (0, release_1.getReleaseMethod)(config);
9111
- if (((_a = config.releases) === null || _a === void 0 ? void 0 : _a.when) === "auto") {
9112
- return {
9113
- main: {
9114
- "create-release": createReleaseJob(config, images, {
9115
- needs: mainWorkflowJobIds,
9116
- }),
9117
- },
9118
- manual: {
9119
- "force-create-release": createReleaseJob(config, images, {
9120
- extraEnv: method.forceReleaseVariables,
9121
- }),
9122
- },
9123
- };
9187
+ if (((_a = config.releases) === null || _a === void 0 ? void 0 : _a.when) !== "auto") {
9188
+ return {};
9124
9189
  }
9125
9190
  return {
9126
- main: {},
9127
- manual: {
9128
- "create-release": createReleaseJob(config, images, { queueCheck: true }),
9129
- // an explicit force option wherever the method distinguishes it
9130
- // (e.g. changesets: release a patch bump without changesets)
9131
- ...(method.forceReleaseVariables
9191
+ "create-release": createReleaseJob(config, images, {
9192
+ needs: mainWorkflowJobIds,
9193
+ }),
9194
+ };
9195
+ };
9196
+ exports.getGithubReleaseJobs = getGithubReleaseJobs;
9197
+ /**
9198
+ * the dispatch workflow to trigger a release by hand — a first-class
9199
+ * entry in the Actions sidebar (the counterpart of gitlab's `create
9200
+ * release` button). Its queue-check step releases right away when the
9201
+ * main workflow run for HEAD is green and otherwise queues the release
9202
+ * for the release-on-green workflow. Where the release method
9203
+ * distinguishes a force mode (e.g. changesets: release a patch bump
9204
+ * without pending changesets), forcing is a checkbox input — a forced
9205
+ * release skips the queue-check and releases immediately, whatever the
9206
+ * pipeline state.
9207
+ */
9208
+ const getGithubCreateReleaseWorkflow = (config, images, workflowEnv) => {
9209
+ const method = (0, release_1.getReleaseMethod)(config);
9210
+ const forceVariables = method.forceReleaseVariables;
9211
+ const job = createReleaseJob(config, images, {
9212
+ queueCheck: true,
9213
+ ...(forceVariables
9214
+ ? {
9215
+ queueCheckIf: "${{ !inputs.force }}",
9216
+ // only effective when the force checkbox is ticked
9217
+ extraEnv: Object.fromEntries(Object.entries(forceVariables).map(([key, value]) => [
9218
+ key,
9219
+ `\${{ inputs.force && '${value}' || '' }}`,
9220
+ ])),
9221
+ }
9222
+ : {}),
9223
+ });
9224
+ return {
9225
+ name: "🚀 catladder create release",
9226
+ on: {
9227
+ workflow_dispatch: forceVariables
9132
9228
  ? {
9133
- "force-create-release": createReleaseJob(config, images, {
9134
- extraEnv: method.forceReleaseVariables,
9135
- }),
9229
+ inputs: {
9230
+ force: {
9231
+ description: "force: release even without pending changes (patch bump), ignoring the pipeline state",
9232
+ required: false,
9233
+ type: "boolean",
9234
+ default: false,
9235
+ },
9236
+ },
9136
9237
  }
9137
- : {}),
9238
+ : {},
9239
+ },
9240
+ permissions: { contents: "read", packages: "write" },
9241
+ env: workflowEnv,
9242
+ jobs: {
9243
+ ...makeReleaseImageEnsureJobs(config, images),
9244
+ "create-release": job,
9138
9245
  },
9139
9246
  };
9140
9247
  };
9141
- exports.getGithubReleaseJobs = getGithubReleaseJobs;
9248
+ exports.getGithubCreateReleaseWorkflow = getGithubCreateReleaseWorkflow;
9142
9249
  /**
9143
9250
  * the release-on-green workflow (manual release mode only): runs on
9144
9251
  * every completed main workflow run. A lightweight host job checks the
@@ -9157,7 +9264,7 @@ const getGithubReleaseOnGreenWorkflow = (config, images, mainWorkflowName, workf
9157
9264
  return null;
9158
9265
  }
9159
9266
  return {
9160
- name: "catladder release on green",
9267
+ name: "đŸ› ī¸ catladder release on green",
9161
9268
  on: {
9162
9269
  workflow_run: {
9163
9270
  workflows: [mainWorkflowName],
@@ -117,3 +117,7 @@ escape hatches to shrink over time, not accumulate.
117
117
  - `catladder-releases` — releasing (semantic-release / changesets)
118
118
  - `catladder-pipelines` — how the generated pipelines work, debugging CI
119
119
  - `catladder-cli` — non-interactive CLI usage and command reference
120
+ - `catladder-migrate-ci-backend` — moving a project between GitLab CI
121
+ and GitHub Actions
122
+ - `catladder-migrate-release-method` — switching between
123
+ semantic-release and changesets