Skip to content

Commit 91d8520

Browse files
authored
Merge pull request #10 from CaQuick/ci/discord-notify
ci: Discord 알림 GitHub Action 추가
2 parents a3566e9 + ca5e785 commit 91d8520

File tree

4 files changed

+578
-0
lines changed

4 files changed

+578
-0
lines changed
Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
import assert from 'node:assert/strict';
2+
import test from 'node:test';
3+
4+
import {
5+
resolveEventType,
6+
buildEmbed,
7+
buildPrMergedEmbed,
8+
buildBranchCreatedEmbed,
9+
buildBranchPushEmbed,
10+
buildIssueOpenedEmbed,
11+
buildWebhookBody,
12+
} from '../discord-notify-lib.mjs';
13+
14+
const META = { repository: 'CaQuick/caquick-be', serverUrl: 'https://github.com' };
15+
16+
// ── resolveEventType ──
17+
18+
test('pull_request closed + merged=true → pr_merged', () => {
19+
const payload = { pull_request: { merged: true } };
20+
assert.equal(resolveEventType('pull_request', payload), 'pr_merged');
21+
});
22+
23+
test('pull_request closed + merged=false → null', () => {
24+
const payload = { pull_request: { merged: false } };
25+
assert.equal(resolveEventType('pull_request', payload), null);
26+
});
27+
28+
test('create + ref_type=branch → branch_created', () => {
29+
const payload = { ref_type: 'branch' };
30+
assert.equal(resolveEventType('create', payload), 'branch_created');
31+
});
32+
33+
test('create + ref_type=tag → null', () => {
34+
const payload = { ref_type: 'tag' };
35+
assert.equal(resolveEventType('create', payload), null);
36+
});
37+
38+
test('push → branch_push', () => {
39+
assert.equal(resolveEventType('push', {}), 'branch_push');
40+
});
41+
42+
test('issues + action=opened → issue_opened', () => {
43+
const payload = { action: 'opened' };
44+
assert.equal(resolveEventType('issues', payload), 'issue_opened');
45+
});
46+
47+
test('issues + action=closed → null', () => {
48+
const payload = { action: 'closed' };
49+
assert.equal(resolveEventType('issues', payload), null);
50+
});
51+
52+
test('unknown event → null', () => {
53+
assert.equal(resolveEventType('deployment', {}), null);
54+
});
55+
56+
// ── buildPrMergedEmbed ──
57+
58+
test('PR 머지 Embed가 올바른 색상과 필드를 갖는다', () => {
59+
const payload = {
60+
pull_request: {
61+
number: 42,
62+
title: 'feat: 로그인 기능 추가',
63+
user: { login: 'chado' },
64+
head: { ref: 'feature/login' },
65+
base: { ref: 'main' },
66+
html_url: 'https://github.com/CaQuick/caquick-be/pull/42',
67+
},
68+
};
69+
70+
const embed = buildPrMergedEmbed(payload, META);
71+
72+
assert.equal(embed.title, '🔀 PR #42 Merged');
73+
assert.equal(embed.description, 'feat: 로그인 기능 추가');
74+
assert.equal(embed.color, 0x6f42c1);
75+
assert.equal(embed.url, 'https://github.com/CaQuick/caquick-be/pull/42');
76+
assert.equal(embed.fields.length, 3);
77+
assert.equal(embed.fields[0].value, '[CaQuick/caquick-be](https://github.com/CaQuick/caquick-be)');
78+
assert.equal(embed.fields[1].value, '[@chado](https://github.com/chado)');
79+
assert.equal(embed.fields[2].value, '`feature/login` → `main`');
80+
});
81+
82+
// ── buildBranchCreatedEmbed ──
83+
84+
test('브랜치 생성 Embed가 올바른 색상과 필드를 갖는다', () => {
85+
const payload = {
86+
ref: 'feature/discord-notify',
87+
ref_type: 'branch',
88+
sender: { login: 'chado' },
89+
};
90+
91+
const embed = buildBranchCreatedEmbed(payload, META);
92+
93+
assert.equal(embed.title, '🌿 New Branch Created');
94+
assert.equal(embed.description, '`feature/discord-notify`');
95+
assert.equal(embed.color, 0x28a745);
96+
assert.ok(embed.url.includes('feature/discord-notify'));
97+
assert.equal(embed.fields.length, 2);
98+
});
99+
100+
// ── buildBranchPushEmbed ──
101+
102+
test('브랜치 푸시 Embed가 올바른 색상과 커밋 목록을 갖는다', () => {
103+
const payload = {
104+
ref: 'refs/heads/feature/discord-notify',
105+
sender: { login: 'chado' },
106+
compare: 'https://github.com/CaQuick/caquick-be/compare/abc...def',
107+
commits: [
108+
{ id: 'abc1234567890', message: 'feat: 웹훅 스크립트 추가' },
109+
{ id: 'def5678901234', message: 'test: 테스트 추가' },
110+
{ id: 'ghi9012345678', message: 'fix: 오타 수정' },
111+
],
112+
};
113+
114+
const embed = buildBranchPushEmbed(payload, META);
115+
116+
assert.equal(embed.title, '📦 Push to feature/discord-notify');
117+
assert.equal(embed.description, '3 commit(s) pushed');
118+
assert.equal(embed.color, 0x0366d6);
119+
assert.equal(embed.fields.length, 3); // Repository, Author, Commits
120+
121+
const commitsField = embed.fields[2];
122+
assert.equal(commitsField.name, 'Commits');
123+
assert.ok(commitsField.value.includes('[`abc1234`]'));
124+
assert.ok(commitsField.value.includes('/commit/abc1234567890'));
125+
assert.ok(commitsField.value.includes('웹훅 스크립트 추가'));
126+
});
127+
128+
test('커밋이 5개를 초과하면 나머지는 요약된다', () => {
129+
const commits = Array.from({ length: 7 }, (_, i) => ({
130+
id: `sha${i}0000000000`,
131+
message: `commit ${i}`,
132+
}));
133+
134+
const payload = {
135+
ref: 'refs/heads/main',
136+
sender: { login: 'chado' },
137+
commits,
138+
};
139+
140+
const embed = buildBranchPushEmbed(payload, META);
141+
const commitsField = embed.fields.find((f) => f.name === 'Commits');
142+
143+
assert.ok(commitsField.value.includes('... and 2 more'));
144+
});
145+
146+
test('커밋이 없는 push도 정상 처리된다', () => {
147+
const payload = {
148+
ref: 'refs/heads/main',
149+
sender: { login: 'chado' },
150+
commits: [],
151+
};
152+
153+
const embed = buildBranchPushEmbed(payload, META);
154+
155+
assert.equal(embed.description, '0 commit(s) pushed');
156+
assert.equal(embed.fields.length, 2); // Commits 필드 없음
157+
});
158+
159+
// ── buildIssueOpenedEmbed ──
160+
161+
test('이슈 생성 Embed가 올바른 색상과 필드를 갖는다', () => {
162+
const payload = {
163+
action: 'opened',
164+
issue: {
165+
number: 45,
166+
title: '로그인 시 세션 만료 처리 안 됨',
167+
user: { login: 'chado' },
168+
html_url: 'https://github.com/CaQuick/caquick-be/issues/45',
169+
labels: [{ name: 'bug' }, { name: 'auth' }],
170+
},
171+
};
172+
173+
const embed = buildIssueOpenedEmbed(payload, META);
174+
175+
assert.equal(embed.title, '📋 New Issue #45');
176+
assert.equal(embed.description, '로그인 시 세션 만료 처리 안 됨');
177+
assert.equal(embed.color, 0xd73a49);
178+
assert.equal(embed.fields.length, 3); // Repository, Author, Labels
179+
180+
const labelsField = embed.fields[2];
181+
assert.equal(labelsField.name, 'Labels');
182+
assert.equal(labelsField.value, 'bug, auth');
183+
});
184+
185+
test('라벨이 없는 이슈는 Labels 필드가 없다', () => {
186+
const payload = {
187+
action: 'opened',
188+
issue: {
189+
number: 46,
190+
title: '기능 요청',
191+
user: { login: 'chado' },
192+
html_url: 'https://github.com/CaQuick/caquick-be/issues/46',
193+
labels: [],
194+
},
195+
};
196+
197+
const embed = buildIssueOpenedEmbed(payload, META);
198+
199+
assert.equal(embed.fields.length, 2); // Labels 필드 없음
200+
});
201+
202+
// ── buildEmbed ──
203+
204+
test('buildEmbed가 이벤트 타입에 따라 올바른 빌더를 호출한다', () => {
205+
const prPayload = {
206+
pull_request: {
207+
number: 1,
208+
title: 'test',
209+
user: { login: 'user' },
210+
head: { ref: 'a' },
211+
base: { ref: 'b' },
212+
},
213+
};
214+
215+
const embed = buildEmbed('pr_merged', prPayload, META);
216+
assert.equal(embed.color, 0x6f42c1);
217+
});
218+
219+
test('buildEmbed에 알 수 없는 이벤트 타입을 전달하면 에러가 발생한다', () => {
220+
assert.throws(() => buildEmbed('unknown', {}, META), /Unknown event type/);
221+
});
222+
223+
// ── buildWebhookBody ──
224+
225+
test('buildWebhookBody가 embed를 embeds 배열로 감싼다', () => {
226+
const embed = { title: 'test', color: 0x000000 };
227+
const body = buildWebhookBody(embed);
228+
229+
assert.deepEqual(body, { embeds: [{ title: 'test', color: 0x000000 }] });
230+
});

0 commit comments

Comments
 (0)