@intentius/chant-lexicon-gitlab 0.0.3 → 0.0.6
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/README.md +9 -46
- package/dist/integrity.json +5 -5
- package/dist/manifest.json +1 -1
- package/dist/meta.json +5 -0
- package/dist/types/index.d.ts +13 -0
- package/package.json +2 -2
- package/src/codegen/docs.ts +30 -438
- package/src/codegen/generate-lexicon.ts +1 -1
- package/src/codegen/parse.test.ts +5 -4
- package/src/codegen/parse.ts +8 -10
- package/src/codegen/snapshot.test.ts +3 -3
- package/src/generated/index.d.ts +13 -0
- package/src/generated/index.ts +1 -0
- package/src/generated/lexicon-gitlab.json +5 -0
- package/src/plugin.test.ts +1 -2
- package/src/plugin.ts +13 -40
- package/src/testdata/ci-schema-fixture.json +105 -229
- package/src/validate.test.ts +13 -22
- package/src/validate.ts +17 -108
package/src/codegen/parse.ts
CHANGED
|
@@ -132,6 +132,7 @@ const PROPERTY_ENTITIES: Array<{
|
|
|
132
132
|
{ typeName: "GitLab::CI::Artifacts", source: "#/definitions/artifacts", description: "Job artifact configuration" },
|
|
133
133
|
{ typeName: "GitLab::CI::Cache", source: "#/definitions/cache_item", description: "Cache configuration" },
|
|
134
134
|
{ typeName: "GitLab::CI::Image", source: "#/definitions/image", description: "Docker image for a job" },
|
|
135
|
+
{ typeName: "GitLab::CI::Service", source: "#/definitions/services:item", description: "Docker service container for a job" },
|
|
135
136
|
{ typeName: "GitLab::CI::Rule", source: "#/definitions/rules:item", description: "Conditional rule for job execution" },
|
|
136
137
|
{ typeName: "GitLab::CI::Retry", source: "#/definitions/retry", description: "Job retry configuration" },
|
|
137
138
|
{ typeName: "GitLab::CI::AllowFailure", source: "#/definitions/allow_failure", description: "Allow failure configuration" },
|
|
@@ -266,17 +267,14 @@ function extractPropertyEntity(
|
|
|
266
267
|
* Resolve a source path to a schema definition.
|
|
267
268
|
*/
|
|
268
269
|
function resolveSource(schema: CISchema, source: string): CISchemaDefinition | null {
|
|
269
|
-
// Special case: rules array item extraction
|
|
270
|
-
if (source === "#/definitions/rules:item") {
|
|
271
|
-
const rulesDef = schema.definitions?.rules;
|
|
272
|
-
if (!rulesDef) return null;
|
|
273
|
-
// rules is an array — get items
|
|
274
|
-
const items = rulesDef.items;
|
|
275
|
-
if (!items) return null;
|
|
276
|
-
return findObjectVariant(items);
|
|
277
|
-
}
|
|
278
|
-
|
|
279
270
|
if (source.startsWith("#/definitions/")) {
|
|
271
|
+
// Array item extraction: "#/definitions/foo:item" → foo.items object variant
|
|
272
|
+
if (source.includes(":item")) {
|
|
273
|
+
const defName = source.slice("#/definitions/".length).replace(":item", "");
|
|
274
|
+
const arrayDef = schema.definitions?.[defName];
|
|
275
|
+
if (!arrayDef?.items) return null;
|
|
276
|
+
return findObjectVariant(arrayDef.items);
|
|
277
|
+
}
|
|
280
278
|
const defName = source.slice("#/definitions/".length);
|
|
281
279
|
return schema.definitions?.[defName] ?? null;
|
|
282
280
|
}
|
|
@@ -10,7 +10,7 @@ describe("generated lexicon-gitlab.json", () => {
|
|
|
10
10
|
const registry = JSON.parse(content);
|
|
11
11
|
|
|
12
12
|
test("is valid JSON with expected entries", () => {
|
|
13
|
-
expect(Object.keys(registry)).toHaveLength(
|
|
13
|
+
expect(Object.keys(registry)).toHaveLength(16);
|
|
14
14
|
});
|
|
15
15
|
|
|
16
16
|
test("contains all resource entities", () => {
|
|
@@ -30,7 +30,7 @@ describe("generated lexicon-gitlab.json", () => {
|
|
|
30
30
|
const propertyNames = [
|
|
31
31
|
"AllowFailure", "Artifacts", "AutoCancel", "Cache",
|
|
32
32
|
"Environment", "Image", "Include", "Parallel",
|
|
33
|
-
"Release", "Retry", "Rule", "Trigger",
|
|
33
|
+
"Release", "Retry", "Rule", "Service", "Trigger",
|
|
34
34
|
];
|
|
35
35
|
for (const name of propertyNames) {
|
|
36
36
|
expect(registry[name]).toBeDefined();
|
|
@@ -55,7 +55,7 @@ describe("generated index.d.ts", () => {
|
|
|
55
55
|
"Job", "Default", "Workflow",
|
|
56
56
|
"AllowFailure", "Artifacts", "AutoCancel", "Cache",
|
|
57
57
|
"Environment", "Image", "Include", "Parallel",
|
|
58
|
-
"Release", "Retry", "Rule", "Trigger",
|
|
58
|
+
"Release", "Retry", "Rule", "Service", "Trigger",
|
|
59
59
|
];
|
|
60
60
|
for (const cls of expectedClasses) {
|
|
61
61
|
expect(content).toContain(`export declare class ${cls}`);
|
package/src/generated/index.d.ts
CHANGED
|
@@ -203,6 +203,19 @@ export declare class Rule {
|
|
|
203
203
|
});
|
|
204
204
|
}
|
|
205
205
|
|
|
206
|
+
export declare class Service {
|
|
207
|
+
constructor(props: {
|
|
208
|
+
/** Full name of the image that should be used. It should contain the Registry part if needed. */
|
|
209
|
+
name: string;
|
|
210
|
+
alias?: string;
|
|
211
|
+
command?: string[];
|
|
212
|
+
docker?: Record<string, unknown>;
|
|
213
|
+
entrypoint?: string[];
|
|
214
|
+
pull_policy?: "always" | "never" | "if-not-present" | "always" | "never" | "if-not-present"[];
|
|
215
|
+
variables?: Record<string, unknown>;
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
|
|
206
219
|
export declare class Trigger {
|
|
207
220
|
constructor(props: {
|
|
208
221
|
/** Path to the project, e.g. `group/project`, or `group/sub-group/project`. */
|
package/src/generated/index.ts
CHANGED
|
@@ -16,6 +16,7 @@ export const Parallel = createProperty("GitLab::CI::Parallel", "gitlab");
|
|
|
16
16
|
export const Release = createProperty("GitLab::CI::Release", "gitlab");
|
|
17
17
|
export const Retry = createProperty("GitLab::CI::Retry", "gitlab");
|
|
18
18
|
export const Rule = createProperty("GitLab::CI::Rule", "gitlab");
|
|
19
|
+
export const Service = createProperty("GitLab::CI::Service", "gitlab");
|
|
19
20
|
export const Trigger = createProperty("GitLab::CI::Trigger", "gitlab");
|
|
20
21
|
|
|
21
22
|
// Re-exports for convenience
|
package/src/plugin.test.ts
CHANGED
|
@@ -96,7 +96,6 @@ describe("gitlabPlugin", () => {
|
|
|
96
96
|
test("returns init templates", () => {
|
|
97
97
|
const templates = gitlabPlugin.initTemplates!();
|
|
98
98
|
expect(templates).toBeDefined();
|
|
99
|
-
expect(templates["_.ts"]).toBeDefined();
|
|
100
99
|
expect(templates["config.ts"]).toBeDefined();
|
|
101
100
|
expect(templates["test.ts"]).toBeDefined();
|
|
102
101
|
});
|
|
@@ -192,7 +191,7 @@ describe("gitlabPlugin", () => {
|
|
|
192
191
|
const result = await catalog.handler();
|
|
193
192
|
const parsed = JSON.parse(result);
|
|
194
193
|
expect(Array.isArray(parsed)).toBe(true);
|
|
195
|
-
expect(parsed.length).toBe(
|
|
194
|
+
expect(parsed.length).toBe(16);
|
|
196
195
|
const job = parsed.find((e: { className: string }) => e.className === "Job");
|
|
197
196
|
expect(job).toBeDefined();
|
|
198
197
|
expect(job.kind).toBe("resource");
|
package/src/plugin.ts
CHANGED
|
@@ -41,20 +41,19 @@ export const gitlabPlugin: LexiconPlugin = {
|
|
|
41
41
|
|
|
42
42
|
initTemplates(): Record<string, string> {
|
|
43
43
|
return {
|
|
44
|
-
"_.ts": `export * from "./config";\n`,
|
|
45
44
|
"config.ts": `/**
|
|
46
45
|
* Shared pipeline configuration
|
|
47
46
|
*/
|
|
48
47
|
|
|
49
|
-
import
|
|
48
|
+
import { Image, Cache } from "@intentius/chant-lexicon-gitlab";
|
|
50
49
|
|
|
51
50
|
// Default image for all jobs
|
|
52
|
-
export const defaultImage = new
|
|
51
|
+
export const defaultImage = new Image({
|
|
53
52
|
name: "node:20-alpine",
|
|
54
53
|
});
|
|
55
54
|
|
|
56
55
|
// Standard cache configuration
|
|
57
|
-
export const npmCache = new
|
|
56
|
+
export const npmCache = new Cache({
|
|
58
57
|
key: "$CI_COMMIT_REF_SLUG",
|
|
59
58
|
paths: ["node_modules/"],
|
|
60
59
|
policy: "pull-push",
|
|
@@ -64,15 +63,15 @@ export const npmCache = new gl.Cache({
|
|
|
64
63
|
* Test job
|
|
65
64
|
*/
|
|
66
65
|
|
|
67
|
-
import
|
|
68
|
-
import
|
|
66
|
+
import { Job, Artifacts } from "@intentius/chant-lexicon-gitlab";
|
|
67
|
+
import { defaultImage, npmCache } from "./config";
|
|
69
68
|
|
|
70
|
-
export const test = new
|
|
69
|
+
export const test = new Job({
|
|
71
70
|
stage: "test",
|
|
72
|
-
image:
|
|
73
|
-
cache:
|
|
71
|
+
image: defaultImage,
|
|
72
|
+
cache: npmCache,
|
|
74
73
|
script: ["npm ci", "npm test"],
|
|
75
|
-
artifacts: new
|
|
74
|
+
artifacts: new Artifacts({
|
|
76
75
|
reports: { junit: "coverage/junit.xml" },
|
|
77
76
|
paths: ["coverage/"],
|
|
78
77
|
expireIn: "1 week",
|
|
@@ -142,18 +141,9 @@ export const test = new gl.Job({
|
|
|
142
141
|
|
|
143
142
|
async validate(options?: { verbose?: boolean }): Promise<void> {
|
|
144
143
|
const { validate } = await import("./validate");
|
|
144
|
+
const { printValidationResult } = await import("@intentius/chant/codegen/validate");
|
|
145
145
|
const result = await validate();
|
|
146
|
-
|
|
147
|
-
for (const check of result.checks) {
|
|
148
|
-
const status = check.ok ? "OK" : "FAIL";
|
|
149
|
-
const msg = check.error ? ` — ${check.error}` : "";
|
|
150
|
-
console.error(` [${status}] ${check.name}${msg}`);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
if (!result.success) {
|
|
154
|
-
throw new Error("Validation failed");
|
|
155
|
-
}
|
|
156
|
-
console.error("All validation checks passed.");
|
|
146
|
+
printValidationResult(result);
|
|
157
147
|
},
|
|
158
148
|
|
|
159
149
|
async coverage(options?: { verbose?: boolean; minOverall?: number }): Promise<void> {
|
|
@@ -166,7 +156,7 @@ export const test = new gl.Job({
|
|
|
166
156
|
|
|
167
157
|
async package(options?: { verbose?: boolean; force?: boolean }): Promise<void> {
|
|
168
158
|
const { packageLexicon } = await import("./codegen/package");
|
|
169
|
-
const {
|
|
159
|
+
const { writeBundleSpec } = await import("@intentius/chant/codegen/package");
|
|
170
160
|
const { join, dirname } = await import("path");
|
|
171
161
|
const { fileURLToPath } = await import("url");
|
|
172
162
|
|
|
@@ -174,24 +164,7 @@ export const test = new gl.Job({
|
|
|
174
164
|
|
|
175
165
|
const pkgDir = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
176
166
|
const distDir = join(pkgDir, "dist");
|
|
177
|
-
|
|
178
|
-
mkdirSync(join(distDir, "rules"), { recursive: true });
|
|
179
|
-
mkdirSync(join(distDir, "skills"), { recursive: true });
|
|
180
|
-
|
|
181
|
-
writeFileSync(join(distDir, "manifest.json"), JSON.stringify(spec.manifest, null, 2));
|
|
182
|
-
writeFileSync(join(distDir, "meta.json"), spec.registry);
|
|
183
|
-
writeFileSync(join(distDir, "types", "index.d.ts"), spec.typesDTS);
|
|
184
|
-
|
|
185
|
-
for (const [name, content] of spec.rules) {
|
|
186
|
-
writeFileSync(join(distDir, "rules", name), content);
|
|
187
|
-
}
|
|
188
|
-
for (const [name, content] of spec.skills) {
|
|
189
|
-
writeFileSync(join(distDir, "skills", name), content);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
if (spec.integrity) {
|
|
193
|
-
writeFileSync(join(distDir, "integrity.json"), JSON.stringify(spec.integrity, null, 2));
|
|
194
|
-
}
|
|
167
|
+
writeBundleSpec(spec, distDir);
|
|
195
168
|
|
|
196
169
|
console.error(`Packaged ${stats.resources} entities, ${stats.ruleCount} rules, ${stats.skillCount} skills`);
|
|
197
170
|
},
|