Support repo-defined custom conventions - #71
Open
davidfou wants to merge 8 commits into
Open
Conversation
Repos can opt into their own conventional-comments vocabulary by committing `.conventional-comments.json` at HEAD. The content script fetches the file same-origin (no extra host permissions, no auth), validates it with a versioned zod schema, and falls back silently to the built-in default on 404, network errors, or schema violations. Adds the JSON Schema (draft 2020-12) at public/schemas/v1/ so users get IDE autocomplete by setting "$schema". E2E coverage spans the existing 4 matrices via two new per-account repos (convention-valid / convention-invalid). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The E2E `globalSetup` already creates each account's test repo on first run via Octokit / Gitbeaker. Extends both platforms' setup to also bootstrap the convention-valid and convention-invalid repos (with their `.conventional-comments.json` files committed at HEAD), so a fresh account doesn't need any manual repo prep. Shared fixtures live in tests/e2e/conventionFixtures.ts so the spec and the setup agree on the same vocabulary. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three CI failures from the first run: - auth.setup timed out after 30s because globalSetup now creates 3 repos serially. Parallelize the bootstraps and bump the setup timeout to 120s as a safety net. - convention.spec.ts beforeEach cleared localStorage before any page.goto, triggering a cross-origin SecurityError on about:blank. Each test navigates fresh; drop the beforeEach. - gitlab navigation specs failed because App returned null while convention loaded, leaving the ccext-container with no dimensions exactly when the visibility probe fired. Seed useConvention with DEFAULT_CONVENTION so the editor renders immediately; rekey ResolvedApp on convention swap so its state re-initializes with the resolved vocabulary. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Private repos (the default for new GitHub/GitLab repos, including our E2E test accounts) return 404 to anonymous requests for raw files, so the convention fetch silently fell back to the built-in default. Use `credentials: "include"` so the user's existing same-origin session cookie authenticates the read. Safe: the request is same-origin (github.com / gitlab.com), so no cross-site cookie leakage. This also makes the feature usable for any private repo where the user is logged in. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The same-origin fetch from the content script uses `credentials: "include"`, but GitHub's `/raw/HEAD/` for a private repo redirects to `raw.githubusercontent.com`, whose response lacks CORS headers for github.com, so the body can't be read. The convention then silently falls back to the default and the spec fails on `data-testlabel: "praise"` instead of `"spotted"`. Bootstrap any repo that ships a `.conventional-comments.json` as public; keep the no-convention repo private (matches what real teams typically have, and the fetcher returns 404 → default either way). Bumps the convention repo names to `v4` so the existing `v3` private repos don't shadow the new bootstrap. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
github.com/{o}/{r}/raw/HEAD 302-redirects to raw.githubusercontent.com,
which returns no Access-Control-Allow-Origin header — a content-script
fetch on github.com can't read it, so every convention silently fell
back to the default and the spec failed on "praise" vs "spotted".
Switch to the platform's content API:
- GitHub: api.github.com/repos/{o}/{r}/contents/<file> with the
`application/vnd.github.raw` Accept header. ACAO: *, so the
cross-origin read works. credentials omitted (api.github.com uses
bearer tokens, not session cookies).
- GitLab: gitlab.com/api/v4/projects/{encoded}/repository/files/{encoded}/raw
(same-origin, credentials included so private repos work via the
user's session cookie).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ResolvedApp was previously remounted via a `key` when the convention swapped from default to custom, but the textarea still carried the prior mount's prefix (`**praise:** `). The new initializer's extractComment couldn't parse it under the custom vocabulary, so it fell through to EMPTY_LABEL and the editor showed "none" instead of "spotted" — exactly what the valid-convention spec asserted against. Revert useConvention to a null-while-pending pattern and only mount ResolvedApp once the final convention is in hand. A `min-h-px` placeholder keeps the wrapper visible during the fetch so the navigation specs don't see a zero-dimension container. Validated locally: convention.spec (4/4) and navigation+edit (18/18 plus 1 skip) green on github-v2. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous null-loader / min-h-px placeholder regressed gitlab
navigation specs (container ended up hidden between Preview→Write)
and the github-v1 visual baseline (extra 1px layout shift).
Render ResolvedApp immediately with DEFAULT_CONVENTION, then watch
the convention prop in a useEffect: when it changes, push the new
defaultLabel via setState. useTextareaWrapper's existing slice-based
effect already swaps the textarea prefix correctly on the next
render — no remount, no direct textarea mutation, no extra DOM
layer.
We don't re-run extractComment against the post-swap textarea: it
still carries the old convention's prefix at that point, so the
match would always fail and the label would collapse to EMPTY_LABEL
("none"). Trusting the new convention's defaultLabel is correct for
the new-comment case the spec exercises.
Validated locally on github-v2: convention (4/4), navigation (8/9 +
1 skip), edit (6/6).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
.conventional-comments.jsonat HEAD. The content script fetches the file same-origin (no extra host permissions, no auth), validates it with a versioned zod schema, and falls back silently to the built-in default on 404, network errors, or schema violations.public/schemas/v1/conventional-comments.schema.jsonso users can wire up IDE autocomplete via\"\$schema\".entrypoints/content/convention/(types, schema, parseRepoUrl, fetchConvention, getConvention) with co-located vitest tests.ResolvedApp;Editoris now driven bylabels/decorations/emptyLabelprops instead of importing the built-in constants directly.github-v1/v2,gitlab-v1/v2) via two new per-account repos (*-convention-valid-v3,*-convention-invalid-v3); seetests/e2e/convention.spec.ts.Out-of-band setup
Before CI E2E goes green, create the two extra repos under each of the 4 e2e accounts (
ccext-e2e-ci-convention-valid-v3andccext-e2e-ci-convention-invalid-v3), each with a PR/MR #1 and a.conventional-comments.jsonat HEAD — valid one declares labelsspotted+approved, decorationblocker,defaultLabel: "spotted"; invalid one is e.g.{"version": 1, "labels": [], "decorations": []}.Test plan
mise run lintmise exec -- pnpm vitest run(153 tests, including 41 new inentrypoints/content/convention/)mise run test:components(27 Playwright CT)mise run build+mise run build:firefoxmise run test:e2e— pending the 8 setup repos above🤖 Generated with Claude Code