The CI4TOSCA Prototype is a Go-based tool for generating CI/CD pipelines from TOSCA build descriptions. It serves as the reference implementation of the CI4TOSCA framework, which introduces a declarative build stage to unify artifact creation within a TOSCA model.
This prototype supports Jenkins, GitHub Actions, and GitLab CI pipelines, integrates with Artifactory and MinIO for artifact storage, and features a plugin-based architecture for extensibility.
Traditional DevOps workflows maintain separate scripts for build and deployment, leading to redundancy, complexity, and vendor lock-in. CI4TOSCA addresses this by embedding build instructions directly in the TOSCA model and transforming them into executable pipelines, reducing configuration effort and increasing maintainability.
This prototype was evaluated through 576 pipeline executions and demonstrated:
- An 83% reduction in CI/CD configuration files
- A 40% reduction in lines of configuration code
- Full tool-switching support with no model changes
For evaluation details, see:
=> CI4TOSCA Evaluation
- Declarative Build Descriptions: Define build logic directly within TOSCA service templates.
- Pipeline Generation: Generate pipelines for Jenkins, GitHub Actions, and GitLab CI.
- Plugin Architecture: Easily add new artifact types, pipeline tools, and storage backends.
- Artifact Storage Support: Uploads to Artifactory, MinIO, S3, and other backends.
- TOSCA Version Support: Supports TOSCA 1.3, 2.0, and future versions via YAML templates.
- Preview Mode: View generated pipelines without writing them to disk.
- Git Integration: Automatically clones repositories referenced in TOSCA inputs.
- Component-Level Configuration: Assign individual pipeline tools and outputs per service.
- Go 1.20 or later
- Valid TOSCA build description file (v1.3 or v2.0)
git clone https://github.com/CI4TOSCA/Prototype
cd Prototype
go mod tidy
go build -o prototypego run orchestrator.go \
--tosca path/to/tosca.yaml \
--tool Jenkins \
--output Jenkinsfile \
--storage https://artifact-store.example.com \
--storageUser user \
--storagePassword passgo run orchestrator.go \
--tosca path/to/tosca.yaml \
--tool comp1=GitHub,comp2=Jenkins \
--output comp1=github.yaml,comp2=jenkinsfile \
--storage https://artifact-store.example.com \
--storageUser user \
--storagePassword passgo run orchestrator.go \
--tosca path/to/tosca.yaml \
--tool GitHub \
--storage https://artifact-store.example.com \
--storageUser user \
--storagePassword pass \
--previewRun all tests:
go test ./... -v| Flag | Description |
|---|---|
--tosca |
Path to the TOSCA input file. |
--tool |
Pipeline tool (global or per-component). |
--output |
Output file(s) (global or per-component). |
--storage |
Artifact storage URL. |
--storageUser |
User name for the storage backend. |
--storagePassword |
Password for the storage backend. |
--preview |
Preview the pipeline without saving it. |
--executeURL |
URL of pipeline tool. |
--executeUser |
User for pipeline tool. |
--executeToken |
Token for pipeline tool. |
--notificationMethod |
Notification type (e.g. slack). |
--notificationWebHook |
Webhook URL for notifications. |
The prototype is structured for extensibility. Each plugin type implements a common interface and is registered dynamically.
- Implement the
Pipelineinterface inpipelines/:
type MyCustomPipeline struct {
BasePipeline
}
func (p *MyCustomPipeline) transform(stages []models.Stage) (string, error) { ... }
func (p *MyCustomPipeline) execute() (string, error) { ... }
func (p *MyCustomPipeline) validate() error { ... }- Register it:
func init() {
pipelines.RegisterPipeline("MyCustomPipeline", func(base pipelines.BasePipeline) pipelines.Pipeline {
return &MyCustomPipeline{BasePipeline: base}
})
}- Implement the
Artifactinterface inartifacts/:
type MyCustomArtifact struct {
BaseArtifact
}
func (m *MyCustomArtifact) GetType() string {
return m.Type
}
func (m *MyCustomArtifact) GenerateStages(buildDescription models.BuildDescription, artifactStorageURL string) ([]models.Stage, error) { ... }
func (m *MyCustomArtifact) GetBuildDescription(artifactType string, componentName string, artifactInputs map[string]interface{}) models.BuildDescription { ... }- Register it:
func init() {
artifacts.RegisterArtifact("MyCustomArtifact", func(base artifacts.BaseArtifact) artifacts.Artifact {
return &MyCustomArtifact{BaseArtifact: base}
})
}- Implement the
ArtifactStorageinterface instorage/:
type MyCustomStorage struct { ... }
func NewCustomStorage(artifactStorageURL string) (*MyCustomStorage, error) { ... }
func (s *MyCustomStorage) GenerateUploadCommand(filePath string, repoPath string) (string, error) { ... }
func (s *MyCustomStorage) GetArtifactStorageURLs(filePath string, repoPath string) string { ... }- Update the switch logic in
storage_handler/NewStorageHandler(...)to support your backend via URL scheme.
- Implement the
Notifierinterface innotifications/:
type MyNotifier struct {
WebhookURL string
}
func (m *MyNotifier) Send(message string) error { ... }- Register it:
func init() {
RegisterNotifier("MyNotifier", NewMyNotifier)
}
func NewMyNotifier(url string) Notifier {
return &MyNotifier{WebhookURL: url}
}tosca_definitions_version: tosca_simple_yaml_1_3
node_types:
my_application:
derived_from: tosca.nodes.SoftwareComponent
metadata:
name: my_application
version: 1.0.0
artifacts:
my_image_source:
file: "./source.tar.gz"
type: CI4TOSCA.Sources
my_application_binary: # For Binary images
file: my_image
type: CI4TOSCA.Binary.Image
interfaces:
Standard:
build:
inputs:
architecture:
type: "x86_64"
directory: "src/"
build_steps:
- step: compile
command: "gcc -o my_app main.c"
- step: package
command: "tar -czf my_app.tar.gz my_app"
my_application_docker: # For Docker images
file: "https://github.com/CI4TOSCA/Evaluation/3_pipeline_files/dockerfiles/VueRailsDockerfile"
type: CI4TOSCA.Docker.Image
properties:
image_name: "vue-rails"
my_application_npm: # For NPM images
file: "https://github.com/khaledosman/angular-realworld-example-app"
type: CI4TOSCA.NPM.Image
properties:
build_command: "run" # optional
my_application_maven: # For Maven images
file: "https://github.com/spring-projects/spring-petclinic"
type: CI4TOSCA.Jar.Image
my_application_extern: # For images build by external pipelines
file: "https://github.com/my-org/my-repo/deploy.yml"
type: CI4TOSCA.ExternalPipeline.Image
properties:
api_token: "XYZ"
body: "my_body" # optional
topology_template:
node_templates:
my_application:
type: my_application
requirements:
- host:
node: my_host
my_host:
type: tosca.nodes.Computetosca_definitions_version: tosca_2_0
service_template:
node_types:
my_application:
derived_from: tosca.nodes.SoftwareComponent
metadata:
name: my_application
version: 1.0.0
artifacts:
my_image_source:
file: "./source.tar.gz"
type: CI4TOSCA.Sources
my_application_binary: # For Binary images
file: my_image
type: CI4TOSCA.Binary.Image
interfaces:
Standard:
build:
inputs:
architecture:
type: "x86_64"
directory: "src/"
build_steps:
- step: compile
command: "gcc -o my_app main.c"
- step: package
command: "tar -czf my_app.tar.gz my_app"
my_application_docker: # For Docker images
file: "https://github.com/CI4TOSCA/Evaluation/3_pipeline_files/dockerfiles/VueRailsDockerfile"
type: CI4TOSCA.Docker.Image
properties:
image_name: "vue-rails"
my_application_npm: # For NPM images
file: "https://github.com/khaledosman/angular-realworld-example-app"
type: CI4TOSCA.NPM.Image
properties:
build_command: "run" # optional
my_application_maven: # For Maven images
file: "https://github.com/spring-projects/spring-petclinic"
type: CI4TOSCA.Jar.Image
my_application_extern: # For images build by external pipelines
file: "https://github.com/my-org/my-repo/deploy.yml"
type: CI4TOSCA.ExternalPipeline.Image
properties:
api_token: "XYZ"
body: "my_body" # optional
node_templates:
my_application:
type: my_application
requirements:
- host:
node: my_host
my_host:
type: tosca.nodes.ComputeThis project is licensed under the MIT License.
See the LICENSE file for details.