SonarCloud integration
How to integrate your workflows with SonarCloud using codemagic.yaml
SonarCloud is SonarQube’s cloud-based code quality and code security service for projects hosted in cloud-based Git repositories such as GitHub, Bitbucket, GitLab and Azure DevOps. It can be used as part of your CI/CD workflow to analyse your code each time you commit new code.
Sample projects that show how to configure SonarQube / SonarCloud integration are available in our sample projects repository for Android and iOS.
Create a SonarCloud account
You will need access to a SonarCloud account and can sign up for free. This will allow you to work with public repositories.
Add your app to SonarCloud
- Log into SonarCloud here
- Enter an organization key and click on Continue.
- Choose the Free plan and click on Create Organization.
- Click on My Account.
- Under the Security tab, generate a token by entering a name and clicking on Generate.
- Copy the token so you can use it as an environment variable in your Codemagic workflow.
- Click on the “+” button in the top-right corner, and select Analyze a new project to add a new project.
- Select the project and click on Set Up.
- Wait for the initial analysis to complete, then modify the Last analysis method.
- Turn off the SonarCloud Automatic Analysis.
You can now upload code analysis reports to SonarCloud from your CI/CD pipeline.
Configuring access to SonarCloud in Codemagic
There are three environment variables that need to be added to your workflow for the SonarCloud integration: SONAR_TOKEN, SONAR_PROJECT_KEY, and SONAR_ORG_KEY.
- SONAR_TOKENis the token you created when setting up your account
- SONAR_PROJECT_KEYcan be obtained from your project settings once it has been added to SonarCloud
- SONAR_ORG_KEYis also obtained from your SonarCloud project settings
- Open your Codemagic app settings, and go to the Environment variables tab. 
- Enter the desired Variable name, e.g. - SONAR_TOKEN.
- Enter the required value as Variable value. 
- Enter the variable group name, e.g. sonarcloud_credentials. Click the button to create the group. 
- Make sure the Secret option is selected. 
- Click the Add button to add the variable. 
- Repeat the process to add all of the required variables. 
- Add the sonarcloud_credentials group in your - codemagic.yamlfile
  environment:
    groups:
      - sonarcloud_credentialsPlatform specific configuration
To use SonarCloud with Android projects, you need to add the sonarqube plugin to the app/build.gradle file:
plugins {
    ...
    id "org.sonarqube" version "3.3"
    ...
}You also need to set Sonarcloud properties in the same app/build.gradle file
sonarqube {
    properties {
        property "sonar.host.url", "https://sonarcloud.io"
        property "sonar.branch", System.getenv("CM_BRANCH")
        property "sonar.projectKey", System.getenv("SONAR_PROJECT_KEY")
        property "sonar.organization", System.getenv("SONAR_ORG_KEY")
        property "sonar.branch.name", System.getenv("CM_BRANCH")
        property "sonar.branch.target", System.getenv("CM_PULL_REQUEST_DEST")
        property "sonar.login", System.getenv("SONAR_TOKEN")
    }
}Finally, add the scripts to build the debug version and generate the analysis report to your codemagic.yaml file
  scripts:
    - name: Generate debug build
      script: | 
        ./gradlew assembleDebug        
    - name: Generate and upload code analysis report
      script: | 
        ./gradlew sonarqubeAn Android sample project that shows how to configure SonarCloud integration is available here
To use SonarCloud with iOS projects, you need to:
- install the Sonar Scanner
- generate a debug build of your project
- convert the coverage report to Sonarqube format
- generate and upload code analysis report
To convert the coverage report to Sonarqube format, create a bash script in your project’s root folder named xccov-to-sonarqube-generic.sh with the following content:
#!/usr/bin/env bash
set -euo pipefail
function convert_file {
  local xccovarchive_file="$1"
  local file_name="$2"
  local xccov_options="$3"
  echo "  <file path=\"$file_name\">"
  xcrun xccov view $xccov_options --file "$file_name" "$xccovarchive_file" | \
    sed -n '
    s/^ *\([0-9][0-9]*\): 0.*$/    <lineToCover lineNumber="\1" covered="false"\/>/p;
    s/^ *\([0-9][0-9]*\): [1-9].*$/    <lineToCover lineNumber="\1" covered="true"\/>/p
    '
  echo '  </file>'
}
function xccov_to_generic {
  echo '<coverage version="1">'
  for xccovarchive_file in "$@"; do
    if [[ ! -d $xccovarchive_file ]]
    then
      echo "Coverage FILE NOT FOUND AT PATH: $xccovarchive_file" 1>&2;
      exit 1
    fi
    local xccov_options=""
    if [[ $xccovarchive_file == *".xcresult"* ]]; then
      xccov_options="--archive"
    fi
    xcrun xccov view $xccov_options --file-list "$xccovarchive_file" | while read -r file_name; do
      convert_file "$xccovarchive_file" "$file_name" "$xccov_options"
    done
  done
  echo '</coverage>'
}
xccov_to_generic "$@"All of the other steps will be performed using scripts in your codemagic.yaml file:
  scripts:
    - name: Install Sonar Scanner
      script: | 
        brew install sonar-scanner
    - name: Generate debug build
      script: | 
        xcodebuild \
          -project "$XCODE_PROJECT" \
          -scheme "$XCODE_SCHEME" \
          -sdk iphonesimulator \
          -destination 'platform=iOS Simulator,name=iPhone 12 Pro,OS=14.5' \
          -derivedDataPath Build/ \
          -enableCodeCoverage YES \
          clean build test CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO
    - name: Convert coverage report to Sonarqube format
      script: | 
        bash xccov-to-sonarqube-generic.sh Build/Logs/Test/*.xcresult/ > sonarqube-generic-coverage.xml
    - name: Generate and upload code analysis report
      script: | 
        export PATH=$PATH:$CM_BUILD_DIR/sonar-scanner/bin    
        sonar-scanner \
          -Dsonar.projectKey=$SONAR_PROJECT_KEY \
          -Dsonar.organization=$SONAR_ORG_KEY \
          -Dsonar.host.url=https://sonarcloud.io \
          -Dsonar.login=$SONAR_TOKEN \
          -Dsonar.projectVersion=1.0.0 \
          -Dsonar.sources=. \
          -Dsonar.cfamily.build-wrapper-output.bypass=true \
          -Dsonar.coverageReportPaths=sonarqube-generic-coverage.xml \
          -Dsonar.c.file.suffixes=- \
          -Dsonar.cpp.file.suffixes=- \
          -Dsonar.objc.file.suffixes=-An iOS sample project that shows how to configure SonarCloud integration is available here