| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191 |
- name: Sonar
- # Privileged trigger: workflow_run is needed to report Sonar results for fork PRs. No PR code is executed; sonar.host.url is pinned on the CLI.
- on: # zizmor: ignore[dangerous-triggers]
- workflow_run:
- workflows: ["Build/Test"]
- types: [completed]
- permissions: {}
- jobs:
- sonar:
- name: Sonar
- runs-on: ubuntu-latest
- if: github.event.workflow_run.conclusion == 'success'
- permissions:
- statuses: write
- contents: read
- actions: read
- steps:
- - name: Set Quality Gate status (pending)
- if: always()
- uses: guibranco/github-status-action-v2@77639353504055053524efa7a3719aaf0b731ce9 # v1.2.4
- with:
- authToken: ${{ secrets.GITHUB_TOKEN }}
- state: 'pending'
- context: 'Quality Gate'
- description: 'Quality Gate check in progress...'
- sha: ${{ github.event.workflow_run.head_sha }}
- target_url: 'https://sonarcloud.io/dashboard?id=opencost_opencost'
- - name: Checkout upstream repository
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
- with:
- repository: opencost/opencost
- ref: develop
- fetch-depth: 0
- persist-credentials: false
- - name: Fetch PR branch from fork
- if: github.event.workflow_run.head_branch != 'develop' || github.event.workflow_run.head_repository.full_name != 'opencost/opencost'
- env:
- HEAD_REPO_FULL_NAME: ${{ github.event.workflow_run.head_repository.full_name }}
- HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }}
- HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
- run: |
- git remote add fork "https://github.com/$HEAD_REPO_FULL_NAME.git"
- if [ "$HEAD_BRANCH" = "develop" ]; then
- # For fork's develop branch, fetch and checkout by SHA to avoid refspec conflict
- git fetch fork "$HEAD_BRANCH"
- git checkout "$HEAD_SHA"
- else
- # For feature branches, fetch and checkout normally
- git fetch fork "$HEAD_BRANCH:$HEAD_BRANCH"
- git checkout "$HEAD_BRANCH"
- fi
- - name: Checkout develop branch at specific SHA
- if: github.event.workflow_run.head_branch == 'develop' && github.event.workflow_run.head_repository.full_name == 'opencost/opencost'
- env:
- HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
- run: |
- git checkout "$HEAD_SHA"
- - name: Download coverage artifacts
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
- with:
- name: code-coverage
- run-id: ${{ github.event.workflow_run.id }}
- github-token: ${{ github.token }}
- path: pr-artifact
- - name: Validate Coverage Vars
- id: validate-vars
- if: github.event.workflow_run.head_branch != 'develop'
- shell: bash
- run: |
- # check the PR number
- pr_content=$(cat pr-artifact/pr_num.txt | tr -d '\n' | tr -d ' ')
- # Check if the content matches a single number
- if [[ "$pr_content" =~ ^[0-9]+$ ]]; then
- echo "The file 'pr_num.txt' contains a single number: $pr_content"
- else
- echo "The file 'pr_num.txt' does not contain a single number."
- exit 1
- fi
- base_content=$(cat pr-artifact/base.txt | tr -d '\n' | tr -d ' ')
- if git check-ref-format --allow-onelevel "$base_content"; then
- echo "The file 'base.txt' contains a valid git ref: $base_content"
- else
- echo "The file 'base.txt' does not contain a valid git ref: $base_content"
- exit 1
- fi
- head_content=$(cat pr-artifact/head.txt | tr -d '\n' | tr -d ' ')
- if git check-ref-format --allow-onelevel "$head_content"; then
- echo "The file 'head.txt' contains a valid git ref: $head_content"
- else
- echo "The file 'head.txt' does not contain a valid git ref: $head_content"
- exit 1
- fi
- - name: set vars
- id: set-vars
- run: |
- echo "SONAR_PR_NUM=$(cat pr-artifact/pr_num.txt | tr -d '\n' | tr -d ' ')" >> $GITHUB_OUTPUT
- echo "SONAR_BASE=$(cat pr-artifact/base.txt | tr -d '\n' | tr -d ' ')" >> $GITHUB_OUTPUT
- echo "SONAR_HEAD=$(cat pr-artifact/head.txt | tr -d '\n' | tr -d ' ')" >> $GITHUB_OUTPUT
- # move coverage file to root where sonar properties file is expecting it
- cp pr-artifact/coverage.out coverage.out
- # on develop branch, only run a baseline scan
- # The checked-out tree may come from a fork PR. sonar.host.url is set on the
- # command line (which overrides sonar-project.properties) so a PR cannot
- # redirect SONAR_TOKEN to another server.
- - name: SonarCloud Scan (Baseline)
- uses: SonarSource/sonarqube-scan-action@ba9859eae8dd6bd29e412f25ddbbef3d032000f4 # v8.2.2
- if: github.event.workflow_run.head_branch == 'develop'
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
- with:
- args: >
- -Dsonar.scm.revision=${{ github.event.workflow_run.head_sha }}
- -Dsonar.host.url=https://sonarcloud.io
- -Dsonar.projectKey=opencost_opencost
- -Dsonar.organization=opencost
- -Dsonar.branch.name=develop
- - name: SonarCloud Scan (PR)
- uses: SonarSource/sonarqube-scan-action@ba9859eae8dd6bd29e412f25ddbbef3d032000f4 # v8.2.2
- if: github.event.workflow_run.head_branch != 'develop'
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
- with:
- args: >
- -Dsonar.scm.revision=${{ github.event.workflow_run.head_sha }}
- -Dsonar.pullrequest.key=${{ steps.set-vars.outputs.SONAR_PR_NUM }}
- -Dsonar.pullrequest.branch=${{ steps.set-vars.outputs.SONAR_HEAD }}
- -Dsonar.pullrequest.base=${{ steps.set-vars.outputs.SONAR_BASE }}
- -Dsonar.host.url=https://sonarcloud.io
- -Dsonar.projectKey=opencost_opencost
- -Dsonar.organization=opencost
- - name: SonarQube Quality Gate check
- id: sonarqube-quality-gate-check
- continue-on-error: true
- uses: sonarsource/sonarqube-quality-gate-action@7a5fffe8e523c40e0c740b6bc2712ab503e52efa # v1.2.1
- # fail step after specific time.
- timeout-minutes: 5
- env:
- SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
- SONAR_HOST_URL: "https://sonarcloud.io"
- - name: Set Quality Gate status (failed - PR)
- id: fail-quality-gate-pr
- if: steps.sonarqube-quality-gate-check.outputs.quality-gate-status != 'PASSED' && steps.set-vars.outputs.SONAR_PR_NUM != ''
- uses: guibranco/github-status-action-v2@77639353504055053524efa7a3719aaf0b731ce9 # v1.2.4
- with:
- authToken: ${{ secrets.GITHUB_TOKEN }}
- state: 'failure'
- context: 'Quality Gate'
- description: 'Quality Gate failed. Check the SonarCloud Dashboard for PR #${{ steps.set-vars.outputs.SONAR_PR_NUM }}'
- sha: ${{ github.event.workflow_run.head_sha }}
- target_url: 'https://sonarcloud.io/dashboard?id=opencost_opencost&pullRequest=${{ steps.set-vars.outputs.SONAR_PR_NUM }}'
- - name: Set Quality Gate status (failed - develop)
- id: fail-quality-gate-develop
- if: steps.sonarqube-quality-gate-check.outputs.quality-gate-status != 'PASSED' && steps.set-vars.outputs.SONAR_PR_NUM == ''
- uses: guibranco/github-status-action-v2@77639353504055053524efa7a3719aaf0b731ce9 # v1.2.4
- with:
- authToken: ${{ secrets.GITHUB_TOKEN }}
- state: 'failure'
- context: 'Quality Gate'
- description: 'Quality Gate failed. Check the SonarCloud Dashboard for more details.'
- sha: ${{ github.event.workflow_run.head_sha }}
- target_url: 'https://sonarcloud.io/dashboard?id=opencost_opencost'
- - name: Set Quality Gate status (passed - PR)
- id: pass-quality-gate-pr
- if: steps.sonarqube-quality-gate-check.outputs.quality-gate-status == 'PASSED' && steps.set-vars.outputs.SONAR_PR_NUM != ''
- uses: guibranco/github-status-action-v2@77639353504055053524efa7a3719aaf0b731ce9 # v1.2.4
- with:
- authToken: ${{ secrets.GITHUB_TOKEN }}
- state: 'success'
- context: 'Quality Gate'
- description: 'Quality Gate passed. Check the SonarCloud Dashboard for PR #${{ steps.set-vars.outputs.SONAR_PR_NUM }}'
- sha: ${{ github.event.workflow_run.head_sha }}
- target_url: 'https://sonarcloud.io/dashboard?id=opencost_opencost&pullRequest=${{ steps.set-vars.outputs.SONAR_PR_NUM }}'
- - name: Set Quality Gate status (passed - develop)
- id: pass-quality-gate-develop
- if: steps.sonarqube-quality-gate-check.outputs.quality-gate-status == 'PASSED' && steps.set-vars.outputs.SONAR_PR_NUM == ''
- uses: guibranco/github-status-action-v2@77639353504055053524efa7a3719aaf0b731ce9 # v1.2.4
- with:
- authToken: ${{ secrets.GITHUB_TOKEN }}
- state: 'success'
- context: 'Quality Gate'
- description: 'Quality Gate passed. Check the SonarCloud Dashboard for more details.'
- sha: ${{ github.event.workflow_run.head_sha }}
- target_url: 'https://sonarcloud.io/dashboard?id=opencost_opencost'
|