diff --git a/.github/workflows/sonarqube-manual.yaml b/.github/workflows/sonarqube-manual.yaml new file mode 100644 index 0000000..4e67656 --- /dev/null +++ b/.github/workflows/sonarqube-manual.yaml @@ -0,0 +1,109 @@ +name: SonarQube Manual Scan + +on: + workflow_call: + inputs: + quality_profile: + description: SonarCloud quality profile name (e.g. Sonar way) + required: true + type: string + sonar_language: + description: SonarCloud language key for the quality profile (e.g. php, java) + required: false + type: string + default: php + ref: + description: Branch, tag, or SHA to analyze (defaults to caller ref) + required: false + type: string + default: "" + fetch_depth: + description: Git fetch depth (0 = full history for Sonar SCM) + required: false + type: number + default: 0 + runs_on: + required: false + type: string + default: ubuntu-latest-8-cores + sonar_scanner_opts: + description: JVM options for the Sonar scanner (e.g. -Xmx4000m) + required: false + type: string + default: -Xmx4000m + secrets: + sonar_token: + required: true + +permissions: + contents: read + +jobs: + sonarqube: + runs-on: ${{ inputs.runs_on }} + name: SonarQube Manual Scan (${{ inputs.quality_profile }}) + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + ref: ${{ inputs.ref != '' && inputs.ref || github.ref }} + fetch-depth: ${{ inputs.fetch_depth }} + + - name: Cache SonarQube scanner data + uses: actions/cache@v5 + with: + path: ~/.sonar/cache + key: ${{ runner.os }}-sonar-${{ hashFiles('sonar-project.properties') }} + restore-keys: | + ${{ runner.os }}-sonar- + + - name: Switch SonarCloud quality profile + id: sonar_profile + env: + SONAR_TOKEN: ${{ secrets.sonar_token }} + run: | + set -euo pipefail + + if [ ! -f sonar-project.properties ]; then + echo "sonar-project.properties not found in repository root" >&2 + exit 1 + fi + + PROJECT_KEY=$(grep -E '^sonar\.projectKey=' sonar-project.properties | head -1 | cut -d= -f2- | tr -d ' \r') + ORGANIZATION=$(grep -E '^sonar\.organization=' sonar-project.properties | head -1 | cut -d= -f2- | tr -d ' \r') + LANGUAGE="${{ inputs.sonar_language }}" + PROFILE="${{ inputs.quality_profile }}" + + RESPONSE=$(curl -sf -u "${SONAR_TOKEN}:" \ + "https://sonarcloud.io/api/qualityprofiles/search?project=${PROJECT_KEY}&organization=${ORGANIZATION}") + PREVIOUS=$(echo "$RESPONSE" | jq -r --arg lang "$LANGUAGE" \ + '.profiles[] | select(.language == $lang) | .name' | head -1) + + echo "previous_profile=${PREVIOUS}" >> "$GITHUB_OUTPUT" + echo "project_key=${PROJECT_KEY}" >> "$GITHUB_OUTPUT" + + curl -sf -u "${SONAR_TOKEN}:" -X POST \ + "https://sonarcloud.io/api/qualityprofiles/add_project" \ + --data-urlencode "project=${PROJECT_KEY}" \ + --data-urlencode "qualityProfile=${PROFILE}" \ + --data-urlencode "language=${LANGUAGE}" + + - name: SonarQube Scan + uses: SonarSource/sonarqube-scan-action@v6.0.0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: ${{ secrets.sonar_token }} + SONAR_SCANNER_OPTS: ${{ inputs.sonar_scanner_opts }} + + - name: Restore SonarCloud quality profile + if: always() && steps.sonar_profile.outputs.previous_profile != '' + env: + SONAR_TOKEN: ${{ secrets.sonar_token }} + run: | + set -euo pipefail + + curl -sf -u "${SONAR_TOKEN}:" -X POST \ + "https://sonarcloud.io/api/qualityprofiles/add_project" \ + --data-urlencode "project=${{ steps.sonar_profile.outputs.project_key }}" \ + --data-urlencode "qualityProfile=${{ steps.sonar_profile.outputs.previous_profile }}" \ + --data-urlencode "language=${{ inputs.sonar_language }}"