Github Actions for c# projects

Michael Svendsen
5 min readMar 11, 2021

Github actions is a great tool for code validation in CI and CD processes involving Github repos. It took me a bit of time to get through a number of different sources and adding a bit of guess work on top of it before I had a working prototype.

So this is a simple introduction on how to get started with a Github actions on your c# project or solution. I’ll walk you through the very basic setup and then you can explore Github actions from there.

To get started copy the test project I’ve created into a repo in your own Github universe. Work with that before you get started on your big projects.

I assume that you already have git in your PATH and that you have a Github account.

Create an empty repository in GHithub:

I’ve named the new repo yourgitactionstest in the example above — you are free to be inventive. Click the create repository button when ready.

Now push my code to your own repo to be able to see the Github actions in play.

cd your\working\directory
git clone git@github.com:MichaelSvendsen/githubactions.git
cd githubactions
git remote set-url origin <link-to-your-new-repo>
git push -u origin master
cd ..
git clone <link-to-your-new-repo>
cd <your-new-repo-name>

You should now have a c# solution for a small and unusefull console app that will work fine for demoing.

It’s made with Visual Studio 19. Open the solution in Visual Studio 19 or newer.

I suggest that you in your local environment run the app to see that it builds and that you run the unittests to see that the tests pass.

When you have done that and made yourself familiar with the small solution get started with adding the Github actions.

Github actions live in the .github\workflows directory in the root of your repository.

The actions file is a .yml file with a definition of what actions you want to happens when you push to a repository or updates an open pull request (or both). In this example we will focus on what happens when you push updates to pull request for a given subset of branches.

You can open this file in your favorite editor.

.gitgub\workflows\ations.yml

… or just look at the file here

name: Validation of Console App
on:
pull_request:
branches: [ master, develop, release/*, hotfix/* ]
jobs:
run-selected-unittests:
runs-on: windows-latest
env:
ACTIONS_ALLOW_UNSECURE_COMMANDS: true
name: Run MSBuild and VSTest

steps:
- name: Checkout code
uses: actions/checkout@v2.1.0
id: checkout_code

- name: Setup MSBuild and add to PATH
uses: microsoft/setup-msbuild@v1.0.0
id: setup_msbuild

- name: Run MSBuild
id: run_msbuild
run: |
msbuild .\gitactionstest.sln /t:clean /p:Configuration=Debug
nuget restore .\gitactionstest.sln
msbuild .\gitactionstest.sln /t:build /p:Configuration=Debug
- name: Setup VSTest and add to PATH
uses: darenm/Setup-VSTest@v1
id: setup_vstest
- name: Test Case Workers
id: run_vstest
working-directory: UnitTests\bin\Debug
run: vstest.console.exe .\UnitTests.dll /Tests:TestCaseWorkerIds,TestCaseWorkersCount

The actual syntax of the commands in the file is well described by Github so Google that to get an understanding from there.

The general flow in the actions.yml file is as follows:

  1. Run for updates to pull requests for repos master, develop, release/* and hotfix/* (you can see that this setup is inspired by gitflow)
  2. Run the actions on the latest version of windows (windows-latest)
  3. Set an environment variable to be able to run msbuild on our code
  4. Checkout the code in the repository
  5. Download and configure msbuild
  6. Build the console application (including using nuget to get packages)
  7. Download and configure VSTest
  8. Run the unittests with VSTest

A clean run of the actions will give you an output like this:

A clean run of the actions

Now let’s try to break something and see the what happens.

Create a new branch for the breaking things:

git checkout master
git pull
git checkout -b Break-Something

Now add a new Case Worker — Michelle — and renumber IDs. Change the file Cases.cs to look like this:

...namespace gitactionstest
{
public class Cases
{
public enum CaseWorkers
{
Joe = 1,
Jane = 2,
Michelle = 3,
Mark = 4
}
}
}

Save the changes and push to Github:

git add Cases.cs
git commit -m "New Case Worker Michelle added"
git push --set-upstream origin Break-Something

Now go to you github account where you have the copy of the repo. You should see something like this:

Click the button Compare & pull request and follw the guide to creat a new pull request. The Github actions will start at they will fail like this:

Clicking the details you can see what failed:

You can now edit the code so you don’t renumber Case Worker IDs and update the test to take Case Worker Michelle into account.

Cases.cs:

...namespace gitactionstest
{
public class Cases
{
public enum CaseWorkers
{
Joe = 1,
Jane = 2,
Mark = 3,
Michelle = 4
}
}
}

CaseWorkerTests.cs:

...namespace UnitTests
{
[TestClass]
public class CaseWorkerTests
{
[TestMethod]
public void TestCaseWorkerIds()
{
Assert.IsTrue((int)Cases.CaseWorkers.Joe == 1);
Assert.IsTrue((int)Cases.CaseWorkers.Jane == 2);
Assert.IsTrue((int)Cases.CaseWorkers.Mark == 3);
Assert.IsTrue((int)Cases.CaseWorkers.Michelle == 4);
}
[TestMethod]
public void TestCaseWorkersCount()
{
Assert.IsTrue(Enum.GetNames(typeof(Cases.CaseWorkers)).Length == 4);
}
}
}

Pushing the changes to the branch will trigger the actions again and you will see that they now pass.

And details shows all is well:

This can seem a little tedious for small projects and small teams.

Projects that benefits from this are long-lived code bases, projects with many developers over time, complex code bases, code you revisit seldomly.

However, you’re not here to be convinced about CI/CD — enjoy!

--

--