Using GitHub Actions to automate testing and publishing of PowerShell modules
This blog post is currently unfinished. It is still published, because its current state might be valuable to others.
I’ve recently had to dip my toes into PowerShell module development. Being far from an expert on PowerShell or the community around it, I found it a bit daunting to setup my module development space for the first time. For the sake of saving you (and me) the trouble of going through that again, I’ll be describing my module development setup here. This will largely focus on the actual code layout, and not so much on the PowerShell code.
I found that all the project templates I could find lacked a few things that were important to me. These include:
- Automate where possible, including automatic testing (CI) and deployment (CD). As little publishing-related stuff should happen on my local machine as possible.
- Easily write-able and run-able tests. The chore of writing tests for modules should be simplified as much as possible, with easy ways to unit test both private and public functions.
- As little code-duplication as possible. If I’ve written something once, I shouldn’t have to copy-paste the file over to every new project I create (which would cause problems when I later have to update it).
Given these requirements, Catesta appeared to be the project template that got closest - with a few changes required.
Initial project setup
Before setting up, you’ll have to decide on whether you want a monorepo, or want to use a new repository for each module. The differences are rather slight, mostly revolving around how contributions happen to each module; but in my case I found that a lot of my modules were related to eachother, and as such chose to use a monorepo, with each project being represented by a folder in a shared repository.
Setting up the basic project for a module is simple enough, using Catesta to provide the boilerplate:
This will set up a general module structure for development. While this structure largely fit my needs (and has been designed by people much smarter than me), I did find that I needed to make a few changes:
This is a file Catesta sets up to install the necessary modules. However, I found that not only was this file incredibly slow when ran in a CI environment, as it forced installs of modules even if already installed, but it would also sometimes continue execution even if installation of a module failed (e.g. if you had a PowerShell instance open with one of the modules imported). I added the following to improve on it:
This file is used to configure the PowerShell linter PSScriptAnalyzer, which runs every time we build to module. While the defaults set up by Catesta are nice, I did find that there were some rules that caused more problems than they solved. In particular, I added the following:
Modifying this file is actually a requirement by Catesta. It contains the module manifest that will be used by PowerShell and PSGallery to understand the module, and contains a few crucial fields that must be set manually:
FunctionsToExport|CmdletsToExport|VariablesToExport|AliasesToExport = '*'
- Contains a list of the functions, cmdlets, variables or aliases the module exports. The default value
'*'is not good practice, and will throw an error in the linting stage. Update these as you develop the module (e.g.
'Foo','Bar'), or set them to the empty list
@()if you have none to export.
- Contains a link to the main website for the project, which will be shown on the PSGallery page. Will throw an error in the linting stage if not set. Usually I set this to the link of the repository on GitHub, linking directly to the sub-folder of the module if I'm using a monorepo.
Building the module for the first time
Once the above changes are done, we’ll want to test that the build process still works:
Depending on whether or not you’ve implemented your module, you might have a failing test - this is intentional from the Catesta template we used to generate the project. Fixing it is a good introduction to how the project is set up.