🛠️ 스케쥴: 리뷰 리마인더 #57
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # .github/workflows/slack-review-reminder.yml | |
| name: "🛠️ 스케쥴: 리뷰 리마인더" | |
| on: | |
| schedule: | |
| - cron: "10 2 * * *" # UTC 02:00 = KST 11:00 (매일) | |
| workflow_dispatch: | |
| permissions: | |
| pull-requests: read | |
| contents: read | |
| jobs: | |
| remind_reviewers: | |
| name: Remind pending reviewers | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Send reminders | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| SLACK_WEBHOOK_URL: ${{ secrets.DABIN_TEST1 }} | |
| REPO: ${{ github.repository }} | |
| QA_TARGET_BRANCH: ${{ vars.ref }} | |
| run: | | |
| set -euo pipefail | |
| # QA 대상 브랜치가 설정 안 돼 있으면 종료 (QA 기간 아님) | |
| if [ -z "${QA_TARGET_BRANCH}" ]; then | |
| echo "QA_TARGET_BRANCH 미설정 — QA 기간 아님, 종료" | |
| exit 0 | |
| fi | |
| # GitHub 아이디 -> Slack 멤버 ID 매핑 | |
| declare -A SLACK_ID_MAP=( | |
| ["MinwooP"]="U04KKJFGJQP" | |
| ["dabinkimm"]="U0XXXXXXXXX" | |
| ) | |
| # 리뷰어(GitHub 아이디) | |
| declare -A PENDING_BY_REVIEWER | |
| # 대상 브랜치로 머지 예정인 열린 PR 목록 조회 | |
| prs=$(gh api "repos/${REPO}/pulls?state=open&base=${QA_TARGET_BRANCH}&per_page=100") | |
| # 1) 모든 PR을 돌면서 사람별로 대기 PR을 모은다 | |
| while read -r pr; do | |
| [ -z "$pr" ] && continue | |
| number=$(echo "$pr" | jq -r '.number') | |
| title=$(echo "$pr" | jq -r '.title') | |
| author=$(echo "$pr" | jq -r '.user.login') | |
| url=$(echo "$pr" | jq -r '.html_url') | |
| # 현재 리뷰 요청이 살아있는(=아직 리뷰 안 한) 리뷰어 목록 | |
| requested=$(echo "$pr" | jq -r '.requested_reviewers[].login') | |
| [ -z "$requested" ] && continue | |
| # 이 PR을 대기 중인 각 리뷰어 항목에 누적 | |
| line="PR: #${number} ${title}"$'\n'"작성자: ${author}"$'\n'"대상 브랜치: ${QA_TARGET_BRANCH}"$'\n'"링크: ${url}" | |
| while read -r reviewer; do | |
| [ -z "$reviewer" ] && continue | |
| if [ -n "${PENDING_BY_REVIEWER[$reviewer]:-}" ]; then | |
| PENDING_BY_REVIEWER[$reviewer]="${PENDING_BY_REVIEWER[$reviewer]}"$'\n\n'"${line}" | |
| else | |
| PENDING_BY_REVIEWER[$reviewer]="${line}" | |
| fi | |
| done <<< "$requested" | |
| done <<< "$(echo "$prs" | jq -c '.[]')" | |
| # 2) 사람별로 묶은 내용을 한 번씩 전송 | |
| if [ ${#PENDING_BY_REVIEWER[@]} -eq 0 ]; then | |
| echo "리마인드 할 대상 없음 — 종료" | |
| exit 0 | |
| fi | |
| for reviewer in "${!PENDING_BY_REVIEWER[@]}"; do | |
| slack_id="${SLACK_ID_MAP[$reviewer]:-}" | |
| if [ -n "$slack_id" ]; then | |
| mention="<@${slack_id}>" | |
| else | |
| mention="@${reviewer}" | |
| fi | |
| body="${PENDING_BY_REVIEWER[$reviewer]}" | |
| text="👀 리뷰 대기 알림"$'\n\n'"${mention} 님, 리뷰 대기 중인 PR이 있습니다."$'\n\n'"${body}" | |
| payload=$(jq -n --arg text "$text" '{text: $text}') | |
| curl -s -X POST -H 'Content-type: application/json' \ | |
| --data "$payload" \ | |
| "${SLACK_WEBHOOK_URL}" | |
| echo "리뷰어 $reviewer 알림 전송 완료" | |
| done |