🌟 [Major]: Module manifests now stamped with the resolved version at build time#136
Merged
Merged
Conversation
Marius Storhaug (MariusStorhaug)
added a commit
to PSModule/Resolve-PSModuleVersion
that referenced
this pull request
May 22, 2026
…tion (#1) Module version resolution is now available as a standalone action. Workflows can call it before building so the resolved version is stamped into the artifact at build time, making the bytes that are tested the bytes that ship. - Resolves PSModule/Process-PSModule#326 ## New: Standalone `Resolve-PSModuleVersion` action The action consumes the JSON `Settings` output from [`PSModule/Get-PSModuleSettings`](https://github.com/PSModule/Get-PSModuleSettings) and emits: | Output | Description | | --- | --- | | `Version` | `Major.Minor.Patch` portion of the resolved version. | | `Prerelease` | Prerelease tag, empty when not a prerelease. | | `FullVersion` | Full version string including `VersionPrefix` and prerelease tag. | | `ReleaseType` | `Release`, `Prerelease`, or `None` when no version bump label is present. | | `CreateRelease` | `true` when a release or prerelease should be created. | Typical usage in the Plan job: ```yaml - name: Resolve module version id: resolve uses: PSModule/Resolve-PSModuleVersion@v1 env: GH_TOKEN: ${{ github.token }} with: Settings: ${{ steps.settings.outputs.Settings }} - name: Build module uses: PSModule/Build-PSModule@v5 with: Version: ${{ steps.resolve.outputs.Version }} Prerelease: ${{ steps.resolve.outputs.Prerelease }} ``` The action validates `Settings.Publish.Module.ReleaseType`, applies `IgnoreLabels` overrides, picks the bump type from PR labels (`MajorLabels` > `MinorLabels` > `PatchLabels` / `AutoPatching`), then computes the next version from the higher of the latest GitHub Release and the latest PowerShell Gallery version. For prereleases it appends the sanitized branch name, optional `DatePrereleaseFormat` timestamp, and an incremental counter calculated from existing prereleases on the same baseline + branch. ## Technical Details - `action.yml`: composite action with inputs `Settings` (required JSON), `Name`, `WorkingDirectory`, `Debug`, `Verbose`, `Version`, `Prerelease`, plus `EventPath` and `EventJson` (both optional, for test overrides — `EventJson` takes precedence over reading the file at `EventPath`). All `${{ }}` template expressions are isolated in `env:` sections per zizmor template-injection requirements. Installs `PSModule/Install-PSModuleHelpers` and `PSSemVer` before running the script. - `scripts/main.ps1`: ports the version-resolution logic that previously lived in `Publish-PSModule/src/init.ps1`. Reads configuration from `PSMODULE_RESOLVE_PSMODULEVERSION_INPUT_Settings` JSON instead of separate env vars. Reads the PR event from `PSMODULE_RESOLVE_PSMODULEVERSION_INPUT_EventJson` when set, falling back to the file at `GITHUB_EVENT_PATH`. Emits outputs via `$env:GITHUB_OUTPUT`. Cleanup-tag discovery stays in `Publish-PSModule/cleanup.ps1` and is intentionally out of scope here. - `.github/workflows/Action-Test.yml`: 6 test jobs covering patch, minor, major, auto-patch, ignore-label, and None scenarios. The ignore-label job passes the fake PR event as a JSON string via `EventJson` to bypass the runner's real event file, which cannot be reliably overridden at the file-system level. - `README.md`: replaces the template scaffold with the action's contract and usage examples. **Implementation plan progress** (PSModule/Process-PSModule#326): - ✅ Create `Resolve-PSModuleVersion` (LICENSE, README, `action.yml`, `scripts/main.ps1`, Action-Test workflow) - ✅ Inputs: `Settings`, `Name`, `WorkingDirectory` (plus `EventPath`/`EventJson` for test overrides) - ✅ Outputs: `Version`, `Prerelease`, `FullVersion`, `ReleaseType`, `CreateRelease` - ✅ Port version-resolution logic from `Publish-PSModule/src/init.ps1` (PSSemVer install, GitHub Releases query, PSGallery query, PR-label parsing, bump selection, prerelease sequencing, `DatePrereleaseFormat`, `VersionPrefix`) - ⬜ Dedicated Pester unit tests for label parsing, bump selection, and prerelease sequencing — covered by the six integration test jobs; a focused unit-test suite remains open Related PRs: - PSModule/Process-PSModule#342 — rewires the workflow's Plan → Build → Test → Publish chain to consume the resolved version. - PSModule/Build-PSModule#136 — accepts `Version` / `Prerelease` inputs and stamps them into the manifest at build time. - PSModule/Publish-PSModule#71 — removes the version-calculation logic that moved here.
- Remove Name input; module name is always inferred from GITHUB_REPOSITORY_NAME - Add OutputFolder input (default: outputs/module) to configure the build output path - Make Version required in action.yml, mandatory in Build-PSModule and Build-PSModuleManifest helpers - Remove 999.0.0 version fallback; build now fails explicitly when Version is not provided - Update Action-Test.yml: remove Name input, add Version: 1.0.0 to all test jobs
Copilot started reviewing on behalf of
Marius Storhaug (MariusStorhaug)
May 24, 2026 22:39
View session
Contributor
There was a problem hiding this comment.
Pull request overview
This PR updates the Build-PSModule GitHub Action so module manifests are stamped at build time with the resolved ModuleVersion and optional prerelease tag, ensuring the tested artifact matches what will be published.
Changes:
- Add/propagate action inputs for
Version,Prerelease, andOutputFolder, and requireVersion. - Stamp
ModuleVersion(and prerelease via manifest generation) duringBuild-PSModuleManifest. - Extend the Action-Test workflow to verify the generated manifest contains the expected version/prerelease values.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
src/main.ps1 |
Reads Version/Prerelease/OutputFolder inputs, enforces Version is provided, and passes values into Build-PSModule. |
src/helpers/Build/Build-PSModuleManifest.ps1 |
Accepts ModuleVersion/ModulePrerelease parameters and uses them when generating the output manifest. |
src/helpers/Build-PSModule.ps1 |
Makes ModuleVersion mandatory and forwards version/prerelease to manifest generation. |
action.yml |
Defines new inputs/environment wiring and marks Version as required. |
.github/workflows/Action-Test.yml |
Adds manifest verification steps (including prerelease scenario) and supplies required Version input in tests. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Marius Storhaug (MariusStorhaug)
added a commit
to PSModule/Publish-PSModule
that referenced
this pull request
May 27, 2026
… before publish (#71) `Publish-PSModule` no longer calculates or mutates the module version. The artifact passed in must already contain the final `ModuleVersion` (and `Prerelease` tag, if any) stamped by the upstream build. Published GitHub Releases now include a downloadable zip of the exact module folder that was tested and pushed to the Gallery. ## Breaking Changes Version-calculation inputs have been removed. Callers must supply a pre-stamped artifact: **Removed inputs:** - `AutoPatching` - `IncrementalPrerelease` - `DatePrereleaseFormat` - `VersionPrefix` - `MajorLabels`, `MinorLabels`, `PatchLabels`, `IgnoreLabels` - `ReleaseType` **Migration:** Consumers on `PSModule/Process-PSModule` get this for free — the workflow resolves the version in the Plan job and stamps it during Build. Direct callers outside of `Process-PSModule` must use [`Resolve-PSModuleVersion`](https://github.com/PSModule/Resolve-PSModuleVersion) to compute the version and [`Build-PSModule`](https://github.com/PSModule/Build-PSModule) v5+ to stamp it before invoking this action. ## New: Module zip uploaded to GitHub Release After creating a GitHub Release, the module folder is zipped (`<Name>-<Version>.zip`) and uploaded as a release asset. The zip preserves the `<Name>/` directory structure so it can be extracted directly into a PowerShell module path. ## Changed: Cleanup only runs after stable releases The cleanup step (which removes old prerelease tags/releases) now only executes when the publish was a stable release. Previously it could inadvertently delete the just-published prerelease. Cleanup also filters on `isPrerelease` to avoid accidentally deleting stable releases whose tag happens to match the derived prerelease name. ## Technical Details - Deleted `src/init.ps1` (the old version-calculation script). - `src/publish.ps1` reads `ModuleVersion` and `Prerelease` directly from the downloaded manifest via `Import-PowerShellDataFile`, validates 3-part format, then publishes untouched via `Publish-PSResource`. - `Test-ModuleManifest` is called as advisory validation (non-terminating) since the built artifact may reference `RequiredModules` not installed on the runner. Structural validation is enforced by explicit regex guards on `ModuleVersion` and `Prerelease`. - `src/cleanup.ps1` derives the prerelease name from the PR head ref, filters on `isPrerelease`, and explicitly excludes the just-published release tag from deletion. - `action.yml` cleanup step gated on `env.PSMODULE_PUBLISH_PSMODULE_CONTEXT_IsPrerelease != 'true'`. - `GITHUB_ENV` writes use `utf8NoBOM` encoding to prevent BOM corruption. - Zip upload and temp file cleanup wrapped in `try/finally` for reliable cleanup on failure. <details><summary>Related issues</summary> - Fixes PSModule/Process-PSModule#326 - PSModule/Process-PSModule#342 - PSModule/Resolve-PSModuleVersion#1 - PSModule/Build-PSModule#136 </details>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Module manifests are now stamped with the resolved version and prerelease tag at build time. The resulting artifact contains its final
ModuleVersion(andPrivateData.PSData.Prerelease) before tests run, so the bytes that are tested are the bytes that ship.Inputs on
Build-PSModuleBuild-PSModulenow exposes new module-centric inputs:NameVersionMajor.Minor.Patch) to stamp into the manifest. Build fails with a clear error when omitted or malformed.Prereleasemybranch001) to stamp intoPrivateData.PSData.Prerelease. When empty, no prerelease tag is written.OutputFolderWorkingDirectory) where the built module is placed. Defaults tooutputs/module.Typical usage downstream of
PSModule/Resolve-PSModuleVersion:Breaking changes
Versionis now required. Callers that previously omitted it (relying on the999.0.0placeholder) must now pass an explicit version inMajor.Minor.Patchformat. Builds fail immediately with a clear error whenVersionis missing or malformed.Technical details
action.yml: addsOutputFolder(defaultoutputs/module),Version(required: true), andPrereleaseinputs;Nameremains optional and still defaults to the repository name.src/main.ps1: readsOutputFolder,Version, andPrereleasefrom env; throws immediately whenVersionis missing or not inMajor.Minor.Patchformat.src/helpers/Build-PSModule.ps1:ModuleVersionparameter is now[Parameter(Mandatory)].src/helpers/Build/Build-PSModuleManifest.ps1:ModuleVersionis[Parameter(Mandatory)]; the999.0.0fallback is removed — the version is assigned directly.Related PRs:
VersionandPrereleasevalues consumed here.