Krong Dev.
CI/CDGitHub Actions

PR 알림과 CI 알림, GitHub에서 Discord로 나눠 보내기

GitHub PR 협업 이벤트와 CI 성공/실패 결과를 하나의 채널에 몰아넣지 않고, GitHub Webhook과 GitHub Actions로 나눠 각각 다른 Discord 채널로 보내도록 구성한 과정을 정리합니다.

PR 알림과 CI 알림, GitHub에서 Discord로 나눠 보내기

GitHub PR 협업 이벤트와 CI 성공/실패 결과를 하나의 채널에 몰아넣지 않고, GitHub Webhook과 GitHub Actions로 나눠 각각 다른 Discord 채널로 보내도록 구성한 과정을 정리합니다.

Github 레포지토리 저장소에 GitHub 알림을 Discord로 연결하는 작업을 맡으면서, 처음엔 웹훅 하나만 걸면 끝나는 줄 알았습니다.
하지만, ci check 여부나 github events 알림 기능을 알게 되면서, 한 가지 의문점이 들었습니다.

GitHub 이벤트를 Discord로 보내는 방법 중 언제 Webhook을 쓰고 언제 Actions를 써야 할까?


채널과 Webhook을 나눈 이유

사람의 이벤트와 자동 결과를 분리한다

GitHub에서 Discord로 보내고자 한 알림은 크게 두 종류였습니다.

  • 협업 이벤트: PR 생성, 리뷰어 지정 요청, PR 병합 또는 닫힘처럼 사람이 만드는 PR 단위 상태 변화
  • 자동 검증 결과: ESLint, TypeScript type check, Next.js build, Storybook test처럼 CI가 만드는 결과

이 둘을 한 채널에 두면 리뷰 알림과 CI 알림이 뒤섞이고, CI 재실행이 잦아질수록 정말 확인해야 할 메시지를 찾기 어려워집니다.
그래서 아래처럼 채널과 알림 경로 자체를 나눴습니다.

plain
// 1. GitHub PR Event
GitHub PR 이벤트
  ↓
GitHub Repository Webhook
  ↓
#프론트-github-events
  ↓
PR 생성 / 리뷰어 요청 / 병합 / 닫힘 알림
plain
// 2. GitHub Actions CI
GitHub Actions CI 완료
  ↓
PR Discord Notification workflow
  ↓
#프론트-github-ci-bot
  ↓
CI 성공 / CI 실패 알림
Discord 채널 역할 메시지를 보내는 주체
#프론트-github-events PR 생성·리뷰어 요청·병합·닫힘 등 PR 단위 협업 알림 GitHub Repository Webhook
#프론트-github-ci-bot CI 성공·실패 알림 GitHub Actions

GitHub Webhook은 GitHub에서 특정 이벤트가 발생했을 때 지정한 URL로 HTTP 요청을 직접 보내는 기능이고, Discord Incoming Webhook은 Discord 특정 채널에 메시지를 남길 수 있는 전용 URL입니다.

About webhooks - GitHub Docs

Webhooks provide a way for notifications to be delivered to an external web server whenever certain events occur on GitHub.

docs.github.com

채널이 2개면 이 둘을 연결하는 Webhook도 2개가 필요합니다.
각각을 어떻게 구성했는지 알아봅니다.


GitHub Webhook으로 협업 이벤트 받기

실제로 받는 이벤트

첫 번째 채널 #프론트-github-events에는 아래 이벤트만 들어오도록 구성했습니다.

  • PR 생성
  • PR 리뷰어 지정 요청
  • PR 병합
  • PR 닫힘

현재 GitHub Webhook 설정에서는 Pull Requests 이벤트 하나만 체크되어 있습니다.
따라서 현재 구성은 PR 단위의 큰 상태 변화만 알리고, 리뷰 제출, 승인, 변경 요청, 댓글, push 같은 세부 이벤트는 Discord로 보내지 않습니다.

이벤트는 최소한으로 고른다

GitHub Repository Webhook 설정 화면에서 이벤트를 고를 때, 실제로 체크한 것과 체크하지 않은 것을 나눠보면 다음과 같습니다.

GitHub Event 실제 동작 Discord 알림 여부
Pull requests PR 생성, 닫힘, 병합, 리뷰어 요청 등 전송
Pull request reviews Approve, Request changes 등 리뷰 제출 미전송
Pull request review comments 코드 줄 단위 inline 댓글 미전송
Pull request review threads 리뷰 스레드 resolve/unresolve 미전송
Issue comments PR 일반 댓글, Issue 댓글 미전송
Pushes 브랜치에 커밋 push 미전송
Workflow runs / Check runs CI workflow·check 상태 미전송 (Actions가 담당)
Webhook events and payloads - GitHub Docs

Learn about when each webhook event occurs and what the payload contains.

docs.github.com

여기서 Pushes를 체크하지 않은 게 중요합니다.
PR 브랜치에 커밋을 push할 때마다 알림이 오면 채널이 금방 시끄러워지기 때문에, 실제로 팀원이 확인해야 하는 필수 이벤트만 받도록 걸러냈습니다.

Payload URL 끝에 /github를 붙이는 이유

GitHub Repository Webhook의 Payload URL은 일반 Discord Webhook URL과 조금 다르게 설정합니다.

plain
https://discord.com/api/webhooks/{WEBHOOK_ID}/{WEBHOOK_TOKEN}/github

그 이유는 GitHub와 Discord는 기본 Webhook payload 형식이 다르기 때문입니다.
GitHub는 GitHub 이벤트 JSON을 그대로 보내는데, Discord의 일반 Incoming Webhook은 Discord 메시지로 JSON으로 받기를 원합니다.

Discord Webhook Resource Document
출처: Discord Webhook Resource Document

그래서 URL 끝에 /github를 붙여야, Discord가 GitHub payload를 해석해서 사람이 읽을 수 있는 메시지로 변환해줍니다.

— ✨ 출처 : Webhook Resource - Documentation - Discord

ping 테스트로 확인하기

GitHub Repository Webhook을 저장하면 GitHub가 자동으로 ping 이벤트를 보냅니다.
여기서 확인한 응답은 아래와 같았습니다.

shell
Event: ping
Response: 204
Completed in: 0.08 seconds

HTTP 204는 요청이 정상 처리됐지만 별도 응답 본문은 없다는 뜻이라, 이 시점에는 연결 자체만 확인된 상태입니다.

GitHub Webhook ping 테스트 Recent deliveries

GitHub 저장소의 Settings → Webhooks → 해당 Webhook → Recent deliveries에서 전송 기록을 볼 수 있고, 원하면 Redeliver로 다시 보낼 수도 있습니다.

PR로 검증하기

실제 협업 알림은 PR을 만들어야 확인할 수 있어서, 빈 커밋으로 테스트 PR을 하나 열어봤습니다.

bash
git checkout -b chore/test-github-events
git commit --allow-empty -m "chore: test github webhook"
git push -u origin chore/test-github-events

이 브랜치로 develop을 대상으로 PR을 생성하면 Pull requests → opened 이벤트가 발생하고, #프론트-github-events 로 메시지가 도착합니다.

테스트 PR 생성 후 `#프론트-github-events`에 도착한 PR opened 알림

테스트 PR 생성 후 #프론트-github-events에 도착한 PR opened 알림

GitHub 입장에서는 PR이 열려야 비로소 pull_request 이벤트가 발생합니다.


GitHub Actions로 CI 결과만 골라 보내기

Workflow 전체가 끝났을 때만 보낸다

GitHub Repository Webhook에서 Check runs, Workflow jobs, Workflow runs 같은 이벤트도 선택할 수 있습니다.
그런데 이렇게 하면 CI 내부 job마다 알림이 따로 옵니다.

plain
ESLint 완료 → 알림
Type check 완료 → 알림
Build 완료 → 알림
Storybook build 완료 → 알림
Storybook test 완료 → 알림

이 방식은 메시지가 너무 많아지고, “전체 CI가 정말 성공했는지”를 한 번에 판단하기도 어렵습니다.
그래서 ci와 storybook job이 모두 끝나 전체 workflow의 conclusion이 결정된 시점에만, 별도 workflow가 Discord 메시지 한 건을 전송하도록 분리했습니다.

plain
ci job 완료
storybook job 완료
			↓
CI workflow 전체 conclusion 결정
			↓
PR Discord Notification 실행
			↓
Discord 메시지 1개 전송

ci.yml: 언제, 무엇을 검사하는가

CI workflow는 핵심 브랜치인 develop, main에 대해서만 실행합니다.

yaml
name: CI

on:
  push:
    branches: [develop, main]
  pull_request:
    branches: [develop, main]

permissions:
  contents: read

permissions: contents: read는 CI가 코드만 checkout해서 검사하면 되므로, 읽기 권한만 부여하였기 때문에 이 workflow는 생성, 수정, push 등의 작업을 할 수 없습니다.

또한 같은 PR에 새 커밋이 push되면 이전 CI를 취소하도록 concurrency도 설정했습니다.

yaml
concurrency:
  group: ci-${{ github.ref }}
  cancel-in-progress: ${{ github.event_name == 'pull_request' }}

cancel-in-progress를 pull_request == true로 둔 것은 PR 브랜치의 예전 커밋에 대한 CI는 취소하되, 핵심 브랜치에 직접 push한 CI는 유지하기 위해서입니다.

Control the concurrency of workflows and jobs - GitHub Docs

Manage which workflows and jobs can run simultaneously.

docs.github.com

두 개의 CI Job

이 workflow는 두 개의 job으로 나뉩니다.

1. 코드 품질과 빌드를 검사하는 ci

yaml
- uses: actions/checkout@v4
  with:
    persist-credentials: false

- uses: actions/setup-node@v4
  with:
    node-version-file: .nvmrc
    cache: npm

- id: install
  run: npm ci

여기서 실행하는 npm ci는 package-lock.json과 정확히 일치하는 의존성만 설치하는 것인데, npm install에서 발생하는 lockfile을 임의로 바꾸거나 의존성 버전이 달라져버릴 수 있는 문제를 해결합니다.

npm-ci | npm Docs

Clean install a project

docs.npmjs.com

persist-credentials: false는 checkout 이후 Github 인증 토큰이 git remote URL에 남지 않도록 하는 보안 설정입니다.

checkout/README.md at main · actions/checkout

Action for checking out a repo. Contribute to actions/checkout development by creating an account on GitHub.

github.com

이렇게 ci 버전을 일치하도록 한 후 검사를 실행합니다.

  • Prettier : 코드 포맷 검사
  • ESLint : 코드 품질 및 잠재적 오류 검사
  • Type Check : TypeScript 타입 오류 검사
  • Build : Next.js production build 가능 여부 검사

2. Storybook 빌드 및 interaction 및 접근성 테스트

yaml
- name: Install Playwright (chromium)
  run: npx playwright install --with-deps chromium

- name: Build Storybook
  run: npm run build-storybook

- name: Test Storybook
  run: npm run test-storybook

Storybook job은 다음을 확인합니다.

  • Storybook build : Story 파일, 컴포넌트, Storybook 설정이 정상 빌드되는지 확인
  • Playwright Chromium 설치 : 브라우저 기반 interaction test 실행 환경 구성
  • Storybook test : play() 기반 사용자 인터랙션 및 접근성 검사 실행

특히 Storybook의 play() 기반 interaction test는 정적 분석나 Axe만으로는 놓치기 쉬운 결함을 잡는 데 유용합니다.

Storybook: Frontend workshop for UI development

Storybook is a frontend workshop for building UI components and pages in isolation. Thousands of teams use it for UI development, testing, and documentation. It's open source and free.

storybook.js.org

여기서 놓치기 쉬운 결함을 예로 들면 다음과 같습니다.

  • 모달 포커스 트랩 부재
  • ESC 키로 모달을 닫지 못하는 문제
  • 로딩 상태에서 버튼의 접근 가능한 이름이 사라지는 문제
  • 클릭 핸들러가 의도한 횟수만큼 호출되지 않는 문제
  • 키보드 TAB 이동 순서 문제

병렬 실행

앞서 언급한 2가지 job, ci와 storybook 사이에는 needs가 없습니다. 즉, 병렬 실행입니다.

yaml
storybook:
  name: Storybook build · test
  runs-on: ubuntu-latest
  timeout-minutes: 15
  # needs: ci

병렬 실행을 하는 이유는 하나의 PR에서 실패 항목을 한 번에 확인하기 위해서입니다.
이렇게 하면 피드백의 밀도를 높일 수 있고, 전체 개발 주기의 병목을 줄여 배포 속도를 개선할 수 있습니다.
실패한 테스트를 수정하기 위해 ci 결과를 여러 번 기다릴 필요가 없기 때문입니다.

반대로 needs: ci로 순차 실행을 하면 의존성을 부여할 수 있습니다.

이 경우의 흐름은 다음과 같습니다.

  1. ci job 성공 → storybook job 실행
  2. ci job 실패 → storybook job 실행 안 함 + Playwright 설치 및 Storybook 빌드 시간 절약

이 방식의 단점은, green CI(✅)의 전체 완료 시간이 길어집니다.

병렬 실행과 순차 실행 비교

방식 장점 단점
병렬 실행 (needs 없음) 전체 CI 시간이 짧고 실패를 한 번에 확인 앞 단계 실패에도 Storybook 실행 비용 발생
순차 실행 (needs: ci) 빨간 PR에서 Playwright·Storybook 실행 비용 절약 정상 PR의 전체 CI 시간이 길어짐

CI 결과 알림의 원리

workflow_run으로 CI 완료 감지

CI 결과 알림은 discord-pr-notification.yml에서 처리합니다.

yaml
name: PR Discord Notification

on:
  workflow_run:
    workflows: ["CI"]
    types: [completed]

concurrency:
  group: discord-${{ github.event.workflow_run.head_sha }}
  cancel-in-progress: true

permissions:
  contents: read
  pull-requests: read

jobs:
  notify:
    runs-on: ubuntu-latest
    timeout-minutes: 5
    if: >-
      github.event.workflow_run.event == 'pull_request' &&
      (github.event.workflow_run.conclusion == 'success' ||
      github.event.workflow_run.conclusion == 'failure')

workflow_run은 다른 GitHub Actions workflow가 끝났을 때 실행되는 트리거입니다.

  1. CI workflow 실행
  2. CI workflow 완료
  3. workflow_run 이벤트 실행
  4. PR Discord Notification 실행

여기서 중요한 점은 workflows: ['CI']의 CI는 반드시 ci.yml의 workflow 이름과 정확히 일치해야 합니다.
아래처럼 이름이 다르면 알림 workflow가 CI 완료를 감지하지 못합니다.

yaml
# ci.yml
name: Frontend CI

# discord-pr-notification.yml
workflows: ["CI"]
Events that trigger workflows - GitHub Docs

You can configure your workflows to run when specific activity on GitHub happens, at a scheduled time, or when an event outside of GitHub occurs.

docs.github.com

어떤 CI 결과만 알려야 할까?

알림 workflow의 if 조건은 다음 두 조건을 모두 만족해야 합니다.

  • github.event.workflow_run.event == 'pull_request'
  • github.event.workflow_run.conclusion == 'success' || github.event.workflow_run.conclusion == 'failure'

즉, PR에서 실행된 CI와 CI 결과가 success 또는 failure일 때에만 Discord 메시지를 전송합니다.

pull-requests: read 권한은 PR 제목, 작성자 리뷰어 목록 등을 GIthub API로 조회하기 위해 필요합니다.
timeout-minutes: 5는 이 job이 오래 실행될 이유가 없으므로, 예외적으로 멈췄을 때 자동 정리하기 위한 안전장치입니다.

Workflow syntax for GitHub Actions - GitHub Docs

A workflow is a configurable automated process made up of one or more jobs. You must create a YAML file to define your workflow configuration.

docs.github.com

아래의 경우들은 전부 제외하였습니다.

  • develop에 직접 push된 CI
  • main에 직접 push된 CI
  • 취소된 CI
  • skipped된 CI
  • draft PR
  • 닫힌 PR
  • 연결된 열린 PR을 찾지 못한 경우

같은 커밋의 중복 알림도 방지합니다.

yaml
concurrency:
  group: discord-${{ github.event.workflow_run.head_sha }}
  cancel-in-progress: true
  1. 같은 head SHA에서 알림 workflow가 중복 실행
  2. 이전 알림 workflow 취소
  3. 마지막 workflow만 Discord 전송

실제 알림 로직 스크립트

실제 알림은 actions/github-script 스텝 하나에서 PR 조회부터 메시지 전송까지 처리합니다.

1. Secret이 없으면 안전하게 건너뛴다

typescript
if (!process.env.DISCORD_WEBHOOK) {
  return core.warning("DISCORD_WEBHOOK_URL secret 미설정 → 알림 스킵");
}

secret이 아직 등록되지 않은 상태에서도 CI 전체가 불필요하게 실패하지 않도록 방어합니다.

2. 연결된 PR을 찾는다

typescript
const run = context.payload.workflow_run;
const { owner, repo } = context.repo;

let ref = run.pull_requests || [];

if (!ref) {
  const { data } = await github.rest.repos.listPullRequestsAssociatedWithCommit({
    owner,
    repo,
    commit_sha: run.head_sha,
  });

  ref = data.find((p) => p.state === "open");
}

if (!ref) {
  return core.info("연결된 열린 PR 없음");
}

먼저 workflow_run.pull_requests에서 PR 정보를 찾습니다.

다만 Fork PR 등 일부 상황에서는 pull_requests 배열이 비어있을 수 있습니다. 이때 CI가 실행된 커밋 SHA와 연결된 열린 PR을 GIthub API로 다시 찾는 fallback을 둡니다.

그래도 PR이 없으면 알림을 스킵합니다.

3. 닫힌 PR과 Draft PR을 제외한다.

typescript
const { data: pr } = await github.rest.pulls.get({
  owner,
  repo,
  pull_number: ref.number,
});

if (pr.state !== "open" || pr.draft) {
  return core.info("닫힘/draft PR → 스킵");
}

Draft PR은 아직 리뷰 요청 전의 작업 중 상태입니다.
따라서 Draft PR에 아래와 같은 메시지를 보내지 않도록 제외합니다.

✅ CI 통과 — 리뷰 부탁드립니다

Actions 탭에서 `CI` 실행이 끝난 직후 `PR Discord Notification`이 이어서 실행되는 모습

Actions 탭에서 CI 실행이 끝난 직후 PR Discord Notification이 이어서 실행되는 모습


작성자와 리뷰어 멘션

Github 아이디를 Discord 멘션으로 바꾸기 위해 Repository Variable DISCORD_USER_MAP을 사용합니다.

javascript
let map = {};

try {
  map = JSON.parse(process.env.DISCORD_USER_MAP || "{}");
} catch {
  core.warning("DISCORD_USER_MAP JSON 파싱 실패");
}

const m = (login) => (map[login] ? `<@${map[login]}>` : `\`${login}\``);

예를 들어 Variable 값은 다음처럼 저장합니다.

json
{
  "seongmin36": "201312188466593805",
  "dew2314": "479166893941325844"
}

변환 결과는 seongmin36 → <@201312188466593805>가 되어 Discord에 실제 사용자를 멘션합니다.
이 값은 Discord Webhook URL처럼 채널 전송 권한을 직접 가진 값이 아닙니다.
따라서 DISCORD_WEBHOOK_URL은 Secret으로 저장하고, GitHub 아이디와 Discord 사용자 ID의 매핑은 Repository Variable로 관리합니다.

Store information in variables - GitHub Docs

GitHub sets default variables for each GitHub Actions workflow run. You can also set custom variables for use in a single workflow or multiple workflows.

docs.github.com

매핑이 없는 GitHub 아이디는 Discord 멘션 대신 코드 텍스트로 표시됩니다. (작성자 unknown-user)

리뷰어는 개인 사용자와 팀 모두 올 수 있으므로 두 경우를 함께 처리합니다.

javascript
const reviewers = [...pr.requested_reviewers.map((r) => m(r.login)), ...pr.requested_teams.map((t) => `@${t.slug}`)].join(", ") || "미배정";

개인 리뷰어는 Discord ‘사용자 멘션’을, 팀 리뷰어는 Github ‘팀 slug’를 @team-name 형태로 표시하고, 리뷰어 설정이 안되어있는 경우에는 ‘미배정’처리를 합니다.


성공과 실패 메시지를 조합한다.

javascript
const ok = run.conclusion === "success";

const content = ok
  ? ["✅ **CI 통과 — 리뷰 부탁드립니다**", `📌 ${pr.title}`, `🔗 <${pr.html_url}>`, `👤 작성자 ${m(pr.user.login)}`, `👁️ 리뷰어 ${reviewers}`].join("\n")
  : ["❌ **CI 실패 — 확인 필요**", `📌 ${pr.title}`, `🔗 <${pr.html_url}>`, `👤 작성자 ${m(pr.user.login)}`, `🪵 로그 <${run.html_url}>`].join("\n");

CI 성공 시 Discord 메시지 예시는 다음과 같습니다.

CI 실패 시에는 로그 링크를 함께 전송합니다.

실패 메시지에 사용하는 run.html_url은 해당 GitHub Actions 실행 페이지입니다.
Discord에서 링크를 클릭하면 실패한 CI 로그로 바로 이동할 수 있습니다.


PR 협업 Webhook과 CI Bot Webhook 비교 표

구분 PR 협업 Webhook CI Bot Webhook
Discord 채널 #프론트-github-webhook #프론트-github-ci-bot
호출 주체 GitHub Repository Webhook GitHub Actions
주요 이벤트 PR 생성, 리뷰, 댓글, 승인, 변경 요청 CI 전체 성공 또는 실패
URL 형식 .../webhooks/.../github .../webhooks/...
/github 필요 여부 필요 필요 없음
메시지 형식 Discord가 GitHub payload 변환 workflow 코드가 Discord JSON을 직접 생성
설정 위치 GitHub Repository Settings → Webhooks GitHub Settings → Secrets and variables → Actions

실제 PR로 검증하기

workflow_run은 설정 PR을 먼저 병합한 뒤 검증한다

workflow_run은 CI가 끝난 뒤 실행되는 후속 workflow입니다.
따라서 CI를 감지하는 discord-pr-notification.yml 파일이 기본 브랜치에 존재하지 않으면, 설정 파일을 처음 추가한 PR에서 후속 알림을 안정적으로 검증하기 어렵습니다.

가장 확실한 검증 순서는 다음과 같습니다.

  1. 설정 PR 생성
    • ci.yml
    • discord-pr-notification.yml
    • Discord Secret / Variable 설정
  2. 설정 PR을 기본 브랜치에 병합
    • main 또는 팀의 기본 브랜치
  3. 새 테스트 브랜치 생성 후 PR 열기
    • pull_request 이벤트로 CI 실행
  4. CI 완료 확인
    • ci job 완료
    • storybook job 완료
    • workflow 전체 conclusion 결정
  5. PR Discord Notification 실행 확인
    • workflow_run: completed 감지
  6. #프론트-github-ci-bot 알림 확인
    • 성공 메시지
    • 또는 실패 메시지와 로그 링크

확인 포인트는 두 가지입니다.

  • workflows: ['CI']의 이름이 실제 CI workflow의 name: CI와 정확히 일치하는가
  • discord-pr-notification.yml이 기본 브랜치에 병합된 뒤 생성한 새 PR에서 후속 workflow가 실행되는가

성공과 실패를 모두 검증한다

성공 메시지만 확인하면 실패 처리와 로그 링크가 정상인지 알 수 없습니다.
따라서 테스트 PR에서 의도적으로 CI를 한 번 실패시킵니다.

예를 들어 typecheck script를 잠시 실패하게 바꿀 수 있습니다.

json
{
  "scripts": {
    "typecheck": "exit 1"
  }
}

변경 후 push합니다.

bash
git add package.json
git commit -m "test: verify CI failure notification"
git push

확인할 항목의 절차는 다음과 같습니다.

“CI 실패 → PR Discord Notification 실행 → #프론트-github-ci-bot 실패 메시지 도착 → GitHub Actions 로그 링크 정상 이동”

테스트가 끝나면 임시 실패 코드를 반드시 되돌립니다.

bash
git restore package.json

git add package.json
git commit -m "chore: remove CI notification test"
git push

마치며

이 구성에서는 PR 협업 이벤트와 CI 결과를 같은 방식으로 처리하지 않았습니다.
현재 Repository Webhook은 Pull requests 이벤트만 구독합니다.
따라서 PR 승인, 변경 요청, 코드 리뷰 댓글, 일반 PR 댓글, push 알림은 Discord로 보내지 않습니다.

반면 CI 알림은 각 job의 완료 시점이 아니라 CI workflow 전체가 끝난 시점에 한 번만 전송합니다.

이 구조를 통해 다음을 얻었습니다.

  • PR 단위 상태 변화와 자동 검증 결과를 서로 다른 채널에서 확인할 수 있습니다.
  • Pushes, Check runs, Workflow jobs처럼 메시지를 과도하게 만들 수 있는 이벤트를 Discord 채널에서 제외할 수 있습니다.
  • CI의 여러 job 결과를 개별적으로 알리는 대신, 최종 성공 또는 실패만 한 번 전달할 수 있습니다.
  • CI 실패 시 Discord 메시지에서 GitHub Actions 로그로 바로 이동할 수 있습니다.
  • Secret 미설정, 연결된 PR 없음, Draft PR, 닫힌 PR, Webhook 전송 실패 같은 예외를 workflow 안에서 방어할 수 있습니다.

결국 Webhook과 Actions의 선택 기준은 단순합니다.

상황 선택
GitHub에서 발생한 PR 상태 변화를 거의 그대로 전달하고 싶을 때 GitHub Repository Webhook
여러 CI job의 결과를 모아 조건에 따라 하나의 메시지로 만들고 싶을 때 GitHub Actions
Discord 메시지 형식, 멘션, PR 정보, 실패 로그 링크를 직접 제어해야 할 때 GitHub Actions

Webhook은 이벤트를 빠르게 전달하는 데 적합하고, Actions는 완료 조건을 판단하고 메시지를 가공하는 데 적합했습니다.