@intentius/chant-lexicon-gitlab 0.0.18 → 0.0.24

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "algorithm": "xxhash64",
3
3
  "artifacts": {
4
- "manifest.json": "2c937933d498dcb5",
4
+ "manifest.json": "5879275be7cad0fa",
5
5
  "meta.json": "c663c6c63748a9d0",
6
6
  "types/index.d.ts": "64e65524615be023",
7
7
  "rules/missing-stage.ts": "6d5379e74209a735",
@@ -28,8 +28,8 @@
28
28
  "rules/wgl027.ts": "ea7928f37607a583",
29
29
  "rules/wgl014.ts": "6248a852888e8028",
30
30
  "rules/yaml-helpers.ts": "3e414c7affe56728",
31
- "skills/chant-gitlab.md": "d791ef1f7f83e9c1",
32
- "skills/gitlab-ci-patterns.md": "bdb522359253aac8"
31
+ "skills/chant-gitlab.md": "fe29add147305b7e",
32
+ "skills/chant-gitlab-patterns.md": "efb54bd8ea52071b"
33
33
  },
34
- "composite": "77e2588f9bf9bc48"
34
+ "composite": "58a5f51312595838"
35
35
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitlab",
3
- "version": "0.0.18",
3
+ "version": "0.0.24",
4
4
  "chantVersion": ">=0.1.0",
5
5
  "namespace": "GitLab",
6
6
  "intrinsics": [
@@ -1,5 +1,5 @@
1
1
  ---
2
- skill: gitlab-ci-patterns
2
+ skill: chant-gitlab-patterns
3
3
  description: GitLab CI/CD pipeline stages, caching, artifacts, includes, and advanced patterns
4
4
  user-invocable: true
5
5
  ---
@@ -8,7 +8,7 @@ user-invocable: true
8
8
 
9
9
  ## How chant and GitLab CI relate
10
10
 
11
- chant is a **synthesis-only** tool — it compiles TypeScript source files into `.gitlab-ci.yml` (YAML). chant does NOT call GitLab APIs. Your job as an agent is to bridge the two:
11
+ chant is a **synthesis compiler** — it compiles TypeScript source files into `.gitlab-ci.yml` (YAML). `chant build` does not call GitLab APIs; synthesis is pure and deterministic. Your job as an agent is to bridge synthesis and deployment:
12
12
 
13
13
  - Use **chant** for: build, lint, diff (local YAML comparison)
14
14
  - Use **git + GitLab API** for: push, merge requests, pipeline monitoring, job logs, rollback, and all deployment operations
@@ -244,7 +244,7 @@ new Job({
244
244
 
245
245
  ### Environment promotion
246
246
 
247
- Deploy through environments in order: dev staging production. Use `rules:` and `when: manual` to gate promotions.
247
+ Deploy through environments in order: dev -> staging -> production. Use `rules:` and `when: manual` to gate promotions.
248
248
 
249
249
  ### Rollback to a previous deployment
250
250
 
@@ -356,11 +356,11 @@ rules:
356
356
 
357
357
  ### Merged results pipelines
358
358
 
359
- Enable in project settings CI/CD General pipelines "Merged results pipelines". These test the result of merging your branch into the target — catching integration issues before merge.
359
+ Enable in project settings -> CI/CD -> General pipelines -> "Merged results pipelines". These test the result of merging your branch into the target — catching integration issues before merge.
360
360
 
361
361
  ### Merge trains
362
362
 
363
- Merge trains queue MRs and test each one merged on top of the previous. Enable in project settings Merge requests "Merge trains". Requires merged results pipelines.
363
+ Merge trains queue MRs and test each one merged on top of the previous. Enable in project settings -> Merge requests -> "Merge trains". Requires merged results pipelines.
364
364
 
365
365
  ## Troubleshooting decision tree
366
366
 
@@ -373,11 +373,11 @@ curl --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
373
373
 
374
374
  ### Step 2: Branch on status
375
375
 
376
- - **`running` / `pending` / `created`** Wait. Do not take action while the pipeline is in progress.
377
- - **`failed`** Read the failed job logs (Step 3).
378
- - **`success`** Pipeline is healthy. If behavior is wrong, check job scripts and configuration.
379
- - **`canceled`** Re-run if needed: `curl --request POST ... /pipelines/$PIPELINE_ID/retry`
380
- - **`skipped`** All jobs were filtered out by `rules:`. Check rule conditions.
376
+ - **`running` / `pending` / `created`** -> Wait. Do not take action while the pipeline is in progress.
377
+ - **`failed`** -> Read the failed job logs (Step 3).
378
+ - **`success`** -> Pipeline is healthy. If behavior is wrong, check job scripts and configuration.
379
+ - **`canceled`** -> Re-run if needed: `curl --request POST ... /pipelines/$PIPELINE_ID/retry`
380
+ - **`skipped`** -> All jobs were filtered out by `rules:`. Check rule conditions.
381
381
 
382
382
  ### Step 3: Read failed job logs
383
383
 
@@ -413,7 +413,7 @@ curl --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
413
413
 
414
414
  Variables are resolved in this order (highest priority first):
415
415
  1. Job-level `variables:`
416
- 2. Project CI/CD variables (Settings CI/CD Variables)
416
+ 2. Project CI/CD variables (Settings -> CI/CD -> Variables)
417
417
  3. Group CI/CD variables
418
418
  4. Instance CI/CD variables
419
419
 
package/package.json CHANGED
@@ -1,7 +1,25 @@
1
1
  {
2
2
  "name": "@intentius/chant-lexicon-gitlab",
3
- "version": "0.0.18",
3
+ "version": "0.0.24",
4
+ "description": "GitLab CI lexicon for chant — declarative IaC in TypeScript",
4
5
  "license": "Apache-2.0",
6
+ "homepage": "https://intentius.io/chant",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/intentius/chant.git",
10
+ "directory": "lexicons/gitlab"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/intentius/chant/issues"
14
+ },
15
+ "keywords": [
16
+ "infrastructure-as-code",
17
+ "iac",
18
+ "typescript",
19
+ "gitlab",
20
+ "gitlab-ci",
21
+ "chant"
22
+ ],
5
23
  "type": "module",
6
24
  "files": [
7
25
  "src/",
@@ -25,7 +43,7 @@
25
43
  "prepack": "bun run generate && bun run bundle && bun run validate"
26
44
  },
27
45
  "dependencies": {
28
- "@intentius/chant": "0.0.18"
46
+ "@intentius/chant": "0.0.22"
29
47
  },
30
48
  "devDependencies": {
31
49
  "typescript": "^5.9.3"
@@ -138,6 +138,16 @@ describe("DockerBuild", () => {
138
138
  const props = (instance.build as any).props;
139
139
  expect(props.rules).toBeUndefined();
140
140
  });
141
+
142
+ test("per-member defaults override build job", () => {
143
+ const instance = DockerBuild({
144
+ defaults: {
145
+ build: { tags: ["docker-runner"] },
146
+ },
147
+ });
148
+ const props = (instance.build as any).props;
149
+ expect(props.tags).toEqual(["docker-runner"]);
150
+ });
141
151
  });
142
152
 
143
153
  // ---------------------------------------------------------------------------
@@ -287,6 +297,36 @@ describe("NodePipeline", () => {
287
297
  const artProps = (props.artifacts as any).props;
288
298
  expect(artProps.when).toBe("always");
289
299
  });
300
+
301
+ test("per-member defaults override build job", () => {
302
+ const instance = NodePipeline({
303
+ defaults: {
304
+ build: { tags: ["node-runner"] },
305
+ },
306
+ });
307
+ const props = (instance.build as any).props;
308
+ expect(props.tags).toEqual(["node-runner"]);
309
+ });
310
+
311
+ test("per-member defaults override test job", () => {
312
+ const instance = NodePipeline({
313
+ defaults: {
314
+ test: { allow_failure: true },
315
+ },
316
+ });
317
+ const props = (instance.test as any).props;
318
+ expect(props.allow_failure).toBe(true);
319
+ });
320
+
321
+ test("per-member defaults override defaults member", () => {
322
+ const instance = NodePipeline({
323
+ defaults: {
324
+ defaults: { interruptible: true },
325
+ },
326
+ });
327
+ const props = (instance.defaults as any).props;
328
+ expect(props.interruptible).toBe(true);
329
+ });
290
330
  });
291
331
 
292
332
  // ---------------------------------------------------------------------------
@@ -451,6 +491,37 @@ describe("PythonPipeline", () => {
451
491
  const cacheProps = (defaultProps.cache[0] as any).props;
452
492
  expect(cacheProps.policy).toBe("pull-push");
453
493
  });
494
+
495
+ test("per-member defaults override test job", () => {
496
+ const instance = PythonPipeline({
497
+ defaults: {
498
+ test: { tags: ["python-runner"] },
499
+ },
500
+ });
501
+ const props = (instance.test as any).props;
502
+ expect(props.tags).toEqual(["python-runner"]);
503
+ });
504
+
505
+ test("per-member defaults override lint job", () => {
506
+ const instance = PythonPipeline({
507
+ defaults: {
508
+ lint: { allow_failure: true },
509
+ },
510
+ });
511
+ const members = instance.members as any;
512
+ const props = (members.lint as any).props;
513
+ expect(props.allow_failure).toBe(true);
514
+ });
515
+
516
+ test("per-member defaults override defaults member", () => {
517
+ const instance = PythonPipeline({
518
+ defaults: {
519
+ defaults: { interruptible: true },
520
+ },
521
+ });
522
+ const props = (instance.defaults as any).props;
523
+ expect(props.interruptible).toBe(true);
524
+ });
454
525
  });
455
526
 
456
527
  // ---------------------------------------------------------------------------
@@ -609,4 +680,26 @@ describe("ReviewApp", () => {
609
680
  const envProps = (props.environment as any).props;
610
681
  expect(envProps.url).toContain("$CI_ENVIRONMENT_SLUG");
611
682
  });
683
+
684
+ test("per-member defaults override deploy job", () => {
685
+ const instance = ReviewApp({
686
+ ...baseProps,
687
+ defaults: {
688
+ deploy: { tags: ["deploy-runner"] },
689
+ },
690
+ });
691
+ const props = (instance.deploy as any).props;
692
+ expect(props.tags).toEqual(["deploy-runner"]);
693
+ });
694
+
695
+ test("per-member defaults override stop job", () => {
696
+ const instance = ReviewApp({
697
+ ...baseProps,
698
+ defaults: {
699
+ stop: { allow_failure: true },
700
+ },
701
+ });
702
+ const props = (instance.stop as any).props;
703
+ expect(props.allow_failure).toBe(true);
704
+ });
612
705
  });
@@ -1,4 +1,4 @@
1
- import { Composite } from "@intentius/chant";
1
+ import { Composite, mergeDefaults } from "@intentius/chant";
2
2
  import { Job, Image, Service, Rule } from "../generated";
3
3
  import { CI } from "../variables";
4
4
 
@@ -23,6 +23,10 @@ export interface DockerBuildProps {
23
23
  rules?: InstanceType<typeof Rule>[];
24
24
  /** Docker version. Default: "27" */
25
25
  dockerVersion?: string;
26
+ /** Per-member defaults for customizing the build job. */
27
+ defaults?: {
28
+ build?: Partial<ConstructorParameters<typeof Job>[0]>;
29
+ };
26
30
  }
27
31
 
28
32
  export const DockerBuild = Composite<DockerBuildProps>((props) => {
@@ -37,6 +41,7 @@ export const DockerBuild = Composite<DockerBuildProps>((props) => {
37
41
  buildArgs,
38
42
  rules,
39
43
  dockerVersion = "27",
44
+ defaults: defs,
40
45
  } = props;
41
46
 
42
47
  const buildArgFlags = buildArgs
@@ -63,7 +68,7 @@ export const DockerBuild = Composite<DockerBuildProps>((props) => {
63
68
  );
64
69
  }
65
70
 
66
- const build = new Job({
71
+ const build = new Job(mergeDefaults({
67
72
  stage,
68
73
  image: new Image({ name: `docker:${dockerVersion}-cli` }),
69
74
  services: [new Service({ name: `docker:${dockerVersion}-dind`, alias: "docker" })],
@@ -75,7 +80,7 @@ export const DockerBuild = Composite<DockerBuildProps>((props) => {
75
80
  ],
76
81
  script,
77
82
  ...(rules ? { rules } : {}),
78
- });
83
+ }, defs?.build));
79
84
 
80
85
  return { build };
81
86
  }, "DockerBuild");
@@ -1,4 +1,4 @@
1
- import { Composite, withDefaults } from "@intentius/chant";
1
+ import { Composite, mergeDefaults, withDefaults } from "@intentius/chant";
2
2
  import { Job, Default, Image, Cache, Artifacts } from "../generated";
3
3
  import { CI } from "../variables";
4
4
 
@@ -17,6 +17,12 @@ export interface NodePipelineProps {
17
17
  artifactExpiry?: string;
18
18
  /** Override auto-detected install command */
19
19
  installCommand?: string;
20
+ /** Per-member defaults for customizing the generated resources. */
21
+ defaults?: {
22
+ defaults?: Partial<ConstructorParameters<typeof Default>[0]>;
23
+ build?: Partial<ConstructorParameters<typeof Job>[0]>;
24
+ test?: Partial<ConstructorParameters<typeof Job>[0]>;
25
+ };
20
26
  }
21
27
 
22
28
  const cacheConfig = {
@@ -52,6 +58,7 @@ export const NodePipeline = Composite<NodePipelineProps>((props) => {
52
58
  buildArtifactPaths = ["dist/"],
53
59
  artifactExpiry = "1 hour",
54
60
  installCommand,
61
+ defaults: defs,
55
62
  } = props;
56
63
 
57
64
  const pm = cacheConfig[packageManager];
@@ -68,13 +75,13 @@ export const NodePipeline = Composite<NodePipelineProps>((props) => {
68
75
 
69
76
  const variables = Object.keys(pm.envVars).length > 0 ? pm.envVars : undefined;
70
77
 
71
- const defaults = new Default({
78
+ const defaults = new Default(mergeDefaults({
72
79
  image: nodeImage,
73
80
  cache: [cache],
74
81
  ...(variables ? {} : {}),
75
- });
82
+ }, defs?.defaults));
76
83
 
77
- const build = new Job({
84
+ const build = new Job(mergeDefaults({
78
85
  stage: "build",
79
86
  script: [install, `${run} ${buildScript}`],
80
87
  artifacts: new Artifacts({
@@ -82,9 +89,9 @@ export const NodePipeline = Composite<NodePipelineProps>((props) => {
82
89
  expire_in: artifactExpiry,
83
90
  }),
84
91
  ...(variables ? { variables } : {}),
85
- });
92
+ }, defs?.build));
86
93
 
87
- const test = new Job({
94
+ const test = new Job(mergeDefaults({
88
95
  stage: "test",
89
96
  script: [install, `${run} ${testScript}`],
90
97
  artifacts: new Artifacts({
@@ -92,7 +99,7 @@ export const NodePipeline = Composite<NodePipelineProps>((props) => {
92
99
  when: "always",
93
100
  }),
94
101
  ...(variables ? { variables } : {}),
95
- });
102
+ }, defs?.test));
96
103
 
97
104
  return { defaults, build, test };
98
105
  }, "NodePipeline");
@@ -1,4 +1,4 @@
1
- import { Composite } from "@intentius/chant";
1
+ import { Composite, mergeDefaults } from "@intentius/chant";
2
2
  import { Job, Default, Image, Cache, Artifacts } from "../generated";
3
3
  import { CI } from "../variables";
4
4
 
@@ -13,6 +13,12 @@ export interface PythonPipelineProps {
13
13
  requirementsFile?: string;
14
14
  /** Use poetry instead of pip. Default: false */
15
15
  usePoetry?: boolean;
16
+ /** Per-member defaults for customizing the generated resources. */
17
+ defaults?: {
18
+ defaults?: Partial<ConstructorParameters<typeof Default>[0]>;
19
+ test?: Partial<ConstructorParameters<typeof Job>[0]>;
20
+ lint?: Partial<ConstructorParameters<typeof Job>[0]>;
21
+ };
16
22
  }
17
23
 
18
24
  export const PythonPipeline = Composite<PythonPipelineProps>((props) => {
@@ -22,6 +28,7 @@ export const PythonPipeline = Composite<PythonPipelineProps>((props) => {
22
28
  lintCommand = "ruff check .",
23
29
  requirementsFile = "requirements.txt",
24
30
  usePoetry = false,
31
+ defaults: defs,
25
32
  } = props;
26
33
 
27
34
  const pythonImage = new Image({ name: `python:${pythonVersion}-slim` });
@@ -42,13 +49,13 @@ export const PythonPipeline = Composite<PythonPipelineProps>((props) => {
42
49
 
43
50
  const activateStep = usePoetry ? "source .venv/bin/activate" : "source .venv/bin/activate";
44
51
 
45
- const defaults = new Default({
52
+ const defaults = new Default(mergeDefaults({
46
53
  image: pythonImage,
47
54
  cache: [cache],
48
55
  before_script: [...installSteps],
49
- });
56
+ }, defs?.defaults));
50
57
 
51
- const test = new Job({
58
+ const test = new Job(mergeDefaults({
52
59
  stage: "test",
53
60
  variables: { PIP_CACHE_DIR: `${CI.ProjectDir}/.pip-cache` },
54
61
  script: [activateStep, testCommand],
@@ -56,15 +63,15 @@ export const PythonPipeline = Composite<PythonPipelineProps>((props) => {
56
63
  reports: { junit: "report.xml" },
57
64
  when: "always",
58
65
  }),
59
- });
66
+ }, defs?.test));
60
67
 
61
68
  const lint =
62
69
  lintCommand !== null
63
- ? new Job({
70
+ ? new Job(mergeDefaults({
64
71
  stage: "test",
65
72
  variables: { PIP_CACHE_DIR: `${CI.ProjectDir}/.pip-cache` },
66
73
  script: [activateStep, lintCommand],
67
- })
74
+ }, defs?.lint))
68
75
  : undefined;
69
76
 
70
77
  if (lint) {
@@ -1,4 +1,4 @@
1
- import { Composite } from "@intentius/chant";
1
+ import { Composite, mergeDefaults } from "@intentius/chant";
2
2
  import { Job, Image, Environment, Rule } from "../generated";
3
3
  import { CI } from "../variables";
4
4
 
@@ -17,6 +17,11 @@ export interface ReviewAppProps {
17
17
  image?: InstanceType<typeof Image>;
18
18
  /** Job stage. Default: "deploy" */
19
19
  stage?: string;
20
+ /** Per-member defaults for customizing the deploy and stop jobs. */
21
+ defaults?: {
22
+ deploy?: Partial<ConstructorParameters<typeof Job>[0]>;
23
+ stop?: Partial<ConstructorParameters<typeof Job>[0]>;
24
+ };
20
25
  }
21
26
 
22
27
  export const ReviewApp = Composite<ReviewAppProps>((props) => {
@@ -28,6 +33,7 @@ export const ReviewApp = Composite<ReviewAppProps>((props) => {
28
33
  autoStopIn = "1 week",
29
34
  image,
30
35
  stage = "deploy",
36
+ defaults: defs,
31
37
  } = props;
32
38
 
33
39
  const stopJobName = `${name}-stop`;
@@ -35,7 +41,7 @@ export const ReviewApp = Composite<ReviewAppProps>((props) => {
35
41
  const deployScriptArr = Array.isArray(deployScript) ? deployScript : [deployScript];
36
42
  const stopScriptArr = Array.isArray(stopScript) ? stopScript : [stopScript];
37
43
 
38
- const deploy = new Job({
44
+ const deploy = new Job(mergeDefaults({
39
45
  stage,
40
46
  ...(image ? { image } : {}),
41
47
  environment: new Environment({
@@ -46,9 +52,9 @@ export const ReviewApp = Composite<ReviewAppProps>((props) => {
46
52
  }),
47
53
  rules: [new Rule({ if: CI.MergeRequestIid })],
48
54
  script: deployScriptArr,
49
- });
55
+ }, defs?.deploy));
50
56
 
51
- const stop = new Job({
57
+ const stop = new Job(mergeDefaults({
52
58
  stage,
53
59
  ...(image ? { image } : {}),
54
60
  environment: new Environment({
@@ -57,7 +63,7 @@ export const ReviewApp = Composite<ReviewAppProps>((props) => {
57
63
  }),
58
64
  rules: [new Rule({ if: CI.MergeRequestIid, when: "manual" })],
59
65
  script: stopScriptArr,
60
- });
66
+ }, defs?.stop));
61
67
 
62
68
  return { deploy, stop };
63
69
  }, "ReviewApp");