Auto-label your GitHub PRs with Sonar Scans
This guide demonstrates how to set up an automation in Port that applies color-coded labels to your GitHub pull requests based on SonarCloud scan reports. These labels help you classify vulnerabilities, code smells, security hotspots, and bugs right from the pull request view.
Common use casesβ
- Enforce code quality standards: Highlight PRs with poor test coverage, high duplication, or critical issues.
- Encourage developer accountability: Make quality regressions visible and traceable at the PR level.
Prerequisitesβ
This guide assumes the following:
- You have a Port account and have completed the onboarding process.
- Port's GitHub app is installed in your account.
- Port's SonarQube integration is installed in your account.
Set up data modelβ
To connect scan data with the correct pull requests, you'll need to link the Pull Request
blueprint with the SonarQube Analysis
blueprint.
Follow the Connect GitHub PR to SonarQube analysis guide to set this up.
Set up automationβ
Once the SonarQube scan entities are linked to their corresponding pull requests, you can configure an automation in Port that triggers a GitHub workflow on PR updates and applies Sonar-based labels directly to the pull request.
This setup involves two parts:
-
Adding a GitHub PAT as a Port secret.
-
Defining the automation in Port.
Add Port secretsβ
To add a secret to your portal:
-
Click on the
...
button in the top right corner of your Port application. -
Click on Credentials.
-
Click on the
Secrets
tab. -
Click on
+ Secret
and add the following secrets:GITHUB_TOKEN
- A GitHub Personal Access Token (classic) with repo and workflow scopes.
Define automation backendβ
-
Go to the Automations page in your portal.
-
Click on the
+ Automation
button. -
Copy and paste the following JSON configuration into the editor:
Apply SonarCloud label automation (Click to expand)
Replace placeholdersMake sure to replace
<YOUR_GITHUB_ORG>
and<YOUR_GITHUB_REPO>
in the url field below with the actual organization and repository where yourapply-sonar-scan-on-pr.yaml
workflow resides.{
"identifier": "addLabelOnGithubPR",
"title": "Add Sonar Scan Label On PR Updated",
"description": "Automation to add Sonar scan label to the GitHub PR upon update",
"trigger": {
"type": "automation",
"event": {
"type": "ENTITY_UPDATED",
"blueprintIdentifier": "githubPullRequest"
},
"condition": {
"type": "JQ",
"expressions": [
".diff.after.relations.sonarAnalysis != null"
],
"combinator": "and"
}
},
"invocationMethod": {
"type": "WEBHOOK",
"url": "https://api.github.com/repos/<YOUR_GITHUB_ORG>/<YOUR_GITHUB_REPO>/actions/workflows/apply-sonar-scan-on-pr.yaml/dispatches",
"method": "POST",
"headers": {
"Accept": "application/vnd.github+json",
"Authorization": "Bearer {{ .secrets.GITHUB_TOKEN }}",
"Content-Type": "application/json"
},
"body": {
"ref": "main",
"inputs": {
"prNumber": "{{ .event.diff.after.properties.prNumber | tostring }}",
"repository": "{{ .event.diff.after.relations.repository }}",
"sonarEntity": "{{ .event.diff.after.relations.sonarAnalysis }}"
}
}
},
"publish": true
} -
Click
Save
.
Create the GitHub workflowβ
Now let us define the GitHub Actions workflow that receives the input and applies labels to the pull request.
We recommend creating a dedicated repository for the workflows that are used by Port actions.
In your dedicated workflow repository, ensure you have a .github/workflows
directory.
-
Create a new file named
apply-sonar-scan-on-pr.yaml
-
Copy and paste the following workflow configuration:
Apply SonarCloud labels workflow (Click to expand)
name: Apply Sonar Scan on PR
on:
workflow_dispatch:
inputs:
prNumber:
required: true
type: string
repository:
required: true
type: string
sonarEntity:
required: true
type: string
jobs:
analyze_sonar:
runs-on: ubuntu-latest
env:
PORT_CLIENT_ID: ${{ secrets.PORT_CLIENT_ID }}
PORT_CLIENT_SECRET: ${{ secrets.PORT_CLIENT_SECRET }}
GH_TOKEN: ${{ secrets.MY_GITHUB_TOKEN }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Fetch Port Access Token
id: fetch_port_token
run: |
PORT_ACCESS_TOKEN=$(curl -s -L 'https://api.getport.io/v1/auth/access_token' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
"clientId": "${{ secrets.PORT_CLIENT_ID }}",
"clientSecret": "${{ secrets.PORT_CLIENT_SECRET }}"
}' | jq -r '.accessToken')
echo "PORT_ACCESS_TOKEN=$PORT_ACCESS_TOKEN" >> "$GITHUB_ENV"
- name: Get Sonar Entity from Port
id: get_sonar
run: |
sonar_entity_id="${{ github.event.inputs.sonarEntity }}"
echo "π Fetching Sonar entity $sonar_entity_id"
sonar_response=$(curl -s -X GET "https://api.port.io/v1/blueprints/sonarQubeAnalysis/entities/$sonar_entity_id" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${{ env.PORT_ACCESS_TOKEN }}")
echo "$sonar_response"
FIXED_ISSUES=$(echo "$sonar_response" | jq '.entity.properties.fixedIssues // 0')
NEW_ISSUES=$(echo "$sonar_response" | jq '.entity.properties.newIssues // 0')
COVERAGE=$(echo "$sonar_response" | jq '.entity.properties.coverage // 0')
DUPLICATIONS=$(echo "$sonar_response" | jq '.entity.properties.duplications // 0')
echo "FIXED_ISSUES=$FIXED_ISSUES" >> "$GITHUB_ENV"
echo "NEW_ISSUES=$NEW_ISSUES" >> "$GITHUB_ENV"
echo "COVERAGE=$COVERAGE" >> "$GITHUB_ENV"
echo "DUPLICATIONS=$DUPLICATIONS" >> "$GITHUB_ENV"
- name: Classify and Apply Sonar Labels
run: |
set -e
repo="${{ github.event.inputs.repository }}"
owner="${{ github.repository_owner }}"
pr_number=$(echo "${{ github.event.inputs.prNumber }}" | grep -o '[0-9]\+$')
# Classify coverage
if (( $(echo "$COVERAGE < 25" | bc -l) )); then
coverage_label="Sonar: Coverage - 0-25%"
elif (( $(echo "$COVERAGE < 50" | bc -l) )); then
coverage_label="Sonar: Coverage - 25-50%"
elif (( $(echo "$COVERAGE < 75" | bc -l) )); then
coverage_label="Sonar: Coverage - 50-75%"
else
coverage_label="Sonar: Coverage - 75-100%"
fi
# Classify new issues
if (( NEW_ISSUES == 0 )); then
new_issues_label="Sonar: Issues - A"
elif (( NEW_ISSUES <= 5 )); then
new_issues_label="Sonar: Issues - B"
elif (( NEW_ISSUES <= 10 )); then
new_issues_label="Sonar: Issues - C"
elif (( NEW_ISSUES <= 20 )); then
new_issues_label="Sonar: Issues - D"
else
new_issues_label="Sonar: Issues - E"
fi
# Classify fixed issues
if (( FIXED_ISSUES == 0 )); then
fixed_issues_label="Sonar: Fixed - A"
elif (( FIXED_ISSUES <= 5 )); then
fixed_issues_label="Sonar: Fixed - B"
elif (( FIXED_ISSUES <= 10 )); then
fixed_issues_label="Sonar: Fixed - C"
elif (( FIXED_ISSUES <= 20 )); then
fixed_issues_label="Sonar: Fixed - D"
else
fixed_issues_label="Sonar: Fixed - E"
fi
# Classify duplications
if (( $(echo "$DUPLICATIONS < 5" | bc -l) )); then
dup_label="Sonar: Duplication - A"
elif (( $(echo "$DUPLICATIONS < 10" | bc -l) )); then
dup_label="Sonar: Duplication - B"
elif (( $(echo "$DUPLICATIONS < 20" | bc -l) )); then
dup_label="Sonar: Duplication - C"
elif (( $(echo "$DUPLICATIONS < 30" | bc -l) )); then
dup_label="Sonar: Duplication - D"
else
dup_label="Sonar: Duplication - E"
fi
labels_to_apply=("$coverage_label" "$new_issues_label" "$fixed_issues_label" "$dup_label")
echo "π·οΈ Will apply labels: ${labels_to_apply[*]}"
# Define a function to assign colors based on grade
get_label_color() {
label="$1"
if [[ "$label" == *" - A" || "$label" == *"75-100%" ]]; then
echo "2cbe4e" # Green
elif [[ "$label" == *" - B" || "$label" == *"50-75%" ]]; then
echo "a2eeef" # Light blue
elif [[ "$label" == *" - C" || "$label" == *"25-50%" ]]; then
echo "fbca04" # Yellow
elif [[ "$label" == *" - D" || "$label" == *"0-25%" ]]; then
echo "f66a0a" # Orange
else
echo "d73a4a" # Red for E or anything else
fi
}
# Create labels if they donβt exist, using dynamic colors
for label in "${labels_to_apply[@]}"; do
color=$(get_label_color "$label")
echo "π οΈ Ensuring label exists: $label with color #$color"
curl -s -o /dev/null -w "%{http_code}" -X POST "https://api.github.com/repos/$owner/$repo/labels" \
-H "Authorization: Bearer $GH_TOKEN" \
-H "Accept: application/vnd.github+json" \
-d "{\"name\": \"$label\", \"color\": \"$color\"}" | grep -qE "201|422"
done
# Apply to PR
echo "π·οΈ Applying labels to PR #$pr_number..."
curl -s -X POST "https://api.github.com/repos/$owner/$repo/issues/$pr_number/labels" \
-H "Authorization: Bearer $GH_TOKEN" \
-H "Accept: application/vnd.github+json" \
-d "{\"labels\": [\"${labels_to_apply[0]}\", \"${labels_to_apply[1]}\", \"${labels_to_apply[2]}\", \"${labels_to_apply[3]}\"]}"Required GitHub SecretsFor this workflow to function properly, you need to add the following secrets to your GitHub repository:
PORT_CLIENT_ID
: The client ID of your Port account.PORT_CLIENT_SECRET
: The client ID of your Port account.MY_GITHUB_TOKEN
: The fine grained GitHub personal access token withRead and Write
access to issues, pull requests across all repositories in your organization.
-
Commit and push the changes to your repository.
Once a pull request associated with a SonarCloud analysis is updated, the automation will be triggered automatically. It will evaluate the latest scan results and apply color-coded labels to the PR, reflecting the quality status of the code.
