GitHub Actions is a popular service for automating developer workflows. In this article I explain the basics of GitHub Actions from the point of view of a .NET developer, show how to create a CI pipeline using Actions and recommend several Actions that are useful for .NET developers.
What is GitHub Actions?
GitHub Actions helps developers automate tasks in the software development lifecycle from the repository itself. This makes it easy to create CI / CD pipelines, perform tests and ensure your code is secure all from within GitHub.
Actions are event-driven but can also be run on a schedule or on-demand. For example, every time a pull request is created, Actions can automatically build and execute unit tests.
Actions run in virtual environments called Runners hosted on Windows, Mac or Ubuntu. Usually they are GitHub-hosted but they can also be self-hosted if you have special requirements.
You can write custom Actions or choose from over 10,000 open source Actions in the GitHub Marketplace.
Actions have a built in Secret Store for any credentials, signing keys, etc that may be required by the process.
GitHub Actions are free for all open source repositories. For private repositories Free users get 2,000 minutes / month, Pro / Team users get 3,000 minutes / month and Enterprise users get 50,000 minutes / month.
What can Actions do?
🏗 Actions can build and test your code.
🚚 They can deploy releases to GitHub, package registries like NuGet, cloud services or on-premises.
👩💼 There are Actions to manage Issues and Pull Requests; for example adding labels or closing stale issues.
🐛 Some Actions review your code for bugs, code smells and broken links.
📣 Actions can manage and synchronise translations and translation services.
📧 There are also Actions that send messages by email, SMS, Teams, Slack, Discord, etc for notification.
🍕 There is even an Action that orders pizza!
So you could create a chain of Actions that will scan your code for bugs and security issues, build and test your application, deploy it to the cloud, send you a message to let you know it was successful and order celebratory pizza for your team!
Workflows, Jobs and Action steps
Actions start with a Workflow that describes a process, written in YAML and stored in the
.github/workflows folder in your repository.
Workflows are made up of one or more Jobs and can be triggered by an event, CRON schedule or manually (
workflow_dispatch). Workflows can have multiple triggers. Event triggers include
release and many more.
A Job is a set of steps that execute on the same Runner. If a Workflow contains multiple Jobs they can be run sequentially or in parallel (default). For example a workflow could have two sequential jobs that build & test code, where the test job will not run if the build job fails.
A step is an individual task that can run commands in a job. Each step can be either an Action or a sequence of shell commands. In this context, Actions are the portable building blocks of a workflow. You can create your own Actions, or use Actions created by the community.
Simple Workflow Example
This is a simple Project Management workflow. It contains one event trigger (
pull_request) and one Job (
assignAuthor) which runs on Ubuntu and has a single Action step from the Marketplace. When a Pull Request is opened it runs the Action which assigns the PR to the person who created it.
Choosing a Runner
GitHub provides cloud hosted runners with Ubuntu, Windows and MacOS operating systems. But how do you choose a runner for a job?
Some Actions on the Marketplace use Docker and will only run on Linux. Linux runners are also cheaper than other operating systems - Windows runners cost 2x and MacOS runners cost 10x the number of minutes used compared to Linux. So unless you specifically need Windows or MacOS to build your application I recommend using an Ubuntu runner. If you're building an application using WinForms, WPF or UWP then you must use a Windows runner. If you're building a Xamarin.Forms or .NET MAUI application that targets iOS or MacOS then you must use a MacOS runner; for Android you can use Windows or MacOS runners. For most other .NET applications an Ubuntu runner can be used.
Using Shell Commands
Lists of pre-installed software for each operating system can be found here. Every runner also includes the standard shell commands and command line utilities you expect to find on that operating system.
Running a single shell command
- name: Copy Test Coverage run: cp coverage/**/coverage.cobertura.xml reports/coverage.cobertura.xml
Running a sequence of shell commands
- name: Restore Nugets run: | nuget restore XamarinApp/XamarinApp/XamarinApp.csproj nuget restore XamarinApp/XamarinApp.Android/XamarinApp.Android.csproj nuget restore XamarinApp/XamarinApp.iOS/XamarinApp.iOS.csproj
CI Build Example
This is a more complicated workflow with multiple steps that is used to build a .NET Core application and run unit tests.
It has multiple event triggers -
pull_request which are only triggered when they happen on the
The Workflow contains one Job -
build which runs on Windows. (the OS is not important for this workflow)
First the workflow checks out the repository into the Runner environment, next it sets up .NET Core 3.1. Then the workflow uses the .NET CLI to restore dependencies, build the solution and run unit tests.
Note this workflow does not include a path or filename for the projects being built. You could copy it to any .NET Core repository to create a CI build, assuming there is a solution file in the root folder.
Useful Actions for .NET Developers
- Setup .NET
As a .NET developer this is probably the most important action to know. It sets up a specific .NET SDK version, adds it to the path and prepares the environment to build .NET applications.
- Setup Nuget
Downloads and installs a specific version of NuGet. NuGet functionality also gets delivered with msbuild and the .NET SDK but if you need to specify a particular version this is the action to use.
- Variable Substitution
This action applies variable substitution to XML, JSON and YAML based configuration and parameter files. It can be used to add secrets to your configuration files so they don't need to be in the code.
- Upload / Download Artifact
These complementary actions allow you to share data between Jobs and store data once a workflow is complete.
- Code Coverage Summary
Reads Cobertura format code coverage files, like those produced by Coverlet, and outputs a text or markdown summary. A little shameless self-promotion for one of my own Actions.😉 I'll write about how you can create your own Action using C# and Docker soon.
- Generate Documentation
This Action runs DocFX to generate documentation from source code and Markdown files.
If you want to learn more about GitHub Actions I recommend Victoria Lo's excellent five part series GitHub Actions 101. Victoria explains workflow syntax in detail, how to add variables and conditions to your workflow and wrting your own Action using Node.js.
GitHub's Brian Douglas regularly writes about GitHub Actions, his recent article 10 GitHub Actions resources to bookmark from the basics to CI/CD contains useful links for beginners and experienced Actions users alike. His YouTube channel also includes lots of tips & tricks for GitHub Actions.
Update 21st Nov 2021: GitHub recently published their own guide - What is GitHub Actions? How automation & CI/CD work on GitHub.
Cover image from dotnet/brand.