Skip to content

Commit 137968c

Browse files
committed
feat: snapi
1 parent 7d680bc commit 137968c

28 files changed

Lines changed: 6213 additions & 92 deletions
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
name: API Breakage Detection
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- 'packages/**'
7+
- 'tools/snapi/**'
8+
push:
9+
branches:
10+
- main
11+
paths:
12+
- 'packages/**'
13+
- 'tools/snapi/**'
14+
15+
concurrency:
16+
group: api-breakage-${{ github.ref }}
17+
cancel-in-progress: true
18+
19+
jobs:
20+
detect-api-changes:
21+
runs-on: ubuntu-latest
22+
permissions:
23+
contents: read
24+
pull-requests: write
25+
statuses: write
26+
27+
env:
28+
GCS_PROJECT_ID: ${{ secrets.GCS_PROJECT_ID }}
29+
GCS_BUCKET: ${{ secrets.GCS_BUCKET }}
30+
31+
steps:
32+
- name: Checkout code
33+
uses: actions/checkout@v4
34+
with:
35+
fetch-depth: 0 # Need full history
36+
37+
- name: Setup
38+
id: config
39+
uses: ./.github/actions/init-blacksmith
40+
with:
41+
turbo-signature: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }}
42+
turbo-team: ${{ vars.TURBO_TEAM }}
43+
turbo-token: ${{ secrets.TURBO_TOKEN }}
44+
45+
- name: Build packages
46+
run: pnpm build
47+
48+
- name: Build Brkr-Brkr
49+
run: pnpm turbo build --filter=@clerk/snapi
50+
51+
- name: Run API breakage detection (PR)
52+
if: github.event_name == 'pull_request'
53+
id: api-check-pr
54+
run: |
55+
# Generate current snapshots
56+
node tools/snapi/dist/cli.js snapshot --config snapi.config.json
57+
58+
# Run breaking changes detection
59+
echo "🔍 Detecting API changes..."
60+
if node tools/snapi/dist/cli.js detect --config snapi.config.json --format markdown --output api-changes-report.md; then
61+
echo "api_check_passed=true" >> $GITHUB_OUTPUT
62+
else
63+
echo "api_check_passed=false" >> $GITHUB_OUTPUT
64+
fi
65+
66+
- name: Update baseline cache (main branch)
67+
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
68+
run: |
69+
node tools/snapi/dist/cli.js snapshot --config snapi.config.json --force
70+
71+
# Store as artifacts for backup
72+
echo "COMMIT_SHA=$(git rev-parse HEAD)" >> $GITHUB_ENV
73+
74+
- name: Upload baseline snapshots (main branch)
75+
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
76+
uses: actions/upload-artifact@v4
77+
with:
78+
name: api-baseline-${{ env.COMMIT_SHA }}
79+
path: .api-snapshots/
80+
retention-days: 90
81+
82+
- name: Comment on PR
83+
if: github.event_name == 'pull_request'
84+
uses: actions/github-script@v7
85+
with:
86+
script: |
87+
const fs = require('fs');
88+
89+
// Read the generated report
90+
let reportContent = '';
91+
try {
92+
reportContent = fs.readFileSync('api-changes-report.md', 'utf8');
93+
} catch (error) {
94+
reportContent = '❌ **Error**: Could not generate API changes report.\n\n' + error.message;
95+
}
96+
97+
// Find existing comment
98+
const comments = await github.rest.issues.listComments({
99+
owner: context.repo.owner,
100+
repo: context.repo.repo,
101+
issue_number: context.issue.number
102+
});
103+
104+
const existingComment = comments.data.find(
105+
comment => comment.user.login === 'github-actions[bot]' &&
106+
comment.body.includes('API Changes Report')
107+
);
108+
109+
const commentBody = `## 🔍 API Changes Report
110+
111+
${reportContent}
112+
113+
---
114+
<sub>🤖 This comment was automatically generated by the API Breakage Detector</sub>`;
115+
116+
if (existingComment) {
117+
// Update existing comment
118+
await github.rest.issues.updateComment({
119+
owner: context.repo.owner,
120+
repo: context.repo.repo,
121+
comment_id: existingComment.id,
122+
body: commentBody
123+
});
124+
} else {
125+
// Create new comment
126+
await github.rest.issues.createComment({
127+
owner: context.repo.owner,
128+
repo: context.repo.repo,
129+
issue_number: context.issue.number,
130+
body: commentBody
131+
});
132+
}
133+
134+
- name: Set commit status
135+
if: github.event_name == 'pull_request'
136+
uses: actions/github-script@v7
137+
with:
138+
script: |
139+
const apiCheckPassed = '${{ steps.api-check-pr.outputs.api_check_passed }}' === 'true';
140+
141+
await github.rest.repos.createCommitStatus({
142+
owner: context.repo.owner,
143+
repo: context.repo.repo,
144+
sha: context.payload.pull_request.head.sha,
145+
state: apiCheckPassed ? 'success' : 'failure',
146+
target_url: `${context.payload.pull_request.html_url}/checks`,
147+
description: apiCheckPassed ?
148+
'No breaking API changes detected' :
149+
'Breaking API changes detected - review required',
150+
context: 'snapi'
151+
});
152+
153+
- name: Upload API snapshots and reports
154+
if: always()
155+
uses: actions/upload-artifact@v4
156+
with:
157+
name: api-debug-${{ github.run_id }}
158+
path: |
159+
.api-snapshots/
160+
api-changes-report.md
161+
retention-days: 7

‎.gitignore‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ testem.log
4040
/typings
4141
**/coverage/**
4242
*.tsbuildinfo
43+
.tmp
4344

4445
# System Files
4546
.DS_Store
@@ -99,3 +100,10 @@ scripts/.env
99100
# typedoc
100101
.typedoc/docs
101102
.typedoc/docs.json
103+
104+
# API Breakage Detection
105+
.api-snapshots/current/
106+
.api-snapshots/temp/
107+
.api-snapshots/.baseline-cache.json
108+
# Keep baseline snapshots in Git for CI
109+
!.api-snapshots/baseline/

‎package.json‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44
"private": true,
55
"license": "MIT",
66
"scripts": {
7+
"api:check": "pnpm --filter=snapi run build && pnpm --filter=snapi run detect",
8+
"api:init": "pnpm --filter=snapi run build && pnpm --filter=snapi run init --output snapi.config.json",
9+
"api:snapshot": "pnpm --filter=snapi run build && pnpm --filter=snapi run snapshot",
10+
"api:suppress": "pnpm --filter=snapi run build && pnpm --filter=snapi run suppress",
711
"build": "FORCE_COLOR=1 turbo build --concurrency=${TURBO_CONCURRENCY:-80%}",
812
"build:declarations": "FORCE_COLOR=1 turbo build:declarations --concurrency=${TURBO_CONCURRENCY:-80%} --filter=@clerk/nextjs --filter=@clerk/clerk-react --filter=@clerk/shared --filter=@clerk/types",
913
"bundlewatch": "turbo bundlewatch",

0 commit comments

Comments
 (0)