Skip to content

Commit 8b2ce3e

Browse files
committed
refactor(stovepipe): scope entities and extensions to gateway only
Replace ChangeInfo with ChangeEvent as the ingestion payload type and introduce ChangeURI as the lightweight pipeline reference. Update Commit entity and create CommitStatusentity. Update ChangeHandler and the filter to accept ChangeEvent. Remove the storage extension and Batch entity, which belong to the orchestrator.
1 parent 831cf94 commit 8b2ce3e

13 files changed

Lines changed: 140 additions & 291 deletions

File tree

stovepipe/core/filter/filter.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ import (
2222
)
2323

2424
// Config controls which VCS URIs are watched.
25-
// WatchedURIPrefixes is a list of URI prefixes to match against ChangeInfo.URI.
25+
// WatchedURIPrefixes is a list of URI prefixes to match against ChangeEvent.URI.
2626
// Example: "git://github.com/uber/go-code/refs/heads/main"
2727
// watches all commits on the main branch of uber/go-code.
28-
func ShouldProcess(event entity.ChangeInfo, watchedPrefixes []string) bool {
28+
func ShouldProcess(event entity.ChangeEvent, watchedPrefixes []string) bool {
2929
for _, prefix := range watchedPrefixes {
3030
if strings.HasPrefix(event.URI, prefix) {
3131
return true

stovepipe/entity/BUILD.bazel

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@ load("@rules_go//go:def.bzl", "go_library")
33
go_library(
44
name = "entity",
55
srcs = [
6-
"batch.go",
6+
"change_event.go",
7+
"change_uri.go",
78
"commit.go",
8-
"entity.go",
99
],
1010
importpath = "github.com/uber/submitqueue/stovepipe/entity",
1111
visibility = ["//visibility:public"],
12+
deps = ["//stovepipe/entity/git"],
1213
)

stovepipe/entity/batch.go

Lines changed: 0 additions & 63 deletions
This file was deleted.

stovepipe/entity/change_event.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Copyright (c) 2025 Uber Technologies, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package entity
16+
17+
import (
18+
"encoding/json"
19+
"fmt"
20+
21+
entitygit "github.com/uber/submitqueue/stovepipe/entity/git"
22+
)
23+
24+
// ChangeEvent represents a single new trunk change entering the pipeline, published to the
25+
// start topic. A trunk change is one commit, so the event carries one git-backed URI. It is
26+
// source-agnostic: both the webhook and the reconciliation poller emit it. Additional fields
27+
// (e.g. source, committer time) can be added later as ingestion needs them.
28+
type ChangeEvent struct {
29+
// URI identifies the commit that entered the pipeline (git://owner/repo/branch/revision).
30+
URI string `json:"uri"`
31+
}
32+
33+
// ToBytes serializes the ChangeEvent to JSON bytes for queue message payload.
34+
func (e ChangeEvent) ToBytes() ([]byte, error) {
35+
return json.Marshal(e)
36+
}
37+
38+
// Validate checks that the change event carries a valid git-backed commit URI.
39+
func (e ChangeEvent) Validate() error {
40+
if e.URI == "" {
41+
return fmt.Errorf("change event requires a commit URI")
42+
}
43+
if _, err := entitygit.ParseChangeID(e.URI); err != nil {
44+
return fmt.Errorf("change event URI: %w", err)
45+
}
46+
return nil
47+
}
48+
49+
// ChangeEventFromBytes deserializes a ChangeEvent from JSON bytes.
50+
func ChangeEventFromBytes(data []byte) (ChangeEvent, error) {
51+
var event ChangeEvent
52+
if err := json.Unmarshal(data, &event); err != nil {
53+
return ChangeEvent{}, err
54+
}
55+
if err := event.Validate(); err != nil {
56+
return ChangeEvent{}, err
57+
}
58+
return event, nil
59+
}

stovepipe/entity/change_uri.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright (c) 2025 Uber Technologies, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package entity
16+
17+
import "encoding/json"
18+
19+
// ChangeURI is the lightweight reference passed between pipeline stages. It
20+
// carries only the change identity; stages re-resolve any state they need.
21+
type ChangeURI struct {
22+
// URI is the change identity (git://owner/repo/branch/revision).
23+
URI string `json:"uri"`
24+
}
25+
26+
// ToBytes serializes the ChangeURI to JSON bytes for a queue message payload.
27+
func (c ChangeURI) ToBytes() ([]byte, error) {
28+
return json.Marshal(c)
29+
}
30+
31+
// ChangeURIFromBytes deserializes a ChangeURI from JSON bytes.
32+
func ChangeURIFromBytes(data []byte) (ChangeURI, error) {
33+
var ref ChangeURI
34+
err := json.Unmarshal(data, &ref)
35+
return ref, err
36+
}

stovepipe/entity/commit.go

Lines changed: 35 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -14,44 +14,50 @@
1414

1515
package entity
1616

17-
// CommitStatus is the validation state of a trunk commit as determined by Stovepipe.
18-
type CommitStatus string
17+
// CommitStatusKind is the validation state of a trunk commit as determined by Stovepipe.
18+
type CommitStatusKind string
1919

2020
const (
21-
// CommitStatusUnknown is the default state when a commit is first ingested.
21+
// CommitStatusKindUnknown is the default state when a commit is first ingested.
2222
// The commit has landed on main but has not yet been validated.
23-
CommitStatusUnknown CommitStatus = ""
24-
// CommitStatusSucceeded means the relevant targets build and test successfully at this commit.
25-
CommitStatusSucceeded CommitStatus = "succeeded"
26-
// CommitStatusFailed means a target is broken at this commit; it is the offending change.
27-
CommitStatusFailed CommitStatus = "failed"
23+
CommitStatusKindUnknown CommitStatusKind = ""
24+
// CommitStatusKindIngested means the commit has been received and recorded by the gateway.
25+
CommitStatusKindIngested CommitStatusKind = "ingested"
26+
// CommitStatusKindQueued means the commit is waiting to enter the validation pipeline.
27+
CommitStatusKindQueued CommitStatusKind = "queued"
28+
// CommitStatusKindProcessing means the commit is actively being validated.
29+
CommitStatusKindProcessing CommitStatusKind = "processing"
30+
// CommitStatusKindSucceeded means the relevant targets build and test successfully at this commit.
31+
CommitStatusKindSucceeded CommitStatusKind = "succeeded"
32+
// CommitStatusKindFailed means a target is broken at this commit; it is the offending change.
33+
CommitStatusKindFailed CommitStatusKind = "failed"
2834
)
2935

3036
// IsCommitStatusTerminal returns true if the status is a final, irreversible state.
31-
func IsCommitStatusTerminal(s CommitStatus) bool {
32-
return s == CommitStatusSucceeded || s == CommitStatusFailed
37+
func IsCommitStatusTerminal(s CommitStatusKind) bool {
38+
return s == CommitStatusKindSucceeded || s == CommitStatusKindFailed
3339
}
3440

35-
// Commit is a trunk commit tracked by Stovepipe. The SHA scoped by Repository and
36-
// Branch is the natural identity and dedup key: a commit announced by both a webhook
37-
// and a poll backfill resolves to the same record and is processed once.
41+
// Commit is a trunk commit tracked by Stovepipe's gateway.
42+
// URI is the primary key — it is the canonical change identity from the originating ChangeEvent.
3843
type Commit struct {
39-
// SHA is the full commit hash. Identity key; immutable after creation.
40-
SHA string
41-
// Repository is the repository URI (e.g. "github.com/uber/go-code").
42-
Repository string
43-
// Branch is the target branch (e.g. "main").
44-
Branch string
45-
// CommitterTimeMs is the committer timestamp in milliseconds since epoch.
46-
// Used to order commits within a range and to establish the trunk sequence.
47-
CommitterTimeMs int64
48-
// Status is the current validation state of this commit.
49-
Status CommitStatus
50-
// Version is incremented on each update and used for optimistic locking.
51-
// Version arithmetic lives in the controller; the store performs a pure conditional write.
52-
Version int32
44+
// URI is the canonical change identity from the originating ChangeEvent.
45+
URI string
46+
// SequenceNumber is the number of commits reachable from this commit on the trunk branch,
47+
// derived from `git rev-list --count`. Higher values are newer.
48+
// Must be populated at ingestion time — a zero value indicates the field was not set.
49+
SequenceNumber int64
5350
// CreatedAt is the time this commit was first recorded, in milliseconds since epoch.
5451
CreatedAt int64
55-
// UpdatedAt is the time this commit was last updated, in milliseconds since epoch.
56-
UpdatedAt int64
52+
}
53+
54+
// CommitStatus is a point-in-time validation status entry for a Commit.
55+
// Multiple CommitStatus records form the status history of a single Commit.
56+
type CommitStatus struct {
57+
// CommitURI is the URI of the Commit this status belongs to.
58+
CommitURI string
59+
// Status is the validation state recorded at this point in time.
60+
Status CommitStatusKind
61+
// CreatedAt is the time this status was recorded, in milliseconds since epoch.
62+
CreatedAt int64
5763
}

stovepipe/entity/entity.go

Lines changed: 0 additions & 41 deletions
This file was deleted.

stovepipe/extension/changeingester/logging.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import (
2525

2626
// LoggingHandler is a stub ChangeHandler that logs received changes.
2727
// Replace with real persistence logic once DB schema is ready.
28+
// Implementations must resolve entity.Commit.SequenceNumber (via `git rev-list --count`)
29+
// before persisting — a zero value indicates the field was not populated.
2830
type LoggingHandler struct {
2931
logger *zap.Logger
3032
}
@@ -35,12 +37,9 @@ func New(logger *zap.Logger) extension.ChangeHandler {
3537
return LoggingHandler{logger: logger}
3638
}
3739

38-
func (h LoggingHandler) IngestChange(ctx context.Context, info entity.ChangeInfo) error {
40+
func (h LoggingHandler) IngestChange(ctx context.Context, event entity.ChangeEvent) error {
3941
h.logger.Info("ingested change",
40-
zap.String("uri", info.URI),
41-
zap.String("previous_uri", info.PreviousURI),
42-
zap.String("author_name", info.AuthorName),
43-
zap.String("author_email", info.AuthorEmail),
42+
zap.String("uri", event.URI),
4443
)
4544
return nil
4645
}

stovepipe/extension/extension.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,5 @@ type ChangeIngester interface {
3030

3131
// ChangeHandler processes a single change received from the ingester.
3232
type ChangeHandler interface {
33-
IngestChange(ctx context.Context, info entity.ChangeInfo) error
33+
IngestChange(ctx context.Context, event entity.ChangeEvent) error
3434
}

stovepipe/extension/storage/BUILD.bazel

Lines changed: 0 additions & 13 deletions
This file was deleted.

0 commit comments

Comments
 (0)