diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml index 27d076d..a6b4bb1 100644 --- a/.github/workflows/quality.yml +++ b/.github/workflows/quality.yml @@ -15,24 +15,24 @@ jobs: uses: actions/setup-java@v4 with: java-version: 17 - distribution: 'zulu' # Alternative distribution options are available. + distribution: "zulu" # Alternative distribution options are available - uses: actions/checkout@v4 with: - fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis - - name: Cache SonarCloud packages + fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis + - name: Cache SonarQube Cloud packages uses: actions/cache@v4 with: path: ~\sonar\cache key: ${{ runner.os }}-sonar restore-keys: ${{ runner.os }}-sonar - - name: Cache SonarCloud scanner + - name: Cache SonarQube Cloud scanner id: cache-sonar-scanner uses: actions/cache@v4 with: path: ${{ runner.temp }}\scanner key: ${{ runner.os }}-sonar-scanner restore-keys: ${{ runner.os }}-sonar-scanner - - name: Install SonarCloud scanner + - name: Install SonarQube Cloud scanner if: steps.cache-sonar-scanner.outputs.cache-hit != 'true' shell: pwsh run: | @@ -44,13 +44,13 @@ jobs: dotnet tool install --global dotnet-coverage - name: Build and analyze env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} shell: pwsh run: | $ErrorActionPreference = "Stop" $PSNativeCommandUseErrorActionPreference = $true - ${{ runner.temp }}\scanner\dotnet-sonarscanner begin /k:"rufer7_github-sonarcloud-integration" /o:"rufer7" /d:sonar.token="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.projectBaseDir="D:\a\github-sonarcloud-integration\github-sonarcloud-integration" /d:sonar.cs.vscoveragexml.reportsPaths=coverage.xml /d:sonar.terraform.provider.azure.version=3.100.0 + ${{ runner.temp }}\scanner\dotnet-sonarscanner begin /k:"rufer7_github-sonarcloud-integration" /o:"rufer7" /d:sonar.token="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.projectBaseDir="D:\a\github-sonarcloud-integration\github-sonarcloud-integration" /d:sonar.cs.vscoveragexml.reportsPaths=coverage.xml /d:sonar.terraform.provider.azure.version=3.100.0 /d:sonar.sca.resolveAsRoot=true dotnet build .\src\ArbitrarySolution.sln --configuration Release - dotnet-coverage collect 'dotnet test .\src\ArbitraryProject.Tests\ArbitraryProject.Tests.csproj' -f xml -o 'coverage.xml' + dotnet-coverage collect 'dotnet test .\src\ArbitraryProject.Tests\ArbitraryProject.Tests.csproj' -f xml -o 'coverage.xml' ${{ runner.temp }}\scanner\dotnet-sonarscanner end /d:sonar.token="${{ secrets.SONAR_TOKEN }}" diff --git a/.gitignore b/.gitignore index 16e8e0f..8a30d25 100644 --- a/.gitignore +++ b/.gitignore @@ -396,7 +396,3 @@ FodyWeavers.xsd # JetBrains Rider *.sln.iml - -# Sonar -# Uncomment the following line to avoid error message "There were errors in the dependency analysis" on the "Dependencies" tab in SoanrQube Cloud due to inclusion of scanner directory -# .sonar/* diff --git a/README.md b/README.md index 23f49f4..d2045cb 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ Scan and analyze GitHub repository with SonarQube Cloud ### Automatic Analysis > [!IMPORTANT] -> With Automatic Analysis for .Net, certain rules for .Net source code are automatically deactivated. This includes security rules, all rules that come from outside the Sonar Way quality profile, as well as certain rules from within it. +> With Automatic Analysis for .NET, certain rules for .NET source code are automatically deactivated. This includes security rules, all rules that come from outside the Sonar Way quality profile, as well as certain rules from within it. > [!NOTE] > Automatic analysis is only supported for GitHub repositories. If you are using a different version control system, you will need to use a different method to analyze your code. @@ -67,9 +67,9 @@ To include i.e. terraform files in the analysis of SonarScanner for .NET, the fo For more details see [here](https://docs.sonarsource.com/sonarqube/9.8/analyzing-source-code/scanners/sonarscanner-for-dotnet/#advanced-topics) -#### Include test coverage +#### Include .NET test coverage -To include test coverage in the analysis of SonarScanner for .NET, the following adjustments are required in the GitHub actions workflow (`.github/workflows/quality.yml`). +To include .NET test coverage in the analysis of SonarScanner for .NET, the following adjustments are required in the GitHub actions workflow (see `.github\workflows\quality.yml`). ```yaml # Install dotnet-coverage @@ -79,20 +79,25 @@ To include test coverage in the analysis of SonarScanner for .NET, the following dotnet tool install --global dotnet-coverage - name: Build and analyze env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} shell: pwsh run: | $ErrorActionPreference = "Stop" $PSNativeCommandUseErrorActionPreference = $true - # Add /d:sonar.cs.vscoveragexml.reportsPaths=coverage.xml - .\.sonar\scanner\dotnet-sonarscanner begin /k:"rufer7_github-sonarcloud-integration" /o:"rufer7" /d:sonar.token="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.projectBaseDir="D:\a\github-sonarcloud-integration\github-sonarcloud-integration" /d:sonar.cs.vscoveragexml.reportsPaths=coverage.xml + # Add /d:sonar.cs.vscoveragexml.reportsPaths=coverage.xml + ${{ runner.temp }}\scanner\dotnet-sonarscanner begin /k:"rufer7_github-sonarcloud-integration" /o:"rufer7" /d:sonar.token="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.projectBaseDir="D:\a\github-sonarcloud-integration\github-sonarcloud-integration" /d:sonar.cs.vscoveragexml.reportsPaths=coverage.xml /d:sonar.terraform.provider.azure.version=3.100.0 /d:sonar.sca.resolveAsRoot=true dotnet build .\src\ArbitrarySolution.sln --configuration Release - # Execute tests and collect coverage - dotnet-coverage collect 'dotnet test .\src\ArbitraryProject.Tests\ArbitraryProject.Tests.csproj' -f xml -o 'coverage.xml' - .\.sonar\scanner\dotnet-sonarscanner end /d:sonar.token="${{ secrets.SONAR_TOKEN }}" + # Execute tests and collect coverage + dotnet-coverage collect 'dotnet test .\src\ArbitraryProject.Tests\ArbitraryProject.Tests.csproj' -f xml -o 'coverage.xml' + ${{ runner.temp }}\scanner\dotnet-sonarscanner end /d:sonar.token="${{ secrets.SONAR_TOKEN }}" ``` +#### Software Composition Analysis (SCA) + +> [!IMPORTANT] +> Currently, it's required to set `sonar.sca.resolveAsRoot=true` in the `dotnet-sonarscanner` begin step to avoid `No lockfile was found for 'PATH_TO_PROJECT_FILE' (nuget)` warning on `Dependency Risks` and `Inventory` > `Dependencies` tabs + ## Scan Results ### SonarQube Cloud @@ -122,5 +127,7 @@ For an example, see [here](https://github.com/rufer7/github-sonarcloud-integrati - [SonarQube Cloud - Getting Started with GitHub](https://docs.sonarsource.com/sonarqube-cloud/getting-started/github/) - [Pull request analysis](https://docs.sonarsource.com/sonarqube-cloud/improving/pull-request-analysis/#existing-pull-requests-on-first-automatic-analysis) -- [.NET test coverage](https://docs.sonarsource.com/sonarqube/9.8/analyzing-source-code/test-coverage/dotnet-test-coverage/) -- [Github action should fail on authentication error](https://community.sonarsource.com/t/github-action-should-fail-on-authn-error/147720) +- [.NET test coverage](https://docs.sonarsource.com/sonarqube-server/analyzing-source-code/test-coverage/dotnet-test-coverage) +- [Github action should fail on authentication error](https://community.sonarsource.com/t/github-action-should-fail-on-authentication-error/147720) +- [Analysis of product projects vs. test projects](https://github.com/SonarSource/sonar-scanner-msbuild/wiki/Analysis-of-product-projects-vs.-test-projects) +- [Parameters not settable in the UI](https://docs.sonarsource.com/sonarqube-cloud/advanced-setup/analysis-parameters/parameters-not-settable-in-ui) diff --git a/deploy/iac/main.tf b/deploy/iac/main.tf index 44ac46c..f0a631a 100644 --- a/deploy/iac/main.tf +++ b/deploy/iac/main.tf @@ -16,7 +16,7 @@ resource "azurerm_storage_account" "sa" { account_replication_type = "GRS" shared_access_key_enabled = false default_to_oauth_authentication = true - min_tls_version = "TLS1_0" # Security issue to be detected by SonarCloud + min_tls_version = "TLS1_0" # Security issue to be detected by SonarQube Cloud } resource "azurerm_role_assignment" "blob-data-owner" { diff --git a/src/ArbitraryProject.Tests/ArbitraryProject.Tests.csproj b/src/ArbitraryProject.Tests/ArbitraryProject.Tests.csproj index e14706f..2dd0331 100644 --- a/src/ArbitraryProject.Tests/ArbitraryProject.Tests.csproj +++ b/src/ArbitraryProject.Tests/ArbitraryProject.Tests.csproj @@ -10,10 +10,17 @@ - - - - + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/src/ArbitraryProject/ArbitraryProject.csproj b/src/ArbitraryProject/ArbitraryProject.csproj index cf2ac82..08f6841 100644 --- a/src/ArbitraryProject/ArbitraryProject.csproj +++ b/src/ArbitraryProject/ArbitraryProject.csproj @@ -7,12 +7,12 @@ + - - + Never diff --git a/src/ArbitraryProject/Controllers/WeatherForecastController.cs b/src/ArbitraryProject/Controllers/WeatherForecastController.cs index eb0cf90..29c2716 100644 --- a/src/ArbitraryProject/Controllers/WeatherForecastController.cs +++ b/src/ArbitraryProject/Controllers/WeatherForecastController.cs @@ -6,10 +6,10 @@ namespace ArbitraryProject.Controllers [Route("[controller]")] public class WeatherForecastController : ControllerBase { - private static readonly string[] Summaries = new[] - { + private static readonly string[] Summaries = + [ "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" - }; + ]; private readonly ILogger _logger; @@ -21,13 +21,14 @@ public WeatherForecastController(ILogger logger) [HttpGet(Name = "GetWeatherForecast")] public IEnumerable Get() { - return Enumerable.Range(1, 5).Select(index => new WeatherForecast + _logger.LogInformation("Generating weather forecast data."); + + return [.. Enumerable.Range(1, 5).Select(index => new WeatherForecast { Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)), TemperatureC = Random.Shared.Next(-20, 55), Summary = Summaries[Random.Shared.Next(Summaries.Length)] - }) - .ToArray(); + })]; } } } diff --git a/src/ArbitraryProject/Program.cs b/src/ArbitraryProject/Program.cs index e1f5e3d..4179287 100644 --- a/src/ArbitraryProject/Program.cs +++ b/src/ArbitraryProject/Program.cs @@ -25,4 +25,4 @@ app.MapControllers(); -app.Run(); +await app.RunAsync();