From eb4631aca90d397c13e6e90902a61579df1d37a2 Mon Sep 17 00:00:00 2001 From: Hojeong Park Date: Tue, 10 Nov 2026 13:09:08 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20=EC=A3=BC=EC=B0=A8=20=EB=A7=88=EB=AC=B4?= =?UTF-8?q?=EB=A6=AC=EC=97=90=EC=84=9C=20Onboarding=20iteration=EC=9D=84?= =?UTF-8?q?=200=EC=A3=BC=EC=B0=A8=EB=A1=9C=20=EC=9D=B8=EC=8B=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Week 필드의 Onboarding iteration이 'Week N' 패턴에 걸리지 않아 /resolve-iteration 이 found:false 를 돌려주고, wrapup 워크플로가 온보딩 주간을 휴식기로 보고 승인·병합·릴리즈를 모두 건너뛰었다. Onboarding 을 0주차로 해석해 week_label 'Onboarding', 태그 v{기수}.0.0 으로 마무리되도록 한다. --- AGENTS.md | 2 +- bun.lock | 1 + utils/iterations.js | 8 +++++++- utils/iterations.test.js | 27 +++++++++++++++++++++++++++ 4 files changed, 36 insertions(+), 2 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 9bb0897..8f08d8f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -42,7 +42,7 @@ wrangler.jsonc Worker 설정과 공개 값(vars) 승인·병합의 공통 규칙은 `utils/prActions.js` 에 있다. 요약하면 Week 가 다르거나 Status 가 `Solving` 인 PR, Draft PR 은 건너뛰고, 승인은 CI 가 통과한 PR 에만, 병합은 승인 리뷰가 있고 `mergeable_state` 가 `clean` 인 PR 에만 한다. -`/resolve-iteration` 이 있는 이유: Actions 의 기본 `GITHUB_TOKEN` 은 org 프로젝트 보드를 읽지 못해서(`read:project` 없음) App 토큰을 가진 이 Worker 가 대신 읽는다. 주차는 보드의 Week(Iteration) 필드에서 오므로 하드코딩하지 않는다. +`/resolve-iteration` 이 있는 이유: Actions 의 기본 `GITHUB_TOKEN` 은 org 프로젝트 보드를 읽지 못해서(`read:project` 없음) App 토큰을 가진 이 Worker 가 대신 읽는다. 주차는 보드의 Week(Iteration) 필드에서 오므로 하드코딩하지 않는다. `Onboarding` iteration 은 0주차(`week: 0`, 릴리즈 태그 `v{기수}.0.0`)로 본다. ## 웹훅 diff --git a/bun.lock b/bun.lock index 9960d9c..e6883d0 100644 --- a/bun.lock +++ b/bun.lock @@ -1,5 +1,6 @@ { "lockfileVersion": 1, + "configVersion": 0, "workspaces": { "": { "name": "dalestudy-github-worker", diff --git a/utils/iterations.js b/utils/iterations.js index 30e215e..a61ac0d 100644 --- a/utils/iterations.js +++ b/utils/iterations.js @@ -11,6 +11,8 @@ import { ALLOWED_ORG } from "./constants.js"; const COHORT_TITLE_PATTERN = /^리트코드 스터디 (\d+)기$/; const WEEK_TITLE_PATTERN = /^Week (\d+)$/; +// 기수 첫 주차 앞의 온보딩 주간. 0주차로 보고 Week 1 앞에 둔다 (릴리즈 태그 v{기수}.0.0) +const ONBOARDING_TITLE = "Onboarding"; const WEEK_FIELD_NAME = "Week"; /** @@ -37,11 +39,15 @@ export function parseCohort(title) { } /** - * Iteration 제목에서 주차 번호 추출 ("Week 7" → 7) + * Iteration 제목에서 주차 번호 추출 ("Week 7" → 7, "Onboarding" → 0) * * @returns {number|null} */ export function parseWeek(title) { + if (title === ONBOARDING_TITLE) { + return 0; + } + const matched = WEEK_TITLE_PATTERN.exec(title ?? ""); return matched ? Number(matched[1]) : null; } diff --git a/utils/iterations.test.js b/utils/iterations.test.js index 0e8850b..23701b6 100644 --- a/utils/iterations.test.js +++ b/utils/iterations.test.js @@ -53,9 +53,14 @@ describe("parseWeek", () => { expect(parseWeek("Week 15")).toBe(15); }); + it("Onboarding은 0주차로 본다", () => { + expect(parseWeek("Onboarding")).toBe(0); + }); + it("형식이 다르면 null을 돌려준다", () => { expect(parseWeek("Week 7(current)")).toBeNull(); expect(parseWeek("Sprint 3")).toBeNull(); + expect(parseWeek("onboarding")).toBeNull(); expect(parseWeek(null)).toBeNull(); }); }); @@ -123,6 +128,28 @@ describe("findCoveringIteration", () => { expect(findCoveringIteration(acrossCohorts, "2026-10-10")).toBeNull(); }); + it("완료된 Onboarding iteration도 0주차로 판정한다", () => { + const withOnboarding = [ + { + number: 30, + title: "리트코드 스터디 9기", + cohort: 9, + iterations: [ + iteration("Week 1", "2026-11-09"), + iteration("Onboarding", "2026-11-02"), + ], + }, + ]; + + expect(findCoveringIteration(withOnboarding, "2026-11-07")).toMatchObject({ + cohort: 9, + week: 0, + weekLabel: "Onboarding", + startDate: "2026-11-02", + endDate: "2026-11-08", + }); + }); + it("Week 형식이 아닌 iteration은 무시한다", () => { const odd = [ {