Skip to content

Commit e2c7fe3

Browse files
Add GitHub Actions for PowerShell module CI/CD pipeline including dependency resolution, building, testing, static analysis, and release processes
1 parent aa06c42 commit e2c7fe3

File tree

9 files changed

+467
-9
lines changed

9 files changed

+467
-9
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
name: CodeQL Analysis
2+
description: Initialize and run CodeQL analysis
3+
runs:
4+
using: composite
5+
steps:
6+
- name: Checkout repository
7+
uses: actions/checkout@v6
8+
- name: Initialize CodeQL
9+
uses: github/codeql-action/init@v4
10+
with:
11+
languages: actions
12+
build-mode: none
13+
- name: Perform CodeQL Analysis
14+
uses: github/codeql-action/analyze@v4
15+
with:
16+
category: "/language:${{matrix.language}}"
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
name: Build PowerShell Module
2+
description: Build module, generate help, and upload artifacts
3+
inputs:
4+
module-list:
5+
description: Comma-separated list of PowerShell modules to cache
6+
required: true
7+
release-type:
8+
description: Type of release (Release, Prerelease, Debug)
9+
default: Debug
10+
required: false
11+
outputs:
12+
build-version:
13+
description: Semantic build version
14+
value: ${{ steps.compute.outputs.build-version }}
15+
release-version:
16+
description: Release version from GitVersion
17+
value: ${{ steps.gitversion.outputs.majorMinorPatch }}
18+
runs:
19+
using: composite
20+
steps:
21+
- name: Checkout repository
22+
uses: actions/checkout@v6
23+
with:
24+
repository: ${{ github.repository }}
25+
fetch-depth: 0
26+
27+
- name: Install GitVersion tool
28+
uses: gittools/actions/gitversion/setup@d0139503a9321f76b4a417dfdc8aebcec24decdd #v4.2.0
29+
with:
30+
versionSpec: '6.5.1'
31+
32+
- name: Get semantic build version
33+
id: gitversion
34+
uses: gittools/actions/gitversion/execute@d0139503a9321f76b4a417dfdc8aebcec24decdd #v4.2.0
35+
with:
36+
configFilePath: GitVersion.yml
37+
disableShallowCloneCheck: true
38+
39+
- name: Restore cached PowerShell modules
40+
uses: potatoqualitee/psmodulecache@ee5e9494714abf56f6efbfa51527b2aec5c761b8 #v6.2.1
41+
with:
42+
modules-to-cache: ${{ inputs.module-list }}
43+
shell: pwsh
44+
updatable: false
45+
46+
- name: Determine build version
47+
id: compute
48+
shell: pwsh
49+
run: |
50+
switch ('${{ inputs.release-type }}') {
51+
'Release' {
52+
$buildVersion = '${{ steps.gitversion.outputs.semVer }}'.Split('-', 2)[0]
53+
}
54+
'Prerelease' {
55+
$buildVersion = '${{ steps.gitversion.outputs.semVer }}'.Split('-', 2)[0] + '-Prerelease'
56+
}
57+
'Debug' {
58+
$buildVersion = '${{ steps.gitversion.outputs.semVer }}'
59+
}
60+
}
61+
echo "build-version=$buildVersion" >> $env:GITHUB_OUTPUT
62+
63+
- name: Run build via Invoke-Build
64+
shell: pwsh
65+
run: |
66+
Set-StrictMode -Version Latest
67+
[void] (Import-Module InvokeBuild)
68+
$requestParam = @{
69+
SemanticVersion = '${{ steps.compute.outputs.build-version }}'
70+
Task = 'Build'
71+
}
72+
Invoke-Build @requestParam
73+
74+
- name: Run Export-CommandHelp via Invoke-Build
75+
shell: pwsh
76+
run: |
77+
Set-StrictMode -off
78+
[void] (Import-Module InvokeBuild)
79+
$requestParam = @{
80+
SemanticVersion = '${{ steps.gitversion.outputs.majorMinorPatch }}'
81+
Task = 'Export-CommandHelp'
82+
}
83+
Invoke-Build @requestParam
84+
85+
- name: Upload build artifacts
86+
uses: actions/upload-artifact@v6
87+
if: (!cancelled())
88+
with:
89+
name: build-v${{ steps.gitversion.outputs.majorMinorPatch }}
90+
path: build
91+
if-no-files-found: warn
92+
93+
- name: Commit generated help
94+
if: ${{ github.ref_name == 'main' && github.event_name == 'push' }}
95+
shell: bash
96+
run: |
97+
git add docs/help
98+
if git diff --cached --quiet; then
99+
echo "No help changes to commit"
100+
exit 0
101+
fi
102+
git config user.name "github-actions[bot]"
103+
git config user.email "github-actions[bot]@users.noreply.github.com"
104+
git commit -m "Update PowerShell help for release v${{ steps.gitversion.outputs.majorMinorPatch }}"
105+
git push origin HEAD:main
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
name: Run InjectionHunter
2+
description: Execute code injection analysis and publish results
3+
inputs:
4+
module-list:
5+
description: Comma-separated list of PowerShell modules to cache
6+
required: true
7+
runs:
8+
using: composite
9+
steps:
10+
- name: Checkout repository
11+
uses: actions/checkout@v6
12+
with:
13+
repository: ${{ github.repository }}
14+
15+
- name: Install and cache PowerShell modules
16+
uses: potatoqualitee/psmodulecache@ee5e9494714abf56f6efbfa51527b2aec5c761b8 #v6.2.1
17+
with:
18+
modules-to-cache: ${{ inputs.module-list }}
19+
shell: pwsh
20+
updatable: false
21+
22+
- name: Run Code Injection Analysis via Invoke-Build
23+
shell: pwsh
24+
run: |
25+
Set-StrictMode -Version Latest
26+
Invoke-Build -Task Invoke-InjectionHunter
27+
28+
- name: Publish Code Injection Analysis Results
29+
uses: EnricoMi/publish-unit-test-result-action@27d65e188ec43221b20d26de30f4892fad91df2f #v2.22.0
30+
if: (!cancelled())
31+
with:
32+
check_run: false
33+
check_name: ">> Report: InjectionHunter"
34+
check_run_annotations : all tests, skipped tests
35+
job_summary: true
36+
comment_title: InjectionHunter Report
37+
comment_mode: off
38+
files: |
39+
test-results/code-injection.xml
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
name: Release PowerShell Module
2+
description: Create GitHub release and optionally publish to PSGallery
3+
inputs:
4+
release-type:
5+
description: Release type
6+
required: true
7+
release-version:
8+
description: Release version
9+
required: true
10+
publish-psgallery:
11+
description: Publish to PowerShell Gallery
12+
required: true
13+
publish-nugetorg:
14+
description: Publish to NuGet.org (not implemented)
15+
required: true
16+
module-list:
17+
description: Comma-separated list of PowerShell modules to cache
18+
required: true
19+
runs:
20+
using: composite
21+
steps:
22+
- name: Checkout repository
23+
uses: actions/checkout@v6
24+
with:
25+
repository: ${{ github.repository }}
26+
27+
- name: Restore cached PowerShell modules
28+
uses: potatoqualitee/psmodulecache@ee5e9494714abf56f6efbfa51527b2aec5c761b8 #v6.2.1
29+
with:
30+
modules-to-cache: ${{ inputs.module-list }}
31+
shell: pwsh
32+
updatable: false
33+
34+
- name: Restore build artifacts
35+
uses: actions/download-artifact@v4
36+
with:
37+
name: build-v${{ inputs.release-version }}
38+
path: build
39+
40+
- name: Display structure of downloaded files
41+
shell: bash
42+
run: ls -R build
43+
44+
- name: Generate release notes
45+
shell: pwsh
46+
id: generate_release_notes
47+
env:
48+
GITHUB_TOKEN: ${{ github.token }}
49+
run: |
50+
git fetch --tags
51+
$previousTag = (git tag --sort=-v:refname)[0]
52+
$uri = "https://api.github.com/repos/${{ github.repository }}/releases/generate-notes"
53+
$body = @{
54+
tag_name = "v${{ inputs.release-version }}"
55+
target_commitish = "main"
56+
previous_tag_name = $previousTag
57+
}
58+
$requestParams = @{
59+
Method = 'Post'
60+
Uri = $uri
61+
Headers = @{
62+
Authorization = "Bearer ${{ env.GITHUB_TOKEN }}"
63+
Accept = 'application/vnd.github+json'
64+
}
65+
Body = ($body | ConvertTo-Json -Depth 3)
66+
ContentType = 'application/json'
67+
}
68+
$result = Invoke-RestMethod @requestParams
69+
Write-Output 'releaseNotes<<EOF' >> $env:GITHUB_OUTPUT
70+
Write-Output ($result.body.ToString()) >> $env:GITHUB_OUTPUT
71+
Write-Output 'EOF' >> $env:GITHUB_OUTPUT
72+
73+
- name: Create release
74+
uses: ncipollo/release-action@v1
75+
with:
76+
name: Release v${{ inputs.release-version }}
77+
tag: v${{ inputs.release-version }}
78+
body: ${{ steps.generate_release_notes.outputs.releaseNotes }}
79+
prerelease: ${{ inputs.release-type == 'Prerelease' }}
80+
allowUpdates: true
81+
82+
- name: Publish build package to PSGallery
83+
if: ${{ inputs.publish-psgallery == 'true' && env.PSGALLERY_API_KEY != '' }}
84+
shell: pwsh
85+
env:
86+
PSGALLERY_API_KEY: ${{ env.PSGALLERY_API_KEY }}
87+
run: |
88+
Set-StrictMode -Version Latest
89+
[void] (Import-Module InvokeBuild)
90+
Invoke-Build -NugetApiKey ${{ env.PSGALLERY_API_KEY }} -Task Publish
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
name: Resolve PowerShell Dependencies
2+
description: Resolve module dependencies from requirements.psd1 and output a comma-separated list
3+
outputs:
4+
module-list:
5+
description: Comma-separated list of modules to cache
6+
value: ${{ steps.resolve.outputs.module-list }}
7+
runs:
8+
using: composite
9+
steps:
10+
- name: Checkout repository
11+
uses: actions/checkout@v6
12+
with:
13+
repository: ${{ github.repository }}
14+
- name: Resolve module dependencies
15+
id: resolve
16+
shell: pwsh
17+
run: |
18+
$moduleRequirements = Import-PowerShellDataFile -Path './requirements.psd1'
19+
$moduleList = foreach ($module in $moduleRequirements.GetEnumerator()) {
20+
$moduleName = $module.Key
21+
$moduleInfo = $module.Value
22+
23+
$name = if ($moduleInfo.Repository -and $moduleInfo.Repository -ne 'PSGallery') {
24+
"$($moduleInfo.Repository)\$moduleName"
25+
}
26+
else {
27+
$moduleName
28+
}
29+
30+
if ($moduleInfo.Version -and $moduleInfo.Version -ne 'latest') {
31+
"$name`:$($moduleInfo.Version)"
32+
}
33+
else {
34+
$name
35+
}
36+
}
37+
$moduleList = $moduleList | Sort-Object | Join-String -Separator ','
38+
"module-list=$moduleList" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
name: Run PSScriptAnalyzer
2+
description: Execute static code analysis and publish results
3+
inputs:
4+
module-list:
5+
description: Comma-separated list of PowerShell modules to cache
6+
required: true
7+
runs:
8+
using: composite
9+
steps:
10+
- name: Checkout repository
11+
uses: actions/checkout@v6
12+
with:
13+
repository: ${{ github.repository }}
14+
15+
- name: Install and cache PowerShell modules
16+
uses: potatoqualitee/psmodulecache@ee5e9494714abf56f6efbfa51527b2aec5c761b8 #v6.2.1
17+
with:
18+
modules-to-cache: ${{ inputs.module-list }}
19+
shell: pwsh
20+
updatable: false
21+
22+
- name: Run Static Code Analysis via Invoke-Build
23+
shell: pwsh
24+
run: |
25+
Set-StrictMode -Version Latest
26+
Invoke-Build -Task Invoke-PSScriptAnalyzer
27+
28+
- name: Publish Static Code Analysis Results
29+
uses: EnricoMi/publish-unit-test-result-action@27d65e188ec43221b20d26de30f4892fad91df2f #v2.22.0
30+
if: (!cancelled())
31+
with:
32+
check_run: false
33+
check_name: ">> Report: PSScriptAnalyzer"
34+
check_run_annotations : all tests, skipped tests
35+
job_summary: true
36+
comment_title: PSScriptAnalyzer Report
37+
comment_mode: off
38+
files: |
39+
test-results/static-code-analysis.xml

0 commit comments

Comments
 (0)