Categories
.NET Development Github Action

Adding GitHub Actions to a .NET Standard Project

GitHub Actions, simply put is a way to add a bit of automation onto your repository. Every time there is triggering event things happen. Things like running tests, deployment, or even a notification into a slack channel. For our purposes every time there is a push, or a pull-request to the develop or master branches; the code should be built and the automated tests should be run.

It turns out that this is a lot easier than you might think, because, GitHub will create a base workflow for those specific steps and all we need to do is make a few modifications. Easy Peasy.

To get started, click on the Actions, find the appropriate starter workflow, in our case .NET, Then Set up this Workflow. GitHub then populates a web editor to edit the file .github/workflows/dotnet.yml


name: .NET

on:
push:
branches: [ develop ]
pull_request:
branches: [ develop ]

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: 3.1.301
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet build --no-restore
-name: Test
run: dotnet test --no-build --verbosity normal

.github/workflows/dotnet.yml

This YAML file contains 3 sections: name, on, and jobs. So lets break down what each section does before any changes are made.


name: .NET

Name section of dotnet.yml

The name is the easiest one. It is simply the name of the workflow. It is not required and the default is the path to the file, in this case it should be .github/workflows/dotnet.yml. I haven’t verified that so it might be something a bit different, but you get the idea.


on:
push:
branches: [develop]
pull_request:
branches: [develop]

On section of dotnet.yml

Next is the on section. This is where we define the events that will trigger the workflow. The first triggering event is push and off of that we see branches. Currently just the develop branch is listed. This then repeated for pull_request. So anytime that there is a push or a pull request to the develop branch this workflow will run.


jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: 3.1.301
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet build --no-restore
- name: Test
run: dotnet test --no-build --verbosity normal

Jobs section of dotnet.yml

Jobs is where the real meat of this file is. Under jobs there is build. Build is a job and you can use any name here. If you would like to call the job hoobastank, that is perfectly fine. You can have as many jobs here as you want; they will all run in parallel.

A job really is an environment. This is why we have the runs-on. We are specifying that our code is supposed to run on ubuntu. This could also be macos or windows. There are other options we could add to the environment.

This job has 5 steps. They are run in order, and if one fails, they all fail. The first two are predefined actions.


- uses: actions/checkout@v2

checkout step

This first step calls the checkout action, version 2. This checks out the current branch so you can do things to it, like compile. It is something that a great many other developers used, so rather than make everyone type out the same instructions over and over it has already been done for you.


- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: 3.1.301

checkout step

Much like the previous step, this step uses a predefined action, setup-dotnet. Now there are a two more pieces:name and with. The name is fairly self explanatory, a human readable name for the step. With is a bit more interesting. It is used to pass variables to the action. Here we are specifying the dotnet-version to be 3.1.301.


- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet build --no-restore
- name: Test
run: dotnet test --no-build --verbosity normal

build steps

These last three steps are simply running commands to Restore dependencies, Build, and Test on the environment.

That is the breakdown of the auto script. To adjust it so it runs on both the develop and master branches we simply need to change the two branches under on to read [ master, develop ] or [ develop ].

This has been a really longwinded way of saying change two lines very slightly. There is a great deal more that can be done. Here are a few links for your reference.

Categories
Development Plugin WordPress

Getting Started with WordPress Plugins

Since I have started writing out some entries into this site, I have discovered that I need some extra functionality. This isn’t that surprising considering that is where WordPress’s strength truly lies: extensibility. Theming is about the look and feel, while plugins are about adding those additional features. What I need is a way to display command line items and code in a nice and orderly way that is uniform throughout the site. The way to do that is through short codes.

Creating the plugin is super simple. Just create the folder /wp-content/plugins/pitheguy replacing ‘pitheguy’ with whatever plugin name you have decided upon. Then create pitheguy.php.


/**
* Plugin Name: Pi The Guy Plugin
*/

Contents of pitheguy.php

That is literally all that is needed to make a plugin. It now appears in the plugin list. There are more fields that can be added to the header which will be covered later.

Currently the plugin does nothing. Lets change that by adding a shortcode to display code.


/**
* Plugin Name: Pi The Guy Plugin
*/
function pitheguy_shortcode_code($attributes, $content) {
return "<span class='pitheguy_code'>${content}</span>";
}
add_shortcode( 'code', 'pitheguy_shortcode_code');

Contents of pitheguy.php

Let’s break down what is going on. First we create the function pitheguy_shortcode_code($attributes, $content). This is the function that is called every time our new shortcode is encountered.

The function name can be anything but this name is used to help ensure uniqueness. The naming convention is {text domain}_{type}_{name}. {text domain} is a unique identifier for this plugin. Using a {text domain} is critical to ensure that no two functions are the same across the vast library of WordPress plugins. This will be used almost like a namespace. Later I will cover using classes, which will eliminate this need but this will suffice for now. The rest of the function name {type}_{name} is for organizational purposes; it’s a shortcode named code.

Two variables are passed in $attributes and $content. Shortcodes are a little like XML; there can be attributes passed in to describe the content inside and tags need to be closed. The first parameter, $attributes, is an associative array of all the attributes being passed in. The attributes don’t have to be declared or even used by your shortcode. The $content is everything that is between the opening and closing tags. In the event that this is to be a self-closing tag, then you would need to put in a default value or just remove the second parameter all together.

The body is simply returning the content wrapped in a <span />. The value that is returned here replaces the opening tag, the content, and the closing tag.

The last line add_shortcode( 'code', 'pitheguy_shortcode_code'); is what adds our new shortcode to WordPress. The name of this function is self explanatory and is a good illustration of self-documenting code. The first parameter 'code' is the name we wish to use. The second is the name of the function 'pitheguy_shortcode_code' that we just wrote to handle the processing.

With all that saved, we can now activate our plugin and use it. Create a new post and put in the first block [code]Hello World!$[/code]. Publish it and have a look see.

What's that? Its not working? That is because there needs to be an opening php tag(<?php). I'll be honest, I forgot it. Once that is at the top of the file it should work. Granted, it really isn't doing anything yet.

It is a good start, and we could add some css at this point, but I am going to do that at the end. What I would like to do is have different types of code blocks depending on what it was, inline, file, or command line. I am going to use the attribute name type with the possible values of inline, file, or command. I would also like to add captions when it is of type file.


function pitheguy_shortcode_code($attributes, $content) {
$a = shortcode_atts( array(
'type' => 'inline',
'caption' => '',
), $attributes);
$type = $a['type'];
if( strcmp($type, 'file') == 0) {
$newContent = " $caption = $a['caption'];
$newContent .= "${caption}";
}
return $newContent;
}

Updated pitheguy_shortcode_code()

So there are a few changes. That first line establishes default values array('type' => 'inline','caption' => '') and copies the passed in values$attributes over the defaults on to a new array $a. Then we extract $type from the array. This allows us to add a new class that is dependent on the type in the span that was created earlier. If that type is file then we attach a second span with the caption. Finally we return this new string.

It is not quite right. Nothing is showing up any different except the type="file" and there it just throws everything off. so lets add some CSS!


function pitheguy_enqueue_scripts() {
wp_register_style( 'pitheguy', plugins_url('style.css', __FILE__) );
wp_enqueue_style( 'pitheguy' );
}

add_action('wp_enqueue_scripts', 'pitheguy_enqueue_scripts');

pitheguy_enqueue_scripts()


.pitheguy_code {
font-family:courier;
}

.pitheguy_code_inline {
background-color:BlanchedAlmond;
}

.pitheguy_code_file {
background-color:Blue;
color:White;
}

.pitheguy_code_command {
background-color:Black;
color:GhostWhite;
}

.pitheguy_code_caption {
font-style: oblique;
}

style.css

Starting to look better. Well, Kind of, Still looks like crap, but at least now the code stuff has been differentiated. There is a block type that is actually designed for this, but if I used that I wouldn't learn anything... I also was unaware of it until after I did this. Now you know.