From fbba28b6d79b60d5a037be355784396dc96da25f Mon Sep 17 00:00:00 2001 From: Kevin New Date: Mon, 23 Feb 2026 17:06:43 -0800 Subject: [PATCH 1/6] feat(queueconfig): adding entity and basic interface for queue config --- entity/queueconfig/BUILD.bazel | 15 ++++++ entity/queueconfig/queueconfig.go | 68 ++++++++++++++++++++++++ entity/queueconfig/queueconfig_test.go | 72 ++++++++++++++++++++++++++ extension/queueconfig/BUILD.bazel | 9 ++++ extension/queueconfig/README.md | 24 +++++++++ extension/queueconfig/queueconfig.go | 22 ++++++++ 6 files changed, 210 insertions(+) create mode 100644 entity/queueconfig/BUILD.bazel create mode 100644 entity/queueconfig/queueconfig.go create mode 100644 entity/queueconfig/queueconfig_test.go create mode 100644 extension/queueconfig/BUILD.bazel create mode 100644 extension/queueconfig/README.md create mode 100644 extension/queueconfig/queueconfig.go diff --git a/entity/queueconfig/BUILD.bazel b/entity/queueconfig/BUILD.bazel new file mode 100644 index 00000000..3f5c2673 --- /dev/null +++ b/entity/queueconfig/BUILD.bazel @@ -0,0 +1,15 @@ +load("@rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "queueconfig", + srcs = ["queueconfig.go"], + importpath = "github.com/uber/submitqueue/entity/queueconfig", + visibility = ["//visibility:public"], +) + +go_test( + name = "queueconfig_test", + srcs = ["queueconfig_test.go"], + embed = [":queueconfig"], + deps = ["@com_github_stretchr_testify//assert"], +) diff --git a/entity/queueconfig/queueconfig.go b/entity/queueconfig/queueconfig.go new file mode 100644 index 00000000..41565719 --- /dev/null +++ b/entity/queueconfig/queueconfig.go @@ -0,0 +1,68 @@ +package queueconfig + +// Repository identifies a source control repository. +// The interpretation of ID is platform-specific and resolved by the change provider: +// - GitHub/GitLab: "owner/repo" (e.g., "uber/submitqueue") +// - Perforce: depot path (e.g., "//depot/project") +// - SVN: repository URL (e.g., "https://svn.example.com/repos/project") +// +// Immutable after creation. +type Repository struct { + // ID is the platform-specific identifier for the repository. + // Opaque to the system; meaningful only to the change provider. + ID string +} + +// Destination identifies the landing target in a version control system. +// The interpretation of Ref is VCS-specific and resolved by the change provider: +// - Git: branch name (e.g., "main", "release/v2") +// - Perforce: stream or depot path (e.g., "//depot/main/...") +// - SVN: repository path (e.g., "trunk/") +// - Mercurial: bookmark name (e.g., "main") +// +// Immutable after creation. +type Destination struct { + // Ref is the version-control-specific reference for the landing target. + // Opaque to the system; meaningful only to the change provider. + Ref string +} + +// QueueConfig holds the configuration for a single submit queue. +// Each queue maps a repository + destination to a processing pipeline. +// A repository can have multiple queues, but each queue has exactly one destination. +// Immutable after creation. +type QueueConfig struct { + // Name uniquely identifies this queue within the system. + // Referenced by entity.Request.Queue. + Name string + + // Repository identifies the source control repository this queue operates on. + Repository Repository + + // Destination is the landing target where changes are merged. + Destination Destination + + // ChangeProviderName identifies which change provider to use (e.g., "github", "gerrit"). + // Resolved to a ChangeProvider instance at wiring time. + ChangeProviderName string + + // ChangeProvider is the change provider to use for this queue. + // TODO: + // ChangeProvider ChangeProvider to be defined in the changeprovider extension package +} + +// NewQueueConfig creates a new QueueConfig with the given parameters. +func NewQueueConfig( + name string, + repository Repository, + destination Destination, + changeProviderName string, +) QueueConfig { + // Create instance of ChangeProvider instance from the change provider name + return QueueConfig{ + Name: name, + Repository: repository, + Destination: destination, + ChangeProviderName: changeProviderName, + } +} diff --git a/entity/queueconfig/queueconfig_test.go b/entity/queueconfig/queueconfig_test.go new file mode 100644 index 00000000..292667fd --- /dev/null +++ b/entity/queueconfig/queueconfig_test.go @@ -0,0 +1,72 @@ +package queueconfig + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestNewQueueConfig(t *testing.T) { + repo := Repository{ID: "uber/submitqueue"} + dest := Destination{Ref: "main"} + + cfg := NewQueueConfig("uber/submitqueue/main", repo, dest, "github") + + assert.Equal(t, "uber/submitqueue/main", cfg.Name) + assert.Equal(t, "uber/submitqueue", cfg.Repository.ID) + assert.Equal(t, "main", cfg.Destination.Ref) + assert.Equal(t, "github", cfg.ChangeProviderName) +} + +func TestNewQueueConfig_DifferentPlatforms(t *testing.T) { + tests := []struct { + name string + repo Repository + destination Destination + provider string + }{ + { + name: "github", + repo: Repository{ID: "uber/cadence"}, + destination: Destination{Ref: "release/v2"}, + provider: "github", + }, + { + name: "gerrit", + repo: Repository{ID: "platform/build"}, + destination: Destination{Ref: "refs/heads/main"}, + provider: "gerrit", + }, + { + name: "perforce", + repo: Repository{ID: "//depot/project"}, + destination: Destination{Ref: "//depot/main/..."}, + provider: "perforce", + }, + { + name: "svn", + repo: Repository{ID: "https://svn.example.com/repos/project"}, + destination: Destination{Ref: "trunk/"}, + provider: "svn", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cfg := NewQueueConfig(tt.name, tt.repo, tt.destination, tt.provider) + + assert.Equal(t, tt.repo, cfg.Repository) + assert.Equal(t, tt.destination, cfg.Destination) + assert.Equal(t, tt.provider, cfg.ChangeProviderName) + }) + } +} + +func TestQueueConfig_ZeroValue(t *testing.T) { + var cfg QueueConfig + + assert.Empty(t, cfg.Name) + assert.Empty(t, cfg.Repository.ID) + assert.Empty(t, cfg.Destination.Ref) + assert.Empty(t, cfg.ChangeProviderName) +} diff --git a/extension/queueconfig/BUILD.bazel b/extension/queueconfig/BUILD.bazel new file mode 100644 index 00000000..f274a446 --- /dev/null +++ b/extension/queueconfig/BUILD.bazel @@ -0,0 +1,9 @@ +load("@rules_go//go:def.bzl", "go_library") + +go_library( + name = "queueconfig", + srcs = ["queueconfig.go"], + importpath = "github.com/uber/submitqueue/extension/queueconfig", + visibility = ["//visibility:public"], + deps = ["//entity/queueconfig"], +) diff --git a/extension/queueconfig/README.md b/extension/queueconfig/README.md new file mode 100644 index 00000000..dd634237 --- /dev/null +++ b/extension/queueconfig/README.md @@ -0,0 +1,24 @@ +# Queue Config Extension + +Vendor-agnostic interface for providing queue configurations. + +## Interfaces + +### Store + +Provides queue configurations by name. + +```go +type Store interface { + Get(ctx context.Context, name string) (queueconfig.QueueConfig, error) + List(ctx context.Context) ([]queueconfig.QueueConfig, error) +} +``` + +## Entities + +Queue configuration entities live in `entity/queueconfig/`: + +- **QueueConfig** — configuration for a single submit queue (name, repository, destination, change provider) +- **Repository** — platform-specific repository identifier (opaque ID string) +- **Destination** — VCS-agnostic landing target (opaque ref string interpreted by the change provider) diff --git a/extension/queueconfig/queueconfig.go b/extension/queueconfig/queueconfig.go new file mode 100644 index 00000000..8b872542 --- /dev/null +++ b/extension/queueconfig/queueconfig.go @@ -0,0 +1,22 @@ +package queueconfig + +import ( + "context" + "errors" + + "github.com/uber/submitqueue/entity/queueconfig" +) + +// ErrNotFound is returned when the requested queue configuration does not exist. +var ErrNotFound = errors.New("queue config not found") + +// Store loads and provides queue configurations. +// Implementations may read from YAML files, databases, remote services, etc. +type Store interface { + // Get returns the configuration for a named queue. + // Returns ErrNotFound if no configuration exists for the given name. + Get(ctx context.Context, name string) (queueconfig.QueueConfig, error) + + // List returns all configured queues. + List(ctx context.Context) ([]queueconfig.QueueConfig, error) +} From bd80298cccdb58b953dfb02f51015292b8b7cc06 Mon Sep 17 00:00:00 2001 From: Kevin New Date: Mon, 23 Feb 2026 17:53:57 -0800 Subject: [PATCH 2/6] fix struct name stuttering --- entity/queueconfig/queueconfig.go | 13 ++++++------- entity/queueconfig/queueconfig_test.go | 12 ++++++------ extension/queueconfig/README.md | 6 +++--- extension/queueconfig/queueconfig.go | 4 ++-- 4 files changed, 17 insertions(+), 18 deletions(-) diff --git a/entity/queueconfig/queueconfig.go b/entity/queueconfig/queueconfig.go index 41565719..2ca27077 100644 --- a/entity/queueconfig/queueconfig.go +++ b/entity/queueconfig/queueconfig.go @@ -27,11 +27,11 @@ type Destination struct { Ref string } -// QueueConfig holds the configuration for a single submit queue. +// Config holds the configuration for a single submit queue. // Each queue maps a repository + destination to a processing pipeline. // A repository can have multiple queues, but each queue has exactly one destination. // Immutable after creation. -type QueueConfig struct { +type Config struct { // Name uniquely identifies this queue within the system. // Referenced by entity.Request.Queue. Name string @@ -51,15 +51,14 @@ type QueueConfig struct { // ChangeProvider ChangeProvider to be defined in the changeprovider extension package } -// NewQueueConfig creates a new QueueConfig with the given parameters. -func NewQueueConfig( +// NewConfig creates a new Config with the given parameters. +func NewConfig( name string, repository Repository, destination Destination, changeProviderName string, -) QueueConfig { - // Create instance of ChangeProvider instance from the change provider name - return QueueConfig{ +) Config { + return Config{ Name: name, Repository: repository, Destination: destination, diff --git a/entity/queueconfig/queueconfig_test.go b/entity/queueconfig/queueconfig_test.go index 292667fd..97f2040d 100644 --- a/entity/queueconfig/queueconfig_test.go +++ b/entity/queueconfig/queueconfig_test.go @@ -6,11 +6,11 @@ import ( "github.com/stretchr/testify/assert" ) -func TestNewQueueConfig(t *testing.T) { +func TestNewConfig(t *testing.T) { repo := Repository{ID: "uber/submitqueue"} dest := Destination{Ref: "main"} - cfg := NewQueueConfig("uber/submitqueue/main", repo, dest, "github") + cfg := NewConfig("uber/submitqueue/main", repo, dest, "github") assert.Equal(t, "uber/submitqueue/main", cfg.Name) assert.Equal(t, "uber/submitqueue", cfg.Repository.ID) @@ -18,7 +18,7 @@ func TestNewQueueConfig(t *testing.T) { assert.Equal(t, "github", cfg.ChangeProviderName) } -func TestNewQueueConfig_DifferentPlatforms(t *testing.T) { +func TestNewConfig_DifferentPlatforms(t *testing.T) { tests := []struct { name string repo Repository @@ -53,7 +53,7 @@ func TestNewQueueConfig_DifferentPlatforms(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - cfg := NewQueueConfig(tt.name, tt.repo, tt.destination, tt.provider) + cfg := NewConfig(tt.name, tt.repo, tt.destination, tt.provider) assert.Equal(t, tt.repo, cfg.Repository) assert.Equal(t, tt.destination, cfg.Destination) @@ -62,8 +62,8 @@ func TestNewQueueConfig_DifferentPlatforms(t *testing.T) { } } -func TestQueueConfig_ZeroValue(t *testing.T) { - var cfg QueueConfig +func TestConfig_ZeroValue(t *testing.T) { + var cfg Config assert.Empty(t, cfg.Name) assert.Empty(t, cfg.Repository.ID) diff --git a/extension/queueconfig/README.md b/extension/queueconfig/README.md index dd634237..e8a03fea 100644 --- a/extension/queueconfig/README.md +++ b/extension/queueconfig/README.md @@ -10,8 +10,8 @@ Provides queue configurations by name. ```go type Store interface { - Get(ctx context.Context, name string) (queueconfig.QueueConfig, error) - List(ctx context.Context) ([]queueconfig.QueueConfig, error) + Get(ctx context.Context, name string) (queueconfig.Config, error) + List(ctx context.Context) ([]queueconfig.Config, error) } ``` @@ -19,6 +19,6 @@ type Store interface { Queue configuration entities live in `entity/queueconfig/`: -- **QueueConfig** — configuration for a single submit queue (name, repository, destination, change provider) +- **Config** — configuration for a single submit queue (name, repository, destination, change provider) - **Repository** — platform-specific repository identifier (opaque ID string) - **Destination** — VCS-agnostic landing target (opaque ref string interpreted by the change provider) diff --git a/extension/queueconfig/queueconfig.go b/extension/queueconfig/queueconfig.go index 8b872542..44d8e2c6 100644 --- a/extension/queueconfig/queueconfig.go +++ b/extension/queueconfig/queueconfig.go @@ -15,8 +15,8 @@ var ErrNotFound = errors.New("queue config not found") type Store interface { // Get returns the configuration for a named queue. // Returns ErrNotFound if no configuration exists for the given name. - Get(ctx context.Context, name string) (queueconfig.QueueConfig, error) + Get(ctx context.Context, name string) (queueconfig.Config, error) // List returns all configured queues. - List(ctx context.Context) ([]queueconfig.QueueConfig, error) + List(ctx context.Context) ([]queueconfig.Config, error) } From d95f7eb7c43741f15dd660367a075a2a99856998 Mon Sep 17 00:00:00 2001 From: "kevin.new" Date: Tue, 24 Feb 2026 18:59:03 +0000 Subject: [PATCH 3/6] move queueconfig up to entity top-level, remove unncessary tests --- entity/BUILD.bazel | 6 ++- entity/queue_config.go | 48 +++++++++++++++++ entity/queue_config_test.go | 29 +++++++++++ entity/queueconfig/BUILD.bazel | 15 ------ entity/queueconfig/queueconfig.go | 67 ------------------------ entity/queueconfig/queueconfig_test.go | 72 -------------------------- extension/queueconfig/BUILD.bazel | 2 +- extension/queueconfig/README.md | 10 ++-- extension/queueconfig/queueconfig.go | 6 +-- 9 files changed, 90 insertions(+), 165 deletions(-) create mode 100644 entity/queue_config.go create mode 100644 entity/queue_config_test.go delete mode 100644 entity/queueconfig/BUILD.bazel delete mode 100644 entity/queueconfig/queueconfig.go delete mode 100644 entity/queueconfig/queueconfig_test.go diff --git a/entity/BUILD.bazel b/entity/BUILD.bazel index 0bb84766..6ca5d5a5 100644 --- a/entity/BUILD.bazel +++ b/entity/BUILD.bazel @@ -7,6 +7,7 @@ go_library( "batch_dependent.go", "build.go", "change_provider.go", + "queue_config.go", "request.go", "speculation_tree.go", ], @@ -16,7 +17,10 @@ go_library( go_test( name = "entity_test", - srcs = ["request_test.go"], + srcs = [ + "queue_config_test.go", + "request_test.go", + ], embed = [":entity"], deps = [ "@com_github_stretchr_testify//assert", diff --git a/entity/queue_config.go b/entity/queue_config.go new file mode 100644 index 00000000..673cbcba --- /dev/null +++ b/entity/queue_config.go @@ -0,0 +1,48 @@ +package entity + +// QueueConfig holds the configuration for a single submit queue. +// Each queue maps a repository + destination to a processing pipeline. +// A repository can have multiple queues, but each queue has exactly one destination. +// Immutable after creation. +type QueueConfig struct { + // Name uniquely identifies this queue within the system. + // Referenced by Request.Queue. + Name string + + // RepositoryID is the platform-specific identifier for the source control repository. + // Opaque to the system; meaningful only to the change provider. + // Examples: + // - GitHub/GitLab: "owner/repo" (e.g., "uber/submitqueue") + // - Perforce: depot path (e.g., "//depot/project") + // - SVN: repository URL (e.g., "https://svn.example.com/repos/project") + RepositoryID string + + // DestinationRef is the VCS-specific reference for the landing target. + // Opaque to the system; meaningful only to the change provider. + // Examples: + // - Git: branch name (e.g., "main", "release/v2") + // - Perforce: stream or depot path (e.g., "//depot/main/...") + // - SVN: repository path (e.g., "trunk/") + // - Mercurial: bookmark name (e.g., "main") + DestinationRef string + + // ChangeProviderNames identifies which change providers to use (e.g., "github", "gerrit"). + // A queue may use multiple providers simultaneously (e.g., "github" and "phabricator"). + // Resolved to ChangeProvider instances at wiring time. + ChangeProviderNames []string +} + +// NewQueueConfig creates a new QueueConfig with the given parameters. +func NewQueueConfig( + name string, + repositoryID string, + destinationRef string, + changeProviderNames []string, +) QueueConfig { + return QueueConfig{ + Name: name, + RepositoryID: repositoryID, + DestinationRef: destinationRef, + ChangeProviderNames: changeProviderNames, + } +} diff --git a/entity/queue_config_test.go b/entity/queue_config_test.go new file mode 100644 index 00000000..c9e4fe2c --- /dev/null +++ b/entity/queue_config_test.go @@ -0,0 +1,29 @@ +package entity + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestNewQueueConfig(t *testing.T) { + cfg := NewQueueConfig("uber/submitqueue/main", "uber/submitqueue", "main", []string{"github"}) + + assert.Equal(t, "uber/submitqueue/main", cfg.Name) + assert.Equal(t, "uber/submitqueue", cfg.RepositoryID) + assert.Equal(t, "main", cfg.DestinationRef) + assert.Equal(t, []string{"github"}, cfg.ChangeProviderNames) +} + +func TestNewQueueConfig_MultipleProviders(t *testing.T) { + cfg := NewQueueConfig( + "uber/go-code/main", + "uber/go-code", + "main", + []string{"github", "phabricator"}, + ) + + assert.Equal(t, "uber/go-code/main", cfg.Name) + assert.Equal(t, []string{"github", "phabricator"}, cfg.ChangeProviderNames) +} + diff --git a/entity/queueconfig/BUILD.bazel b/entity/queueconfig/BUILD.bazel deleted file mode 100644 index 3f5c2673..00000000 --- a/entity/queueconfig/BUILD.bazel +++ /dev/null @@ -1,15 +0,0 @@ -load("@rules_go//go:def.bzl", "go_library", "go_test") - -go_library( - name = "queueconfig", - srcs = ["queueconfig.go"], - importpath = "github.com/uber/submitqueue/entity/queueconfig", - visibility = ["//visibility:public"], -) - -go_test( - name = "queueconfig_test", - srcs = ["queueconfig_test.go"], - embed = [":queueconfig"], - deps = ["@com_github_stretchr_testify//assert"], -) diff --git a/entity/queueconfig/queueconfig.go b/entity/queueconfig/queueconfig.go deleted file mode 100644 index 2ca27077..00000000 --- a/entity/queueconfig/queueconfig.go +++ /dev/null @@ -1,67 +0,0 @@ -package queueconfig - -// Repository identifies a source control repository. -// The interpretation of ID is platform-specific and resolved by the change provider: -// - GitHub/GitLab: "owner/repo" (e.g., "uber/submitqueue") -// - Perforce: depot path (e.g., "//depot/project") -// - SVN: repository URL (e.g., "https://svn.example.com/repos/project") -// -// Immutable after creation. -type Repository struct { - // ID is the platform-specific identifier for the repository. - // Opaque to the system; meaningful only to the change provider. - ID string -} - -// Destination identifies the landing target in a version control system. -// The interpretation of Ref is VCS-specific and resolved by the change provider: -// - Git: branch name (e.g., "main", "release/v2") -// - Perforce: stream or depot path (e.g., "//depot/main/...") -// - SVN: repository path (e.g., "trunk/") -// - Mercurial: bookmark name (e.g., "main") -// -// Immutable after creation. -type Destination struct { - // Ref is the version-control-specific reference for the landing target. - // Opaque to the system; meaningful only to the change provider. - Ref string -} - -// Config holds the configuration for a single submit queue. -// Each queue maps a repository + destination to a processing pipeline. -// A repository can have multiple queues, but each queue has exactly one destination. -// Immutable after creation. -type Config struct { - // Name uniquely identifies this queue within the system. - // Referenced by entity.Request.Queue. - Name string - - // Repository identifies the source control repository this queue operates on. - Repository Repository - - // Destination is the landing target where changes are merged. - Destination Destination - - // ChangeProviderName identifies which change provider to use (e.g., "github", "gerrit"). - // Resolved to a ChangeProvider instance at wiring time. - ChangeProviderName string - - // ChangeProvider is the change provider to use for this queue. - // TODO: - // ChangeProvider ChangeProvider to be defined in the changeprovider extension package -} - -// NewConfig creates a new Config with the given parameters. -func NewConfig( - name string, - repository Repository, - destination Destination, - changeProviderName string, -) Config { - return Config{ - Name: name, - Repository: repository, - Destination: destination, - ChangeProviderName: changeProviderName, - } -} diff --git a/entity/queueconfig/queueconfig_test.go b/entity/queueconfig/queueconfig_test.go deleted file mode 100644 index 97f2040d..00000000 --- a/entity/queueconfig/queueconfig_test.go +++ /dev/null @@ -1,72 +0,0 @@ -package queueconfig - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestNewConfig(t *testing.T) { - repo := Repository{ID: "uber/submitqueue"} - dest := Destination{Ref: "main"} - - cfg := NewConfig("uber/submitqueue/main", repo, dest, "github") - - assert.Equal(t, "uber/submitqueue/main", cfg.Name) - assert.Equal(t, "uber/submitqueue", cfg.Repository.ID) - assert.Equal(t, "main", cfg.Destination.Ref) - assert.Equal(t, "github", cfg.ChangeProviderName) -} - -func TestNewConfig_DifferentPlatforms(t *testing.T) { - tests := []struct { - name string - repo Repository - destination Destination - provider string - }{ - { - name: "github", - repo: Repository{ID: "uber/cadence"}, - destination: Destination{Ref: "release/v2"}, - provider: "github", - }, - { - name: "gerrit", - repo: Repository{ID: "platform/build"}, - destination: Destination{Ref: "refs/heads/main"}, - provider: "gerrit", - }, - { - name: "perforce", - repo: Repository{ID: "//depot/project"}, - destination: Destination{Ref: "//depot/main/..."}, - provider: "perforce", - }, - { - name: "svn", - repo: Repository{ID: "https://svn.example.com/repos/project"}, - destination: Destination{Ref: "trunk/"}, - provider: "svn", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - cfg := NewConfig(tt.name, tt.repo, tt.destination, tt.provider) - - assert.Equal(t, tt.repo, cfg.Repository) - assert.Equal(t, tt.destination, cfg.Destination) - assert.Equal(t, tt.provider, cfg.ChangeProviderName) - }) - } -} - -func TestConfig_ZeroValue(t *testing.T) { - var cfg Config - - assert.Empty(t, cfg.Name) - assert.Empty(t, cfg.Repository.ID) - assert.Empty(t, cfg.Destination.Ref) - assert.Empty(t, cfg.ChangeProviderName) -} diff --git a/extension/queueconfig/BUILD.bazel b/extension/queueconfig/BUILD.bazel index f274a446..27a152fa 100644 --- a/extension/queueconfig/BUILD.bazel +++ b/extension/queueconfig/BUILD.bazel @@ -5,5 +5,5 @@ go_library( srcs = ["queueconfig.go"], importpath = "github.com/uber/submitqueue/extension/queueconfig", visibility = ["//visibility:public"], - deps = ["//entity/queueconfig"], + deps = ["//entity"], ) diff --git a/extension/queueconfig/README.md b/extension/queueconfig/README.md index e8a03fea..f1cefc9e 100644 --- a/extension/queueconfig/README.md +++ b/extension/queueconfig/README.md @@ -10,15 +10,13 @@ Provides queue configurations by name. ```go type Store interface { - Get(ctx context.Context, name string) (queueconfig.Config, error) - List(ctx context.Context) ([]queueconfig.Config, error) + Get(ctx context.Context, name string) (entity.QueueConfig, error) + List(ctx context.Context) ([]entity.QueueConfig, error) } ``` ## Entities -Queue configuration entities live in `entity/queueconfig/`: +Queue configuration entity lives in `entity/queue_config.go`: -- **Config** — configuration for a single submit queue (name, repository, destination, change provider) -- **Repository** — platform-specific repository identifier (opaque ID string) -- **Destination** — VCS-agnostic landing target (opaque ref string interpreted by the change provider) +- **QueueConfig** — configuration for a single submit queue (name, repository ID, destination ref, change provider names) diff --git a/extension/queueconfig/queueconfig.go b/extension/queueconfig/queueconfig.go index 44d8e2c6..22f33835 100644 --- a/extension/queueconfig/queueconfig.go +++ b/extension/queueconfig/queueconfig.go @@ -4,7 +4,7 @@ import ( "context" "errors" - "github.com/uber/submitqueue/entity/queueconfig" + "github.com/uber/submitqueue/entity" ) // ErrNotFound is returned when the requested queue configuration does not exist. @@ -15,8 +15,8 @@ var ErrNotFound = errors.New("queue config not found") type Store interface { // Get returns the configuration for a named queue. // Returns ErrNotFound if no configuration exists for the given name. - Get(ctx context.Context, name string) (queueconfig.Config, error) + Get(ctx context.Context, name string) (entity.QueueConfig, error) // List returns all configured queues. - List(ctx context.Context) ([]queueconfig.Config, error) + List(ctx context.Context) ([]entity.QueueConfig, error) } From 717d87af0df63d06afd4a751336e41e1695f0b66 Mon Sep 17 00:00:00 2001 From: "kevin.new" Date: Tue, 24 Feb 2026 20:02:40 +0000 Subject: [PATCH 4/6] changing to VSCType, VSCRepo, Target; added Create to queueconfig store interface --- entity/queue_config.go | 46 +++++++++++++--------------- entity/queue_config_test.go | 21 +++---------- extension/queueconfig/README.md | 2 +- extension/queueconfig/queueconfig.go | 7 +++++ 4 files changed, 33 insertions(+), 43 deletions(-) diff --git a/entity/queue_config.go b/entity/queue_config.go index 673cbcba..f07d317f 100644 --- a/entity/queue_config.go +++ b/entity/queue_config.go @@ -1,48 +1,44 @@ package entity // QueueConfig holds the configuration for a single submit queue. -// Each queue maps a repository + destination to a processing pipeline. -// A repository can have multiple queues, but each queue has exactly one destination. +// Each queue maps a VCS repository + target to a processing pipeline. +// A repository can have multiple queues, but each queue has exactly one target. // Immutable after creation. type QueueConfig struct { // Name uniquely identifies this queue within the system. // Referenced by Request.Queue. Name string - // RepositoryID is the platform-specific identifier for the source control repository. - // Opaque to the system; meaningful only to the change provider. - // Examples: - // - GitHub/GitLab: "owner/repo" (e.g., "uber/submitqueue") + // VCSType identifies the version control system (e.g., "git", "svn", "perforce"). + // A queue operates on exactly one VCS. + VCSType string + + // VCSRepo identifies the repository in the version control system. + // The format is VCS-specific: + // - Git: remote URL (e.g., "git@github.com:uber/submitqueue.git") // - Perforce: depot path (e.g., "//depot/project") // - SVN: repository URL (e.g., "https://svn.example.com/repos/project") - RepositoryID string + VCSRepo string - // DestinationRef is the VCS-specific reference for the landing target. - // Opaque to the system; meaningful only to the change provider. - // Examples: - // - Git: branch name (e.g., "main", "release/v2") + // Target is the landing target where changes are merged. + // The format is VCS-specific: + // - Git: branch ref (e.g., "main", "release/v2") // - Perforce: stream or depot path (e.g., "//depot/main/...") // - SVN: repository path (e.g., "trunk/") - // - Mercurial: bookmark name (e.g., "main") - DestinationRef string - - // ChangeProviderNames identifies which change providers to use (e.g., "github", "gerrit"). - // A queue may use multiple providers simultaneously (e.g., "github" and "phabricator"). - // Resolved to ChangeProvider instances at wiring time. - ChangeProviderNames []string + Target string } // NewQueueConfig creates a new QueueConfig with the given parameters. func NewQueueConfig( name string, - repositoryID string, - destinationRef string, - changeProviderNames []string, + vcsType string, + vcsRepo string, + target string, ) QueueConfig { return QueueConfig{ - Name: name, - RepositoryID: repositoryID, - DestinationRef: destinationRef, - ChangeProviderNames: changeProviderNames, + Name: name, + VCSType: vcsType, + VCSRepo: vcsRepo, + Target: target, } } diff --git a/entity/queue_config_test.go b/entity/queue_config_test.go index c9e4fe2c..5d187f92 100644 --- a/entity/queue_config_test.go +++ b/entity/queue_config_test.go @@ -7,23 +7,10 @@ import ( ) func TestNewQueueConfig(t *testing.T) { - cfg := NewQueueConfig("uber/submitqueue/main", "uber/submitqueue", "main", []string{"github"}) + cfg := NewQueueConfig("uber/submitqueue/main", "git", "git@github.com:uber/submitqueue.git", "main") assert.Equal(t, "uber/submitqueue/main", cfg.Name) - assert.Equal(t, "uber/submitqueue", cfg.RepositoryID) - assert.Equal(t, "main", cfg.DestinationRef) - assert.Equal(t, []string{"github"}, cfg.ChangeProviderNames) + assert.Equal(t, "git", cfg.VCSType) + assert.Equal(t, "git@github.com:uber/submitqueue.git", cfg.VCSRepo) + assert.Equal(t, "main", cfg.Target) } - -func TestNewQueueConfig_MultipleProviders(t *testing.T) { - cfg := NewQueueConfig( - "uber/go-code/main", - "uber/go-code", - "main", - []string{"github", "phabricator"}, - ) - - assert.Equal(t, "uber/go-code/main", cfg.Name) - assert.Equal(t, []string{"github", "phabricator"}, cfg.ChangeProviderNames) -} - diff --git a/extension/queueconfig/README.md b/extension/queueconfig/README.md index f1cefc9e..4c94c8c8 100644 --- a/extension/queueconfig/README.md +++ b/extension/queueconfig/README.md @@ -19,4 +19,4 @@ type Store interface { Queue configuration entity lives in `entity/queue_config.go`: -- **QueueConfig** — configuration for a single submit queue (name, repository ID, destination ref, change provider names) +- **QueueConfig** — configuration for a single submit queue (name, VCS type, VCS repo, target) diff --git a/extension/queueconfig/queueconfig.go b/extension/queueconfig/queueconfig.go index 22f33835..4a8c953b 100644 --- a/extension/queueconfig/queueconfig.go +++ b/extension/queueconfig/queueconfig.go @@ -10,9 +10,16 @@ import ( // ErrNotFound is returned when the requested queue configuration does not exist. var ErrNotFound = errors.New("queue config not found") +// ErrAlreadyExists is returned when a queue configuration with the same name already exists. +var ErrAlreadyExists = errors.New("queue config already exists") + // Store loads and provides queue configurations. // Implementations may read from YAML files, databases, remote services, etc. type Store interface { + // Create adds a new queue configuration. + // Returns ErrAlreadyExists if a configuration with the same name already exists. + Create(ctx context.Context, config entity.QueueConfig) error + // Get returns the configuration for a named queue. // Returns ErrNotFound if no configuration exists for the given name. Get(ctx context.Context, name string) (entity.QueueConfig, error) From 906958462baaffdbee30021404f586fd4cb4a24a Mon Sep 17 00:00:00 2001 From: "kevin.new" Date: Tue, 24 Feb 2026 20:57:33 +0000 Subject: [PATCH 5/6] rename to VCSAddress to be less 'git'-y --- entity/queue_config.go | 14 +++++++------- entity/queue_config_test.go | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/entity/queue_config.go b/entity/queue_config.go index f07d317f..9e042921 100644 --- a/entity/queue_config.go +++ b/entity/queue_config.go @@ -13,12 +13,12 @@ type QueueConfig struct { // A queue operates on exactly one VCS. VCSType string - // VCSRepo identifies the repository in the version control system. + // VCSAddress identifies the repository in the version control system. // The format is VCS-specific: // - Git: remote URL (e.g., "git@github.com:uber/submitqueue.git") // - Perforce: depot path (e.g., "//depot/project") // - SVN: repository URL (e.g., "https://svn.example.com/repos/project") - VCSRepo string + VCSAddress string // Target is the landing target where changes are merged. // The format is VCS-specific: @@ -32,13 +32,13 @@ type QueueConfig struct { func NewQueueConfig( name string, vcsType string, - vcsRepo string, + vcsAddress string, target string, ) QueueConfig { return QueueConfig{ - Name: name, - VCSType: vcsType, - VCSRepo: vcsRepo, - Target: target, + Name: name, + VCSType: vcsType, + VCSAddress: vcsAddress, + Target: target, } } diff --git a/entity/queue_config_test.go b/entity/queue_config_test.go index 5d187f92..3e181656 100644 --- a/entity/queue_config_test.go +++ b/entity/queue_config_test.go @@ -11,6 +11,6 @@ func TestNewQueueConfig(t *testing.T) { assert.Equal(t, "uber/submitqueue/main", cfg.Name) assert.Equal(t, "git", cfg.VCSType) - assert.Equal(t, "git@github.com:uber/submitqueue.git", cfg.VCSRepo) + assert.Equal(t, "git@github.com:uber/submitqueue.git", cfg.VCSAddress) assert.Equal(t, "main", cfg.Target) } From c7cd6b48f2caecafea053d3cd67389d5954f1eba Mon Sep 17 00:00:00 2001 From: "kevin.new" Date: Tue, 24 Feb 2026 22:43:52 +0000 Subject: [PATCH 6/6] removed Create from queueconfig interface --- extension/queueconfig/queueconfig.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/extension/queueconfig/queueconfig.go b/extension/queueconfig/queueconfig.go index 4a8c953b..22f33835 100644 --- a/extension/queueconfig/queueconfig.go +++ b/extension/queueconfig/queueconfig.go @@ -10,16 +10,9 @@ import ( // ErrNotFound is returned when the requested queue configuration does not exist. var ErrNotFound = errors.New("queue config not found") -// ErrAlreadyExists is returned when a queue configuration with the same name already exists. -var ErrAlreadyExists = errors.New("queue config already exists") - // Store loads and provides queue configurations. // Implementations may read from YAML files, databases, remote services, etc. type Store interface { - // Create adds a new queue configuration. - // Returns ErrAlreadyExists if a configuration with the same name already exists. - Create(ctx context.Context, config entity.QueueConfig) error - // Get returns the configuration for a named queue. // Returns ErrNotFound if no configuration exists for the given name. Get(ctx context.Context, name string) (entity.QueueConfig, error)