@intentius/chant-lexicon-gitlab 0.0.6 → 0.0.8

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": "c72b64b58dec21e0",
4
+ "manifest.json": "3a48cdeca93a7a4d",
5
5
  "meta.json": "9ee0d2f2d1679f09",
6
6
  "types/index.d.ts": "4e56a7de40d655c0",
7
7
  "rules/missing-stage.ts": "6d5379e74209a735",
@@ -11,7 +11,7 @@
11
11
  "rules/wgl011.ts": "b6b97e5104d91267",
12
12
  "rules/yaml-helpers.ts": "a66cc193b4ef4f0a",
13
13
  "rules/wgl010.ts": "1548cad287cdf286",
14
- "skills/gitlab-ci.md": "f860e40c2643c327"
14
+ "skills/chant-gitlab.md": "92ce73e97ee82ac9"
15
15
  },
16
- "composite": "95b9f28f579d5862"
16
+ "composite": "c6ad87f69da787de"
17
17
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitlab",
3
- "version": "0.0.6",
3
+ "version": "0.0.8",
4
4
  "chantVersion": ">=0.1.0",
5
5
  "namespace": "GitLab",
6
6
  "intrinsics": [
@@ -0,0 +1,59 @@
1
+ ---
2
+ skill: chant-gitlab
3
+ description: Build, validate, and deploy GitLab CI pipelines from a chant project
4
+ user-invocable: true
5
+ ---
6
+
7
+ # Deploying GitLab CI Pipelines from Chant
8
+
9
+ This project defines GitLab CI jobs as TypeScript in `src/`. Use these steps to build, validate, and deploy.
10
+
11
+ ## Build the pipeline
12
+
13
+ ```bash
14
+ chant build src/ --output .gitlab-ci.yml
15
+ ```
16
+
17
+ ## Validate before pushing
18
+
19
+ ```bash
20
+ chant lint src/
21
+ ```
22
+
23
+ For API-level validation against your GitLab instance:
24
+ ```bash
25
+ curl --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
26
+ "https://gitlab.com/api/v4/ci/lint" \
27
+ --data "{\"content\": \"$(cat .gitlab-ci.yml)\"}"
28
+ ```
29
+
30
+ ## Deploy
31
+
32
+ Commit and push the generated `.gitlab-ci.yml` — GitLab runs the pipeline automatically:
33
+
34
+ ```bash
35
+ chant build src/ --output .gitlab-ci.yml
36
+ git add .gitlab-ci.yml
37
+ git commit -m "Update pipeline"
38
+ git push
39
+ ```
40
+
41
+ ## Check pipeline status
42
+
43
+ - GitLab UI: project → CI/CD → Pipelines
44
+ - API: `curl --header "PRIVATE-TOKEN: $GITLAB_TOKEN" "https://gitlab.com/api/v4/projects/$PROJECT_ID/pipelines?per_page=5"`
45
+
46
+ ## Retry a failed job
47
+
48
+ - GitLab UI: click Retry on the failed job
49
+ - API: `curl --request POST --header "PRIVATE-TOKEN: $GITLAB_TOKEN" "https://gitlab.com/api/v4/projects/$PROJECT_ID/jobs/$JOB_ID/retry"`
50
+
51
+ ## Cancel a running pipeline
52
+
53
+ - API: `curl --request POST --header "PRIVATE-TOKEN: $GITLAB_TOKEN" "https://gitlab.com/api/v4/projects/$PROJECT_ID/pipelines/$PIPELINE_ID/cancel"`
54
+
55
+ ## Troubleshooting
56
+
57
+ - Check job logs in GitLab UI: project → CI/CD → Jobs → click the job
58
+ - `chant lint src/` catches: missing scripts (WGL002), deprecated only/except (WGL001), missing stages (WGL003), artifacts without expiry (WGL004)
59
+ - Post-synth checks (WGL010, WGL011) run during build
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentius/chant-lexicon-gitlab",
3
- "version": "0.0.6",
3
+ "version": "0.0.8",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "files": ["src/", "dist/"],
@@ -58,8 +58,7 @@ The generated file includes:
58
58
  | Chant (TypeScript) | YAML output | Rule |
59
59
  |--------------------|-------------|------|
60
60
  | \`export const buildApp = new Job({...})\` | \`build-app:\` | Export name → kebab-case job key |
61
- | \`expireIn: "1 week"\` | \`expire_in: 1 week\` | camelCase snake_case |
62
- | \`ifCondition: ...\` | \`if: ...\` | Reserved word properties use suffixed names |
61
+ | \`expire_in: "1 week"\` | \`expire_in: 1 week\` | Property names use spec-native snake_case |
63
62
  | \`new Image({ name: "node:20" })\` | \`image: node:20\` | Single-property objects are collapsed |
64
63
 
65
64
  ## Validating locally
@@ -108,7 +107,7 @@ export async function generateDocs(opts?: { verbose?: boolean }): Promise<void>
108
107
  description: "Jobs, stages, artifacts, caching, images, rules, environments, and triggers in the GitLab CI/CD lexicon",
109
108
  content: `Every exported \`Job\` declaration becomes a job entry in the generated \`.gitlab-ci.yml\`. The serializer handles the translation automatically:
110
109
 
111
- - Converts camelCase property names to snake_case (\`expireIn\` \`expire_in\`)
110
+ - Property names use spec-native snake_case (\`expire_in\`, \`allow_failure\`)
112
111
  - Converts export names to kebab-case job keys (\`buildApp\` → \`build-app\`)
113
112
  - Collects stages from all jobs into a \`stages:\` list
114
113
  - Collapses single-property objects (\`new Image({ name: "node:20" })\` → \`image: node:20\`)
@@ -539,6 +538,61 @@ deploy:
539
538
  5. **JUnit reports** — test artifacts include JUnit XML for GitLab MR display
540
539
  `,
541
540
  },
541
+ {
542
+ slug: "skills",
543
+ title: "AI Skills",
544
+ description: "AI agent skills bundled with the GitLab CI/CD lexicon",
545
+ content: `The GitLab lexicon ships an AI skill called **chant-gitlab** that teaches AI coding agents (like Claude Code) how to build, validate, and deploy GitLab CI pipelines from a chant project.
546
+
547
+ ## What are skills?
548
+
549
+ Skills are structured markdown documents bundled with a lexicon. When an AI agent works in a chant project, it discovers and loads relevant skills automatically — giving it operational knowledge about the deployment workflow without requiring the user to explain each step.
550
+
551
+ ## Installation
552
+
553
+ When you scaffold a new project with \`chant init --lexicon gitlab\`, the skill is installed to \`.claude/skills/chant-gitlab/SKILL.md\` for automatic discovery by Claude Code.
554
+
555
+ For existing projects, create the file manually:
556
+
557
+ \`\`\`
558
+ .claude/
559
+ skills/
560
+ chant-gitlab/
561
+ SKILL.md # skill content (see below)
562
+ \`\`\`
563
+
564
+ ## Skill: chant-gitlab
565
+
566
+ The \`chant-gitlab\` skill covers the full deployment lifecycle:
567
+
568
+ - **Build** — \`chant build src/ --output .gitlab-ci.yml\`
569
+ - **Validate** — \`chant lint src/\` + GitLab CI Lint API
570
+ - **Deploy** — commit and push the generated YAML
571
+ - **Status** — GitLab UI or pipelines API
572
+ - **Retry** — retry failed jobs via UI or API
573
+ - **Cancel** — cancel running pipelines via API
574
+ - **Troubleshooting** — job logs, lint rule codes (WGL001–WGL004), post-synth checks (WGL010, WGL011)
575
+
576
+ The skill is invocable as a slash command: \`/chant-gitlab\`
577
+
578
+ ## MCP integration
579
+
580
+ The lexicon also provides MCP (Model Context Protocol) tools and resources that AI agents can use programmatically:
581
+
582
+ | MCP tool | Description |
583
+ |----------|-------------|
584
+ | \`build\` | Build the chant project |
585
+ | \`lint\` | Run lint rules |
586
+ | \`explain\` | Summarize project resources |
587
+ | \`scaffold\` | Generate starter files |
588
+ | \`search\` | Search available resource types |
589
+ | \`gitlab:diff\` | Compare current build output against previous |
590
+
591
+ | MCP resource | Description |
592
+ |--------------|-------------|
593
+ | \`resource-catalog\` | JSON list of all supported GitLab CI entity types |
594
+ | \`examples/basic-pipeline\` | Example pipeline with build, test, and deploy jobs |`,
595
+ },
542
596
  ],
543
597
  basePath: "/chant/lexicons/gitlab/",
544
598
  };
@@ -3,7 +3,9 @@
3
3
  * with GitLab-specific manifest building and skill collection.
4
4
  */
5
5
 
6
+ import { createRequire } from "module";
6
7
  import { readFileSync } from "fs";
8
+ const require = createRequire(import.meta.url);
7
9
  import { join, dirname } from "path";
8
10
  import { fileURLToPath } from "url";
9
11
  import type { IntrinsicDef } from "@intentius/chant/lexicon";
@@ -65,7 +65,7 @@ workflow:
65
65
  expect(workflow!.properties.name).toBe("My Pipeline");
66
66
  });
67
67
 
68
- test("converts snake_case keys to camelCase", () => {
68
+ test("preserves spec-native snake_case property keys", () => {
69
69
  const yaml = `
70
70
  test-job:
71
71
  stage: test
@@ -77,8 +77,8 @@ test-job:
77
77
  - npm test
78
78
  `;
79
79
  const ir = parser.parse(yaml);
80
- expect(ir.resources[0].properties.beforeScript).toEqual(["echo setup"]);
81
- expect(ir.resources[0].properties.afterScript).toEqual(["echo done"]);
80
+ expect(ir.resources[0].properties.before_script).toEqual(["echo setup"]);
81
+ expect(ir.resources[0].properties.after_script).toEqual(["echo done"]);
82
82
  });
83
83
 
84
84
  test("converts kebab-case job names to camelCase", () => {
@@ -10,6 +10,14 @@ import type { TemplateParser, TemplateIR, ResourceIR } from "@intentius/chant/im
10
10
  /**
11
11
  * Reserved top-level keys in .gitlab-ci.yml that are NOT job definitions.
12
12
  */
13
+ /**
14
+ * Convert snake_case to camelCase — used only for TS variable names (logicalId),
15
+ * NOT for spec property names.
16
+ */
17
+ function snakeToCamelCase(name: string): string {
18
+ return name.replace(/_([a-z])/g, (_, c: string) => c.toUpperCase());
19
+ }
20
+
13
21
  const RESERVED_KEYS = new Set([
14
22
  "stages",
15
23
  "variables",
@@ -24,28 +32,6 @@ const RESERVED_KEYS = new Set([
24
32
  "pages",
25
33
  ]);
26
34
 
27
- /**
28
- * Map snake_case GitLab CI keys to camelCase for Chant properties.
29
- */
30
- function toCamelCase(name: string): string {
31
- return name.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
32
- }
33
-
34
- /**
35
- * Recursively convert snake_case keys in an object to camelCase.
36
- */
37
- function camelCaseKeys(value: unknown): unknown {
38
- if (value === null || value === undefined) return value;
39
- if (Array.isArray(value)) return value.map(camelCaseKeys);
40
- if (typeof value === "object") {
41
- const result: Record<string, unknown> = {};
42
- for (const [key, val] of Object.entries(value as Record<string, unknown>)) {
43
- result[toCamelCase(key)] = camelCaseKeys(val);
44
- }
45
- return result;
46
- }
47
- return value;
48
- }
49
35
 
50
36
  /**
51
37
  * Parse a YAML document into a plain object.
@@ -227,7 +213,7 @@ export class GitLabParser implements TemplateParser {
227
213
  resources.push({
228
214
  logicalId: "defaults",
229
215
  type: "GitLab::CI::Default",
230
- properties: camelCaseKeys(doc.default) as Record<string, unknown>,
216
+ properties: doc.default as Record<string, unknown>,
231
217
  });
232
218
  }
233
219
 
@@ -236,7 +222,7 @@ export class GitLabParser implements TemplateParser {
236
222
  resources.push({
237
223
  logicalId: "workflow",
238
224
  type: "GitLab::CI::Workflow",
239
- properties: camelCaseKeys(doc.workflow) as Record<string, unknown>,
225
+ properties: doc.workflow as Record<string, unknown>,
240
226
  });
241
227
  }
242
228
 
@@ -256,9 +242,9 @@ export class GitLabParser implements TemplateParser {
256
242
  obj.needs !== undefined
257
243
  ) {
258
244
  resources.push({
259
- logicalId: toCamelCase(key.replace(/-/g, "_")),
245
+ logicalId: snakeToCamelCase(key.replace(/-/g, "_")),
260
246
  type: "GitLab::CI::Job",
261
- properties: camelCaseKeys(obj) as Record<string, unknown>,
247
+ properties: obj as Record<string, unknown>,
262
248
  metadata: {
263
249
  originalName: key,
264
250
  stage: typeof obj.stage === "string" ? obj.stage : undefined,
@@ -1,5 +1,7 @@
1
+ import { createRequire } from "module";
1
2
  import type { CompletionContext, CompletionItem } from "@intentius/chant/lsp/types";
2
3
  import { LexiconIndex, lexiconCompletions, type LexiconEntry } from "@intentius/chant/lsp/lexicon-providers";
4
+ const require = createRequire(import.meta.url);
3
5
 
4
6
  let cachedIndex: LexiconIndex | null = null;
5
7
 
package/src/lsp/hover.ts CHANGED
@@ -1,5 +1,7 @@
1
+ import { createRequire } from "module";
1
2
  import type { HoverContext, HoverInfo } from "@intentius/chant/lsp/types";
2
3
  import { LexiconIndex, lexiconHover, type LexiconEntry } from "@intentius/chant/lsp/lexicon-providers";
4
+ const require = createRequire(import.meta.url);
3
5
 
4
6
  let cachedIndex: LexiconIndex | null = null;
5
7
 
@@ -159,9 +159,12 @@ describe("gitlabPlugin", () => {
159
159
  test("returns skills", () => {
160
160
  const skills = gitlabPlugin.skills!();
161
161
  expect(skills).toHaveLength(1);
162
- expect(skills[0].name).toBe("gitlab-ci");
162
+ expect(skills[0].name).toBe("chant-gitlab");
163
163
  expect(skills[0].description).toBeDefined();
164
- expect(skills[0].content).toContain("GitLab CI/CD");
164
+ expect(skills[0].content).toContain("skill: chant-gitlab");
165
+ expect(skills[0].content).toContain("user-invocable: true");
166
+ expect(skills[0].content).toContain("chant build");
167
+ expect(skills[0].content).toContain("chant lint");
165
168
  expect(skills[0].triggers).toHaveLength(2);
166
169
  expect(skills[0].examples).toHaveLength(1);
167
170
  });
@@ -217,10 +220,6 @@ describe("gitlabPlugin", () => {
217
220
  expect(typeof gitlabPlugin.coverage).toBe("function");
218
221
  });
219
222
 
220
- test("has rollback method", () => {
221
- expect(typeof gitlabPlugin.rollback).toBe("function");
222
- });
223
-
224
223
  test("has docs method", () => {
225
224
  expect(typeof gitlabPlugin.docs).toBe("function");
226
225
  });
package/src/plugin.ts CHANGED
@@ -5,7 +5,9 @@
5
5
  * for GitLab CI/CD pipelines.
6
6
  */
7
7
 
8
+ import { createRequire } from "module";
8
9
  import type { LexiconPlugin, IntrinsicDef, SkillDefinition } from "@intentius/chant/lexicon";
10
+ const require = createRequire(import.meta.url);
9
11
  import type { LintRule } from "@intentius/chant/lint/rule";
10
12
  import type { PostSynthCheck } from "@intentius/chant/lint/post-synth";
11
13
  import { gitlabSerializer } from "./serializer";
@@ -169,31 +171,6 @@ export const test = new Job({
169
171
  console.error(`Packaged ${stats.resources} entities, ${stats.ruleCount} rules, ${stats.skillCount} skills`);
170
172
  },
171
173
 
172
- async rollback(options?: { restore?: string; verbose?: boolean }): Promise<void> {
173
- const { listSnapshots, restoreSnapshot } = await import("./codegen/rollback");
174
- const { join, dirname } = await import("path");
175
- const { fileURLToPath } = await import("url");
176
-
177
- const pkgDir = dirname(dirname(fileURLToPath(import.meta.url)));
178
- const snapshotsDir = join(pkgDir, ".snapshots");
179
-
180
- if (options?.restore) {
181
- const generatedDir = join(pkgDir, "src", "generated");
182
- restoreSnapshot(String(options.restore), generatedDir);
183
- console.error(`Restored snapshot: ${options.restore}`);
184
- } else {
185
- const snapshots = listSnapshots(snapshotsDir);
186
- if (snapshots.length === 0) {
187
- console.error("No snapshots available.");
188
- } else {
189
- console.error(`Available snapshots (${snapshots.length}):`);
190
- for (const s of snapshots) {
191
- console.error(` ${s.timestamp} ${s.resourceCount} resources ${s.path}`);
192
- }
193
- }
194
- }
195
- },
196
-
197
174
  mcpTools() {
198
175
  return [
199
176
  {
@@ -283,45 +260,67 @@ export const deploy = new Job({
283
260
  skills(): SkillDefinition[] {
284
261
  return [
285
262
  {
286
- name: "gitlab-ci",
287
- description: "GitLab CI/CD best practices and common patterns",
263
+ name: "chant-gitlab",
264
+ description: "GitLab CI/CD pipeline management workflows, patterns, and troubleshooting",
288
265
  content: `---
289
- name: gitlab-ci
290
- description: GitLab CI/CD best practices and common patterns
266
+ skill: chant-gitlab
267
+ description: Build, validate, and deploy GitLab CI pipelines from a chant project
268
+ user-invocable: true
291
269
  ---
292
270
 
293
- # GitLab CI/CD with Chant
294
-
295
- ## Common Entity Types
296
-
297
- - \`Job\` Pipeline job definition
298
- - \`Default\` — Default settings inherited by all jobs
299
- - \`Workflow\` — Pipeline-level configuration
300
- - \`Artifacts\` Job artifact configuration
301
- - \`Cache\` — Cache configuration
302
- - \`Image\` — Docker image for a job
303
- - \`Rule\` Conditional execution rule
304
- - \`Environment\` — Deployment environment
305
- - \`Trigger\` — Trigger downstream pipeline
306
- - \`Include\` — Include external CI configuration
307
-
308
- ## Predefined Variables
309
-
310
- - \`CI.CommitBranch\` — Current branch name
311
- - \`CI.CommitSha\` Current commit SHA
312
- - \`CI.PipelineSource\` — What triggered the pipeline
313
- - \`CI.ProjectPath\` Project path (group/project)
314
- - \`CI.Registry\` — Container registry URL
315
- - \`CI.MergeRequestIid\` — MR internal ID
316
-
317
- ## Best Practices
318
-
319
- 1. **Use stages** — Organize jobs into logical stages (build, test, deploy)
320
- 2. **Cache dependencies** — Cache node_modules, pip packages, etc.
321
- 3. **Use rules** Prefer \`rules:\` over \`only:/except:\` for conditional execution
322
- 4. **Minimize artifacts** — Only preserve files needed by later stages
323
- 5. **Use includes** Share common configuration across projects
324
- 6. **Set timeouts** — Prevent stuck jobs from blocking pipelines
271
+ # Deploying GitLab CI Pipelines from Chant
272
+
273
+ This project defines GitLab CI jobs as TypeScript in \`src/\`. Use these steps to build, validate, and deploy.
274
+
275
+ ## Build the pipeline
276
+
277
+ \`\`\`bash
278
+ chant build src/ --output .gitlab-ci.yml
279
+ \`\`\`
280
+
281
+ ## Validate before pushing
282
+
283
+ \`\`\`bash
284
+ chant lint src/
285
+ \`\`\`
286
+
287
+ For API-level validation against your GitLab instance:
288
+ \`\`\`bash
289
+ curl --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \\
290
+ "https://gitlab.com/api/v4/ci/lint" \\
291
+ --data "{\\"content\\": \\"$(cat .gitlab-ci.yml)\\"}"
292
+ \`\`\`
293
+
294
+ ## Deploy
295
+
296
+ Commit and push the generated \`.gitlab-ci.yml\` — GitLab runs the pipeline automatically:
297
+
298
+ \`\`\`bash
299
+ chant build src/ --output .gitlab-ci.yml
300
+ git add .gitlab-ci.yml
301
+ git commit -m "Update pipeline"
302
+ git push
303
+ \`\`\`
304
+
305
+ ## Check pipeline status
306
+
307
+ - GitLab UI: project → CI/CD → Pipelines
308
+ - API: \`curl --header "PRIVATE-TOKEN: $GITLAB_TOKEN" "https://gitlab.com/api/v4/projects/$PROJECT_ID/pipelines?per_page=5"\`
309
+
310
+ ## Retry a failed job
311
+
312
+ - GitLab UI: click Retry on the failed job
313
+ - API: \`curl --request POST --header "PRIVATE-TOKEN: $GITLAB_TOKEN" "https://gitlab.com/api/v4/projects/$PROJECT_ID/jobs/$JOB_ID/retry"\`
314
+
315
+ ## Cancel a running pipeline
316
+
317
+ - API: \`curl --request POST --header "PRIVATE-TOKEN: $GITLAB_TOKEN" "https://gitlab.com/api/v4/projects/$PROJECT_ID/pipelines/$PIPELINE_ID/cancel"\`
318
+
319
+ ## Troubleshooting
320
+
321
+ - Check job logs in GitLab UI: project → CI/CD → Jobs → click the job
322
+ - \`chant lint src/\` catches: missing scripts (WGL002), deprecated only/except (WGL001), missing stages (WGL003), artifacts without expiry (WGL004)
323
+ - Post-synth checks (WGL010, WGL011) run during build
325
324
  `,
326
325
  triggers: [
327
326
  { type: "file-pattern", value: "**/*.gitlab.ts" },
@@ -121,12 +121,12 @@ describe("gitlabSerializer.serialize", () => {
121
121
  expect(output).toContain("my-test-job:");
122
122
  });
123
123
 
124
- test("converts camelCase property keys to snake_case", () => {
124
+ test("passes through spec-native snake_case property keys", () => {
125
125
  const entities = new Map<string, Declarable>();
126
126
  entities.set("job", new MockJob({
127
- beforeScript: ["echo hello"],
128
- afterScript: ["echo done"],
129
- expireIn: "1 week",
127
+ before_script: ["echo hello"],
128
+ after_script: ["echo done"],
129
+ expire_in: "1 week",
130
130
  }));
131
131
 
132
132
  const output = gitlabSerializer.serialize(entities);
@@ -270,7 +270,7 @@ describe("nested objects and arrays", () => {
270
270
 
271
271
  const output = gitlabSerializer.serialize(entities);
272
272
  expect(output).toContain("variables:");
273
- expect(output).toContain("node_env: production");
273
+ expect(output).toContain("NODE_ENV: production");
274
274
  });
275
275
 
276
276
  test("serializes arrays of strings", () => {
@@ -289,7 +289,7 @@ describe("nested objects and arrays", () => {
289
289
  const entities = new Map<string, Declarable>();
290
290
  entities.set("job", new MockJob({
291
291
  interruptible: true,
292
- allowFailure: false,
292
+ allow_failure: false,
293
293
  }));
294
294
 
295
295
  const output = gitlabSerializer.serialize(entities);
package/src/serializer.ts CHANGED
@@ -14,13 +14,6 @@ import type { LexiconOutput } from "@intentius/chant/lexicon-output";
14
14
  import { walkValue, type SerializerVisitor } from "@intentius/chant/serializer-walker";
15
15
  import { INTRINSIC_MARKER } from "@intentius/chant/intrinsic";
16
16
 
17
- /**
18
- * Convert camelCase or PascalCase to snake_case.
19
- */
20
- function toSnakeCase(name: string): string {
21
- return name.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase();
22
- }
23
-
24
17
  /**
25
18
  * GitLab CI visitor for the generic serializer walker.
26
19
  */
@@ -36,12 +29,11 @@ function gitlabVisitor(entityNames: Map<Declarable, string>): SerializerVisitor
36
29
  const result: Record<string, unknown> = {};
37
30
  for (const [key, value] of Object.entries(props)) {
38
31
  if (value !== undefined) {
39
- result[toSnakeCase(key)] = walk(value);
32
+ result[key] = walk(value);
40
33
  }
41
34
  }
42
35
  return Object.keys(result).length > 0 ? result : undefined;
43
36
  },
44
- transformKey: toSnakeCase,
45
37
  };
46
38
  }
47
39
 
@@ -1,37 +0,0 @@
1
- ---
2
- name: gitlab-ci
3
- description: GitLab CI/CD best practices and common patterns
4
- ---
5
-
6
- # GitLab CI/CD with Chant
7
-
8
- ## Common Entity Types
9
-
10
- - `Job` — Pipeline job definition
11
- - `Default` — Default settings inherited by all jobs
12
- - `Workflow` — Pipeline-level configuration
13
- - `Artifacts` — Job artifact configuration
14
- - `Cache` — Cache configuration
15
- - `Image` — Docker image for a job
16
- - `Rule` — Conditional execution rule
17
- - `Environment` — Deployment environment
18
- - `Trigger` — Trigger downstream pipeline
19
- - `Include` — Include external CI configuration
20
-
21
- ## Predefined Variables
22
-
23
- - `CI.CommitBranch` — Current branch name
24
- - `CI.CommitSha` — Current commit SHA
25
- - `CI.PipelineSource` — What triggered the pipeline
26
- - `CI.ProjectPath` — Project path (group/project)
27
- - `CI.Registry` — Container registry URL
28
- - `CI.MergeRequestIid` — MR internal ID
29
-
30
- ## Best Practices
31
-
32
- 1. **Use stages** — Organize jobs into logical stages (build, test, deploy)
33
- 2. **Cache dependencies** — Cache node_modules, pip packages, etc.
34
- 3. **Use rules** — Prefer `rules:` over `only:/except:` for conditional execution
35
- 4. **Minimize artifacts** — Only preserve files needed by later stages
36
- 5. **Use includes** — Share common configuration across projects
37
- 6. **Set timeouts** — Prevent stuck jobs from blocking pipelines
@@ -1,26 +0,0 @@
1
- /**
2
- * Rollback and snapshot management for GitLab CI lexicon.
3
- *
4
- * Wraps the core rollback module with GitLab-specific artifact names.
5
- */
6
-
7
- export type { ArtifactSnapshot, SnapshotInfo } from "@intentius/chant/codegen/rollback";
8
- export {
9
- snapshotArtifacts,
10
- saveSnapshot,
11
- restoreSnapshot,
12
- listSnapshots,
13
- } from "@intentius/chant/codegen/rollback";
14
-
15
- /**
16
- * GitLab-specific artifact filenames to snapshot.
17
- */
18
- export const GITLAB_ARTIFACT_NAMES = ["lexicon-gitlab.json", "index.d.ts", "index.ts"];
19
-
20
- /**
21
- * Snapshot GitLab lexicon artifacts.
22
- */
23
- export function snapshotGitLabArtifacts(generatedDir: string) {
24
- const { snapshotArtifacts } = require("@intentius/chant/codegen/rollback");
25
- return snapshotArtifacts(generatedDir, GITLAB_ARTIFACT_NAMES);
26
- }