[관리]GITHUB ‐ DISCORD Pull Request 연동 - gyunam-bark/nb02-how-do-i-look-team1 GitHub Wiki
사전 준비
디스코드 채널 소유자(관리자)에게 웹훅 URL 요청
디스코드 채널 소유자(관리자) 만 웹훅 URL 을 생성할 수 있습니다.
채널 소유자일 경우
[서버 설정] 의 [앱] 아래에 있는 [연동] 에서 생성할 수 있습니다.
[개발자 모드] 활성화
디스코드의 [설정] 의 [고급] 아래에 있는 [개발자 모드]를 활성화합니다.
개발자 모드가 활성화 되어야 유저의 고유 ID 를 확인할 수 있습니다.
유저 고유 ID 는 숫자로만 이루어져 있습니다.
이 고유 ID 는 Github Actions 에서 메세지를 보낼때 멘션을 지정하기 위한 값이므로, 팀원들의 ID 값들을 리스트업 합니다.
Github Secret 설정
Github 내부에는 외부에서 접근할 수 없고, 상수 처럼 사용할 수 있는 Secret 이라는 값을 등록할 수 있습니다.
Github 저장소 내부에서 쓰이는 .env 라고 이해하면 됩니다.
Secret 이름은 편하게 지어도 됩니다.
하지만 상수기 때문에 대체로 CAMEL_CASE 를 따릅니다.
How Do I Look 은 아래의 두 Secret 을 사용합니다.
1. DISCORD_WEBHOOK_URL
2. USER_MAP
주의
Secret 은 지정하고 나서 다른 곳에 기록하는 것을 권장합니다.
관리자에게도 보이지 않는 것을 원칙으로 하기 때문에, 저장 후 다시 수정하려고 들어가도 기존 값은 보이지 않습니다.
Github Actions
파일 위치는 Merge 될 브랜치
DEV 브랜치에 머지될 예정이라면, DEV 브랜치의 .github/workflows/에 해당 .yml 이 있어야 동작합니다.
.github
ㄴworkflows
ㄴpr-to-discord.yml
on 이벤트
Github Actions 에서는 on 이벤트로 특정한 상황일 때 작업들(jobs)을 동작하도록 할 수 있습니다.
on:
pull_request: # PULL REQUEST 가 발생했을 때
types: [opened, reopend, ready_for_review] # 열렸을 때, 다시 열렸을 때, 리뷰를 기다리는 중일 때
이번 How Do I Look 은 단순히 PR 이 발생하면 디스코드로 알림을 보내는 것이 목표였습니다.
그래서 [PR 열림, PR 재열림, 리뷰 대기] 이렇게 3가지 경우만 체크합니다.
jobs
그리고 그 이벤트가 동작했을 때 작업할 목록을 작성합니다.
jobs:
notify-discord: # 진행할 작업 이름을 지정
runs-on: ubuntu-latest # GITHUB가 지원하는 리눅스 최신버전
Github Actions 는 어떤 이벤트가 동작하면, 정해진 컨테이너를 실행해서 명령어에 따라 동작하는 기능입니다.
단순히 디스코드 웹훅으로 메세지를 보내는 것은 리눅스 컨테이너로도 충분합니다.
다만, 무료로 사용되는 성능에서는 약간의 딜레이(5초~10초)가 발생합니다.
steps
steps 는 하나의 job 이 사용하는 동작들을 순서대로 작성합니다.
내부 동작 코드는 bash 로 작성합니다.
run: 에 해당 step 이 동작할 bash 스크립트를 작성할 수 있습니다.
예시) PR 유저 가져오는 bash 스트립트
jobs:
notify-discord:
runs-on: ubuntu-latest
steps:
- name: Get PR reviewers
id: reviewers
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
PR_NUMBER="${{ github.event.pull_request.number }}"
REPO="${{ github.repository }}"
echo "Fetching reviewers for PR #$PR_NUMBER from $REPO"
API_RESPONSE=$(gh api repos/$REPO/pulls/$PR_NUMBER 2>err.log || echo "")
if [ -s err.log ]; then
echo "Error from GitHub API:"
cat err.log
fi
if [ -z "$API_RESPONSE" ]; then
REVIEWERS="[]"
else
# 안정적으로 리뷰어 목록 파싱 (null 및 빈 배열 모두 처리)
REVIEWERS=$(echo "$API_RESPONSE" | jq -c '[.requested_reviewers?[]?.login] // []')
fi
echo "Reviewers JSON: $REVIEWERS"
# base64 인코딩하여 GitHub Actions output으로 전달
REVIEWERS_B64=$(echo "$REVIEWERS" | base64)
echo "reviewers_b64=$REVIEWERS_B64" >> "$GITHUB_OUTPUT"
pr-to-discord.yml
name: Notify Reviewers on PR
on:
workflow_dispatch:
pull_request:
types: [opened, reopened, ready_for_review]
jobs:
notify-discord:
runs-on: ubuntu-latest
steps:
- name: Get PR reviewers
id: reviewers
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
PR_NUMBER="${{ github.event.pull_request.number }}"
REPO="${{ github.repository }}"
echo "Fetching reviewers for PR #$PR_NUMBER from $REPO"
API_RESPONSE=$(gh api repos/$REPO/pulls/$PR_NUMBER 2>err.log || echo "")
if [ -s err.log ]; then
echo "Error from GitHub API:"
cat err.log
fi
if [ -z "$API_RESPONSE" ]; then
REVIEWERS="[]"
else
# 안정적으로 리뷰어 목록 파싱 (null 및 빈 배열 모두 처리)
REVIEWERS=$(echo "$API_RESPONSE" | jq -c '[.requested_reviewers?[]?.login] // []')
fi
echo "Reviewers JSON: $REVIEWERS"
# base64 인코딩하여 GitHub Actions output으로 전달
REVIEWERS_B64=$(echo "$REVIEWERS" | base64)
echo "reviewers_b64=$REVIEWERS_B64" >> "$GITHUB_OUTPUT"
- name: Notify Discord
env:
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
USER_MAP: ${{ secrets.USER_MAP }} # 예: {"alice": "1234", "bob": "5678"}
run: |
set -euo pipefail
PR_TITLE="${{ github.event.pull_request.title }}"
PR_URL="${{ github.event.pull_request.html_url }}"
# base64 디코딩 후 JSON 배열로 파싱
REVIEWERS_JSON=$(echo "${{ steps.reviewers.outputs.reviewers_b64 }}" | base64 --decode)
echo "Parsed reviewers: $REVIEWERS_JSON"
MENTION_LIST=""
for user in $(echo "$REVIEWERS_JSON" | jq -r '.[]'); do
DISCORD_ID=$(echo "$USER_MAP" | jq -r --arg u "$user" '.[$u] // empty')
if [ -n "$DISCORD_ID" ]; then
MENTION_LIST="$MENTION_LIST <@$DISCORD_ID>"
else
MENTION_LIST="$MENTION_LIST @$user"
fi
done
if [ -z "$MENTION_LIST" ]; then
MENTION_LIST="(리뷰어가 지정되지 않았습니다)"
fi
curl -X POST "$DISCORD_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d @- <<EOF
{
"content": "${MENTION_LIST}\n새로운 Pull Request: **${PR_TITLE}**\n${PR_URL}"
}
EOF
문제해결
Github Secret 파싱 에러
USER_MAPS 가 온전한 json 형태여야 합니다. 그리고 띄어쓰기 및 줄바꿈이 없어야 합니다.
맥의 경우 '"' 쌍따옴표가 스마트 쌍따옴표 로 표시되는 경우가 있습니다. 특히, 맥 내장 기본 메모 에서 쌍따옴표를 사용해서 복사 붙여넣기 할 경우에 해당 문제가 발생할 수 있습니다.
가능한 vscode 에서 json 작업을 해서 secret 에 복사 붙여넣기 하기를 권장합니다.
folk 한 경우
원칙적으로 folk한 저장소는 깃허브에서 완전 별개의 저장소로 인식합니다.
그래서 설정해뒀던 Secret 을 팀원 개인별로 설정을 완료해야만 동작합니다!!