From e1cfa624e4af463d37388856cf5b2a54fa23c26c Mon Sep 17 00:00:00 2001 From: Maysun J Faisal Date: Wed, 28 Oct 2020 17:28:34 -0400 Subject: [PATCH 01/13] test api's override func Signed-off-by: Maysun J Faisal --- devfile.yaml | 78 +++++++++++----------------- go.sum | 3 ++ main.go | 12 ++++- pkg/devfile/parser/data/interface.go | 3 ++ pkg/devfile/parser/data/v2/types.go | 11 ++++ pkg/devfile/parser/devfileobj.go | 8 +-- pkg/devfile/parser/parse.go | 54 +++++++++++++------ 7 files changed, 97 insertions(+), 72 deletions(-) diff --git a/devfile.yaml b/devfile.yaml index 89587661..2eea734b 100644 --- a/devfile.yaml +++ b/devfile.yaml @@ -2,53 +2,33 @@ schemaVersion: 2.0.0 metadata: name: nodejs version: 1.0.0 - alpha.build-dockerfile: https://raw.githubusercontent.com/odo-devfiles/registry/master/devfiles/nodejs/build/Dockerfile - alpha.deployment-manifest: https://raw.githubusercontent.com/odo-devfiles/registry/master/devfiles/nodejs/deploy/deployment-manifest.yaml -starterProjects: -- name: nodejs-starter - git: - remotes: - origin: https://github.com/odo-devfiles/nodejs-ex.git -components: -- name: runtime - container: - endpoints: - - name: http-3000 - targetPort: 3000 - image: registry.access.redhat.com/ubi8/nodejs-12:1-45 - memoryLimit: 1024Mi - mountSources: true - sourceMapping: /project +parent: + uri: https://raw.githubusercontent.com/openshift/odo/master/tests/examples/source/devfiles/nodejs/devfileCompositeCommands.yaml + commands: + - id: buildAndMkdir + composite: + label: Build and Mkdir + commands: + - createfile + - install + parallel: false + group: + kind: build + isDefault: true + components: + - name: runtime + container: + # image: registry.access.redhat.com/ubi8/nodejs-12:1-36 + env: + - name: MEME + value: /mycustom/path/ commands: -- exec: - commandLine: npm install - component: runtime - group: - isDefault: true - kind: build - workingDir: /project - id: install -- exec: - commandLine: npm start - component: runtime - group: - isDefault: true - kind: run - workingDir: /project - id: run -- exec: - commandLine: npm run debug - component: runtime - group: - isDefault: true - kind: debug - workingDir: /project - id: debug -- exec: - commandLine: npm test - component: runtime - group: - isDefault: true - kind: test - workingDir: /project - id: test + - id: createfile + exec: + component: runtime + commandLine: touch /projects/testfile + workingDir: ${PROJECTS_ROOT} + group: + kind: build + isDefault: false + \ No newline at end of file diff --git a/go.sum b/go.sum index 7580fec1..c4ad3ca9 100644 --- a/go.sum +++ b/go.sum @@ -167,7 +167,9 @@ github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:Fecb github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -218,6 +220,7 @@ github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzp github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY70sEEpE= github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= diff --git a/main.go b/main.go index 988953aa..dc3c7b7d 100644 --- a/main.go +++ b/main.go @@ -3,6 +3,7 @@ package main import ( "fmt" "reflect" + "strings" devfilepkg "github.com/devfile/library/pkg/devfile" "github.com/devfile/library/pkg/devfile/parser" @@ -23,12 +24,19 @@ func main() { for _, component := range devfile.Data.GetComponents() { if component.Container != nil { fmt.Println(component.Container.Image) + for _, env := range component.Container.Env { + fmt.Printf("%s: %s\n", env.Name, env.Value) + } } } for _, command := range devfile.Data.GetCommands() { - if command.Exec != nil { - fmt.Println(command.Exec.Group.Kind) + // if command.Exec != nil { + // fmt.Println(command.Exec.Group.Kind) + // } + fmt.Println("main.go cmd is " + command.Id) + if command.Id == "buildAndMkdir" { + fmt.Println("main.go composite commands: " + strings.Join(command.Composite.Commands, " ")) } } } diff --git a/pkg/devfile/parser/data/interface.go b/pkg/devfile/parser/data/interface.go index 84d0d8c0..8d41658a 100644 --- a/pkg/devfile/parser/data/interface.go +++ b/pkg/devfile/parser/data/interface.go @@ -44,4 +44,7 @@ type DevfileData interface { AddVolume(volume v1.Component, path string) error DeleteVolume(name string) error GetVolumeMountPath(name string) (string, error) + + GetDevfileWorkspace() *v1.DevWorkspaceTemplateSpecContent + SetDevfileWorkspace(content v1.DevWorkspaceTemplateSpecContent) } diff --git a/pkg/devfile/parser/data/v2/types.go b/pkg/devfile/parser/data/v2/types.go index e7fdff4e..3f7be501 100644 --- a/pkg/devfile/parser/data/v2/types.go +++ b/pkg/devfile/parser/data/v2/types.go @@ -8,3 +8,14 @@ import ( type DevfileV2 struct { v1.Devfile } + +// GetDevfileWorkspace returns the workspace content for the devfile +func (d *DevfileV2) GetDevfileWorkspace() *v1.DevWorkspaceTemplateSpecContent { + + return &d.DevWorkspaceTemplateSpecContent +} + +// SetDevfileWorkspace sets the workspace content +func (d *DevfileV2) SetDevfileWorkspace(content v1.DevWorkspaceTemplateSpecContent) { + d.DevWorkspaceTemplateSpecContent = content +} diff --git a/pkg/devfile/parser/devfileobj.go b/pkg/devfile/parser/devfileobj.go index 13ccfa74..a4c6a453 100644 --- a/pkg/devfile/parser/devfileobj.go +++ b/pkg/devfile/parser/devfileobj.go @@ -70,8 +70,8 @@ func (d DevfileObj) OverrideCommands(overridePatch []v1.CommandParentOverride) ( for _, patchCommand := range overridePatch { found := false for _, originalCommand := range d.Data.GetCommands() { - - if strings.ToLower(patchCommand.Id) == originalCommand.Id { + fmt.Printf(">>> MJF PARENT CMD: %v\n", originalCommand.Id) + if patchCommand.Id == originalCommand.Id { found = true var devfileCommand v1.Command @@ -97,7 +97,7 @@ func (d DevfileObj) OverrideCommands(overridePatch []v1.CommandParentOverride) ( } } if !found { - return fmt.Errorf("the command to override is not found in the parent") + return fmt.Errorf("the command %s to override is not found in the parent", patchCommand.Id) } } return nil @@ -170,7 +170,7 @@ func (d DevfileObj) OverrideProjects(overridePatch []v1.ProjectParentOverride) e } } if !found { - return fmt.Errorf("the command to override is not found in the parent") + return fmt.Errorf("the project to override is not found in the parent") } } return nil diff --git a/pkg/devfile/parser/parse.go b/pkg/devfile/parser/parse.go index cb05af43..0fdba382 100644 --- a/pkg/devfile/parser/parse.go +++ b/pkg/devfile/parser/parse.go @@ -2,15 +2,18 @@ package parser import ( "encoding/json" + "fmt" + "strings" - devfileCtx "github.com/devfile/library/pkg/devfile/parser/context" - "github.com/devfile/library/pkg/devfile/parser/data" + devfileCtx "github.com/devfile/parser/pkg/devfile/parser/context" + "github.com/devfile/parser/pkg/devfile/parser/data" + "k8s.io/klog" "reflect" v1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + apiOverride "github.com/devfile/api/pkg/utils/overriding" "github.com/pkg/errors" - "k8s.io/klog" ) // ParseDevfile func validates the devfile integrity. @@ -99,28 +102,45 @@ func parseParent(d DevfileObj) error { if err != nil { return err } - klog.V(4).Infof("overriding data of devfile with URI: %v", parent.Uri) - // override the parent's components, commands, projects and events - err = parentData.OverrideComponents(d.Data.GetParent().Components) + parentWorkspaceContent := parentData.Data.GetDevfileWorkspace() + result, err := apiOverride.OverrideDevWorkspaceTemplateSpec(parentWorkspaceContent, parent) if err != nil { return err } - err = parentData.OverrideCommands(d.Data.GetParent().Commands) - if err != nil { - return err + for _, command := range result.Commands { + fmt.Println(">>> API command is " + command.Id) + if command.Id == "buildAndMkdir" { + fmt.Println("API composite commands: " + strings.Join(command.Composite.Commands, " ")) + } } - err = parentData.OverrideProjects(d.Data.GetParent().Projects) - if err != nil { - return err - } + parentData.Data.SetDevfileWorkspace(*result) - err = parentData.OverrideStarterProjects(d.Data.GetParent().StarterProjects) - if err != nil { - return err - } + // // fmt.Println("parent Data", parentData) + // klog.V(4).Infof("overriding data of devfile with URI: %v", parent.Uri) + + // // override the parent's components, commands, projects and events + // err = parentData.OverrideComponents(d.Data.GetParent().Components) + // if err != nil { + // return err + // } + + // err = parentData.OverrideCommands(d.Data.GetParent().Commands) + // if err != nil { + // return err + // } + + // err = parentData.OverrideProjects(d.Data.GetParent().Projects) + // if err != nil { + // return err + // } + + // err = parentData.OverrideStarterProjects(d.Data.GetParent().StarterProjects) + // if err != nil { + // return err + // } klog.V(4).Infof("adding data of devfile with URI: %v", parent.Uri) From 66a47aebac45bcf371bfd8893ee0b19874fcbc40 Mon Sep 17 00:00:00 2001 From: Maysun J Faisal Date: Mon, 23 Nov 2020 14:57:21 -0500 Subject: [PATCH 02/13] rebase with master Signed-off-by: Maysun J Faisal --- pkg/devfile/parser/parse.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/devfile/parser/parse.go b/pkg/devfile/parser/parse.go index 0fdba382..dcf1fed5 100644 --- a/pkg/devfile/parser/parse.go +++ b/pkg/devfile/parser/parse.go @@ -5,8 +5,8 @@ import ( "fmt" "strings" - devfileCtx "github.com/devfile/parser/pkg/devfile/parser/context" - "github.com/devfile/parser/pkg/devfile/parser/data" + devfileCtx "github.com/devfile/library/pkg/devfile/parser/context" + "github.com/devfile/library/pkg/devfile/parser/data" "k8s.io/klog" "reflect" From ef341159ef7f93e8cb759265e9b31ccf277d40d7 Mon Sep 17 00:00:00 2001 From: Stephanie Date: Tue, 1 Dec 2020 15:02:34 -0500 Subject: [PATCH 03/13] added parseplugin Signed-off-by: Stephanie --- main.go | 14 +- pkg/devfile/parser/context/context.go | 1 - pkg/devfile/parser/devfileobj.go | 208 ---- pkg/devfile/parser/devfileobj_test.go | 1399 ------------------------- pkg/devfile/parser/parse.go | 88 +- pkg/devfile/parser/writer.go | 5 +- 6 files changed, 62 insertions(+), 1653 deletions(-) delete mode 100644 pkg/devfile/parser/devfileobj_test.go diff --git a/main.go b/main.go index dc3c7b7d..d094b266 100644 --- a/main.go +++ b/main.go @@ -3,7 +3,6 @@ package main import ( "fmt" "reflect" - "strings" devfilepkg "github.com/devfile/library/pkg/devfile" "github.com/devfile/library/pkg/devfile/parser" @@ -11,7 +10,7 @@ import ( ) func main() { - devfile, err := ParseDevfile("devfile.yaml") + devfile, err := ParseDevfile("./devfile.yaml") if err != nil { fmt.Println(err) } else { @@ -24,19 +23,12 @@ func main() { for _, component := range devfile.Data.GetComponents() { if component.Container != nil { fmt.Println(component.Container.Image) - for _, env := range component.Container.Env { - fmt.Printf("%s: %s\n", env.Name, env.Value) - } } } for _, command := range devfile.Data.GetCommands() { - // if command.Exec != nil { - // fmt.Println(command.Exec.Group.Kind) - // } - fmt.Println("main.go cmd is " + command.Id) - if command.Id == "buildAndMkdir" { - fmt.Println("main.go composite commands: " + strings.Join(command.Composite.Commands, " ")) + if command.Exec != nil { + fmt.Println(command.Exec.Group.Kind) } } } diff --git a/pkg/devfile/parser/context/context.go b/pkg/devfile/parser/context/context.go index 49448eb0..c00763c6 100644 --- a/pkg/devfile/parser/context/context.go +++ b/pkg/devfile/parser/context/context.go @@ -67,7 +67,6 @@ func (d *DevfileCtx) Populate() (err error) { return err } klog.V(4).Infof("absolute devfile path: '%s'", d.absPath) - // Read and save devfile content if err := d.SetDevfileContent(); err != nil { return err diff --git a/pkg/devfile/parser/devfileobj.go b/pkg/devfile/parser/devfileobj.go index a4c6a453..f7ee33e9 100644 --- a/pkg/devfile/parser/devfileobj.go +++ b/pkg/devfile/parser/devfileobj.go @@ -1,15 +1,8 @@ package parser import ( - "encoding/json" - "fmt" - "strings" - - v1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" devfileCtx "github.com/devfile/library/pkg/devfile/parser/context" "github.com/devfile/library/pkg/devfile/parser/data" - "github.com/pkg/errors" - "k8s.io/apimachinery/pkg/util/strategicpatch" ) // Default filenames for create devfile @@ -27,204 +20,3 @@ type DevfileObj struct { // Data has the devfile data Data data.DevfileData } - -// OverrideComponents overrides the components of the parent devfile -// overridePatch contains the patches to be applied to the parent's components -func (d DevfileObj) OverrideComponents(overridePatch []v1.ComponentParentOverride) error { - // func (d DevfileObj) OverrideComponents(overridePatch interface{}) error { - for _, patchComponent := range overridePatch { - found := false - for _, originalComponent := range d.Data.GetComponents() { - if strings.ToLower(patchComponent.Name) == originalComponent.Name { - found = true - - var updatedComponent v1.ContainerComponent - - merged, err := handleMerge(originalComponent.Container, patchComponent.Container, v1.ContainerComponent{}) - if err != nil { - return err - } - err = json.Unmarshal(merged, &updatedComponent) - if err != nil { - return errors.Wrap(err, "failed to unmarshal override components") - } - - d.Data.UpdateComponent(v1.Component{ - Name: patchComponent.Name, - ComponentUnion: v1.ComponentUnion{ - Container: &updatedComponent, - }, - }) - } - } - if !found { - return fmt.Errorf("the component to override is not found in the parent") - } - } - return nil -} - -// OverrideCommands overrides the commands of the parent devfile -// overridePatch contains the patches to be applied to the parent's commands -func (d DevfileObj) OverrideCommands(overridePatch []v1.CommandParentOverride) (err error) { - for _, patchCommand := range overridePatch { - found := false - for _, originalCommand := range d.Data.GetCommands() { - fmt.Printf(">>> MJF PARENT CMD: %v\n", originalCommand.Id) - if patchCommand.Id == originalCommand.Id { - found = true - - var devfileCommand v1.Command - - if patchCommand.Exec != nil && originalCommand.Exec != nil { - devfileCommand, err = overrideExecCommand(patchCommand, originalCommand) - if err != nil { - return err - } - - } else if patchCommand.Composite != nil && originalCommand.Composite != nil { - devfileCommand, err = overrideCompositeCommand(patchCommand, originalCommand) - if err != nil { - return err - } - // TODO: add other command types - } else { - // If the original command and patch command are different types, then we can't patch, so throw an error - return fmt.Errorf("cannot overide command %q with a different type of command", originalCommand.Id) - } - - d.Data.UpdateCommand(devfileCommand) - } - } - if !found { - return fmt.Errorf("the command %s to override is not found in the parent", patchCommand.Id) - } - } - return nil -} - -// overrideCompositeCommand overrides the given parent composite commmand -// patchCommand contains the patches to be applied to the parent's command -func overrideCompositeCommand(patchCommand v1.CommandParentOverride, originalCommand v1.Command) (v1.Command, error) { - var updatedComposite v1.CompositeCommand - - merged, err := handleMerge(originalCommand.Composite, patchCommand.Composite, v1.CompositeCommand{}) - if err != nil { - return v1.Command{}, err - } - - err = json.Unmarshal(merged, &updatedComposite) - if err != nil { - return v1.Command{}, errors.Wrap(err, "failed to unmarshal override commands") - } - return v1.Command{ - Id: patchCommand.Id, - CommandUnion: v1.CommandUnion{ - Composite: &updatedComposite, - }, - }, nil -} - -// overrideExecCommand overrides the given parent Exec commmand -// patchCommand contains the patches to be applied to the parent's command -func overrideExecCommand(patchCommand v1.CommandParentOverride, originalCommand v1.Command) (v1.Command, error) { - var updatedExec v1.ExecCommand - merged, err := handleMerge(originalCommand.Exec, patchCommand.Exec, v1.ExecCommand{}) - if err != nil { - return v1.Command{}, err - } - - err = json.Unmarshal(merged, &updatedExec) - if err != nil { - return v1.Command{}, errors.Wrap(err, "failed to unmarshal override commands") - } - return v1.Command{ - Id: patchCommand.Id, - CommandUnion: v1.CommandUnion{ - Exec: &updatedExec, - }, - }, nil -} - -// OverrideProjects overrides the projects of the parent devfile -// overridePatch contains the patches to be applied to the parent's projects -func (d DevfileObj) OverrideProjects(overridePatch []v1.ProjectParentOverride) error { - for _, patchProject := range overridePatch { - found := false - for _, originalProject := range d.Data.GetProjects() { - if strings.ToLower(patchProject.Name) == originalProject.Name { - found = true - var updatedProject v1.Project - - merged, err := handleMerge(originalProject, patchProject, v1.Project{}) - if err != nil { - return err - } - - err = json.Unmarshal(merged, &updatedProject) - if err != nil { - return errors.Wrap(err, "failed to unmarshal override projects") - } - - d.Data.UpdateProject(updatedProject) - } - } - if !found { - return fmt.Errorf("the project to override is not found in the parent") - } - } - return nil -} - -// OverrideStarterProjects overrides the starter projects of the parent devfile -// overridePatch contains the patches to be applied to the parent's starter projects -func (d DevfileObj) OverrideStarterProjects(overridePatch []v1.StarterProjectParentOverride) error { - for _, patchProject := range overridePatch { - found := false - for _, originalProject := range d.Data.GetStarterProjects() { - if strings.ToLower(patchProject.Name) == originalProject.Name { - found = true - var updatedProject v1.StarterProject - - merged, err := handleMerge(originalProject, patchProject, v1.StarterProject{}) - if err != nil { - return err - } - - err = json.Unmarshal(merged, &updatedProject) - if err != nil { - return errors.Wrap(err, "failed to unmarshal override starter projects") - } - d.Data.UpdateStarterProject(updatedProject) - } - } - if !found { - return fmt.Errorf("the starterProject to override is not found in the parent") - } - } - return nil -} - -// handleMerge merges the patch to the original data -// dataStruct is the type of the original and the patch data -func handleMerge(original, patch, dataStruct interface{}) ([]byte, error) { - // if reflect.TypeOf(original) != reflect.TypeOf(patch) { - // return nil, fmt.Errorf("type of original and patch doesn't match") - // } - - originalJson, err := json.Marshal(original) - if err != nil { - return nil, err - } - - patchJson, err := json.Marshal(patch) - if err != nil { - return nil, err - } - - merged, err := strategicpatch.StrategicMergePatch(originalJson, patchJson, dataStruct) - if err != nil { - return nil, err - } - return merged, nil -} diff --git a/pkg/devfile/parser/devfileobj_test.go b/pkg/devfile/parser/devfileobj_test.go deleted file mode 100644 index 4a976c68..00000000 --- a/pkg/devfile/parser/devfileobj_test.go +++ /dev/null @@ -1,1399 +0,0 @@ -package parser - -import ( - "reflect" - "testing" - - devfileCtx "github.com/devfile/library/pkg/devfile/parser/context" - v2 "github.com/devfile/library/pkg/devfile/parser/data/v2" - "github.com/devfile/library/pkg/testingutil" - "github.com/kylelemons/godebug/pretty" - - v1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" -) - -const devfileTempPath = "devfile.yaml" - -func TestDevfileObj_OverrideCommands(t *testing.T) { - componentName0 := "component-0" - overrideComponent0 := "override-component-0" - - commandLineBuild := "npm build" - overrideBuild := "npm custom build" - commandLineRun := "npm run" - - workingDir := "/project" - overrideWorkingDir := "/data" - - type args struct { - overridePatch []v1.CommandParentOverride - } - tests := []struct { - name string - devFileObj DevfileObj - args args - wantDevFileObj DevfileObj - wantErr bool - }{ - { - name: "case 1: override a command's non list/map fields", - devFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v2.DevfileV2{ - Devfile: v1.Devfile{ - DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ - DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ - Commands: []v1.Command{ - { - Id: "devbuild", - CommandUnion: v1.CommandUnion{ - Exec: &v1.ExecCommand{ - CommandLine: commandLineBuild, - Component: componentName0, - Env: nil, - LabeledCommand: v1.LabeledCommand{ - BaseCommand: v1.BaseCommand{ - Group: &v1.CommandGroup{ - IsDefault: false, - Kind: v1.BuildCommandGroupKind, - }, - }, - }, - WorkingDir: workingDir, - }, - }, - }, - }, - }, - }, - }, - }, - }, - args: args{ - overridePatch: []v1.CommandParentOverride{ - { - Id: "devbuild", - CommandUnionParentOverride: v1.CommandUnionParentOverride{ - Exec: &v1.ExecCommandParentOverride{ - CommandLine: overrideBuild, - Component: overrideComponent0, - LabeledCommandParentOverride: v1.LabeledCommandParentOverride{ - BaseCommandParentOverride: v1.BaseCommandParentOverride{ - Group: &v1.CommandGroupParentOverride{ - IsDefault: true, - Kind: v1.CommandGroupKindParentOverride(v1.BuildCommandGroupKind), - }, - }, - }, - WorkingDir: overrideWorkingDir, - }, - }, - }, - }, - }, - wantDevFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v2.DevfileV2{ - Devfile: v1.Devfile{ - DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ - DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ - Commands: []v1.Command{ - { - Id: "devbuild", - CommandUnion: v1.CommandUnion{ - Exec: &v1.ExecCommand{ - CommandLine: overrideBuild, - Component: overrideComponent0, - LabeledCommand: v1.LabeledCommand{ - BaseCommand: v1.BaseCommand{ - Group: &v1.CommandGroup{ - IsDefault: true, - Kind: v1.BuildCommandGroupKind, - }, - }, - }, - WorkingDir: overrideWorkingDir, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - { - name: "case 2: append/override a command's list fields based on the key", - devFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v2.DevfileV2{ - Devfile: v1.Devfile{ - DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ - DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ - Commands: []v1.Command{ - { - Id: "devbuild", - CommandUnion: v1.CommandUnion{ - Exec: &v1.ExecCommand{ - LabeledCommand: v1.LabeledCommand{ - BaseCommand: v1.BaseCommand{ - Attributes: map[string]string{ - "key-0": "value-0", - }, - }, - }, - Env: []v1.EnvVar{ - testingutil.GetFakeEnv("env-0", "value-0"), - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - args: args{ - overridePatch: []v1.CommandParentOverride{ - { - Id: "devbuild", - CommandUnionParentOverride: v1.CommandUnionParentOverride{ - Exec: &v1.ExecCommandParentOverride{ - LabeledCommandParentOverride: v1.LabeledCommandParentOverride{ - BaseCommandParentOverride: v1.BaseCommandParentOverride{ - Attributes: map[string]string{ - "key-1": "value-1", - }, - }, - }, - Env: []v1.EnvVarParentOverride{ - testingutil.GetFakeEnvParentOverride("env-0", "value-0-0"), - testingutil.GetFakeEnvParentOverride("env-1", "value-1"), - }, - }, - }, - }, - }, - }, - wantDevFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v2.DevfileV2{ - Devfile: v1.Devfile{ - DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ - DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ - Commands: []v1.Command{ - { - Id: "devbuild", - CommandUnion: v1.CommandUnion{ - Exec: &v1.ExecCommand{ - LabeledCommand: v1.LabeledCommand{ - BaseCommand: v1.BaseCommand{ - Attributes: map[string]string{ - "key-0": "value-0", - "key-1": "value-1", - }, - }, - }, - Env: []v1.EnvVar{ - testingutil.GetFakeEnv("env-0", "value-0-0"), - testingutil.GetFakeEnv("env-1", "value-1"), - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - { - name: "case 3: if multiple, override the correct command", - devFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v2.DevfileV2{ - Devfile: v1.Devfile{ - DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ - DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ - Commands: []v1.Command{ - { - Id: "devbuild", - CommandUnion: v1.CommandUnion{ - Exec: &v1.ExecCommand{ - CommandLine: commandLineBuild, - }, - }, - }, - { - Id: "devrun", - CommandUnion: v1.CommandUnion{ - Exec: &v1.ExecCommand{ - CommandLine: commandLineRun, - }, - }, - }, - }, - }, - }, - }, - }, - }, - args: args{ - overridePatch: []v1.CommandParentOverride{ - { - Id: "devbuild", - CommandUnionParentOverride: v1.CommandUnionParentOverride{ - Exec: &v1.ExecCommandParentOverride{ - CommandLine: overrideBuild, - }, - }, - }, - }, - }, - wantDevFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v2.DevfileV2{ - Devfile: v1.Devfile{ - DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ - DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ - Commands: []v1.Command{ - { - Id: "devbuild", - CommandUnion: v1.CommandUnion{ - Exec: &v1.ExecCommand{ - CommandLine: overrideBuild, - }, - }, - }, - { - Id: "devrun", - CommandUnion: v1.CommandUnion{ - Exec: &v1.ExecCommand{ - CommandLine: commandLineRun, - }, - }, - }, - }, - }, - }, - }, - }, - }, - wantErr: false, - }, - { - name: "case 4: throw error if command to override is not found", - devFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v2.DevfileV2{ - Devfile: v1.Devfile{ - DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ - DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ - Commands: []v1.Command{ - { - Id: "devbuild", - CommandUnion: v1.CommandUnion{ - Exec: &v1.ExecCommand{ - Env: []v1.EnvVar{ - testingutil.GetFakeEnv("env-0", "value-0"), - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - args: args{ - overridePatch: []v1.CommandParentOverride{ - { - Id: "devbuild-custom", - CommandUnionParentOverride: v1.CommandUnionParentOverride{ - Exec: &v1.ExecCommandParentOverride{ - Env: []v1.EnvVarParentOverride{ - testingutil.GetFakeEnvParentOverride("env-0", "value-0-0"), - testingutil.GetFakeEnvParentOverride("env-1", "value-1"), - }, - }, - }, - }, - }, - }, - wantDevFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v2.DevfileV2{ - Devfile: v1.Devfile{ - DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ - DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ - Commands: []v1.Command{}, - }, - }, - }, - }, - }, - wantErr: true, - }, - { - name: "case 5: override a composite command", - devFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v2.DevfileV2{ - Devfile: v1.Devfile{ - DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ - DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ - Commands: []v1.Command{ - { - Id: "exec1", - CommandUnion: v1.CommandUnion{ - Exec: &v1.ExecCommand{ - CommandLine: commandLineBuild, - }, - }, - }, - { - Id: "exec2", - CommandUnion: v1.CommandUnion{ - Exec: &v1.ExecCommand{ - CommandLine: commandLineBuild, - }, - }, - }, - { - Id: "exec3", - CommandUnion: v1.CommandUnion{ - Exec: &v1.ExecCommand{ - CommandLine: commandLineBuild, - }, - }, - }, - { - Id: "mycomposite", - CommandUnion: v1.CommandUnion{ - Composite: &v1.CompositeCommand{ - Commands: []string{"exec1", "exec2"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - args: args{ - overridePatch: []v1.CommandParentOverride{ - { - Id: "mycomposite", - CommandUnionParentOverride: v1.CommandUnionParentOverride{ - Composite: &v1.CompositeCommandParentOverride{ - Commands: []string{"exec1", "exec3"}, - }, - }, - }, - }, - }, - wantDevFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v2.DevfileV2{ - Devfile: v1.Devfile{ - DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ - DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ - Commands: []v1.Command{ - { - Id: "exec1", - CommandUnion: v1.CommandUnion{ - Exec: &v1.ExecCommand{ - CommandLine: commandLineBuild, - }, - }, - }, - { - Id: "exec2", - CommandUnion: v1.CommandUnion{ - Exec: &v1.ExecCommand{ - CommandLine: commandLineBuild, - }, - }, - }, - { - Id: "exec3", - CommandUnion: v1.CommandUnion{ - Exec: &v1.ExecCommand{ - CommandLine: commandLineBuild, - }, - }, - }, - { - Id: "mycomposite", - CommandUnion: v1.CommandUnion{ - Composite: &v1.CompositeCommand{ - Commands: []string{"exec1", "exec3"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - { - name: "case 6: throw error if trying to overide command with different type", - devFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v2.DevfileV2{ - Devfile: v1.Devfile{ - DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ - DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ - Commands: []v1.Command{ - { - Id: "devbuild", - CommandUnion: v1.CommandUnion{ - Exec: &v1.ExecCommand{ - Env: []v1.EnvVar{ - testingutil.GetFakeEnv("env-0", "value-0-0"), - }, - CommandLine: commandLineBuild, - }, - }, - }, - }, - }, - }, - }, - }, - }, - args: args{ - overridePatch: []v1.CommandParentOverride{ - { - Id: "devbuild", - CommandUnionParentOverride: v1.CommandUnionParentOverride{ - Composite: &v1.CompositeCommandParentOverride{}, - }, - }, - }, - }, - wantDevFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v2.DevfileV2{ - Devfile: v1.Devfile{ - DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ - DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ - Commands: []v1.Command{}, - }, - }, - }, - }, - }, - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - err := tt.devFileObj.OverrideCommands(tt.args.overridePatch) - - if (err != nil) != tt.wantErr { - t.Errorf("OverrideCommands() error = %v, wantErr %v", err, tt.wantErr) - return - } - - if tt.wantErr && err != nil { - return - } - - if !reflect.DeepEqual(tt.wantDevFileObj, tt.devFileObj) { - t.Errorf("expected devfile and got devfile are different: %v", pretty.Compare(tt.wantDevFileObj, tt.devFileObj)) - } - }) - } -} - -func TestDevfileObj_OverrideComponents(t *testing.T) { - - containerImage0 := "image-0" - containerImage1 := "image-1" - - overrideContainerImage := "image-0-override" - MountSources := false - overrideMountSources := true - - type args struct { - overridePatch []v1.ComponentParentOverride - } - tests := []struct { - name string - devFileObj DevfileObj - args args - wantDevFileObj DevfileObj - wantErr bool - }{ - { - name: "case 1: override a container's non list/map fields", - devFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v2.DevfileV2{ - Devfile: v1.Devfile{ - DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ - DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ - Components: []v1.Component{ - { - Name: "nodejs", - ComponentUnion: v1.ComponentUnion{ - Container: &v1.ContainerComponent{ - Container: v1.Container{ - Args: []string{"arg-0", "arg-1"}, - Command: []string{"cmd-0", "cmd-1"}, - Image: containerImage0, - MemoryLimit: "512Mi", - MountSources: &MountSources, - SourceMapping: "/source", - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - args: args{ - overridePatch: []v1.ComponentParentOverride{ - { - Name: "nodejs", - ComponentUnionParentOverride: v1.ComponentUnionParentOverride{ - Container: &v1.ContainerComponentParentOverride{ - ContainerParentOverride: v1.ContainerParentOverride{ - Args: []string{"arg-0-0", "arg-1-1"}, - Command: []string{"cmd-0-0", "cmd-1-1"}, - MemoryLimit: "1Gi", - Image: overrideContainerImage, - MountSources: &overrideMountSources, - SourceMapping: "/data", - }, - }, - }, - }, - }, - }, - wantDevFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v2.DevfileV2{ - Devfile: v1.Devfile{ - DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ - DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ - Components: []v1.Component{ - { - Name: "nodejs", - ComponentUnion: v1.ComponentUnion{ - Container: &v1.ContainerComponent{ - Container: v1.Container{ - Args: []string{"arg-0-0", "arg-1-1"}, - Command: []string{"cmd-0-0", "cmd-1-1"}, - Image: overrideContainerImage, - MemoryLimit: "1Gi", - MountSources: &overrideMountSources, - SourceMapping: "/data", - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - wantErr: false, - }, - { - name: "case 2: append/override a command's list fields based on the key", - devFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v2.DevfileV2{ - Devfile: v1.Devfile{ - DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ - DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ - Components: []v1.Component{ - { - Name: "nodejs", - ComponentUnion: v1.ComponentUnion{ - Container: &v1.ContainerComponent{ - Endpoints: []v1.Endpoint{ - { - Attributes: map[string]string{ - "key-0": "value-0", - "key-1": "value-1", - }, - Name: "endpoint-0", - TargetPort: 8080, - }, - }, - Container: v1.Container{ - Env: []v1.EnvVar{ - testingutil.GetFakeEnv("env-0", "value-0"), - }, - VolumeMounts: []v1.VolumeMount{ - testingutil.GetFakeVolumeMount("volume-0", "path-0"), - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - args: args{ - overridePatch: []v1.ComponentParentOverride{ - { - Name: "nodejs", - ComponentUnionParentOverride: v1.ComponentUnionParentOverride{ - Container: &v1.ContainerComponentParentOverride{ - Endpoints: []v1.EndpointParentOverride{ - { - Attributes: map[string]string{ - "key-1": "value-1-1", - "key-append": "value-append", - }, - Name: "endpoint-0", - TargetPort: 9090, - }, - { - Attributes: map[string]string{ - "key-0": "value-0", - }, - Name: "endpoint-1", - TargetPort: 3000, - }, - }, - ContainerParentOverride: v1.ContainerParentOverride{ - Env: []v1.EnvVarParentOverride{ - testingutil.GetFakeEnvParentOverride("env-0", "value-0-0"), - testingutil.GetFakeEnvParentOverride("env-1", "value-1"), - }, - VolumeMounts: []v1.VolumeMountParentOverride{ - testingutil.GetFakeVolumeMountParentOverride("volume-0", "path-0-0"), - testingutil.GetFakeVolumeMountParentOverride("volume-1", "path-1"), - }, - }, - }, - }, - }, - }, - }, - wantDevFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v2.DevfileV2{ - Devfile: v1.Devfile{ - DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ - DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ - Components: []v1.Component{ - { - Name: "nodejs", - ComponentUnion: v1.ComponentUnion{ - Container: &v1.ContainerComponent{ - Container: v1.Container{ - Env: []v1.EnvVar{ - testingutil.GetFakeEnv("env-0", "value-0-0"), - testingutil.GetFakeEnv("env-1", "value-1"), - }, - VolumeMounts: []v1.VolumeMount{ - testingutil.GetFakeVolumeMount("volume-0", "path-0-0"), - testingutil.GetFakeVolumeMount("volume-1", "path-1"), - }, - }, - Endpoints: []v1.Endpoint{ - { - Attributes: map[string]string{ - "key-0": "value-0", - "key-1": "value-1-1", - "key-append": "value-append", - }, - Name: "endpoint-0", - TargetPort: 9090, - }, - { - Attributes: map[string]string{ - "key-0": "value-0", - }, - Name: "endpoint-1", - TargetPort: 3000, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - wantErr: false, - }, - { - name: "case 3: if multiple, override the correct command", - devFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v2.DevfileV2{ - Devfile: v1.Devfile{ - DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ - DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ - Components: []v1.Component{ - { - Name: "nodejs", - ComponentUnion: v1.ComponentUnion{ - Container: &v1.ContainerComponent{ - Container: v1.Container{ - Image: containerImage0, - }, - }, - }, - }, - { - Name: "runtime", - ComponentUnion: v1.ComponentUnion{ - Container: &v1.ContainerComponent{ - Container: v1.Container{ - Image: containerImage1, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - args: args{ - overridePatch: []v1.ComponentParentOverride{ - { - Name: "nodejs", - ComponentUnionParentOverride: v1.ComponentUnionParentOverride{ - Container: &v1.ContainerComponentParentOverride{ - ContainerParentOverride: v1.ContainerParentOverride{ - Image: overrideContainerImage, - }, - }, - }, - }, - { - Name: "runtime", - ComponentUnionParentOverride: v1.ComponentUnionParentOverride{ - Container: &v1.ContainerComponentParentOverride{ - ContainerParentOverride: v1.ContainerParentOverride{ - Image: containerImage1, - }, - }, - }, - }, - }, - }, - wantDevFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v2.DevfileV2{ - Devfile: v1.Devfile{ - DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ - DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ - Components: []v1.Component{ - { - Name: "nodejs", - ComponentUnion: v1.ComponentUnion{ - Container: &v1.ContainerComponent{ - Container: v1.Container{ - Image: overrideContainerImage, - }, - }, - }, - }, - { - Name: "runtime", - ComponentUnion: v1.ComponentUnion{ - Container: &v1.ContainerComponent{ - Container: v1.Container{ - Image: containerImage1, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - wantErr: false, - }, - { - name: "case 4: throw error if component to override is not found", - devFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v2.DevfileV2{ - Devfile: v1.Devfile{ - DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ - DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ - Components: []v1.Component{ - { - Name: "nodejs", - ComponentUnion: v1.ComponentUnion{ - Container: &v1.ContainerComponent{ - Container: v1.Container{ - Image: containerImage0, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - args: args{ - overridePatch: []v1.ComponentParentOverride{ - { - Name: "nodejs-custom", - ComponentUnionParentOverride: v1.ComponentUnionParentOverride{ - Container: &v1.ContainerComponentParentOverride{ - ContainerParentOverride: v1.ContainerParentOverride{ - Image: containerImage0, - }, - }, - }, - }, - }, - }, - wantDevFileObj: DevfileObj{}, - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - err := tt.devFileObj.OverrideComponents(tt.args.overridePatch) - if (err != nil) != tt.wantErr { - t.Errorf("OverrideComponents() error = %v, wantErr %v", err, tt.wantErr) - } - - if tt.wantErr && err != nil { - return - } - - if !reflect.DeepEqual(tt.wantDevFileObj, tt.devFileObj) { - t.Errorf("expected devfile and got devfile are different: %v", pretty.Compare(tt.wantDevFileObj, tt.devFileObj)) - } - }) - } -} - -func TestDevfileObj_OverrideProjects(t *testing.T) { - projectName0 := "project-0" - projectName1 := "project-1" - - type args struct { - overridePatch []v1.ProjectParentOverride - } - tests := []struct { - name string - devFileObj DevfileObj - wantDevFileObj DevfileObj - args args - wantErr bool - }{ - { - name: "case 1: override a project's fields", - devFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v2.DevfileV2{ - Devfile: v1.Devfile{ - DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ - DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ - Projects: []v1.Project{ - { - ClonePath: "/data", - ProjectSource: v1.ProjectSource{ - Github: &v1.GithubProjectSource{ - GitLikeProjectSource: v1.GitLikeProjectSource{ - CheckoutFrom: &v1.CheckoutFrom{ - Revision: "master", - }, - }, - }, - Zip: nil, - }, - Name: projectName0, - }, - }, - }, - }, - }, - }, - }, - args: args{ - overridePatch: []v1.ProjectParentOverride{ - { - ClonePath: "/source", - ProjectSourceParentOverride: v1.ProjectSourceParentOverride{ - Github: &v1.GithubProjectSourceParentOverride{ - GitLikeProjectSourceParentOverride: v1.GitLikeProjectSourceParentOverride{ - CheckoutFrom: &v1.CheckoutFromParentOverride{ - Revision: "release-1.0.0", - }, - }, - }, - Zip: nil, - }, - Name: projectName0, - }, - }, - }, - wantDevFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v2.DevfileV2{ - Devfile: v1.Devfile{ - DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ - DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ - Projects: []v1.Project{ - { - ClonePath: "/source", - ProjectSource: v1.ProjectSource{ - Github: &v1.GithubProjectSource{ - GitLikeProjectSource: v1.GitLikeProjectSource{ - CheckoutFrom: &v1.CheckoutFrom{ - Revision: "release-1.0.0", - }, - }, - }, - Zip: nil, - }, - Name: projectName0, - }, - }, - }, - }, - }, - }, - }, - }, - { - name: "case 2: if multiple, override the correct project", - devFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v2.DevfileV2{ - Devfile: v1.Devfile{ - DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ - DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ - Projects: []v1.Project{ - { - ClonePath: "/data", - ProjectSource: v1.ProjectSource{ - Github: &v1.GithubProjectSource{ - GitLikeProjectSource: v1.GitLikeProjectSource{ - CheckoutFrom: &v1.CheckoutFrom{ - Revision: "master", - }, - }, - }, - Zip: nil, - }, - Name: projectName0, - }, - { - ProjectSource: v1.ProjectSource{ - Github: &v1.GithubProjectSource{ - GitLikeProjectSource: v1.GitLikeProjectSource{ - CheckoutFrom: &v1.CheckoutFrom{ - Revision: "master", - }, - }, - }, - }, - Name: projectName1, - }, - }, - }, - }, - }, - }, - }, - args: args{ - overridePatch: []v1.ProjectParentOverride{ - { - ClonePath: "/source", - ProjectSourceParentOverride: v1.ProjectSourceParentOverride{ - Github: &v1.GithubProjectSourceParentOverride{ - GitLikeProjectSourceParentOverride: v1.GitLikeProjectSourceParentOverride{ - CheckoutFrom: &v1.CheckoutFromParentOverride{ - Revision: "release-1.0.0", - }, - }, - }, - Zip: nil, - }, - Name: projectName0, - }, - }, - }, - wantDevFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v2.DevfileV2{ - Devfile: v1.Devfile{ - DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ - DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ - Projects: []v1.Project{ - { - ClonePath: "/source", - ProjectSource: v1.ProjectSource{ - Github: &v1.GithubProjectSource{ - GitLikeProjectSource: v1.GitLikeProjectSource{ - CheckoutFrom: &v1.CheckoutFrom{ - Revision: "release-1.0.0", - }, - }, - }, - Zip: nil, - }, - Name: projectName0, - }, - { - ProjectSource: v1.ProjectSource{ - Github: &v1.GithubProjectSource{ - GitLikeProjectSource: v1.GitLikeProjectSource{ - CheckoutFrom: &v1.CheckoutFrom{ - Revision: "master", - }, - }, - }, - }, - Name: projectName1, - }, - }, - }, - }, - }, - }, - }, - }, - { - name: "case 3: throw error if project to override is not found", - devFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v2.DevfileV2{ - Devfile: v1.Devfile{ - DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ - DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ - Projects: []v1.Project{ - { - ClonePath: "/data", - ProjectSource: v1.ProjectSource{ - Github: &v1.GithubProjectSource{ - GitLikeProjectSource: v1.GitLikeProjectSource{ - CheckoutFrom: &v1.CheckoutFrom{ - Revision: "master", - }, - }, - }, - Zip: nil, - }, - Name: projectName0, - }, - }, - }, - }, - }, - }, - }, - args: args{ - overridePatch: []v1.ProjectParentOverride{ - { - ClonePath: "/source", - ProjectSourceParentOverride: v1.ProjectSourceParentOverride{ - Github: &v1.GithubProjectSourceParentOverride{ - GitLikeProjectSourceParentOverride: v1.GitLikeProjectSourceParentOverride{ - CheckoutFrom: &v1.CheckoutFromParentOverride{ - Revision: "release-1.0.0", - }, - }, - }, - Zip: nil, - }, - Name: "custom-project", - }, - }, - }, - wantDevFileObj: DevfileObj{}, - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - err := tt.devFileObj.OverrideProjects(tt.args.overridePatch) - - if (err != nil) != tt.wantErr { - t.Errorf("OverrideProjects() error = %v, wantErr %v", err, tt.wantErr) - return - } - - if tt.wantErr && err != nil { - return - } - - if !reflect.DeepEqual(tt.wantDevFileObj, tt.devFileObj) { - t.Errorf("expected devfile and got devfile are different: %v", pretty.Compare(tt.wantDevFileObj, tt.devFileObj)) - } - }) - } -} - -func TestDevfileObj_OverrideStarterProjects(t *testing.T) { - projectName1 := "starter-1" - projectName2 := "starter-2" - - type args struct { - overridePatch []v1.StarterProjectParentOverride - } - tests := []struct { - name string - devFileObj DevfileObj - wantDevFileObj DevfileObj - args args - wantErr bool - }{ - { - name: "Case 1: override a starter projects fields", - devFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v2.DevfileV2{ - Devfile: v1.Devfile{ - DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ - DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ - StarterProjects: []v1.StarterProject{ - { - Name: projectName1, - SubDir: "/data", - ProjectSource: v1.ProjectSource{ - Github: &v1.GithubProjectSource{ - GitLikeProjectSource: v1.GitLikeProjectSource{ - Remotes: map[string]string{"origin": "url"}, - CheckoutFrom: &v1.CheckoutFrom{Revision: "master"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - args: args{ - overridePatch: []v1.StarterProjectParentOverride{ - { - Name: projectName1, - SubDir: "/source", - ProjectSourceParentOverride: v1.ProjectSourceParentOverride{ - Github: &v1.GithubProjectSourceParentOverride{ - GitLikeProjectSourceParentOverride: v1.GitLikeProjectSourceParentOverride{ - Remotes: map[string]string{"origin": "url"}, - CheckoutFrom: &v1.CheckoutFromParentOverride{Revision: "release-1.0.0"}, - }, - }, - Zip: nil, - }, - }, - }, - }, - wantDevFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v2.DevfileV2{ - Devfile: v1.Devfile{ - DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ - DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ - StarterProjects: []v1.StarterProject{ - { - Name: projectName1, - SubDir: "/source", - ProjectSource: v1.ProjectSource{ - Github: &v1.GithubProjectSource{ - GitLikeProjectSource: v1.GitLikeProjectSource{ - Remotes: map[string]string{"origin": "url"}, - CheckoutFrom: &v1.CheckoutFrom{Revision: "release-1.0.0"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - { - name: "Case 2: if multiple, override the correct starter project", - devFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v2.DevfileV2{ - Devfile: v1.Devfile{ - DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ - DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ - StarterProjects: []v1.StarterProject{ - { - Name: projectName1, - SubDir: "/data", - ProjectSource: v1.ProjectSource{ - Github: &v1.GithubProjectSource{ - GitLikeProjectSource: v1.GitLikeProjectSource{ - Remotes: map[string]string{"origin": "url"}, - CheckoutFrom: &v1.CheckoutFrom{Revision: "master"}, - }, - }, - }, - }, - { - Name: projectName2, - ProjectSource: v1.ProjectSource{ - Github: &v1.GithubProjectSource{ - GitLikeProjectSource: v1.GitLikeProjectSource{ - Remotes: map[string]string{"origin": "url"}, - CheckoutFrom: &v1.CheckoutFrom{Revision: "master"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - args: args{ - overridePatch: []v1.StarterProjectParentOverride{ - { - Name: projectName1, - SubDir: "/source", - ProjectSourceParentOverride: v1.ProjectSourceParentOverride{ - Github: &v1.GithubProjectSourceParentOverride{ - GitLikeProjectSourceParentOverride: v1.GitLikeProjectSourceParentOverride{ - Remotes: map[string]string{"origin": "url"}, - CheckoutFrom: &v1.CheckoutFromParentOverride{Revision: "release-1.0.0"}, - }, - }, - }, - }, - }, - }, - wantDevFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v2.DevfileV2{ - Devfile: v1.Devfile{ - DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ - DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ - StarterProjects: []v1.StarterProject{ - { - Name: projectName1, - SubDir: "/source", - ProjectSource: v1.ProjectSource{ - Github: &v1.GithubProjectSource{ - GitLikeProjectSource: v1.GitLikeProjectSource{ - Remotes: map[string]string{"origin": "url"}, - CheckoutFrom: &v1.CheckoutFrom{Revision: "release-1.0.0"}, - }, - }, - }, - }, - { - Name: projectName2, - ProjectSource: v1.ProjectSource{ - Github: &v1.GithubProjectSource{ - GitLikeProjectSource: v1.GitLikeProjectSource{ - Remotes: map[string]string{"origin": "url"}, - CheckoutFrom: &v1.CheckoutFrom{Revision: "master"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - { - name: "Case 3: throw error if starter project to override is not found", - devFileObj: DevfileObj{ - Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), - Data: &v2.DevfileV2{ - Devfile: v1.Devfile{ - DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ - DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ - StarterProjects: []v1.StarterProject{ - { - Name: projectName1, - SubDir: "/data", - ProjectSource: v1.ProjectSource{ - Github: &v1.GithubProjectSource{ - GitLikeProjectSource: v1.GitLikeProjectSource{ - Remotes: map[string]string{"origin": "url"}, - CheckoutFrom: &v1.CheckoutFrom{Revision: "master"}, - }, - }, - Zip: nil, - }, - }, - }, - }, - }, - }, - }, - }, - args: args{ - overridePatch: []v1.StarterProjectParentOverride{ - { - Name: "custom-starter-project", - SubDir: "/source", - ProjectSourceParentOverride: v1.ProjectSourceParentOverride{ - Github: &v1.GithubProjectSourceParentOverride{ - GitLikeProjectSourceParentOverride: v1.GitLikeProjectSourceParentOverride{ - Remotes: map[string]string{"origin": "url"}, - CheckoutFrom: &v1.CheckoutFromParentOverride{Revision: "release-1.0.0"}, - }, - }, - Zip: nil, - }, - }, - }, - }, - wantDevFileObj: DevfileObj{}, - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - err := tt.devFileObj.OverrideStarterProjects(tt.args.overridePatch) - - if (err != nil) != tt.wantErr { - t.Errorf("OverrideStarterProjects() error = %v, wantErr %v", err, tt.wantErr) - return - } - - if tt.wantErr && err != nil { - return - } - - if !reflect.DeepEqual(tt.wantDevFileObj, tt.devFileObj) { - t.Errorf("expected devfile and got devfile are different: %v", pretty.Compare(tt.wantDevFileObj, tt.devFileObj)) - } - }) - } -} diff --git a/pkg/devfile/parser/parse.go b/pkg/devfile/parser/parse.go index dcf1fed5..f89ea87b 100644 --- a/pkg/devfile/parser/parse.go +++ b/pkg/devfile/parser/parse.go @@ -2,8 +2,6 @@ package parser import ( "encoding/json" - "fmt" - "strings" devfileCtx "github.com/devfile/library/pkg/devfile/parser/context" "github.com/devfile/library/pkg/devfile/parser/data" @@ -47,6 +45,11 @@ func parseDevfile(d DevfileObj) (DevfileObj, error) { } } + err = parsePlugin(d) + if err != nil { + return DevfileObj{}, err + } + // Successful return d, nil } @@ -109,39 +112,8 @@ func parseParent(d DevfileObj) error { return err } - for _, command := range result.Commands { - fmt.Println(">>> API command is " + command.Id) - if command.Id == "buildAndMkdir" { - fmt.Println("API composite commands: " + strings.Join(command.Composite.Commands, " ")) - } - } - parentData.Data.SetDevfileWorkspace(*result) - // // fmt.Println("parent Data", parentData) - // klog.V(4).Infof("overriding data of devfile with URI: %v", parent.Uri) - - // // override the parent's components, commands, projects and events - // err = parentData.OverrideComponents(d.Data.GetParent().Components) - // if err != nil { - // return err - // } - - // err = parentData.OverrideCommands(d.Data.GetParent().Commands) - // if err != nil { - // return err - // } - - // err = parentData.OverrideProjects(d.Data.GetParent().Projects) - // if err != nil { - // return err - // } - - // err = parentData.OverrideStarterProjects(d.Data.GetParent().StarterProjects) - // if err != nil { - // return err - // } - klog.V(4).Infof("adding data of devfile with URI: %v", parent.Uri) // since the parent's data has been overriden @@ -178,3 +150,53 @@ func parseParent(d DevfileObj) error { } return nil } + +func parsePlugin(d DevfileObj) (err error) { + + for _, component := range d.Data.GetComponents() { + if component.Plugin != nil && !reflect.DeepEqual(component.Plugin, &v1.PluginComponent{}) { + plugin := component.Plugin + var pluginData DevfileObj + if plugin.Uri != "" { + pluginData, err = ParseFromURL(plugin.Uri) + if err != nil { + return err + } + } + pluginWorkspaceContent := pluginData.Data.GetDevfileWorkspace() + result, err := apiOverride.OverrideDevWorkspaceTemplateSpec(pluginWorkspaceContent, plugin) + if err != nil { + return err + } + pluginData.Data.SetDevfileWorkspace(*result) + klog.V(4).Infof("adding data of devfile with URI: %v", plugin.Uri) + // since the plugin's data has been overriden + // add the items back to the current devfile + // error indicates that the item has been defined again in the current devfile + commandsMap := pluginData.Data.GetCommands() + commands := make([]v1.Command, 0, len(commandsMap)) + for _, command := range commandsMap { + commands = append(commands, command) + } + + // plugin component contributes components, commands and events + err = d.Data.AddCommands(commands...) + if err != nil { + return errors.Wrapf(err, "error while adding commands from the plugin devfiles") + } + + err = d.Data.AddComponents(pluginData.Data.GetComponents()) + if err != nil { + return errors.Wrapf(err, "error while adding components from the plugin devfiles") + } + + err = d.Data.AddEvents(pluginData.Data.GetEvents()) + if err != nil { + return errors.Wrapf(err, "error while adding events from the plugin devfiles") + } + return nil + } + } + return nil + +} diff --git a/pkg/devfile/parser/writer.go b/pkg/devfile/parser/writer.go index e583b774..a98ceca7 100644 --- a/pkg/devfile/parser/writer.go +++ b/pkg/devfile/parser/writer.go @@ -5,6 +5,7 @@ import ( "sigs.k8s.io/yaml" + "github.com/devfile/library/pkg/testingutil/filesystem" "github.com/pkg/errors" "k8s.io/klog" ) @@ -38,9 +39,11 @@ func (d *DevfileObj) WriteYamlDevfile() error { if err != nil { return errors.Wrapf(err, "failed to marshal devfile object into yaml") } - // Write to devfile.yaml fs := d.Ctx.GetFs() + if fs == nil { + fs = filesystem.DefaultFs{} + } err = fs.WriteFile(d.Ctx.GetAbsPath(), yamlData, 0644) if err != nil { return errors.Wrapf(err, "failed to create devfile yaml file") From 0fa0338a0d180f0e057899f4acf7a3b7538a35b0 Mon Sep 17 00:00:00 2001 From: Stephanie Date: Thu, 10 Dec 2020 21:38:04 -0500 Subject: [PATCH 04/13] parse flatterned devfile and raw devfile Signed-off-by: Stephanie --- go.mod | 1 + go.sum | 6 + pkg/devfile/parser/data/v2/components.go | 12 + pkg/devfile/parser/parse.go | 156 +-- pkg/devfile/parser/parse_test.go | 1279 ++++++++++++++++++++-- 5 files changed, 1277 insertions(+), 177 deletions(-) diff --git a/go.mod b/go.mod index 86679275..3571b183 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( github.com/devfile/api v0.0.0-20201103130402-29b8738e196e github.com/fatih/color v1.7.0 github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 + github.com/go-test/deep v1.0.7 github.com/gobwas/glob v0.2.3 github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 diff --git a/go.sum b/go.sum index c4ad3ca9..40a5ba6d 100644 --- a/go.sum +++ b/go.sum @@ -48,6 +48,10 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/devfile/api v0.0.0-20201103130402-29b8738e196e h1:Ha6wyKs7VWqQTz2Fm1o4PAYpKX6SIiYjgWmGzNW8cBE= github.com/devfile/api v0.0.0-20201103130402-29b8738e196e/go.mod h1:hp5Lmob7ESmtSZXZ7xRN9o8vemsen9111+ASi2YuXs4= +github.com/devfile/api v0.0.0-20201126204309-ec222215253e h1:NO6mS8ktVFjkVIKZKF2JjfL3ZxXw4VAtKIZWyp9e2kQ= +github.com/devfile/api v0.0.0-20201207181959-9c86a407ff76 h1:zXpN4o1q3+GJvmErCjsrv7DajFf2zAT8B1fc6K0bKHQ= +github.com/devfile/api v0.0.0-20201208170158-4312e2a2642f h1:XDOQzW4WpBE+dXH7I7AnOheSjc6hHBipQn9whGDglaM= +github.com/devfile/api v0.0.0-20201210141610-fb248c2367ba h1:+LpXC7ebW+H4fjQNCzjcR2FKrma2OsbMLn6Q7KLbO1I= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= @@ -122,6 +126,8 @@ github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+ github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.0.7 h1:/VSMRlnY/JSyqxQUzQLKVMAskpY/NZKFA5j2P+0pP2M= +github.com/go-test/deep v1.0.7/go.mod h1:QV8Hv/iy04NyLBxAdO9njL0iVPN1S4d/A3NVv1V36o8= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= diff --git a/pkg/devfile/parser/data/v2/components.go b/pkg/devfile/parser/data/v2/components.go index 15cc6b59..79230b6d 100644 --- a/pkg/devfile/parser/data/v2/components.go +++ b/pkg/devfile/parser/data/v2/components.go @@ -18,6 +18,7 @@ func (d *DevfileV2) AddComponents(components []v1.Component) error { // can exist in devfile containerMap := make(map[string]bool) volumeMap := make(map[string]bool) + pluginMap := make(map[string]bool) for _, component := range d.Components { if component.Volume != nil { @@ -26,6 +27,9 @@ func (d *DevfileV2) AddComponents(components []v1.Component) error { if component.Container != nil { containerMap[component.Name] = true } + if component.Plugin != nil { + pluginMap[component.Name] = true + } } for _, component := range components { @@ -45,6 +49,14 @@ func (d *DevfileV2) AddComponents(components []v1.Component) error { return &common.FieldAlreadyExistError{Name: component.Name, Field: "component"} } } + + if component.Plugin != nil { + if _, ok := pluginMap[component.Name]; !ok { + d.Components = append(d.Components, component) + } else { + return &common.FieldAlreadyExistError{Name: component.Name, Field: "component"} + } + } } return nil } diff --git a/pkg/devfile/parser/parse.go b/pkg/devfile/parser/parse.go index f89ea87b..47d55dc5 100644 --- a/pkg/devfile/parser/parse.go +++ b/pkg/devfile/parser/parse.go @@ -16,7 +16,7 @@ import ( // ParseDevfile func validates the devfile integrity. // Creates devfile context and runtime objects -func parseDevfile(d DevfileObj) (DevfileObj, error) { +func parseDevfile(d DevfileObj, flattenedDevfile bool) (DevfileObj, error) { // Validate devfile err := d.Ctx.Validate() @@ -36,25 +36,18 @@ func parseDevfile(d DevfileObj) (DevfileObj, error) { return d, errors.Wrapf(err, "failed to decode devfile content") } - if d.Data.GetParent() != nil { - if !reflect.DeepEqual(d.Data.GetParent(), &v1.Parent{}) && d.Data.GetParent().Uri != "" { - err = parseParent(d) - if err != nil { - return DevfileObj{}, err - } + if flattenedDevfile { + err = parseParentAndPlugin(d) + if err != nil { + return DevfileObj{}, err } } - err = parsePlugin(d) - if err != nil { - return DevfileObj{}, err - } - // Successful return d, nil } -// Parse func populates the devfile data, parses and validates the devfile integrity. +// Parse func populates the flattened devfile data, parses and validates the devfile integrity. // Creates devfile context and runtime objects func Parse(path string) (d DevfileObj, err error) { @@ -66,7 +59,20 @@ func Parse(path string) (d DevfileObj, err error) { if err != nil { return d, err } - return parseDevfile(d) + return parseDevfile(d, true) +} + +// ParseRawDevfile populates the raw devfile data witout overring and merging +func ParseRawDevfile(path string) (d DevfileObj, err error) { + // NewDevfileCtx + d.Ctx = devfileCtx.NewDevfileCtx(path) + + // Fill the fields of DevfileCtx struct + err = d.Ctx.Populate() + if err != nil { + return d, err + } + return parseDevfile(d, false) } // ParseFromURL func parses and validates the devfile integrity. @@ -79,7 +85,7 @@ func ParseFromURL(url string) (d DevfileObj, err error) { if err != nil { return d, err } - return parseDevfile(d) + return parseDevfile(d, true) } // ParseFromData func parses and validates the devfile integrity. @@ -95,64 +101,34 @@ func ParseFromData(data []byte) (d DevfileObj, err error) { return d, err } - return parseDevfile(d) + return parseDevfile(d, true) } -func parseParent(d DevfileObj) error { - parent := d.Data.GetParent() - - parentData, err := ParseFromURL(parent.Uri) - if err != nil { - return err - } - - parentWorkspaceContent := parentData.Data.GetDevfileWorkspace() - result, err := apiOverride.OverrideDevWorkspaceTemplateSpec(parentWorkspaceContent, parent) - if err != nil { - return err - } - - parentData.Data.SetDevfileWorkspace(*result) - - klog.V(4).Infof("adding data of devfile with URI: %v", parent.Uri) - - // since the parent's data has been overriden - // add the items back to the current devfile - // error indicates that the item has been defined again in the current devfile - commandsMap := parentData.Data.GetCommands() - commands := make([]v1.Command, 0, len(commandsMap)) - for _, command := range commandsMap { - commands = append(commands, command) - } - err = d.Data.AddCommands(commands...) - if err != nil { - return errors.Wrapf(err, "error while adding commands from the parent devfiles") - } - - err = d.Data.AddComponents(parentData.Data.GetComponents()) - if err != nil { - return errors.Wrapf(err, "error while adding components from the parent devfiles") - } +func parseParentAndPlugin(d DevfileObj) (err error) { + flattenedParent := &v1.DevWorkspaceTemplateSpecContent{} + if d.Data.GetParent() != nil { + if !reflect.DeepEqual(d.Data.GetParent(), &v1.Parent{}) && d.Data.GetParent().Uri != "" { + parent := d.Data.GetParent() - err = d.Data.AddProjects(parentData.Data.GetProjects()) - if err != nil { - return errors.Wrapf(err, "error while adding projects from the parent devfiles") - } + parentData, err := ParseFromURL(parent.Uri) + if err != nil { + return err + } - err = d.Data.AddStarterProjects(parentData.Data.GetStarterProjects()) - if err != nil { - return errors.Wrapf(err, "error while adding starter projects from the parent devfiles") - } + parentWorkspaceContent := parentData.Data.GetDevfileWorkspace() + if !reflect.DeepEqual(parent.ParentOverrides, v1.ParentOverrides{}) { + flattenedParent, err = apiOverride.OverrideDevWorkspaceTemplateSpec(parentWorkspaceContent, parent.ParentOverrides) + if err != nil { + return err + } + } else { + flattenedParent = parentWorkspaceContent + } - err = d.Data.AddEvents(parentData.Data.GetEvents()) - if err != nil { - return errors.Wrapf(err, "error while adding events from the parent devfiles") + klog.V(4).Infof("adding data of devfile with URI: %v", parent.Uri) + } } - return nil -} - -func parsePlugin(d DevfileObj) (err error) { - + plugins := []*v1.DevWorkspaceTemplateSpecContent{} for _, component := range d.Data.GetComponents() { if component.Plugin != nil && !reflect.DeepEqual(component.Plugin, &v1.PluginComponent{}) { plugin := component.Plugin @@ -164,39 +140,23 @@ func parsePlugin(d DevfileObj) (err error) { } } pluginWorkspaceContent := pluginData.Data.GetDevfileWorkspace() - result, err := apiOverride.OverrideDevWorkspaceTemplateSpec(pluginWorkspaceContent, plugin) - if err != nil { - return err - } - pluginData.Data.SetDevfileWorkspace(*result) - klog.V(4).Infof("adding data of devfile with URI: %v", plugin.Uri) - // since the plugin's data has been overriden - // add the items back to the current devfile - // error indicates that the item has been defined again in the current devfile - commandsMap := pluginData.Data.GetCommands() - commands := make([]v1.Command, 0, len(commandsMap)) - for _, command := range commandsMap { - commands = append(commands, command) - } - - // plugin component contributes components, commands and events - err = d.Data.AddCommands(commands...) - if err != nil { - return errors.Wrapf(err, "error while adding commands from the plugin devfiles") - } - - err = d.Data.AddComponents(pluginData.Data.GetComponents()) - if err != nil { - return errors.Wrapf(err, "error while adding components from the plugin devfiles") - } - - err = d.Data.AddEvents(pluginData.Data.GetEvents()) - if err != nil { - return errors.Wrapf(err, "error while adding events from the plugin devfiles") + result := pluginWorkspaceContent + if !reflect.DeepEqual(plugin.PluginOverrides, v1.PluginOverrides{}) { + result, err = apiOverride.OverrideDevWorkspaceTemplateSpec(pluginWorkspaceContent, plugin.PluginOverrides) + if err != nil { + return err + } } - return nil + plugins = append(plugins, result) } } - return nil + mergedContent, err := apiOverride.MergeDevWorkspaceTemplateSpec(d.Data.GetDevfileWorkspace(), flattenedParent, plugins...) + if err != nil { + return err + } + d.Data.SetDevfileWorkspace(*mergedContent) + // remove parent from flatterned devfile + d.Data.SetParent(nil) + return nil } diff --git a/pkg/devfile/parser/parse_test.go b/pkg/devfile/parser/parse_test.go index 40432e05..92850f71 100644 --- a/pkg/devfile/parser/parse_test.go +++ b/pkg/devfile/parser/parse_test.go @@ -15,17 +15,20 @@ import ( ) const schemaV200 = "2.0.0" +const devfileTempPath = "devfile.yaml" -func Test_parseParent(t *testing.T) { +func Test_parseParentAndPlugin(t *testing.T) { type args struct { devFileObj DevfileObj } tests := []struct { - name string - args args - parentDevFile DevfileObj - wantDevFile DevfileObj - wantErr bool + name string + args args + parentDevfile DevfileObj + pluginDevfile DevfileObj + pluginOverride v1.PluginOverrides + wantDevFile DevfileObj + wantErr bool }{ { name: "case 1: it should override the requested parent's data and add the local devfile's data", @@ -107,7 +110,7 @@ func Test_parseParent(t *testing.T) { }, }, }, - parentDevFile: DevfileObj{ + parentDevfile: DevfileObj{ Data: &v2.DevfileV2{ Devfile: v1.Devfile{ DevfileHeader: devfilepkg.DevfileHeader{ @@ -170,26 +173,26 @@ func Test_parseParent(t *testing.T) { DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ Commands: []v1.Command{ { - Id: "devbuild", + Id: "devrun", CommandUnion: v1.CommandUnion{ Exec: &v1.ExecCommand{ - WorkingDir: "/projects/nodejs-starter", + CommandLine: "npm run", + WorkingDir: "/projects/nodejs-starter", }, }, }, { - Id: "devrun", + Id: "devbuild", CommandUnion: v1.CommandUnion{ Exec: &v1.ExecCommand{ - CommandLine: "npm run", - WorkingDir: "/projects/nodejs-starter", + WorkingDir: "/projects/nodejs-starter", }, }, }, }, Components: []v1.Component{ { - Name: "runtime", + Name: "nodejs", ComponentUnion: v1.ComponentUnion{ Container: &v1.ContainerComponent{ Container: v1.Container{ @@ -199,7 +202,7 @@ func Test_parseParent(t *testing.T) { }, }, { - Name: "nodejs", + Name: "runtime", ComponentUnion: v1.ComponentUnion{ Container: &v1.ContainerComponent{ Container: v1.Container{ @@ -213,13 +216,11 @@ func Test_parseParent(t *testing.T) { WorkspaceEvents: v1.WorkspaceEvents{ PostStart: []string{"post-start-0"}, PostStop: []string{"post-stop"}, + PreStop: []string{}, + PreStart: []string{}, }, }, Projects: []v1.Project{ - { - ClonePath: "/projects", - Name: "nodejs-starter-build", - }, { ClonePath: "/projects", ProjectSource: v1.ProjectSource{ @@ -233,6 +234,10 @@ func Test_parseParent(t *testing.T) { }, Name: "nodejs-starter", }, + { + ClonePath: "/projects", + Name: "nodejs-starter-build", + }, }, }, }, @@ -288,7 +293,7 @@ func Test_parseParent(t *testing.T) { }, }, }, - parentDevFile: DevfileObj{ + parentDevfile: DevfileObj{ Data: &v2.DevfileV2{ Devfile: v1.Devfile{ DevfileHeader: devfilepkg.DevfileHeader{ @@ -351,40 +356,40 @@ func Test_parseParent(t *testing.T) { DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ Commands: []v1.Command{ { - Id: "devbuild", + Id: "devrun", CommandUnion: v1.CommandUnion{ Exec: &v1.ExecCommand{ - WorkingDir: "/projects/nodejs-starter", + CommandLine: "npm run", + WorkingDir: "/projects", }, }, }, { - Id: "devrun", + Id: "devbuild", CommandUnion: v1.CommandUnion{ Exec: &v1.ExecCommand{ - CommandLine: "npm run", - WorkingDir: "/projects", + WorkingDir: "/projects/nodejs-starter", }, }, }, }, Components: []v1.Component{ { - Name: "runtime", + Name: "nodejs", ComponentUnion: v1.ComponentUnion{ Container: &v1.ContainerComponent{ Container: v1.Container{ - Image: "quay.io/nodejs-12", + Image: "quay.io/nodejs-10", }, }, }, }, { - Name: "nodejs", + Name: "runtime", ComponentUnion: v1.ComponentUnion{ Container: &v1.ContainerComponent{ Container: v1.Container{ - Image: "quay.io/nodejs-10", + Image: "quay.io/nodejs-12", }, }, }, @@ -394,13 +399,11 @@ func Test_parseParent(t *testing.T) { WorkspaceEvents: v1.WorkspaceEvents{ PostStart: []string{"post-start-0"}, PostStop: []string{"post-stop"}, + PreStop: []string{}, + PreStart: []string{}, }, }, Projects: []v1.Project{ - { - ClonePath: "/projects", - Name: "nodejs-starter-build", - }, { ClonePath: "/data", ProjectSource: v1.ProjectSource{ @@ -414,6 +417,10 @@ func Test_parseParent(t *testing.T) { }, Name: "nodejs-starter", }, + { + ClonePath: "/projects", + Name: "nodejs-starter-build", + }, }, }, }, @@ -466,7 +473,7 @@ func Test_parseParent(t *testing.T) { }, }, }, - parentDevFile: DevfileObj{ + parentDevfile: DevfileObj{ Data: &v2.DevfileV2{ Devfile: v1.Devfile{ DevfileHeader: devfilepkg.DevfileHeader{ @@ -512,7 +519,7 @@ func Test_parseParent(t *testing.T) { }, }, }, - parentDevFile: DevfileObj{ + parentDevfile: DevfileObj{ Data: &v2.DevfileV2{ Devfile: v1.Devfile{ DevfileHeader: devfilepkg.DevfileHeader{ @@ -567,7 +574,7 @@ func Test_parseParent(t *testing.T) { }, }, }, - parentDevFile: DevfileObj{ + parentDevfile: DevfileObj{ Data: &v2.DevfileV2{ Devfile: v1.Devfile{ DevfileHeader: devfilepkg.DevfileHeader{ @@ -598,7 +605,7 @@ func Test_parseParent(t *testing.T) { wantErr: true, }, { - name: "case 6: error out if the same event is defined again in the local devfile", + name: "case 6: should not have error if the same event is defined again in the local devfile", args: args{ devFileObj: DevfileObj{ Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), @@ -617,7 +624,7 @@ func Test_parseParent(t *testing.T) { }, }, }, - parentDevFile: DevfileObj{ + parentDevfile: DevfileObj{ Data: &v2.DevfileV2{ Devfile: v1.Devfile{ DevfileHeader: devfilepkg.DevfileHeader{ @@ -636,9 +643,23 @@ func Test_parseParent(t *testing.T) { }, }, wantDevFile: DevfileObj{ - Data: &v2.DevfileV2{}, + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Events: &v1.Events{ + WorkspaceEvents: v1.WorkspaceEvents{ + PostStop: []string{"post-stop"}, + PreStart: []string{}, + PreStop: []string{}, + PostStart: []string{}, + }, + }, + }, + }, + }, + }, }, - wantErr: true, }, { name: "case 7: error out if the same project is defined again in the local devfile", @@ -661,7 +682,7 @@ func Test_parseParent(t *testing.T) { }, }, }, - parentDevFile: DevfileObj{ + parentDevfile: DevfileObj{ Data: &v2.DevfileV2{ Devfile: v1.Devfile{ DevfileHeader: devfilepkg.DevfileHeader{ @@ -685,45 +706,1145 @@ func Test_parseParent(t *testing.T) { }, wantErr: true, }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - data, err := yaml.Marshal(tt.parentDevFile.Data) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - _, err = w.Write(data) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - })) - defer testServer.Close() - - parent := tt.args.devFileObj.Data.GetParent() - if parent == nil { - parent = &v1.Parent{} - } - parent.Uri = testServer.URL - - tt.args.devFileObj.Data.SetParent(parent) - tt.wantDevFile.Data.SetParent(parent) - err := parseParent(tt.args.devFileObj) - - // Unexpected error - if (err != nil) != tt.wantErr { - t.Errorf("parseParent() error = %v, wantErr %v", err, tt.wantErr) - return - } - - // Expected error and got an err - if tt.wantErr && err != nil { - return - } - - if !reflect.DeepEqual(tt.args.devFileObj.Data, tt.wantDevFile.Data) { - t.Errorf("wanted: %v, got: %v, difference at %v", tt.wantDevFile, tt.args.devFileObj, pretty.Compare(tt.args.devFileObj.Data, tt.wantDevFile.Data)) - } + { + name: "case 8: it should merge the plugin's uri data and add the local devfile's data", + args: args{ + devFileObj: DevfileObj{ + Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Commands: []v1.Command{ + { + Id: "devbuild", + CommandUnion: v1.CommandUnion{ + Exec: &v1.ExecCommand{ + WorkingDir: "/projects/nodejs-starter", + }, + }, + }, + }, + Components: []v1.Component{ + { + Name: "runtime", + ComponentUnion: v1.ComponentUnion{ + Container: &v1.ContainerComponent{ + Container: v1.Container{ + Image: "quay.io/nodejs-12", + }, + }, + }, + }, + }, + Events: &v1.Events{ + WorkspaceEvents: v1.WorkspaceEvents{ + PostStop: []string{"post-stop"}, + }, + }, + Projects: []v1.Project{ + { + ClonePath: "/projects", + Name: "nodejs-starter-build", + }, + }, + }, + }, + }, + }, + }, + }, + pluginDevfile: DevfileObj{ + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevfileHeader: devfilepkg.DevfileHeader{ + SchemaVersion: schemaV200, + }, + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Commands: []v1.Command{ + { + Id: "devrun", + CommandUnion: v1.CommandUnion{ + Exec: &v1.ExecCommand{ + WorkingDir: "/projects", + CommandLine: "npm run", + }, + }, + }, + }, + Components: []v1.Component{ + { + Name: "nodejs", + ComponentUnion: v1.ComponentUnion{ + Container: &v1.ContainerComponent{ + Container: v1.Container{ + Image: "quay.io/nodejs-10", + }, + }, + }, + }, + }, + Events: &v1.Events{ + WorkspaceEvents: v1.WorkspaceEvents{ + PostStart: []string{"post-start-0"}, + }, + }, + Projects: []v1.Project{ + { + ClonePath: "/data", + ProjectSource: v1.ProjectSource{ + Github: &v1.GithubProjectSource{ + GitLikeProjectSource: v1.GitLikeProjectSource{ + Remotes: map[string]string{ + "master": "https://githube.com/somerepo/someproject.git", + }, + }, + }, + }, + Name: "nodejs-starter", + }, + }, + }, + }, + }, + }, + }, + wantDevFile: DevfileObj{ + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Commands: []v1.Command{ + { + Id: "devrun", + CommandUnion: v1.CommandUnion{ + Exec: &v1.ExecCommand{ + CommandLine: "npm run", + WorkingDir: "/projects", + }, + }, + }, + { + Id: "devbuild", + CommandUnion: v1.CommandUnion{ + Exec: &v1.ExecCommand{ + WorkingDir: "/projects/nodejs-starter", + }, + }, + }, + }, + Components: []v1.Component{ + { + Name: "nodejs", + ComponentUnion: v1.ComponentUnion{ + Container: &v1.ContainerComponent{ + Container: v1.Container{ + Image: "quay.io/nodejs-10", + }, + }, + }, + }, + { + Name: "runtime", + ComponentUnion: v1.ComponentUnion{ + Container: &v1.ContainerComponent{ + Container: v1.Container{ + Image: "quay.io/nodejs-12", + }, + }, + }, + }, + }, + Events: &v1.Events{ + WorkspaceEvents: v1.WorkspaceEvents{ + PostStart: []string{"post-start-0"}, + PostStop: []string{"post-stop"}, + PreStop: []string{}, + PreStart: []string{}, + }, + }, + Projects: []v1.Project{ + { + ClonePath: "/data", + ProjectSource: v1.ProjectSource{ + Github: &v1.GithubProjectSource{ + GitLikeProjectSource: v1.GitLikeProjectSource{ + Remotes: map[string]string{ + "master": "https://githube.com/somerepo/someproject.git", + }, + }, + }, + }, + Name: "nodejs-starter", + }, + { + ClonePath: "/projects", + Name: "nodejs-starter-build", + }, + }, + }, + }, + }, + }, + }, + }, + { + name: "case 9: it should override the plugin's data with local overrides and add the local devfile's data", + args: args{ + devFileObj: DevfileObj{ + Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Commands: []v1.Command{ + { + Id: "devbuild", + CommandUnion: v1.CommandUnion{ + Exec: &v1.ExecCommand{ + WorkingDir: "/projects/nodejs-starter", + }, + }, + }, + }, + Components: []v1.Component{ + { + Name: "runtime", + ComponentUnion: v1.ComponentUnion{ + Container: &v1.ContainerComponent{ + Container: v1.Container{ + Image: "quay.io/nodejs-12", + }, + }, + }, + }, + }, + Events: &v1.Events{ + WorkspaceEvents: v1.WorkspaceEvents{ + PostStop: []string{"post-stop"}, + }, + }, + Projects: []v1.Project{ + { + ClonePath: "/projects", + Name: "nodejs-starter-build", + }, + }, + }, + }, + }, + }, + }, + }, + pluginDevfile: DevfileObj{ + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevfileHeader: devfilepkg.DevfileHeader{ + SchemaVersion: schemaV200, + }, + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Commands: []v1.Command{ + { + Id: "devrun", + CommandUnion: v1.CommandUnion{ + Exec: &v1.ExecCommand{ + WorkingDir: "/projects", + CommandLine: "npm run", + }, + }, + }, + }, + Components: []v1.Component{ + { + Name: "nodejs", + ComponentUnion: v1.ComponentUnion{ + Container: &v1.ContainerComponent{ + Container: v1.Container{ + Image: "quay.io/nodejs-10", + }, + }, + }, + }, + }, + Events: &v1.Events{ + WorkspaceEvents: v1.WorkspaceEvents{ + PostStart: []string{"post-start-0"}, + }, + }, + Projects: []v1.Project{ + { + ClonePath: "/data", + ProjectSource: v1.ProjectSource{ + Github: &v1.GithubProjectSource{ + GitLikeProjectSource: v1.GitLikeProjectSource{ + Remotes: map[string]string{ + "master": "https://githube.com/somerepo/someproject.git", + }, + }, + }, + }, + Name: "nodejs-starter", + }, + }, + }, + }, + }, + }, + }, + pluginOverride: v1.PluginOverrides{ + OverridesBase: v1.OverridesBase{}, + Components: []v1.ComponentPluginOverride{ + { + Name: "nodejs", + ComponentUnionPluginOverride: v1.ComponentUnionPluginOverride{ + Container: &v1.ContainerComponentPluginOverride{ + ContainerPluginOverride: v1.ContainerPluginOverride{ + Image: "quay.io/nodejs-12", + }, + }, + }, + }, + }, + Commands: []v1.CommandPluginOverride{ + { + Id: "devrun", + CommandUnionPluginOverride: v1.CommandUnionPluginOverride{ + Exec: &v1.ExecCommandPluginOverride{ + WorkingDir: "/projects-new", + CommandLine: "npm build", + }, + }, + }, + }, + }, + wantDevFile: DevfileObj{ + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Commands: []v1.Command{ + { + Id: "devrun", + CommandUnion: v1.CommandUnion{ + Exec: &v1.ExecCommand{ + CommandLine: "npm build", + WorkingDir: "/projects-new", + }, + }, + }, + { + Id: "devbuild", + CommandUnion: v1.CommandUnion{ + Exec: &v1.ExecCommand{ + WorkingDir: "/projects/nodejs-starter", + }, + }, + }, + }, + Components: []v1.Component{ + { + Name: "nodejs", + ComponentUnion: v1.ComponentUnion{ + Container: &v1.ContainerComponent{ + Container: v1.Container{ + Image: "quay.io/nodejs-12", + }, + }, + }, + }, + { + Name: "runtime", + ComponentUnion: v1.ComponentUnion{ + Container: &v1.ContainerComponent{ + Container: v1.Container{ + Image: "quay.io/nodejs-12", + }, + }, + }, + }, + }, + Events: &v1.Events{ + WorkspaceEvents: v1.WorkspaceEvents{ + PostStart: []string{"post-start-0"}, + PostStop: []string{"post-stop"}, + PreStop: []string{}, + PreStart: []string{}, + }, + }, + Projects: []v1.Project{ + { + ClonePath: "/data", + ProjectSource: v1.ProjectSource{ + Github: &v1.GithubProjectSource{ + GitLikeProjectSource: v1.GitLikeProjectSource{ + Remotes: map[string]string{ + "master": "https://githube.com/somerepo/someproject.git", + }, + }, + }, + }, + Name: "nodejs-starter", + }, + { + ClonePath: "/projects", + Name: "nodejs-starter-build", + }, + }, + }, + }, + }, + }, + }, + }, + { + name: "case 10: it should error out when the plugin devfile is invalid", + args: args{ + devFileObj: DevfileObj{ + Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{}, + }, + }, + }, + }, + pluginDevfile: DevfileObj{ + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevfileHeader: devfilepkg.DevfileHeader{ + SchemaVersion: schemaV200, + }, + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Commands: []v1.Command{}, + Components: []v1.Component{}, + Projects: []v1.Project{}, + }, + }, + }, + }, + }, + pluginOverride: v1.PluginOverrides{ + Commands: []v1.CommandPluginOverride{ + { + Id: "devrun", + CommandUnionPluginOverride: v1.CommandUnionPluginOverride{ + Exec: &v1.ExecCommandPluginOverride{ + WorkingDir: "/projects/nodejs-starter", + }, + }, + }, + }, + }, + wantDevFile: DevfileObj{ + Data: &v2.DevfileV2{}, + }, + wantErr: true, + }, + { + name: "case 11: error out if the same plugin command is defined again in the local devfile", + args: args{ + devFileObj: DevfileObj{ + Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Commands: []v1.Command{ + { + Id: "devbuild", + CommandUnion: v1.CommandUnion{ + Exec: &v1.ExecCommand{ + WorkingDir: "/projects/nodejs-starter", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + pluginDevfile: DevfileObj{ + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevfileHeader: devfilepkg.DevfileHeader{ + SchemaVersion: schemaV200, + }, + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Commands: []v1.Command{ + { + Id: "devbuild", + CommandUnion: v1.CommandUnion{ + Exec: &v1.ExecCommand{ + WorkingDir: "/projects/nodejs-starter", + }, + }, + }, + }, + }, + }, + }, + }, + }, + wantDevFile: DevfileObj{ + Data: &v2.DevfileV2{}, + }, + wantErr: true, + }, + { + name: "case 12: error out if the same plugin component is defined again in the local devfile", + args: args{ + devFileObj: DevfileObj{ + Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Components: []v1.Component{ + { + Name: "runtime", + ComponentUnion: v1.ComponentUnion{ + Container: &v1.ContainerComponent{ + Container: v1.Container{ + Image: "quay.io/nodejs-12", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + pluginDevfile: DevfileObj{ + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevfileHeader: devfilepkg.DevfileHeader{ + SchemaVersion: schemaV200, + }, + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Components: []v1.Component{ + { + Name: "runtime", + ComponentUnion: v1.ComponentUnion{ + Container: &v1.ContainerComponent{ + Container: v1.Container{ + Image: "quay.io/nodejs-12", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + wantDevFile: DevfileObj{ + Data: &v2.DevfileV2{}, + }, + wantErr: true, + }, + { + name: "case 13: error out if the same project is defined again in the local devfile", + args: args{ + devFileObj: DevfileObj{ + Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Projects: []v1.Project{ + { + ClonePath: "/projects", + Name: "nodejs-starter-build", + }, + }, + }, + }, + }, + }, + }, + }, + pluginDevfile: DevfileObj{ + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevfileHeader: devfilepkg.DevfileHeader{ + SchemaVersion: schemaV200, + }, + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Projects: []v1.Project{ + { + ClonePath: "/projects", + Name: "nodejs-starter-build", + }, + }, + }, + }, + }, + }, + }, + wantDevFile: DevfileObj{ + Data: &v2.DevfileV2{}, + }, + wantErr: true, + }, + { + name: "case 14: error out if the same project is defined in the both plugin devfile and parent", + args: args{ + devFileObj: DevfileObj{ + Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Projects: []v1.Project{ + { + ClonePath: "/projects", + Name: "nodejs-starter-build", + }, + }, + }, + }, + }, + }, + }, + }, + pluginDevfile: DevfileObj{ + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevfileHeader: devfilepkg.DevfileHeader{ + SchemaVersion: schemaV200, + }, + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Projects: []v1.Project{ + { + ClonePath: "/projects", + Name: "nodejs-starter", + }, + }, + }, + }, + }, + }, + }, + parentDevfile: DevfileObj{ + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevfileHeader: devfilepkg.DevfileHeader{ + SchemaVersion: schemaV200, + }, + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Projects: []v1.Project{ + { + ClonePath: "/projects", + Name: "nodejs-starter", + }, + }, + }, + }, + }, + }, + }, + wantDevFile: DevfileObj{ + Data: &v2.DevfileV2{}, + }, + wantErr: true, + }, + { + name: "case 14: error out if the same command is defined in both plugin devfile and parent devfile", + args: args{ + devFileObj: DevfileObj{ + Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Commands: []v1.Command{ + { + Id: "devbuild", + CommandUnion: v1.CommandUnion{ + Exec: &v1.ExecCommand{ + WorkingDir: "/projects/nodejs-starter", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + pluginDevfile: DevfileObj{ + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevfileHeader: devfilepkg.DevfileHeader{ + SchemaVersion: schemaV200, + }, + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Commands: []v1.Command{ + { + Id: "devrun", + CommandUnion: v1.CommandUnion{ + Exec: &v1.ExecCommand{ + WorkingDir: "/projects/nodejs-starter", + }, + }, + }, + }, + }, + }, + }, + }, + }, + parentDevfile: DevfileObj{ + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevfileHeader: devfilepkg.DevfileHeader{ + SchemaVersion: schemaV200, + }, + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Commands: []v1.Command{ + { + Id: "devrun", + CommandUnion: v1.CommandUnion{ + Exec: &v1.ExecCommand{ + WorkingDir: "/projects/nodejs-starter", + }, + }, + }, + }, + }, + }, + }, + }, + }, + wantDevFile: DevfileObj{ + Data: &v2.DevfileV2{}, + }, + wantErr: true, + }, + { + name: "case 15: error out if the same component is defined in both plugin devfile and parent devfile", + args: args{ + devFileObj: DevfileObj{ + Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Components: []v1.Component{ + { + Name: "runtime", + ComponentUnion: v1.ComponentUnion{ + Container: &v1.ContainerComponent{ + Container: v1.Container{ + Image: "quay.io/nodejs-12", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + pluginDevfile: DevfileObj{ + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevfileHeader: devfilepkg.DevfileHeader{ + SchemaVersion: schemaV200, + }, + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Components: []v1.Component{ + { + Name: "build", + ComponentUnion: v1.ComponentUnion{ + Container: &v1.ContainerComponent{ + Container: v1.Container{ + Image: "quay.io/nodejs-12", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + parentDevfile: DevfileObj{ + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevfileHeader: devfilepkg.DevfileHeader{ + SchemaVersion: schemaV200, + }, + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Components: []v1.Component{ + { + Name: "build", + ComponentUnion: v1.ComponentUnion{ + Container: &v1.ContainerComponent{ + Container: v1.Container{ + Image: "quay.io/nodejs-10", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + wantDevFile: DevfileObj{ + Data: &v2.DevfileV2{}, + }, + wantErr: true, + }, + { + name: "case 16: it should override the requested parent's data and plugin's data, and add the local devfile's data", + args: args{ + devFileObj: DevfileObj{ + Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + Parent: &v1.Parent{ + ParentOverrides: v1.ParentOverrides{ + Commands: []v1.CommandParentOverride{ + { + Id: "devrun", + CommandUnionParentOverride: v1.CommandUnionParentOverride{ + Exec: &v1.ExecCommandParentOverride{ + WorkingDir: "/projects/nodejs-starter", + }, + }, + }, + }, + Projects: []v1.ProjectParentOverride{ + { + ClonePath: "/projects", + Name: "nodejs-starter", + }, + }, + }, + }, + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Commands: []v1.Command{ + { + Id: "devbuild", + CommandUnion: v1.CommandUnion{ + Exec: &v1.ExecCommand{ + WorkingDir: "/projects/nodejs-starter", + }, + }, + }, + }, + Components: []v1.Component{ + { + Name: "runtime", + ComponentUnion: v1.ComponentUnion{ + Container: &v1.ContainerComponent{ + Container: v1.Container{ + Image: "quay.io/nodejs-12", + }, + }, + }, + }, + }, + Events: &v1.Events{ + WorkspaceEvents: v1.WorkspaceEvents{ + PostStop: []string{"post-stop"}, + }, + }, + Projects: []v1.Project{ + { + ClonePath: "/projects", + Name: "nodejs-starter-build", + }, + }, + }, + }, + }, + }, + }, + }, + parentDevfile: DevfileObj{ + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevfileHeader: devfilepkg.DevfileHeader{ + SchemaVersion: schemaV200, + }, + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Commands: []v1.Command{ + { + Id: "devrun", + CommandUnion: v1.CommandUnion{ + Exec: &v1.ExecCommand{ + WorkingDir: "/projects", + CommandLine: "npm run", + }, + }, + }, + }, + Events: &v1.Events{ + WorkspaceEvents: v1.WorkspaceEvents{ + PostStart: []string{"post-start-0"}, + }, + }, + Projects: []v1.Project{ + { + ClonePath: "/data", + ProjectSource: v1.ProjectSource{ + Github: &v1.GithubProjectSource{ + GitLikeProjectSource: v1.GitLikeProjectSource{ + Remotes: map[string]string{ + "master": "https://githube.com/somerepo/someproject.git", + }, + }, + }, + }, + Name: "nodejs-starter", + }, + }, + }, + }, + }, + }, + }, + pluginDevfile: DevfileObj{ + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevfileHeader: devfilepkg.DevfileHeader{ + SchemaVersion: schemaV200, + }, + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Commands: []v1.Command{ + { + Id: "devdebug", + CommandUnion: v1.CommandUnion{ + Exec: &v1.ExecCommand{ + WorkingDir: "/projects", + CommandLine: "npm debug", + }, + }, + }, + }, + Components: []v1.Component{ + { + Name: "nodejs", + ComponentUnion: v1.ComponentUnion{ + Container: &v1.ContainerComponent{ + Container: v1.Container{ + Image: "quay.io/nodejs-10", + }, + }, + }, + }, + }, + Events: &v1.Events{ + WorkspaceEvents: v1.WorkspaceEvents{ + PreStart: []string{"pre-start-0"}, + }, + }, + }, + }, + }, + }, + }, + pluginOverride: v1.PluginOverrides{ + Components: []v1.ComponentPluginOverride{ + { + Name: "nodejs", + ComponentUnionPluginOverride: v1.ComponentUnionPluginOverride{ + Container: &v1.ContainerComponentPluginOverride{ + ContainerPluginOverride: v1.ContainerPluginOverride{ + Image: "quay.io/nodejs-12", + }, + }, + }, + }, + }, + }, + wantDevFile: DevfileObj{ + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Commands: []v1.Command{ + { + Id: "devrun", + CommandUnion: v1.CommandUnion{ + Exec: &v1.ExecCommand{ + CommandLine: "npm run", + WorkingDir: "/projects/nodejs-starter", + }, + }, + }, + { + Id: "devdebug", + CommandUnion: v1.CommandUnion{ + Exec: &v1.ExecCommand{ + WorkingDir: "/projects", + CommandLine: "npm debug", + }, + }, + }, + { + Id: "devbuild", + CommandUnion: v1.CommandUnion{ + Exec: &v1.ExecCommand{ + WorkingDir: "/projects/nodejs-starter", + }, + }, + }, + }, + Components: []v1.Component{ + { + Name: "nodejs", + ComponentUnion: v1.ComponentUnion{ + Container: &v1.ContainerComponent{ + Container: v1.Container{ + Image: "quay.io/nodejs-12", + }, + }, + }, + }, + { + Name: "runtime", + ComponentUnion: v1.ComponentUnion{ + Container: &v1.ContainerComponent{ + Container: v1.Container{ + Image: "quay.io/nodejs-12", + }, + }, + }, + }, + }, + Events: &v1.Events{ + WorkspaceEvents: v1.WorkspaceEvents{ + PostStart: []string{"post-start-0"}, + PostStop: []string{"post-stop"}, + PreStop: []string{}, + PreStart: []string{"pre-start-0"}, + }, + }, + Projects: []v1.Project{ + { + ClonePath: "/projects", + ProjectSource: v1.ProjectSource{ + Github: &v1.GithubProjectSource{ + GitLikeProjectSource: v1.GitLikeProjectSource{ + Remotes: map[string]string{ + "master": "https://githube.com/somerepo/someproject.git", + }, + }, + }, + }, + Name: "nodejs-starter", + }, + { + ClonePath: "/projects", + Name: "nodejs-starter-build", + }, + }, + }, + }, + }, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if !reflect.DeepEqual(tt.parentDevfile, DevfileObj{}) { + testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + data, err := yaml.Marshal(tt.parentDevfile.Data) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + _, err = w.Write(data) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + })) + defer testServer.Close() + parent := tt.args.devFileObj.Data.GetParent() + if parent == nil { + parent = &v1.Parent{} + } + parent.Uri = testServer.URL + + tt.args.devFileObj.Data.SetParent(parent) + } + if !reflect.DeepEqual(tt.pluginDevfile, DevfileObj{}) { + testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + data, err := yaml.Marshal(tt.pluginDevfile.Data) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + _, err = w.Write(data) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + })) + defer testServer.Close() + plugincomp := []v1.Component{ + { + Name: "plugincomp", + ComponentUnion: v1.ComponentUnion{ + Plugin: &v1.PluginComponent{ + ImportReference: v1.ImportReference{ + ImportReferenceUnion: v1.ImportReferenceUnion{ + Uri: testServer.URL, + }, + }, + PluginOverrides: tt.pluginOverride, + }, + }, + }, + } + tt.args.devFileObj.Data.AddComponents(plugincomp) + + } + err := parseParentAndPlugin(tt.args.devFileObj) + + // Unexpected error + if (err != nil) != tt.wantErr { + t.Errorf("parseParentAndPlugin() error = %v, wantErr %v", err, tt.wantErr) + return + } + + // Expected error and got an err + if tt.wantErr && err != nil { + return + } + + if !reflect.DeepEqual(tt.args.devFileObj.Data, tt.wantDevFile.Data) { + t.Errorf("wanted: %v, got: %v, difference at %v", tt.wantDevFile.Data, tt.args.devFileObj.Data, pretty.Compare(tt.args.devFileObj.Data, tt.wantDevFile.Data)) + } + }) } } From 0d08514d56b6348c2a8b617b6097dbcfdf6e0669 Mon Sep 17 00:00:00 2001 From: Stephanie Date: Thu, 10 Dec 2020 21:39:32 -0500 Subject: [PATCH 05/13] commit go mod Signed-off-by: Stephanie --- go.mod | 1 - 1 file changed, 1 deletion(-) diff --git a/go.mod b/go.mod index 3571b183..86679275 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,6 @@ require ( github.com/devfile/api v0.0.0-20201103130402-29b8738e196e github.com/fatih/color v1.7.0 github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 - github.com/go-test/deep v1.0.7 github.com/gobwas/glob v0.2.3 github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 From 1ba75b4da48029e2a3547df79241a0b0fdd7ef4e Mon Sep 17 00:00:00 2001 From: Stephanie Date: Thu, 10 Dec 2020 21:40:22 -0500 Subject: [PATCH 06/13] checkout the old devfile Signed-off-by: Stephanie --- devfile.yaml | 78 +++++++++++++++++++++++++++++++++------------------- go.sum | 2 -- 2 files changed, 49 insertions(+), 31 deletions(-) diff --git a/devfile.yaml b/devfile.yaml index 2eea734b..89587661 100644 --- a/devfile.yaml +++ b/devfile.yaml @@ -2,33 +2,53 @@ schemaVersion: 2.0.0 metadata: name: nodejs version: 1.0.0 -parent: - uri: https://raw.githubusercontent.com/openshift/odo/master/tests/examples/source/devfiles/nodejs/devfileCompositeCommands.yaml - commands: - - id: buildAndMkdir - composite: - label: Build and Mkdir - commands: - - createfile - - install - parallel: false - group: - kind: build - isDefault: true - components: - - name: runtime - container: - # image: registry.access.redhat.com/ubi8/nodejs-12:1-36 - env: - - name: MEME - value: /mycustom/path/ + alpha.build-dockerfile: https://raw.githubusercontent.com/odo-devfiles/registry/master/devfiles/nodejs/build/Dockerfile + alpha.deployment-manifest: https://raw.githubusercontent.com/odo-devfiles/registry/master/devfiles/nodejs/deploy/deployment-manifest.yaml +starterProjects: +- name: nodejs-starter + git: + remotes: + origin: https://github.com/odo-devfiles/nodejs-ex.git +components: +- name: runtime + container: + endpoints: + - name: http-3000 + targetPort: 3000 + image: registry.access.redhat.com/ubi8/nodejs-12:1-45 + memoryLimit: 1024Mi + mountSources: true + sourceMapping: /project commands: - - id: createfile - exec: - component: runtime - commandLine: touch /projects/testfile - workingDir: ${PROJECTS_ROOT} - group: - kind: build - isDefault: false - \ No newline at end of file +- exec: + commandLine: npm install + component: runtime + group: + isDefault: true + kind: build + workingDir: /project + id: install +- exec: + commandLine: npm start + component: runtime + group: + isDefault: true + kind: run + workingDir: /project + id: run +- exec: + commandLine: npm run debug + component: runtime + group: + isDefault: true + kind: debug + workingDir: /project + id: debug +- exec: + commandLine: npm test + component: runtime + group: + isDefault: true + kind: test + workingDir: /project + id: test diff --git a/go.sum b/go.sum index 40a5ba6d..bee6aed3 100644 --- a/go.sum +++ b/go.sum @@ -126,8 +126,6 @@ github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+ github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-test/deep v1.0.7 h1:/VSMRlnY/JSyqxQUzQLKVMAskpY/NZKFA5j2P+0pP2M= -github.com/go-test/deep v1.0.7/go.mod h1:QV8Hv/iy04NyLBxAdO9njL0iVPN1S4d/A3NVv1V36o8= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= From 55a7af22ac2328d378bb4bb189356098a32b514b Mon Sep 17 00:00:00 2001 From: Stephanie Date: Fri, 11 Dec 2020 18:49:05 -0500 Subject: [PATCH 07/13] pull latest api repo Signed-off-by: Stephanie --- go.mod | 2 +- go.sum | 2 ++ pkg/devfile/parser/data/v2/common/options_test.go | 2 +- pkg/testingutil/devfile.go | 8 ++++++++ 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 4761fdb9..7537dcf1 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/devfile/library go 1.13 require ( - github.com/devfile/api v0.0.0-20201126204309-ec222215253e + github.com/devfile/api v0.0.0-20201211221100-a68230324c7e github.com/fatih/color v1.7.0 github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 github.com/gobwas/glob v0.2.3 diff --git a/go.sum b/go.sum index 7badb7e8..78cacc9a 100644 --- a/go.sum +++ b/go.sum @@ -51,6 +51,8 @@ github.com/devfile/api v0.0.0-20201126204309-ec222215253e/go.mod h1:/aDiwWjDEW/f github.com/devfile/api v0.0.0-20201207181959-9c86a407ff76 h1:zXpN4o1q3+GJvmErCjsrv7DajFf2zAT8B1fc6K0bKHQ= github.com/devfile/api v0.0.0-20201208170158-4312e2a2642f h1:XDOQzW4WpBE+dXH7I7AnOheSjc6hHBipQn9whGDglaM= github.com/devfile/api v0.0.0-20201210141610-fb248c2367ba h1:+LpXC7ebW+H4fjQNCzjcR2FKrma2OsbMLn6Q7KLbO1I= +github.com/devfile/api v0.0.0-20201211221100-a68230324c7e h1:Jy3C3ul05YvL4bJpAVhFwPZD8neOJUBZy7GuCcjc8nc= +github.com/devfile/api v0.0.0-20201211221100-a68230324c7e/go.mod h1:/aDiwWjDEW/fY1/Ig8umVtmneAXKZImnLvWqzMlcfrY= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= diff --git a/pkg/devfile/parser/data/v2/common/options_test.go b/pkg/devfile/parser/data/v2/common/options_test.go index 3fc8f833..a342b413 100644 --- a/pkg/devfile/parser/data/v2/common/options_test.go +++ b/pkg/devfile/parser/data/v2/common/options_test.go @@ -56,7 +56,7 @@ func TestFilterDevfileObject(t *testing.T) { }, }, wantFilter: false, - wantErr: false, + wantErr: true, }, } diff --git a/pkg/testingutil/devfile.go b/pkg/testingutil/devfile.go index 2024c4b0..08cca6a3 100644 --- a/pkg/testingutil/devfile.go +++ b/pkg/testingutil/devfile.go @@ -215,6 +215,14 @@ func (d TestDevfileData) GetDevfileVolumeComponents(options common.DevfileOption return components, nil } +// GetDevfileWorkspace is a mock func to get the DevfileWorkspace in a test devfile +func (d TestDevfileData) GetDevfileWorkspace() *v1.DevWorkspaceTemplateSpecContent { + return &v1.DevWorkspaceTemplateSpecContent{} +} + +// SetDevfileWorkspace is a mock func to set the DevfileWorkspace in a test devfile +func (d TestDevfileData) SetDevfileWorkspace(content v1.DevWorkspaceTemplateSpecContent) {} + // Validate is a mock validation that always validates without error func (d TestDevfileData) Validate() error { return nil From 4d02f8bc047bf213bb5831db8c8432b41900a164 Mon Sep 17 00:00:00 2001 From: Stephanie Date: Tue, 15 Dec 2020 10:17:29 -0500 Subject: [PATCH 08/13] fix the unit test Signed-off-by: Stephanie --- pkg/devfile/parser/data/v2/common/options.go | 4 +++- pkg/devfile/parser/data/v2/common/options_test.go | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/pkg/devfile/parser/data/v2/common/options.go b/pkg/devfile/parser/data/v2/common/options.go index ffdfb710..c8e721cd 100644 --- a/pkg/devfile/parser/data/v2/common/options.go +++ b/pkg/devfile/parser/data/v2/common/options.go @@ -4,6 +4,7 @@ import ( "reflect" "github.com/devfile/api/pkg/attributes" + attriutespkg "github.com/devfile/api/pkg/attributes" ) // DevfileOptions provides options for Devfile operations @@ -19,7 +20,8 @@ func FilterDevfileObject(attributes attributes.Attributes, options DevfileOption for key, value := range options.Filter { currentFilterIn := false attrValue := attributes.Get(key, &err) - if err != nil { + var keynotfound = &attriutespkg.KeyNotFoundError{Key: key} + if err != nil && err.Error() != keynotfound.Error() { return false, err } else if reflect.DeepEqual(attrValue, value) { currentFilterIn = true diff --git a/pkg/devfile/parser/data/v2/common/options_test.go b/pkg/devfile/parser/data/v2/common/options_test.go index a342b413..3fc8f833 100644 --- a/pkg/devfile/parser/data/v2/common/options_test.go +++ b/pkg/devfile/parser/data/v2/common/options_test.go @@ -56,7 +56,7 @@ func TestFilterDevfileObject(t *testing.T) { }, }, wantFilter: false, - wantErr: true, + wantErr: false, }, } From be272c3f3a960d9a9a291fe5e01a83ffe5fa2e27 Mon Sep 17 00:00:00 2001 From: Stephanie Date: Tue, 15 Dec 2020 15:01:30 -0500 Subject: [PATCH 09/13] run go mod tidy Signed-off-by: Stephanie --- go.sum | 7 ------- 1 file changed, 7 deletions(-) diff --git a/go.sum b/go.sum index 78cacc9a..68bd42ff 100644 --- a/go.sum +++ b/go.sum @@ -44,13 +44,6 @@ github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7Do github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/devfile/api v0.0.0-20201103130402-29b8738e196e h1:Ha6wyKs7VWqQTz2Fm1o4PAYpKX6SIiYjgWmGzNW8cBE= -github.com/devfile/api v0.0.0-20201103130402-29b8738e196e/go.mod h1:hp5Lmob7ESmtSZXZ7xRN9o8vemsen9111+ASi2YuXs4= -github.com/devfile/api v0.0.0-20201126204309-ec222215253e h1:NO6mS8ktVFjkVIKZKF2JjfL3ZxXw4VAtKIZWyp9e2kQ= -github.com/devfile/api v0.0.0-20201126204309-ec222215253e/go.mod h1:/aDiwWjDEW/fY1/Ig8umVtmneAXKZImnLvWqzMlcfrY= -github.com/devfile/api v0.0.0-20201207181959-9c86a407ff76 h1:zXpN4o1q3+GJvmErCjsrv7DajFf2zAT8B1fc6K0bKHQ= -github.com/devfile/api v0.0.0-20201208170158-4312e2a2642f h1:XDOQzW4WpBE+dXH7I7AnOheSjc6hHBipQn9whGDglaM= -github.com/devfile/api v0.0.0-20201210141610-fb248c2367ba h1:+LpXC7ebW+H4fjQNCzjcR2FKrma2OsbMLn6Q7KLbO1I= github.com/devfile/api v0.0.0-20201211221100-a68230324c7e h1:Jy3C3ul05YvL4bJpAVhFwPZD8neOJUBZy7GuCcjc8nc= github.com/devfile/api v0.0.0-20201211221100-a68230324c7e/go.mod h1:/aDiwWjDEW/fY1/Ig8umVtmneAXKZImnLvWqzMlcfrY= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= From 70e85e6260220fb85b4635f20807351d45a8437c Mon Sep 17 00:00:00 2001 From: Stephanie Date: Wed, 16 Dec 2020 14:22:07 -0500 Subject: [PATCH 10/13] address review comments Signed-off-by: Stephanie --- pkg/devfile/parser/data/v2/common/options.go | 9 +-- pkg/devfile/parser/data/v2/components.go | 44 ++--------- pkg/devfile/parser/data/v2/components_test.go | 6 -- pkg/devfile/parser/data/v2/types.go | 11 --- pkg/devfile/parser/data/v2/workspace.go | 16 ++++ pkg/devfile/parser/data/v2/workspace_test.go | 74 +++++++++++++++++++ pkg/devfile/parser/parse.go | 38 ++++++---- 7 files changed, 123 insertions(+), 75 deletions(-) create mode 100644 pkg/devfile/parser/data/v2/workspace.go create mode 100644 pkg/devfile/parser/data/v2/workspace_test.go diff --git a/pkg/devfile/parser/data/v2/common/options.go b/pkg/devfile/parser/data/v2/common/options.go index c8e721cd..f4de76ee 100644 --- a/pkg/devfile/parser/data/v2/common/options.go +++ b/pkg/devfile/parser/data/v2/common/options.go @@ -3,8 +3,7 @@ package common import ( "reflect" - "github.com/devfile/api/pkg/attributes" - attriutespkg "github.com/devfile/api/pkg/attributes" + apiAttributes "github.com/devfile/api/pkg/attributes" ) // DevfileOptions provides options for Devfile operations @@ -14,14 +13,14 @@ type DevfileOptions struct { } // FilterDevfileObject filters devfile attributes with the given options -func FilterDevfileObject(attributes attributes.Attributes, options DevfileOptions) (bool, error) { +func FilterDevfileObject(attributes apiAttributes.Attributes, options DevfileOptions) (bool, error) { var err error filterIn := true for key, value := range options.Filter { currentFilterIn := false attrValue := attributes.Get(key, &err) - var keynotfound = &attriutespkg.KeyNotFoundError{Key: key} - if err != nil && err.Error() != keynotfound.Error() { + var keyNotFoundErr = &apiAttributes.KeyNotFoundError{Key: key} + if err != nil && err.Error() != keyNotFoundErr.Error() { return false, err } else if reflect.DeepEqual(attrValue, value) { currentFilterIn = true diff --git a/pkg/devfile/parser/data/v2/components.go b/pkg/devfile/parser/data/v2/components.go index 79aab973..e6a4b708 100644 --- a/pkg/devfile/parser/data/v2/components.go +++ b/pkg/devfile/parser/data/v2/components.go @@ -60,48 +60,16 @@ func (d *DevfileV2) GetDevfileVolumeComponents(options common.DevfileOptions) ([ // if a component is already defined, error out func (d *DevfileV2) AddComponents(components []v1.Component) error { - // different map for volume and container component as a volume and a container with same name - // can exist in devfile - containerMap := make(map[string]bool) - volumeMap := make(map[string]bool) - pluginMap := make(map[string]bool) + componentMap := make(map[string]bool) for _, component := range d.Components { - if component.Volume != nil { - volumeMap[component.Name] = true - } - if component.Container != nil { - containerMap[component.Name] = true - } - if component.Plugin != nil { - pluginMap[component.Name] = true - } + componentMap[component.Name] = true } - for _, component := range components { - - if component.Volume != nil { - if _, ok := volumeMap[component.Name]; !ok { - d.Components = append(d.Components, component) - } else { - return &common.FieldAlreadyExistError{Name: component.Name, Field: "component"} - } - } - - if component.Container != nil { - if _, ok := containerMap[component.Name]; !ok { - d.Components = append(d.Components, component) - } else { - return &common.FieldAlreadyExistError{Name: component.Name, Field: "component"} - } - } - - if component.Plugin != nil { - if _, ok := pluginMap[component.Name]; !ok { - d.Components = append(d.Components, component) - } else { - return &common.FieldAlreadyExistError{Name: component.Name, Field: "component"} - } + if _, ok := componentMap[component.Name]; !ok { + d.Components = append(d.Components, component) + } else { + return &common.FieldAlreadyExistError{Name: component.Name, Field: "component"} } } return nil diff --git a/pkg/devfile/parser/data/v2/components_test.go b/pkg/devfile/parser/data/v2/components_test.go index 0369607f..930612da 100644 --- a/pkg/devfile/parser/data/v2/components_test.go +++ b/pkg/devfile/parser/data/v2/components_test.go @@ -35,12 +35,6 @@ func TestDevfile200_AddComponent(t *testing.T) { }, }, newComponents: []v1.Component{ - { - Name: "component2", - ComponentUnion: v1.ComponentUnion{ - Container: &v1.ContainerComponent{}, - }, - }, { Name: "component3", ComponentUnion: v1.ComponentUnion{ diff --git a/pkg/devfile/parser/data/v2/types.go b/pkg/devfile/parser/data/v2/types.go index 3f7be501..e7fdff4e 100644 --- a/pkg/devfile/parser/data/v2/types.go +++ b/pkg/devfile/parser/data/v2/types.go @@ -8,14 +8,3 @@ import ( type DevfileV2 struct { v1.Devfile } - -// GetDevfileWorkspace returns the workspace content for the devfile -func (d *DevfileV2) GetDevfileWorkspace() *v1.DevWorkspaceTemplateSpecContent { - - return &d.DevWorkspaceTemplateSpecContent -} - -// SetDevfileWorkspace sets the workspace content -func (d *DevfileV2) SetDevfileWorkspace(content v1.DevWorkspaceTemplateSpecContent) { - d.DevWorkspaceTemplateSpecContent = content -} diff --git a/pkg/devfile/parser/data/v2/workspace.go b/pkg/devfile/parser/data/v2/workspace.go new file mode 100644 index 00000000..54e047e2 --- /dev/null +++ b/pkg/devfile/parser/data/v2/workspace.go @@ -0,0 +1,16 @@ +package v2 + +import ( + v1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" +) + +// GetDevfileWorkspace returns the workspace content for the devfile +func (d *DevfileV2) GetDevfileWorkspace() *v1.DevWorkspaceTemplateSpecContent { + + return &d.DevWorkspaceTemplateSpecContent +} + +// SetDevfileWorkspace sets the workspace content +func (d *DevfileV2) SetDevfileWorkspace(content v1.DevWorkspaceTemplateSpecContent) { + d.DevWorkspaceTemplateSpecContent = content +} diff --git a/pkg/devfile/parser/data/v2/workspace_test.go b/pkg/devfile/parser/data/v2/workspace_test.go new file mode 100644 index 00000000..75f95237 --- /dev/null +++ b/pkg/devfile/parser/data/v2/workspace_test.go @@ -0,0 +1,74 @@ +package v2 + +import ( + "reflect" + "testing" + + v1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" +) + +func TestDevfile200_SetDevfileWorkspace(t *testing.T) { + + type args struct { + name string + } + tests := []struct { + name string + workspace v1.DevWorkspaceTemplateSpecContent + devfilev2 *DevfileV2 + expectedDevfilev2 *DevfileV2 + }{ + { + name: "set workspace", + devfilev2: &DevfileV2{ + v1.Devfile{}, + }, + workspace: v1.DevWorkspaceTemplateSpecContent{ + Components: []v1.Component{ + { + Name: "component1", + ComponentUnion: v1.ComponentUnion{ + Container: &v1.ContainerComponent{}, + }, + }, + { + Name: "component2", + ComponentUnion: v1.ComponentUnion{ + Volume: &v1.VolumeComponent{}, + }, + }, + }, + }, + expectedDevfilev2: &DevfileV2{ + v1.Devfile{ + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Components: []v1.Component{ + { + Name: "component1", + ComponentUnion: v1.ComponentUnion{ + Container: &v1.ContainerComponent{}, + }, + }, + { + Name: "component2", + ComponentUnion: v1.ComponentUnion{ + Volume: &v1.VolumeComponent{}, + }, + }, + }, + }, + }, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.devfilev2.SetDevfileWorkspace(tt.workspace) + if !reflect.DeepEqual(tt.devfilev2, tt.expectedDevfilev2) { + t.Errorf("TestDevfile200_SetDevfileWorkspace() expected %v, got %v", tt.expectedDevfilev2, tt.devfilev2) + } + }) + } +} diff --git a/pkg/devfile/parser/parse.go b/pkg/devfile/parser/parse.go index 83ab3636..82927e46 100644 --- a/pkg/devfile/parser/parse.go +++ b/pkg/devfile/parser/parse.go @@ -2,6 +2,7 @@ package parser import ( "encoding/json" + "fmt" devfileCtx "github.com/devfile/library/pkg/devfile/parser/context" "github.com/devfile/library/pkg/devfile/parser/data" @@ -63,7 +64,7 @@ func Parse(path string) (d DevfileObj, err error) { return parseDevfile(d, true) } -// ParseRawDevfile populates the raw devfile data witout overring and merging +// ParseRawDevfile populates the raw devfile data without overriding and merging func ParseRawDevfile(path string) (d DevfileObj, err error) { // NewDevfileCtx d.Ctx = devfileCtx.NewDevfileCtx(path) @@ -108,15 +109,20 @@ func ParseFromData(data []byte) (d DevfileObj, err error) { func parseParentAndPlugin(d DevfileObj) (err error) { flattenedParent := &v1.DevWorkspaceTemplateSpecContent{} if d.Data.GetParent() != nil { - if !reflect.DeepEqual(d.Data.GetParent(), &v1.Parent{}) && d.Data.GetParent().Uri != "" { - parent := d.Data.GetParent() + if !reflect.DeepEqual(d.Data.GetParent(), &v1.Parent{}) { - parentData, err := ParseFromURL(parent.Uri) - if err != nil { - return err + parent := d.Data.GetParent() + var parentDevfileObj DevfileObj + if d.Data.GetParent().Uri != "" { + parentDevfileObj, err = ParseFromURL(parent.Uri) + if err != nil { + return err + } + } else { + return fmt.Errorf("parent URI undefined, currently only URI is suppported") } - parentWorkspaceContent := parentData.Data.GetDevfileWorkspace() + parentWorkspaceContent := parentDevfileObj.Data.GetDevfileWorkspace() if !reflect.DeepEqual(parent.ParentOverrides, v1.ParentOverrides{}) { flattenedParent, err = apiOverride.OverrideDevWorkspaceTemplateSpec(parentWorkspaceContent, parent.ParentOverrides) if err != nil { @@ -129,7 +135,7 @@ func parseParentAndPlugin(d DevfileObj) (err error) { klog.V(4).Infof("adding data of devfile with URI: %v", parent.Uri) } } - plugins := []*v1.DevWorkspaceTemplateSpecContent{} + flattenedPlugins := []*v1.DevWorkspaceTemplateSpecContent{} components, err := d.Data.GetComponents(common.DevfileOptions{}) if err != nil { return err @@ -137,25 +143,27 @@ func parseParentAndPlugin(d DevfileObj) (err error) { for _, component := range components { if component.Plugin != nil && !reflect.DeepEqual(component.Plugin, &v1.PluginComponent{}) { plugin := component.Plugin - var pluginData DevfileObj + var pluginDevfileObj DevfileObj if plugin.Uri != "" { - pluginData, err = ParseFromURL(plugin.Uri) + pluginDevfileObj, err = ParseFromURL(plugin.Uri) if err != nil { return err } + } else { + return fmt.Errorf("parent URI undefined, currently only URI is suppported") } - pluginWorkspaceContent := pluginData.Data.GetDevfileWorkspace() - result := pluginWorkspaceContent + pluginWorkspaceContent := pluginDevfileObj.Data.GetDevfileWorkspace() + flattenedPlugin := pluginWorkspaceContent if !reflect.DeepEqual(plugin.PluginOverrides, v1.PluginOverrides{}) { - result, err = apiOverride.OverrideDevWorkspaceTemplateSpec(pluginWorkspaceContent, plugin.PluginOverrides) + flattenedPlugin, err = apiOverride.OverrideDevWorkspaceTemplateSpec(pluginWorkspaceContent, plugin.PluginOverrides) if err != nil { return err } } - plugins = append(plugins, result) + flattenedPlugins = append(flattenedPlugins, flattenedPlugin) } } - mergedContent, err := apiOverride.MergeDevWorkspaceTemplateSpec(d.Data.GetDevfileWorkspace(), flattenedParent, plugins...) + mergedContent, err := apiOverride.MergeDevWorkspaceTemplateSpec(d.Data.GetDevfileWorkspace(), flattenedParent, flattenedPlugins...) if err != nil { return err } From b658fa4fd5b259dbb01299c54957e75869a3d877 Mon Sep 17 00:00:00 2001 From: Stephanie Date: Mon, 21 Dec 2020 15:23:21 -0500 Subject: [PATCH 11/13] add more unit tests Signed-off-by: Stephanie --- devfile.yaml | 35 ++- main.go | 35 ++- pkg/devfile/parser/data/interface.go | 2 + pkg/devfile/parser/parse.go | 2 +- pkg/devfile/parser/parse_test.go | 365 +++++++++++++++++++++++++-- 5 files changed, 406 insertions(+), 33 deletions(-) diff --git a/devfile.yaml b/devfile.yaml index b4490506..d9913736 100644 --- a/devfile.yaml +++ b/devfile.yaml @@ -4,13 +4,24 @@ metadata: version: 1.0.0 attributes: alpha.build-dockerfile: /relative/path/to/Dockerfile +parent: + uri: https://raw.githubusercontent.com/odo-devfiles/registry/master/devfiles/nodejs/devfile.yaml + commands: + - id: install + exec: + component: runtime + commandLine: npm install + workingDir: /project-starter + group: + kind: build + isDefault: true starterProjects: -- name: nodejs-starter +- name: nodejs-starter2 git: remotes: origin: https://github.com/odo-devfiles/nodejs-ex.git components: -- name: runtime +- name: runtime2 attributes: tool: console-import import: @@ -23,7 +34,7 @@ components: memoryLimit: 1024Mi mountSources: true sourceMapping: /project -- name: runtime2 +- name: runtime3 attributes: tool: odo cli: @@ -36,7 +47,7 @@ components: memoryLimit: 1024Mi mountSources: true sourceMapping: /project -- name: runtime3 +- name: runtime4 attributes: tool: workspace-operator container: @@ -50,39 +61,39 @@ components: commands: - exec: commandLine: npm install - component: runtime + component: runtime2 group: isDefault: true kind: build workingDir: /project - id: install + id: install2 attributes: tool: odo mandatory: false - exec: commandLine: npm start - component: runtime + component: runtime2 group: isDefault: true kind: run workingDir: /project - id: run + id: run2 attributes: tool: odo mandatory: true - exec: commandLine: npm run debug - component: runtime + component: runtime2 group: isDefault: true kind: debug workingDir: /project - id: debug + id: debug2 - exec: commandLine: npm test - component: runtime + component: runtime2 group: isDefault: true kind: test workingDir: /project - id: test + id: test2 diff --git a/main.go b/main.go index 1546b8e8..17a09b68 100644 --- a/main.go +++ b/main.go @@ -21,6 +21,29 @@ func main() { fmt.Printf("schema version: %s\n", d.SchemaVersion) } + components, e := devfile.Data.GetComponents(common.DevfileOptions{}) + if e != nil { + fmt.Printf("err: %v\n", err) + } + fmt.Printf("All component: \n") + for _, component := range components { + fmt.Printf("%s\n", component.Name) + } + + fmt.Printf("All Exec commands: \n") + commands, e := devfile.Data.GetCommands(common.DevfileOptions{}) + if e != nil { + fmt.Printf("err: %v\n", err) + } + for _, command := range commands { + if command.Exec != nil { + fmt.Printf("command %s is with kind: %s", command.Id, command.Exec.Group.Kind) + fmt.Printf("workingDir is: %s\n", command.Exec.WorkingDir) + } + } + + fmt.Println("=========================================================") + compOptions := common.DevfileOptions{ Filter: map[string]interface{}{ "tool": "console-import", @@ -30,14 +53,14 @@ func main() { }, } - components, e := devfile.Data.GetComponents(compOptions) + components, e = devfile.Data.GetComponents(compOptions) if e != nil { fmt.Printf("err: %v\n", err) } - + fmt.Printf("Container components applied filter: \n") for _, component := range components { if component.Container != nil { - fmt.Printf("component container: %s\n", component.Name) + fmt.Printf("%s\n", component.Name) } } @@ -47,13 +70,15 @@ func main() { }, } - commands, e := devfile.Data.GetCommands(cmdOptions) + fmt.Printf("Exec commands applied filter: \n") + commands, e = devfile.Data.GetCommands(cmdOptions) if e != nil { fmt.Printf("err: %v\n", err) } for _, command := range commands { if command.Exec != nil { - fmt.Printf("exec command kind: %s\n", command.Exec.Group.Kind) + fmt.Printf("command %s is with kind: %s", command.Id, command.Exec.Group.Kind) + fmt.Printf("workingDir is: %s\n", command.Exec.WorkingDir) } } diff --git a/pkg/devfile/parser/data/interface.go b/pkg/devfile/parser/data/interface.go index 236b2173..56dd6e68 100644 --- a/pkg/devfile/parser/data/interface.go +++ b/pkg/devfile/parser/data/interface.go @@ -47,8 +47,10 @@ type DevfileData interface { DeleteVolume(name string) error GetVolumeMountPath(name string) (string, error) + // workspace related methods GetDevfileWorkspace() *v1.DevWorkspaceTemplateSpecContent SetDevfileWorkspace(content v1.DevWorkspaceTemplateSpecContent) + //utils GetDevfileContainerComponents(common.DevfileOptions) ([]v1.Component, error) GetDevfileVolumeComponents(common.DevfileOptions) ([]v1.Component, error) diff --git a/pkg/devfile/parser/parse.go b/pkg/devfile/parser/parse.go index 82927e46..10775865 100644 --- a/pkg/devfile/parser/parse.go +++ b/pkg/devfile/parser/parse.go @@ -150,7 +150,7 @@ func parseParentAndPlugin(d DevfileObj) (err error) { return err } } else { - return fmt.Errorf("parent URI undefined, currently only URI is suppported") + return fmt.Errorf("plugin URI undefined, currently only URI is suppported") } pluginWorkspaceContent := pluginDevfileObj.Data.GetDevfileWorkspace() flattenedPlugin := pluginWorkspaceContent diff --git a/pkg/devfile/parser/parse_test.go b/pkg/devfile/parser/parse_test.go index 92850f71..02feb106 100644 --- a/pkg/devfile/parser/parse_test.go +++ b/pkg/devfile/parser/parse_test.go @@ -1,6 +1,7 @@ package parser import ( + "net" "net/http" "net/http/httptest" "reflect" @@ -18,17 +19,19 @@ const schemaV200 = "2.0.0" const devfileTempPath = "devfile.yaml" func Test_parseParentAndPlugin(t *testing.T) { + type args struct { devFileObj DevfileObj } tests := []struct { - name string - args args - parentDevfile DevfileObj - pluginDevfile DevfileObj - pluginOverride v1.PluginOverrides - wantDevFile DevfileObj - wantErr bool + name string + args args + parentDevfile DevfileObj + pluginDevfile DevfileObj + pluginOverride v1.PluginOverrides + wantDevFile DevfileObj + wantErr bool + testRecursiveReference bool }{ { name: "case 1: it should override the requested parent's data and add the local devfile's data", @@ -662,7 +665,7 @@ func Test_parseParentAndPlugin(t *testing.T) { }, }, { - name: "case 7: error out if the same project is defined again in the local devfile", + name: "case 7: error out if the parent project is defined again in the local devfile", args: args{ devFileObj: DevfileObj{ Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), @@ -922,7 +925,7 @@ func Test_parseParentAndPlugin(t *testing.T) { }, Events: &v1.Events{ WorkspaceEvents: v1.WorkspaceEvents{ - PostStop: []string{"post-stop"}, + PostStop: []string{"post-stop-1"}, }, }, Projects: []v1.Project{ @@ -971,6 +974,7 @@ func Test_parseParentAndPlugin(t *testing.T) { Events: &v1.Events{ WorkspaceEvents: v1.WorkspaceEvents{ PostStart: []string{"post-start-0"}, + PostStop: []string{"post-stop-2"}, }, }, Projects: []v1.Project{ @@ -1068,7 +1072,7 @@ func Test_parseParentAndPlugin(t *testing.T) { Events: &v1.Events{ WorkspaceEvents: v1.WorkspaceEvents{ PostStart: []string{"post-start-0"}, - PostStop: []string{"post-stop"}, + PostStop: []string{"post-stop-1", "post-stop-2"}, PreStop: []string{}, PreStart: []string{}, }, @@ -1254,7 +1258,7 @@ func Test_parseParentAndPlugin(t *testing.T) { wantErr: true, }, { - name: "case 13: error out if the same project is defined again in the local devfile", + name: "case 13: error out if the plugin project is defined again in the local devfile", args: args{ devFileObj: DevfileObj{ Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), @@ -1363,7 +1367,7 @@ func Test_parseParentAndPlugin(t *testing.T) { wantErr: true, }, { - name: "case 14: error out if the same command is defined in both plugin devfile and parent devfile", + name: "case 15: error out if the same command is defined in both plugin devfile and parent devfile", args: args{ devFileObj: DevfileObj{ Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), @@ -1439,7 +1443,7 @@ func Test_parseParentAndPlugin(t *testing.T) { wantErr: true, }, { - name: "case 15: error out if the same component is defined in both plugin devfile and parent devfile", + name: "case 16: error out if the same component is defined in both plugin devfile and parent devfile", args: args{ devFileObj: DevfileObj{ Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), @@ -1521,7 +1525,7 @@ func Test_parseParentAndPlugin(t *testing.T) { wantErr: true, }, { - name: "case 16: it should override the requested parent's data and plugin's data, and add the local devfile's data", + name: "case 17: it should override the requested parent's data and plugin's data, and add the local devfile's data", args: args{ devFileObj: DevfileObj{ Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), @@ -1775,6 +1779,322 @@ func Test_parseParentAndPlugin(t *testing.T) { }, }, }, + { + name: "case 18: error out if the plugin component is defined with a different component type in the local devfile", + args: args{ + devFileObj: DevfileObj{ + Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Components: []v1.Component{ + { + Name: "runtime", + ComponentUnion: v1.ComponentUnion{ + Container: &v1.ContainerComponent{ + Container: v1.Container{ + Image: "quay.io/nodejs-12", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + pluginDevfile: DevfileObj{ + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevfileHeader: devfilepkg.DevfileHeader{ + SchemaVersion: schemaV200, + }, + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Components: []v1.Component{ + { + Name: "runtime", + ComponentUnion: v1.ComponentUnion{ + Volume: &v1.VolumeComponent{ + Volume: v1.Volume{ + Size: "500Mi", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + wantDevFile: DevfileObj{ + Data: &v2.DevfileV2{}, + }, + wantErr: true, + }, + { + name: "case 19: it should override with no errors if the plugin component is defined with a different component type in the plugin override", + args: args{ + devFileObj: DevfileObj{ + Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{}, + }, + }, + }, + pluginOverride: v1.PluginOverrides{ + Components: []v1.ComponentPluginOverride{ + { + Name: "runtime", + ComponentUnionPluginOverride: v1.ComponentUnionPluginOverride{ + Container: &v1.ContainerComponentPluginOverride{ + ContainerPluginOverride: v1.ContainerPluginOverride{ + Image: "quay.io/nodejs-12", + }, + }, + }, + }, + }, + }, + pluginDevfile: DevfileObj{ + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevfileHeader: devfilepkg.DevfileHeader{ + SchemaVersion: schemaV200, + }, + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Components: []v1.Component{ + { + Name: "runtime", + ComponentUnion: v1.ComponentUnion{ + Volume: &v1.VolumeComponent{ + Volume: v1.Volume{ + Size: "500Mi", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + wantDevFile: DevfileObj{ + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Components: []v1.Component{ + { + Name: "runtime", + ComponentUnion: v1.ComponentUnion{ + Container: &v1.ContainerComponent{ + Container: v1.Container{ + Image: "quay.io/nodejs-12", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + wantErr: false, + }, + { + name: "case 20: error out if the parent component is defined with a different component type in the local devfile", + args: args{ + devFileObj: DevfileObj{ + Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Components: []v1.Component{ + { + Name: "runtime", + ComponentUnion: v1.ComponentUnion{ + Container: &v1.ContainerComponent{ + Container: v1.Container{ + Image: "quay.io/nodejs-12", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + parentDevfile: DevfileObj{ + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevfileHeader: devfilepkg.DevfileHeader{ + SchemaVersion: schemaV200, + }, + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Components: []v1.Component{ + { + Name: "runtime", + ComponentUnion: v1.ComponentUnion{ + Volume: &v1.VolumeComponent{ + Volume: v1.Volume{ + Size: "500Mi", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + wantDevFile: DevfileObj{ + Data: &v2.DevfileV2{}, + }, + wantErr: true, + }, + { + name: "case 21: it should override with no errors if the parent component is defined with a different component type in the parent override", + args: args{ + devFileObj: DevfileObj{ + Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + Parent: &v1.Parent{ + ParentOverrides: v1.ParentOverrides{ + Components: []v1.ComponentParentOverride{ + { + Name: "runtime", + ComponentUnionParentOverride: v1.ComponentUnionParentOverride{ + Container: &v1.ContainerComponentParentOverride{ + ContainerParentOverride: v1.ContainerParentOverride{ + Image: "quay.io/nodejs-12", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + parentDevfile: DevfileObj{ + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevfileHeader: devfilepkg.DevfileHeader{ + SchemaVersion: schemaV200, + }, + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Components: []v1.Component{ + { + Name: "runtime", + ComponentUnion: v1.ComponentUnion{ + Volume: &v1.VolumeComponent{ + Volume: v1.Volume{ + Size: "500Mi", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + wantDevFile: DevfileObj{ + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Components: []v1.Component{ + { + Name: "runtime", + ComponentUnion: v1.ComponentUnion{ + Container: &v1.ContainerComponent{ + Container: v1.Container{ + Image: "quay.io/nodejs-12", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + wantErr: false, + }, + { + name: "case 22: error out if the URI is recursively referenced", + args: args{ + devFileObj: DevfileObj{ + Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + Parent: &v1.Parent{ + ImportReference: v1.ImportReference{ + ImportReferenceUnion: v1.ImportReferenceUnion{ + Uri: "http://127.0.0.1:8080", + }, + }, + }, + }, + }, + }, + }, + }, + pluginDevfile: DevfileObj{ + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevfileHeader: devfilepkg.DevfileHeader{ + SchemaVersion: schemaV200, + }, + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Components: []v1.Component{ + { + Name: "runtime", + ComponentUnion: v1.ComponentUnion{ + Volume: &v1.VolumeComponent{ + Volume: v1.Volume{ + Size: "500Mi", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + wantDevFile: DevfileObj{ + Data: &v2.DevfileV2{}, + }, + wantErr: true, + testRecursiveReference: true, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -1799,7 +2119,8 @@ func Test_parseParentAndPlugin(t *testing.T) { tt.args.devFileObj.Data.SetParent(parent) } if !reflect.DeepEqual(tt.pluginDevfile, DevfileObj{}) { - testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + + testServer := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { data, err := yaml.Marshal(tt.pluginDevfile.Data) if err != nil { t.Errorf("unexpected error: %v", err) @@ -1809,7 +2130,21 @@ func Test_parseParentAndPlugin(t *testing.T) { t.Errorf("unexpected error: %v", err) } })) + if tt.testRecursiveReference { + // create a listener with the desired port. + l, err := net.Listen("tcp", "127.0.0.1:8080") + if err != nil { + t.Errorf("unexpected error: %v", err) + } + + // NewUnstartedServer creates a listener. Close that listener and replace + // with the one we created. + testServer.Listener.Close() + testServer.Listener = l + } + testServer.Start() defer testServer.Close() + plugincomp := []v1.Component{ { Name: "plugincomp", From 8c7cbd67c0df63cb4d3919ea6c430679c15c4695 Mon Sep 17 00:00:00 2001 From: Stephanie Date: Mon, 21 Dec 2020 16:02:48 -0500 Subject: [PATCH 12/13] block recersive reference Signed-off-by: Stephanie --- pkg/devfile/parser/parse.go | 12 ++++++++++-- pkg/devfile/parser/parse_test.go | 19 ++++++++----------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/pkg/devfile/parser/parse.go b/pkg/devfile/parser/parse.go index 10775865..4d287ae2 100644 --- a/pkg/devfile/parser/parse.go +++ b/pkg/devfile/parser/parse.go @@ -16,6 +16,8 @@ import ( "github.com/pkg/errors" ) +var URLMap = make(map[string]bool) + // ParseDevfile func validates the devfile integrity. // Creates devfile context and runtime objects func parseDevfile(d DevfileObj, flattenedDevfile bool) (DevfileObj, error) { @@ -44,7 +46,9 @@ func parseDevfile(d DevfileObj, flattenedDevfile bool) (DevfileObj, error) { return DevfileObj{}, err } } - + for url := range URLMap { + delete(URLMap, url) + } // Successful return d, nil } @@ -80,8 +84,12 @@ func ParseRawDevfile(path string) (d DevfileObj, err error) { // ParseFromURL func parses and validates the devfile integrity. // Creates devfile context and runtime objects func ParseFromURL(url string) (d DevfileObj, err error) { + if _, exist := URLMap[url]; !exist { + URLMap[url] = true + } else { + return d, fmt.Errorf("URL is recursively referenced") + } d.Ctx = devfileCtx.NewURLDevfileCtx(url) - // Fill the fields of DevfileCtx struct err = d.Ctx.PopulateFromURL() if err != nil { diff --git a/pkg/devfile/parser/parse_test.go b/pkg/devfile/parser/parse_test.go index 02feb106..8aef10f2 100644 --- a/pkg/devfile/parser/parse_test.go +++ b/pkg/devfile/parser/parse_test.go @@ -2050,17 +2050,7 @@ func Test_parseParentAndPlugin(t *testing.T) { devFileObj: DevfileObj{ Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), Data: &v2.DevfileV2{ - Devfile: v1.Devfile{ - DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ - Parent: &v1.Parent{ - ImportReference: v1.ImportReference{ - ImportReferenceUnion: v1.ImportReferenceUnion{ - Uri: "http://127.0.0.1:8080", - }, - }, - }, - }, - }, + Devfile: v1.Devfile{}, }, }, }, @@ -2071,6 +2061,13 @@ func Test_parseParentAndPlugin(t *testing.T) { SchemaVersion: schemaV200, }, DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + Parent: &v1.Parent{ + ImportReference: v1.ImportReference{ + ImportReferenceUnion: v1.ImportReferenceUnion{ + Uri: "http://127.0.0.1:8080", + }, + }, + }, DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ Components: []v1.Component{ { From cd34c20195d8bef1d62c0e4ab634ae043c176a2b Mon Sep 17 00:00:00 2001 From: Stephanie Date: Mon, 21 Dec 2020 17:44:37 -0500 Subject: [PATCH 13/13] add a new unit test to test for dup uri in multiple references Signed-off-by: Stephanie --- pkg/devfile/parser/parse.go | 2 +- pkg/devfile/parser/parse_test.go | 215 +++++++++++++++++++++++++++++++ 2 files changed, 216 insertions(+), 1 deletion(-) diff --git a/pkg/devfile/parser/parse.go b/pkg/devfile/parser/parse.go index 4d287ae2..43c72895 100644 --- a/pkg/devfile/parser/parse.go +++ b/pkg/devfile/parser/parse.go @@ -87,7 +87,7 @@ func ParseFromURL(url string) (d DevfileObj, err error) { if _, exist := URLMap[url]; !exist { URLMap[url] = true } else { - return d, fmt.Errorf("URL is recursively referenced") + return d, fmt.Errorf("URI %v is recursively referenced", url) } d.Ctx = devfileCtx.NewURLDevfileCtx(url) // Fill the fields of DevfileCtx struct diff --git a/pkg/devfile/parser/parse_test.go b/pkg/devfile/parser/parse_test.go index 8aef10f2..5c15290d 100644 --- a/pkg/devfile/parser/parse_test.go +++ b/pkg/devfile/parser/parse_test.go @@ -1,6 +1,7 @@ package parser import ( + "fmt" "net" "net/http" "net/http/httptest" @@ -2180,3 +2181,217 @@ func Test_parseParentAndPlugin(t *testing.T) { }) } } + +func Test_parseParentAndPlugin_RecursivelyReference_withMultipleURI(t *testing.T) { + const uri1 = "127.0.0.1:8080" + const uri2 = "127.0.0.1:9090" + const uri3 = "127.0.0.1:8090" + const httpPrefix = "http://" + + devFileObj := DevfileObj{ + Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + Parent: &v1.Parent{ + ImportReference: v1.ImportReference{ + ImportReferenceUnion: v1.ImportReferenceUnion{ + Uri: httpPrefix + uri1, + }, + }, + }, + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Components: []v1.Component{ + { + Name: "runtime2", + ComponentUnion: v1.ComponentUnion{ + Volume: &v1.VolumeComponent{ + Volume: v1.Volume{ + Size: "500Mi", + }, + }, + }, + }, + }, + }, + }, + }, + }, + } + parentDevfile1 := DevfileObj{ + Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevfileHeader: devfilepkg.DevfileHeader{ + SchemaVersion: schemaV200, + }, + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + Parent: &v1.Parent{ + ImportReference: v1.ImportReference{ + ImportReferenceUnion: v1.ImportReferenceUnion{ + Uri: httpPrefix + uri2, + }, + }, + }, + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Components: []v1.Component{ + { + Name: "runtime", + ComponentUnion: v1.ComponentUnion{ + Volume: &v1.VolumeComponent{ + Volume: v1.Volume{ + Size: "500Mi", + }, + }, + }, + }, + }, + }, + }, + }, + }, + } + parentDevfile2 := DevfileObj{ + Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevfileHeader: devfilepkg.DevfileHeader{ + SchemaVersion: schemaV200, + }, + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Components: []v1.Component{ + { + Name: "plugin", + ComponentUnion: v1.ComponentUnion{ + Plugin: &v1.PluginComponent{ + ImportReference: v1.ImportReference{ + ImportReferenceUnion: v1.ImportReferenceUnion{ + Uri: httpPrefix + uri3, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } + parentDevfile3 := DevfileObj{ + Ctx: devfileCtx.NewDevfileCtx(devfileTempPath), + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevfileHeader: devfilepkg.DevfileHeader{ + SchemaVersion: schemaV200, + }, + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + Parent: &v1.Parent{ + ImportReference: v1.ImportReference{ + ImportReferenceUnion: v1.ImportReferenceUnion{ + Uri: httpPrefix + uri1, + }, + }, + }, + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Components: []v1.Component{ + { + Name: "test", + ComponentUnion: v1.ComponentUnion{ + Volume: &v1.VolumeComponent{ + Volume: v1.Volume{ + Size: "500Mi", + }, + }, + }, + }, + }, + }, + }, + }, + }, + } + + testServer1 := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + data, err := yaml.Marshal(parentDevfile1.Data) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + _, err = w.Write(data) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + })) + // create a listener with the desired port. + l1, err := net.Listen("tcp", uri1) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + + // NewUnstartedServer creates a listener. Close that listener and replace + // with the one we created. + testServer1.Listener.Close() + testServer1.Listener = l1 + + testServer1.Start() + defer testServer1.Close() + + testServer2 := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + data, err := yaml.Marshal(parentDevfile2.Data) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + _, err = w.Write(data) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + })) + // create a listener with the desired port. + l2, err := net.Listen("tcp", uri2) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + + // NewUnstartedServer creates a listener. Close that listener and replace + // with the one we created. + testServer2.Listener.Close() + testServer2.Listener = l2 + + testServer2.Start() + defer testServer2.Close() + + testServer3 := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + data, err := yaml.Marshal(parentDevfile3.Data) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + _, err = w.Write(data) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + })) + // create a listener with the desired port. + l3, err := net.Listen("tcp", uri3) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + + // NewUnstartedServer creates a listener. Close that listener and replace + // with the one we created. + testServer3.Listener.Close() + testServer3.Listener = l3 + + testServer3.Start() + defer testServer3.Close() + t.Run("it should error out if URI is recursively referenced with multiple references", func(t *testing.T) { + err := parseParentAndPlugin(devFileObj) + expectedErr := fmt.Sprintf("URI %v%v is recursively referenced", httpPrefix, uri1) + // Unexpected error + if err == nil || !reflect.DeepEqual(expectedErr, err.Error()) { + t.Errorf("Test_parseParentAndPlugin_RecursivelyReference_withMultipleURI() unexpected error = %v", err) + return + } + + }) +}