Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
},
{
"name": "powershellbuild",
"source": "./powershellbuild",
"source": "./plugins/powershellbuild",
"description": "PowerShellBuild — standardized build, test, and publish tasks for PowerShell module development",
"version": "1.0.0",
"author": {
Expand Down
102 changes: 99 additions & 3 deletions plugins/powershellbuild/evals/evals.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,115 @@
"id": 1,
"prompt": "I'm starting a new PowerShell module project called 'PSUtilities'. It'll have Public and Private function folders and a tests/ directory with Pester 5 tests. Can you scaffold the full build system using PowerShellBuild — I need build.ps1, psakeFile.ps1, and requirements.psd1. I want code coverage at 80% and PSScriptAnalyzer enabled.",
"expected_output": "Three files: build.ps1 (Bootstrap + Invoke-psake entry point), psakeFile.ps1 (Import-Module PowerShellBuild, properties block with PSBPreference settings for coverage threshold 0.80 and ScriptAnalysis, tasks using -FromModule PowerShellBuild), requirements.psd1 (psake, PowerShellBuild, Pester, PSScriptAnalyzer, platyPS). Structure follows PowerShellBuild conventions.",
"files": []
"files": [],
"assertions": [
{
"name": "has_all_three_files",
"type": "regex",
"value": "(?i)(build\\.ps1|psakeFile\\.ps1|requirements\\.psd1)",
"description": "Should generate build.ps1, psakeFile.ps1, and requirements.psd1"
},
{
"name": "uses_from_module",
"type": "contains",
"value": "-FromModule PowerShellBuild",
"description": "psakeFile.ps1 should use -FromModule PowerShellBuild for task definitions"
},
{
"name": "has_code_coverage_threshold",
"type": "regex",
"value": "CodeCoverage\\.Threshold\\s*=\\s*0\\.80",
"description": "Code coverage threshold should be set to 0.80 (80%)"
},
{
"name": "has_script_analysis_enabled",
"type": "regex",
"value": "ScriptAnalysis\\.Enabled\\s*=\\s*\\$true",
"description": "PSScriptAnalyzer should be explicitly enabled via PSBPreference"
},
{
"name": "has_required_dependencies",
"type": "regex",
"value": "(?i)(PowerShellBuild|psake|Pester|PSScriptAnalyzer)",
"description": "requirements.psd1 should include psake, PowerShellBuild, Pester, and PSScriptAnalyzer"
}
]
},
{
"id": 2,
"prompt": "My PowerShellBuild project builds fine locally but I need to set up GitHub Actions CI. I want it to run tests on every push and PR, then publish to PSGallery automatically when I push to main. The API key should come from a GitHub secret called PSGALLERY_API_KEY.",
"expected_output": "A GitHub Actions workflow YAML with two jobs: test (runs on push/PR, calls ./build.ps1 -Task Test -Bootstrap on windows-latest) and publish (depends on test, only on main branch, passes PSGALLERY_API_KEY secret as env var). Uses actions/checkout@v4.",
"files": []
"files": [],
"assertions": [
{
"name": "has_two_jobs",
"type": "regex",
"value": "(?i)(test:|publish:)",
"description": "Workflow should have separate test and publish jobs"
},
{
"name": "triggers_on_push_and_pr",
"type": "regex",
"value": "(?i)(push|pull_request)",
"description": "Test job should trigger on both push and pull_request events"
},
{
"name": "publish_only_on_main",
"type": "regex",
"value": "(?i)(refs/heads/main|github\\.ref.*main)",
"description": "Publish job should only run on main branch"
},
{
"name": "has_psgallery_secret",
"type": "contains",
"value": "PSGALLERY_API_KEY",
"description": "PSGALLERY_API_KEY should be passed from GitHub secrets"
},
{
"name": "uses_build_ps1",
"type": "regex",
"value": "(?i)(\\.[\\/]build\\.ps1|build\\.ps1)",
"description": "Workflow should call ./build.ps1 rather than Invoke-psake directly"
}
]
},
{
"id": 3,
"prompt": "I want to use Invoke-Build instead of psake for my PowerShellBuild project. Can you show me how to set up the .build.ps1 file? I need to compile the module into a single PSM1 from Classes, Private, and Public folders, run code coverage, and exclude any .Tests.ps1 files from the build output.",
"expected_output": "A .build.ps1 using Invoke-Build syntax: Import-Module PowerShellBuild -Force, . PowerShellBuild.IB.Tasks, then PSBPreference settings for CompileModule=$true, CompileDirectories=@('Classes','Private','Public'), Exclude=@('*.Tests.ps1'), CodeCoverage.Enabled=$true. Default task set to Build or Test.",
"files": []
"files": [],
"assertions": [
{
"name": "uses_ib_tasks",
"type": "contains",
"value": "PowerShellBuild.IB.Tasks",
"description": "Should use . PowerShellBuild.IB.Tasks to load Invoke-Build tasks"
},
{
"name": "has_compile_module",
"type": "regex",
"value": "CompileModule\\s*=\\s*\\$true",
"description": "CompileModule should be set to $true"
},
{
"name": "has_compile_directories",
"type": "regex",
"value": "CompileDirectories\\s*=",
"description": "CompileDirectories should include Classes, Private, and Public"
},
{
"name": "has_exclude_tests",
"type": "regex",
"value": "(?i)(Exclude.*Tests\\.ps1|Tests\\.ps1.*Exclude)",
"description": "Exclude pattern should filter out *.Tests.ps1 files"
},
{
"name": "has_code_coverage_enabled",
"type": "regex",
"value": "CodeCoverage\\.Enabled\\s*=\\s*\\$true",
"description": "Code coverage should be enabled via PSBPreference"
}
]
}
]
}
118 changes: 8 additions & 110 deletions plugins/powershellbuild/skills/powershellbuild/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: powershellbuild
description: PowerShellBuild module for standardized PowerShell module development. Use when Claude needs to help set up or troubleshoot PowerShellBuild-based projects, generate psakeFile.ps1 or .build.ps1 files using PowerShellBuild tasks, configure build/test/publish pipelines for PowerShell modules, or work with PSBPreference settings. Triggers include mentions of PowerShellBuild, PSBPreference, PowerShell module builds, Pester, PSScriptAnalyzer, PlatyPS, PSGallery publishing, or any request to set up a PowerShell module build system.
description: This skill should be used when the user asks to "set up PowerShellBuild", "create a psakeFile with -FromModule", "configure PSBPreference", "publish a PowerShell module to PSGallery", "set up Pester tests for a module", or mentions PowerShellBuild, PSBPreference, -FromModule PowerShellBuild, PowerShellBuild.IB.Tasks, PSScriptAnalyzer integration, PlatyPS help generation, code coverage thresholds, or PowerShell module build/test/publish pipelines.
---

# PowerShellBuild
Expand All @@ -15,10 +15,10 @@ PowerShellBuild provides standardized build, test, and publish tasks for PowerSh
- **Not sure / starting fresh** → default to psake (simpler syntax)

**What do you need?**
- Set up a new module project → [Complete Example](#complete-example)
- Set up a new module project → See `references/complete-example.md`
- Override build behavior → [Configuration ($PSBPreference)](#configuration-psbpreference)
- Customize task dependencies → [Modifying Task Dependencies](#modifying-task-dependencies)
- CI/CD setup → [CI/CD Integration](#cicd-integration)
- CI/CD setup → See `references/ci-cd.md`

## Quick Start

Expand Down Expand Up @@ -140,82 +140,6 @@ $PSBTestDependency = 'Pester' # skip analysis
$PSBPublishDependency = 'Build' # publish without tests (not recommended)
```

## Complete Example

### build.ps1

```powershell
[cmdletbinding(DefaultParameterSetName = 'Task')]
param(
[parameter(ParameterSetName = 'Task', position = 0)]
[string[]]$Task = 'default',

[switch]$Bootstrap,

[parameter(ParameterSetName = 'Help')]
[switch]$Help
)

$ErrorActionPreference = 'Stop'

if ($Bootstrap.IsPresent) {
Get-PackageProvider -Name Nuget -ForceBootstrap | Out-Null
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted
if (-not (Get-Module -Name PSDepend -ListAvailable)) {
Install-Module -Name PSDepend -Repository PSGallery -Scope CurrentUser
}
Import-Module -Name PSDepend -Verbose:$false
Invoke-PSDepend -Path './requirements.psd1' -Install -Import -Force -WarningAction SilentlyContinue
}

$psakeFile = './psakeFile.ps1'
if ($PSCmdlet.ParameterSetName -eq 'Help') {
Get-PSakeScriptTasks -buildFile $psakeFile | Format-Table -Property Name, Description
} else {
Set-BuildEnvironment -Force
Invoke-psake -buildFile $psakeFile -taskList $Task -Verbose:$VerbosePreference
exit ([int](-not $psake.build_success))
}
```

### requirements.psd1

```powershell
@{
PSDependOptions = @{ Target = 'CurrentUser' }
psake = '4.9.0'
PowerShellBuild = 'latest'
Pester = @{
MinimumVersion = '5.6.1'
Parameters = @{ SkipPublisherCheck = $true }
}
PSScriptAnalyzer = '1.24.0'
platyPS = '0.14.2'
}
```

### psakeFile.ps1 (full)

```powershell
properties {
$PSBPreference.Build.CompileModule = $true
$PSBPreference.Build.CompileDirectories = @('Enum', 'Classes', 'Private', 'Public')
$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 Test

task Clean -FromModule PowerShellBuild
task Build -FromModule PowerShellBuild
task Analyze -FromModule PowerShellBuild
task Pester -FromModule PowerShellBuild
task Test -FromModule PowerShellBuild
task Publish -FromModule PowerShellBuild
```

## Invoke-Build Alternative

```powershell
Expand All @@ -228,37 +152,6 @@ $PSBPreference.Test.CodeCoverage.Threshold = 0.75
task . Build
```

## CI/CD Integration

### GitHub Actions

```yaml
name: CI

on: [push, pull_request]

jobs:
test:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- name: Test
shell: pwsh
run: ./build.ps1 -Task Test -Bootstrap

publish:
needs: test
runs-on: windows-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: Publish
shell: pwsh
run: ./build.ps1 -Task Publish -Bootstrap
env:
PSGALLERY_API_KEY: ${{ secrets.PSGALLERY_API_KEY }}
```

## Troubleshooting

| Problem | Solution |
Expand All @@ -270,3 +163,8 @@ jobs:
| ScriptAnalyzer fails build | Fix violations or set `FailBuildOnSeverityLevel = 'Warning'` |
| Code coverage below threshold | Raise `CodeCoverage.Threshold` or add tests |
| Publish fails | Verify `PSGALLERY_API_KEY` env var is set |

## References

- **`references/complete-example.md`** - Full project scaffold: build.ps1, requirements.psd1, psakeFile.ps1 with all tasks
- **`references/ci-cd.md`** - GitHub Actions workflow for test and publish pipelines
37 changes: 37 additions & 0 deletions plugins/powershellbuild/skills/powershellbuild/references/ci-cd.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# CI/CD Integration with PowerShellBuild

## GitHub Actions

```yaml
name: CI

on: [push, pull_request]

jobs:
test:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- name: Test
shell: pwsh
run: ./build.ps1 -Task Test -Bootstrap

publish:
needs: test
runs-on: windows-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: Publish
shell: pwsh
run: ./build.ps1 -Task Publish -Bootstrap
env:
PSGALLERY_API_KEY: ${{ secrets.PSGALLERY_API_KEY }}
```

### Key Points

- Always use `./build.ps1` as the entry point, not `Invoke-psake` directly — `build.ps1` handles bootstrapping dependencies and setting up the build environment.
- Use `-Bootstrap` on the first run (or always in CI) to install dependencies from `requirements.psd1`.
- Pass secrets as environment variables, not as parameters.
- Publish job should depend on the test job (`needs: test`) and only run on main branch.
Loading
Loading