도시락 팀의 회의를 진행하던 중 각자 공부한 내용을 공유하자는 의견이 나왔다.
study라는 repository를 새로 만들었는데, 새로운 글이 올라오는 경우 팀 디스코드에 알림이 가면 좋을 것 같아서 알아보게 되었다.
요즘 github action으로 cI의 편리함을 흠뻑 느끼고 있다.
없었을 때는 어떻게 살았지.
이번에는 main에 push가 발생하면 해당 pr 안의 commit message를 확인하고, `docs` 키워드로 작성된 commit message가 있는 경우 디스코드에 알림을 보내주는 기능을 구현해보려고 한다.
웹훅(Webhook)
간단하게 웹훅은 웹앱에서 발생한 이벤트를 커스텀 callback으로 변환하는 방법으로 구현된 시스템이다.
보통은 클라이언트에서 서버로 API 요청을 보내지만, 웹훅의 경우 반대로 서버에서 클라이언트에 API 요청을 보내게 된다.
https://frtt0608.tistory.com/143
Discord에서 웹훅 URL 생성하기
웹훅 URL은 웹훅의 엔드포인트라고 생각하면 된다.
웹훅으로 발생한 이벤트가 전달되는 곳이 웹훅 URL이다.
따라서 원하는 디스코드 서버에 웹훅URL을 생성해줬다.
디스코드 > 웹훅 연결을 원하는 서버 > 서버 설정 > 앱 > 연동 > 웹후크
위와 같이 현재 서버에서 존재하는 웹훅을 확인할 수 있다.
새 웹후크 버튼을 눌러
이미지와 같이 웹후크의 이름, 연결을 원하는 채널을 선택해주고 웹후크 URL을 복사해주면 디스코드에서 해야하는 일은 끝이다.
Github Secrets 등록하기
웹훅URL은 Github Action에 직접 작성할 경우 URL이 공개되어 외부에서도 우리 서버의 채널에 접근이 가능해진다.
따라서 github secret으로 등록해서 사용해야한다.
원하는 repository > Settings > Secrets and variables > Actions > New repository secret
들어가서 원하는 이름으로 secret을 만들어주면 된다.
값 부분에는 위에서 생성한 웹후크의 URL을 복사해서 넣어주면 된다.
Github Actions Workflow 작성하기
이제 가장 메인인 github actions workflow를 작성해줄 차례이다.
디스코드에 메시지를 보낼 때 단순히 줄글로 보낼 수도 있지만, 가독성 좋고 확인하고 싶게 만들기 위해 작성자와 커밋 메시지, 커밋 바로가기 링크도 추가해주려고 한다.
Repository에 .gitnub 폴더를 만들고 그 하단에 workflows라는 폴더를 만들어준다.
해당 workflows 안에 원하는_이름.yml을 만들어 코드를 작성해주면 된다.
아래는 작성한 notify-docs.yml 파일이다.
notify-docs.yml
name: Notify Discord when docs commit is pushed
on:
push:
branches:
- main
jobs:
notify-discord:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Check if there is a docs commit
id: check_docs
run: |
echo "Checking commits for docs:"
for i in $(seq 0 $(($(jq '.commits | length' "$GITHUB_EVENT_PATH") - 1))); do
commit_message=$(jq -r ".commits[$i].message" "$GITHUB_EVENT_PATH")
commit_id=$(jq -r ".commits[$i].id" "$GITHUB_EVENT_PATH")
echo "Found commit: $commit_message"
if [[ "$commit_message" == docs:* ]]; then
echo "docs commit detected."
echo "found=true" >> $GITHUB_ENV
echo "commit_message=$commit_message" >> $GITHUB_ENV
echo "commit_id=$commit_id" >> $GITHUB_ENV
break
fi
done
- name: Notify Discord
if: env.found == 'true'
env:
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
run: |
payload=$(jq -n --arg actor "${{ github.actor }}" \
--arg message "${{ env.commit_message }}" \
--arg commit_url "https://github.com/${{ github.repository }}/commit/${{ env.commit_id }}" \
'{
"embeds": [
{
"title": "📚 New Docs Update",
"description": "\($actor)님이 새로운 학습 내용을 정리했습니다!\n📝 \($message)\n🔗 [커밋 보러 가기](\($commit_url))",
"color": 3447003,
"timestamp": now | todateiso8601
}
]
}')
curl -H "Content-Type: application/json" \
-X POST \
-d "$payload" \
"$DISCORD_WEBHOOK"
추후에 github acrtion 기본 형식 정리를 할 예정이라, 그 부분을 제외하고 위의 workflow 코드를 일부 설명하자면
name: Notify Discord when docs commit is pushed
on:
push:
branches:
- main
jobs:
notify-discord:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Check if there is a docs commit
id: check_docs
run: |
echo "Checking commits for docs:"
# 발생한 이벤트 정보를 담은 JSON 파일의 경로($GITHUB_EVENT_PATH)
# commits 배열의 길이를 구하고, 0부터 마지막 인덱스까지 순회
# JSON 파일을 순회하며 각 커밋 메시지와 커밋 id를 jq를 통해 추출 후 환경변수에 저장
for i in $(seq 0 $(($(jq '.commits | length' "$GITHUB_EVENT_PATH") - 1))); do
commit_message=$(jq -r ".commits[$i].message" "$GITHUB_EVENT_PATH")
commit_id=$(jq -r ".commits[$i].id" "$GITHUB_EVENT_PATH")
echo "Found commit: $commit_message"
# 커밋메시지가 docs로 시작하는 커밋이 있는지 검사
# 해당하는 조건의 커밋이 존재하면 해당 커밋의 커밋메시지와 커밋 id를 환경변수에 저장
# PR 단위로 관리하기로 했었기 때문에 PR 내 모든 커밋메시지를 순회하면서 'docs'를 찾음
if [[ "$commit_message" == docs:* ]]; then
echo "docs commit detected."
echo "found=true" >> $GITHUB_ENV
echo "commit_message=$commit_message" >> $GITHUB_ENV
echo "commit_id=$commit_id" >> $GITHUB_ENV
break
fi
done
- name: Notify Discord
# 'docs:' 커밋이 있을 때만 실행되도록 조건 설정
if: env.found == 'true'
env:
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
run: |
# 디스코드에 보낼 payload JSON 생성
# actor: 커밋 작성자, message: 커밋 메시지, commit_url: 커밋 링크
payload=$(jq -n --arg actor "${{ github.actor }}" \
--arg message "${{ env.commit_message }}" \
--arg commit_url "https://github.com/${{ github.repository }}/commit/${{ env.commit_id }}" \
'{
# discord에 등록될 메시지 형태
"embeds": [
{
"title": "📚 New Docs Update",
"description": "\($actor)님이 새로운 학습 내용을 정리했습니다!\n📝 \($message)\n🔗 [커밋 보러 가기](\($commit_url))",
"color": 3447003,
"timestamp": now | todateiso8601
}
]
}')
# discord 웹훅 URL을 이용해 서버에 post 요청
curl -H "Content-Type: application/json" \
-X POST \
-d "$payload" \
"$DISCORD_WEBHOOK"
성공!!
이제 이거 응용해서 프로젝트 폴더에 적용시키면 프로젝트 PR이나 특정 branch push 시 팀원들 모두가 알 수 있도록 알림을 보낼 수 있게 설정할 수 있을거 같다!
원래는 젠킨스를 사용해서 할 수도 있어서 만약 젠킨스를 사용하게 된다면 어떻게 다른지 비교해봐도 재밌을 거 같다.