actually need to test no diff detected case #4
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Weekly API Diff | |
| on: | |
| push: | |
| branches: [tsdiff_script] # temporary: remove before merging to main | |
| schedule: | |
| - cron: '0 17 * * 1' # Monday 9am PST / 10am PDT (GH Actions cron is UTC) | |
| workflow_dispatch: # manual trigger for testing | |
| jobs: | |
| weekly-api-diff: | |
| runs-on: ubuntu-latest | |
| env: | |
| SNAPSHOTS_REPO: LFDanLu/react-spectrum-api-snapshots | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 # required for build:api-published to find the last Publish commit | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: '24' | |
| cache: 'yarn' | |
| - run: yarn --immutable | |
| # Build current main API (~20 min, always fresh) | |
| - name: Build current API snapshot | |
| run: yarn build:api-branch | |
| # Build release baseline using the last Publish commit (~20 min, always fresh) | |
| - name: Build release baseline | |
| run: yarn build:api-published | |
| - name: Generate diff | |
| run: yarn compare:apis --isCI > /tmp/diff-current.txt 2>&1 || true | |
| # Check out snapshots repo so we can read the previous diff and commit the new one | |
| - uses: actions/checkout@v4 | |
| with: | |
| repository: ${{ env.SNAPSHOTS_REPO }} | |
| path: snapshots | |
| token: ${{ secrets.SNAPSHOTS_REPO_TOKEN }} | |
| # Compute week-to-week delta and commit new diff | |
| - name: Save diff and compute delta | |
| run: | | |
| TODAY=$(date +%Y-%m-%d) | |
| echo "TODAY=$TODAY" >> $GITHUB_ENV | |
| cp /tmp/diff-current.txt snapshots/diffs/$TODAY.txt | |
| PREV=$(ls -t snapshots/diffs/*.txt 2>/dev/null | sed -n '2p') | |
| if [ -n "$PREV" ]; then | |
| diff "$PREV" snapshots/diffs/$TODAY.txt > /tmp/weekly-delta.txt || true | |
| else | |
| echo "(first run — no previous diff to compare against)" > /tmp/weekly-delta.txt | |
| fi | |
| if [ -s /tmp/diff-current.txt ]; then | |
| cd snapshots | |
| git config user.email "github-actions@github.com" | |
| git config user.name "GitHub Actions" | |
| git add diffs/$TODAY.txt | |
| git commit -m "weekly api diff $TODAY" | |
| git push | |
| fi | |
| # Summarize with GitHub Models (free via GITHUB_TOKEN) and post to Slack | |
| - name: Summarize and post to Slack | |
| env: | |
| SLACK_TSDIFF_CHROMATIC_BOT_TOKEN: ${{ secrets.SLACK_TSDIFF_CHROMATIC_BOT_TOKEN }} | |
| SLACK_CHANNEL_ID: ${{ secrets.TEST_SLACK_ID }} | |
| GITHUB_TOKEN: ${{ github.token }} | |
| run: | | |
| python3 << 'PYEOF' | |
| import json, os, urllib.request, subprocess | |
| required = ['SLACK_TSDIFF_CHROMATIC_BOT_TOKEN', 'SLACK_CHANNEL_ID', 'GITHUB_TOKEN', 'TODAY', 'SNAPSHOTS_REPO', 'GITHUB_WORKSPACE'] | |
| missing = [k for k in required if not os.environ.get(k)] | |
| if missing: | |
| raise SystemExit(f"Missing required environment variables: {', '.join(missing)}") | |
| today = os.environ['TODAY'] | |
| channel = os.environ['SLACK_CHANNEL_ID'] | |
| snapshots_repo = os.environ['SNAPSHOTS_REPO'] | |
| slack_token = os.environ['SLACK_TSDIFF_CHROMATIC_BOT_TOKEN'] | |
| github_token = os.environ['GITHUB_TOKEN'] | |
| workspace = os.environ['GITHUB_WORKSPACE'] | |
| diff_url = f"https://github.com/{snapshots_repo}/blob/main/diffs/{today}.txt" | |
| diff_size = os.path.getsize('/tmp/diff-current.txt') | |
| if diff_size == 0: | |
| message = f"📊 Weekly API Diff — {today}\n\nNo API changes vs release baseline this week — either nothing new has landed on main yet, or all pending changes were included in a release." | |
| else: | |
| delta = open('/tmp/weekly-delta.txt').read()[:4000] | |
| # Extract classification rules from prompt.md (single source of truth) | |
| prompt_md = open(f"{workspace}/scripts/weekly-api-diff/prompt.md").read() | |
| rules_start = prompt_md.find("Apply these grouping and classification rules") | |
| rules_end = prompt_md.find("\n## Step 9", rules_start) | |
| rules = prompt_md[rules_start:rules_end].strip() if rules_start != -1 else "" | |
| payload = { | |
| "model": "gpt-4o-mini", | |
| "max_tokens": 600, | |
| "messages": [{ | |
| "role": "user", | |
| "content": f"Summarize this week-to-week react-spectrum API diff in under 200 words using bullet points.\n\n{rules}\n\nDelta (changes from last week):\n{delta}" | |
| }] | |
| } | |
| req = urllib.request.Request( | |
| 'https://models.inference.ai.azure.com/chat/completions', | |
| data=json.dumps(payload).encode(), | |
| headers={ | |
| 'Authorization': f'Bearer {github_token}', | |
| 'Content-Type': 'application/json' | |
| } | |
| ) | |
| summary = json.loads(urllib.request.urlopen(req).read())['choices'][0]['message']['content'] | |
| message = f"📊 Weekly API Diff — {today}\n\n{summary}\n\nFull diff vs release: {diff_url}\n\nReact ✅ if changes look expected, or 🚨 if something looks wrong." | |
| req = urllib.request.Request( | |
| 'https://slack.com/api/chat.postMessage', | |
| data=json.dumps({"channel": channel, "text": message}).encode(), | |
| headers={ | |
| 'Authorization': f'Bearer {slack_token}', | |
| 'Content-Type': 'application/json' | |
| } | |
| ) | |
| resp = json.loads(urllib.request.urlopen(req).read()) | |
| print("Slack response:", resp.get('ok'), resp.get('error', '')) | |
| if not resp.get('ok'): | |
| raise SystemExit(f"Slack error: {resp.get('error')}") | |
| PYEOF |