Skip to content

Commit 28e4d22

Browse files
authored
Merge branch 'main' into mnoah1/pin-docker-compose
2 parents 0128cca + d0d5f8b commit 28e4d22

196 files changed

Lines changed: 14605 additions & 1268 deletions

File tree

Some content is hidden

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

‎.dockerignore‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
.git
2+
bazel-*
3+
bin
4+
web/**/.next
5+
web/**/coverage
6+
web/**/dist
7+
web/**/node_modules
8+
web/**/playwright-report
9+
web/**/test-results
10+
web/**/*.tsbuildinfo
Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: Upload Bazel test logs
2-
description: Upload bazel-testlogs on job failure so truncated CI output is not the only diagnostic.
2+
description: Upload bazel-testlogs and test outputs (for example Playwright traces and compose logs) on job failure so truncated CI output is not the only diagnostic.
33

44
runs:
55
using: composite
@@ -8,6 +8,8 @@ runs:
88
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
99
with:
1010
name: testlogs-${{ github.job }}-${{ github.run_id }}-${{ github.run_attempt }}
11-
path: bazel-testlogs/**/test.log
11+
path: |
12+
bazel-testlogs/**/test.log
13+
bazel-testlogs/**/test.outputs/**
1214
if-no-files-found: warn
1315
retention-days: 7

‎.github/workflows/ci.yml‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,22 @@ jobs:
104104
if: ${{ failure() }}
105105
uses: ./.github/actions/upload-testlogs
106106

107+
web:
108+
name: Web
109+
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.draft == false }}
110+
runs-on: ubuntu-latest
111+
steps:
112+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
113+
with:
114+
persist-credentials: false
115+
- uses: ./.github/actions/setup
116+
- name: Run web checks
117+
run: make web-check
118+
119+
- name: Upload Bazel failure logs
120+
if: ${{ failure() }}
121+
uses: ./.github/actions/upload-testlogs
122+
107123
# ---------------------------------------------------------------------------
108124
# INTEGRATION TESTS (e2e, gateway, orchestrator)
109125
# ---------------------------------------------------------------------------
@@ -135,6 +151,22 @@ jobs:
135151
if: ${{ failure() }}
136152
uses: ./.github/actions/upload-testlogs
137153

154+
web-e2e:
155+
name: Web E2E
156+
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.draft == false }}
157+
runs-on: ubuntu-latest
158+
steps:
159+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
160+
with:
161+
persist-credentials: false
162+
- uses: ./.github/actions/setup
163+
- name: Run real-stack web E2E
164+
run: make web-e2e-test
165+
166+
- name: Upload Bazel failure logs
167+
if: ${{ failure() }}
168+
uses: ./.github/actions/upload-testlogs
169+
138170
gateway-integration-test:
139171
name: Gateway Integration Test
140172
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.draft == false }}
@@ -354,6 +386,8 @@ jobs:
354386
- merger-integration-test
355387
- storage-integration-test
356388
- consumer-integration-test
389+
- web
390+
- web-e2e
357391
- workflow-security
358392
steps:
359393
- name: Fail if any required check did not succeed

‎.gitignore‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,13 @@ bin/
2727
# Documentation site build output
2828
/tool/docsite/build/
2929
/tool/docsite/hooks/__pycache__/
30+
31+
# Web workspace build output
32+
/web/node_modules/
33+
/web/**/node_modules/
34+
/web/**/dist/
35+
/web/**/.next/
36+
/web/**/coverage/
37+
/web/**/playwright-report/
38+
/web/**/test-results/
39+
/web/**/*.tsbuildinfo

‎BUILD.bazel‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ load("@gazelle//:def.bzl", "gazelle")
1010
# Exclude nested worktrees (created under .claude/worktrees) so gazelle does not
1111
# index them as duplicate rule definitions and corrupt the canonical BUILD files.
1212
# gazelle:exclude .claude
13+
# gazelle:exclude web
1314

1415
# Disable Gazelle proto rule generation globally. We rely on the checked-in
1516
# .pb.go files in protopb/ dirs (plain go_library) rather than Bazel proto

‎MODULE.bazel‎

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,15 @@ bazel_dep(name = "git", version = "2.55.0")
55
bazel_dep(name = "rules_go", version = "0.59.0")
66
bazel_dep(name = "gazelle", version = "0.53.0")
77
bazel_dep(name = "rules_proto", version = "7.1.0")
8+
bazel_dep(name = "aspect_rules_js", version = "3.5.0")
9+
bazel_dep(name = "aspect_rules_ts", version = "3.10.1")
10+
bazel_dep(name = "rules_nodejs", version = "6.7.3")
11+
bazel_dep(name = "rules_oci", version = "2.3.0")
12+
bazel_dep(name = "rules_pkg", version = "1.0.1")
13+
bazel_dep(name = "rules_playwright", version = "0.5.3")
814
bazel_dep(name = "rules_python", version = "2.2.0")
15+
bazel_dep(name = "bazel_lib", version = "3.7.2")
16+
bazel_dep(name = "platforms", version = "1.1.0")
917

1018
bazel_dep(name = "rules_docker_compose", version = "0.4.0", dev_dependency = True)
1119

@@ -31,6 +39,52 @@ use_repo(protoc, "toolchains_protoc_hub")
3139

3240
register_toolchains("@toolchains_protoc_hub//:all")
3341

42+
node = use_extension("@rules_nodejs//nodejs:extensions.bzl", "node")
43+
node.toolchain(node_version = "22.20.0")
44+
45+
typescript = use_extension("@aspect_rules_ts//ts:extensions.bzl", "typescript")
46+
typescript.deps(version_from = "//web:package.json")
47+
use_repo(typescript, "npm_typescript")
48+
49+
npm = use_extension("@aspect_rules_js//npm:extensions.bzl", "npm")
50+
npm.npm_translate_lock(
51+
name = "npm",
52+
pnpm_lock = "//web:pnpm-lock.yaml",
53+
)
54+
use_repo(npm, "npm")
55+
56+
playwright = use_extension("@rules_playwright//playwright:extensions.bzl", "playwright")
57+
playwright.repo(
58+
name = "playwright",
59+
integrity_path_map = {
60+
"builds/chromium/1193/chromium-linux.zip": "sha256-AzVW84unLl+wfBqcmm4P9WtYI8LMQF4DS6V2OmLirRI=",
61+
"builds/chromium/1193/chromium-mac-arm64.zip": "sha256-v7p0571A21zCoO9gPsm6kXNs9ragg2wnpZabV7gES2E=",
62+
},
63+
playwright_version = "1.55.1",
64+
)
65+
use_repo(playwright, "playwright")
66+
67+
oci = use_extension("@rules_oci//oci:extensions.bzl", "oci")
68+
oci.pull(
69+
name = "node_22_20_0_bookworm_slim",
70+
digest = "sha256:b21fe589dfbe5cc39365d0544b9be3f1f33f55f3c86c87a76ff65a02f8f5848e",
71+
image = "node",
72+
platforms = ["linux/amd64"],
73+
)
74+
oci.pull(
75+
name = "mysql_8_0",
76+
digest = "sha256:7dcddc01f13bab2f15cde676d44d01f61fc9f99fe7785e86196dfc07d358ae2b",
77+
image = "mysql",
78+
platforms = ["linux/amd64"],
79+
)
80+
use_repo(
81+
oci,
82+
"mysql_8_0",
83+
"mysql_8_0_linux_amd64",
84+
"node_22_20_0_bookworm_slim",
85+
"node_22_20_0_bookworm_slim_linux_amd64",
86+
)
87+
3488
GO_VERSION = "1.25.0"
3589

3690
go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk")

‎Makefile‎

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ COMPOSE = $(BAZEL) run @rules_docker_compose//docker_compose --
88
COMPOSE_FILE = $(abspath service/submitqueue/docker-compose.yml)
99
GATEWAY_COMPOSE_FILE = $(abspath service/submitqueue/gateway/server/docker-compose.yml)
1010
ORCHESTRATOR_COMPOSE_FILE = $(abspath service/submitqueue/orchestrator/server/docker-compose.yml)
11+
WEB_COMPOSE_FILE = $(abspath service/submitqueue/docker-compose.web.yml)
1112

1213
# Fixed project name for local manual testing (tests use unique random names)
1314
SUBMITQUEUE_LOCAL_PROJECT = submitqueue
@@ -41,6 +42,11 @@ PROTO_PACKAGES = api/base/change api/base/hook api/base/mergestrategy api/base/m
4142
# Set REPO_ROOT for docker-compose
4243
export REPO_ROOT := $(shell pwd)
4344

45+
# Local-only credential for the reference web host. Override it for manual
46+
# testing; production authentication is deliberately outside this demo.
47+
export SUBMITQUEUE_WEB_TOKEN ?= test
48+
export SUBMITQUEUE_WEB_CURSOR_SECRET ?= local-demo-cursor-secret
49+
4450
# Which provider the demo stack targets, and the only difference between a free
4551
# local run and a live one. Selects a configuration directory rather than a code
4652
# path, so adding a provider is mostly adding a directory — see
@@ -148,7 +154,7 @@ define assert_clean
148154
fi
149155
endef
150156

151-
.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 demo-requests deps docs-build docs-serve 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-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 test-race tidy tidy-bazel tidy-go help
157+
.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 demo-requests deps docs-build docs-serve 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-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 test-race tidy tidy-bazel tidy-go web-build web-check web-e2e-test web-image-load web-install web-proto help
152158

153159

154160
build: ## Build all services and examples
@@ -371,7 +377,7 @@ local-submitqueue-clean: ## Stop the stack and remove its volumes, images, and P
371377
@echo "Cleaning all services and data..."
372378
@# The overlay is named so that volumes it declares — Runway's checkouts —
373379
@# are removed too, rather than surviving as an orphan.
374-
@$(COMPOSE) -f $(COMPOSE_FILE) -f $(PROVIDER_COMPOSE_FILE) -p $(SUBMITQUEUE_LOCAL_PROJECT) down -v --rmi local
380+
@$(COMPOSE) -f $(COMPOSE_FILE) -f $(PROVIDER_COMPOSE_FILE) -f $(WEB_COMPOSE_FILE) -p $(SUBMITQUEUE_LOCAL_PROJECT) down -v --rmi local
375381
@rm -rf "$(SQ_GIT_SANDBOX_DIR)"
376382
@echo "All services, volumes, images, and $(SQ_GIT_SANDBOX_DIR) removed."
377383

@@ -460,7 +466,7 @@ local-runway-stop: ## Stop Runway service
460466
@echo "Runway services stopped."
461467

462468
local-submitqueue-logs: ## View logs from all running services
463-
@$(COMPOSE) -f $(COMPOSE_FILE) -p $(SUBMITQUEUE_LOCAL_PROJECT) logs -f
469+
@$(COMPOSE) -f $(COMPOSE_FILE) -f $(PROVIDER_COMPOSE_FILE) -f $(WEB_COMPOSE_FILE) -p $(SUBMITQUEUE_LOCAL_PROJECT) logs -f
464470

465471
local-submitqueue-orchestrator-start: build-submitqueue-orchestrator-linux ## Start Orchestrator service locally (Orchestrator + 2 MySQL databases)
466472
@echo "Starting Orchestrator with docker-compose..."
@@ -484,11 +490,12 @@ local-submitqueue-orchestrator-stop: ## Stop Orchestrator service
484490
local-submitqueue-ps: ## Show running containers and their ports
485491
@echo "Running containers and ports:"
486492
@echo ""
487-
@$(COMPOSE) -f $(COMPOSE_FILE) -p $(SUBMITQUEUE_LOCAL_PROJECT) ps
493+
@$(COMPOSE) -f $(COMPOSE_FILE) -f $(PROVIDER_COMPOSE_FILE) -f $(WEB_COMPOSE_FILE) -p $(SUBMITQUEUE_LOCAL_PROJECT) ps
488494
@echo ""
489495
@echo "📡 Service Endpoints:"
490496
@echo " Gateway gRPC: localhost:$$(docker port $(SUBMITQUEUE_LOCAL_PROJECT)-gateway-service-1 8080 2>/dev/null | cut -d: -f2 || echo 'not running')"
491497
@echo " Orchestrator gRPC: localhost:$$(docker port $(SUBMITQUEUE_LOCAL_PROJECT)-orchestrator-service-1 8080 2>/dev/null | cut -d: -f2 || echo 'not running')"
498+
@echo " Web UX: http://localhost:$$(docker port $(SUBMITQUEUE_LOCAL_PROJECT)-web-service-1 3000 2>/dev/null | cut -d: -f2 || echo 'not running')"
492499
@echo ""
493500
@echo "🗄️ Database Endpoints:"
494501
@echo " MySQL App: localhost:$$(docker port $(SUBMITQUEUE_LOCAL_PROJECT)-mysql-app-1 3306 2>/dev/null | cut -d: -f2 || echo 'not running')"
@@ -506,11 +513,11 @@ local-submitqueue-ps: ## Show running containers and their ports
506513

507514
local-submitqueue-restart: build-all-linux ## Restart all services (rebuild and restart)
508515
@echo "Restarting all services..."
509-
@$(COMPOSE) -f $(COMPOSE_FILE) -p $(SUBMITQUEUE_LOCAL_PROJECT) restart
516+
@$(COMPOSE) -f $(COMPOSE_FILE) -f $(PROVIDER_COMPOSE_FILE) -f $(WEB_COMPOSE_FILE) -p $(SUBMITQUEUE_LOCAL_PROJECT) restart
510517
@echo "Services restarted!"
511518
@make local-submitqueue-ps
512519

513-
local-submitqueue-start: build-all-linux ## Start full stack (PROVIDER=fake|git|github; github needs GITHUB_TOKEN)
520+
local-submitqueue-start: build-all-linux web-image-load ## Start full stack (PROVIDER=fake|git|github; github needs GITHUB_TOKEN)
514521
@echo "Starting full stack against provider '$(PROVIDER)' ($(SQ_PROVIDER_CONFIG_DIR))..."
515522
@test -f "$(SQ_PROVIDER_CONFIG_DIR)/merge.yaml" \
516523
|| { echo "No such provider '$(PROVIDER)': $(SQ_PROVIDER_CONFIG_DIR)/merge.yaml not found"; exit 2; }
@@ -529,13 +536,16 @@ local-submitqueue-start: build-all-linux ## Start full stack (PROVIDER=fake|git|
529536
else \
530537
export SQ_CONTAINER_USER=$$(id -u):$$(id -g); \
531538
fi; \
532-
$(COMPOSE) -f $(COMPOSE_FILE) -f $(PROVIDER_COMPOSE_FILE) -p $(SUBMITQUEUE_LOCAL_PROJECT) up -d --build --wait
539+
$(COMPOSE) -f $(COMPOSE_FILE) -f $(PROVIDER_COMPOSE_FILE) -f $(WEB_COMPOSE_FILE) -p $(SUBMITQUEUE_LOCAL_PROJECT) up -d --build --wait
533540
@echo "Applying database schemas..."
534541
@$(MAKE) -s local-init-submitqueue-schemas
535542
@echo ""
536543
@echo "✅ Stack is running against provider '$(PROVIDER)'."
537544
@echo ""
538545
@echo "Gateway gRPC port: $$(docker port $(SUBMITQUEUE_LOCAL_PROJECT)-gateway-service-1 8080 2>/dev/null | cut -d: -f2 || echo 'unknown')"
546+
@echo "Web UX: http://localhost:$$(docker port $(SUBMITQUEUE_LOCAL_PROJECT)-web-service-1 3000 2>/dev/null | cut -d: -f2 || echo 'unknown')"
547+
@echo "Web username: test"
548+
@echo "Web token: $(SUBMITQUEUE_WEB_TOKEN)"
539549
@if [ "$(PROVIDER)" = "git" ]; then \
540550
echo "Land target: $(SQ_GIT_SANDBOX_DIR)/sandbox.git"; \
541551
fi
@@ -545,7 +555,7 @@ local-submitqueue-start: build-all-linux ## Start full stack (PROVIDER=fake|git|
545555

546556
local-submitqueue-stop: ## Stop the SubmitQueue stack (keeps PROVIDER=git's sandbox; the databases do not survive)
547557
@echo "Stopping SubmitQueue services..."
548-
@$(COMPOSE) -f $(COMPOSE_FILE) -f $(PROVIDER_COMPOSE_FILE) -p $(SUBMITQUEUE_LOCAL_PROJECT) down
558+
@$(COMPOSE) -f $(COMPOSE_FILE) -f $(PROVIDER_COMPOSE_FILE) -f $(WEB_COMPOSE_FILE) -p $(SUBMITQUEUE_LOCAL_PROJECT) down
549559
@# Both MySQL services mount anonymous volumes, so `down` detaches them and
550560
@# the next `up` creates fresh ones. Saying "data preserved" here would be
551561
@# read as "your requests are still there", which they are not.
@@ -557,7 +567,7 @@ local-submitqueue-stop: ## Stop the SubmitQueue stack (keeps PROVIDER=git's sand
557567

558568
local-stop: ## Stop every local stack — SubmitQueue, Stovepipe, and Runway
559569
@echo "Stopping all services..."
560-
@$(COMPOSE) -f $(COMPOSE_FILE) -p $(SUBMITQUEUE_LOCAL_PROJECT) down
570+
@$(COMPOSE) -f $(COMPOSE_FILE) -f $(PROVIDER_COMPOSE_FILE) -f $(WEB_COMPOSE_FILE) -p $(SUBMITQUEUE_LOCAL_PROJECT) down
561571
@$(COMPOSE) -f $(STOVEPIPE_COMPOSE_FILE) -p $(STOVEPIPE_LOCAL_PROJECT) down
562572
@$(COMPOSE) -f $(RUNWAY_COMPOSE_FILE) -p $(RUNWAY_LOCAL_PROJECT) down
563573
@echo "Services stopped. Anonymous database volumes are not reused on the next start."
@@ -687,6 +697,28 @@ tidy-go: ## Run go mod tidy
687697
@echo "Running go mod tidy..."
688698
@$(BAZEL) run @rules_go//go -- mod tidy -e
689699

700+
web-build: ## Build the web packages and deployable Next.js image with Bazel
701+
@$(BAZEL) build //web/submitqueue:pkg //web/service/submitqueue:image
702+
703+
web-check: ## Run web generation, packaging, lint, type, unit, and image checks with Bazel
704+
@$(BAZEL) test //web:check --test_output=errors
705+
@$(BAZEL) build //web/service/submitqueue:image
706+
707+
web-e2e-test: ## Run the Bazel-managed real-stack Playwright and axe web test
708+
@$(BAZEL) test //web/test/e2e:web_test --test_output=errors
709+
710+
web-image-load: ## Build and load the deployable web image into Docker with Bazel (also tagged with SQ_DOCKER_IMAGE_PREFIX)
711+
@$(BAZEL) run //web/service/submitqueue:image_load
712+
@if [ -n "$$SQ_DOCKER_IMAGE_PREFIX" ] && [ "$$SQ_DOCKER_IMAGE_PREFIX" != "submitqueue" ]; then \
713+
docker tag submitqueue-web-service:latest "$$SQ_DOCKER_IMAGE_PREFIX-web-service:latest"; \
714+
fi
715+
716+
web-install: ## Install the pinned web workspace dependencies
717+
@corepack pnpm@10.17.1 --dir web install --frozen-lockfile
718+
719+
web-proto: ## Regenerate the committed TypeScript protobuf API with Bazel
720+
@$(BAZEL) run //web/api:generate
721+
690722
help: ## Show this help message
691723
@echo "Available targets:"
692724
@echo ""

‎REPO.bazel‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ignore_directories(["**/node_modules"])

‎api/base/change/proto/BUILD.bazel‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
exports_files(
22
["change.proto"],
3-
visibility = ["//tool/proto:__pkg__"],
3+
visibility = [
4+
"//tool/proto:__pkg__",
5+
"//web/api:__pkg__",
6+
],
47
)
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
exports_files(
22
["mergestrategy.proto"],
3-
visibility = ["//tool/proto:__pkg__"],
3+
visibility = [
4+
"//tool/proto:__pkg__",
5+
"//web/api:__pkg__",
6+
],
47
)

0 commit comments

Comments
 (0)