-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPublishModuleToPowerShellGallery.yaml
More file actions
160 lines (148 loc) · 6.75 KB
/
PublishModuleToPowerShellGallery.yaml
File metadata and controls
160 lines (148 loc) · 6.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
name: Publish Module to PowerShell Gallery
on:
push:
branches:
- main
paths:
- '{{ModuleName}}/{{ModuleName}}.psd1'
workflow_dispatch:
permissions:
contents: write
jobs:
publish:
name: Publish Module
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
# Never publish the un-initialized template — the .psd1 still has
# {{ModuleName}} and {{GUID}} placeholders. Same marker as CI.yaml:
# CHANGELOG.template.md exists only pre-init. hashFiles() is not allowed
# in jobs.<job_id>.if, so we evaluate it in a step and gate the
# version-detection and release-check steps on the resulting output;
# everything downstream cascades on those steps' outputs and skips
# naturally when they don't run.
- name: Detect template state
id: template_guard
shell: bash
run: |
if [ -f CHANGELOG.template.md ]; then
echo "is_template=true" >> "$GITHUB_OUTPUT"
else
echo "is_template=false" >> "$GITHUB_OUTPUT"
fi
- name: Get Module Version
id: version
if: steps.template_guard.outputs.is_template == 'false'
shell: pwsh
run: |
$manifest = Import-PowerShellDataFile -Path ./{{ModuleName}}/{{ModuleName}}.psd1
$version = $manifest.ModuleVersion
Write-Host "Module version: $version"
"version=$version" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
- name: Check if Release Exists
id: check_release
if: steps.template_guard.outputs.is_template == 'false'
shell: bash
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
VERSION: ${{ steps.version.outputs.version }}
run: |
if gh release view "v$VERSION" > /dev/null 2>&1; then
echo "exists=true" >> $GITHUB_OUTPUT
echo "GitHub release v$VERSION already exists"
else
echo "exists=false" >> $GITHUB_OUTPUT
echo "GitHub release v$VERSION does not exist"
fi
- name: Check if PSGallery Version Exists
id: check_psgallery
# Run regardless of whether the GitHub release exists, so a release that was
# created but never published can still be recovered (see Publish gating below).
if: steps.template_guard.outputs.is_template == 'false'
shell: pwsh
env:
VERSION: ${{ steps.version.outputs.version }}
run: |
$version = $env:VERSION
$findError = $null
$published = Find-Module -Name {{ModuleName}} -RequiredVersion $version -Repository PSGallery -ErrorAction SilentlyContinue -ErrorVariable findError
if ($published) {
Write-Host "PSGallery version $version already exists"
"exists=true" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
} elseif ($findError) {
# Find-Module records no error when the version simply isn't on the gallery,
# so a recorded error means the query itself failed (transient/network). Don't
# treat that as "not published" (publishing is now gated only on this check) —
# fail so the run is visibly retryable instead of attempting a blind publish.
throw "PowerShell Gallery query failed for version ${version}: $($findError[0].Exception.Message)"
} else {
Write-Host "PSGallery version $version not found - will publish"
"exists=false" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
}
- name: Bootstrap
if: steps.check_release.outputs.exists == 'false' || steps.check_psgallery.outputs.exists == 'false'
shell: pwsh
run: ./build.ps1 -Task Init -Bootstrap
- name: Create GitHub Release
if: steps.check_release.outputs.exists == 'false'
shell: pwsh
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPOSITORY: ${{ github.repository }}
VERSION: ${{ steps.version.outputs.version }}
run: |
$version = $env:VERSION
# Build release notes from this version's CHANGELOG.md section so the release
# body carries only the curated, user-facing entries (not the full PR list that
# --generate-notes produces, which is dominated by bot/CI/chore PRs).
# Read defensively: a missing/unreadable CHANGELOG.md must fall back to
# --generate-notes (below), never fail the publish.
$changelogLines = $null
if (Test-Path -LiteralPath './CHANGELOG.md') {
try {
$changelogLines = Get-Content -LiteralPath './CHANGELOG.md' -ErrorAction Stop
}
catch {
Write-Host "::warning::Could not read CHANGELOG.md ($($_.Exception.Message)); falling back to auto-generated notes."
}
}
$captured = [System.Collections.Generic.List[string]]::new()
if ($changelogLines) {
$headerPattern = '^##\s+\[' + [regex]::Escape($version) + '\]'
$capturing = $false
foreach ($line in $changelogLines) {
if (-not $capturing) {
if ($line -match $headerPattern) { $capturing = $true }
continue
}
if ($line -match '^##\s+\[') { break } # next version header ends the section
$captured.Add($line)
}
}
$body = ($captured -join "`n").Trim()
if ([string]::IsNullOrWhiteSpace($body)) {
Write-Host "::warning::No CHANGELOG.md section found for $version; falling back to auto-generated notes."
gh release create "v$version" --title "v$version" --generate-notes
}
else {
# Append a compare link against the most recent existing tag. The v$version
# tag does not exist yet (this step creates it), so the latest tag is the
# previous release.
$previousTag = git tag --list 'v*' --sort=-version:refname |
Where-Object { $_ -ne "v$version" } |
Select-Object -First 1
if ($previousTag) {
$body += "`n`n**Full Changelog**: https://github.com/$env:REPOSITORY/compare/$previousTag...v$version"
}
Set-Content -LiteralPath './release-notes.md' -Value $body -Encoding utf8
gh release create "v$version" --title "v$version" --notes-file './release-notes.md'
}
- name: Publish to PSGallery
if: steps.check_psgallery.outputs.exists == 'false'
shell: pwsh
env:
PSGALLERY_API_KEY: ${{ secrets.PSGALLERY_API_KEY }}
run: ./build.ps1 -Task Publish -Bootstrap