feat(api): adopt uploads.sh links pasted into PR bodies/comments (#701) - #707
Conversation
Scans pull_request opened/edited and issue_comment created/edited text for uploads.sh file URLs (storage host, embed host, /f/ page — resolved via #702's resolveAttachSourceKey) and copies every one that resolves to an object in the repo's own bound workspace into that PR/issue's attachment prefix, reusing #702's attachExistingObject verbatim for the copy + additive gh.* metadata merge (PR #157 preserve contract). Chose copy over metadata-only-in-place adoption: the managed-comment renderer (gatherCommentBody) lists objects by R2 key prefix, not by gh.* metadata query, so a copy under the PR's attachment prefix is what makes adoption show up in the comment and screenshots-page grouping without also changing the renderer. Copy (never move) leaves the originally-pasted URL resolving untouched, satisfying the no-private-migration constraint. New adoptLinkedFiles knob in .uploads.yml (default on for bound repos), plumbed through packages/comment-config, the golden fixture, the generated CLI copy, workspace defaults, and the comment-config docs page, mirroring ingestBotAttachments end to end. Noise guard: a lone adopted link with nothing else to consolidate does not trigger a managed comment on its own — sync only fires on 2+ adopted files this pass, one adopted file mixed with existing attachments, or an already-existing managed comment.
🦋 Changeset detectedLatest commit: 6d31dae The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
Important Review skippedAuto reviews are limited based on label configuration. 🏷️ Required labels (at least one) (2)
🚫 Excluded labels (none allowed) (1)
Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Closes #701.
Builds on #706 (
github-attachmodule), which merged tomainwhile this branch was in progress — this PR targetsmaindirectly (rebased after #706 landed), no stacking needed.What
Webhook "link adoption": when a PR body or
issue_comment(created/edited) references an uploads.sh file URL that was pasted in directly — not uploaded via--pr/attach --branch— the webhook now adopts it into that PR/issue's attachment context, so it gets pairing, dedupe, the activity feed, and screenshots-page grouping automatically, same as anything attached through the paved path.Reuses #706's
github-attachmodule verbatim rather than reimplementing it:resolveAttachSourceKeyfor URL→key resolution (storage host, embed host,/f/page — all three, and a URL that doesn't resolve to an object in the scanning repo's own bound workspace just doesn't resolve, so cross-workspace URLs are silently dropped, never claimed).attachExistingObjectfor the copy + additivegh.repo/gh.kind/gh.number/gh.refmetadata merge (PR feat: per-file metadata — PR/issue context, custom tags, and search #157 preserve contract — the source's own metadata rides along unchanged).New module:
apps/api/src/github-link-adopt.ts.Copy vs. metadata-only
Went with copy (via
attachExistingObject), not metadata-only-in-place tagging. The managed-comment renderer (gatherCommentBody) lists objects by R2 key prefix undergh/<owner>/<name>/..., not by agh.*metadata query — a metadata-only tag on the originalf/key would be invisible to the comment/screenshots-page renderer without also changing it, which felt like more surface area than this issue needs. Copying (never moving —movedefaults tofalse) means:f/source migrated intogh/private/— only the fresh copy lands there; the source stays exactly where it was.Noise guard
Per the issue: a lone adopted image already visible inline in the PR/comment shouldn't trigger a managed comment that just repeats it.
adoptLinkedFilesingithub-link-adopt.tsgathers the PR's pre-adoption attachment count first, then only callspostManagedCommentwhen:Config knob
.uploads.yml'sadoptLinkedFiles(boolean, default on for bound repos — binding is already an explicit opt-in relationship, same posture asingestGithubAttachments). Plumbed the same way asingestBotAttachments, end to end:packages/comment-config/src/index.ts(schema, parse, resolve,AUTO_COMMENT_OPTIONS)test/fixtures/comment-config-golden.json(new parse + resolve cases,adoptLinkedFilesadded to every existing resolve-case expectation)packages/uploads/src/comment-config.generated.ts(regenerated vianode packages/uploads/scripts/inline-shared.mjs— do not hand-edit)apps/api/src/workspace.ts(githubAdoptLinkedFilesworkspace default) +apps/api/src/repo-comment-config.tsmappingapps/web/src/pages/docs/comment-config.astrodocsIdempotency / constraints
attachExistingObject's own contract) — safe across webhook redeliveries and comment-edit rescans.pull_requestopened/editedandissue_commentcreated/edited.issue_commentdeletedis intentionally excluded from adoption (unlike ingest) — there's no ledger to detach from; a deleted comment just has nothing left to scan.extractWebhookEventis a cheap payload-only check (hasLinkCandidate— anyhttp(s)://substring); real workspace-scoped resolution happens downstream inadoptLinkedFilesForWebhook, same "compact WebhookEvent, consumer re-fetches current text" shapeingestalready uses.Tests
apps/api/src/github-link-adopt.test.ts— URL extraction, workspace-scoped resolution (including cross-workspace drop), additive-metadata copy, all three noise-guard branches, idempotency,adoptLinkedFilesForWebhook's no-op contract (unlinked repo, knob off).apps/api/src/github-webhook-queue.test.ts—extractWebhookEventadopt-gating cases (mirroring the existingingestcases) and queue dispatch/retry foradoptevents.packages/comment-config/src/index.test.ts/packages/uploads/test/comment-config.test.ts— exercise the new golden-fixture cases automatically (shared fixture, no new test code needed there).pnpm test(305 files / 4530 tests),pnpm typecheck, andpnpm checkall pass locally.Deviations from the brief