Code isn't analyzed using Azure DevOps Unity 3D pipeline

Dear community,

in general, the idea is to build a project developed in Unity 3D via a pipeline so that we can analyze its code with SonarCloud.
The build of a Unity 3D application is first done via Unity itself, which creates a Visual Studio .sln. This in turn is used to create an App Package from the project.

To map this in Azure DevOps, we use the following extensions:

To build the pipeline, we used the following documentation:

https://sonarcloud.io/documentation/advanced-setup/ci-based-analysis/sonarscanner-for-dotnet/

The pipeline runs through successfully. SonarCloud also seems to work somehow. The problem, however, is that SonarCloud doesn’t seem to analyze any code. See screenshot:

Our pipeline.yaml file:

# This build pipeline is designed for ARM UWP projects, running Unity 2019.x or later, with MRTK Foundation 
# If using 2018.x or earlier: Change unity.installComponents to 'Windows, UWP_IL2CPP'
# If not using MRTK Foundation: Change unity.executeMethod to your build method (We recommend basing off the one in MRTK Foundation)
# If you want to build x86 UWP builds: In theory should just be able to change vs.appxPlatforms, but it's a TODO
 
# This pipeline depends on secret variables that you must define within your Azure DevOps!
#   unity.username  = <Your Unity account username / email>
#   unity.password  = <Your Unity account password>
#   unity.serialkey = <The serial key for your Unity pro licence>
# Without all three, this pipeline will fail to run!
 
# Unity will be licensed, used, and then unlicensed during the unity and unitytests jobs in this pipeline.
# A Pro license works on 2 machines, and in theory this pipeline will only use one licence at a time.
# However, should there be unexpected errors and deactivation doesn't complete properly, you may need to log into your Unity account and deactivate all.
 
# Variables predefined for this build process:
variables:
 
  # If true, will run tests, otherwise skip them. If you do not have tests, set to false to increase build speed.
  runTests: false
 
  # The path to the folder which contains the Assets folder of the project.
  # If your Unity project is located in a subfolder of your repo, make sure it is reflected in this.
  unity.projectPath:        '$(System.DefaultWorkingDirectory)/'
 
  # If you are using Unity 2019 or later, leave this alone!
  unity.installComponents:  'Windows, UWP'
  # If you are using Unity 2018 or earlier, comment out the above and uncomment below:
  #  unity.installComponents:  'Windows, UWP_IL2CPP'
  # Explanation: In Unity 2019 and later, .NET scripting was removed. You no longer need to specify 'UWP_IL2CPP', it's now simply 'UWP'!
 
  # The build method of the Unity project. This assumes you have MRTK in your project, and uses its build script.
  # If you want to customize your build script, change the method name here:
  unity.executeMethod:      'Microsoft.MixedReality.Toolkit.Build.Editor.UnityPlayerBuildTools.StartCommandLineBuild'
 
  # Are we buolding an .appx for x86 or ARM?
  # TODO: Theoretically, could expect to use 'x86|ARM' to build for both HL1 and 2, but yet to get that to work.
  vs.appxPlatforms:         'ARM'
 
  # I would not expect you to have to change the rest of these unless you had a special reason:
  unity.targetBuild:        'WindowsStoreApps'
  unity.outputPath:         '/Builds/WSAPlayer'
  unity.editorPath:         '/Editor/Unity.exe'
  vs.packagePath:           '/AppPackages'
 
  # This also needs to be passed to the install template, along with unity.projectPath
  unity.installFolder:      'C:/Program Files/Unity/Hub/Editor/'
  
# What causes us to build? A push to master or a feature branch causes us to build...
trigger:
  batch: true
  branches:
    include:
    - master
    - feature/*
 
# Windows machine with Visual Studio 2019:
pool:
  vmImage: 'windows-2019'
 
# Two jobs in this pipeline:
# - Build the Unity
# - Run Unity tests
# Note: The build job can be uncommented and broken up into two jobs, for when that makes sense.
jobs:
 
# Install Unity (from cache or download) then create Visual Studio project from Unity
- job: unity
  timeoutInMinutes: 0
  displayName: Unity Build
  variables:
    installCached: false
  # Try to ensure that we have the right secrets set up to continue, otherwise fail the job:
  condition: or( not(variables['unity.username']), not(variables['unity.password']), not(variables['unity.serialKey']) )
  steps:
  # What version of Unity does the project say that it wants?:
  - task: UnityGetProjectVersionTask@1
    name: unitygetprojectversion
    displayName: Calling UnityGetProjectVersionV1 from unity-azure-pipelines-tasks extension
    inputs:
      unityProjectPath: '$(unity.projectPath)'
 
# TODO: This is the start of code that is repeated in other jobs, and ought to be done via a seperate file template.
  # Do we have that Unity installation cached? If so, install from cache:
  # (Note: The key is the hashed contents of the ProjectVersion.txt file)
  # What is this? See https://docs.microsoft.com/en-us/azure/devops/pipelines/caching/index?view=azure-devops
  - task: CacheBeta@0
    displayName: Check if Unity installation is cached
    inputs:
      key: $(Agent.OS) | "$(unitygetprojectversion.projectVersion)" | "$(unity.installComponents)"
      path: "$(unity.installFolder)$(unitygetprojectversion.projectVersion)"
      cacheHitVar: installCached
 
  # Install the Unity setup module (if we aren't cached):
  - task: PowerShell@2  
    displayName: Install Unity
    condition: and(succeeded(), ne(variables['installCached'], true))
    inputs:
      targetType: 'inline'
      script: |
        Install-Module -Name UnitySetup -AllowPrerelease -Force -AcceptLicense
 
  # Download and run the installer for Unity Components defined in unity.installComponents:
  - task: PowerShell@2
    displayName: Installing Unity Components '$(unity.installComponents)'
    condition: and(succeeded(), ne(variables['installCached'], true))
    inputs:
      targetType: 'inline'
      script: |   
        Install-UnitySetupInstance -Installers (Find-UnitySetupInstaller -Version '$(unitygetprojectversion.projectVersion)' -Components $(unity.installComponents)) -Verbose
# TODO: This is the end of code that is repeated in other jobs, and ought to be done via a seperate file template.
 
  # Activate the Unity license (In theory, should deactivate the licence after use!):
  - task: UnityActivateLicenseTask@1
    displayName: Calling UnityActivateLicenseTask@1 from unity-azure-pipelines-tasks extension
    inputs:
      username: '$(unity.username)'
      password: '$(unity.password)'
      serial: '$(unity.serialkey)'
      unityEditorsPathMode: 'unityHub'
      unityProjectPath: '$(unity.projectPath)'
 
  # Build the project with Unity using the script defined in unity.executeMethod:
  - task: UnityBuildTask@3
    displayName: Calling UnityBuildTask@3 from unity-azure-pipelines-tasks extension
    name: runbuild
    inputs:
      buildScriptType: existing
      scriptExecuteMethod: '$(unity.executeMethod)'
      buildTarget: '$(unity.targetBuild)'
      unityProjectPath: '$(unity.projectPath)'
      outputPath: '$(Build.BinariesDirectory)'
 
  # Publish the Solution folder:
  - task: PublishPipelineArtifact@0
    displayName: 'Publish Pipeline Artifact'
    inputs:
      artifactName: 'sln'
      targetPath: '$(unity.projectPath)$(unity.outputPath)'
 
  - task: SonarCloudPrepare@1
    inputs:
      SonarCloud: 'SonarCloud'
      organization: 'nameOfOurOrganization'
      scannerMode: 'MSBuild'
      projectKey: 'ourProjectKey'
      projectName: 'ourProjectName'
      extraProperties: |
        sonar.verbose=true
 
  # Find, download, and cache NuGet:
  - task: NuGetToolInstaller@1
    displayName: 'Install NuGet'
 
  # Restore the NuGet packages for the solution:
  - task: NuGetCommand@2
    displayName: 'NuGet restore'
    inputs:
      restoreSolution: '$(unity.projectPath)$(unity.outputPath)/*.sln' # Change to '$(unity.projectPath)$(unity.outputPath)/*.sln' to resume two jobs
 
  # Build the solution with Visual Studio to make an .appx:
  - task: MSBuild@1
    displayName: 'Build solution'
    inputs:
      solution: '$(unity.projectPath)$(unity.outputPath)' # Change to '$(unity.projectPath)$(unity.outputPath)' to resume two jobs
      configuration: Release
      msbuildArguments: '/p:AppxBundle=Always /p:AppxBundlePlatforms="$(vs.appxPlatforms)" /p:PackageCertificatePassword="$(unity.CertificatePassword)"'
 
  # Publish the package (.appxbundle/.msixbundle) that we just built:
  - task: PublishPipelineArtifact@0
    displayName: 'Publish Pipeline Artifact'
    inputs:
      artifactName: 'apppackages'
      targetPath: '$(unity.projectPath)$(unity.outputPath)$(vs.packagePath)'  # Change to '$(unity.projectPath)$(unity.outputPath)$(vs.packagePath)' to resume two jobs
 
  - task: SonarCloudAnalyze@1
 
  - task: SonarCloudPublish@1
    inputs:
      pollingTimeoutSec: '300'

Our project properties (sonar-project.properties):

# must be unique in a given SonarQube instance
sonar.projectKey=ourProjectKey
 
# --- optional properties ---
 
# defaults to project key
#sonar.projectName=My project
# defaults to 'not provided'
#sonar.projectVersion=1.0
 
# Path is relative to the sonar-project.properties file. Defaults to .
sonar.sources=Assets
 
# Encoding of the source code. Default is default system encoding
#sonar.sourceEncoding=UTF-8

→ The path points to the directory where all C# files are located.

In the logs I could find for example the following WARNING:
WARN: Property missing: ‘sonar.cs.analyzer.projectOutPaths’.

So far we have not been able to find a solution.

We would appreciate if you could help us.

Thank you very much in advance!

Welcome to our Community @paulo_novatec !
Is your project private or public? If public, could you please share the repository and SonarCloud URLs?
I understood that the sonar-project.properties file is in a parent folder compared to the Assets folder, that is correct? Something like this:

/sonar-project.properties
/Assets/* (all source files)

If you have access to the logs, could you check if any file is analysed? You can also share this log with me in a private message, if you think is better!

Hi @Alexandre_Holzhey,
thank you very much for your response!
The project is private which is why I cant share the repo and SonarCloud URL with you.

I understood that the sonar-project.properties file is in a parent folder compared to the Assets folder, that is correct?

→ Yes that is correct.

I would really like to share the logs with you in a private message. Thank you so much!

Hey @Alexandre_Holzhey,

unfortunately I can’t write you any private messages, although I reached the necessary trust level…
Which is why you can find the logs below:

(logs removed for security)

I only posted the logs from the SonarCloud tasks. Please let me know if other ones would be interesting too :slight_smile:

Thank you very much in advance!

@paulo_novatec,

Can you confirm whether you are trying to analyze C# or C/C++ files, or both?

Earlier in the thread you mentioned C#, but there are no C# files referenced in the analysis log, only C/C++.

If you want to analyze C/C++ files then you need to use the CFamily build wrapper.