Getting started with GitHub and the .NET Core Action

GitHub actions allows us to add workflows to our projects.

In the previous three posts we looked at using Appveyor, Circleci and Travis CI to create our CI/CD pipelines, now let’s look at using GitHub Actions.

  • From your GitHub project, select the Actions tab
  • GitHub kindly lists a suggested workflow, so as my project is in C# it suggests a .NET Core build action, select Set up this workflow if it suits your needs (it does for this example)
  • You’ll now get to edit the Actions yml configuration, I’ll accept it by clicking Start commit and this will add the dotnet-core.yml to .github/workflows. Just click commit to add it to your repository.
  • From the Actions | .NET Core workflow, press the Create status badge, then Copy status badge Markdown and place this markdown into your README.md

Note: If you’re using the .NET Core workflow and using multi targets (i.e. <TargetFrameworks>netcoreapp3.1;net472</TargetFrameworks> then you may find the build failing because the .NET 4.7.2 frameworks is not installed.

The process described above, demonstrated that we have a YML based DSL for creating our workflow, checkout Workflow syntax for GitHub Actions.

Let’s take a look at a workflow file for one of my projects – in this case .NET core was not suitable, instead I wanted .NET Framework

name: .NET Core

on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

jobs:
  build:

    runs-on: windows-latest

    steps:
    - uses: actions/checkout@v2
    - name: Setup MSBuild Path
      uses: warrenbuckley/Setup-MSBuild@v1
      
    - name: Setup NuGet
      uses: NuGet/setup-nuget@v1.0.2
     
    - name: Restore NuGet Packages
      run: nuget restore MyApplication.sln
 
    - name: Build
      run: msbuild MyApplication.sln /p:Configuration=Release /p:DeployOnBuild=true

The name is what you’ll see in your list of GitHub actions (via the GitHub project’s Actions tab/button, this workflow monitors pushes and pull requests on master and then has a list of jobs to undertake once this workflow is triggered.

We’re going to run this workflow on Windows as the project is a .NET framework application. The steps of the workflow specify the “parts” required to build and test the project, so require the checkout action and Setup-MSBuild, setup-nuget libraries. Then we run the nuget restore to get all nuget package then build the application.

Note: I’ve not include tests as yet on this workflow, so I’ll leave that to the reader.

As usual we’ll want to create a badge, in the Actions tab in GitHub, select the workflow and on the right of the screen is a button Create status badge. Click this then press the Copy status badge Markdown button and this will place the Markdown into your clipboard. Here’s an example of mine

![.NET Core](https://github.com/putridparrot/MyApplication/workflows/.NET%20Core/badge.svg)

Getting started with Travis CI and GitHub

As I’m seemingly trying out each free tier CI/CD online service I can, let’s look into Travis CI.

  • Create an account, with you preferred authentication provider (from the one’s they have available)
  • Sign-in, if not done so already
  • We need to click on Activate All Repositories using GitHub Apps
  • Then click Approve & Install. You can select specific repos. if you wish before click on this button
  • You’ll be asked to sign in again this will take you to GitHub where you click Authorise travis-pro if you wish to continue
  • You’ll then be redirected to Travis CI

Let’s get started

In your project’s repository add the file .travis.yml an example is shown below

language: csharp

branches:
  only:
  - master

If you’ve read the previous posts, you won’t be surprised to see another .yml file with the Travis CI DSL. If we take a look at Building a C#, F#, or Visual Basic Project we can see that the language for the .travis.yml is csharp for .NET languages C#, F# and VB.NET.

Here’s my .travis.yml for an F# .NET core project

language: csharp
mono: none
dotnet: 3.1
solution: FSharp.Health.sln

script:
  - dotnet build
  - dotnet test

Pretty straight forward, we use the script section for the steps to run the dotnet commands to build and test our code.

Ofcourse we’ll want to add a build badge to the README.md, so from the build within Travis CI simply click on the build badge next to your project name, then select FORMAT Markdown. Here’s an example for my FSharp.Health project

[![Build Status](https://travis-ci.com/putridparrot/FSharp.Health.svg?branch=master)](https://travis-ci.com/putridparrot/FSharp.Health)

Getting started with Circleci and GitHub

In my previous post I talked about using CI/CD along with GitHub and in that post we concentrated on Appveyor. Let’s now look at one of the alternatives, Circleci.

As you’d expect, you need to create an account and I used GitHub authentication as I wanted this CI/CD application working with my GitHub projects. It’s probably not a requirement but certainly everything integrated nicely (I’ve not yet seen if that differs with alternative repositories hosts).

Once you’ve created your account you’ll need to install the Circleci application within GitHub – I actually don’t recall the process but I suspect there’s an “Install Application” button or the likes.

Let’s get started

Due to the GitHub integration you’ll see a list of your projects. Simply press the Set Up Project button. That’s pretty much all there is to it to get started, but we’re probably going to want to customise the process.

In your project’s repository add the file config.yml into the .circleci folder, as below

.circleci/config.yml

This allows us to write the configuration for our Circleci build pipeline using a DSL. Here’s one for an F# project I have in Circleci

 version: 2.1

 orbs:
  win: circleci/windows@2.2.0

 jobs:
   build:
     executor: win/default     
    
     steps:
       - checkout
       - run: dotnet build
       - run: dotnet test Image.Processing.Tests

In this case we’re using the 2.1 (see CircleCI 2.1 Configuration Reference Guide.

The first thing we do (after setting the version of the DSL) is to map to an orb definition. In this case we’re using a predefined orb, we can actually create our own orbs if needed (but we’re not going there at the moment, or maybe ever, we’ll have to wait and see).

Note: An orb is a shareable package of configuration, see Explore Orbs for a whole bunch of different orbs..

Now we supply the jobs. In this case a build job using win/default, basically a Windows image.

Next we set up the build steps. These are self-explanatory, as you’d expect, we need to checkout our code, build the code and then run our tests. There’s a checkout step, the rest can be thought of as simply commands to run.

We’re now going to want to add a badge to the README.md in our project to allow us and others to see the status of our build.

Unlike Appveryor (unless I’m missing something, in which case I’ll update this post later) there’s no copy & paste option for the badge link, instead have a look as Adding Status Badges, here’s the template

[![<ORG_NAME>](https://circleci.com/<VCS>/<ORG_NAME>/<PROJECT_NAME>.svg?style=svg)](<LINK>)

So for my F# Image.Processing project this looks like the following

[![putridparrot](https://circleci.com/gh/putridparrot/Image.Processing.svg?style=svg)](https://circleci.com/gh/circleci/circleci-docs)

At this time, I’m not sure how to link to the specific build (or whether this is possible), I ‘ll add to this post in the future if I find it’s possible.

Note: If you prefer, change style=svg to style=shield for a different looking status image.

That should get you started.

Getting started with Appveyor and GitHub

I wanted to add some CI/CD (more CI than CD) to some of my GitHub projects. There’s several options available for this, including online or on-prem. Two seemed to catch my eye on other GitHub repositories, Appveyor and Circleci.

Both offer free plans which, as you’d expect, have some limitations. However for the most part these are things that don’t matter too much to my projects, i.e. you may be limited to public repositories only (hence they’re supporting OSS), probably only run a single build at a time etc.

Let’s get started

The application we’re going to look into here is AppVeyor.

Simply create an account and I used GitHub authentication to sign in – seemed logical as I was ultimately wanting this to integrate into GitHub.

Once you’ve signed in you’ll be presented with an Install button to install their app. into your GitHub space – I assume this is how it works, I’ve not looked into it further, either way this hooks into your repo. changes and triggers your project’s build.

Next up you go to the Project option in the Appveyor UI and select New Project. To be honest all is pretty obvious. Now with the GitHub integration you’ll get a list of available projects from your GitHub account.

Select Add and you’re done! Well sort of…

You may need to make some configuration changes, either within the Appveyor UI or better still (imho) via their DSL.

All you need to do is add a file named appveyor.yml. Here’s a simple example for a .NET project

version: 1.0.{build}

image: Visual Studio 2019

build:
  verbosity: minimal

before_build:
- cmd: nuget restore

Checkout the appveyor.yml reference for more information.

Basically what we’ve done in the above yml, is created a a build version, this will be displayed within the Appveyor UI when you inspect builds. Next we’ve stated what image we want to use to build our project, obviously Visual Studio 2019 is specified for my .NET projects.

The build can be set to quiet, minimal, normal or detailed. For now mine is minimal.

Finally I’ve added a pre-build step (before_build) and listed the command nuget restore. This was because for the projects I’ve tried, I have to update the nuget packaged first.

We’re not specifying the branches, but we can add a whitelist of branches that should be part of the build like this

branches:
  only:
    - master
    - production

By default Appveyor detects whether there’s tests and can run these automatically, but you might prefer to set a custom test step. For example I found an F# project ran tests fine locally but failed on Appveyor, adding the following solve this (here I’ve specified the assembly to test)

test_script:
- cmd: dotnet test FSharp.Units.Tests

Next up we’ll want to have a badge in our README.md so we can see the state of our build or better still, others can see the state of our build. If you select the project’s settings and then the Badges option, there’s a sample markdown code section where you can just copy the markdown and place in your README.md and it’ll show the build status in a nice little indicator.

Here we’ve looked at the basics for setting up a build with the DSL. Obviously this is a great way of doing things, but whilst setting up your DSL it means for every change, you need to commit and push then wait for the build to complete to see if everything works. In Appveyor you can go to the Setting | General option of your project and click Ignore appveyor.yml and instead set everything up in the Appveyor UI. Then you can go to the Settings | Export YAML option to generate your configuration.

That should get you started.

Converting old style csproj to new style sdk

This tool’s pretty good for converting the old style csproj files to the new SDK style.

Just install using

dotnet tool install --global Project2015To2017.Migrate2019.Tool

Now navigate to where your solution is (that you want to convert) and from the command prompt run

dotnet migrate-2019 wizard "D:\Path\To\My\TestProject.sln"

You’ll be asked if you want to backup things and whether you want to migrate, answer Y to the migrate question (backing up is up to you). This will then locate all the csproj’s in the solution and convert them.

Tests are failing with DateTime expected format

I’m creating some builds on appveyor for some of my GitHub projects and hit a small snag. All of the DateTime’s in my tests have test data in the en-GB format, i.e. dd/MM/yyyy.

Note: Whilst I haven’t checked, I suspect appveyor is hosted on en-US machines.

A simple way to resolve this is, just add a NUnit SetUp that converts the current culture to the expected culture, i.e.

SetUp]
public void SetUp()
{
   var culture = new CultureInfo("en-GB");
   Thread.CurrentThread.CurrentCulture = culture;
   Thread.CurrentThread.CurrentUICulture = culture;
}

Deploying React to GitHub Pages

  • Create a new repository on GitHub, so we have something to refer to mine’s called react.io so simply replace this with your repo name within these steps, also the steps will show my GitHub repository at putridparrot, again replace this with your GitHub username.
  • Clone the repository onto your local machine
  • In the parent folder of your cloned repository run
    yarn create react-app react.io --typescript
    

    Note: without –typescript if you want plain JavaScript code.

  • cd back into your repo folder and type
    yarn add gh-pages -D
    
  • Open your packages.json and add the following (below the “verson” is a good place)
    "homepage": "http://putridparrot.github.io/react.io",
    
  • Next up we need to add a predeploy and deploy script within the “scripts” section of the packages.json, so add these
    "deploy": "gh-pages -d build",
    "predeploy": "yarn run build"
    
  • Run the following from your shell/terminal
    yarn deploy
    

When we run yarn deploy the predeploy script is run and will create a gh-pages branch on your GitHub remote repo. Also it will default to this branch and when you go to the Settings page of your repository and scroll to the GithHub Pages section, you should see the source set to gh-pages branch.

As this point my React GitHub pages site should be visible at

https://putridparrot.github.io/react.io/

You may well want to push the source of your React application to GitHub as well, so simply commit and push to master or another branch, DO NOT overwrite the gh-pages branch, this is basically your deployed site.

To update your GitHub pages, simply run the following each time you’re ready to deploy to gh-pages

yarn deploy

The updated deployment may take up to ten minute to become available.

Creating types in Haskell

In most programming language we need ways to declare our own types. These help with readability, modularity etc. Haskell is no different in offering these capabilities.

We can create a simple data type using the data keyword, followed by either of available values (in C# this would be similar to an enum). So here’s the definition of a Boolean type

data Bool = False | True

The values after the = are the value constructors with the | being like an or, hence this Bool have either False or True value.

Note: The type name and the value constructor must be capital cased.

We can also declare types more like structs/classes in that we can define the field types that make up the type. For example here’s a Point type

data Point = Point Integer Integer

In this example we could create a point as follows

pt = Point 1 2

Accessing these values can be a little verbose (especially when we might have lots of fields) because of the lack of any names, hence we’d use pattern matching, i.e.

xpt :: Point -> Integer
xpt (Point x _) = x

-- example of printing the x value of value pt of type Point
print (xpt pt)

Note: The type annotation is not required and the underscore is a discard, hence is ignored.

We can combine types just as we combined False and True into essentially a union. So for example here we have a data type Shape with constructors for Circle and Triangle.

data Shape = Triangle Int Int Int | Circle Int

triangle = Triangle 1 2 3
circle = Circle 4

It’s not clear what these fields of the constructors mean, so let’s add some names which also allows us to more easily access specific values from the data (i.e. fixes the issue with using pattern matching – which ofcourse is still a valid way of doing things).

data Shape = Triangle { 
   hypotenuse :: Int, 
   opposite :: Int, 
   adjacent :: Int 
} | Circle { 
  radius :: Int 
}

We can declare instances of this type using names or without names, for example

-- not using names
triangle = Triangle 1 2 3
-- with names
triangle1 = Triangle { opposite = 5, hypotenuse = 6, adjacent = 7 }

Instead of creating a function to extract a value (like we did with the xpt function we created) we can now use the following

print (hypotenuse triangle)

and Haskell essentially creates the function for us, i.e. using the REPL along with :t hypotenuse we get the following

hypotenuse :: Shape -> Int

Haskell is immutable, so how do we make changes to an instance of data? Well we “copy and update”. Thankfully Haskell makes this easy (so we don’t have to literally create copies of every field on our data and then change values).

If you’ve used JavaScript it’s like using a spread operator of in F# and with.

newTriangle = triangle { hypotenuse = 10 } 

In this case newTriangle is a copy of the triangle data, with the hypotenuse changed.

Unit testing Haskel code with HUnit

As with most languages nowadays, we want to have some unit testing libraries/frameworks. Obviously Haskell is no different and we have tools such as HUnit.

Let’s first create a simple little bit of code to test, here’s my Calculator.hs file (abridged just to show the code I intend to write tests for)

module Modules.Calculator where

factorial :: (Integral a) => a -> a  
factorial 0 = 1  
factorial n = n * factorial (n - 1) 

We’ll need to have installed the HUnit package, if you haven’t already then run

cabal install --lib QuickCheck HUnit

We’ll store our tests in a folder named test off of our root folder (the name of the folder can be altered if you prefer).

Here’s our test code (my file is named CalculatorTests.hs)

module Main (main) where

import Test.HUnit
import System.Exit

import Modules.Calculator as Calc

testZeroCase = TestCase(assertEqual "Factorial 1" (1) (Calc.factorial 1))
testNonZeroCase = TestCase(assertEqual "Factorial 10" (2) (Calc.factorial 10))

main :: IO ()
main = do
    counts <- runTestTT ( test [
        testZeroCase,
        testNonZeroCase
        ])
    if (errors counts + failures counts == 0)
        then exitSuccess
        else exitFailure

In the above code we import our library code and have two tests, the first tests our factorial code with a 0 value, the second tests a non-zero. In this instance I’ve purposefully written a breaking test.

Before we run these and/or fix the tests let’s see what we’re doing with the test code. We create a function for the TestCase and within the TestCase we have our assertion along with a message prefix (the string), next we have the expected value and finally the actual value or in this case the function call which returns the actual value.

In main we basically create the test runner and supply an array of the test functions to be run, finally we exit the runner with success or failure.

Now before we can run our tests we need to declare a Test-Suite within the .cabal file. We add the following to the file

Test-Suite test-Calculator
  type:                exitcode-stdio-1.0
  hs-source-dirs:      test
                       .
  default-language:    Haskell2010
  main-is:             CalculatorTests.hs
  other-modules:       Modules.Calculator
  build-depends:       base >=4.14 && <4.15, HUnit

This tells cabal the folder to look for the tests (test in this case) along with . for the current folder (otherwise our tests won’t find out Calculator module). We then state what the main application for the cabal to run for the tests, include other modules etc.

Now run

cabal test

If all goes well you’ll get something like the following

Running 1 test suites...
Test suite test-Calculator: RUNNING...
### Failure in: 1
test\CalculatorTests.hs:9
Factorial 10
expected: 2
 but got: 3628800
Cases: 2  Tried: 2  Errors: 0  Failures: 1
Test suite test-Calculator: FAIL
Test suite logged to:
D:\Development\somefolder\test\HaskellBasics-0.1.0.0-test-HaskellBasics.log
0 of 1 test suites (0 of 1 test cases) passed.
cabal.exe: Tests failed for test:test-Calculator from
Calculator-0.1.0.0.

Obviously the test with the prefix message “Factorial 10” failed with the expected value 2 but the actual value 3628800, so we can fix that test case so it looks like this

testNonZeroCase = TestCase(assertEqual "Factorial 10" (3628800) (Calc.factorial 10))

and now all our tests will pass.

I’ll leave it to the reader to look into the other assertions etc. For example, checkout Test.HUnit.Base

Other References

HUnit: A unit testing framework for Haskell