Skip to content

feat: add bazel-diff serve HTTP query service (#29)#393

Open
tinder-maxwellelliott wants to merge 2 commits into
masterfrom
claude/happy-thompson-6e024a
Open

feat: add bazel-diff serve HTTP query service (#29)#393
tinder-maxwellelliott wants to merge 2 commits into
masterfrom
claude/happy-thompson-6e024a

Conversation

@tinder-maxwellelliott

Copy link
Copy Markdown
Collaborator

Summary

Implements #29 (RFC: Bazel Query Service) — the "bazel-diff as a service" model from the BazelCon talk that inspired this repo — as a first, self-contained increment: core service + per-SHA hash cache.

A new bazel-diff serve subcommand runs the affectedness calculation as a long-running HTTP service. Hashes for each commit SHA are generated once and cached, so repeat queries are near-instant.

What's included

New com.bazel_diff.server package + cli/ServeCommand.kt:

  • HTTP/JSON server (BazelDiffServer) built on the JDK's com.sun.net.httpserverno new Maven dependency:
    • GET /health200 once warm, 503 otherwise (load-balancer signal)
    • GET /impacted_targets?from=<rev>&to=<rev>[&targetType=Rule,SourceFile] → JSON
  • Per-SHA hash cache (HashCacheStorage byte-interface + LocalDiskHashCacheStorage, atomic writes). Cache key folds in a fingerprint of the query-affecting flags, so a server started with different flags never serves another configuration's hashes. The interface is built to drop in a remote (S3) backend later.
  • Git orchestration (GitClient/ProcessGitClient): subprocess git fetch / resolve / checkout, reusing the existing process() helper.
  • Services: HashService (per-SHA generate + cache, single workspace lock since one clone is shared) and ImpactedTargetsService, which reuses CalculateImpactedTargetsInteractor — the exact logic behind get-impacted-targets — so results are identical to the CLI.
  • Startup: an initial git fetch gates readiness; a fetch failure "lame-ducks" the instance (health stays 503) rather than attempting an in-place repair, per the RFC.

Query-affecting flags (--useCquery, --fineGrainedHashExternalRepos, etc.) mirror generate-hashes, so the hashes the service produces match a cold CLI run.

Tests & coverage

  • Unit tests for each component (storage, git client, hash service, impacted-targets service, server, serve command).
  • A real end-to-end test (E2ETest#testServeEndToEnd) builds a two-commit git repo from the shell-only distance_metrics workspace, runs serve in a background thread, and drives /health + /impacted_targets over real HTTP with real bazel query.
  • New code is ~97% line-covered (ServeCommand 99%); the change raises overall coverage above the 91% baseline and clears the 90% gate.

Docs

README gains a "Query Service (experimental)" section, and the serve help is wired into the generated CLI reference (tools/generate_readme.py / readme_template.md / tools/BUILD).

Deliberately deferred (follow-ups)

Remote (S3) cache backend, OCI/Docker image, k8s manifests, load balancing / multi-instance, dynamic scaling, and git auth-key config. These are the natural next increments of the RFC.

🤖 Generated with Claude Code

tinder-maxwellelliott and others added 2 commits June 26, 2026 16:20
Implements the "bazel-diff as a service" model from the BazelCon talk that
inspired this repo (issue #29), as a first self-contained increment: core
service + per-SHA hash cache.

New `com.bazel_diff.server` package + `serve` subcommand:
- HTTP/JSON server on the JDK's com.sun.net.httpserver (no new dependency)
  with GET /health and GET /impacted_targets?from&to[&targetType].
- Per-SHA hash cache behind a byte-oriented HashCacheStorage interface
  (LocalDiskHashCacheStorage impl, atomic writes); cache key folds in a
  fingerprint of the query-affecting flags. The interface is ready for a
  remote (e.g. S3) backend.
- GitClient/ProcessGitClient: subprocess git fetch/resolve/checkout.
- HashService (per-SHA generate+cache, single workspace lock) and
  ImpactedTargetsService, which reuse CalculateImpactedTargetsInteractor so
  results match `get-impacted-targets`.
- Initial `git fetch` gates readiness; a fetch failure "lame-ducks" the
  instance (health stays 503) rather than self-repairing.

Query-affecting flags mirror `generate-hashes`, so hashes the service
produces match a cold CLI run.

Tests: unit tests per component plus a real end-to-end test
(E2ETest#testServeEndToEnd) that drives the live server over HTTP against a
two-commit git repo with real `bazel query`. New code is ~97% line-covered.

Docs: README "Query Service (experimental)" section, with the `serve` help
wired into the generated CLI reference.

Deferred to follow-ups: remote (S3) cache backend, OCI image, k8s manifests,
load balancing / multi-instance, dynamic scaling, git auth config.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds a JGit-backed GitClient so the query service performs git fetch /
resolve / checkout in-process, without forking a `git` subprocess or
requiring a `git` binary on the PATH.

- JGitClient implements the existing GitClient interface (drop-in).
- `--gitEngine` selects the backend: `jgit` (default, in-process) or
  `subprocess` (shells out to --gitPath, exact C-git behavior, useful for
  workspaces relying on checkout filters/hooks JGit doesn't run).
- Pins org.eclipse.jgit 5.13.x (the last Java-8-compatible line, matching
  bazel-diff's documented minimum) and repins maven_install.json.

Note: "in process" removes the subprocess only; the working tree is still
materialized on disk because `bazel query` reads real files. JGit's
InMemoryRepository can't back a bazel workspace.

Tests: JGitClientTest (resolve/checkout/fetch incl. remote loop and error
paths against a real repo) + engine-selection tests; the serve E2E now
exercises JGit by default. New code remains ~97% line-covered.

Docs: README + generated serve help document --gitEngine and the on-disk
working-tree caveat.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant