From 309724b12b14f4434634b56b175880bcf9d95ace Mon Sep 17 00:00:00 2001 From: Jake Jackson Date: Fri, 10 Oct 2025 10:44:35 -0400 Subject: [PATCH] Add SonarQube Coverage and report generation (#16112) * added sonar config file and started cleaning up * we do not place the report at the root of the repo * limit scope to only the awx directory and its contents * update exclusions for things in awx/ that we don't want covered --- .github/workflows/sonarcloud_pr.yml | 85 +++++++++++++++++ sonar-project.properties | 141 ++++++++++++++++++++++++++++ 2 files changed, 226 insertions(+) create mode 100644 .github/workflows/sonarcloud_pr.yml create mode 100644 sonar-project.properties diff --git a/.github/workflows/sonarcloud_pr.yml b/.github/workflows/sonarcloud_pr.yml new file mode 100644 index 0000000000..192066707f --- /dev/null +++ b/.github/workflows/sonarcloud_pr.yml @@ -0,0 +1,85 @@ +--- +name: SonarQube + +on: + workflow_run: + workflows: + - CI + types: + - completed + +permissions: read-all + +jobs: + sonarqube: + runs-on: ubuntu-latest + if: github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'pull_request' + steps: + - name: Checkout Code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + show-progress: false + + - name: Download coverage report artifact + uses: actions/download-artifact@v4 + with: + name: coverage-report + path: reports/ + github-token: ${{ secrets.GITHUB_TOKEN }} + run-id: ${{ github.event.workflow_run.id }} + + - name: Download PR number artifact + uses: actions/download-artifact@v4 + with: + name: pr-number + path: . + github-token: ${{ secrets.GITHUB_TOKEN }} + run-id: ${{ github.event.workflow_run.id }} + + - name: Extract PR number + run: | + cat pr-number.txt + echo "PR_NUMBER=$(cat pr-number.txt)" >> $GITHUB_ENV + + - name: Get PR info + uses: octokit/request-action@v2.x + id: pr_info + with: + route: GET /repos/{repo}/pulls/{number} + repo: ${{ github.event.repository.full_name }} + number: ${{ env.PR_NUMBER }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Set PR info into env + run: | + echo "PR_BASE=${{ fromJson(steps.pr_info.outputs.data).base.ref }}" >> $GITHUB_ENV + echo "PR_HEAD=${{ fromJson(steps.pr_info.outputs.data).head.ref }}" >> $GITHUB_ENV + + - name: Add base branch + run: | + gh pr checkout ${{ env.PR_NUMBER }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract and export repo owner/name + run: | + REPO_SLUG="${GITHUB_REPOSITORY}" + IFS="/" read -r REPO_OWNER REPO_NAME <<< "$REPO_SLUG" + echo "REPO_OWNER=$REPO_OWNER" >> $GITHUB_ENV + echo "REPO_NAME=$REPO_NAME" >> $GITHUB_ENV + + - name: SonarQube scan + uses: SonarSource/sonarqube-scan-action@v5 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: ${{ secrets[format('{0}', vars.SONAR_TOKEN_SECRET_NAME)] }} + with: + args: > + -Dsonar.organization=${{ env.REPO_OWNER }} + -Dsonar.projectKey=${{ env.REPO_OWNER }}_${{ env.REPO_NAME }} + -Dsonar.pullrequest.key=${{ env.PR_NUMBER }} + -Dsonar.pullrequest.branch=${{ env.PR_HEAD }} + -Dsonar.pullrequest.base=${{ env.PR_BASE }} + -Dsonar.scm.revision=${{ github.event.workflow_run.head_sha }} diff --git a/sonar-project.properties b/sonar-project.properties new file mode 100644 index 0000000000..0c9b431801 --- /dev/null +++ b/sonar-project.properties @@ -0,0 +1,141 @@ +# SonarCloud project configuration for AWX +# Complete documentation: https://docs.sonarqube.org/latest/analysis/analysis-parameters/ + +# ============================================================================= +# PROJECT IDENTIFICATION (REQUIRED) +# ============================================================================= + +# The unique project identifier. This is mandatory. +# Do not duplicate or reuse! +# Available characters: [a-zA-Z0-9_:\.\-] +# Must have least one non-digit. +sonar.projectKey=ansible_awx +sonar.organization=ansible + +# Project metadata +sonar.projectName=awx + +# ============================================================================= +# SOURCE AND TEST CONFIGURATION +# ============================================================================= + +# Source directories to analyze +sonar.sources=. +sonar.inclusions=awx/** + +# Test directories +sonar.tests=awx/main/tests + +# Test file patterns +sonar.test.inclusions=\ + **/test_*.py,\ + **/*_test.py,\ + **/tests/**/*.py + +# Set branch-specific new code definition +# +# This is important to always check against the main branch for new PRs, +# otherwise the PR may fail during backporting, since the old version of the code +# may not respect the minimum requirements for the existing Quality Gate. +sonar.newCode.referenceBranch=devel + +# ============================================================================= +# LANGUAGE CONFIGURATION +# ============================================================================= + +# Python versions supported by the project +#sonar.python.version=3.9,3.10,3.11 + +# File encoding +sonar.sourceEncoding=UTF-8 + +# ============================================================================= +# REPORTS AND COVERAGE +# ============================================================================= + +# Test and coverage reports (paths relative to project root) +sonar.python.coverage.reportPaths=reports/coverage.xml +sonar.python.xunit.reportPath=/reports/junit.xml + +# External tool reports (add these paths when tools are configured) +# sonar.python.pylint.reportPaths=reports/pylint-report.txt +# sonar.python.bandit.reportPaths=reports/bandit-report.json +# sonar.python.mypy.reportPath=reports/mypy-report.txt +# sonar.python.flake8.reportPaths=reports/flake8-report.txt +# sonar.python.xunit.reportPath=reports/junit.xml + +# ============================================================================= +# EXCLUSIONS - FILES AND DIRECTORIES TO IGNORE +# ============================================================================= + +# General exclusions - files and directories to ignore from analysis +sonar.exclusions=\ + **/tests/**,\ + **/__pycache__/**,\ + **/*.pyc,\ + **/*.pyo,\ + **/*.pyd,\ + **/build/**,\ + **/dist/**,\ + **/*.egg-info/** + +# ============================================================================= +# COVERAGE EXCLUSIONS +# ============================================================================= + +# Files to exclude from coverage calculations +sonar.coverage.exclusions=\ + **/tests/**,\ + **/.tox/**,\ + **/test_*.py,\ + **/*_test.py,\ + **/conftest.py,\ + **/migrations/**,\ + **/settings*.py,\ + **/defaults.py,\ + **/manage.py,\ + **/__main__.py,\ + tools/scripts/** + +# ============================================================================= +# DUPLICATION EXCLUSIONS +# ============================================================================= + +# Ignore code duplication in migrations and tests +sonar.cpd.exclusions=\ + **/migrations/**,\ + **/tests/** + +# ============================================================================= +# ISSUE IGNORE RULES +# ============================================================================= + +# Ignore specific rules for certain file patterns +sonar.issue.ignore.multicriteria=e1 +# Ignore "should be a variable" in migrations +sonar.issue.ignore.multicriteria.e1.ruleKey=python:S1192 +sonar.issue.ignore.multicriteria.e1.resourceKey=**/migrations/**/* + +# ============================================================================= +# GITHUB INTEGRATION +# ============================================================================= + +# The following properties are automatically handled by GitHub Actions: +# sonar.pullrequest.key - handled automatically +# sonar.pullrequest.branch - handled automatically +# sonar.pullrequest.base - handled automatically + +# ============================================================================= +# DEBUGGING +# ============================================================================= + +# These are aggressive settings to ensure maximum detection +# do not use in production + +# sonar.verbose=true +# sonar.log.level=DEBUG +# sonar.scm.exclusions.disabled=true +# sonar.java.skipUnchanged=false +# sonar.scm.forceReloadAll=true +# sonar.filesize.limit=100 +# sonar.qualitygate.wait=true \ No newline at end of file