DEV Community

lastlink
lastlink

Posted on

dotnet-ci-pipelines

My Workflow

Note: # description: A project to demonstrate using github actions for a .net core 3.1 project. Uses unit tests, json snapshots, database tests using docker service containers. Demonstrates their use in github actions, bitbucket, azure devops, and gitlab.

Submission Category:

Note: # Maintainer Must-Haves

Yaml File or Link to Code

GitHub logo lastlink / dotnet-ci-pipelines

dotnet ci cd pipelines for github, azure devops, gitlab, bitbucket, and etc.

DOTNET CORE CI PIPELINE EXAMPLE:

Goal to have dotnet core c# example pipelines for major git source control dev ops including github, azure devops, gitlab, bitbucket, and etc. Should auto run only on a new pull request, show test results in native ui per website, code coverage, and some additional manual steps running code quality analysis. Badge support native is also nice or from https://shields.io/category/build. Also will try service containers and database unit tests Originally off of gitlab-ci-example-dotnetcore.

Contribution

  • Please do a pull request to the proper source control pipeline that you are trying to update.

TOC

  • limits 2,000 (per month) to 20 concurrent jobs support windows, ubuntu, mac
    • doesn't currently support retry and max timeout although will cancel when limit reached.
  • Badges - workflow
  • api docs - docfx html only
  • [!] Tests - noโ€ฆ

name: .NET Core

# use https://marketplace.visualstudio.com/items?itemName=me-dutour-mathieu.vscode-github-actions to validate yml in vscode
env:
  NUGET_PACKAGES_DIRECTORY: '.nupkg'
  RESHARPER_CLI_NAME: 'JetBrains.ReSharper.CommandLineTools.Unix'
  RESHARPER_CLI_VERSION: "2019.2.3"
  DOCKER_DRIVER: overlay
  CONTAINER_IMAGE: codeclimate/codeclimate
  CONTAINER_TAG: '0.85.2'
  rIds: ${{ secrets.rIds }}
  dotnetVersion: 3.1.102

on:
  pull_request:
    branches:
      - master
  push:
    branches:
      - master

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v1
    - name: Setup .NET Core
      uses: actions/setup-dotnet@v1
      with:
        dotnet-version: ${{ env.dotnetVersion}}
    - name: Build with dotnet
      run: |
        export DOTNET_CLI_TELEMETRY_OPTOUT=1
        dotnet publish -c Release
    - name: Tests
      run: |
        cp MyProject.Repository.Test/Data/appSettings.gitlab.json MyProject.Repository.Test/Data/AppSettings.json
        dotnet test --logger "junit" /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:CoverletOutput='./TestResults/'
    - name: Coverage Report
      run: |
        dotnet --version
        dotnet tool install dotnet-reportgenerator-globaltool --tool-path tools
        ./tools/reportgenerator "-reports:**/TestResults/coverage.opencover.xml;" "-targetdir:Reports" -reportTypes:TextSummary;
        ./tools/reportgenerator "-reports:**/TestResults/coverage.opencover.xml;" "-targetdir:Reports" -reportTypes:Html;
        ./tools/reportgenerator "-reports:**/TestResults/coverage.opencover.xml;" "-targetdir:Reports" -reportTypes:Badges;
        cat ./Reports/Summary.txt
    - uses: actions/upload-artifact@v1
      with:
          name: CodeCoverage
          path: Reports
    - name: Resharper Code Quality
      run: |
        # apt update && apt install -y curl zip unzip
        curl -LO "https://download.jetbrains.com/resharper/ReSharperUltimate.$RESHARPER_CLI_VERSION/$RESHARPER_CLI_NAME.$RESHARPER_CLI_VERSION.zip"
        unzip -q $RESHARPER_CLI_NAME.$RESHARPER_CLI_VERSION.zip -d "resharper"
        mkdir -p CodeQuality
        files=(*.sln)
        sh ./resharper/dupfinder.sh "${files[0]}" --output=CodeQuality/dupfinderReport.html --format=Html
        sh ./resharper/inspectcode.sh "${files[0]}" --output=CodeQuality/inspectcodeReport.html --format=Html
    - uses: actions/upload-artifact@v1
      with:
          name: CodeQuality
          path: CodeQuality
    - name: prerelease
      if: ${{ env.rIds }} != ''
      run: |
        echo 'build, obfuscate, and release'
        dotnet tool install Obfuscar.GlobalTool --tool-path tools --version 2.2.28
        bash scripts/extractRelease.sh
        export rIds=${{ env.rIds }}
        bash ./scripts/pipeline.sh
        bash ./scripts/finalRelease.sh
    - name: upload release
      uses: actions/upload-artifact@v2
      if: ${{ env.rIds }} != ''
      with:
        name: Release_unix
        path: Release/post

  build-win:
    runs-on: windows-latest
    steps:
    - uses: actions/checkout@v1
    - name: Setup .NET Core
      uses: actions/setup-dotnet@v1
      with:
        dotnet-version: ${{ env.dotnetVersion}}
    - name: Build with dotnet
      run: |
        set DOTNET_CLI_TELEMETRY_OPTOUT=1
        dotnet publish -c Release
    - name: Tests
      run: |
        copy MyProject.Repository.Test/Data/appSettings.gitlab.json MyProject.Repository.Test/Data/AppSettings.json
        dotnet test --logger "junit" /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:CoverletOutput='.\TestResults\'
    - name: prerelease
      if: ${{ env.rIds }} != ''
      run: |
        echo "build, obfuscate, and release"
        dotnet tool install Obfuscar.GlobalTool --tool-path tools --version 2.2.28
        .\scripts\extractRelease.cmd
        set rIds=$env:rIds
        .\scripts\pipeline.cmd
        .\scripts\finalRelease.cmd
    - name: upload release
      uses: actions/upload-artifact@v2
      if: ${{ env.rIds }} != ''
      with:
        name: Release_win
        path: Release\post

  unit_test_db_mssql:
    runs-on: ubuntu-latest
    # Service containers to run with `runner-job`
    services:
      # Label used to access the service container
      localhost_mysql:
        # Docker Hub image
        image: mcr.microsoft.com/mssql/server:2019-latest
        #
        ports:
          # Opens tcp port 6379 on the host and service container
          - 1433:1433
        env:
          GIT_SUBMODULE_STRATEGY: recursive
          ACCEPT_EULA: Y
          SA_PASSWORD: yourStrong(!)Password
    steps:
    - uses: actions/checkout@v1
    - name: Setup .NET Core
      uses: actions/setup-dotnet@v1
      with:
        dotnet-version: ${{ env.dotnetVersion}}
    - name: enabledb
      run: cp ./MyProject.Repository.Test/Data/appSettings.bitbucket.mssql.json ./MyProject.Repository.Test/Data/AppSettings.json
    - name: Tests
      run: |
        cd MyProject.Repository.Test
        dotnet test --logger "junit" /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:CoverletOutput='./TestResults/'

  unit_test_db_postgres:
    runs-on: ubuntu-latest
    # Service containers to run with `runner-job`
    services:
      # Label used to access the service container
      redis:
        # Docker Hub image
        image: postgres:11
        #
        ports:
          - 5432:5432
        # Provide the password for postgres
        env:
          POSTGRES_DB: mockDb
          POSTGRES_USER: postgres
          POSTGRES_PASSWORD: "mysecretpassword"
          POSTGRES_HOST_AUTH_METHOD: trust
        # Set health checks to wait until postgres has started
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
    steps:
    - uses: actions/checkout@v1
    - name: Setup .NET Core
      uses: actions/setup-dotnet@v1
      with:
        dotnet-version: ${{ env.dotnetVersion}}
    - name: enabledb
      run: cp ./MyProject.Repository.Test/Data/appSettings.devops.postgres.json ./MyProject.Repository.Test/Data/AppSettings.json
    - name: Tests
      run: |
        cd MyProject.Repository.Test
        dotnet test --logger "junit" /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:CoverletOutput='./TestResults/'

  unit_test_db_mysql:
    runs-on: ubuntu-latest
    # Service containers to run with `runner-job`
    services:
      # Label used to access the service container
      redis:
        # Docker Hub image
        image: mysql:5.7.29
        #
        ports:
          - 3306:3306
        env:
          MYSQL_DATABASE: "mockDb"
          MYSQL_ROOT_PASSWORD: "mysecretpw"
    steps:
    - uses: actions/checkout@v1
    - name: Setup .NET Core
      uses: actions/setup-dotnet@v1
      with:
        dotnet-version: ${{ env.dotnetVersion}}
    - name: enabledb
      run: cp ./MyProject.Repository.Test/Data/appSettings.devops.mysql.json ./MyProject.Repository.Test/Data/AppSettings.json
    - name: Tests
      run: |
        cd MyProject.Repository.Test
        dotnet test --logger "junit" /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:CoverletOutput='./TestResults/'

  code_docs:
    runs-on: windows-latest
    name: code documentation
    steps:
      - uses: actions/checkout@v1
      - name: docfx
        run: |
          curl -LO "https://github.com/dotnet/docfx/releases/download/v2.48/docfx.zip"
          powershell.exe -NoP -NonI -Command "Expand-Archive '.\docfx.zip' '.\docfx\'" 
          ./docfx/docfx.exe
      - uses: actions/upload-artifact@v1
        with:
          name: CodeDocs
          path: _site

  security:
    runs-on: ubuntu-latest
    name: Snyk Security Scan
    steps:
      - uses: actions/checkout@v1
      - name: Setup .NET Core
        uses: actions/setup-dotnet@v1
        with:
          dotnet-version: ${{ env.dotnetVersion}}
      - name: Build with dotnet
        run: |
          export DOTNET_CLI_TELEMETRY_OPTOUT=1
          dotnet build
      - name: Run Snyk to check for vulnerabilities
        uses: snyk/actions/dotnet@master
        with:
          args: --file=MyProject.sln
        env:
          SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
Enter fullscreen mode Exit fullscreen mode

Additional Resources / Info

Note: # https://github.com/lastlink/dotnet-ci-pipelines/blob/master/.github/workflows/dotnetcore.yml

Note: # @lastlink

[Reminder]: # (Submissions are due on December 8th, 2021 (11:59 PM PT or 2 AM ET/6 AM UTC on December 9th).

Top comments (5)

Collapse
 
abhijit_sinha_ profile image
Abhijit Sinha

Hi!
Really thanks for the article.

I am facing one issue in my project.

Scenario:- project repository is available in GitHub and we have an azure devops pipeline for ci-cd tasks.
The only thing is not working is auto trigger.. i want to run the pipeline whenever someone approves the PR for the branch main automatically.
Can someone help me with this issue by writing a yml code?

Collapse
 
lastlink profile image
lastlink

There arenโ€™t triggers for approved pr. You can after an approved pr is merged have a trigger on the target branch like dev or master to auto run. If you have a pr trigger the pipeline will auto run when a pr is created and any changes pushed to the branch before the pipeline is merged. Another options is you can have manual approvals for stages in a pipeline that only run when approved. E.g. pr pipeline auto builds and runs tests, manual approval to deploy to dev.

Collapse
 
abhijit_sinha_ profile image
Abhijit Sinha

I want to build something like that only, like when the code is merge to dev it should trigger the azure pipeline to start run.

Any help writing yaml will be helpful.

Collapse
 
andresparrab profile image
Keny Andres Parra Bobadilla

Hi!
Thanks for this info, it help me understand better.
But i was wondering if you could help me with this task:
I want to deploy to azure let say a solution with both webjobs, webapp, etc to azure everything is in .Net exept the front end that is in Angular.
And i want to have a pipeline that look lite this:
build, test (unit, integration)-> deploy to DEV -> Deploy to Qa -> Deply to Staging -> swap to production.

I want to have this kind of pipeline so that i cant test my donet app in dev, end if every is working send it to acc and so on and so on.

I have look in google, youtube etc. but it seem dificult to find this info for .net with gitlab.

In azure devops you can choose like build for .net and will get lot of predifine task, like restore the solutionm download nugets, build the solution and zip in in an artifac. also for deply to different stages. But with gitlab i dont fins such things.
Sorry for the lon text.

Thank you in advance. anoob in gitlab

Collapse
 
anhnh1001 profile image
Huy Anh Nguyen

Thank you for the article, need to save it later for further learning.