From ab53a99c12c176bbf034788b8616d7782e4c1760 Mon Sep 17 00:00:00 2001 From: jungcome7 Date: Mon, 30 Mar 2026 14:20:27 +0900 Subject: [PATCH 1/7] ci(design-system): add Slack notification on DS changes Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/design-system-notify.yml | 227 +++++++++++++++++++++ 1 file changed, 227 insertions(+) create mode 100644 .github/workflows/design-system-notify.yml diff --git a/.github/workflows/design-system-notify.yml b/.github/workflows/design-system-notify.yml new file mode 100644 index 0000000000..4901837f3b --- /dev/null +++ b/.github/workflows/design-system-notify.yml @@ -0,0 +1,227 @@ +# Design System 변경 시 Slack 알림을 보내는 워크플로우 +# +# 흐름: +# 1. develop push 시 packages/design-system/ 하위 파일 변경 감지 +# 2. 변경된 컴포넌트/foundation 이름 추출 (kebab-case → DSPascalCase) +# 3. Claude API로 diff 요약 생성 +# 4. Slack Block Kit 형식으로 알림 전송 +# +# Slack 메시지 예시: +# [Extension DS] DSColor, DSTypography 업데이트 +# 🔧 *DSColor*: dark/light 테마 토큰 값 변경 +# 📖 Storybook | #1901 +name: Design System Change Notification + +on: + push: + branches: + - develop + paths: + - "packages/design-system/src/**" + workflow_dispatch: + +jobs: + notify: + name: Notify Slack on Design System changes + runs-on: ubuntu-24.04 + timeout-minutes: 5 + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + # Step 1: 변경된 컴포넌트 이름 추출 + - name: Extract component info + id: components + run: | + BASE_SHA=${{ github.event.before }} + HEAD_SHA=${{ github.sha }} + STORYBOOK_BASE="https://chainapsis.github.io/keplr-wallet/storybook/?path=" + + # 변경된 디렉토리 목록 (foundation/color, foundation/typography 등) + CHANGED_DIRS=$(git diff --name-only $BASE_SHA...$HEAD_SHA -- 'packages/design-system/src/' \ + | grep -E '(components|foundation|theme)/' \ + | sed -E 's|packages/design-system/src/(components|foundation|theme)/([^/]+)/.*|\1/\2|' \ + | sort -u) + + # DSPascalCase 이름 목록 (kebab-case → DSPascalCase) + COMPONENTS=$(echo "$CHANGED_DIRS" \ + | while read dir_path; do + echo "$dir_path" | sed -E 's|.*/||' | sed -E 's/-(.)/\U\1/g; s/^(.)/DS\U\1/' + done \ + | paste -sd ',' - | sed 's/,/, /g') + echo "names=${COMPONENTS:-Unknown}" >> $GITHUB_OUTPUT + + # DSName|storybook_url 매핑 파일 생성 + if [ -z "$CHANGED_DIRS" ]; then + > /tmp/component_urls.txt + else + echo "$CHANGED_DIRS" | while read dir_path; do + category=$(echo "$dir_path" | cut -d/ -f1) + dir_name=$(echo "$dir_path" | cut -d/ -f2) + ds_name=$(echo "$dir_name" | sed -E 's/-(.)/\U\1/g; s/^(.)/DS\U\1/') + # Storybook path: foundations-color, components-button 등 + echo "${ds_name}|${STORYBOOK_BASE}${category}-${dir_name}" + done > /tmp/component_urls.txt + fi + + # 신규 컴포넌트: 디렉토리 자체가 BASE_SHA에 없었던 경우만 + NEW_COMPONENTS=$(git diff --name-status $BASE_SHA...$HEAD_SHA -- 'packages/design-system/src/' \ + | grep '^A' \ + | grep -E '(components|foundation|theme)/[^/]+/' \ + | sed -E 's|.*packages/design-system/src/(components|foundation|theme)/([^/]+)/.*|\1/\2|' \ + | sort -u \ + | while read dir_path; do + if ! git ls-tree -r "$BASE_SHA" -- "packages/design-system/src/${dir_path}/" 2>/dev/null | grep -q .; then + echo "$dir_path" | sed -E 's|.*/||' | sed -E 's/-(.)/\U\1/g; s/^(.)/DS\U\1/' + fi + done \ + | paste -sd ',' - | sed 's/,/, /g') + echo "new_components=${NEW_COMPONENTS}" >> $GITHUB_OUTPUT + + echo "storybook_link=https://chainapsis.github.io/keplr-wallet/storybook/" >> $GITHUB_OUTPUT + + # Step 2: Claude API로 diff 요약 생성 + - name: Summarize changes with Claude + id: summary + run: | + BASE_SHA=${{ github.event.before }} + HEAD_SHA=${{ github.sha }} + + git diff $BASE_SHA...$HEAD_SHA -- 'packages/design-system/src/' | head -500 > /tmp/diff.txt + + DIFF_CONTENT=$(cat /tmp/diff.txt) + + PROMPT="아래 diff를 분석해서 컴포넌트별 변경사항을 요약해줘. + + 변경된 컴포넌트: ${{ steps.components.outputs.names }} + 이 중 새로 추가된 컴포넌트: ${{ steps.components.outputs.new_components }} + + 규칙: + - 새 컴포넌트는 🆕, 수정된 컴포넌트는 🔧로 시작 + - 컴포넌트명은 *bold*, 콜론 뒤에 한줄 설명 + - 주요 props는 들여쓰기 후 • 로 나열 (prop명: 설명) + - 반드시 diff의 실제 변경 내용만 사용할 것 + - 서론/결론 없이 컴포넌트별 요약만 출력 + + 형식 참고용 예시 (이 내용을 그대로 쓰지 말 것): + 🆕 *DSBadge*: 뱃지 컴포넌트 추가 + • variant: solid, outline 등 스타일 선택 + 🔧 *DSColor*: dark 테마 토큰 값 변경 + • fill.neutral.high: gray10 → gray200으로 변경" + + jq -n --arg prompt "$PROMPT" --arg diff "$DIFF_CONTENT" '{ + "model": "claude-haiku-4-5", + "max_tokens": 600, + "messages": [{ + "role": "user", + "content": ($prompt + "\n\ndiff:\n" + $diff) + }] + }' > /tmp/payload.json + + RESPONSE=$(curl -s "https://api.anthropic.com/v1/messages" \ + -H "Content-Type: application/json" \ + -H "x-api-key: $ANTHROPIC_API_KEY" \ + -H "anthropic-version: 2023-06-01" \ + -d @/tmp/payload.json) + + echo "Claude API Response: $RESPONSE" + + ERROR_TYPE=$(echo "$RESPONSE" | jq -r '.error.type // empty') + if [ -n "$ERROR_TYPE" ]; then + ERROR_MSG=$(echo "$RESPONSE" | jq -r '.error.message // empty') + echo "API Error: $ERROR_TYPE - $ERROR_MSG" + SUMMARY="디자인 시스템이 업데이트되었습니다." + else + SUMMARY=$(echo "$RESPONSE" | jq -r '.content[0].text // "디자인 시스템이 업데이트되었습니다."' \ + | tr -d '`' \ + | sed 's/\*\*/*/g' \ + | grep -E '^(🆕|🔧| +•)' \ + ) + fi + echo "text<> $GITHUB_OUTPUT + echo "$SUMMARY" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + env: + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY_FOR_DS }} + + # Step 3: Slack Block Kit 형식으로 알림 전송 + - name: Send Slack notification + run: | + NEW_COMPONENTS="${{ steps.components.outputs.new_components }}" + ALL_COMPONENTS="${{ steps.components.outputs.names }}" + SUMMARY="${{ steps.summary.outputs.text }}" + STORYBOOK_LINK="${{ steps.components.outputs.storybook_link }}" + + # 헤더: 추가/업데이트 구분 + if [ -n "$NEW_COMPONENTS" ]; then + UPDATED_COMPONENTS=$(comm -23 \ + <(echo "$ALL_COMPONENTS" | tr ',' '\n' | sed 's/^ //' | sort) \ + <(echo "$NEW_COMPONENTS" | tr ',' '\n' | sed 's/^ //' | sort) \ + | paste -sd ',' - | sed 's/,/, /g') + + if [ -n "$UPDATED_COMPONENTS" ]; then + HEADER="[Extension DS] ${NEW_COMPONENTS} 추가 · ${UPDATED_COMPONENTS} 업데이트" + else + HEADER="[Extension DS] ${NEW_COMPONENTS} 추가" + fi + else + HEADER="[Extension DS] ${ALL_COMPONENTS} 업데이트" + fi + + # 컴포넌트명에 Storybook 링크 삽입: *DSXxx* → ** + while IFS='|' read -r ds_name url; do + SUMMARY=$(echo "$SUMMARY" | sed "s@\\*${ds_name}\\*@*<${url}|${ds_name}>*@g") + done < /tmp/component_urls.txt + + MSG="$SUMMARY" + + COMMIT_MESSAGE="${{ github.event.head_commit.message }}" + PR_NUMBER=$(echo "$COMMIT_MESSAGE" | grep -oP '#\K\d+' | head -1) + + if [ -n "$PR_NUMBER" ]; then + PR_LINK="" + else + COMMIT_SHORT_SHA=$(echo "${{ github.sha }}" | cut -c1-7) + PR_LINK="<${{ github.event.head_commit.url }}|${COMMIT_SHORT_SHA}>" + fi + + jq -n \ + --arg header "$HEADER" \ + --arg content "$MSG" \ + --arg storybook_link "<${STORYBOOK_LINK}|📖 Storybook>" \ + --arg pr_link "$PR_LINK" \ + '{ + "blocks": [ + { + "type": "header", + "text": { + "type": "plain_text", + "text": $header + } + }, + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": $content + } + }, + { + "type": "context", + "elements": [ + { + "type": "mrkdwn", + "text": ($storybook_link + " | " + $pr_link) + } + ] + } + ] + }' > /tmp/slack_payload.json + + curl -X POST \ + -H "Content-Type: application/json" \ + -d @/tmp/slack_payload.json \ + "$SLACK_WEBHOOK_URL" + env: + SLACK_WEBHOOK_URL: ${{ secrets.DS_NOTIFICATION_SLACK_WEBHOOK_URL }} From 5433d910cc969e58e1e9547701c675d7ad711e91 Mon Sep 17 00:00:00 2001 From: jungcome7 Date: Mon, 30 Mar 2026 14:49:08 +0900 Subject: [PATCH 2/7] fix(ci): fix sed delimiter conflict and theme root file handling Separate sed patterns per category to avoid | delimiter collision with alternation. Handle theme root files (e.g. theme/index.ts) that have no subdirectory. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/design-system-notify.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/design-system-notify.yml b/.github/workflows/design-system-notify.yml index 4901837f3b..fb68a382b2 100644 --- a/.github/workflows/design-system-notify.yml +++ b/.github/workflows/design-system-notify.yml @@ -39,9 +39,10 @@ jobs: STORYBOOK_BASE="https://chainapsis.github.io/keplr-wallet/storybook/?path=" # 변경된 디렉토리 목록 (foundation/color, foundation/typography 등) + # sed 구분자와 alternation | 충돌 방지를 위해 카테고리별 별도 패턴 사용 CHANGED_DIRS=$(git diff --name-only $BASE_SHA...$HEAD_SHA -- 'packages/design-system/src/' \ | grep -E '(components|foundation|theme)/' \ - | sed -E 's|packages/design-system/src/(components|foundation|theme)/([^/]+)/.*|\1/\2|' \ + | sed -E 's|.*/components/([^/]+)/.*|components/\1|; s|.*/foundation/([^/]+)/.*|foundation/\1|; s|.*/theme/([^/]+)/.*|theme/\1|; s|.*/theme/[^/]+$|theme|' \ | sort -u) # DSPascalCase 이름 목록 (kebab-case → DSPascalCase) @@ -69,7 +70,7 @@ jobs: NEW_COMPONENTS=$(git diff --name-status $BASE_SHA...$HEAD_SHA -- 'packages/design-system/src/' \ | grep '^A' \ | grep -E '(components|foundation|theme)/[^/]+/' \ - | sed -E 's|.*packages/design-system/src/(components|foundation|theme)/([^/]+)/.*|\1/\2|' \ + | sed -E 's|.*/components/([^/]+)/.*|components/\1|; s|.*/foundation/([^/]+)/.*|foundation/\1|; s|.*/theme/([^/]+)/.*|theme/\1|' \ | sort -u \ | while read dir_path; do if ! git ls-tree -r "$BASE_SHA" -- "packages/design-system/src/${dir_path}/" 2>/dev/null | grep -q .; then From 0ec99ad43469bcf8db0b841de7f6105b27373926 Mon Sep 17 00:00:00 2001 From: jungcome7 Date: Mon, 30 Mar 2026 15:11:43 +0900 Subject: [PATCH 3/7] fix(ci): fix Storybook URL mapping in DS notification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Map foundation → foundations (plural) for Storybook path - Use /docs/ path for stable component links Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/design-system-notify.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/design-system-notify.yml b/.github/workflows/design-system-notify.yml index fb68a382b2..70b2591a89 100644 --- a/.github/workflows/design-system-notify.yml +++ b/.github/workflows/design-system-notify.yml @@ -61,8 +61,15 @@ jobs: category=$(echo "$dir_path" | cut -d/ -f1) dir_name=$(echo "$dir_path" | cut -d/ -f2) ds_name=$(echo "$dir_name" | sed -E 's/-(.)/\U\1/g; s/^(.)/DS\U\1/') - # Storybook path: foundations-color, components-button 등 - echo "${ds_name}|${STORYBOOK_BASE}${category}-${dir_name}" + # Storybook URL: /story/foundations-color--color + # category 매핑: foundation → foundations, components → components, theme → foundations + case "$category" in + foundation) sb_category="foundations" ;; + theme) sb_category="foundations" ;; + *) sb_category="$category" ;; + esac + sb_name="${dir_name:-theme}" + echo "${ds_name}|${STORYBOOK_BASE}/docs/${sb_category}-${sb_name}--docs" done > /tmp/component_urls.txt fi From 4e9cf749fb1a10a1d33069753cb999f198295de4 Mon Sep 17 00:00:00 2001 From: jungcome7 Date: Mon, 30 Mar 2026 15:17:11 +0900 Subject: [PATCH 4/7] fix(ci): link to story page instead of docs in DS notification Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/design-system-notify.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/design-system-notify.yml b/.github/workflows/design-system-notify.yml index 70b2591a89..554abbdbf1 100644 --- a/.github/workflows/design-system-notify.yml +++ b/.github/workflows/design-system-notify.yml @@ -69,7 +69,7 @@ jobs: *) sb_category="$category" ;; esac sb_name="${dir_name:-theme}" - echo "${ds_name}|${STORYBOOK_BASE}/docs/${sb_category}-${sb_name}--docs" + echo "${ds_name}|${STORYBOOK_BASE}/story/${sb_category}-${sb_name}--${sb_name}" done > /tmp/component_urls.txt fi From d5311d8b7cff871ce6936618798f0cdcf30da09e Mon Sep 17 00:00:00 2001 From: jungcome7 Date: Mon, 30 Mar 2026 15:33:03 +0900 Subject: [PATCH 5/7] fix(ci): add permissions block to DS notification workflow Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/design-system-notify.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/design-system-notify.yml b/.github/workflows/design-system-notify.yml index 554abbdbf1..0632ddeb5a 100644 --- a/.github/workflows/design-system-notify.yml +++ b/.github/workflows/design-system-notify.yml @@ -25,6 +25,8 @@ jobs: name: Notify Slack on Design System changes runs-on: ubuntu-24.04 timeout-minutes: 5 + permissions: + contents: read steps: - uses: actions/checkout@v4 with: From 0591b3ccfc497de87decd9aaecbccf62b99bc649 Mon Sep 17 00:00:00 2001 From: jungcome7 Date: Mon, 30 Mar 2026 15:34:57 +0900 Subject: [PATCH 6/7] fix(ci): prevent shell injection in DS notification workflow Move head_commit.message and head_commit.url to env block to avoid direct shell interpolation of untrusted input. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/design-system-notify.yml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/workflows/design-system-notify.yml b/.github/workflows/design-system-notify.yml index 0632ddeb5a..0ca476a214 100644 --- a/.github/workflows/design-system-notify.yml +++ b/.github/workflows/design-system-notify.yml @@ -186,14 +186,13 @@ jobs: MSG="$SUMMARY" - COMMIT_MESSAGE="${{ github.event.head_commit.message }}" - PR_NUMBER=$(echo "$COMMIT_MESSAGE" | grep -oP '#\K\d+' | head -1) + PR_NUMBER=$(echo "$COMMIT_MSG" | grep -oP '#\K\d+' | head -1) if [ -n "$PR_NUMBER" ]; then - PR_LINK="" + PR_LINK="" else - COMMIT_SHORT_SHA=$(echo "${{ github.sha }}" | cut -c1-7) - PR_LINK="<${{ github.event.head_commit.url }}|${COMMIT_SHORT_SHA}>" + COMMIT_SHORT_SHA=$(echo "$GITHUB_SHA" | cut -c1-7) + PR_LINK="<${COMMIT_URL}|${COMMIT_SHORT_SHA}>" fi jq -n \ @@ -235,3 +234,7 @@ jobs: "$SLACK_WEBHOOK_URL" env: SLACK_WEBHOOK_URL: ${{ secrets.DS_NOTIFICATION_SLACK_WEBHOOK_URL }} + COMMIT_MSG: ${{ github.event.head_commit.message }} + COMMIT_URL: ${{ github.event.head_commit.url }} + GITHUB_SHA: ${{ github.sha }} + GITHUB_REPOSITORY: ${{ github.repository }} From a78bf1cb5c70db434371f4117f6c23245879811a Mon Sep 17 00:00:00 2001 From: jungcome7 Date: Mon, 30 Mar 2026 15:35:21 +0900 Subject: [PATCH 7/7] chore(ci): remove redundant env vars (GITHUB_SHA, GITHUB_REPOSITORY are built-in) Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/design-system-notify.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/design-system-notify.yml b/.github/workflows/design-system-notify.yml index 0ca476a214..4fb486e6e0 100644 --- a/.github/workflows/design-system-notify.yml +++ b/.github/workflows/design-system-notify.yml @@ -236,5 +236,3 @@ jobs: SLACK_WEBHOOK_URL: ${{ secrets.DS_NOTIFICATION_SLACK_WEBHOOK_URL }} COMMIT_MSG: ${{ github.event.head_commit.message }} COMMIT_URL: ${{ github.event.head_commit.url }} - GITHUB_SHA: ${{ github.sha }} - GITHUB_REPOSITORY: ${{ github.repository }}