Skip to content

Commit

Permalink
Reorganize migrate constaints check and add unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
pkosiec committed Jan 26, 2024
1 parent 0b12844 commit 1d2fe77
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 29 deletions.
33 changes: 5 additions & 28 deletions cmd/cli/cmd/migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (

"github.com/AlecAivazis/survey/v2"
"github.com/fatih/color"
semver "github.com/hashicorp/go-version"
"github.com/pkg/browser"
"github.com/spf13/cobra"
"go.szostok.io/version"
Expand All @@ -20,10 +19,6 @@ import (
"github.com/kubeshop/botkube/internal/kubex"
)

var (
botkubeMinVersionConstraint = ">= 1.0"
)

// NewMigrate returns a cobra.Command for migrate the OS into Cloud.
func NewMigrate() *cobra.Command {
var opts migrate.Options
Expand Down Expand Up @@ -68,18 +63,12 @@ func NewMigrate() *cobra.Command {

status.Infof("Checking if Botkube version %q can be migrated safely", botkubeVersionStr)

botkubeVersionConstraints := getBotkubeVersionConstraints()
constraint, err := semver.NewConstraint(botkubeVersionConstraints)
if err != nil {
return fmt.Errorf("unable to parse Botkube semver version constraints: %w", err)
}

botkubeVersion, err := semver.NewVersion(botkubeVersionStr)
botkubeVersionConstraints := migrate.BotkubeVersionConstraints()
isCompatible, err := migrate.IsCompatible(botkubeVersionConstraints, botkubeVersionStr)
if err != nil {
return fmt.Errorf("unable to parse botkube version %s as semver: %w", botkubeVersion, err)
status.Infof("Unable to check if Botkube version %q is within range of Botkube version constraints %q: %s", botkubeVersionStr, botkubeVersionConstraints, err.Error())
// continue anyway as this shouldn't fail the whole migration
}

isCompatible := constraint.Check(botkubeVersion)
if !isCompatible && !opts.AutoApprove {
run := false

Expand All @@ -90,7 +79,7 @@ func NewMigrate() *cobra.Command {
Botkube version constraints for the currently installed CLI: %s
We recommend upgrading your CLI to the latest version. In order to do so, navigate to https://docs.botkube.io/.
Do you wish to continue?`, version.Get().Version, botkubeVersion, botkubeVersionConstraints),
Do you wish to continue?`, version.Get().Version, botkubeVersionStr, botkubeVersionConstraints),
Default: false,
}

Expand Down Expand Up @@ -151,15 +140,3 @@ func NewMigrate() *cobra.Command {

return migrate
}

func getBotkubeVersionConstraints() string {
cliVer := version.Get().Version
cliVersion, err := semver.NewVersion(cliVer)

botkubeMaxVersionConstraint := ""
if err == nil {
botkubeMaxVersionConstraint = fmt.Sprintf(", <= %s", cliVersion.String())
}

return fmt.Sprintf("%s%s", botkubeMinVersionConstraint, botkubeMaxVersionConstraint)
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ require (
github.com/AlecAivazis/survey/v2 v2.3.7
github.com/DanielTitkov/go-adaptive-cards v0.2.2
github.com/MakeNowJust/heredoc v1.0.0
github.com/Masterminds/semver/v3 v3.2.1
github.com/Masterminds/sprig/v3 v3.2.3
github.com/PullRequestInc/go-gpt3 v1.2.0
github.com/alexflint/go-arg v1.4.3
Expand Down Expand Up @@ -104,7 +105,6 @@ require (
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
github.com/BurntSushi/toml v1.3.2 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.2.1 // indirect
github.com/Masterminds/squirrel v1.5.4 // indirect
github.com/Microsoft/hcsshim v0.11.0 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 // indirect
Expand Down
40 changes: 40 additions & 0 deletions internal/cli/migrate/compatibility.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package migrate

import (
"fmt"

"github.com/Masterminds/semver/v3"
"go.szostok.io/version"
)

const (
botkubeMinVersionConstraint = ">= 1.0"
)

// BotkubeVersionConstraints returns Botkube version constraints as a string.
func BotkubeVersionConstraints() string {
botkubeMaxVersionConstraint := ""

cliVer := version.Get().Version
cliVersion, err := semver.NewVersion(cliVer)
if err == nil {
botkubeMaxVersionConstraint = fmt.Sprintf(", <= %s", cliVersion.String())
}

return fmt.Sprintf("%s%s", botkubeMinVersionConstraint, botkubeMaxVersionConstraint)
}

// IsCompatible checks if Botkube version is compatible with the migrate command.
func IsCompatible(botkubeVersionConstraintsStr string, botkubeVersionStr string) (bool, error) {
constraint, err := semver.NewConstraint(botkubeVersionConstraintsStr)
if err != nil {
return false, fmt.Errorf("unable to parse Botkube semver version constraints: %w", err)
}

botkubeVersion, err := semver.NewVersion(botkubeVersionStr)
if err != nil {
return false, fmt.Errorf("unable to parse botkube version %s as semver: %w", botkubeVersion, err)
}

return constraint.Check(botkubeVersion), nil
}
93 changes: 93 additions & 0 deletions internal/cli/migrate/compatibility_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package migrate

import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestIsCompatible(t *testing.T) {
testCases := []struct {
Name string
BotkubeVersionConstraintsStr string
BotkubeVersionStr string
ExpectedResult bool
ExpectedErrMessage string
}{
// TODO: The following test cases should pass, but they don't because of the bug in the `semver` library.
// See: https://github.com/Masterminds/semver/issues/177
// The problem occurs only in the RC releases, so this isn't a huge issue for us.
//
//{
// Name: "RC within range",
// BotkubeVersionStr: "1.8.0-rc.1",
// BotkubeVersionConstraintsStr: ">= 1.0, <= 1.8.0-rc.1",
// ExpectedResult: true,
// ExpectedErrMessage: "",
//},
//{
// Name: "RC within range 2",
// BotkubeVersionStr: "1.8.0-rc.1",
// BotkubeVersionConstraintsStr: ">= 1.0, <= 1.8.0",
// ExpectedResult: true,
// ExpectedErrMessage: "",
//},
{
Name: "Final version out of range",
BotkubeVersionStr: "1.8.0",
BotkubeVersionConstraintsStr: ">= 1.0, <= 1.8.0-rc.1",
ExpectedResult: false,
ExpectedErrMessage: "",
},
{
Name: "Final version within range",
BotkubeVersionStr: "1.8.0",
BotkubeVersionConstraintsStr: ">= 1.0, <= 1.8.0",
ExpectedResult: true,
ExpectedErrMessage: "",
},
{
Name: "Lowest version within range",
BotkubeVersionStr: "1.0.0",
BotkubeVersionConstraintsStr: ">= 1.0, <= 1.8.0",
ExpectedResult: true,
ExpectedErrMessage: "",
},
{
Name: "Older",
BotkubeVersionStr: "1.7.0",
BotkubeVersionConstraintsStr: ">= 1.0, <= 1.8.0",
ExpectedResult: true,
ExpectedErrMessage: "",
},
{
Name: "Newer",
BotkubeVersionStr: "1.9.0",
BotkubeVersionConstraintsStr: ">= 1.0, <= 1.8.0",
ExpectedResult: false,
ExpectedErrMessage: "",
},
{
Name: "Invalid constraint",
BotkubeVersionStr: "1.8.0",
BotkubeVersionConstraintsStr: ">= 1.0, <= dev",
ExpectedResult: false,
ExpectedErrMessage: "unable to parse Botkube semver version constraints: improper constraint: >= 1.0, <= dev",
},
}

for _, tc := range testCases {
t.Run(tc.Name, func(t *testing.T) {
result, err := IsCompatible(tc.BotkubeVersionConstraintsStr, tc.BotkubeVersionStr)
if tc.ExpectedErrMessage != "" {
require.Error(t, err)
assert.EqualError(t, err, tc.ExpectedErrMessage)
return
}

require.NoError(t, err)
assert.Equal(t, tc.ExpectedResult, result)
})
}
}

0 comments on commit 1d2fe77

Please sign in to comment.