@catladder/cli 5.1.3 → 5.2.0

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.
@@ -4803,9 +4803,20 @@ const createGitlabPipelineWithDefaults = ({ image, variables, before_script, aut
4803
4803
  ],
4804
4804
  workflow: {
4805
4805
  name: "$PIPELINE_ICON $PIPELINE_NAME",
4806
+ // superseded pipelines must actually die: "interruptible" cancels
4807
+ // every interruptible job, while gitlab's default "conservative"
4808
+ // lets one started `interruptible: false` job shield the whole
4809
+ // pipeline from cancellation. The rules below opt the pipelines
4810
+ // that must run to completion back out.
4811
+ // NOTE: this only tunes the project setting "Auto-cancel
4812
+ // redundant pipelines" — with that setting off nothing cancels.
4813
+ auto_cancel: { on_new_commit: "interruptible" },
4806
4814
  rules: [
4807
4815
  {
4808
4816
  if: '$CI_PIPELINE_SOURCE == "trigger"',
4817
+ // an agent run is not redundant work: a commit landing while
4818
+ // it thinks must not kill it
4819
+ auto_cancel: { on_new_commit: "none" },
4809
4820
  variables: {
4810
4821
  PIPELINE_ICON: "🤖",
4811
4822
  PIPELINE_NAME: "Thinking...",
@@ -4834,6 +4845,11 @@ const createGitlabPipelineWithDefaults = ({ image, variables, before_script, aut
4834
4845
  },
4835
4846
  {
4836
4847
  if: rules_1.RULE_IS_TAGGED_RELEASE.if,
4848
+ // a release pipeline always runs through: tags are immutable,
4849
+ // so this only bites when someone force-moves one — and a
4850
+ // release cancelled halfway leaves the version published in
4851
+ // some places and missing in others
4852
+ auto_cancel: { on_new_commit: "none" },
4837
4853
  variables: {
4838
4854
  PIPELINE_ICON: "🐱📦",
4839
4855
  PIPELINE_NAME: "Release $CI_COMMIT_TAG",
@@ -4950,6 +4966,12 @@ mainBranchJobNames) => {
4950
4966
  image: releaseImage,
4951
4967
  script: [method.script],
4952
4968
  after_script: [EXPIRED_TOKEN_HELP],
4969
+ // a release in flight must never be killed by a new commit — a
4970
+ // half-published version (tag pushed, npm publish missing) is not
4971
+ // recoverable by re-running. Under gitlab's default "conservative"
4972
+ // auto-cancel this also shields the rest of the pipeline, but only
4973
+ // once the release actually started, which is late by construction.
4974
+ interruptible: false,
4953
4975
  };
4954
4976
  const forceReleaseJob = {
4955
4977
  ["⚠️ force create release"]: {
@@ -4973,6 +4995,10 @@ mainBranchJobNames) => {
4973
4995
  stage: "test",
4974
4996
  image: releaseImage,
4975
4997
  script: [method.checkScript],
4998
+ // a redundant report is worthless: without this the job
4999
+ // defaults to interruptible: false and, once started, stops
5000
+ // gitlab from auto-cancelling the superseded MR pipeline
5001
+ interruptible: true,
4976
5002
  allow_failure: true,
4977
5003
  artifacts: {
4978
5004
  paths: ["changeset-report.md"],
@@ -5042,6 +5068,9 @@ mainBranchJobNames) => {
5042
5068
  script: [
5043
5069
  `echo "release queued — '${exports.RELEASE_EXECUTOR_JOB_NAME}' runs it as soon as every other job in this pipeline succeeded"`,
5044
5070
  ],
5071
+ // the recorded intent must survive a new commit: cancelling it
5072
+ // would silently drop the queued release
5073
+ interruptible: false,
5045
5074
  needs: [],
5046
5075
  // allow_failure keeps the unclicked button from blocking the
5047
5076
  // pipeline AND makes the executor's needs treat it as optional
@@ -11355,9 +11355,20 @@ const createGitlabPipelineWithDefaults = ({ image, variables, before_script, aut
11355
11355
  ],
11356
11356
  workflow: {
11357
11357
  name: "$PIPELINE_ICON $PIPELINE_NAME",
11358
+ // superseded pipelines must actually die: "interruptible" cancels
11359
+ // every interruptible job, while gitlab's default "conservative"
11360
+ // lets one started `interruptible: false` job shield the whole
11361
+ // pipeline from cancellation. The rules below opt the pipelines
11362
+ // that must run to completion back out.
11363
+ // NOTE: this only tunes the project setting "Auto-cancel
11364
+ // redundant pipelines" — with that setting off nothing cancels.
11365
+ auto_cancel: { on_new_commit: "interruptible" },
11358
11366
  rules: [
11359
11367
  {
11360
11368
  if: '$CI_PIPELINE_SOURCE == "trigger"',
11369
+ // an agent run is not redundant work: a commit landing while
11370
+ // it thinks must not kill it
11371
+ auto_cancel: { on_new_commit: "none" },
11361
11372
  variables: {
11362
11373
  PIPELINE_ICON: "🤖",
11363
11374
  PIPELINE_NAME: "Thinking...",
@@ -11386,6 +11397,11 @@ const createGitlabPipelineWithDefaults = ({ image, variables, before_script, aut
11386
11397
  },
11387
11398
  {
11388
11399
  if: rules_1.RULE_IS_TAGGED_RELEASE.if,
11400
+ // a release pipeline always runs through: tags are immutable,
11401
+ // so this only bites when someone force-moves one — and a
11402
+ // release cancelled halfway leaves the version published in
11403
+ // some places and missing in others
11404
+ auto_cancel: { on_new_commit: "none" },
11389
11405
  variables: {
11390
11406
  PIPELINE_ICON: "🐱📦",
11391
11407
  PIPELINE_NAME: "Release $CI_COMMIT_TAG",
@@ -11502,6 +11518,12 @@ mainBranchJobNames) => {
11502
11518
  image: releaseImage,
11503
11519
  script: [method.script],
11504
11520
  after_script: [EXPIRED_TOKEN_HELP],
11521
+ // a release in flight must never be killed by a new commit — a
11522
+ // half-published version (tag pushed, npm publish missing) is not
11523
+ // recoverable by re-running. Under gitlab's default "conservative"
11524
+ // auto-cancel this also shields the rest of the pipeline, but only
11525
+ // once the release actually started, which is late by construction.
11526
+ interruptible: false,
11505
11527
  };
11506
11528
  const forceReleaseJob = {
11507
11529
  ["⚠️ force create release"]: {
@@ -11525,6 +11547,10 @@ mainBranchJobNames) => {
11525
11547
  stage: "test",
11526
11548
  image: releaseImage,
11527
11549
  script: [method.checkScript],
11550
+ // a redundant report is worthless: without this the job
11551
+ // defaults to interruptible: false and, once started, stops
11552
+ // gitlab from auto-cancelling the superseded MR pipeline
11553
+ interruptible: true,
11528
11554
  allow_failure: true,
11529
11555
  artifacts: {
11530
11556
  paths: ["changeset-report.md"],
@@ -11594,6 +11620,9 @@ mainBranchJobNames) => {
11594
11620
  script: [
11595
11621
  `echo "release queued — '${exports.RELEASE_EXECUTOR_JOB_NAME}' runs it as soon as every other job in this pipeline succeeded"`,
11596
11622
  ],
11623
+ // the recorded intent must survive a new commit: cancelling it
11624
+ // would silently drop the queued release
11625
+ interruptible: false,
11597
11626
  needs: [],
11598
11627
  // allow_failure keeps the unclicked button from blocking the
11599
11628
  // pipeline AND makes the executor's needs treat it as optional
@@ -37,6 +37,38 @@ Generated layout:
37
37
  Stages: setup → test → build → deploy → verify (post-deploy checks),
38
38
  plus stop jobs for review-app teardown.
39
39
 
40
+ ## Superseded pipelines are cancelled
41
+
42
+ Pushing a new commit cancels the pipeline of the previous one, so the
43
+ runners are not busy with results nobody will read.
44
+
45
+ | Pipeline | On a new commit |
46
+ |---|---|
47
+ | `mr` | cancelled |
48
+ | `mainBranch` (dev) | cancelled, except a release already running |
49
+ | `taggedRelease` | **runs through** — never cancelled |
50
+ | agent runs (`trigger`) | **runs through** — never cancelled |
51
+
52
+ - **GitHub**: the generated MR workflow sets `concurrency` with
53
+ `cancel-in-progress: true`.
54
+ - **GitLab**: generated `workflow:auto_cancel:on_new_commit:
55
+ interruptible`, with per-rule `none` for tags and agent runs. Every
56
+ job carries an explicit `interruptible`, jobs that must finish
57
+ (release jobs, agent jobs) carry `interruptible: false`.
58
+
59
+ **GitLab requires the project setting too.** The generated YAML only
60
+ tunes *how* redundant pipelines are cancelled — it does not switch the
61
+ feature on. If old pipelines keep running, check **Settings > CI/CD >
62
+ General pipelines > Auto-cancel redundant pipelines**; with that
63
+ checkbox off nothing is ever cancelled. (`catladder project-doctor`
64
+ does not check this.)
65
+
66
+ **Adding a hand-written GitLab job?** Set `interruptible` explicitly.
67
+ GitLab defaults it to `false`, and a non-interruptible job that has
68
+ started keeps *itself* alive — under gitlab's own default
69
+ (`conservative`, which catladder overrides) it would shield the whole
70
+ pipeline from cancellation.
71
+
40
72
  ## Review-app auto-stop and pinning (GitLab)
41
73
 
42
74
  GitLab review environments stop automatically after 1 week, dev
@@ -33,9 +33,20 @@ const createGitlabPipelineWithDefaults = ({ image, variables, before_script, aut
33
33
  ],
34
34
  workflow: {
35
35
  name: "$PIPELINE_ICON $PIPELINE_NAME",
36
+ // superseded pipelines must actually die: "interruptible" cancels
37
+ // every interruptible job, while gitlab's default "conservative"
38
+ // lets one started `interruptible: false` job shield the whole
39
+ // pipeline from cancellation. The rules below opt the pipelines
40
+ // that must run to completion back out.
41
+ // NOTE: this only tunes the project setting "Auto-cancel
42
+ // redundant pipelines" — with that setting off nothing cancels.
43
+ auto_cancel: { on_new_commit: "interruptible" },
36
44
  rules: [
37
45
  {
38
46
  if: '$CI_PIPELINE_SOURCE == "trigger"',
47
+ // an agent run is not redundant work: a commit landing while
48
+ // it thinks must not kill it
49
+ auto_cancel: { on_new_commit: "none" },
39
50
  variables: {
40
51
  PIPELINE_ICON: "🤖",
41
52
  PIPELINE_NAME: "Thinking...",
@@ -64,6 +75,11 @@ const createGitlabPipelineWithDefaults = ({ image, variables, before_script, aut
64
75
  },
65
76
  {
66
77
  if: rules_1.RULE_IS_TAGGED_RELEASE.if,
78
+ // a release pipeline always runs through: tags are immutable,
79
+ // so this only bites when someone force-moves one — and a
80
+ // release cancelled halfway leaves the version published in
81
+ // some places and missing in others
82
+ auto_cancel: { on_new_commit: "none" },
67
83
  variables: {
68
84
  PIPELINE_ICON: "🐱📦",
69
85
  PIPELINE_NAME: "Release $CI_COMMIT_TAG",
@@ -1 +1 @@
1
- {"version":3,"file":"createGitlabPipeline.js","sourceRoot":"","sources":["../../../../../../../../packages/pipeline/src/backends/gitlab/createGitlabPipeline.ts"],"names":[],"mappings":";;;AACA,0CAAwD;AACxD,6CAIwB;AACxB,uCAIqB;AAGrB;;;;;GAKG;AACH,MAAM,sBAAsB,GAAG,SAAS,CAAC;AAElC,MAAM,gCAAgC,GAAG,CAAC,EAC/C,KAAK,EACL,SAAS,EACT,aAAa,EACb,QAAQ,EACR,GAAG,MAAM,EAGV,EAAsB,EAAE;IACvB,MAAM,QAAQ,GAAG,QAAQ,IAAI,QAAQ,CAAC,QAAQ,CAAC;IAC/C,OAAO;QACL,KAAK,EAAE,KAAK,aAAL,KAAK,cAAL,KAAK,GAAI,sBAAsB;QACtC,SAAS,EAAE;YACT,cAAc,EAAE,MAAM,EAAE,uFAAuF;YAC/G,0BAA0B,EAAE,MAAM,EAAE,kCAAkC;YACtE,uBAAuB,EAAE,MAAM,EAAE,gCAAgC;YACjE,wBAAwB,EAAE,IAAI,EAAE,0EAA0E;YAE1G,SAAS,EAAE,GAAG,EAAE,yBAAyB;YACzC,0DAA0D;YAC1D,0DAA0D;YAC1D,4CAA4C;YAC5C,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,oCAAyB,CAAC,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACrE,GAAG,CAAC,SAAS,aAAT,SAAS,cAAT,SAAS,GAAI,EAAE,CAAC;SACrB;QACD,aAAa,EAAE;YACb,GAAG,CAAC,GAAG,4BAAqB,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CACpD,MAAM,CAAC,cAAc,EAAE,CACxB;YACD,GAAG,CAAC,aAAa,aAAb,aAAa,cAAb,aAAa,GAAI,EAAE,CAAC;SACzB;QACD,QAAQ,EAAE;YACR,IAAI,EAAE,+BAA+B;YACrC,KAAK,EAAE;gBACL;oBACE,EAAE,EAAE,mCAAmC;oBACvC,SAAS,EAAE;wBACT,aAAa,EAAE,IAAI;wBACnB,aAAa,EAAE,aAAa;qBAC7B;iBACF;gBACD,+DAA+D;gBAC/D,uCAAuC;gBACvC,GAAG,CAAC,QAAQ;oBACV,CAAC,CAAC;wBACE;4BACE,EAAE,EAAE,GAAG,6BAAqB,CAAC,EAAE,oCAAoC,IAAA,iCAAsB,EAAC,QAAQ,CAAC,GAAG;4BACtG,SAAS,EAAE;gCACT,aAAa,EAAE,MAAM;gCACrB,aAAa,EACX,mDAAmD;gCACrD,CAAC,oCAAyB,CAAC,EAAE,OAAO;6BACrC;yBACF;qBACF;oBACH,CAAC,CAAC,EAAE,CAAC;gBACP;oBACE,EAAE,EAAE,6BAAqB,CAAC,EAAE;oBAC5B,SAAS,EAAE;wBACT,aAAa,EAAE,MAAM;wBACrB,aAAa,EAAE,mDAAmD;qBACnE;iBACF;gBACD;oBACE,EAAE,EAAE,8BAAsB,CAAC,EAAE;oBAC7B,SAAS,EAAE;wBACT,aAAa,EAAE,MAAM;wBACrB,aAAa,EAAE,wBAAwB;qBACxC;iBACF;gBACD;oBACE,EAAE,EAAE,kDAA0C,CAAC,EAAE;oBACjD,SAAS,EAAE;wBACT,aAAa,EAAE,MAAM;wBACrB,aAAa,EAAE,yBAAyB;qBACzC;iBACF;gBAED;oBACE,IAAI,EAAE,QAAQ,EAAE,WAAW;oBAC3B,SAAS,EAAE;wBACT,aAAa,EAAE,KAAK;wBACpB,aAAa,EAAE,SAAS;qBACzB;iBACF;aACF;SACF;QAED,GAAG,MAAM;KACV,CAAC;AACJ,CAAC,CAAC;AA1FW,QAAA,gCAAgC,oCA0F3C"}
1
+ {"version":3,"file":"createGitlabPipeline.js","sourceRoot":"","sources":["../../../../../../../../packages/pipeline/src/backends/gitlab/createGitlabPipeline.ts"],"names":[],"mappings":"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"}
@@ -7,6 +7,7 @@ export declare const getGitlabReleaseJobs: (config: Config, images: JobImagesPla
7
7
  stage: string;
8
8
  image: string;
9
9
  script: string[];
10
+ interruptible: true;
10
11
  allow_failure: true;
11
12
  artifacts: {
12
13
  paths: string[];
@@ -42,6 +43,7 @@ export declare const getGitlabReleaseJobs: (config: Config, images: JobImagesPla
42
43
  image: string;
43
44
  script: string[];
44
45
  after_script: string[];
46
+ interruptible: false;
45
47
  };
46
48
  "create release": {
47
49
  rules: {
@@ -58,6 +60,7 @@ export declare const getGitlabReleaseJobs: (config: Config, images: JobImagesPla
58
60
  image: string;
59
61
  script: string[];
60
62
  after_script: string[];
63
+ interruptible: false;
61
64
  needs?: undefined;
62
65
  allow_failure?: undefined;
63
66
  };
@@ -81,6 +84,7 @@ export declare const getGitlabReleaseJobs: (config: Config, images: JobImagesPla
81
84
  image: string;
82
85
  script: string[];
83
86
  after_script: string[];
87
+ interruptible: false;
84
88
  };
85
89
  "create release": {
86
90
  rules: {
@@ -97,6 +101,7 @@ export declare const getGitlabReleaseJobs: (config: Config, images: JobImagesPla
97
101
  image: string;
98
102
  script: string[];
99
103
  after_script: string[];
104
+ interruptible: false;
100
105
  needs?: undefined;
101
106
  allow_failure?: undefined;
102
107
  };
@@ -105,6 +110,7 @@ export declare const getGitlabReleaseJobs: (config: Config, images: JobImagesPla
105
110
  stage: string;
106
111
  image: string;
107
112
  script: string[];
113
+ interruptible: true;
108
114
  allow_failure: true;
109
115
  artifacts: {
110
116
  paths: string[];
@@ -140,6 +146,7 @@ export declare const getGitlabReleaseJobs: (config: Config, images: JobImagesPla
140
146
  image: string;
141
147
  script: string[];
142
148
  after_script: string[];
149
+ interruptible: false;
143
150
  };
144
151
  "create release": {
145
152
  allow_failure: true;
@@ -157,6 +164,7 @@ export declare const getGitlabReleaseJobs: (config: Config, images: JobImagesPla
157
164
  image: string;
158
165
  script: string[];
159
166
  after_script: string[];
167
+ interruptible: false;
160
168
  needs?: undefined;
161
169
  };
162
170
  } | {
@@ -179,6 +187,7 @@ export declare const getGitlabReleaseJobs: (config: Config, images: JobImagesPla
179
187
  image: string;
180
188
  script: string[];
181
189
  after_script: string[];
190
+ interruptible: false;
182
191
  };
183
192
  "create release": {
184
193
  allow_failure: true;
@@ -196,6 +205,7 @@ export declare const getGitlabReleaseJobs: (config: Config, images: JobImagesPla
196
205
  image: string;
197
206
  script: string[];
198
207
  after_script: string[];
208
+ interruptible: false;
199
209
  needs?: undefined;
200
210
  };
201
211
  } | {
@@ -203,6 +213,7 @@ export declare const getGitlabReleaseJobs: (config: Config, images: JobImagesPla
203
213
  stage: string;
204
214
  image: string;
205
215
  script: string[];
216
+ interruptible: true;
206
217
  allow_failure: true;
207
218
  artifacts: {
208
219
  paths: string[];
@@ -238,11 +249,13 @@ export declare const getGitlabReleaseJobs: (config: Config, images: JobImagesPla
238
249
  image: string;
239
250
  script: string[];
240
251
  after_script: string[];
252
+ interruptible: false;
241
253
  };
242
254
  "create release": {
243
255
  stage: string;
244
256
  image: string;
245
257
  script: string[];
258
+ interruptible: false;
246
259
  needs: any[];
247
260
  allow_failure: true;
248
261
  rules: {
@@ -277,6 +290,7 @@ export declare const getGitlabReleaseJobs: (config: Config, images: JobImagesPla
277
290
  image: string;
278
291
  script: string[];
279
292
  after_script: string[];
293
+ interruptible: false;
280
294
  };
281
295
  } | {
282
296
  "\uD83E\uDD8B changeset check"?: undefined;
@@ -298,11 +312,13 @@ export declare const getGitlabReleaseJobs: (config: Config, images: JobImagesPla
298
312
  image: string;
299
313
  script: string[];
300
314
  after_script: string[];
315
+ interruptible: false;
301
316
  };
302
317
  "create release": {
303
318
  stage: string;
304
319
  image: string;
305
320
  script: string[];
321
+ interruptible: false;
306
322
  needs: any[];
307
323
  allow_failure: true;
308
324
  rules: {
@@ -337,5 +353,6 @@ export declare const getGitlabReleaseJobs: (config: Config, images: JobImagesPla
337
353
  image: string;
338
354
  script: string[];
339
355
  after_script: string[];
356
+ interruptible: false;
340
357
  };
341
358
  };
@@ -53,6 +53,12 @@ mainBranchJobNames) => {
53
53
  image: releaseImage,
54
54
  script: [method.script],
55
55
  after_script: [EXPIRED_TOKEN_HELP],
56
+ // a release in flight must never be killed by a new commit — a
57
+ // half-published version (tag pushed, npm publish missing) is not
58
+ // recoverable by re-running. Under gitlab's default "conservative"
59
+ // auto-cancel this also shields the rest of the pipeline, but only
60
+ // once the release actually started, which is late by construction.
61
+ interruptible: false,
56
62
  };
57
63
  const forceReleaseJob = {
58
64
  ["⚠️ force create release"]: {
@@ -76,6 +82,10 @@ mainBranchJobNames) => {
76
82
  stage: "test",
77
83
  image: releaseImage,
78
84
  script: [method.checkScript],
85
+ // a redundant report is worthless: without this the job
86
+ // defaults to interruptible: false and, once started, stops
87
+ // gitlab from auto-cancelling the superseded MR pipeline
88
+ interruptible: true,
79
89
  allow_failure: true,
80
90
  artifacts: {
81
91
  paths: ["changeset-report.md"],
@@ -145,6 +155,9 @@ mainBranchJobNames) => {
145
155
  script: [
146
156
  `echo "release queued — '${exports.RELEASE_EXECUTOR_JOB_NAME}' runs it as soon as every other job in this pipeline succeeded"`,
147
157
  ],
158
+ // the recorded intent must survive a new commit: cancelling it
159
+ // would silently drop the queued release
160
+ interruptible: false,
148
161
  needs: [],
149
162
  // allow_failure keeps the unclicked button from blocking the
150
163
  // pipeline AND makes the executor's needs treat it as optional
@@ -1 +1 @@
1
- {"version":3,"file":"gitlabReleaseJobs.js","sourceRoot":"","sources":["../../../../../../../../packages/pipeline/src/backends/gitlab/gitlabReleaseJobs.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"gitlabReleaseJobs.js","sourceRoot":"","sources":["../../../../../../../../packages/pipeline/src/backends/gitlab/gitlabReleaseJobs.ts"],"names":[],"mappings":";;;AAAA,uCAOqB;AAErB,2CAAiD;AAIjD,MAAM,kBAAkB,GACtB,gJAAgJ,CAAC;AAEnJ;;;;GAIG;AACH,MAAM,gBAAgB,GAAG,EAAE,CAAC;AAEf,QAAA,uBAAuB,GAAG,gBAAgB,CAAC;AAC3C,QAAA,yBAAyB,GAAG,mCAAmC,CAAC;AAE7E,MAAM,gBAAgB,GAAG;IACvB,oCAA4B;IAC5B,mCAA2B;IAC3B,8BAAsB;CACvB,CAAC;AAEF,sEAAsE;AACtE,mEAAmE;AACnE,uEAAuE;AACvE,oCAAoC;AACpC,MAAM,kBAAkB,GAAG;IACzB,GAAG,gBAAgB;IACnB;QACE,EAAE,EAAE,kCAA0B;QAC9B,IAAI,EAAE,QAAQ;KACf;IACD;QACE,EAAE,EAAE,oCAA4B;QAChC,IAAI,EAAE,QAAQ;KACf;CACqB,CAAC;AAElB,MAAM,oBAAoB,GAAG,CAClC,MAAc,EACd,MAAqB;AACrB;;;;GAIG;AACH,kBAA4B,EAC5B,EAAE;;IACF,MAAM,MAAM,GAAG,IAAA,0BAAgB,EAAC,MAAM,CAAC,CAAC;IACxC,qEAAqE;IACrE,qEAAqE;IACrE,kEAAkE;IAClE,uCAAuC;IACvC,MAAM,YAAY,GAAG,MAAM,CAAC,UAAU,CAAC;QACrC,cAAc,EAAE,MAAM,CAAC,KAAK;KAC7B,CAAC,CAAC,KAAK,CAAC;IAET,MAAM,cAAc,GAAG;QACrB,KAAK,EAAE,SAAS;QAChB,KAAK,EAAE,YAAY;QACnB,MAAM,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC;QACvB,YAAY,EAAE,CAAC,kBAAkB,CAAC;QAClC,+DAA+D;QAC/D,kEAAkE;QAClE,mEAAmE;QACnE,mEAAmE;QACnE,oEAAoE;QACpE,aAAa,EAAE,KAAK;KACE,CAAC;IAEzB,MAAM,eAAe,GAAG;QACtB,CAAC,yBAAyB,CAAC,EAAE;YAC3B,GAAG,cAAc;YACjB,KAAK,EAAE,EAAE;YACT,aAAa,EAAE,IAAI;YACnB,2DAA2D;YAC3D,wDAAwD;YACxD,GAAG,CAAC,MAAM,CAAC,qBAAqB;gBAC9B,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,qBAAqB,EAAE;gBAC7C,CAAC,CAAC,EAAE,CAAC;YACP,KAAK,EAAE,kBAAkB;SACH;KACzB,CAAC;IAEF,mEAAmE;IACnE,8DAA8D;IAC9D,gCAAgC;IAChC,MAAM,QAAQ,GAAG,MAAM,CAAC,WAAW;QACjC,CAAC,CAAC;YACE,CAAC,oBAAoB,CAAC,EAAE;gBACtB,KAAK,EAAE,MAAM;gBACb,KAAK,EAAE,YAAY;gBACnB,MAAM,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC;gBAC5B,wDAAwD;gBACxD,4DAA4D;gBAC5D,yDAAyD;gBACzD,aAAa,EAAE,IAAI;gBACnB,aAAa,EAAE,IAAI;gBACnB,SAAS,EAAE;oBACT,KAAK,EAAE,CAAC,qBAAqB,CAAC;oBAC9B,SAAS,EAAE,kBAAkB;oBAC7B,2CAA2C;oBAC3C,IAAI,EAAE,QAAiB;iBACxB;gBACD,KAAK,EAAE;oBACL,mCAA2B;oBAC3B,8BAAsB;oBACtB,6BAAqB;iBACC;aACF;SACzB;QACH,CAAC,CAAC,EAAE,CAAC;IAEP,IAAI,CAAA,MAAA,MAAM,CAAC,QAAQ,0CAAE,IAAI,MAAK,MAAM,EAAE,CAAC;QACrC,OAAO;YACL,CAAC,+BAAuB,CAAC,EAAE;gBACzB,GAAG,cAAc;gBACjB,KAAK,EAAE;oBACL,GAAG,gBAAgB;oBACnB;wBACE,EAAE,EAAE,kCAA0B;wBAC9B,IAAI,EAAE,YAAY;qBACnB;oBACD;wBACE,EAAE,EAAE,oCAA4B;wBAChC,IAAI,EAAE,QAAQ;wBACd,sDAAsD;wBACtD,gDAAgD;wBAChD,aAAa,EAAE,IAAI;qBACpB;iBACqB;aACF;YACxB,GAAG,eAAe;YAClB,GAAG,QAAQ;SACZ,CAAC;IACJ,CAAC;IAED,MAAM,aAAa,GAAG;QACpB,EAAE,GAAG,EAAE,+BAAuB,EAAE;QAChC,iEAAiE;QACjE,uBAAuB;QACvB,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;KACrE,CAAC;IAEF,IAAI,aAAa,CAAC,MAAM,GAAG,gBAAgB,EAAE,CAAC;QAC5C,OAAO,CAAC,IAAI,CACV,6CAA6C,gBAAgB,UAAU;YACrE,QAAQ,+BAAuB,qCAAqC;YACpE,0DAA0D,gBAAgB,GAAG,CAChF,CAAC;QACF,OAAO;YACL,CAAC,+BAAuB,CAAC,EAAE;gBACzB,GAAG,cAAc;gBACjB,aAAa,EAAE,IAAI;gBACnB,KAAK,EAAE,kBAAkB;aACH;YACxB,GAAG,eAAe;YAClB,GAAG,QAAQ;SACZ,CAAC;IACJ,CAAC;IAED,OAAO;QACL,oEAAoE;QACpE,kEAAkE;QAClE,qEAAqE;QACrE,qEAAqE;QACrE,CAAC,+BAAuB,CAAC,EAAE;YACzB,KAAK,EAAE,SAAS;YAChB,KAAK,EAAE,YAAY;YACnB,MAAM,EAAE;gBACN,2BAA2B,iCAAyB,kEAAkE;aACvH;YACD,+DAA+D;YAC/D,yCAAyC;YACzC,aAAa,EAAE,KAAK;YACpB,KAAK,EAAE,EAAE;YACT,6DAA6D;YAC7D,+DAA+D;YAC/D,2DAA2D;YAC3D,aAAa,EAAE,IAAI;YACnB,KAAK,EAAE,kBAAkB;SACH;QACxB,mEAAmE;QACnE,oEAAoE;QACpE,kEAAkE;QAClE,sCAAsC;QACtC,CAAC,iCAAyB,CAAC,EAAE;YAC3B,GAAG,cAAc;YACjB,KAAK,EAAE,aAAa;YACpB,KAAK,EAAE;gBACL,GAAG,gBAAgB;gBACnB;oBACE,EAAE,EAAE,kCAA0B;oBAC9B,IAAI,EAAE,YAAY;iBACnB;gBACD;oBACE,EAAE,EAAE,oCAA4B;oBAChC,IAAI,EAAE,YAAY;iBACnB;aACqB;SACF;QACxB,GAAG,eAAe;QAClB,GAAG,QAAQ;KACZ,CAAC;AACJ,CAAC,CAAC;AAtKW,QAAA,oBAAoB,wBAsK/B"}
@@ -4,6 +4,33 @@ export { Retry, Image as GitlabJobImage } from "./gitlab-ci-yml";
4
4
  export type Artifacts = GitlabCiArtifacts;
5
5
  export type { GitlabJobCache };
6
6
  export type GitlabRule = Exclude<Exclude<Rules, null>[number], string | string[]>;
7
+ /**
8
+ * gitlab's auto-cancel policy for redundant pipelines. Tunes the
9
+ * project setting "Auto-cancel redundant pipelines" (Settings > CI/CD >
10
+ * General pipelines) — it does NOT enable it: with the setting off,
11
+ * nothing is ever cancelled regardless of this.
12
+ *
13
+ * needs gitlab >= 16.8 (top-level) / >= 16.10 (per workflow rule).
14
+ */
15
+ export interface GitlabAutoCancel {
16
+ /**
17
+ * - `conservative` (gitlab's default): cancel the whole pipeline, but
18
+ * only while no `interruptible: false` job has *started* — a single
19
+ * such job then shields every other job from cancellation
20
+ * - `interruptible`: cancel every `interruptible: true` job, with no
21
+ * such veto
22
+ * - `none`: never auto-cancel
23
+ */
24
+ on_new_commit?: "conservative" | "interruptible" | "none";
25
+ on_job_failure?: "all" | "none";
26
+ }
27
+ /**
28
+ * a workflow rule may override {@link GitlabAutoCancel} per pipeline
29
+ * kind — job rules may not.
30
+ */
31
+ export type GitlabWorkflowRule = GitlabRule & {
32
+ auto_cancel?: GitlabAutoCancel;
33
+ };
7
34
  export type GitlabEnvironment = Omit<Exclude<JobTemplate["environment"], undefined | string>, "deployment_tier">;
8
35
  export interface GitlabJobDef extends Pick<JobTemplate, "after_script" | "allow_failure" | "artifacts" | "before_script" | "coverage" | "dependencies" | "environment" | "except" | "hooks" | "image" | "interruptible" | "needs" | "only" | "parallel" | "release" | "resource_group" | "retry" | "rules" | "script" | "services" | "stage" | "tags" | "trigger" | "variables"> {
9
36
  stage: JobTemplate["stage"];
@@ -23,8 +50,9 @@ export interface GitlabJobDef extends Pick<JobTemplate, "after_script" | "allow_
23
50
  export interface GitlabPipeline extends Pick<JobTemplate, "variables"> {
24
51
  image: string;
25
52
  workflow?: {
26
- rules: GitlabRule[];
27
53
  name?: string;
54
+ auto_cancel?: GitlabAutoCancel;
55
+ rules: GitlabWorkflowRule[];
28
56
  variables?: Record<string, string>;
29
57
  };
30
58
  stages: string[];
@@ -37,6 +37,38 @@ Generated layout:
37
37
  Stages: setup → test → build → deploy → verify (post-deploy checks),
38
38
  plus stop jobs for review-app teardown.
39
39
 
40
+ ## Superseded pipelines are cancelled
41
+
42
+ Pushing a new commit cancels the pipeline of the previous one, so the
43
+ runners are not busy with results nobody will read.
44
+
45
+ | Pipeline | On a new commit |
46
+ |---|---|
47
+ | `mr` | cancelled |
48
+ | `mainBranch` (dev) | cancelled, except a release already running |
49
+ | `taggedRelease` | **runs through** — never cancelled |
50
+ | agent runs (`trigger`) | **runs through** — never cancelled |
51
+
52
+ - **GitHub**: the generated MR workflow sets `concurrency` with
53
+ `cancel-in-progress: true`.
54
+ - **GitLab**: generated `workflow:auto_cancel:on_new_commit:
55
+ interruptible`, with per-rule `none` for tags and agent runs. Every
56
+ job carries an explicit `interruptible`, jobs that must finish
57
+ (release jobs, agent jobs) carry `interruptible: false`.
58
+
59
+ **GitLab requires the project setting too.** The generated YAML only
60
+ tunes *how* redundant pipelines are cancelled — it does not switch the
61
+ feature on. If old pipelines keep running, check **Settings > CI/CD >
62
+ General pipelines > Auto-cancel redundant pipelines**; with that
63
+ checkbox off nothing is ever cancelled. (`catladder project-doctor`
64
+ does not check this.)
65
+
66
+ **Adding a hand-written GitLab job?** Set `interruptible` explicitly.
67
+ GitLab defaults it to `false`, and a non-interruptible job that has
68
+ started keeps *itself* alive — under gitlab's own default
69
+ (`conservative`, which catladder overrides) it would shield the whole
70
+ pipeline from cancellation.
71
+
40
72
  ## Review-app auto-stop and pinning (GitLab)
41
73
 
42
74
  GitLab review environments stop automatically after 1 week, dev