From 2d97157c9e4b9460b6038c118e3595664068ad58 Mon Sep 17 00:00:00 2001 From: shiouen Date: Wed, 17 Nov 2021 13:32:08 +0100 Subject: [PATCH 01/54] small doc update --- pkg/api/git.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/api/git.go b/pkg/api/git.go index 94cdcb6..75000ce 100644 --- a/pkg/api/git.go +++ b/pkg/api/git.go @@ -57,7 +57,7 @@ func (api GitAPI) SetConfig(key string, value string) (err error) { return api.commander.Run("git", "config", key, value) } -// SetConfigIfNotSet sets a git config key and value only if the config does not exist. +// SetConfigIfNotSet sets a git config key and value if the config does not exist. // returns an error if the command failed. func (api GitAPI) SetConfigIfNotSet(key string, value string) (err error) { if _, err = api.GetConfig(key); err != nil { From ffcbee33ead5031cd9e730e7ffa2d1b472593f83 Mon Sep 17 00:00:00 2001 From: shiouen Date: Wed, 17 Nov 2021 13:32:46 +0100 Subject: [PATCH 02/54] abstracted predict version logic into core package --- pkg/commands/predict-version.go | 25 +++++++++---------------- pkg/core/predict.go | 24 ++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 16 deletions(-) create mode 100644 pkg/core/predict.go diff --git a/pkg/commands/predict-version.go b/pkg/commands/predict-version.go index 0ca74b4..a975847 100644 --- a/pkg/commands/predict-version.go +++ b/pkg/commands/predict-version.go @@ -2,12 +2,11 @@ package commands import ( "fmt" + "github.com/restechnica/semverbot/pkg/core" "github.com/spf13/cobra" "github.com/spf13/viper" - "github.com/restechnica/semverbot/internal/semver" - "github.com/restechnica/semverbot/pkg/api" "github.com/restechnica/semverbot/pkg/cli" ) @@ -34,23 +33,17 @@ func PredictVersionCommandPreRunE(cmd *cobra.Command, args []string) (err error) // PredictVersionCommandRunE runs the command. // returns an error if the command fails. func PredictVersionCommandRunE(cmd *cobra.Command, args []string) (err error) { - var versionAPI = api.NewVersionAPI() - var version = versionAPI.GetVersionOrDefault(cli.DefaultVersion) - - var mode = viper.GetString(cli.SemverModeConfigKey) - var modeDetectionMap = viper.GetStringMapStringSlice(cli.SemverDetectionConfigKey) - var modeDetector = semver.NewModeDetector(modeDetectionMap) - - var semverModeAPI = api.NewSemverModeAPI(modeDetector) - var semverMode = semverModeAPI.SelectMode(mode) + var options = &core.PredictVersionOptions{ + DefaultVersion: cli.DefaultVersion, + SemverDetection: viper.GetStringMapStringSlice(cli.SemverDetectionConfigKey), + SemverMode: viper.GetString(cli.SemverModeConfigKey), + } - var incrementedVersion string + var version string - if incrementedVersion, err = semverMode.Increment(version); err != nil { - return err + if version, err = core.PredictVersion(options); err == nil { + fmt.Println(version) } - fmt.Println(incrementedVersion) - return err } diff --git a/pkg/core/predict.go b/pkg/core/predict.go new file mode 100644 index 0000000..aa1388a --- /dev/null +++ b/pkg/core/predict.go @@ -0,0 +1,24 @@ +package core + +import ( + "github.com/restechnica/semverbot/internal/semver" + "github.com/restechnica/semverbot/pkg/api" +) + +type PredictVersionOptions struct { + DefaultVersion string + SemverDetection map[string][]string + SemverMode string +} + +func PredictVersion(options *PredictVersionOptions) (prediction string, err error) { + var versionAPI = api.NewVersionAPI() + var version = versionAPI.GetVersionOrDefault(options.DefaultVersion) + + var modeDetector = semver.NewModeDetector(options.SemverDetection) + + var semverModeAPI = api.NewSemverModeAPI(modeDetector) + var semverMode = semverModeAPI.SelectMode(options.SemverMode) + + return semverMode.Increment(version) +} From 03f82410ed10b17a484bd46842070ddc350545e0 Mon Sep 17 00:00:00 2001 From: shiouen Date: Wed, 17 Nov 2021 14:41:44 +0100 Subject: [PATCH 03/54] removed internal/senver readme --- internal/semver/readme.md | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 internal/semver/readme.md diff --git a/internal/semver/readme.md b/internal/semver/readme.md deleted file mode 100644 index 04556fc..0000000 --- a/internal/semver/readme.md +++ /dev/null @@ -1,3 +0,0 @@ -this stuff needs to move to the pkg folder somewhere - -perhaps ./pkg/core/semver.go or ./pkg/core/semver/... From 9ed136a19a1bb5594ff5d60190e92c64ba9d9f07 Mon Sep 17 00:00:00 2001 From: shiouen Date: Wed, 17 Nov 2021 17:21:44 +0100 Subject: [PATCH 04/54] moved internal/semver to pkg/semver - renamed semver.detection config to semver.match - removed internal/senver readme --- .semverbot.toml | 2 +- pkg/api/semver.go | 2 +- pkg/api/version.go | 2 +- pkg/cli/config.go | 4 ++-- pkg/cli/constants.go | 2 +- pkg/commands/predict-version.go | 8 ++++---- pkg/commands/release-version.go | 4 ++-- pkg/commands/root.go | 2 +- pkg/core/predict.go | 10 +++++----- {internal => pkg}/semver/auto.go | 0 {internal => pkg}/semver/auto_test.go | 0 {internal => pkg}/semver/detection.go | 12 ++++++------ {internal => pkg}/semver/gitbranch.go | 0 {internal => pkg}/semver/gitcommit.go | 6 +++--- {internal => pkg}/semver/gitcommit_test.go | 10 +++++----- {internal => pkg}/semver/major.go | 0 {internal => pkg}/semver/major_test.go | 0 {internal => pkg}/semver/minor.go | 0 {internal => pkg}/semver/minor_test.go | 0 {internal => pkg}/semver/mode.go | 0 {internal => pkg}/semver/parse.go | 0 {internal => pkg}/semver/patch.go | 0 {internal => pkg}/semver/patch_test.go | 0 {internal => pkg}/semver/trim.go | 0 24 files changed, 32 insertions(+), 32 deletions(-) rename {internal => pkg}/semver/auto.go (100%) rename {internal => pkg}/semver/auto_test.go (100%) rename {internal => pkg}/semver/detection.go (68%) rename {internal => pkg}/semver/gitbranch.go (100%) rename {internal => pkg}/semver/gitcommit.go (87%) rename {internal => pkg}/semver/gitcommit_test.go (92%) rename {internal => pkg}/semver/major.go (100%) rename {internal => pkg}/semver/major_test.go (100%) rename {internal => pkg}/semver/minor.go (100%) rename {internal => pkg}/semver/minor_test.go (100%) rename {internal => pkg}/semver/mode.go (100%) rename {internal => pkg}/semver/parse.go (100%) rename {internal => pkg}/semver/patch.go (100%) rename {internal => pkg}/semver/patch_test.go (100%) rename {internal => pkg}/semver/trim.go (100%) diff --git a/.semverbot.toml b/.semverbot.toml index 2f75cdf..4311d9c 100644 --- a/.semverbot.toml +++ b/.semverbot.toml @@ -10,7 +10,7 @@ prefix = "v" [semver] mode = "auto" -[semver.detection] +[semver.match] patch = ["fix/", "[fix]"] minor = ["feature/", "[feature]"] major = ["release/", "[release]"] diff --git a/pkg/api/semver.go b/pkg/api/semver.go index a629f63..ba53aa7 100644 --- a/pkg/api/semver.go +++ b/pkg/api/semver.go @@ -1,7 +1,7 @@ package api import ( - "github.com/restechnica/semverbot/internal/semver" + "github.com/restechnica/semverbot/pkg/semver" ) // SemverModeAPI an API to work with different modes. diff --git a/pkg/api/version.go b/pkg/api/version.go index 71f76ea..e0e2038 100644 --- a/pkg/api/version.go +++ b/pkg/api/version.go @@ -3,8 +3,8 @@ package api import ( "fmt" - "github.com/restechnica/semverbot/internal/semver" "github.com/restechnica/semverbot/pkg/cli" + "github.com/restechnica/semverbot/pkg/semver" ) // VersionAPI an API to work with versions. diff --git a/pkg/cli/config.go b/pkg/cli/config.go index 257caa8..04446ac 100644 --- a/pkg/cli/config.go +++ b/pkg/cli/config.go @@ -10,8 +10,8 @@ const ( // GitTagsPrefixConfigKey key for the git tags prefix config in the semverbot config file. GitTagsPrefixConfigKey = "git.tags.prefix" - // SemverDetectionConfigKey key for the semver detection config in the semverbot config file. - SemverDetectionConfigKey = "semver.detection" + // SemverMatchConfigKey key for the semver match config in the semverbot config file. + SemverMatchConfigKey = "semver.match" // SemverModeConfigKey key for the semver mode config in the semverbot config file. SemverModeConfigKey = "semver.mode" diff --git a/pkg/cli/constants.go b/pkg/cli/constants.go index 6637fa5..1059eea 100644 --- a/pkg/cli/constants.go +++ b/pkg/cli/constants.go @@ -14,7 +14,7 @@ prefix = "v" [semver] mode = "auto" -[semver.detection] +[semver.match] patch = ["fix/", "[fix]"] minor = ["feature/", "[feature]"] major = ["release/", "[release]"] diff --git a/pkg/commands/predict-version.go b/pkg/commands/predict-version.go index a975847..2d2e652 100644 --- a/pkg/commands/predict-version.go +++ b/pkg/commands/predict-version.go @@ -2,12 +2,12 @@ package commands import ( "fmt" - "github.com/restechnica/semverbot/pkg/core" "github.com/spf13/cobra" "github.com/spf13/viper" "github.com/restechnica/semverbot/pkg/cli" + "github.com/restechnica/semverbot/pkg/core" ) // NewPredictVersionCommand creates a new predict version command. @@ -34,9 +34,9 @@ func PredictVersionCommandPreRunE(cmd *cobra.Command, args []string) (err error) // returns an error if the command fails. func PredictVersionCommandRunE(cmd *cobra.Command, args []string) (err error) { var options = &core.PredictVersionOptions{ - DefaultVersion: cli.DefaultVersion, - SemverDetection: viper.GetStringMapStringSlice(cli.SemverDetectionConfigKey), - SemverMode: viper.GetString(cli.SemverModeConfigKey), + DefaultVersion: cli.DefaultVersion, + SemverMatchMap: viper.GetStringMapStringSlice(cli.SemverMatchConfigKey), + SemverMode: viper.GetString(cli.SemverModeConfigKey), } var version string diff --git a/pkg/commands/release-version.go b/pkg/commands/release-version.go index dab64cb..f483b20 100644 --- a/pkg/commands/release-version.go +++ b/pkg/commands/release-version.go @@ -6,9 +6,9 @@ import ( "github.com/spf13/cobra" "github.com/spf13/viper" - "github.com/restechnica/semverbot/internal/semver" "github.com/restechnica/semverbot/pkg/api" "github.com/restechnica/semverbot/pkg/cli" + "github.com/restechnica/semverbot/pkg/semver" ) // NewReleaseVersionCommand creates a new release version command. @@ -38,7 +38,7 @@ func ReleaseVersionCommandRunE(cmd *cobra.Command, args []string) error { var version = versionAPI.GetVersionOrDefault(cli.DefaultVersion) var mode = viper.GetString(cli.SemverModeConfigKey) - var modeDetectionMap = viper.GetStringMapStringSlice(cli.SemverDetectionConfigKey) + var modeDetectionMap = viper.GetStringMapStringSlice(cli.SemverMatchConfigKey) var modeDetector = semver.NewModeDetector(modeDetectionMap) var semverModeAPI = api.NewSemverModeAPI(modeDetector) diff --git a/pkg/commands/root.go b/pkg/commands/root.go index 4f32a92..3c6c7e6 100644 --- a/pkg/commands/root.go +++ b/pkg/commands/root.go @@ -74,7 +74,7 @@ func LoadConfig() (err error) { // LoadDefaultConfig loads the default semverbot config. func LoadDefaultConfig() { viper.SetDefault(cli.GitTagsPrefixConfigKey, "v") - viper.SetDefault(cli.SemverDetectionConfigKey, map[string][]string{}) + viper.SetDefault(cli.SemverMatchConfigKey, map[string][]string{}) viper.SetDefault(cli.SemverModeConfigKey, "auto") } diff --git a/pkg/core/predict.go b/pkg/core/predict.go index aa1388a..ca47f76 100644 --- a/pkg/core/predict.go +++ b/pkg/core/predict.go @@ -1,21 +1,21 @@ package core import ( - "github.com/restechnica/semverbot/internal/semver" "github.com/restechnica/semverbot/pkg/api" + "github.com/restechnica/semverbot/pkg/semver" ) type PredictVersionOptions struct { - DefaultVersion string - SemverDetection map[string][]string - SemverMode string + DefaultVersion string + SemverMatchMap map[string][]string + SemverMode string } func PredictVersion(options *PredictVersionOptions) (prediction string, err error) { var versionAPI = api.NewVersionAPI() var version = versionAPI.GetVersionOrDefault(options.DefaultVersion) - var modeDetector = semver.NewModeDetector(options.SemverDetection) + var modeDetector = semver.NewModeDetector(options.SemverMatchMap) var semverModeAPI = api.NewSemverModeAPI(modeDetector) var semverMode = semverModeAPI.SelectMode(options.SemverMode) diff --git a/internal/semver/auto.go b/pkg/semver/auto.go similarity index 100% rename from internal/semver/auto.go rename to pkg/semver/auto.go diff --git a/internal/semver/auto_test.go b/pkg/semver/auto_test.go similarity index 100% rename from internal/semver/auto_test.go rename to pkg/semver/auto_test.go diff --git a/internal/semver/detection.go b/pkg/semver/detection.go similarity index 68% rename from internal/semver/detection.go rename to pkg/semver/detection.go index 65d4986..ca235e0 100644 --- a/internal/semver/detection.go +++ b/pkg/semver/detection.go @@ -7,20 +7,20 @@ import ( // ModeDetector detects which mode should be applied. type ModeDetector struct { - ModeDetectionMap map[string][]string + SemverMatchMap map[string][]string } // NewModeDetector creates a new ModeDetector with a detection configuration. // returns the new ModeDetector. -func NewModeDetector(modeDetectionMap map[string][]string) ModeDetector { - return ModeDetector{ModeDetectionMap: modeDetectionMap} +func NewModeDetector(semverMatchMap map[string][]string) ModeDetector { + return ModeDetector{SemverMatchMap: semverMatchMap} } -// DetectMode detects which semver level mode (patch, minor, major) based -// on a string and the ModeDetectionMap. +// DetectMode detects the semver level mode (patch, minor, major) based +// on a string and the SemverMatchMap. // Returns the detected mode or an error if no mode was detected. func (detector ModeDetector) DetectMode(target string) (detected Mode, err error) { - for mode, substrings := range detector.ModeDetectionMap { + for mode, substrings := range detector.SemverMatchMap { for _, substring := range substrings { if strings.Contains(target, substring) { switch mode { diff --git a/internal/semver/gitbranch.go b/pkg/semver/gitbranch.go similarity index 100% rename from internal/semver/gitbranch.go rename to pkg/semver/gitbranch.go diff --git a/internal/semver/gitcommit.go b/pkg/semver/gitcommit.go similarity index 87% rename from internal/semver/gitcommit.go rename to pkg/semver/gitcommit.go index 3b0d483..7e27911 100644 --- a/internal/semver/gitcommit.go +++ b/pkg/semver/gitcommit.go @@ -24,15 +24,15 @@ func NewGitCommitMode(detector ModeDetector) GitCommitMode { // Returns the incremented version or an error if it failed to detect the mode based on the git commit. func (mode GitCommitMode) Increment(targetVersion string) (nextVersion string, err error) { var message string - var matchedMode Mode + var detectedMode Mode if message, err = mode.Commander.Output("git", "show", "-s", "--format=%s"); err != nil { return } - if matchedMode, err = mode.ModeDetector.DetectMode(message); err != nil { + if detectedMode, err = mode.ModeDetector.DetectMode(message); err != nil { return } - return matchedMode.Increment(targetVersion) + return detectedMode.Increment(targetVersion) } diff --git a/internal/semver/gitcommit_test.go b/pkg/semver/gitcommit_test.go similarity index 92% rename from internal/semver/gitcommit_test.go rename to pkg/semver/gitcommit_test.go index 764654b..aae461b 100644 --- a/internal/semver/gitcommit_test.go +++ b/pkg/semver/gitcommit_test.go @@ -11,7 +11,7 @@ import ( "github.com/restechnica/semverbot/internal/mocks" ) -var modeDetectionMap = map[string][]string{ +var semverMatchMap = map[string][]string{ Patch: {"[fix]", "fix/"}, Minor: {"[feature]", "feature/"}, Major: {"[release]", "release/"}, @@ -47,7 +47,7 @@ func TestGitCommitMode_GitCommitConstant(t *testing.T) { // t.Run(test.Name, func(t *testing.T) { // var want = test.Want // -// var gitCommitMode = NewGitCommitMode(NewModeDetector(modeDetectionMap)) +// var gitCommitMode = NewGitCommitMode(NewModeDetector(semverMatchMap)) // var got, err = gitCommitMode.ModeDetector.(test.Message) // // assert.NoError(t, err) @@ -68,7 +68,7 @@ func TestGitCommitMode_GitCommitConstant(t *testing.T) { // t.Run(test.Name, func(t *testing.T) { // var want = fmt.Sprintf(`could not match a mode to the commit message "%s"`, test.Message) // -// var gitCommitMode = NewGitCommitMode(modeDetectionMap) +// var gitCommitMode = NewGitCommitMode(semverMatchMap) // var _, err = gitCommitMode.GetMatchedMode(test.Message) // // assert.Error(t, err) @@ -101,7 +101,7 @@ func TestGitCommitMode_Increment(t *testing.T) { var cmder = mocks.NewMockCommander() cmder.On("Output", mock.Anything, mock.Anything).Return(test.Message, nil) - var gitCommitMode = NewGitCommitMode(NewModeDetector(modeDetectionMap)) + var gitCommitMode = NewGitCommitMode(NewModeDetector(semverMatchMap)) gitCommitMode.Commander = cmder var got, err = gitCommitMode.Increment(test.Version) @@ -130,7 +130,7 @@ func TestGitCommitMode_Increment(t *testing.T) { var cmder = mocks.NewMockCommander() cmder.On("Output", mock.Anything, mock.Anything).Return(test.Message, test.GitError) - var gitCommitMode = NewGitCommitMode(NewModeDetector(modeDetectionMap)) + var gitCommitMode = NewGitCommitMode(NewModeDetector(semverMatchMap)) gitCommitMode.Commander = cmder var _, err = gitCommitMode.Increment(test.Version) diff --git a/internal/semver/major.go b/pkg/semver/major.go similarity index 100% rename from internal/semver/major.go rename to pkg/semver/major.go diff --git a/internal/semver/major_test.go b/pkg/semver/major_test.go similarity index 100% rename from internal/semver/major_test.go rename to pkg/semver/major_test.go diff --git a/internal/semver/minor.go b/pkg/semver/minor.go similarity index 100% rename from internal/semver/minor.go rename to pkg/semver/minor.go diff --git a/internal/semver/minor_test.go b/pkg/semver/minor_test.go similarity index 100% rename from internal/semver/minor_test.go rename to pkg/semver/minor_test.go diff --git a/internal/semver/mode.go b/pkg/semver/mode.go similarity index 100% rename from internal/semver/mode.go rename to pkg/semver/mode.go diff --git a/internal/semver/parse.go b/pkg/semver/parse.go similarity index 100% rename from internal/semver/parse.go rename to pkg/semver/parse.go diff --git a/internal/semver/patch.go b/pkg/semver/patch.go similarity index 100% rename from internal/semver/patch.go rename to pkg/semver/patch.go diff --git a/internal/semver/patch_test.go b/pkg/semver/patch_test.go similarity index 100% rename from internal/semver/patch_test.go rename to pkg/semver/patch_test.go diff --git a/internal/semver/trim.go b/pkg/semver/trim.go similarity index 100% rename from internal/semver/trim.go rename to pkg/semver/trim.go From d041be26b6ce06218ea83590e61d41c81453f2be Mon Sep 17 00:00:00 2001 From: shiouen Date: Wed, 17 Nov 2021 17:47:13 +0100 Subject: [PATCH 05/54] abstracted get version logic into core - small doc refactor --- cmd/sbot.go | 2 +- internal/mocks/mocks.go | 10 +++++----- pkg/api/git.go | 18 +++++++++--------- pkg/api/semver.go | 4 ++-- pkg/api/version.go | 10 +++++----- pkg/commands/get-version.go | 10 +++------- pkg/commands/get.go | 2 +- pkg/commands/init.go | 4 ++-- pkg/commands/predict-version.go | 6 +++--- pkg/commands/predict.go | 2 +- pkg/commands/push-version.go | 4 ++-- pkg/commands/push.go | 2 +- pkg/commands/release-version.go | 6 +++--- pkg/commands/release.go | 2 +- pkg/commands/root.go | 10 +++++----- pkg/commands/update-version.go | 4 ++-- pkg/commands/update.go | 2 +- pkg/core/get.go | 13 +++++++++++++ pkg/semver/detection.go | 2 +- pkg/semver/parse.go | 2 +- pkg/semver/trim.go | 2 +- 21 files changed, 63 insertions(+), 54 deletions(-) create mode 100644 pkg/core/get.go diff --git a/cmd/sbot.go b/cmd/sbot.go index 4c72fd4..aec497a 100644 --- a/cmd/sbot.go +++ b/cmd/sbot.go @@ -7,7 +7,7 @@ import ( ) // NewApp creates a new semverbot CLI app -// returns a spf13/cobra command. +// Returns a spf13/cobra command. func NewApp() *cobra.Command { return commands.NewRootCommand() } diff --git a/internal/mocks/mocks.go b/internal/mocks/mocks.go index 1037274..9013e9d 100644 --- a/internal/mocks/mocks.go +++ b/internal/mocks/mocks.go @@ -10,20 +10,20 @@ type MockCommander struct { } // NewMockCommander creates a new MockCommander. -// returns the new MockCommander. +// Returns the new MockCommander. func NewMockCommander() *MockCommander { return &MockCommander{} } // Output runs a mock command. -// returns mocked output or a mocked error. +// Returns mocked output or a mocked error. func (mock *MockCommander) Output(name string, arg ...string) (string, error) { args := mock.Called(name, arg) return args.String(0), args.Error(1) } // Run runs a mock command. -// returns a mocked error. +// Returns a mocked error. func (mock *MockCommander) Run(name string, arg ...string) error { args := mock.Called(name, arg) return args.Error(0) @@ -35,13 +35,13 @@ type MockSemverMode struct { } // NewMockSemverMode creates a new MockSemverMode. -// returns the new MockSemverMode. +// Returns the new MockSemverMode. func NewMockSemverMode() *MockSemverMode { return &MockSemverMode{} } // Increment mock increments a version. -// returns an incremented mock version. +// Returns an incremented mock version. func (mock *MockSemverMode) Increment(targetVersion string) (nextVersion string, err error) { args := mock.Called(targetVersion) return args.String(0), args.Error(1) diff --git a/pkg/api/git.go b/pkg/api/git.go index 75000ce..97f2d0c 100644 --- a/pkg/api/git.go +++ b/pkg/api/git.go @@ -10,55 +10,55 @@ type GitAPI struct { } // NewGitAPI creates a new GitAPI with a commander to run git commands. -// returns the new GitAPI. +// Returns the new GitAPI. func NewGitAPI() GitAPI { return GitAPI{commander: commands.NewExecCommander()} } // CreateAnnotatedTag creates an annotated git tag. -// returns an error if the command fails. +// Returns an error if the command fails. func (api GitAPI) CreateAnnotatedTag(tag string) (err error) { return api.commander.Run("git", "tag", "-a", tag, "-m", tag) } // FetchTags fetches all tags from the remote origin. -// returns an error if the command fails. +// Returns an error if the command fails. func (api GitAPI) FetchTags() (err error) { return api.commander.Run("git", "fetch", "--tags") } // FetchUnshallow convert a shallow repository to a complete one. -// returns an error if the command fails. +// Returns an error if the command fails. func (api GitAPI) FetchUnshallow() (err error) { return api.commander.Run("git", "fetch", "--unshallow") } // GetConfig gets the git config for a specific key. -// returns the value of the git config as a string and an error if the command failed. +// Returns the value of the git config as a string and an error if the command failed. func (api GitAPI) GetConfig(key string) (value string, err error) { return api.commander.Output("git", "config", "--get", key) } // GetLatestAnnotatedTag gets the latest annotated git tag. -// returns the git tag and an error if the command failed. +// Returns the git tag and an error if the command failed. func (api GitAPI) GetLatestAnnotatedTag() (value string, err error) { return api.commander.Output("git", "describe", "--tags") } // PushTag pushes a tag to the remote origin. -// returns an error if the command failed. +// Returns an error if the command failed. func (api GitAPI) PushTag(tag string) (err error) { return api.commander.Run("git", "push", "origin", tag) } // SetConfig sets a git config key and value. -// returns an error if the command failed. +// Returns an error if the command failed. func (api GitAPI) SetConfig(key string, value string) (err error) { return api.commander.Run("git", "config", key, value) } // SetConfigIfNotSet sets a git config key and value if the config does not exist. -// returns an error if the command failed. +// Returns an error if the command failed. func (api GitAPI) SetConfigIfNotSet(key string, value string) (err error) { if _, err = api.GetConfig(key); err != nil { err = api.SetConfig(key, value) diff --git a/pkg/api/semver.go b/pkg/api/semver.go index ba53aa7..e8aa82a 100644 --- a/pkg/api/semver.go +++ b/pkg/api/semver.go @@ -12,7 +12,7 @@ type SemverModeAPI struct { // NewSemverModeAPI creates a new semver mode API with a mode detector to pass // it on to the different modes that require it. -// returns the new SemverModeAPI. +// Returns the new SemverModeAPI. func NewSemverModeAPI(detector semver.ModeDetector) SemverModeAPI { return SemverModeAPI{ GitBranchMode: semver.NewGitBranchMode(detector), @@ -21,7 +21,7 @@ func NewSemverModeAPI(detector semver.ModeDetector) SemverModeAPI { } // SelectMode selects the mode corresponding to the mode string. -// returns the corresponding mode. +// Returns the corresponding mode. func (api SemverModeAPI) SelectMode(mode string) semver.Mode { switch mode { case semver.Auto: diff --git a/pkg/api/version.go b/pkg/api/version.go index e0e2038..8393e41 100644 --- a/pkg/api/version.go +++ b/pkg/api/version.go @@ -13,14 +13,14 @@ type VersionAPI struct { } // NewVersionAPI creates a new VersionAPI. -// returns the new VersionAPI. +// Returns the new VersionAPI. func NewVersionAPI() VersionAPI { return VersionAPI{NewGitAPI()} } // GetVersion gets the current version. // Git adds newlines to certain command output, which is why the version is trimmed. -// returns the current version or an error if the GitAPI failed. +// Returns the current version or an error if the GitAPI failed. func (api VersionAPI) GetVersion() (version string, err error) { if version, err = api.GitAPI.GetLatestAnnotatedTag(); err != nil { return version, err @@ -30,7 +30,7 @@ func (api VersionAPI) GetVersion() (version string, err error) { // GetVersionOrDefault gets the current version. // Defaults to a provided default version if the GitAPI failed. -// returns the current version. +// Returns the current version. func (api VersionAPI) GetVersionOrDefault(defaultVersion string) (version string) { var err error @@ -42,14 +42,14 @@ func (api VersionAPI) GetVersionOrDefault(defaultVersion string) (version string } // PredictVersion predicts the next version with a provided semver mode. -// returns the next version or an error if increment the current version failed. +// Returns the next version or an error if increment the current version failed. func (api VersionAPI) PredictVersion(mode semver.Mode) (version string, err error) { version = api.GetVersionOrDefault(cli.DefaultVersion) return mode.Increment(version) } // PushVersion pushes a version with a provided version prefix. -// returns an error if the the GitAPI failed. +// Returns an error if the the GitAPI failed. func (api VersionAPI) PushVersion(prefix string) (err error) { var version = api.GetVersionOrDefault(cli.DefaultVersion) var prefixedVersion = fmt.Sprintf("%s%s", prefix, version) diff --git a/pkg/commands/get-version.go b/pkg/commands/get-version.go index 65b7ba1..f6bfe4a 100644 --- a/pkg/commands/get-version.go +++ b/pkg/commands/get-version.go @@ -2,15 +2,13 @@ package commands import ( "fmt" + "github.com/restechnica/semverbot/pkg/core" "github.com/spf13/cobra" - - "github.com/restechnica/semverbot/pkg/api" - "github.com/restechnica/semverbot/pkg/cli" ) // NewGetVersionCommand creates a new get version command. -// returns the new spf13/cobra command. +// Returns the new spf13/cobra command. func NewGetVersionCommand() *cobra.Command { var command = &cobra.Command{ Use: "version", @@ -22,7 +20,5 @@ func NewGetVersionCommand() *cobra.Command { // GetVersionCommandRun runs the command. func GetVersionCommandRun(cmd *cobra.Command, args []string) { - var versionAPI = api.NewVersionAPI() - var version = versionAPI.GetVersionOrDefault(cli.DefaultVersion) - fmt.Println(version) + fmt.Println(core.GetVersion()) } diff --git a/pkg/commands/get.go b/pkg/commands/get.go index 0411e96..bf2d904 100644 --- a/pkg/commands/get.go +++ b/pkg/commands/get.go @@ -5,7 +5,7 @@ import ( ) // NewGetCommand creates a new get command. -// returns a new init spf13/cobra command. +// Returns a new init spf13/cobra command. func NewGetCommand() *cobra.Command { var command = &cobra.Command{ Use: "get", diff --git a/pkg/commands/init.go b/pkg/commands/init.go index 35606cb..e8267d4 100644 --- a/pkg/commands/init.go +++ b/pkg/commands/init.go @@ -11,7 +11,7 @@ import ( ) // NewInitCommand creates a new init command. -// returns a new init spf13/cobra command. +// Returns a new init spf13/cobra command. func NewInitCommand() *cobra.Command { var command = &cobra.Command{ Use: "init", @@ -23,7 +23,7 @@ func NewInitCommand() *cobra.Command { } // InitCommandRunE runs the init command. -// returns an error if the command failed. +// Returns an error if the command failed. func InitCommandRunE(cmd *cobra.Command, args []string) (err error) { var file *os.File diff --git a/pkg/commands/predict-version.go b/pkg/commands/predict-version.go index 2d2e652..022326f 100644 --- a/pkg/commands/predict-version.go +++ b/pkg/commands/predict-version.go @@ -11,7 +11,7 @@ import ( ) // NewPredictVersionCommand creates a new predict version command. -// returns the new spf13/cobra command. +// Returns the new spf13/cobra command. func NewPredictVersionCommand() *cobra.Command { var command = &cobra.Command{ Use: "version", @@ -25,13 +25,13 @@ func NewPredictVersionCommand() *cobra.Command { } // PredictVersionCommandPreRunE runs before the command runs. -// returns an error if it fails. +// Returns an error if it fails. func PredictVersionCommandPreRunE(cmd *cobra.Command, args []string) (err error) { return viper.BindPFlag(cli.SemverModeConfigKey, cmd.Flags().Lookup("mode")) } // PredictVersionCommandRunE runs the command. -// returns an error if the command fails. +// Returns an error if the command fails. func PredictVersionCommandRunE(cmd *cobra.Command, args []string) (err error) { var options = &core.PredictVersionOptions{ DefaultVersion: cli.DefaultVersion, diff --git a/pkg/commands/predict.go b/pkg/commands/predict.go index cc33407..6ef7b60 100644 --- a/pkg/commands/predict.go +++ b/pkg/commands/predict.go @@ -5,7 +5,7 @@ import ( ) // NewPredictCommand creates a new predict command. -// returns the new spf13/cobra command. +// Returns the new spf13/cobra command. func NewPredictCommand() *cobra.Command { var command = &cobra.Command{ Use: "predict", diff --git a/pkg/commands/push-version.go b/pkg/commands/push-version.go index a9bd0b9..b903da3 100644 --- a/pkg/commands/push-version.go +++ b/pkg/commands/push-version.go @@ -11,7 +11,7 @@ import ( ) // NewPushVersionCommand creates a new push version command. -// returns the new spf13/cobra command. +// Returns the new spf13/cobra command. func NewPushVersionCommand() *cobra.Command { var command = &cobra.Command{ Use: "version", @@ -22,7 +22,7 @@ func NewPushVersionCommand() *cobra.Command { } // PushVersionCommandRunE runs the command. -// returns an error if the command fails. +// Returns an error if the command fails. func PushVersionCommandRunE(cmd *cobra.Command, args []string) (err error) { var versionAPI = api.NewVersionAPI() var version = versionAPI.GetVersionOrDefault(cli.DefaultVersion) diff --git a/pkg/commands/push.go b/pkg/commands/push.go index a5e09d0..19d29ea 100644 --- a/pkg/commands/push.go +++ b/pkg/commands/push.go @@ -5,7 +5,7 @@ import ( ) // NewPushCommand creates a new push command. -// returns the new spf13/cobra command. +// Returns the new spf13/cobra command. func NewPushCommand() *cobra.Command { var command = &cobra.Command{ Use: "push", diff --git a/pkg/commands/release-version.go b/pkg/commands/release-version.go index f483b20..1cd45de 100644 --- a/pkg/commands/release-version.go +++ b/pkg/commands/release-version.go @@ -12,7 +12,7 @@ import ( ) // NewReleaseVersionCommand creates a new release version command. -// returns the new spf13/cobra command. +// Returns the new spf13/cobra command. func NewReleaseVersionCommand() *cobra.Command { var command = &cobra.Command{ Use: "version", @@ -26,13 +26,13 @@ func NewReleaseVersionCommand() *cobra.Command { } // ReleaseVersionCommandPreRunE runs before the command runs. -// returns an error if it fails. +// Returns an error if it fails. func ReleaseVersionCommandPreRunE(cmd *cobra.Command, args []string) (err error) { return viper.BindPFlag(cli.SemverModeConfigKey, cmd.Flags().Lookup("mode")) } // ReleaseVersionCommandRunE runs the command. -// returns an error if the command fails. +// Returns an error if the command fails. func ReleaseVersionCommandRunE(cmd *cobra.Command, args []string) error { var versionAPI = api.NewVersionAPI() var version = versionAPI.GetVersionOrDefault(cli.DefaultVersion) diff --git a/pkg/commands/release.go b/pkg/commands/release.go index 71673d7..0246c5b 100644 --- a/pkg/commands/release.go +++ b/pkg/commands/release.go @@ -3,7 +3,7 @@ package commands import "github.com/spf13/cobra" // NewReleaseCommand creates a new release command. -// returns the new spf13/cobra command. +// Returns the new spf13/cobra command. func NewReleaseCommand() *cobra.Command { var command = &cobra.Command{ Use: "release", diff --git a/pkg/commands/root.go b/pkg/commands/root.go index 3c6c7e6..e649cbd 100644 --- a/pkg/commands/root.go +++ b/pkg/commands/root.go @@ -11,7 +11,7 @@ import ( ) // NewRootCommand creates a new root command. -// returns the new spf13/cobra command. +// Returns the new spf13/cobra command. func NewRootCommand() *cobra.Command { var command = &cobra.Command{ Use: "sbot", @@ -32,7 +32,7 @@ func NewRootCommand() *cobra.Command { } // RootCommandPersistentPreRunE runs before the command and any subcommand runs. -// returns an error if it failed. +// Returns an error if it failed. func RootCommandPersistentPreRunE(cmd *cobra.Command, args []string) (err error) { LoadDefaultConfig() @@ -52,7 +52,7 @@ func RootCommandPersistentPreRunE(cmd *cobra.Command, args []string) (err error) } // LoadConfig loads the semverbot configuration file. -// returns an error if it fails. +// Returns an error if it fails. func LoadConfig() (err error) { if cli.ConfigFlag != "" { viper.SetConfigFile(cli.ConfigFlag) @@ -79,7 +79,7 @@ func LoadDefaultConfig() { } // LoadFlags loads root command flags. -// returns an error if it fails. +// Returns an error if it fails. func LoadFlags(cmd *cobra.Command) (err error) { return err //return viper.BindPFlag("git.tags.fetch", cmd.Flags().Lookup("fetch")) -- example on how to load flags @@ -87,7 +87,7 @@ func LoadFlags(cmd *cobra.Command) (err error) { // SetGitConfigIfConfigured Sets the git config only when the semverbot config exists and // the git config does not exist. -// returns an error if it fails. +// Returns an error if it fails. func SetGitConfigIfConfigured() (err error) { var gitAPI = api.NewGitAPI() diff --git a/pkg/commands/update-version.go b/pkg/commands/update-version.go index 6aec553..faa22a0 100644 --- a/pkg/commands/update-version.go +++ b/pkg/commands/update-version.go @@ -8,7 +8,7 @@ import ( ) // NewUpdateVersionCommand creates a new update version command. -// returns the new spf13/cobra command. +// Returns the new spf13/cobra command. func NewUpdateVersionCommand() *cobra.Command { var command = &cobra.Command{ Use: "version", @@ -19,7 +19,7 @@ func NewUpdateVersionCommand() *cobra.Command { } // UpdateVersionCommandRunE runs before the commands runs. -// returns an error if it fails. +// Returns an error if it fails. func UpdateVersionCommandRunE(cmd *cobra.Command, args []string) (err error) { var gitAPI = api.NewGitAPI() diff --git a/pkg/commands/update.go b/pkg/commands/update.go index 2f39e93..ae0c58c 100644 --- a/pkg/commands/update.go +++ b/pkg/commands/update.go @@ -5,7 +5,7 @@ import ( ) // NewUpdateCommand creates a new update command. -// returns the new spf13/cobra command. +// Returns the new spf13/cobra command. func NewUpdateCommand() *cobra.Command { var command = &cobra.Command{ Use: "update", diff --git a/pkg/core/get.go b/pkg/core/get.go new file mode 100644 index 0000000..b8acfe9 --- /dev/null +++ b/pkg/core/get.go @@ -0,0 +1,13 @@ +package core + +import ( + "github.com/restechnica/semverbot/pkg/api" + "github.com/restechnica/semverbot/pkg/cli" +) + +// GetVersion gets the current version based on the latest annotated git tag. +// Returns the current version. +func GetVersion() string { + var versionAPI = api.NewVersionAPI() + return versionAPI.GetVersionOrDefault(cli.DefaultVersion) +} diff --git a/pkg/semver/detection.go b/pkg/semver/detection.go index ca235e0..f4e9e19 100644 --- a/pkg/semver/detection.go +++ b/pkg/semver/detection.go @@ -11,7 +11,7 @@ type ModeDetector struct { } // NewModeDetector creates a new ModeDetector with a detection configuration. -// returns the new ModeDetector. +// Returns the new ModeDetector. func NewModeDetector(semverMatchMap map[string][]string) ModeDetector { return ModeDetector{SemverMatchMap: semverMatchMap} } diff --git a/pkg/semver/parse.go b/pkg/semver/parse.go index 7a13bb0..3c88db3 100644 --- a/pkg/semver/parse.go +++ b/pkg/semver/parse.go @@ -5,7 +5,7 @@ import blangsemver "github.com/blang/semver/v4" // Parse parses a version string into a semver version struct. // It tolerates certain version specifications that do not strictly adhere to semver specs. // See the library documentation for more information. -// returns the parsed blang/semver/v4 Version. +// Returns the parsed blang/semver/v4 Version. func Parse(version string) (blangsemver.Version, error) { return blangsemver.ParseTolerant(version) } diff --git a/pkg/semver/trim.go b/pkg/semver/trim.go index b61b73b..a15f51b 100644 --- a/pkg/semver/trim.go +++ b/pkg/semver/trim.go @@ -3,7 +3,7 @@ package semver import blangsemver "github.com/blang/semver/v4" // Trim trims a semver version string of anything but major.minor.patch information. -// returns the trimmed semver version. +// Returns the trimmed semver version. func Trim(version string) (string, error) { var semverVersion blangsemver.Version var err error From bad33d9392c720524304322f12bb36ba60bffd57 Mon Sep 17 00:00:00 2001 From: shiouen Date: Wed, 17 Nov 2021 17:53:27 +0100 Subject: [PATCH 06/54] finalized moving get version logic into core --- pkg/commands/get-version.go | 5 ++++- pkg/core/get.go | 9 ++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/pkg/commands/get-version.go b/pkg/commands/get-version.go index f6bfe4a..2387ef1 100644 --- a/pkg/commands/get-version.go +++ b/pkg/commands/get-version.go @@ -2,6 +2,7 @@ package commands import ( "fmt" + "github.com/restechnica/semverbot/pkg/cli" "github.com/restechnica/semverbot/pkg/core" "github.com/spf13/cobra" @@ -20,5 +21,7 @@ func NewGetVersionCommand() *cobra.Command { // GetVersionCommandRun runs the command. func GetVersionCommandRun(cmd *cobra.Command, args []string) { - fmt.Println(core.GetVersion()) + var options = &core.GetVersionOptions{DefaultVersion: cli.DefaultVersion} + var version = core.GetVersion(options) + fmt.Println(version) } diff --git a/pkg/core/get.go b/pkg/core/get.go index b8acfe9..f5ea4dc 100644 --- a/pkg/core/get.go +++ b/pkg/core/get.go @@ -2,12 +2,15 @@ package core import ( "github.com/restechnica/semverbot/pkg/api" - "github.com/restechnica/semverbot/pkg/cli" ) +type GetVersionOptions struct { + DefaultVersion string +} + // GetVersion gets the current version based on the latest annotated git tag. // Returns the current version. -func GetVersion() string { +func GetVersion(options *GetVersionOptions) string { var versionAPI = api.NewVersionAPI() - return versionAPI.GetVersionOrDefault(cli.DefaultVersion) + return versionAPI.GetVersionOrDefault(options.DefaultVersion) } From b8071c18d5218a1569cba8a6b605dfc3b86ce914 Mon Sep 17 00:00:00 2001 From: shiouen Date: Wed, 17 Nov 2021 18:08:06 +0100 Subject: [PATCH 07/54] abstracted push version logic into core --- pkg/commands/push-version.go | 15 ++++++--------- pkg/core/push.go | 22 ++++++++++++++++++++++ 2 files changed, 28 insertions(+), 9 deletions(-) create mode 100644 pkg/core/push.go diff --git a/pkg/commands/push-version.go b/pkg/commands/push-version.go index b903da3..10b0aab 100644 --- a/pkg/commands/push-version.go +++ b/pkg/commands/push-version.go @@ -1,12 +1,11 @@ package commands import ( - "fmt" + "github.com/restechnica/semverbot/pkg/core" "github.com/spf13/cobra" "github.com/spf13/viper" - "github.com/restechnica/semverbot/pkg/api" "github.com/restechnica/semverbot/pkg/cli" ) @@ -24,12 +23,10 @@ func NewPushVersionCommand() *cobra.Command { // PushVersionCommandRunE runs the command. // Returns an error if the command fails. func PushVersionCommandRunE(cmd *cobra.Command, args []string) (err error) { - var versionAPI = api.NewVersionAPI() - var version = versionAPI.GetVersionOrDefault(cli.DefaultVersion) - - var gitTagPrefix = viper.GetString(cli.GitTagsPrefixConfigKey) - var prefixedVersion = fmt.Sprintf("%s%s", gitTagPrefix, version) + var options = &core.PushVersionOptions{ + DefaultVersion: cli.DefaultVersion, + GitTagsPrefix: viper.GetString(cli.GitTagsPrefixConfigKey), + } - var gitAPI = api.NewGitAPI() - return gitAPI.PushTag(prefixedVersion) + return core.PushVersion(options) } diff --git a/pkg/core/push.go b/pkg/core/push.go new file mode 100644 index 0000000..c29ec59 --- /dev/null +++ b/pkg/core/push.go @@ -0,0 +1,22 @@ +package core + +import ( + "fmt" + + "github.com/restechnica/semverbot/pkg/api" +) + +type PushVersionOptions struct { + DefaultVersion string + GitTagsPrefix string +} + +func PushVersion(options *PushVersionOptions) (err error) { + var versionAPI = api.NewVersionAPI() + var version = versionAPI.GetVersionOrDefault(options.DefaultVersion) + + var prefixedVersion = fmt.Sprintf("%s%s", options.GitTagsPrefix, version) + + var gitAPI = api.NewGitAPI() + return gitAPI.PushTag(prefixedVersion) +} From bf7fb78c9b7717c4b281ce38c93b9f22b9a6e4ce Mon Sep 17 00:00:00 2001 From: shiouen Date: Wed, 17 Nov 2021 19:14:20 +0100 Subject: [PATCH 08/54] abstracted release version logic into core --- pkg/commands/release-version.go | 32 +++++++---------------------- pkg/core/release.go | 36 +++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 25 deletions(-) create mode 100644 pkg/core/release.go diff --git a/pkg/commands/release-version.go b/pkg/commands/release-version.go index 1cd45de..fce2652 100644 --- a/pkg/commands/release-version.go +++ b/pkg/commands/release-version.go @@ -1,14 +1,12 @@ package commands import ( - "fmt" + "github.com/restechnica/semverbot/pkg/core" "github.com/spf13/cobra" "github.com/spf13/viper" - "github.com/restechnica/semverbot/pkg/api" "github.com/restechnica/semverbot/pkg/cli" - "github.com/restechnica/semverbot/pkg/semver" ) // NewReleaseVersionCommand creates a new release version command. @@ -34,28 +32,12 @@ func ReleaseVersionCommandPreRunE(cmd *cobra.Command, args []string) (err error) // ReleaseVersionCommandRunE runs the command. // Returns an error if the command fails. func ReleaseVersionCommandRunE(cmd *cobra.Command, args []string) error { - var versionAPI = api.NewVersionAPI() - var version = versionAPI.GetVersionOrDefault(cli.DefaultVersion) - - var mode = viper.GetString(cli.SemverModeConfigKey) - var modeDetectionMap = viper.GetStringMapStringSlice(cli.SemverMatchConfigKey) - var modeDetector = semver.NewModeDetector(modeDetectionMap) - - var semverModeAPI = api.NewSemverModeAPI(modeDetector) - var semverMode = semverModeAPI.SelectMode(mode) - - var incrementedVersion string - var err error - - if incrementedVersion, err = semverMode.Increment(version); err != nil { - return err + var options = &core.ReleaseVersionOptions{ + DefaultVersion: cli.DefaultVersion, + GitTagsPrefix: viper.GetString(cli.GitTagsPrefixConfigKey), + SemverMatchMap: viper.GetStringMapStringSlice(cli.SemverMatchConfigKey), + SemverMode: viper.GetString(cli.SemverModeConfigKey), } - var gitTagPrefix = viper.GetString(cli.GitTagsPrefixConfigKey) - incrementedVersion = fmt.Sprintf("%s%s", gitTagPrefix, incrementedVersion) - - var gitAPI = api.NewGitAPI() - err = gitAPI.CreateAnnotatedTag(incrementedVersion) - - return err + return core.ReleaseVersion(options) } diff --git a/pkg/core/release.go b/pkg/core/release.go new file mode 100644 index 0000000..d7cb53f --- /dev/null +++ b/pkg/core/release.go @@ -0,0 +1,36 @@ +package core + +import ( + "fmt" + + "github.com/restechnica/semverbot/pkg/api" + "github.com/restechnica/semverbot/pkg/semver" +) + +type ReleaseVersionOptions struct { + DefaultVersion string + GitTagsPrefix string + SemverMatchMap map[string][]string + SemverMode string +} + +func ReleaseVersion(options *ReleaseVersionOptions) (err error) { + var versionAPI = api.NewVersionAPI() + var version = versionAPI.GetVersionOrDefault(options.DefaultVersion) + + var modeDetector = semver.NewModeDetector(options.SemverMatchMap) + + var semverModeAPI = api.NewSemverModeAPI(modeDetector) + var semverMode = semverModeAPI.SelectMode(options.SemverMode) + + var incrementedVersion string + + if incrementedVersion, err = semverMode.Increment(version); err != nil { + return err + } + + incrementedVersion = fmt.Sprintf("%s%s", options.GitTagsPrefix, incrementedVersion) + + var gitAPI = api.NewGitAPI() + return gitAPI.CreateAnnotatedTag(incrementedVersion) +} From ec978b65e7aa49281b2c3ef3fd74d4333174ce32 Mon Sep 17 00:00:00 2001 From: shiouen Date: Wed, 17 Nov 2021 19:33:37 +0100 Subject: [PATCH 09/54] abstracted init and update version logic into core --- pkg/commands/init.go | 40 +++++++------------------------ pkg/commands/update-version.go | 19 +++------------ pkg/core/init.go | 44 ++++++++++++++++++++++++++++++++++ pkg/core/update.go | 23 ++++++++++++++++++ 4 files changed, 78 insertions(+), 48 deletions(-) create mode 100644 pkg/core/init.go create mode 100644 pkg/core/update.go diff --git a/pkg/commands/init.go b/pkg/commands/init.go index e8267d4..ce32c8c 100644 --- a/pkg/commands/init.go +++ b/pkg/commands/init.go @@ -1,13 +1,11 @@ package commands import ( - "io" - "os" - - "github.com/AlecAivazis/survey/v2" - "github.com/spf13/cobra" + "fmt" "github.com/restechnica/semverbot/pkg/cli" + "github.com/restechnica/semverbot/pkg/core" + "github.com/spf13/cobra" ) // NewInitCommand creates a new init command. @@ -16,7 +14,7 @@ func NewInitCommand() *cobra.Command { var command = &cobra.Command{ Use: "init", RunE: InitCommandRunE, - Short: "Creates a default .semverbot.toml config", + Short: fmt.Sprintf(`Creates a default "%s" config`, cli.DefaultConfigFilePath), } return command @@ -25,32 +23,10 @@ func NewInitCommand() *cobra.Command { // InitCommandRunE runs the init command. // Returns an error if the command failed. func InitCommandRunE(cmd *cobra.Command, args []string) (err error) { - var file *os.File - - if _, err = os.Stat(cli.DefaultConfigFilePath); !os.IsNotExist(err) { - var prompt = &survey.Confirm{ - Message: "Do you wish to overwrite your current config?", - } - - var isOk = false - - if err = survey.AskOne(prompt, &isOk); err != nil { - return err - } - - if !isOk { - return - } - } - - if file, err = os.Create(cli.DefaultConfigFilePath); err != nil { - return err - } - - if _, err = io.WriteString(file, cli.DefaultConfig); err != nil { - _ = file.Close() - return err + var options = &core.InitOptions{ + Config: cli.DefaultConfig, + ConfigFilePath: cli.DefaultConfigFilePath, } - return file.Close() + return core.Init(options) } diff --git a/pkg/commands/update-version.go b/pkg/commands/update-version.go index faa22a0..d6f904b 100644 --- a/pkg/commands/update-version.go +++ b/pkg/commands/update-version.go @@ -1,9 +1,8 @@ package commands import ( - "fmt" + "github.com/restechnica/semverbot/pkg/core" - "github.com/restechnica/semverbot/pkg/api" "github.com/spf13/cobra" ) @@ -18,20 +17,8 @@ func NewUpdateVersionCommand() *cobra.Command { return command } -// UpdateVersionCommandRunE runs before the commands runs. +// UpdateVersionCommandRunE runs the commands. // Returns an error if it fails. func UpdateVersionCommandRunE(cmd *cobra.Command, args []string) (err error) { - var gitAPI = api.NewGitAPI() - - if err = gitAPI.FetchUnshallow(); err != nil { - fmt.Println("something went wrong while fetching from git, attempting to fetch tags anyway") - } - - if err = gitAPI.FetchTags(); err != nil { - fmt.Println("something went wrong while updating the version") - } else { - fmt.Println("successfully fetched the latest git tags") - } - - return err + return core.UpdateVersion() } diff --git a/pkg/core/init.go b/pkg/core/init.go new file mode 100644 index 0000000..5980b1e --- /dev/null +++ b/pkg/core/init.go @@ -0,0 +1,44 @@ +package core + +import ( + "io" + "os" + + "github.com/AlecAivazis/survey/v2" +) + +type InitOptions struct { + ConfigFilePath string + Config string +} + +func Init(options *InitOptions) (err error) { + var file *os.File + + if _, err = os.Stat(options.ConfigFilePath); !os.IsNotExist(err) { + var prompt = &survey.Confirm{ + Message: "Do you wish to overwrite your current config?", + } + + var isOk = false + + if err = survey.AskOne(prompt, &isOk); err != nil { + return err + } + + if !isOk { + return + } + } + + if file, err = os.Create(options.ConfigFilePath); err != nil { + return err + } + + if _, err = io.WriteString(file, options.Config); err != nil { + _ = file.Close() + return err + } + + return file.Close() +} diff --git a/pkg/core/update.go b/pkg/core/update.go new file mode 100644 index 0000000..bc24719 --- /dev/null +++ b/pkg/core/update.go @@ -0,0 +1,23 @@ +package core + +import ( + "fmt" + + "github.com/restechnica/semverbot/pkg/api" +) + +func UpdateVersion() (err error) { + var gitAPI = api.NewGitAPI() + + if err = gitAPI.FetchUnshallow(); err != nil { + fmt.Println("something went wrong while fetching from git, attempting to fetch tags anyway") + } + + if err = gitAPI.FetchTags(); err != nil { + fmt.Println("something went wrong while updating the version") + } else { + fmt.Println("successfully fetched the latest git tags") + } + + return err +} From d801c262f734114c0e40e059ee4a4763015a3801 Mon Sep 17 00:00:00 2001 From: shiouen Date: Wed, 17 Nov 2021 19:35:29 +0100 Subject: [PATCH 10/54] formatting --- pkg/commands/get-version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/commands/get-version.go b/pkg/commands/get-version.go index 2387ef1..cd5ece4 100644 --- a/pkg/commands/get-version.go +++ b/pkg/commands/get-version.go @@ -2,9 +2,9 @@ package commands import ( "fmt" + "github.com/restechnica/semverbot/pkg/cli" "github.com/restechnica/semverbot/pkg/core" - "github.com/spf13/cobra" ) From dbe2796a95cd4cc3347012a30324557ba8d2af7c Mon Sep 17 00:00:00 2001 From: shiouen Date: Wed, 17 Nov 2021 19:43:58 +0100 Subject: [PATCH 11/54] documented core methods --- pkg/core/init.go | 3 +++ pkg/core/predict.go | 2 ++ pkg/core/push.go | 2 ++ pkg/core/release.go | 3 +++ pkg/core/update.go | 2 ++ 5 files changed, 12 insertions(+) diff --git a/pkg/core/init.go b/pkg/core/init.go index 5980b1e..eb12980 100644 --- a/pkg/core/init.go +++ b/pkg/core/init.go @@ -12,6 +12,9 @@ type InitOptions struct { Config string } +// Init initializes a config file with defaults. +// It will prompt for confirmation before overwriting existing files. +// Returns an error if something went wrong with IO operations or the prompt. func Init(options *InitOptions) (err error) { var file *os.File diff --git a/pkg/core/predict.go b/pkg/core/predict.go index ca47f76..786b5f7 100644 --- a/pkg/core/predict.go +++ b/pkg/core/predict.go @@ -11,6 +11,8 @@ type PredictVersionOptions struct { SemverMode string } +// PredictVersion predicts a version based on the latest annotated git tag and a map of matched to specific strings. +// Returns the predicted version or an error if anything went wrong with the increment. func PredictVersion(options *PredictVersionOptions) (prediction string, err error) { var versionAPI = api.NewVersionAPI() var version = versionAPI.GetVersionOrDefault(options.DefaultVersion) diff --git a/pkg/core/push.go b/pkg/core/push.go index c29ec59..47b694c 100644 --- a/pkg/core/push.go +++ b/pkg/core/push.go @@ -11,6 +11,8 @@ type PushVersionOptions struct { GitTagsPrefix string } +// PushVersion pushes the latest annotated git tag to the git origin. +// Returns an error if pushing the tag went wrong. func PushVersion(options *PushVersionOptions) (err error) { var versionAPI = api.NewVersionAPI() var version = versionAPI.GetVersionOrDefault(options.DefaultVersion) diff --git a/pkg/core/release.go b/pkg/core/release.go index d7cb53f..ef86327 100644 --- a/pkg/core/release.go +++ b/pkg/core/release.go @@ -14,6 +14,9 @@ type ReleaseVersionOptions struct { SemverMode string } +// ReleaseVersion releases a new version by incrementing the latest annotated git tag. +// It creates an annotated git tag for the new version. +// Returns an error if anything went wrong with incrementing or tagging. func ReleaseVersion(options *ReleaseVersionOptions) (err error) { var versionAPI = api.NewVersionAPI() var version = versionAPI.GetVersionOrDefault(options.DefaultVersion) diff --git a/pkg/core/update.go b/pkg/core/update.go index bc24719..5e9787c 100644 --- a/pkg/core/update.go +++ b/pkg/core/update.go @@ -6,6 +6,8 @@ import ( "github.com/restechnica/semverbot/pkg/api" ) +// UpdateVersion changes the current git repo into an unshallow repo and fetches all git tags. +// Returns and error if anything went wrong. func UpdateVersion() (err error) { var gitAPI = api.NewGitAPI() From a2ef27024eb950b811b4a747eb4ffc5f267cef04 Mon Sep 17 00:00:00 2001 From: shiouen Date: Wed, 17 Nov 2021 19:45:46 +0100 Subject: [PATCH 12/54] fixed some docs --- pkg/core/predict.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/core/predict.go b/pkg/core/predict.go index 786b5f7..ccb3f03 100644 --- a/pkg/core/predict.go +++ b/pkg/core/predict.go @@ -11,7 +11,8 @@ type PredictVersionOptions struct { SemverMode string } -// PredictVersion predicts a version based on the latest annotated git tag and a map of matched to specific strings. +// PredictVersion predicts a version based on the latest annotated git tag and a map of semver levels +// matched to specific strings. // Returns the predicted version or an error if anything went wrong with the increment. func PredictVersion(options *PredictVersionOptions) (prediction string, err error) { var versionAPI = api.NewVersionAPI() From 93d7babd587d7e163eaf55352d623a5c4696dc23 Mon Sep 17 00:00:00 2001 From: shiouen Date: Wed, 17 Nov 2021 20:44:12 +0100 Subject: [PATCH 13/54] moved commands package to the cli package - moved constants to internal package - created editable CLI defaults --- cmd/sbot.go | 3 +-- {pkg/cli => internal}/constants.go | 2 +- pkg/{ => cli}/commands/get-version.go | 0 pkg/{ => cli}/commands/get.go | 0 pkg/{ => cli}/commands/init.go | 0 pkg/{ => cli}/commands/predict-version.go | 0 pkg/{ => cli}/commands/predict.go | 0 pkg/{ => cli}/commands/push-version.go | 0 pkg/{ => cli}/commands/push.go | 0 pkg/{ => cli}/commands/release-version.go | 0 pkg/{ => cli}/commands/release.go | 0 pkg/{ => cli}/commands/root.go | 0 pkg/{ => cli}/commands/update-version.go | 0 pkg/{ => cli}/commands/update.go | 0 pkg/cli/defaults.go | 14 ++++++++++++++ pkg/cli/flags.go | 4 ++-- 16 files changed, 18 insertions(+), 5 deletions(-) rename {pkg/cli => internal}/constants.go (96%) rename pkg/{ => cli}/commands/get-version.go (100%) rename pkg/{ => cli}/commands/get.go (100%) rename pkg/{ => cli}/commands/init.go (100%) rename pkg/{ => cli}/commands/predict-version.go (100%) rename pkg/{ => cli}/commands/predict.go (100%) rename pkg/{ => cli}/commands/push-version.go (100%) rename pkg/{ => cli}/commands/push.go (100%) rename pkg/{ => cli}/commands/release-version.go (100%) rename pkg/{ => cli}/commands/release.go (100%) rename pkg/{ => cli}/commands/root.go (100%) rename pkg/{ => cli}/commands/update-version.go (100%) rename pkg/{ => cli}/commands/update.go (100%) create mode 100644 pkg/cli/defaults.go diff --git a/cmd/sbot.go b/cmd/sbot.go index aec497a..e89478b 100644 --- a/cmd/sbot.go +++ b/cmd/sbot.go @@ -1,9 +1,8 @@ package cmd import ( + "github.com/restechnica/semverbot/pkg/cli/commands" "github.com/spf13/cobra" - - "github.com/restechnica/semverbot/pkg/commands" ) // NewApp creates a new semverbot CLI app diff --git a/pkg/cli/constants.go b/internal/constants.go similarity index 96% rename from pkg/cli/constants.go rename to internal/constants.go index 1059eea..ece3640 100644 --- a/pkg/cli/constants.go +++ b/internal/constants.go @@ -1,4 +1,4 @@ -package cli +package internal const ( // DefaultConfig the default config. diff --git a/pkg/commands/get-version.go b/pkg/cli/commands/get-version.go similarity index 100% rename from pkg/commands/get-version.go rename to pkg/cli/commands/get-version.go diff --git a/pkg/commands/get.go b/pkg/cli/commands/get.go similarity index 100% rename from pkg/commands/get.go rename to pkg/cli/commands/get.go diff --git a/pkg/commands/init.go b/pkg/cli/commands/init.go similarity index 100% rename from pkg/commands/init.go rename to pkg/cli/commands/init.go diff --git a/pkg/commands/predict-version.go b/pkg/cli/commands/predict-version.go similarity index 100% rename from pkg/commands/predict-version.go rename to pkg/cli/commands/predict-version.go diff --git a/pkg/commands/predict.go b/pkg/cli/commands/predict.go similarity index 100% rename from pkg/commands/predict.go rename to pkg/cli/commands/predict.go diff --git a/pkg/commands/push-version.go b/pkg/cli/commands/push-version.go similarity index 100% rename from pkg/commands/push-version.go rename to pkg/cli/commands/push-version.go diff --git a/pkg/commands/push.go b/pkg/cli/commands/push.go similarity index 100% rename from pkg/commands/push.go rename to pkg/cli/commands/push.go diff --git a/pkg/commands/release-version.go b/pkg/cli/commands/release-version.go similarity index 100% rename from pkg/commands/release-version.go rename to pkg/cli/commands/release-version.go diff --git a/pkg/commands/release.go b/pkg/cli/commands/release.go similarity index 100% rename from pkg/commands/release.go rename to pkg/cli/commands/release.go diff --git a/pkg/commands/root.go b/pkg/cli/commands/root.go similarity index 100% rename from pkg/commands/root.go rename to pkg/cli/commands/root.go diff --git a/pkg/commands/update-version.go b/pkg/cli/commands/update-version.go similarity index 100% rename from pkg/commands/update-version.go rename to pkg/cli/commands/update-version.go diff --git a/pkg/commands/update.go b/pkg/cli/commands/update.go similarity index 100% rename from pkg/commands/update.go rename to pkg/cli/commands/update.go diff --git a/pkg/cli/defaults.go b/pkg/cli/defaults.go new file mode 100644 index 0000000..527155b --- /dev/null +++ b/pkg/cli/defaults.go @@ -0,0 +1,14 @@ +package cli + +import "github.com/restechnica/semverbot/internal" + +var ( + // DefaultConfig the default config. + DefaultConfig = internal.DefaultConfig + + // DefaultConfigFilePath the default relative filepath to the config file. + DefaultConfigFilePath = internal.DefaultConfigFilePath + + // DefaultVersion the default version when no other version can be found. + DefaultVersion = internal.DefaultVersion +) diff --git a/pkg/cli/flags.go b/pkg/cli/flags.go index 61731ae..a2b76c9 100644 --- a/pkg/cli/flags.go +++ b/pkg/cli/flags.go @@ -1,9 +1,9 @@ package cli var ( - // ConfigFlag a global flag which enables control over the semverbot config file location. + // ConfigFlag a flag which configures the config file location. ConfigFlag string - // ModeFlag a flag which defines which mode to use to increment the current version. + // ModeFlag a flag which indicates the semver mode to increment the current version with. ModeFlag string ) From ed218f9820a4e8a05ac6802cb391cce6d5feb6a2 Mon Sep 17 00:00:00 2001 From: shiouen Date: Wed, 17 Nov 2021 20:45:38 +0100 Subject: [PATCH 14/54] small rename --- pkg/cli/{config.go => configs.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename pkg/cli/{config.go => configs.go} (100%) diff --git a/pkg/cli/config.go b/pkg/cli/configs.go similarity index 100% rename from pkg/cli/config.go rename to pkg/cli/configs.go From 34eebdadb8749b46e5b5039c602cc9215ef49ec5 Mon Sep 17 00:00:00 2001 From: shiouen Date: Thu, 18 Nov 2021 01:46:12 +0100 Subject: [PATCH 15/54] formatting --- pkg/api/version.go | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/pkg/api/version.go b/pkg/api/version.go index 8393e41..431fdca 100644 --- a/pkg/api/version.go +++ b/pkg/api/version.go @@ -1,9 +1,6 @@ package api import ( - "fmt" - - "github.com/restechnica/semverbot/pkg/cli" "github.com/restechnica/semverbot/pkg/semver" ) @@ -41,17 +38,16 @@ func (api VersionAPI) GetVersionOrDefault(defaultVersion string) (version string return version } -// PredictVersion predicts the next version with a provided semver mode. -// Returns the next version or an error if increment the current version failed. -func (api VersionAPI) PredictVersion(mode semver.Mode) (version string, err error) { - version = api.GetVersionOrDefault(cli.DefaultVersion) - return mode.Increment(version) -} - -// PushVersion pushes a version with a provided version prefix. -// Returns an error if the the GitAPI failed. -func (api VersionAPI) PushVersion(prefix string) (err error) { - var version = api.GetVersionOrDefault(cli.DefaultVersion) - var prefixedVersion = fmt.Sprintf("%s%s", prefix, version) - return api.GitAPI.PushTag(prefixedVersion) -} +//// PredictVersion predicts the next version with a provided semver mode. +//// Returns the next version or an error if increment the current version failed. +//func (api VersionAPI) PredictVersion(target string, mode semver.Mode) (version string, err error) { +// return mode.Increment(target) +//} +// +//// PushVersion pushes a version with a provided version prefix. +//// Returns an error if the the GitAPI failed. +//func (api VersionAPI) PushVersion(prefix string) (err error) { +// var version = api.GetVersionOrDefault(cli.DefaultVersion) +// var prefixedVersion = fmt.Sprintf("%s%s", prefix, version) +// return api.GitAPI.PushTag(prefixedVersion) +//} From b46979dc5c5157102165c60fc8c3d7c29233b4bb Mon Sep 17 00:00:00 2001 From: shiouen Date: Thu, 18 Nov 2021 15:06:00 +0100 Subject: [PATCH 16/54] applied different cmd folder structure - root main.go is now a copy of the cmd/sbot/main.go - some makefile improvements --- Makefile | 11 +++++++---- cmd/sbot.go | 12 ------------ cmd/sbot/main.go | 11 +++++++++++ main.go | 8 +++++--- 4 files changed, 23 insertions(+), 19 deletions(-) delete mode 100644 cmd/sbot.go create mode 100644 cmd/sbot/main.go diff --git a/Makefile b/Makefile index 98fe892..9d4fc4b 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,15 @@ # make sure targets do not conflict with file and folder names .PHONY: build clean test +BIN = bin +GOBUILD = go build + # build the project build: - go build -o bin/sbot - GOOS=windows GOARCH=amd64 go build -o bin/sbot-windows-amd64 - GOOS=linux GOARCH=amd64 go build -o bin/sbot-linux-amd64 - GOOS=darwin GOARCH=amd64 go build -o bin/sbot-darwin-amd64 + $(GOBUILD) -o $(BIN)/sbot + GOOS=windows GOARCH=amd64 $(GOBUILD) -o $(BIN)/sbot-windows-amd64.exe + GOOS=linux GOARCH=amd64 $(GOBUILD) -o $(BIN)/sbot-linux-amd64 + GOOS=darwin GOARCH=amd64 $(GOBUILD) -o $(BIN)/sbot-darwin-amd64 # run quality assessment checks check: diff --git a/cmd/sbot.go b/cmd/sbot.go deleted file mode 100644 index e89478b..0000000 --- a/cmd/sbot.go +++ /dev/null @@ -1,12 +0,0 @@ -package cmd - -import ( - "github.com/restechnica/semverbot/pkg/cli/commands" - "github.com/spf13/cobra" -) - -// NewApp creates a new semverbot CLI app -// Returns a spf13/cobra command. -func NewApp() *cobra.Command { - return commands.NewRootCommand() -} diff --git a/cmd/sbot/main.go b/cmd/sbot/main.go new file mode 100644 index 0000000..f6fc74a --- /dev/null +++ b/cmd/sbot/main.go @@ -0,0 +1,11 @@ +package main + +import ( + "github.com/restechnica/semverbot/pkg/cli/commands" +) + +// main bootstraps the `sbot` CLI app. +func main() { + var cli = commands.NewRootCommand() + _ = cli.Execute() +} diff --git a/main.go b/main.go index 5d1e0dd..f6fc74a 100644 --- a/main.go +++ b/main.go @@ -1,9 +1,11 @@ package main -import "github.com/restechnica/semverbot/cmd" +import ( + "github.com/restechnica/semverbot/pkg/cli/commands" +) // main bootstraps the `sbot` CLI app. func main() { - var app = cmd.NewApp() - _ = app.Execute() + var cli = commands.NewRootCommand() + _ = cli.Execute() } From 27b434f92300625d3ff4dcb112718a87b40dd044 Mon Sep 17 00:00:00 2001 From: shiouen Date: Thu, 18 Nov 2021 16:19:58 +0100 Subject: [PATCH 17/54] moved the git API to its own package, refactors --- pkg/api/version.go | 5 ++-- pkg/cli/commands/root.go | 4 +-- pkg/core/push.go | 3 ++- pkg/core/release.go | 3 ++- pkg/core/update.go | 4 +-- pkg/{api/git.go => git/api.go} | 47 +++++++++++++++++++++------------- 6 files changed, 40 insertions(+), 26 deletions(-) rename pkg/{api/git.go => git/api.go} (55%) diff --git a/pkg/api/version.go b/pkg/api/version.go index 431fdca..2dd8168 100644 --- a/pkg/api/version.go +++ b/pkg/api/version.go @@ -1,18 +1,19 @@ package api import ( + "github.com/restechnica/semverbot/pkg/git" "github.com/restechnica/semverbot/pkg/semver" ) // VersionAPI an API to work with versions. type VersionAPI struct { - GitAPI GitAPI + GitAPI git.API } // NewVersionAPI creates a new VersionAPI. // Returns the new VersionAPI. func NewVersionAPI() VersionAPI { - return VersionAPI{NewGitAPI()} + return VersionAPI{git.NewAPI()} } // GetVersion gets the current version. diff --git a/pkg/cli/commands/root.go b/pkg/cli/commands/root.go index e649cbd..c59dd0f 100644 --- a/pkg/cli/commands/root.go +++ b/pkg/cli/commands/root.go @@ -6,8 +6,8 @@ import ( "github.com/spf13/cobra" "github.com/spf13/viper" - "github.com/restechnica/semverbot/pkg/api" "github.com/restechnica/semverbot/pkg/cli" + "github.com/restechnica/semverbot/pkg/git" ) // NewRootCommand creates a new root command. @@ -89,7 +89,7 @@ func LoadFlags(cmd *cobra.Command) (err error) { // the git config does not exist. // Returns an error if it fails. func SetGitConfigIfConfigured() (err error) { - var gitAPI = api.NewGitAPI() + var gitAPI = git.NewAPI() if viper.IsSet(cli.GitConfigEmailConfigKey) { var email = viper.GetString(cli.GitConfigEmailConfigKey) diff --git a/pkg/core/push.go b/pkg/core/push.go index 47b694c..d99d614 100644 --- a/pkg/core/push.go +++ b/pkg/core/push.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/restechnica/semverbot/pkg/api" + "github.com/restechnica/semverbot/pkg/git" ) type PushVersionOptions struct { @@ -19,6 +20,6 @@ func PushVersion(options *PushVersionOptions) (err error) { var prefixedVersion = fmt.Sprintf("%s%s", options.GitTagsPrefix, version) - var gitAPI = api.NewGitAPI() + var gitAPI = git.NewAPI() return gitAPI.PushTag(prefixedVersion) } diff --git a/pkg/core/release.go b/pkg/core/release.go index ef86327..a25468f 100644 --- a/pkg/core/release.go +++ b/pkg/core/release.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/restechnica/semverbot/pkg/api" + "github.com/restechnica/semverbot/pkg/git" "github.com/restechnica/semverbot/pkg/semver" ) @@ -34,6 +35,6 @@ func ReleaseVersion(options *ReleaseVersionOptions) (err error) { incrementedVersion = fmt.Sprintf("%s%s", options.GitTagsPrefix, incrementedVersion) - var gitAPI = api.NewGitAPI() + var gitAPI = git.NewAPI() return gitAPI.CreateAnnotatedTag(incrementedVersion) } diff --git a/pkg/core/update.go b/pkg/core/update.go index 5e9787c..0a75819 100644 --- a/pkg/core/update.go +++ b/pkg/core/update.go @@ -3,13 +3,13 @@ package core import ( "fmt" - "github.com/restechnica/semverbot/pkg/api" + "github.com/restechnica/semverbot/pkg/git" ) // UpdateVersion changes the current git repo into an unshallow repo and fetches all git tags. // Returns and error if anything went wrong. func UpdateVersion() (err error) { - var gitAPI = api.NewGitAPI() + var gitAPI = git.NewAPI() if err = gitAPI.FetchUnshallow(); err != nil { fmt.Println("something went wrong while fetching from git, attempting to fetch tags anyway") diff --git a/pkg/api/git.go b/pkg/git/api.go similarity index 55% rename from pkg/api/git.go rename to pkg/git/api.go index 97f2d0c..a33939a 100644 --- a/pkg/api/git.go +++ b/pkg/git/api.go @@ -1,65 +1,76 @@ -package api +package git -import ( - "github.com/restechnica/semverbot/internal/commands" -) +import "github.com/restechnica/semverbot/internal/commands" -// GitAPI an API to interact with the git CLI. -type GitAPI struct { +// API an API to interact with the git CLI. +type API struct { commander commands.Commander } -// NewGitAPI creates a new GitAPI with a commander to run git commands. -// Returns the new GitAPI. -func NewGitAPI() GitAPI { - return GitAPI{commander: commands.NewExecCommander()} +// NewAPI creates a new API with a commander to run git commands. +// Returns the new API. +func NewAPI() API { + return API{commander: commands.NewExecCommander()} } // CreateAnnotatedTag creates an annotated git tag. // Returns an error if the command fails. -func (api GitAPI) CreateAnnotatedTag(tag string) (err error) { +func (api API) CreateAnnotatedTag(tag string) (err error) { return api.commander.Run("git", "tag", "-a", tag, "-m", tag) } // FetchTags fetches all tags from the remote origin. // Returns an error if the command fails. -func (api GitAPI) FetchTags() (err error) { +func (api API) FetchTags() (err error) { return api.commander.Run("git", "fetch", "--tags") } // FetchUnshallow convert a shallow repository to a complete one. // Returns an error if the command fails. -func (api GitAPI) FetchUnshallow() (err error) { +func (api API) FetchUnshallow() (err error) { return api.commander.Run("git", "fetch", "--unshallow") } // GetConfig gets the git config for a specific key. // Returns the value of the git config as a string and an error if the command failed. -func (api GitAPI) GetConfig(key string) (value string, err error) { +func (api API) GetConfig(key string) (value string, err error) { return api.commander.Output("git", "config", "--get", key) } // GetLatestAnnotatedTag gets the latest annotated git tag. // Returns the git tag and an error if the command failed. -func (api GitAPI) GetLatestAnnotatedTag() (value string, err error) { +func (api API) GetLatestAnnotatedTag() (tag string, err error) { return api.commander.Output("git", "describe", "--tags") } +// GetMergedBranchName gets the source branch name if the last commit is a merge. +// Returns the branch name or an error if something went wrong with git. +func (api API) GetMergedBranchName() (name string, err error) { + return api.commander.Output( + "git", + "name-rev", + "--name-only", + "--refs=refs/heads/*", + "--refs=refs/remotes/*", + "HEAD^2", + ) +} + // PushTag pushes a tag to the remote origin. // Returns an error if the command failed. -func (api GitAPI) PushTag(tag string) (err error) { +func (api API) PushTag(tag string) (err error) { return api.commander.Run("git", "push", "origin", tag) } // SetConfig sets a git config key and value. // Returns an error if the command failed. -func (api GitAPI) SetConfig(key string, value string) (err error) { +func (api API) SetConfig(key string, value string) (err error) { return api.commander.Run("git", "config", key, value) } // SetConfigIfNotSet sets a git config key and value if the config does not exist. // Returns an error if the command failed. -func (api GitAPI) SetConfigIfNotSet(key string, value string) (err error) { +func (api API) SetConfigIfNotSet(key string, value string) (err error) { if _, err = api.GetConfig(key); err != nil { err = api.SetConfig(key, value) } From 1e2e12fd59e3a03a1d0c74bfb004c1f8db543204 Mon Sep 17 00:00:00 2001 From: shiouen Date: Thu, 18 Nov 2021 16:38:41 +0100 Subject: [PATCH 18/54] moved the remaining APIs to their own package - big refactors --- pkg/api/semver.go | 42 -------------------------- pkg/core/get.go | 4 +-- pkg/core/predict.go | 6 ++-- pkg/core/push.go | 4 +-- pkg/core/release.go | 8 ++--- pkg/semver/api.go | 38 +++++++++++++++++++++++ pkg/{api/version.go => version/api.go} | 22 +++++++------- 7 files changed, 60 insertions(+), 64 deletions(-) delete mode 100644 pkg/api/semver.go create mode 100644 pkg/semver/api.go rename pkg/{api/version.go => version/api.go} (68%) diff --git a/pkg/api/semver.go b/pkg/api/semver.go deleted file mode 100644 index e8aa82a..0000000 --- a/pkg/api/semver.go +++ /dev/null @@ -1,42 +0,0 @@ -package api - -import ( - "github.com/restechnica/semverbot/pkg/semver" -) - -// SemverModeAPI an API to work with different modes. -type SemverModeAPI struct { - GitBranchMode semver.GitBranchMode - GitCommitMode semver.GitCommitMode -} - -// NewSemverModeAPI creates a new semver mode API with a mode detector to pass -// it on to the different modes that require it. -// Returns the new SemverModeAPI. -func NewSemverModeAPI(detector semver.ModeDetector) SemverModeAPI { - return SemverModeAPI{ - GitBranchMode: semver.NewGitBranchMode(detector), - GitCommitMode: semver.NewGitCommitMode(detector), - } -} - -// SelectMode selects the mode corresponding to the mode string. -// Returns the corresponding mode. -func (api SemverModeAPI) SelectMode(mode string) semver.Mode { - switch mode { - case semver.Auto: - return semver.NewAutoMode([]semver.Mode{api.GitBranchMode, api.GitCommitMode}) - case semver.GitCommit: - return api.GitCommitMode - case semver.GitBranch: - return api.GitBranchMode - case semver.Patch: - return semver.NewPatchMode() - case semver.Minor: - return semver.NewMinorMode() - case semver.Major: - return semver.NewMajorMode() - default: - return semver.NewPatchMode() - } -} diff --git a/pkg/core/get.go b/pkg/core/get.go index f5ea4dc..4a163e0 100644 --- a/pkg/core/get.go +++ b/pkg/core/get.go @@ -1,7 +1,7 @@ package core import ( - "github.com/restechnica/semverbot/pkg/api" + "github.com/restechnica/semverbot/pkg/version" ) type GetVersionOptions struct { @@ -11,6 +11,6 @@ type GetVersionOptions struct { // GetVersion gets the current version based on the latest annotated git tag. // Returns the current version. func GetVersion(options *GetVersionOptions) string { - var versionAPI = api.NewVersionAPI() + var versionAPI = version.NewAPI() return versionAPI.GetVersionOrDefault(options.DefaultVersion) } diff --git a/pkg/core/predict.go b/pkg/core/predict.go index ccb3f03..5fbc4ce 100644 --- a/pkg/core/predict.go +++ b/pkg/core/predict.go @@ -1,8 +1,8 @@ package core import ( - "github.com/restechnica/semverbot/pkg/api" "github.com/restechnica/semverbot/pkg/semver" + "github.com/restechnica/semverbot/pkg/version" ) type PredictVersionOptions struct { @@ -15,12 +15,12 @@ type PredictVersionOptions struct { // matched to specific strings. // Returns the predicted version or an error if anything went wrong with the increment. func PredictVersion(options *PredictVersionOptions) (prediction string, err error) { - var versionAPI = api.NewVersionAPI() + var versionAPI = version.NewAPI() var version = versionAPI.GetVersionOrDefault(options.DefaultVersion) var modeDetector = semver.NewModeDetector(options.SemverMatchMap) - var semverModeAPI = api.NewSemverModeAPI(modeDetector) + var semverModeAPI = semver.NewModeAPI(modeDetector) var semverMode = semverModeAPI.SelectMode(options.SemverMode) return semverMode.Increment(version) diff --git a/pkg/core/push.go b/pkg/core/push.go index d99d614..2aa48a1 100644 --- a/pkg/core/push.go +++ b/pkg/core/push.go @@ -2,8 +2,8 @@ package core import ( "fmt" + "github.com/restechnica/semverbot/pkg/version" - "github.com/restechnica/semverbot/pkg/api" "github.com/restechnica/semverbot/pkg/git" ) @@ -15,7 +15,7 @@ type PushVersionOptions struct { // PushVersion pushes the latest annotated git tag to the git origin. // Returns an error if pushing the tag went wrong. func PushVersion(options *PushVersionOptions) (err error) { - var versionAPI = api.NewVersionAPI() + var versionAPI = version.NewAPI() var version = versionAPI.GetVersionOrDefault(options.DefaultVersion) var prefixedVersion = fmt.Sprintf("%s%s", options.GitTagsPrefix, version) diff --git a/pkg/core/release.go b/pkg/core/release.go index a25468f..32d77ef 100644 --- a/pkg/core/release.go +++ b/pkg/core/release.go @@ -3,9 +3,9 @@ package core import ( "fmt" - "github.com/restechnica/semverbot/pkg/api" "github.com/restechnica/semverbot/pkg/git" "github.com/restechnica/semverbot/pkg/semver" + "github.com/restechnica/semverbot/pkg/version" ) type ReleaseVersionOptions struct { @@ -19,13 +19,13 @@ type ReleaseVersionOptions struct { // It creates an annotated git tag for the new version. // Returns an error if anything went wrong with incrementing or tagging. func ReleaseVersion(options *ReleaseVersionOptions) (err error) { - var versionAPI = api.NewVersionAPI() + var versionAPI = version.NewAPI() var version = versionAPI.GetVersionOrDefault(options.DefaultVersion) var modeDetector = semver.NewModeDetector(options.SemverMatchMap) - var semverModeAPI = api.NewSemverModeAPI(modeDetector) - var semverMode = semverModeAPI.SelectMode(options.SemverMode) + var modeAPI = semver.NewModeAPI(modeDetector) + var semverMode = modeAPI.SelectMode(options.SemverMode) var incrementedVersion string diff --git a/pkg/semver/api.go b/pkg/semver/api.go new file mode 100644 index 0000000..2f75a00 --- /dev/null +++ b/pkg/semver/api.go @@ -0,0 +1,38 @@ +package semver + +// ModeAPI an API to work with different modes. +type ModeAPI struct { + GitBranchMode GitBranchMode + GitCommitMode GitCommitMode +} + +// NewModeAPI creates a new semver mode API with a mode detector to pass +// it on to the different modes that require it. +// Returns the new ModeAPI. +func NewModeAPI(detector ModeDetector) ModeAPI { + return ModeAPI{ + GitBranchMode: NewGitBranchMode(detector), + GitCommitMode: NewGitCommitMode(detector), + } +} + +// SelectMode selects the mode corresponding to the mode string. +// Returns the corresponding mode. +func (api ModeAPI) SelectMode(mode string) Mode { + switch mode { + case Auto: + return NewAutoMode([]Mode{api.GitBranchMode, api.GitCommitMode}) + case GitCommit: + return api.GitCommitMode + case GitBranch: + return api.GitBranchMode + case Patch: + return NewPatchMode() + case Minor: + return NewMinorMode() + case Major: + return NewMajorMode() + default: + return NewPatchMode() + } +} diff --git a/pkg/api/version.go b/pkg/version/api.go similarity index 68% rename from pkg/api/version.go rename to pkg/version/api.go index 2dd8168..8c6be98 100644 --- a/pkg/api/version.go +++ b/pkg/version/api.go @@ -1,25 +1,25 @@ -package api +package version import ( "github.com/restechnica/semverbot/pkg/git" "github.com/restechnica/semverbot/pkg/semver" ) -// VersionAPI an API to work with versions. -type VersionAPI struct { +// API an API to work with versions. +type API struct { GitAPI git.API } -// NewVersionAPI creates a new VersionAPI. -// Returns the new VersionAPI. -func NewVersionAPI() VersionAPI { - return VersionAPI{git.NewAPI()} +// NewAPI creates a new API. +// Returns the new API. +func NewAPI() API { + return API{git.NewAPI()} } // GetVersion gets the current version. // Git adds newlines to certain command output, which is why the version is trimmed. // Returns the current version or an error if the GitAPI failed. -func (api VersionAPI) GetVersion() (version string, err error) { +func (api API) GetVersion() (version string, err error) { if version, err = api.GitAPI.GetLatestAnnotatedTag(); err != nil { return version, err } @@ -29,7 +29,7 @@ func (api VersionAPI) GetVersion() (version string, err error) { // GetVersionOrDefault gets the current version. // Defaults to a provided default version if the GitAPI failed. // Returns the current version. -func (api VersionAPI) GetVersionOrDefault(defaultVersion string) (version string) { +func (api API) GetVersionOrDefault(defaultVersion string) (version string) { var err error if version, err = api.GetVersion(); err != nil { @@ -41,13 +41,13 @@ func (api VersionAPI) GetVersionOrDefault(defaultVersion string) (version string //// PredictVersion predicts the next version with a provided semver mode. //// Returns the next version or an error if increment the current version failed. -//func (api VersionAPI) PredictVersion(target string, mode semver.Mode) (version string, err error) { +//func (api API) PredictVersion(target string, mode semver.Mode) (version string, err error) { // return mode.Increment(target) //} // //// PushVersion pushes a version with a provided version prefix. //// Returns an error if the the GitAPI failed. -//func (api VersionAPI) PushVersion(prefix string) (err error) { +//func (api API) PushVersion(prefix string) (err error) { // var version = api.GetVersionOrDefault(cli.DefaultVersion) // var prefixedVersion = fmt.Sprintf("%s%s", prefix, version) // return api.GitAPI.PushTag(prefixedVersion) From 4256133570423575edb1288924530f89736e1e16 Mon Sep 17 00:00:00 2001 From: shiouen Date: Thu, 18 Nov 2021 16:39:16 +0100 Subject: [PATCH 19/54] fixed import formatting --- pkg/core/push.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/core/push.go b/pkg/core/push.go index 2aa48a1..eec1299 100644 --- a/pkg/core/push.go +++ b/pkg/core/push.go @@ -2,9 +2,9 @@ package core import ( "fmt" - "github.com/restechnica/semverbot/pkg/version" "github.com/restechnica/semverbot/pkg/git" + "github.com/restechnica/semverbot/pkg/version" ) type PushVersionOptions struct { From c4e1bec2ea7eb567c4825be1d48110d7473a53f0 Mon Sep 17 00:00:00 2001 From: shiouen Date: Thu, 18 Nov 2021 17:34:44 +0100 Subject: [PATCH 20/54] implemented predict and release version methods in version api - switched to version api in core package - moved all remaining 'rogue' git executions to the git api --- pkg/core/get.go | 4 ++-- pkg/core/predict.go | 17 +++++++--------- pkg/core/push.go | 13 +++--------- pkg/core/release.go | 27 +++++++++---------------- pkg/git/api.go | 6 ++++++ pkg/{version => versions}/api.go | 34 +++++++++++++++++++------------- pkg/versions/prefix.go | 7 +++++++ 7 files changed, 54 insertions(+), 54 deletions(-) rename pkg/{version => versions}/api.go (53%) create mode 100644 pkg/versions/prefix.go diff --git a/pkg/core/get.go b/pkg/core/get.go index 4a163e0..e36f1bc 100644 --- a/pkg/core/get.go +++ b/pkg/core/get.go @@ -1,7 +1,7 @@ package core import ( - "github.com/restechnica/semverbot/pkg/version" + "github.com/restechnica/semverbot/pkg/versions" ) type GetVersionOptions struct { @@ -11,6 +11,6 @@ type GetVersionOptions struct { // GetVersion gets the current version based on the latest annotated git tag. // Returns the current version. func GetVersion(options *GetVersionOptions) string { - var versionAPI = version.NewAPI() + var versionAPI = versions.NewAPI() return versionAPI.GetVersionOrDefault(options.DefaultVersion) } diff --git a/pkg/core/predict.go b/pkg/core/predict.go index 5fbc4ce..493a952 100644 --- a/pkg/core/predict.go +++ b/pkg/core/predict.go @@ -1,8 +1,7 @@ package core import ( - "github.com/restechnica/semverbot/pkg/semver" - "github.com/restechnica/semverbot/pkg/version" + "github.com/restechnica/semverbot/pkg/versions" ) type PredictVersionOptions struct { @@ -15,13 +14,11 @@ type PredictVersionOptions struct { // matched to specific strings. // Returns the predicted version or an error if anything went wrong with the increment. func PredictVersion(options *PredictVersionOptions) (prediction string, err error) { - var versionAPI = version.NewAPI() + var versionAPI = versions.NewAPI() var version = versionAPI.GetVersionOrDefault(options.DefaultVersion) - - var modeDetector = semver.NewModeDetector(options.SemverMatchMap) - - var semverModeAPI = semver.NewModeAPI(modeDetector) - var semverMode = semverModeAPI.SelectMode(options.SemverMode) - - return semverMode.Increment(version) + return versionAPI.PredictVersion( + version, + options.SemverMatchMap, + options.SemverMode, + ) } diff --git a/pkg/core/push.go b/pkg/core/push.go index eec1299..62fdae4 100644 --- a/pkg/core/push.go +++ b/pkg/core/push.go @@ -1,10 +1,7 @@ package core import ( - "fmt" - - "github.com/restechnica/semverbot/pkg/git" - "github.com/restechnica/semverbot/pkg/version" + "github.com/restechnica/semverbot/pkg/versions" ) type PushVersionOptions struct { @@ -15,11 +12,7 @@ type PushVersionOptions struct { // PushVersion pushes the latest annotated git tag to the git origin. // Returns an error if pushing the tag went wrong. func PushVersion(options *PushVersionOptions) (err error) { - var versionAPI = version.NewAPI() + var versionAPI = versions.NewAPI() var version = versionAPI.GetVersionOrDefault(options.DefaultVersion) - - var prefixedVersion = fmt.Sprintf("%s%s", options.GitTagsPrefix, version) - - var gitAPI = git.NewAPI() - return gitAPI.PushTag(prefixedVersion) + return versionAPI.PushVersion(version, options.GitTagsPrefix) } diff --git a/pkg/core/release.go b/pkg/core/release.go index 32d77ef..5b27c41 100644 --- a/pkg/core/release.go +++ b/pkg/core/release.go @@ -1,11 +1,7 @@ package core import ( - "fmt" - - "github.com/restechnica/semverbot/pkg/git" - "github.com/restechnica/semverbot/pkg/semver" - "github.com/restechnica/semverbot/pkg/version" + "github.com/restechnica/semverbot/pkg/versions" ) type ReleaseVersionOptions struct { @@ -19,22 +15,17 @@ type ReleaseVersionOptions struct { // It creates an annotated git tag for the new version. // Returns an error if anything went wrong with incrementing or tagging. func ReleaseVersion(options *ReleaseVersionOptions) (err error) { - var versionAPI = version.NewAPI() - var version = versionAPI.GetVersionOrDefault(options.DefaultVersion) - - var modeDetector = semver.NewModeDetector(options.SemverMatchMap) + var versionAPI = versions.NewAPI() - var modeAPI = semver.NewModeAPI(modeDetector) - var semverMode = modeAPI.SelectMode(options.SemverMode) - - var incrementedVersion string + var version = versionAPI.GetVersionOrDefault(options.DefaultVersion) - if incrementedVersion, err = semverMode.Increment(version); err != nil { + if version, err = versionAPI.PredictVersion( + version, + options.SemverMatchMap, + options.SemverMode, + ); err != nil { return err } - incrementedVersion = fmt.Sprintf("%s%s", options.GitTagsPrefix, incrementedVersion) - - var gitAPI = git.NewAPI() - return gitAPI.CreateAnnotatedTag(incrementedVersion) + return versionAPI.ReleaseVersion(version) } diff --git a/pkg/git/api.go b/pkg/git/api.go index a33939a..925f3c7 100644 --- a/pkg/git/api.go +++ b/pkg/git/api.go @@ -43,6 +43,12 @@ func (api API) GetLatestAnnotatedTag() (tag string, err error) { return api.commander.Output("git", "describe", "--tags") } +// GetLatestCommitMessage gets the latest git commit message. +// Returns the git commit message or an error if the command failed. +func (api API) GetLatestCommitMessage() (message string, err error) { + return api.commander.Output("git", "--no-pager", "show", "-s", "--format=%s") +} + // GetMergedBranchName gets the source branch name if the last commit is a merge. // Returns the branch name or an error if something went wrong with git. func (api API) GetMergedBranchName() (name string, err error) { diff --git a/pkg/version/api.go b/pkg/versions/api.go similarity index 53% rename from pkg/version/api.go rename to pkg/versions/api.go index 8c6be98..e6672dc 100644 --- a/pkg/version/api.go +++ b/pkg/versions/api.go @@ -1,4 +1,4 @@ -package version +package versions import ( "github.com/restechnica/semverbot/pkg/git" @@ -39,16 +39,22 @@ func (api API) GetVersionOrDefault(defaultVersion string) (version string) { return version } -//// PredictVersion predicts the next version with a provided semver mode. -//// Returns the next version or an error if increment the current version failed. -//func (api API) PredictVersion(target string, mode semver.Mode) (version string, err error) { -// return mode.Increment(target) -//} -// -//// PushVersion pushes a version with a provided version prefix. -//// Returns an error if the the GitAPI failed. -//func (api API) PushVersion(prefix string) (err error) { -// var version = api.GetVersionOrDefault(cli.DefaultVersion) -// var prefixedVersion = fmt.Sprintf("%s%s", prefix, version) -// return api.GitAPI.PushTag(prefixedVersion) -//} +// PredictVersion predicts the next version with a provided semver mode. +// Returns the next version or an error if incrementing the current version failed. +func (api API) PredictVersion(version string, matchMap map[string][]string, mode string) (string, error) { + var modeDetector = semver.NewModeDetector(matchMap) + var semverModeAPI = semver.NewModeAPI(modeDetector) + var semverMode = semverModeAPI.SelectMode(mode) + return semverMode.Increment(version) +} + +func (api API) ReleaseVersion(version string) (err error) { + return api.GitAPI.CreateAnnotatedTag(version) +} + +// PushVersion pushes a version with a prefix. +// Returns an error if the the GitAPI failed. +func (api API) PushVersion(version string, prefix string) (err error) { + var prefixedVersion = AddPrefix(version, prefix) + return api.GitAPI.PushTag(prefixedVersion) +} diff --git a/pkg/versions/prefix.go b/pkg/versions/prefix.go new file mode 100644 index 0000000..7af81c6 --- /dev/null +++ b/pkg/versions/prefix.go @@ -0,0 +1,7 @@ +package versions + +import "fmt" + +func AddPrefix(version string, prefix string) string { + return fmt.Sprintf("%s%s", prefix, version) +} From b27831036e3d4adb4e379c11583f578501861575 Mon Sep 17 00:00:00 2001 From: shiouen Date: Thu, 18 Nov 2021 18:00:15 +0100 Subject: [PATCH 21/54] moved more core logic into the version api - update core documentation to be more simplified - updated version api documentation to be more in-depth --- pkg/core/get.go | 2 +- pkg/core/predict.go | 11 +++------- pkg/core/push.go | 4 ++-- pkg/core/release.go | 18 +++++++--------- pkg/core/update.go | 25 ++++++----------------- pkg/versions/api.go | 50 ++++++++++++++++++++++++++++++++------------- 6 files changed, 55 insertions(+), 55 deletions(-) diff --git a/pkg/core/get.go b/pkg/core/get.go index e36f1bc..832a6fb 100644 --- a/pkg/core/get.go +++ b/pkg/core/get.go @@ -8,7 +8,7 @@ type GetVersionOptions struct { DefaultVersion string } -// GetVersion gets the current version based on the latest annotated git tag. +// GetVersion gets the current version. // Returns the current version. func GetVersion(options *GetVersionOptions) string { var versionAPI = versions.NewAPI() diff --git a/pkg/core/predict.go b/pkg/core/predict.go index 493a952..5569e82 100644 --- a/pkg/core/predict.go +++ b/pkg/core/predict.go @@ -10,15 +10,10 @@ type PredictVersionOptions struct { SemverMode string } -// PredictVersion predicts a version based on the latest annotated git tag and a map of semver levels -// matched to specific strings. -// Returns the predicted version or an error if anything went wrong with the increment. +// PredictVersion predicts the next version. +// Returns the predicted version or an error if anything went wrong with the prediction. func PredictVersion(options *PredictVersionOptions) (prediction string, err error) { var versionAPI = versions.NewAPI() var version = versionAPI.GetVersionOrDefault(options.DefaultVersion) - return versionAPI.PredictVersion( - version, - options.SemverMatchMap, - options.SemverMode, - ) + return versionAPI.PredictVersion(version, options.SemverMatchMap, options.SemverMode) } diff --git a/pkg/core/push.go b/pkg/core/push.go index 62fdae4..1d29955 100644 --- a/pkg/core/push.go +++ b/pkg/core/push.go @@ -9,8 +9,8 @@ type PushVersionOptions struct { GitTagsPrefix string } -// PushVersion pushes the latest annotated git tag to the git origin. -// Returns an error if pushing the tag went wrong. +// PushVersion pushes the current version. +// Returns an error if the push went wrong. func PushVersion(options *PushVersionOptions) (err error) { var versionAPI = versions.NewAPI() var version = versionAPI.GetVersionOrDefault(options.DefaultVersion) diff --git a/pkg/core/release.go b/pkg/core/release.go index 5b27c41..7a33b3c 100644 --- a/pkg/core/release.go +++ b/pkg/core/release.go @@ -11,21 +11,17 @@ type ReleaseVersionOptions struct { SemverMode string } -// ReleaseVersion releases a new version by incrementing the latest annotated git tag. -// It creates an annotated git tag for the new version. -// Returns an error if anything went wrong with incrementing or tagging. -func ReleaseVersion(options *ReleaseVersionOptions) (err error) { +// ReleaseVersion releases a new version. +// Returns an error if anything went wrong with the prediction or releasing. +func ReleaseVersion(options *ReleaseVersionOptions) error { var versionAPI = versions.NewAPI() - var version = versionAPI.GetVersionOrDefault(options.DefaultVersion) + var currentVersion = versionAPI.GetVersionOrDefault(options.DefaultVersion) + var predictedVersion, err = versionAPI.PredictVersion(currentVersion, options.SemverMatchMap, options.SemverMode) - if version, err = versionAPI.PredictVersion( - version, - options.SemverMatchMap, - options.SemverMode, - ); err != nil { + if err != nil { return err } - return versionAPI.ReleaseVersion(version) + return versionAPI.ReleaseVersion(predictedVersion) } diff --git a/pkg/core/update.go b/pkg/core/update.go index 0a75819..20d52be 100644 --- a/pkg/core/update.go +++ b/pkg/core/update.go @@ -1,25 +1,12 @@ package core import ( - "fmt" - - "github.com/restechnica/semverbot/pkg/git" + "github.com/restechnica/semverbot/pkg/versions" ) -// UpdateVersion changes the current git repo into an unshallow repo and fetches all git tags. -// Returns and error if anything went wrong. -func UpdateVersion() (err error) { - var gitAPI = git.NewAPI() - - if err = gitAPI.FetchUnshallow(); err != nil { - fmt.Println("something went wrong while fetching from git, attempting to fetch tags anyway") - } - - if err = gitAPI.FetchTags(); err != nil { - fmt.Println("something went wrong while updating the version") - } else { - fmt.Println("successfully fetched the latest git tags") - } - - return err +// UpdateVersion updates to the latest version. +// Returns an error if updating the version went wrong. +func UpdateVersion() error { + var versionAPI = versions.NewAPI() + return versionAPI.UpdateVersion() } diff --git a/pkg/versions/api.go b/pkg/versions/api.go index e6672dc..d7aa09f 100644 --- a/pkg/versions/api.go +++ b/pkg/versions/api.go @@ -1,6 +1,8 @@ package versions import ( + "fmt" + "github.com/restechnica/semverbot/pkg/git" "github.com/restechnica/semverbot/pkg/semver" ) @@ -10,25 +12,24 @@ type API struct { GitAPI git.API } -// NewAPI creates a new API. +// NewAPI creates a new version API. // Returns the new API. func NewAPI() API { return API{git.NewAPI()} } -// GetVersion gets the current version. -// Git adds newlines to certain command output, which is why the version is trimmed. +// GetVersion gets the current version by getting the latest annotated git tag. +// The tag is trimmed because git adds newlines to the underlying command. // Returns the current version or an error if the GitAPI failed. -func (api API) GetVersion() (version string, err error) { - if version, err = api.GitAPI.GetLatestAnnotatedTag(); err != nil { - return version, err +func (api API) GetVersion() (currentVersion string, err error) { + if currentVersion, err = api.GitAPI.GetLatestAnnotatedTag(); err != nil { + return currentVersion, err } - return semver.Trim(version) + return semver.Trim(currentVersion) } -// GetVersionOrDefault gets the current version. -// Defaults to a provided default version if the GitAPI failed. -// Returns the current version. +// GetVersionOrDefault gets the current version or a default version if it failed. +// Returns the current version or a default version. func (api API) GetVersionOrDefault(defaultVersion string) (version string) { var err error @@ -39,8 +40,9 @@ func (api API) GetVersionOrDefault(defaultVersion string) (version string) { return version } -// PredictVersion predicts the next version with a provided semver mode. -// Returns the next version or an error if incrementing the current version failed. +// PredictVersion increments a version based on a semver mode and a map of semver levels with matching strings. +// The matching strings will be matched against git information to detect which semver level to increment. +// Returns the next version or an error if the increment failed. func (api API) PredictVersion(version string, matchMap map[string][]string, mode string) (string, error) { var modeDetector = semver.NewModeDetector(matchMap) var semverModeAPI = semver.NewModeAPI(modeDetector) @@ -48,13 +50,33 @@ func (api API) PredictVersion(version string, matchMap map[string][]string, mode return semverMode.Increment(version) } +// ReleaseVersion releases a version by creating an annotated git tag. +// Returns an error if the tag creation failed. func (api API) ReleaseVersion(version string) (err error) { return api.GitAPI.CreateAnnotatedTag(version) } -// PushVersion pushes a version with a prefix. -// Returns an error if the the GitAPI failed. +// PushVersion pushes a version by pushing a git tag with a prefix. +// Returns an error if pushing the tag failed. func (api API) PushVersion(version string, prefix string) (err error) { var prefixedVersion = AddPrefix(version, prefix) return api.GitAPI.PushTag(prefixedVersion) } + +// UpdateVersion updates the version by making the git repo unshallow and by fetching all git tags. +// Returns and error if anything went wrong. +func (api API) UpdateVersion() (err error) { + var gitAPI = git.NewAPI() + + if err = gitAPI.FetchUnshallow(); err != nil { + fmt.Println("something went wrong while fetching from git, attempting to fetch tags anyway") + } + + if err = gitAPI.FetchTags(); err != nil { + fmt.Println("something went wrong while updating the version") + } else { + fmt.Println("successfully fetched the latest git tags") + } + + return err +} From 6a46f825c6ab509332015524d4f06433a15f5532 Mon Sep 17 00:00:00 2001 From: shiouen Date: Thu, 18 Nov 2021 18:08:42 +0100 Subject: [PATCH 22/54] exposed the GitAPI commander publicly (good for unit testing) - git branch mode and git commit mode have been changed to run git commands through the git api --- pkg/git/api.go | 22 +++++++++++----------- pkg/semver/gitbranch.go | 9 ++++----- pkg/semver/gitcommit.go | 8 ++++---- pkg/semver/gitcommit_test.go | 8 ++++---- 4 files changed, 23 insertions(+), 24 deletions(-) diff --git a/pkg/git/api.go b/pkg/git/api.go index 925f3c7..3c3620f 100644 --- a/pkg/git/api.go +++ b/pkg/git/api.go @@ -4,55 +4,55 @@ import "github.com/restechnica/semverbot/internal/commands" // API an API to interact with the git CLI. type API struct { - commander commands.Commander + Commander commands.Commander } // NewAPI creates a new API with a commander to run git commands. // Returns the new API. func NewAPI() API { - return API{commander: commands.NewExecCommander()} + return API{Commander: commands.NewExecCommander()} } // CreateAnnotatedTag creates an annotated git tag. // Returns an error if the command fails. func (api API) CreateAnnotatedTag(tag string) (err error) { - return api.commander.Run("git", "tag", "-a", tag, "-m", tag) + return api.Commander.Run("git", "tag", "-a", tag, "-m", tag) } // FetchTags fetches all tags from the remote origin. // Returns an error if the command fails. func (api API) FetchTags() (err error) { - return api.commander.Run("git", "fetch", "--tags") + return api.Commander.Run("git", "fetch", "--tags") } // FetchUnshallow convert a shallow repository to a complete one. // Returns an error if the command fails. func (api API) FetchUnshallow() (err error) { - return api.commander.Run("git", "fetch", "--unshallow") + return api.Commander.Run("git", "fetch", "--unshallow") } // GetConfig gets the git config for a specific key. // Returns the value of the git config as a string and an error if the command failed. func (api API) GetConfig(key string) (value string, err error) { - return api.commander.Output("git", "config", "--get", key) + return api.Commander.Output("git", "config", "--get", key) } // GetLatestAnnotatedTag gets the latest annotated git tag. // Returns the git tag and an error if the command failed. func (api API) GetLatestAnnotatedTag() (tag string, err error) { - return api.commander.Output("git", "describe", "--tags") + return api.Commander.Output("git", "describe", "--tags") } // GetLatestCommitMessage gets the latest git commit message. // Returns the git commit message or an error if the command failed. func (api API) GetLatestCommitMessage() (message string, err error) { - return api.commander.Output("git", "--no-pager", "show", "-s", "--format=%s") + return api.Commander.Output("git", "--no-pager", "show", "-s", "--format=%s") } // GetMergedBranchName gets the source branch name if the last commit is a merge. // Returns the branch name or an error if something went wrong with git. func (api API) GetMergedBranchName() (name string, err error) { - return api.commander.Output( + return api.Commander.Output( "git", "name-rev", "--name-only", @@ -65,13 +65,13 @@ func (api API) GetMergedBranchName() (name string, err error) { // PushTag pushes a tag to the remote origin. // Returns an error if the command failed. func (api API) PushTag(tag string) (err error) { - return api.commander.Run("git", "push", "origin", tag) + return api.Commander.Run("git", "push", "origin", tag) } // SetConfig sets a git config key and value. // Returns an error if the command failed. func (api API) SetConfig(key string, value string) (err error) { - return api.commander.Run("git", "config", key, value) + return api.Commander.Run("git", "config", key, value) } // SetConfigIfNotSet sets a git config key and value if the config does not exist. diff --git a/pkg/semver/gitbranch.go b/pkg/semver/gitbranch.go index 430b1ae..9e1fe34 100644 --- a/pkg/semver/gitbranch.go +++ b/pkg/semver/gitbranch.go @@ -3,7 +3,7 @@ package semver import ( "fmt" - "github.com/restechnica/semverbot/internal/commands" + "github.com/restechnica/semverbot/pkg/git" ) // GitBranch mode name for GitBranchMode. @@ -12,14 +12,14 @@ const GitBranch = "git-branch" // GitBranchMode implementation of the Mode interface. // It increments the semver level based on the naming of the source branch of a git merge. type GitBranchMode struct { - Commander commands.Commander + GitAPI git.API ModeDetector ModeDetector } // NewGitBranchMode creates a new GitBranchMode. // Returns the new GitBranchMode. func NewGitBranchMode(detector ModeDetector) GitBranchMode { - return GitBranchMode{Commander: commands.ExecCommander{}, ModeDetector: detector} + return GitBranchMode{GitAPI: git.NewAPI(), ModeDetector: detector} } // Increment increments the semver level based on the naming of the source branch of a git merge. @@ -29,8 +29,7 @@ func (mode GitBranchMode) Increment(targetVersion string) (nextVersion string, e var branchName string var matchedMode Mode - if branchName, err = mode.Commander.Output("git", "name-rev", "--name-only", "--refs=refs/heads/*", - "--refs=refs/remotes/*", "HEAD^2"); err != nil { + if branchName, err = mode.GitAPI.GetMergedBranchName(); err != nil { return } diff --git a/pkg/semver/gitcommit.go b/pkg/semver/gitcommit.go index 7e27911..4edc632 100644 --- a/pkg/semver/gitcommit.go +++ b/pkg/semver/gitcommit.go @@ -1,7 +1,7 @@ package semver import ( - "github.com/restechnica/semverbot/internal/commands" + "github.com/restechnica/semverbot/pkg/git" ) // GitCommit mode name for GitCommitMode. @@ -10,14 +10,14 @@ const GitCommit = "git-commit" // GitCommitMode implementation of the Mode interface. // It increments the semver level based on the latest git commit messages. type GitCommitMode struct { - Commander commands.Commander + GitAPI git.API ModeDetector ModeDetector } // NewGitCommitMode creates a new GitCommitMode. // Returns the new GitCommitMode. func NewGitCommitMode(detector ModeDetector) GitCommitMode { - return GitCommitMode{Commander: commands.ExecCommander{}, ModeDetector: detector} + return GitCommitMode{GitAPI: git.NewAPI(), ModeDetector: detector} } // Increment increments a given version based on the latest git commit message. @@ -26,7 +26,7 @@ func (mode GitCommitMode) Increment(targetVersion string) (nextVersion string, e var message string var detectedMode Mode - if message, err = mode.Commander.Output("git", "show", "-s", "--format=%s"); err != nil { + if message, err = mode.GitAPI.GetLatestCommitMessage(); err != nil { return } diff --git a/pkg/semver/gitcommit_test.go b/pkg/semver/gitcommit_test.go index aae461b..db2cee7 100644 --- a/pkg/semver/gitcommit_test.go +++ b/pkg/semver/gitcommit_test.go @@ -4,11 +4,11 @@ import ( "fmt" "testing" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" "github.com/restechnica/semverbot/internal/mocks" + "github.com/restechnica/semverbot/pkg/git" ) var semverMatchMap = map[string][]string{ @@ -102,7 +102,7 @@ func TestGitCommitMode_Increment(t *testing.T) { cmder.On("Output", mock.Anything, mock.Anything).Return(test.Message, nil) var gitCommitMode = NewGitCommitMode(NewModeDetector(semverMatchMap)) - gitCommitMode.Commander = cmder + gitCommitMode.GitAPI = git.API{Commander: cmder} var got, err = gitCommitMode.Increment(test.Version) assert.NoError(t, err) @@ -131,7 +131,7 @@ func TestGitCommitMode_Increment(t *testing.T) { cmder.On("Output", mock.Anything, mock.Anything).Return(test.Message, test.GitError) var gitCommitMode = NewGitCommitMode(NewModeDetector(semverMatchMap)) - gitCommitMode.Commander = cmder + gitCommitMode.GitAPI = git.API{Commander: cmder} var _, err = gitCommitMode.Increment(test.Version) assert.Error(t, err) From 50c96aa6380767829a54946d00ce251821f2f369 Mon Sep 17 00:00:00 2001 From: shiouen Date: Thu, 18 Nov 2021 18:26:05 +0100 Subject: [PATCH 23/54] added semver package readme --- pkg/semver/readme.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 pkg/semver/readme.md diff --git a/pkg/semver/readme.md b/pkg/semver/readme.md new file mode 100644 index 0000000..cfb3057 --- /dev/null +++ b/pkg/semver/readme.md @@ -0,0 +1 @@ +not entirely happy with this package's structure/contents, but it works :) \ No newline at end of file From 345b5787b9dc4a30eca6dedbec9dc5e9bae0662d Mon Sep 17 00:00:00 2001 From: shiouen Date: Thu, 18 Nov 2021 18:46:24 +0100 Subject: [PATCH 24/54] config file flag usage now makes use of default config file path instead of hardcoded path --- cmd/sbot/main.go | 4 ++-- main.go | 4 ++-- pkg/cli/commands/root.go | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/cmd/sbot/main.go b/cmd/sbot/main.go index f6fc74a..3a302f0 100644 --- a/cmd/sbot/main.go +++ b/cmd/sbot/main.go @@ -6,6 +6,6 @@ import ( // main bootstraps the `sbot` CLI app. func main() { - var cli = commands.NewRootCommand() - _ = cli.Execute() + var cmd = commands.NewRootCommand() + _ = cmd.Execute() } diff --git a/main.go b/main.go index f6fc74a..3a302f0 100644 --- a/main.go +++ b/main.go @@ -6,6 +6,6 @@ import ( // main bootstraps the `sbot` CLI app. func main() { - var cli = commands.NewRootCommand() - _ = cli.Execute() + var cmd = commands.NewRootCommand() + _ = cmd.Execute() } diff --git a/pkg/cli/commands/root.go b/pkg/cli/commands/root.go index c59dd0f..bd249ea 100644 --- a/pkg/cli/commands/root.go +++ b/pkg/cli/commands/root.go @@ -2,6 +2,7 @@ package commands import ( "errors" + "fmt" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -19,7 +20,7 @@ func NewRootCommand() *cobra.Command { } command.PersistentFlags().StringVarP(&cli.ConfigFlag, "config", "c", "", - `sbot config (default ".semverbot.toml")`) + fmt.Sprintf(`configures which config file to use (default "%s")`, cli.DefaultConfigFilePath)) command.AddCommand(NewGetCommand()) command.AddCommand(NewInitCommand()) From cc100d73cc7e4ddbedff9041cbe547bd9f66bc70 Mon Sep 17 00:00:00 2001 From: shiouen Date: Sat, 20 Nov 2021 14:13:07 +0100 Subject: [PATCH 25/54] added string util methods --- internal/util/strings.go | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 internal/util/strings.go diff --git a/internal/util/strings.go b/internal/util/strings.go new file mode 100644 index 0000000..a735118 --- /dev/null +++ b/internal/util/strings.go @@ -0,0 +1,34 @@ +package util + +import "strings" + +// SplitByDelimiterString splits a string by multiple delimiters. +// Returns the resulting slice of strings. +func SplitByDelimiterString(target string, delimiters string) []string { + var splitDelimiters = strings.Split(delimiters, "") + + return strings.FieldsFunc(target, func(r rune) bool { + for _, delimiter := range splitDelimiters { + if delimiter == string(r) { + return true + } + } + return false + }) +} + +// SliceContainsString returns true if a string equals an element in the slice. +func SliceContainsString(container []string, value string) bool { + for _, contained := range container { + if contained == value { + return true + } + } + return false +} + +// Contains returns true if a string, split by delimiters, contains another string. +func Contains(target string, value string, delimiters string) bool { + var slice = SplitByDelimiterString(target, delimiters) + return SliceContainsString(slice, value) +} From b50f26955ac0d4c2c801e3a1d10198f4373f48eb Mon Sep 17 00:00:00 2001 From: shiouen Date: Sat, 20 Nov 2021 14:13:19 +0100 Subject: [PATCH 26/54] deleted readme --- pkg/semver/readme.md | 1 - 1 file changed, 1 deletion(-) delete mode 100644 pkg/semver/readme.md diff --git a/pkg/semver/readme.md b/pkg/semver/readme.md deleted file mode 100644 index cfb3057..0000000 --- a/pkg/semver/readme.md +++ /dev/null @@ -1 +0,0 @@ -not entirely happy with this package's structure/contents, but it works :) \ No newline at end of file From ae5873ed0821eafc5f801eb8f201718ec3824477 Mon Sep 17 00:00:00 2001 From: shiouen Date: Sat, 20 Nov 2021 14:22:29 +0100 Subject: [PATCH 27/54] moved semver modes to a modes package - renamed the mode api - removed mode detector - added delimiters to git modes - moved mode detection to git modes - implemented delimiter logic for git modes --- pkg/{semver => modes}/api.go | 22 +++---- pkg/{semver => modes}/auto.go | 2 +- pkg/{semver => modes}/auto_test.go | 2 +- pkg/modes/gitbranch.go | 78 +++++++++++++++++++++++++ pkg/modes/gitcommit.go | 70 ++++++++++++++++++++++ pkg/{semver => modes}/gitcommit_test.go | 2 +- pkg/{semver => modes}/major.go | 9 ++- pkg/{semver => modes}/major_test.go | 2 +- pkg/{semver => modes}/minor.go | 9 ++- pkg/{semver => modes}/minor_test.go | 2 +- pkg/{semver => modes}/mode.go | 2 +- pkg/{semver => modes}/patch.go | 5 +- pkg/{semver => modes}/patch_test.go | 2 +- pkg/semver/detection.go | 40 ------------- pkg/semver/gitbranch.go | 47 --------------- pkg/semver/gitcommit.go | 38 ------------ pkg/versions/api.go | 5 +- 17 files changed, 185 insertions(+), 152 deletions(-) rename pkg/{semver => modes}/api.go (58%) rename pkg/{semver => modes}/auto.go (98%) rename pkg/{semver => modes}/auto_test.go (99%) create mode 100644 pkg/modes/gitbranch.go create mode 100644 pkg/modes/gitcommit.go rename pkg/{semver => modes}/gitcommit_test.go (99%) rename pkg/{semver => modes}/major.go (80%) rename pkg/{semver => modes}/major_test.go (98%) rename pkg/{semver => modes}/minor.go (80%) rename pkg/{semver => modes}/minor_test.go (98%) rename pkg/{semver => modes}/mode.go (90%) rename pkg/{semver => modes}/patch.go (86%) rename pkg/{semver => modes}/patch_test.go (98%) delete mode 100644 pkg/semver/detection.go delete mode 100644 pkg/semver/gitbranch.go delete mode 100644 pkg/semver/gitcommit.go diff --git a/pkg/semver/api.go b/pkg/modes/api.go similarity index 58% rename from pkg/semver/api.go rename to pkg/modes/api.go index 2f75a00..89f1857 100644 --- a/pkg/semver/api.go +++ b/pkg/modes/api.go @@ -1,24 +1,26 @@ -package semver +package modes -// ModeAPI an API to work with different modes. -type ModeAPI struct { +type SemverMap map[string][]string + +// API an API to work with different modes. +type API struct { GitBranchMode GitBranchMode GitCommitMode GitCommitMode } -// NewModeAPI creates a new semver mode API with a mode detector to pass +// NewAPI creates a new semver mode API with a mode detector to pass // it on to the different modes that require it. -// Returns the new ModeAPI. -func NewModeAPI(detector ModeDetector) ModeAPI { - return ModeAPI{ - GitBranchMode: NewGitBranchMode(detector), - GitCommitMode: NewGitCommitMode(detector), +// Returns the new API. +func NewAPI(semverMap SemverMap) API { + return API{ + GitBranchMode: NewGitBranchMode(semverMap), + GitCommitMode: NewGitCommitMode(semverMap), } } // SelectMode selects the mode corresponding to the mode string. // Returns the corresponding mode. -func (api ModeAPI) SelectMode(mode string) Mode { +func (api API) SelectMode(mode string) Mode { switch mode { case Auto: return NewAutoMode([]Mode{api.GitBranchMode, api.GitCommitMode}) diff --git a/pkg/semver/auto.go b/pkg/modes/auto.go similarity index 98% rename from pkg/semver/auto.go rename to pkg/modes/auto.go index 74d8a97..df38068 100644 --- a/pkg/semver/auto.go +++ b/pkg/modes/auto.go @@ -1,4 +1,4 @@ -package semver +package modes // Auto mode name for AutoMode. const Auto = "auto" diff --git a/pkg/semver/auto_test.go b/pkg/modes/auto_test.go similarity index 99% rename from pkg/semver/auto_test.go rename to pkg/modes/auto_test.go index a5b5a38..ae76f8b 100644 --- a/pkg/semver/auto_test.go +++ b/pkg/modes/auto_test.go @@ -1,4 +1,4 @@ -package semver +package modes import ( "fmt" diff --git a/pkg/modes/gitbranch.go b/pkg/modes/gitbranch.go new file mode 100644 index 0000000..5857e5d --- /dev/null +++ b/pkg/modes/gitbranch.go @@ -0,0 +1,78 @@ +package modes + +import ( + "fmt" + + "github.com/restechnica/semverbot/internal/util" + "github.com/restechnica/semverbot/pkg/git" +) + +// GitBranch mode name for GitBranchMode. +const GitBranch = "git-branch" + +// GitBranchMode implementation of the Mode interface. +// It increments the semver level based on the naming of the source branch of a git merge. +type GitBranchMode struct { + Delimiters string + GitAPI git.API + SemverMap SemverMap +} + +// NewGitBranchMode creates a new GitBranchMode. +// Returns the new GitBranchMode. +func NewGitBranchMode(delimiters string, semverMap SemverMap) GitBranchMode { + return GitBranchMode{Delimiters: delimiters, GitAPI: git.NewAPI(), SemverMap: semverMap} +} + +// Increment increments the semver level based on the naming of the source branch of a git merge. +// Returns the incremented version or an error if the last git commit is not a merge or if no mode was detected +// based on the branch name. +func (mode GitBranchMode) Increment(targetVersion string) (nextVersion string, err error) { + var branchName string + var matchedMode Mode + + if branchName, err = mode.GitAPI.GetMergedBranchName(); err != nil { + return + } + + var isMergeCommit = branchName != "" + + if !isMergeCommit { + return nextVersion, fmt.Errorf("failed to increment version because the latest git commit is not a merge commit") + } + + if matchedMode, err = mode.DetectMode(branchName); err != nil { + return nextVersion, err + } + + return matchedMode.Increment(targetVersion) +} + +// DetectMode detects the mode (patch, minor, major) based on a git branch name. +// Returns the detected mode. +// Currently forces the level to be in a certain position, must change +func (mode GitBranchMode) DetectMode(branchName string) (detected Mode, err error) { + for key, values := range mode.SemverMap { + for _, value := range values { + if mode.isMatch(branchName, value) { + switch key { + case Patch: + detected = NewPatchMode() + case Minor: + detected = NewMinorMode() + case Major: + detected = NewMajorMode() + } + return detected, err + } + } + } + + return detected, fmt.Errorf(`failed to detect mode from git commit message "%s" with delimiters "%s"`, + branchName, mode.Delimiters) +} + +// isMatch returns true if a string is part of branch name, after splitting the branch name with delimiters +func (mode GitBranchMode) isMatch(branchName string, value string) bool { + return util.Contains(branchName, value, mode.Delimiters) +} diff --git a/pkg/modes/gitcommit.go b/pkg/modes/gitcommit.go new file mode 100644 index 0000000..9ba2b49 --- /dev/null +++ b/pkg/modes/gitcommit.go @@ -0,0 +1,70 @@ +package modes + +import ( + "fmt" + + "github.com/restechnica/semverbot/internal/util" + "github.com/restechnica/semverbot/pkg/git" +) + +// GitCommit mode name for GitCommitMode. +const GitCommit = "git-commit" + +// GitCommitMode implementation of the Mode interface. +// It increments the semver level based on the latest git commit messages. +type GitCommitMode struct { + Delimiters string + GitAPI git.API + SemverMap SemverMap +} + +// NewGitCommitMode creates a new GitCommitMode. +// Returns the new GitCommitMode. +func NewGitCommitMode(delimiters string, semverMap SemverMap) GitCommitMode { + return GitCommitMode{Delimiters: delimiters, GitAPI: git.NewAPI(), SemverMap: semverMap} +} + +// Increment increments a given version based on the latest git commit message. +// Returns the incremented version or an error if it failed to detect the mode based on the git commit. +func (mode GitCommitMode) Increment(targetVersion string) (nextVersion string, err error) { + var message string + var detectedMode Mode + + if message, err = mode.GitAPI.GetLatestCommitMessage(); err != nil { + return + } + + if detectedMode, err = mode.DetectMode(message); err != nil { + return + } + + return detectedMode.Increment(targetVersion) +} + +// DetectMode detects the mode (patch, minor, major) based on a git commit message. +// Returns the detected mode. +func (mode GitCommitMode) DetectMode(commitMessage string) (detected Mode, err error) { + for level, values := range mode.SemverMap { + for _, value := range values { + if mode.isMatch(commitMessage, value) { + switch level { + case Patch: + detected = NewPatchMode() + case Minor: + detected = NewMinorMode() + case Major: + detected = NewMajorMode() + } + return detected, err + } + } + } + + return detected, fmt.Errorf(`failed to detect mode from git commit message "%s" with delimiters "%s"`, + commitMessage, mode.Delimiters) +} + +// isMatch returns true if a string is part of commit message, after splitting the git commit message with delimiters +func (mode GitCommitMode) isMatch(commitMessage string, value string) bool { + return util.Contains(commitMessage, value, mode.Delimiters) +} diff --git a/pkg/semver/gitcommit_test.go b/pkg/modes/gitcommit_test.go similarity index 99% rename from pkg/semver/gitcommit_test.go rename to pkg/modes/gitcommit_test.go index db2cee7..48e038b 100644 --- a/pkg/semver/gitcommit_test.go +++ b/pkg/modes/gitcommit_test.go @@ -1,4 +1,4 @@ -package semver +package modes import ( "fmt" diff --git a/pkg/semver/major.go b/pkg/modes/major.go similarity index 80% rename from pkg/semver/major.go rename to pkg/modes/major.go index 89b7b27..25c4ddc 100644 --- a/pkg/semver/major.go +++ b/pkg/modes/major.go @@ -1,6 +1,9 @@ -package semver +package modes -import blangsemver "github.com/blang/semver/v4" +import ( + blangsemver "github.com/blang/semver/v4" + "github.com/restechnica/semverbot/pkg/semver" +) // Major semver version level for major const Major = "major" @@ -20,7 +23,7 @@ func NewMajorMode() MajorMode { func (majorMode MajorMode) Increment(targetVersion string) (nextVersion string, err error) { var version blangsemver.Version - if version, err = Parse(targetVersion); err != nil { + if version, err = semver.Parse(targetVersion); err != nil { return } diff --git a/pkg/semver/major_test.go b/pkg/modes/major_test.go similarity index 98% rename from pkg/semver/major_test.go rename to pkg/modes/major_test.go index 277cfcd..64e99eb 100644 --- a/pkg/semver/major_test.go +++ b/pkg/modes/major_test.go @@ -1,4 +1,4 @@ -package semver +package modes import ( "testing" diff --git a/pkg/semver/minor.go b/pkg/modes/minor.go similarity index 80% rename from pkg/semver/minor.go rename to pkg/modes/minor.go index bd4cb20..1933e14 100644 --- a/pkg/semver/minor.go +++ b/pkg/modes/minor.go @@ -1,6 +1,9 @@ -package semver +package modes -import blangsemver "github.com/blang/semver/v4" +import ( + blangsemver "github.com/blang/semver/v4" + "github.com/restechnica/semverbot/pkg/semver" +) // Minor semver version level for minor const Minor = "minor" @@ -20,7 +23,7 @@ func NewMinorMode() MinorMode { func (minorMode MinorMode) Increment(targetVersion string) (nextVersion string, err error) { var version blangsemver.Version - if version, err = Parse(targetVersion); err != nil { + if version, err = semver.Parse(targetVersion); err != nil { return } diff --git a/pkg/semver/minor_test.go b/pkg/modes/minor_test.go similarity index 98% rename from pkg/semver/minor_test.go rename to pkg/modes/minor_test.go index 214d764..b3d25dd 100644 --- a/pkg/semver/minor_test.go +++ b/pkg/modes/minor_test.go @@ -1,4 +1,4 @@ -package semver +package modes import ( "testing" diff --git a/pkg/semver/mode.go b/pkg/modes/mode.go similarity index 90% rename from pkg/semver/mode.go rename to pkg/modes/mode.go index 5f908fd..3f249aa 100644 --- a/pkg/semver/mode.go +++ b/pkg/modes/mode.go @@ -1,4 +1,4 @@ -package semver +package modes // Mode interface which increments a specific semver level. type Mode interface { diff --git a/pkg/semver/patch.go b/pkg/modes/patch.go similarity index 86% rename from pkg/semver/patch.go rename to pkg/modes/patch.go index ef24aec..5baa4d6 100644 --- a/pkg/semver/patch.go +++ b/pkg/modes/patch.go @@ -1,7 +1,8 @@ -package semver +package modes import ( blangsemver "github.com/blang/semver/v4" + "github.com/restechnica/semverbot/pkg/semver" ) // Patch semver version level for patch @@ -22,7 +23,7 @@ func NewPatchMode() PatchMode { func (mode PatchMode) Increment(targetVersion string) (nextVersion string, err error) { var version blangsemver.Version - if version, err = Parse(targetVersion); err != nil { + if version, err = semver.Parse(targetVersion); err != nil { return } diff --git a/pkg/semver/patch_test.go b/pkg/modes/patch_test.go similarity index 98% rename from pkg/semver/patch_test.go rename to pkg/modes/patch_test.go index 7c2a5c5..989aba6 100644 --- a/pkg/semver/patch_test.go +++ b/pkg/modes/patch_test.go @@ -1,4 +1,4 @@ -package semver +package modes import ( "testing" diff --git a/pkg/semver/detection.go b/pkg/semver/detection.go deleted file mode 100644 index f4e9e19..0000000 --- a/pkg/semver/detection.go +++ /dev/null @@ -1,40 +0,0 @@ -package semver - -import ( - "fmt" - "strings" -) - -// ModeDetector detects which mode should be applied. -type ModeDetector struct { - SemverMatchMap map[string][]string -} - -// NewModeDetector creates a new ModeDetector with a detection configuration. -// Returns the new ModeDetector. -func NewModeDetector(semverMatchMap map[string][]string) ModeDetector { - return ModeDetector{SemverMatchMap: semverMatchMap} -} - -// DetectMode detects the semver level mode (patch, minor, major) based -// on a string and the SemverMatchMap. -// Returns the detected mode or an error if no mode was detected. -func (detector ModeDetector) DetectMode(target string) (detected Mode, err error) { - for mode, substrings := range detector.SemverMatchMap { - for _, substring := range substrings { - if strings.Contains(target, substring) { - switch mode { - case Patch: - detected = NewPatchMode() - case Minor: - detected = NewMinorMode() - case Major: - detected = NewMajorMode() - } - return detected, err - } - } - } - - return detected, fmt.Errorf(`failed to detect mode from "%s"`, target) -} diff --git a/pkg/semver/gitbranch.go b/pkg/semver/gitbranch.go deleted file mode 100644 index 9e1fe34..0000000 --- a/pkg/semver/gitbranch.go +++ /dev/null @@ -1,47 +0,0 @@ -package semver - -import ( - "fmt" - - "github.com/restechnica/semverbot/pkg/git" -) - -// GitBranch mode name for GitBranchMode. -const GitBranch = "git-branch" - -// GitBranchMode implementation of the Mode interface. -// It increments the semver level based on the naming of the source branch of a git merge. -type GitBranchMode struct { - GitAPI git.API - ModeDetector ModeDetector -} - -// NewGitBranchMode creates a new GitBranchMode. -// Returns the new GitBranchMode. -func NewGitBranchMode(detector ModeDetector) GitBranchMode { - return GitBranchMode{GitAPI: git.NewAPI(), ModeDetector: detector} -} - -// Increment increments the semver level based on the naming of the source branch of a git merge. -// Returns the incremented version or an error if the last git commit is not a merge or if no mode was detected -// based on the branch name. -func (mode GitBranchMode) Increment(targetVersion string) (nextVersion string, err error) { - var branchName string - var matchedMode Mode - - if branchName, err = mode.GitAPI.GetMergedBranchName(); err != nil { - return - } - - var isMergeCommit = branchName != "" - - if !isMergeCommit { - return nextVersion, fmt.Errorf("failed to increment version because the latest git commit is not a merge commit") - } - - if matchedMode, err = mode.ModeDetector.DetectMode(branchName); err != nil { - return nextVersion, err - } - - return matchedMode.Increment(targetVersion) -} diff --git a/pkg/semver/gitcommit.go b/pkg/semver/gitcommit.go deleted file mode 100644 index 4edc632..0000000 --- a/pkg/semver/gitcommit.go +++ /dev/null @@ -1,38 +0,0 @@ -package semver - -import ( - "github.com/restechnica/semverbot/pkg/git" -) - -// GitCommit mode name for GitCommitMode. -const GitCommit = "git-commit" - -// GitCommitMode implementation of the Mode interface. -// It increments the semver level based on the latest git commit messages. -type GitCommitMode struct { - GitAPI git.API - ModeDetector ModeDetector -} - -// NewGitCommitMode creates a new GitCommitMode. -// Returns the new GitCommitMode. -func NewGitCommitMode(detector ModeDetector) GitCommitMode { - return GitCommitMode{GitAPI: git.NewAPI(), ModeDetector: detector} -} - -// Increment increments a given version based on the latest git commit message. -// Returns the incremented version or an error if it failed to detect the mode based on the git commit. -func (mode GitCommitMode) Increment(targetVersion string) (nextVersion string, err error) { - var message string - var detectedMode Mode - - if message, err = mode.GitAPI.GetLatestCommitMessage(); err != nil { - return - } - - if detectedMode, err = mode.ModeDetector.DetectMode(message); err != nil { - return - } - - return detectedMode.Increment(targetVersion) -} diff --git a/pkg/versions/api.go b/pkg/versions/api.go index d7aa09f..b3c4190 100644 --- a/pkg/versions/api.go +++ b/pkg/versions/api.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/restechnica/semverbot/pkg/git" + "github.com/restechnica/semverbot/pkg/modes" "github.com/restechnica/semverbot/pkg/semver" ) @@ -44,8 +45,8 @@ func (api API) GetVersionOrDefault(defaultVersion string) (version string) { // The matching strings will be matched against git information to detect which semver level to increment. // Returns the next version or an error if the increment failed. func (api API) PredictVersion(version string, matchMap map[string][]string, mode string) (string, error) { - var modeDetector = semver.NewModeDetector(matchMap) - var semverModeAPI = semver.NewModeAPI(modeDetector) + var modeDetector = modes.NewModeDetector(matchMap) + var semverModeAPI = modes.NewAPI(modeDetector) var semverMode = semverModeAPI.SelectMode(mode) return semverMode.Increment(version) } From 730e69f1400085e9522d6b7516d2a7781cc05e73 Mon Sep 17 00:00:00 2001 From: shiouen Date: Sat, 20 Nov 2021 14:33:21 +0100 Subject: [PATCH 28/54] renamed a few concepts (semver map and mode) --- pkg/cli/commands/predict-version.go | 6 +++--- pkg/cli/commands/release-version.go | 9 ++++----- pkg/cli/commands/root.go | 5 +++-- pkg/cli/configs.go | 8 ++++---- pkg/core/predict.go | 7 ++++--- pkg/core/release.go | 6 +++--- pkg/modes/gitcommit_test.go | 10 +++++----- pkg/versions/api.go | 4 ++-- 8 files changed, 28 insertions(+), 27 deletions(-) diff --git a/pkg/cli/commands/predict-version.go b/pkg/cli/commands/predict-version.go index 022326f..5651658 100644 --- a/pkg/cli/commands/predict-version.go +++ b/pkg/cli/commands/predict-version.go @@ -27,7 +27,7 @@ func NewPredictVersionCommand() *cobra.Command { // PredictVersionCommandPreRunE runs before the command runs. // Returns an error if it fails. func PredictVersionCommandPreRunE(cmd *cobra.Command, args []string) (err error) { - return viper.BindPFlag(cli.SemverModeConfigKey, cmd.Flags().Lookup("mode")) + return viper.BindPFlag(cli.ModeConfigKey, cmd.Flags().Lookup("mode")) } // PredictVersionCommandRunE runs the command. @@ -35,8 +35,8 @@ func PredictVersionCommandPreRunE(cmd *cobra.Command, args []string) (err error) func PredictVersionCommandRunE(cmd *cobra.Command, args []string) (err error) { var options = &core.PredictVersionOptions{ DefaultVersion: cli.DefaultVersion, - SemverMatchMap: viper.GetStringMapStringSlice(cli.SemverMatchConfigKey), - SemverMode: viper.GetString(cli.SemverModeConfigKey), + Mode: viper.GetString(cli.ModeConfigKey), + SemverMap: viper.GetStringMapStringSlice(cli.SemverMapConfigKey), } var version string diff --git a/pkg/cli/commands/release-version.go b/pkg/cli/commands/release-version.go index fce2652..f591189 100644 --- a/pkg/cli/commands/release-version.go +++ b/pkg/cli/commands/release-version.go @@ -1,12 +1,11 @@ package commands import ( - "github.com/restechnica/semverbot/pkg/core" - "github.com/spf13/cobra" "github.com/spf13/viper" "github.com/restechnica/semverbot/pkg/cli" + "github.com/restechnica/semverbot/pkg/core" ) // NewReleaseVersionCommand creates a new release version command. @@ -26,7 +25,7 @@ func NewReleaseVersionCommand() *cobra.Command { // ReleaseVersionCommandPreRunE runs before the command runs. // Returns an error if it fails. func ReleaseVersionCommandPreRunE(cmd *cobra.Command, args []string) (err error) { - return viper.BindPFlag(cli.SemverModeConfigKey, cmd.Flags().Lookup("mode")) + return viper.BindPFlag(cli.ModeConfigKey, cmd.Flags().Lookup("mode")) } // ReleaseVersionCommandRunE runs the command. @@ -35,8 +34,8 @@ func ReleaseVersionCommandRunE(cmd *cobra.Command, args []string) error { var options = &core.ReleaseVersionOptions{ DefaultVersion: cli.DefaultVersion, GitTagsPrefix: viper.GetString(cli.GitTagsPrefixConfigKey), - SemverMatchMap: viper.GetStringMapStringSlice(cli.SemverMatchConfigKey), - SemverMode: viper.GetString(cli.SemverModeConfigKey), + Mode: viper.GetString(cli.ModeConfigKey), + SemverMap: viper.GetStringMapStringSlice(cli.SemverMapConfigKey), } return core.ReleaseVersion(options) diff --git a/pkg/cli/commands/root.go b/pkg/cli/commands/root.go index bd249ea..9a68f2e 100644 --- a/pkg/cli/commands/root.go +++ b/pkg/cli/commands/root.go @@ -9,6 +9,7 @@ import ( "github.com/restechnica/semverbot/pkg/cli" "github.com/restechnica/semverbot/pkg/git" + "github.com/restechnica/semverbot/pkg/modes" ) // NewRootCommand creates a new root command. @@ -75,8 +76,8 @@ func LoadConfig() (err error) { // LoadDefaultConfig loads the default semverbot config. func LoadDefaultConfig() { viper.SetDefault(cli.GitTagsPrefixConfigKey, "v") - viper.SetDefault(cli.SemverMatchConfigKey, map[string][]string{}) - viper.SetDefault(cli.SemverModeConfigKey, "auto") + viper.SetDefault(cli.SemverMapConfigKey, modes.SemverMap{}) + viper.SetDefault(cli.ModeConfigKey, "auto") } // LoadFlags loads root command flags. diff --git a/pkg/cli/configs.go b/pkg/cli/configs.go index 04446ac..9e85df8 100644 --- a/pkg/cli/configs.go +++ b/pkg/cli/configs.go @@ -10,9 +10,9 @@ const ( // GitTagsPrefixConfigKey key for the git tags prefix config in the semverbot config file. GitTagsPrefixConfigKey = "git.tags.prefix" - // SemverMatchConfigKey key for the semver match config in the semverbot config file. - SemverMatchConfigKey = "semver.match" + // ModeConfigKey key for the mode config in the semverbot config file. + ModeConfigKey = "mode" - // SemverModeConfigKey key for the semver mode config in the semverbot config file. - SemverModeConfigKey = "semver.mode" + // SemverMapConfigKey key for the semver map config in the semverbot config file. + SemverMapConfigKey = "semver" ) diff --git a/pkg/core/predict.go b/pkg/core/predict.go index 5569e82..ef79934 100644 --- a/pkg/core/predict.go +++ b/pkg/core/predict.go @@ -1,13 +1,14 @@ package core import ( + "github.com/restechnica/semverbot/pkg/modes" "github.com/restechnica/semverbot/pkg/versions" ) type PredictVersionOptions struct { DefaultVersion string - SemverMatchMap map[string][]string - SemverMode string + Mode string + SemverMap modes.SemverMap } // PredictVersion predicts the next version. @@ -15,5 +16,5 @@ type PredictVersionOptions struct { func PredictVersion(options *PredictVersionOptions) (prediction string, err error) { var versionAPI = versions.NewAPI() var version = versionAPI.GetVersionOrDefault(options.DefaultVersion) - return versionAPI.PredictVersion(version, options.SemverMatchMap, options.SemverMode) + return versionAPI.PredictVersion(version, options.SemverMap, options.Mode) } diff --git a/pkg/core/release.go b/pkg/core/release.go index 7a33b3c..0a5c096 100644 --- a/pkg/core/release.go +++ b/pkg/core/release.go @@ -7,8 +7,8 @@ import ( type ReleaseVersionOptions struct { DefaultVersion string GitTagsPrefix string - SemverMatchMap map[string][]string - SemverMode string + Mode string + SemverMap map[string][]string } // ReleaseVersion releases a new version. @@ -17,7 +17,7 @@ func ReleaseVersion(options *ReleaseVersionOptions) error { var versionAPI = versions.NewAPI() var currentVersion = versionAPI.GetVersionOrDefault(options.DefaultVersion) - var predictedVersion, err = versionAPI.PredictVersion(currentVersion, options.SemverMatchMap, options.SemverMode) + var predictedVersion, err = versionAPI.PredictVersion(currentVersion, options.SemverMap, options.Mode) if err != nil { return err diff --git a/pkg/modes/gitcommit_test.go b/pkg/modes/gitcommit_test.go index 48e038b..9ed8f60 100644 --- a/pkg/modes/gitcommit_test.go +++ b/pkg/modes/gitcommit_test.go @@ -11,7 +11,7 @@ import ( "github.com/restechnica/semverbot/pkg/git" ) -var semverMatchMap = map[string][]string{ +var semverMap = SemverMap{ Patch: {"[fix]", "fix/"}, Minor: {"[feature]", "feature/"}, Major: {"[release]", "release/"}, @@ -47,7 +47,7 @@ func TestGitCommitMode_GitCommitConstant(t *testing.T) { // t.Run(test.Name, func(t *testing.T) { // var want = test.Want // -// var gitCommitMode = NewGitCommitMode(NewModeDetector(semverMatchMap)) +// var gitCommitMode = NewGitCommitMode(NewModeDetector(semverMap)) // var got, err = gitCommitMode.ModeDetector.(test.Message) // // assert.NoError(t, err) @@ -68,7 +68,7 @@ func TestGitCommitMode_GitCommitConstant(t *testing.T) { // t.Run(test.Name, func(t *testing.T) { // var want = fmt.Sprintf(`could not match a mode to the commit message "%s"`, test.Message) // -// var gitCommitMode = NewGitCommitMode(semverMatchMap) +// var gitCommitMode = NewGitCommitMode(semverMap) // var _, err = gitCommitMode.GetMatchedMode(test.Message) // // assert.Error(t, err) @@ -101,7 +101,7 @@ func TestGitCommitMode_Increment(t *testing.T) { var cmder = mocks.NewMockCommander() cmder.On("Output", mock.Anything, mock.Anything).Return(test.Message, nil) - var gitCommitMode = NewGitCommitMode(NewModeDetector(semverMatchMap)) + var gitCommitMode = NewGitCommitMode(NewModeDetector(semverMap)) gitCommitMode.GitAPI = git.API{Commander: cmder} var got, err = gitCommitMode.Increment(test.Version) @@ -130,7 +130,7 @@ func TestGitCommitMode_Increment(t *testing.T) { var cmder = mocks.NewMockCommander() cmder.On("Output", mock.Anything, mock.Anything).Return(test.Message, test.GitError) - var gitCommitMode = NewGitCommitMode(NewModeDetector(semverMatchMap)) + var gitCommitMode = NewGitCommitMode(NewModeDetector(semverMap)) gitCommitMode.GitAPI = git.API{Commander: cmder} var _, err = gitCommitMode.Increment(test.Version) diff --git a/pkg/versions/api.go b/pkg/versions/api.go index b3c4190..a347a6d 100644 --- a/pkg/versions/api.go +++ b/pkg/versions/api.go @@ -44,8 +44,8 @@ func (api API) GetVersionOrDefault(defaultVersion string) (version string) { // PredictVersion increments a version based on a semver mode and a map of semver levels with matching strings. // The matching strings will be matched against git information to detect which semver level to increment. // Returns the next version or an error if the increment failed. -func (api API) PredictVersion(version string, matchMap map[string][]string, mode string) (string, error) { - var modeDetector = modes.NewModeDetector(matchMap) +func (api API) PredictVersion(version string, semverMap modes.SemverMap, mode string) (string, error) { + var modeDetector = modes.NewModeDetector(semverMap) var semverModeAPI = modes.NewAPI(modeDetector) var semverMode = semverModeAPI.SelectMode(mode) return semverMode.Increment(version) From 24638c742f1cc76823b02cadcd38ac0e195eb8b5 Mon Sep 17 00:00:00 2001 From: shiouen Date: Sat, 20 Nov 2021 14:41:12 +0100 Subject: [PATCH 29/54] added delimiter config defaults - added delimiters config keys --- internal/constants.go | 25 +++++++++++++++++++------ pkg/cli/configs.go | 16 +++++++++++----- pkg/cli/defaults.go | 6 ++++++ 3 files changed, 36 insertions(+), 11 deletions(-) diff --git a/internal/constants.go b/internal/constants.go index ece3640..92863c7 100644 --- a/internal/constants.go +++ b/internal/constants.go @@ -2,7 +2,9 @@ package internal const ( // DefaultConfig the default config. - DefaultConfig = `[git] + DefaultConfig = `mode = "auto" + +[git] [git.config] email = "semverbot@github.com" @@ -12,18 +14,29 @@ name = "semverbot" prefix = "v" [semver] -mode = "auto" +patch = ["fix", "bug"] +minor = ["feature"] +major = ["release"] + +[modes] + +[modes.git-branch] +delimiters = "/" -[semver.match] -patch = ["fix/", "[fix]"] -minor = ["feature/", "[feature]"] -major = ["release/", "[release]"] +[modes.git-commit] +delimiters = "[]" ` // DefaultConfigFilePath the default relative filepath to the config file. DefaultConfigFilePath = ".semverbot.toml" + // DefaultGitBranchDelimiters the default delimiters used by the git-branch mode. + DefaultGitBranchDelimiters = "/" + + // DefaultGitCommitDelimiters the default delimiters used by the git-commit mode. + DefaultGitCommitDelimiters = "[]" + // DefaultVersion the default version when no other version can be found. DefaultVersion = "0.0.0" ) diff --git a/pkg/cli/configs.go b/pkg/cli/configs.go index 9e85df8..46cd17b 100644 --- a/pkg/cli/configs.go +++ b/pkg/cli/configs.go @@ -1,18 +1,24 @@ package cli const ( - // GitConfigEmailConfigKey key for the git email config in the semverbot config file. + // GitConfigEmailConfigKey key for the git email config. GitConfigEmailConfigKey = "git.config.email" - // GitConfigNameConfigKey key for the git name config in the semverbot config file. + // GitConfigNameConfigKey key for the git name config. GitConfigNameConfigKey = "git.config.name" - // GitTagsPrefixConfigKey key for the git tags prefix config in the semverbot config file. + // GitTagsPrefixConfigKey key for the git tags prefix config. GitTagsPrefixConfigKey = "git.tags.prefix" - // ModeConfigKey key for the mode config in the semverbot config file. + // ModeConfigKey key for the mode config. ModeConfigKey = "mode" - // SemverMapConfigKey key for the semver map config in the semverbot config file. + // ModesGitBranchDelimitersConfigKey key for the git-branch delimiters config. + ModesGitBranchDelimitersConfigKey = "modes.git-branch.delimiters" + + // ModesGitCommitDelimitersConfigKey key for the git-commit delimiters config. + ModesGitCommitDelimitersConfigKey = "modes.git-commit.delimiters" + + // SemverMapConfigKey key for the semver map config. SemverMapConfigKey = "semver" ) diff --git a/pkg/cli/defaults.go b/pkg/cli/defaults.go index 527155b..8f263c2 100644 --- a/pkg/cli/defaults.go +++ b/pkg/cli/defaults.go @@ -9,6 +9,12 @@ var ( // DefaultConfigFilePath the default relative filepath to the config file. DefaultConfigFilePath = internal.DefaultConfigFilePath + // DefaultGitBranchDelimiters the default delimiters used by the git-branch mode. + DefaultGitBranchDelimiters = internal.DefaultGitBranchDelimiters + + // DefaultGitCommitDelimiters the default delimiters used by the git-commit mode. + DefaultGitCommitDelimiters = internal.DefaultGitCommitDelimiters + // DefaultVersion the default version when no other version can be found. DefaultVersion = internal.DefaultVersion ) From 62cbcf492b485a6eba41ea48f40c6afb205aede8 Mon Sep 17 00:00:00 2001 From: shiouen Date: Sat, 20 Nov 2021 15:27:35 +0100 Subject: [PATCH 30/54] fixed a bug in versions API preventing a release from prefixing versions before pushing them as a git tag - added git mode delimiters as parameters for the modes API - added modes API as parameter of the version API - core release logic now reuses core predict logic - added defaults for git tags prefix and mode configs - added viper defaults for git mode delimiter configs --- .semverbot.toml | 17 ++++++++++++----- internal/constants.go | 8 ++++++++ pkg/cli/commands/predict-version.go | 8 +++++--- pkg/cli/commands/release-version.go | 17 +++++++++++------ pkg/cli/commands/root.go | 6 ++++-- pkg/cli/defaults.go | 6 ++++++ pkg/core/get.go | 3 ++- pkg/core/predict.go | 11 +++++++---- pkg/core/push.go | 3 ++- pkg/core/release.go | 21 +++++++++++---------- pkg/modes/api.go | 6 +++--- pkg/modes/gitcommit_test.go | 16 ++++++++-------- pkg/versions/api.go | 21 ++++++++++++--------- 13 files changed, 91 insertions(+), 52 deletions(-) diff --git a/.semverbot.toml b/.semverbot.toml index 4311d9c..766ac21 100644 --- a/.semverbot.toml +++ b/.semverbot.toml @@ -1,3 +1,5 @@ +mode = "auto" + [git] [git.config] @@ -8,9 +10,14 @@ name = "semverbot" prefix = "v" [semver] -mode = "auto" +patch = ["fix", "bug"] +minor = ["feature"] +major = ["release"] + +[modes] + +[modes.git-branch] +delimiters = "/" -[semver.match] -patch = ["fix/", "[fix]"] -minor = ["feature/", "[feature]"] -major = ["release/", "[release]"] +[modes.git-commit] +delimiters = "[]" \ No newline at end of file diff --git a/internal/constants.go b/internal/constants.go index 92863c7..6e6b363 100644 --- a/internal/constants.go +++ b/internal/constants.go @@ -1,5 +1,7 @@ package internal +import "github.com/restechnica/semverbot/pkg/modes" + const ( // DefaultConfig the default config. DefaultConfig = `mode = "auto" @@ -37,6 +39,12 @@ delimiters = "[]" // DefaultGitCommitDelimiters the default delimiters used by the git-commit mode. DefaultGitCommitDelimiters = "[]" + // DefaultGitTagsPrefix the default prefix prepended to git tags. + DefaultGitTagsPrefix = "v" + + // DefaultMode the default mode for incrementing versions. + DefaultMode = modes.Auto + // DefaultVersion the default version when no other version can be found. DefaultVersion = "0.0.0" ) diff --git a/pkg/cli/commands/predict-version.go b/pkg/cli/commands/predict-version.go index 5651658..4071dd5 100644 --- a/pkg/cli/commands/predict-version.go +++ b/pkg/cli/commands/predict-version.go @@ -34,9 +34,11 @@ func PredictVersionCommandPreRunE(cmd *cobra.Command, args []string) (err error) // Returns an error if the command fails. func PredictVersionCommandRunE(cmd *cobra.Command, args []string) (err error) { var options = &core.PredictVersionOptions{ - DefaultVersion: cli.DefaultVersion, - Mode: viper.GetString(cli.ModeConfigKey), - SemverMap: viper.GetStringMapStringSlice(cli.SemverMapConfigKey), + DefaultVersion: cli.DefaultVersion, + GitBranchDelimiters: viper.GetString(cli.ModesGitBranchDelimitersConfigKey), + GitCommitDelimiters: viper.GetString(cli.ModesGitCommitDelimitersConfigKey), + Mode: viper.GetString(cli.ModeConfigKey), + SemverMap: viper.GetStringMapStringSlice(cli.SemverMapConfigKey), } var version string diff --git a/pkg/cli/commands/release-version.go b/pkg/cli/commands/release-version.go index f591189..08f0ba6 100644 --- a/pkg/cli/commands/release-version.go +++ b/pkg/cli/commands/release-version.go @@ -31,12 +31,17 @@ func ReleaseVersionCommandPreRunE(cmd *cobra.Command, args []string) (err error) // ReleaseVersionCommandRunE runs the command. // Returns an error if the command fails. func ReleaseVersionCommandRunE(cmd *cobra.Command, args []string) error { - var options = &core.ReleaseVersionOptions{ - DefaultVersion: cli.DefaultVersion, - GitTagsPrefix: viper.GetString(cli.GitTagsPrefixConfigKey), - Mode: viper.GetString(cli.ModeConfigKey), - SemverMap: viper.GetStringMapStringSlice(cli.SemverMapConfigKey), + var predictOptions = &core.PredictVersionOptions{ + DefaultVersion: cli.DefaultVersion, + GitBranchDelimiters: viper.GetString(cli.ModesGitBranchDelimitersConfigKey), + GitCommitDelimiters: viper.GetString(cli.ModesGitCommitDelimitersConfigKey), + Mode: viper.GetString(cli.ModeConfigKey), + SemverMap: viper.GetStringMapStringSlice(cli.SemverMapConfigKey), } - return core.ReleaseVersion(options) + var releaseOptions = &core.ReleaseVersionOptions{ + GitTagsPrefix: viper.GetString(cli.GitTagsPrefixConfigKey), + } + + return core.ReleaseVersion(predictOptions, releaseOptions) } diff --git a/pkg/cli/commands/root.go b/pkg/cli/commands/root.go index 9a68f2e..6b0611d 100644 --- a/pkg/cli/commands/root.go +++ b/pkg/cli/commands/root.go @@ -75,9 +75,11 @@ func LoadConfig() (err error) { // LoadDefaultConfig loads the default semverbot config. func LoadDefaultConfig() { - viper.SetDefault(cli.GitTagsPrefixConfigKey, "v") + viper.SetDefault(cli.GitTagsPrefixConfigKey, cli.DefaultGitTagsPrefix) + viper.SetDefault(cli.ModeConfigKey, cli.DefaultMode) + viper.SetDefault(cli.ModesGitBranchDelimitersConfigKey, cli.DefaultGitBranchDelimiters) + viper.SetDefault(cli.ModesGitCommitDelimitersConfigKey, cli.DefaultGitCommitDelimiters) viper.SetDefault(cli.SemverMapConfigKey, modes.SemverMap{}) - viper.SetDefault(cli.ModeConfigKey, "auto") } // LoadFlags loads root command flags. diff --git a/pkg/cli/defaults.go b/pkg/cli/defaults.go index 8f263c2..bd396bc 100644 --- a/pkg/cli/defaults.go +++ b/pkg/cli/defaults.go @@ -15,6 +15,12 @@ var ( // DefaultGitCommitDelimiters the default delimiters used by the git-commit mode. DefaultGitCommitDelimiters = internal.DefaultGitCommitDelimiters + // DefaultGitTagsPrefix the default prefix prepended to git tags. + DefaultGitTagsPrefix = internal.DefaultGitTagsPrefix + + // DefaultMode the default mode for incrementing versions. + DefaultMode = internal.DefaultMode + // DefaultVersion the default version when no other version can be found. DefaultVersion = internal.DefaultVersion ) diff --git a/pkg/core/get.go b/pkg/core/get.go index 832a6fb..be10967 100644 --- a/pkg/core/get.go +++ b/pkg/core/get.go @@ -1,6 +1,7 @@ package core import ( + "github.com/restechnica/semverbot/pkg/modes" "github.com/restechnica/semverbot/pkg/versions" ) @@ -11,6 +12,6 @@ type GetVersionOptions struct { // GetVersion gets the current version. // Returns the current version. func GetVersion(options *GetVersionOptions) string { - var versionAPI = versions.NewAPI() + var versionAPI = versions.NewAPI(modes.API{}) return versionAPI.GetVersionOrDefault(options.DefaultVersion) } diff --git a/pkg/core/predict.go b/pkg/core/predict.go index ef79934..48e01d5 100644 --- a/pkg/core/predict.go +++ b/pkg/core/predict.go @@ -6,15 +6,18 @@ import ( ) type PredictVersionOptions struct { - DefaultVersion string - Mode string - SemverMap modes.SemverMap + DefaultVersion string + GitBranchDelimiters string + GitCommitDelimiters string + Mode string + SemverMap modes.SemverMap } // PredictVersion predicts the next version. // Returns the predicted version or an error if anything went wrong with the prediction. func PredictVersion(options *PredictVersionOptions) (prediction string, err error) { - var versionAPI = versions.NewAPI() + var modeAPI = modes.NewAPI(options.SemverMap, options.GitBranchDelimiters, options.GitCommitDelimiters) + var versionAPI = versions.NewAPI(modeAPI) var version = versionAPI.GetVersionOrDefault(options.DefaultVersion) return versionAPI.PredictVersion(version, options.SemverMap, options.Mode) } diff --git a/pkg/core/push.go b/pkg/core/push.go index 1d29955..de31b4a 100644 --- a/pkg/core/push.go +++ b/pkg/core/push.go @@ -1,6 +1,7 @@ package core import ( + "github.com/restechnica/semverbot/pkg/modes" "github.com/restechnica/semverbot/pkg/versions" ) @@ -12,7 +13,7 @@ type PushVersionOptions struct { // PushVersion pushes the current version. // Returns an error if the push went wrong. func PushVersion(options *PushVersionOptions) (err error) { - var versionAPI = versions.NewAPI() + var versionAPI = versions.NewAPI(modes.API{}) var version = versionAPI.GetVersionOrDefault(options.DefaultVersion) return versionAPI.PushVersion(version, options.GitTagsPrefix) } diff --git a/pkg/core/release.go b/pkg/core/release.go index 0a5c096..2627b55 100644 --- a/pkg/core/release.go +++ b/pkg/core/release.go @@ -1,27 +1,28 @@ package core import ( + "github.com/restechnica/semverbot/pkg/modes" "github.com/restechnica/semverbot/pkg/versions" ) type ReleaseVersionOptions struct { - DefaultVersion string - GitTagsPrefix string - Mode string - SemverMap map[string][]string + DefaultVersion string + GitTagsPrefix string + GitBranchDelimiters string + GitCommitDelimiters string + Mode string + SemverMap modes.SemverMap } // ReleaseVersion releases a new version. // Returns an error if anything went wrong with the prediction or releasing. -func ReleaseVersion(options *ReleaseVersionOptions) error { - var versionAPI = versions.NewAPI() - - var currentVersion = versionAPI.GetVersionOrDefault(options.DefaultVersion) - var predictedVersion, err = versionAPI.PredictVersion(currentVersion, options.SemverMap, options.Mode) +func ReleaseVersion(predictOptions *PredictVersionOptions, releaseOptions *ReleaseVersionOptions) error { + var versionAPI = versions.NewAPI(modes.API{}) + var predictedVersion, err = PredictVersion(predictOptions) if err != nil { return err } - return versionAPI.ReleaseVersion(predictedVersion) + return versionAPI.ReleaseVersion(predictedVersion, releaseOptions.GitTagsPrefix) } diff --git a/pkg/modes/api.go b/pkg/modes/api.go index 89f1857..66b80d2 100644 --- a/pkg/modes/api.go +++ b/pkg/modes/api.go @@ -11,10 +11,10 @@ type API struct { // NewAPI creates a new semver mode API with a mode detector to pass // it on to the different modes that require it. // Returns the new API. -func NewAPI(semverMap SemverMap) API { +func NewAPI(semverMap SemverMap, gitBranchDelimiters string, GitCommitDelimiters string) API { return API{ - GitBranchMode: NewGitBranchMode(semverMap), - GitCommitMode: NewGitCommitMode(semverMap), + GitBranchMode: NewGitBranchMode(gitBranchDelimiters, semverMap), + GitCommitMode: NewGitCommitMode(GitCommitDelimiters, semverMap), } } diff --git a/pkg/modes/gitcommit_test.go b/pkg/modes/gitcommit_test.go index 9ed8f60..19c81a5 100644 --- a/pkg/modes/gitcommit_test.go +++ b/pkg/modes/gitcommit_test.go @@ -12,9 +12,9 @@ import ( ) var semverMap = SemverMap{ - Patch: {"[fix]", "fix/"}, - Minor: {"[feature]", "feature/"}, - Major: {"[release]", "release/"}, + Patch: {"fix"}, + Minor: {"feature"}, + Major: {"release"}, } func TestGitCommitMode_GitCommitConstant(t *testing.T) { @@ -87,11 +87,11 @@ func TestGitCommitMode_Increment(t *testing.T) { var tests = []Test{ {Name: "IncrementPatchWithBrackets", Message: "[fix] some message", Version: "0.0.0", Want: "0.0.1"}, - {Name: "IncrementPatchWithTrailingSlash", Message: "Merged: repo/fix/some-error", Version: "0.0.1", Want: "0.0.2"}, + //{Name: "IncrementPatchWithTrailingSlash", Message: "Merged: repo/fix/some-error", Version: "0.0.1", Want: "0.0.2"}, {Name: "IncrementMinorWithBrackets", Message: "some [feature] message", Version: "0.0.0", Want: "0.1.0"}, - {Name: "IncrementMinorWithTrailingSlash", Message: "Merged: repo/feature/some-error", Version: "0.1.0", Want: "0.2.0"}, + //{Name: "IncrementMinorWithTrailingSlash", Message: "Merged: repo/feature/some-error", Version: "0.1.0", Want: "0.2.0"}, {Name: "IncrementMajorWithBrackets", Message: "some message [release]", Version: "0.0.0", Want: "1.0.0"}, - {Name: "IncrementMajorWithTrailingSlash", Message: "Merged: repo/release/some-error", Version: "1.0.0", Want: "2.0.0"}, + //{Name: "IncrementMajorWithTrailingSlash", Message: "Merged: repo/release/some-error", Version: "1.0.0", Want: "2.0.0"}, } for _, test := range tests { @@ -101,7 +101,7 @@ func TestGitCommitMode_Increment(t *testing.T) { var cmder = mocks.NewMockCommander() cmder.On("Output", mock.Anything, mock.Anything).Return(test.Message, nil) - var gitCommitMode = NewGitCommitMode(NewModeDetector(semverMap)) + var gitCommitMode = NewGitCommitMode("[]", semverMap) gitCommitMode.GitAPI = git.API{Commander: cmder} var got, err = gitCommitMode.Increment(test.Version) @@ -130,7 +130,7 @@ func TestGitCommitMode_Increment(t *testing.T) { var cmder = mocks.NewMockCommander() cmder.On("Output", mock.Anything, mock.Anything).Return(test.Message, test.GitError) - var gitCommitMode = NewGitCommitMode(NewModeDetector(semverMap)) + var gitCommitMode = NewGitCommitMode("[]", semverMap) gitCommitMode.GitAPI = git.API{Commander: cmder} var _, err = gitCommitMode.Increment(test.Version) diff --git a/pkg/versions/api.go b/pkg/versions/api.go index a347a6d..01e1f01 100644 --- a/pkg/versions/api.go +++ b/pkg/versions/api.go @@ -10,13 +10,17 @@ import ( // API an API to work with versions. type API struct { - GitAPI git.API + GitAPI git.API + ModeAPI modes.API } // NewAPI creates a new version API. // Returns the new API. -func NewAPI() API { - return API{git.NewAPI()} +func NewAPI(modeAPI modes.API) API { + return API{ + GitAPI: git.NewAPI(), + ModeAPI: modeAPI, + } } // GetVersion gets the current version by getting the latest annotated git tag. @@ -45,16 +49,15 @@ func (api API) GetVersionOrDefault(defaultVersion string) (version string) { // The matching strings will be matched against git information to detect which semver level to increment. // Returns the next version or an error if the increment failed. func (api API) PredictVersion(version string, semverMap modes.SemverMap, mode string) (string, error) { - var modeDetector = modes.NewModeDetector(semverMap) - var semverModeAPI = modes.NewAPI(modeDetector) - var semverMode = semverModeAPI.SelectMode(mode) + var semverMode = api.ModeAPI.SelectMode(mode) return semverMode.Increment(version) } -// ReleaseVersion releases a version by creating an annotated git tag. +// ReleaseVersion releases a version by creating an annotated git tag with a prefix. // Returns an error if the tag creation failed. -func (api API) ReleaseVersion(version string) (err error) { - return api.GitAPI.CreateAnnotatedTag(version) +func (api API) ReleaseVersion(version string, prefix string) (err error) { + var prefixedVersion = AddPrefix(version, prefix) + return api.GitAPI.CreateAnnotatedTag(prefixedVersion) } // PushVersion pushes a version by pushing a git tag with a prefix. From 8013a763efe6de1ee3a7e55ddaa1ef8db77b0202 Mon Sep 17 00:00:00 2001 From: shiouen Date: Sat, 20 Nov 2021 15:54:55 +0100 Subject: [PATCH 31/54] untangled modes api and version api - fixed git branch mode error message --- .semverbot.toml | 2 +- pkg/core/get.go | 3 +-- pkg/core/predict.go | 12 ++++++++---- pkg/core/push.go | 3 +-- pkg/core/release.go | 2 +- pkg/modes/gitbranch.go | 2 +- pkg/versions/api.go | 18 ++++++------------ 7 files changed, 19 insertions(+), 23 deletions(-) diff --git a/.semverbot.toml b/.semverbot.toml index 766ac21..73428ab 100644 --- a/.semverbot.toml +++ b/.semverbot.toml @@ -20,4 +20,4 @@ major = ["release"] delimiters = "/" [modes.git-commit] -delimiters = "[]" \ No newline at end of file +delimiters = "[]" diff --git a/pkg/core/get.go b/pkg/core/get.go index be10967..832a6fb 100644 --- a/pkg/core/get.go +++ b/pkg/core/get.go @@ -1,7 +1,6 @@ package core import ( - "github.com/restechnica/semverbot/pkg/modes" "github.com/restechnica/semverbot/pkg/versions" ) @@ -12,6 +11,6 @@ type GetVersionOptions struct { // GetVersion gets the current version. // Returns the current version. func GetVersion(options *GetVersionOptions) string { - var versionAPI = versions.NewAPI(modes.API{}) + var versionAPI = versions.NewAPI() return versionAPI.GetVersionOrDefault(options.DefaultVersion) } diff --git a/pkg/core/predict.go b/pkg/core/predict.go index 48e01d5..b6d113e 100644 --- a/pkg/core/predict.go +++ b/pkg/core/predict.go @@ -13,11 +13,15 @@ type PredictVersionOptions struct { SemverMap modes.SemverMap } -// PredictVersion predicts the next version. -// Returns the predicted version or an error if anything went wrong with the prediction. +// PredictVersion predicts a version based on a modes.Mode and a modes.SemverMap. +// The modes.SemverMap values will be matched against git information to detect which semver level to increment. +// Returns the next version or an error if the prediction failed. func PredictVersion(options *PredictVersionOptions) (prediction string, err error) { var modeAPI = modes.NewAPI(options.SemverMap, options.GitBranchDelimiters, options.GitCommitDelimiters) - var versionAPI = versions.NewAPI(modeAPI) + var mode = modeAPI.SelectMode(options.Mode) + + var versionAPI = versions.NewAPI() var version = versionAPI.GetVersionOrDefault(options.DefaultVersion) - return versionAPI.PredictVersion(version, options.SemverMap, options.Mode) + + return versionAPI.PredictVersion(version, mode) } diff --git a/pkg/core/push.go b/pkg/core/push.go index de31b4a..1d29955 100644 --- a/pkg/core/push.go +++ b/pkg/core/push.go @@ -1,7 +1,6 @@ package core import ( - "github.com/restechnica/semverbot/pkg/modes" "github.com/restechnica/semverbot/pkg/versions" ) @@ -13,7 +12,7 @@ type PushVersionOptions struct { // PushVersion pushes the current version. // Returns an error if the push went wrong. func PushVersion(options *PushVersionOptions) (err error) { - var versionAPI = versions.NewAPI(modes.API{}) + var versionAPI = versions.NewAPI() var version = versionAPI.GetVersionOrDefault(options.DefaultVersion) return versionAPI.PushVersion(version, options.GitTagsPrefix) } diff --git a/pkg/core/release.go b/pkg/core/release.go index 2627b55..b5a4f75 100644 --- a/pkg/core/release.go +++ b/pkg/core/release.go @@ -17,7 +17,7 @@ type ReleaseVersionOptions struct { // ReleaseVersion releases a new version. // Returns an error if anything went wrong with the prediction or releasing. func ReleaseVersion(predictOptions *PredictVersionOptions, releaseOptions *ReleaseVersionOptions) error { - var versionAPI = versions.NewAPI(modes.API{}) + var versionAPI = versions.NewAPI() var predictedVersion, err = PredictVersion(predictOptions) if err != nil { diff --git a/pkg/modes/gitbranch.go b/pkg/modes/gitbranch.go index 5857e5d..6cde412 100644 --- a/pkg/modes/gitbranch.go +++ b/pkg/modes/gitbranch.go @@ -68,7 +68,7 @@ func (mode GitBranchMode) DetectMode(branchName string) (detected Mode, err erro } } - return detected, fmt.Errorf(`failed to detect mode from git commit message "%s" with delimiters "%s"`, + return detected, fmt.Errorf(`failed to detect mode from git branch name "%s" with delimiters "%s"`, branchName, mode.Delimiters) } diff --git a/pkg/versions/api.go b/pkg/versions/api.go index 01e1f01..235a325 100644 --- a/pkg/versions/api.go +++ b/pkg/versions/api.go @@ -10,17 +10,13 @@ import ( // API an API to work with versions. type API struct { - GitAPI git.API - ModeAPI modes.API + GitAPI git.API } // NewAPI creates a new version API. // Returns the new API. -func NewAPI(modeAPI modes.API) API { - return API{ - GitAPI: git.NewAPI(), - ModeAPI: modeAPI, - } +func NewAPI() API { + return API{GitAPI: git.NewAPI()} } // GetVersion gets the current version by getting the latest annotated git tag. @@ -45,12 +41,10 @@ func (api API) GetVersionOrDefault(defaultVersion string) (version string) { return version } -// PredictVersion increments a version based on a semver mode and a map of semver levels with matching strings. -// The matching strings will be matched against git information to detect which semver level to increment. +// PredictVersion increments a version based on a modes.Mode. // Returns the next version or an error if the increment failed. -func (api API) PredictVersion(version string, semverMap modes.SemverMap, mode string) (string, error) { - var semverMode = api.ModeAPI.SelectMode(mode) - return semverMode.Increment(version) +func (api API) PredictVersion(version string, mode modes.Mode) (string, error) { + return mode.Increment(version) } // ReleaseVersion releases a version by creating an annotated git tag with a prefix. From 26ecfab8d41981e938becd6ba21b35fed4edaeca Mon Sep 17 00:00:00 2001 From: shiouen Date: Sat, 20 Nov 2021 16:01:35 +0100 Subject: [PATCH 32/54] simplified .semverbot.toml --- .semverbot.toml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.semverbot.toml b/.semverbot.toml index 73428ab..33bdb51 100644 --- a/.semverbot.toml +++ b/.semverbot.toml @@ -13,11 +13,3 @@ prefix = "v" patch = ["fix", "bug"] minor = ["feature"] major = ["release"] - -[modes] - -[modes.git-branch] -delimiters = "/" - -[modes.git-commit] -delimiters = "[]" From f94c962bccc441788bb837af338fcf84e19933c9 Mon Sep 17 00:00:00 2001 From: shiouen Date: Sat, 20 Nov 2021 16:41:39 +0100 Subject: [PATCH 33/54] implemented dynamic default config --- internal/constants.go | 27 ------------------------ pkg/cli/commands/init.go | 2 +- pkg/cli/defaults.go | 45 ++++++++++++++++++++++++++++++++++++---- 3 files changed, 42 insertions(+), 32 deletions(-) diff --git a/internal/constants.go b/internal/constants.go index 6e6b363..6024cc9 100644 --- a/internal/constants.go +++ b/internal/constants.go @@ -3,33 +3,6 @@ package internal import "github.com/restechnica/semverbot/pkg/modes" const ( - // DefaultConfig the default config. - DefaultConfig = `mode = "auto" - -[git] - -[git.config] -email = "semverbot@github.com" -name = "semverbot" - -[git.tags] -prefix = "v" - -[semver] -patch = ["fix", "bug"] -minor = ["feature"] -major = ["release"] - -[modes] - -[modes.git-branch] -delimiters = "/" - -[modes.git-commit] -delimiters = "[]" - -` - // DefaultConfigFilePath the default relative filepath to the config file. DefaultConfigFilePath = ".semverbot.toml" diff --git a/pkg/cli/commands/init.go b/pkg/cli/commands/init.go index ce32c8c..665b3bb 100644 --- a/pkg/cli/commands/init.go +++ b/pkg/cli/commands/init.go @@ -24,7 +24,7 @@ func NewInitCommand() *cobra.Command { // Returns an error if the command failed. func InitCommandRunE(cmd *cobra.Command, args []string) (err error) { var options = &core.InitOptions{ - Config: cli.DefaultConfig, + Config: cli.GetDefaultConfig(), ConfigFilePath: cli.DefaultConfigFilePath, } diff --git a/pkg/cli/defaults.go b/pkg/cli/defaults.go index bd396bc..bc13b08 100644 --- a/pkg/cli/defaults.go +++ b/pkg/cli/defaults.go @@ -1,11 +1,12 @@ package cli -import "github.com/restechnica/semverbot/internal" +import ( + "fmt" -var ( - // DefaultConfig the default config. - DefaultConfig = internal.DefaultConfig + "github.com/restechnica/semverbot/internal" +) +var ( // DefaultConfigFilePath the default relative filepath to the config file. DefaultConfigFilePath = internal.DefaultConfigFilePath @@ -24,3 +25,39 @@ var ( // DefaultVersion the default version when no other version can be found. DefaultVersion = internal.DefaultVersion ) + +func GetDefaultConfig() string { + const template = `mode = "%s" + +[git] + +[git.config] +email = "semverbot@github.com" +name = "semverbot" + +[git.tags] +prefix = "%s" + +[semver] +patch = ["fix", "bug"] +minor = ["feature"] +major = ["release"] + +[modes] + +[modes.git-branch] +delimiters = "%s" + +[modes.git-commit] +delimiters = "%s" + +` + + return fmt.Sprintf( + template, + DefaultMode, + DefaultGitTagsPrefix, + DefaultGitBranchDelimiters, + DefaultGitCommitDelimiters, + ) +} From 467cfc9cc9acaf5a8dd171e8b33f01420ff7eb58 Mon Sep 17 00:00:00 2001 From: shiouen Date: Sat, 20 Nov 2021 20:05:50 +0100 Subject: [PATCH 34/54] added unit tests to semver package --- pkg/semver/parse_test.go | 51 ++++++++++++++++++++++++++++++ pkg/semver/trim_test.go | 68 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100644 pkg/semver/parse_test.go create mode 100644 pkg/semver/trim_test.go diff --git a/pkg/semver/parse_test.go b/pkg/semver/parse_test.go new file mode 100644 index 0000000..ad5cfdf --- /dev/null +++ b/pkg/semver/parse_test.go @@ -0,0 +1,51 @@ +package semver + +import ( + "fmt" + "github.com/stretchr/testify/assert" + "strings" + "testing" +) + +func TestParse_Parse(t *testing.T) { + type Test struct { + Name string + Major string + Minor string + Patch string + Prebuild string + Prefix string + } + + var tests = []Test{ + {Name: "Default", Major: "0", Minor: "0", Patch: "0"}, + {Name: "Patch", Major: "0", Minor: "0", Patch: "1"}, + {Name: "Minor", Major: "0", Minor: "2", Patch: "0"}, + {Name: "Major", Major: "3", Minor: "0", Patch: "0"}, + {Name: "DiscardPrefix", Major: "1", Minor: "0", Patch: "0", Prefix: "v"}, + {Name: "KeepPrebuild", Major: "2", Minor: "0", Patch: "0", Prebuild: "-pre+001"}, + } + + for _, test := range tests { + t.Run(test.Name, func(t *testing.T) { + var version = fmt.Sprintf(`%s%s.%s.%s%s`, test.Prefix, test.Major, test.Minor, test.Patch, + test.Prebuild) + + var got, err = Parse(version) + + assert.Equal(t, test.Major, fmt.Sprint(got.Major), `want: "%s", got: "%d"`, test.Major, got.Major) + assert.Equal(t, test.Minor, fmt.Sprint(got.Minor), `want: "%s", got: "%s"`, test.Minor, got.Minor) + assert.Equal(t, test.Patch, fmt.Sprint(got.Patch), `want: "%s", got: "%s"`, test.Patch, got.Patch) + + if test.Prefix != "" { + assert.False(t, strings.HasPrefix(got.String(), test.Prefix)) + } + + if test.Prebuild != "" { + assert.True(t, strings.HasSuffix(got.String(), test.Prebuild)) + } + + assert.NoError(t, err) + }) + } +} diff --git a/pkg/semver/trim_test.go b/pkg/semver/trim_test.go new file mode 100644 index 0000000..98794d4 --- /dev/null +++ b/pkg/semver/trim_test.go @@ -0,0 +1,68 @@ +package semver + +import ( + "fmt" + "github.com/stretchr/testify/assert" + "strings" + "testing" +) + +func TestTrim_Trim(t *testing.T) { + type Test struct { + Name string + Major string + Minor string + Patch string + Prebuild string + Prefix string + } + + var tests = []Test{ + {Name: "Default", Major: "0", Minor: "0", Patch: "0"}, + {Name: "Patch", Major: "0", Minor: "0", Patch: "1"}, + {Name: "Minor", Major: "0", Minor: "2", Patch: "0"}, + {Name: "Major", Major: "3", Minor: "0", Patch: "0"}, + {Name: "DiscardPrefix", Major: "1", Minor: "0", Patch: "0", Prefix: "v"}, + {Name: "DiscardPrebuild", Major: "2", Minor: "0", Patch: "0", Prebuild: "-pre+001"}, + } + + for _, test := range tests { + t.Run(test.Name, func(t *testing.T) { + var version = fmt.Sprintf(`%s%s.%s.%s%s`, test.Prefix, test.Major, test.Minor, test.Patch, + test.Prebuild) + + var want = strings.ReplaceAll(version, test.Prefix, "") + want = strings.ReplaceAll(want, test.Prebuild, "") + + var got, err = Trim(version) + + assert.Equal(t, want, got, `want: "%s", got: "%s"`, want, got) + + if test.Prefix != "" { + assert.False(t, strings.HasPrefix(got, test.Prefix)) + } + + if test.Prebuild != "" { + assert.False(t, strings.HasSuffix(got, test.Prebuild)) + } + + assert.NoError(t, err) + }) + } + + type ErrorTest struct { + Name string + Version string + } + + var errorTests = []ErrorTest{ + {Name: "ReturnErrorOnInvalidVersion", Version: "invalid"}, + } + + for _, test := range errorTests { + t.Run(test.Name, func(t *testing.T) { + var _, got = Trim(test.Version) + assert.Error(t, got) + }) + } +} From 57d98b63780aa98a4677f95a865560ad79995374 Mon Sep 17 00:00:00 2001 From: shiouen Date: Sat, 20 Nov 2021 21:41:06 +0100 Subject: [PATCH 35/54] added prefix tests - added version api tests (get, getOrDefault, newApi) --- pkg/semver/parse_test.go | 2 +- pkg/semver/trim_test.go | 2 +- pkg/versions/api_test.go | 131 ++++++++++++++++++++++++++++++++++++ pkg/versions/prefix_test.go | 28 ++++++++ 4 files changed, 161 insertions(+), 2 deletions(-) create mode 100644 pkg/versions/api_test.go create mode 100644 pkg/versions/prefix_test.go diff --git a/pkg/semver/parse_test.go b/pkg/semver/parse_test.go index ad5cfdf..8723c69 100644 --- a/pkg/semver/parse_test.go +++ b/pkg/semver/parse_test.go @@ -7,7 +7,7 @@ import ( "testing" ) -func TestParse_Parse(t *testing.T) { +func TestParse(t *testing.T) { type Test struct { Name string Major string diff --git a/pkg/semver/trim_test.go b/pkg/semver/trim_test.go index 98794d4..e478d12 100644 --- a/pkg/semver/trim_test.go +++ b/pkg/semver/trim_test.go @@ -7,7 +7,7 @@ import ( "testing" ) -func TestTrim_Trim(t *testing.T) { +func TestTrim(t *testing.T) { type Test struct { Name string Major string diff --git a/pkg/versions/api_test.go b/pkg/versions/api_test.go new file mode 100644 index 0000000..7efc8f4 --- /dev/null +++ b/pkg/versions/api_test.go @@ -0,0 +1,131 @@ +package versions + +import ( + "fmt" + "github.com/restechnica/semverbot/pkg/cli" + "testing" + + "github.com/restechnica/semverbot/internal/mocks" + "github.com/restechnica/semverbot/pkg/git" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +func TestAPI_GetVersion(t *testing.T) { + type Test struct { + Name string + Version string + } + + var tests = []Test{ + {Name: "ReturnVersion", Version: "0.0.0"}, + } + + for _, test := range tests { + t.Run(test.Name, func(t *testing.T) { + var cmder = mocks.NewMockCommander() + cmder.On("Output", mock.Anything, mock.Anything).Return(test.Version, nil) + + var gitAPI = git.API{Commander: cmder} + var versionAPI = API{GitAPI: gitAPI} + + var got, err = versionAPI.GetVersion() + + assert.NoError(t, err) + assert.Equal(t, test.Version, got, `want: "%s, got: "%s"`, test.Version, got) + }) + } + + type ErrorTest struct { + Error error + Name string + } + + var errorTests = []ErrorTest{ + {Name: "ReturnErrorOnGitError", Error: fmt.Errorf("some-error")}, + } + + for _, test := range errorTests { + t.Run(test.Name, func(t *testing.T) { + var cmder = mocks.NewMockCommander() + cmder.On("Output", mock.Anything, mock.Anything).Return("", test.Error) + + var gitAPI = git.API{Commander: cmder} + var versionAPI = API{GitAPI: gitAPI} + + var _, got = versionAPI.GetVersion() + assert.Error(t, got) + }) + } +} + +func TestAPI_GetVersionOrDefault(t *testing.T) { + type Test struct { + Name string + Version string + } + + var tests = []Test{ + {Name: "ReturnVersionWithoutError", Version: "0.0.0"}, + } + + for _, test := range tests { + t.Run(test.Name, func(t *testing.T) { + var cmder = mocks.NewMockCommander() + cmder.On("Output", mock.Anything, mock.Anything).Return(test.Version, nil) + + var gitAPI = git.API{Commander: cmder} + var versionAPI = API{GitAPI: gitAPI} + + var got, err = versionAPI.GetVersion() + + assert.NoError(t, err) + assert.Equal(t, test.Version, got, `want: "%s, got: "%s"`, test.Version, got) + }) + } + + type ErrorTest struct { + Error error + Name string + } + + var errorTests = []ErrorTest{ + {Name: "ReturnDefaultVersionOnGitError", Error: fmt.Errorf("some-error")}, + } + + for _, test := range errorTests { + t.Run(test.Name, func(t *testing.T) { + var cmder = mocks.NewMockCommander() + cmder.On("Output", mock.Anything, mock.Anything).Return("", test.Error) + + var gitAPI = git.API{Commander: cmder} + var versionAPI = API{GitAPI: gitAPI} + + var got = versionAPI.GetVersionOrDefault(cli.DefaultVersion) + assert.Equal(t, cli.DefaultVersion, got, `want: "%s, got: "%s"`, cli.DefaultVersion, got) + }) + } +} + +func TestAPI_PredictVersion(t *testing.T) { + +} + +func TestAPI_PushVersion(t *testing.T) { + +} + +func TestAPI_ReleaseVersion(t *testing.T) { + +} + +func TestAPI_UpdateVersion(t *testing.T) { + +} + +func TestNewAPI(t *testing.T) { + t.Run("ValidateState", func(t *testing.T) { + var api = NewAPI() + assert.NotNil(t, api.GitAPI) + }) +} diff --git a/pkg/versions/prefix_test.go b/pkg/versions/prefix_test.go new file mode 100644 index 0000000..9bf00ff --- /dev/null +++ b/pkg/versions/prefix_test.go @@ -0,0 +1,28 @@ +package versions + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestAddPrefix(t *testing.T) { + type Test struct { + Name string + Version string + Prefix string + } + + var tests = []Test{ + {Name: "HappyPath", Version: "0.0.0", Prefix: "v"}, + } + + for _, test := range tests { + t.Run(test.Name, func(t *testing.T) { + var got = AddPrefix(test.Version, test.Prefix) + assert.True(t, strings.HasPrefix(got, test.Prefix)) + assert.True(t, strings.HasSuffix(got, test.Version)) + }) + } +} From 52484df040eec58395a7d436caa8a71532d618d6 Mon Sep 17 00:00:00 2001 From: shiouen Date: Sat, 20 Nov 2021 23:22:01 +0100 Subject: [PATCH 36/54] moved mocks to different files - created git api interface to help with faking and mocking - renamed the original implementation to git command api - created fake git api - moved err handling logic and prints from version api UpdateVersion method to CLI command instead --- internal/fakes/git.go | 87 ++++++++++ internal/mocks/{mocks.go => commander.go} | 22 +-- internal/mocks/mode.go | 21 +++ pkg/cli/commands/init.go | 3 +- pkg/cli/commands/root.go | 2 +- pkg/cli/commands/update-version.go | 12 +- pkg/git/api.go | 46 ++++-- pkg/modes/auto_test.go | 6 +- pkg/modes/gitbranch.go | 2 +- pkg/modes/gitcommit.go | 2 +- pkg/modes/gitcommit_test.go | 4 +- pkg/semver/parse_test.go | 3 +- pkg/semver/trim_test.go | 3 +- pkg/versions/api.go | 20 +-- pkg/versions/api_test.go | 192 +++++++++++++++++++++- 15 files changed, 351 insertions(+), 74 deletions(-) create mode 100644 internal/fakes/git.go rename internal/mocks/{mocks.go => commander.go} (54%) create mode 100644 internal/mocks/mode.go diff --git a/internal/fakes/git.go b/internal/fakes/git.go new file mode 100644 index 0000000..72a0dd1 --- /dev/null +++ b/internal/fakes/git.go @@ -0,0 +1,87 @@ +package fakes + +import "fmt" + +// FakeGitAPI a git.API interface fake implementation. +type FakeGitAPI struct { + Config map[string]string + LocalTags []string + PushedTags []string +} + +// NewFakeGitAPI creates a new FakeGitAPI. +// Returns the new FakeGitAPI. +func NewFakeGitAPI() *FakeGitAPI { + return &FakeGitAPI{ + Config: map[string]string{}, + LocalTags: []string{}, + PushedTags: []string{}, + } +} + +// CreateAnnotatedTag creates a fake tag. +func (fake *FakeGitAPI) CreateAnnotatedTag(tag string) (err error) { + fake.LocalTags = append(fake.LocalTags, tag) + return err +} + +// FetchTags does nothing. +func (fake *FakeGitAPI) FetchTags() (err error) { + return err +} + +// FetchUnshallow does nothing. +func (fake *FakeGitAPI) FetchUnshallow() (err error) { + return err +} + +// GetConfig returns a fake config. +func (fake *FakeGitAPI) GetConfig(key string) (value string, err error) { + var config, exists = fake.Config[key] + + if exists { + return config, nil + } + + return "", fmt.Errorf("config does not exist") +} + +// GetLatestAnnotatedTag returns a fake tag. +func (fake *FakeGitAPI) GetLatestAnnotatedTag() (tag string, err error) { + if len(fake.LocalTags) == 0 { + return tag, fmt.Errorf("no tags found") + } + return fake.LocalTags[len(fake.LocalTags)-1], nil +} + +// GetLatestCommitMessage does nothing. +func (fake *FakeGitAPI) GetLatestCommitMessage() (message string, err error) { + return message, err +} + +// GetMergedBranchName does nothing. +func (fake *FakeGitAPI) GetMergedBranchName() (name string, err error) { + return name, err +} + +// PushTag pushes a fake tag. +func (fake *FakeGitAPI) PushTag(tag string) (err error) { + + fake.PushedTags = append(fake.PushedTags, tag) + return err +} + +// SetConfig sets a fake config. +func (fake *FakeGitAPI) SetConfig(key string, value string) (err error) { + fake.Config[key] = value + return err +} + +// SetConfigIfNotSet sets a fake config if it does not exist. +func (fake *FakeGitAPI) SetConfigIfNotSet(key string, value string) (err error) { + if _, err = fake.GetConfig(key); err != nil { + err = fake.SetConfig(key, value) + } + + return err +} diff --git a/internal/mocks/mocks.go b/internal/mocks/commander.go similarity index 54% rename from internal/mocks/mocks.go rename to internal/mocks/commander.go index 9013e9d..a3bf663 100644 --- a/internal/mocks/mocks.go +++ b/internal/mocks/commander.go @@ -1,8 +1,6 @@ package mocks -import ( - "github.com/stretchr/testify/mock" -) +import "github.com/stretchr/testify/mock" // MockCommander a commander interface mock implementation. type MockCommander struct { @@ -28,21 +26,3 @@ func (mock *MockCommander) Run(name string, arg ...string) error { args := mock.Called(name, arg) return args.Error(0) } - -// MockSemverMode a semver mode interface mock implementation. -type MockSemverMode struct { - mock.Mock -} - -// NewMockSemverMode creates a new MockSemverMode. -// Returns the new MockSemverMode. -func NewMockSemverMode() *MockSemverMode { - return &MockSemverMode{} -} - -// Increment mock increments a version. -// Returns an incremented mock version. -func (mock *MockSemverMode) Increment(targetVersion string) (nextVersion string, err error) { - args := mock.Called(targetVersion) - return args.String(0), args.Error(1) -} diff --git a/internal/mocks/mode.go b/internal/mocks/mode.go new file mode 100644 index 0000000..8233e2b --- /dev/null +++ b/internal/mocks/mode.go @@ -0,0 +1,21 @@ +package mocks + +import "github.com/stretchr/testify/mock" + +// MockMode a semver mode interface mock implementation. +type MockMode struct { + mock.Mock +} + +// NewMockMode creates a new MockMode. +// Returns the new MockMode. +func NewMockMode() *MockMode { + return &MockMode{} +} + +// Increment mock increments a version. +// Returns an incremented mock version. +func (mock *MockMode) Increment(targetVersion string) (nextVersion string, err error) { + args := mock.Called(targetVersion) + return args.String(0), args.Error(1) +} diff --git a/pkg/cli/commands/init.go b/pkg/cli/commands/init.go index 665b3bb..470cfa9 100644 --- a/pkg/cli/commands/init.go +++ b/pkg/cli/commands/init.go @@ -3,9 +3,10 @@ package commands import ( "fmt" + "github.com/spf13/cobra" + "github.com/restechnica/semverbot/pkg/cli" "github.com/restechnica/semverbot/pkg/core" - "github.com/spf13/cobra" ) // NewInitCommand creates a new init command. diff --git a/pkg/cli/commands/root.go b/pkg/cli/commands/root.go index 6b0611d..0e24e0c 100644 --- a/pkg/cli/commands/root.go +++ b/pkg/cli/commands/root.go @@ -93,7 +93,7 @@ func LoadFlags(cmd *cobra.Command) (err error) { // the git config does not exist. // Returns an error if it fails. func SetGitConfigIfConfigured() (err error) { - var gitAPI = git.NewAPI() + var gitAPI = git.NewCommandAPI() if viper.IsSet(cli.GitConfigEmailConfigKey) { var email = viper.GetString(cli.GitConfigEmailConfigKey) diff --git a/pkg/cli/commands/update-version.go b/pkg/cli/commands/update-version.go index d6f904b..28e903c 100644 --- a/pkg/cli/commands/update-version.go +++ b/pkg/cli/commands/update-version.go @@ -1,9 +1,11 @@ package commands import ( - "github.com/restechnica/semverbot/pkg/core" + "fmt" "github.com/spf13/cobra" + + "github.com/restechnica/semverbot/pkg/core" ) // NewUpdateVersionCommand creates a new update version command. @@ -20,5 +22,11 @@ func NewUpdateVersionCommand() *cobra.Command { // UpdateVersionCommandRunE runs the commands. // Returns an error if it fails. func UpdateVersionCommandRunE(cmd *cobra.Command, args []string) (err error) { - return core.UpdateVersion() + if err = core.UpdateVersion(); err != nil { + return fmt.Errorf("something went wrong while updating the version") + } + + fmt.Println("successfully fetched the latest git tags") + + return err } diff --git a/pkg/git/api.go b/pkg/git/api.go index 3c3620f..23cab91 100644 --- a/pkg/git/api.go +++ b/pkg/git/api.go @@ -2,56 +2,70 @@ package git import "github.com/restechnica/semverbot/internal/commands" -// API an API to interact with the git CLI. -type API struct { +// API interface to interact with git. +type API interface { + CreateAnnotatedTag(tag string) (err error) + FetchTags() (err error) + FetchUnshallow() (err error) + GetConfig(key string) (value string, err error) + GetLatestAnnotatedTag() (tag string, err error) + GetLatestCommitMessage() (message string, err error) + GetMergedBranchName() (name string, err error) + PushTag(tag string) (err error) + SetConfig(key string, value string) (err error) + SetConfigIfNotSet(key string, value string) (err error) +} + +// CommandAPI an CommandAPI to interact with the git CLI. +type CommandAPI struct { Commander commands.Commander } -// NewAPI creates a new API with a commander to run git commands. -// Returns the new API. -func NewAPI() API { - return API{Commander: commands.NewExecCommander()} +// NewCommandAPI creates a new CommandAPI with a commander to run git commands. +// Returns the new CommandAPI. +func NewCommandAPI() CommandAPI { + return CommandAPI{Commander: commands.NewExecCommander()} } // CreateAnnotatedTag creates an annotated git tag. // Returns an error if the command fails. -func (api API) CreateAnnotatedTag(tag string) (err error) { +func (api CommandAPI) CreateAnnotatedTag(tag string) (err error) { return api.Commander.Run("git", "tag", "-a", tag, "-m", tag) } // FetchTags fetches all tags from the remote origin. // Returns an error if the command fails. -func (api API) FetchTags() (err error) { +func (api CommandAPI) FetchTags() (err error) { return api.Commander.Run("git", "fetch", "--tags") } // FetchUnshallow convert a shallow repository to a complete one. // Returns an error if the command fails. -func (api API) FetchUnshallow() (err error) { +func (api CommandAPI) FetchUnshallow() (err error) { return api.Commander.Run("git", "fetch", "--unshallow") } // GetConfig gets the git config for a specific key. // Returns the value of the git config as a string and an error if the command failed. -func (api API) GetConfig(key string) (value string, err error) { +func (api CommandAPI) GetConfig(key string) (value string, err error) { return api.Commander.Output("git", "config", "--get", key) } // GetLatestAnnotatedTag gets the latest annotated git tag. // Returns the git tag and an error if the command failed. -func (api API) GetLatestAnnotatedTag() (tag string, err error) { +func (api CommandAPI) GetLatestAnnotatedTag() (tag string, err error) { return api.Commander.Output("git", "describe", "--tags") } // GetLatestCommitMessage gets the latest git commit message. // Returns the git commit message or an error if the command failed. -func (api API) GetLatestCommitMessage() (message string, err error) { +func (api CommandAPI) GetLatestCommitMessage() (message string, err error) { return api.Commander.Output("git", "--no-pager", "show", "-s", "--format=%s") } // GetMergedBranchName gets the source branch name if the last commit is a merge. // Returns the branch name or an error if something went wrong with git. -func (api API) GetMergedBranchName() (name string, err error) { +func (api CommandAPI) GetMergedBranchName() (name string, err error) { return api.Commander.Output( "git", "name-rev", @@ -64,19 +78,19 @@ func (api API) GetMergedBranchName() (name string, err error) { // PushTag pushes a tag to the remote origin. // Returns an error if the command failed. -func (api API) PushTag(tag string) (err error) { +func (api CommandAPI) PushTag(tag string) (err error) { return api.Commander.Run("git", "push", "origin", tag) } // SetConfig sets a git config key and value. // Returns an error if the command failed. -func (api API) SetConfig(key string, value string) (err error) { +func (api CommandAPI) SetConfig(key string, value string) (err error) { return api.Commander.Run("git", "config", key, value) } // SetConfigIfNotSet sets a git config key and value if the config does not exist. // Returns an error if the command failed. -func (api API) SetConfigIfNotSet(key string, value string) (err error) { +func (api CommandAPI) SetConfigIfNotSet(key string, value string) (err error) { if _, err = api.GetConfig(key); err != nil { err = api.SetConfig(key, value) } diff --git a/pkg/modes/auto_test.go b/pkg/modes/auto_test.go index ae76f8b..da54f23 100644 --- a/pkg/modes/auto_test.go +++ b/pkg/modes/auto_test.go @@ -23,7 +23,7 @@ func TestAutoMode_Increment(t *testing.T) { const target = "0.0.0" const want = "1.0.0" - var gitCommitMode = mocks.NewMockSemverMode() + var gitCommitMode = mocks.NewMockMode() gitCommitMode.On("Increment", target).Return(want, nil) var autoMode = NewAutoMode([]Mode{gitCommitMode}) @@ -37,7 +37,7 @@ func TestAutoMode_Increment(t *testing.T) { const target = "0.0.0" const want = "0.0.1" - var gitCommitMode = mocks.NewMockSemverMode() + var gitCommitMode = mocks.NewMockMode() gitCommitMode.On("Increment", target).Return("", fmt.Errorf("some-error")) var autoMode = NewAutoMode([]Mode{gitCommitMode}) @@ -59,7 +59,7 @@ func TestAutoMode_Increment(t *testing.T) { for _, test := range errorTests { t.Run(test.Name, func(t *testing.T) { - var gitCommitMode = mocks.NewMockSemverMode() + var gitCommitMode = mocks.NewMockMode() gitCommitMode.On("Increment", test.Version).Return("", fmt.Errorf("some-error")) var autoMode = NewAutoMode([]Mode{gitCommitMode}) diff --git a/pkg/modes/gitbranch.go b/pkg/modes/gitbranch.go index 6cde412..8c94b5a 100644 --- a/pkg/modes/gitbranch.go +++ b/pkg/modes/gitbranch.go @@ -21,7 +21,7 @@ type GitBranchMode struct { // NewGitBranchMode creates a new GitBranchMode. // Returns the new GitBranchMode. func NewGitBranchMode(delimiters string, semverMap SemverMap) GitBranchMode { - return GitBranchMode{Delimiters: delimiters, GitAPI: git.NewAPI(), SemverMap: semverMap} + return GitBranchMode{Delimiters: delimiters, GitAPI: git.NewCommandAPI(), SemverMap: semverMap} } // Increment increments the semver level based on the naming of the source branch of a git merge. diff --git a/pkg/modes/gitcommit.go b/pkg/modes/gitcommit.go index 9ba2b49..aca1888 100644 --- a/pkg/modes/gitcommit.go +++ b/pkg/modes/gitcommit.go @@ -21,7 +21,7 @@ type GitCommitMode struct { // NewGitCommitMode creates a new GitCommitMode. // Returns the new GitCommitMode. func NewGitCommitMode(delimiters string, semverMap SemverMap) GitCommitMode { - return GitCommitMode{Delimiters: delimiters, GitAPI: git.NewAPI(), SemverMap: semverMap} + return GitCommitMode{Delimiters: delimiters, GitAPI: git.NewCommandAPI(), SemverMap: semverMap} } // Increment increments a given version based on the latest git commit message. diff --git a/pkg/modes/gitcommit_test.go b/pkg/modes/gitcommit_test.go index 19c81a5..85b51e8 100644 --- a/pkg/modes/gitcommit_test.go +++ b/pkg/modes/gitcommit_test.go @@ -102,7 +102,7 @@ func TestGitCommitMode_Increment(t *testing.T) { cmder.On("Output", mock.Anything, mock.Anything).Return(test.Message, nil) var gitCommitMode = NewGitCommitMode("[]", semverMap) - gitCommitMode.GitAPI = git.API{Commander: cmder} + gitCommitMode.GitAPI = git.CommandAPI{Commander: cmder} var got, err = gitCommitMode.Increment(test.Version) assert.NoError(t, err) @@ -131,7 +131,7 @@ func TestGitCommitMode_Increment(t *testing.T) { cmder.On("Output", mock.Anything, mock.Anything).Return(test.Message, test.GitError) var gitCommitMode = NewGitCommitMode("[]", semverMap) - gitCommitMode.GitAPI = git.API{Commander: cmder} + gitCommitMode.GitAPI = git.CommandAPI{Commander: cmder} var _, err = gitCommitMode.Increment(test.Version) assert.Error(t, err) diff --git a/pkg/semver/parse_test.go b/pkg/semver/parse_test.go index 8723c69..8ebc7b7 100644 --- a/pkg/semver/parse_test.go +++ b/pkg/semver/parse_test.go @@ -2,9 +2,10 @@ package semver import ( "fmt" - "github.com/stretchr/testify/assert" "strings" "testing" + + "github.com/stretchr/testify/assert" ) func TestParse(t *testing.T) { diff --git a/pkg/semver/trim_test.go b/pkg/semver/trim_test.go index e478d12..1bb6e3f 100644 --- a/pkg/semver/trim_test.go +++ b/pkg/semver/trim_test.go @@ -2,9 +2,10 @@ package semver import ( "fmt" - "github.com/stretchr/testify/assert" "strings" "testing" + + "github.com/stretchr/testify/assert" ) func TestTrim(t *testing.T) { diff --git a/pkg/versions/api.go b/pkg/versions/api.go index 235a325..740b25f 100644 --- a/pkg/versions/api.go +++ b/pkg/versions/api.go @@ -1,8 +1,6 @@ package versions import ( - "fmt" - "github.com/restechnica/semverbot/pkg/git" "github.com/restechnica/semverbot/pkg/modes" "github.com/restechnica/semverbot/pkg/semver" @@ -16,7 +14,7 @@ type API struct { // NewAPI creates a new version API. // Returns the new API. func NewAPI() API { - return API{GitAPI: git.NewAPI()} + return API{GitAPI: git.NewCommandAPI()} } // GetVersion gets the current version by getting the latest annotated git tag. @@ -62,19 +60,9 @@ func (api API) PushVersion(version string, prefix string) (err error) { } // UpdateVersion updates the version by making the git repo unshallow and by fetching all git tags. -// Returns and error if anything went wrong. +// Returns and error if anything went wrong. Errors from making the git repo unshallow are ignored. func (api API) UpdateVersion() (err error) { - var gitAPI = git.NewAPI() - - if err = gitAPI.FetchUnshallow(); err != nil { - fmt.Println("something went wrong while fetching from git, attempting to fetch tags anyway") - } - - if err = gitAPI.FetchTags(); err != nil { - fmt.Println("something went wrong while updating the version") - } else { - fmt.Println("successfully fetched the latest git tags") - } - + err = api.GitAPI.FetchUnshallow() + err = api.GitAPI.FetchTags() return err } diff --git a/pkg/versions/api_test.go b/pkg/versions/api_test.go index 7efc8f4..3e41c30 100644 --- a/pkg/versions/api_test.go +++ b/pkg/versions/api_test.go @@ -2,13 +2,16 @@ package versions import ( "fmt" - "github.com/restechnica/semverbot/pkg/cli" "testing" - "github.com/restechnica/semverbot/internal/mocks" - "github.com/restechnica/semverbot/pkg/git" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" + + "github.com/restechnica/semverbot/internal/fakes" + "github.com/restechnica/semverbot/internal/mocks" + "github.com/restechnica/semverbot/pkg/cli" + "github.com/restechnica/semverbot/pkg/git" + "github.com/restechnica/semverbot/pkg/modes" ) func TestAPI_GetVersion(t *testing.T) { @@ -26,7 +29,7 @@ func TestAPI_GetVersion(t *testing.T) { var cmder = mocks.NewMockCommander() cmder.On("Output", mock.Anything, mock.Anything).Return(test.Version, nil) - var gitAPI = git.API{Commander: cmder} + var gitAPI = git.CommandAPI{Commander: cmder} var versionAPI = API{GitAPI: gitAPI} var got, err = versionAPI.GetVersion() @@ -50,10 +53,11 @@ func TestAPI_GetVersion(t *testing.T) { var cmder = mocks.NewMockCommander() cmder.On("Output", mock.Anything, mock.Anything).Return("", test.Error) - var gitAPI = git.API{Commander: cmder} + var gitAPI = git.CommandAPI{Commander: cmder} var versionAPI = API{GitAPI: gitAPI} var _, got = versionAPI.GetVersion() + assert.Error(t, got) }) } @@ -74,7 +78,7 @@ func TestAPI_GetVersionOrDefault(t *testing.T) { var cmder = mocks.NewMockCommander() cmder.On("Output", mock.Anything, mock.Anything).Return(test.Version, nil) - var gitAPI = git.API{Commander: cmder} + var gitAPI = git.CommandAPI{Commander: cmder} var versionAPI = API{GitAPI: gitAPI} var got, err = versionAPI.GetVersion() @@ -90,7 +94,7 @@ func TestAPI_GetVersionOrDefault(t *testing.T) { } var errorTests = []ErrorTest{ - {Name: "ReturnDefaultVersionOnGitError", Error: fmt.Errorf("some-error")}, + {Name: "ReturnDefaultVersionOnGitApiError", Error: fmt.Errorf("some-error")}, } for _, test := range errorTests { @@ -98,29 +102,201 @@ func TestAPI_GetVersionOrDefault(t *testing.T) { var cmder = mocks.NewMockCommander() cmder.On("Output", mock.Anything, mock.Anything).Return("", test.Error) - var gitAPI = git.API{Commander: cmder} + var gitAPI = git.CommandAPI{Commander: cmder} var versionAPI = API{GitAPI: gitAPI} var got = versionAPI.GetVersionOrDefault(cli.DefaultVersion) + assert.Equal(t, cli.DefaultVersion, got, `want: "%s, got: "%s"`, cli.DefaultVersion, got) }) } } func TestAPI_PredictVersion(t *testing.T) { + type Test struct { + Mode modes.Mode + Name string + Version string + Want string + } + + var tests = []Test{ + {Name: "ReturnPatchPrediction", Mode: modes.NewPatchMode(), Version: "0.0.0", Want: "0.0.1"}, + {Name: "ReturnMinorPrediction", Mode: modes.NewMinorMode(), Version: "0.0.0", Want: "0.1.0"}, + {Name: "ReturnMajorPrediction", Mode: modes.NewMajorMode(), Version: "0.0.0", Want: "1.0.0"}, + } + + for _, test := range tests { + t.Run(test.Name, func(t *testing.T) { + var cmder = mocks.NewMockCommander() + cmder.On("Output", mock.Anything, mock.Anything).Return(test.Version, nil) + + var gitAPI = git.CommandAPI{Commander: cmder} + var versionAPI = API{GitAPI: gitAPI} + + var got, err = versionAPI.PredictVersion(test.Version, test.Mode) + + assert.NoError(t, err) + assert.Equal(t, test.Want, got, `want: "%s, got: "%s"`, test.Want, got) + }) + } + + type ErrorTest struct { + Error error + Name string + Version string + } + var errorTests = []ErrorTest{ + {Name: "ReturnErrorOnModeIncrementError", Error: fmt.Errorf("some-error"), Version: "invalid"}, + } + + for _, test := range errorTests { + t.Run(test.Name, func(t *testing.T) { + var versionAPI = API{} + + var mode = mocks.NewMockMode() + mode.On("Increment", mock.Anything).Return(test.Version, test.Error) + + var _, got = versionAPI.PredictVersion("0.0.0", mode) + + assert.Error(t, got) + }) + } } func TestAPI_PushVersion(t *testing.T) { + type Test struct { + Mode modes.Mode + Name string + Prefix string + Version string + Want string + } + + var tests = []Test{ + {Name: "PushWithPrefix", Mode: modes.NewPatchMode(), Prefix: "v", Version: "0.0.1", Want: "v0.0.1"}, + {Name: "PushWithoutPrefix", Mode: modes.NewPatchMode(), Prefix: "", Version: "0.0.1", Want: "0.0.1"}, + } + + for _, test := range tests { + t.Run(test.Name, func(t *testing.T) { + var gitAPI = fakes.NewFakeGitAPI() + var versionAPI = API{GitAPI: gitAPI} + + var err = versionAPI.PushVersion(test.Version, test.Prefix) + + var pushedTags = versionAPI.GitAPI.(*fakes.FakeGitAPI).PushedTags + var got = pushedTags[len(pushedTags)-1] + + assert.NoError(t, err) + assert.Equal(t, test.Want, got, `want: "%s, got: "%s"`, test.Want, got) + }) + } + + type ErrorTest struct { + Error error + Name string + Version string + } + var errorTests = []ErrorTest{ + {Name: "ReturnErrorOnGitApiError", Error: fmt.Errorf("some-error"), Version: "invalid"}, + } + + for _, test := range errorTests { + t.Run(test.Name, func(t *testing.T) { + var cmder = mocks.NewMockCommander() + cmder.On("Run", mock.Anything, mock.Anything).Return(test.Error) + + var gitAPI = git.CommandAPI{Commander: cmder} + var versionAPI = API{GitAPI: gitAPI} + + var got = versionAPI.PushVersion("0.0.1", "v") + + assert.Error(t, got) + }) + } } func TestAPI_ReleaseVersion(t *testing.T) { + type Test struct { + Mode modes.Mode + Name string + Prefix string + Version string + Want string + } + var tests = []Test{ + {Name: "PushWithPrefix", Mode: modes.NewPatchMode(), Prefix: "v", Version: "0.0.1", Want: "v0.0.1"}, + {Name: "PushWithoutPrefix", Mode: modes.NewPatchMode(), Prefix: "", Version: "0.0.1", Want: "0.0.1"}, + } + + for _, test := range tests { + t.Run(test.Name, func(t *testing.T) { + var gitAPI = fakes.NewFakeGitAPI() + var versionAPI = API{GitAPI: gitAPI} + + var err = versionAPI.ReleaseVersion(test.Version, test.Prefix) + + var localTags = versionAPI.GitAPI.(*fakes.FakeGitAPI).LocalTags + var got = localTags[len(localTags)-1] + + assert.NoError(t, err) + assert.Equal(t, test.Want, got, `want: "%s, got: "%s"`, test.Want, got) + }) + } + + type ErrorTest struct { + Error error + Name string + Version string + } + + var errorTests = []ErrorTest{ + {Name: "ReturnErrorOnGitApiError", Error: fmt.Errorf("some-error"), Version: "invalid"}, + } + + for _, test := range errorTests { + t.Run(test.Name, func(t *testing.T) { + var cmder = mocks.NewMockCommander() + cmder.On("Run", mock.Anything, mock.Anything).Return(test.Error) + + var gitAPI = git.CommandAPI{Commander: cmder} + var versionAPI = API{GitAPI: gitAPI} + + var got = versionAPI.ReleaseVersion("0.0.1", "v") + + assert.Error(t, got) + }) + } } func TestAPI_UpdateVersion(t *testing.T) { + type ErrorTest struct { + Error error + Name string + Version string + } + + var errorTests = []ErrorTest{ + {Name: "ReturnErrorOnGitApiError", Error: fmt.Errorf("some-error"), Version: "invalid"}, + } + + for _, test := range errorTests { + t.Run(test.Name, func(t *testing.T) { + var cmder = mocks.NewMockCommander() + cmder.On("Run", mock.Anything, mock.Anything).Return(test.Error) + + var gitAPI = git.CommandAPI{Commander: cmder} + var versionAPI = API{GitAPI: gitAPI} + var got = versionAPI.UpdateVersion() + + assert.Error(t, got) + }) + } } func TestNewAPI(t *testing.T) { From 8717405de0295df96283ebf165c7566c6ea1cd50 Mon Sep 17 00:00:00 2001 From: shiouen Date: Sat, 20 Nov 2021 23:27:27 +0100 Subject: [PATCH 37/54] separated git command api from the git api interface - renamed git command api to git cli --- pkg/cli/commands/root.go | 2 +- pkg/git/api.go | 84 ------------------------------------ pkg/git/cli.go | 85 +++++++++++++++++++++++++++++++++++++ pkg/modes/gitbranch.go | 2 +- pkg/modes/gitcommit.go | 2 +- pkg/modes/gitcommit_test.go | 4 +- pkg/versions/api.go | 2 +- pkg/versions/api_test.go | 16 +++---- 8 files changed, 99 insertions(+), 98 deletions(-) create mode 100644 pkg/git/cli.go diff --git a/pkg/cli/commands/root.go b/pkg/cli/commands/root.go index 0e24e0c..f685e1f 100644 --- a/pkg/cli/commands/root.go +++ b/pkg/cli/commands/root.go @@ -93,7 +93,7 @@ func LoadFlags(cmd *cobra.Command) (err error) { // the git config does not exist. // Returns an error if it fails. func SetGitConfigIfConfigured() (err error) { - var gitAPI = git.NewCommandAPI() + var gitAPI = git.NewCLI() if viper.IsSet(cli.GitConfigEmailConfigKey) { var email = viper.GetString(cli.GitConfigEmailConfigKey) diff --git a/pkg/git/api.go b/pkg/git/api.go index 23cab91..a0402e8 100644 --- a/pkg/git/api.go +++ b/pkg/git/api.go @@ -1,7 +1,5 @@ package git -import "github.com/restechnica/semverbot/internal/commands" - // API interface to interact with git. type API interface { CreateAnnotatedTag(tag string) (err error) @@ -15,85 +13,3 @@ type API interface { SetConfig(key string, value string) (err error) SetConfigIfNotSet(key string, value string) (err error) } - -// CommandAPI an CommandAPI to interact with the git CLI. -type CommandAPI struct { - Commander commands.Commander -} - -// NewCommandAPI creates a new CommandAPI with a commander to run git commands. -// Returns the new CommandAPI. -func NewCommandAPI() CommandAPI { - return CommandAPI{Commander: commands.NewExecCommander()} -} - -// CreateAnnotatedTag creates an annotated git tag. -// Returns an error if the command fails. -func (api CommandAPI) CreateAnnotatedTag(tag string) (err error) { - return api.Commander.Run("git", "tag", "-a", tag, "-m", tag) -} - -// FetchTags fetches all tags from the remote origin. -// Returns an error if the command fails. -func (api CommandAPI) FetchTags() (err error) { - return api.Commander.Run("git", "fetch", "--tags") -} - -// FetchUnshallow convert a shallow repository to a complete one. -// Returns an error if the command fails. -func (api CommandAPI) FetchUnshallow() (err error) { - return api.Commander.Run("git", "fetch", "--unshallow") -} - -// GetConfig gets the git config for a specific key. -// Returns the value of the git config as a string and an error if the command failed. -func (api CommandAPI) GetConfig(key string) (value string, err error) { - return api.Commander.Output("git", "config", "--get", key) -} - -// GetLatestAnnotatedTag gets the latest annotated git tag. -// Returns the git tag and an error if the command failed. -func (api CommandAPI) GetLatestAnnotatedTag() (tag string, err error) { - return api.Commander.Output("git", "describe", "--tags") -} - -// GetLatestCommitMessage gets the latest git commit message. -// Returns the git commit message or an error if the command failed. -func (api CommandAPI) GetLatestCommitMessage() (message string, err error) { - return api.Commander.Output("git", "--no-pager", "show", "-s", "--format=%s") -} - -// GetMergedBranchName gets the source branch name if the last commit is a merge. -// Returns the branch name or an error if something went wrong with git. -func (api CommandAPI) GetMergedBranchName() (name string, err error) { - return api.Commander.Output( - "git", - "name-rev", - "--name-only", - "--refs=refs/heads/*", - "--refs=refs/remotes/*", - "HEAD^2", - ) -} - -// PushTag pushes a tag to the remote origin. -// Returns an error if the command failed. -func (api CommandAPI) PushTag(tag string) (err error) { - return api.Commander.Run("git", "push", "origin", tag) -} - -// SetConfig sets a git config key and value. -// Returns an error if the command failed. -func (api CommandAPI) SetConfig(key string, value string) (err error) { - return api.Commander.Run("git", "config", key, value) -} - -// SetConfigIfNotSet sets a git config key and value if the config does not exist. -// Returns an error if the command failed. -func (api CommandAPI) SetConfigIfNotSet(key string, value string) (err error) { - if _, err = api.GetConfig(key); err != nil { - err = api.SetConfig(key, value) - } - - return err -} diff --git a/pkg/git/cli.go b/pkg/git/cli.go new file mode 100644 index 0000000..ed4f585 --- /dev/null +++ b/pkg/git/cli.go @@ -0,0 +1,85 @@ +package git + +import "github.com/restechnica/semverbot/internal/commands" + +// CLI an CLI to interact with the git CLI. +type CLI struct { + Commander commands.Commander +} + +// NewCLI creates a new CLI with a commander to run git commands. +// Returns the new CLI. +func NewCLI() CLI { + return CLI{Commander: commands.NewExecCommander()} +} + +// CreateAnnotatedTag creates an annotated git tag. +// Returns an error if the command fails. +func (api CLI) CreateAnnotatedTag(tag string) (err error) { + return api.Commander.Run("git", "tag", "-a", tag, "-m", tag) +} + +// FetchTags fetches all tags from the remote origin. +// Returns an error if the command fails. +func (api CLI) FetchTags() (err error) { + return api.Commander.Run("git", "fetch", "--tags") +} + +// FetchUnshallow convert a shallow repository to a complete one. +// Returns an error if the command fails. +func (api CLI) FetchUnshallow() (err error) { + return api.Commander.Run("git", "fetch", "--unshallow") +} + +// GetConfig gets the git config for a specific key. +// Returns the value of the git config as a string and an error if the command failed. +func (api CLI) GetConfig(key string) (value string, err error) { + return api.Commander.Output("git", "config", "--get", key) +} + +// GetLatestAnnotatedTag gets the latest annotated git tag. +// Returns the git tag and an error if the command failed. +func (api CLI) GetLatestAnnotatedTag() (tag string, err error) { + return api.Commander.Output("git", "describe", "--tags") +} + +// GetLatestCommitMessage gets the latest git commit message. +// Returns the git commit message or an error if the command failed. +func (api CLI) GetLatestCommitMessage() (message string, err error) { + return api.Commander.Output("git", "--no-pager", "show", "-s", "--format=%s") +} + +// GetMergedBranchName gets the source branch name if the last commit is a merge. +// Returns the branch name or an error if something went wrong with git. +func (api CLI) GetMergedBranchName() (name string, err error) { + return api.Commander.Output( + "git", + "name-rev", + "--name-only", + "--refs=refs/heads/*", + "--refs=refs/remotes/*", + "HEAD^2", + ) +} + +// PushTag pushes a tag to the remote origin. +// Returns an error if the command failed. +func (api CLI) PushTag(tag string) (err error) { + return api.Commander.Run("git", "push", "origin", tag) +} + +// SetConfig sets a git config key and value. +// Returns an error if the command failed. +func (api CLI) SetConfig(key string, value string) (err error) { + return api.Commander.Run("git", "config", key, value) +} + +// SetConfigIfNotSet sets a git config key and value if the config does not exist. +// Returns an error if the command failed. +func (api CLI) SetConfigIfNotSet(key string, value string) (err error) { + if _, err = api.GetConfig(key); err != nil { + err = api.SetConfig(key, value) + } + + return err +} diff --git a/pkg/modes/gitbranch.go b/pkg/modes/gitbranch.go index 8c94b5a..472b5ff 100644 --- a/pkg/modes/gitbranch.go +++ b/pkg/modes/gitbranch.go @@ -21,7 +21,7 @@ type GitBranchMode struct { // NewGitBranchMode creates a new GitBranchMode. // Returns the new GitBranchMode. func NewGitBranchMode(delimiters string, semverMap SemverMap) GitBranchMode { - return GitBranchMode{Delimiters: delimiters, GitAPI: git.NewCommandAPI(), SemverMap: semverMap} + return GitBranchMode{Delimiters: delimiters, GitAPI: git.NewCLI(), SemverMap: semverMap} } // Increment increments the semver level based on the naming of the source branch of a git merge. diff --git a/pkg/modes/gitcommit.go b/pkg/modes/gitcommit.go index aca1888..e9e7c84 100644 --- a/pkg/modes/gitcommit.go +++ b/pkg/modes/gitcommit.go @@ -21,7 +21,7 @@ type GitCommitMode struct { // NewGitCommitMode creates a new GitCommitMode. // Returns the new GitCommitMode. func NewGitCommitMode(delimiters string, semverMap SemverMap) GitCommitMode { - return GitCommitMode{Delimiters: delimiters, GitAPI: git.NewCommandAPI(), SemverMap: semverMap} + return GitCommitMode{Delimiters: delimiters, GitAPI: git.NewCLI(), SemverMap: semverMap} } // Increment increments a given version based on the latest git commit message. diff --git a/pkg/modes/gitcommit_test.go b/pkg/modes/gitcommit_test.go index 85b51e8..1b4f76a 100644 --- a/pkg/modes/gitcommit_test.go +++ b/pkg/modes/gitcommit_test.go @@ -102,7 +102,7 @@ func TestGitCommitMode_Increment(t *testing.T) { cmder.On("Output", mock.Anything, mock.Anything).Return(test.Message, nil) var gitCommitMode = NewGitCommitMode("[]", semverMap) - gitCommitMode.GitAPI = git.CommandAPI{Commander: cmder} + gitCommitMode.GitAPI = git.CLI{Commander: cmder} var got, err = gitCommitMode.Increment(test.Version) assert.NoError(t, err) @@ -131,7 +131,7 @@ func TestGitCommitMode_Increment(t *testing.T) { cmder.On("Output", mock.Anything, mock.Anything).Return(test.Message, test.GitError) var gitCommitMode = NewGitCommitMode("[]", semverMap) - gitCommitMode.GitAPI = git.CommandAPI{Commander: cmder} + gitCommitMode.GitAPI = git.CLI{Commander: cmder} var _, err = gitCommitMode.Increment(test.Version) assert.Error(t, err) diff --git a/pkg/versions/api.go b/pkg/versions/api.go index 740b25f..9261e81 100644 --- a/pkg/versions/api.go +++ b/pkg/versions/api.go @@ -14,7 +14,7 @@ type API struct { // NewAPI creates a new version API. // Returns the new API. func NewAPI() API { - return API{GitAPI: git.NewCommandAPI()} + return API{GitAPI: git.NewCLI()} } // GetVersion gets the current version by getting the latest annotated git tag. diff --git a/pkg/versions/api_test.go b/pkg/versions/api_test.go index 3e41c30..61b29fc 100644 --- a/pkg/versions/api_test.go +++ b/pkg/versions/api_test.go @@ -29,7 +29,7 @@ func TestAPI_GetVersion(t *testing.T) { var cmder = mocks.NewMockCommander() cmder.On("Output", mock.Anything, mock.Anything).Return(test.Version, nil) - var gitAPI = git.CommandAPI{Commander: cmder} + var gitAPI = git.CLI{Commander: cmder} var versionAPI = API{GitAPI: gitAPI} var got, err = versionAPI.GetVersion() @@ -53,7 +53,7 @@ func TestAPI_GetVersion(t *testing.T) { var cmder = mocks.NewMockCommander() cmder.On("Output", mock.Anything, mock.Anything).Return("", test.Error) - var gitAPI = git.CommandAPI{Commander: cmder} + var gitAPI = git.CLI{Commander: cmder} var versionAPI = API{GitAPI: gitAPI} var _, got = versionAPI.GetVersion() @@ -78,7 +78,7 @@ func TestAPI_GetVersionOrDefault(t *testing.T) { var cmder = mocks.NewMockCommander() cmder.On("Output", mock.Anything, mock.Anything).Return(test.Version, nil) - var gitAPI = git.CommandAPI{Commander: cmder} + var gitAPI = git.CLI{Commander: cmder} var versionAPI = API{GitAPI: gitAPI} var got, err = versionAPI.GetVersion() @@ -102,7 +102,7 @@ func TestAPI_GetVersionOrDefault(t *testing.T) { var cmder = mocks.NewMockCommander() cmder.On("Output", mock.Anything, mock.Anything).Return("", test.Error) - var gitAPI = git.CommandAPI{Commander: cmder} + var gitAPI = git.CLI{Commander: cmder} var versionAPI = API{GitAPI: gitAPI} var got = versionAPI.GetVersionOrDefault(cli.DefaultVersion) @@ -131,7 +131,7 @@ func TestAPI_PredictVersion(t *testing.T) { var cmder = mocks.NewMockCommander() cmder.On("Output", mock.Anything, mock.Anything).Return(test.Version, nil) - var gitAPI = git.CommandAPI{Commander: cmder} + var gitAPI = git.CLI{Commander: cmder} var versionAPI = API{GitAPI: gitAPI} var got, err = versionAPI.PredictVersion(test.Version, test.Mode) @@ -209,7 +209,7 @@ func TestAPI_PushVersion(t *testing.T) { var cmder = mocks.NewMockCommander() cmder.On("Run", mock.Anything, mock.Anything).Return(test.Error) - var gitAPI = git.CommandAPI{Commander: cmder} + var gitAPI = git.CLI{Commander: cmder} var versionAPI = API{GitAPI: gitAPI} var got = versionAPI.PushVersion("0.0.1", "v") @@ -263,7 +263,7 @@ func TestAPI_ReleaseVersion(t *testing.T) { var cmder = mocks.NewMockCommander() cmder.On("Run", mock.Anything, mock.Anything).Return(test.Error) - var gitAPI = git.CommandAPI{Commander: cmder} + var gitAPI = git.CLI{Commander: cmder} var versionAPI = API{GitAPI: gitAPI} var got = versionAPI.ReleaseVersion("0.0.1", "v") @@ -289,7 +289,7 @@ func TestAPI_UpdateVersion(t *testing.T) { var cmder = mocks.NewMockCommander() cmder.On("Run", mock.Anything, mock.Anything).Return(test.Error) - var gitAPI = git.CommandAPI{Commander: cmder} + var gitAPI = git.CLI{Commander: cmder} var versionAPI = API{GitAPI: gitAPI} var got = versionAPI.UpdateVersion() From bef8a40c2852ff1f0a32750d32f74146b7d3df54 Mon Sep 17 00:00:00 2001 From: shiouen Date: Sat, 20 Nov 2021 23:28:25 +0100 Subject: [PATCH 38/54] small doc update --- pkg/git/cli.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/git/cli.go b/pkg/git/cli.go index ed4f585..b82644d 100644 --- a/pkg/git/cli.go +++ b/pkg/git/cli.go @@ -2,7 +2,7 @@ package git import "github.com/restechnica/semverbot/internal/commands" -// CLI an CLI to interact with the git CLI. +// CLI a git.API to interact with the git CLI. type CLI struct { Commander commands.Commander } From 063946b90dcadbea5d935773b6d26d26fd3a5912 Mon Sep 17 00:00:00 2001 From: shiouen Date: Sat, 20 Nov 2021 23:49:02 +0100 Subject: [PATCH 39/54] added CommandError tests - added NewCommandError function --- internal/commands/error.go | 14 +++++++++++-- internal/commands/error_test.go | 35 +++++++++++++++++++++++++++++++++ internal/commands/exec.go | 2 +- 3 files changed, 48 insertions(+), 3 deletions(-) create mode 100644 internal/commands/error_test.go diff --git a/internal/commands/error.go b/internal/commands/error.go index f88c621..f29dae4 100644 --- a/internal/commands/error.go +++ b/internal/commands/error.go @@ -4,12 +4,22 @@ import ( "fmt" ) +var CommandErrorTemplate = "command %s exited with %s, output: \n%s" + type CommandError struct { Arguments []string - Output string Err error + Output string +} + +func NewCommandError(arguments []string, output string, err error) CommandError { + return CommandError{ + Arguments: arguments, + Err: err, + Output: output, + } } func (e CommandError) Error() string { - return fmt.Sprintf("command %s exited with %s, output: \n%s", e.Arguments, e.Err.Error(), e.Output) + return fmt.Sprintf(CommandErrorTemplate, e.Arguments, e.Err.Error(), e.Output) } diff --git a/internal/commands/error_test.go b/internal/commands/error_test.go new file mode 100644 index 0000000..74eb838 --- /dev/null +++ b/internal/commands/error_test.go @@ -0,0 +1,35 @@ +package commands + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestCommandError_Error(t *testing.T) { + t.Run("ValidateMessage", func(t *testing.T) { + var args = []string{"some", "command", "arguments"} + var err = fmt.Errorf("some-error") + var output = "some-output" + + var want = fmt.Sprintf(CommandErrorTemplate, args, err, output) + + var cmdError = CommandError{Arguments: args, Err: err, Output: output}.Error() + assert.Equal(t, want, cmdError, `want: "%s", got: "%s"`, want, cmdError) + }) +} + +func TestNewCommandError(t *testing.T) { + t.Run("ValidateState", func(t *testing.T) { + var args = []string{"some", "command", "arguments"} + var err = fmt.Errorf("some-error") + var output = "some-output" + + var cmdError = NewCommandError(args, output, err) + + assert.Equal(t, args, cmdError.Arguments, `want: "%s", got: "%s"`, args, cmdError.Arguments) + assert.Equal(t, err, cmdError.Err, `want: "%s", got: "%s"`, err, cmdError.Err) + assert.Equal(t, output, cmdError.Output, `want: "%s", got: "%s"`, output, cmdError.Output) + }) +} diff --git a/internal/commands/exec.go b/internal/commands/exec.go index e4b1bac..a97f59d 100644 --- a/internal/commands/exec.go +++ b/internal/commands/exec.go @@ -28,7 +28,7 @@ func (c ExecCommander) Output(name string, arg ...string) (string, error) { var output = buffer.String() if err != nil { - return "", CommandError{Arguments: command.Args, Err: err, Output: output} + return "", NewCommandError(command.Args, output, err) } return output, err From 5adf695e9fde702d108a5d97439bc1983a75ccfd Mon Sep 17 00:00:00 2001 From: shiouen Date: Sun, 21 Nov 2021 00:18:24 +0100 Subject: [PATCH 40/54] added util string tests --- internal/util/strings.go | 18 +++---- internal/util/strings_test.go | 88 +++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 9 deletions(-) create mode 100644 internal/util/strings_test.go diff --git a/internal/util/strings.go b/internal/util/strings.go index a735118..8a33eb4 100644 --- a/internal/util/strings.go +++ b/internal/util/strings.go @@ -2,6 +2,12 @@ package util import "strings" +// Contains returns true if a string, split by delimiters, contains another string. +func Contains(target string, value string, delimiters string) bool { + var slice = SplitByDelimiterString(target, delimiters) + return SliceContainsString(slice, value) +} + // SplitByDelimiterString splits a string by multiple delimiters. // Returns the resulting slice of strings. func SplitByDelimiterString(target string, delimiters string) []string { @@ -18,17 +24,11 @@ func SplitByDelimiterString(target string, delimiters string) []string { } // SliceContainsString returns true if a string equals an element in the slice. -func SliceContainsString(container []string, value string) bool { - for _, contained := range container { - if contained == value { +func SliceContainsString(slice []string, value string) bool { + for _, element := range slice { + if element == value { return true } } return false } - -// Contains returns true if a string, split by delimiters, contains another string. -func Contains(target string, value string, delimiters string) bool { - var slice = SplitByDelimiterString(target, delimiters) - return SliceContainsString(slice, value) -} diff --git a/internal/util/strings_test.go b/internal/util/strings_test.go new file mode 100644 index 0000000..21da979 --- /dev/null +++ b/internal/util/strings_test.go @@ -0,0 +1,88 @@ +package util + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +/* +func Contains(target string, value string, delimiters string) bool { + var slice = SplitByDelimiterString(target, delimiters) + return SliceContainsString(slice, value) +} +*/ +func TestContains(t *testing.T) { + type Test struct { + Delimiters string + Name string + TargetString string + Value string + Want bool + } + + var tests = []Test{ + {Name: "EmptyDelimiters", Delimiters: "", TargetString: "some-value", Value: "value", Want: false}, + {Name: "EmptyTargetString", Delimiters: "-", TargetString: "", Value: "value", Want: false}, + {Name: "EmptyValue", Delimiters: "/", TargetString: "some/string", Value: "", Want: false}, + {Name: "IncorrectDelimiters", Delimiters: "/", TargetString: "some-value", Value: "value", Want: false}, + {Name: "OneDelimiterButWrongLocation", Delimiters: "/", TargetString: "some/feature [test]", Value: "feature", Want: false}, + {Name: "OneDelimiterButCorrectLocation", Delimiters: "/", TargetString: "some/feature/ [test]", Value: "feature", Want: true}, + {Name: "MultipleDelimiters", Delimiters: "/[]", TargetString: "some/feature [test]", Value: "test", Want: true}, + } + + for _, test := range tests { + t.Run(test.Name, func(t *testing.T) { + var got = Contains(test.TargetString, test.Value, test.Delimiters) + assert.Equal(t, test.Want, got, `want: "%s, got: "%s"`, test.Want, got) + }) + } +} + +func TestSplitByDelimiterString(t *testing.T) { + type Test struct { + Delimiters string + Name string + TargetString string + Want []string + } + + var tests = []Test{ + {Name: "EmptyDelimiters", Delimiters: "", TargetString: "some-string", Want: []string{"some-string"}}, + {Name: "EmptyTargetString", Delimiters: "/", TargetString: "", Want: []string{}}, + {Name: "IncorrectDelimiters", Delimiters: "/", TargetString: "some-string", Want: []string{"some-string"}}, + {Name: "OneDelimiter", Delimiters: "/", TargetString: "some/feature [test]", Want: []string{"some", "feature [test]"}}, + {Name: "MultipleDelimiters", Delimiters: "/[]", TargetString: "some/feature [test]", Want: []string{"some", "feature ", "test"}}, + } + + for _, test := range tests { + t.Run(test.Name, func(t *testing.T) { + var got = SplitByDelimiterString(test.TargetString, test.Delimiters) + assert.Equal(t, test.Want, got, `want: "%s, got: "%s"`, test.Want, got) + }) + } +} + +func TestSliceContainsString(t *testing.T) { + type Test struct { + Name string + Slice []string + Value string + Want bool + } + + var tests = []Test{ + {Name: "EmptySlice", Slice: []string{}, Value: "test", Want: false}, + {Name: "EmptyValue", Slice: []string{"test"}, Value: "", Want: false}, + {Name: "OneSliceElementWithValue", Slice: []string{"test"}, Value: "test", Want: true}, + {Name: "MultipleSliceElementsWithValue", Slice: []string{"one", "test", "two"}, Value: "test", Want: true}, + {Name: "OneSliceElementWithoutValue", Slice: []string{"without"}, Value: "test", Want: false}, + {Name: "MultipleElementWithoutValue", Slice: []string{"without", "with", "out"}, Value: "test", Want: false}, + } + + for _, test := range tests { + t.Run(test.Name, func(t *testing.T) { + var got = SliceContainsString(test.Slice, test.Value) + assert.Equal(t, test.Want, got, `want: "%s, got: "%s"`, test.Want, got) + }) + } +} From a17641b8a9ebbde0c0f4dadfa00655a0cfb426fe Mon Sep 17 00:00:00 2001 From: shiouen Date: Sun, 21 Nov 2021 00:20:11 +0100 Subject: [PATCH 41/54] removed unnecessary doc --- internal/util/strings_test.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/internal/util/strings_test.go b/internal/util/strings_test.go index 21da979..80d3670 100644 --- a/internal/util/strings_test.go +++ b/internal/util/strings_test.go @@ -5,12 +5,6 @@ import ( "testing" ) -/* -func Contains(target string, value string, delimiters string) bool { - var slice = SplitByDelimiterString(target, delimiters) - return SliceContainsString(slice, value) -} -*/ func TestContains(t *testing.T) { type Test struct { Delimiters string From 17dbf1e233c8d2a9a0003242961a817e38dff627 Mon Sep 17 00:00:00 2001 From: shiouen Date: Sun, 21 Nov 2021 00:24:14 +0100 Subject: [PATCH 42/54] test renaming --- internal/util/strings_test.go | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/internal/util/strings_test.go b/internal/util/strings_test.go index 80d3670..700e2f7 100644 --- a/internal/util/strings_test.go +++ b/internal/util/strings_test.go @@ -15,13 +15,14 @@ func TestContains(t *testing.T) { } var tests = []Test{ - {Name: "EmptyDelimiters", Delimiters: "", TargetString: "some-value", Value: "value", Want: false}, - {Name: "EmptyTargetString", Delimiters: "-", TargetString: "", Value: "value", Want: false}, - {Name: "EmptyValue", Delimiters: "/", TargetString: "some/string", Value: "", Want: false}, - {Name: "IncorrectDelimiters", Delimiters: "/", TargetString: "some-value", Value: "value", Want: false}, - {Name: "OneDelimiterButWrongLocation", Delimiters: "/", TargetString: "some/feature [test]", Value: "feature", Want: false}, - {Name: "OneDelimiterButCorrectLocation", Delimiters: "/", TargetString: "some/feature/ [test]", Value: "feature", Want: true}, - {Name: "MultipleDelimiters", Delimiters: "/[]", TargetString: "some/feature [test]", Value: "test", Want: true}, + {Name: "EmptyDelimitersReturnsFalse", Delimiters: "", TargetString: "some-value", Value: "value", Want: false}, + {Name: "EmptyTargetStringWithNonEmptyValueReturnsFalse", Delimiters: "-", TargetString: "", Value: "value", Want: false}, + {Name: "EmptyTargetStringWithEmptyValueReturnsFalse", Delimiters: "-", TargetString: "", Value: "", Want: false}, + {Name: "EmptyValueReturnsFalse", Delimiters: "/", TargetString: "some/string", Value: "", Want: false}, + {Name: "IncorrectDelimitersReturnsFalse", Delimiters: "/", TargetString: "some-value", Value: "value", Want: false}, + {Name: "OneDelimiterButWrongLocationReturnsFalse", Delimiters: "/", TargetString: "some/feature [test]", Value: "feature", Want: false}, + {Name: "OneDelimiterButCorrectLocationReturnsTrue", Delimiters: "/", TargetString: "some/feature/ [test]", Value: "feature", Want: true}, + {Name: "MultipleDelimitersReturnsTrue", Delimiters: "/[]", TargetString: "some/feature [test]", Value: "test", Want: true}, } for _, test := range tests { From 1a4f3b334f76eb9943b2beabb70496be81fcf6f1 Mon Sep 17 00:00:00 2001 From: shiouen Date: Sun, 21 Nov 2021 01:18:55 +0100 Subject: [PATCH 43/54] added git cli tests --- pkg/git/cli_test.go | 197 +++++++++++++++++++++++++++++++++++++++ pkg/versions/api_test.go | 5 + 2 files changed, 202 insertions(+) create mode 100644 pkg/git/cli_test.go diff --git a/pkg/git/cli_test.go b/pkg/git/cli_test.go new file mode 100644 index 0000000..78987b9 --- /dev/null +++ b/pkg/git/cli_test.go @@ -0,0 +1,197 @@ +package git + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + + "github.com/restechnica/semverbot/internal/mocks" +) + +func TestCLI_CreateAnnotatedTag(t *testing.T) { + t.Run("ReturnErrorOnCommanderError", func(t *testing.T) { + var want = fmt.Errorf("some-error") + + var cmder = mocks.NewMockCommander() + cmder.On("Run", mock.Anything, mock.Anything).Return(want) + + var gitCLI = CLI{Commander: cmder} + var got = gitCLI.CreateAnnotatedTag("0.0.0") + + assert.Error(t, got) + assert.Equal(t, want, got, `want: "%s, got: "%s"`, want, got) + }) +} + +func TestCLI_FetchTags(t *testing.T) { + t.Run("ReturnErrorOnCommanderError", func(t *testing.T) { + var want = fmt.Errorf("some-error") + + var cmder = mocks.NewMockCommander() + cmder.On("Run", mock.Anything, mock.Anything).Return(want) + + var gitCLI = CLI{Commander: cmder} + var got = gitCLI.FetchTags() + + assert.Error(t, got) + assert.Equal(t, want, got, `want: "%s, got: "%s"`, want, got) + }) +} + +func TestCLI_FetchUnshallow(t *testing.T) { + t.Run("ReturnErrorOnCommanderError", func(t *testing.T) { + var want = fmt.Errorf("some-error") + + var cmder = mocks.NewMockCommander() + cmder.On("Run", mock.Anything, mock.Anything).Return(want) + + var gitCLI = CLI{Commander: cmder} + var got = gitCLI.FetchUnshallow() + + assert.Error(t, got) + assert.Equal(t, want, got, `want: "%s, got: "%s"`, want, got) + }) +} + +func TestCLI_GetConfig(t *testing.T) { + t.Run("ReturnErrorOnCommanderError", func(t *testing.T) { + var want = fmt.Errorf("some-error") + + var cmder = mocks.NewMockCommander() + cmder.On("Output", mock.Anything, mock.Anything).Return("value", want) + + var gitCLI = CLI{Commander: cmder} + var _, got = gitCLI.GetConfig("key") + + assert.Error(t, got) + assert.Equal(t, want, got, `want: "%s, got: "%s"`, want, got) + }) +} + +func TestCLI_GetLatestAnnotatedTag(t *testing.T) { + t.Run("ReturnErrorOnCommanderError", func(t *testing.T) { + var want = fmt.Errorf("some-error") + + var cmder = mocks.NewMockCommander() + cmder.On("Output", mock.Anything, mock.Anything).Return("value", want) + + var gitCLI = CLI{Commander: cmder} + var _, got = gitCLI.GetLatestAnnotatedTag() + + assert.Error(t, got) + assert.Equal(t, want, got, `want: "%s, got: "%s"`, want, got) + }) +} + +func TestCLI_GetLatestCommitMessage(t *testing.T) { + t.Run("ReturnErrorOnCommanderError", func(t *testing.T) { + var want = fmt.Errorf("some-error") + + var cmder = mocks.NewMockCommander() + cmder.On("Output", mock.Anything, mock.Anything).Return("value", want) + + var gitCLI = CLI{Commander: cmder} + var _, got = gitCLI.GetLatestCommitMessage() + + assert.Error(t, got) + assert.Equal(t, want, got, `want: "%s, got: "%s"`, want, got) + }) +} + +func TestCLI_GetMergedBranchName(t *testing.T) { + t.Run("ReturnErrorOnCommanderError", func(t *testing.T) { + var want = fmt.Errorf("some-error") + + var cmder = mocks.NewMockCommander() + cmder.On("Output", mock.Anything, mock.Anything).Return("value", want) + + var gitCLI = CLI{Commander: cmder} + var _, got = gitCLI.GetMergedBranchName() + + assert.Error(t, got) + assert.Equal(t, want, got, `want: "%s, got: "%s"`, want, got) + }) +} + +func TestCLI_PushTag(t *testing.T) { + t.Run("ReturnErrorOnCommanderError", func(t *testing.T) { + var want = fmt.Errorf("some-error") + + var cmder = mocks.NewMockCommander() + cmder.On("Run", mock.Anything, mock.Anything).Return(want) + + var gitCLI = CLI{Commander: cmder} + var got = gitCLI.PushTag("tag") + + assert.Error(t, got) + assert.Equal(t, want, got, `want: "%s, got: "%s"`, want, got) + }) +} + +func TestCLI_SetConfig(t *testing.T) { + t.Run("ReturnErrorOnCommanderError", func(t *testing.T) { + var want = fmt.Errorf("some-error") + + var cmder = mocks.NewMockCommander() + cmder.On("Run", mock.Anything, mock.Anything).Return(want) + + var gitCLI = CLI{Commander: cmder} + var got = gitCLI.SetConfig("key", "value") + + assert.Error(t, got) + assert.Equal(t, want, got, `want: "%s, got: "%s"`, want, got) + }) +} + +func TestCLI_SetConfigIfNotSet(t *testing.T) { + t.Run("DoNotSetConfigIfConfigExists", func(t *testing.T) { + var cmder = mocks.NewMockCommander() + cmder.On("Output", mock.Anything, mock.Anything).Return("value", nil) + + var gitCLI = CLI{Commander: cmder} + var got = gitCLI.SetConfigIfNotSet("key", "value") + + cmder.AssertCalled(t, "Output", mock.Anything, mock.Anything) + cmder.AssertNotCalled(t, "Run", mock.Anything, mock.Anything) + assert.NoError(t, got) + assert.Equal(t, nil, got, `want: "%s, got: "%s"`, nil, got) + }) + + t.Run("SetConfigIfConfigDoesNotExist", func(t *testing.T) { + var cmder = mocks.NewMockCommander() + cmder.On("Output", mock.Anything, mock.Anything).Return("value", fmt.Errorf("some-error")) + cmder.On("Run", mock.Anything, mock.Anything).Return(nil) + + var gitCLI = CLI{Commander: cmder} + var got = gitCLI.SetConfigIfNotSet("key", "value") + + cmder.AssertCalled(t, "Output", mock.Anything, mock.Anything) + cmder.AssertCalled(t, "Run", mock.Anything, mock.Anything) + assert.NoError(t, got) + assert.Equal(t, nil, got, `want: "%s, got: "%s"`, nil, got) + }) + + t.Run("ReturnErrorOnSetConfigError", func(t *testing.T) { + var want = fmt.Errorf("some-error") + + var cmder = mocks.NewMockCommander() + cmder.On("Output", mock.Anything, mock.Anything).Return("value", fmt.Errorf("some-error")) + cmder.On("Run", mock.Anything, mock.Anything).Return(fmt.Errorf("some-error")) + + var gitCLI = CLI{Commander: cmder} + var got = gitCLI.SetConfigIfNotSet("key", "value") + + assert.Error(t, got) + assert.Equal(t, want, got, `want: "%s, got: "%s"`, want, got) + }) +} + +func TestNewCLI(t *testing.T) { + t.Run("ValidateState", func(t *testing.T) { + var cli = NewCLI() + assert.NotNil(t, cli) + assert.NotNil(t, cli.Commander) + }) +} diff --git a/pkg/versions/api_test.go b/pkg/versions/api_test.go index 61b29fc..9ed43db 100644 --- a/pkg/versions/api_test.go +++ b/pkg/versions/api_test.go @@ -59,6 +59,7 @@ func TestAPI_GetVersion(t *testing.T) { var _, got = versionAPI.GetVersion() assert.Error(t, got) + assert.Equal(t, test.Error, got, `want: "%s, got: "%s"`, test.Error, got) }) } } @@ -161,6 +162,7 @@ func TestAPI_PredictVersion(t *testing.T) { var _, got = versionAPI.PredictVersion("0.0.0", mode) assert.Error(t, got) + assert.Equal(t, test.Error, got, `want: "%s, got: "%s"`, test.Error, got) }) } } @@ -215,6 +217,7 @@ func TestAPI_PushVersion(t *testing.T) { var got = versionAPI.PushVersion("0.0.1", "v") assert.Error(t, got) + assert.Equal(t, test.Error, got, `want: "%s, got: "%s"`, test.Error, got) }) } } @@ -269,6 +272,7 @@ func TestAPI_ReleaseVersion(t *testing.T) { var got = versionAPI.ReleaseVersion("0.0.1", "v") assert.Error(t, got) + assert.Equal(t, test.Error, got, `want: "%s, got: "%s"`, test.Error, got) }) } } @@ -295,6 +299,7 @@ func TestAPI_UpdateVersion(t *testing.T) { var got = versionAPI.UpdateVersion() assert.Error(t, got) + assert.Equal(t, test.Error, got, `want: "%s, got: "%s"`, test.Error, got) }) } } From 17fa1109a52ebd9c48d0a11a53fd0559ccf3e22d Mon Sep 17 00:00:00 2001 From: shiouen Date: Sun, 21 Nov 2021 01:20:54 +0100 Subject: [PATCH 44/54] removed some commented tests --- pkg/modes/major_test.go | 1 - pkg/modes/minor_test.go | 1 - pkg/modes/patch_test.go | 1 - 3 files changed, 3 deletions(-) diff --git a/pkg/modes/major_test.go b/pkg/modes/major_test.go index 64e99eb..85d91c6 100644 --- a/pkg/modes/major_test.go +++ b/pkg/modes/major_test.go @@ -47,7 +47,6 @@ func TestMajorMode_Increment(t *testing.T) { var errorTests = []ErrorTest{ {Name: "ReturnErrorOnInvalidTargetVersion", TargetVersion: "invalid"}, - //{Name: "ReturnErrorOnInvalidCharacter", TargetVersion: "v1.2.3"}, } for _, test := range errorTests { diff --git a/pkg/modes/minor_test.go b/pkg/modes/minor_test.go index b3d25dd..5b0e5e9 100644 --- a/pkg/modes/minor_test.go +++ b/pkg/modes/minor_test.go @@ -47,7 +47,6 @@ func TestMinorMode_Increment(t *testing.T) { var errorTests = []ErrorTest{ {Name: "ReturnErrorOnInvalidTargetVersion", TargetVersion: "invalid"}, - //{Name: "ReturnErrorOnInvalidCharacter", TargetVersion: "v1.2.3"}, } for _, test := range errorTests { diff --git a/pkg/modes/patch_test.go b/pkg/modes/patch_test.go index 989aba6..45701c3 100644 --- a/pkg/modes/patch_test.go +++ b/pkg/modes/patch_test.go @@ -46,7 +46,6 @@ func TestPatchMode_Increment(t *testing.T) { var errorTests = []ErrorTest{ {Name: "ReturnErrorOnInvalidTargetVersion", TargetVersion: "invalid"}, - //{Name: "ReturnErrorOnInvalidCharacter", TargetVersion: "v1.2.3"}, } for _, test := range errorTests { From d9d6dc0bd9919a4aa305237d862c376758edde48 Mon Sep 17 00:00:00 2001 From: shiouen Date: Sun, 21 Nov 2021 02:29:33 +0100 Subject: [PATCH 45/54] added git-branch mode tests - added mock git api for testing - fixed overlooked bug in git branch DetectMode method --- internal/mocks/git.go | 86 +++++++++++++++ internal/util/strings_test.go | 3 +- pkg/modes/auto_test.go | 1 - pkg/modes/gitbranch.go | 8 +- pkg/modes/gitbranch_test.go | 191 ++++++++++++++++++++++++++++++++++ 5 files changed, 282 insertions(+), 7 deletions(-) create mode 100644 internal/mocks/git.go create mode 100644 pkg/modes/gitbranch_test.go diff --git a/internal/mocks/git.go b/internal/mocks/git.go new file mode 100644 index 0000000..4b9ca45 --- /dev/null +++ b/internal/mocks/git.go @@ -0,0 +1,86 @@ +package mocks + +import ( + "github.com/stretchr/testify/mock" +) + +// MockGitAPI a git.API interface mock implementation. +type MockGitAPI struct { + mock.Mock +} + +// NewMockGitAPI creates a new MockGitAPI. +// Returns the new MockGitAPI. +func NewMockGitAPI() *MockGitAPI { + return &MockGitAPI{} +} + +// CreateAnnotatedTag mocks creating a tag. +// Returns a mocked error. +func (mock *MockGitAPI) CreateAnnotatedTag(tag string) (err error) { + args := mock.Called(tag) + return args.Error(0) +} + +// FetchTags mocks fetching tags. +// Returns a mocked error. +func (mock *MockGitAPI) FetchTags() (err error) { + args := mock.Called() + return args.Error(0) +} + +// FetchUnshallow mocks changing to an unshallow repo. +// Returns a mocked error. +func (mock *MockGitAPI) FetchUnshallow() (err error) { + args := mock.Called() + return args.Error(0) +} + +// GetConfig mocks getting a config. +// Returns a mocked config or a mocked error. +func (mock *MockGitAPI) GetConfig(key string) (value string, err error) { + args := mock.Called(key) + return args.String(0), args.Error(1) +} + +// GetLatestAnnotatedTag mocks getting the latest annotated tag. +// Returns a mocked tag or a mocked error. +func (mock *MockGitAPI) GetLatestAnnotatedTag() (tag string, err error) { + args := mock.Called() + return args.String(0), args.Error(1) +} + +// GetLatestCommitMessage mocks getting the latest commit message. +// Returns a mocked commit message or a mocked error. +func (mock *MockGitAPI) GetLatestCommitMessage() (message string, err error) { + args := mock.Called() + return args.String(0), args.Error(1) +} + +// GetMergedBranchName mocks getting a merged branch name. +// Returns a mocked merged branch name or a mocked error. +func (mock *MockGitAPI) GetMergedBranchName() (name string, err error) { + args := mock.Called() + return args.String(0), args.Error(1) +} + +// PushTag pushes a fake tag. +// Returns a mocked error. +func (mock *MockGitAPI) PushTag(tag string) (err error) { + args := mock.Called(tag) + return args.Error(0) +} + +// SetConfig mocks setting a config. +// Returns a mocked error. +func (mock *MockGitAPI) SetConfig(key string, value string) (err error) { + args := mock.Called(key, value) + return args.Error(0) +} + +// SetConfigIfNotSet mocks setting a config if not set. +// Returns a mocked error. +func (mock *MockGitAPI) SetConfigIfNotSet(key string, value string) (err error) { + args := mock.Called(key, value) + return args.Error(0) +} diff --git a/internal/util/strings_test.go b/internal/util/strings_test.go index 700e2f7..a473224 100644 --- a/internal/util/strings_test.go +++ b/internal/util/strings_test.go @@ -1,8 +1,9 @@ package util import ( - "github.com/stretchr/testify/assert" "testing" + + "github.com/stretchr/testify/assert" ) func TestContains(t *testing.T) { diff --git a/pkg/modes/auto_test.go b/pkg/modes/auto_test.go index da54f23..256726f 100644 --- a/pkg/modes/auto_test.go +++ b/pkg/modes/auto_test.go @@ -54,7 +54,6 @@ func TestAutoMode_Increment(t *testing.T) { var errorTests = []ErrorTest{ {Name: "ReturnErrorOnInvalidVersion", Version: "invalid"}, - //{Name: "ReturnErrorOnInvalidCharacter", Version: "v1.0.0"}, // commented due to TolerantParse } for _, test := range errorTests { diff --git a/pkg/modes/gitbranch.go b/pkg/modes/gitbranch.go index 472b5ff..42612bb 100644 --- a/pkg/modes/gitbranch.go +++ b/pkg/modes/gitbranch.go @@ -50,20 +50,18 @@ func (mode GitBranchMode) Increment(targetVersion string) (nextVersion string, e // DetectMode detects the mode (patch, minor, major) based on a git branch name. // Returns the detected mode. -// Currently forces the level to be in a certain position, must change func (mode GitBranchMode) DetectMode(branchName string) (detected Mode, err error) { for key, values := range mode.SemverMap { for _, value := range values { if mode.isMatch(branchName, value) { switch key { case Patch: - detected = NewPatchMode() + return NewPatchMode(), err case Minor: - detected = NewMinorMode() + return NewMinorMode(), err case Major: - detected = NewMajorMode() + return NewMajorMode(), err } - return detected, err } } } diff --git a/pkg/modes/gitbranch_test.go b/pkg/modes/gitbranch_test.go new file mode 100644 index 0000000..05c8e89 --- /dev/null +++ b/pkg/modes/gitbranch_test.go @@ -0,0 +1,191 @@ +package modes + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/restechnica/semverbot/internal/mocks" +) + +func TestGitBranchMode_DetectMode(t *testing.T) { + var semverMap = SemverMap{ + "major": []string{"release"}, + "minor": []string{"feature"}, + "patch": []string{"fix", "bug"}, + } + + type Test struct { + BranchName string + Delimiters string + Name string + SemverMap SemverMap + Want Mode + } + + var tests = []Test{ + {Name: "DetectPatchMode", BranchName: "fix/some-bug", Delimiters: "/", SemverMap: semverMap, Want: NewPatchMode()}, + {Name: "DetectMinorMode", BranchName: "feature/some-bug", Delimiters: "/", SemverMap: semverMap, Want: NewMinorMode()}, + {Name: "DetectMajorMode", BranchName: "release/some-bug", Delimiters: "/", SemverMap: semverMap, Want: NewMajorMode()}, + } + + for _, test := range tests { + t.Run(test.Name, func(t *testing.T) { + var mode = NewGitBranchMode(test.Delimiters, test.SemverMap) + var got, err = mode.DetectMode(test.BranchName) + + assert.NoError(t, err) + assert.IsType(t, test.Want, got, `want: "%s, got: "%s"`, test.Want, got) + }) + } + + type ErrorTest struct { + BranchName string + Delimiters string + Error error + Name string + SemverMap SemverMap + } + + var errorTests = []ErrorTest{ + { + Name: "DetectNothingWithEmptySemverMap", + BranchName: "feature/some-feature", + Delimiters: "/", + Error: fmt.Errorf(`failed to detect mode from git branch name "feature/some-feature" with delimiters "/"`), + SemverMap: SemverMap{}, + }, + { + Name: "DetectNothingWithEmptyDelimiters", + BranchName: "feature/some-feature", + Delimiters: "", + Error: fmt.Errorf(`failed to detect mode from git branch name "feature/some-feature" with delimiters ""`), + SemverMap: semverMap, + }, + { + Name: "DetectNothingWithEmptyBranchName", + BranchName: "", + Delimiters: "/", + Error: fmt.Errorf(`failed to detect mode from git branch name "" with delimiters "/"`), + SemverMap: semverMap, + }, + { + Name: "DetectNothingWithFaultySemverMap", + BranchName: "feature/some-feature", + Delimiters: "/", + Error: fmt.Errorf(`failed to detect mode from git branch name "feature/some-feature" with delimiters "/"`), + SemverMap: SemverMap{ + "mnr": []string{"feature"}, + }, + }, + } + + for _, test := range errorTests { + t.Run(test.Name, func(t *testing.T) { + var mode = NewGitBranchMode(test.Delimiters, test.SemverMap) + var _, got = mode.DetectMode(test.BranchName) + + assert.Error(t, got) + assert.Equal(t, test.Error, got, `want: "%s, got: "%s"`, test.Error, got) + }) + } +} + +func TestGitBranchMode_Increment(t *testing.T) { + type Test struct { + BranchName string + Delimiters string + Name string + SemverMap SemverMap + Version string + Want string + } + + var tests = []Test{ + {Name: "IncrementPatch", BranchName: "fix/some-bug", Delimiters: "/", SemverMap: semverMap, Version: "0.0.0", Want: "0.0.1"}, + {Name: "IncrementMinor", BranchName: "feature/some-bug", Delimiters: "/", SemverMap: semverMap, Version: "0.0.1", Want: "0.1.0"}, + {Name: "IncrementMajor", BranchName: "release/some-bug", Delimiters: "/", SemverMap: semverMap, Version: "0.1.0", Want: "1.0.0"}, + } + + for _, test := range tests { + t.Run(test.Name, func(t *testing.T) { + var gitAPI = mocks.NewMockGitAPI() + gitAPI.On("GetMergedBranchName").Return(test.BranchName, nil) + + var mode = NewGitBranchMode(test.Delimiters, test.SemverMap) + mode.GitAPI = gitAPI + + var got, err = mode.Increment(test.Version) + + assert.NoError(t, err) + assert.IsType(t, test.Want, got, `want: "%s, got: "%s"`, test.Want, got) + }) + } + + t.Run("ReturnErrorOnGitAPIError", func(t *testing.T) { + var want = fmt.Errorf("some-error") + + var gitAPI = mocks.NewMockGitAPI() + gitAPI.On("GetMergedBranchName").Return("", want) + + var mode = NewGitBranchMode("/", semverMap) + mode.GitAPI = gitAPI + + var _, got = mode.Increment("0.0.0") + + assert.Error(t, got) + assert.Equal(t, want, got, `want: "%s, got: "%s"`, want, got) + }) + + t.Run("ReturnErrorIfNoMergeCommit", func(t *testing.T) { + var want = fmt.Errorf("failed to increment version because the latest git commit is not a merge commit") + + var gitAPI = mocks.NewMockGitAPI() + gitAPI.On("GetMergedBranchName").Return("", nil) + + var mode = NewGitBranchMode("/", semverMap) + mode.GitAPI = gitAPI + + var _, got = mode.Increment("0.0.0") + + assert.Error(t, got) + assert.Equal(t, want, got, `want: "%s, got: "%s"`, want, got) + }) + + t.Run("ReturnErrorIfNoMatchingMode", func(t *testing.T) { + var gitAPI = mocks.NewMockGitAPI() + gitAPI.On("GetMergedBranchName").Return("feat/some-feature", nil) + + var mode = NewGitBranchMode("/", semverMap) + mode.GitAPI = gitAPI + + var _, got = mode.Increment("0.0.0") + + assert.Error(t, got) + }) + + t.Run("ReturnErrorIfInvalidVersion", func(t *testing.T) { + var gitAPI = mocks.NewMockGitAPI() + gitAPI.On("GetMergedBranchName").Return("feat/some-feature", nil) + + var mode = NewGitBranchMode("/", semverMap) + mode.GitAPI = gitAPI + + var _, got = mode.Increment("invalid") + + assert.Error(t, got) + }) +} + +func TestNewGitBranchMode(t *testing.T) { + t.Run("ValidateState", func(t *testing.T) { + var delimiters = "/" + var semverMap = SemverMap{} + var mode = NewGitBranchMode(delimiters, semverMap) + + assert.NotNil(t, mode) + assert.NotEmpty(t, mode.Delimiters) + assert.NotNil(t, mode.SemverMap) + }) +} From ec0c0e41ea5742e31ca41daccb7f84bc573baaa4 Mon Sep 17 00:00:00 2001 From: shiouen Date: Sun, 21 Nov 2021 02:59:46 +0100 Subject: [PATCH 46/54] untangled mode api and git modes - created tests for modes api - moved semvermap to its own file --- pkg/core/predict.go | 5 ++- pkg/modes/api.go | 11 +++---- pkg/modes/api_test.go | 62 +++++++++++++++++++++++++++++++++++++ pkg/modes/gitbranch_test.go | 12 +++++-- pkg/modes/gitcommit_test.go | 12 +++---- pkg/modes/semvermap.go | 4 +++ 6 files changed, 89 insertions(+), 17 deletions(-) create mode 100644 pkg/modes/api_test.go create mode 100644 pkg/modes/semvermap.go diff --git a/pkg/core/predict.go b/pkg/core/predict.go index b6d113e..3e1d7b2 100644 --- a/pkg/core/predict.go +++ b/pkg/core/predict.go @@ -17,7 +17,10 @@ type PredictVersionOptions struct { // The modes.SemverMap values will be matched against git information to detect which semver level to increment. // Returns the next version or an error if the prediction failed. func PredictVersion(options *PredictVersionOptions) (prediction string, err error) { - var modeAPI = modes.NewAPI(options.SemverMap, options.GitBranchDelimiters, options.GitCommitDelimiters) + var gitBranchMode = modes.NewGitBranchMode(options.GitBranchDelimiters, options.SemverMap) + var gitCommitMode = modes.NewGitCommitMode(options.GitCommitDelimiters, options.SemverMap) + + var modeAPI = modes.NewAPI(gitBranchMode, gitCommitMode) var mode = modeAPI.SelectMode(options.Mode) var versionAPI = versions.NewAPI() diff --git a/pkg/modes/api.go b/pkg/modes/api.go index 66b80d2..23a9497 100644 --- a/pkg/modes/api.go +++ b/pkg/modes/api.go @@ -1,20 +1,17 @@ package modes -type SemverMap map[string][]string - // API an API to work with different modes. type API struct { GitBranchMode GitBranchMode GitCommitMode GitCommitMode } -// NewAPI creates a new semver mode API with a mode detector to pass -// it on to the different modes that require it. +// NewAPI creates a new semver mode API. // Returns the new API. -func NewAPI(semverMap SemverMap, gitBranchDelimiters string, GitCommitDelimiters string) API { +func NewAPI(gitBranchMode GitBranchMode, gitCommitMode GitCommitMode) API { return API{ - GitBranchMode: NewGitBranchMode(gitBranchDelimiters, semverMap), - GitCommitMode: NewGitCommitMode(GitCommitDelimiters, semverMap), + GitBranchMode: gitBranchMode, + GitCommitMode: gitCommitMode, } } diff --git a/pkg/modes/api_test.go b/pkg/modes/api_test.go new file mode 100644 index 0000000..e595913 --- /dev/null +++ b/pkg/modes/api_test.go @@ -0,0 +1,62 @@ +package modes + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestAPI_SelectMode(t *testing.T) { + var semverMap = SemverMap{ + Patch: {"fix", "bug"}, + Minor: {"feature"}, + Major: {"release"}, + } + + var gitBranchDelimiters = "/" + var gitCommitDelimiters = "[]():" + + type Test struct { + Mode string + Name string + Want Mode + } + + var tests = []Test{ + {Name: "SelectPatchMode", Mode: Patch, Want: NewPatchMode()}, + {Name: "SelectPatchModeIfInvalidMode", Mode: "invalid", Want: NewPatchMode()}, + {Name: "SelectMinorMode", Mode: Minor, Want: NewMinorMode()}, + {Name: "SelectMajorMode", Mode: Major, Want: NewMajorMode()}, + {Name: "SelectAutoMode", Mode: Auto, Want: AutoMode{}}, + {Name: "SelectGitBranchMode", Mode: GitBranch, Want: GitBranchMode{}}, + {Name: "SelectGitCommitMode", Mode: GitCommit, Want: GitCommitMode{}}, + } + + for _, test := range tests { + t.Run(test.Name, func(t *testing.T) { + var gitBranchMode = NewGitBranchMode(gitBranchDelimiters, semverMap) + var gitCommitMode = NewGitCommitMode(gitCommitDelimiters, semverMap) + + var modeAPI = NewAPI(gitBranchMode, gitCommitMode) + var got = modeAPI.SelectMode(test.Mode) + + assert.IsType(t, test.Want, got, `want: "%s, got: "%s"`, test.Want, got) + }) + } +} + +func TestNewAPI(t *testing.T) { + t.Run("ValidateState", func(t *testing.T) { + var gitBranchDelimiters = "/" + var gitCommitDelimiters = "[]" + + var semverMap = SemverMap{} + var gitBranchMode = NewGitBranchMode(gitBranchDelimiters, semverMap) + var gitCommitMode = NewGitCommitMode(gitCommitDelimiters, semverMap) + var modeAPI = NewAPI(gitBranchMode, gitCommitMode) + + assert.NotNil(t, modeAPI) + assert.NotNil(t, modeAPI.GitBranchMode) + assert.NotNil(t, modeAPI.GitCommitMode) + }) +} diff --git a/pkg/modes/gitbranch_test.go b/pkg/modes/gitbranch_test.go index 05c8e89..e856391 100644 --- a/pkg/modes/gitbranch_test.go +++ b/pkg/modes/gitbranch_test.go @@ -11,9 +11,9 @@ import ( func TestGitBranchMode_DetectMode(t *testing.T) { var semverMap = SemverMap{ - "major": []string{"release"}, - "minor": []string{"feature"}, - "patch": []string{"fix", "bug"}, + Patch: {"fix", "bug"}, + Minor: {"feature"}, + Major: {"release"}, } type Test struct { @@ -93,6 +93,12 @@ func TestGitBranchMode_DetectMode(t *testing.T) { } func TestGitBranchMode_Increment(t *testing.T) { + var semverMap = SemverMap{ + Patch: {"fix", "bug"}, + Minor: {"feature"}, + Major: {"release"}, + } + type Test struct { BranchName string Delimiters string diff --git a/pkg/modes/gitcommit_test.go b/pkg/modes/gitcommit_test.go index 1b4f76a..f9f670e 100644 --- a/pkg/modes/gitcommit_test.go +++ b/pkg/modes/gitcommit_test.go @@ -11,12 +11,6 @@ import ( "github.com/restechnica/semverbot/pkg/git" ) -var semverMap = SemverMap{ - Patch: {"fix"}, - Minor: {"feature"}, - Major: {"release"}, -} - func TestGitCommitMode_GitCommitConstant(t *testing.T) { t.Run("CheckConstant", func(t *testing.T) { var want = "git-commit" @@ -78,6 +72,12 @@ func TestGitCommitMode_GitCommitConstant(t *testing.T) { //} func TestGitCommitMode_Increment(t *testing.T) { + var semverMap = SemverMap{ + Patch: {"fix"}, + Minor: {"feature"}, + Major: {"release"}, + } + type Test struct { Message string Name string diff --git a/pkg/modes/semvermap.go b/pkg/modes/semvermap.go new file mode 100644 index 0000000..595d69a --- /dev/null +++ b/pkg/modes/semvermap.go @@ -0,0 +1,4 @@ +package modes + +// SemverMap type to keep things shorter and more readable. +type SemverMap map[string][]string From f186502281ad613f231f44fed70e794cfaa8230e Mon Sep 17 00:00:00 2001 From: shiouen Date: Sun, 21 Nov 2021 03:02:23 +0100 Subject: [PATCH 47/54] added git branch constant test --- pkg/modes/gitbranch_test.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pkg/modes/gitbranch_test.go b/pkg/modes/gitbranch_test.go index e856391..9e8e8ac 100644 --- a/pkg/modes/gitbranch_test.go +++ b/pkg/modes/gitbranch_test.go @@ -9,6 +9,15 @@ import ( "github.com/restechnica/semverbot/internal/mocks" ) +func TestGitBranchMode_GitBranchConstant(t *testing.T) { + t.Run("CheckConstant", func(t *testing.T) { + var want = "git-branch" + var got = GitBranch + + assert.Equal(t, want, got, `want: "%s", got: "%s"`, want, got) + }) +} + func TestGitBranchMode_DetectMode(t *testing.T) { var semverMap = SemverMap{ Patch: {"fix", "bug"}, From 0f73d6af1be2be31be4bd05f5cd8b08c1e3b9848 Mon Sep 17 00:00:00 2001 From: shiouen Date: Sun, 21 Nov 2021 03:19:42 +0100 Subject: [PATCH 48/54] refreshed git commit mode tests --- pkg/modes/gitbranch_test.go | 4 +- pkg/modes/gitcommit_test.go | 237 ++++++++++++++++++++++-------------- 2 files changed, 147 insertions(+), 94 deletions(-) diff --git a/pkg/modes/gitbranch_test.go b/pkg/modes/gitbranch_test.go index 9e8e8ac..64d62e4 100644 --- a/pkg/modes/gitbranch_test.go +++ b/pkg/modes/gitbranch_test.go @@ -85,7 +85,7 @@ func TestGitBranchMode_DetectMode(t *testing.T) { Delimiters: "/", Error: fmt.Errorf(`failed to detect mode from git branch name "feature/some-feature" with delimiters "/"`), SemverMap: SemverMap{ - "mnr": []string{"feature"}, + "mnr": {"feature"}, }, }, } @@ -182,7 +182,7 @@ func TestGitBranchMode_Increment(t *testing.T) { t.Run("ReturnErrorIfInvalidVersion", func(t *testing.T) { var gitAPI = mocks.NewMockGitAPI() - gitAPI.On("GetMergedBranchName").Return("feat/some-feature", nil) + gitAPI.On("GetMergedBranchName").Return("feature/some-feat", nil) var mode = NewGitBranchMode("/", semverMap) mode.GitAPI = gitAPI diff --git a/pkg/modes/gitcommit_test.go b/pkg/modes/gitcommit_test.go index f9f670e..822dae1 100644 --- a/pkg/modes/gitcommit_test.go +++ b/pkg/modes/gitcommit_test.go @@ -2,13 +2,10 @@ package modes import ( "fmt" + "github.com/restechnica/semverbot/internal/mocks" "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - - "github.com/restechnica/semverbot/internal/mocks" - "github.com/restechnica/semverbot/pkg/git" ) func TestGitCommitMode_GitCommitConstant(t *testing.T) { @@ -20,121 +17,177 @@ func TestGitCommitMode_GitCommitConstant(t *testing.T) { }) } -// TODO move to ModeDetector -//func TestGitCommitMode_GetMatchedMode(t *testing.T) { -// type Test struct { -// Message string -// Name string -// Want Mode -// } -// -// var tests = []Test{ -// {Name: "GetPatchModeWithBrackets", Message: "[fix] some message", Want: NewPatchMode()}, -// {Name: "GetPatchModeWithTrailingSlash", Message: "Merged: repo/fix/some-error", Want: NewPatchMode()}, -// {Name: "GetMinorModeWithBrackets", Message: "some [feature] message", Want: NewMinorMode()}, -// {Name: "GetMinorModeWithTrailingSlash", Message: "Merged: repo/feature/some-error", Want: NewMinorMode()}, -// {Name: "GetMajorModeWithBrackets", Message: "some message [release]", Want: NewMajorMode()}, -// {Name: "GetMajorModeWithTrailingSlash", Message: "Merged: repo/release/some-error", Want: NewMajorMode()}, -// } -// -// for _, test := range tests { -// t.Run(test.Name, func(t *testing.T) { -// var want = test.Want -// -// var gitCommitMode = NewGitCommitMode(NewModeDetector(semverMap)) -// var got, err = gitCommitMode.ModeDetector.(test.Message) -// -// assert.NoError(t, err) -// assert.IsType(t, want, got, `want: "%s", got: "%s"`, want, got) -// }) -// } -// -// type ErrorTest struct { -// Message string -// Name string -// } -// -// var errorTests = []ErrorTest{ -// {Name: "ReturnErrorOnUnmatchedMode", Message: "[fix some message"}, -// } -// -// for _, test := range errorTests { -// t.Run(test.Name, func(t *testing.T) { -// var want = fmt.Sprintf(`could not match a mode to the commit message "%s"`, test.Message) -// -// var gitCommitMode = NewGitCommitMode(semverMap) -// var _, err = gitCommitMode.GetMatchedMode(test.Message) -// -// assert.Error(t, err) -// assert.Equal(t, err.Error(), want, `want: "%s", got: "%s"`, want, err.Error()) -// }) -// } -//} - -func TestGitCommitMode_Increment(t *testing.T) { +func TestGitCommitMode_DetectMode(t *testing.T) { var semverMap = SemverMap{ - Patch: {"fix"}, - Minor: {"feature"}, + Patch: {"fix", "bug"}, + Minor: {"feature", "feat"}, Major: {"release"}, } type Test struct { - Message string - Name string - Version string - Want string + CommitMessage string + Delimiters string + Name string + SemverMap SemverMap + Want Mode } var tests = []Test{ - {Name: "IncrementPatchWithBrackets", Message: "[fix] some message", Version: "0.0.0", Want: "0.0.1"}, - //{Name: "IncrementPatchWithTrailingSlash", Message: "Merged: repo/fix/some-error", Version: "0.0.1", Want: "0.0.2"}, - {Name: "IncrementMinorWithBrackets", Message: "some [feature] message", Version: "0.0.0", Want: "0.1.0"}, - //{Name: "IncrementMinorWithTrailingSlash", Message: "Merged: repo/feature/some-error", Version: "0.1.0", Want: "0.2.0"}, - {Name: "IncrementMajorWithBrackets", Message: "some message [release]", Version: "0.0.0", Want: "1.0.0"}, - //{Name: "IncrementMajorWithTrailingSlash", Message: "Merged: repo/release/some-error", Version: "1.0.0", Want: "2.0.0"}, + {Name: "DetectPatchMode", CommitMessage: "[bug] some fix", Delimiters: "[]", SemverMap: semverMap, Want: NewPatchMode()}, + {Name: "DetectPatchMode", CommitMessage: "[fix] some bug", Delimiters: "[]", SemverMap: semverMap, Want: NewPatchMode()}, + {Name: "DetectMinorMode", CommitMessage: "feat(subject): some changes", Delimiters: "():", SemverMap: semverMap, Want: NewMinorMode()}, + {Name: "DetectMinorMode", CommitMessage: "[feature] some changes", Delimiters: "[]", SemverMap: semverMap, Want: NewMinorMode()}, + {Name: "DetectMajorMode", CommitMessage: "release/some-bug", Delimiters: "/", SemverMap: semverMap, Want: NewMajorMode()}, } for _, test := range tests { t.Run(test.Name, func(t *testing.T) { - var want = test.Want - - var cmder = mocks.NewMockCommander() - cmder.On("Output", mock.Anything, mock.Anything).Return(test.Message, nil) - - var gitCommitMode = NewGitCommitMode("[]", semverMap) - gitCommitMode.GitAPI = git.CLI{Commander: cmder} - var got, err = gitCommitMode.Increment(test.Version) + var mode = NewGitBranchMode(test.Delimiters, test.SemverMap) + var got, err = mode.DetectMode(test.CommitMessage) assert.NoError(t, err) - assert.Equal(t, want, got, `want: "%s, got: "%s"`, want, got) + assert.IsType(t, test.Want, got, `want: "%s, got: "%s"`, test.Want, got) }) } type ErrorTest struct { - GitError error - Message string - Name string - Version string + CommitMessage string + Delimiters string + Error error + Name string + SemverMap SemverMap } var errorTests = []ErrorTest{ - {Name: "ReturnErrorOnUnmatchedMode", Message: "[fix some message", Version: "0.0.0", GitError: nil}, - {Name: "ReturnErrorOnInvalidVersion", Message: "[fix] some message", Version: "invalid", GitError: nil}, - //{Name: "ReturnErrorOnInvalidCharacter", Message: "[fix] some message", Version: "v1.0.0", GitError: nil}, // commented out due to TolerantParse - {Name: "ReturnErrorOnGitError", Message: "[fix] some message", Version: "1.0.0", - GitError: fmt.Errorf("some-error")}, + { + Name: "DetectNothingWithEmptySemverMap", + CommitMessage: "[feature] some changes", + Delimiters: "[]", + Error: fmt.Errorf(`failed to detect mode from git branch name "[feature] some changes" with delimiters "[]"`), + SemverMap: SemverMap{}, + }, + { + Name: "DetectNothingWithEmptyDelimiters", + CommitMessage: "[feature] some changes", + Delimiters: "", + Error: fmt.Errorf(`failed to detect mode from git branch name "[feature] some changes" with delimiters ""`), + SemverMap: semverMap, + }, + { + Name: "DetectNothingWithEmptyCommitMessage", + CommitMessage: "", + Delimiters: "/", + Error: fmt.Errorf(`failed to detect mode from git branch name "" with delimiters "/"`), + SemverMap: semverMap, + }, + { + Name: "DetectNothingWithFaultySemverMap", + CommitMessage: "[feature] some changes", + Delimiters: "[]", + Error: fmt.Errorf(`failed to detect mode from git branch name "[feature] some changes" with delimiters "[]"`), + SemverMap: SemverMap{ + "mnr": {"feature"}, + }, + }, } for _, test := range errorTests { t.Run(test.Name, func(t *testing.T) { - var cmder = mocks.NewMockCommander() - cmder.On("Output", mock.Anything, mock.Anything).Return(test.Message, test.GitError) + var mode = NewGitBranchMode(test.Delimiters, test.SemverMap) + var _, got = mode.DetectMode(test.CommitMessage) - var gitCommitMode = NewGitCommitMode("[]", semverMap) - gitCommitMode.GitAPI = git.CLI{Commander: cmder} - var _, err = gitCommitMode.Increment(test.Version) + assert.Error(t, got) + assert.Equal(t, test.Error, got, `want: "%s, got: "%s"`, test.Error, got) + }) + } +} - assert.Error(t, err) +func TestGitCommitMode_Increment(t *testing.T) { + var semverMap = SemverMap{ + Patch: {"fix", "bug"}, + Minor: {"feature"}, + Major: {"release"}, + } + + type Test struct { + CommitMessage string + Delimiters string + Name string + SemverMap SemverMap + Version string + Want string + } + + var tests = []Test{ + {Name: "IncrementPatch", CommitMessage: "[fix] some-bug", Delimiters: "[]", SemverMap: semverMap, Version: "0.0.0", Want: "0.0.1"}, + {Name: "IncrementPatch", CommitMessage: "[fi] some/bug", Delimiters: "/", SemverMap: semverMap, Version: "0.0.0", Want: "0.0.1"}, + {Name: "IncrementMinor", CommitMessage: "[feature] some-feat", Delimiters: "[]", SemverMap: semverMap, Version: "0.0.1", Want: "0.1.0"}, + {Name: "IncrementMajor", CommitMessage: "[release] some-release", Delimiters: "[]", SemverMap: semverMap, Version: "0.1.0", Want: "1.0.0"}, + } + + for _, test := range tests { + t.Run(test.Name, func(t *testing.T) { + var gitAPI = mocks.NewMockGitAPI() + gitAPI.On("GetLatestCommitMessage").Return(test.CommitMessage, nil) + + var mode = NewGitCommitMode(test.Delimiters, test.SemverMap) + mode.GitAPI = gitAPI + + var got, err = mode.Increment(test.Version) + + assert.NoError(t, err) + assert.IsType(t, test.Want, got, `want: "%s, got: "%s"`, test.Want, got) }) } + + t.Run("ReturnErrorOnGitAPIError", func(t *testing.T) { + var want = fmt.Errorf("some-error") + + var gitAPI = mocks.NewMockGitAPI() + gitAPI.On("GetLatestCommitMessage").Return("", want) + + var mode = NewGitCommitMode("[]", semverMap) + mode.GitAPI = gitAPI + + var _, got = mode.Increment("0.0.0") + + assert.Error(t, got) + assert.Equal(t, want, got, `want: "%s, got: "%s"`, want, got) + }) + + t.Run("ReturnErrorIfNoMatchingMode", func(t *testing.T) { + var gitAPI = mocks.NewMockGitAPI() + gitAPI.On("GetLatestCommitMessage").Return("nomatch/some-feature", nil) + + var mode = NewGitCommitMode("/", semverMap) + mode.GitAPI = gitAPI + + var _, got = mode.Increment("0.0.0") + + assert.Error(t, got) + }) + + t.Run("ReturnErrorIfInvalidVersion", func(t *testing.T) { + var gitAPI = mocks.NewMockGitAPI() + gitAPI.On("GetLatestCommitMessage").Return("[feature]some-feature", nil) + + var mode = NewGitCommitMode("[]", semverMap) + mode.GitAPI = gitAPI + + var _, got = mode.Increment("invalid") + + assert.Error(t, got) + }) +} + +func TestNewGitCommitMode(t *testing.T) { + t.Run("ValidateState", func(t *testing.T) { + var delimiters = "[]" + var semverMap = SemverMap{} + var mode = NewGitCommitMode(delimiters, semverMap) + + assert.NotNil(t, mode) + assert.NotEmpty(t, mode.Delimiters) + assert.NotNil(t, mode.SemverMap) + }) } From 40092f3d8f15f03c22b0c3ffeb87d7a07161f618 Mon Sep 17 00:00:00 2001 From: shiouen Date: Sun, 21 Nov 2021 03:20:44 +0100 Subject: [PATCH 49/54] formatting --- pkg/modes/gitcommit_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/modes/gitcommit_test.go b/pkg/modes/gitcommit_test.go index 822dae1..f6de5ed 100644 --- a/pkg/modes/gitcommit_test.go +++ b/pkg/modes/gitcommit_test.go @@ -2,9 +2,10 @@ package modes import ( "fmt" - "github.com/restechnica/semverbot/internal/mocks" "testing" + "github.com/restechnica/semverbot/internal/mocks" + "github.com/stretchr/testify/assert" ) From 37d9ba1ed9057b66cacc019cf7ed5e399133a03c Mon Sep 17 00:00:00 2001 From: Olivier Van Aken Date: Mon, 22 Nov 2021 01:03:25 +0100 Subject: [PATCH 50/54] moved semvermap to semver package - renamed it to just Map --- pkg/cli/commands/root.go | 4 ++-- pkg/core/predict.go | 7 ++++--- pkg/core/release.go | 4 ++-- pkg/modes/api_test.go | 6 ++++-- pkg/modes/gitbranch.go | 5 +++-- pkg/modes/gitbranch_test.go | 17 +++++++++-------- pkg/modes/gitcommit.go | 6 ++++-- pkg/modes/gitcommit_test.go | 18 ++++++++++-------- pkg/modes/semvermap.go | 4 ---- pkg/semver/map.go | 4 ++++ 10 files changed, 42 insertions(+), 33 deletions(-) delete mode 100644 pkg/modes/semvermap.go create mode 100644 pkg/semver/map.go diff --git a/pkg/cli/commands/root.go b/pkg/cli/commands/root.go index f685e1f..db634f6 100644 --- a/pkg/cli/commands/root.go +++ b/pkg/cli/commands/root.go @@ -9,7 +9,7 @@ import ( "github.com/restechnica/semverbot/pkg/cli" "github.com/restechnica/semverbot/pkg/git" - "github.com/restechnica/semverbot/pkg/modes" + "github.com/restechnica/semverbot/pkg/semver" ) // NewRootCommand creates a new root command. @@ -79,7 +79,7 @@ func LoadDefaultConfig() { viper.SetDefault(cli.ModeConfigKey, cli.DefaultMode) viper.SetDefault(cli.ModesGitBranchDelimitersConfigKey, cli.DefaultGitBranchDelimiters) viper.SetDefault(cli.ModesGitCommitDelimitersConfigKey, cli.DefaultGitCommitDelimiters) - viper.SetDefault(cli.SemverMapConfigKey, modes.SemverMap{}) + viper.SetDefault(cli.SemverMapConfigKey, semver.Map{}) } // LoadFlags loads root command flags. diff --git a/pkg/core/predict.go b/pkg/core/predict.go index 3e1d7b2..5c23c63 100644 --- a/pkg/core/predict.go +++ b/pkg/core/predict.go @@ -2,6 +2,7 @@ package core import ( "github.com/restechnica/semverbot/pkg/modes" + "github.com/restechnica/semverbot/pkg/semver" "github.com/restechnica/semverbot/pkg/versions" ) @@ -10,11 +11,11 @@ type PredictVersionOptions struct { GitBranchDelimiters string GitCommitDelimiters string Mode string - SemverMap modes.SemverMap + SemverMap semver.Map } -// PredictVersion predicts a version based on a modes.Mode and a modes.SemverMap. -// The modes.SemverMap values will be matched against git information to detect which semver level to increment. +// PredictVersion predicts a version based on a modes.Mode and a modes.Map. +// The modes.Map values will be matched against git information to detect which semver level to increment. // Returns the next version or an error if the prediction failed. func PredictVersion(options *PredictVersionOptions) (prediction string, err error) { var gitBranchMode = modes.NewGitBranchMode(options.GitBranchDelimiters, options.SemverMap) diff --git a/pkg/core/release.go b/pkg/core/release.go index b5a4f75..6804c83 100644 --- a/pkg/core/release.go +++ b/pkg/core/release.go @@ -1,7 +1,7 @@ package core import ( - "github.com/restechnica/semverbot/pkg/modes" + "github.com/restechnica/semverbot/pkg/semver" "github.com/restechnica/semverbot/pkg/versions" ) @@ -11,7 +11,7 @@ type ReleaseVersionOptions struct { GitBranchDelimiters string GitCommitDelimiters string Mode string - SemverMap modes.SemverMap + SemverMap semver.Map } // ReleaseVersion releases a new version. diff --git a/pkg/modes/api_test.go b/pkg/modes/api_test.go index e595913..642d26e 100644 --- a/pkg/modes/api_test.go +++ b/pkg/modes/api_test.go @@ -4,10 +4,12 @@ import ( "testing" "github.com/stretchr/testify/assert" + + "github.com/restechnica/semverbot/pkg/semver" ) func TestAPI_SelectMode(t *testing.T) { - var semverMap = SemverMap{ + var semverMap = semver.Map{ Patch: {"fix", "bug"}, Minor: {"feature"}, Major: {"release"}, @@ -50,7 +52,7 @@ func TestNewAPI(t *testing.T) { var gitBranchDelimiters = "/" var gitCommitDelimiters = "[]" - var semverMap = SemverMap{} + var semverMap = semver.Map{} var gitBranchMode = NewGitBranchMode(gitBranchDelimiters, semverMap) var gitCommitMode = NewGitCommitMode(gitCommitDelimiters, semverMap) var modeAPI = NewAPI(gitBranchMode, gitCommitMode) diff --git a/pkg/modes/gitbranch.go b/pkg/modes/gitbranch.go index 42612bb..d416c44 100644 --- a/pkg/modes/gitbranch.go +++ b/pkg/modes/gitbranch.go @@ -5,6 +5,7 @@ import ( "github.com/restechnica/semverbot/internal/util" "github.com/restechnica/semverbot/pkg/git" + "github.com/restechnica/semverbot/pkg/semver" ) // GitBranch mode name for GitBranchMode. @@ -15,12 +16,12 @@ const GitBranch = "git-branch" type GitBranchMode struct { Delimiters string GitAPI git.API - SemverMap SemverMap + SemverMap semver.Map } // NewGitBranchMode creates a new GitBranchMode. // Returns the new GitBranchMode. -func NewGitBranchMode(delimiters string, semverMap SemverMap) GitBranchMode { +func NewGitBranchMode(delimiters string, semverMap semver.Map) GitBranchMode { return GitBranchMode{Delimiters: delimiters, GitAPI: git.NewCLI(), SemverMap: semverMap} } diff --git a/pkg/modes/gitbranch_test.go b/pkg/modes/gitbranch_test.go index 64d62e4..764d85e 100644 --- a/pkg/modes/gitbranch_test.go +++ b/pkg/modes/gitbranch_test.go @@ -7,6 +7,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/restechnica/semverbot/internal/mocks" + "github.com/restechnica/semverbot/pkg/semver" ) func TestGitBranchMode_GitBranchConstant(t *testing.T) { @@ -19,7 +20,7 @@ func TestGitBranchMode_GitBranchConstant(t *testing.T) { } func TestGitBranchMode_DetectMode(t *testing.T) { - var semverMap = SemverMap{ + var semverMap = semver.Map{ Patch: {"fix", "bug"}, Minor: {"feature"}, Major: {"release"}, @@ -29,7 +30,7 @@ func TestGitBranchMode_DetectMode(t *testing.T) { BranchName string Delimiters string Name string - SemverMap SemverMap + SemverMap semver.Map Want Mode } @@ -54,7 +55,7 @@ func TestGitBranchMode_DetectMode(t *testing.T) { Delimiters string Error error Name string - SemverMap SemverMap + SemverMap semver.Map } var errorTests = []ErrorTest{ @@ -63,7 +64,7 @@ func TestGitBranchMode_DetectMode(t *testing.T) { BranchName: "feature/some-feature", Delimiters: "/", Error: fmt.Errorf(`failed to detect mode from git branch name "feature/some-feature" with delimiters "/"`), - SemverMap: SemverMap{}, + SemverMap: semver.Map{}, }, { Name: "DetectNothingWithEmptyDelimiters", @@ -84,7 +85,7 @@ func TestGitBranchMode_DetectMode(t *testing.T) { BranchName: "feature/some-feature", Delimiters: "/", Error: fmt.Errorf(`failed to detect mode from git branch name "feature/some-feature" with delimiters "/"`), - SemverMap: SemverMap{ + SemverMap: semver.Map{ "mnr": {"feature"}, }, }, @@ -102,7 +103,7 @@ func TestGitBranchMode_DetectMode(t *testing.T) { } func TestGitBranchMode_Increment(t *testing.T) { - var semverMap = SemverMap{ + var semverMap = semver.Map{ Patch: {"fix", "bug"}, Minor: {"feature"}, Major: {"release"}, @@ -112,7 +113,7 @@ func TestGitBranchMode_Increment(t *testing.T) { BranchName string Delimiters string Name string - SemverMap SemverMap + SemverMap semver.Map Version string Want string } @@ -196,7 +197,7 @@ func TestGitBranchMode_Increment(t *testing.T) { func TestNewGitBranchMode(t *testing.T) { t.Run("ValidateState", func(t *testing.T) { var delimiters = "/" - var semverMap = SemverMap{} + var semverMap = semver.Map{} var mode = NewGitBranchMode(delimiters, semverMap) assert.NotNil(t, mode) diff --git a/pkg/modes/gitcommit.go b/pkg/modes/gitcommit.go index e9e7c84..5fa28fa 100644 --- a/pkg/modes/gitcommit.go +++ b/pkg/modes/gitcommit.go @@ -3,6 +3,8 @@ package modes import ( "fmt" + "github.com/restechnica/semverbot/pkg/semver" + "github.com/restechnica/semverbot/internal/util" "github.com/restechnica/semverbot/pkg/git" ) @@ -15,12 +17,12 @@ const GitCommit = "git-commit" type GitCommitMode struct { Delimiters string GitAPI git.API - SemverMap SemverMap + SemverMap semver.Map } // NewGitCommitMode creates a new GitCommitMode. // Returns the new GitCommitMode. -func NewGitCommitMode(delimiters string, semverMap SemverMap) GitCommitMode { +func NewGitCommitMode(delimiters string, semverMap semver.Map) GitCommitMode { return GitCommitMode{Delimiters: delimiters, GitAPI: git.NewCLI(), SemverMap: semverMap} } diff --git a/pkg/modes/gitcommit_test.go b/pkg/modes/gitcommit_test.go index f6de5ed..8cd8eb1 100644 --- a/pkg/modes/gitcommit_test.go +++ b/pkg/modes/gitcommit_test.go @@ -4,6 +4,8 @@ import ( "fmt" "testing" + "github.com/restechnica/semverbot/pkg/semver" + "github.com/restechnica/semverbot/internal/mocks" "github.com/stretchr/testify/assert" @@ -19,7 +21,7 @@ func TestGitCommitMode_GitCommitConstant(t *testing.T) { } func TestGitCommitMode_DetectMode(t *testing.T) { - var semverMap = SemverMap{ + var semverMap = semver.Map{ Patch: {"fix", "bug"}, Minor: {"feature", "feat"}, Major: {"release"}, @@ -29,7 +31,7 @@ func TestGitCommitMode_DetectMode(t *testing.T) { CommitMessage string Delimiters string Name string - SemverMap SemverMap + SemverMap semver.Map Want Mode } @@ -56,7 +58,7 @@ func TestGitCommitMode_DetectMode(t *testing.T) { Delimiters string Error error Name string - SemverMap SemverMap + SemverMap semver.Map } var errorTests = []ErrorTest{ @@ -65,7 +67,7 @@ func TestGitCommitMode_DetectMode(t *testing.T) { CommitMessage: "[feature] some changes", Delimiters: "[]", Error: fmt.Errorf(`failed to detect mode from git branch name "[feature] some changes" with delimiters "[]"`), - SemverMap: SemverMap{}, + SemverMap: semver.Map{}, }, { Name: "DetectNothingWithEmptyDelimiters", @@ -86,7 +88,7 @@ func TestGitCommitMode_DetectMode(t *testing.T) { CommitMessage: "[feature] some changes", Delimiters: "[]", Error: fmt.Errorf(`failed to detect mode from git branch name "[feature] some changes" with delimiters "[]"`), - SemverMap: SemverMap{ + SemverMap: semver.Map{ "mnr": {"feature"}, }, }, @@ -104,7 +106,7 @@ func TestGitCommitMode_DetectMode(t *testing.T) { } func TestGitCommitMode_Increment(t *testing.T) { - var semverMap = SemverMap{ + var semverMap = semver.Map{ Patch: {"fix", "bug"}, Minor: {"feature"}, Major: {"release"}, @@ -114,7 +116,7 @@ func TestGitCommitMode_Increment(t *testing.T) { CommitMessage string Delimiters string Name string - SemverMap SemverMap + SemverMap semver.Map Version string Want string } @@ -184,7 +186,7 @@ func TestGitCommitMode_Increment(t *testing.T) { func TestNewGitCommitMode(t *testing.T) { t.Run("ValidateState", func(t *testing.T) { var delimiters = "[]" - var semverMap = SemverMap{} + var semverMap = semver.Map{} var mode = NewGitCommitMode(delimiters, semverMap) assert.NotNil(t, mode) diff --git a/pkg/modes/semvermap.go b/pkg/modes/semvermap.go deleted file mode 100644 index 595d69a..0000000 --- a/pkg/modes/semvermap.go +++ /dev/null @@ -1,4 +0,0 @@ -package modes - -// SemverMap type to keep things shorter and more readable. -type SemverMap map[string][]string diff --git a/pkg/semver/map.go b/pkg/semver/map.go new file mode 100644 index 0000000..667a786 --- /dev/null +++ b/pkg/semver/map.go @@ -0,0 +1,4 @@ +package semver + +// Map a type to keep things shorter and more readable. +type Map map[string][]string From 9a220ace67bbae26b9da93ae1ca48c10c31796d6 Mon Sep 17 00:00:00 2001 From: Olivier Van Aken Date: Mon, 22 Nov 2021 02:09:17 +0100 Subject: [PATCH 51/54] refreshed older unit tests in modes package --- pkg/modes/auto_test.go | 68 ++++++++++++++++----------------------- pkg/modes/major_test.go | 71 +++++++++++++++++++---------------------- pkg/modes/minor_test.go | 69 ++++++++++++++++++--------------------- pkg/modes/patch_test.go | 68 ++++++++++++++++++--------------------- 4 files changed, 123 insertions(+), 153 deletions(-) diff --git a/pkg/modes/auto_test.go b/pkg/modes/auto_test.go index 256726f..74d2403 100644 --- a/pkg/modes/auto_test.go +++ b/pkg/modes/auto_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" "github.com/restechnica/semverbot/internal/mocks" ) @@ -19,52 +20,39 @@ func TestAutoMode_AutoConstant(t *testing.T) { } func TestAutoMode_Increment(t *testing.T) { - t.Run("IncrementWithGitCommitMode", func(t *testing.T) { - const target = "0.0.0" - const want = "1.0.0" - - var gitCommitMode = mocks.NewMockMode() - gitCommitMode.On("Increment", target).Return(want, nil) - - var autoMode = NewAutoMode([]Mode{gitCommitMode}) - var got, err = autoMode.Increment(target) - - assert.NoError(t, err) - assert.Equal(t, want, got, `want: "%s", got: "%s"`, want, got) - }) - - t.Run("IncrementWithPatchMode", func(t *testing.T) { - const target = "0.0.0" - const want = "0.0.1" - - var gitCommitMode = mocks.NewMockMode() - gitCommitMode.On("Increment", target).Return("", fmt.Errorf("some-error")) - - var autoMode = NewAutoMode([]Mode{gitCommitMode}) - var got, err = autoMode.Increment(target) - - assert.NoError(t, err) - assert.Equal(t, want, got, `want: "%s", got: "%s"`, want, got) - }) - - type ErrorTest struct { + type Test struct { + Modes []Mode Name string Version string + Want string } - var errorTests = []ErrorTest{ - {Name: "ReturnErrorOnInvalidVersion", Version: "invalid"}, - } + var mockMode = mocks.NewMockMode() + mockMode.On("Increment", mock.Anything).Return("", fmt.Errorf("some-error")) - for _, test := range errorTests { - t.Run(test.Name, func(t *testing.T) { - var gitCommitMode = mocks.NewMockMode() - gitCommitMode.On("Increment", test.Version).Return("", fmt.Errorf("some-error")) + var tests = []Test{ + {Name: "IncrementMajor", Modes: []Mode{NewMajorMode()}, Version: "0.0.0", Want: "1.0.0"}, + {Name: "IncrementMinor", Modes: []Mode{NewMinorMode()}, Version: "0.0.0", Want: "0.1.0"}, + {Name: "IncrementPatch", Modes: []Mode{NewPatchMode()}, Version: "0.0.0", Want: "0.0.1"}, + {Name: "DefaultToPatchIfModeSliceEmpty", Modes: []Mode{}, Version: "0.0.0", Want: "0.0.1"}, + {Name: "IncrementWithSecondModeAfterFirstFailed", Modes: []Mode{mockMode, NewMinorMode()}, Version: "0.0.0", Want: "0.1.0"}, + } - var autoMode = NewAutoMode([]Mode{gitCommitMode}) - var _, err = autoMode.Increment(test.Version) + for _, test := range tests { + var mode = NewAutoMode(test.Modes) + var got, err = mode.Increment(test.Version) - assert.Error(t, err) - }) + assert.NoError(t, err) + assert.IsType(t, test.Want, got, `want: "%s, got: "%s"`, test.Want, got) } } + +func TestNewAutoMode(t *testing.T) { + t.Run("ValidateState", func(t *testing.T) { + var mockMode = mocks.NewMockMode() + var modes = []Mode{mockMode, mockMode, mockMode} + var mode = NewAutoMode(modes) + assert.NotNil(t, mode) + assert.NotEmpty(t, mode.Modes) + }) +} diff --git a/pkg/modes/major_test.go b/pkg/modes/major_test.go index 85d91c6..cf443b5 100644 --- a/pkg/modes/major_test.go +++ b/pkg/modes/major_test.go @@ -6,54 +6,49 @@ import ( "github.com/stretchr/testify/assert" ) -func TestMajorMode_MajorConstant(t *testing.T) { - t.Run("CheckConstant", func(t *testing.T) { - var want = "major" - var got = Major - - assert.Equal(t, want, got, `want: "%s", got: "%s"`, want, got) - }) -} - func TestMajorMode_Increment(t *testing.T) { type Test struct { - Name string - TargetVersion string - Want string + Name string + Version string + Want string } var tests = []Test{ - {Name: "HappyPath", TargetVersion: "1.0.0", Want: "2.0.0"}, - {Name: "ResetPatch", TargetVersion: "7.0.4", Want: "8.0.0"}, - {Name: "ResetMinor", TargetVersion: "6.8.0", Want: "7.0.0"}, - {Name: "DiscardPreBuild", TargetVersion: "2.0.0-pre+001", Want: "3.0.0"}, + {Name: "IncrementMajor", Version: "0.0.0", Want: "1.0.0"}, + {Name: "DiscardPrefix", Version: "v1.0.0", Want: "2.0.0"}, + {Name: "DiscardPrebuild", Version: "2.0.0-pre+001", Want: "3.0.0"}, + {Name: "ResetMinor", Version: "4.5.0", Want: "5.0.0"}, + {Name: "ResetPatch", Version: "3.0.4", Want: "4.0.0"}, + {Name: "ResetPatchAndMinor", Version: "2.1.5", Want: "3.0.0"}, } for _, test := range tests { - t.Run(test.Name, func(t *testing.T) { - var want = test.Want - var mode = NewMajorMode() - var got, err = mode.Increment(test.TargetVersion) - - assert.NoError(t, err) - assert.Equal(t, want, got, `want: %s, got: %s`, want, got) - }) - } + var mode = NewMajorMode() + var got, err = mode.Increment(test.Version) - type ErrorTest struct { - Name string - TargetVersion string + assert.NoError(t, err) + assert.IsType(t, test.Want, got, `want: "%s, got: "%s"`, test.Want, got) } - var errorTests = []ErrorTest{ - {Name: "ReturnErrorOnInvalidTargetVersion", TargetVersion: "invalid"}, - } + t.Run("ReturnErrorOnInvalidVersion", func(t *testing.T) { + var mode = NewMajorMode() + var _, got = mode.Increment("invalid") + assert.Error(t, got) + }) +} - for _, test := range errorTests { - t.Run(test.Name, func(t *testing.T) { - var mode = NewMajorMode() - var _, got = mode.Increment(test.TargetVersion) - assert.Error(t, got) - }) - } +func TestMajorMode_MajorConstant(t *testing.T) { + t.Run("CheckConstant", func(t *testing.T) { + var want = "major" + var got = Major + assert.Equal(t, want, got, `want: "%s", got: "%s"`, want, got) + }) +} + +func TestNewMajorMode(t *testing.T) { + t.Run("ValidateState", func(t *testing.T) { + var mode = NewMajorMode() + assert.NotNil(t, mode) + assert.IsType(t, MajorMode{}, mode) + }) } diff --git a/pkg/modes/minor_test.go b/pkg/modes/minor_test.go index 5b0e5e9..76c4c18 100644 --- a/pkg/modes/minor_test.go +++ b/pkg/modes/minor_test.go @@ -6,54 +6,47 @@ import ( "github.com/stretchr/testify/assert" ) -func TestMinorMode_MinorConstant(t *testing.T) { - t.Run("CheckConstant", func(t *testing.T) { - var want = "minor" - var got = Minor - - assert.Equal(t, want, got, `want: "%s", got: "%s"`, want, got) - }) -} - func TestMinorMode_Increment(t *testing.T) { type Test struct { - Name string - TargetVersion string - Want string + Name string + Version string + Want string } var tests = []Test{ - {Name: "HappyPath", TargetVersion: "0.1.0", Want: "0.2.0"}, - {Name: "ResetPatch", TargetVersion: "0.2.3", Want: "0.3.0"}, - {Name: "NoResetMajor", TargetVersion: "6.7.0", Want: "6.8.0"}, - {Name: "DiscardPreBuild", TargetVersion: "0.6.0-pre+001", Want: "0.7.0"}, + {Name: "IncrementMinor", Version: "0.0.0", Want: "0.1.0"}, + {Name: "DiscardPrefix", Version: "v0.1.0", Want: "0.2.0"}, + {Name: "DiscardPrebuild", Version: "0.2.0-pre+001", Want: "0.3.0"}, + {Name: "ResetPatch", Version: "3.0.4", Want: "3.1.0"}, } for _, test := range tests { - t.Run(test.Name, func(t *testing.T) { - var want = test.Want - var mode = NewMinorMode() - var got, err = mode.Increment(test.TargetVersion) - - assert.NoError(t, err) - assert.Equal(t, want, got, `want: %s, got: %s`, want, got) - }) - } + var mode = NewMinorMode() + var got, err = mode.Increment(test.Version) - type ErrorTest struct { - Name string - TargetVersion string + assert.NoError(t, err) + assert.IsType(t, test.Want, got, `want: "%s, got: "%s"`, test.Want, got) } - var errorTests = []ErrorTest{ - {Name: "ReturnErrorOnInvalidTargetVersion", TargetVersion: "invalid"}, - } + t.Run("ReturnErrorOnInvalidVersion", func(t *testing.T) { + var mode = NewMinorMode() + var _, got = mode.Increment("invalid") + assert.Error(t, got) + }) +} - for _, test := range errorTests { - t.Run(test.Name, func(t *testing.T) { - var mode = NewMinorMode() - var _, got = mode.Increment(test.TargetVersion) - assert.Error(t, got) - }) - } +func TestMinorMode_MinorConstant(t *testing.T) { + t.Run("CheckConstant", func(t *testing.T) { + var want = "minor" + var got = Minor + assert.Equal(t, want, got, `want: "%s", got: "%s"`, want, got) + }) +} + +func TestNewMinorMode(t *testing.T) { + t.Run("ValidateState", func(t *testing.T) { + var mode = NewMinorMode() + assert.NotNil(t, mode) + assert.IsType(t, MinorMode{}, mode) + }) } diff --git a/pkg/modes/patch_test.go b/pkg/modes/patch_test.go index 45701c3..65fc5eb 100644 --- a/pkg/modes/patch_test.go +++ b/pkg/modes/patch_test.go @@ -6,53 +6,47 @@ import ( "github.com/stretchr/testify/assert" ) -func TestPatchMode_PatchConstant(t *testing.T) { - t.Run("CheckConstant", func(t *testing.T) { - var want = "patch" - var got = Patch - - assert.Equal(t, want, got, `want: "%s", got: "%s"`, want, got) - }) -} - func TestPatchMode_Increment(t *testing.T) { type Test struct { - Name string - TargetVersion string - Want string + Name string + Version string + Want string } var tests = []Test{ - {Name: "HappyPath", TargetVersion: "0.0.1", Want: "0.0.2"}, - {Name: "DiscardPreBuild", TargetVersion: "0.0.8-pre+001", Want: "0.0.9"}, - {Name: "NoResetMajorMinor", TargetVersion: "5.4.3", Want: "5.4.4"}, + {Name: "IncrementPatch", Version: "0.0.0", Want: "0.0.1"}, + {Name: "DiscardPrefix", Version: "v0.0.1", Want: "0.0.2"}, + {Name: "DiscardPrebuild", Version: "0.0.2-pre+001", Want: "0.0.3"}, + {Name: "NoResets", Version: "3.2.0", Want: "3.2.1"}, } for _, test := range tests { - t.Run(test.Name, func(t *testing.T) { - var want = test.Want - var mode = NewPatchMode() - var got, err = mode.Increment(test.TargetVersion) - - assert.NoError(t, err) - assert.Equal(t, want, got, `want: %s, got: %s`, want, got) - }) - } + var mode = NewPatchMode() + var got, err = mode.Increment(test.Version) - type ErrorTest struct { - Name string - TargetVersion string + assert.NoError(t, err) + assert.IsType(t, test.Want, got, `want: "%s, got: "%s"`, test.Want, got) } - var errorTests = []ErrorTest{ - {Name: "ReturnErrorOnInvalidTargetVersion", TargetVersion: "invalid"}, - } + t.Run("ReturnErrorOnInvalidVersion", func(t *testing.T) { + var mode = NewPatchMode() + var _, got = mode.Increment("invalid") + assert.Error(t, got) + }) +} - for _, test := range errorTests { - t.Run(test.Name, func(t *testing.T) { - var mode = NewPatchMode() - var _, got = mode.Increment(test.TargetVersion) - assert.Error(t, got) - }) - } +func TestPatchMode_PatchConstant(t *testing.T) { + t.Run("CheckConstant", func(t *testing.T) { + var want = "patch" + var got = Patch + assert.Equal(t, want, got, `want: "%s", got: "%s"`, want, got) + }) +} + +func TestNewPatchMode(t *testing.T) { + t.Run("ValidateState", func(t *testing.T) { + var mode = NewPatchMode() + assert.NotNil(t, mode) + assert.IsType(t, PatchMode{}, mode) + }) } From 3d78f8835ff36b2ef232f0ce0bf71aabe60a2343 Mon Sep 17 00:00:00 2001 From: shiouen Date: Mon, 22 Nov 2021 18:43:38 +0100 Subject: [PATCH 52/54] updated readme --- .semverbot.toml | 8 ++ README.md | 188 +++++++++++++++++++++++++-------------- cmd/sbot/main.go | 2 +- internal/util/strings.go | 2 +- 4 files changed, 133 insertions(+), 67 deletions(-) diff --git a/.semverbot.toml b/.semverbot.toml index 33bdb51..73428ab 100644 --- a/.semverbot.toml +++ b/.semverbot.toml @@ -13,3 +13,11 @@ prefix = "v" patch = ["fix", "bug"] minor = ["feature"] major = ["release"] + +[modes] + +[modes.git-branch] +delimiters = "/" + +[modes.git-commit] +delimiters = "[]" diff --git a/README.md b/README.md index c15d322..d747869 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,3 @@ - # Semverbot [![github.com release badge](https://img.shields.io/github/release/restechnica/semverbot.svg)](https://github.com/restechnica/anyreleaser/semverbot/) @@ -7,39 +6,21 @@ [![goreportcard.com badge](https://goreportcard.com/badge/github.com/restechnica/semverbot)](https://goreportcard.com/report/github.com/restechnica/semverbot) [![img.shields.io MPL2 license badge](https://img.shields.io/github/license/restechnica/semverbot)](./LICENSE) -A CLI which automates semver versioning based on git information. - -## Why Semverbot? - -There are several reasons why you should consider using `sbot` for your semver versioning. - -### Automation and pipelines - -* `sbot` uses `git` under the hood, which is today's widely adopted version control system -* `sbot` does **not** use a file to keep track of the version - * no pipeline loops - * no need to maintain the version in two places, e.g., both a package.json file and git tags -* `sbot` is ready to be used in pipelines out of the box - -Note: it is still possible to use `sbot` and file-based versioning tools side-by-side - -### Convenience - -* `sbot` is designed to be used by both developers and pipelines -* `sbot` is platform independent - * support for Windows, Linux and macOS - * no dependency on 'complex' `npm`, `pip` or other package management installations -* `sbot` is fast -* `sbot` heavily simplifies incrementing semver levels based on git information - * today's `git` projects already hold a lot of useful semver information, e.g., branch names like `feature/xxx` or commit messages like `[fix] xxx` - * no need to create and maintain custom code for semver level detection - -### Configurability - -* `sbot` supports a well-documented configuration file - * intuitively customize how patch, minor and major levels are detected -* `sbot` supports some flags to override parts of the configuration file on the fly - +A CLI which automates semver versioning. + +## Table of Contents + +* [Requirements](#requirements) +* [How to install](#how-to-install) + * [Github](#github) + * [Homebrew](#homebrew) +* [Usage](#commands) +* [Modes](#modes) +* [How to configure](#how-to-configure) +* [Configuration properties](#configuration-properties) +* [Examples](#examples) +* [Why Semverbot?](#why-semverbot) + ## Requirements `sbot` requires a `git` installation. @@ -52,10 +33,9 @@ The tool is available for Windows, Linux and macOS. ### github The following example works for a GitHub Workflow, other CI/CD tooling will require a different path setup. -The curl command remains the same. ```shell -SEMVERBOT_VERSION=0.1.2 +SEMVERBOT_VERSION=1.0.0 mkdir bin echo "$(pwd)/bin" >> $GITHUB_PATH curl -o bin/sbot -L https://github.com/restechnica/semverbot/releases/download/v$SEMVERBOT_VERSION/sbot-linux-amd64 @@ -71,7 +51,7 @@ brew tap restechnica/tap git@github.com:restechnica/homebrew-tap.git brew install restechnica/tap/semverbot ``` -## Commands +## Usage Each command has a `-h, --help` flag available. @@ -90,7 +70,7 @@ See [Modes](#modes) for more documentation on the supported modes. ### `sbot push version` -Pushes the latest `git` tag. Equivalent to `git push origin {prefix}{version}`. +Pushes the latest `git` tag to the remote repository. Equivalent to `git push origin {prefix}{version}`. ### `sbot release version [-m, --mode] ` @@ -99,7 +79,8 @@ Defaults to mode `auto`. See [Modes](#modes) for more documentation on the suppo ### `sbot update version` -Fetches all tags with `git` to make sure the git repo has the latest tags available. Equivalent to `git fetch --unshallow`. +Fetches all tags with `git` to make sure the git repo has the latest tags available. +Equivalent to running `git fetch --unshallow` and `git fetch --tags`. This command is very useful in pipelines where shallow clones are often the default to save time and space. ## Modes @@ -138,13 +119,16 @@ Increments the `patch` level. ## How to configure -`sbot` supports a configuration file. It looks for a `.semverbot.toml` file in the current working directory by default. `.json` and `.yaml` formats are also supported, but `.toml` is highly recommended. +`sbot` supports a configuration file. It looks for a `.semverbot.toml` file in the current working directory by default. +`.json` and `.yaml` formats are not officially supported, but might work. Using `.toml` is highly recommended. ### Defaults `sbot init` generates the following configuration: ```toml +mode = "auto" + [git] [git.config] @@ -155,16 +139,30 @@ name = "semverbot" prefix = "v" [semver] -mode = "auto" +patch = ["fix", "bug"] +minor = ["feature"] +major = ["release"] + +[modes] + +[modes.git-branch] +delimiters = "/" -[semver.detection] -patch = ["fix/", "[fix]"] -minor = ["feature/", "[feature]"] -major = ["release/", "[release]"] +[modes.git-commit] +delimiters = "[]" ``` ## Configuration properties +### mode + +`sbot` supports multiple modes to detect which semver level it should increment. Each mode works with different criteria. +A `mode` flag enables you to switch modes on the fly. + +See [Modes](#modes) for documentation about the supported modes. + +Defaults to `auto`. + ### git `sbot` works with `git` under the hood, which needs to be set up properly. These config options make sure `git` is set up properly for your environment before running an `sbot` command. @@ -184,31 +182,45 @@ Without this config `sbot` might show unexpected behaviour. ### git.tags.prefix Different platforms and environments work with different (or without) version prefixes. This option enables you to set whatever prefix you would like to work with. -The 'v' prefix, e.g. `v1.0.1` is used by default due to its popularity, e.g. some Golang tools completely depend on it. +The `"v"` prefix, e.g. `v1.0.1` is used by default due to its popularity, e.g. some Golang tools completely depend on it. Note: `sbot` will always display the version without the prefix. -### semver.detection +### semver + +This is where you configure what you think a semver level should be mapped to. -Some `sbot` semver modes require input to detect which semver level should be incremented. -Each level will be assigned a collection of matching strings, which are to be matched against `git` information. +A mapping of semver levels and words, which are matched against git information. +Whenever a match happens, `sbot` will increment the corresponding level. See [Modes](#modes) for documentation about the supported modes. -### semver.detection.[level] +### modes -An array of strings which are to be matched against git information, like branch names and commit messages. -Whenever a match happens, `sbot` will increment the corresponding level. +`sbot` works with different modes, which sometimes require configuration. -### semver.mode -`sbot` supports multiple modes to detect which semver level it should increment. Each mode works with different criteria. -A `mode` flag enables you to switch modes on the fly. +### modes.git-branch.delimiters -See [Modes](#modes) for documentation about the supported modes. +A string of delimiters which are used to split a git branch name. +The matching words for each semver level in the semver map are matched against each of the resulting strings from the split. + +e.g. delimiters `"/"` will split `feature/some-feature` into `["feature", "some-feature"]`, +and the `feature` and `some-feature` strings will be matched against semver map values. + +Defaults to `"/"` due to its popular use in branch names. + +### modes.git-commit.delimiters + +A string of delimiters which are used to split a git commit message. + +e.g. delimiters `"[]"` will split `[feature] some-feature` into `["feature", " some-feature"]`, +and the `feature` and ` some-feature` strings will be matched against semver map values. + +Defaults to `"[]"` due to its popular use in branch names. ## Examples -## Local +### Local Make sure `sbot` is installed. @@ -226,7 +238,7 @@ These commands are basically all you need to work with `sbot` locally. ```shell # installation -SEMVERBOT_VERSION=0.1.2 +SEMVERBOT_VERSION=1.0.0 mkdir bin echo "$(pwd)/bin" >> $GITHUB_PATH curl -o bin/sbot -L https://github.com/restechnica/semverbot/releases/download/v$SEMVERBOT_VERSION/sbot-linux-amd64 @@ -253,7 +265,7 @@ on: branches: [ main ] env: - SEMVERBOT_VERSION: "0.1.2" + SEMVERBOT_VERSION: "1.0.0" jobs: build: @@ -272,16 +284,62 @@ jobs: curl -o bin/sbot -L https://github.com/restechnica/semverbot/releases/download/v$SEMVERBOT_VERSION/sbot-linux-amd64 chmod +x bin/sbot - - name: prepare release + - name: update version run: | sbot update version - echo "RELEASE_VERSION=$(sbot predict version)" >> $GITHUB_ENV + echo "CURRENT_VERSION=$(sbot get version)" >> $GITHUB_ENV + echo "RELEASE_VERSION=$(sbot predict version)" >> $GITHUB_ENV + echo "current version: $CURRENT_VERSION" + echo "next version: $RELEASE_VERSION" - - name: release + ... build / publish ... + + - name: release version run: | - echo "current version: $(sbot get version)" - echo "next version: $RELEASE_VERSION" - sbot release version sbot push version ``` + +### Development workflow + +A typical development workflow when working with `sbot`: + +`[create branch 'feature/my-feature' from main/master]` > `[make changes]` > `[push changes]` > `[create pull request]` > `[approve pull request]` > `[merge pull request]` > `[trigger pipeline]` > +`[calculate next version based on branch name]` > `[build application]` > `[publish artifact]` > `[semverbot release & push version]` + +## Why Semverbot? + +There are several reasons why you should consider using `sbot` for your semver versioning. + +`sbot` is originally made for large scale IT departments which maintain hundreds, if not thousands, of code repositories. +Manual releases for each of those components and their subcomponents simply costs a lot of developer time. + +1. Standardize how your releases are tagged +2. Automate the releasing process for potentially thousands of code repositories + +### Automation and pipelines + +`sbot` automates the process of tagging releases for you. +* `sbot` uses `git` under the hood, which is today's widely adopted version control system +* `sbot` does **not** use a file to keep track of the version + * no pipeline loops + * no need to maintain the version in two places, e.g., both a package.json file and git tags +* `sbot` is ready to be used in pipelines out of the box + +Note: it is still possible to use `sbot` and file-based versioning tools side-by-side + +### Convenience + +* `sbot` is designed to be used by both developers and pipelines +* `sbot` is platform independent + * support for Windows, Linux and macOS + * no dependency on 'complex' `npm`, `pip` or other package management installations +* `sbot` heavily simplifies incrementing semver levels based on git information + * today's `git` projects already hold a lot of useful semver information, e.g., branch names like `feature/xxx` or commit messages like `[fix] xxx` + * no need to create and maintain custom code for semver level detection + +### Configurability + +* `sbot` supports a well-documented configuration file + * intuitively customize how patch, minor and major levels are detected +* `sbot` supports several flags to override parts of the configuration file on the fly diff --git a/cmd/sbot/main.go b/cmd/sbot/main.go index 3a302f0..ea3b9f8 100644 --- a/cmd/sbot/main.go +++ b/cmd/sbot/main.go @@ -4,7 +4,7 @@ import ( "github.com/restechnica/semverbot/pkg/cli/commands" ) -// main bootstraps the `sbot` CLI app. +// main bootstraps the `sbot` CLI. func main() { var cmd = commands.NewRootCommand() _ = cmd.Execute() diff --git a/internal/util/strings.go b/internal/util/strings.go index 8a33eb4..cad2b31 100644 --- a/internal/util/strings.go +++ b/internal/util/strings.go @@ -2,7 +2,7 @@ package util import "strings" -// Contains returns true if a string, split by delimiters, contains another string. +// Contains returns true if a slice, created by splitting a target string by delimiters, contains a value. func Contains(target string, value string, delimiters string) bool { var slice = SplitByDelimiterString(target, delimiters) return SliceContainsString(slice, value) From 5fa01d0587386b8434c5497f5a38545a7777f74b Mon Sep 17 00:00:00 2001 From: shiouen Date: Mon, 22 Nov 2021 18:45:22 +0100 Subject: [PATCH 53/54] updated readme again --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d747869..199da14 100644 --- a/README.md +++ b/README.md @@ -246,11 +246,12 @@ chmod +x bin/sbot # preparation sbot update version +echo "CURRENT_VERSION=$(sbot get version)" >> $GITHUB_ENV echo "RELEASE_VERSION=$(sbot predict version)" >> $GITHUB_ENV +echo "current version: $CURRENT_VERSION" +echo "next version: $RELEASE_VERSION" # usage -echo "current version: $(sbot get version)" -echo "next version: $RELEASE_VERSION" sbot release version sbot push version ``` From c76fc54dc4c61b09da2ff25c74b4900a9d4e2a28 Mon Sep 17 00:00:00 2001 From: shiouen Date: Mon, 22 Nov 2021 18:52:15 +0100 Subject: [PATCH 54/54] typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 199da14..3874095 100644 --- a/README.md +++ b/README.md @@ -197,7 +197,7 @@ See [Modes](#modes) for documentation about the supported modes. ### modes -`sbot` works with different modes, which sometimes require configuration. +`sbot` works with different modes, which might require configuration. ### modes.git-branch.delimiters