diff --git a/Makefile b/Makefile index c3e4bb2c7..22d48888d 100644 --- a/Makefile +++ b/Makefile @@ -591,7 +591,7 @@ GO_GENERATE_PACKAGES := \ ./runway/extension/merger/... \ ./stovepipe/core/requestlog/... \ ./stovepipe/extension/buildrunner/... \ - ./stovepipe/extension/projectresult/... \ + ./stovepipe/extension/projectstatus/... \ ./stovepipe/extension/queueconfig/... \ ./stovepipe/extension/sourcecontrol/... \ ./stovepipe/extension/storage/... \ diff --git a/doc/rfc/stovepipe/workflow.md b/doc/rfc/stovepipe/workflow.md index a3683db42..9a1466472 100644 --- a/doc/rfc/stovepipe/workflow.md +++ b/doc/rfc/stovepipe/workflow.md @@ -43,7 +43,7 @@ Greenness is recorded as a **health degree** where **`0` means green** and **hig ### Project — greenness at a finer grain -A **project** is a caller-defined slice of the repository. Whole-repo greenness answers "is the branch green at this URI"; project greenness answers the question deployments actually need — **"is *this project* green at this URI"**, and its dual, "what is the latest URI at which this project is green". The running pipeline does not derive projects from a target graph. On a succeeded or failed request, `record` gives the request's terminal build id to `projectresult.Resolver` and writes one validation fact per result it returns. The example server wires the noop resolver, which returns no results. How a resolver chooses projects is implementer-specific. The separate analyze stage that would map a target graph to project-scoped builds is not built; see [Designed, not built](#designed-not-built-project-analysis). +A **project** is a caller-defined slice of the repository. Whole-repo greenness answers "is the branch green at this URI"; project greenness answers the question deployments actually need — **"is *this project* green at this URI"**, and its dual, "what is the latest URI at which this project is green". The running pipeline does not derive projects from a target graph. On a succeeded or failed request, `record` gives the request's terminal build id to `projectstatus.Resolver` and writes one validation fact per result it returns. The example server wires the noop resolver, which returns no results. How a resolver chooses projects is implementer-specific. The separate analyze stage that would map a target graph to project-scoped builds is not built; see [Designed, not built](#designed-not-built-project-analysis). ### Promotion ref — the last green commit, by name @@ -64,7 +64,7 @@ Hooks are the notification boundary. When validation of a commit begins, when a ## Workflow -What runs is one pass per Request. It establishes whole-repository greenness, and on a succeeded or failed outcome `record` also gives the Request's terminal build id to `projectresult.Resolver` before writing whatever project facts it returns. That call is inline on the record delivery. It does not publish to another stage, and it does not start another build. +What runs is one pass per Request. It establishes whole-repository greenness, and on a succeeded or failed outcome `record` also gives the Request's terminal build id to `projectstatus.Resolver` before writing whatever project facts it returns. That call is inline on the record delivery. It does not publish to another stage, and it does not start another build. ``` external poller ──(Queue name)──► ┌──────────────────────────────┐ @@ -116,7 +116,7 @@ What runs is one pass per Request. It establishes whole-repository greenness, an 2. **process** — decides build strategy (incremental since last-green vs full monorepo), gates concurrent work per Queue, coalesces backlog to the latest head, publishes a **hook event** announcing that validation of the commit has begun, and publishes to `build`. See [process.md](steps/process.md). 3. **build** — runs the build-runner for the chosen scope. A flag derived from `process` decides whether to build relative to the last-green **baseline URI** (incremental) or from scratch (full). It records a build and publishes the BuildID. 4. **buildsignal** — polls until the build is terminal, records that status, releases the Queue's `in_flight_count` slot, projects the terminal status and build id onto the Request (`succeeded` / `failed` / `cancelled`), and publishes the RequestID to `record`. -5. **record** — for a succeeded or failed Request, writes the whole-repo greenness for the head URI (`0` green / `1` broken to start), derived from the Request's build outcome. On green it advances the Queue's **last-green URI** so the next `process` can build incrementally from here, and asks `SourceControl` to advance the Queue's **promotion ref** to the same commit (see [Promotion ref](#promotion-ref--the-last-green-commit-by-name)). It then gives the Request's terminal build id to `projectresult.Resolver` and writes one validation fact per returned result. The example server uses the noop resolver, so that list is empty unless a deployment supplies another. It publishes `validation.repository.recorded` for that fact. The Queue's `in_flight_count` was already released by `buildsignal` when the build went terminal. A cancelled Request writes no fact and publishes `validation.repository.cancelled`, so a consumer can stop waiting on the commit. +5. **record** — for a succeeded or failed Request, writes the whole-repo greenness for the head URI (`0` green / `1` broken to start), derived from the Request's build outcome. On green it advances the Queue's **last-green URI** so the next `process` can build incrementally from here, and asks `SourceControl` to advance the Queue's **promotion ref** to the same commit (see [Promotion ref](#promotion-ref--the-last-green-commit-by-name)). It then gives the Request's terminal build id to `projectstatus.Resolver` and writes one validation fact per returned result. The example server uses the noop resolver, so that list is empty unless a deployment supplies another. It publishes `validation.repository.recorded` for that fact. The Queue's `in_flight_count` was already released by `buildsignal` when the build went terminal. A cancelled Request writes no fact and publishes `validation.repository.cancelled`, so a consumer can stop waiting on the commit. ### Designed, not built: project analysis @@ -154,4 +154,4 @@ Callers gate deployments on greenness, so the dangerous failure is a Request tha - **Greenness degree semantics.** The endpoints (`0` green, `1` fully broken) are fixed; the meaning of intermediate values once projects exist (fraction of projects broken? weighted severity?) is deferred until project analysis is concrete. - **Poller vs. webhook ingestion.** Only the external poller is in scope now. The dedup key is designed so a webhook producer can be added later without changing identity, but that producer is out of scope for this RFC. -- **Project mapping contract.** Not built. There is no analyze controller or topic. `record` already persists facts from `projectresult.Resolver` on the same delivery as the repository fact. The unbuilt analyze design — a target-graph mapping, project-scoped builds, and whether that mapping is an extension or an external service — is still open. +- **Project mapping contract.** Not built. There is no analyze controller or topic. `record` already persists facts from `projectstatus.Resolver` on the same delivery as the repository fact. The unbuilt analyze design — a target-graph mapping, project-scoped builds, and whether that mapping is an extension or an external service — is still open. diff --git a/service/stovepipe/server/BUILD.bazel b/service/stovepipe/server/BUILD.bazel index a053297a8..1e015a8f1 100644 --- a/service/stovepipe/server/BUILD.bazel +++ b/service/stovepipe/server/BUILD.bazel @@ -33,7 +33,7 @@ go_library( "//stovepipe/core/requestlog:go_default_library", "//stovepipe/extension/buildrunner:go_default_library", "//stovepipe/extension/buildrunner/fake:go_default_library", - "//stovepipe/extension/projectresult/noop:go_default_library", + "//stovepipe/extension/projectstatus/noop:go_default_library", "//stovepipe/extension/queueconfig/default:go_default_library", "//stovepipe/extension/sourcecontrol:go_default_library", "//stovepipe/extension/sourcecontrol/fake:go_default_library", diff --git a/service/stovepipe/server/main.go b/service/stovepipe/server/main.go index e0184ba0c..00e5811a6 100644 --- a/service/stovepipe/server/main.go +++ b/service/stovepipe/server/main.go @@ -55,7 +55,7 @@ import ( "github.com/uber/submitqueue/stovepipe/core/requestlog" "github.com/uber/submitqueue/stovepipe/extension/buildrunner" buildrunnerfake "github.com/uber/submitqueue/stovepipe/extension/buildrunner/fake" - projectresultnoop "github.com/uber/submitqueue/stovepipe/extension/projectresult/noop" + projectstatusnoop "github.com/uber/submitqueue/stovepipe/extension/projectstatus/noop" queueconfigdefault "github.com/uber/submitqueue/stovepipe/extension/queueconfig/default" "github.com/uber/submitqueue/stovepipe/extension/sourcecontrol" sourcecontrolfake "github.com/uber/submitqueue/stovepipe/extension/sourcecontrol/fake" @@ -441,7 +441,7 @@ func registerPrimaryControllers( } count++ - recordController := record.NewController(logger, scope, store, materializer, projectresultnoop.New(), sourceControl, registry, stovepipemq.TopicKeyRecord, "stovepipe-record") + recordController := record.NewController(logger, scope, store, materializer, projectstatusnoop.New(), sourceControl, registry, stovepipemq.TopicKeyRecord, "stovepipe-record") if err := c.Register(recordController); err != nil { return count, fmt.Errorf("failed to register record controller: %w", err) } diff --git a/stovepipe/controller/record/BUILD.bazel b/stovepipe/controller/record/BUILD.bazel index f5eed3d46..edb3275ae 100644 --- a/stovepipe/controller/record/BUILD.bazel +++ b/stovepipe/controller/record/BUILD.bazel @@ -19,7 +19,7 @@ go_library( "//stovepipe/core/messagequeue:go_default_library", "//stovepipe/core/requestlog:go_default_library", "//stovepipe/entity:go_default_library", - "//stovepipe/extension/projectresult:go_default_library", + "//stovepipe/extension/projectstatus:go_default_library", "//stovepipe/extension/sourcecontrol:go_default_library", "//stovepipe/extension/storage:go_default_library", "@com_github_uber_go_tally//:go_default_library", @@ -47,9 +47,9 @@ go_test( "//stovepipe/core/requestlog:go_default_library", "//stovepipe/core/requestlog/mock:go_default_library", "//stovepipe/entity:go_default_library", - "//stovepipe/extension/projectresult:go_default_library", - "//stovepipe/extension/projectresult/mock:go_default_library", - "//stovepipe/extension/projectresult/noop:go_default_library", + "//stovepipe/extension/projectstatus:go_default_library", + "//stovepipe/extension/projectstatus/mock:go_default_library", + "//stovepipe/extension/projectstatus/noop:go_default_library", "//stovepipe/extension/sourcecontrol:go_default_library", "//stovepipe/extension/sourcecontrol/mock:go_default_library", "//stovepipe/extension/storage:go_default_library", diff --git a/stovepipe/controller/record/record.go b/stovepipe/controller/record/record.go index 12e7161c8..a4bd64165 100644 --- a/stovepipe/controller/record/record.go +++ b/stovepipe/controller/record/record.go @@ -48,7 +48,7 @@ import ( stovepipemq "github.com/uber/submitqueue/stovepipe/core/messagequeue" "github.com/uber/submitqueue/stovepipe/core/requestlog" "github.com/uber/submitqueue/stovepipe/entity" - "github.com/uber/submitqueue/stovepipe/extension/projectresult" + "github.com/uber/submitqueue/stovepipe/extension/projectstatus" "github.com/uber/submitqueue/stovepipe/extension/sourcecontrol" "github.com/uber/submitqueue/stovepipe/extension/storage" "go.uber.org/zap" @@ -58,15 +58,15 @@ import ( // when that fact is green advances the queue's last-green bookmark and promotes // the commit. Implements consumer.Controller. type Controller struct { - logger *zap.SugaredLogger - metricsScope tally.Scope - stores storage.Factory - materializer requestlog.Materializer - projectResultFactory projectresult.Factory - sourceControl sourcecontrol.Factory - registry consumer.TopicRegistry - topicKey consumer.TopicKey - consumerGroup string + logger *zap.SugaredLogger + metricsScope tally.Scope + stores storage.Factory + materializer requestlog.Materializer + projectStatusResolverFactory projectstatus.ResolverFactory + sourceControl sourcecontrol.Factory + registry consumer.TopicRegistry + topicKey consumer.TopicKey + consumerGroup string } // Verify Controller implements consumer.Controller interface at compile time. @@ -85,7 +85,7 @@ func NewController( scope tally.Scope, stores storage.Factory, materializer requestlog.Materializer, - projectResultFactory projectresult.Factory, + projectStatusResolverFactory projectstatus.ResolverFactory, sourceControl sourcecontrol.Factory, registry consumer.TopicRegistry, topicKey consumer.TopicKey, @@ -93,15 +93,15 @@ func NewController( ) *Controller { name := string(topicKey) + "_controller" return &Controller{ - logger: logger.Named(name), - metricsScope: scope.SubScope(name), - stores: stores, - materializer: materializer, - projectResultFactory: projectResultFactory, - sourceControl: sourceControl, - registry: registry, - topicKey: topicKey, - consumerGroup: consumerGroup, + logger: logger.Named(name), + metricsScope: scope.SubScope(name), + stores: stores, + materializer: materializer, + projectStatusResolverFactory: projectStatusResolverFactory, + sourceControl: sourceControl, + registry: registry, + topicKey: topicKey, + consumerGroup: consumerGroup, } } @@ -184,16 +184,16 @@ func (c *Controller) Process(ctx context.Context, delivery consumer.Delivery) er } func (c *Controller) recordProjectFacts(ctx context.Context, store storage.Storage, request entity.Request) error { - resolver, err := c.projectResultFactory.For(projectresult.Config{QueueName: request.Queue}) + resolver, err := c.projectStatusResolverFactory.For(projectstatus.ResolverConfig{QueueName: request.Queue}) if err != nil { - return fmt.Errorf("failed to resolve project result resolver for queue %q: %w", request.Queue, err) + return fmt.Errorf("resolve project status resolver for queue %q: %w", request.Queue, err) } results, err := resolver.Resolve(ctx, request, request.TerminalBuildID) if err != nil { - return fmt.Errorf("failed to resolve project results for request %q: %w", request.ID, err) + return fmt.Errorf("resolve project status results for request %q: %w", request.ID, err) } - if err := validateProjectResults(request, results); err != nil { + if err := validateProjectStatusResults(request, results); err != nil { return err } for _, result := range results { @@ -214,18 +214,18 @@ func (c *Controller) recordProjectFacts(ctx context.Context, store storage.Stora return c.persistProjectFactsRecordedLog(ctx, store, request, len(results)) } -func validateProjectResults(request entity.Request, results []projectresult.Result) error { +func validateProjectStatusResults(request entity.Request, results []projectstatus.Result) error { seen := make(map[string]struct{}, len(results)) for _, result := range results { if result.Project == "" { - return fmt.Errorf("project result for request %q has an empty project", request.ID) + return fmt.Errorf("project status result for request %q has an empty project", request.ID) } if _, ok := seen[result.Project]; ok { - return fmt.Errorf("project result for request %q contains duplicate project %q", request.ID, result.Project) + return fmt.Errorf("project status result for request %q contains duplicate project %q", request.ID, result.Project) } seen[result.Project] = struct{}{} if math.IsNaN(result.Degree) || result.Degree < entity.DegreeGreen || result.Degree > entity.DegreeBroken { - return fmt.Errorf("project result for request %q and project %q has invalid degree %v", request.ID, result.Project, result.Degree) + return fmt.Errorf("project status result for request %q and project %q has invalid degree %v", request.ID, result.Project, result.Degree) } } return nil diff --git a/stovepipe/controller/record/record_test.go b/stovepipe/controller/record/record_test.go index 5556bb7ce..0559c6a80 100644 --- a/stovepipe/controller/record/record_test.go +++ b/stovepipe/controller/record/record_test.go @@ -35,9 +35,9 @@ import ( "github.com/uber/submitqueue/stovepipe/core/requestlog" requestlogmock "github.com/uber/submitqueue/stovepipe/core/requestlog/mock" "github.com/uber/submitqueue/stovepipe/entity" - "github.com/uber/submitqueue/stovepipe/extension/projectresult" - projectresultmock "github.com/uber/submitqueue/stovepipe/extension/projectresult/mock" - projectresultnoop "github.com/uber/submitqueue/stovepipe/extension/projectresult/noop" + "github.com/uber/submitqueue/stovepipe/extension/projectstatus" + projectstatusmock "github.com/uber/submitqueue/stovepipe/extension/projectstatus/mock" + projectstatusnoop "github.com/uber/submitqueue/stovepipe/extension/projectstatus/noop" "github.com/uber/submitqueue/stovepipe/extension/sourcecontrol" sourcecontrolmock "github.com/uber/submitqueue/stovepipe/extension/sourcecontrol/mock" "github.com/uber/submitqueue/stovepipe/extension/storage" @@ -198,7 +198,7 @@ func newControllerForTopic(t *testing.T, ctrl *gomock.Controller, topicKey consu scope, staticStorageFactory{store: m.store}, m.materializer, - projectresultnoop.New(), + projectstatusnoop.New(), staticSourceControlFactory{sourceControl: m.sourceControl}, registry, topicKey, @@ -334,19 +334,19 @@ func TestProcess_AdvancesBookmarkOnSuccess(t *testing.T) { } } -func TestProcess_RecordsNamedProjectResults(t *testing.T) { +func TestProcess_RecordsNamedProjectStatusResults(t *testing.T) { ctrl := gomock.NewController(t) c, m := newController(t, ctrl) eventMaterializer := requestlogmock.NewMockMaterializer(ctrl) c.materializer = eventMaterializer - projectResultFactory := projectresultmock.NewMockFactory(ctrl) - projectResultResolver := projectresultmock.NewMockResolver(ctrl) - c.projectResultFactory = projectResultFactory - projectResultFactory.EXPECT().For(projectresult.Config{QueueName: testQueue}). - Return(projectResultResolver, nil) - projectResultResolver.EXPECT().Resolve( + projectStatusResolverFactory := projectstatusmock.NewMockResolverFactory(ctrl) + projectStatusResolver := projectstatusmock.NewMockResolver(ctrl) + c.projectStatusResolverFactory = projectStatusResolverFactory + projectStatusResolverFactory.EXPECT().For(projectstatus.ResolverConfig{QueueName: testQueue}). + Return(projectStatusResolver, nil) + projectStatusResolver.EXPECT().Resolve( gomock.Any(), requestWithState(entity.RequestStateFailed), "bk-1", - ).Return([]projectresult.Result{ + ).Return([]projectstatus.Result{ {Project: "project-a", Degree: entity.DegreeBroken}, {Project: "project-b", Degree: entity.DegreeBroken}, }, nil) @@ -388,26 +388,26 @@ func TestRecordProjectFacts_PassesEmptyTerminalBuild(t *testing.T) { c, m := newController(t, ctrl) request := requestWithState(entity.RequestStateFailed) request.TerminalBuildID = "" - projectResultFactory := projectresultmock.NewMockFactory(ctrl) - projectResultResolver := projectresultmock.NewMockResolver(ctrl) - c.projectResultFactory = projectResultFactory - projectResultFactory.EXPECT().For(projectresult.Config{QueueName: testQueue}). - Return(projectResultResolver, nil) - projectResultResolver.EXPECT().Resolve(gomock.Any(), request, "").Return(nil, nil) + projectStatusResolverFactory := projectstatusmock.NewMockResolverFactory(ctrl) + projectStatusResolver := projectstatusmock.NewMockResolver(ctrl) + c.projectStatusResolverFactory = projectStatusResolverFactory + projectStatusResolverFactory.EXPECT().For(projectstatus.ResolverConfig{QueueName: testQueue}). + Return(projectStatusResolver, nil) + projectStatusResolver.EXPECT().Resolve(gomock.Any(), request, "").Return(nil, nil) err := c.recordProjectFacts(queueContext(), m.store, request) require.NoError(t, err) } -func TestProcess_RejectsInvalidProjectResultsBeforeWritingFacts(t *testing.T) { +func TestProcess_RejectsInvalidProjectStatusResultsBeforeWritingFacts(t *testing.T) { ctrl := gomock.NewController(t) c, m := newController(t, ctrl) - projectResultFactory := projectresultmock.NewMockFactory(ctrl) - projectResultResolver := projectresultmock.NewMockResolver(ctrl) - c.projectResultFactory = projectResultFactory - projectResultFactory.EXPECT().For(projectresult.Config{QueueName: testQueue}). - Return(projectResultResolver, nil) - projectResultResolver.EXPECT().Resolve(gomock.Any(), gomock.Any(), gomock.Any()).Return([]projectresult.Result{ + projectStatusResolverFactory := projectstatusmock.NewMockResolverFactory(ctrl) + projectStatusResolver := projectstatusmock.NewMockResolver(ctrl) + c.projectStatusResolverFactory = projectStatusResolverFactory + projectStatusResolverFactory.EXPECT().For(projectstatus.ResolverConfig{QueueName: testQueue}). + Return(projectStatusResolver, nil) + projectStatusResolver.EXPECT().Resolve(gomock.Any(), gomock.Any(), gomock.Any()).Return([]projectstatus.Result{ {Project: "project-a", Degree: entity.DegreeBroken}, {Project: "project-b", Degree: math.NaN()}, }, nil) diff --git a/stovepipe/extension/projectresult/BUILD.bazel b/stovepipe/extension/projectstatus/BUILD.bazel similarity index 83% rename from stovepipe/extension/projectresult/BUILD.bazel rename to stovepipe/extension/projectstatus/BUILD.bazel index 601806570..754b45dab 100644 --- a/stovepipe/extension/projectresult/BUILD.bazel +++ b/stovepipe/extension/projectstatus/BUILD.bazel @@ -2,8 +2,8 @@ load("@rules_go//go:def.bzl", "go_library") go_library( name = "go_default_library", - srcs = ["projectresult.go"], - importpath = "github.com/uber/submitqueue/stovepipe/extension/projectresult", + srcs = ["projectstatus.go"], + importpath = "github.com/uber/submitqueue/stovepipe/extension/projectstatus", visibility = ["//visibility:public"], deps = ["//stovepipe/entity:go_default_library"], ) diff --git a/stovepipe/extension/projectresult/mock/BUILD.bazel b/stovepipe/extension/projectstatus/mock/BUILD.bazel similarity index 72% rename from stovepipe/extension/projectresult/mock/BUILD.bazel rename to stovepipe/extension/projectstatus/mock/BUILD.bazel index 057fc4f16..c8ca67644 100644 --- a/stovepipe/extension/projectresult/mock/BUILD.bazel +++ b/stovepipe/extension/projectstatus/mock/BUILD.bazel @@ -2,12 +2,12 @@ load("@rules_go//go:def.bzl", "go_library") go_library( name = "go_default_library", - srcs = ["projectresult_mock.go"], - importpath = "github.com/uber/submitqueue/stovepipe/extension/projectresult/mock", + srcs = ["projectstatus_mock.go"], + importpath = "github.com/uber/submitqueue/stovepipe/extension/projectstatus/mock", visibility = ["//visibility:public"], deps = [ "//stovepipe/entity:go_default_library", - "//stovepipe/extension/projectresult:go_default_library", + "//stovepipe/extension/projectstatus:go_default_library", "@org_uber_go_mock//gomock:go_default_library", ], ) diff --git a/stovepipe/extension/projectresult/mock/projectresult_mock.go b/stovepipe/extension/projectstatus/mock/projectstatus_mock.go similarity index 62% rename from stovepipe/extension/projectresult/mock/projectresult_mock.go rename to stovepipe/extension/projectstatus/mock/projectstatus_mock.go index 15bd7a870..6716365b2 100644 --- a/stovepipe/extension/projectresult/mock/projectresult_mock.go +++ b/stovepipe/extension/projectstatus/mock/projectstatus_mock.go @@ -1,9 +1,9 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: projectresult.go +// Source: projectstatus.go // // Generated by this command: // -// mockgen -source=projectresult.go -destination=mock/projectresult_mock.go -package=mock +// mockgen -source=projectstatus.go -destination=mock/projectstatus_mock.go -package=mock // // Package mock is a generated GoMock package. @@ -14,7 +14,7 @@ import ( reflect "reflect" entity "github.com/uber/submitqueue/stovepipe/entity" - projectresult "github.com/uber/submitqueue/stovepipe/extension/projectresult" + projectstatus "github.com/uber/submitqueue/stovepipe/extension/projectstatus" gomock "go.uber.org/mock/gomock" ) @@ -43,10 +43,10 @@ func (m *MockResolver) EXPECT() *MockResolverMockRecorder { } // Resolve mocks base method. -func (m *MockResolver) Resolve(ctx context.Context, request entity.Request, terminalBuildID string) ([]projectresult.Result, error) { +func (m *MockResolver) Resolve(ctx context.Context, request entity.Request, terminalBuildID string) ([]projectstatus.Result, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Resolve", ctx, request, terminalBuildID) - ret0, _ := ret[0].([]projectresult.Result) + ret0, _ := ret[0].([]projectstatus.Result) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -57,41 +57,41 @@ func (mr *MockResolverMockRecorder) Resolve(ctx, request, terminalBuildID any) * return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Resolve", reflect.TypeOf((*MockResolver)(nil).Resolve), ctx, request, terminalBuildID) } -// MockFactory is a mock of Factory interface. -type MockFactory struct { +// MockResolverFactory is a mock of ResolverFactory interface. +type MockResolverFactory struct { ctrl *gomock.Controller - recorder *MockFactoryMockRecorder + recorder *MockResolverFactoryMockRecorder isgomock struct{} } -// MockFactoryMockRecorder is the mock recorder for MockFactory. -type MockFactoryMockRecorder struct { - mock *MockFactory +// MockResolverFactoryMockRecorder is the mock recorder for MockResolverFactory. +type MockResolverFactoryMockRecorder struct { + mock *MockResolverFactory } -// NewMockFactory creates a new mock instance. -func NewMockFactory(ctrl *gomock.Controller) *MockFactory { - mock := &MockFactory{ctrl: ctrl} - mock.recorder = &MockFactoryMockRecorder{mock} +// NewMockResolverFactory creates a new mock instance. +func NewMockResolverFactory(ctrl *gomock.Controller) *MockResolverFactory { + mock := &MockResolverFactory{ctrl: ctrl} + mock.recorder = &MockResolverFactoryMockRecorder{mock} return mock } // EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockFactory) EXPECT() *MockFactoryMockRecorder { +func (m *MockResolverFactory) EXPECT() *MockResolverFactoryMockRecorder { return m.recorder } // For mocks base method. -func (m *MockFactory) For(cfg projectresult.Config) (projectresult.Resolver, error) { +func (m *MockResolverFactory) For(cfg projectstatus.ResolverConfig) (projectstatus.Resolver, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "For", cfg) - ret0, _ := ret[0].(projectresult.Resolver) + ret0, _ := ret[0].(projectstatus.Resolver) ret1, _ := ret[1].(error) return ret0, ret1 } // For indicates an expected call of For. -func (mr *MockFactoryMockRecorder) For(cfg any) *gomock.Call { +func (mr *MockResolverFactoryMockRecorder) For(cfg any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "For", reflect.TypeOf((*MockFactory)(nil).For), cfg) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "For", reflect.TypeOf((*MockResolverFactory)(nil).For), cfg) } diff --git a/stovepipe/extension/projectresult/noop/BUILD.bazel b/stovepipe/extension/projectstatus/noop/BUILD.bazel similarity index 78% rename from stovepipe/extension/projectresult/noop/BUILD.bazel rename to stovepipe/extension/projectstatus/noop/BUILD.bazel index 6a5e4ddc6..27c92784d 100644 --- a/stovepipe/extension/projectresult/noop/BUILD.bazel +++ b/stovepipe/extension/projectstatus/noop/BUILD.bazel @@ -3,11 +3,11 @@ load("@rules_go//go:def.bzl", "go_library", "go_test") go_library( name = "go_default_library", srcs = ["noop.go"], - importpath = "github.com/uber/submitqueue/stovepipe/extension/projectresult/noop", + importpath = "github.com/uber/submitqueue/stovepipe/extension/projectstatus/noop", visibility = ["//visibility:public"], deps = [ "//stovepipe/entity:go_default_library", - "//stovepipe/extension/projectresult:go_default_library", + "//stovepipe/extension/projectstatus:go_default_library", ], ) @@ -17,7 +17,7 @@ go_test( embed = [":go_default_library"], deps = [ "//stovepipe/entity:go_default_library", - "//stovepipe/extension/projectresult:go_default_library", + "//stovepipe/extension/projectstatus:go_default_library", "@com_github_stretchr_testify//require:go_default_library", ], ) diff --git a/stovepipe/extension/projectresult/noop/noop.go b/stovepipe/extension/projectstatus/noop/noop.go similarity index 59% rename from stovepipe/extension/projectresult/noop/noop.go rename to stovepipe/extension/projectstatus/noop/noop.go index f9c45850f..cecdd6a42 100644 --- a/stovepipe/extension/projectresult/noop/noop.go +++ b/stovepipe/extension/projectstatus/noop/noop.go @@ -12,35 +12,36 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package noop provides a projectresult.Factory that records no project -// outcomes. Use it when a deployment has not configured project attribution. +// Package noop provides a projectstatus.ResolverFactory that returns no +// project status results. Use it when a deployment has not configured project +// status resolution. package noop import ( "context" "github.com/uber/submitqueue/stovepipe/entity" - "github.com/uber/submitqueue/stovepipe/extension/projectresult" + "github.com/uber/submitqueue/stovepipe/extension/projectstatus" ) // Verify interface compliance at compile time. -var _ projectresult.Factory = Factory{} +var _ projectstatus.ResolverFactory = ResolverFactory{} -// Factory returns a resolver that records no project outcomes. -type Factory struct{} +// ResolverFactory returns a resolver with no project status results. +type ResolverFactory struct{} -// New returns a no-op project-result Factory. -func New() Factory { - return Factory{} +// New returns a no-op project-status ResolverFactory. +func New() ResolverFactory { + return ResolverFactory{} } // For returns the no-op resolver for a queue. -func (Factory) For(projectresult.Config) (projectresult.Resolver, error) { +func (ResolverFactory) For(projectstatus.ResolverConfig) (projectstatus.Resolver, error) { return resolver{}, nil } type resolver struct{} -func (resolver) Resolve(context.Context, entity.Request, string) ([]projectresult.Result, error) { +func (resolver) Resolve(context.Context, entity.Request, string) ([]projectstatus.Result, error) { return nil, nil } diff --git a/stovepipe/extension/projectresult/noop/noop_test.go b/stovepipe/extension/projectstatus/noop/noop_test.go similarity index 79% rename from stovepipe/extension/projectresult/noop/noop_test.go rename to stovepipe/extension/projectstatus/noop/noop_test.go index df55ef719..82e8b9c6f 100644 --- a/stovepipe/extension/projectresult/noop/noop_test.go +++ b/stovepipe/extension/projectstatus/noop/noop_test.go @@ -20,11 +20,11 @@ import ( "github.com/stretchr/testify/require" "github.com/uber/submitqueue/stovepipe/entity" - "github.com/uber/submitqueue/stovepipe/extension/projectresult" + "github.com/uber/submitqueue/stovepipe/extension/projectstatus" ) -func TestFactory_ReturnsResolverWithoutProjectResults(t *testing.T) { - resolver, err := New().For(projectresult.Config{QueueName: "monorepo/main"}) +func TestResolverFactory_ReturnsResolverWithoutProjectStatusResults(t *testing.T) { + resolver, err := New().For(projectstatus.ResolverConfig{QueueName: "monorepo/main"}) require.NoError(t, err) results, err := resolver.Resolve(context.Background(), entity.Request{}, "bk-1") diff --git a/stovepipe/extension/projectresult/projectresult.go b/stovepipe/extension/projectstatus/projectstatus.go similarity index 53% rename from stovepipe/extension/projectresult/projectresult.go rename to stovepipe/extension/projectstatus/projectstatus.go index 3f1d6f68d..c3a86a749 100644 --- a/stovepipe/extension/projectresult/projectresult.go +++ b/stovepipe/extension/projectstatus/projectstatus.go @@ -12,11 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package projectresult defines the optional integration that attributes a -// completed validation to named projects. -package projectresult +// Package projectstatus defines the optional integration that resolves project +// status results from a completed validation. +package projectstatus -//go:generate go run go.uber.org/mock/mockgen -source=projectresult.go -destination=mock/projectresult_mock.go -package=mock +//go:generate go run go.uber.org/mock/mockgen -source=projectstatus.go -destination=mock/projectstatus_mock.go -package=mock import ( "context" @@ -24,8 +24,8 @@ import ( "github.com/uber/submitqueue/stovepipe/entity" ) -// Result is one project-scoped validation outcome. The record stage supplies -// the request identity and recording timestamp when it persists this result. +// Result is one project status result. The record stage supplies the request +// identity and recording timestamp when it persists this result. type Result struct { // Project identifies the project to which this result applies. Project string @@ -33,22 +33,22 @@ type Result struct { Degree float64 } -// Resolver attributes one terminal validation request to named project -// outcomes. terminalBuildID identifies the build that established the request's -// terminal state, or is empty when no build established it. Implementations may -// use any repository-specific analysis they need to obtain those outcomes. +// Resolver resolves named project status results from one terminal validation. +// terminalBuildID identifies the build that established the request's terminal +// state, or is empty when no build established it. Implementations may use any +// repository-specific analysis they need to obtain those results. // Returning no results is valid. type Resolver interface { Resolve(ctx context.Context, request entity.Request, terminalBuildID string) ([]Result, error) } -// Config carries the queue identity handed to a Factory. -type Config struct { +// ResolverConfig carries the queue identity handed to a ResolverFactory. +type ResolverConfig struct { // QueueName identifies the queue served by the resolver. QueueName string } -// Factory constructs a Resolver for one queue. -type Factory interface { - For(cfg Config) (Resolver, error) +// ResolverFactory constructs a Resolver for one queue. +type ResolverFactory interface { + For(cfg ResolverConfig) (Resolver, error) }