diff --git a/docs/powershellbuild/_category_.json b/docs/powershellbuild/_category_.json new file mode 100644 index 0000000..4d1c384 --- /dev/null +++ b/docs/powershellbuild/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "PowerShellBuild", + "position": 3, + "link": { + "type": "generated-index", + "description": "Learn how to use PowerShellBuild, the official companion module that provides reusable psake tasks for building, testing, and publishing PowerShell modules." + } +} diff --git a/docs/powershellbuild/configuration.md b/docs/powershellbuild/configuration.md new file mode 100644 index 0000000..971aa46 --- /dev/null +++ b/docs/powershellbuild/configuration.md @@ -0,0 +1,234 @@ +--- +title: "Configuration Reference" +description: "Complete reference for the $PSBPreference hashtable and task dependency variables in PowerShellBuild." +--- + +# Configuration Reference + +PowerShellBuild exposes all of its settings through a single hashtable called `$PSBPreference`. Override values in the `properties` block of your `psakeFile.ps1`. Task dependency chains can also be customized via separate variables set outside the `properties` block. + +## Setting Preferences + +```powershell title="psakeFile.ps1" +properties { + # Override any $PSBPreference keys here + $PSBPreference.General.ModuleName = 'MyModule' + $PSBPreference.Build.OutDir = "$PSScriptRoot/build" + $PSBPreference.Test.ScriptAnalysis.Enabled = $true + $PSBPreference.Test.CodeCoverage.Enabled = $true + $PSBPreference.Test.CodeCoverage.Threshold = 0.80 + $PSBPreference.Publish.PSRepositoryApiKey = $env:PSGALLERY_API_KEY +} + +task default -depends Build +task Build -FromModule PowerShellBuild -Version '0.7.1' +``` + +Values not overridden retain their defaults as defined in PowerShellBuild's `build.properties.ps1`. + +--- + +## General + +| Setting | Default | Description | +|---------|---------|-------------| +| `General.ProjectRoot` | (auto-detected) | Root directory of the project | +| `General.SrcRootDir` | `$ProjectRoot/src` | Directory containing module source files | +| `General.ModuleName` | (basename of `.psd1`) | Name of the module | +| `General.ModuleVersion` | (from manifest) | Module version number | +| `General.ModuleManifestPath` | (auto-detected) | Path to the `.psd1` manifest | + +--- + +## Build + +| Setting | Default | Description | +|---------|---------|-------------| +| `Build.OutDir` | `$ProjectRoot/build` | Root output directory | +| `Build.ModuleOutDir` | `$OutDir/$ModuleName` | Module-specific output subdirectory (computed) | +| `Build.CompileModule` | `$false` | If `$true`, concatenate all `.ps1` source files into a single `.psm1` | +| `Build.CompileDirectories` | `'Enum','Classes','Private','Public'` | Directories whose `.ps1` files are merged when compiling | +| `Build.CopyDirectories` | `@()` | Directories copied as-is (not compiled) to the output | +| `Build.Exclude` | `@()` | File patterns excluded from the output | + +### Module Compilation + +Setting `CompileModule = $true` merges all `.ps1` files from `CompileDirectories` into the root `.psm1`. This can improve module load time and is common for published modules. + +```powershell +properties { + $PSBPreference.Build.CompileModule = $true + $PSBPreference.Build.CompileDirectories = @('Enum', 'Classes', 'Private', 'Public') + $PSBPreference.Build.CopyDirectories = @('data', 'lib') +} +``` + +--- + +## Test + +| Setting | Default | Description | +|---------|---------|-------------| +| `Test.Enabled` | `$true` | Enable or disable Pester tests | +| `Test.RootDir` | `$ProjectRoot/tests` | Directory containing Pester test files | +| `Test.OutputFile` | `$null` | Path to write NUnitXml test results (useful for CI) | +| `Test.OutputFormat` | `'NUnitXml'` | Test result format | +| `Test.ImportModule` | `$false` | Import the built module before running tests | +| `Test.OutputVerbosity` | `'Detailed'` | Pester output verbosity level | +| `Test.SkipRemainingOnFailure` | `'None'` | Skip strategy after a test failure | + +### Script Analysis + +| Setting | Default | Description | +|---------|---------|-------------| +| `Test.ScriptAnalysis.Enabled` | `$true` | Run PSScriptAnalyzer | +| `Test.ScriptAnalysis.FailBuildOnSeverityLevel` | `'Error'` | Build fails on violations at or above this severity (`'Error'`, `'Warning'`, `'Information'`) | +| `Test.ScriptAnalysis.SettingsPath` | `./PSScriptAnalyzerSettings.psd1` | Path to a PSScriptAnalyzer settings file. Defaults to `PSScriptAnalyzerSettings.psd1` in the project root — if the file exists it is used automatically | + +```powershell +properties { + # Fail on warnings too + $PSBPreference.Test.ScriptAnalysis.FailBuildOnSeverityLevel = 'Warning' + + # Override the default settings file location + $PSBPreference.Test.ScriptAnalysis.SettingsPath = "$PSScriptRoot/build/analyzersettings.psd1" +} +``` + +### Code Coverage + +| Setting | Default | Description | +|---------|---------|-------------| +| `Test.CodeCoverage.Enabled` | `$false` | Enable code coverage reporting | +| `Test.CodeCoverage.Threshold` | `0.75` | Minimum coverage ratio (0.0–1.0); build fails below this | +| `Test.CodeCoverage.Files` | (staged module files) | Files included in coverage analysis | +| `Test.CodeCoverage.OutputFile` | `$null` | Path to write the coverage report | +| `Test.CodeCoverage.OutputFileFormat` | `'JaCoCo'` | Coverage report format | + +```powershell +properties { + $PSBPreference.Test.CodeCoverage.Enabled = $true + $PSBPreference.Test.CodeCoverage.Threshold = 0.80 + $PSBPreference.Test.CodeCoverage.OutputFile = "$PSScriptRoot/coverage.xml" + $PSBPreference.Test.CodeCoverage.OutputFileFormat = 'JaCoCo' +} +``` + +--- + +## Help + +| Setting | Default | Description | +|---------|---------|-------------| +| `Help.DefaultLocale` | `'en-US'` | Locale used when generating MAML and updatable help | +| `Help.UpdatableHelpOutDir` | `$null` | Directory where updatable help `.cab` files are written | +| `Help.ConvertReadMeToAboutHelp` | `$false` | Convert `README.md` to an `about_.help.txt` file | + +--- + +## Docs + +| Setting | Default | Description | +|---------|---------|-------------| +| `Docs.RootDir` | `$ProjectRoot/docs` | Directory for PlatyPS markdown source files | +| `Docs.Overwrite` | `$false` | Overwrite existing markdown files when regenerating | +| `Docs.AlphabeticParamsOrder` | `$false` | Sort parameters alphabetically in generated markdown | +| `Docs.ExcludeDontShow` | `$false` | Exclude parameters marked `[DontShow]` | +| `Docs.UseFullTypeName` | `$false` | Use fully-qualified type names instead of short names | + +--- + +## Publish + +| Setting | Default | Description | +|---------|---------|-------------| +| `Publish.PSRepository` | `'PSGallery'` | Name of the PowerShell repository to publish to | +| `Publish.PSRepositoryApiKey` | `$null` | API key for authenticating with the repository | +| `Publish.PSRepositoryCredential` | `$null` | `PSCredential` for authenticating with the repository | + +```powershell +properties { + $PSBPreference.Publish.PSRepository = 'PSGallery' + $PSBPreference.Publish.PSRepositoryApiKey = $env:PSGALLERY_API_KEY +} +``` + +--- + +## Sign + +| Setting | Default | Description | +|---------|---------|-------------| +| `Sign.Enabled` | `$false` | Enable Authenticode signing | +| `Sign.CertificateSource` | `'Auto'` | How to resolve the signing certificate (`'Auto'`, `'CertStore'`, `'Thumbprint'`, `'EnvVar'`, `'PfxFile'`) | +| `Sign.CertStoreLocation` | `$null` | Certificate store path (e.g., `'Cert:\CurrentUser\My'`) | +| `Sign.Thumbprint` | `$null` | Specific certificate thumbprint | +| `Sign.CertificateEnvVar` | `'SIGNCERTIFICATE'` | Environment variable containing a Base64-encoded PFX | +| `Sign.CertificatePasswordEnvVar` | `$null` | Environment variable containing the PFX password | +| `Sign.PfxFilePath` | `$null` | Path to a PFX/P12 file | +| `Sign.PfxFilePassword` | `$null` | Password for the PFX file | +| `Sign.SkipCertificateValidation` | `$false` | Skip certificate validity checks (not recommended for production) | +| `Sign.TimestampServer` | `$null` | RFC 3161 timestamp server URI | +| `Sign.HashAlgorithm` | `'SHA256'` | Authenticode hash algorithm | +| `Sign.FilesToSign` | `@('*.psd1','*.psm1','*.ps1')` | File patterns to sign in the output directory | + +### Catalog + +| Setting | Default | Description | +|---------|---------|-------------| +| `Sign.Catalog.Enabled` | `$false` | Create a Windows catalog (`.cat`) file | +| `Sign.Catalog.Version` | `2` | Catalog hash version | +| `Sign.Catalog.FileName` | (module name) | Catalog filename (without `.cat` extension) | + +```powershell +properties { + $PSBPreference.Sign.Enabled = $true + $PSBPreference.Sign.CertificateSource = 'EnvVar' + $PSBPreference.Sign.TimestampServer = 'http://timestamp.digicert.com' + $PSBPreference.Sign.Catalog.Enabled = $true +} +``` + +--- + +## Task Dependency Variables + +To change which tasks a given task depends on, set these variables **outside** the `properties` block, before any PowerShellBuild task references: + +| Variable | Controls dependencies of | Default | +|----------|--------------------------|---------| +| `$PSBCleanDependency` | `Clean` | `'Init'` | +| `$PSBStageFilesDependency` | `StageFiles` | `'Clean'` | +| `$PSBBuildHelpDependency` | `BuildHelp` | `'GenerateMarkdown', 'GenerateMAML'` | +| `$PSBGenerateMarkdownDependency` | `GenerateMarkdown` | `'StageFiles'` | +| `$PSBGenerateMAMLDependency` | `GenerateMAML` | `'GenerateMarkdown'` | +| `$PSBGenerateUpdatableHelpDependency` | `GenerateUpdatableHelp` | `'BuildHelp'` | +| `$PSBBuildDependency` | `Build` | `'StageFiles', 'BuildHelp'` | +| `$PSBAnalyzeDependency` | `Analyze` | `'Build'` | +| `$PSBPesterDependency` | `Pester` | `'Build'` | +| `$PSBTestDependency` | `Test` | `'Pester', 'Analyze'` | +| `$PSBPublishDependency` | `Publish` | `'Test'` | +| `$PSBSignModuleDependency` | `SignModule` | `'Build'` | +| `$PSBBuildCatalogDependency` | `BuildCatalog` | `'SignModule'` | +| `$PSBSignCatalogDependency` | `SignCatalog` | `'BuildCatalog'` | +| `$PSBSignDependency` | `Sign` | `'SignCatalog'` | + +### Example: Remove Analyze from the Test pipeline + +```powershell title="psakeFile.ps1" +# Set outside properties block +$PSBTestDependency = 'Pester' # Test only depends on Pester, not Analyze + +properties { + $PSBPreference.Test.ScriptAnalysis.Enabled = $false +} + +task default -depends Test +task Test -FromModule PowerShellBuild -Version '0.7.1' +``` + +## See Also + +- [Task Reference](./task-reference) — What each task does +- [Getting Started](./getting-started) — Minimal project setup +- [Real-World Example](./real-world-example) — Configuration in context diff --git a/docs/powershellbuild/getting-started.md b/docs/powershellbuild/getting-started.md new file mode 100644 index 0000000..26a4d6d --- /dev/null +++ b/docs/powershellbuild/getting-started.md @@ -0,0 +1,156 @@ +--- +title: "Getting Started with PowerShellBuild" +description: "Step-by-step guide to adding PowerShellBuild to a PowerShell module project and running your first build." +--- + +# Getting Started with PowerShellBuild + +This guide walks through adding PowerShellBuild to a PowerShell module project from scratch. By the end you will have a working build pipeline that cleans, stages, analyzes, tests, and packages your module. + +## Prerequisites + +- PowerShell 5.1 or PowerShell 7+ +- psake >= 4.9.0 +- PowerShellBuild >= 0.7.0 + +Install both modules from the PowerShell Gallery: + +```powershell +Install-Module -Name psake -Repository PSGallery +Install-Module -Name PowerShellBuild -Repository PSGallery +``` + +## Expected Directory Structure + +PowerShellBuild expects a conventional PowerShell module layout. The defaults work with the following structure (all paths are configurable — see [Configuration](./configuration)): + +``` +MyModule/ +├── src/ +│ ├── MyModule.psd1 # Module manifest +│ ├── MyModule.psm1 # Root module file +│ ├── Public/ # Exported functions +│ │ └── Get-Thing.ps1 +│ └── Private/ # Internal functions +│ └── Invoke-Helper.ps1 +├── tests/ +│ └── MyModule.Tests.ps1 # Pester tests +├── docs/ # PlatyPS markdown (generated) +├── build/ # Output directory (generated) +├── psakeFile.ps1 # Your build task file +├── build.ps1 # Build bootstrap script +└── requirements.psd1 # Module dependencies +``` + +## Minimal Setup + +### 1. Create `psakeFile.ps1` + +The simplest possible build file just references the `Build` task from PowerShellBuild: + +```powershell title="psakeFile.ps1" +properties { + $PSBPreference.Build.OutDir = "$PSScriptRoot/build" + $PSBPreference.General.SrcRootDir = "$PSScriptRoot/src" +} + +task default -depends Build + +task Build -FromModule PowerShellBuild -Version '0.7.1' +``` + +That is all you need. When psake runs the `Build` task, it loads it from the PowerShellBuild module and automatically runs the full dependency chain: + +``` +Init → Clean → StageFiles → GenerateMarkdown → GenerateMAML → BuildHelp → Build +``` + +### 2. Create `build.ps1` + +A bootstrap script that installs dependencies and invokes psake: + +```powershell title="build.ps1" +[CmdletBinding()] +param( + [string[]]$Task = 'default', + [switch]$Bootstrap +) + +if ($Bootstrap) { + Get-PackageProvider -Name NuGet -ForceBootstrap | Out-Null + Set-PSRepository -Name PSGallery -InstallationPolicy Trusted + Install-Module -Name psake, PowerShellBuild -Scope CurrentUser -Force +} + +Import-Module psake +Invoke-psake -buildFile "$PSScriptRoot/psakeFile.ps1" -taskList $Task -nologo + +exit ([int](-not $psake.build_success)) +``` + +### 3. Run the Build + +```powershell +# First-time setup +.\build.ps1 -Bootstrap + +# Build the module +.\build.ps1 + +# Run tests only +.\build.ps1 -Task Test + +# Publish to PSGallery +.\build.ps1 -Task Publish +``` + +## What Each Task Does + +When you run `.\build.ps1` (which runs the `default` task → `Build`), here is what happens: + +| Step | Task | What it does | +|------|------|-------------| +| 1 | `Init` | Calls `Initialize-PSBuild` to set up build variables | +| 2 | `Clean` | Removes the output directory | +| 3 | `StageFiles` | Copies (or compiles) module source into the output directory | +| 4 | `GenerateMarkdown` | Generates PlatyPS markdown from module help comments | +| 5 | `GenerateMAML` | Converts PlatyPS markdown to MAML help XML | +| 6 | `BuildHelp` | Meta-task — signals that help generation is complete | +| 7 | `Build` | Meta-task — signals that the build is complete | + +Running `.\build.ps1 -Task Test` additionally runs: + +| Step | Task | What it does | +|------|------|-------------| +| 8 | `Analyze` | Runs PSScriptAnalyzer against the staged module | +| 9 | `Pester` | Runs Pester tests, optionally with code coverage | +| 10 | `Test` | Meta-task — signals that all tests passed | + +## Using with Invoke-Build + +If you prefer Invoke-Build over psake, PowerShellBuild supports it via a dot-sourced task file: + +```powershell title=".build.ps1" +Import-Module PowerShellBuild + +# Dot-source the Invoke-Build task definitions +. PowerShellBuild.IB.Tasks + +# Override preferences after import +$PSBPreference.Build.OutDir = "$PSScriptRoot/build" +$PSBPreference.General.SrcRootDir = "$PSScriptRoot/src" +$PSBPreference.Test.ScriptAnalysis.Enabled = $true +``` + +Run it with: + +```powershell +Invoke-Build Build +Invoke-Build Test +``` + +## Next Steps + +- [Task Reference](./task-reference) — Full list of tasks and their dependencies +- [Configuration](./configuration) — Customize `$PSBPreference` to fit your project +- [Real-World Example](./real-world-example) — A complete project with CI/CD integration diff --git a/docs/powershellbuild/introduction.md b/docs/powershellbuild/introduction.md new file mode 100644 index 0000000..8020d27 --- /dev/null +++ b/docs/powershellbuild/introduction.md @@ -0,0 +1,91 @@ +--- +title: "Introduction to PowerShellBuild" +description: "Learn what PowerShellBuild is, how it relates to psake, and when to use it for building PowerShell modules." +--- + +# Introduction to PowerShellBuild + +[PowerShellBuild](https://github.com/psake/PowerShellBuild) is the official companion module to psake. Where psake is a general-purpose build automation engine, PowerShellBuild is a curated library of pre-built psake tasks that handle every step of a PowerShell module's lifecycle — building, testing, analysis, help generation, signing, and publishing — so you don't have to write that scaffolding from scratch. + +## The Problem It Solves + +Every PowerShell module project needs roughly the same build pipeline: + +1. Clean the output directory +2. Stage (copy/compile) module files to the output +3. Run PSScriptAnalyzer for code quality +4. Run Pester tests +5. Generate MAML help from PlatyPS markdown +6. Publish to the PowerShell Gallery + +Writing this pipeline from scratch in every project is repetitive. If you discover a better pattern (say, a smarter way to compute code coverage), you'd have to update every project manually. PowerShellBuild solves this by packaging the pipeline as a versioned, distributable module — update the module version and all your projects get the improvement. + +## How It Relates to psake + +PowerShellBuild lives under the same GitHub organization as psake (`psake/PowerShellBuild`) and is built on a feature introduced in **psake v4.8.0**: the ability to reference shared tasks distributed inside a PowerShell module. + +``` +┌─────────────────────────────────────┐ +│ Your project's psakeFile.ps1 │ +│ │ +│ task Build -FromModule │ +│ PowerShellBuild -Version 0.7.1 │ +└────────────────┬────────────────────┘ + │ psake loads tasks from + ▼ +┌─────────────────────────────────────┐ +│ PowerShellBuild module │ +│ (Init → Clean → StageFiles → │ +│ BuildHelp → Build → ...) │ +└─────────────────────────────────────┘ +``` + +When psake encounters a task declared with `-FromModule`, it automatically loads that task (and all its dependencies) from the installed module and runs them as if they were defined locally. Your `psakeFile.ps1` stays minimal; PowerShellBuild handles the details. + +## Also Supports Invoke-Build + +PowerShellBuild is not limited to psake. It ships Invoke-Build task files as well, accessible through the `PowerShellBuild.IB.Tasks` PowerShell alias. See the [PowerShellBuild README](https://github.com/psake/PowerShellBuild/blob/main/README.md) for Invoke-Build usage. The rest of this section focuses on the psake integration. + +## When to Use PowerShellBuild + +**Use PowerShellBuild when:** +- You are building a PowerShell module (`.psd1` / `.psm1`) and want a standardized pipeline +- You want to avoid writing boilerplate psake tasks that every PS module project needs +- You want your build pipeline versioned and shareable across multiple module projects + +**Write custom psake tasks instead when:** +- You are building something other than a PowerShell module (a .NET solution, a Node.js app, a Docker image, etc.) +- You need a workflow that significantly deviates from the standard module structure +- You are using psake purely for orchestration of external tools + +## Installation + +Install PowerShellBuild from the PowerShell Gallery: + +```powershell +Install-Module -Name PowerShellBuild -Repository PSGallery +``` + +psake v4.9.0 or later is also required: + +```powershell +Install-Module -Name psake -Repository PSGallery +``` + +Or declare both as dependencies in a `requirements.psd1` (managed via [PSDepend](https://github.com/RamblingCookieMonster/PSDepend)): + +```powershell +@{ + psake = 'latest' + PowerShellBuild = 'latest' +} +``` + +## See Also + +- [Getting Started with PowerShellBuild](./getting-started) — Set up your first project +- [Task Reference](./task-reference) — All available tasks and their dependencies +- [Configuration Reference](./configuration) — `$PSBPreference` settings +- [Real-World Example](./real-world-example) — Complete project walkthrough +- [psake GitHub](https://github.com/psake/psake) — psake source and issues +- [PowerShellBuild GitHub](https://github.com/psake/PowerShellBuild) — PowerShellBuild source diff --git a/docs/powershellbuild/real-world-example.md b/docs/powershellbuild/real-world-example.md new file mode 100644 index 0000000..77352da --- /dev/null +++ b/docs/powershellbuild/real-world-example.md @@ -0,0 +1,306 @@ +--- +title: "Real-World Example" +description: "A complete PowerShellBuild project with custom tasks, CI/CD integration, and PSGallery publishing." +--- + +# Real-World Example + +This page shows a production-ready PowerShell module project that uses PowerShellBuild for its build pipeline. It covers the full lifecycle: local development, automated testing, and publishing to the PowerShell Gallery via GitHub Actions. + +## Project Structure + +``` +MyModule/ +├── src/ +│ ├── MyModule.psd1 +│ ├── MyModule.psm1 +│ ├── Public/ +│ │ ├── Get-Widget.ps1 +│ │ └── New-Widget.ps1 +│ └── Private/ +│ └── Invoke-WidgetHelper.ps1 +├── tests/ +│ ├── Get-Widget.Tests.ps1 +│ └── New-Widget.Tests.ps1 +├── docs/ # PlatyPS markdown (auto-generated by GenerateMarkdown) +├── .github/ +│ └── workflows/ +│ └── build.yml +├── psakeFile.ps1 +├── build.ps1 +├── PSScriptAnalyzerSettings.psd1 # Auto-detected by PowerShellBuild +└── requirements.psd1 +``` + +## `requirements.psd1` + +Declare all PowerShell module dependencies. [PSDepend](https://github.com/RamblingCookieMonster/PSDepend) installs these during bootstrap. + +```powershell title="requirements.psd1" +@{ + psake = 'latest' + PowerShellBuild = 'latest' + Pester = 'latest' + PSScriptAnalyzer = 'latest' + platyPS = '0.14.2' +} +``` + +## `build.ps1` + +The bootstrap entry point that handles dependency installation and task dispatch. + +```powershell title="build.ps1" +#Requires -Version 5.1 + +[CmdletBinding()] +param( + [string[]]$Task = 'default', + + [switch]$Bootstrap, + + [hashtable]$Properties = @{} +) + +Set-StrictMode -Version Latest + +if ($Bootstrap) { + Write-Host 'Bootstrapping build dependencies...' -ForegroundColor Cyan + + Get-PackageProvider -Name NuGet -ForceBootstrap | Out-Null + Set-PSRepository -Name PSGallery -InstallationPolicy Trusted + + if (-not (Get-Module -Name PSDepend -ListAvailable)) { + Install-Module -Name PSDepend -Scope CurrentUser -Force + } + + Import-Module PSDepend + Invoke-PSDepend -Path "$PSScriptRoot/requirements.psd1" -Install -Import -Force + Write-Host 'Bootstrap complete.' -ForegroundColor Green +} + +Import-Module psake -ErrorAction Stop + +Invoke-psake ` + -buildFile "$PSScriptRoot/psakeFile.ps1" ` + -taskList $Task ` + -properties $Properties ` + -nologo + +exit ([int](-not $psake.build_success)) +``` + +## `psakeFile.ps1` + +A realistic build file with customized preferences, custom tasks alongside PowerShellBuild tasks, and a `Deploy` task that wraps the release workflow. + +```powershell title="psakeFile.ps1" +#Requires -Version 5.1 + +# --- Task dependency overrides (must be set before referencing PowerShellBuild tasks) --- +# Publish only requires a successful build, not the full test suite in this example. +# Tests are enforced in CI; the Publish task is only invoked from GitHub Actions. +$PSBPublishDependency = 'Build' + +# --- +properties { + # General + $PSBPreference.General.SrcRootDir = "$PSScriptRoot/src" + $PSBPreference.General.ModuleName = 'MyModule' + + # Build + $PSBPreference.Build.OutDir = "$PSScriptRoot/build" + $PSBPreference.Build.CompileModule = $true + $PSBPreference.Build.CompileDirectories = @('Enum', 'Classes', 'Private', 'Public') + + # Test — Pester + $PSBPreference.Test.Enabled = $true + $PSBPreference.Test.RootDir = "$PSScriptRoot/tests" + $PSBPreference.Test.OutputFile = "$PSScriptRoot/build/TestResults.xml" + $PSBPreference.Test.OutputFormat = 'NUnitXml' + $PSBPreference.Test.ImportModule = $true + + # Test — PSScriptAnalyzer + # SettingsPath defaults to ./PSScriptAnalyzerSettings.psd1 in the project root + $PSBPreference.Test.ScriptAnalysis.Enabled = $true + $PSBPreference.Test.ScriptAnalysis.FailBuildOnSeverityLevel = 'Error' + + # Test — Code Coverage + $PSBPreference.Test.CodeCoverage.Enabled = $true + $PSBPreference.Test.CodeCoverage.Threshold = 0.80 + $PSBPreference.Test.CodeCoverage.OutputFile = "$PSScriptRoot/build/coverage.xml" + $PSBPreference.Test.CodeCoverage.OutputFileFormat = 'JaCoCo' + + # Help + $PSBPreference.Help.DefaultLocale = 'en-US' + $PSBPreference.Docs.RootDir = "$PSScriptRoot/docs" + + # Publish — API key supplied by CI; falls back to env var for local releases + $PSBPreference.Publish.PSRepository = 'PSGallery' + $PSBPreference.Publish.PSRepositoryApiKey = $env:PSGALLERY_API_KEY +} + +# --- +# Entry points +# --- + +task default -depends Test + +# Import PowerShellBuild tasks +task Init -FromModule PowerShellBuild -Version '0.7.1' +task Clean -FromModule PowerShellBuild -Version '0.7.1' +task StageFiles -FromModule PowerShellBuild -Version '0.7.1' +task Build -FromModule PowerShellBuild -Version '0.7.1' +task Analyze -FromModule PowerShellBuild -Version '0.7.1' +task Pester -FromModule PowerShellBuild -Version '0.7.1' +task Test -FromModule PowerShellBuild -Version '0.7.1' +task Publish -FromModule PowerShellBuild -Version '0.7.1' + +# --- +# Custom tasks +# --- + +task BumpVersion -depends Init { + param([string]$BumpType = 'Patch') + + $manifestPath = $PSBPreference.General.ModuleManifestPath + $manifest = Import-PowerShellDataFile $manifestPath + $current = [System.Version]$manifest.ModuleVersion + + $next = switch ($BumpType) { + 'Major' { [System.Version]::new($current.Major + 1, 0, 0) } + 'Minor' { [System.Version]::new($current.Major, $current.Minor + 1, 0) } + 'Patch' { [System.Version]::new($current.Major, $current.Minor, $current.Build + 1) } + } + + Update-ModuleManifest -Path $manifestPath -ModuleVersion $next.ToString() + Write-Host "Version bumped $current -> $next" -ForegroundColor Green +} + +task ValidateReadme -precondition { Test-Path "$PSScriptRoot/README.md" } { + $content = Get-Content "$PSScriptRoot/README.md" -Raw + + $requiredSections = @('## Installation', '## Usage', '## Contributing') + foreach ($section in $requiredSections) { + if ($content -notmatch [regex]::Escape($section)) { + throw "README.md is missing section: $section" + } + } + + Write-Host 'README.md validation passed.' -ForegroundColor Green +} + +# Deploy = bump version + validate docs + publish +task Deploy -depends BumpVersion, ValidateReadme, Publish { + $manifest = Import-PowerShellDataFile $PSBPreference.General.ModuleManifestPath + Write-Host "MyModule v$($manifest.ModuleVersion) deployed to PSGallery." -ForegroundColor Green +} +``` + +## `PSScriptAnalyzerSettings.psd1` + +PowerShellBuild looks for `PSScriptAnalyzerSettings.psd1` in the project root by default. Place your custom rules here and they will be picked up automatically — no need to set `SettingsPath`. + +```powershell title="PSScriptAnalyzerSettings.psd1" +@{ + ExcludeRules = @( + 'PSAvoidUsingWriteHost' # Write-Host is acceptable in build scripts + ) + Severity = @('Error', 'Warning') +} +``` + +## GitHub Actions Workflow + +This workflow runs the full test suite on every push and pull request, and publishes to PSGallery when a tag is pushed. + +```yaml title=".github/workflows/build.yml" +name: Build + +on: + push: + branches: [main] + tags: ['v*'] + pull_request: + branches: [main] + +jobs: + test: + name: Test (PS ${{ matrix.ps-version }} on ${{ matrix.os }}) + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest] + ps-version: ['7.4'] + + steps: + - uses: actions/checkout@v4 + + - name: Bootstrap dependencies + shell: pwsh + run: .\build.ps1 -Bootstrap + + - name: Run tests + shell: pwsh + run: .\build.ps1 -Task Test + + - name: Upload test results + if: always() + uses: actions/upload-artifact@v4 + with: + name: test-results-${{ matrix.os }} + path: build/TestResults.xml + + - name: Upload coverage report + if: always() + uses: actions/upload-artifact@v4 + with: + name: coverage-${{ matrix.os }} + path: build/coverage.xml + + publish: + name: Publish to PSGallery + needs: test + runs-on: ubuntu-latest + if: startsWith(github.ref, 'refs/tags/v') + + steps: + - uses: actions/checkout@v4 + + - name: Bootstrap dependencies + shell: pwsh + run: .\build.ps1 -Bootstrap + + - name: Publish module + shell: pwsh + env: + PSGALLERY_API_KEY: ${{ secrets.PSGALLERY_API_KEY }} + run: .\build.ps1 -Task Publish +``` + +## Local Development Workflow + +```powershell +# First-time setup +.\build.ps1 -Bootstrap + +# Day-to-day: run tests +.\build.ps1 + +# Check code quality only +.\build.ps1 -Task Analyze + +# Rebuild from scratch +.\build.ps1 -Task Clean, Build + +# Bump the patch version and publish a release +.\build.ps1 -Task Deploy +``` + +## See Also + +- [Getting Started](./getting-started) — Minimal project setup +- [Task Reference](./task-reference) — All available tasks +- [Configuration](./configuration) — Full `$PSBPreference` reference +- [GitHub Actions Integration](/docs/ci-examples/github-actions) — General psake CI/CD patterns +- [Publishing PowerShell Modules](https://learn.microsoft.com/en-us/powershell/gallery/how-to/publishing-packages/publishing-a-package) — PSGallery publishing guide diff --git a/docs/powershellbuild/task-reference.md b/docs/powershellbuild/task-reference.md new file mode 100644 index 0000000..bc4ed16 --- /dev/null +++ b/docs/powershellbuild/task-reference.md @@ -0,0 +1,266 @@ +--- +title: "Task Reference" +description: "Complete reference for all pre-built psake tasks in PowerShellBuild, including dependencies and behavior." +--- + +# Task Reference + +PowerShellBuild provides two categories of tasks: **primary tasks** that you invoke directly, and **secondary tasks** that are called as dependencies but can also be invoked directly. + +## Task Dependency Graph + +```mermaid +graph TD + Init --> Clean + Clean --> StageFiles + StageFiles --> GenerateMarkdown + GenerateMarkdown --> GenerateMAML + GenerateMAML --> BuildHelp + StageFiles --> BuildHelp + BuildHelp --> Build + StageFiles --> Build + + Build --> Analyze + Build --> Pester + Analyze --> Test + Pester --> Test + + Test --> Publish + + Build --> SignModule + SignModule --> BuildCatalog + BuildCatalog --> SignCatalog + SignCatalog --> Sign + + BuildHelp --> GenerateUpdatableHelp +``` + +## Primary Tasks + +These are the tasks you will typically invoke directly. + +### `Init` + +Initializes the build environment by calling `Initialize-PSBuild`, which sets up `$PSBPreference` defaults and resolves paths relative to the project root. + +**Default dependencies:** none +**Dependency variable:** `$PSBCleanDependency` controls what `Clean` depends on (defaults to `'Init'`) + +```powershell +Invoke-psake -taskList Init +``` + +--- + +### `Clean` + +Removes the module output directory (`$PSBPreference.Build.ModuleOutDir`) to ensure a fresh build. + +**Default dependencies:** `Init` +**Dependency variable:** `$PSBStageFilesDependency` + +```powershell +Invoke-psake -taskList Clean +``` + +--- + +### `Build` + +Meta-task that represents a fully built module. Runs `StageFiles` and `BuildHelp`. This is the task you reference with `-FromModule PowerShellBuild` in your `psakeFile.ps1`. + +**Default dependencies:** `StageFiles`, `BuildHelp` +**Dependency variable:** `$PSBBuildDependency` + +```powershell +# In your psakeFile.ps1 +task Build -FromModule PowerShellBuild -Version '0.7.1' +``` + +--- + +### `Analyze` + +Runs [PSScriptAnalyzer](https://github.com/PowerShell/PSScriptAnalyzer) against the staged module files. Fails the build if any rule violations exceed the configured severity threshold (default: `'Error'`). + +**Default dependencies:** `Build` +**Dependency variable:** `$PSBAnalyzeDependency` +**Precondition:** Only runs if `$PSBPreference.Test.ScriptAnalysis.Enabled` is `$true` and PSScriptAnalyzer is installed. + +```powershell +Invoke-psake -taskList Analyze +``` + +--- + +### `Pester` + +Runs [Pester](https://pester.dev) tests found under `$PSBPreference.Test.RootDir`. Optionally generates a code coverage report. + +**Default dependencies:** `Build` +**Dependency variable:** `$PSBPesterDependency` +**Precondition:** Only runs if `$PSBPreference.Test.Enabled` is `$true`. + +```powershell +Invoke-psake -taskList Pester +``` + +--- + +### `Test` + +Meta-task that runs both `Pester` and `Analyze`. Use this as your standard "did everything pass?" task. + +**Default dependencies:** `Pester`, `Analyze` +**Dependency variable:** `$PSBTestDependency` + +```powershell +Invoke-psake -taskList Test +``` + +--- + +### `Publish` + +Publishes the staged module to the configured PowerShell repository (default: PSGallery). Requires `$PSBPreference.Publish.PSRepositoryApiKey` or `$PSBPreference.Publish.PSRepositoryCredential`. + +**Default dependencies:** `Test` +**Dependency variable:** `$PSBPublishDependency` + +```powershell +Invoke-psake -taskList Publish +``` + +--- + +### `Sign` + +Meta-task that signs the module files and catalog. Runs the full signing chain: `SignModule` → `BuildCatalog` → `SignCatalog`. + +**Default dependencies:** `SignCatalog` +**Dependency variable:** `$PSBSignDependency` + +```powershell +Invoke-psake -taskList Sign +``` + +--- + +## Secondary Tasks + +These tasks are called as dependencies by the primary tasks. You can also invoke them directly for targeted operations. + +### `StageFiles` + +Copies or compiles module source files into the output directory. If `$PSBPreference.Build.CompileModule` is `$true`, it concatenates all `.ps1` files from `CompileDirectories` into a single `.psm1`. Otherwise it copies them as-is. + +**Default dependencies:** `Clean` + +--- + +### `BuildHelp` + +Meta-task that coordinates help generation. Depends on `GenerateMarkdown` and `GenerateMAML`. + +**Default dependencies:** `GenerateMarkdown`, `GenerateMAML` +**Dependency variable:** `$PSBBuildHelpDependency` + +--- + +### `GenerateMarkdown` + +Uses [PlatyPS](https://github.com/PowerShell/platyPS) to generate markdown help files from the module's comment-based help. Output goes to `$PSBPreference.Docs.RootDir`. + +**Default dependencies:** `StageFiles` +**Dependency variable:** `$PSBGenerateMarkdownDependency` + +--- + +### `GenerateMAML` + +Converts PlatyPS markdown files into MAML-format XML help (the format that `Get-Help` reads). Output is placed in the staged module directory. + +**Default dependencies:** `GenerateMarkdown` +**Dependency variable:** `$PSBGenerateMAMLDependency` + +--- + +### `GenerateUpdatableHelp` + +Creates a `.cab` file for [Updatable Help](https://learn.microsoft.com/en-us/powershell/scripting/developer/help/supporting-updatable-help) using `Build-PSBuildUpdatableHelp`. + +**Default dependencies:** `BuildHelp` +**Dependency variable:** `$PSBGenerateUpdatableHelpDependency` + +```powershell +Invoke-psake -taskList GenerateUpdatableHelp +``` + +--- + +### `SignModule` + +Signs all module files (`.psd1`, `.psm1`, `.ps1`) in the output directory with an Authenticode signature. Controlled by `$PSBPreference.Sign.*` settings. + +**Default dependencies:** `Build` +**Dependency variable:** `$PSBSignModuleDependency` + +--- + +### `BuildCatalog` + +Creates a Windows catalog (`.cat`) file for the built module using `New-FileCatalog`. + +**Default dependencies:** `SignModule` +**Dependency variable:** `$PSBBuildCatalogDependency` + +--- + +### `SignCatalog` + +Signs the module catalog (`.cat`) file with an Authenticode signature. + +**Default dependencies:** `BuildCatalog` +**Dependency variable:** `$PSBSignCatalogDependency` + +--- + +### `?` + +Lists all available tasks (psake's built-in help task). + +```powershell +Invoke-psake -taskList ? +``` + +--- + +## Customizing Task Dependencies + +To change which tasks a given task depends on, set the corresponding dependency variable **outside** the `properties` block in your `psakeFile.ps1`, before any PowerShellBuild task references: + +```powershell title="psakeFile.ps1" +# Override before referencing PowerShellBuild tasks +$PSBTestDependency = 'Pester' # Skip Analyze +$PSBPublishDependency = 'Build' # Publish without running tests + +properties { + $PSBPreference.Test.ScriptAnalysis.Enabled = $false +} + +task default -depends Build + +task Build -FromModule PowerShellBuild -Version '0.7.1' +task Test -FromModule PowerShellBuild -Version '0.7.1' +task Publish -FromModule PowerShellBuild -Version '0.7.1' +``` + +:::warning +Removing `Test` from the `Publish` dependency chain means you can publish without passing tests. Only do this in controlled scenarios such as a pre-release pipeline where tests are already enforced upstream. +::: + +## See Also + +- [Configuration](./configuration) — Full `$PSBPreference` reference +- [Getting Started](./getting-started) — Set up your first project +- [Real-World Example](./real-world-example) — Custom tasks alongside PowerShellBuild tasks diff --git a/docusaurus.config.ts b/docusaurus.config.ts index faa2b5e..311a021 100644 --- a/docusaurus.config.ts +++ b/docusaurus.config.ts @@ -92,6 +92,12 @@ const config: Config = { position: 'left', label: 'Guides', }, + { + type: 'docSidebar', + sidebarId: 'powershellBuildSidebar', + position: 'left', + label: 'PowerShellBuild', + }, { type: 'docSidebar', sidebarId: 'referenceSidebar', @@ -120,6 +126,10 @@ const config: Config = { label: 'Guides', to: '/docs/tutorial-basics/default-build-files', }, + { + label: 'PowerShellBuild', + to: '/docs/powershellbuild/introduction', + }, { label: 'Command Reference', to: '/docs/commands/Invoke-psake', diff --git a/plan.md b/plan.md new file mode 100644 index 0000000..f93ad46 --- /dev/null +++ b/plan.md @@ -0,0 +1,128 @@ +# Plan: Add PowerShellBuild Documentation Section + +## Background + +PowerShellBuild is the official companion module to psake (same GitHub org: `psake/PowerShellBuild`). It provides reusable, pre-packaged build tasks for PowerShell module projects — covering build, test, analysis, help generation, signing, and publishing. It leverages psake's shared-task feature (introduced in v4.8.0) so module authors get a full pipeline with minimal configuration. Currently, the psake docs site has zero coverage of PowerShellBuild (it's listed as a future Phase 4 item in `DOCUMENTATION_EXPANSION_PLAN.md`). + +## Proposed Structure + +Create a new `docs/powershellbuild/` directory with five focused pages, added as a **"PowerShellBuild" category** in the `guidesSidebar` (positioned between "Advanced Techniques" and "Build Type Examples"). + +### Files to Create + +#### 1. `docs/powershellbuild/_category_.json` +Category metadata for Docusaurus sidebar auto-generation. + +```json +{ + "label": "PowerShellBuild", + "position": 3, + "link": { + "type": "generated-index", + "description": "Learn how to use PowerShellBuild, the official companion module that provides reusable psake tasks for building, testing, and publishing PowerShell modules." + } +} +``` + +#### 2. `docs/powershellbuild/introduction.md` +**Purpose:** What PowerShellBuild is, why it exists, and how it relates to psake. + +Content outline: +- What is PowerShellBuild (companion module providing shared psake tasks) +- The problem it solves (boilerplate reduction for PS module authors) +- Relationship to psake — psake is the engine, PowerShellBuild is the pre-built task library +- Also supports Invoke-Build (brief mention, link to their docs) +- When to use PowerShellBuild vs. writing custom psake tasks +- Links to GitHub repo and PowerShell Gallery + +#### 3. `docs/powershellbuild/getting-started.md` +**Purpose:** Step-by-step guide to add PowerShellBuild to a PowerShell module project. + +Content outline: +- Prerequisites (psake >= 4.9.0, PowerShell 5.1+/7+) +- Installation (`Install-Module -Name PowerShellBuild`) +- Minimal psakeFile.ps1 example using `-FromModule PowerShellBuild` +- Expected directory structure for a PowerShell module project +- Running the build (`Invoke-psake`) +- What happens when you run Build (walkthrough of the task chain: Init → Clean → StageFiles → BuildHelp → Build) +- Invoke-Build alternative (dot-sourcing via `PowerShellBuild.IB.Tasks` alias) + +#### 4. `docs/powershellbuild/task-reference.md` +**Purpose:** Complete reference of all pre-built tasks with their dependencies and behavior. + +Content outline: +- Primary tasks table (Init, Clean, Build, Analyze, Pester, Test, Publish, Sign) +- Secondary tasks table (StageFiles, BuildHelp, GenerateMarkdown, GenerateMAML, GenerateUpdatableHelp, SignModule, BuildCatalog, SignCatalog) +- Mermaid diagram showing the full task dependency graph +- Description of each task's behavior +- How to run specific tasks (`Invoke-psake -taskList Analyze`) + +#### 5. `docs/powershellbuild/configuration.md` +**Purpose:** Complete reference for `$PSBPreference` and task dependency customization. + +Content outline: +- Overview of `$PSBPreference` hashtable +- Configuration categories with all options: + - General (ProjectRoot, SrcRootDir, ModuleName, etc.) + - Build (OutDir, CompileModule, CompileDirectories, CopyDirectories, Exclude) + - Test (Enabled, RootDir, OutputFile, OutputFormat, OutputVerbosity) + - Script Analysis (Enabled, FailBuildOnSeverityLevel, SettingsPath) + - Code Coverage (Enabled, Threshold, OutputFileFormat) + - Help (DefaultLocale, UpdatableHelpOutDir, ConvertReadMeToAboutHelp) + - Docs (RootDir, Overwrite, AlphabeticParamsOrder, UseFullTypeName) + - Publish (PSRepository, PSRepositoryApiKey, PSRepositoryCredential) + - Sign (Enabled, CertificateSource, Thumbprint, TimestampServer, HashAlgorithm) +- Example: Customizing configuration in the `properties` block +- Task dependency variables ($PSBBuildDependency, $PSBTestDependency, etc.) +- Example: Changing task dependency chains + +#### 6. `docs/powershellbuild/real-world-example.md` +**Purpose:** A complete, end-to-end example showing PowerShellBuild in a real project. + +Content outline: +- Complete project structure (directory tree) +- Full psakeFile.ps1 with customized preferences and added custom tasks +- build.ps1 bootstrap wrapper +- requirements.psd1 with PowerShellBuild dependency +- CI/CD integration (GitHub Actions workflow using PowerShellBuild tasks) +- Publishing to PSGallery via the Publish task +- Combining custom tasks with PowerShellBuild tasks (e.g., adding a Deploy task that depends on Publish) + +### File to Modify + +#### `sidebars.ts` +Add a new "PowerShellBuild" category to `guidesSidebar`, between "Advanced Techniques" and "Build Type Examples": + +```typescript +{ + type: 'category', + label: 'PowerShellBuild', + items: [ + 'powershellbuild/introduction', + 'powershellbuild/getting-started', + 'powershellbuild/task-reference', + 'powershellbuild/configuration', + 'powershellbuild/real-world-example', + ], +}, +``` + +## Implementation Steps + +1. Create `docs/powershellbuild/_category_.json` +2. Create `docs/powershellbuild/introduction.md` +3. Create `docs/powershellbuild/getting-started.md` +4. Create `docs/powershellbuild/task-reference.md` +5. Create `docs/powershellbuild/configuration.md` +6. Create `docs/powershellbuild/real-world-example.md` +7. Update `sidebars.ts` — add PowerShellBuild category to `guidesSidebar` +8. Verify: run `yarn run start` or `.\build.ps1 -Task Test` to validate sidebar links and build + +## Conventions to Follow + +- **Frontmatter:** Each `.md` file gets `title` and `description` fields +- **Structure:** Intro paragraph → main sections with `##` headings → code examples → "See Also" links +- **Code blocks:** Use ` ```powershell ` for PS examples, ` ```yaml ` for CI configs +- **Cross-references:** Link to existing psake docs (e.g., tasks, properties, CI/CD examples) +- **No emoji** unless the user explicitly requests them +- **Mermaid diagrams** are supported and enabled in docusaurus config — use for the task dependency graph diff --git a/sidebars.ts b/sidebars.ts index eadf34c..544006e 100644 --- a/sidebars.ts +++ b/sidebars.ts @@ -73,6 +73,15 @@ const sidebars: SidebarsConfig = { }, ], + // PowerShellBuild - Companion module for building PowerShell modules + powershellBuildSidebar: [ + 'powershellbuild/introduction', + 'powershellbuild/getting-started', + 'powershellbuild/task-reference', + 'powershellbuild/configuration', + 'powershellbuild/real-world-example', + ], + // Reference - Command reference, troubleshooting, and lookup materials referenceSidebar: [ {