Skip to content

Commit c90e9b4

Browse files
authored
[AAP-52434] Rework the SonarQube Cloud integration (#829)
1 parent b5f1040 commit c90e9b4

File tree

2 files changed

+293
-46
lines changed

2 files changed

+293
-46
lines changed

.github/workflows/sonar-pr.yml

Lines changed: 154 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,20 @@
1+
# SonarCloud PR Workflow for django-ansible-base
2+
#
3+
# This workflow runs on every pull request and push to the repository.
4+
#
5+
# Steps overview:
6+
# 1. Download coverage data from CI workflow
7+
# 2. Check for backport labels (skip if found)
8+
# 3. Check for Python file changes (skip if none)
9+
# 4. Extract PR info and set environment
10+
# 5. Run SonarCloud analysis with quality gate
11+
#
12+
# What files are scanned:
13+
# - All Python files (.py) in the repository
14+
# - Excludes: tests, scripts, dev environments, external collections
15+
# - Quality gate focuses on new/changed code in PR only
16+
17+
118
# With much help from:
219
# https://community.sonarsource.com/t/how-to-use-sonarcloud-with-a-forked-repository-on-github/7363/30
320
# https://community.sonarsource.com/t/how-to-use-sonarcloud-with-a-forked-repository-on-github/7363/32
@@ -8,71 +25,183 @@ on:
825
- CI
926
types:
1027
- completed
28+
workflow_dispatch:
29+
inputs:
30+
pr_number:
31+
description: 'PR number (for push events, use 0)'
32+
required: true
33+
type: string
34+
event_type:
35+
description: 'Event type (push or pull_request)'
36+
required: true
37+
type: string
38+
commit_sha:
39+
description: 'Commit SHA'
40+
required: true
41+
type: string
42+
repository:
43+
description: 'Repository name'
44+
required: true
45+
type: string
46+
ci_run_id:
47+
description: 'CI workflow run ID (for downloading coverage artifact)'
48+
required: false
49+
type: string
50+
permissions: read-all
1151
jobs:
1252
sonar:
1353
name: Upload to SonarCloud
1454
runs-on: ubuntu-latest
15-
if: github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'pull_request'
55+
if: |
56+
(github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'pull_request') ||
57+
(github.event_name == 'workflow_dispatch')
1658
steps:
17-
- uses: actions/checkout@v4
18-
with:
19-
show-progress: false
59+
- uses: actions/checkout@v3
2060

21-
# Always use a full sha here to protect tokens, it's a third-party action
61+
# Download coverage artifact (for both workflow_run and workflow_dispatch)
2262
- name: Download coverage artifact
63+
if: |
64+
github.event_name == 'workflow_run' ||
65+
(github.event_name == 'workflow_dispatch' && inputs.ci_run_id != '')
2366
uses: dawidd6/action-download-artifact@246dbf436b23d7c49e21a7ab8204ca9ecd1fe615
2467
with:
2568
github_token: ${{ secrets.GITHUB_TOKEN }}
2669
workflow: CI
27-
run_id: ${{ github.event.workflow_run.id }}
70+
run_id: ${{ github.event_name == 'workflow_run' && github.event.workflow_run.id || inputs.ci_run_id }}
2871
name: coverage
2972

30-
- name: Extract PR number from coverage.xml
73+
# Set PR number based on trigger type
74+
- name: Set PR number and event type
3175
run: |
32-
echo "PR_NUMBER=$(grep -m 1 '<!-- PR' coverage.xml | awk '{print $3}')" >> $GITHUB_ENV
76+
if [ "${{ github.event_name }}" = "workflow_run" ]; then
77+
# Extract from coverage.xml for workflow_run
78+
echo "PR_NUMBER=$(grep -m 1 '<!-- PR' coverage.xml | awk '{print $3}')" >> $GITHUB_ENV
79+
echo "EVENT_TYPE=pull_request" >> $GITHUB_ENV
80+
echo "COMMIT_SHA=${{ github.event.workflow_run.head_sha }}" >> $GITHUB_ENV
81+
echo "REPO_NAME=${{ github.event.repository.full_name }}" >> $GITHUB_ENV
82+
else
83+
# Use inputs for workflow_dispatch
84+
echo "PR_NUMBER=${{ inputs.pr_number }}" >> $GITHUB_ENV
85+
echo "EVENT_TYPE=${{ inputs.event_type }}" >> $GITHUB_ENV
86+
echo "COMMIT_SHA=${{ inputs.commit_sha }}" >> $GITHUB_ENV
87+
echo "REPO_NAME=${{ inputs.repository }}" >> $GITHUB_ENV
88+
fi
3389
3490
- name: Get PR info
91+
if: env.EVENT_TYPE == 'pull_request' && env.PR_NUMBER != '0'
3592
uses: octokit/[email protected]
3693
id: pr_info
3794
with:
3895
route: GET /repos/{repo}/pulls/{number}
39-
repo: ${{ github.event.repository.full_name }}
96+
repo: ${{ env.REPO_NAME }}
4097
number: ${{ env.PR_NUMBER }}
4198
env:
4299
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
43100

101+
- name: Print SonarCloud Analysis Decision Summary
102+
id: print_summary
103+
run: |
104+
echo "🔍 SonarCloud Analysis Decision Summary"
105+
echo "========================================"
106+
107+
# Check CI Event type
108+
if [ "${{ env.EVENT_TYPE }}" = "pull_request" ]; then
109+
echo "├── CI Event: ✅ Pull Request"
110+
111+
# Check backport labels (only for PRs)
112+
if [ "${{ env.PR_NUMBER }}" != "0" ]; then
113+
echo "├── Backport Label: ➖ N/A (Skip check for workflow_dispatch)"
114+
115+
# Check Python changes for PRs
116+
files=$(gh api repos/${{ env.REPO_NAME }}/pulls/${{ env.PR_NUMBER }}/files --jq '.[].filename')
117+
118+
# Get file extensions for summary
119+
extensions=$(echo "$files" | sed 's/.*\.//' | sort | uniq | tr '\n' ',' | sed 's/,$//')
120+
121+
# Check if any Python files were changed
122+
python_files=$(echo "$files" | grep '\.py$' || true)
123+
if [ -z "$python_files" ]; then
124+
echo "├── Python Changes: ❌ None (.$extensions only)"
125+
echo "└── Result: ⏭️ Skip - \"No Python code changes detected\""
126+
exit 0
127+
else
128+
python_count=$(echo "$python_files" | wc -l)
129+
echo "├── Python Changes: ✅ Found ($python_count files)"
130+
echo "└── Result: ✅ Proceed - \"Running SonarCloud analysis\""
131+
fi
132+
else
133+
echo "├── Backport Label: ➖ N/A (Not a PR)"
134+
echo "└── Result: ✅ Proceed - \"Running SonarCloud analysis\""
135+
fi
136+
else
137+
# For push events, always proceed
138+
echo "├── CI Event: ✅ Push"
139+
echo "├── Backport Label: ➖ N/A (Push event)"
140+
echo "├── Python Changes: ➖ N/A (Full codebase scan)"
141+
echo "└── Result: ✅ Proceed - \"Running SonarCloud analysis\""
142+
fi
143+
env:
144+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
145+
146+
- name: Check if analysis should proceed
147+
id: check_proceed
148+
run: |
149+
# This step only runs if we got past the summary step
150+
# which means all conditions are met for analysis
151+
echo "proceed=true" >> $GITHUB_OUTPUT
152+
echo "✅ All conditions met - proceeding with SonarCloud analysis"
153+
44154
- name: Set PR info into env
155+
if: steps.check_proceed.outputs.proceed == 'true' && env.EVENT_TYPE == 'pull_request' && env.PR_NUMBER != '0' && steps.pr_info.outputs.data != ''
45156
run: |
46157
echo "PR_BASE=${{ fromJson(steps.pr_info.outputs.data).base.ref }}" >> $GITHUB_ENV
47158
echo "PR_HEAD=${{ fromJson(steps.pr_info.outputs.data).head.ref }}" >> $GITHUB_ENV
48159
49-
- name: Add base branch
160+
- name: Get changed Python files for Sonar
161+
if: steps.check_proceed.outputs.proceed == 'true' && env.EVENT_TYPE == 'pull_request' && env.PR_NUMBER != '0'
50162
run: |
51-
gh pr checkout ${{ env.PR_NUMBER }}
163+
files=$(gh api repos/${{ env.REPO_NAME }}/pulls/${{ env.PR_NUMBER }}/files --jq '.[].filename')
164+
echo "All changed files in PR:"
165+
echo "$files"
166+
python_files=$(echo "$files" | grep '\.py$' || true)
167+
if [ -n "$python_files" ]; then
168+
echo "Changed Python files:"
169+
echo "$python_files"
170+
# Convert to comma-separated list for sonar.inclusions
171+
inclusions=$(echo "$python_files" | tr '\n' ',' | sed 's/,$//')
172+
echo "SONAR_INCLUSIONS=$inclusions" >> $GITHUB_ENV
173+
echo "Will scan these Python files: $inclusions"
174+
fi
52175
env:
53176
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
54177

55-
- name: 'Extract and export repo owner/name'
56-
shell: bash
178+
- name: Add base branch (for PRs)
179+
if: steps.check_proceed.outputs.proceed == 'true' && env.EVENT_TYPE == 'pull_request' && env.PR_NUMBER != '0'
57180
run: |
58-
# 1. Read the full slug (owner/repo)
59-
REPO_SLUG="${GITHUB_REPOSITORY}"
60-
# 2. Split into owner and repo
61-
IFS="/" read -r REPO_OWNER REPO_NAME <<< "$REPO_SLUG"
62-
# 3. Export to the workflow environment
63-
echo "REPO_OWNER=$REPO_OWNER" >> $GITHUB_ENV
64-
echo "REPO_NAME=$REPO_NAME" >> $GITHUB_ENV
181+
gh pr checkout ${{ env.PR_NUMBER }}
182+
env:
183+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
65184

66-
- name: SonarQube Scan
185+
- name: SonarCloud Scan (Pull Request)
186+
if: steps.check_proceed.outputs.proceed == 'true' && env.EVENT_TYPE == 'pull_request' && env.PR_NUMBER != '0'
67187
uses: SonarSource/sonarqube-scan-action@v5
68188
env:
69189
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
70-
SONAR_TOKEN: ${{ secrets[format('{0}', vars.SONAR_TOKEN_SECRET_NAME)] }}
190+
SONAR_TOKEN: ${{ secrets[format('{0}', vars.SONAR_TOKEN_SECRET_NAME)] }}
71191
with:
72192
args: >
73-
-Dsonar.projectKey=${{ env.REPO_OWNER }}_${{ env.REPO_NAME }}
74-
-Dsonar.organization=${{ env.REPO_OWNER }}
75-
-Dsonar.scm.revision=${{ github.event.workflow_run.head_sha }}
193+
-Dsonar.scm.revision=${{ env.COMMIT_SHA }}
76194
-Dsonar.pullrequest.key=${{ env.PR_NUMBER }}
77195
-Dsonar.pullrequest.branch=${{ env.PR_HEAD }}
78196
-Dsonar.pullrequest.base=${{ env.PR_BASE }}
197+
${{ env.SONAR_INCLUSIONS && format('-Dsonar.inclusions={0}', env.SONAR_INCLUSIONS) || '' }}
198+
199+
- name: SonarCloud Scan (Push)
200+
if: steps.check_proceed.outputs.proceed == 'true' && env.EVENT_TYPE == 'push'
201+
uses: SonarSource/sonarqube-scan-action@v5
202+
env:
203+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
204+
SONAR_TOKEN: ${{ secrets[format('{0}', vars.SONAR_TOKEN_SECRET_NAME)] }}
205+
with:
206+
args: >
207+
-Dsonar.scm.revision=${{ env.COMMIT_SHA }}

0 commit comments

Comments
 (0)