From 5d8964f789f1cdfb1a784770db2911a8e483fed1 Mon Sep 17 00:00:00 2001 From: Choosla Date: Mon, 29 Sep 2025 20:08:19 +0900 Subject: [PATCH] =?UTF-8?q?=EA=B3=B5=ED=86=B5=20GitWorkflow=EB=A5=BC=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/assign.yml | 24 +++++++++ .github/workflows/close-issue-develop.yml | 45 ++++++++++++++++ .github/workflows/pr.yml | 62 +++++++++++++++++++++++ 3 files changed, 131 insertions(+) create mode 100644 .github/workflows/assign.yml create mode 100644 .github/workflows/close-issue-develop.yml create mode 100644 .github/workflows/pr.yml diff --git a/.github/workflows/assign.yml b/.github/workflows/assign.yml new file mode 100644 index 0000000..e7cf205 --- /dev/null +++ b/.github/workflows/assign.yml @@ -0,0 +1,24 @@ +name: Assign issue creator + +on: + issues: + types: [opened] + +permissions: + issues: write + +jobs: + assign: + runs-on: ubuntu-latest + steps: + - name: 이슈 발행자 등록 + uses: actions/github-script@v7 + with: + script: | + const creator = context.payload.issue.user.login; + await github.rest.issues.addAssignees({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + assignees: [creator] + }); diff --git a/.github/workflows/close-issue-develop.yml b/.github/workflows/close-issue-develop.yml new file mode 100644 index 0000000..e137bc5 --- /dev/null +++ b/.github/workflows/close-issue-develop.yml @@ -0,0 +1,45 @@ +name: Auto Close Issues on dev merge + +permissions: + issues: write + +on: + pull_request: + types: [closed] + +jobs: + close-issues: + if: > + github.event.pull_request.merged == true && + github.event.pull_request.base.ref == 'dev' + runs-on: ubuntu-latest + + steps: + - name: Close linked issues + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const prBody = context.payload.pull_request.body; + const issueLines = prBody.split('\n'); + + // 클로징 키워드가 있는 줄에서만 이슈 번호 추출 + const closingKeywords = ['close', 'closes', 'closed', 'fix', 'fixes', 'fixed', 'resolve', 'resolves', 'resolved']; + const issuePattern = /#(\d+)/g; + + for (const line of issueLines) { + const lower = line.toLowerCase(); + if (closingKeywords.some(k => lower.includes(k))) { + let match; + while ((match = issuePattern.exec(line)) !== null) { + const issue_number = parseInt(match[1]); + await github.rest.issues.update({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number, + state: 'closed' + }); + console.log(`✅ Closed issue #${issue_number}`); + } + } + } diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml new file mode 100644 index 0000000..b42650a --- /dev/null +++ b/.github/workflows/pr.yml @@ -0,0 +1,62 @@ +name: PR Assignee & 전체 Collaborators 리뷰 요청 + +on: + pull_request: + types: [opened, reopened, ready_for_review] + +permissions: + organization: read # orgs.listMembers 호출용 + issues: write # 이슈(Assignee) 추가용 + pull-requests: write # 리뷰어 요청용 + +jobs: + assign-and-request: + runs-on: ubuntu-latest + steps: + - name: Assign 및 리뷰어 일괄 요청 + uses: actions/github-script@v7 + with: + script: | + const { owner, repo } = context.repo; + const prNumber = context.payload.pull_request.number; + const prAuthor = context.payload.pull_request.user.login; + + // 1) Assignee 지정 (PR 연 사람을 지정) + try { + await github.rest.issues.addAssignees({ + owner, + repo, + issue_number: prNumber, + assignees: [prAuthor] + }); + } catch (e) { + core.warning(`Assignee를 지정할 수 없습니다: ${e.message}. PR 작성자가 collaborator가 아닐 수 있습니다.`); + } + + // 2) 조직(Organization) 멤버 전체 조회 + const members = await github.paginate( + github.rest.orgs.listMembers, + { org: owner } + ); + const allLogins = members.map(u => u.login); + + // 3) PR 작성자와 봇 계정 제외 + const reviewers = allLogins.filter( + login => login !== prAuthor && !login.endsWith('[bot]') + ); + if (reviewers.length === 0) { + core.info('등록할 리뷰어가 없습니다.'); + return; + } + + // 4) 최대 15명씩 나눠서 리뷰 요청 (API 제한) + const chunkSize = 15; + for (let i = 0; i < reviewers.length; i += chunkSize) { + const chunk = reviewers.slice(i, i + chunkSize); + await github.rest.pulls.requestReviewers({ + owner, + repo, + pull_number: prNumber, + reviewers: chunk + }); + }