@intentius/chant-lexicon-gitlab 0.124.56 → 0.124.57

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.
@@ -18,6 +18,14 @@
18
18
  * A wave's `environment` is the job's own `environment:`; protect it in the
19
19
  * project settings to put a reviewer in front of the job as well.
20
20
  *
21
+ * The wave jobs carry no `resource_group` (ruling for ci-products
22
+ * 2026-10-28, "Ledger lock"), the same as the GitHub and Forgejo waves files
23
+ * carry no concurrency group: a per-wave resource group would keep two
24
+ * pipelines' plunge stacks apart where their resource rows do not meet. A
25
+ * stock Pulumi stack or a Terraform root waits for its row on chant's ledger,
26
+ * oldest commit first, up to the job's `timeout`, which `CHANT_LOCK_WAIT`
27
+ * sits five minutes under; the project's own maximum timeout still caps it.
28
+ *
21
29
  * With `resume` on the spec (#3683), a `<name>-resume` job runs `chant run
22
30
  * resume --op <name>` in scheduled pipelines only: create a pipeline schedule
23
31
  * with the spec's cron. It retries a waiting wave's job once its approval
@@ -1 +1 @@
1
- {"version":3,"file":"generate-op-waves-pipeline.d.ts","sourceRoot":"","sources":["../../src/components/generate-op-waves-pipeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4DG;AAkBH,OAAO,EAYL,KAAK,WAAW,EACjB,MAAM,8BAA8B,CAAC;AAEtC,OAAO,KAAK,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAO9F,yHAAyH;AACzH,eAAO,MAAM,oBAAoB,GAAoB,CAAC;AAEtD,gHAAgH;AAChH,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,sBAAsB,GAAG,qBAAqB,CAqKvH"}
1
+ {"version":3,"file":"generate-op-waves-pipeline.d.ts","sourceRoot":"","sources":["../../src/components/generate-op-waves-pipeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoEG;AAkBH,OAAO,EAaL,KAAK,WAAW,EACjB,MAAM,8BAA8B,CAAC;AAEtC,OAAO,KAAK,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAO9F,yHAAyH;AACzH,eAAO,MAAM,oBAAoB,GAAoB,CAAC;AAEtD,gHAAgH;AAChH,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,sBAAsB,GAAG,qBAAqB,CAuKvH"}
@@ -18,6 +18,14 @@
18
18
  * A wave's `environment` is the job's own `environment:`; protect it in the
19
19
  * project settings to put a reviewer in front of the job as well.
20
20
  *
21
+ * The wave jobs carry no `resource_group` (ruling for ci-products
22
+ * 2026-10-28, "Ledger lock"), the same as the GitHub and Forgejo waves files
23
+ * carry no concurrency group: a per-wave resource group would keep two
24
+ * pipelines' plunge stacks apart where their resource rows do not meet. A
25
+ * stock Pulumi stack or a Terraform root waits for its row on chant's ledger,
26
+ * oldest commit first, up to the job's `timeout`, which `CHANT_LOCK_WAIT`
27
+ * sits five minutes under; the project's own maximum timeout still caps it.
28
+ *
21
29
  * With `resume` on the spec (#3683), a `<name>-resume` job runs `chant run
22
30
  * resume --op <name>` in scheduled pipelines only: create a pipeline schedule
23
31
  * with the spec's cron. It retries a waiting wave's job once its approval
@@ -60,7 +68,7 @@
60
68
  * after it stop.
61
69
  */
62
70
  import { assertGitlabBranch, assertGitlabEnvironment, assertRunnerLabels, CI_IMAGE, environmentDoc, GITLAB_FULL_HISTORY, GITLAB_MERGE_REQUEST_SOURCE, GITLAB_SCHEDULE_SOURCE, gitlabIdTokensDoc, gitlabPushRule, gitlabSetupScript, gitlabTags, nonEmpty, pushBranches, } from "@intentius/chant/ci-jobs";
63
- import { opWaveGroupOf, opWaveJobs, opWaveOutcomeDir, opWavesControlTarget, opWavesLastJobs, OP_WAVES_APPROVAL_STATUS_VAR, opWavesApprovalStatusCommand, opWavesPostsApprovalStatus, opWavesOutcomeCommand, opWavesRecordPlansCommand, opWavesResumeCommand, } from "@intentius/chant/op/op-waves";
71
+ import { opWaveGroupOf, opWaveJobs, opWaveJobTimeout, opWaveOutcomeDir, opWavesControlTarget, opWavesLastJobs, OP_WAVES_APPROVAL_STATUS_VAR, opWavesApprovalStatusCommand, opWavesPostsApprovalStatus, opWavesOutcomeCommand, opWavesRecordPlansCommand, opWavesResumeCommand, } from "@intentius/chant/op/op-waves";
64
72
  import { CONTROL_OUTCOME_VAR, CONTROL_TOKEN_VARS, controlDispatchJob } from "@intentius/chant/control/dispatch";
65
73
  import { gitlabTradeIdTokens, gitlabTradeLines, TRADE_SPEC_ENV } from "@intentius/chant/ci-identity";
66
74
  import { JOB_GUARD_ENV, jobGuardLine, jobGuardSpec, opWaveJobLabel } from "@intentius/chant/ci-job-guard";
@@ -108,6 +116,8 @@ export function generateGitlabOpWavesPipeline(spec, options) {
108
116
  if (spec.resume)
109
117
  stages.push("resume");
110
118
  const entries = [["stages", stages]];
119
+ // The ruling for ci-products (2026-10-28): each wave job's timeout, and the lock wait five minutes under it.
120
+ const timeout = opWaveJobTimeout(options.jobTimeoutMinutes);
111
121
  const variables = nonEmpty("variables", options.variables).variables;
112
122
  if (variables)
113
123
  entries.push(["variables", variables]);
@@ -162,10 +172,10 @@ export function generateGitlabOpWavesPipeline(spec, options) {
162
172
  stage: stages[job.wave - 1 + (byReview ? 1 : 0)],
163
173
  image,
164
174
  ...(tags ? { tags } : {}),
165
- resource_group: `${spec.name}-${wave.name}`,
175
+ timeout: `${timeout.minutes} minutes`,
166
176
  ...(environment ? { environment: environmentDoc(environment) } : {}),
167
177
  ...(idTokens ? { id_tokens: idTokens } : {}),
168
- variables: { ...GITLAB_FULL_HISTORY, ...(wave.variables ?? {}), ...(group?.variables ?? {}), ...(cloud ? { [TRADE_SPEC_ENV]: JSON.stringify(cloud) } : {}), [JOB_GUARD_ENV]: JSON.stringify(guard) },
178
+ variables: { ...GITLAB_FULL_HISTORY, ...timeout.env, ...(wave.variables ?? {}), ...(group?.variables ?? {}), ...(cloud ? { [TRADE_SPEC_ENV]: JSON.stringify(cloud) } : {}), [JOB_GUARD_ENV]: JSON.stringify(guard) },
169
179
  rules,
170
180
  ...(job.needs.length > 0 ? { needs: job.needs } : {}),
171
181
  script: [jobGuardLine(), ...(cloud ? gitlabTradeLines() : []), ...dropControl, ...setup, ...(options.beforeScript ?? []), job.command.join(" "), ...(options.extraScript ?? [])],
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "algorithm": "sha256",
3
3
  "artifacts": {
4
- "manifest.json": "601276a64d47a1758b2b6e26d232c5f746ec007b05950d993fc37ef4f09e2250",
4
+ "manifest.json": "617558151e681cf5f4ea5df936170cd8ec7739e81744fb3157b8f34f416b02eb",
5
5
  "meta.json": "db082fbf90c5941c498b2bee0f106103449c1a4c257716ca2220f0dd490450b2",
6
6
  "types/index.d.ts": "a048a66ebe20da0cb5fc889054cac69044d9bf882e2c56b5c5bf113d1f3ba57c",
7
7
  "rules/artifact-no-expiry.ts": "0ca5bb972d4a542126e8a0229d43b55658394cb7dd9b9923b2c590bec1c2ad7d",
@@ -55,5 +55,5 @@
55
55
  "skills/chant-gitlab-migrate.md": "4853d04980560b379e5b0f7267dcb0a1e5d5879cb9e9931681ce76b2a5fe69d8",
56
56
  "skills/chant-gitlab-patterns.md": "6d9a44e9e8de4c3820be9d65381b0d2ede4cb3626aaaf0011e21838a9fbf556e"
57
57
  },
58
- "composite": "9ed920259d4f54b7734a8887fd98ea4e6357311cde69b7a84197365dc95505b5"
58
+ "composite": "841ec4d4eec31c0a7724d61da9bf8b8f1592960dde4938b1b9140fe3ec0d9b7b"
59
59
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitlab",
3
- "version": "0.124.56",
3
+ "version": "0.124.57",
4
4
  "chantVersion": ">=0.1.0",
5
5
  "namespace": "GitLab",
6
6
  "intrinsics": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentius/chant-lexicon-gitlab",
3
- "version": "0.124.56",
3
+ "version": "0.124.57",
4
4
  "description": "GitLab CI lexicon for chant — declarative IaC in TypeScript",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://intentius.io/chant",
@@ -67,8 +67,8 @@
67
67
  "typescript": "^5.9.3"
68
68
  },
69
69
  "peerDependencies": {
70
- "@intentius/chant": "^0.124.56",
71
- "@intentius/chant-lexicon-github": "^0.124.56"
70
+ "@intentius/chant": "^0.124.57",
71
+ "@intentius/chant-lexicon-github": "^0.124.57"
72
72
  },
73
73
  "peerDependenciesMeta": {
74
74
  "@intentius/chant-lexicon-github": {
@@ -15,9 +15,10 @@ wave-1-dev:
15
15
  tags:
16
16
  - docker
17
17
  - dev
18
- resource_group: migrations-dev
18
+ timeout: '180 minutes'
19
19
  variables:
20
20
  GIT_DEPTH: '0'
21
+ CHANT_LOCK_WAIT: '10500'
21
22
  CHANT_JOB_GUARD: '{"forge":"gitlab","job":"wave 1 (dev) of migrations","branches":["main"],"runnerTags":["docker","dev"]}'
22
23
  rules:
23
24
  - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "main"'
@@ -38,12 +39,13 @@ wave-2-prod-decide:
38
39
  image: node:22
39
40
  tags:
40
41
  - plan
41
- resource_group: migrations-prod
42
+ timeout: '180 minutes'
42
43
  id_tokens:
43
44
  PLAN_TOKEN:
44
45
  aud: plan.example
45
46
  variables:
46
47
  GIT_DEPTH: '0'
48
+ CHANT_LOCK_WAIT: '10500'
47
49
  CHANT_JOB_GUARD: '{"forge":"gitlab","job":"the deciding job of wave 2 (prod) of migrations","branches":["main"],"runnerTags":["plan"]}'
48
50
  rules:
49
51
  - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "main"'
@@ -67,7 +69,7 @@ wave-2-prod-us:
67
69
  image: node:22
68
70
  tags:
69
71
  - us-apply
70
- resource_group: migrations-prod
72
+ timeout: '180 minutes'
71
73
  environment:
72
74
  name: prod-us
73
75
  id_tokens:
@@ -75,6 +77,7 @@ wave-2-prod-us:
75
77
  aud: us.example
76
78
  variables:
77
79
  GIT_DEPTH: '0'
80
+ CHANT_LOCK_WAIT: '10500'
78
81
  REGION: us
79
82
  CHANT_JOB_GUARD: '{"forge":"gitlab","job":"job group us of wave 2 (prod) of migrations","forgeEnvironment":"prod-us","branches":["main"],"runnerTags":["us-apply"]}'
80
83
  rules:
@@ -99,7 +102,7 @@ wave-2-prod-eu:
99
102
  image: node:22
100
103
  tags:
101
104
  - eu-apply
102
- resource_group: migrations-prod
105
+ timeout: '180 minutes'
103
106
  environment:
104
107
  name: prod-eu
105
108
  id_tokens:
@@ -107,6 +110,7 @@ wave-2-prod-eu:
107
110
  aud: eu.example
108
111
  variables:
109
112
  GIT_DEPTH: '0'
113
+ CHANT_LOCK_WAIT: '10500'
110
114
  CHANT_JOB_GUARD: '{"forge":"gitlab","job":"job group eu of wave 2 (prod) of migrations","forgeEnvironment":"prod-eu","branches":["main"],"runnerTags":["eu-apply"]}'
111
115
  rules:
112
116
  - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "main"'
@@ -95,9 +95,9 @@ describe("a runner per wave and job groups per wave (#3914)", () => {
95
95
  test("tags, environment, id_tokens, variables and the group's command on each job", () => {
96
96
  const yaml = generateGitlabOpWavesPipeline(grouped, { specFile: "waves.json" }).files[0]!.yaml;
97
97
  expect(yaml).toMatch(/wave-1-dev:\n\s+stage: wave-1-dev\n\s+image: node:22\n\s+tags:\n\s+- docker\n\s+- dev\n/);
98
- expect(yaml).toMatch(/wave-2-prod-decide:\n\s+stage: wave-2-prod\n\s+image: node:22\n\s+tags:\n\s+- plan\n\s+resource_group: migrations-prod\n\s+id_tokens:\n\s+PLAN_TOKEN:\n\s+aud: plan.example\n/);
98
+ expect(yaml).toMatch(/wave-2-prod-decide:\n\s+stage: wave-2-prod\n\s+image: node:22\n\s+tags:\n\s+- plan\n\s+timeout: '180 minutes'\n\s+id_tokens:\n\s+PLAN_TOKEN:\n\s+aud: plan.example\n/);
99
99
  expect(yaml).toMatch(
100
- /wave-2-prod-us:\n\s+stage: wave-2-prod\n\s+image: node:22\n\s+tags:\n\s+- us-apply\n\s+resource_group: migrations-prod\n\s+environment:\n\s+name: prod-us\n\s+id_tokens:\n\s+CLOUD_TOKEN:\n\s+aud: us.example\n\s+variables:\n\s+GIT_DEPTH: '0'\n\s+REGION: us\n\s+CHANT_JOB_GUARD: [^\n]*\n[\s\S]*?needs:\n\s+- wave-2-prod-decide\n\s+script:\n\s+- [^\n]*node -e[^\n]*\n\s+- echo us\n\s+- chant run wave --spec waves.json --wave 2 --group us\n/,
100
+ /wave-2-prod-us:\n\s+stage: wave-2-prod\n\s+image: node:22\n\s+tags:\n\s+- us-apply\n\s+timeout: '180 minutes'\n\s+environment:\n\s+name: prod-us\n\s+id_tokens:\n\s+CLOUD_TOKEN:\n\s+aud: us.example\n\s+variables:\n\s+GIT_DEPTH: '0'\n\s+CHANT_LOCK_WAIT: '10500'\n\s+REGION: us\n\s+CHANT_JOB_GUARD: [^\n]*\n[\s\S]*?needs:\n\s+- wave-2-prod-decide\n\s+script:\n\s+- [^\n]*node -e[^\n]*\n\s+- echo us\n\s+- chant run wave --spec waves.json --wave 2 --group us\n/,
101
101
  );
102
102
  expect(yaml).toMatch(/wave-2-prod-eu:[\s\S]*?id_tokens:\n\s+CLOUD_TOKEN:\n\s+aud: eu.example\n/);
103
103
  expect(yaml).not.toContain("_AUDIENCE");
@@ -149,3 +149,12 @@ describe("an Op wave's jobs by cloud identity (#4332)", () => {
149
149
  expect(jobs.every((j) => j.command[0] === "chant")).toBe(true);
150
150
  });
151
151
  });
152
+
153
+ describe("the ledger lock (ruling for ci-products 2026-10-28)", () => {
154
+ test("the wave jobs carry no resource_group; each carries its timeout and the lock wait under it", () => {
155
+ const yaml = generateGitlabOpWavesPipeline(spec, { specFile: "waves.json" }).files[0]!.yaml;
156
+ expect(yaml).not.toContain("resource_group");
157
+ expect(yaml).toContain("timeout: '180 minutes'\n");
158
+ expect(yaml).toContain("CHANT_LOCK_WAIT: '10500'\n");
159
+ });
160
+ });
@@ -18,6 +18,14 @@
18
18
  * A wave's `environment` is the job's own `environment:`; protect it in the
19
19
  * project settings to put a reviewer in front of the job as well.
20
20
  *
21
+ * The wave jobs carry no `resource_group` (ruling for ci-products
22
+ * 2026-10-28, "Ledger lock"), the same as the GitHub and Forgejo waves files
23
+ * carry no concurrency group: a per-wave resource group would keep two
24
+ * pipelines' plunge stacks apart where their resource rows do not meet. A
25
+ * stock Pulumi stack or a Terraform root waits for its row on chant's ledger,
26
+ * oldest commit first, up to the job's `timeout`, which `CHANT_LOCK_WAIT`
27
+ * sits five minutes under; the project's own maximum timeout still caps it.
28
+ *
21
29
  * With `resume` on the spec (#3683), a `<name>-resume` job runs `chant run
22
30
  * resume --op <name>` in scheduled pipelines only: create a pipeline schedule
23
31
  * with the spec's cron. It retries a waiting wave's job once its approval
@@ -79,6 +87,7 @@ import {
79
87
  import {
80
88
  opWaveGroupOf,
81
89
  opWaveJobs,
90
+ opWaveJobTimeout,
82
91
  opWaveOutcomeDir,
83
92
  opWavesControlTarget,
84
93
  opWavesLastJobs,
@@ -136,6 +145,8 @@ export function generateGitlabOpWavesPipeline(spec: OpWavesSpec, options: OpWave
136
145
  if (control) stages.push("control");
137
146
  if (spec.resume) stages.push("resume");
138
147
  const entries: Array<readonly [string, unknown]> = [["stages", stages]];
148
+ // The ruling for ci-products (2026-10-28): each wave job's timeout, and the lock wait five minutes under it.
149
+ const timeout = opWaveJobTimeout(options.jobTimeoutMinutes);
139
150
  const variables = nonEmpty("variables", options.variables).variables;
140
151
  if (variables) entries.push(["variables", variables]);
141
152
  if (byReview) {
@@ -189,10 +200,10 @@ export function generateGitlabOpWavesPipeline(spec: OpWavesSpec, options: OpWave
189
200
  stage: stages[job.wave - 1 + (byReview ? 1 : 0)],
190
201
  image,
191
202
  ...(tags ? { tags } : {}),
192
- resource_group: `${spec.name}-${wave.name}`,
203
+ timeout: `${timeout.minutes} minutes`,
193
204
  ...(environment ? { environment: environmentDoc(environment) } : {}),
194
205
  ...(idTokens ? { id_tokens: idTokens } : {}),
195
- variables: { ...GITLAB_FULL_HISTORY, ...(wave.variables ?? {}), ...(group?.variables ?? {}), ...(cloud ? { [TRADE_SPEC_ENV]: JSON.stringify(cloud) } : {}), [JOB_GUARD_ENV]: JSON.stringify(guard) },
206
+ variables: { ...GITLAB_FULL_HISTORY, ...timeout.env, ...(wave.variables ?? {}), ...(group?.variables ?? {}), ...(cloud ? { [TRADE_SPEC_ENV]: JSON.stringify(cloud) } : {}), [JOB_GUARD_ENV]: JSON.stringify(guard) },
196
207
  rules,
197
208
  ...(job.needs.length > 0 ? { needs: job.needs } : {}),
198
209
  script: [jobGuardLine(), ...(cloud ? gitlabTradeLines() : []), ...dropControl, ...setup, ...(options.beforeScript ?? []), job.command.join(" "), ...(options.extraScript ?? [])],