From 1dde0b9e9f58ad183b715fab0a753c31bb8cf6d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20SAILLANT?= <108685187+electron-rare@users.noreply.github.com> Date: Thu, 26 Mar 2026 18:26:10 +0100 Subject: [PATCH] feat(web): GitHub PR API + Redis dev compose - project-store.ts: fetchGitHubPRs() calls GitHub API (electron-rare/Kill_LIFE) with GITHUB_TOKEN; falls back to local git derivation when token absent - repoProvider field updated to github:electron-rare/Kill_LIFE - .env.example: add GITHUB_TOKEN + GITHUB_REPO vars - compose.dev.yml: redis:7-alpine on 127.0.0.1:6379 for EDA worker dev Co-Authored-By: Claude Sonnet 4.6 --- web/.env.example | 4 +++ web/compose.dev.yml | 12 +++++++ web/lib/project-store.ts | 74 +++++++++++++++++++++++++++++++++++----- 3 files changed, 81 insertions(+), 9 deletions(-) create mode 100644 web/compose.dev.yml diff --git a/web/.env.example b/web/.env.example index 6ff031c..4f02d4e 100644 --- a/web/.env.example +++ b/web/.env.example @@ -3,3 +3,7 @@ EDA_QUEUE_NAME=yiacad-eda KICANVAS_BUNDLE_URL=https://kicanvas.org/kicanvas/kicanvas.js KIBOT_CONFIG=/absolute/path/to/kibot.yaml KIAUTO_BIN=kiauto + +# GitHub PR integration +GITHUB_TOKEN=ghp_... +GITHUB_REPO=electron-rare/Kill_LIFE diff --git a/web/compose.dev.yml b/web/compose.dev.yml new file mode 100644 index 0000000..c787c70 --- /dev/null +++ b/web/compose.dev.yml @@ -0,0 +1,12 @@ +services: + redis: + image: redis:7-alpine + container_name: yiacad-redis-dev + restart: unless-stopped + ports: + - "127.0.0.1:6379:6379" + volumes: + - yiacad-redis-data:/data + +volumes: + yiacad-redis-data: diff --git a/web/lib/project-store.ts b/web/lib/project-store.ts index 2901421..295214d 100644 --- a/web/lib/project-store.ts +++ b/web/lib/project-store.ts @@ -269,6 +269,60 @@ function buildReviewSummary( return `${branch ?? "detached-head"} · ${changeLabel} · latest CI ${latestRun} · ${artifacts.length} artifact(s)`; } +// --------------------------------------------------------------------------- +// GitHub PR API +// --------------------------------------------------------------------------- + +const GITHUB_REPO = + process.env.GITHUB_REPO ?? "electron-rare/Kill_LIFE"; +const GITHUB_API = "https://api.github.com"; + +async function fetchGitHubPRs(artifacts: ArtifactRecord[]): Promise { + const token = process.env.GITHUB_TOKEN; + if (!token) return null; + + try { + const resp = await fetch(`${GITHUB_API}/repos/${GITHUB_REPO}/pulls?state=open&per_page=20`, { + headers: { + Authorization: `Bearer ${token}`, + Accept: "application/vnd.github+json", + "X-GitHub-Api-Version": "2022-11-28", + }, + signal: AbortSignal.timeout(5000), + }); + if (!resp.ok) return null; + + const prs = (await resp.json()) as Array>; + const artifactIds = artifacts.map((a) => a.id); + + return prs.map((pr) => { + const files: string[] = []; + const title = typeof pr.title === "string" ? pr.title : ""; + const sourceBranch = (pr.head as Record)?.ref as string ?? ""; + const targetBranch = (pr.base as Record)?.ref as string ?? "main"; + const author = ((pr.user as Record)?.login as string) ?? "unknown"; + const state = typeof pr.state === "string" ? pr.state : "open"; + const number = typeof pr.number === "number" ? pr.number : 0; + + return { + id: String(number), + title, + status: state, + author, + hasPcbDiff: false, + hasDiagramDiff: false, + hasArtifactPreview: artifactIds.length > 0, + sourceBranch, + targetBranch, + changedFiles: files, + artifactIds, + } satisfies PullRequestRecord; + }); + } catch { + return null; + } +} + function derivePullRequests( branch: string | null, head: string | null, @@ -321,20 +375,22 @@ export async function getProjectSnapshot() { loadArtifacts(), getGitProjectState(REPO_ROOT, PROJECT_ROOT) ]); - const pullRequests = derivePullRequests( - gitState.branch, - gitState.head, - gitState.author, - gitState.changedFiles, - ciRuns, - artifacts - ); + const pullRequests = + (await fetchGitHubPRs(artifacts)) ?? + derivePullRequests( + gitState.branch, + gitState.head, + gitState.author, + gitState.changedFiles, + ciRuns, + artifacts + ); return { id: `yiacad-${gitState.branch ?? "local"}`, name: "YiACAD Local Workspace", rootPath: toPosixPath(relative(REPO_ROOT, PROJECT_ROOT)), - repoProvider: "local git read model (ready for gitea/gitlab adapter)", + repoProvider: `github:${GITHUB_REPO}`, repoVisibility: "repo-backed working tree", repoBranch: gitState.branch, repoHead: gitState.head,