Skip to content

ci(release): create the GitHub release after the Gallery upload - #54

Merged
fadwen merged 1 commit into
mainfrom
ci/github-release
Nov 12, 2026
Merged

fadwen merged 1 commit into
mainfrom
ci/github-release

Conversation

@fadwen

@fadwen fadwen commented Nov 12, 2026

Copy link
Copy Markdown
Owner

Summary

Pushing a version tag published the module to the PowerShell Gallery but did not create a GitHub release. The repository therefore lists no release for any of its published versions. release.yml now creates one for each tag.

Changes

  • New github-release job after publish. It runs on ubuntu-latest and is the only job with contents: write; the workflow default stays contents: read.
    • Notes, every run. It reads the module name and ModuleVersion from the one manifest at the repository root and takes that version's ## [<version>] section of CHANGELOG.md. The notes are that section, an Update-PSResource <Module> block above it, and a link to the full CHANGELOG at the tag below it. A missing or empty section fails the job. Dry runs build the notes too, so the CHANGELOG is checked before a tag exists.
    • Release, tag pushes only. gh release create v<version> --verify-tag runs only for a tag push, never for a dry run. A release that already exists for the tag, such as one written by hand, is left unchanged. GitHub decides which release is Latest by version, so a later patch to an older line does not take over the label.
  • CLAUDE.md: the release section now describes the new step and the CHANGELOG section it depends on.

Verification

  • A dry run of the release workflow on this branch passed every job: https://github.com/fadwen/IntuneScriptLab/actions/runs/43288426200. The GitHub release job built the 0.34.0 notes (2,448 characters) and skipped the create step.
  • I extracted the notes step and ran it locally against the current main CHANGELOG and manifest of each module repository, this one included. Each produced its latest version's notes.
  • It also fails on a missing section and on an empty one, and does not take ## [1.1.0.1] for 1.1.0.
  • Not exercised: the create step itself, which runs only on a tag push. Its commands are gh release view and gh release create, the same ones used for the hand-made releases.

Notes

A tag published the module to the PowerShell Gallery but created no
GitHub release, so the repository lists none for any published version.
The other module repositories get the same job, so all of them release
the same way.

A github-release job now follows the publish job. It takes the module
name and version from the root manifest and uses that version's
CHANGELOG.md section as the release notes, with an Update-PSResource
line and a link to the full history. It fails when the section is
missing or empty. The notes are built in every run, a dry run included,
so a missing section shows up before a tag is pushed. The release itself
is created only for a tag push, with --verify-tag, and a release that
already exists for the tag is left as written. The job alone has
contents: write; the workflow keeps contents: read.

@fadwen fadwen left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Notes on the lines whose reason the diff does not show.

for ($i = $start + 1; $i -lt $lines.Count; $i++) {
if ($lines[$i] -match '^## \[') { $end = $i; break }
}
$section = if ($end -gt $start + 1) { ($lines[($start + 1)..($end - 1)] -join "`n").Trim() }

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The guard matters. When a version heading is followed directly by the next heading, ($start + 1)..($end - 1) counts down instead of up and picks up the next version's heading, so an empty section would have become notes holding the previous release. This is one of the cases tested locally.

Write-Host $notes

- name: Create the GitHub release
if: ${{ startsWith(github.ref, 'refs/tags/') && !inputs.dryRun }}

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the condition the Publish step already uses. On a tag push inputs.dryRun is empty, so !inputs.dryRun is true. A workflow_dispatch with the default dryRun: true skips the step, so a dry run never creates a release.

run: |
$ErrorActionPreference = 'Stop'
# A release made by hand before this job ran is kept as written
gh release view $env:RELEASE_TAG *> $null

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check exists so re-running the job is safe. If it fails after the Gallery upload, re-running it creates the release. If a release was written by hand in the meantime, the re-run leaves that one alone instead of failing on a duplicate or overwriting it.

@fadwen
fadwen merged commit 942b028 into main Nov 12, 2026
10 checks passed
@fadwen
fadwen deleted the ci/github-release branch November 12, 2026 20:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant