A GitHub Action Template for a dotnet NuGet package

I’ve recently been using GitHub Actions a lot more heavily and as you know, I have a lot of GitHub repositories that become NuGet packages. I have been using AppVeyor and have had no issues with it. The only reason I’m switching to GitHub actions is to learn new things and perhaps to be able to do it all in one site.

This GitHub action template will generate a NuGet package for any repository that is setup as a Microlibrary (See We are already in the age of Microlibraries).

Requirements to use the DotNet Nuget Package Workflow

This template is easy to use.

Requirements

  1. It is for a microlibrary.
    A microlibrary is basically a repository with only one dll project. In C#, that means a repo is setup with only one Visual Studio solution that usually has two projects:

    1. The DLL project
    2. The unit test project (The template will fail without a unit test project.)
  2. The template assumes you have everything in a directory called src.
    1. The solution is in the src directory.
    2. There is a nuget.config in the src directory
  3. The DLL project is configured to build a NuGet package on Release builds.
    Note: Add this to your csproj file:

    <GeneratePackageOnBuild Condition="'$(Configuration)'=='Release'">True</GeneratePackageOnBuild>
  4. The GitHub actions template is not in the src directory, but in this directory
    .github\workflows
  5. This template publishes to NuGet.org and you must create a key in NuGet.org, then in GitHub repo settings, make that key a secret called:
    NUGET_API_KEY

Options

Note everything is required.

  1. Versioning is created using the Build and typed in versions.
    1. Changing the version is easy. Just update the yml file.
    2. Want a new version to start at 0? (For example, you are at 1.1.25 and you want to go to 1.2.0)
      1. Simply set the base offset found below in the ‘# Get build number’ section of the template to subtract the build count.
        For example, if you are on build 121 and your next build will be 122, set the value to -122.
  2. Code Coverage
    1. You can enforce code coverage and get a nice report in pull requests for the provided coverage.
      1. Chaning the code coverage percentage requirement is easy.
      2. Disabling code coverage is an option.
    2. The code coverage tool used doesn’t work with windows-latest. Notice the yml file says:
      runs-on: ubuntu-latest
      However, you can run on windows-latest, and this template will simply skip those lines.
  3. There is an option for you to have a vNext branch that will build prerelease versions.
    If you want your vNext branch to be named something else such as future or current then you can just find and replace vNext with the desired branch name.
  4. You can change the version of dotnet:
    dotnet-version: [ ‘8.0.x’ ]
# Created by Jared Barneck (Rhyous).
# Used to build dotnet microlibraries and publish them to NuGet
name: CI - Main

# Controls when the workflow will run
on:
  # Triggers the workflow on push events to the "master" or "vNext" branches
  push:
    branches: [ "master", "vNext" ]
    paths-ignore:
      - '**.md' 
      - '**.yml' 
      - '**/*.Tests/**' 
      - '**/.editorconfig' 
      - '**/.editorconfig' 
      - '**/.gitignore' 
      - '**/docs/**' 
      - '**/NuGet.Config' 
      - '.gitignore'
      
  # Allows you to run this workflow manually from the Actions tab
  workflow_dispatch:
 
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
  # This workflow contains a single job called "build"
  build:
    # The type of runner that the job will run on
    runs-on: ubuntu-latest
    defaults:
      run:
        # There should only be one solution file (.sln) and it should be in the src dir.
        working-directory: src
      
    strategy:
      matrix:
        dotnet-version: [ '8.0.x' ]

    # Steps represent a sequence of tasks that will be executed as part of the job
    steps:
      # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
      - uses: actions/checkout@v3
      
      # Get dotnet setup and ready to work
      - name: Setup .NET Core SDK ${{ matrix.dotnet-version }}
        uses: actions/setup-dotnet@v4
        with:
          dotnet-version: ${{ matrix.dotnet-version }}

      # Restore nuget packages
      - name: Restoring NuGet packages
        run: dotnet restore
        
      # Get build number
      - name: Get Build Number with base offset
        uses: mlilback/build-number@v1
        with:
          base: -8
          run-id: ${{github.run_number}}
        
      # Build - Main
      - name: Build source
        if: github.ref == 'refs/heads/master'
        run: dotnet build --configuration Release --no-restore -p:AssemblyVersion=1.3.0 -p:FileVersion=1.3.${{env.BUILD_NUMBER}} -p:Version=1.3.${{env.BUILD_NUMBER}}

      # Build - vNext
      - name: Build source
        if: github.ref == 'refs/heads/vNext'
        run: dotnet build --configuration Release --no-restore -p:AssemblyVersion=2.0.0 -p:FileVersion=2.0.${{env.BUILD_NUMBER}} -p:Version=2.0.${{env.BUILD_NUMBER}} --version-suffix alpha
        
      # Run Unit Tests
      # Add coverlet.collector nuget package to test project - 'dotnet add &amp;amp;lt;TestProject.cspoj&amp;amp;gt; package coverlet
      - name: Run Tests
        run: dotnet test --no-build --configuration Release --verbosity normal --collect:"XPlat Code Coverage" --logger trx --results-directory coverage --filter TestCategory!=SkipCI
        
      # Install ReportGenerator
      - name: Install ReportGenerator
        run: dotnet tool install -g dotnet-reportgenerator-globaltool
        
      # Run ReportGenerator
      - name: Run ReportGenerator
        run: reportgenerator -reports:./coverage/*/coverage.cobertura.xml -targetdir:coveragereport -reportType:Cobertura
        
      # Code Coverage
      - name: Code Coverage Report
        if: runner.os == 'Linux'
        uses: irongut/CodeCoverageSummary@v1.3.0
        with:
          filename: '**/Cobertura.xml'
          badge: true
          fail_below_min: true
          format: markdown
          hide_branch_rate: false
          hide_complexity: true
          indicators: true
          output: both
          thresholds: '60 80'

      - name: Add Coverage PR Comment
        uses: marocchino/sticky-pull-request-comment@v2
        if: runner.os == 'Linux' &amp;amp;amp;&amp;amp;amp; github.event_name == 'pull_request'
        with:
          recreate: true
          path: code-coverage-results.md

      # Publish NuGet
      - name: Publish the NuGet package
        if: ${{ (github.event_name == 'push' || github.event_name == 'workflow_dispatch') &amp;amp;amp;&amp;amp;amp; github.ref == 'refs/heads/master' }}
        run: dotnet nuget push "**/*.nupkg" --source "https://api.nuget.org/v3/index.json" --api-key ${{ secrets.NUGET_API_KEY }} --skip-duplicate

Leave a Reply

How to post code in comments?