Skip to content

[Refactor/#8] CLAUDE.md ignore 처리 #20

[Refactor/#8] CLAUDE.md ignore 처리

[Refactor/#8] CLAUDE.md ignore 처리 #20

Workflow file for this run

name: PR Labeler
on:
pull_request:
types: [opened, synchronize, edited]
jobs:
# ==========================================================================
# Size Label - PR 크기에 따른 라벨 (변경 시 업데이트)
# ==========================================================================
size-label:
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- name: Label PR by Size
uses: actions/github-script@v7
with:
script: |
const prNumber = context.payload.pull_request.number;
const { data: pr } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber
});
const totalChanges = pr.additions + pr.deletions;
console.log(`PR #${prNumber} 변경: +${pr.additions} -${pr.deletions} (총 ${totalChanges} lines)`);
const sizeLabels = {
'size/XS': { max: 10, color: '3CBF00' },
'size/S': { max: 50, color: '5D9801' },
'size/M': { max: 200, color: 'FBCA04' },
'size/L': { max: 500, color: 'FFA500' },
'size/XL': { max: Infinity, color: 'D93F0B' }
};
let newSizeLabel = 'size/XL';
for (const [label, config] of Object.entries(sizeLabels)) {
if (totalChanges <= config.max) {
newSizeLabel = label;
break;
}
}
// 현재 라벨 확인
const { data: currentLabels } = await github.rest.issues.listLabelsOnIssue({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber
});
const currentSizeLabel = currentLabels.find(l => l.name.startsWith('size/'));
// 같은 라벨이면 스킵
if (currentSizeLabel?.name === newSizeLabel) {
console.log(`이미 올바른 크기 라벨: ${newSizeLabel}`);
return;
}
// 기존 size 라벨 제거
if (currentSizeLabel) {
await github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
name: currentSizeLabel.name
});
}
// 라벨이 없으면 생성
try {
await github.rest.issues.getLabel({
owner: context.repo.owner,
repo: context.repo.repo,
name: newSizeLabel
});
} catch (error) {
if (error.status === 404) {
await github.rest.issues.createLabel({
owner: context.repo.owner,
repo: context.repo.repo,
name: newSizeLabel,
color: sizeLabels[newSizeLabel].color,
description: `PR size: ${newSizeLabel.replace('size/', '')}`
});
}
}
// 새 라벨 추가
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
labels: [newSizeLabel]
});
console.log(`크기 라벨 적용: ${newSizeLabel}`);
# ==========================================================================
# Type Label - PR 커밋들에서 타입 추출 (없을 때만 추가)
# ==========================================================================
type-label:
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- name: Label PR by Commit Types
uses: actions/github-script@v7
with:
script: |
const prNumber = context.payload.pull_request.number;
// 지원하는 타입 라벨 정의
const typeLabels = {
'feat': { color: '0E8A16', description: '새로운 기능' },
'fix': { color: 'D93F0B', description: '버그 수정' },
'refactor': { color: '1D76DB', description: '리팩토링' },
'design': { color: 'F9D0C4', description: 'UI/디자인 변경' },
'style': { color: 'FEF2C0', description: '코드 스타일 변경' },
'docs': { color: '0075CA', description: '문서 수정' },
'test': { color: 'BFD4F2', description: '테스트 코드' },
'chore': { color: 'D4C5F9', description: '기타 변경사항' },
'init': { color: '5319E7', description: '초기 생성' },
'rename': { color: 'C2E0C6', description: '파일/폴더명 변경' },
'remove': { color: 'B60205', description: '파일 삭제' },
'cicd': { color: 'FBCA04', description: 'CI/CD 관련' }
};
const typeKeys = Object.keys(typeLabels);
const typePattern = new RegExp(`(?:^|\\s)(${typeKeys.join('|')})(?:\\([^)]*\\))?:`, 'i');
// PR의 커밋 목록 가져오기
const { data: commits } = await github.rest.pulls.listCommits({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber
});
console.log(`PR #${prNumber} 커밋 수: ${commits.length}`);
// 각 커밋에서 타입 추출 (중복 제거)
const detectedTypes = new Set();
for (const commit of commits) {
const message = commit.commit.message.split('\n')[0]; // 첫 줄만
const match = message.match(typePattern);
if (match) {
detectedTypes.add(match[1].toLowerCase());
}
console.log(` - ${message.substring(0, 60)}${message.length > 60 ? '...' : ''}`);
}
console.log(`감지된 타입: ${[...detectedTypes].join(', ') || '없음'}`);
if (detectedTypes.size === 0) {
console.log('커밋에서 타입을 찾을 수 없습니다.');
return;
}
// 현재 라벨 확인
const { data: currentLabels } = await github.rest.issues.listLabelsOnIssue({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber
});
const currentLabelNames = currentLabels.map(l => l.name);
// 추가할 타입 라벨 필터링 (이미 있는 것 제외)
const labelsToAdd = [...detectedTypes].filter(type => !currentLabelNames.includes(type));
if (labelsToAdd.length === 0) {
console.log('모든 타입 라벨이 이미 존재합니다.');
return;
}
// 라벨이 없으면 생성
for (const type of labelsToAdd) {
const labelConfig = typeLabels[type];
try {
await github.rest.issues.getLabel({
owner: context.repo.owner,
repo: context.repo.repo,
name: type
});
} catch (error) {
if (error.status === 404) {
await github.rest.issues.createLabel({
owner: context.repo.owner,
repo: context.repo.repo,
name: type,
color: labelConfig.color,
description: labelConfig.description
});
}
}
}
// 타입 라벨 추가
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
labels: labelsToAdd
});
console.log(`타입 라벨 추가: ${labelsToAdd.join(', ')}`);