지난번에 코드리뷰를 하는 방법에 대해 알아보았어요.
이번 시간에는 제가 우리팀의 코드리뷰 문화를 발전 시키기 위해 했던 삽질..
슬랙 알림 자동화로 코드리뷰 문화 개선했던 이야기를 구체적으로 해볼게요.
계기
저희 팀의 그라운드 룰로 상호 코드 리뷰 후 몇 명 이상의 동의가 있어야 개발 브랜치로 병합할 수 있었어요.
백엔드는 5명이고, 병합을 하기 위해서 3명 이상의 동의가 필요했던 것이죠.
불편했던 점은 누가 PR를 생성하면, 일일이 팀원을 찾아 다니면서 "누구 누구야! 나 코드리뷰좀 해줄래?"라고 말을 해야했고, 또 상대방은 리드리뷰 후 "나 코드리뷰 다했으니까 확인해줘"라고 찾아 다니며 말해야하는 불편함이 있었죠..
무식해서 용감했던 저는 팀원들에게 당당하게 "이 문제 내가 해결한다! 딱 일주일만 줘라!!!"라고 했던 것이 큰 재앙을 불러왔습니다.
도전 1 : 무식하게 부딪혀보기
당시 저는 github Actions에 대한 이해도가 전~~~혀 없는 상대여서 이것 저것 Github 공식 문서들을 뒤지다가 Github Webhook이라는 녀석을 발견합니다.
이 녀석은 설정된 레포지토리에 이벤트가 발생하면 설정해둔 API로 여러 설정 값들을 넣어 POST 요청을 보냅니다.
여기서 저는 정말 무식한 방법을 생각하고 적용하게 됩니다..
1. "Slack 알람용 Springboot 서버"에서 Github Webhook을 처리하는 API 생성
2. Github Webhook이 보낸 Payload를 "Slack 알람용 Springboot 서버"에서 정보 파싱
3. 적절한 정보를 다시 조합해서 Slack Webhook으로 "Slack 알람용 Springboot 서버"가 API 요청
딱 봐도 문제가 보이죠.
SpringBoot 실행시킬 환경도 필요하고. 내가 직접 로직도 만들어야하니 관리하기 너무 빡시죠..
그래서 친구 동기에게 고민을 풀어 놓으니 Github Action을 쓰면 편하다는 겁니다.
그래? 그게 뭔데 하면서 주말을 꼬박 머리 박으며 문서를 읽었죠..
도전2 : Github Actions로 ...
팀원들에게 일주일만에 완성시킨다고 호언장담 해놓고 남은 시간은 고작 토요일과 일요일뿐이었어요.
그래서 저는 주말 시간을 모두 투자해서 Github Actions와 Slack API docs 만지작 거렸습니다.
시간을 때려 넣으니 버벅 버벅 , 작동은 겨우하는 알림를 만들었습니다.
간단하게 누가 PR을 요청하면 요청을 받고 Slack bot으로 메세지를 지정해서 밀어넣으면 끝!
name: pull request
on:
pull_request:
types: [opened, reopened]
// ... 생략
id: pull_request_notify
uses: slackapi/slack-github-action@v1.26.0
with:
channel-id: ${{secrets.SLACK_BE_REVIEW_CHANNEL}}
payload: |
{
"text": "⌛PR왔다 리뷰해라⌛",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*📬${{steps.extract_receiver_list.outputs.requester}}님의 PR이 도착했어요.📬*\n\n\n⚡⚡⚡⚡⚡⚡⚡⚡⚡\n*⚡<${{github.event.pull_request.html_url}}| [${{steps.extract_receiver_list.outputs.requester}}] 혼구멍 내러가기~>⚡* \n⚡⚡⚡⚡⚡⚡⚡⚡⚡\n\n _혼내줄 사람들: ${{steps.extract_receiver_list.outputs.names}}_ \n"
}
},
{
"type": "divider"
}
]
}
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
아주 간단한 형태였어요.
그런데 저는 리뷰요청뿐만 아니라, 응답도 알림을 자동화하고 싶었어요.
도전3: 이쁘게 메세지 쓰레드로 넣기
이게 마지막 도전이자. 결론이데요.
결과물부터 보여드리겠습니다.
리뷰 요청(PR)이 도착하면 아래 같이 리뷰어들을 멘션합니다.
그리고 리뷰어들이 리뷰를 완료하면 아래와 같이 이쁘게 리뷰가 완료 되었음을 리뷰이에게 알리는 기능까지였습니다.😄
어떤가요? 저는 생각보다 완성본이 맘에 들었어요.
이제부터 본격적으로 어떻게 구현했는지 말씀드릴게요
우선, 알림을 받을 팀원들의 Slack과 GitHub ID 같은 정보는 Actions Secret에 넣어 관리했습니다. 이런 정보들도 중요한 개인 정보로 볼 수 있어 보안을 위해 별도로 보호된 공간에 저장해 두는 거죠.
[
{
"name" : "프 람",
"tag": "be",
"githubId": "koust6u",
"slackId": "*****"
},
... 생략
{
"name" : "파 란",
"tag" : "fe",
"githubId": "abccd",
"slackId" : "*****"
},
{
"name": "해 시",
"tag" : "fe",
"githubId": "xyzz",
"slackId": "*****"
}
]
Actions Secret에 base64로 인코딩후 넣어두고 Actions에서 디코딩 후 필요정보를 사용해서 쓰기로 했습니다.
- name: Decode base64 and parse JSON
run: |
echo ${{secrets.SLACK_CREW_INFO_JSON}} | base64 --decode > decoded.json
JSON_CONTENT=$(cat decoded.json | jq -c .)
echo "CREW_INFO_JSON=$JSON_CONTENT" >> $GITHUB_ENV
그 다음으로 Thread 댓글로 리뷰 응답을 추가하려면, 각 리뷰나 댓글이 언제 작성되었는지 알 수 있는 고유한 타임스탬프(timestamp) 값을 저장해두는 것이 중요합니다.
- PR 리뷰 시에 댓글이 작성되면 해당 댓글의 타임스탬프 값을 저장합니다. 이 타임스탬프는 댓글 작성 시간을 나타내며, 후에 해당 댓글에 응답할 때 이 정보를 사용합니다.
- 이후 Thread 댓글로 답글을 추가할 때, 저장된 타임스탬프 값을 이용해 어느 댓글에 대한 응답인지 연결할 수 있습니다.
즉, 타임스탬프를 통해 각 댓글을 고유하게 식별하고, 이를 기반으로 리뷰 응답이 자연스럽게 이어질 수 있도록 하는 방식입니다.
조금 복잡하지만 저는 이렇게 해결했어요.
1. PR 요청이 오면 Secret에 등록한 팀원들 정보와 적절히 가공하여 Slack 메세지로 알림을 보냅니다.
- name: Extract receiver list
id: extract_receiver_list
uses: actions/github-script@v7.0.1
with:
script: |
const excludeMember = context.payload.pull_request.user.login;
const members = JSON.parse(process.env.CREW_INFO_JSON);
const requester = members.find(entry => entry.githubId === excludeMember);
let outputString = '';
for (const member of members) {
if ((member.githubId !== excludeMember) && (member.tag === requester.tag)) {
outputString += `<@${member.slackId}> `;
}
}
console.log(`::set-output name=names::${outputString.trim()}`);
console.log(`::set-output name=requester::${requester.name}`);
2. 가공한 정보를 slack 알림 전송
- name: pull_request_noifiy
id: pull_request_notify
uses: slackapi/slack-github-action@v1.26.0
with:
channel-id: ${{secrets.SLACK_BE_REVIEW_CHANNEL}}
payload: |
{
"text": "⌛PR왔다 리뷰해라⌛",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*📬${{steps.extract_receiver_list.outputs.requester}}님의 PR이 도착했어요.📬*\n\n\n⚡⚡⚡⚡⚡⚡⚡⚡⚡\n*⚡<${{github.event.pull_request.html_url}}| [${{steps.extract_receiver_list.outputs.requester}}] 혼구멍 내러가기~>⚡* \n⚡⚡⚡⚡⚡⚡⚡⚡⚡\n\n _혼내줄 사람들: ${{steps.extract_receiver_list.outputs.names}}_ \n"
}
},
{
"type": "divider"
}
]
}
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
3. 등록된 PR timestamp를 github 별도 브랜치에 저장
- name: Append Thread info to JSON
run: |
NEW_THREAD_JSON=$(jq -n \
--arg url "${{ github.event.pull_request.html_url }}" \
--arg author "${{ github.event.pull_request.user.login }}" \
--arg thread_ts "${{ steps.pull_request_notify.outputs.ts }}" \
'{pr_url: $url, author: $author, thread_ts: $thread_ts}')
mkdir -p .github/logs
cd .github/logs
if [ -f thread_fe.json ]; then
jq --argjson new "$NEW_THREAD_JSON" '. += [$new]' thread_fe.json > thread_fe.tmp.json
mv thread_fe.tmp.json thread_fe.json
else
echo "[$NEW_THREAD_JSON]" > thread_fe.json
fi
- name: Commit updated thread_fe.json
run: |
git config --global user.email "action@github.com"
git config --global user.name "GitHub Actions"
git add .github/logs/thread_fe.json
git commit -m "Update thread_fe.json with new thread data"
git push origin ${{ vars.SLACK_BRANCH }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
자 여기까지 왔으면, PR이 발생하면, 코드리뷰해달라고 팀원들에게 재촉할 준비가 다되었습니다.
혹시 자세한 구현 내용이 궁금하면 댓글로 남겨주세요 😄
'삽질 보고서' 카테고리의 다른 글
API 응답속도 개선하기 (1) | 2025.01.30 |
---|---|
테스트가 느려서 테스팅하기 싫을때 (0) | 2025.01.24 |
우리도 무중단 배포 할래요. (0) | 2024.10.27 |