Sonarqube scanner GitHub MacOS - Swift - Objective-C - Migration Azure to GitHub

Hi everyone,

  • Dev Platform: GitHub Enterprise
  • Sonarqube Scanner: Enterprise Edition Version 9.9 (build 65466)
  • Project type: iOS App (Swift & Objective-C)

What are you trying to achieve?

Migrate Sonarqube yml Pipeline from Azure to GitHub, so basically, I already have Sonarqube dashboard.

what have you tried so far to achieve this?

  1. Open GitHub
  2. Go to Code Scanning and search for Sonarqube plugin
  3. Press on “Configure” and start with default template
  4. In Sonarqube dashboard I set up in the DevOps settings GitHub and tried the configuration (Configuration valid)
  5. Created in GitHub the token secrets and host URL
  6. Tried to run and upload the code to my two branches on Sonar Dashboard
  7. I have a main branch and development branch in the app and I want to upload to Sonar Dashboard (I already have these branches created in the past when I used Azure Pipeline)

Default Template:

# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.

# This workflow helps you trigger a SonarQube analysis of your code and populates
# GitHub Code Scanning alerts with the vulnerabilities found.
# (this feature is available starting from SonarQube 9.7, Developer Edition and above)

# 1. Make sure you add a valid GitHub configuration to your SonarQube (Administration > DevOps platforms > GitHub)

# 2. Import your project on SonarQube
#     * Add your repository as a new project by clicking "Create project" from your homepage.
#
# 3. Select GitHub Actions as your CI and follow the tutorial
#     * a. Generate a new token and add it to your GitHub repository's secrets using the name SONAR_TOKEN
#          (On SonarQube, click on your avatar on top-right > My account > Security or ask your administrator)
#
#     * b. Copy/paste your SonarQube host URL to your GitHub repository's secrets using the name SONAR_HOST_URL
#
#     * c. Copy/paste the project Key into the args parameter below
#          (You'll find this information in SonarQube by following the tutorial or by clicking on Project Information at the top-right of your project's homepage)

# Feel free to take a look at our documentation (https://docs.sonarqube.org/latest/analysis/github-integration/)
# or reach out to our community forum if you need some help (https://community.sonarsource.com/c/sq/10)

name: SonarQube analysis

on:
  push:
    branches: [ "development", "main"]
  pull_request:
    branches: [ "development" ]
  workflow_dispatch:

permissions:
  pull-requests: read # allows SonarQube to decorate PRs with analysis results

jobs:
  Analysis:
    runs-on: ubuntu-latest

    steps:
      - name: Analyze with SonarQube

        # You can pin the exact commit or the version.
        # uses: SonarSource/sonarqube-scan-action@v1.1.0
        uses: SonarSource/sonarqube-scan-action@7295e71c9583053f5bf40e9d4068a0c974603ec8
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}  # Needed to get PR information
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}   # Generate a token on SonarQube, add it to the secrets of this repo with the name SONAR_TOKEN (Settings > Secrets > Actions > add new repository secret)
          SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}   # add the URL of your instance to the secrets of this repo with the name SONAR_HOST_URL (Settings > Secrets > Actions > add new repository secret)
        with:
          # Additional arguments for the sonarcloud scanner
          args:
            # Unique key of your project. You can find it in SonarQube > [my project] > Project Information (top-right menu)
            # mandatory
            -Dsonar.projectKey=
            # Comma-separated paths to directories containing main source files.
            #-Dsonar.sources= # optional, default is project base directory
            # When you need the analysis to take place in a directory other than the one from which it was launched
            #-Dsonar.projectBaseDir= # optional, default is .
            # Comma-separated paths to directories containing test source files.
            #-Dsonar.tests= # optional. For more info about Code Coverage, please refer to https://docs.sonarcloud.io/enriching/test-coverage/overview/
            # Adds more detail to both client and server-side analysis logs, activating DEBUG mode for the scanner, and adding client-side environment variables and system properties to the server-side log of analysis report processing.
            #-Dsonar.verbose= # optional, default is false

I changed it with required and mandatory field, but first of all I cannot run on macOS-latest because

SonarSource/sonarqube-scan-action@7295e71c9583053f5bf40e9d4068a0c974603ec8

got me this error:

Run SonarSource/sonarqube-scan-action@master
Error: Container action is only supported on Linux

It’s tough to implement (migrate) from Azure to GitHub.

My actual yml is this one (I’ll change some sensitive data)

# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.

# This workflow helps you trigger a SonarQube analysis of your code and populates
# GitHub Code Scanning alerts with the vulnerabilities found.
# (this feature is available starting from SonarQube 9.7, Developer Edition and above)

# 1. Make sure you add a valid GitHub configuration to your SonarQube (Administration > DevOps platforms > GitHub)

# 2. Import your project on SonarQube
#     * Add your repository as a new project by clicking "Create project" from your homepage.
#
# 3. Select GitHub Actions as your CI and follow the tutorial
#     * a. Generate a new token and add it to your GitHub repository's secrets using the name SONAR_TOKEN
#          (On SonarQube, click on your avatar on top-right > My account > Security or ask your administrator)
#
#     * b. Copy/paste your SonarQube host URL to your GitHub repository's secrets using the name SONAR_HOST_URL
#
#     * c. Copy/paste the project Key into the args parameter below
#          (You'll find this information in SonarQube by following the tutorial or by clicking on Project Information at the top-right of your project's homepage)

# Feel free to take a look at our documentation (https://docs.sonarqube.org/latest/analysis/github-integration/)
# or reach out to our community forum if you need some help (https://community.sonarsource.com/c/sq/10)

name: SonarQube Scan
on:
  workflow_dispatch:
jobs:
  AnalysisMacOS:
    runs-on: macos-latest

    steps:
      - name: Install sonar-scanner with brew and print the version
        run: |
          echo "Install sonar-scanner with brew and print the version"
          brew install sonar-scanner
          sonar-scanner --version
        shell: bash

      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 1
          ref: development

  AnalysisUbuntu:
    runs-on: ubuntu-latest

    steps:
      - name: Analyze with SonarQube
        uses: SonarSource/sonarqube-scan-action@master
        env:
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
          SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
        with:
          args: >
            -Dsonar.verbose=true
            -Dsonar.projectKey= -> pasted from Sonar settings
            -Dsonar.projectName= -> same here
            -Dsonar.tests=MyAppTests,**/*.swift
            -Dsonar.coverage.exclusions=**/*.xml,Pods/**/*,Reports/**/*,DerivedData/**/*,**/*.html,**
            -Dsonar.swift.simulator=platform=iOS Simulator,name=iPhone 14,OS=16.2
            -Dsonar.swift.project=MyApp.xcodeproj
            -Dsonar.swift.appName=MyAppName
            -Dsonar.swift.appScheme=MyAppName
            -Dsonar.swift.appConfiguration=Debug
            -Dsonar.sourceEncoding=UTF-8
 -Dsonar.swift.excludePathsFromCoverage=build,DerivedData,fastlane,Pods,reports,xcov_output
            -Dsonar.swift.excludedPathsFromCoverage=.*Tests.*
            -Dsonar.c.file.suffixes=-
            -Dsonar.objc.file.suffixes=.h,.m
            -Dsonar.cfamily.build-wrapper-output=build_wrapper_output_directory
            -Dsonar.swift.swiftlint.reportPaths=DerivedData/swiftlint.json
            -Dsonar.coverageReportPaths=DerivedData/sonarqube-converted.xml
            -Dsonar.cfamily.threads=4
            -Dsonar.branch.name=SonarBranchName
            -Dsonar.projectVersion= Get from Fastlane

  AnalysisMacOS_step2:
    runs-on: ${{ vars.CLOUDMACOSVERSION}}
    steps:
      - name: SwiftLint JSON for SonarQube
        run: |
          echo -e ">>> installing swiftlint <<<"
          brew install swiftlint
          echo -e ">>> entering source directory <<<"
          cd ${{ github.workspace }}
          echo -e ">>> creating swiftlint json file <<<"
          touch DerivedData/swiftlint.json
          echo -e ">>> running swiftlint with stock config <<<"
          swiftlint --config ${{ github.workspace }}/.swiftlint.yml --reporter json > DerivedData/swiftlint.json
          echo -e ">>> listing folder <<<"
          ls
        shell: bash

      - name: Set Up Fastlane -  Xcode Build with SonarQube Wrapper
        run: |
          fastlane xcodeSonarQubeEnterpriseBuild
        shell: bash

      - name: SonarQube Coverage (cococo) - No ObjC
        run: |
          echo -e "copying cococo command line into /usr/local/bin"
          cp cococo /usr/local/bin
          echo -e "generating code coverage without .h .m files for SonarQube"
          cococo DerivedData/Logs/Test/*.xcresult --excluded .h .m > DerivedData/sonarqube-converted.xml
        shell: bash
  • -Dsonar.swift.simulator=platform=iOS Simulator,name=iPhone 14,OS=16.2
    Not work I got this error → ERROR: Unrecognized option: Simulator,name=iPhone

  • ${{ github.workspace }}
    Not such file or directory

  • SwiftLint Installation

To reinstall 0.53.0, run:
  brew reinstall swiftlint
>>> entering source directory <<<
>>> creating swiftlint json file <<<
touch: DerivedData/swiftlint.json: No such file or directory
Error: Process completed with exit code 1.```
  • uses: SonarSource/sonarqube-scan-action@master
Run SonarSource/sonarqube-scan-action@master
Error: Container action is only supported on Linux
  • This fastlane xcodeSonarQubeEnterpriseBuild
lane :xcodeSonarQubeEnterpriseBuild do
    xcode_select("/Applications/Xcode_15.0.1.app")
    Dir.chdir("../") do
      begin
        sh("./fastlane/build-wrapper-macosx-x86 --out-dir build_wrapper_output_directory xcodebuild -workspace MyApp.xcworkspace -scheme MyApp -derivedDataPath DerivedData/ -enableCodeCoverage YES -destination 'platform=iOS Simulator,name=iPhone SE (3rd generation) (17.0)' clean build test")
      rescue => exception
        puts ""
      end
    end
  end

And this is some of errors. I also tried a lot of stuff to split in 3 Analisys, but not work.

Is there any “easy” way to implement it for iOS App with the above parameters?

thanks

Hey there.

I think this example Github repo should help you: GitHub - sonarsource-cfamily-examples/macos-xcode-gh-actions-sq: An example xcode configuration for C++ project on MacOS using GitHub Actions and analyzed on SonarQube

Hi,

done but I got this error

Run curl -sSLo $HOME/.sonar/build-wrapper-macosx-x86.zip ***/static/cpp/build-wrapper-macosx-x86.zip
  End-of-central-directory signature not found.  Either this file is not
Archive:  /Users/runner/.sonar/build-wrapper-macosx-x86.zip
  a zipfile, or it constitutes one disk of a multi-part archive.  In the
  latter case the central directory and zipfile comment will be found on
  the last disk(s) of this archive.
unzip:  cannot find zipfile directory in one of /Users/runner/.sonar/build-wrapper-macosx-x86.zip or
        /Users/runner/.sonar/build-wrapper-macosx-x86.zip.zip, and cannot find /Users/runner/.sonar/build-wrapper-macosx-x86.zip.ZIP, period.
Error: Process completed with exit code 9.

but my question is: why SonarQube and GitHub don’t they have full support for macOS as well as microsoft does?

Plugin used in Azure

  • SonarQubePrepare@4

  • SonarQubeAnalyze@4

  • SonarQubePublish@4

  • LINK

Azure DevOps server - build agents
If you are using Microsoft-hosted build agents

then there is nothing else to install. The extension will work with all of the hosted agents (Windows, Linux, and macOS).

(very hard to integrate in GitHub)

Is there any hope that we can reach the same level of support as on Microsft - Azure?

it’s a strong lack, almost enough to push us to abandon SonarQube as a static scan tool

Thanks

SonarQube’s GitHub Action (sonarqube-scan) is a Docker-based action, which only runs on Linux hosts.

I would like it if we moved to a Javascript action that worked cross-platform (which is actually how our Azure DevOps integration works), but that wasn’t available when the action was initially developed.

Is there any development planned to add MacOS compatibility, any release date?

For now, how can I solve the problem?

Do the first step on Ubunto and then launch the rest on Ubuntu?

Thanks again

The example offered for GitHub Actions + macOS typically works, so it’s odd that you get an issue related to unzipping the file.

Do you get the same results if you run the commands locally on macOS (exactly as they are written in the example)?

Right now, I don’t have an ETA for better GitHub actions support with macOS.

Hi, I hope SonarQube will be integrated very soon also for GitHub. Now is very a mess

Other questions about:

  • build-wrapper-macosx-x86

but I got this error:

:0: warning: legacy driver is now deprecated; consider avoiding specifying '-disallow-use-new-driver’build-wrapper: connect to /tmp/build-wrapper-socket.hMNfR9: Operation not permitted

My Fastlane is this one:

 lane :run_build do
    xcode_select("/Applications/#{Version::MyVersion}")
    Dir.chdir("../") do
      begin
        sh("./build-wrapper-macosx-x86 --out-dir build_wrapper_output_directory xcodebuild -workspace MyTarget.xcworkspace -scheme MyTarget -derivedDataPath DerivedData/ -enableCodeCoverage YES -destination 'platform=iOS Simulator,name=#{MyDevice}' clean build test")
      rescue => exception
        puts ""
      end
    end
  end

Is there a new build wrapper for Apple Silicon and MacOS 13 and above?

Or could you explain me how to write a correct fastlane in order to do the same thing?

I also added in sonar args:

-Dsonar.cfamily.compile-commands=compile_commands.json

Thanks for the help

Hey @salvatore.boemia

The build-wrapper is compatible with Apple Silicon starting in SonarQube v10.2 (the latest non-LTS version of SonarQube is v10.3)

A workaround to use the compilation database is identified in this ticket: [CPP-3987] - Jira

I’m using

  • SonarQube Enterprise Edition Version 10.2.1 (build 78527)
  • MacOS 13 (GitHub Runner Image)
  • Xcode 15.1 (GitHub Runner Image)

but the build-wrapper silent failed before invoking the sonar scanner action.

In MacOS Analysis, I invoke the lane in the Fastfile as pasted above.

I got a lot of errors like this errors during the lane execution, but the GitHub Action continued on error

[00:48:13]: <unknown>:0: warning: legacy driver is now deprecated; consider avoiding specifying '-disallow-use-new-driver'build-wrapper: connect to /tmp/build-wrapper-socket.fPkqxg: Operation not permitted

And I got this error during the GitHub Action on Ubuntu

2024-01-17T00:53:50.3193032Z java.lang.IllegalStateException: The "build-wrapper-dump.json" file was found empty. Please make sure that:
2024-01-17T00:53:50.3194416Z   * you are using the latest version of the build-wrapper and the CFamily analyzer
2024-01-17T00:53:50.3195244Z   * your compiler is supported
2024-01-17T00:53:50.3195876Z   * you are wrapping your build correctly
2024-01-17T00:53:50.3196434Z   * you are wrapping a full/clean build
2024-01-17T00:53:50.3197849Z   * if you are building your project inside a Docker container, build-wrapper is wrapping the build process inside the container and not wrapping the external Docker process
2024-01-17T00:53:50.3204305Z 	at com.sonar.cpp.plugin.CFamilySensor.process(CFamilySensor.java:602)

Do you have some other suggestions to achieve this?

Thanks

Hi

tried with compilation database but I got an error like this

INFO: Found empty cache on server
DEBUG: Shutting down the bridge server
DEBUG: The worker thread exited with code 1
DEBUG: The bridge server shut down
INFO: ------------------------------------------------------------------------
INFO: EXECUTION FAILURE
NFO: ------------------------------------------------------------------------
INFO: Total time: 6:08.633s
INFO: Final Memory: 335M/890M
ERROR: Error during SonarScanner execution
java.lang.IllegalStateException: java.nio.file.NoSuchFileException: /github/workspace/compile_commands.json
at com.sonar.cpp.plugin.CompileCommandsReader.readCaptures(CompileCommandsReader.java:65)
at com.sonar.cpp.plugin.CFamilySensor.process(CFamilySensor.java:1445)
at com.sonar.cpp.plugin.CFamilySensor.processConfigurationReader(CFamilySensor.java:750)
at com.sonar.cpp.plugin.CFamilySensor.lambda$process$4(CFamilySensor.java:468)
at java.base/java.lang.Iterable.forEach(Iterable.java:75)
at com.sonar.cpp.plugin.CFamilySensor.process(CFamilySensor.java:468)
at com.sonar.cpp.plugin.CFamilySensor.execute(CFamilySensor.java:241)
at org.sonar.scanner.sensor.AbstractSensorWrapper.analyse(AbstractSensorWrapper.java:64)
at org.sonar.scanner.sensor.ModuleSensorsExecutor.execute(ModuleSensorsExecutor.java:88)
at org.sonar.scanner.sensor.ModuleSensorsExecutor.execute(ModuleSensorsExecutor.java:64)
at org.sonar.scanner.scan.SpringModuleScanContainer.doAfterStart(SpringModuleScanContainer.java:82)
at org.sonar.core.platform.SpringComponentContainer.startComponents(SpringComponentContainer.java:201)
at org.sonar.core.platform.SpringComponentContainer.execute(SpringComponentContainer.java:180)
at org.sonar.scanner.scan.SpringProjectScanContainer.scan(SpringProjectScanContainer.java:398)
at org.sonar.scanner.scan.SpringProjectScanContainer.scanRecursively(SpringProjectScanContainer.java:394)
09:34:11.696 INFO: ------------------------------------------------------------------------
at org.sonar.scanner.scan.SpringProjectScanContainer.doAfterStart(SpringProjectScanContainer.java:363)
at org.sonar.core.platform.SpringComponentContainer.startComponents(SpringComponentContainer.java:201)
at org.sonar.core.platform.SpringComponentContainer.execute(SpringComponentContainer.java:180)
at org.sonar.scanner.bootstrap.SpringGlobalContainer.doAfterStart(SpringGlobalContainer.java:139)
at org.sonar.core.platform.SpringComponentContainer.startComponents(SpringComponentContainer.java:201)
at org.sonar.core.platform.SpringComponentContainer.execute(SpringComponentContainer.java:180)
at org.sonar.batch.bootstrapper.Batch.doExecute(Batch.java:71)
at org.sonar.batch.bootstrapper.Batch.execute(Batch.java:65)
at org.sonarsource.scanner.api.internal.batch.BatchIsolatedLauncher.execute(BatchIsolatedLauncher.java:46)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.sonarsource.scanner.api.internal.IsolatedLauncherProxy.invoke(IsolatedLauncherProxy.java:60)
at jdk.proxy1/jdk.proxy1.$Proxy0.execute(Unknown Source)
at org.sonarsource.scanner.api.EmbeddedScanner.doExecute(EmbeddedScanner.java:189)
at org.sonarsource.scanner.api.EmbeddedScanner.execute(EmbeddedScanner.java:138)
at org.sonarsource.scanner.cli.Main.execute(Main.java:126)
at org.sonarsource.scanner.cli.Main.execute(Main.java:81)
at org.sonarsource.scanner.cli.Main.main(Main.java:62)
Caused by: java.nio.file.NoSuchFileException: /github/workspace/compile_commands.json
at java.base/sun.nio.fs.UnixException.translateToIOException(UnixException.java:92)
at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:106)
at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:111)
at java.base/sun.nio.fs.UnixFileSystemProvider.newByteChannel(UnixFileSystemProvider.java:218)
at java.base/java.nio.file.Files.newByteChannel(Files.java:380)
at java.base/java.nio.file.Files.newByteChannel(Files.java:432)
at java.base/java.nio.file.spi.FileSystemProvider.newInputStream(FileSystemProvider.java:422)
at java.base/java.nio.file.Files.newInputStream(Files.java:160)
at java.base/java.nio.file.Files.newBufferedReader(Files.java:2922)
at java.base/java.nio.file.Files.newBufferedReader(Files.java:2955)
at com.sonar.cpp.plugin.CompileCommandsReader.readCaptures(CompileCommandsReader.java:55)
more

This is my lane

lane :run_xcodeSonarQubeEnterpriseBuild do
  xcode_select("/Applications/#{XcodeVersion::MyVersion}")

  # Configure CMake if your project uses it
  Dir.chdir("../") do
    begin
      sh("cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON .")
    rescue => exception
      puts "Error configuring CMake: #{exception.message}"
    end
  end

  # Generate Compilation Database in Xcode
  Dir.chdir("../") do
    begin
      sh("xcodebuild clean build OTHER_CFLAGS=\"\$(inherited) -gen-cdb-fragment-path \$(PROJECT_DIR)/CompilationDatabase\"")
      sh("pushd CompilationDatabase")
      sh("sed -e '1s/^/[\\'$'\\n''/' -e '$s/,$/\\'$'\\n'']/' *.json > ../compile_commands.json")
      sh("popd")
    rescue => exception
      puts "Error generating Compilation Database: #{exception.message}"
    end
  end

  # Execute build, test, etc. as desired
  Dir.chdir("../") do
    begin
      sh("xcodebuild -workspace MyApp.xcworkspace -scheme MyApp -derivedDataPath DerivedData/ -enableCodeCoverage YES -destination 'platform=iOS Simulator,name=#{MyDevice}' clean build test OTHER_CFLAGS=\"\$(inherited) -Xclang -load -Xclang #{Dir.pwd}/CompilationDatabase/libScanComponentsAST.dylib\"")
    rescue => exception
      puts "Error executing xcodebuild: #{exception.message}"
    end
  end
end

I really don’t know why it’s so hard to use Sonarqube + GitHub + Xcode

Any suggestion?

Thanks