From a9d1f4c2a0007cd7e825494775ab04df6afb571e Mon Sep 17 00:00:00 2001 From: opficdev <162981733+opficdev@users.noreply.github.com> Date: Wed, 24 Jun 2026 23:05:04 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20check=20metadata=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=EC=8B=A4=ED=8C=A8=20=EA=B2=A9=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 5 ++-- src/workflows/mergeRiskWatch.ts | 41 ++++++++++++++++---------- tests/workflows/mergeRiskWatch.test.ts | 29 ++++++++++++++++++ 3 files changed, 56 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 1c86b1d..0f5d644 100644 --- a/README.md +++ b/README.md @@ -32,11 +32,10 @@ fine-grained PAT는 GitHub `Settings` > `Developer settings` > `Personal access | --- | --- | | Repository access | 감시 대상 repository만 선택 | | Contents | Read-only | -| Checks | Read-only | | Pull requests | Read-only | | Metadata | Read-only. GitHub가 자동 포함 | -`Contents: Read-only`는 checkout과 branch fetch에 필요합니다. `Checks: Read-only`는 branch head SHA의 check run 조회에 필요합니다. `Pull requests: Read-only`는 commit에 연결된 PR metadata 조회에 필요합니다. +`Contents: Read-only`는 checkout과 branch fetch에 필요합니다. `Pull requests: Read-only`는 commit에 연결된 PR metadata 조회에 필요합니다. ### Consumer workflow permissions @@ -251,7 +250,7 @@ scheduled run은 consumer repository의 실제 remote branch를 fetch하고, `ba | workflow가 시작되지 않음 | consumer workflow가 `schedule`, `workflow_dispatch` 중 필요한 trigger를 가지고 있는지 확인 | | checkout 또는 fetch 실패 | `WATCHER_GITHUB_TOKEN`의 Repository access, `Contents: Read-only`, workflow `contents: read` 확인 | | PR metadata가 비어 있음 | `WATCHER_GITHUB_TOKEN`의 `Pull requests: Read-only`, commit에 연결된 PR 존재 여부 확인 | -| check metadata가 비어 있음 | `WATCHER_GITHUB_TOKEN`의 `Checks: Read-only`, 해당 branch head SHA의 check run 존재 여부 확인 | +| check metadata가 비어 있음 | 해당 branch head SHA의 check run 존재 여부 확인 | | AI prediction이 `skipped`로 표시됨 | deterministic possibility status가 `critical`인지와 `confirmed_conflict`가 아닌지 확인 | | AI prediction이 `failed`로 표시됨 | `OPENAI_API_KEY` secret, OpenAI API 응답 형식, rate limit 상태 확인 | | Discord 전송이 되지 않음 | `DISCORD_WEBHOOK_URL` secret, Discord incoming webhook URL, webhook channel 권한 확인 | diff --git a/src/workflows/mergeRiskWatch.ts b/src/workflows/mergeRiskWatch.ts index 9e00888..c895e30 100644 --- a/src/workflows/mergeRiskWatch.ts +++ b/src/workflows/mergeRiskWatch.ts @@ -279,23 +279,28 @@ export function githubMetadataClientFor(options: MergeRiskWatchOptions): { return { checksFor: async ref => { - const response = await githubJson(options, [ - "repos", - owner, - repo, - "commits", - ref, - "check-runs" - ], { - per_page: "100" - }) + try { + const response = await githubJson(options, [ + "repos", + owner, + repo, + "commits", + ref, + "check-runs" + ], { + per_page: "100" + }) - return (response.check_runs ?? []) - .map(check => ({ - name: check.name ?? "unknown", - status: check.status ?? "unknown", - conclusion: check.conclusion ?? undefined - })) + return (response.check_runs ?? []) + .map(check => ({ + name: check.name ?? "unknown", + status: check.status ?? "unknown", + conclusion: check.conclusion ?? undefined + })) + } catch (error) { + console.warn(`GitHub check metadata request failed: ${warningMessageFor(error)}`) + return [] + } }, pullRequestFor: async (sha, branchName) => { const pulls = await githubJson(options, [ @@ -322,6 +327,10 @@ export function githubMetadataClientFor(options: MergeRiskWatchOptions): { } } +function warningMessageFor(error: unknown): string { + return error instanceof Error ? error.message : String(error) +} + // git diff hunk header를 BranchChangedHunk 목록으로 변환 async function collectChangedHunks(input: { repositoryPath: string diff --git a/tests/workflows/mergeRiskWatch.test.ts b/tests/workflows/mergeRiskWatch.test.ts index 29e96e6..f94375c 100644 --- a/tests/workflows/mergeRiskWatch.test.ts +++ b/tests/workflows/mergeRiskWatch.test.ts @@ -216,6 +216,23 @@ test("collects check metadata from GitHub check runs API", async () => { }]) }) +// check run metadata 조회 실패가 branch 수집 실패로 전파되지 않는지 확인 +test("returns empty check metadata when GitHub check runs request fails", async () => { + const client = githubMetadataClientFor({ + ...baseOptions(), + fetch: async () => new Response("{}", { + status: 403, + headers: { + "Content-Type": "application/json" + } + }) + }) + + const checks = await suppressConsoleWarn(() => client.checksFor("abc123")) + + assert.deepEqual(checks, []) +}) + // commit에 연결된 PR 목록에서 branch와 맞는 Pull Request metadata를 선택하는지 확인 test("collects pull request metadata for matching branch", async () => { const client = githubMetadataClientFor({ @@ -347,6 +364,18 @@ function restoreEnv(name: string, value: string | undefined): void { process.env[name] = value } +async function suppressConsoleWarn(operation: () => Promise): Promise { + const originalWarn = console.warn + + console.warn = () => {} + + try { + return await operation() + } finally { + console.warn = originalWarn + } +} + async function git(cwd: string, args: string[]): Promise { const result = await execFileAsync("git", args, { cwd,