Skip to content

feat(git): Vercel-style sticky PR/MR preview comments on deploys - #96

Merged
dviejokfs merged 2 commits into
mainfrom
feat/pr-preview-comments
May 25, 2026
Merged

dviejokfs merged 2 commits into
mainfrom
feat/pr-preview-comments

Conversation

@dviejokfs

@dviejokfs dviejokfs commented May 25, 2026 •

Copy link
Copy Markdown
Contributor

Summary

When a deployment for a branch with an open PR/MR moves through created → succeeded/failed, post or update a single sticky comment that reflects the latest state. The comment is keyed by a hidden HTML marker so subsequent updates edit in place rather than spam the PR with new comments.

  • New PrCommenter trait + GitPrCommenter impl that dispatches by provider type (GitHub via REST /repos/.../pulls + issue comments, GitLab via REST /merge_requests + notes). Sticky marker is per (project, environment) so multiple Temps envs targeting the same PR each get their own comment.
  • New PrCommentListener background task: subscribes to Job::DeploymentCreated / DeploymentSucceeded / DeploymentFailed and calls the commenter with the right phase. Self-contained — uses events the deployments crate already emits, so no wiring changes are needed in temps-deployments.
  • Graceful degradation: missing git connection, no open PR, unsupported provider, or 403/401 from the provider (e.g. existing GitHub Apps without pull_requests:write) all log at warn/debug and return Ok. Deployments are never blocked by commenting failures.

What the comment looks like

🚧 Deploying preview

Building commit `abc1234`…

→ on success the same comment becomes:

✅ Preview ready

Commit: `abc1234`

🔗 Open preview

→ on failure:

❌ Preview build failed

Commit: `abc1234`

Scope deliberately kept small

  • No new tables, no migrations, no schema changes.
  • No new `Job` variants — reuses existing `DeploymentCreated/Succeeded/Failed` broadcasts.
  • No per-PR environments. Preview env is whatever environment the deployment already targets.

Known limitations / follow-ups

  1. Existing GitHub Apps may lack `pull_requests:write`. The current manifest in `GitProviderFlow.tsx` already requests it for new installs. Old installations hit 403 and are logged at warn level — those users would need to upgrade their app's permissions to get comments. UI nudge for that can be a follow-up.
  2. Fork PRs not commented. GitHub's `head=owner:branch` filter only matches same-repo PRs. Temps doesn't deploy fork PRs today so this matches existing behavior.
  3. No teardown comment on PR close/merge. The sticky comment stays even after the env URL stops responding. Vercel behaves the same; can be added later if needed.

Test plan

  • `cargo check --lib` clean across the workspace (714 crates, 0 errors)
  • `cargo test --lib -p temps-git` — 120/120 passing (15 new tests for the PR commenter)
  • `cargo clippy --lib -p temps-git --no-deps` — 0 errors
  • Unit tests cover: render-body for each phase, marker scoping, GitHub create/edit/no-PR/403 paths, GitLab create/edit/no-MR paths
  • Manual smoke test: open a PR in a connected repo, push to it, watch comment appear and update through phases

Related

Companion fix for the branch-delete bug (#1239) lives on a separate branch (`security/0.1.0-hardening`) and isn't bundled here.

dviejokfs added 2 commits May 25, 2026 20:06
Vercel-style: when a deployment for a branch with an open PR moves
through created → succeeded/failed, we post or update a single sticky
comment that always reflects the latest state. The comment is keyed by
a hidden HTML marker so subsequent updates edit-in-place rather than
spamming the PR with new comments.

- New PrCommenter trait + GitPrCommenter impl that dispatches by
  provider type (GitHub via REST /repos/.../pulls + issue comments,
  GitLab via REST /merge_requests + notes). Sticky marker is
  per-(project, environment) so multiple Temps envs targeting the
  same PR each get their own comment.

- New PrCommentListener: background task that subscribes to
  Job::DeploymentCreated / DeploymentSucceeded / DeploymentFailed
  and calls the commenter with the right phase. Self-contained —
  uses events the deployments crate already emits, so no wiring
  changes are needed in temps-deployments.

- Graceful degradation: missing git connection, no open PR, or
  forbidden by provider (e.g. existing GitHub Apps without
  pull_requests:write) all log warn and return Ok. Deployments
  are never blocked by commenting failures.

- 15 unit tests cover GitHub + GitLab create/edit/no-PR/403 paths
  via mockito. All temps-git tests pass (120/120).
Adds 8 integration tests for PrCommentListener::handle_job covering:
- DeploymentCreated with/without branch (Started phase, skip)
- DeploymentSucceeded with/without URL (Ready phase, skip)
- DeploymentSucceeded with missing deployment row (no-op)
- DeploymentFailed with branch (Failed phase)
- Unrelated event (ignored)

Uses Sea-ORM MockDatabase for the deployment lookups and a
RecordingCommenter PrCommenter double to capture and assert the
phases the listener produces. Brings temps-git test count to 128
(was 120), all passing.

Adds the Unreleased CHANGELOG entry that the GitHub Actions check
requires.
@dviejokfs
dviejokfs merged commit df75b52 into main May 25, 2026
11 checks passed
@dviejokfs
dviejokfs deleted the feat/pr-preview-comments branch June 5, 2026 11:03
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