I'm working on a c# .net6 project and I'm trying to integrate SonarCloud using GitHub Actions.
I have a build and sonarcloud workflow that looks like this:
name: .NET
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout#v2
- name: Setup .NET
uses: actions/setup-dotnet#v1
with:
dotnet-version: 6.0.x
- name: Restore dependencies
run: dotnet restore
working-directory: Backend
- name: Build
run: dotnet build --no-restore
working-directory: Backend
- name: Test
run: dotnet test --no-build --verbosity normal
working-directory: Backend
sonarcloud:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout#v2
with:
# Disabling shallow clone is recommended for improving relevancy of reporting
fetch-depth: 0
- name: SonarCloud Scan
uses: sonarsource/sonarcloud-github-action#master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
The build works fine and the tests are passing but sonarcloud is always showing no issue despite writing some code smells and duplications on purpose to see if it works.
Image
I see that sonarcloud is seeing all of my code so that shouldn't be a problem.
I have a sonar-project.properties file and an analysis is running every time there is either a push or a pull request so I guess the setup is good but I don't get why it doesn't report any issue, either code smells or duplicate code. Are there any more setups I should've made?
At SonarSource it states to not use the action if
You want to analyze a .NET solution
But instead:
Follow our interactive tutorial for Github Actions after importing your project directly in SonarCloud
That's probably because you have to call dotnet-sonarscanner begin before executing dotnet test and finish the analysis by invoking dotnet-sonarscanner end.
BTW: This also introduces a problem if you want to analyse PRs from a fork, since secrets are not passed to such PRs and using other triggers introduces high security risks. (see github-actions-preventing-pwn-requests)
Related
I am trying to establish a GitHub workflow with the help of GitHub Actions. Theoretically, the workflow would deploy any new changes to the web server each time a pull request is merged into the master branch.
This is my yaml file thus far:
name: .NET
on:
push:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout#v2
- name: Setup .NET
uses: actions/setup-dotnet#v1
with:
dotnet-version: 3.1.x
- name: Restore dependencies
run: dotnet restore src/my.Web.sln
- name: Build application
run: dotnet build src/my.Web.sln --no-restore
- name: Test application
run: dotnet test src/my.Web.sln --no-restore --verbosity normal
- name: Publish artifacts to default path
run: dotnet publish src/my.Web.sln
- name: Upload build artifacts for deployment
uses: actions/upload-artifact#v2
with:
name: Application
path: /home/runner/work/my-website/my-website/src/my.Web/bin/Debug/netcoreapp3.1/publish/
I can download the artifacts after each merge fine, but all the .dll files are uploaded even though I only want the ones that were updated in the most recent push.
Stack Overflow answers on other questions suggested adding fetch-depth: 0 under the actions/checkout#v2 step to get only the latest push, but all the files of the application are still uploaded.
I have a dotnet project and am trying to build a CI/CD pipeline that does the following using Github Actions:
Builds the project on a PR or master change.
Tests the project on a PR or master change.
On a master change calculates a semver (ideally a changelog too but that's less important).
On a master change uses this semver, builds a nuget package, and publishes it to GitHub and Nuget.
So far, I have this workflow that builds and tests my project. This seems to work nicely. However, it also has a publish step, which never seems to be run (I guess the if is wrong(?)) and I'm really not sure where to start with the SemVer part of what I want.
name: .NET Build, Test and Publish
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
env:
DISCOS_API_KEY: ${{ secrets.DISCOS_API_KEY }}
DISCOS_API_URL: http://localhost:3000/api/
steps:
- uses: actions/checkout#v2
with:
submodules: recursive
- name: Build docker stack
run: docker-compose -f src/DISCOSweb-Sdk/DISCOSweb-Sdk.Tests/docker-compose.yml up -d --force-recreate --build
- name: Setup .NET
uses: actions/setup-dotnet#v1
with:
dotnet-version: 6.0.x
- name: Restore dependencies
run: dotnet restore src/DISCOSweb-Sdk/DISCOSweb-Sdk.sln
- name: Build
run: dotnet build --no-restore src/DISCOSweb-Sdk/DISCOSweb-Sdk.sln
- name: Test
run: dotnet test --no-build --verbosity normal src/DISCOSweb-Sdk/DISCOSweb-Sdk.sln
publish: # This stage is never run
if: github.event.pull_request.merged == 'true'
needs: build
runs-on: ubuntu-latest
steps:
- name: Publish
id: publish_nuget
uses: brandedoutcast/publish-nuget#v2
with:
PACKAGE_NAME: DISCOSweb-Sdk
PROJECT_FILE_PATH: "**/DISCOSweb-Sdk.csproj"
BUILD_CONFIGURATION: Release
NUGET_KEY: ${{secrets.NUGET_KEY}}
VERSION_STATIC: 1.0.0 # Replace with something better
I feel like this should be a relatively common and straightforward thing to do so any assistance would be really appreciated.
I managed to accomplish this by splitting my CI and CD workflows, and making use of some very helpful packages.
CI Workflow
This first workflow runs on PRs and pushes to master. It's worth noting that when branch protection is on, a push to master is synonymous with a merged PR.
name: .NET Continuous Integration
on:
pull_request:
branches: [ master ]
push:
branches: [ master ]
jobs:
test:
name: Test Project (Mock API)
runs-on: ubuntu-latest
env:
DISCOS_API_KEY: ${{ secrets.DISCOS_API_KEY }}
DISCOS_API_URL: http://localhost:3000/api/
steps:
- uses: actions/checkout#v3
- name: Setup .NET
uses: actions/setup-dotnet#v2
with:
dotnet-version: 6.0.x
- name: Build docker stack
run: docker-compose -f ./src/DiscosWebSdk/DiscosWebSdk.Tests/docker-compose.yml up -d --force-recreate --build
- name: Run tests against mock API
run: dotnet test --logger GitHubActions ./src/DiscosWebSdk/DiscosWebSdk.sln
CD Workflow
There's a bit more to the CD workflow. It runs on pushes to master but only when there are changes made to the folder containing the actual source code for the SDK (that's what the paths block does).
I then used the mathieudutour/github-tag-action#v6.0 action to tag the commit with a calculated semantic version (calculated using conventional commits).
The package build is then tagged with this version using the -p:PackageVersion=${{ steps.tag_version.outputs.new_version }} option on dotnet nuget pack.
The ncipollo/release-action#v1 also creates a release on Github.
Finally, building and pushing the release to Github and Nuget is done using dotnet nuget push as usual.
name: .NET Continuous Deployment
on:
push:
branches: [ master ]
paths:
- src/DiscosWebSdk/DiscosWebSdk/**
workflow_dispatch:
jobs:
test:
name: Test Project (Real API)
runs-on: ubuntu-latest
env:
DISCOS_API_KEY: ${{ secrets.DISCOS_API_KEY }}
DISCOS_API_URL: https://discosweb.esoc.esa.int/api/
steps:
- uses: actions/checkout#v3
- name: Setup .NET
uses: actions/setup-dotnet#v2
with:
dotnet-version: 6.0.x
- name: Test against real API
run: dotnet test --logger GitHubActions ./src/DiscosWebSdk/DiscosWebSdk.sln
semantic-release:
needs: test
name: Create a Package Release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout#v3 # Need the full commit history for conventional commit
- name: Setup .NET
uses: actions/setup-dotnet#v2
with:
dotnet-version: 6.0.x
- name: Bump version and push tag
id: tag_version
uses: mathieudutour/github-tag-action#v6.0
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
- name: Create a GitHub release
uses: ncipollo/release-action#v1
with:
tag: ${{ steps.tag_version.outputs.new_tag }}
name: Release ${{ steps.tag_version.outputs.new_tag }}
body: ${{ steps.tag_version.outputs.changelog }}
- name: Create Nuget Package
run: dotnet build -c Release ./src/DiscosWebSdk/DiscosWebSdk/DiscosWebSdk.csproj && dotnet pack -c Release -p:PackageVersion=${{ steps.tag_version.outputs.new_version }} -o . ./src/DiscosWebSdk/DiscosWebSdk/DiscosWebSdk.csproj
- name: Upload Package for Publishing
uses: actions/upload-artifact#v3
with:
name: PackedLib
path: ./*.nupkg
github-publish:
needs: semantic-release
name: Publish to Github
runs-on: ubuntu-latest
steps:
- name: Download built project
uses: actions/download-artifact#v3
with:
name: PackedLib
- name: Setup .NET
uses: actions/setup-dotnet#v2
with:
dotnet-version: 6.0.x
- name: Push Package to GitHub
run: dotnet nuget push --api-key ${{secrets.GITHUB_TOKEN}} --source "https://nuget.pkg.github.com/hughesjs/index.json" *.nupkg
nuget-publish:
needs: semantic-release
name: Publish to Nuget
runs-on: ubuntu-latest
steps:
- name: Download built project
uses: actions/download-artifact#v3
with:
name: PackedLib
- name: Setup .NET
uses: actions/setup-dotnet#v2
with:
dotnet-version: 6.0.x
- name: Push Package to Nuget
run: dotnet nuget push --api-key ${{secrets.NUGET_KEY}} --source "https://api.nuget.org/v3/index.json" *.nupkg
I'm trying to contribute to a great project (https://github.com/billbogaiv/hybrid-model-binding) - I want to update the target framework and set up tests.
My fork: https://github.com/Misiu/hybrid-model-binding/tree/tests
I've updated the project from netstandard2.1 to netcoreapp3.1 and everything works fine.
So now I have 3 projects in the solution:
HybridModelBinding - main library project
AspNetCoreWebApplication - project with samples
HybridModelBinding.UnitTests - project that will contain unit tests
I'd like my tests to run on multiple dotnet versions, so I've added this workflow:
name: .NET Core
# Trigger event on a push or pull request
on: [push, pull_request]
# Jobs that run in parallel
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
dotnet-version: [ '3.1.x','5.0.x', '6.0.x' ]
# Steps that run sequentially
steps:
- name: Checkout
uses: actions/checkout#v2
- name: Setup .NET Core SDK ${{ matrix.dotnet-version }}
uses: actions/setup-dotnet#v1.7.2
with:
dotnet-version: ${{ matrix.dotnet-version }}
- name: Install dependencies
run: dotnet restore
- name: Build
run: dotnet build --configuration Release --no-restore
- name: Test
run: dotnet test --no-restore --verbosity normal
So in theory everything should be built and run on 3 runtimes.
The first build works fine (on 3.1.x), but the second and third throw errors:
Test run for
/home/runner/work/hybrid-model-binding/hybrid-model-binding/tests/HybridModelBinding.UnitTests/bin/Debug/netcoreapp3.1/HybridModelBinding.UnitTests.dll
(.NETCoreApp,Version=v3.1) Microsoft (R) Test Execution Command Line
Tool Version 16.11.0 Copyright (c) Microsoft Corporation. All rights
reserved.
Starting test execution, please wait... A total of 1 test files
matched the specified pattern. Testhost process exited with error: It
was not possible to find any compatible framework version The
framework 'Microsoft.AspNetCore.App', version '3.1.0' was not found.
The following frameworks were found:
5.0.14 at [/home/runner/.dotnet/shared/Microsoft.AspNetCore.App] You can resolve the problem by installing the specified framework
and/or SDK. The specified framework can be found at:
https://aka.ms/dotnet-core-applaunch?framework=Microsoft.AspNetCore.App&framework_version=3.1.0&arch=x64&rid=ubuntu.20.04-x64
. Please check the diagnostic logs for more information.
Test Run Aborted.
3>Done Building Project "/home/runner/work/hybrid-model-binding/hybrid-model-binding/tests/HybridModelBinding.UnitTests/HybridModelBinding.UnitTests.csproj"
(VSTest target(s)) -- FAILED.
1>Done Building Project "/home/runner/work/hybrid-model-binding/hybrid-model-binding/HybridModelBinding.sln"
(VSTest target(s)) -- FAILED.
Build FAILED.
Build summary: https://github.com/Misiu/hybrid-model-binding/runs/5392702331?check_suite_focus=true
I can compile projects locally and run the tests, but I'd like to run them on GitHub, so in the future, we can add more tests and develop the library easier.
Specify the Target framework monikers (TFMs) via include under the matrix and specify the framework for dotnet test by adding the argument -f=${{ matrix.tfm }}.
name: .NET Core
# Trigger event on a push or pull request
on: [push, pull_request]
# Jobs that run in parallel
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
include:
- dotnet-version: '3.1.x'
tfm: 'netcoreapp3.1'
- dotnet-version: '5.0.x'
tfm: 'net5.0'
- dotnet-version: '6.0.x'
tfm: 'net6.0'
# Steps that run sequentially
steps:
- name: Checkout
uses: actions/checkout#v2
- name: Setup .NET Core SDK ${{ matrix.dotnet-version }}
uses: actions/setup-dotnet#v1.7.2
with:
dotnet-version: ${{ matrix.dotnet-version }}
- name: Install dependencies
run: dotnet restore -p:TargetFramework=${{ matrix.tfm }}
- name: Build
run: dotnet build --configuration Release --no-restore
- name: Test
run: dotnet test --no-restore --verbosity normal -f=${{ matrix.tfm }}
Sources
https://learn.microsoft.com/en-us/dotnet/standard/frameworks#supported-target-frameworks
https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-test#options
https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#using-environment-variables-in-a-matrix
I have a .Net 5 solution with multiple xUnit test projects which is a public repository hosted on Github. I would like to generate code coverage reports and display them on Codecov.
First I run
dotnet add package coverlet.msbuild
for each test project. I know that I can navigate to the .sln directory and generate a new report via
dotnet test /p:CollectCoverage=true
I authorized Codecov, so it knows about this project. I think only the main and dev branches are relevant so I started with this workflow
name: Generate coverage report on push
on:
push:
branches:
- 'main'
- 'dev'
jobs:
generate-coverage-report-on-push:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./DirectoryWithSlnFile
steps:
- uses: actions/checkout#v2
- name: Setup .NET
uses: actions/setup-dotnet#v1
with:
dotnet-version: 5.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build project
run: dotnet build --no-restore
- name: Generate coverage report
run: dotnet test --no-build --verbosity normal /p:CollectCoverage=true
What needs to be done now to upload the report from all test projects to Codecov? E.g.
- name: Upload coverage report
run: upload to Codecov with CODECOV_TOKEN if pushed on main or dev
I just stumbled upon this when having the same question. This is how I made it work.
First, the step you already had but just for completeness. Add coverlet to the test project(s):
dotnet add package coverlet.msbuild
Then, in the GitHub Actions workflow file, add the following steps:
- name: Test
run: dotnet test --no-build --verbosity normal /p:CollectCoverage=true /p:CoverletOutputFormat=opencover
- name: Codecov
uses: codecov/codecov-action#v2
with:
file: coverage.opencover.xml
directory: FUI.Tests
I am trying to deploy an app with github actions. I linked my azure account to my github repository and the following actions has been created:
name: Build and deploy ASP.Net Core app to Azure Web App - my_app_name
on:
push:
branches:
- master
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout#master
- name: Set up .NET Core
uses: actions/setup-dotnet#v1
with:
dotnet-version: '3.1.102'
- name: Build with dotnet
run: dotnet build --configuration Release
- name: dotnet publish
run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/myapp
- name: Deploy to Azure Web App
uses: azure/webapps-deploy#v1
with:
app-name: 'my_app_name'
slot-name: 'production'
publish-profile: ${{ secrets.AzureAppService_PublishProfile_xxxxxx }}
package: ${{env.DOTNET_ROOT}}/myapp
I have some variables in my appsettings.json file that I want to overwrite, but I don't find how to do it.
You may add the following action prior to deploying the artifacts to azure.
You can specify multiple files and it is supported with wildcard entries too.
The environment variable key must be specified with dot separated heirarchy.
#substitute production appsettings entries to appsettings json file
- name: App Settings Variable Substitution
uses: microsoft/variable-substitution#v1
with:
files: '${{env.DOTNET_ROOT}}/myapp/appsettings.json'
env:
ConnectionStrings.Default: ${{ secrets.SOME_CONNECTION_STRING }}
App.ServerRootAddress: ${{ env.SERVER_ROOT_ADDRESS }}
The above action can be used for xml and yaml file changes too.