@intentius/chant-lexicon-gitlab 0.120.0 → 0.121.1
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.
- package/dist/import/generator.d.ts.map +1 -1
- package/dist/import/parser.d.ts.map +1 -1
- package/dist/integrity.json +2 -2
- package/dist/manifest.json +1 -1
- package/package.json +3 -3
- package/src/import/generator.test.ts +10 -0
- package/src/import/generator.ts +25 -4
- package/src/import/parser.test.ts +22 -6
- package/src/import/parser.ts +17 -1
- package/src/import/roundtrip.test.ts +64 -12
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/import/generator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAC5F,OAAO,KAAK,EAAE,UAAU,EAAc,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/import/generator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAC5F,OAAO,KAAK,EAAE,UAAU,EAAc,MAAM,gCAAgC,CAAC;AA0C7E;;GAEG;AACH,qBAAa,eAAgB,YAAW,mBAAmB;IACzD,QAAQ,CAAC,EAAE,EAAE,UAAU,GAAG,aAAa,EAAE,CA8DxC;IAED,OAAO,CAAC,yBAAyB;IAejC,OAAO,CAAC,SAAS;IAejB,OAAO,CAAC,SAAS;IAqCjB,OAAO,CAAC,WAAW;CA2BpB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/import/parser.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAc,MAAM,gCAAgC,CAAC;AA6B7F;;GAEG;AACH,qBAAa,YAAa,YAAW,cAAc;IACjD,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,
|
|
1
|
+
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/import/parser.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAc,MAAM,gCAAgC,CAAC;AA6B7F;;GAEG;AACH,qBAAa,YAAa,YAAW,cAAc;IACjD,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,CA4EjC;CACF"}
|
package/dist/integrity.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"algorithm": "sha256",
|
|
3
3
|
"artifacts": {
|
|
4
|
-
"manifest.json": "
|
|
4
|
+
"manifest.json": "694e53b8684573c4917b2ffe236247835db6e58188b8b44e5a381e401ca35a08",
|
|
5
5
|
"meta.json": "db082fbf90c5941c498b2bee0f106103449c1a4c257716ca2220f0dd490450b2",
|
|
6
6
|
"types/index.d.ts": "a048a66ebe20da0cb5fc889054cac69044d9bf882e2c56b5c5bf113d1f3ba57c",
|
|
7
7
|
"rules/artifact-no-expiry.ts": "3f3cabf9792cbf8207e53a25f506715466b19ec25e9c3b4d0d77fed6b2eb4542",
|
|
@@ -55,5 +55,5 @@
|
|
|
55
55
|
"skills/chant-gitlab-migrate.md": "4853d04980560b379e5b0f7267dcb0a1e5d5879cb9e9931681ce76b2a5fe69d8",
|
|
56
56
|
"skills/chant-gitlab-patterns.md": "6d9a44e9e8de4c3820be9d65381b0d2ede4cb3626aaaf0011e21838a9fbf556e"
|
|
57
57
|
},
|
|
58
|
-
"composite": "
|
|
58
|
+
"composite": "773f17febcc5969a1d05fc81090404f1950d2258d388c3d8932224be38dbc460"
|
|
59
59
|
}
|
package/dist/manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intentius/chant-lexicon-gitlab",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.121.1",
|
|
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.
|
|
71
|
-
"@intentius/chant-lexicon-github": "^0.
|
|
70
|
+
"@intentius/chant": "^0.121.1",
|
|
71
|
+
"@intentius/chant-lexicon-github": "^0.121.1",
|
|
72
72
|
"typescript": "^5.9.3"
|
|
73
73
|
},
|
|
74
74
|
"peerDependenciesMeta": {
|
|
@@ -148,4 +148,14 @@ describe("GitLabGenerator", () => {
|
|
|
148
148
|
const files = generator.generate(ir);
|
|
149
149
|
expect(files[0].content).toContain("Pipeline stages: build, test, deploy");
|
|
150
150
|
});
|
|
151
|
+
|
|
152
|
+
test("a key that is not an identifier is quoted", () => {
|
|
153
|
+
const ir: TemplateIR = {
|
|
154
|
+
resources: [{ logicalId: "pipeline", type: "GitLab::CI::Pipeline", properties: { variables: { "MY-VAR": "x", GIT_DEPTH: "0" } } }],
|
|
155
|
+
parameters: [],
|
|
156
|
+
};
|
|
157
|
+
const content = generator.generate(ir)[0]!.content;
|
|
158
|
+
expect(content).toContain('"MY-VAR": "x"');
|
|
159
|
+
expect(content).toContain('GIT_DEPTH: "0"');
|
|
160
|
+
});
|
|
151
161
|
});
|
package/src/import/generator.ts
CHANGED
|
@@ -15,6 +15,7 @@ const TYPE_TO_CLASS: Record<string, string> = {
|
|
|
15
15
|
"GitLab::CI::Job": "Job",
|
|
16
16
|
"GitLab::CI::Default": "Default",
|
|
17
17
|
"GitLab::CI::Workflow": "Workflow",
|
|
18
|
+
"GitLab::CI::Pipeline": "Pipeline",
|
|
18
19
|
};
|
|
19
20
|
|
|
20
21
|
/**
|
|
@@ -44,6 +45,9 @@ const PROPERTY_CONSTRUCTORS: Record<string, string> = {
|
|
|
44
45
|
inherit: "Inherit",
|
|
45
46
|
};
|
|
46
47
|
|
|
48
|
+
/** An object key as TypeScript accepts it: bare when it is an identifier, quoted otherwise. */
|
|
49
|
+
const tsKey = (key: string): string => (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key) ? key : JSON.stringify(key));
|
|
50
|
+
|
|
47
51
|
/**
|
|
48
52
|
* Generate TypeScript source code from a GitLab CI IR.
|
|
49
53
|
*/
|
|
@@ -68,14 +72,18 @@ export class GitLabGenerator implements TypeScriptGenerator {
|
|
|
68
72
|
lines.push(`import { ${imports} } from "@intentius/chant-lexicon-gitlab";`);
|
|
69
73
|
lines.push("");
|
|
70
74
|
|
|
75
|
+
// A Pipeline resource declares the stages and includes (#3742); without
|
|
76
|
+
// one, the metadata is written as comments.
|
|
77
|
+
const hasPipeline = ir.resources.some((r) => r.type === "GitLab::CI::Pipeline");
|
|
78
|
+
|
|
71
79
|
// Emit stages if present in metadata
|
|
72
|
-
if (ir.metadata?.stages && Array.isArray(ir.metadata.stages)) {
|
|
80
|
+
if (!hasPipeline && ir.metadata?.stages && Array.isArray(ir.metadata.stages)) {
|
|
73
81
|
lines.push(`// Pipeline stages: ${(ir.metadata.stages as string[]).join(", ")}`);
|
|
74
82
|
lines.push("");
|
|
75
83
|
}
|
|
76
84
|
|
|
77
85
|
// Emit includes as comments
|
|
78
|
-
if (ir.metadata?.include) {
|
|
86
|
+
if (!hasPipeline && ir.metadata?.include) {
|
|
79
87
|
lines.push("// Imported includes (not converted):");
|
|
80
88
|
const includes = Array.isArray(ir.metadata.include) ? ir.metadata.include : [ir.metadata.include];
|
|
81
89
|
for (const inc of includes) {
|
|
@@ -117,6 +125,9 @@ export class GitLabGenerator implements TypeScriptGenerator {
|
|
|
117
125
|
if (key === "rules" && Array.isArray(value)) {
|
|
118
126
|
used.add("Rule");
|
|
119
127
|
}
|
|
128
|
+
if (key === "include" && (Array.isArray(value) ? value : [value]).some((i) => typeof i === "object" && i !== null)) {
|
|
129
|
+
used.add("Include");
|
|
130
|
+
}
|
|
120
131
|
}
|
|
121
132
|
}
|
|
122
133
|
|
|
@@ -128,7 +139,7 @@ export class GitLabGenerator implements TypeScriptGenerator {
|
|
|
128
139
|
for (const [key, value] of Object.entries(props)) {
|
|
129
140
|
if (value === undefined || value === null) continue;
|
|
130
141
|
const emitted = this.emitValue(key, value, depth + 1);
|
|
131
|
-
entries.push(`${innerIndent}${key}: ${emitted},`);
|
|
142
|
+
entries.push(`${innerIndent}${tsKey(key)}: ${emitted},`);
|
|
132
143
|
}
|
|
133
144
|
|
|
134
145
|
if (entries.length === 0) return "{}";
|
|
@@ -145,6 +156,16 @@ export class GitLabGenerator implements TypeScriptGenerator {
|
|
|
145
156
|
return `new ${constructor}(${propsStr})`;
|
|
146
157
|
}
|
|
147
158
|
|
|
159
|
+
// A Pipeline's include: each object is an Include, a string stays a string.
|
|
160
|
+
if (key === "include") {
|
|
161
|
+
const item = (i: unknown, d: number) =>
|
|
162
|
+
typeof i === "object" && i !== null && !Array.isArray(i) ? `new Include(${this.emitProps(i as Record<string, unknown>, d)})` : this.emitLiteral(i, d);
|
|
163
|
+
if (!Array.isArray(value)) return item(value, depth);
|
|
164
|
+
const indent = " ".repeat(depth);
|
|
165
|
+
const innerIndent = " ".repeat(depth + 1);
|
|
166
|
+
return `[\n${value.map((i) => `${innerIndent}${item(i, depth + 1)},`).join("\n")}\n${indent}]`;
|
|
167
|
+
}
|
|
168
|
+
|
|
148
169
|
// Rules array — wrap each item in Rule constructor
|
|
149
170
|
if (key === "rules" && Array.isArray(value)) {
|
|
150
171
|
const items = value.map((item) => {
|
|
@@ -183,7 +204,7 @@ export class GitLabGenerator implements TypeScriptGenerator {
|
|
|
183
204
|
if (entries.length === 0) return "{}";
|
|
184
205
|
const indent = " ".repeat(depth);
|
|
185
206
|
const innerIndent = " ".repeat(depth + 1);
|
|
186
|
-
const items = entries.map(([k, v]) => `${innerIndent}${k}: ${this.emitLiteral(v, depth + 1)},`);
|
|
207
|
+
const items = entries.map(([k, v]) => `${innerIndent}${tsKey(k)}: ${this.emitLiteral(v, depth + 1)},`);
|
|
187
208
|
return `{\n${items.join("\n")}\n${indent}}`;
|
|
188
209
|
}
|
|
189
210
|
|
|
@@ -15,10 +15,11 @@ test-job:
|
|
|
15
15
|
- npm test
|
|
16
16
|
`;
|
|
17
17
|
const ir = parser.parse(yaml);
|
|
18
|
-
expect(ir.resources).toHaveLength(
|
|
19
|
-
expect(ir.resources[0].type).toBe("GitLab::CI::
|
|
20
|
-
expect(ir.resources[
|
|
21
|
-
expect(ir.resources[
|
|
18
|
+
expect(ir.resources).toHaveLength(2);
|
|
19
|
+
expect(ir.resources[0].type).toBe("GitLab::CI::Pipeline");
|
|
20
|
+
expect(ir.resources[1].type).toBe("GitLab::CI::Job");
|
|
21
|
+
expect(ir.resources[1].properties.stage).toBe("test");
|
|
22
|
+
expect(ir.resources[1].properties.script).toEqual(["npm test"]);
|
|
22
23
|
});
|
|
23
24
|
|
|
24
25
|
test("parses multiple jobs", () => {
|
|
@@ -134,9 +135,24 @@ test-job:
|
|
|
134
135
|
- npm test
|
|
135
136
|
`;
|
|
136
137
|
const ir = parser.parse(yaml);
|
|
137
|
-
// Only the job
|
|
138
|
+
// Only the job is a Job; stages, variables and include are the Pipeline (#3742)
|
|
138
139
|
const jobs = ir.resources.filter((r) => r.type === "GitLab::CI::Job");
|
|
139
140
|
expect(jobs).toHaveLength(1);
|
|
141
|
+
expect(ir.resources[0]).toEqual({
|
|
142
|
+
logicalId: "pipeline",
|
|
143
|
+
type: "GitLab::CI::Pipeline",
|
|
144
|
+
properties: { include: [{ local: "shared.yml" }], stages: ["test"], variables: { NODE_ENV: "production" } },
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
test("a job named pipeline keeps its name; the Pipeline takes another (#3742)", () => {
|
|
149
|
+
const ir = parser.parse(`stages: [test]\npipeline:\n stage: test\n script: [x]\n`);
|
|
150
|
+
expect(ir.resources.map((r) => r.logicalId)).toEqual(["pipelineConfig", "pipeline"]);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
test("a file with no include, stages or variables has no Pipeline", () => {
|
|
154
|
+
const ir = parser.parse(`job:\n script: [x]\n`);
|
|
155
|
+
expect(ir.resources.map((r) => r.type)).toEqual(["GitLab::CI::Job"]);
|
|
140
156
|
});
|
|
141
157
|
|
|
142
158
|
test("handles JSON input", () => {
|
|
@@ -145,7 +161,7 @@ test-job:
|
|
|
145
161
|
"test-job": { stage: "test", script: ["npm test"] },
|
|
146
162
|
});
|
|
147
163
|
const ir = parser.parse(json);
|
|
148
|
-
expect(ir.resources).
|
|
164
|
+
expect(ir.resources.map((r) => r.type)).toEqual(["GitLab::CI::Pipeline", "GitLab::CI::Job"]);
|
|
149
165
|
});
|
|
150
166
|
|
|
151
167
|
test("returns empty parameters (GitLab CI has no parameters)", () => {
|
package/src/import/parser.ts
CHANGED
|
@@ -87,7 +87,23 @@ export class GitLabParser implements TemplateParser {
|
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
//
|
|
90
|
+
// The file's top-level include, stages and variables are a Pipeline
|
|
91
|
+
// (#3742), so a rebuild writes them back: stages as written, a stage no
|
|
92
|
+
// job uses and the declared order included.
|
|
93
|
+
const pipeline: Record<string, unknown> = {};
|
|
94
|
+
if (doc.include !== undefined && doc.include !== null) pipeline.include = doc.include;
|
|
95
|
+
if (Array.isArray(doc.stages)) pipeline.stages = doc.stages;
|
|
96
|
+
if (doc.variables && typeof doc.variables === "object") pipeline.variables = doc.variables;
|
|
97
|
+
if (Object.keys(pipeline).length > 0) {
|
|
98
|
+
const taken = new Set(resources.map((r) => r.logicalId));
|
|
99
|
+
resources.unshift({
|
|
100
|
+
logicalId: taken.has("pipeline") ? "pipelineConfig" : "pipeline",
|
|
101
|
+
type: "GitLab::CI::Pipeline",
|
|
102
|
+
properties: pipeline,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Also kept as metadata, for callers that read the IR without the Pipeline.
|
|
91
107
|
const metadata: Record<string, unknown> = {};
|
|
92
108
|
if (doc.stages) metadata.stages = doc.stages;
|
|
93
109
|
if (doc.include) metadata.include = doc.include;
|
|
@@ -65,7 +65,8 @@ deploy-prod:
|
|
|
65
65
|
- deploy.sh
|
|
66
66
|
`;
|
|
67
67
|
const ir = parser.parse(yaml);
|
|
68
|
-
|
|
68
|
+
// the Pipeline and 3 jobs
|
|
69
|
+
expect(ir.resources).toHaveLength(4);
|
|
69
70
|
|
|
70
71
|
const files = generator.generate(ir);
|
|
71
72
|
const content = files[0].content;
|
|
@@ -73,7 +74,8 @@ deploy-prod:
|
|
|
73
74
|
expect(content).toContain("buildApp");
|
|
74
75
|
expect(content).toContain("runTests");
|
|
75
76
|
expect(content).toContain("deployProd");
|
|
76
|
-
expect(content).toContain("Pipeline
|
|
77
|
+
expect(content).toContain("new Pipeline(");
|
|
78
|
+
expect(content).toContain('stages: ["build", "test", "deploy"]');
|
|
77
79
|
});
|
|
78
80
|
|
|
79
81
|
test("pipeline with defaults and workflow roundtrip", () => {
|
|
@@ -108,7 +110,8 @@ test-job:
|
|
|
108
110
|
expect(files).toHaveLength(1);
|
|
109
111
|
const content = files[0].content;
|
|
110
112
|
|
|
111
|
-
|
|
113
|
+
// the Pipeline and 1 job
|
|
114
|
+
expect(ir.resources).toHaveLength(2);
|
|
112
115
|
expect(content).toContain("new Job(");
|
|
113
116
|
expect(content).toContain("npm ci");
|
|
114
117
|
expect(content).toContain("npm test");
|
|
@@ -122,13 +125,13 @@ test-job:
|
|
|
122
125
|
|
|
123
126
|
const content = files[0].content;
|
|
124
127
|
|
|
125
|
-
// 4 jobs: build-app, lint, unit-tests, deploy-staging
|
|
126
|
-
expect(ir.resources).toHaveLength(
|
|
128
|
+
// the Pipeline and 4 jobs: build-app, lint, unit-tests, deploy-staging
|
|
129
|
+
expect(ir.resources).toHaveLength(5);
|
|
127
130
|
expect(content).toContain("buildApp");
|
|
128
131
|
expect(content).toContain("lint");
|
|
129
132
|
expect(content).toContain("unitTests");
|
|
130
133
|
expect(content).toContain("deployStaging");
|
|
131
|
-
expect(content).toContain(
|
|
134
|
+
expect(content).toContain('stages: ["build", "test", "deploy"]');
|
|
132
135
|
// Artifacts and cache references
|
|
133
136
|
expect(content).toContain("dist/");
|
|
134
137
|
expect(content).toContain("package-lock.json");
|
|
@@ -141,7 +144,8 @@ test-job:
|
|
|
141
144
|
|
|
142
145
|
const content = files[0].content;
|
|
143
146
|
|
|
144
|
-
|
|
147
|
+
// the Pipeline and 2 jobs
|
|
148
|
+
expect(ir.resources).toHaveLength(3);
|
|
145
149
|
expect(content).toContain("buildImage");
|
|
146
150
|
expect(content).toContain("pushLatest");
|
|
147
151
|
expect(content).toContain("docker:27-cli");
|
|
@@ -157,8 +161,8 @@ test-job:
|
|
|
157
161
|
|
|
158
162
|
const content = files[0].content;
|
|
159
163
|
|
|
160
|
-
// 5 jobs: build, deploy-review, stop-review, deploy-staging, deploy-production
|
|
161
|
-
expect(ir.resources).toHaveLength(
|
|
164
|
+
// the Pipeline and 5 jobs: build, deploy-review, stop-review, deploy-staging, deploy-production
|
|
165
|
+
expect(ir.resources).toHaveLength(6);
|
|
162
166
|
expect(content).toContain("deployReview");
|
|
163
167
|
expect(content).toContain("stopReview");
|
|
164
168
|
expect(content).toContain("deployStaging");
|
|
@@ -179,7 +183,8 @@ test-job:
|
|
|
179
183
|
// default + build + unit-test + integration-test + deploy
|
|
180
184
|
expect(ir.resources.length).toBeGreaterThanOrEqual(3);
|
|
181
185
|
expect(content).toContain("new Default(");
|
|
182
|
-
// Include references
|
|
186
|
+
// Include references are the Pipeline's include (#3742)
|
|
187
|
+
expect(content).toContain("new Pipeline(");
|
|
183
188
|
expect(content).toContain("Auto-DevOps.gitlab-ci.yml");
|
|
184
189
|
expect(content).toContain("interruptible");
|
|
185
190
|
});
|
|
@@ -191,8 +196,8 @@ test-job:
|
|
|
191
196
|
|
|
192
197
|
const content = files[0].content;
|
|
193
198
|
|
|
194
|
-
// frontend, backend, e2e-matrix, deploy-all
|
|
195
|
-
expect(ir.resources).toHaveLength(
|
|
199
|
+
// the Pipeline, frontend, backend, e2e-matrix, deploy-all
|
|
200
|
+
expect(ir.resources).toHaveLength(5);
|
|
196
201
|
expect(content).toContain("frontend");
|
|
197
202
|
expect(content).toContain("backend");
|
|
198
203
|
expect(content).toContain("e2eMatrix");
|
|
@@ -219,3 +224,50 @@ test-job:
|
|
|
219
224
|
}
|
|
220
225
|
});
|
|
221
226
|
});
|
|
227
|
+
|
|
228
|
+
describe("roundtrip: parse → generate → build (#3742)", () => {
|
|
229
|
+
test("top-level include, variables and stages come back from the build, an unused stage and the order included", async () => {
|
|
230
|
+
const { mkdirSync, rmSync, writeFileSync } = await import("fs");
|
|
231
|
+
const { build } = await import("@intentius/chant/build");
|
|
232
|
+
const { gitlabSerializer } = await import("../serializer");
|
|
233
|
+
const { gitlabPlugin } = await import("../plugin");
|
|
234
|
+
const { parseYAML } = await import("@intentius/chant/yaml");
|
|
235
|
+
|
|
236
|
+
const yaml = `
|
|
237
|
+
include:
|
|
238
|
+
- local: ci/shared.yml
|
|
239
|
+
variables:
|
|
240
|
+
GIT_DEPTH: "0"
|
|
241
|
+
stages: [review, apply, ops]
|
|
242
|
+
|
|
243
|
+
plan:
|
|
244
|
+
stage: review
|
|
245
|
+
script: [plan.sh]
|
|
246
|
+
|
|
247
|
+
apply:
|
|
248
|
+
stage: apply
|
|
249
|
+
script: [apply.sh]
|
|
250
|
+
`;
|
|
251
|
+
const [file] = generator.generate(parser.parse(yaml));
|
|
252
|
+
expect(file!.content).toContain("new Pipeline(");
|
|
253
|
+
expect(file!.content).toContain("new Include(");
|
|
254
|
+
|
|
255
|
+
const dir = join(dirname(fileURLToPath(import.meta.url)), `.import-build-tmp-${process.pid}`);
|
|
256
|
+
try {
|
|
257
|
+
mkdirSync(join(dir, "src"), { recursive: true });
|
|
258
|
+
writeFileSync(join(dir, "src", file!.path), file!.content);
|
|
259
|
+
const result = await build(join(dir, "src"), [gitlabSerializer], undefined, {
|
|
260
|
+
intrinsics: gitlabPlugin.intrinsics!(),
|
|
261
|
+
lexicons: ["gitlab"],
|
|
262
|
+
});
|
|
263
|
+
expect(result.errors).toEqual([]);
|
|
264
|
+
const out = result.outputs.get("gitlab");
|
|
265
|
+
const doc = parseYAML(typeof out === "string" ? out : String((out as { primary?: string }).primary)) as Record<string, unknown>;
|
|
266
|
+
expect(doc.include).toEqual([{ local: "ci/shared.yml" }]);
|
|
267
|
+
expect(doc.variables).toEqual({ GIT_DEPTH: "0" });
|
|
268
|
+
expect(doc.stages).toEqual(["review", "apply", "ops"]);
|
|
269
|
+
} finally {
|
|
270
|
+
rmSync(dir, { recursive: true, force: true });
|
|
271
|
+
}
|
|
272
|
+
}, 120_000);
|
|
273
|
+
});
|