Skip to content

Commit 7f82fde

Browse files
authored
campaigns: restore pre-3.20 instance compatibility (#370)
The author name and e-mail fields were always sent, but the schema Sourcegraph 3.19 uses to validate changeset specs don't include these fields. Since we're doing version detection for feature flags (quirks) now anyway, let's use that to not set the author name and e-mail if they're not explicitly provided when talking to a 3.19 instance. If the user provides an author name and/or e-mail and sends a changeset spec to a pre-3.20 instance, the request will fail, but since those are 3.20 features that's OK.
1 parent 97ff80a commit 7f82fde

File tree

7 files changed

+68
-28
lines changed

7 files changed

+68
-28
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ All notable changes to `src-cli` are documented in this file.
1717

1818
### Fixed
1919

20+
- Restored backward compatibility when creating campaigns against Sourcegraph 3.19, provided author details are not provided in the campaign spec. [#370](https://github.com/sourcegraph/src-cli/pull/370)
21+
2022
### Removed
2123

2224
## 3.21.6

internal/campaigns/changeset_spec.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,6 @@ type CreatedChangeset struct {
2828
type GitCommitDescription struct {
2929
Message string `json:"message"`
3030
Diff string `json:"diff"`
31-
AuthorName string `json:"authorName"`
32-
AuthorEmail string `json:"authorEmail"`
31+
AuthorName string `json:"authorName,omitempty"`
32+
AuthorEmail string `json:"authorEmail,omitempty"`
3333
}

internal/campaigns/executor.go

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -85,12 +85,13 @@ func (ts *TaskStatus) IsCompleted() bool {
8585
type executor struct {
8686
ExecutorOpts
8787

88-
cache ExecutionCache
89-
client api.Client
90-
logger *LogManager
91-
creator *WorkspaceCreator
92-
tasks sync.Map
93-
tempDir string
88+
cache ExecutionCache
89+
client api.Client
90+
features featureFlags
91+
logger *LogManager
92+
creator *WorkspaceCreator
93+
tasks sync.Map
94+
tempDir string
9495

9596
par *parallel.Run
9697
doneEnqueuing chan struct{}
@@ -99,12 +100,13 @@ type executor struct {
99100
specsMu sync.Mutex
100101
}
101102

102-
func newExecutor(opts ExecutorOpts, client api.Client) *executor {
103+
func newExecutor(opts ExecutorOpts, client api.Client, features featureFlags) *executor {
103104
return &executor{
104105
ExecutorOpts: opts,
105106
cache: opts.Cache,
106107
creator: opts.Creator,
107108
client: client,
109+
features: features,
108110
doneEnqueuing: make(chan struct{}),
109111
logger: NewLogManager(opts.TempDir, opts.KeepLogs),
110112
tempDir: opts.TempDir,
@@ -208,7 +210,7 @@ func (x *executor) do(ctx context.Context, task *Task) (err error) {
208210
diff = result.Commits[0].Diff
209211
}
210212

211-
spec := createChangesetSpec(task, diff)
213+
spec := createChangesetSpec(task, diff, x.features)
212214

213215
status.Cached = true
214216
status.ChangesetSpec = spec
@@ -267,7 +269,7 @@ func (x *executor) do(ctx context.Context, task *Task) (err error) {
267269
}
268270

269271
// Build the changeset spec.
270-
spec := createChangesetSpec(task, string(diff))
272+
spec := createChangesetSpec(task, string(diff), x.features)
271273

272274
status.ChangesetSpec = spec
273275
x.updateTaskStatus(task, status)
@@ -305,16 +307,18 @@ func reachedTimeout(cmdCtx context.Context, err error) bool {
305307
return errors.Is(err, context.DeadlineExceeded)
306308
}
307309

308-
func createChangesetSpec(task *Task, diff string) *ChangesetSpec {
310+
func createChangesetSpec(task *Task, diff string, features featureFlags) *ChangesetSpec {
309311
repo := task.Repository.Name
310312

311313
var authorName string
312314
var authorEmail string
313315

314316
if task.Template.Commit.Author == nil {
315-
// user did not provide author info, so use defaults
316-
authorName = "Sourcegraph"
317-
authorEmail = "[email protected]"
317+
if features.includeAutoAuthorDetails {
318+
// user did not provide author info, so use defaults
319+
authorName = "Sourcegraph"
320+
authorEmail = "[email protected]"
321+
}
318322
} else {
319323
authorName = task.Template.Commit.Author.Name
320324
authorEmail = task.Template.Commit.Author.Email

internal/campaigns/executor_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ func TestExecutor_Integration(t *testing.T) {
144144
opts.Timeout = 5 * time.Second
145145
}
146146

147-
executor := newExecutor(opts, client)
147+
executor := newExecutor(opts, client, featuresAllEnabled())
148148

149149
template := &ChangesetTemplate{}
150150
for _, r := range tc.repos {

internal/campaigns/features.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package campaigns
2+
3+
import (
4+
"github.com/pkg/errors"
5+
"github.com/sourcegraph/src-cli/internal/api"
6+
)
7+
8+
// featureFlags represent features that are only available on certain
9+
// Sourcegraph versions and we therefore have to detect at runtime.
10+
type featureFlags struct {
11+
includeAutoAuthorDetails bool
12+
useGzipCompression bool
13+
}
14+
15+
func (ff *featureFlags) setFromVersion(version string) error {
16+
for _, feature := range []struct {
17+
flag *bool
18+
constraint string
19+
minDate string
20+
}{
21+
{&ff.includeAutoAuthorDetails, ">= 3.20.0", "2020-09-10"},
22+
{&ff.useGzipCompression, ">= 3.21.0", "2020-10-12"},
23+
} {
24+
value, err := api.CheckSourcegraphVersion(version, feature.constraint, feature.minDate)
25+
if err != nil {
26+
return errors.Wrap(err, "failed to check version returned by Sourcegraph")
27+
}
28+
*feature.flag = value
29+
}
30+
31+
return nil
32+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package campaigns
2+
3+
func featuresAllEnabled() featureFlags {
4+
return featureFlags{
5+
includeAutoAuthorDetails: true,
6+
useGzipCompression: true,
7+
}
8+
}

internal/campaigns/service.go

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ import (
1717
)
1818

1919
type Service struct {
20-
allowUnsupported bool
21-
client api.Client
22-
useGzipCompression bool
20+
allowUnsupported bool
21+
client api.Client
22+
features featureFlags
2323
}
2424

2525
type ServiceOpts struct {
@@ -71,17 +71,11 @@ func (svc *Service) DetermineFeatureFlags(ctx context.Context) error {
7171
return errors.Wrap(err, "failed to query Sourcegraph version to check for available features")
7272
}
7373

74-
supportsGzip, err := api.CheckSourcegraphVersion(version, ">= 3.21.0", "2020-10-12")
75-
if err != nil {
76-
return errors.Wrap(err, "failed to check version returned by Sourcegraph")
77-
}
78-
svc.useGzipCompression = supportsGzip
79-
80-
return nil
74+
return svc.features.setFromVersion(version)
8175
}
8276

8377
func (svc *Service) newRequest(query string, vars map[string]interface{}) api.Request {
84-
if svc.useGzipCompression {
78+
if svc.features.useGzipCompression {
8579
return svc.client.NewGzippedRequest(query, vars)
8680
}
8781
return svc.client.NewRequest(query, vars)
@@ -201,7 +195,7 @@ type ExecutorOpts struct {
201195
}
202196

203197
func (svc *Service) NewExecutor(opts ExecutorOpts) Executor {
204-
return newExecutor(opts, svc.client)
198+
return newExecutor(opts, svc.client, svc.features)
205199
}
206200

207201
func (svc *Service) NewWorkspaceCreator(dir string, cleanArchives bool) *WorkspaceCreator {

0 commit comments

Comments
 (0)