Multi-Branch Scanning
Introduction
This document explains how to set up GitHub Actions workflows to perform CodeScan static analysis on a repository, including a baseline scan for the main branch and multi-branch scanning. Due to limitations in CodeScan/Sonar, special steps are required to manage the master/main branch creation.
YAML Files Overview
First YAML Option 1
Baseline scan on main branch (flexible push/PR)
Uses ubuntu-latest
; scans changed files only; generates SARIF
.
First YAML Option 2
Baseline scan on main branch (restricted to main)
Uses ubuntu-latest
; fails on red quality gate; requires secrets for login.
Second YAML
Multi-branch scan
Runs on any branch; push = standard branch analysis; PR = comparison analysis.
First YAML – Baseline Scan Options
Option 1
name: CI env: SONAR_SCANNER_VERSION: 5.0.1.3006 on: push: branches: - '*' paths-ignore: - src/test/java/** - target/** pull_request: branches: - '*' paths-ignore: - src/test/java/** - target/** jobs: build: runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 - name: Cache files uses: actions/cache@v4 with: path: | ~/.sonar key: ${{ runner.os }}-sonar restore-keys: ${{ runner.os }}-sonar - name: Run Codescan On Push if: github.event_name == 'push' uses: codescan-io/[email protected] with: scanChangedFilesOnly: true organization: 'Enter organization key here' projectKey: 'Enter project key here' codeScanUrl: 'Enter your instance URL' login: ${{ secrets.codescan_token }} generateSarifFile: true - name: Run Codescan On PR if: github.event_name == 'pull_request' uses: codescan-io/[email protected] with: scanChangedFilesOnly: true organization: 'Enter organization key here' projectKey: 'Enter project key here' codeScanUrl: 'Enter your instance URL' login: ${{ secrets.codescan_token }} generateSarifFile: true args: | sonar.pullrequest.branch=${{github.head_ref}} sonar.pullrequest.base=${{github.base_ref}} sonar.pullrequest.key=${{github.event.number}} - name: Upload SARIF file uses: github/codeql-action/upload-sarif@v3 with: sarif_file: codescan.sarif - name: Archive code coverage results uses: actions/upload-artifact@v4 with: name: codescan.sarif path: codescan.sarif
Option 2
name: CI on: push: branches: [main] pull_request: branches: [main] env: SONAR_SCANNER_VERSION: 5.0.1.3006 jobs: build: runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 - name: Cache files uses: actions/cache@v4 with: path: | ~/.sonar key: ${{ runner.os }}-sonar restore-keys: ${{ runner.os }}-sonar - name: Run Codescan On Push if: github.event_name == 'push' uses: codescan-io/[email protected] with: organization: 'Enter organization key here' projectKey: 'Enter project key here' codeScanUrl: 'Enter your instance URL' login: ${{ secrets.codescan_token }} generateSarifFile: true failOnRedQualityGate: true - name: Run Codescan On PR if: github.event_name == 'pull_request' uses: codescan-io/[email protected] with: organization: 'Enter organization key here' projectKey: 'Enter project key here' codeScanUrl: 'Enter your instance URL' login: ${{ secrets.codescan_token }} scanChangedFilesOnly: true generateSarifFile: true failOnRedQualityGate: true args: | sonar.pullrequest.branch=${{github.head_ref}} sonar.pullrequest.base=${{github.base_ref}} sonar.pullrequest.key=${{github.event.number}} - name: Upload SARIF file uses: github/codeql-action/upload-sarif@v3 with: sarif_file: codescan.sarif - name: Archive code coverage results uses: actions/upload-artifact@v4 with: name: codescan.sarif path: codescan.sarif
Handling Master/Main Branch Issue
After the first scan, a master branch may exist in CodeScan.
When switching to the second YAML, pushing to main may create an extra main branch.
Steps to resolve:
Delete the newly created main branch in CodeScan.
Rename the master branch to main.
Confirm the baseline analysis is associated with the main.
Second YAML – Multi-Branch Scan
name: CI env: SONAR_SCANNER_VERSION: 5.0.1.3006 SONAR_SOURCES: force-app on: push: branches: - '*' paths-ignore: - src/test/java/** - target/** pull_request: branches: - '*' paths-ignore: - src/test/java/** - target/** jobs: build: runs-on: macos-latest steps: - name: Checkout repository uses: actions/checkout@v4 with: fetch-depth: 0 - name: Cache files uses: actions/cache@v4 with: path: | ~/.sonar key: ${{ runner.os }}-sonar restore-keys: ${{ runner.os }}-sonar - name: Run Codescan On Push if: github.event_name == 'push' uses: codescan-io/[email protected] with: scanChangedFilesOnly: true organization: 'Enter organization key here' projectKey: 'Enter project key here' codeScanUrl: 'Enter your instance URL' login: ${{ secrets.codescan_token }} generateSarifFile: true args: | sonar.branch.name=${{ github.ref_name }} sonar.sources=${{ env.SONAR_SOURCES }} sonar.exclusions=target/**,src/test/java/** - name: Run Codescan On PR if: github.event_name == 'pull_request' uses: codescan-io/[email protected] with: scanChangedFilesOnly: true organization: 'Enter organization key here' projectKey: 'Enter project key here' codeScanUrl: 'Enter your instance URL' login: ${{ secrets.codescan_token }} generateSarifFile: true args: | sonar.pullrequest.key=${{ github.event.pull_request.number }} sonar.pullrequest.branch=${{ github.head_ref }} sonar.pullrequest.base=${{ github.base_ref }} sonar.sources=${{ env.SONAR_SOURCES }} sonar.exclusions=target/**,src/test/java/** - name: Upload SARIF file uses: github/codeql-action/upload-sarif@v3 with: sarif_file: codescan.sarif - name: Archive code coverage results uses: actions/upload-artifact@v4 with: name: codescan.sarif
Step-by-Step Workflow
Initial Baseline Scan
Add first YAML (Option 1 or 2) to scan main branch.
Push and verify baseline scan on CodeScan.
Branch Adjustment
Replace YAML with second YAML
Delete extra main branch in CodeScan if created.
Rename master to main.
Multi-Branch Scanning.
Push to other branches to enable scanning.
Verify SARIF upload and analysis in GitHub.
Notes & Considerations
Sonar/CodeScan limitations require the baseline to be on main/master first.
Always fetch full history for PR analysis (fetch-depth: 0).
SONAR_SOURCES: force-app Incase folder structure is other than DX
SONAR_SOURCES: src (or) .(. here represents the ROOT FOLDER)
Specifying Root Folder, CodeScan always scans the Root folder mentioned and files within it.
In scenarios where the customer has multiple root folders, using (.) will make sure every root folder in the repo is scanned.
Last updated
Was this helpful?