- 34e30ad: updated dependencies
-
e53a7c1: Added pipeline simulation feature and improved remote extends handling
Simulation Features:
- Added
simulateCLI command to simulate GitLab CI pipeline execution - Added
PipelineSimulatorclass for rule evaluation and job filtering - Support for branch, tag, and merge request pipeline simulation
- Multiple output formats: summary, table, JSON, YAML, and text
- Predefined CI variables automatically set based on context
- Comprehensive integration and E2E test coverage
Remote Extends Improvements:
- Added
mergeRemoteExtendsglobal option to control remote extends resolution - Fixed remote extends resolution for accurate pipeline simulation
- Better handling of remote includes and templates
Documentation & Testing:
- Enhanced CLI documentation with predefined variables table
- Added error handling documentation for remote includes
- Added "Common Pitfalls & Best Practices" section
- Improved JSDoc coverage for all public APIs
- Added
-
b6d0966: Add child pipeline visualization and fluent API support
New Features:
- Added
childPipeline()method to define child pipelines via callback API - Added
writeYamlFiles()method to automatically write parent and all child pipeline YAML files - Child pipelines are now fully visualized in Mermaid diagrams, ASCII trees, and stage tables
- Child pipelines defined via callback are tracked and don't require filesystem access for visualization
API Changes:
- Added
ChildPipelineConfiginterface to track child pipeline configurations - Extended
PipelineStatewithchildPipelinesmap and getter methods - Added public getters to
ConfigBuilder:jobs,templates,stages,jobOptionsMap - Extended
VisualizationParamswithtrackedChildPipelinesparameter - Enhanced
extractChildPipelinesto prioritize tracked configs over file system parsing
Visualization Enhancements:
generateMermaidDiagramshows child pipelines as subgraphs with dotted trigger edgesgenerateAsciiTreedisplays child pipelines with 🔀 indicatorgenerateStageTableincludes child pipeline jobs with separator rows and proper indentation- Added
TriggerInfointerface to track trigger configurations inExtendsGraphNode - Extended
buildExtendsGraphto extract trigger information from job definitions
Example:
config.childPipeline( "trigger:deploy", (child) => { child.stages("deploy") child.job("deploy:prod", { script: ["./deploy.sh"] }) return child }, { strategy: "depend", outputPath: "ci/deploy-pipeline.yml", }, ) await config.writeYamlFiles(".") // Writes: .gitlab-ci.yml + ci/deploy-pipeline.yml
- Added
- ac8da01: Add "Limitations" section to README
- 2b79ae0: Add comprehensive JSDoc documentation across the entire codebase
- Added detailed JSDoc comments to all public APIs and internal functions
- Included practical examples for complex methods
- Added @see references linking to official GitLab CI/CD documentation
- Documented all helper functions in importer, resolver, serializer, and visualization modules
- Enhanced PipelineState class methods with parameter descriptions and usage examples
- Improved documentation for TypeScript AST generation utilities
- 87c99cf: Improve visualization rendering with professional libraries
- Replace custom ASCII tree rendering with
oo-ascii-treefor better box-drawing characters - Replace custom table rendering with
climtfor professional CLI tables- Change table layout from horizontal to vertical (Stage | Job columns)
- Display one job per row with full ext ends chains
- Replace custom ASCII tree rendering with
-
280e33e: Add CLI visualization tool for GitLab CI pipelines
- New
gitlab-ci-buildercommand-line tool withvisualizesubcommand - Supports multiple input formats: local YAML files and remote URLs
- Three visualization formats:
- Mermaid diagram: Interactive flowchart visualization
- ASCII tree: Text-based dependency tree
- Stage table: Organized view by pipeline stages
- Built-in support for extends resolution and dependency analysis
- Easy to use:
npx @noxify/gitlab-ci-builder visualize .gitlab-ci.yml
# Visualize local YAML file (all formats) gitlab-ci-builder visualize .gitlab-ci.yml # Show only Mermaid diagram gitlab-ci-builder visualize .gitlab-ci.yml -f mermaid # Visualize remote pipeline gitlab-ci-builder visualize https://gitlab.com/my-org/my-project/-/raw/main/.gitlab-ci.yml # Show ASCII tree without stages gitlab-ci-builder visualize pipeline.yml -f ascii --show-stages=false
import { visualizeYaml } from "@noxify/gitlab-ci-builder" const yamlContent = ` stages: [build, test] build: stage: build script: npm run build ` const result = await visualizeYaml(yamlContent, { format: "all" }) console.log(result.mermaid) // Mermaid diagram console.log(result.ascii) // ASCII tree console.log(result.table) // Stage table
import { ConfigBuilder } from "@noxify/gitlab-ci-builder" const config = new ConfigBuilder() .stages("build", "test", "deploy") .template(".base", { image: "node:22" }) .extends(".base", "build", { stage: "build", script: ["npm run build"] }) .extends(".base", "test", { stage: "test", script: ["npm test"] }) // Generate visualizations directly from ConfigBuilder const mermaid = config.generateMermaidDiagram({ showStages: true }) const ascii = config.generateAsciiTree({ showRemotes: true }) const table = config.generateStageTable() console.log(mermaid) console.log(ascii) console.log(table)
import { ConfigBuilder, visualizeYaml } from "@noxify/gitlab-ci-builder" const config = new ConfigBuilder() .include({ remote: "https://custom-gitlab-host.com/org/branch/spec.yml" }) .stages("build", "test", "deploy") .template(".base", { image: "node:22" }) .extends(".base", "build", { stage: "build", script: ["npm run build"] }) .extends(".base", "test", { stage: "test", script: ["npm test"] }) const yaml = config.toYaml() const result = await visualizeYaml(yaml, { format: "all", // Optional: Authentication for private repositories gitlabToken: process.env.GITLAB_TOKEN, // Optional: GitLab host URL for project/template includes (default: https://gitlab.com) gitlabUrl: "https://custom-gitlab-host.com", }) console.log(result.mermaid) console.log(result.ascii) console.log(result.table)
- New
-
712ec0d: Fluent Job Builder API
New Feature: Fluent Job Builder API
Added a powerful fluent builder interface for defining jobs and templates with chainable methods:
New Methods:
addJob(name)- Create a new job with fluent builder interfaceaddTemplate(name)- Create a new template with fluent builder interface
JobBuilder Methods: Common properties:
stage(stage)- Set job stageextends(extend)- Set extendsimage(image)- Set imagescript(script)- Set scriptbeforeScript(script)- Set before_scriptafterScript(script)- Set after_scriptservices(services)- Set servicescache(cache)- Set cacheartifacts(artifacts)- Set artifactssetVariables(vars)- Set job variablesenvironment(env)- Set environmentwhen(when)- Set when conditionrules(rules)- Set rulesneeds(needs)- Set needstags(tags)- Set tagsallowFailure(bool)- Set allow_failuretimeout(timeout)- Set timeoutretry(retry)- Set retryparallel(parallel)- Set paralleltrigger(trigger)- Set triggercoverage(pattern)- Set coverage patterndependencies(deps)- Set dependenciesresourceGroup(group)- Set resource_grouprelease(release)- Set releaseinterruptible(bool)- Set interruptibleidTokens(tokens)- Set id_tokens
Utility methods:
set(props)- Bulk set multiple properties at oncejobOptions(opts)- Set job options (remote, mergeExtends, etc.)remote(bool)- Mark job as remotemergeExtends(bool)- Control extends mergingresolveTemplatesOnly(bool)- Control template resolutiondone()- Finalize job and return to ConfigBuilder
Auto-Return Behavior: When you call
addJob()oraddTemplate()from a JobBuilder, the previous job is automatically saved and a new builder is returned:const config = new ConfigBuilder() // Fluent API with auto-return config .stages("build", "test", "deploy") .addTemplate(".node") .image("node:20") .cache({ paths: ["node_modules/"] }) .addJob("test") .stage("test") .extends(".node") .script(["npm test"]) .addJob("build") .stage("build") .extends(".node") .script(["npm run build"]) .addJob("deploy") .stage("deploy") .extends("build") .script(["kubectl apply -f k8s/"]) .when("manual") .done() // Or use done() to explicitly return to ConfigBuilder config .addJob("lint") .stage("test") .script(["npm run lint"]) .done() .addJob("format") .stage("test") .script(["npm run format:check"]) .done() // Bulk property updates with set() config .addJob("complex") .set({ stage: "test", image: "node:20", script: ["npm test"], cache: { paths: ["node_modules/"] }, artifacts: { paths: ["coverage/"] }, }) .done()
Benefits:
- Type-safe: Full TypeScript support with autocomplete
- Readable: Clear, declarative pipeline definitions
- Flexible: Mix with existing
job()andtemplate()methods - Convenient: Auto-return behavior reduces boilerplate
- Powerful: All job properties supported with dedicated methods
This fluent API is especially useful for complex pipelines with many jobs, making the code more maintainable and easier to read.
-
712ec0d: Graph Visualization
New Features: Graph Visualization
Added powerful visualization capabilities to analyze and visualize extends relationships in your GitLab CI pipelines:
New Methods:
getExtendsGraph()- Get the extends dependency graph for programmatic accessgenerateMermaidDiagram(options?)- Generate Mermaid diagram for documentation/GitHubgenerateAsciiTree(options?)- Generate ASCII tree for terminal outputgenerateStageTable(options?)- Generate CLI table with stages as columns
Visualization Options:
showRemote: boolean- Show remote jobs with 🌐 indicatorshowStages: boolean- Include job stages in outputhighlightCycles: boolean- Highlight circular dependencies if detected
Example Usage:
const config = new ConfigBuilder() // ... configure your pipeline ... // Generate individual visualizations const mermaid = config.generateMermaidDiagram({ showStages: true }) const ascii = config.generateAsciiTree({ showRemote: true }) const table = config.generateStageTable() console.log(mermaid) // Mermaid diagram console.log(ascii) // ASCII tree console.log(table) // Stage table
This feature is especially useful for:
- Documenting complex CI configurations
- Debugging extends chains and dependencies
- Understanding job relationships at a glance
- Detecting circular dependencies visually
-
712ec0d: Enhanced Validation API
New Feature: Enhanced Validation API
Added dedicated validation methods for better control over pipeline validation:
New Methods:
validate()- Validate pipeline and throw errors if validation fails (logs warnings to console)safeValidate()- Validate pipeline without throwing errors, returns validation result with{ valid, errors, warnings }
Enhanced Methods:
getPlainObject(options?)- Now accepts{ skipValidation?: boolean }option to skip validation when you've already validated separatelytoJSON(options?)- Now accepts{ skipValidation?: boolean }optiontoYaml(options?)- Now accepts{ skipValidation?: boolean }option
Breaking Changes:
finalize()is nowprivate- usesafeValidate()for programmatic validation orvalidate()for validation that throws errors
Usage Examples:
// Standard validation (throws on error) config.validate() const pipeline = config.getPlainObject({ skipValidation: true }) // Safe validation (no throw) const result = config.safeValidate() if (!result.valid) { console.error("Validation errors:", result.errors) return } if (result.warnings.length > 0) { console.warn("Warnings:", result.warnings) } const pipeline = config.getPlainObject({ skipValidation: true }) // Quick validation (default behavior) const pipeline = config.getPlainObject() // validates automatically
Benefits:
- Separation of concerns: Validation is now separate from pipeline retrieval
- Better error handling:
safeValidate()enables programmatic error handling without try/catch - Performance: Skip validation when using multiple output methods (
toYaml(),toJSON(), etc.) - Flexible: Choose between throwing (
validate()) or returning errors (safeValidate())
-
118f5d4: Fixed extends resolution behavior with
resolveTemplatesOnly: truePreviously, when
resolveTemplatesOnly: truewas set (the default), ALL extends were removed after merging, including normal jobs and remote references that should have been preserved.Old behavior (incorrect):
- Templates (
.prefix) were merged ✅ - Normal jobs (without
.) were merged ❌ (should stay in extends) - Remote jobs were merged ❌ (should stay in extends)
- Unknown/external jobs were merged ❌ (should stay in extends)
New behavior (correct):
- Templates (
.prefix) are merged ✅ - Normal jobs (without
.) remain in extends ✅ - Remote jobs remain in extends ✅
- Unknown/external jobs remain in extends ✅
This fix enables proper GitLab CI template composition patterns, particularly for shallow jobs that use
remote: trueto reference jobs from other configurations without merging them. - Templates (
- a04d3ff: Add comprehensive test infrastructure for GitLab CI templates with local YAML storage and improve type safety for rules array access
- Add test helper utilities for GitLab template round-trip testing
- Add 22 official GitLab CI templates as local test fixtures
- Add integration tests for language templates (19 tests)
- Add integration tests for infrastructure templates (3 tests)
- Add integration tests for browser performance artifacts (2 tests)
- Add support for
specwithinputs(GitLab CI/CD components) - Add integration tests for multi-document YAML with OpenTofu component
- Add interpolation support for schema fields that can contain GitLab CI/CD variables
- Fix TypeScript type errors in test assertions for rules array access by adding proper type guards
- Remove 'pages' from reserved job names (it's a valid GitLab Pages job name)
- Reorganize tests into unit and integration directories
-
05df231: Major Release: Improved Type Safety and GitLab CI Compatibility
This release brings significant improvements to type safety, extends resolution, and compatibility with complex GitLab CI configurations.
The internal architecture has been completely refactored for better type safety and reliability:
- Type System: Job definitions now use explicit input/output types (
JobDefinitionInput,JobDefinitionNormalized,JobDefinitionOutput) instead of a singleJobDefinitiontype. This provides better IntelliSense support and catches errors at compile time. - Extends Resolution: Completely rewritten extends resolution with proper topological sorting, cycle detection, and merge strategies that match GitLab CI's behavior.
- State Management: New internal
PipelineStatemodel for cleaner separation of concerns and better maintainability.
If you're using TypeScript, you may need to update type annotations that reference the old
JobDefinitiontype. However, the public API remains the same - all existing code usingConfigBuildershould continue to work without changes.-
Complex Script Support: Full support for multiline scripts with shell operators, heredocs, and GitLab CI variables
config.job("release", { before_script: [ "npm ci --cache .npm --prefer-offline", `{ echo "@\${CI_PROJECT_ROOT_NAMESPACE}:registry=\${CI_API_V4_URL}/projects/\${CI_PROJECT_ID}/packages/npm/" echo "\${CI_API_V4_URL#https?}/projects/\${CI_PROJECT_ID}/packages/npm/:_authToken=\${CI_JOB_TOKEN}" } | tee -a .npmrc`, ], })
-
Array Syntax Normalization: Single-element arrays in
extendsare now properly normalized to strings, matching GitLab CI's behavior# Input YAML job: extends: [.base] # Single-element array # Now correctly outputs job: extends: .base # Normalized to string
-
Parallel Matrix Support: Fixed schema to accept string, number, and array values for
parallel.matrix, supporting all GitLab CI patternsconfig.job("test", { parallel: { matrix: [ { NODE_VERSION: "18" }, // String values ✓ { PARALLEL_COUNT: 3 }, // Number values ✓ { BROWSERS: ["chrome", "firefox"] }, // Array values ✓ ], }, })
- Variable Preservation: GitLab CI variables like
${CI_COMMIT_BRANCH}are now correctly preserved during YAML import/export cycles - Template Literal Escaping: Fixed double-escaping bug in generated TypeScript code for multiline scripts
- Explicit Types: All pipeline components now have well-defined input and output types
- Union Type Handling: Improved type guards for properties that can be strings or objects (like
environment,cache,needs) - Better IntelliSense: More accurate autocomplete and type checking in your IDE
- 241 tests covering all functionality
- 86%+ test coverage with comprehensive real-world use case tests
- New test suites for:
- Complex script handling with GitLab CI variables
- Merge strategies and extends resolution
- Pipeline state management
- Real-world deployment scenarios
For most users, no changes are required. However, if you have TypeScript code that references internal types:
Before:
import type { JobDefinition } from "@noxify/gitlab-ci-builder" const job: JobDefinition = { ... }
After:
import type { JobDefinitionInput } from "@noxify/gitlab-ci-builder" const job: JobDefinitionInput = { ... }
The public API (
ConfigBuildermethods, import/export functions) remains fully compatible with previous versions. - Type System: Job definitions now use explicit input/output types (
- 9db94c7: Extended
!referencetag support to handle scalar values (e.g.,image,extends) in addition to arrays, ensuring inline format without quotes for all use cases.
-
5c870cc: Add support for
artifacts.reports.annotationsproperty withstring | string[]type. Import now intelligently normalizes single-element arrays to strings for cleaner generated code. -
5229108: Add support for default export in
dynamicInclude. Config modules can now use eitherexport default function(config: Config)or the existingexport function extendConfig(config: Config). Default export is preferred when both are present. -
2c0a5ba: Add support for
extendsas bothstringandstring[]. Single extends are optimized to string format in generated code for better readability. -
d1602ed: Add support for
artifacts.reports.dotenvproperty withstring | string[]type. Import now intelligently normalizes single-element arrays to strings for cleaner generated code. -
151d1fb: Add
asExtendedConfigoption to importer for function-based exportsThe
fromYaml()andimportYamlFile()functions now accept anImportOptionsparameter with anasExtendedConfigoption. When set totrue:- Uses
import type { Config }instead ofimport { Config } - Generates a function that receives a
Configinstance as parameter - Exports
export default function (config: Config) { ... return config }instead of direct config export - Properly indents all config calls within the function body
This enables creating modular config extensions that can be composed together, similar to the dynamic include pattern but with full TypeScript type safety at compile time.
Example output with
asExtendedConfig: true:import type { Config } from "@noxify/gitlab-ci-builder" export default function (config: Config) { config.stages("build", "test") config.job("build", { stage: "build", script: ["npm run build"], }) return config }
- Uses
-
0453041: Add flexible job configuration options with
JobOptionsinterface andglobalOptions()method.New Features:
JobOptionsinterface: Unified options object forjob(),template(), andextends()methods with:resolveExtends?: boolean- Control whether parent templates are resolved (default:true)mergeExisting?: boolean- Control merge behavior for duplicate job names (default:true)hidden?: boolean- Mark job as template (replaces boolean parameter)
globalOptions(options: GlobalOptions)method: Set default options for all jobs:resolveExtends?: boolean- Disable extends resolution globallymergeExisting?: boolean- Control default merge behavior- Job-level options override global settings
Benefits:
- Preserve
extendsreferences in output whenresolveExtends: false - Fine-grained control over job merging behavior
- Unified options interface for cleaner API
Example:
const config = new Config() // Global: disable extends resolution for all jobs config.globalOptions({ resolveExtends: false }) config.template(".base", { script: ["base command"] }) // This job keeps extends reference (global setting) config.job("job1", { extends: ".base" }) // This job resolves extends (local override) config.job("job2", { extends: ".base" }, { resolveExtends: true }) // Replace instead of merge config.job("test", { stage: "test" }) config.job("test", { script: ["override"] }, { mergeExisting: false })
-
0f6fffc: Add support for
rules.existsproperty withstring | string[]type to match GitLab CI specification. -
32286d9: Add support for
remoteflag on jobs and templates- Added
remoteoption to exclude jobs/templates from merging and output
- Added
-
f7412c0: Improve script formatting in YAML import with intelligent detection of shell operators.
The import now intelligently formats
script,before_script, andafter_scriptproperties:- Simple multi-line commands → Split into string array for better readability
- Line continuations (
\) → Preserved as template literals - Shell operators (heredoc
<<, pipes|, redirects>,>>,2>,<) → Preserved as template literals - Single-line commands → Formatted as simple strings
This produces more idiomatic and readable TypeScript code while preserving shell command semantics.
-
00274d9: Add missing
optionalproperty toneedsdefinitions (both job and pipeline needs) to match GitLab CI specification. -
8074252: Add missing
nameproperty toworkflowdefinition to match GitLab CI specification.
-
df32a6d: Change
dynamicIncludeconfig functions to return theConfiginstance for consistency with the fluent builder pattern.Included config files should now return the config:
export default function (config: Config) { config.stages("build") return config }
-
99b83b0: Fixed YAML serialization of
!referencetags to output inline format without quotes, enabling proper GitLab CI reference resolution. -
dd6b3e7: Fixed remote flag handling - internal properties are now stripped after extends resolution to ensure remote jobs/templates are correctly excluded from merging while preserving their references.
-
8f94028: Fix regression in YAML import script formatting where multi-line simple script blocks produced a nested array structure (
script: [[...]]) instead of a flat array (script: [ ... ]).The importer now flattens multi-line simple commands correctly and preserves template literals only when shell operators (pipes, heredoc, redirects, continuations) are present.
-
6c9d68b: Improve YAML anchor handling by filtering out anchor definitions that don't contain valid job objects. This prevents type errors when importing GitLab CI files with pure anchor arrays.
-
0bf73bc: Disable log for importing file
-
1ee8b06: ensure
needsExtendsis always removed from final outputPreviously
needsExtends(internal merge-order metadata) was only deleted in certain branches of the cleanup logic, causing it to leak into the final YAML when a job had a single remoteextendsreference. Now it's unconditionally removed from all jobs during serialization. -
491ec44: Fix import code generation to properly handle single-element arrays for properties like
extends, optimizing output format for better code readability. -
83530eb: fixes problem while resolving the extends. unknown extends aren't removed now, so we can also specify remote jobs/tempates.
-
185d58d: Fix: remote flag is now internal-only
- The
remoteoption for jobs/templates is now used only for merge logic and is stripped from the final YAML output. - Prevents leaking internal flags into exported pipeline definitions.
- The
-
32286d9: Rename option
resolveExtendstomergeExtends- The option controlling whether parent templates/jobs are merged is now called
mergeExtends(wasresolveExtends).
- The option controlling whether parent templates/jobs are merged is now called
-
32286d9: Add tests for resolveTemplatesOnly option
- Added tests for global and job-level resolveTemplatesOnly
-
75edc28: Fix script parser to preserve shell control structures
The YAML importer now correctly detects and preserves shell control structures (if/then/else/fi, for/do/done, while/do/done, until/do/done, case/esac) as template literals instead of splitting them into separate array elements.
Previously, multi-line scripts with control structures were incorrectly split:
// Before (incorrect) script: ['if [ "$VAR" = "true" ]; then', 'echo "yes"', "else", 'echo "no"', "fi"]
Now they are preserved as cohesive blocks:
// After (correct) script: [ `if [ "$VAR" = "true" ]; then echo "yes" else echo "no" fi `, ]
This ensures shell scripts with control flow are generated correctly and maintain their intended structure.
- 651d7a1: support
!referencetag
- 1a6f848: update readme
- 1a6f848: fix ci:version and ci:publish
- 52a0098: update workflow
- fd05add: npm trusted publish
- 3b23c22: update publish config
- f9c01fe: Refactor the whole package
- renamed
gitlab-ymltogitlab-ci-builder - Re-implements some missing methods
- Added tests
- Introduces an export function ( beta )
- Introduces an import function ( beta )
- renamed