From 3d5e04505b74a1d8ea1d2e2e1b57f92cd0b77c6c Mon Sep 17 00:00:00 2001 From: Armel Soro Date: Tue, 24 Oct 2023 10:10:14 +0200 Subject: [PATCH 1/9] Add test cases highlighting the issue and expectations Signed-off-by: Armel Soro --- pkg/devfile/parse_test.go | 86 ++++++++++++++++++- .../testdata/{devfile1.yaml => .devfile.yaml} | 0 pkg/devfile/testdata/.devfile.yml | 28 ++++++ pkg/devfile/testdata/devfile.yaml | 35 ++++++++ pkg/devfile/testdata/devfile.yml | 28 ++++++ pkg/devfile/testdata/valid-devfile.yaml.txt | 28 ++++++ 6 files changed, 204 insertions(+), 1 deletion(-) rename pkg/devfile/testdata/{devfile1.yaml => .devfile.yaml} (100%) create mode 100644 pkg/devfile/testdata/.devfile.yml create mode 100644 pkg/devfile/testdata/devfile.yaml create mode 100644 pkg/devfile/testdata/devfile.yml create mode 100644 pkg/devfile/testdata/valid-devfile.yaml.txt diff --git a/pkg/devfile/parse_test.go b/pkg/devfile/parse_test.go index eaafe75b..f7fbd252 100644 --- a/pkg/devfile/parse_test.go +++ b/pkg/devfile/parse_test.go @@ -415,7 +415,7 @@ spec: ExternalVariables: map[string]string{ "PARAMS": "baz", }, - Path: "./testdata/devfile1.yaml", + Path: "./testdata/devfile.yaml", }, }, wantCommandLine: "./main baz", @@ -527,6 +527,90 @@ spec: StarterProjects: map[string][]string{}, }, }, + { + name: "parsing devfile with .yml extension", + args: args{ + args: parser.ParserArgs{ + ExternalVariables: map[string]string{ + "PARAMS": "from devfile.yml", + }, + Path: "./testdata/devfile.yml", + }, + }, + wantCommandLine: "./main from devfile.yml", + wantVariables: map[string]string{ + "PARAMS": "from devfile.yml", + }, + wantVarWarning: variables.VariableWarning{ + Commands: map[string][]string{}, + Components: map[string][]string{}, + Projects: map[string][]string{}, + StarterProjects: map[string][]string{}, + }, + }, + { + name: "parsing .devfile with .yml extension", + args: args{ + args: parser.ParserArgs{ + ExternalVariables: map[string]string{ + "PARAMS": "from .devfile.yml", + }, + Path: "./testdata/.devfile.yml", + }, + }, + wantCommandLine: "./main from .devfile.yml", + wantVariables: map[string]string{ + "PARAMS": "from .devfile.yml", + }, + wantVarWarning: variables.VariableWarning{ + Commands: map[string][]string{}, + Components: map[string][]string{}, + Projects: map[string][]string{}, + StarterProjects: map[string][]string{}, + }, + }, + { + name: "parsing .devfile with .yaml extension", + args: args{ + args: parser.ParserArgs{ + ExternalVariables: map[string]string{ + "PARAMS": "from .devfile.yaml", + }, + Path: "./testdata/.devfile.yaml", + }, + }, + wantCommandLine: "./main from .devfile.yaml", + wantVariables: map[string]string{ + "PARAMS": "from .devfile.yaml", + }, + wantVarWarning: variables.VariableWarning{ + Commands: map[string][]string{}, + Components: map[string][]string{}, + Projects: map[string][]string{}, + StarterProjects: map[string][]string{}, + }, + }, + { + name: "parsing any valid devfile regardless of extension", + args: args{ + args: parser.ParserArgs{ + ExternalVariables: map[string]string{ + "PARAMS": "from any valid devfile file", + }, + Path: "./testdata/valid-devfile.yaml.txt", + }, + }, + wantCommandLine: "./main from any valid devfile file", + wantVariables: map[string]string{ + "PARAMS": "from any valid devfile file", + }, + wantVarWarning: variables.VariableWarning{ + Commands: map[string][]string{}, + Components: map[string][]string{}, + Projects: map[string][]string{}, + StarterProjects: map[string][]string{}, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/pkg/devfile/testdata/devfile1.yaml b/pkg/devfile/testdata/.devfile.yaml similarity index 100% rename from pkg/devfile/testdata/devfile1.yaml rename to pkg/devfile/testdata/.devfile.yaml diff --git a/pkg/devfile/testdata/.devfile.yml b/pkg/devfile/testdata/.devfile.yml new file mode 100644 index 00000000..981ff767 --- /dev/null +++ b/pkg/devfile/testdata/.devfile.yml @@ -0,0 +1,28 @@ +commands: +- exec: + commandLine: ./main {{ PARAMS }} + component: runtime + group: + isDefault: true + kind: run + workingDir: ${PROJECT_SOURCE} + id: run +components: +- container: + image: busybox:latest + command: [tail] + args: [ -f, /dev/null ] + mountSources: true + name: runtime +- kubernetes: + uri: http://127.0.0.1:8080/outerloop-deploy.yaml + name: outerloop-deploy +- openshift: + uri: http://127.0.0.1:8080/outerloop-service.yaml + name: outerloop-deploy2 +metadata: + description: Test stack (Busybox) + displayName: Test stack + name: my-test-app + version: 0.1.0 +schemaVersion: 2.2.0 \ No newline at end of file diff --git a/pkg/devfile/testdata/devfile.yaml b/pkg/devfile/testdata/devfile.yaml new file mode 100644 index 00000000..9286575b --- /dev/null +++ b/pkg/devfile/testdata/devfile.yaml @@ -0,0 +1,35 @@ +commands: +- exec: + commandLine: ./main {{ PARAMS }} + component: runtime + group: + isDefault: true + kind: run + workingDir: ${PROJECT_SOURCE} + id: run +components: +- container: + endpoints: + - name: http + targetPort: 8080 + image: golang:latest + memoryLimit: 1024Mi + mountSources: true + name: runtime +- kubernetes: + uri: http://127.0.0.1:8080/outerloop-deploy.yaml + name: outerloop-deploy +- openshift: + uri: http://127.0.0.1:8080/outerloop-service.yaml + name: outerloop-deploy2 +metadata: + description: Stack with the latest Go version + displayName: Go Runtime + icon: https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/golang.svg + language: go + name: my-go-app + projectType: go + tags: + - Go + version: 1.0.0 +schemaVersion: 2.2.0 \ No newline at end of file diff --git a/pkg/devfile/testdata/devfile.yml b/pkg/devfile/testdata/devfile.yml new file mode 100644 index 00000000..981ff767 --- /dev/null +++ b/pkg/devfile/testdata/devfile.yml @@ -0,0 +1,28 @@ +commands: +- exec: + commandLine: ./main {{ PARAMS }} + component: runtime + group: + isDefault: true + kind: run + workingDir: ${PROJECT_SOURCE} + id: run +components: +- container: + image: busybox:latest + command: [tail] + args: [ -f, /dev/null ] + mountSources: true + name: runtime +- kubernetes: + uri: http://127.0.0.1:8080/outerloop-deploy.yaml + name: outerloop-deploy +- openshift: + uri: http://127.0.0.1:8080/outerloop-service.yaml + name: outerloop-deploy2 +metadata: + description: Test stack (Busybox) + displayName: Test stack + name: my-test-app + version: 0.1.0 +schemaVersion: 2.2.0 \ No newline at end of file diff --git a/pkg/devfile/testdata/valid-devfile.yaml.txt b/pkg/devfile/testdata/valid-devfile.yaml.txt new file mode 100644 index 00000000..981ff767 --- /dev/null +++ b/pkg/devfile/testdata/valid-devfile.yaml.txt @@ -0,0 +1,28 @@ +commands: +- exec: + commandLine: ./main {{ PARAMS }} + component: runtime + group: + isDefault: true + kind: run + workingDir: ${PROJECT_SOURCE} + id: run +components: +- container: + image: busybox:latest + command: [tail] + args: [ -f, /dev/null ] + mountSources: true + name: runtime +- kubernetes: + uri: http://127.0.0.1:8080/outerloop-deploy.yaml + name: outerloop-deploy +- openshift: + uri: http://127.0.0.1:8080/outerloop-service.yaml + name: outerloop-deploy2 +metadata: + description: Test stack (Busybox) + displayName: Test stack + name: my-test-app + version: 0.1.0 +schemaVersion: 2.2.0 \ No newline at end of file From fd5fccb9f78610f3542c51a3bffbff6aedf54283 Mon Sep 17 00:00:00 2001 From: Armel Soro Date: Tue, 24 Oct 2023 10:12:13 +0200 Subject: [PATCH 2/9] Do not make any assumption on the file name when parsing The parser should act generically, and be able to parse any file it is provided, regardless of name and file extension. Signed-off-by: Armel Soro --- pkg/devfile/parser/context/context.go | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/pkg/devfile/parser/context/context.go b/pkg/devfile/parser/context/context.go index 97ab49d3..4fc66759 100644 --- a/pkg/devfile/parser/context/context.go +++ b/pkg/devfile/parser/context/context.go @@ -16,11 +16,7 @@ package parser import ( - "fmt" "net/url" - "os" - "path/filepath" - "strings" "github.com/devfile/library/v2/pkg/testingutil/filesystem" "github.com/devfile/library/v2/pkg/util" @@ -96,17 +92,6 @@ func (d *DevfileCtx) populateDevfile() (err error) { // Populate fills the DevfileCtx struct with relevant context info func (d *DevfileCtx) Populate() (err error) { - if !strings.HasSuffix(d.relPath, ".yaml") { - if _, err := os.Stat(filepath.Join(d.relPath, "devfile.yaml")); os.IsNotExist(err) { - if _, err := os.Stat(filepath.Join(d.relPath, ".devfile.yaml")); os.IsNotExist(err) { - return fmt.Errorf("the provided path is not a valid yaml filepath, and devfile.yaml or .devfile.yaml not found in the provided path : %s", d.relPath) - } else { - d.relPath = filepath.Join(d.relPath, ".devfile.yaml") - } - } else { - d.relPath = filepath.Join(d.relPath, "devfile.yaml") - } - } if err := d.SetAbsPath(); err != nil { return err } From b2cc7841dd7603ab668cc048c3d3e56deadce6e6 Mon Sep 17 00:00:00 2001 From: Armel Soro Date: Tue, 24 Oct 2023 10:13:43 +0200 Subject: [PATCH 3/9] Clarify and test the `DevfileObj.WriteYamlDevfile` behavior It actually is able to write to the path in the Devfile object context, not just a `devfile.yaml` file Signed-off-by: Armel Soro --- pkg/devfile/parser/writer.go | 6 +- pkg/devfile/parser/writer_test.go | 145 ++++++++++++++++++------------ 2 files changed, 91 insertions(+), 60 deletions(-) diff --git a/pkg/devfile/parser/writer.go b/pkg/devfile/parser/writer.go index ed3f2870..a22c218e 100644 --- a/pkg/devfile/parser/writer.go +++ b/pkg/devfile/parser/writer.go @@ -26,7 +26,7 @@ import ( "k8s.io/klog" ) -// WriteYamlDevfile creates a devfile.yaml file +// WriteYamlDevfile writes the content of the Devfile data to its absolute path on the filesystem. func (d *DevfileObj) WriteYamlDevfile() error { // Check kubernetes components, and restore original uri content @@ -41,7 +41,7 @@ func (d *DevfileObj) WriteYamlDevfile() error { if err != nil { return errors.Wrapf(err, "failed to marshal devfile object into yaml") } - // Write to devfile.yaml + // Write to the absolute path fs := d.Ctx.GetFs() if fs == nil { fs = filesystem.DefaultFs{} @@ -52,7 +52,7 @@ func (d *DevfileObj) WriteYamlDevfile() error { } // Successful - klog.V(2).Infof("devfile yaml created at: '%s'", OutputDevfileYamlPath) + klog.V(2).Infof("devfile written to: '%s'", d.Ctx.GetAbsPath()) return nil } diff --git a/pkg/devfile/parser/writer_test.go b/pkg/devfile/parser/writer_test.go index db50c8ec..e31d49ed 100644 --- a/pkg/devfile/parser/writer_test.go +++ b/pkg/devfile/parser/writer_test.go @@ -17,67 +17,96 @@ package parser import ( "fmt" + "strings" + "testing" + v1 "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2" apiAttributes "github.com/devfile/api/v2/pkg/attributes" devfilepkg "github.com/devfile/api/v2/pkg/devfile" devfileCtx "github.com/devfile/library/v2/pkg/devfile/parser/context" v2 "github.com/devfile/library/v2/pkg/devfile/parser/data/v2" "github.com/devfile/library/v2/pkg/testingutil/filesystem" - "strings" - "testing" ) -func TestWriteYamlDevfile(t *testing.T) { +func TestDevfileObj_WriteYamlDevfile(t *testing.T) { var ( schemaVersion = "2.2.0" - testName = "TestName" uri = "./relative/path/deploy.yaml" uri2 = "./relative/path/deploy2.yaml" - attributes = apiAttributes.Attributes{}.PutString(K8sLikeComponentOriginalURIKey, uri) - attributes2 = apiAttributes.Attributes{}.PutString(K8sLikeComponentOriginalURIKey, uri2) ) - t.Run("write yaml devfile", func(t *testing.T) { - - // Use fakeFs - fs := filesystem.NewFakeFs() + tests := []struct { + name string + fileName string + wantErr bool + }{ + { + name: "write devfile with .yaml extension", + fileName: OutputDevfileYamlPath, + }, + { + name: "write .devfile with .yaml extension", + fileName: ".devfile.yaml", + }, + { + name: "write devfile with .yml extension", + fileName: "devfile.yml", + }, + { + name: "write .devfile with .yml extension", + fileName: ".devfile.yml", + }, + { + name: "write any file, regardless of name and extension", + fileName: "some-random-file", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var ( + // Use fakeFs + fs = filesystem.NewFakeFs() + attributes = apiAttributes.Attributes{}.PutString(K8sLikeComponentOriginalURIKey, uri) + attributes2 = apiAttributes.Attributes{}.PutString(K8sLikeComponentOriginalURIKey, uri2) + ) - // DevfileObj - devfileObj := DevfileObj{ - Ctx: devfileCtx.FakeContext(fs, OutputDevfileYamlPath), - Data: &v2.DevfileV2{ - Devfile: v1.Devfile{ - DevfileHeader: devfilepkg.DevfileHeader{ - SchemaVersion: schemaVersion, - Metadata: devfilepkg.DevfileMetadata{ - Name: testName, + // DevfileObj + devfileObj := DevfileObj{ + Ctx: devfileCtx.FakeContext(fs, tt.fileName), + Data: &v2.DevfileV2{ + Devfile: v1.Devfile{ + DevfileHeader: devfilepkg.DevfileHeader{ + SchemaVersion: schemaVersion, + Metadata: devfilepkg.DevfileMetadata{ + Name: tt.name, + }, }, - }, - DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ - DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ - Components: []v1.Component{ - { - Name: "kubeComp", - Attributes: attributes, - ComponentUnion: v1.ComponentUnion{ - Kubernetes: &v1.KubernetesComponent{ - K8sLikeComponent: v1.K8sLikeComponent{ - K8sLikeComponentLocation: v1.K8sLikeComponentLocation{ - Inlined: "placeholder", + DevWorkspaceTemplateSpec: v1.DevWorkspaceTemplateSpec{ + DevWorkspaceTemplateSpecContent: v1.DevWorkspaceTemplateSpecContent{ + Components: []v1.Component{ + { + Name: "kubeComp", + Attributes: attributes, + ComponentUnion: v1.ComponentUnion{ + Kubernetes: &v1.KubernetesComponent{ + K8sLikeComponent: v1.K8sLikeComponent{ + K8sLikeComponentLocation: v1.K8sLikeComponentLocation{ + Inlined: "placeholder", + }, }, }, }, }, - }, - { - Name: "openshiftComp", - Attributes: attributes2, - ComponentUnion: v1.ComponentUnion{ - Openshift: &v1.OpenshiftComponent{ - K8sLikeComponent: v1.K8sLikeComponent{ - K8sLikeComponentLocation: v1.K8sLikeComponentLocation{ - Inlined: "placeholder", + { + Name: "openshiftComp", + Attributes: attributes2, + ComponentUnion: v1.ComponentUnion{ + Openshift: &v1.OpenshiftComponent{ + K8sLikeComponent: v1.K8sLikeComponent{ + K8sLikeComponentLocation: v1.K8sLikeComponentLocation{ + Inlined: "placeholder", + }, }, }, }, @@ -87,24 +116,26 @@ func TestWriteYamlDevfile(t *testing.T) { }, }, }, - }, - } - devfileObj.Ctx.SetConvertUriToInlined(true) + } + devfileObj.Ctx.SetConvertUriToInlined(true) - // test func() - err := devfileObj.WriteYamlDevfile() - if err != nil { - t.Errorf("TestWriteYamlDevfile() unexpected error: '%v'", err) - } + // test func() + err := devfileObj.WriteYamlDevfile() + if (err != nil) != tt.wantErr { + t.Errorf("TestWriteYamlDevfile() unexpected error: '%v', wantErr=%v", err, tt.wantErr) + return + } - if _, err := fs.Stat(OutputDevfileYamlPath); err != nil { - t.Errorf("TestWriteYamlDevfile() unexpected error: '%v'", err) - } + if _, err := fs.Stat(tt.fileName); err != nil { + t.Errorf("TestWriteYamlDevfile() unexpected error: '%v'", err) + } + + data, err := fs.ReadFile(tt.fileName) + if err != nil { + t.Errorf("TestWriteYamlDevfile() unexpected error: '%v'", err) + return + } - data, err := fs.ReadFile(OutputDevfileYamlPath) - if err != nil { - t.Errorf("TestWriteYamlDevfile() unexpected error: '%v'", err) - } else { content := string(data) if strings.Contains(content, "inlined") || strings.Contains(content, K8sLikeComponentOriginalURIKey) { t.Errorf("TestWriteYamlDevfile() failed: kubernetes component should not contain inlined or %s", K8sLikeComponentOriginalURIKey) @@ -115,6 +146,6 @@ func TestWriteYamlDevfile(t *testing.T) { if !strings.Contains(content, fmt.Sprintf("uri: %s", uri2)) { t.Errorf("TestWriteYamlDevfile() failed: openshift component does not contain uri") } - } - }) + }) + } } From 5d30522521b2d183ca6dfa882cd977d03297832a Mon Sep 17 00:00:00 2001 From: Armel Soro Date: Tue, 24 Oct 2023 10:14:33 +0200 Subject: [PATCH 4/9] Clarify the README doc Signed-off-by: Armel Soro --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 902d4352..6ab17c23 100644 --- a/README.md +++ b/README.md @@ -8,11 +8,11 @@ ## About The Devfile Parser library is a Golang module that: -1. parses the devfile.yaml as specified by the [api](https://devfile.github.io/devfile/api-reference.html) & [schema](https://github.com/devfile/api/tree/main/schemas/latest). -2. writes to the devfile.yaml with the updated data. +1. parses a devfile as specified by the [api](https://devfile.io/docs/2.2.1/devfile-schema) & [schema](https://github.com/devfile/api/tree/main/schemas/latest). +2. writes to the specified devfile with the updated data. 3. generates Kubernetes objects for the various devfile resources. 4. defines util functions for the devfile. -5. downloads resources from a parent devfile if specified in the devfile.yaml +5. downloads resources from a parent devfile if specified in the devfile. ## Private repository support From b03c9af6719a8edb82c3b3325f69fe985617394a Mon Sep 17 00:00:00 2001 From: Armel Soro Date: Tue, 31 Oct 2023 16:22:12 +0100 Subject: [PATCH 5/9] Revert "Do not make any assumption on the file name when parsing" This reverts commit fd5fccb9f78610f3542c51a3bffbff6aedf54283. Signed-off-by: Armel Soro --- pkg/devfile/parser/context/context.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/pkg/devfile/parser/context/context.go b/pkg/devfile/parser/context/context.go index 4fc66759..97ab49d3 100644 --- a/pkg/devfile/parser/context/context.go +++ b/pkg/devfile/parser/context/context.go @@ -16,7 +16,11 @@ package parser import ( + "fmt" "net/url" + "os" + "path/filepath" + "strings" "github.com/devfile/library/v2/pkg/testingutil/filesystem" "github.com/devfile/library/v2/pkg/util" @@ -92,6 +96,17 @@ func (d *DevfileCtx) populateDevfile() (err error) { // Populate fills the DevfileCtx struct with relevant context info func (d *DevfileCtx) Populate() (err error) { + if !strings.HasSuffix(d.relPath, ".yaml") { + if _, err := os.Stat(filepath.Join(d.relPath, "devfile.yaml")); os.IsNotExist(err) { + if _, err := os.Stat(filepath.Join(d.relPath, ".devfile.yaml")); os.IsNotExist(err) { + return fmt.Errorf("the provided path is not a valid yaml filepath, and devfile.yaml or .devfile.yaml not found in the provided path : %s", d.relPath) + } else { + d.relPath = filepath.Join(d.relPath, ".devfile.yaml") + } + } else { + d.relPath = filepath.Join(d.relPath, "devfile.yaml") + } + } if err := d.SetAbsPath(); err != nil { return err } From 4fa9a83362cf3c63e3c336f376dc08ee1aa8e1a6 Mon Sep 17 00:00:00 2001 From: Armel Soro Date: Tue, 31 Oct 2023 18:34:03 +0100 Subject: [PATCH 6/9] For backward compatibility, make sure to handle the case where a context path is passed Signed-off-by: Armel Soro --- pkg/devfile/parser/context/context.go | 21 +- pkg/devfile/parser/context/location.go | 64 ++++++ pkg/devfile/parser/context/location_test.go | 218 ++++++++++++++++++++ 3 files changed, 287 insertions(+), 16 deletions(-) create mode 100644 pkg/devfile/parser/context/location.go create mode 100644 pkg/devfile/parser/context/location_test.go diff --git a/pkg/devfile/parser/context/context.go b/pkg/devfile/parser/context/context.go index 97ab49d3..e1138185 100644 --- a/pkg/devfile/parser/context/context.go +++ b/pkg/devfile/parser/context/context.go @@ -16,11 +16,7 @@ package parser import ( - "fmt" "net/url" - "os" - "path/filepath" - "strings" "github.com/devfile/library/v2/pkg/testingutil/filesystem" "github.com/devfile/library/v2/pkg/util" @@ -96,23 +92,16 @@ func (d *DevfileCtx) populateDevfile() (err error) { // Populate fills the DevfileCtx struct with relevant context info func (d *DevfileCtx) Populate() (err error) { - if !strings.HasSuffix(d.relPath, ".yaml") { - if _, err := os.Stat(filepath.Join(d.relPath, "devfile.yaml")); os.IsNotExist(err) { - if _, err := os.Stat(filepath.Join(d.relPath, ".devfile.yaml")); os.IsNotExist(err) { - return fmt.Errorf("the provided path is not a valid yaml filepath, and devfile.yaml or .devfile.yaml not found in the provided path : %s", d.relPath) - } else { - d.relPath = filepath.Join(d.relPath, ".devfile.yaml") - } - } else { - d.relPath = filepath.Join(d.relPath, "devfile.yaml") - } + d.relPath, err = lookupDevfileFromPath(d.fs, d.relPath) + if err != nil { + return err } - if err := d.SetAbsPath(); err != nil { + if err = d.SetAbsPath(); err != nil { return err } klog.V(4).Infof("absolute devfile path: '%s'", d.absPath) // Read and save devfile content - if err := d.SetDevfileContent(); err != nil { + if err = d.SetDevfileContent(); err != nil { return err } return d.populateDevfile() diff --git a/pkg/devfile/parser/context/location.go b/pkg/devfile/parser/context/location.go new file mode 100644 index 00000000..559bb817 --- /dev/null +++ b/pkg/devfile/parser/context/location.go @@ -0,0 +1,64 @@ +// +// Copyright Red Hat, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package parser + +import ( + "errors" + "fmt" + "io/fs" + "path/filepath" + "strings" + + "github.com/devfile/library/v2/pkg/testingutil/filesystem" +) + +// possibleDevfileNames contains possible filenames for a devfile. +// Those are checked in this priority order from a given context dir. +var possibleDevfileNames = []string{ + "devfile.yaml", + ".devfile.yaml", + "devfile.yml", + ".devfile.yml", +} + +// lookupDevfileFromPath returns the file path to use as devfile filename, by looking at the relative path specified in relPath. +// If relPath is not a directory, it is returned as is. +// For backward compatibility, if relPath is a directory, it will try to detect the first existing devfile filename under relPath, +// based on the list of possible devfile filenames defined in the sorted possibleDevfileNames. +// It returns any error found while interacting with the filesystem, or if no file was found from the list of possible devfile names. +func lookupDevfileFromPath(fsys filesystem.Filesystem, relPath string) (string, error) { + stat, err := fsys.Stat(relPath) + if err != nil { + return "", err + } + + if !stat.IsDir() { + return relPath, nil + } + + for _, possibleDevfileName := range possibleDevfileNames { + p := filepath.Join(relPath, possibleDevfileName) + if _, err = fsys.Stat(p); errors.Is(err, fs.ErrNotExist) { + continue + } + return p, nil + } + + return "", fmt.Errorf( + "the provided path is not a valid yaml filepath, and no possible devfile could be found in the provided path : %s. Possible filenames for a devfile: %s", + relPath, + strings.Join(possibleDevfileNames, ", ")) +} diff --git a/pkg/devfile/parser/context/location_test.go b/pkg/devfile/parser/context/location_test.go new file mode 100644 index 00000000..8358a7f9 --- /dev/null +++ b/pkg/devfile/parser/context/location_test.go @@ -0,0 +1,218 @@ +// +// Copyright Red Hat, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package parser + +import ( + "path/filepath" + "testing" + + "github.com/devfile/library/v2/pkg/testingutil/filesystem" + "github.com/google/go-cmp/cmp" +) + +func Test_lookupDevfileFromPath(t *testing.T) { + type fields struct { + relPath string + fsCustomizer func(filesystem.Filesystem) error + } + tests := []struct { + name string + fields fields + want string + wantErr bool + }{ + { + name: "invalid relative path", + fields: fields{ + relPath: "non/existent/relative/path", + }, + wantErr: true, + }, + { + name: "invalid absolute path", + fields: fields{ + relPath: "/non/existent/absolute/path", + }, + wantErr: true, + }, + { + name: "relative path to file", + fields: fields{ + relPath: "my-devfile.yaml", + fsCustomizer: func(fs filesystem.Filesystem) error { + _, err := fs.Create("my-devfile.yaml") + return err + }, + }, + wantErr: false, + want: "my-devfile.yaml", + }, + { + name: "absolute path to file", + fields: fields{ + relPath: "/my-absolute-devfile.yaml", + fsCustomizer: func(fs filesystem.Filesystem) error { + _, err := fs.Create("/my-absolute-devfile.yaml") + return err + }, + }, + wantErr: false, + want: "/my-absolute-devfile.yaml", + }, + { + name: "empty directory", + fields: fields{ + relPath: "my-files", + fsCustomizer: func(fs filesystem.Filesystem) error { + return fs.MkdirAll("my-files", 0755) + }, + }, + wantErr: true, + }, + { + name: "directory with no devfile filename detected", + fields: fields{ + relPath: "my-files", + fsCustomizer: func(fs filesystem.Filesystem) error { + dir := "my-files" + err := fs.MkdirAll("my-files", 0755) + if err != nil { + return err + } + for _, f := range possibleDevfileNames { + if _, err = fs.Create(filepath.Join(dir, f+".bak")); err != nil { + return err + } + } + return err + }, + }, + wantErr: true, + }, + { + name: "directory with all possible devfile filenames => priority to devfile.yaml", + fields: fields{ + relPath: "my-devfiles", + fsCustomizer: func(fs filesystem.Filesystem) error { + dir := "my-devfiles" + err := fs.MkdirAll("my-devfiles", 0755) + if err != nil { + return err + } + for _, f := range possibleDevfileNames { + if _, err = fs.Create(filepath.Join(dir, f)); err != nil { + return err + } + } + return err + }, + }, + wantErr: false, + want: "my-devfiles/devfile.yaml", + }, + { + name: "directory with missing devfile.yaml => priority to .devfile.yaml", + fields: fields{ + relPath: "my-devfiles", + fsCustomizer: func(fs filesystem.Filesystem) error { + dir := "my-devfiles" + err := fs.MkdirAll("my-devfiles", 0755) + if err != nil { + return err + } + for _, f := range possibleDevfileNames { + if f == "devfile.yaml" { + continue + } + if _, err = fs.Create(filepath.Join(dir, f)); err != nil { + return err + } + } + return err + }, + }, + wantErr: false, + want: "my-devfiles/.devfile.yaml", + }, + { + name: "directory with missing devfile.yaml and .devfile.yaml => priority to devfile.yml", + fields: fields{ + relPath: "my-devfiles", + fsCustomizer: func(fs filesystem.Filesystem) error { + dir := "my-devfiles" + err := fs.MkdirAll("my-devfiles", 0755) + if err != nil { + return err + } + for _, f := range possibleDevfileNames { + if f == "devfile.yaml" || f == ".devfile.yaml" { + continue + } + if _, err = fs.Create(filepath.Join(dir, f)); err != nil { + return err + } + } + return err + }, + }, + wantErr: false, + want: "my-devfiles/devfile.yml", + }, + { + name: "directory with missing devfile.yaml and .devfile.yaml and devfile.yml => priority to .devfile.yml", + fields: fields{ + relPath: "my-devfiles", + fsCustomizer: func(fs filesystem.Filesystem) error { + dir := "my-devfiles" + err := fs.MkdirAll("my-devfiles", 0755) + if err != nil { + return err + } + for _, f := range possibleDevfileNames { + if f == "devfile.yaml" || f == ".devfile.yaml" || f == "devfile.yml" { + continue + } + if _, err = fs.Create(filepath.Join(dir, f)); err != nil { + return err + } + } + return err + }, + }, + wantErr: false, + want: "my-devfiles/.devfile.yml", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + fs := filesystem.NewFakeFs() + var err error + if tt.fields.fsCustomizer != nil { + err = tt.fields.fsCustomizer(fs) + } + if err != nil { + t.Fatalf("unexpected error while setting up filesystem: %v", err) + } + got, err := lookupDevfileFromPath(fs, tt.fields.relPath) + if (err != nil) != tt.wantErr { + t.Errorf("lookupDevfileFromPath(): unexpected error: %v. wantErr=%v", err, tt.wantErr) + } + if diff := cmp.Diff(tt.want, got); diff != "" { + t.Errorf("lookupDevfileFromPath(): mismatch (-want +got): %s\n", diff) + } + }) + } +} From 523a229843e91a8ab936fdd0e2e9d53ae356a6b2 Mon Sep 17 00:00:00 2001 From: Armel Soro Date: Tue, 31 Oct 2023 18:35:41 +0100 Subject: [PATCH 7/9] Enhance parser unit tests to check which file was parsed Signed-off-by: Armel Soro --- pkg/devfile/parse_test.go | 37 +++++++++++++++++++++ pkg/devfile/testdata/.devfile.yaml | 2 +- pkg/devfile/testdata/.devfile.yml | 2 +- pkg/devfile/testdata/devfile.yaml | 2 +- pkg/devfile/testdata/devfile.yml | 2 +- pkg/devfile/testdata/valid-devfile.yaml.txt | 2 +- 6 files changed, 42 insertions(+), 5 deletions(-) diff --git a/pkg/devfile/parse_test.go b/pkg/devfile/parse_test.go index f7fbd252..c216d482 100644 --- a/pkg/devfile/parse_test.go +++ b/pkg/devfile/parse_test.go @@ -17,6 +17,7 @@ package devfile import ( "context" + "fmt" "net" "net/http" "net/http/httptest" @@ -273,6 +274,7 @@ spec: wantKubernetesInline string wantOpenshiftInline string wantVariables map[string]string + additionalChecks func(parser.DevfileObj) error }{ { name: "with external overriding variables", @@ -547,6 +549,13 @@ spec: Projects: map[string][]string{}, StarterProjects: map[string][]string{}, }, + additionalChecks: func(devfileObj parser.DevfileObj) error { + if devfileObj.Data.GetMetadata().DisplayName != "Test stack (devfile.yml)" { + return fmt.Errorf("expected 'Test stack (devfile.yml)' as metadata.displayName in devfile, but got %q", + devfileObj.Data.GetMetadata().DisplayName) + } + return nil + }, }, { name: "parsing .devfile with .yml extension", @@ -568,6 +577,13 @@ spec: Projects: map[string][]string{}, StarterProjects: map[string][]string{}, }, + additionalChecks: func(devfileObj parser.DevfileObj) error { + if devfileObj.Data.GetMetadata().DisplayName != "Test stack (.devfile.yml)" { + return fmt.Errorf("expected 'Test stack (.devfile.yml)' as metadata.displayName in devfile, but got %q", + devfileObj.Data.GetMetadata().DisplayName) + } + return nil + }, }, { name: "parsing .devfile with .yaml extension", @@ -589,6 +605,13 @@ spec: Projects: map[string][]string{}, StarterProjects: map[string][]string{}, }, + additionalChecks: func(devfileObj parser.DevfileObj) error { + if devfileObj.Data.GetMetadata().DisplayName != "Go Runtime (.devfile.yaml)" { + return fmt.Errorf("expected 'Go Runtime (.devfile.yaml)' as metadata.displayName in devfile, but got %q", + devfileObj.Data.GetMetadata().DisplayName) + } + return nil + }, }, { name: "parsing any valid devfile regardless of extension", @@ -610,6 +633,13 @@ spec: Projects: map[string][]string{}, StarterProjects: map[string][]string{}, }, + additionalChecks: func(devfileObj parser.DevfileObj) error { + if devfileObj.Data.GetMetadata().DisplayName != "Test stack (valid-devfile.yaml.txt)" { + return fmt.Errorf("expected 'Test stack (valid-devfile.yaml.txt)' as metadata.displayName in devfile, but got %q", + devfileObj.Data.GetMetadata().DisplayName) + } + return nil + }, }, } for _, tt := range tests { @@ -731,6 +761,13 @@ spec: if !reflect.DeepEqual(variables, tt.wantVariables) { t.Errorf("variables are %+v, expected %+v", variables, tt.wantVariables) } + + if tt.additionalChecks != nil { + err = tt.additionalChecks(gotD) + if err != nil { + t.Errorf("unexpected error while performing specific checks: %v", err) + } + } }) } } diff --git a/pkg/devfile/testdata/.devfile.yaml b/pkg/devfile/testdata/.devfile.yaml index 9286575b..927dff87 100644 --- a/pkg/devfile/testdata/.devfile.yaml +++ b/pkg/devfile/testdata/.devfile.yaml @@ -24,7 +24,7 @@ components: name: outerloop-deploy2 metadata: description: Stack with the latest Go version - displayName: Go Runtime + displayName: Go Runtime (.devfile.yaml) icon: https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/golang.svg language: go name: my-go-app diff --git a/pkg/devfile/testdata/.devfile.yml b/pkg/devfile/testdata/.devfile.yml index 981ff767..3625c0b8 100644 --- a/pkg/devfile/testdata/.devfile.yml +++ b/pkg/devfile/testdata/.devfile.yml @@ -22,7 +22,7 @@ components: name: outerloop-deploy2 metadata: description: Test stack (Busybox) - displayName: Test stack + displayName: Test stack (.devfile.yml) name: my-test-app version: 0.1.0 schemaVersion: 2.2.0 \ No newline at end of file diff --git a/pkg/devfile/testdata/devfile.yaml b/pkg/devfile/testdata/devfile.yaml index 9286575b..63abe9ce 100644 --- a/pkg/devfile/testdata/devfile.yaml +++ b/pkg/devfile/testdata/devfile.yaml @@ -24,7 +24,7 @@ components: name: outerloop-deploy2 metadata: description: Stack with the latest Go version - displayName: Go Runtime + displayName: Go Runtime (devfile.yaml) icon: https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/golang.svg language: go name: my-go-app diff --git a/pkg/devfile/testdata/devfile.yml b/pkg/devfile/testdata/devfile.yml index 981ff767..23bd7e0b 100644 --- a/pkg/devfile/testdata/devfile.yml +++ b/pkg/devfile/testdata/devfile.yml @@ -22,7 +22,7 @@ components: name: outerloop-deploy2 metadata: description: Test stack (Busybox) - displayName: Test stack + displayName: Test stack (devfile.yml) name: my-test-app version: 0.1.0 schemaVersion: 2.2.0 \ No newline at end of file diff --git a/pkg/devfile/testdata/valid-devfile.yaml.txt b/pkg/devfile/testdata/valid-devfile.yaml.txt index 981ff767..8cb9d9e9 100644 --- a/pkg/devfile/testdata/valid-devfile.yaml.txt +++ b/pkg/devfile/testdata/valid-devfile.yaml.txt @@ -22,7 +22,7 @@ components: name: outerloop-deploy2 metadata: description: Test stack (Busybox) - displayName: Test stack + displayName: Test stack (valid-devfile.yaml.txt) name: my-test-app version: 0.1.0 schemaVersion: 2.2.0 \ No newline at end of file From a03659af4b1d2a2272689f3759028550f9c9e38b Mon Sep 17 00:00:00 2001 From: Armel Soro Date: Tue, 31 Oct 2023 18:47:42 +0100 Subject: [PATCH 8/9] Add more test cases to check the priority order when searching for default devfiles Signed-off-by: Armel Soro --- pkg/devfile/parse_test.go | 112 ++++++++++++++++++ .../priority-for-devfile_yml/.devfile.yml | 28 +++++ .../priority-for-devfile_yml/devfile.yml | 28 +++++ .../.devfile.yaml | 35 ++++++ .../.devfile.yml | 28 +++++ .../priority-for-dot_devfile_yaml/devfile.yml | 28 +++++ .../priority-for-dot_devfile_yml/.devfile.yml | 28 +++++ 7 files changed, 287 insertions(+) create mode 100644 pkg/devfile/testdata/priority-for-devfile_yml/.devfile.yml create mode 100644 pkg/devfile/testdata/priority-for-devfile_yml/devfile.yml create mode 100644 pkg/devfile/testdata/priority-for-dot_devfile_yaml/.devfile.yaml create mode 100644 pkg/devfile/testdata/priority-for-dot_devfile_yaml/.devfile.yml create mode 100644 pkg/devfile/testdata/priority-for-dot_devfile_yaml/devfile.yml create mode 100644 pkg/devfile/testdata/priority-for-dot_devfile_yml/.devfile.yml diff --git a/pkg/devfile/parse_test.go b/pkg/devfile/parse_test.go index c216d482..3213518a 100644 --- a/pkg/devfile/parse_test.go +++ b/pkg/devfile/parse_test.go @@ -529,6 +529,118 @@ spec: StarterProjects: map[string][]string{}, }, }, + { + name: "parsing devfile with context path containing multiple devfiles => priority to devfile.yaml", + args: args{ + args: parser.ParserArgs{ + ExternalVariables: map[string]string{ + "PARAMS": "from devfile.yaml based on priority", + }, + Path: "./testdata", + }, + }, + wantCommandLine: "./main from devfile.yaml based on priority", + wantVariables: map[string]string{ + "PARAMS": "from devfile.yaml based on priority", + }, + wantVarWarning: variables.VariableWarning{ + Commands: map[string][]string{}, + Components: map[string][]string{}, + Projects: map[string][]string{}, + StarterProjects: map[string][]string{}, + }, + additionalChecks: func(devfileObj parser.DevfileObj) error { + if devfileObj.Data.GetMetadata().DisplayName != "Go Runtime (devfile.yaml)" { + return fmt.Errorf("expected 'Go Runtime (devfile.yaml)' as metadata.displayName in devfile, but got %q", + devfileObj.Data.GetMetadata().DisplayName) + } + return nil + }, + }, + { + name: "parsing devfile with context path containing multiple devfiles => priority to .devfile.yaml", + args: args{ + args: parser.ParserArgs{ + ExternalVariables: map[string]string{ + "PARAMS": "from .devfile.yaml based on priority", + }, + Path: "./testdata/priority-for-dot_devfile_yaml", + }, + }, + wantCommandLine: "./main from .devfile.yaml based on priority", + wantVariables: map[string]string{ + "PARAMS": "from .devfile.yaml based on priority", + }, + wantVarWarning: variables.VariableWarning{ + Commands: map[string][]string{}, + Components: map[string][]string{}, + Projects: map[string][]string{}, + StarterProjects: map[string][]string{}, + }, + additionalChecks: func(devfileObj parser.DevfileObj) error { + if devfileObj.Data.GetMetadata().DisplayName != "Go Runtime (.devfile.yaml)" { + return fmt.Errorf("expected 'Go Runtime (.devfile.yaml)' as metadata.displayName in devfile, but got %q", + devfileObj.Data.GetMetadata().DisplayName) + } + return nil + }, + }, + { + name: "parsing devfile with context path containing multiple devfiles => priority to devfile.yml", + args: args{ + args: parser.ParserArgs{ + ExternalVariables: map[string]string{ + "PARAMS": "from devfile.yml based on priority", + }, + Path: "./testdata/priority-for-devfile_yml", + }, + }, + wantCommandLine: "./main from devfile.yml based on priority", + wantVariables: map[string]string{ + "PARAMS": "from devfile.yml based on priority", + }, + wantVarWarning: variables.VariableWarning{ + Commands: map[string][]string{}, + Components: map[string][]string{}, + Projects: map[string][]string{}, + StarterProjects: map[string][]string{}, + }, + additionalChecks: func(devfileObj parser.DevfileObj) error { + if devfileObj.Data.GetMetadata().DisplayName != "Test stack (devfile.yml)" { + return fmt.Errorf("expected 'Test stack (devfile.yml)' as metadata.displayName in devfile, but got %q", + devfileObj.Data.GetMetadata().DisplayName) + } + return nil + }, + }, + { + name: "parsing devfile with context path containing multiple devfiles => priority to .devfile.yml", + args: args{ + args: parser.ParserArgs{ + ExternalVariables: map[string]string{ + "PARAMS": "from .devfile.yml based on priority", + }, + Path: "./testdata/priority-for-dot_devfile_yml", + }, + }, + wantCommandLine: "./main from .devfile.yml based on priority", + wantVariables: map[string]string{ + "PARAMS": "from .devfile.yml based on priority", + }, + wantVarWarning: variables.VariableWarning{ + Commands: map[string][]string{}, + Components: map[string][]string{}, + Projects: map[string][]string{}, + StarterProjects: map[string][]string{}, + }, + additionalChecks: func(devfileObj parser.DevfileObj) error { + if devfileObj.Data.GetMetadata().DisplayName != "Test stack (.devfile.yml)" { + return fmt.Errorf("expected 'Test stack (.devfile.yml)' as metadata.displayName in devfile, but got %q", + devfileObj.Data.GetMetadata().DisplayName) + } + return nil + }, + }, { name: "parsing devfile with .yml extension", args: args{ diff --git a/pkg/devfile/testdata/priority-for-devfile_yml/.devfile.yml b/pkg/devfile/testdata/priority-for-devfile_yml/.devfile.yml new file mode 100644 index 00000000..3625c0b8 --- /dev/null +++ b/pkg/devfile/testdata/priority-for-devfile_yml/.devfile.yml @@ -0,0 +1,28 @@ +commands: +- exec: + commandLine: ./main {{ PARAMS }} + component: runtime + group: + isDefault: true + kind: run + workingDir: ${PROJECT_SOURCE} + id: run +components: +- container: + image: busybox:latest + command: [tail] + args: [ -f, /dev/null ] + mountSources: true + name: runtime +- kubernetes: + uri: http://127.0.0.1:8080/outerloop-deploy.yaml + name: outerloop-deploy +- openshift: + uri: http://127.0.0.1:8080/outerloop-service.yaml + name: outerloop-deploy2 +metadata: + description: Test stack (Busybox) + displayName: Test stack (.devfile.yml) + name: my-test-app + version: 0.1.0 +schemaVersion: 2.2.0 \ No newline at end of file diff --git a/pkg/devfile/testdata/priority-for-devfile_yml/devfile.yml b/pkg/devfile/testdata/priority-for-devfile_yml/devfile.yml new file mode 100644 index 00000000..23bd7e0b --- /dev/null +++ b/pkg/devfile/testdata/priority-for-devfile_yml/devfile.yml @@ -0,0 +1,28 @@ +commands: +- exec: + commandLine: ./main {{ PARAMS }} + component: runtime + group: + isDefault: true + kind: run + workingDir: ${PROJECT_SOURCE} + id: run +components: +- container: + image: busybox:latest + command: [tail] + args: [ -f, /dev/null ] + mountSources: true + name: runtime +- kubernetes: + uri: http://127.0.0.1:8080/outerloop-deploy.yaml + name: outerloop-deploy +- openshift: + uri: http://127.0.0.1:8080/outerloop-service.yaml + name: outerloop-deploy2 +metadata: + description: Test stack (Busybox) + displayName: Test stack (devfile.yml) + name: my-test-app + version: 0.1.0 +schemaVersion: 2.2.0 \ No newline at end of file diff --git a/pkg/devfile/testdata/priority-for-dot_devfile_yaml/.devfile.yaml b/pkg/devfile/testdata/priority-for-dot_devfile_yaml/.devfile.yaml new file mode 100644 index 00000000..927dff87 --- /dev/null +++ b/pkg/devfile/testdata/priority-for-dot_devfile_yaml/.devfile.yaml @@ -0,0 +1,35 @@ +commands: +- exec: + commandLine: ./main {{ PARAMS }} + component: runtime + group: + isDefault: true + kind: run + workingDir: ${PROJECT_SOURCE} + id: run +components: +- container: + endpoints: + - name: http + targetPort: 8080 + image: golang:latest + memoryLimit: 1024Mi + mountSources: true + name: runtime +- kubernetes: + uri: http://127.0.0.1:8080/outerloop-deploy.yaml + name: outerloop-deploy +- openshift: + uri: http://127.0.0.1:8080/outerloop-service.yaml + name: outerloop-deploy2 +metadata: + description: Stack with the latest Go version + displayName: Go Runtime (.devfile.yaml) + icon: https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/golang.svg + language: go + name: my-go-app + projectType: go + tags: + - Go + version: 1.0.0 +schemaVersion: 2.2.0 \ No newline at end of file diff --git a/pkg/devfile/testdata/priority-for-dot_devfile_yaml/.devfile.yml b/pkg/devfile/testdata/priority-for-dot_devfile_yaml/.devfile.yml new file mode 100644 index 00000000..3625c0b8 --- /dev/null +++ b/pkg/devfile/testdata/priority-for-dot_devfile_yaml/.devfile.yml @@ -0,0 +1,28 @@ +commands: +- exec: + commandLine: ./main {{ PARAMS }} + component: runtime + group: + isDefault: true + kind: run + workingDir: ${PROJECT_SOURCE} + id: run +components: +- container: + image: busybox:latest + command: [tail] + args: [ -f, /dev/null ] + mountSources: true + name: runtime +- kubernetes: + uri: http://127.0.0.1:8080/outerloop-deploy.yaml + name: outerloop-deploy +- openshift: + uri: http://127.0.0.1:8080/outerloop-service.yaml + name: outerloop-deploy2 +metadata: + description: Test stack (Busybox) + displayName: Test stack (.devfile.yml) + name: my-test-app + version: 0.1.0 +schemaVersion: 2.2.0 \ No newline at end of file diff --git a/pkg/devfile/testdata/priority-for-dot_devfile_yaml/devfile.yml b/pkg/devfile/testdata/priority-for-dot_devfile_yaml/devfile.yml new file mode 100644 index 00000000..23bd7e0b --- /dev/null +++ b/pkg/devfile/testdata/priority-for-dot_devfile_yaml/devfile.yml @@ -0,0 +1,28 @@ +commands: +- exec: + commandLine: ./main {{ PARAMS }} + component: runtime + group: + isDefault: true + kind: run + workingDir: ${PROJECT_SOURCE} + id: run +components: +- container: + image: busybox:latest + command: [tail] + args: [ -f, /dev/null ] + mountSources: true + name: runtime +- kubernetes: + uri: http://127.0.0.1:8080/outerloop-deploy.yaml + name: outerloop-deploy +- openshift: + uri: http://127.0.0.1:8080/outerloop-service.yaml + name: outerloop-deploy2 +metadata: + description: Test stack (Busybox) + displayName: Test stack (devfile.yml) + name: my-test-app + version: 0.1.0 +schemaVersion: 2.2.0 \ No newline at end of file diff --git a/pkg/devfile/testdata/priority-for-dot_devfile_yml/.devfile.yml b/pkg/devfile/testdata/priority-for-dot_devfile_yml/.devfile.yml new file mode 100644 index 00000000..3625c0b8 --- /dev/null +++ b/pkg/devfile/testdata/priority-for-dot_devfile_yml/.devfile.yml @@ -0,0 +1,28 @@ +commands: +- exec: + commandLine: ./main {{ PARAMS }} + component: runtime + group: + isDefault: true + kind: run + workingDir: ${PROJECT_SOURCE} + id: run +components: +- container: + image: busybox:latest + command: [tail] + args: [ -f, /dev/null ] + mountSources: true + name: runtime +- kubernetes: + uri: http://127.0.0.1:8080/outerloop-deploy.yaml + name: outerloop-deploy +- openshift: + uri: http://127.0.0.1:8080/outerloop-service.yaml + name: outerloop-deploy2 +metadata: + description: Test stack (Busybox) + displayName: Test stack (.devfile.yml) + name: my-test-app + version: 0.1.0 +schemaVersion: 2.2.0 \ No newline at end of file From 728befe3ea37211661bdaf148183a5540dbbd77c Mon Sep 17 00:00:00 2001 From: Armel Soro Date: Tue, 31 Oct 2023 18:55:25 +0100 Subject: [PATCH 9/9] Clarify the documentation of `ParserArgs.Path` Signed-off-by: Armel Soro --- pkg/devfile/parser/context/context.go | 5 ++++- pkg/devfile/parser/parse.go | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/pkg/devfile/parser/context/context.go b/pkg/devfile/parser/context/context.go index e1138185..0a283121 100644 --- a/pkg/devfile/parser/context/context.go +++ b/pkg/devfile/parser/context/context.go @@ -32,7 +32,10 @@ type DevfileCtx struct { // absolute path of devfile absPath string - // relative path of devfile + // relative path of devfile. + // It can also be a relative or absolute path to a folder containing one or more devfiles, + // in which case the library will try to pick an existing one, based on the following priority order: + // devfile.yaml > .devfile.yaml > devfile.yml > .devfile.yml relPath string // raw content of the devfile diff --git a/pkg/devfile/parser/parse.go b/pkg/devfile/parser/parse.go index f6b681f9..29bf13d9 100644 --- a/pkg/devfile/parser/parse.go +++ b/pkg/devfile/parser/parse.go @@ -80,7 +80,10 @@ func parseDevfile(d DevfileObj, resolveCtx *resolutionContextTree, tool resolver // ParserArgs is the struct to pass into parser functions which contains required info for parsing devfile. // It accepts devfile path, devfile URL or devfile content in []byte format. type ParserArgs struct { - // Path is a relative or absolute devfile path on disk + // Path is a relative or absolute devfile path on disk. + // It can also be a relative or absolute path to a folder containing one or more devfiles, + // in which case the library will try to pick an existing one, based on the following priority order: + // devfile.yaml > .devfile.yaml > devfile.yml > .devfile.yml Path string // URL is the URL address of the specific devfile. URL string