From d924b765b93a279dc7af72c3908d88e936262593 Mon Sep 17 00:00:00 2001 From: Jordan Keister Date: Wed, 14 Feb 2024 11:42:49 -0600 Subject: [PATCH] use contributions path as fallback search for template inputs (#1221) Signed-off-by: Jordan Keister --- alpha/template/composite/builder.go | 32 +++++-- alpha/template/composite/builder_test.go | 97 ++++++++++++++++++++++ alpha/template/composite/composite.go | 8 +- alpha/template/composite/composite_test.go | 2 +- alpha/template/composite/types.go | 1 + cmd/opm/alpha/template/composite.go | 8 +- 6 files changed, 138 insertions(+), 10 deletions(-) diff --git a/alpha/template/composite/builder.go b/alpha/template/composite/builder.go index 953868f3e..e22b5e49c 100644 --- a/alpha/template/composite/builder.go +++ b/alpha/template/composite/builder.go @@ -28,8 +28,9 @@ const ( ) type BuilderConfig struct { - WorkingDir string - OutputType string + WorkingDir string + OutputType string + ContributionPath string } type Builder interface { @@ -80,7 +81,14 @@ func (bb *BasicBuilder) Build(ctx context.Context, reg image.Registry, dir strin b := basictemplate.Template{Registry: reg} reader, err := os.Open(basicConfig.Input) if err != nil { - return fmt.Errorf("error reading basic template: %v", err) + if os.IsNotExist(err) && bb.builderCfg.ContributionPath != "" { + reader, err = os.Open(path.Join(bb.builderCfg.ContributionPath, basicConfig.Input)) + if err != nil { + return fmt.Errorf("error reading basic template: %v (tried contribution-local path: %q)", err, bb.builderCfg.ContributionPath) + } + } else { + return fmt.Errorf("error reading basic template: %v", err) + } } defer reader.Close() @@ -140,7 +148,14 @@ func (sb *SemverBuilder) Build(ctx context.Context, reg image.Registry, dir stri reader, err := os.Open(semverConfig.Input) if err != nil { - return fmt.Errorf("error reading semver template: %v", err) + if os.IsNotExist(err) && sb.builderCfg.ContributionPath != "" { + reader, err = os.Open(path.Join(sb.builderCfg.ContributionPath, semverConfig.Input)) + if err != nil { + return fmt.Errorf("error reading semver template: %v (tried contribution-local path: %q)", err, sb.builderCfg.ContributionPath) + } + } else { + return fmt.Errorf("error reading semver template: %v", err) + } } defer reader.Close() @@ -202,7 +217,14 @@ func (rb *RawBuilder) Build(ctx context.Context, _ image.Registry, dir string, t reader, err := os.Open(rawConfig.Input) if err != nil { - return fmt.Errorf("error reading raw input file: %s, %v", rawConfig.Input, err) + if os.IsNotExist(err) && rb.builderCfg.ContributionPath != "" { + reader, err = os.Open(path.Join(rb.builderCfg.ContributionPath, rawConfig.Input)) + if err != nil { + return fmt.Errorf("error reading raw input file: %v (tried contribution-local path: %q)", err, rb.builderCfg.ContributionPath) + } + } else { + return fmt.Errorf("error reading raw input file: %v", err) + } } defer reader.Close() diff --git a/alpha/template/composite/builder_test.go b/alpha/template/composite/builder_test.go index 63a127a97..4a70c3067 100644 --- a/alpha/template/composite/builder_test.go +++ b/alpha/template/composite/builder_test.go @@ -6,6 +6,7 @@ import ( "io" "os" "path" + "path/filepath" "testing" "github.com/stretchr/testify/require" @@ -210,6 +211,38 @@ func TestBasicBuilder(t *testing.T) { "basic template configuration is invalid: basic template config must have a non-empty input (templateDefinition.config.input),basic template config must have a non-empty output (templateDefinition.config.output)") }, }, + { + name: "successful basic build yaml output using contribution cwd to find inputs", + validate: true, + basicBuilder: NewBasicBuilder(BuilderConfig{ + WorkingDir: testDir, + OutputType: "yaml", + ContributionPath: filepath.Join(testDir, "components"), + }), + templateDefinition: TemplateDefinition{ + Schema: BasicBuilderSchema, + Config: []byte(fmt.Sprintf(validConfigTemplate, "basic.yaml", "catalog.yaml")), + }, + files: map[string]string{ + "components/basic.yaml": basicYaml, + }, + buildAssertions: func(t *testing.T, dir string, buildErr error) { + require.NoError(t, buildErr) + // check if the catalog.yaml file exists in the correct place + filePath := path.Join(dir, "catalog.yaml") + _, err := os.Stat(filePath) + require.NoError(t, err) + file, err := os.Open(filePath) + require.NoError(t, err) + defer file.Close() + fileData, err := io.ReadAll(file) + require.NoError(t, err) + require.Equal(t, string(fileData), basicBuiltFbcYaml) + }, + validateAssertions: func(t *testing.T, validateErr error) { + require.NoError(t, validateErr) + }, + }, } for i, tc := range testCases { @@ -673,6 +706,38 @@ func TestSemverBuilder(t *testing.T) { ) }, }, + { + name: "successful semver build json output using contribution cwd to find inputs", + validate: true, + semverBuilder: NewSemverBuilder(BuilderConfig{ + WorkingDir: testDir, + OutputType: "json", + ContributionPath: filepath.Join(testDir, "components"), + }), + templateDefinition: TemplateDefinition{ + Schema: SemverBuilderSchema, + Config: []byte(fmt.Sprintf(validConfigTemplate, "semver.yaml", "catalog.json")), + }, + files: map[string]string{ + "components/semver.yaml": semverYaml, + }, + buildAssertions: func(t *testing.T, dir string, buildErr error) { + require.NoError(t, buildErr) + // check if the catalog.yaml file exists in the correct place + filePath := path.Join(dir, "catalog.json") + _, err := os.Stat(filePath) + require.NoError(t, err) + file, err := os.Open(filePath) + require.NoError(t, err) + defer file.Close() + fileData, err := io.ReadAll(file) + require.NoError(t, err) + require.Equal(t, semverBuiltFbcJson, string(fileData)) + }, + validateAssertions: func(t *testing.T, validateErr error) { + require.NoError(t, validateErr) + }, + }, } for i, tc := range testCases { @@ -1144,6 +1209,38 @@ func TestRawBuilder(t *testing.T) { "raw template configuration is invalid: raw template config must have a non-empty input (templateDefinition.config.input),raw template config must have a non-empty output (templateDefinition.config.output)") }, }, + { + name: "successful raw build json output using contribution cwd to find inputs", + validate: true, + rawBuilder: NewRawBuilder(BuilderConfig{ + WorkingDir: testDir, + OutputType: "json", + ContributionPath: filepath.Join(testDir, "components"), + }), + templateDefinition: TemplateDefinition{ + Schema: RawBuilderSchema, + Config: []byte(fmt.Sprintf(validConfigTemplate, "raw.yaml", "catalog.json")), + }, + files: map[string]string{ + "components/raw.yaml": rawYaml, + }, + buildAssertions: func(t *testing.T, dir string, buildErr error) { + require.NoError(t, buildErr) + // check if the catalog.yaml file exists in the correct place + filePath := path.Join(dir, "catalog.json") + _, err := os.Stat(filePath) + require.NoError(t, err) + file, err := os.Open(filePath) + require.NoError(t, err) + defer file.Close() + fileData, err := io.ReadAll(file) + require.NoError(t, err) + require.Equal(t, string(fileData), rawBuiltFbcJson) + }, + validateAssertions: func(t *testing.T, validateErr error) { + require.NoError(t, validateErr) + }, + }, } for i, tc := range testCases { diff --git a/alpha/template/composite/composite.go b/alpha/template/composite/composite.go index a4335fd9b..e88daa7b2 100644 --- a/alpha/template/composite/composite.go +++ b/alpha/template/composite/composite.go @@ -19,9 +19,10 @@ func WithCatalogFile(catalogFile io.Reader) TemplateOption { } } -func WithContributionFile(contribFile io.Reader) TemplateOption { +func WithContributionFile(contribFile io.Reader, contribPath string) TemplateOption { return func(t *Template) { t.contributionFile = contribFile + t.contributionPath = contribPath } } @@ -230,8 +231,9 @@ func (t *Template) newCatalogBuilderMap(catalogs []Catalog, outputType string) ( builderMap := make(BuilderMap) for _, schema := range catalog.Builders { builder, err := t.builderForSchema(schema, BuilderConfig{ - WorkingDir: catalog.Destination.WorkingDir, - OutputType: outputType, + WorkingDir: catalog.Destination.WorkingDir, + OutputType: outputType, + ContributionPath: t.contributionPath, }) if err != nil { return nil, fmt.Errorf("getting builder %q for catalog %q: %v", schema, catalog.Name, err) diff --git a/alpha/template/composite/composite_test.go b/alpha/template/composite/composite_test.go index ac4da6ed4..f46f39446 100644 --- a/alpha/template/composite/composite_test.go +++ b/alpha/template/composite/composite_test.go @@ -436,7 +436,7 @@ func TestParseContributionSpec(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - template := NewTemplate(WithContributionFile(strings.NewReader(tc.composite))) + template := NewTemplate(WithContributionFile(strings.NewReader(tc.composite), "")) contrib, err := template.parseContributionSpec() tc.assertions(t, contrib, err) }) diff --git a/alpha/template/composite/types.go b/alpha/template/composite/types.go index 93b53883c..32116bea1 100644 --- a/alpha/template/composite/types.go +++ b/alpha/template/composite/types.go @@ -43,6 +43,7 @@ type builderFunc func(BuilderConfig) Builder type Template struct { catalogFile io.Reader contributionFile io.Reader + contributionPath string validate bool outputType string registry image.Registry diff --git a/cmd/opm/alpha/template/composite.go b/cmd/opm/alpha/template/composite.go index df4499876..20c9a1e5c 100644 --- a/cmd/opm/alpha/template/composite.go +++ b/cmd/opm/alpha/template/composite.go @@ -4,6 +4,7 @@ import ( "log" "net/http" "os" + "path/filepath" "github.com/spf13/cobra" @@ -49,6 +50,11 @@ and a 'composite template' file`, } defer compositeReader.Close() + compositePath, err := filepath.Abs(filepath.Dir(compositeFile)) + if err != nil { + log.Fatalf("getting absolute path of composite config file %q: %v", compositeFile, err) + } + // catalog maintainer's 'catalogs.yaml' file tempCatalog, err := composite.FetchCatalogConfig(catalogFile, http.DefaultClient) if err != nil { @@ -58,7 +64,7 @@ and a 'composite template' file`, template := composite.NewTemplate( composite.WithCatalogFile(tempCatalog), - composite.WithContributionFile(compositeReader), + composite.WithContributionFile(compositeReader, compositePath), composite.WithOutputType(output), composite.WithRegistry(reg), )