From f1cfb63fb5254c0c8f2fc7a63c8f620cb4fd5884 Mon Sep 17 00:00:00 2001 From: Carlos Alexandro Becker Date: Fri, 26 Jan 2018 14:35:06 -0200 Subject: [PATCH] feat: allowing anchors and simplified code --- config/config.go | 119 +---------------------------- config/config_test.go | 7 +- config/testdata/invalid_config.yml | 38 +-------- 3 files changed, 10 insertions(+), 154 deletions(-) diff --git a/config/config.go b/config/config.go index 5f4aa5f0d..d2a6b9dd4 100644 --- a/config/config.go +++ b/config/config.go @@ -3,11 +3,9 @@ package config import ( - "fmt" "io" "io/ioutil" "os" - "strings" "github.com/apex/log" yaml "gopkg.in/yaml.v2" @@ -24,9 +22,6 @@ type GitHubURLs struct { type Repo struct { Owner string `yaml:",omitempty"` Name string `yaml:",omitempty"` - - // Capture all undefined fields and should be empty after loading - XXX map[string]interface{} `yaml:",inline"` } // String of the repo, e.g. owner/name @@ -52,9 +47,6 @@ type Homebrew struct { Homepage string `yaml:",omitempty"` SkipUpload bool `yaml:"skip_upload,omitempty"` DownloadStrategy string `yaml:"download_strategy,omitempty"` - - // Capture all undefined fields and should be empty after loading - XXX map[string]interface{} `yaml:",inline"` } // CommitAuthor is the author of a Git commit @@ -67,17 +59,11 @@ type CommitAuthor struct { type Hooks struct { Pre string `yaml:",omitempty"` Post string `yaml:",omitempty"` - - // Capture all undefined fields and should be empty after loading - XXX map[string]interface{} `yaml:",inline"` } // IgnoredBuild represents a build ignored by the user type IgnoredBuild struct { Goos, Goarch, Goarm string - - // Capture all undefined fields and should be empty after loading - XXX map[string]interface{} `yaml:",inline"` } // Build contains the build configuration section @@ -92,18 +78,12 @@ type Build struct { Binary string `yaml:",omitempty"` Hooks Hooks `yaml:",omitempty"` Env []string `yaml:",omitempty"` - - // Capture all undefined fields and should be empty after loading - XXX map[string]interface{} `yaml:",inline"` } // FormatOverride is used to specify a custom format for a specific GOOS. type FormatOverride struct { Goos string `yaml:",omitempty"` Format string `yaml:",omitempty"` - - // Capture all undefined fields and should be empty after loading - XXX map[string]interface{} `yaml:",inline"` } // Archive config used for the archive @@ -115,9 +95,6 @@ type Archive struct { FormatOverrides []FormatOverride `yaml:"format_overrides,omitempty"` WrapInDirectory bool `yaml:"wrap_in_directory,omitempty"` Files []string `yaml:",omitempty"` - - // Capture all undefined fields and should be empty after loading - XXX map[string]interface{} `yaml:",inline"` } // Release config used for the GitHub release @@ -126,8 +103,6 @@ type Release struct { Draft bool `yaml:",omitempty"` Prerelease bool `yaml:",omitempty"` NameTemplate string `yaml:"name_template,omitempty"` - // Capture all undefined fields and should be empty after loading - XXX map[string]interface{} `yaml:",inline"` } // FPM config @@ -145,9 +120,6 @@ type FPM struct { License string `yaml:",omitempty"` Bindir string `yaml:",omitempty"` Files map[string]string `yaml:",omitempty"` - - // Capture all undefined fields and should be empty after loading - XXX map[string]interface{} `yaml:",inline"` } // Sign config @@ -175,25 +147,16 @@ type Snapcraft struct { Grade string `yaml:",omitempty"` Confinement string `yaml:",omitempty"` Apps map[string]SnapcraftAppMetadata `yaml:",omitempty"` - - // Capture all undefined fields and should be empty after loading - XXX map[string]interface{} `yaml:",inline"` } // Snapshot config type Snapshot struct { NameTemplate string `yaml:"name_template,omitempty"` - - // Capture all undefined fields and should be empty after loading - XXX map[string]interface{} `yaml:",inline"` } // Checksum config type Checksum struct { NameTemplate string `yaml:"name_template,omitempty"` - - // Capture all undefined fields and should be empty after loading - XXX map[string]interface{} `yaml:",inline"` } // Docker image config @@ -208,9 +171,6 @@ type Docker struct { OldTagTemplate string `yaml:"tag_template,omitempty"` TagTemplates []string `yaml:"tag_templates,omitempty"` Files []string `yaml:"extra_files,omitempty"` - - // Capture all undefined fields and should be empty after loading - XXX map[string]interface{} `yaml:",inline"` } // Artifactory server configuration @@ -219,26 +179,17 @@ type Artifactory struct { Name string `yaml:",omitempty"` Username string `yaml:",omitempty"` Mode string `yaml:",omitempty"` - - // Capture all undefined fields and should be empty after loading - XXX map[string]interface{} `yaml:",inline"` } // Filters config type Filters struct { Exclude []string `yaml:",omitempty"` - - // Capture all undefined fields and should be empty after loading - XXX map[string]interface{} `yaml:",inline"` } // Changelog Config type Changelog struct { Filters Filters `yaml:",omitempty"` Sort string `yaml:",omitempty"` - - // Capture all undefined fields and should be empty after loading - XXX map[string]interface{} `yaml:",inline"` } // Project includes all project configuration @@ -263,9 +214,6 @@ type Project struct { // should be set if using github enterprise GitHubURLs GitHubURLs `yaml:"github_urls,omitempty"` - - // Capture all undefined fields and should be empty after loading - XXX map[string]interface{} `yaml:",inline"` } // Load config file @@ -284,72 +232,9 @@ func LoadReader(fd io.Reader) (config Project, err error) { if err != nil { return config, err } - if err := yaml.Unmarshal(data, &config); err != nil { + if err := yaml.UnmarshalStrict(data, &config); err != nil { return config, err } log.WithField("config", config).Debug("loaded config file") - return config, checkOverflows(config) -} - -// TODO: check if we can use UnmarshalStrict instead of the manual checkOverflow -func checkOverflows(config Project) error { - var overflow = &overflowChecker{} - overflow.check(config.XXX, "") - overflow.check(config.Archive.XXX, "archive") - for i, ov := range config.Archive.FormatOverrides { - overflow.check(ov.XXX, fmt.Sprintf("archive.format_overrides[%d]", i)) - } - overflow.check(config.Brew.XXX, "brew") - overflow.check(config.Brew.GitHub.XXX, "brew.github") - for i, build := range config.Builds { - overflow.check(build.XXX, fmt.Sprintf("builds[%d]", i)) - overflow.check(build.Hooks.XXX, fmt.Sprintf("builds[%d].hooks", i)) - for j, ignored := range build.Ignore { - overflow.check(ignored.XXX, fmt.Sprintf("builds[%d].ignored_builds[%d]", i, j)) - } - } - overflow.check(config.FPM.XXX, "fpm") - overflow.check(config.Snapcraft.XXX, "snapcraft") - overflow.check(config.Release.XXX, "release") - overflow.check(config.Release.GitHub.XXX, "release.github") - overflow.check(config.SingleBuild.XXX, "build") - overflow.check(config.SingleBuild.Hooks.XXX, "builds.hooks") - for i, ignored := range config.SingleBuild.Ignore { - overflow.check(ignored.XXX, fmt.Sprintf("builds.ignored_builds[%d]", i)) - } - overflow.check(config.Snapshot.XXX, "snapshot") - overflow.check(config.Checksum.XXX, "checksum") - for i, docker := range config.Dockers { - overflow.check(docker.XXX, fmt.Sprintf("docker[%d]", i)) - } - for i, artifactory := range config.Artifactories { - overflow.check(artifactory.XXX, fmt.Sprintf("artifactory[%d]", i)) - } - overflow.check(config.Changelog.XXX, "changelog") - overflow.check(config.Changelog.Filters.XXX, "changelog.filters") - return overflow.err() -} - -type overflowChecker struct { - fields []string -} - -func (o *overflowChecker) check(m map[string]interface{}, ctx string) { - for k := range m { - var key = fmt.Sprintf("%s.%s", ctx, k) - if ctx == "" { - key = k - } - o.fields = append(o.fields, key) - } -} - -func (o *overflowChecker) err() error { - if len(o.fields) == 0 { - return nil - } - return fmt.Errorf( - "unknown fields in the config file: %s", - strings.Join(o.fields, ", "), - ) + return config, nil } diff --git a/config/config_test.go b/config/config_test.go index 427a7225e..6c2041a59 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -59,10 +59,15 @@ func TestFileNotFound(t *testing.T) { func TestInvalidFields(t *testing.T) { _, err := Load("testdata/invalid_config.yml") - assert.EqualError(t, err, "unknown fields in the config file: invalid_root, archive.invalid_archive, archive.format_overrides[0].invalid_archive_fmtoverrides, brew.invalid_brew, brew.github.invalid_brew_github, builds[0].invalid_builds, builds[0].hooks.invalid_builds_hooks, builds[0].ignored_builds[0].invalid_builds_ignore, fpm.invalid_fpm, release.invalid_release, release.github.invalid_release_github, build.invalid_build, builds.hooks.invalid_build_hook, builds.ignored_builds[0].invalid_build_ignore, snapshot.invalid_snapshot, docker[0].invalid_docker, artifactory[0].invalid_artifactory, changelog.invalid_changelog, changelog.filters.invalid_filters") + assert.EqualError(t, err, "yaml: unmarshal errors:\n line 2: field invalid_yaml not found in struct config.Build") } func TestInvalidYaml(t *testing.T) { _, err := Load("testdata/invalid.yml") assert.EqualError(t, err, "yaml: line 1: did not find expected node content") } + +func TestConfigWithAnchors(t *testing.T) { + _, err := Load("testdata/anchor.yaml") + assert.NoError(t, err) +} diff --git a/config/testdata/invalid_config.yml b/config/testdata/invalid_config.yml index 6c2956f10..126c5f137 100644 --- a/config/testdata/invalid_config.yml +++ b/config/testdata/invalid_config.yml @@ -1,37 +1,3 @@ -invalid_root: 1 build: - invalid_build: 1 - hooks: - invalid_build_hook: 1 - ignore: - - invalid_build_ignore: 1 -builds: -- invalid_builds: 1 - hooks: - invalid_builds_hooks: 1 - ignore: - - invalid_builds_ignore: 1 -archive: - invalid_archive: 1 - format_overrides: - - invalid_archive_fmtoverrides: 1 -release: - invalid_release: 1 - github: - invalid_release_github: 1 -brew: - invalid_brew: 1 - github: - invalid_brew_github: 1 -fpm: - invalid_fpm: 1 -snapshot: - invalid_snapshot: 1 -dockers: - - invalid_docker: 1 -artifactories: - - invalid_artifactory: 1 -changelog: - invalid_changelog: 1 - filters: - invalid_filters: 1 + invalid_yaml: 1 +