I’ve created a template to quickly get started building a sample PowerShell Module that includes different components such as Classes, Enum, private and public functions, DSC Resources, some Unit tests, Quality tests, code coverage, deployment, dependency resolution for build, and AppVeyor Integration.
To be fair, I haven’t invented anything, and I’ve based this work on many shoulders of giants:
- I follow Warren Frame’s (@psCookieMonster ) Module format (except for the tests, this is worth a post of its own)
- I also leverage a few of his modules: PSDepend, BuildHelpers, PSDeploy
- I use Invoke-Build by Roman Kuzmin (@romkuzminas) the Task runner (instead of PSake for instance)
- The module scaffolding from this example is done via Plaster by Keith Hill (@r_keith_hill) and David Wilson (@daviwil).
As you can see on the video above, here’s the value of the model:
Quick and custom scaffolding. It also allows to add feature later by re-invoking the template on top of the project (Plaster will warn of conflicts and will backup files).
Another nice approach to Plaster is to keep my modules and their build pipeline consistent and up-to-date while allowing my build system to evolve. If I change my build system (in SampleBuild), I can re-apply that updated template onto my other projects, and see what has changed and update as appropriate.
Access to the build mechanism is done by a single point of entry, the .build.ps1 file.
Calling it first with the -ResolveDependency option will bootstrap PSDepend, and then resolve the dependencies listed in the Dependency file of the project: PSDepend.build.ps1
The goal in the end is to have no tight dependency with any specific CI tool, and to be able to run the same pipeline and tests from the Dev workstations, or any build host while benefiting from specific features of those tools (i.e. Test reports and Artefacts repository in AppVeyor).
This is how AppVeyor is configured in the very simple AppVeyor.yml. There are no complex integration here, because I want to keep the pipeline flexible enough to run on other CI tools or on a workstation.
That build script is actually an InvokeBuild task, so when calling the script, and after PSDepend has finished pulling and installing itself and the dependencies, it hands off the rest of the execution to InvokeBuild.
The key to invoke build here is that the parameters of that files can be propagated down to the other InvokeBuild tasks called in the Build sequence, and that the ‘orchestration’ of the tasks is also done in this file.
The Build sequence is the chain of tasks to be executed when called, with the task ‘.’ being the default task when no Task name(s) is provided. This tells you what task will be attempted:
task . Clean, SetBuildEnvironment, QualityTestsStopOnFail, CopySourceToModuleOut, MergeFilesToPSM1, CleanOutputEmptyFolders, UnitTests, UploadUnitTestResultsToAppVeyor, FailBuildIfFailedUnitTest, FailIfLastCodeConverageUnderThreshold, IntegrationTests, DeployAll
It’s worth mentioning that some of those tasks can have extra logic that will condition whether they’re run or not. For instance, the UploadUnitTestResultsToAppVeyor will run only if the build is run on AppVeyor.
There are many other features and decisions to discuss about, even more ideas to explore and code to refactor, so feel free to raise a GitHub Issue if you have questions or constructive feedback… The project does lacks of documentation, as it started more like a sandbox but I now use it more and more as it saves me (and others’) time.