{{announcement.body}}
{{announcement.title}}

Publish NuGet Packages Using GitHub Actions

DZone 's Guide to

Publish NuGet Packages Using GitHub Actions

A walkthrough on how we published NetLicensing C# Client library to NuGet repository using GitHub Actions.

· DevOps Zone ·
Free Resource

Unbelievable! One of the oldest NetLicensing Client libraries for C# (with the first GitHub push made on Oct 2, 2013) was not available in one of the essential package managers for .NET

Better late than never — so we decided to change this status quo, and today want to share with you our this walkthrough on how we published NetLicensing C# Client library to NuGet repository using GitHub Actions.

Background Info — GitHub Flow

Before moving forward, just a note about GitHub Flow workflow adopted for Labs64 projects hosted at GitHub

“Pull Request” or “PR” is a very useful feature of the GitHub version control system and allowing efficient feature and bugfix development with the GitHub Flow.

The below diagram showing GitHub Flow adopted for Labs64 projects:

GitHub Flow

Any new feature or defect fix implementation is being done only in a dedicated feature branch. When branch implementation is ready to be integrated into the master branch, a Pull Request gets created. Using this PR, team members, working on a particular feature/enhancement/bug fix, can get feedback from other team members along the way. 

This feedback is being used to make further changes and commits to the branch before finally merging the changes back up to the 'master' branch.

For the above GitHub Flow following workflows will be defined:

  • CI — build and test push commits at Pull Request branches and master
  • Release — package and publish C# library after successful CI run on 'master'

Create Actions Workflow

There are two ways how you can create a new GitHub Actions workflow: 

  • Wizard — Use predefined configurations for your environment and technology stack. GitHub Actions offering heaps of community built actions that cover the whole #devops spectrum. 
  • Manually — Create a new workflow YAML file in the repository .github/workflows directory.
YAML
 




xxxxxxxxxx
1
23


 
1
name: NetLicensing C# Client — CI
2
 
          
3
on:
4
  push:
5
    branches: [ master ]
6
  pull_request:
7
    branches: [ master ]
8
 
          
9
jobs:
10
  build:
11
    runs-on: ubuntu-latest
12
    steps:
13
    - uses: actions/checkout@v2
14
    - name: Setup .NET Core
15
      uses: actions/setup-dotnet@v1
16
      with:
17
        dotnet-version: '3.1.x'
18
    - name: Install dependencies
19
      run: dotnet restore
20
    - name: Build
21
      run: dotnet build --configuration Release --no-restore
22
    - name: Test
23
      run: dotnet run --project NetLicensingClient-demo



Publish NuGet Package

After Pull Request merge and successful “CI” workflow run, we trigger a second “Release” workflow to push 'master' branch code base to NuGet.

YAML
 




xxxxxxxxxx
1
29


1
name: NetLicensing C# Client - Release
2
 
          
3
on:
4
  workflow_run:
5
    workflows: ["NetLicensing C# Client - CI"]
6
    branches: [ master ]
7
    types:
8
      - completed
9
 
          
10
jobs:
11
  publish-nuget:
12
    runs-on: ubuntu-latest
13
    steps:
14
    - uses: actions/checkout@v2
15
    - name: Setup .NET Core
16
      uses: actions/setup-dotnet@v1
17
      with:
18
        dotnet-version: '3.1.x'
19
    - name: Install dependencies
20
      run: dotnet restore
21
    - name: Build
22
      run: dotnet build --configuration Release --no-restore
23
    - name: Publish to NuGet
24
      uses: brandedoutcast/publish-nuget@v2
25
      with:
26
        PROJECT_FILE_PATH: NetLicensingClient/NetLicensingClient.csproj
27
        VERSION_REGEX: '^\s*<PackageVersion>(.*)<\/PackageVersion>\s*$'
28
        TAG_FORMAT: '*'
29
        NUGET_KEY: ${{secrets.NUGET_API_KEY}}



brandedoutcast/publish-nuget community action definition provides a very useful option to Publish Nuget packages every time the new project version is available. 

The action by default looks for changes to the <version></version> tag in your .csproj file, which we had to tweak in our case using VERSION_REGEX configuration parameter to '^\s*<PackageVersion>(.*)<\/PackageVersion>\s*$' to match the format of the Visual Studio 2019.

For a basic action setup, you only need to set PROJECT_FILE_PATH and NUGET_KEY.

Create NuGet API Key

NuGet API key needs to be created and added to GitHub Actions to authenticate publish requests to NuGet.

In the key creation dialogue provide:

  • Key Name — use this name to easily identify the API key scope
  • Package Owner — your NuGet account
  • Select Scope - choose “Push new packages and package versions”
  • Glob Pattern — use "*" to select all packages

The created API key needs to be added to the GitHub repository “Secrets” section.

In our configuration we use NUGET_API_KEY as a key name; you can choose the name accordingly to your name schema, however.

Execution

After your GitHub Actions setup is complete the CI workflow will be executed every time you push changes in master or feature branch. After the successful merge and incremented project version number, the Release workflow will start and publish the NuGet package. Voilà!

Manual Tasks and Open Points

Having the most of the steps automated we still have some minor but essential manual steps:

  • GitHub release version — Create a new GitHub release version for the created tag
  • NuGet package documentation — Provide a link to the prepared README-nuget.md file in the “Manage package” at NuGet
  • Increase project next development version in Visual Studio

Possibly, there are some handy automation options available for the above manual tasks. We will be happy for any suggestions from the community.

Topics:
c#, continious integration, csharp, devops, github, github actions, nuget, nuget packages, tutorial

Published at DZone with permission of Labs64 NetLicensing . See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}