feat(forge): GitHub adapter — second implementation keeps the seam a contract (#2693, milestone 288 step 8)
CI & Build / Python lint (push) Successful in 4s
CI & Build / Plugin hooks (push) Successful in 12s
CI & Build / integration (push) Successful in 27s
CI & Build / TypeScript typecheck (push) Successful in 34s
CI & Build / Python tests (push) Successful in 1m8s
CI & Build / Build & push image (push) Successful in 45s
CI & Build / Python lint (push) Successful in 4s
CI & Build / Plugin hooks (push) Successful in 12s
CI & Build / integration (push) Successful in 27s
CI & Build / TypeScript typecheck (push) Successful in 34s
CI & Build / Python tests (push) Successful in 1m8s
CI & Build / Build & push image (push) Successful in 45s
ForgeAdapter is now a named base class carrying the shared plumbing (host join, error taxonomy, contents decoding, archive, default_branch, latest_commit); GiteaForge keeps its exact behavior and GitHubForge joins with the real differences: api.github.com / GHE /api/v3 host mapping, Bearer auth, a commits call for the provenance stamp (GitHub's contents payload only carries the blob sha), and the codeload tarball redirect. The contract grew latest_commit, and with it the cached-SHA short-circuit in pull-time freshness: a stored provenance commit that still heads the recorded path confirms 'current' without a content transfer — the economy that fits pulls inside GitHub's rate limits; every surprise falls back to the full fetch. Webhook deliveries now also accept X-Hub-Signature-256 (sha256=<hex>); the payload shape was already common. Settings card copy covers both forges' token scopes; the kind selector already flowed from the server. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -33,7 +33,7 @@ import re
|
||||
import tarfile
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from scribe.services.forge import GiteaForge, get_forge
|
||||
from scribe.services.forge import ForgeAdapter, get_forge
|
||||
from scribe.services.repo_bindings import keys_for_project
|
||||
from scribe.services.settings import get_setting, set_setting
|
||||
|
||||
@@ -252,7 +252,7 @@ async def _recorded_locations(user_id: int, project_id: int) -> list[tuple[str,
|
||||
|
||||
|
||||
async def compute_coverage(
|
||||
user_id: int, project_id: int, *, forge: GiteaForge | None = None
|
||||
user_id: int, project_id: int, *, forge: ForgeAdapter | None = None
|
||||
) -> dict | None:
|
||||
"""Measure a project's pattern-library coverage against its bound repos.
|
||||
|
||||
@@ -299,7 +299,7 @@ async def compute_coverage(
|
||||
|
||||
|
||||
async def refresh_coverage(
|
||||
user_id: int, project_id: int, *, forge: GiteaForge | None = None
|
||||
user_id: int, project_id: int, *, forge: ForgeAdapter | None = None
|
||||
) -> dict | None:
|
||||
"""Compute and cache. The only writer of the cache key."""
|
||||
coverage = await compute_coverage(user_id, project_id, forge=forge)
|
||||
|
||||
Reference in New Issue
Block a user