Skip to content

Commit ce13667

Browse files
authored
Merge pull request #1902 from chainapsis/roy/keplr-2050
[🎨 Design System] Slack notification on DS changes
2 parents f805652 + a78bf1c commit ce13667

1 file changed

Lines changed: 238 additions & 0 deletions

File tree

Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
# Design System 변경 시 Slack 알림을 보내는 워크플로우
2+
#
3+
# 흐름:
4+
# 1. develop push 시 packages/design-system/ 하위 파일 변경 감지
5+
# 2. 변경된 컴포넌트/foundation 이름 추출 (kebab-case → DSPascalCase)
6+
# 3. Claude API로 diff 요약 생성
7+
# 4. Slack Block Kit 형식으로 알림 전송
8+
#
9+
# Slack 메시지 예시:
10+
# [Extension DS] DSColor, DSTypography 업데이트
11+
# 🔧 *DSColor*: dark/light 테마 토큰 값 변경
12+
# 📖 Storybook | #1901
13+
name: Design System Change Notification
14+
15+
on:
16+
push:
17+
branches:
18+
- develop
19+
paths:
20+
- "packages/design-system/src/**"
21+
workflow_dispatch:
22+
23+
jobs:
24+
notify:
25+
name: Notify Slack on Design System changes
26+
runs-on: ubuntu-24.04
27+
timeout-minutes: 5
28+
permissions:
29+
contents: read
30+
steps:
31+
- uses: actions/checkout@v4
32+
with:
33+
fetch-depth: 0
34+
35+
# Step 1: 변경된 컴포넌트 이름 추출
36+
- name: Extract component info
37+
id: components
38+
run: |
39+
BASE_SHA=${{ github.event.before }}
40+
HEAD_SHA=${{ github.sha }}
41+
STORYBOOK_BASE="https://chainapsis.github.io/keplr-wallet/storybook/?path="
42+
43+
# 변경된 디렉토리 목록 (foundation/color, foundation/typography 등)
44+
# sed 구분자와 alternation | 충돌 방지를 위해 카테고리별 별도 패턴 사용
45+
CHANGED_DIRS=$(git diff --name-only $BASE_SHA...$HEAD_SHA -- 'packages/design-system/src/' \
46+
| grep -E '(components|foundation|theme)/' \
47+
| sed -E 's|.*/components/([^/]+)/.*|components/\1|; s|.*/foundation/([^/]+)/.*|foundation/\1|; s|.*/theme/([^/]+)/.*|theme/\1|; s|.*/theme/[^/]+$|theme|' \
48+
| sort -u)
49+
50+
# DSPascalCase 이름 목록 (kebab-case → DSPascalCase)
51+
COMPONENTS=$(echo "$CHANGED_DIRS" \
52+
| while read dir_path; do
53+
echo "$dir_path" | sed -E 's|.*/||' | sed -E 's/-(.)/\U\1/g; s/^(.)/DS\U\1/'
54+
done \
55+
| paste -sd ',' - | sed 's/,/, /g')
56+
echo "names=${COMPONENTS:-Unknown}" >> $GITHUB_OUTPUT
57+
58+
# DSName|storybook_url 매핑 파일 생성
59+
if [ -z "$CHANGED_DIRS" ]; then
60+
> /tmp/component_urls.txt
61+
else
62+
echo "$CHANGED_DIRS" | while read dir_path; do
63+
category=$(echo "$dir_path" | cut -d/ -f1)
64+
dir_name=$(echo "$dir_path" | cut -d/ -f2)
65+
ds_name=$(echo "$dir_name" | sed -E 's/-(.)/\U\1/g; s/^(.)/DS\U\1/')
66+
# Storybook URL: /story/foundations-color--color
67+
# category 매핑: foundation → foundations, components → components, theme → foundations
68+
case "$category" in
69+
foundation) sb_category="foundations" ;;
70+
theme) sb_category="foundations" ;;
71+
*) sb_category="$category" ;;
72+
esac
73+
sb_name="${dir_name:-theme}"
74+
echo "${ds_name}|${STORYBOOK_BASE}/story/${sb_category}-${sb_name}--${sb_name}"
75+
done > /tmp/component_urls.txt
76+
fi
77+
78+
# 신규 컴포넌트: 디렉토리 자체가 BASE_SHA에 없었던 경우만
79+
NEW_COMPONENTS=$(git diff --name-status $BASE_SHA...$HEAD_SHA -- 'packages/design-system/src/' \
80+
| grep '^A' \
81+
| grep -E '(components|foundation|theme)/[^/]+/' \
82+
| sed -E 's|.*/components/([^/]+)/.*|components/\1|; s|.*/foundation/([^/]+)/.*|foundation/\1|; s|.*/theme/([^/]+)/.*|theme/\1|' \
83+
| sort -u \
84+
| while read dir_path; do
85+
if ! git ls-tree -r "$BASE_SHA" -- "packages/design-system/src/${dir_path}/" 2>/dev/null | grep -q .; then
86+
echo "$dir_path" | sed -E 's|.*/||' | sed -E 's/-(.)/\U\1/g; s/^(.)/DS\U\1/'
87+
fi
88+
done \
89+
| paste -sd ',' - | sed 's/,/, /g')
90+
echo "new_components=${NEW_COMPONENTS}" >> $GITHUB_OUTPUT
91+
92+
echo "storybook_link=https://chainapsis.github.io/keplr-wallet/storybook/" >> $GITHUB_OUTPUT
93+
94+
# Step 2: Claude API로 diff 요약 생성
95+
- name: Summarize changes with Claude
96+
id: summary
97+
run: |
98+
BASE_SHA=${{ github.event.before }}
99+
HEAD_SHA=${{ github.sha }}
100+
101+
git diff $BASE_SHA...$HEAD_SHA -- 'packages/design-system/src/' | head -500 > /tmp/diff.txt
102+
103+
DIFF_CONTENT=$(cat /tmp/diff.txt)
104+
105+
PROMPT="아래 diff를 분석해서 컴포넌트별 변경사항을 요약해줘.
106+
107+
변경된 컴포넌트: ${{ steps.components.outputs.names }}
108+
이 중 새로 추가된 컴포넌트: ${{ steps.components.outputs.new_components }}
109+
110+
규칙:
111+
- 새 컴포넌트는 🆕, 수정된 컴포넌트는 🔧로 시작
112+
- 컴포넌트명은 *bold*, 콜론 뒤에 한줄 설명
113+
- 주요 props는 들여쓰기 후 • 로 나열 (prop명: 설명)
114+
- 반드시 diff의 실제 변경 내용만 사용할 것
115+
- 서론/결론 없이 컴포넌트별 요약만 출력
116+
117+
형식 참고용 예시 (이 내용을 그대로 쓰지 말 것):
118+
🆕 *DSBadge*: 뱃지 컴포넌트 추가
119+
• variant: solid, outline 등 스타일 선택
120+
🔧 *DSColor*: dark 테마 토큰 값 변경
121+
• fill.neutral.high: gray10 → gray200으로 변경"
122+
123+
jq -n --arg prompt "$PROMPT" --arg diff "$DIFF_CONTENT" '{
124+
"model": "claude-haiku-4-5",
125+
"max_tokens": 600,
126+
"messages": [{
127+
"role": "user",
128+
"content": ($prompt + "\n\ndiff:\n" + $diff)
129+
}]
130+
}' > /tmp/payload.json
131+
132+
RESPONSE=$(curl -s "https://api.anthropic.com/v1/messages" \
133+
-H "Content-Type: application/json" \
134+
-H "x-api-key: $ANTHROPIC_API_KEY" \
135+
-H "anthropic-version: 2023-06-01" \
136+
-d @/tmp/payload.json)
137+
138+
echo "Claude API Response: $RESPONSE"
139+
140+
ERROR_TYPE=$(echo "$RESPONSE" | jq -r '.error.type // empty')
141+
if [ -n "$ERROR_TYPE" ]; then
142+
ERROR_MSG=$(echo "$RESPONSE" | jq -r '.error.message // empty')
143+
echo "API Error: $ERROR_TYPE - $ERROR_MSG"
144+
SUMMARY="디자인 시스템이 업데이트되었습니다."
145+
else
146+
SUMMARY=$(echo "$RESPONSE" | jq -r '.content[0].text // "디자인 시스템이 업데이트되었습니다."' \
147+
| tr -d '`' \
148+
| sed 's/\*\*/*/g' \
149+
| grep -E '^(🆕|🔧| +•)' \
150+
)
151+
fi
152+
echo "text<<EOF" >> $GITHUB_OUTPUT
153+
echo "$SUMMARY" >> $GITHUB_OUTPUT
154+
echo "EOF" >> $GITHUB_OUTPUT
155+
env:
156+
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY_FOR_DS }}
157+
158+
# Step 3: Slack Block Kit 형식으로 알림 전송
159+
- name: Send Slack notification
160+
run: |
161+
NEW_COMPONENTS="${{ steps.components.outputs.new_components }}"
162+
ALL_COMPONENTS="${{ steps.components.outputs.names }}"
163+
SUMMARY="${{ steps.summary.outputs.text }}"
164+
STORYBOOK_LINK="${{ steps.components.outputs.storybook_link }}"
165+
166+
# 헤더: 추가/업데이트 구분
167+
if [ -n "$NEW_COMPONENTS" ]; then
168+
UPDATED_COMPONENTS=$(comm -23 \
169+
<(echo "$ALL_COMPONENTS" | tr ',' '\n' | sed 's/^ //' | sort) \
170+
<(echo "$NEW_COMPONENTS" | tr ',' '\n' | sed 's/^ //' | sort) \
171+
| paste -sd ',' - | sed 's/,/, /g')
172+
173+
if [ -n "$UPDATED_COMPONENTS" ]; then
174+
HEADER="[Extension DS] ${NEW_COMPONENTS} 추가 · ${UPDATED_COMPONENTS} 업데이트"
175+
else
176+
HEADER="[Extension DS] ${NEW_COMPONENTS} 추가"
177+
fi
178+
else
179+
HEADER="[Extension DS] ${ALL_COMPONENTS} 업데이트"
180+
fi
181+
182+
# 컴포넌트명에 Storybook 링크 삽입: *DSXxx* → *<url|DSXxx>*
183+
while IFS='|' read -r ds_name url; do
184+
SUMMARY=$(echo "$SUMMARY" | sed "s@\\*${ds_name}\\*@*<${url}|${ds_name}>*@g")
185+
done < /tmp/component_urls.txt
186+
187+
MSG="$SUMMARY"
188+
189+
PR_NUMBER=$(echo "$COMMIT_MSG" | grep -oP '#\K\d+' | head -1)
190+
191+
if [ -n "$PR_NUMBER" ]; then
192+
PR_LINK="<https://github.com/${GITHUB_REPOSITORY}/pull/${PR_NUMBER}|#${PR_NUMBER}>"
193+
else
194+
COMMIT_SHORT_SHA=$(echo "$GITHUB_SHA" | cut -c1-7)
195+
PR_LINK="<${COMMIT_URL}|${COMMIT_SHORT_SHA}>"
196+
fi
197+
198+
jq -n \
199+
--arg header "$HEADER" \
200+
--arg content "$MSG" \
201+
--arg storybook_link "<${STORYBOOK_LINK}|📖 Storybook>" \
202+
--arg pr_link "$PR_LINK" \
203+
'{
204+
"blocks": [
205+
{
206+
"type": "header",
207+
"text": {
208+
"type": "plain_text",
209+
"text": $header
210+
}
211+
},
212+
{
213+
"type": "section",
214+
"text": {
215+
"type": "mrkdwn",
216+
"text": $content
217+
}
218+
},
219+
{
220+
"type": "context",
221+
"elements": [
222+
{
223+
"type": "mrkdwn",
224+
"text": ($storybook_link + " | " + $pr_link)
225+
}
226+
]
227+
}
228+
]
229+
}' > /tmp/slack_payload.json
230+
231+
curl -X POST \
232+
-H "Content-Type: application/json" \
233+
-d @/tmp/slack_payload.json \
234+
"$SLACK_WEBHOOK_URL"
235+
env:
236+
SLACK_WEBHOOK_URL: ${{ secrets.DS_NOTIFICATION_SLACK_WEBHOOK_URL }}
237+
COMMIT_MSG: ${{ github.event.head_commit.message }}
238+
COMMIT_URL: ${{ github.event.head_commit.url }}

0 commit comments

Comments
 (0)