Skip to content

Commit 31774de

Browse files
tychtjanclaude
andcommitted
feat: use GitHub API instead of cloning gdc-nas
- Add new API-based analyzer (gdc_nas_api_analyzer.py) - Uses gh CLI for API calls - no clone required - Requires GDC_NAS_READ_TOKEN secret with repo read access - State stored in .github/gdc-nas-last-analyzed.txt file Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 81d21c3 commit 31774de

3 files changed

Lines changed: 607 additions & 192 deletions

File tree

.github/workflows/sdk-diff-analyzer.yaml

Lines changed: 95 additions & 191 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
name: SDK Diff Analyzer
33

44
# Analyzes gdc-nas repository for REST API changes that may require SDK updates.
5+
# Uses GitHub API - no clone required.
56
# Reports are uploaded as artifacts for use by sdk-analyze and jira-sync skills.
67

78
on:
@@ -13,21 +14,20 @@ on:
1314
workflow_dispatch:
1415
inputs:
1516
commits_to_analyze:
16-
description: 'Number of commits to analyze if no state exists (default: 50)'
17+
description: 'Number of commits to analyze (default: 50)'
1718
default: '50'
18-
force_full_scan:
19-
description: 'Ignore last-analyzed state and analyze N commits from HEAD'
20-
default: 'false'
21-
type: boolean
19+
since_commit:
20+
description: 'Analyze since this commit SHA (overrides state tag)'
21+
default: ''
2222
debug:
2323
description: 'Enable verbose debug logging'
2424
default: 'true'
2525
type: boolean
2626

2727
env:
28-
# Tag in this repo that stores the last analyzed gdc-nas commit hash
29-
STATE_TAG: 'gdc-nas-analyzer/last-commit'
3028
GDC_NAS_REPO: 'gooddata/gdc-nas'
29+
# File in this repo that stores the last analyzed gdc-nas commit SHA
30+
STATE_FILE: '.github/gdc-nas-last-analyzed.txt'
3131

3232
jobs:
3333
analyze:
@@ -37,206 +37,115 @@ jobs:
3737
permissions:
3838
contents: write
3939
actions: write
40+
env:
41+
# Use PAT for gdc-nas access, falls back to GITHUB_TOKEN
42+
GH_TOKEN: ${{ secrets.GDC_NAS_READ_TOKEN || secrets.GITHUB_TOKEN }}
4043
steps:
41-
- name: Debug - Show environment
44+
- name: Debug - Environment info
4245
run: |
43-
echo "=== Environment Info ==="
46+
echo "=== Environment ==="
4447
echo "Repository: ${{ github.repository }}"
45-
echo "Ref: ${{ github.ref }}"
46-
echo "SHA: ${{ github.sha }}"
47-
echo "Actor: ${{ github.actor }}"
4848
echo "Event: ${{ github.event_name }}"
49-
echo "Runner OS: ${{ runner.os }}"
50-
echo "Working directory: $(pwd)"
49+
echo "Runner: ${{ runner.os }}"
50+
echo "GH CLI version: $(gh --version | head -1)"
5151
echo ""
5252
echo "=== Inputs ==="
5353
echo "commits_to_analyze: ${{ inputs.commits_to_analyze || '50' }}"
54-
echo "force_full_scan: ${{ inputs.force_full_scan || 'false' }}"
55-
echo "debug: ${{ inputs.debug || 'true' }}"
56-
57-
- name: Checkout SDK repository
58-
uses: actions/checkout@v4
59-
with:
60-
fetch-depth: 0 # Need full history for tag operations
54+
echo "since_commit: ${{ inputs.since_commit || '(not set)' }}"
6155
62-
- name: Debug - SDK repo info
56+
- name: Verify gdc-nas access
6357
run: |
64-
echo "=== SDK Repository ==="
65-
echo "Current directory: $(pwd)"
66-
echo "Git status:"
67-
git status
68-
echo ""
69-
echo "Recent tags:"
70-
git tag -l | tail -10 || echo "No tags found"
71-
echo ""
72-
echo "Looking for state tag '${{ env.STATE_TAG }}':"
73-
git show-ref --tags "${{ env.STATE_TAG }}" || echo "State tag not found"
58+
echo "=== Testing API access to ${{ env.GDC_NAS_REPO }} ==="
59+
if gh api "repos/${{ env.GDC_NAS_REPO }}" --jq '.full_name' 2>/dev/null; then
60+
echo "✅ Access verified"
61+
else
62+
echo "❌ Cannot access ${{ env.GDC_NAS_REPO }}"
63+
echo ""
64+
echo "To fix: Add a Personal Access Token with 'repo' scope as secret GDC_NAS_READ_TOKEN"
65+
exit 1
66+
fi
7467
75-
- name: Clone gdc-nas repository
68+
- name: Checkout SDK repository
7669
uses: actions/checkout@v4
7770
with:
78-
repository: ${{ env.GDC_NAS_REPO }}
79-
path: gdc-nas
80-
fetch-depth: 0 # Full history needed for diff analysis
81-
token: ${{ secrets.GDC_NAS_READ_TOKEN || secrets.GITHUB_TOKEN }}
82-
83-
- name: Debug - gdc-nas repo info
84-
run: |
85-
echo "=== gdc-nas Repository ==="
86-
echo "Directory contents:"
87-
ls -la gdc-nas/ | head -20
88-
echo ""
89-
echo "Git log (last 5 commits):"
90-
git -C gdc-nas log --oneline -5
91-
echo ""
92-
echo "Current HEAD:"
93-
git -C gdc-nas rev-parse HEAD
94-
echo ""
95-
echo "Total commits in repo:"
96-
git -C gdc-nas rev-list --count HEAD
71+
fetch-depth: 1
9772

9873
- name: Setup Python
9974
uses: actions/setup-python@v5
10075
with:
10176
python-version: '3.12'
10277

103-
- name: Debug - Python info
78+
- name: Get current gdc-nas HEAD
79+
id: gdc_nas
10480
run: |
105-
echo "=== Python Environment ==="
106-
python3 --version
107-
which python3
108-
echo ""
109-
echo "Analyzer script exists:"
110-
ls -la scripts/gdc_nas_diff_analyzer.py || echo "SCRIPT NOT FOUND!"
111-
echo ""
112-
echo "Script is executable:"
113-
head -5 scripts/gdc_nas_diff_analyzer.py
81+
HEAD_SHA=$(gh api "repos/${{ env.GDC_NAS_REPO }}/commits/HEAD" --jq '.sha')
82+
echo "head_sha=$HEAD_SHA" >> $GITHUB_OUTPUT
83+
echo "gdc-nas HEAD: $HEAD_SHA"
11484
115-
- name: Get last analyzed commit
116-
id: state
85+
- name: Determine analysis range
86+
id: range
11787
run: |
118-
set -x # Enable command tracing
119-
120-
COMMITS_TO_ANALYZE="${{ inputs.commits_to_analyze || '50' }}"
121-
FORCE_FULL="${{ inputs.force_full_scan || 'false' }}"
122-
123-
echo "=== Determining analysis range ==="
124-
echo "COMMITS_TO_ANALYZE: $COMMITS_TO_ANALYZE"
125-
echo "FORCE_FULL: $FORCE_FULL"
126-
127-
# Get current gdc-nas HEAD
128-
GDC_NAS_HEAD=$(git -C gdc-nas rev-parse HEAD)
129-
echo "gdc_nas_head=$GDC_NAS_HEAD" >> $GITHUB_OUTPUT
130-
echo "Current gdc-nas HEAD: $GDC_NAS_HEAD"
131-
132-
if [ "$FORCE_FULL" = "true" ]; then
133-
echo "Force full scan requested"
134-
echo "since=HEAD~${COMMITS_TO_ANALYZE}" >> $GITHUB_OUTPUT
135-
echo "mode=force" >> $GITHUB_OUTPUT
136-
elif git show-ref --tags --quiet "$STATE_TAG"; then
137-
# Tag exists - get the stored gdc-nas commit from tag message
138-
echo "State tag found, reading contents..."
139-
LAST_COMMIT=$(git tag -l --format='%(contents)' "$STATE_TAG" | head -1)
140-
echo "Found state tag with gdc-nas commit: $LAST_COMMIT"
141-
142-
# Verify this commit exists in gdc-nas
143-
if git -C gdc-nas rev-parse "$LAST_COMMIT" >/dev/null 2>&1; then
144-
echo "Commit verified in gdc-nas"
145-
echo "since=$LAST_COMMIT" >> $GITHUB_OUTPUT
88+
COMMITS="${{ inputs.commits_to_analyze || '50' }}"
89+
SINCE_INPUT="${{ inputs.since_commit }}"
90+
91+
echo "=== Determining range ==="
92+
93+
if [ -n "$SINCE_INPUT" ]; then
94+
# User provided explicit since commit
95+
echo "Using user-provided since commit: $SINCE_INPUT"
96+
echo "since=$SINCE_INPUT" >> $GITHUB_OUTPUT
97+
echo "mode=manual" >> $GITHUB_OUTPUT
98+
elif [ -f "${{ env.STATE_FILE }}" ]; then
99+
# Read from state file
100+
LAST_SHA=$(cat "${{ env.STATE_FILE }}" | tr -d '[:space:]')
101+
echo "Found state file with SHA: $LAST_SHA"
102+
103+
# Verify commit exists
104+
if gh api "repos/${{ env.GDC_NAS_REPO }}/commits/$LAST_SHA" --jq '.sha' >/dev/null 2>&1; then
105+
echo "Commit verified, using incremental mode"
106+
echo "since=$LAST_SHA" >> $GITHUB_OUTPUT
146107
echo "mode=incremental" >> $GITHUB_OUTPUT
147108
else
148-
echo "Warning: Stored commit not found in gdc-nas, falling back to HEAD~${COMMITS_TO_ANALYZE}"
149-
echo "since=HEAD~${COMMITS_TO_ANALYZE}" >> $GITHUB_OUTPUT
109+
echo "Stored commit not found, falling back to last $COMMITS commits"
110+
echo "since=" >> $GITHUB_OUTPUT
150111
echo "mode=fallback" >> $GITHUB_OUTPUT
112+
echo "commits=$COMMITS" >> $GITHUB_OUTPUT
151113
fi
152114
else
153-
echo "No state tag found, analyzing last ${COMMITS_TO_ANALYZE} commits"
154-
echo "since=HEAD~${COMMITS_TO_ANALYZE}" >> $GITHUB_OUTPUT
115+
echo "No state file, analyzing last $COMMITS commits"
116+
echo "since=" >> $GITHUB_OUTPUT
155117
echo "mode=initial" >> $GITHUB_OUTPUT
118+
echo "commits=$COMMITS" >> $GITHUB_OUTPUT
156119
fi
157120
158-
set +x
159-
160-
- name: Check for new commits
161-
id: check
162-
working-directory: gdc-nas
121+
- name: Run API-based analyzer
122+
id: analyze
163123
run: |
164-
set -x
165-
SINCE="${{ steps.state.outputs.since }}"
166-
167-
echo "=== Checking commits ==="
168-
echo "SINCE: $SINCE"
124+
mkdir -p reports
169125
170-
# Count commits to analyze
171-
if [[ "$SINCE" == HEAD~* ]]; then
172-
NUM="${SINCE#HEAD~}"
173-
COMMIT_COUNT=$NUM
174-
echo "Using HEAD~N format, will analyze $NUM commits"
175-
else
176-
COMMIT_COUNT=$(git rev-list --count "${SINCE}..HEAD" 2>/dev/null || echo "0")
177-
echo "Counting commits from $SINCE to HEAD: $COMMIT_COUNT"
178-
fi
126+
echo "=== Running Analyzer ==="
127+
echo "Mode: ${{ steps.range.outputs.mode }}"
179128
180-
echo "commit_count=$COMMIT_COUNT" >> $GITHUB_OUTPUT
129+
ARGS="--repo ${{ env.GDC_NAS_REPO }} --output-dir ./reports"
181130
182-
if [ "$COMMIT_COUNT" -eq 0 ]; then
183-
echo "No new commits to analyze"
184-
echo "skip=true" >> $GITHUB_OUTPUT
131+
if [ -n "${{ steps.range.outputs.since }}" ]; then
132+
ARGS="$ARGS --since ${{ steps.range.outputs.since }}"
185133
else
186-
echo "Will analyze $COMMIT_COUNT commits"
187-
echo "skip=false" >> $GITHUB_OUTPUT
134+
ARGS="$ARGS --commits ${{ steps.range.outputs.commits || '50' }}"
188135
fi
189-
set +x
190-
191-
- name: Run SDK diff analyzer
192-
if: steps.check.outputs.skip != 'true'
193-
run: |
194-
set -x
195-
mkdir -p reports
196-
197-
echo "=== Running Analyzer ==="
198-
echo "Since: ${{ steps.state.outputs.since }}"
199-
echo "Mode: ${{ steps.state.outputs.mode }}"
200-
echo "Commit count: ${{ steps.check.outputs.commit_count }}"
201-
202-
# Run with verbose output
203-
python3 scripts/gdc_nas_diff_analyzer.py \
204-
--since "${{ steps.state.outputs.since }}" \
205-
--sdk-details \
206-
--output-dir ./reports \
207-
--repo-path ./gdc-nas \
208-
2>&1 | tee analyzer_output.log
209136
210-
ANALYZER_EXIT_CODE=${PIPESTATUS[0]}
211-
echo "Analyzer exit code: $ANALYZER_EXIT_CODE"
137+
echo "Running: python3 scripts/gdc_nas_api_analyzer.py $ARGS"
138+
python3 scripts/gdc_nas_api_analyzer.py $ARGS 2>&1 | tee analyzer.log
212139
213140
echo ""
214-
echo "=== Reports directory ==="
215-
ls -la reports/ || echo "Reports directory empty or missing"
141+
echo "=== Reports ==="
142+
ls -la reports/
216143
217-
# Check if any reports were generated
218-
if [ -f reports/00-summary.md ]; then
219-
echo ""
220-
echo "=== Summary report content ==="
221-
cat reports/00-summary.md
222-
else
223-
echo "No SDK-relevant changes detected, creating minimal summary"
224-
cat > reports/00-summary.md << EOF
225-
# SDK Diff Analysis - No Changes
226-
227-
**Run:** ${{ github.run_number }}
228-
**Date:** $(date -u +%Y-%m-%dT%H:%M:%SZ)
229-
**Mode:** ${{ steps.state.outputs.mode }}
230-
**Commits analyzed:** ${{ steps.check.outputs.commit_count }}
231-
**gdc-nas HEAD:** \`${{ steps.state.outputs.gdc_nas_head }}\`
232-
233-
*No SDK-relevant changes detected in the analyzed commits.*
234-
EOF
235-
fi
236-
set +x
144+
# Count SDK-relevant reports (excluding summary)
145+
REPORT_COUNT=$(ls reports/*.md 2>/dev/null | grep -v "00-summary" | wc -l || echo "0")
146+
echo "sdk_reports=$REPORT_COUNT" >> $GITHUB_OUTPUT
237147
238148
- name: Upload analysis reports
239-
if: steps.check.outputs.skip != 'true'
240149
uses: actions/upload-artifact@v4
241150
with:
242151
name: sdk-diff-reports-${{ github.run_number }}
@@ -248,49 +157,44 @@ jobs:
248157
uses: actions/upload-artifact@v4
249158
with:
250159
name: analyzer-log-${{ github.run_number }}
251-
path: analyzer_output.log
160+
path: analyzer.log
252161
retention-days: 7
253162
if-no-files-found: ignore
254163

255-
- name: Update state tag
256-
if: steps.check.outputs.skip != 'true'
164+
- name: Update state file
257165
run: |
258-
set -x
259-
GDC_NAS_HEAD="${{ steps.state.outputs.gdc_nas_head }}"
166+
echo "=== Updating state ==="
167+
HEAD_SHA="${{ steps.gdc_nas.outputs.head_sha }}"
260168
261-
echo "=== Updating state tag ==="
262-
echo "Will store gdc-nas commit: $GDC_NAS_HEAD"
169+
echo "$HEAD_SHA" > "${{ env.STATE_FILE }}"
170+
echo "Stored SHA: $HEAD_SHA"
263171
264-
# Configure git for tagging
172+
# Commit and push state file
265173
git config user.name "github-actions[bot]"
266174
git config user.email "github-actions[bot]@users.noreply.github.com"
267175
268-
# Create/update annotated tag with gdc-nas commit in message
269-
git tag -f -a "$STATE_TAG" -m "$GDC_NAS_HEAD"
270-
271-
echo "Pushing tag to origin..."
272-
git push -f origin "$STATE_TAG"
273-
274-
echo "Updated $STATE_TAG to track gdc-nas commit: $GDC_NAS_HEAD"
176+
git add "${{ env.STATE_FILE }}"
275177
276-
# Verify
277-
echo "Verifying tag:"
278-
git show-ref --tags "$STATE_TAG"
279-
set +x
178+
if git diff --staged --quiet; then
179+
echo "No changes to state file"
180+
else
181+
git commit -m "chore: update gdc-nas analyzer state to ${HEAD_SHA:0:12}"
182+
git push
183+
echo "State file updated and pushed"
184+
fi
280185
281186
- name: Job summary
282187
if: always()
283188
run: |
284-
cat >> $GITHUB_STEP_SUMMARY << EOF
189+
cat >> $GITHUB_STEP_SUMMARY << 'EOF'
285190
## SDK Diff Analyzer Results
286191
287192
| Parameter | Value |
288193
|-----------|-------|
289-
| Mode | ${{ steps.state.outputs.mode }} |
290-
| Since | \`${{ steps.state.outputs.since }}\` |
291-
| gdc-nas HEAD | \`${{ steps.state.outputs.gdc_nas_head }}\` |
292-
| Commits analyzed | ${{ steps.check.outputs.commit_count }} |
293-
| Skipped | ${{ steps.check.outputs.skip }} |
194+
| Mode | ${{ steps.range.outputs.mode }} |
195+
| Since | `${{ steps.range.outputs.since || 'N/A' }}` |
196+
| gdc-nas HEAD | `${{ steps.gdc_nas.outputs.head_sha }}` |
197+
| SDK-relevant commits | ${{ steps.analyze.outputs.sdk_reports }} |
294198
295199
EOF
296200

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,9 @@ target-version = "py310"
118118
"packages/gooddata-fdw/src/gooddata_fdw/__init__.py" = ["F401"]
119119
"packages/gooddata-flight-server/src/gooddata_flight_server/__init__.py" = ["F401"]
120120
"packages/gooddata-flexconnect/src/gooddata_flexconnect/__init__.py" = ["F401"]
121-
# Standalone analyzer script - ignore performance suggestions
121+
# Standalone analyzer scripts - ignore performance suggestions
122122
"scripts/gdc_nas_diff_analyzer.py" = ["PERF401", "PIE810"]
123+
"scripts/gdc_nas_api_analyzer.py" = ["PERF401"]
123124

124125
[tool.ruff.format]
125126
exclude = ['(gooddata-api-client|.*\.snapshot\..*)']

0 commit comments

Comments
 (0)