Skip to content

예외 처리를 강화하고 API 호출 최적화 #845

예외 처리를 강화하고 API 호출 최적화

예외 처리를 강화하고 API 호출 최적화 #845

name: Auto Assign, Review, and Merge
on:
pull_request:
types:
- opened
- labeled
- unlabeled
- review_requested
- review_request_removed
pull_request_review:
types:
- submitted
jobs:
auto-assign:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Set up Node.js
uses: actions/setup-node@v2
with:
node-version: "16"
- name: Assign PR creator as Assignee
uses: actions/github-script@v6
with:
script: |
const prNumber = context.payload.pull_request.number;
const currentAssignees = context.payload.pull_request.assignees.map(a => a.login);
// PR 작성자가 이미 담당자로 지정되어 있지 않은 경우에만 할당
if (!currentAssignees.includes(context.actor)) {
await github.rest.issues.addAssignees({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
assignees: [context.actor]
});
}
auto-reviewers:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
needs: auto-assign
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Set up Node.js
uses: actions/setup-node@v2
with:
node-version: "16"
- name: Add reviewers based on labels
uses: actions/github-script@v6
with:
script: |
const prNumber = context.payload.pull_request.number;
const prAuthor = context.payload.pull_request.user.login;
const assignees = context.payload.pull_request.assignees.map(a => a.login);
// 현재 리뷰어 목록 가져오기
const currentReviewers = context.payload.pull_request.requested_reviewers
? context.payload.pull_request.requested_reviewers.map(r => r.login)
: [];
const BE_reviewers = ['summersummerwhy', 'ezcolin2', 'Tolerblanc'];
const FE_reviewers = ['yewonJin', 'djk01281'];
const doc_reviewers = ['summersummerwhy', 'ezcolin2', 'Tolerblanc', 'yewonJin', 'djk01281'];
// Function to filter out assignees, PR author, and current reviewers
const filterReviewers = (reviewers) => {
return reviewers.filter(r =>
!assignees.includes(r) &&
r !== prAuthor &&
!currentReviewers.includes(r)
);
};
// Check the labels on the PR and assign appropriate reviewers
const labels = context.payload.pull_request.labels.map(label => label.name);
let reviewersToAdd = [];
if (labels.includes('🐧🚀😶‍🌫️ BE')) {
reviewersToAdd.push(...filterReviewers(BE_reviewers));
}
if (labels.includes('🐳🐣 FE')) {
reviewersToAdd.push(...filterReviewers(FE_reviewers));
}
if (labels.includes('📚 Documentation')) {
reviewersToAdd.push(...filterReviewers(doc_reviewers));
}
// Remove duplicates and limit the number of reviewers
reviewersToAdd = [...new Set(reviewersToAdd)];
const maxReviewers = 4; // 최대 리뷰어 수 제한
reviewersToAdd = reviewersToAdd.slice(0, maxReviewers);
// Request reviewers only if there are new reviewers to add
if (reviewersToAdd.length > 0) {
try {
await github.rest.pulls.requestReviewers({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber,
reviewers: reviewersToAdd
});
console.log(`Added reviewers: ${reviewersToAdd.join(', ')}`);
} catch (error) {
console.error('Failed to add reviewers:', error);
// 실패해도 워크플로우는 계속 진행
}
} else {
console.log('No new reviewers to add');
}
auto-merge:
if: github.event_name == 'pull_request_review' && github.event.review.state == 'approved'
runs-on: ubuntu-latest
permissions:
pull-requests: write
contents: write
steps:
- name: Merge and Close PR if Approved
uses: actions/github-script@v6
with:
script: |
const prNumber = context.payload.pull_request.number || context.payload.review.pull_request_number;
try {
// PR 정보 가져오기
const pr = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber
});
if (pr.data.merged) {
console.log('PR이 이미 머지되었습니다.');
return;
}
// 머지 가능 상태 확인
if (!pr.data.mergeable) {
console.log('PR에 충돌이 있습니다. 수동 확인이 필요합니다.');
core.setFailed('PR에 충돌이 있어 자동 머지를 진행할 수 없습니다.');
return;
}
// 모든 리뷰 확인
const reviews = await github.rest.pulls.listReviews({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber
});
// 각 리뷰어의 최신 리뷰 상태만 확인
const latestReviews = new Map();
reviews.data.forEach(review => {
latestReviews.set(review.user.login, review.state);
});
const hasRejection = Array.from(latestReviews.values()).includes('CHANGES_REQUESTED');
const approvalCount = Array.from(latestReviews.values()).filter(state => state === 'APPROVED').length;
if (!hasRejection && approvalCount >= 1) {
console.log('PR 머지를 시도합니다...');
await github.rest.pulls.merge({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber
});
// 브랜치 삭제
const branchName = pr.data.head.ref;
if (branchName !== 'main' && branchName !== 'master') {
await github.rest.git.deleteRef({
owner: context.repo.owner,
repo: context.repo.repo,
ref: `heads/${branchName}`
});
}
} else {
console.log('머지 조건이 충족되지 않았습니다.');
}
} catch (error) {
console.error('Error:', error);
core.setFailed(error.message);
}