From cee370f8084687335f05d4b7752e901f50568a25 Mon Sep 17 00:00:00 2001 From: Joel Hendrix Date: Wed, 31 Jul 2019 17:04:24 -0700 Subject: [PATCH] Tooling fixes Return empty slice when no tags are found. Added module version string validation. Added optional arg 'initial module version' to versioner tool. --- tools/apidiff/repo/repo.go | 3 +++ tools/internal/modinfo/modinfo.go | 6 ++++++ tools/internal/modinfo/modinfo_test.go | 12 ++++++++++++ tools/versioner/cmd/root.go | 27 ++++++++++++++++++++------ 4 files changed, 42 insertions(+), 6 deletions(-) diff --git a/tools/apidiff/repo/repo.go b/tools/apidiff/repo/repo.go index bf7c4baa10ac..f9ac85cdecda 100644 --- a/tools/apidiff/repo/repo.go +++ b/tools/apidiff/repo/repo.go @@ -168,6 +168,9 @@ func (wt WorkingTree) ListTags(pattern string) ([]string, error) { if err != nil { return nil, errors.New(string(output)) } + if len(output) == 0 { + return []string{}, nil + } tags := strings.Split(strings.TrimSpace(string(output)), "\n") sort.Strings(tags) return tags, nil diff --git a/tools/internal/modinfo/modinfo.go b/tools/internal/modinfo/modinfo.go index 1ab4232c0bc8..f97fc35dfff9 100644 --- a/tools/internal/modinfo/modinfo.go +++ b/tools/internal/modinfo/modinfo.go @@ -206,3 +206,9 @@ func (m module) NewModule() bool { func (m module) GenerateReport() report.Package { return report.Generate(m.lhs, m.rhs, false, false) } + +// IsValidModuleVersion returns true if the provided string is a valid module version (e.g. v1.2.3). +func IsValidModuleVersion(v string) bool { + r := regexp.MustCompile(`^v\d+\.\d+\.\d+$`) + return r.MatchString(v) +} diff --git a/tools/internal/modinfo/modinfo_test.go b/tools/internal/modinfo/modinfo_test.go index ffea0aa50085..ee297fb8f78f 100644 --- a/tools/internal/modinfo/modinfo_test.go +++ b/tools/internal/modinfo/modinfo_test.go @@ -212,3 +212,15 @@ func TestCreateModuleNameFromPathFail(t *testing.T) { t.Fatalf("expected empty module name, got %s", n) } } + +func TestIsValidModuleVersion(t *testing.T) { + if !IsValidModuleVersion("v10.21.23") { + t.Fatal("unexpected invalid module version") + } + if IsValidModuleVersion("1.2.3") { + t.Fatal("unexpected valid module version, missing v") + } + if IsValidModuleVersion("v11.563") { + t.Fatal("unexpected valid module version, missing patch") + } +} diff --git a/tools/versioner/cmd/root.go b/tools/versioner/cmd/root.go index f9d39e4a12b8..6c254e97c4a7 100644 --- a/tools/versioner/cmd/root.go +++ b/tools/versioner/cmd/root.go @@ -32,15 +32,19 @@ import ( ) var rootCmd = &cobra.Command{ - Use: "versioner ", + Use: "versioner [initial module version]", Short: "Creates or updates the latest major version for a package from staged content.", Long: `This tool will compare a staged package against its latest major version to detect breaking changes. If there are no breaking changes the latest major version is updated with the staged content. If there are breaking changes the staged content becomes the next latest major vesion and the go.mod file is updated. +The default version for new modules is v1.0.0 or the value specified for [initial module version]. `, Args: func(cmd *cobra.Command, args []string) error { - if err := cobra.ExactArgs(1)(cmd, args); err != nil { + if err := cobra.MinimumNArgs(1)(cmd, args); err != nil { + return err + } + if err := cobra.MaximumNArgs(2)(cmd, args); err != nil { return err } return nil @@ -55,6 +59,8 @@ var ( semverRegex = regexp.MustCompile(`v\d+\.\d+\.\d+$`) // this is used so tests can hook getTags() to return whatever tags getTagsHook func(string, string) ([]string, error) + // default version to start a module at if not specified + startingModVer = "v1.0.0" ) func init() { @@ -81,6 +87,12 @@ func theCommand(args []string) error { // does the actual work func theCommandImpl(args []string) (string, error) { stage := filepath.Clean(args[0]) + if len(args) == 2 { + if !modinfo.IsValidModuleVersion(args[1]) { + return "", fmt.Errorf("the string '%s' is not a valid module version", args[1]) + } + startingModVer = args[1] + } lmv, err := findLatestMajorVersion(stage) if err != nil { return "", fmt.Errorf("failed to find latest major version: %v", err) @@ -273,13 +285,16 @@ func calculateModuleTag(tags []string, mod modinfo.Provider) (string, error) { if mod.BreakingChanges() { return tagPrefix + ".0.0", nil } + if len(tags) == 0 { + if mod.VersionSuffix() { + panic("module contains a version suffix but no tags were found") + } + // this is the first module version + return tagPrefix + "/" + startingModVer, nil + } if !mod.VersionSuffix() { tagPrefix = tagPrefix + "/v1" } - if len(tags) == 0 { - // this is v1.0.0 - return tagPrefix + ".0.0", nil - } tag := tags[len(tags)-1] v := semverRegex.FindString(tag) if v == "" {