From bc4ae2f8c2ed825d839daf7162791fe28977e483 Mon Sep 17 00:00:00 2001 From: Onsi Fakhouri Date: Wed, 12 Oct 2022 14:30:53 -0600 Subject: [PATCH] Ginkgo cli can identify version mismatches and emit a helpful error message --- ginkgo/build/build_command.go | 2 + ginkgo/internal/verify_version.go | 54 +++++++++++++++++++ ginkgo/run/run_command.go | 2 + ginkgo/watch/watch_command.go | 2 + .../_fixtures/version_mismatch_fixture/go.mod | 16 ++++++ .../_fixtures/version_mismatch_fixture/go.sum | 18 +++++++ .../version_mismatch_fixture_suite_test.go | 17 ++++++ integration/run_test.go | 14 +++++ 8 files changed, 125 insertions(+) create mode 100644 ginkgo/internal/verify_version.go create mode 100644 integration/_fixtures/version_mismatch_fixture/go.mod create mode 100644 integration/_fixtures/version_mismatch_fixture/go.sum create mode 100644 integration/_fixtures/version_mismatch_fixture/version_mismatch_fixture_suite_test.go diff --git a/ginkgo/build/build_command.go b/ginkgo/build/build_command.go index f7d2eaf0b..5db5d1a7b 100644 --- a/ginkgo/build/build_command.go +++ b/ginkgo/build/build_command.go @@ -39,6 +39,8 @@ func buildSpecs(args []string, cliConfig types.CLIConfig, goFlagsConfig types.Go command.AbortWith("Found no test suites") } + internal.VerifyCLIAndFrameworkVersion(suites) + opc := internal.NewOrderedParallelCompiler(cliConfig.ComputedNumCompilers()) opc.StartCompiling(suites, goFlagsConfig) diff --git a/ginkgo/internal/verify_version.go b/ginkgo/internal/verify_version.go new file mode 100644 index 000000000..9da1bab3d --- /dev/null +++ b/ginkgo/internal/verify_version.go @@ -0,0 +1,54 @@ +package internal + +import ( + "fmt" + "os/exec" + "regexp" + "strings" + + "github.com/onsi/ginkgo/v2/formatter" + "github.com/onsi/ginkgo/v2/types" +) + +var versiorRe = regexp.MustCompile(`v(\d+\.\d+\.\d+)`) + +func VerifyCLIAndFrameworkVersion(suites TestSuites) { + cliVersion := types.VERSION + mismatches := map[string][]string{} + + for _, suite := range suites { + cmd := exec.Command("go", "list", "-m", "github.com/onsi/ginkgo/v2") + cmd.Dir = suite.Path + output, err := cmd.CombinedOutput() + if err != nil { + continue + } + components := strings.Split(string(output), " ") + if len(components) != 2 { + continue + } + matches := versiorRe.FindStringSubmatch(components[1]) + if matches == nil || len(matches) != 2 { + continue + } + libraryVersion := matches[1] + if cliVersion != libraryVersion { + mismatches[libraryVersion] = append(mismatches[libraryVersion], suite.PackageName) + } + } + + if len(mismatches) == 0 { + return + } + + fmt.Println(formatter.F("{{red}}{{bold}}Ginkgo detected a version mismatch between the Ginkgo CLI and the version of Ginkgo imported by your packages:{{/}}")) + + fmt.Println(formatter.Fi(1, "Ginkgo CLI Version:")) + fmt.Println(formatter.Fi(2, "{{bold}}%s{{/}}", cliVersion)) + fmt.Println(formatter.Fi(1, "Mismatched package versions found:")) + for version, packages := range mismatches { + fmt.Println(formatter.Fi(2, "{{bold}}%s{{/}} used by %s", version, strings.Join(packages, ", "))) + } + fmt.Println("") + fmt.Println(formatter.Fiw(1, formatter.COLS, "{{gray}}Ginkgo will continue to attempt to run but you may see errors (including flag parsing errors) and should either update your go.mod or your version of the Ginkgo CLI to match.\n\nTo install the matching version of the CLI run\n {{bold}}go install github.com/onsi/ginkgo/v2/ginkgo{{/}}{{gray}}\nfrom a path that contains a go.mod file. Alternatively you can use\n {{bold}}go run github.com/onsi/ginkgo/v2/ginkgo{{/}}{{gray}}\nfrom a path that contains a go.mod file to invoke the matching version of the Ginkgo CLI.\n\nIf you are attempting to test multiple packages that each have a different version of the Ginkgo library with a single Ginkgo CLI that is currently unsupported.\n{{/}}")) +} diff --git a/ginkgo/run/run_command.go b/ginkgo/run/run_command.go index 952d9efe9..aaed4d570 100644 --- a/ginkgo/run/run_command.go +++ b/ginkgo/run/run_command.go @@ -69,6 +69,8 @@ func (r *SpecRunner) RunSpecs(args []string, additionalArgs []string) { skippedSuites := suites.WithState(internal.TestSuiteStateSkippedByFilter) suites = suites.WithoutState(internal.TestSuiteStateSkippedByFilter) + internal.VerifyCLIAndFrameworkVersion(suites) + if len(skippedSuites) > 0 { fmt.Println("Will skip:") for _, skippedSuite := range skippedSuites { diff --git a/ginkgo/watch/watch_command.go b/ginkgo/watch/watch_command.go index d9d71866b..bde4193ce 100644 --- a/ginkgo/watch/watch_command.go +++ b/ginkgo/watch/watch_command.go @@ -65,6 +65,8 @@ type SpecWatcher struct { func (w *SpecWatcher) WatchSpecs(args []string, additionalArgs []string) { suites := internal.FindSuites(args, w.cliConfig, false).WithoutState(internal.TestSuiteStateSkippedByFilter) + internal.VerifyCLIAndFrameworkVersion(suites) + if len(suites) == 0 { command.AbortWith("Found no test suites") } diff --git a/integration/_fixtures/version_mismatch_fixture/go.mod b/integration/_fixtures/version_mismatch_fixture/go.mod new file mode 100644 index 000000000..07f641f74 --- /dev/null +++ b/integration/_fixtures/version_mismatch_fixture/go.mod @@ -0,0 +1,16 @@ +module version_mismatch_fixture + +go 1.19 + +require ( + github.com/onsi/ginkgo/v2 v2.2.0 + github.com/onsi/gomega v1.20.1 +) + +require ( + github.com/google/go-cmp v0.5.8 // indirect + golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect + golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect + golang.org/x/text v0.3.7 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/integration/_fixtures/version_mismatch_fixture/go.sum b/integration/_fixtures/version_mismatch_fixture/go.sum new file mode 100644 index 000000000..5466fdec3 --- /dev/null +++ b/integration/_fixtures/version_mismatch_fixture/go.sum @@ -0,0 +1,18 @@ +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/onsi/ginkgo/v2 v2.2.0 h1:3ZNA3L1c5FYDFTTxbFeVGGD8jYvjYauHD30YgLxVsNI= +github.com/onsi/ginkgo/v2 v2.2.0/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk= +github.com/onsi/gomega v1.20.1 h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q= +github.com/onsi/gomega v1.20.1/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/integration/_fixtures/version_mismatch_fixture/version_mismatch_fixture_suite_test.go b/integration/_fixtures/version_mismatch_fixture/version_mismatch_fixture_suite_test.go new file mode 100644 index 000000000..788157cc1 --- /dev/null +++ b/integration/_fixtures/version_mismatch_fixture/version_mismatch_fixture_suite_test.go @@ -0,0 +1,17 @@ +package version_mismatch_fixture_test + +import ( + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func TestVersionMismatchFixture(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "VersionMismatchFixture Suite") +} + +var _ = It("has the error message we expect...", func() { + +}) diff --git a/integration/run_test.go b/integration/run_test.go index 80913cf60..073e5083e 100644 --- a/integration/run_test.go +++ b/integration/run_test.go @@ -443,4 +443,18 @@ var _ = Describe("Running Specs", func() { Ω(names).Should(Equal(expectedNames)) }) }) + + Context("when there is a version mismatch between the cli and the test package", func() { + It("emits a useful error and tries running", func() { + fm.MountFixture(("version_mismatch")) + session := startGinkgo(fm.PathTo("version_mismatch"), "--no-color") + Eventually(session).Should(gbytes.Say("Ginkgo detected a version mismatch between the Ginkgo CLI and the version of Ginkgo imported by your packages")) + Eventually(session).Should(gbytes.Say("Mismatched package versions found")) + Eventually(session).Should(gbytes.Say("2.2.0")) + Eventually(session).Should(gbytes.Say("used by version_mismatch")) + + session.Kill() + Eventually(session).Should(gexec.Exit()) + }) + }) })