diff --git a/cmd/src/batch_common.go b/cmd/src/batch_common.go index cbd58b4e72..ff51ed64d3 100644 --- a/cmd/src/batch_common.go +++ b/cmd/src/batch_common.go @@ -177,37 +177,17 @@ func batchDefaultCacheDir() string { if err != nil { return "" } - - // Check if there's an old campaigns cache directory but not a new batch - // directory: if so, we should rename the old directory and carry on. - // - // TODO(campaigns-deprecation): we can remove this migration shim after June - // 2021. - old := path.Join(uc, "sourcegraph", "campaigns") dir := path.Join(uc, "sourcegraph", "batch") - if _, err := os.Stat(dir); os.IsNotExist(err) { - if _, err := os.Stat(old); os.IsExist(err) { - // We'll just try to do this without checking for an error: if it - // fails, we'll carry on and let the normal cache directory handling - // logic take care of it. - os.Rename(old, dir) - } - } return dir } // batchDefaultTempDirPrefix returns the prefix to be passed to ioutil.TempFile. -// If one of the environment variables SRC_BATCH_TMP_DIR or -// SRC_CAMPAIGNS_TMP_DIR is set, that is used as the prefix. Otherwise we use -// "/tmp". +// If the environment variable SRC_BATCH_TMP_DIR is set, that is used as the prefix. +// Otherwise we use "/tmp". func batchDefaultTempDirPrefix() string { - // TODO(campaigns-deprecation): we can remove this migration shim in - // Sourcegraph 4.0. - for _, env := range []string{"SRC_BATCH_TMP_DIR", "SRC_CAMPAIGNS_TMP_DIR"} { - if p := os.Getenv(env); p != "" { - return p - } + if p := os.Getenv("SRC_BATCH_TMP_DIR"); p != "" { + return p } // On macOS, we use an explicit prefix for our temp directories, because @@ -280,7 +260,7 @@ func executeBatchSpec(ctx context.Context, ui ui.ExecUI, opts executeBatchSpecOp imageCache := docker.NewImageCache() - if err := svc.DetermineFeatureFlags(ctx); err != nil { + if err := validateSourcegraphVersionConstraint(ctx, svc); err != nil { return err } @@ -399,7 +379,6 @@ func executeBatchSpec(ctx context.Context, ui ui.ExecUI, opts executeBatchSpecOp GlobalEnv: os.Environ(), IsRemote: false, }, - Features: svc.Features(), Logger: logManager, Cache: executor.NewDiskCache(opts.flags.cacheDir), GlobalEnv: os.Environ(), @@ -604,3 +583,14 @@ func getBatchParallelism(ctx context.Context, flag int) (int, error) { return docker.NCPU(ctx) } + +func validateSourcegraphVersionConstraint(ctx context.Context, svc *service.Service) error { + ffs, err := svc.DetermineFeatureFlags(ctx) + if err != nil { + return err + } + if ffs.Sourcegraph40 { + return nil + } + return errors.Newf("\n\n * Warning:\n This version of src-cli requires Sourcegraph version 4.0 or newer. If you're not on Sourcegraph 4.0 or newer, please use the 3.x release of src-cli that corresponds to your Sourcegraph version.\n\n") +} diff --git a/cmd/src/batch_new.go b/cmd/src/batch_new.go index 9d692e00ec..577da8bd4b 100644 --- a/cmd/src/batch_new.go +++ b/cmd/src/batch_new.go @@ -48,7 +48,7 @@ Examples: Client: cfg.apiClient(apiFlags, flagSet.Output()), }) - if err := svc.DetermineFeatureFlags(ctx); err != nil { + if err := validateSourcegraphVersionConstraint(ctx, svc); err != nil { return err } diff --git a/cmd/src/batch_remote.go b/cmd/src/batch_remote.go index 261831c11c..483e6e8db9 100644 --- a/cmd/src/batch_remote.go +++ b/cmd/src/batch_remote.go @@ -52,7 +52,7 @@ Examples: Client: cfg.apiClient(flags.api, flagSet.Output()), }) - if err := svc.DetermineFeatureFlags(ctx); err != nil { + if err := validateSourcegraphVersionConstraint(ctx, svc); err != nil { return err } diff --git a/cmd/src/batch_repositories.go b/cmd/src/batch_repositories.go index 3d92b578bb..31cbbf6d8c 100644 --- a/cmd/src/batch_repositories.go +++ b/cmd/src/batch_repositories.go @@ -64,7 +64,7 @@ Examples: Client: client, }) - if err := svc.DetermineFeatureFlags(ctx); err != nil { + if err := validateSourcegraphVersionConstraint(ctx, svc); err != nil { return err } diff --git a/cmd/src/batch_validate.go b/cmd/src/batch_validate.go index ae5b20e1e4..a9571348e9 100644 --- a/cmd/src/batch_validate.go +++ b/cmd/src/batch_validate.go @@ -63,7 +63,7 @@ Examples: Client: cfg.apiClient(apiFlags, flagSet.Output()), }) - if err := svc.DetermineFeatureFlags(ctx); err != nil { + if err := validateSourcegraphVersionConstraint(ctx, svc); err != nil { ui.ExecutionError(err) return err } diff --git a/go.mod b/go.mod index 9d37a66f31..b7e61b08bd 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/sourcegraph/go-diff v0.6.1 github.com/sourcegraph/jsonx v0.0.0-20200629203448-1a936bd500cf github.com/sourcegraph/scip v0.2.0 - github.com/sourcegraph/sourcegraph/lib v0.0.0-20220822143138-d621aac70d3d + github.com/sourcegraph/sourcegraph/lib v0.0.0-20220825181731-397a768a5290 github.com/stretchr/testify v1.7.2 golang.org/x/net v0.0.0-20220722155237-a158d28d115b golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 @@ -103,7 +103,7 @@ require ( go.uber.org/zap v1.21.0 // indirect golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect - golang.org/x/sys v0.0.0-20220818161305-2296e01440c6 // indirect + golang.org/x/sys v0.0.0-20220823224334-20c2bfdbfe24 // indirect golang.org/x/term v0.0.0-20220411215600-e5f449aeb171 // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/tools v0.1.12 // indirect diff --git a/go.sum b/go.sum index fe55304b2e..bb2cb1200e 100644 --- a/go.sum +++ b/go.sum @@ -370,8 +370,8 @@ github.com/sourcegraph/log v0.0.0-20220707160925-6a936691c838 h1:8wknDSCUVYbaRT6 github.com/sourcegraph/log v0.0.0-20220707160925-6a936691c838/go.mod h1:zWEPlKrWBUVpko/tOgDS+qrp7BmzaCcmUrh9+ver1iQ= github.com/sourcegraph/scip v0.2.0 h1:Z9rR9TNONtRhqcpm0JP/yEBUy0fBKaSVbWIZKih5v04= github.com/sourcegraph/scip v0.2.0/go.mod h1:EYyT39nXdZDNVmgbJAlyIVWbEb1txnAOKpJPSYpvgXk= -github.com/sourcegraph/sourcegraph/lib v0.0.0-20220822143138-d621aac70d3d h1:bUaXAbtXSWbcv8LjDwwYXo0grERhlOJDn2T8ROe/Mmc= -github.com/sourcegraph/sourcegraph/lib v0.0.0-20220822143138-d621aac70d3d/go.mod h1:9wnFUNfpORLAOJn4XAO7ZeWnYkf6/CxlWaTU1vlpuKc= +github.com/sourcegraph/sourcegraph/lib v0.0.0-20220825181731-397a768a5290 h1:SLCu3Rf1eLZ4sNKl0Bg1oURTgDxEutRCaTQt5dpVqH4= +github.com/sourcegraph/sourcegraph/lib v0.0.0-20220825181731-397a768a5290/go.mod h1:9wnFUNfpORLAOJn4XAO7ZeWnYkf6/CxlWaTU1vlpuKc= github.com/sourcegraph/yaml v1.0.1-0.20200714132230-56936252f152 h1:z/MpntplPaW6QW95pzcAR/72Z5TWDyDnSo0EOcyij9o= github.com/sourcegraph/yaml v1.0.1-0.20200714132230-56936252f152/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= @@ -535,8 +535,8 @@ golang.org/x/sys v0.0.0-20211102192858-4dd72447c267/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211213223007-03aa0b5f6827/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220818161305-2296e01440c6 h1:Sx/u41w+OwrInGdEckYmEuU5gHoGSL4QbDz3S9s6j4U= -golang.org/x/sys v0.0.0-20220818161305-2296e01440c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220823224334-20c2bfdbfe24 h1:TyKJRhyo17yWxOMCTHKWrc5rddHORMlnZ/j57umaUd8= +golang.org/x/sys v0.0.0-20220823224334-20c2bfdbfe24/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20220411215600-e5f449aeb171 h1:EH1Deb8WZJ0xc0WK//leUHXcX9aLE5SymusoTmMZye8= golang.org/x/term v0.0.0-20220411215600-e5f449aeb171/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= diff --git a/internal/api/api.go b/internal/api/api.go index eaa3a39de7..25e87f814e 100644 --- a/internal/api/api.go +++ b/internal/api/api.go @@ -16,6 +16,7 @@ import ( ioaux "github.com/jig/teereadcloser" "github.com/kballard/go-shellquote" "github.com/mattn/go-isatty" + "github.com/sourcegraph/src-cli/internal/version" ) @@ -28,13 +29,6 @@ type Client interface { // NewRequest creates a GraphQL request. NewRequest(query string, vars map[string]interface{}) Request - // NewGzippedRequest creates a GraphQL request with gzip compression turned on. - NewGzippedRequest(query string, vars map[string]interface{}) Request - - // NewGzippedQuery is a convenience wrapper around NewQuery with gzip - // compression turned on. - NewGzippedQuery(query string) Request - // NewHTTPRequest creates an http.Request for the Sourcegraph API. // // path is joined against the API route. For example on Sourcegraph.com this @@ -72,7 +66,6 @@ type request struct { client *client query string vars map[string]interface{} - gzip bool } // ClientOpts encapsulates the options given to NewClient. @@ -132,19 +125,6 @@ func (c *client) NewRequest(query string, vars map[string]interface{}) Request { } } -func (c *client) NewGzippedRequest(query string, vars map[string]interface{}) Request { - return &request{ - client: c, - query: query, - vars: vars, - gzip: true, - } -} - -func (c *client) NewGzippedQuery(query string) Request { - return c.NewGzippedRequest(query, nil) -} - func (c *client) Do(req *http.Request) (*http.Response, error) { return c.httpClient.Do(req) } @@ -216,9 +196,7 @@ func (r *request) do(ctx context.Context, result interface{}) (bool, error) { } var bufBody io.Reader = bytes.NewBuffer(reqBody) - if r.gzip { - bufBody = gzipReader(bufBody) - } + bufBody = gzipReader(bufBody) // Create the HTTP request. req, err := r.client.NewHTTPRequest(ctx, "POST", ".api/graphql", bufBody) @@ -226,9 +204,8 @@ func (r *request) do(ctx context.Context, result interface{}) (bool, error) { return false, err } - if r.gzip { - req.Header.Set("Content-Encoding", "gzip") - } + // Use gzip compression. + req.Header.Set("Content-Encoding", "gzip") // Perform the request. resp, err := r.client.httpClient.Do(req) diff --git a/internal/batches/executor/coordinator.go b/internal/batches/executor/coordinator.go index 970ae6c555..77441f3717 100644 --- a/internal/batches/executor/coordinator.go +++ b/internal/batches/executor/coordinator.go @@ -9,7 +9,6 @@ import ( "github.com/sourcegraph/sourcegraph/lib/batches/execution" "github.com/sourcegraph/sourcegraph/lib/batches/execution/cache" - "github.com/sourcegraph/src-cli/internal/batches" "github.com/sourcegraph/src-cli/internal/batches/log" ) @@ -34,8 +33,6 @@ type NewCoordinatorOpts struct { Logger log.LogManager GlobalEnv []string - // Used by batcheslib.BuildChangesetSpecs - Features batches.FeatureFlags IsRemote bool } @@ -124,10 +121,7 @@ func (c Coordinator) buildChangesetSpecs(task *Task, batchSpec *batcheslib.Batch }, } - return batcheslib.BuildChangesetSpecs(input, batcheslib.ChangesetSpecFeatureFlags{ - IncludeAutoAuthorDetails: c.opts.Features.IncludeAutoAuthorDetails, - AllowOptionalPublished: c.opts.Features.AllowOptionalPublished, - }) + return batcheslib.BuildChangesetSpecs(input) } func (c *Coordinator) loadCachedStepResults(ctx context.Context, task *Task, globalEnv []string) error { diff --git a/internal/batches/executor/coordinator_test.go b/internal/batches/executor/coordinator_test.go index 93cb69a4a2..5ac48da62d 100644 --- a/internal/batches/executor/coordinator_test.go +++ b/internal/batches/executor/coordinator_test.go @@ -82,7 +82,7 @@ func TestCoordinator_Execute(t *testing.T) { {task: sourcegraphTask, stepResults: []execution.AfterStepResult{{Diff: `dummydiff2`}}}, }, }, - opts: NewCoordinatorOpts{Features: featuresAllEnabled()}, + opts: NewCoordinatorOpts{}, wantCacheEntries: 2, wantSpecs: []*batcheslib.ChangesetSpec{ @@ -150,7 +150,7 @@ func TestCoordinator_Execute(t *testing.T) { }, }, }, - opts: NewCoordinatorOpts{Features: featuresAllEnabled()}, + opts: NewCoordinatorOpts{}, wantCacheEntries: 1, wantSpecs: []*batcheslib.ChangesetSpec{ @@ -201,7 +201,7 @@ func TestCoordinator_Execute(t *testing.T) { {task: sourcegraphTask, stepResults: []execution.AfterStepResult{{Diff: nestedChangesDiff}}}, }, }, - opts: NewCoordinatorOpts{Features: featuresAllEnabled()}, + opts: NewCoordinatorOpts{}, // TODO: Fix comment. // We have 4 ChangesetSpecs, but we only want 2 cache entries, @@ -249,7 +249,7 @@ func TestCoordinator_Execute(t *testing.T) { {task: sourcegraphTask, stepResults: []execution.AfterStepResult{{Diff: `dummydiff2`, StepIndex: 0}}}, }, }, - opts: NewCoordinatorOpts{Features: featuresAllEnabled()}, + opts: NewCoordinatorOpts{}, wantCacheEntries: 2, wantSpecs: []*batcheslib.ChangesetSpec{ diff --git a/internal/batches/executor/executor_test.go b/internal/batches/executor/executor_test.go index 9b9167956c..2a6040ffdc 100644 --- a/internal/batches/executor/executor_test.go +++ b/internal/batches/executor/executor_test.go @@ -25,7 +25,6 @@ import ( "github.com/sourcegraph/sourcegraph/lib/batches/template" "github.com/sourcegraph/src-cli/internal/api" - "github.com/sourcegraph/src-cli/internal/batches" "github.com/sourcegraph/src-cli/internal/batches/docker" "github.com/sourcegraph/src-cli/internal/batches/mock" "github.com/sourcegraph/src-cli/internal/batches/repozip" @@ -510,18 +509,6 @@ func addToPath(t *testing.T, relPath string) { os.Setenv("PATH", fmt.Sprintf("%s%c%s", dummyDockerPath, os.PathListSeparator, os.Getenv("PATH"))) } -func featuresAllEnabled() batches.FeatureFlags { - return batches.FeatureFlags{ - AllowArrayEnvironments: true, - IncludeAutoAuthorDetails: true, - UseGzipCompression: true, - AllowTransformChanges: true, - AllowWorkspaces: true, - AllowConditionalExec: true, - AllowOptionalPublished: true, - } -} - func TestExecutor_CachedStepResults(t *testing.T) { t.Run("single step cached", func(t *testing.T) { archive := mock.RepoArchive{ diff --git a/internal/batches/features.go b/internal/batches/features.go index c27e94596f..0a020b6bc6 100644 --- a/internal/batches/features.go +++ b/internal/batches/features.go @@ -9,16 +9,7 @@ import ( // FeatureFlags represent features that are only available on certain // Sourcegraph versions and we therefore have to detect at runtime. type FeatureFlags struct { - AllowArrayEnvironments bool - IncludeAutoAuthorDetails bool - UseGzipCompression bool - AllowTransformChanges bool - AllowWorkspaces bool - BatchChanges bool - AllowConditionalExec bool - AllowOptionalPublished bool - ServerSideBatchChanges bool - BitbucketCloud bool + Sourcegraph40 bool } func (ff *FeatureFlags) SetFromVersion(version string) error { @@ -34,16 +25,9 @@ func (ff *FeatureFlags) SetFromVersion(version string) error { // ">= 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. - {&ff.AllowArrayEnvironments, ">= 3.23.0-0", "2020-11-24"}, - {&ff.IncludeAutoAuthorDetails, ">= 3.20.0-0", "2020-09-10"}, - {&ff.UseGzipCompression, ">= 3.21.0-0", "2020-10-12"}, - {&ff.AllowTransformChanges, ">= 3.23.0-0", "2020-12-11"}, - {&ff.AllowWorkspaces, ">= 3.25.0-0", "2021-01-29"}, - {&ff.BatchChanges, ">= 3.26.0-0", "2021-03-07"}, - {&ff.AllowConditionalExec, ">= 3.28.0-0", "2021-05-05"}, - {&ff.AllowOptionalPublished, ">= 3.30.0-0", "2021-06-21"}, - {&ff.ServerSideBatchChanges, ">= 3.37.0-0", "2022-02-08"}, - {&ff.BitbucketCloud, ">= 3.40.0-0", "2022-04-20"}, + // Example usage: + // {&ff.FlagName, ">= 3.23.0-0", "2020-11-24"}, + {&ff.Sourcegraph40, ">= 4.0.0-0", "2022-08-24"}, } { value, err := api.CheckSourcegraphVersion(version, feature.constraint, feature.minDate) if err != nil { diff --git a/internal/batches/graphql/batch_change.go b/internal/batches/graphql/batch_change.go deleted file mode 100644 index d29ee33c2e..0000000000 --- a/internal/batches/graphql/batch_change.go +++ /dev/null @@ -1,5 +0,0 @@ -package graphql - -type BatchChange struct { - URL string -} diff --git a/internal/batches/graphql/batches.go b/internal/batches/graphql/batches.go index 54fd1f26d8..5f8dfa84c8 100644 --- a/internal/batches/graphql/batches.go +++ b/internal/batches/graphql/batches.go @@ -1,66 +1,13 @@ package graphql -import ( - "context" -) +type BatchSpecID string +type ChangesetSpecID string -type batchesBackend struct { - commonBackend +type CreateBatchSpecResponse struct { + ID BatchSpecID + ApplyURL string } -var _ Operations = &batchesBackend{} - -const applyBatchChangeMutation = ` -mutation ApplyBatchChange($batchSpec: ID!) { - applyBatchChange(batchSpec: $batchSpec) { - ...batchChangeFields - } -} - -fragment batchChangeFields on BatchChange { - url -} -` - -func (bb *batchesBackend) ApplyBatchChange(ctx context.Context, batchSpecID BatchSpecID) (*BatchChange, error) { - var result struct { - BatchChange *BatchChange `json:"applyBatchChange"` - } - if ok, err := bb.newRequest(applyBatchChangeMutation, map[string]interface{}{ - "batchSpec": batchSpecID, - }).Do(ctx, &result); err != nil || !ok { - return nil, err - } - return result.BatchChange, nil -} - -const createBatchSpecMutation = ` -mutation CreateBatchSpec( - $namespace: ID!, - $spec: String!, - $changesetSpecs: [ID!]! -) { - createBatchSpec( - namespace: $namespace, - batchSpec: $spec, - changesetSpecs: $changesetSpecs - ) { - id - applyURL - } -} -` - -func (bb *batchesBackend) CreateBatchSpec(ctx context.Context, namespace, spec string, changesetSpecIDs []ChangesetSpecID) (*CreateBatchSpecResponse, error) { - var result struct { - CreateBatchSpec CreateBatchSpecResponse - } - if ok, err := bb.newRequest(createBatchSpecMutation, map[string]interface{}{ - "namespace": namespace, - "spec": spec, - "changesetSpecs": changesetSpecIDs, - }).Do(ctx, &result); err != nil || !ok { - return nil, err - } - return &result.CreateBatchSpec, nil +type BatchChange struct { + URL string } diff --git a/internal/batches/graphql/campaigns.go b/internal/batches/graphql/campaigns.go deleted file mode 100644 index a45abffef4..0000000000 --- a/internal/batches/graphql/campaigns.go +++ /dev/null @@ -1,64 +0,0 @@ -package graphql - -import "context" - -type campaignsBackend struct { - commonBackend -} - -var _ Operations = &campaignsBackend{} - -const applyCampaignMutation = ` -mutation ApplyCampaign($campaignSpec: ID!) { - applyCampaign(campaignSpec: $campaignSpec) { - ...campaignFields - } -} - -fragment campaignFields on Campaign { - url -} -` - -func (cb *campaignsBackend) ApplyBatchChange(ctx context.Context, batchSpecID BatchSpecID) (*BatchChange, error) { - var result struct { - BatchChange *BatchChange `json:"applyCampaign"` - } - if ok, err := cb.newRequest(applyCampaignMutation, map[string]interface{}{ - "campaignSpec": batchSpecID, - }).Do(ctx, &result); err != nil || !ok { - return nil, err - } - return result.BatchChange, nil -} - -const createCampaignSpecMutation = ` -mutation CreateCampaignSpec( - $namespace: ID!, - $spec: String!, - $changesetSpecs: [ID!]! -) { - createCampaignSpec( - namespace: $namespace, - campaignSpec: $spec, - changesetSpecs: $changesetSpecs - ) { - id - applyURL - } -} -` - -func (cb *campaignsBackend) CreateBatchSpec(ctx context.Context, namespace, spec string, changesetSpecIDs []ChangesetSpecID) (*CreateBatchSpecResponse, error) { - var result struct { - CreateCampaignSpec CreateBatchSpecResponse - } - if ok, err := cb.newRequest(createCampaignSpecMutation, map[string]interface{}{ - "namespace": namespace, - "spec": spec, - "changesetSpecs": changesetSpecIDs, - }).Do(ctx, &result); err != nil || !ok { - return nil, err - } - return &result.CreateCampaignSpec, nil -} diff --git a/internal/batches/graphql/common.go b/internal/batches/graphql/common.go deleted file mode 100644 index 1581ac9f53..0000000000 --- a/internal/batches/graphql/common.go +++ /dev/null @@ -1,17 +0,0 @@ -package graphql - -import ( - "github.com/sourcegraph/src-cli/internal/api" -) - -type commonBackend struct { - client api.Client - useGzipCompression bool -} - -func (b *commonBackend) newRequest(query string, vars map[string]interface{}) api.Request { - if b.useGzipCompression { - return b.client.NewGzippedRequest(query, vars) - } - return b.client.NewRequest(query, vars) -} diff --git a/internal/batches/graphql/operations.go b/internal/batches/graphql/operations.go deleted file mode 100644 index fe1b721543..0000000000 --- a/internal/batches/graphql/operations.go +++ /dev/null @@ -1,39 +0,0 @@ -package graphql - -import ( - "context" - - "github.com/sourcegraph/src-cli/internal/api" -) - -// Operations defines queries and mutations that are used by src-cli for Batch -// Change operations, and that vary between the old Campaigns world and the new -// Batch Changes world. -// -// TODO(campaigns-deprecation): this can be removed in Sourcegraph 4.0. -type Operations interface { - ApplyBatchChange(ctx context.Context, batchSpecID BatchSpecID) (*BatchChange, error) - CreateBatchSpec(ctx context.Context, namespace, spec string, changesetSpecIDs []ChangesetSpecID) (*CreateBatchSpecResponse, error) -} - -type BatchSpecID string -type ChangesetSpecID string - -type CreateBatchSpecResponse struct { - ID BatchSpecID - ApplyURL string -} - -func NewOperations(client api.Client, batchChanges, useGzipCompression bool) Operations { - backend := commonBackend{ - client: client, - useGzipCompression: useGzipCompression, - } - - if batchChanges { - return &batchesBackend{backend} - } - - return &campaignsBackend{backend} - -} diff --git a/internal/batches/service/remote.go b/internal/batches/service/remote.go index dc63a47daf..87733240b8 100644 --- a/internal/batches/service/remote.go +++ b/internal/batches/service/remote.go @@ -8,13 +8,6 @@ import ( var ErrServerSideBatchChangesUnsupported = errors.New("server side batch changes are not available on this Sourcegraph instance") -func (svc *Service) areServerSideBatchChangesSupported() error { - if !svc.features.ServerSideBatchChanges { - return ErrServerSideBatchChangesUnsupported - } - return nil -} - const upsertEmptyBatchChangeQuery = ` mutation UpsertEmptyBatchChange( $name: String! @@ -34,10 +27,6 @@ func (svc *Service) UpsertBatchChange( name string, namespaceID string, ) (string, error) { - if err := svc.areServerSideBatchChangesSupported(); err != nil { - return "", err - } - var resp struct { UpsertEmptyBatchChange struct { Name string `json:"name"` @@ -82,10 +71,6 @@ func (svc *Service) CreateBatchSpecFromRaw( allowUnsupported bool, noCache bool, ) (string, error) { - if err := svc.areServerSideBatchChangesSupported(); err != nil { - return "", err - } - var resp struct { CreateBatchSpecFromRaw struct { ID string `json:"id"` @@ -118,10 +103,6 @@ func (svc *Service) ExecuteBatchSpec( batchSpecID string, noCache bool, ) (string, error) { - if err := svc.areServerSideBatchChangesSupported(); err != nil { - return "", err - } - var resp struct { ExecuteBatchSpec struct { ID string `json:"id"` @@ -157,10 +138,6 @@ type BatchSpecWorkspaceResolution struct { } func (svc *Service) GetBatchSpecWorkspaceResolution(ctx context.Context, id string) (*BatchSpecWorkspaceResolution, error) { - if err := svc.areServerSideBatchChangesSupported(); err != nil { - return nil, err - } - var resp struct { Node struct { WorkspaceResolution BatchSpecWorkspaceResolution `json:"workspaceResolution"` diff --git a/internal/batches/service/service.go b/internal/batches/service/service.go index 7a8287f031..960de35283 100644 --- a/internal/batches/service/service.go +++ b/internal/batches/service/service.go @@ -23,8 +23,7 @@ import ( ) type Service struct { - client api.Client - features batches.FeatureFlags + client api.Client } type Opts struct { @@ -73,49 +72,70 @@ func (svc *Service) getSourcegraphVersion(ctx context.Context) (string, error) { return result.Site.ProductVersion, err } -// DetermineFeatureFlags fetches the version of the configured Sourcegraph -// instance and then sets flags on the Service itself to use features available -// in that version, e.g. gzip compression. -func (svc *Service) DetermineFeatureFlags(ctx context.Context) error { +// DetermineFeatureFlags fetches the version of the configured Sourcegraph and +// returns the enabled features. +func (svc *Service) DetermineFeatureFlags(ctx context.Context) (*batches.FeatureFlags, error) { version, err := svc.getSourcegraphVersion(ctx) if err != nil { - return errors.Wrap(err, "failed to query Sourcegraph version to check for available features") + return nil, errors.Wrap(err, "failed to query Sourcegraph version to check for available features") } - - return svc.SetFeatureFlagsForVersion(version) + ffs := &batches.FeatureFlags{} + return ffs, ffs.SetFromVersion(version) } -func (svc *Service) SetFeatureFlagsForVersion(version string) error { - return svc.features.SetFromVersion(version) +const applyBatchChangeMutation = ` +mutation ApplyBatchChange($batchSpec: ID!) { + applyBatchChange(batchSpec: $batchSpec) { + ...batchChangeFields + } } -// TODO(campaigns-deprecation): this shim can be removed in Sourcegraph 4.0. -func (svc *Service) newOperations() graphql.Operations { - return graphql.NewOperations( - svc.client, - svc.features.BatchChanges, - svc.features.UseGzipCompression, - ) +fragment batchChangeFields on BatchChange { + url } +` -func (svc *Service) newRequest(query string, vars map[string]interface{}) api.Request { - if svc.features.UseGzipCompression { - return svc.client.NewGzippedRequest(query, vars) +func (svc *Service) ApplyBatchChange(ctx context.Context, spec graphql.BatchSpecID) (*graphql.BatchChange, error) { + var result struct { + BatchChange *graphql.BatchChange `json:"applyBatchChange"` + } + if ok, err := svc.client.NewRequest(applyBatchChangeMutation, map[string]interface{}{ + "batchSpec": spec, + }).Do(ctx, &result); err != nil || !ok { + return nil, err } - return svc.client.NewRequest(query, vars) + return result.BatchChange, nil } -func (svc *Service) ApplyBatchChange(ctx context.Context, spec graphql.BatchSpecID) (*graphql.BatchChange, error) { - return svc.newOperations().ApplyBatchChange(ctx, spec) +const createBatchSpecMutation = ` +mutation CreateBatchSpec( + $namespace: ID!, + $spec: String!, + $changesetSpecs: [ID!]! +) { + createBatchSpec( + namespace: $namespace, + batchSpec: $spec, + changesetSpecs: $changesetSpecs + ) { + id + applyURL + } } +` func (svc *Service) CreateBatchSpec(ctx context.Context, namespace, spec string, ids []graphql.ChangesetSpecID) (graphql.BatchSpecID, string, error) { - result, err := svc.newOperations().CreateBatchSpec(ctx, namespace, spec, ids) - if err != nil { + var result struct { + CreateBatchSpec graphql.CreateBatchSpecResponse + } + if ok, err := svc.client.NewRequest(createBatchSpecMutation, map[string]interface{}{ + "namespace": namespace, + "spec": spec, + "changesetSpecs": ids, + }).Do(ctx, &result); err != nil || !ok { return "", "", err } - - return result.ID, result.ApplyURL, nil + return result.CreateBatchSpec.ID, result.CreateBatchSpec.ApplyURL, nil } const createChangesetSpecMutation = ` @@ -142,7 +162,7 @@ func (svc *Service) CreateChangesetSpec(ctx context.Context, spec *batcheslib.Ch ID string } } - if ok, err := svc.newRequest(createChangesetSpecMutation, map[string]interface{}{ + if ok, err := svc.client.NewRequest(createChangesetSpecMutation, map[string]interface{}{ "spec": string(raw), }).Do(ctx, &result); err != nil || !ok { return "", err @@ -196,7 +216,7 @@ func (svc *Service) ResolveWorkspacesForBatchSpec(ctx context.Context, spec *bat SearchResultPaths []string } } - if ok, err := svc.newRequest(resolveWorkspacesForBatchSpecQuery, map[string]interface{}{ + if ok, err := svc.client.NewRequest(resolveWorkspacesForBatchSpecQuery, map[string]interface{}{ "spec": string(raw), }).Do(ctx, &result); err != nil || !ok { return nil, nil, err @@ -364,10 +384,6 @@ func (svc *Service) BuildTasks(attributes *templatelib.BatchChangeAttributes, st return buildTasks(attributes, steps, workspaces) } -func (svc *Service) Features() batches.FeatureFlags { - return svc.features -} - func (svc *Service) CreateImportChangesetSpecs(ctx context.Context, batchSpec *batcheslib.BatchSpec) ([]*batcheslib.ChangesetSpec, error) { return batcheslib.BuildImportChangesetSpecs(ctx, batchSpec.ImportChangesets, func(ctx context.Context, repoNames []string) (_ map[string]string, errs error) { repoNameIDs := map[string]string{} @@ -451,11 +467,7 @@ func (e *duplicateBranchesErr) Error() string { } func (svc *Service) ParseBatchSpec(dir string, data []byte, isRemote bool) (*batcheslib.BatchSpec, error) { - spec, err := batcheslib.ParseBatchSpec(data, batcheslib.ParseBatchSpecOptions{ - AllowArrayEnvironments: svc.features.AllowArrayEnvironments, - AllowTransformChanges: svc.features.AllowTransformChanges, - AllowConditionalExec: svc.features.AllowConditionalExec, - }) + spec, err := batcheslib.ParseBatchSpec(data) if err != nil { return nil, errors.Wrap(err, "parsing batch spec") } @@ -530,11 +542,6 @@ changesetTemplate: message: Append Hello World to all README.md files ` -const exampleSpecPublishFlagTmpl = ` - # Change published to true once you're ready to create changesets on the code host. - published: false -` - func (svc *Service) GenerateExampleSpec(ctx context.Context, fileName string) error { // Try to create file. Bail out, if it already exists. f, err := os.OpenFile(fileName, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0644) @@ -546,11 +553,7 @@ func (svc *Service) GenerateExampleSpec(ctx context.Context, fileName string) er } defer f.Close() - t := exampleSpecTmpl - if !svc.features.AllowOptionalPublished { - t += exampleSpecPublishFlagTmpl - } - tmpl, err := template.New("").Parse(t) + tmpl, err := template.New("").Parse(exampleSpecTmpl) if err != nil { return err } diff --git a/internal/batches/ui/tui.go b/internal/batches/ui/tui.go index bedec35639..ed3e5e3117 100644 --- a/internal/batches/ui/tui.go +++ b/internal/batches/ui/tui.go @@ -274,7 +274,7 @@ func prettyPrintBatchUnlicensedError(out *output.Output, err error) error { // verbose mode, but let the original error bubble up rather // than this one. out.Verbosef("Unexpected error parsing the GraphQL error: %v", cerr) - } else if code == "ErrCampaignsUnlicensed" || code == "ErrBatchChangesUnlicensed" { + } else if code == "ErrBatchChangesUnlicensed" { // OK, let's print a better message, then return an // exitCodeError to suppress the normal automatic error block. // Note that we have hand wrapped the output at 80 (printable)