Skip to content

Commit 341f921

Browse files
tablackburnclaude
andcommitted
ci(release): build release notes from CHANGELOG and harden version expansion
Ports the ScheduledTasksManager release-tooling improvements into the template so every module scaffolded from it inherits them. - Create GitHub Release: extract the published version's section from CHANGELOG.md and pass it via --notes-file (in pwsh), instead of --generate-notes. The latter lists every merged PR since the last release tag, which between version bumps is dominated by bot/CI/chore PRs and buries the actual user-facing changes. Includes a Full Changelog compare link and falls back to --generate-notes if a version has no changelog section (so a release is never blocked). - Pass the version output via env (VERSION) in the 'Check if Release Exists', 'Check if PSGallery Version Exists', and 'Create GitHub Release' steps instead of inlining ${{ steps.version.outputs.version }} into the run scripts. Inline template expansion is substituted into the script text before the shell runs (a template-injection vector zizmor/CodeRabbit flag); env vars are read at runtime. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent ec17dd4 commit 341f921

1 file changed

Lines changed: 43 additions & 8 deletions

File tree

.github/workflows/PublishModuleToPowerShellGallery.yaml

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -54,21 +54,24 @@ jobs:
5454
shell: bash
5555
env:
5656
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
57+
VERSION: ${{ steps.version.outputs.version }}
5758
run: |
58-
if gh release view "v${{ steps.version.outputs.version }}" > /dev/null 2>&1; then
59+
if gh release view "v$VERSION" > /dev/null 2>&1; then
5960
echo "exists=true" >> $GITHUB_OUTPUT
60-
echo "GitHub release v${{ steps.version.outputs.version }} already exists"
61+
echo "GitHub release v$VERSION already exists"
6162
else
6263
echo "exists=false" >> $GITHUB_OUTPUT
63-
echo "GitHub release v${{ steps.version.outputs.version }} does not exist"
64+
echo "GitHub release v$VERSION does not exist"
6465
fi
6566
6667
- name: Check if PSGallery Version Exists
6768
id: check_psgallery
6869
if: steps.check_release.outputs.exists == 'false'
6970
shell: pwsh
71+
env:
72+
VERSION: ${{ steps.version.outputs.version }}
7073
run: |
71-
$version = "${{ steps.version.outputs.version }}"
74+
$version = $env:VERSION
7275
$published = Find-Module -Name {{ModuleName}} -RequiredVersion $version -Repository PSGallery -ErrorAction SilentlyContinue
7376
if ($published) {
7477
Write-Host "PSGallery version $version already exists"
@@ -85,13 +88,45 @@ jobs:
8588

8689
- name: Create GitHub Release
8790
if: steps.check_release.outputs.exists == 'false'
88-
shell: bash
91+
shell: pwsh
8992
env:
9093
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
94+
REPOSITORY: ${{ github.repository }}
95+
VERSION: ${{ steps.version.outputs.version }}
9196
run: |
92-
gh release create "v${{ steps.version.outputs.version }}" \
93-
--title "v${{ steps.version.outputs.version }}" \
94-
--generate-notes
97+
$version = $env:VERSION
98+
99+
# Build release notes from this version's CHANGELOG.md section so the release
100+
# body carries only the curated, user-facing entries (not the full PR list that
101+
# --generate-notes produces, which is dominated by bot/CI/chore PRs).
102+
$headerPattern = '^##\s+\[' + [regex]::Escape($version) + '\]'
103+
$capturing = $false
104+
$captured = [System.Collections.Generic.List[string]]::new()
105+
foreach ($line in (Get-Content -LiteralPath './CHANGELOG.md')) {
106+
if (-not $capturing) {
107+
if ($line -match $headerPattern) { $capturing = $true }
108+
continue
109+
}
110+
if ($line -match '^##\s+\[') { break } # next version header ends the section
111+
$captured.Add($line)
112+
}
113+
$body = ($captured -join "`n").Trim()
114+
115+
if ([string]::IsNullOrWhiteSpace($body)) {
116+
Write-Host "::warning::No CHANGELOG.md section found for $version; falling back to auto-generated notes."
117+
gh release create "v$version" --title "v$version" --generate-notes
118+
}
119+
else {
120+
# Append a compare link against the most recent existing tag. The v$version
121+
# tag does not exist yet (this step creates it), so the latest tag is the
122+
# previous release.
123+
$previousTag = git tag --list 'v*' --sort=-version:refname | Select-Object -First 1
124+
if ($previousTag) {
125+
$body += "`n`n**Full Changelog**: https://github.com/$env:REPOSITORY/compare/$previousTag...v$version"
126+
}
127+
Set-Content -LiteralPath './release-notes.md' -Value $body -Encoding utf8
128+
gh release create "v$version" --title "v$version" --notes-file './release-notes.md'
129+
}
95130
96131
- name: Publish to PSGallery
97132
if: steps.check_release.outputs.exists == 'false' && steps.check_psgallery.outputs.exists == 'false'

0 commit comments

Comments
 (0)