diff --git a/AGENTS.md b/AGENTS.md index e1a7859..192b38e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -54,7 +54,7 @@ wrangler.jsonc Worker 설정과 공개 값(vars) | `pull_request` (`opened`, `reopened`, `synchronize`) | Week 검사, AI 풀이 분석 check run(`tagPatterns`), 학습 현황 댓글(`postLearningStatus`) | | `issue_comment`, `pull_request_review_comment` (`created`) | `@dalestudy` 멘션에 응답한다. `approve`·`승인` 이면 PR 을 승인하고, 그 밖에는 AI 리뷰를 단다 | -Week 검사는 제목이 `WEEK NN Solutions` 형태인 풀이 PR 만 대상으로 하고, 경고 댓글은 봇이 단 것만 지운다. AI 풀이 분석과 학습 현황 댓글은 제목과 상관없이 돌리고(`[user] Onboarding` 같은 PR 도 포함), 풀이 파일이 없으면 두 핸들러가 AI 를 부르지 않고 건너뛴다. +Week 검사는 제목에 `Week 숫자` 또는 `Onboarding`이 포함된 풀이 PR을 대상으로 하고, 경고 댓글은 봇이 단 것만 지운다. AI 풀이 분석과 학습 현황 댓글은 제목과 상관없이 돌리고(`[user] Onboarding` 같은 PR 도 포함), 풀이 파일이 없으면 두 핸들러가 AI 를 부르지 않고 건너뛴다. ### AI 작업을 별도 invocation 으로 나누기 diff --git a/handlers/webhooks.test.js b/handlers/webhooks.test.js index 6f9371c..3f9e524 100644 --- a/handlers/webhooks.test.js +++ b/handlers/webhooks.test.js @@ -409,7 +409,10 @@ describe("handlePullRequestEvent — WEEK 가 없는 제목", () => { }); }); - it("Week 체크는 건너뛰지만 AI 핸들러는 디스패치한다", async () => { + it.each([ + ["[testuser] Onboarding", true], + ["docs: update README", false], + ])("%s: Week 검사 여부는 %s이고 AI 핸들러는 디스패치한다", async (title, checksWeek) => { const ctx = { waitUntil: vi.fn() }; const env = { AI: FAKE_AI, @@ -418,13 +421,16 @@ describe("handlePullRequestEvent — WEEK 가 없는 제목", () => { }; const response = await handleWebhook( - makeRequest("pull_request", onboardingPayload), + makeRequest("pull_request", { + ...onboardingPayload, + pull_request: { ...onboardingPayload.pull_request, title }, + }), env, ctx ); expect(response.status).toBe(200); - expect(handleWeekComment).not.toHaveBeenCalled(); + expect(handleWeekComment).toHaveBeenCalledTimes(checksWeek ? 1 : 0); expect(ctx.waitUntil).toHaveBeenCalledTimes(2); const fetchedUrls = globalThis.fetch.mock.calls.map(([url]) => url); diff --git a/utils/validation.js b/utils/validation.js index fe9cb07..5e52754 100644 --- a/utils/validation.js +++ b/utils/validation.js @@ -4,9 +4,9 @@ import { ALLOWED_ORG } from "./constants.js"; -// "[dale] WEEK 07 Solutions" 같은 풀이 제출 PR 제목. -// 제목 규칙이 강제되지 않아 "Solutions"를 빼먹는 PR이 있으므로 주차만 확인한다. -const SOLUTION_TITLE_PATTERN = /week\s*\d+/i; +// "[dale] WEEK 07 Solutions", "[dale] Onboarding" 같은 풀이 제출 PR 제목. +// 제목 규칙이 강제되지 않아 "Solutions"를 빼먹는 PR이 있으므로 주차 또는 Onboarding을 확인한다. +const SOLUTION_TITLE_PATTERN = /week\s*\d+|onboarding/i; /** * Organization 검증 diff --git a/utils/validation.test.js b/utils/validation.test.js index 4d442af..0fc07d9 100644 --- a/utils/validation.test.js +++ b/utils/validation.test.js @@ -10,6 +10,12 @@ describe("isSolutionPR", () => { expect(isSolutionPR("[user] WEEK15 Solutions")).toBe(true); }); + it("Onboarding이 포함된 제목도 풀이 PR로 인식한다", () => { + expect(isSolutionPR("[user] Onboarding")).toBe(true); + expect(isSolutionPR("[user] onboarding")).toBe(true); + expect(isSolutionPR("[user] ONBOARDING Solutions")).toBe(true); + }); + it("봇 테스트나 저장소 정리 PR은 제외한다", () => { expect(isSolutionPR("260806 봇 댓글 기능 테스트")).toBe(false); expect(isSolutionPR("bot test")).toBe(false);