Skip to content

Commit 712ec0d

Browse files
committed
refactor: make finalize() private, add public validation API
- Add validate() and safeValidate() methods for validation - Enhance getPlainObject/toJSON/toYaml with skipValidation option - Remove visualizeGraph() method (use individual methods instead) - Update all tests to use new validation pattern
1 parent f482b95 commit 712ec0d

19 files changed

+1452
-89
lines changed

.changeset/add-fluent-api.md

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
---
2+
"@noxify/gitlab-ci-builder": minor
3+
---
4+
5+
Fluent Job Builder API
6+
7+
**New Feature: Fluent Job Builder API**
8+
9+
Added a powerful fluent builder interface for defining jobs and templates with chainable methods:
10+
11+
**New Methods:**
12+
13+
- `addJob(name)` - Create a new job with fluent builder interface
14+
- `addTemplate(name)` - Create a new template with fluent builder interface
15+
16+
**JobBuilder Methods:**
17+
Common properties:
18+
19+
- `stage(stage)` - Set job stage
20+
- `extends(extend)` - Set extends
21+
- `image(image)` - Set image
22+
- `script(script)` - Set script
23+
- `beforeScript(script)` - Set before_script
24+
- `afterScript(script)` - Set after_script
25+
- `services(services)` - Set services
26+
- `cache(cache)` - Set cache
27+
- `artifacts(artifacts)` - Set artifacts
28+
- `setVariables(vars)` - Set job variables
29+
- `environment(env)` - Set environment
30+
- `when(when)` - Set when condition
31+
- `rules(rules)` - Set rules
32+
- `needs(needs)` - Set needs
33+
- `tags(tags)` - Set tags
34+
- `allowFailure(bool)` - Set allow_failure
35+
- `timeout(timeout)` - Set timeout
36+
- `retry(retry)` - Set retry
37+
- `parallel(parallel)` - Set parallel
38+
- `trigger(trigger)` - Set trigger
39+
- `coverage(pattern)` - Set coverage pattern
40+
- `dependencies(deps)` - Set dependencies
41+
- `resourceGroup(group)` - Set resource_group
42+
- `release(release)` - Set release
43+
- `interruptible(bool)` - Set interruptible
44+
- `idTokens(tokens)` - Set id_tokens
45+
46+
Utility methods:
47+
48+
- `set(props)` - Bulk set multiple properties at once
49+
- `jobOptions(opts)` - Set job options (remote, mergeExtends, etc.)
50+
- `remote(bool)` - Mark job as remote
51+
- `mergeExtends(bool)` - Control extends merging
52+
- `resolveTemplatesOnly(bool)` - Control template resolution
53+
- `done()` - Finalize job and return to ConfigBuilder
54+
55+
**Auto-Return Behavior:**
56+
When you call `addJob()` or `addTemplate()` from a JobBuilder, the previous job is automatically saved and a new builder is returned:
57+
58+
```typescript
59+
const config = new ConfigBuilder()
60+
61+
// Fluent API with auto-return
62+
config
63+
.stages("build", "test", "deploy")
64+
.addTemplate(".node")
65+
.image("node:20")
66+
.cache({ paths: ["node_modules/"] })
67+
.addJob("test")
68+
.stage("test")
69+
.extends(".node")
70+
.script(["npm test"])
71+
.addJob("build")
72+
.stage("build")
73+
.extends(".node")
74+
.script(["npm run build"])
75+
.addJob("deploy")
76+
.stage("deploy")
77+
.extends("build")
78+
.script(["kubectl apply -f k8s/"])
79+
.when("manual")
80+
.done()
81+
82+
// Or use done() to explicitly return to ConfigBuilder
83+
config
84+
.addJob("lint")
85+
.stage("test")
86+
.script(["npm run lint"])
87+
.done()
88+
.addJob("format")
89+
.stage("test")
90+
.script(["npm run format:check"])
91+
.done()
92+
93+
// Bulk property updates with set()
94+
config
95+
.addJob("complex")
96+
.set({
97+
stage: "test",
98+
image: "node:20",
99+
script: ["npm test"],
100+
cache: { paths: ["node_modules/"] },
101+
artifacts: { paths: ["coverage/"] },
102+
})
103+
.done()
104+
```
105+
106+
**Benefits:**
107+
108+
- **Type-safe**: Full TypeScript support with autocomplete
109+
- **Readable**: Clear, declarative pipeline definitions
110+
- **Flexible**: Mix with existing `job()` and `template()` methods
111+
- **Convenient**: Auto-return behavior reduces boilerplate
112+
- **Powerful**: All job properties supported with dedicated methods
113+
114+
This fluent API is especially useful for complex pipelines with many jobs, making the code more maintainable and easier to read.
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
---
2+
"@noxify/gitlab-ci-builder": minor
3+
---
4+
5+
Graph Visualization
6+
7+
**New Features: Graph Visualization**
8+
9+
Added powerful visualization capabilities to analyze and visualize extends relationships in your GitLab CI pipelines:
10+
11+
**New Methods:**
12+
13+
- `getExtendsGraph()` - Get the extends dependency graph for programmatic access
14+
- `generateMermaidDiagram(options?)` - Generate Mermaid diagram for documentation/GitHub
15+
- `generateAsciiTree(options?)` - Generate ASCII tree for terminal output
16+
- `generateStageTable(options?)` - Generate CLI table with stages as columns
17+
18+
**Visualization Options:**
19+
20+
- `showRemote: boolean` - Show remote jobs with 🌐 indicator
21+
- `showStages: boolean` - Include job stages in output
22+
- `highlightCycles: boolean` - Highlight circular dependencies if detected
23+
24+
**Example Usage:**
25+
26+
```javascript
27+
const config = new ConfigBuilder()
28+
// ... configure your pipeline ...
29+
30+
// Generate individual visualizations
31+
const mermaid = config.generateMermaidDiagram({ showStages: true })
32+
const ascii = config.generateAsciiTree({ showRemote: true })
33+
const table = config.generateStageTable()
34+
35+
console.log(mermaid) // Mermaid diagram
36+
console.log(ascii) // ASCII tree
37+
console.log(table) // Stage table
38+
```
39+
40+
This feature is especially useful for:
41+
42+
- Documenting complex CI configurations
43+
- Debugging extends chains and dependencies
44+
- Understanding job relationships at a glance
45+
- Detecting circular dependencies visually

.changeset/add-validation-api.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
---
2+
"@noxify/gitlab-ci-builder": minor
3+
---
4+
5+
Enhanced Validation API
6+
7+
**New Feature: Enhanced Validation API**
8+
9+
Added dedicated validation methods for better control over pipeline validation:
10+
11+
**New Methods:**
12+
13+
- `validate()` - Validate pipeline and throw errors if validation fails (logs warnings to console)
14+
- `safeValidate()` - Validate pipeline without throwing errors, returns validation result with `{ valid, errors, warnings }`
15+
16+
**Enhanced Methods:**
17+
18+
- `getPlainObject(options?)` - Now accepts `{ skipValidation?: boolean }` option to skip validation when you've already validated separately
19+
- `toJSON(options?)` - Now accepts `{ skipValidation?: boolean }` option
20+
- `toYaml(options?)` - Now accepts `{ skipValidation?: boolean }` option
21+
22+
**Breaking Changes:**
23+
24+
- `finalize()` is now `private` - use `safeValidate()` for programmatic validation or `validate()` for validation that throws errors
25+
26+
**Usage Examples:**
27+
28+
```typescript
29+
// Standard validation (throws on error)
30+
config.validate()
31+
const pipeline = config.getPlainObject({ skipValidation: true })
32+
33+
// Safe validation (no throw)
34+
const result = config.safeValidate()
35+
if (!result.valid) {
36+
console.error("Validation errors:", result.errors)
37+
return
38+
}
39+
if (result.warnings.length > 0) {
40+
console.warn("Warnings:", result.warnings)
41+
}
42+
const pipeline = config.getPlainObject({ skipValidation: true })
43+
44+
// Quick validation (default behavior)
45+
const pipeline = config.getPlainObject() // validates automatically
46+
```
47+
48+
**Benefits:**
49+
50+
- **Separation of concerns**: Validation is now separate from pipeline retrieval
51+
- **Better error handling**: `safeValidate()` enables programmatic error handling without try/catch
52+
- **Performance**: Skip validation when using multiple output methods (`toYaml()`, `toJSON()`, etc.)
53+
- **Flexible**: Choose between throwing (`validate()`) or returning errors (`safeValidate()`)

README.md

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -506,18 +506,20 @@ the runtime builder and are derived from the JSDoc on the source `ConfigBuilder`
506506
- `patch(callback: (plain: GitLabCi) => void): void`
507507
- Register a patcher callback that runs on the plain object before it is returned.
508508

509-
- `getPlainObject(): PipelineOutput`
509+
- `validate(): void`
510+
- Validate the configuration and throw an error if validation fails. Logs warnings to console.
511+
512+
- `safeValidate(): SafeValidationResult`
513+
- Validate the configuration without throwing. Returns `{ valid: boolean, errors: ValidationError[], warnings: ValidationError[] }`.
514+
515+
- `getPlainObject(options?: { skipValidation?: boolean }): PipelineOutput`
510516
- Return a YAML-serializable pipeline object with resolved extends and applied patchers.
511-
Returns the result of `finalize().pipeline`.
517+
- By default, validates before returning. Set `skipValidation: true` to skip validation (e.g., after calling `safeValidate()`).
512518

513-
- `toJSON(): PipelineOutput`
519+
- `toJSON(options?: { skipValidation?: boolean }): PipelineOutput`
514520
- Alias for `getPlainObject()` (useful for `JSON.stringify`).
515521

516-
- `finalize(): FinalizeResult`
517-
- Finalize the configuration and return the resolved pipeline with validation metadata.
518-
- Returns `{ pipeline: PipelineOutput, errors: ValidationError[], warnings: ValidationError[], metadata: { skippedChecks: string[] } }`
519-
520-
- `toYaml(): string`
522+
- `toYaml(options?: { skipValidation?: boolean }): string`
521523
- Convert the configuration to a formatted YAML string.
522524

523525
- `writeYamlFile(filePath: string): Promise<void>`

0 commit comments

Comments
 (0)