diff --git a/cmd/src/teams.go b/cmd/src/teams.go index 98708dc1ee..1f3f5b2622 100644 --- a/cmd/src/teams.go +++ b/cmd/src/teams.go @@ -1,8 +1,13 @@ package main import ( + "context" "flag" "fmt" + "os" + + "github.com/sourcegraph/src-cli/internal/api" + "github.com/sourcegraph/src-cli/internal/features" ) var teamsCommands commander @@ -27,6 +32,9 @@ Use "src teams [command] -h" for more information about a command. flagSet := flag.NewFlagSet("teams", flag.ExitOnError) handler := func(args []string) error { + if err := checkTeamsAvailability(); err != nil { + return err + } teamsCommands.run(flagSet, "src teams", usage, args) return nil } @@ -42,6 +50,27 @@ Use "src teams [command] -h" for more information about a command. }) } +// checkTeamsAvailability verifies that the connected Sourcegraph instance +// supports teams. Teams were removed in Sourcegraph 7.0. +func checkTeamsAvailability() error { + client := cfg.apiClient(api.NewFlags(flag.NewFlagSet("", flag.ContinueOnError)), os.Stderr) + + version, err := api.GetSourcegraphVersion(context.Background(), client) + if err != nil || version == "" { + // If we can't determine the version, let the command proceed. + return nil + } + + var ffs features.FeatureFlags + if err := ffs.SetFromVersion(version, true); err != nil { + return nil + } + if ffs.Sourcegraph70 { + return fmt.Errorf("the 'src teams' commands are not available for Sourcegraph versions 7.0 and later (detected version: %s). Teams have been removed", version) + } + return nil +} + const teamFragment = ` fragment TeamFields on Team { id diff --git a/internal/api/version.go b/internal/api/version.go new file mode 100644 index 0000000000..dbbf1ffefd --- /dev/null +++ b/internal/api/version.go @@ -0,0 +1,17 @@ +package api + +import "context" + +// GetSourcegraphVersion queries the Sourcegraph instance for its product version. +func GetSourcegraphVersion(ctx context.Context, client Client) (string, error) { + var result struct { + Site struct { + ProductVersion string + } + } + ok, err := client.NewQuery(`query { site { productVersion } }`).Do(ctx, &result) + if err != nil || !ok { + return "", err + } + return result.Site.ProductVersion, nil +} diff --git a/internal/batches/features.go b/internal/batches/features.go index 228775f66a..6084777b48 100644 --- a/internal/batches/features.go +++ b/internal/batches/features.go @@ -1,48 +1,6 @@ package batches -import ( - "fmt" - "log" +import "github.com/sourcegraph/src-cli/internal/features" - "github.com/sourcegraph/sourcegraph/lib/api" - "github.com/sourcegraph/sourcegraph/lib/errors" -) - -// FeatureFlags represent features that are only available on certain -// Sourcegraph versions and we therefore have to detect at runtime. -type FeatureFlags struct { - Sourcegraph40 bool - BinaryDiffs bool -} - -func (ff *FeatureFlags) SetFromVersion(version string, skipErrors bool) error { - for _, feature := range []struct { - flag *bool - constraint string - minDate string - }{ - // NOTE: It's necessary to include a "-0" prerelease suffix on each constraint so that - // prereleases of future versions are still considered to satisfy the constraint. - // - // For example, the version "3.35.1-rc.3" is not considered to satisfy the constraint - // ">= 3.23.0". However, the same version IS considered to satisfy the constraint - // "3.23.0-0". See - // https://github.com/Masterminds/semver#working-with-prerelease-versions for more. - // Example usage: - // {&ff.FlagName, ">= 3.23.0-0", "2020-11-24"}, - {&ff.Sourcegraph40, ">= 4.0.0-0", "2022-08-24"}, - {&ff.BinaryDiffs, ">= 4.3.0-0", "2022-11-29"}, - } { - value, err := api.CheckSourcegraphVersion(version, feature.constraint, feature.minDate) - if err != nil { - if skipErrors { - log.Printf("failed to check version returned by Sourcegraph: %s. Assuming no feature flags.", version) - } else { - return errors.Wrap(err, fmt.Sprintf("failed to check version returned by Sourcegraph: %s", version)) - } - } - *feature.flag = value - } - - return nil -} +// FeatureFlags is an alias for features.FeatureFlags for backwards compatibility. +type FeatureFlags = features.FeatureFlags diff --git a/internal/features/features.go b/internal/features/features.go new file mode 100644 index 0000000000..657ece2f14 --- /dev/null +++ b/internal/features/features.go @@ -0,0 +1,50 @@ +package features + +import ( + "fmt" + "log" + + "github.com/sourcegraph/sourcegraph/lib/api" + "github.com/sourcegraph/sourcegraph/lib/errors" +) + +// FeatureFlags represent features that are only available on certain +// Sourcegraph versions and we therefore have to detect at runtime. +type FeatureFlags struct { + Sourcegraph40 bool + BinaryDiffs bool + Sourcegraph70 bool +} + +func (ff *FeatureFlags) SetFromVersion(version string, skipErrors bool) error { + for _, feature := range []struct { + flag *bool + constraint string + minDate string + }{ + // NOTE: It's necessary to include a "-0" prerelease suffix on each constraint so that + // prereleases of future versions are still considered to satisfy the constraint. + // + // For example, the version "3.35.1-rc.3" is not considered to satisfy the constraint + // ">= 3.23.0". However, the same version IS considered to satisfy the constraint + // "3.23.0-0". See + // https://github.com/Masterminds/semver#working-with-prerelease-versions for more. + // Example usage: + // {&ff.FlagName, ">= 3.23.0-0", "2020-11-24"}, + {&ff.Sourcegraph40, ">= 4.0.0-0", "2022-08-24"}, + {&ff.BinaryDiffs, ">= 4.3.0-0", "2022-11-29"}, + {&ff.Sourcegraph70, ">= 7.0.0-0", "2026-02-25"}, + } { + value, err := api.CheckSourcegraphVersion(version, feature.constraint, feature.minDate) + if err != nil { + if skipErrors { + log.Printf("failed to check version returned by Sourcegraph: %s. Assuming no feature flags.", version) + } else { + return errors.Wrap(err, fmt.Sprintf("failed to check version returned by Sourcegraph: %s", version)) + } + } + *feature.flag = value + } + + return nil +}