diff --git a/.github/workflows/ff-merge.yml b/.github/workflows/ff-merge.yml index a9b91f85..7b7555b9 100644 --- a/.github/workflows/ff-merge.yml +++ b/.github/workflows/ff-merge.yml @@ -1,15 +1,15 @@ name: FF-Only Merge to Master on: - pull_request_review: - types: [submitted] + pull_request: + types: [labeled] check_suite: types: [completed] jobs: ff-merge: if: | - github.event_name == 'pull_request_review' || + (github.event_name == 'pull_request' && github.event.label.name == 'ready-to-merge') || (github.event_name == 'check_suite' && github.event.check_suite.conclusion == 'success') runs-on: ubuntu-latest @@ -21,16 +21,25 @@ jobs: script: | let prNumber, headSha; - if (context.eventName === 'pull_request_review') { + if (context.eventName === 'pull_request') { const pr = context.payload.pull_request; if (pr.base.ref !== 'master' || pr.head.ref !== 'develop' || pr.state !== 'open') { core.setOutput('ready', 'false'); return; } - if (context.payload.review.state !== 'approved') { + + // 레이블을 부착한 주체의 저장소 권한 확인 + const { data: perm } = await github.rest.repos.getCollaboratorPermissionLevel({ + owner: context.repo.owner, + repo: context.repo.repo, + username: context.payload.sender.login, + }); + + if (!['admin', 'write'].includes(perm.permission)) { core.setOutput('ready', 'false'); return; } + prNumber = pr.number; headSha = pr.head.sha; } else { @@ -56,25 +65,15 @@ jobs: } } - // 승인 상태 확인 - const { data: reviews } = await github.rest.pulls.listReviews({ + // ready-to-merge 레이블 확인 + const { data: pr } = await github.rest.pulls.get({ owner: context.repo.owner, repo: context.repo.repo, pull_number: prNumber, }); - const latest = {}; - for (const r of reviews) { - if (r.state !== 'COMMENTED') { - latest[r.user.login] = r.state; - } - } - - const values = Object.values(latest); - const approved = values.filter(s => s === 'APPROVED').length >= 1; - const blocked = values.some(s => s === 'CHANGES_REQUESTED'); - - if (!approved || blocked) { + const hasLabel = pr.labels.some(l => l.name === 'ready-to-merge'); + if (!hasLabel) { core.setOutput('ready', 'false'); return; } @@ -87,7 +86,7 @@ jobs: per_page: 100, }); - const ciRuns = check_runs.filter(r => r.name !== context.workflow); + const ciRuns = check_runs.filter(r => r.name !== context.job); const allPassed = ciRuns.length > 0 && ciRuns.every(r => r.status === 'completed' && ['success', 'skipped', 'neutral'].includes(r.conclusion) @@ -120,9 +119,9 @@ jobs: APPROVED_SHA="${{ steps.validate.outputs.head_sha }}" CURRENT_SHA=$(git rev-parse origin/develop) if [ "$APPROVED_SHA" != "$CURRENT_SHA" ]; then - echo "develop이 승인 이후 변경되었습니다." - echo " 승인된 SHA: $APPROVED_SHA" - echo " 현재 SHA: $CURRENT_SHA" + echo "레이블 부착 이후 develop이 변경되었습니다." + echo " 레이블 시점 SHA: $APPROVED_SHA" + echo " 현재 SHA: $CURRENT_SHA" exit 1 fi