Skip to content

Commit 540b86c

Browse files
authored
Merge branch 'main' into manjari/tango-analyzer
2 parents 8b63965 + e47fee7 commit 540b86c

46 files changed

Lines changed: 4302 additions & 1695 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

MODULE.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ use_repo(
6666
"org_golang_google_protobuf",
6767
"org_golang_x_oauth2",
6868
"org_golang_x_sync",
69+
"org_golang_x_term",
6970
"org_uber_go_fx",
7071
"org_uber_go_mock",
7172
"org_uber_go_yarpc",

Makefile

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,10 @@ export SQ_PROVIDER_CONFIG_DIR ?= $(REPO_ROOT)/service/submitqueue/demo/provider/
5656
DEMO_REPO ?= behinddwalls/sq-demo
5757
COUNT ?= 3
5858
FILES ?= 3
59+
CONCURRENCY ?= 5
5960
STACKED ?= false
61+
SINCE ?= 1h
62+
LIMIT ?= 50
6063
LAND ?= true
6164
WATCH ?= true
6265
QUEUE ?= demo-queue
@@ -74,7 +77,7 @@ define assert_clean
7477
fi
7578
endef
7679

77-
.PHONY: build build-all-linux build-runway-linux build-submitqueue-gateway-linux build-submitqueue-orchestrator-linux build-stovepipe-linux build-stovepipe-linux-debug check-gazelle check-mocks check-tidy clean clean-proto deps e2e-test fmt gazelle integration-test integration-test-submitqueue-consumer integration-test-extensions integration-test-submitqueue-gateway integration-test-submitqueue-orchestrator license-fix lint lint-fmt lint-license local-init-runway-queue-schema local-init-stovepipe-schemas local-runway-start local-runway-stop local-submitqueue-clean local-submitqueue-gateway-start local-submitqueue-gateway-stop local-init-submitqueue-schemas local-submitqueue-logs local-submitqueue-orchestrator-start local-submitqueue-orchestrator-stop local-submitqueue-ps local-submitqueue-restart local-submitqueue-start local-stop local-stovepipe-debug-start local-stovepipe-logs local-stovepipe-start local-stovepipe-stop mocks proto query-deps query-targets run-client-runway run-client-submitqueue-gateway run-client-submitqueue-orchestrator run-client-stovepipe run-queue-admin test test-no-cache tidy tidy-bazel tidy-go help
80+
.PHONY: build build-all-linux build-runway-linux build-submitqueue-gateway-client build-submitqueue-gateway-linux build-submitqueue-gateway-server build-submitqueue-orchestrator-linux build-stovepipe-linux build-stovepipe-linux-debug check-gazelle check-mocks check-tidy clean clean-proto deps e2e-test fmt gazelle integration-test integration-test-submitqueue-consumer integration-test-extensions integration-test-submitqueue-gateway integration-test-submitqueue-orchestrator license-fix lint lint-binary lint-fmt lint-license local-init-runway-queue-schema local-init-stovepipe-schemas local-runway-start local-runway-stop local-submitqueue-clean local-submitqueue-gateway-start local-submitqueue-gateway-stop local-init-submitqueue-schemas local-submitqueue-logs local-submitqueue-orchestrator-start local-submitqueue-orchestrator-stop local-submitqueue-ps local-submitqueue-restart local-submitqueue-start local-stop local-stovepipe-debug-start local-stovepipe-logs local-stovepipe-start local-stovepipe-stop mocks proto query-deps query-targets run-client-runway run-client-submitqueue-gateway run-client-submitqueue-orchestrator run-client-stovepipe run-queue-admin test test-no-cache tidy tidy-bazel tidy-go help
7881

7982

8083
build: ## Build all services and examples
@@ -96,6 +99,14 @@ build-runway-linux: ## Build Runway Linux binary for Docker
9699
cp -f bazel-bin/service/runway/server/runway .docker-bin/runway
97100
@echo "Runway Linux binary ready at .docker-bin/runway"
98101

102+
build-submitqueue-gateway-client: ## Build the gateway client CLI for the host platform into bin/client
103+
@echo "Building gateway client..."
104+
@$(BAZEL) build //service/submitqueue/gateway/client:gateway
105+
@mkdir -p bin
106+
@cp -f bazel-bin/service/submitqueue/gateway/client/gateway_/gateway bin/client 2>/dev/null || \
107+
cp -f bazel-bin/service/submitqueue/gateway/client/gateway bin/client
108+
@echo "Gateway client ready at bin/client"
109+
99110
build-submitqueue-gateway-linux: ## Build Gateway Linux binary for Docker
100111
@echo "Building Gateway Linux binary for Docker..."
101112
@$(BAZEL) build --platforms=@rules_go//go/toolchain:linux_amd64 //service/submitqueue/gateway/server:gateway
@@ -104,6 +115,14 @@ build-submitqueue-gateway-linux: ## Build Gateway Linux binary for Docker
104115
cp -f bazel-bin/service/submitqueue/gateway/server/gateway .docker-bin/gateway
105116
@echo "Gateway Linux binary ready at .docker-bin/gateway"
106117

118+
build-submitqueue-gateway-server: ## Build the gateway server for the host platform into bin/server
119+
@echo "Building gateway server..."
120+
@$(BAZEL) build //service/submitqueue/gateway/server:gateway
121+
@mkdir -p bin
122+
@cp -f bazel-bin/service/submitqueue/gateway/server/gateway_/gateway bin/server 2>/dev/null || \
123+
cp -f bazel-bin/service/submitqueue/gateway/server/gateway bin/server
124+
@echo "Gateway server ready at bin/server"
125+
107126
build-submitqueue-orchestrator-linux: ## Build Orchestrator Linux binary for Docker
108127
@echo "Building Orchestrator Linux binary for Docker..."
109128
@$(BAZEL) build --platforms=@rules_go//go/toolchain:linux_amd64 //service/submitqueue/orchestrator/server:orchestrator
@@ -153,13 +172,14 @@ clean-proto: ## Clean generated proto files
153172
@rm -f $(foreach p,$(PROTO_PACKAGES),$(p)/protopb/*.pb.go $(p)/protopb/*.pb.yarpc.go)
154173
@echo "Proto clean complete!"
155174

156-
demo-pr: ## Create N PRs in the demo repo, enqueue each as it is created, and watch (COUNT=3 FILES=3; needs GITHUB_TOKEN)
175+
demo-pr: ## Create N PRs in the demo repo, enqueue each as it is created, and watch (COUNT=3 FILES=3 CONCURRENCY=5; needs GITHUB_TOKEN)
157176
@$(BAZEL) run //service/submitqueue/demo/pr -- \
158177
-repo $(DEMO_REPO) \
159178
-count $(COUNT) \
160179
-files $(FILES) \
180+
-concurrency $(CONCURRENCY) \
161181
-stacked=$(STACKED) \
162-
-gateway $(GATEWAY_ADDR) \
182+
-addr $(GATEWAY_ADDR) \
163183
-queue $(QUEUE) \
164184
-strategy $(STRATEGY) \
165185
-land=$(LAND) -watch=$(WATCH)
@@ -227,12 +247,23 @@ land-status: ## Read a landed request's status (SQID=... [QUEUE=demo-queue])
227247
@$(BAZEL) run //service/submitqueue/gateway/client:gateway -- \
228248
-addr $(GATEWAY_ADDR) status -queue $(QUEUE) -sqid $(SQID)
229249

250+
land-list: ## Show a queue's recent requests as a table (QUEUE=demo-queue SINCE=1h LIMIT=50)
251+
@$(BAZEL) run //service/submitqueue/gateway/client:gateway -- \
252+
-addr $(GATEWAY_ADDR) list -queue $(QUEUE) -since $(SINCE) -limit $(LIMIT)
253+
254+
land-watch: ## Follow a queue's requests until they settle (QUEUE=demo-queue SINCE=15m LIMIT=50)
255+
@$(BAZEL) run //service/submitqueue/gateway/client:gateway -- \
256+
-addr $(GATEWAY_ADDR) watch -queue $(QUEUE) -since $(SINCE) -limit $(LIMIT)
257+
230258
license-fix: ## Add missing license headers to source files
231259
@$(BAZEL) run //tool/linter/licenseheader -- --fix
232260

233-
lint: lint-fmt lint-license lint-message-id lint-queue-shard ## Run all linters
261+
lint: lint-binary lint-fmt lint-license lint-message-id lint-queue-shard ## Run all linters
234262
@echo "All lint checks passed."
235263

264+
lint-binary: ## Check no binary file is tracked in the repository
265+
@$(BAZEL) run //tool/linter/binaryfile
266+
236267
lint-fmt: fmt ## Check code formatting (fails if unformatted)
237268
$(call assert_clean,make fmt)
238269
@echo "All code is properly formatted."

README.md

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,34 +15,38 @@ Cross-domain Go code (errors, metrics, consumer framework, HTTP helpers, shared
1515

1616
## Quick Start
1717

18-
Requires Docker and Docker Compose. See [Development Setup](doc/howto/DEVELOPMENT.md) for full prerequisites.
18+
Land a change and watch it reach `landed`. Requires Docker and Docker Compose, and nothing else — no repository, no account, no token. See [Development Setup](doc/howto/DEVELOPMENT.md) for full prerequisites.
1919

2020
```bash
21-
# Build everything
22-
make build
23-
24-
# Run unit tests
25-
make test
26-
27-
# Start full stack locally (Gateway + Orchestrator + MySQL via Docker Compose)
21+
# Start the full stack (Gateway + Orchestrator + Runway + MySQL)
2822
make local-submitqueue-start
2923

30-
# Test with grpcurl
31-
grpcurl -plaintext -d '{"message": "hello"}' localhost:8081 uber.submitqueue.gateway.SubmitQueueGateway/Ping
24+
# Compose publishes a random host port; the line above prints it, as does this
25+
make local-submitqueue-ps
26+
export GATEWAY_ADDR=localhost:<gateway port>
27+
28+
# Submit a change, and follow the receipt it returns
29+
make land QUEUE=test-queue \
30+
URI='git://git.example.com/demo/refs%2Fheads%2Ffeature-a/1111111111111111111111111111111111111111'
31+
make land-status QUEUE=test-queue SQID=test-queue/1
3232

3333
# Stop services
3434
make local-stop
3535
```
3636

37-
See [service/README.md](service/README.md) for more examples including running individual services and clients.
37+
Every integration at the edges is faked — the change provider, CI, and the merge itself — so the run is free and finishes in seconds. The queue's own logic is real: validation, batching, conflict analysis, and speculation all run, and the request log records the full trail from `accepted` to `landed`. Nothing is pushed to any repository.
38+
39+
[Quickstart](doc/howto/QUICKSTART.md) explains the change URI, how to make a change fail on demand, and what this does and does not prove. From there, `make e2e-git-test` adds a real git merge (still no credentials), and [PROVIDER-E2E.md](doc/howto/PROVIDER-E2E.md) adds a live provider. See [service/README.md](service/README.md) for running individual services and clients.
3840

3941
## Documentation
4042

4143
| Document | Description |
4244
|----------|-------------|
45+
| [Quickstart](doc/howto/QUICKSTART.md) | Land a change locally with no credentials |
4346
| [Development Setup](doc/howto/DEVELOPMENT.md) | Prerequisites, build, environment, IDE setup |
4447
| [Contributing](CONTRIBUTING.md) | How to contribute, workflow, guidelines |
4548
| [Testing Guide](doc/howto/TESTING.md) | Unit, integration, and E2E testing patterns |
49+
| [Landing real changes](doc/howto/PROVIDER-E2E.md) | Running the pipeline against a live provider |
4650
| [Architecture Guide](CLAUDE.md) | Project layout, patterns, conventions |
4751
| [Examples](service/README.md) | Running services, clients, API reference |
4852
| [RFCs](doc/rfc/index.md) | Design documents and proposals |

doc/howto/DEVELOPMENT.md

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ make test
5151

5252
## Try It Locally
5353

54-
After building, start the full stack to confirm everything works end to end:
54+
After building, start the full stack and land a change through it:
5555

5656
```bash
5757
# 1. Confirm Docker is running
@@ -60,16 +60,21 @@ docker ps
6060
# 2. Start the full stack
6161
make local-submitqueue-start
6262

63-
# 3. Check services are up (Gateway on :8081, Orchestrator on :8082)
63+
# 3. Read the gateway's port (Compose publishes a random one)
6464
make local-submitqueue-ps
65+
export GATEWAY_ADDR=localhost:<gateway port>
6566

66-
# 4. Test Gateway with grpcurl
67-
grpcurl -plaintext -d '{"message": "hello"}' localhost:8081 uber.submitqueue.gateway.SubmitQueueGateway/Ping
67+
# 4. Land a change and follow it to a terminal status
68+
make land QUEUE=test-queue \
69+
URI='git://git.example.com/demo/refs%2Fheads%2Ffeature-a/1111111111111111111111111111111111111111'
70+
make land-status QUEUE=test-queue SQID=test-queue/1
6871

6972
# 5. Stop services
7073
make local-stop
7174
```
7275

76+
[QUICKSTART.md](QUICKSTART.md) walks through the same run in detail — what the change URI has to look like, how to make a change fail on demand, and which parts of the pipeline are faked.
77+
7378
If any step fails, see [Troubleshooting](#troubleshooting) below.
7479

7580
## IDE Setup

doc/howto/PROVIDER-E2E.md

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,27 +97,32 @@ Opening pull requests by hand gets old fast. `demo-pr` creates them, enqueues th
9797
make demo-pr # 3 independent PRs, each enqueued as it is created
9898
make demo-pr COUNT=8 # more traffic
9999
make demo-pr FILES=8 # wider changes, more files per PR
100+
make demo-pr CONCURRENCY=1 # create them one at a time
100101
make demo-pr STACKED=true # one stack, enqueued as a single request
101102
make demo-pr LAND=false # create only, print the land command
102103
```
103104

104105
Each pull request is enqueued the moment it exists, so the queue is already working on the first while the last is still being opened. That overlap is the point: a queue holding one request at a time never batches, never analyzes a conflict against another batch, and never speculates. Nothing is awaited until every request is in.
105106

107+
Independent pull requests are created **five at a time** by default (`CONCURRENCY`). Opening one is several round trips — a branch, a commit per file, the pull request itself — so creating them serially was most of what a large run spent its time on, and it delayed the overlap the demo exists to show. A stack ignores the setting: each of its changes is based on the branch before it, so the next cannot be cut until the previous head exists. Lower it if the provider starts refusing bursts.
108+
106109
The table is there from the start — one row per land request, drawn before the first pull request exists and filled in as the run proceeds. Whatever is happening right now is a single line underneath it, so creating and enqueuing does not scroll the table away:
107110

108111
```
109112
REQUEST CHANGES ELAPSED STAGE
110-
───────────── ─────── ─────── ─────────────────────────────────────────────────
111-
demo-queue/12 #31 34s accepted → started → validated → batched → landed
112-
demo-queue/13 #32 31s accepted → started → validated → batched
113+
───────────── ─────── ─────── ────────────────────────────────────────────────
114+
demo-queue/12 #31 34s accepted → started → validating → validated →
115+
batched → speculating → speculated → landing →
116+
landed
117+
demo-queue/13 #32 31s accepted → started → validating → validated
113118
demo-queue/14 #33 28s accepted → started
114119
115120
▸ 1 of 3 settled
116121
```
117122

118123
Each row shows the states its request passed through, not just the one it is in. That comes from the gateway's history API rather than from sampling the current status, so a transition between two polls is not missed. `CHANGES` links to the pull request: on a terminal `#31` is clickable, and in a redirected run it is written out as a full URL instead. `ELAPSED` runs from the moment the gateway accepted the request and stops when it settles, so a finished row keeps the time it took rather than counting on.
119124

120-
The trail is only as detailed as what the pipeline reports, which today is `accepted`, `started`, `validated`, `batched` and then a terminal `landed`, `error` or `cancelled`. The finer-grained statuses the API defines — `speculating`, `building`, `landing` and the rest — are never published, so a request sits on `batched` for the whole of its active life even while its batch is speculating and building. Do not read that as the request being stuck.
125+
The trail is as detailed as what the pipeline reports, which is the full walk: `accepted`, `started`, `validating`, `validated`, `batched`, `speculating`, `speculated`, `landing`, and then a terminal `landed`, `error` or `cancelled`. `building` and `built` are recorded alongside as events rather than statuses. A long pause on `speculating` is the batch waiting on its build, not a stuck request.
121126

122127
`STACKED=true` is the exception to the overlap: one request carries the whole chain, so it can only go in once every pull request in it exists. That is the atomic-stack path — the whole set reaches `main` in a single push, and the table shows it as the single row it is.
123128

@@ -129,6 +134,40 @@ The command exits non-zero if any request settles anywhere other than `landed`,
129134

130135
## Watching it work
131136

137+
The queue itself is readable without creating any traffic:
138+
139+
```bash
140+
make land-list # a table of recent requests
141+
make land-list SINCE=24h LIMIT=200 # a wider window
142+
make land-watch # follow them until they settle
143+
```
144+
145+
Both draw the same table `make demo-pr` does — the demo tool and the CLI share it — but against whatever the queue already holds, so watching a queue no longer means adding to it. `land-watch` fixes its set when it starts and exits non-zero if any request in that set finishes anywhere other than `landed`, which makes it usable from a script. A request accepted after the watch begins is not picked up: a watch that grew as the queue did would never finish.
146+
147+
Under the hood these are `client list` and `client watch`, which take a queue and reach any gateway:
148+
149+
```bash
150+
bazel run //service/submitqueue/gateway/client:gateway -- \
151+
-addr sq.example.com:443 -tls list -queue my-queue -since 1h
152+
```
153+
154+
`-addr` is passed to the dialler untouched, so `dns:///host:port` and `unix:///path.sock` work as well as a plain `host:port`. Transport security is a separate flag rather than part of the address, because gRPC keeps target resolution and credentials apart — there is no `grpcs://` to write.
155+
156+
A listing of a busy queue is mostly `speculating` rows, since that is where a request spends most of its active life — waiting on the build its batch was admitted for.
157+
158+
### Authentication
159+
160+
The gateway admits every caller. It is a sandbox stack, and nothing in it checks a credential.
161+
162+
The client can still present one, for a gateway reached through something that does — a proxy, a mesh sidecar, an ingress that terminates auth ahead of the service. It reads `SQ_TOKEN` by default and sends it as `Authorization: Bearer …`; `-token-env` names a different variable, and an unset one sends nothing rather than failing, which is how it stays usable against a stack that wants no credential.
163+
164+
```bash
165+
SQ_TOKEN=$(cat ~/.sq-token) bazel run //service/submitqueue/gateway/client:gateway -- \
166+
-addr sq.example.com:443 -tls list -queue my-queue
167+
```
168+
169+
### Service logs
170+
132171
```bash
133172
docker compose -p submitqueue-provider logs -f runway-service
134173
```

0 commit comments

Comments
 (0)