Skip to content

Commit a8a0678

Browse files
committed
fixup! move some more variables into the httpClient
1 parent 85e6f48 commit a8a0678

5 files changed

Lines changed: 46 additions & 117 deletions

File tree

submitqueue/extension/buildrunner/buildkite/BUILD.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ go_library(
66
"buildkite.go",
77
"client.go",
88
"config.go",
9-
"factory.go",
109
],
1110
importpath = "github.com/uber/submitqueue/submitqueue/extension/buildrunner/buildkite",
1211
visibility = ["//visibility:public"],
@@ -21,6 +20,7 @@ go_test(
2120
srcs = ["buildkite_test.go"],
2221
embed = [":buildkite"],
2322
deps = [
23+
"//core/httpclient",
2424
"//submitqueue/entity",
2525
"//submitqueue/extension/buildrunner",
2626
"@com_github_stretchr_testify//assert",

submitqueue/extension/buildrunner/buildkite/buildkite.go

Lines changed: 21 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ import (
4646
"fmt"
4747
"net/http"
4848
"strconv"
49-
"strings"
5049
"sync"
5150
"time"
5251

@@ -146,19 +145,11 @@ type Params struct {
146145
// pipeline and starts its background worker goroutine. The goroutine runs for
147146
// the lifetime of the process.
148147
//
149-
// Returns an error if OrgSlug, PipelineSlug, or Branch are empty.
148+
// The HTTPClient must have BaseURLTransport configured to the pipeline's API
149+
// root (e.g. "https://api.buildkite.com/v2/organizations/{org}/pipelines/{slug}"),
150+
// and an auth transport that injects the Authorization header.
150151
func NewBuildRunner(params Params) (buildrunner.BuildRunner, error) {
151152
cfg := params.Config
152-
if cfg.OrgSlug == "" {
153-
return nil, fmt.Errorf("buildkite: OrgSlug is required")
154-
}
155-
if cfg.PipelineSlug == "" {
156-
return nil, fmt.Errorf("buildkite: PipelineSlug is required")
157-
}
158-
if cfg.Branch == "" {
159-
return nil, fmt.Errorf("buildkite: Branch is required")
160-
}
161-
162153
httpClient := params.HTTPClient
163154
if httpClient == nil {
164155
httpClient = http.DefaultClient
@@ -231,11 +222,11 @@ func (r *runner) Status(ctx context.Context, buildID entity.BuildID) (entity.Bui
231222
var resp buildResponse
232223
switch {
233224
case cached:
234-
org, pipeline, number, err := parseBuildRef(ref)
225+
number, err := parseBuildRef(ref)
235226
if err != nil {
236227
return entity.BuildStatusUnknown, nil, fmt.Errorf("buildkite: malformed build ref: %w", err)
237228
}
238-
resp, err = r.client.getBuild(ctx, org, pipeline, number)
229+
resp, err = r.client.getBuild(ctx, number)
239230
if err != nil {
240231
return entity.BuildStatusUnknown, nil, fmt.Errorf("buildkite: get build: %w", err)
241232
}
@@ -246,7 +237,7 @@ func (r *runner) Status(ctx context.Context, buildID entity.BuildID) (entity.Bui
246237
// loop in Accepted forever.
247238
return entity.BuildStatusFailed, entity.BuildMetadata{"error": reason}, nil
248239
}
249-
found, exists, err := r.client.findBuildByMeta(ctx, r.cfg.OrgSlug, r.cfg.PipelineSlug, metaKeyBuildID, buildID.ID)
240+
found, exists, err := r.client.findBuildByMeta(ctx, metaKeyBuildID, buildID.ID)
250241
if err != nil {
251242
return entity.BuildStatusUnknown, nil, fmt.Errorf("buildkite: find build: %w", err)
252243
}
@@ -256,7 +247,7 @@ func (r *runner) Status(ctx context.Context, buildID entity.BuildID) (entity.Bui
256247
// loop keeps waiting without treating this as terminal.
257248
return entity.BuildStatusAccepted, nil, nil
258249
}
259-
ref = encodeBuildRef(r.cfg.OrgSlug, r.cfg.PipelineSlug, found.Number)
250+
ref = encodeBuildRef(found.Number)
260251
r.storeRef(buildID.ID, ref)
261252
resp = found
262253
}
@@ -305,7 +296,6 @@ func (r *runner) processTrigger(job triggerJob) {
305296
headJSON, _ := json.Marshal(job.headURIs)
306297

307298
req := createBuildRequest{
308-
Branch: r.cfg.Branch,
309299
Message: "submitqueue speculative build",
310300
Env: map[string]string{
311301
EnvKeyBaseURIs: string(baseJSON),
@@ -322,15 +312,15 @@ func (r *runner) processTrigger(job triggerJob) {
322312
ctx, cancel := r.opCtx()
323313
defer cancel()
324314
var e error
325-
resp, e = r.client.createBuild(ctx, r.cfg.OrgSlug, r.cfg.PipelineSlug, req)
315+
resp, e = r.client.createBuild(ctx, req)
326316
return e
327317
})
328318
if err != nil {
329319
r.markSubmitFailed(job.buildID, fmt.Sprintf("buildkite submission failed after retries: %v", err))
330320
return
331321
}
332322

333-
r.storeRef(job.buildID, encodeBuildRef(r.cfg.OrgSlug, r.cfg.PipelineSlug, resp.Number))
323+
r.storeRef(job.buildID, encodeBuildRef(resp.Number))
334324
}
335325

336326
// processCancel cancels the Buildkite build, recovering its reference from the
@@ -340,26 +330,26 @@ func (r *runner) processCancel(job cancelJob) {
340330
ref, cached := r.lookupRef(job.buildID)
341331
if !cached {
342332
ctx, cancel := r.opCtx()
343-
found, exists, err := r.client.findBuildByMeta(ctx, r.cfg.OrgSlug, r.cfg.PipelineSlug, metaKeyBuildID, job.buildID)
333+
found, exists, err := r.client.findBuildByMeta(ctx, metaKeyBuildID, job.buildID)
344334
cancel()
345335
if err != nil || !exists {
346336
// Nothing to cancel (not yet submitted) or a transient lookup
347337
// failure; the caller may re-issue Cancel.
348338
return
349339
}
350-
ref = encodeBuildRef(r.cfg.OrgSlug, r.cfg.PipelineSlug, found.Number)
340+
ref = encodeBuildRef(found.Number)
351341
r.storeRef(job.buildID, ref)
352342
}
353343

354-
org, pipeline, number, err := parseBuildRef(ref)
344+
number, err := parseBuildRef(ref)
355345
if err != nil {
356346
return
357347
}
358348

359349
_ = r.withRetry(func() error {
360350
ctx, cancel := r.opCtx()
361351
defer cancel()
362-
return r.client.cancelBuild(ctx, org, pipeline, number)
352+
return r.client.cancelBuild(ctx, number)
363353
})
364354
}
365355

@@ -450,30 +440,19 @@ func flattenURIs(changes []entity.Change) []string {
450440
return uris
451441
}
452442

453-
// encodeBuildRef encodes org, pipeline, and build number into the internal
454-
// reference string stored in r.refs.
455-
// Format: "{org}/{pipeline}/{number}". Buildkite slugs are [a-z0-9-] so "/"
456-
// is unambiguous as a separator.
457-
func encodeBuildRef(org, pipeline string, number int) string {
458-
return fmt.Sprintf("%s/%s/%d", org, pipeline, number)
443+
// encodeBuildRef encodes a Buildkite build number as the internal reference
444+
// string stored in r.refs.
445+
func encodeBuildRef(number int) string {
446+
return strconv.Itoa(number)
459447
}
460448

461449
// parseBuildRef is the inverse of encodeBuildRef.
462-
func parseBuildRef(ref string) (org, pipeline string, number int, err error) {
463-
last := strings.LastIndex(ref, "/")
464-
if last < 1 {
465-
return "", "", 0, fmt.Errorf("invalid build ref %q", ref)
466-
}
467-
number, err = strconv.Atoi(ref[last+1:])
450+
func parseBuildRef(ref string) (int, error) {
451+
n, err := strconv.Atoi(ref)
468452
if err != nil {
469-
return "", "", 0, fmt.Errorf("invalid build ref %q: non-numeric number segment", ref)
470-
}
471-
prefix := ref[:last]
472-
first := strings.Index(prefix, "/")
473-
if first < 1 {
474-
return "", "", 0, fmt.Errorf("invalid build ref %q", ref)
453+
return 0, fmt.Errorf("invalid build ref %q", ref)
475454
}
476-
return prefix[:first], prefix[first+1:], number, nil
455+
return n, nil
477456
}
478457

479458
// mapState maps a Buildkite build state string to a BuildStatus.

submitqueue/extension/buildrunner/buildkite/buildkite_test.go

Lines changed: 16 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,7 @@ func newTestRunner(t *testing.T, handler http.Handler) *runner {
4242
require.NoError(t, err)
4343
return newRunner(
4444
Config{
45-
OrgSlug: "test-org",
46-
PipelineSlug: "my-pipeline",
4745
QueueName: "my-queue",
48-
Branch: "main",
4946
SubmitTimeout: 5 * time.Second,
5047
MaxSubmitAttempts: 3,
5148
SubmitBackoff: time.Millisecond,
@@ -100,32 +97,11 @@ func emptyListHandler(t *testing.T) http.HandlerFunc {
10097
// --- Interface / constructor ---
10198

10299
func TestNew_ImplementsInterface(t *testing.T) {
103-
r, err := NewBuildRunner(Params{Config: Config{
104-
OrgSlug: "org",
105-
PipelineSlug: "pipeline",
106-
Branch: "main",
107-
}})
100+
r, err := NewBuildRunner(Params{})
108101
require.NoError(t, err)
109102
var _ buildrunner.BuildRunner = r
110103
}
111104

112-
func TestNew_Validation(t *testing.T) {
113-
tests := []struct {
114-
name string
115-
params Params
116-
}{
117-
{"missing org", Params{Config: Config{PipelineSlug: "p", Branch: "main"}}},
118-
{"missing pipeline", Params{Config: Config{OrgSlug: "org", Branch: "main"}}},
119-
{"missing branch", Params{Config: Config{OrgSlug: "org", PipelineSlug: "p"}}},
120-
}
121-
for _, tt := range tests {
122-
t.Run(tt.name, func(t *testing.T) {
123-
_, err := NewBuildRunner(tt.params)
124-
require.Error(t, err)
125-
})
126-
}
127-
}
128-
129105
// --- Trigger ---
130106

131107
func TestTrigger_EnqueuesJobAndReturnsID(t *testing.T) {
@@ -177,7 +153,6 @@ func TestTrigger_SubmitsCorrectPayloadToBuildkite(t *testing.T) {
177153

178154
var req createBuildRequest
179155
require.NoError(t, json.Unmarshal(capturedBody, &req))
180-
assert.Equal(t, "main", req.Branch)
181156
assert.Equal(t, `["github://org/repo/pull/1/aaa111"]`, req.Env[EnvKeyBaseURIs])
182157
assert.Equal(t, `["github://org/repo/pull/2/bbb222"]`, req.Env[EnvKeyHeadURIs])
183158
assert.Equal(t, "my-queue", req.Env[EnvKeyQueue])
@@ -188,7 +163,7 @@ func TestTrigger_SubmitsCorrectPayloadToBuildkite(t *testing.T) {
188163
// After a successful submit the ref is cached, so Status uses getBuild.
189164
ref, ok := r.lookupRef(id.ID)
190165
require.True(t, ok)
191-
assert.Equal(t, encodeBuildRef("test-org", "my-pipeline", 42), ref)
166+
assert.Equal(t, encodeBuildRef(42), ref)
192167
}
193168

194169
func TestTrigger_EmptyBase_ProducesJSONArray(t *testing.T) {
@@ -235,7 +210,7 @@ func TestTrigger_MultipleChangesFlattened(t *testing.T) {
235210

236211
func TestTrigger_QueueFull_ReturnsError(t *testing.T) {
237212
r := newRunner(
238-
Config{OrgSlug: "org", PipelineSlug: "p", Branch: "main"},
213+
Config{},
239214
&client{httpClient: http.DefaultClient},
240215
1, 1,
241216
)
@@ -267,7 +242,7 @@ func TestProcessTrigger_RetriesTransientFailureThenSucceeds(t *testing.T) {
267242
assert.Equal(t, 2, posts, "submit should retry after a transient failure")
268243
ref, ok := r.lookupRef(id.ID)
269244
require.True(t, ok)
270-
assert.Equal(t, encodeBuildRef("test-org", "my-pipeline", 7), ref)
245+
assert.Equal(t, encodeBuildRef(7), ref)
271246
}
272247

273248
func TestTrigger_SubmitExhaustsRetries_BuildFails(t *testing.T) {
@@ -331,7 +306,7 @@ func TestStatus_ReturnsLiveBuildkiteState(t *testing.T) {
331306
}))
332307

333308
// Inject ref directly (simulates successful processTrigger).
334-
r.storeRef("some-id", encodeBuildRef("test-org", "my-pipeline", 7))
309+
r.storeRef("some-id", encodeBuildRef(7))
335310

336311
status, meta, err := r.Status(context.Background(), entity.BuildID{ID: "some-id"})
337312
require.NoError(t, err)
@@ -360,14 +335,14 @@ func TestStatus_RecoversRefAfterCacheMiss(t *testing.T) {
360335
// The recovered ref is now cached for subsequent calls.
361336
ref, ok := r.lookupRef("bk-lost")
362337
require.True(t, ok)
363-
assert.Equal(t, encodeBuildRef("test-org", "my-pipeline", 7), ref)
338+
assert.Equal(t, encodeBuildRef(7), ref)
364339
}
365340

366341
func TestStatus_BuildkiteNotFound(t *testing.T) {
367342
r := newTestRunner(t, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
368343
w.WriteHeader(http.StatusNotFound)
369344
}))
370-
r.storeRef("some-id", encodeBuildRef("test-org", "my-pipeline", 99))
345+
r.storeRef("some-id", encodeBuildRef(99))
371346

372347
_, _, err := r.Status(context.Background(), entity.BuildID{ID: "some-id"})
373348
require.Error(t, err)
@@ -391,7 +366,7 @@ func TestCancel_CallsBuildkiteWhenRefKnown(t *testing.T) {
391366
w.WriteHeader(http.StatusOK)
392367
_, _ = w.Write(buildJSON(5, "canceled", ""))
393368
}))
394-
r.storeRef("some-id", encodeBuildRef("test-org", "my-pipeline", 5))
369+
r.storeRef("some-id", encodeBuildRef(5))
395370

396371
require.NoError(t, r.Cancel(context.Background(), entity.BuildID{ID: "some-id"}))
397372
drainCancel(t, r)
@@ -435,15 +410,15 @@ func TestCancel_AlreadyTerminal_Noop(t *testing.T) {
435410
r := newTestRunner(t, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
436411
w.WriteHeader(http.StatusUnprocessableEntity)
437412
}))
438-
r.storeRef("some-id", encodeBuildRef("test-org", "my-pipeline", 5))
413+
r.storeRef("some-id", encodeBuildRef(5))
439414

440415
require.NoError(t, r.Cancel(context.Background(), entity.BuildID{ID: "some-id"}))
441416
drainCancel(t, r) // must not panic or error
442417
}
443418

444419
func TestCancel_QueueFull_ReturnsError(t *testing.T) {
445420
r := newRunner(
446-
Config{OrgSlug: "org", PipelineSlug: "p", Branch: "main"},
421+
Config{},
447422
&client{httpClient: http.DefaultClient},
448423
1, 1,
449424
)
@@ -454,29 +429,18 @@ func TestCancel_QueueFull_ReturnsError(t *testing.T) {
454429
// --- Internal helpers ---
455430

456431
func TestEncodeParseBuildRef_RoundTrip(t *testing.T) {
457-
tests := []struct {
458-
org string
459-
pipeline string
460-
number int
461-
}{
462-
{"myorg", "my-pipeline", 1},
463-
{"uber", "submit-queue-ci", 9999},
464-
{"a", "b", 0},
465-
}
466-
for _, tt := range tests {
467-
ref := encodeBuildRef(tt.org, tt.pipeline, tt.number)
468-
org, pipeline, number, err := parseBuildRef(ref)
432+
for _, n := range []int{1, 9999, 0} {
433+
ref := encodeBuildRef(n)
434+
got, err := parseBuildRef(ref)
469435
require.NoError(t, err)
470-
assert.Equal(t, tt.org, org)
471-
assert.Equal(t, tt.pipeline, pipeline)
472-
assert.Equal(t, tt.number, number)
436+
assert.Equal(t, n, got)
473437
}
474438
}
475439

476440
func TestParseBuildRef_Invalid(t *testing.T) {
477-
for _, ref := range []string{"", "noslash", "only/one", "org/pipeline/notanumber"} {
441+
for _, ref := range []string{"", "notanumber", "org/pipeline/1"} {
478442
t.Run(ref, func(t *testing.T) {
479-
_, _, _, err := parseBuildRef(ref)
443+
_, err := parseBuildRef(ref)
480444
require.Error(t, err)
481445
})
482446
}

0 commit comments

Comments
 (0)