Skip to content

Commit

Permalink
Fix command line flag parsing for common options
Browse files Browse the repository at this point in the history
* Add flag to set the prefix for a prerelease if one isn't present on the given version.
* Add tests for the new flag
* Update tests to catch a few more edge cases

Fixes #2
  • Loading branch information
jaevans committed Aug 27, 2024
1 parent 53b42aa commit 6a25dd3
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 38 deletions.
36 changes: 23 additions & 13 deletions cmd/bump.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@ import (
// "golang.org/x/mod/semver"

"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/spf13/viper"
)

// bumpCmd represents the bump command
var bumpCmd = &cobra.Command{
Use: "bump",
Short: "Bump a semver version",
Long: `Bump a semver version to the next major, minor, patch, or prerelease version.
Long: `
Bump a semver version to the next major, minor, patch, or prerelease version.
Examples:
semvertool bump --major 0.1.0-alpha.1+build.1
Expand All @@ -34,36 +36,44 @@ var bumpCmd = &cobra.Command{
semvertool bump --prerelease 1.1.1-alpha.1.0
1.1.1-alpha.1.1
semvertool bump --build $(git rev-parse --short HEAD) 1.1.1-alpha.1
1.1.1-alpha.2+3f6d1270
semvertool bump 1.1.1-alpha.2+3f6d1270`,
semvertool bump 1.1.1-alpha.2+3f6d1270
1.1.1
semvertool bump --prerelease --prerelease-prefix snapshot 1.1.1
1.1.2-snapshot.1
`,
Run: runBump,
}

func init() {
rootCmd.AddCommand(bumpCmd)

addCommonBumpFlags(bumpCmd)
bumpCmd.Flags().String("metadata", "", "Append the given string to the version as metadata.")

viper.BindPFlags(bumpCmd.Flags())
cf := getCommonBumpFlags()
bumpCmd.Flags().AddFlagSet(cf)
bumpCmd.Flags().StringP("metadata", "", "", "Append the given string to the version as metadata.")
bumpCmd.MarkFlagsMutuallyExclusive("major", "minor", "patch", "prerelease", "from-message")
}

func runBump(cmd *cobra.Command, args []string) {

// Flags can only be bound once, so it needs to be done in the Run function
// The also need to be done one at a time, so we can't use BindPFlags
// See https://github.com/spf13/viper/issues/375#issuecomment-794668149
cmd.Flags().VisitAll(func(flag *pflag.Flag) {
_ = viper.BindPFlag(flag.Name, flag)
})
if len(args) < 1 {
cmd.Help()
_ = cmd.Help()
return
}
if len(args) > 1 {
fmt.Println("Too many arguments")
fmt.Println()
cmd.Help()
_ = cmd.Help()
return
}
oldV := args[0]
newV, err := doBump(oldV, getBumpType())
bumpType := getBumpType()
newV, err := doBump(oldV, bumpType)
if err != nil {
fmt.Println("Error bumping version:", err)
return
Expand Down
23 changes: 20 additions & 3 deletions cmd/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/Masterminds/semver"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/spf13/viper"

goget "github.com/go-git/go-git/v5"
Expand Down Expand Up @@ -44,17 +45,27 @@ var gitCmd = &cobra.Command{
git tag v1.0.0-alpha.2+3f6d1270
semvertool git --minor
v1.1.0
git tag v1.0.0-alpha.3+3f6d1270
semvertool git
v1.0.1
git tag v1.1.0
semvertool git --prerelease
v1.1.1-alpha.1
`,
Run: runGit,
}

func init() {
rootCmd.AddCommand(gitCmd)

addCommonBumpFlags(gitCmd)
cf := getCommonBumpFlags()
gitCmd.Flags().AddFlagSet(cf)
gitCmd.Flags().BoolP("hash", "s", false, "Append the short hash (sha) to the version as metadata information.")
gitCmd.Flags().BoolP("from-commit", "c", false, "Extract the bump type from a commit message")
viper.BindPFlags(gitCmd.Flags())
gitCmd.MarkFlagsMutuallyExclusive("major", "minor", "patch", "prerelease", "from-message", "from-commit")

}

func getTags(repo *goget.Repository) ([]*semver.Version, error) {
Expand Down Expand Up @@ -130,8 +141,14 @@ func gitBump(repo *goget.Repository) (*semver.Version, error) {
}

func runGit(cmd *cobra.Command, args []string) {
// Flags can only be bound once, so it needs to be done in the Run function
// The also need to be done one at a time, so we can't use BindPFlags
// See https://github.com/spf13/viper/issues/375#issuecomment-794668149
cmd.Flags().VisitAll(func(flag *pflag.Flag) {
_ = viper.BindPFlag(flag.Name, flag)
})
if len(args) != 0 {
fmt.Println("No arguments allowed")
fmt.Printf("Unexpected arguments: %v\n", args)
return
}

Expand Down
19 changes: 19 additions & 0 deletions cmd/git_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,26 @@ func TestGitBump_WithHash(t *testing.T) {

viper.Set("hash", true)
result, err := gitBump(repo)
viper.Reset()
expected := "v1.0.1+" + shortHash
assert.NoError(t, err)
assert.Equal(t, expected, result.Original())
}

func TestGitBump_WithPrereleasePrefix(t *testing.T) {
repo, err := setupRepo()
assert.NoError(t, err)

commit, err := commitFile("file1.txt", repo)
assert.NoError(t, err)

_, err = repo.CreateTag("v1.0.0", commit, nil)
assert.NoError(t, err)

viper.Set("prerelease", true)
viper.Set("prerelease-prefix", "alpha")
result, err := gitBump(repo)
expected := "v1.0.1-alpha.1"
assert.NoError(t, err)
assert.Equal(t, expected, result.Original())
}
32 changes: 16 additions & 16 deletions cmd/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"strings"

"github.com/Masterminds/semver"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/spf13/viper"
)

Expand All @@ -19,8 +19,8 @@ const (
MinorBump BumpType = "minor"
PatchBump BumpType = "patch"
PrereleaseBump BumpType = "prerelease"
UnknownBump BumpType = ""
NoBump BumpType = ""
UnknownBump BumpType = "unknown"
NoBump BumpType = "none"
)

func extractBumpTypeFromMessage(s string) BumpType {
Expand Down Expand Up @@ -67,9 +67,9 @@ func getBumpType() BumpType {
messageBump := extractBumpTypeFromMessage(fromMessage)
if messageBump == UnknownBump || messageBump == NoBump {
fmt.Println("No valid bump type found in the commit message")
} else {
return messageBump
}
return messageBump

}
if viper.GetBool("major") {
return MajorBump
Expand Down Expand Up @@ -105,10 +105,9 @@ func doBump(version string, bumpWhat BumpType) (*semver.Version, error) {
case PrereleaseBump:
prerelease := v.Prerelease()
if len(prerelease) == 0 {
fmt.Println("No prerelease found, bumping patch version")
vNew := v.IncPatch()
v = &vNew
return v, nil
vNew, err := vNew.SetPrerelease(viper.GetString("prerelease-prefix") + ".1")
return &vNew, err
}
prefix, number, err := extractTrailingDigits(prerelease)
if err == ErrNoTrailingDigits && !strings.Contains(prefix, ".") {
Expand All @@ -134,12 +133,13 @@ func doBump(version string, bumpWhat BumpType) (*semver.Version, error) {
return v, nil
}

func addCommonBumpFlags(cmd *cobra.Command) {
cmd.Flags().Bool("major", false, "Bump the major version")
cmd.Flags().Bool("minor", false, "Bump the minor version")
cmd.Flags().Bool("patch", false, "Bump the patch version")
cmd.Flags().Bool("prerelease", false, "Bump the prerelease version")
cmd.Flags().StringP("from-message", "m", "", "Extract the bump type from a commit message")
cmd.MarkFlagsMutuallyExclusive("major", "minor", "patch", "prerelease", "from-message")
viper.BindPFlags(cmd.Flags())
func getCommonBumpFlags() *pflag.FlagSet {
commonFlags := pflag.NewFlagSet("common", pflag.ExitOnError)
commonFlags.Bool("major", false, "Bump the major version")
commonFlags.Bool("minor", false, "Bump the minor version")
commonFlags.Bool("patch", false, "Bump the patch version")
commonFlags.Bool("prerelease", false, "Bump the prerelease version")
commonFlags.StringP("from-message", "m", "", "Extract the bump type from a commit message")
commonFlags.StringP("prerelease-prefix", "p", "prerelease", "Set the prefix for the prerelease version if there is no existing prefix.")
return commonFlags
}
78 changes: 72 additions & 6 deletions cmd/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func TestExtractBumpType_ValidCaseInsensitive(t *testing.T) {
// Returns an empty string when given an empty string.
func TestExtractBumpType_EmptyString(t *testing.T) {
commitMessage := ""
expected := UnknownBump
expected := NoBump

result := extractBumpTypeFromMessage(commitMessage)

Expand All @@ -78,7 +78,18 @@ func TestExtractBumpType_EmptyString(t *testing.T) {
// Returns an empty string when given a commit message that does not contain a bump tag.
func TestExtractBumpType_NoBumpTag(t *testing.T) {
commitMessage := "Fix bug"
expected := UnknownBump
expected := NoBump

result := extractBumpTypeFromMessage(commitMessage)

if result != expected {
t.Errorf("Expected '%s', but got '%s'", expected, result)
}
}

func TestExtractBumpType_BumpNoType(t *testing.T) {
commitMessage := "Fix bug [bump ]"
expected := NoBump

result := extractBumpTypeFromMessage(commitMessage)

Expand All @@ -90,7 +101,7 @@ func TestExtractBumpType_NoBumpTag(t *testing.T) {
// Returns an empty string when given a commit message containing a bump tag with an invalid bump type.
func TestExtractBumpType_InvalidBumpType(t *testing.T) {
commitMessage := "[bump invalid]"
expected := UnknownBump
expected := NoBump

result := extractBumpTypeFromMessage(commitMessage)

Expand Down Expand Up @@ -126,7 +137,7 @@ func TestExtractBumpType_ValidBumpTypeWithWhitespace(t *testing.T) {
// Returns an empty string when given a commit message containing a bump tag with a valid bump type but with additional non-whitespace characters.
func TestExtractBumpType_InvalidBumpTypeWithAdditionalCharactersAfter(t *testing.T) {
commitMessage := "[bump majorabc]"
expected := UnknownBump
expected := NoBump

result := extractBumpTypeFromMessage(commitMessage)

Expand All @@ -138,7 +149,7 @@ func TestExtractBumpType_InvalidBumpTypeWithAdditionalCharactersAfter(t *testing
// Returns an empty string when given a commit message containing a bump tag with a valid bump type but with additional characters before the tag.
func TestExtractBumpType_InvalidBumpTypeWithAdditionalCharactersBefore(t *testing.T) {
commitMessage := "Some additional characters [bump asdf major]"
expected := UnknownBump
expected := NoBump

result := extractBumpTypeFromMessage(commitMessage)

Expand Down Expand Up @@ -248,6 +259,22 @@ func TestGetBUmpType_FromEmptyMessage(t *testing.T) {
assert.Equal(t, expected, result)
}

func TestGetBUmpType_FromEmptyBumpMessage(t *testing.T) {
viper.Reset()
viper.Set("from-message", "[bump]")
expected := NoBump
result := getBumpType()
assert.Equal(t, expected, result)
}

func TestGetBUmpType_FromInvalidBumpMessage(t *testing.T) {
viper.Reset()
viper.Set("from-message", "[bump invalid]")
expected := NoBump
result := getBumpType()
assert.Equal(t, expected, result)
}

// **********************
// doBump
// **********************
Expand Down Expand Up @@ -289,9 +316,11 @@ func TestDoBump_ValidVersionPrereleaseBump(t *testing.T) {
}

func TestDoBump_ValidVersionPrereleaseBumpNoPrerelease(t *testing.T) {
viper.Reset()
viper.Set("prerelease-prefix", "alpha")
version := "1.2.3"
bumpType := PrereleaseBump
expected := "1.2.4"
expected := "1.2.4-alpha.1"
result, err := doBump(version, bumpType)
assert.NoError(t, err)
assert.Equal(t, expected, result.String())
Expand Down Expand Up @@ -339,3 +368,40 @@ func TestDoBump_PrereleaseClearsBuild(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, expected, result.String())
}
func TestDoBump_PatchClearsPrerelease(t *testing.T) {
viper.Reset()
version := "1.2.3-alpha.0"
bumpType := PatchBump
expected := "1.2.3"
result, err := doBump(version, bumpType)
assert.NoError(t, err)
assert.Equal(t, expected, result.String())
}
func TestDoBump_MinorClearsPrerelease(t *testing.T) {
version := "1.2.3-alpha.0"
bumpType := MinorBump
expected := "1.3.0"
result, err := doBump(version, bumpType)
assert.NoError(t, err)
assert.Equal(t, expected, result.String())
}

func TestDoBump_MajorClearsPrerelease(t *testing.T) {
version := "1.2.3-alpha.0"
bumpType := MajorBump
expected := "2.0.0"
result, err := doBump(version, bumpType)
assert.NoError(t, err)
assert.Equal(t, expected, result.String())
}

func TestDoBump_AddsCorrectPrereleasePrefix(t *testing.T) {
viper.Reset()
viper.Set("prerelease-prefix", "snapshot")
version := "1.2.3"
bumpType := PrereleaseBump
expected := "1.2.4-snapshot.1"
result, err := doBump(version, bumpType)
assert.NoError(t, err)
assert.Equal(t, expected, result.String())
}

0 comments on commit 6a25dd3

Please sign in to comment.