Skip to content

✨ [Major]: Move version calculation to Plan job and ship the built artifact (#326)#339

Closed
Marius Storhaug (MariusStorhaug) wants to merge 1 commit into
mainfrom
feat/326-resolve-psmodule-version
Closed

✨ [Major]: Move version calculation to Plan job and ship the built artifact (#326)#339
Marius Storhaug (MariusStorhaug) wants to merge 1 commit into
mainfrom
feat/326-resolve-psmodule-version

Conversation

@MariusStorhaug

@MariusStorhaug Marius Storhaug (MariusStorhaug) commented May 17, 2026

Copy link
Copy Markdown
Member

Why

Today the version a module is published with is calculated after tests pass, inside Publish-PSModule. Build-PSModule
stamps a placeholder (999.0.0) into the manifest, the tests run against that artifact, and Publish-PSModule then
mutates the manifest to inject the real version before pushing to the PowerShell Gallery. This breaks CI/CD's first
principle: the artifact you tested is not the artifact you ship.

What

The version is now calculated before the build, in a new Plan job that supersedes Get-Settings. The same artifact
flows through test → publish unchanged.

flowchart LR
  A[Plan<br/>Get-Settings + Resolve-PSModuleVersion] --> B[Build-Module<br/>stamps version into manifest]
  B --> C[Test-* / Coverage]
  C --> D[Publish-Module<br/>publishes artifact + uploads zip to release]
Loading

Changes in this PR (Process-PSModule)

  • Renames Get-Settings.ymlPlan.yml. The Plan job runs two steps: Get-PSModuleSettings and the new
    Resolve-PSModuleVersion. Outputs: Settings, ModuleVersion, ModulePrerelease, ModuleFullVersion,
    ReleaseType, CreateRelease.
  • workflow.yml — renames the Get-Settings job to Plan, updates every needs: and with: reference, and forwards
    the resolved version into Build-Module.
  • Build-Module.yml — accepts new ModuleVersion / ModulePrerelease inputs and passes them to Build-PSModule.
  • Publish-Module.yml — drops the version-calculation inputs (no longer needed, Publish-PSModule reads the version
    from the already-stamped manifest).
  • README updated with the Plan job description and a note that the built module is now attached to GitHub Releases.

Companion PRs / repos

Repo Change Link
PSModule/Resolve-PSModuleVersion Initial implementation (NEW repo, NEW action) https://github.com/PSModule/Resolve-PSModuleVersion (committed to main)
PSModule/Build-PSModule Minor — adds Version/Prerelease inputs PSModule/Build-PSModule#135
PSModule/Publish-PSModule Major / BREAKING — drops version calculation, publishes pre-stamped artifact, uploads module zip to release PSModule/Publish-PSModule#71

Built module as a release asset

Implemented in Publish-PSModule/src/publish.ps1: after gh release create, the module folder is zipped to
<Name>-<Version>.zip and uploaded via gh release upload <tag> <zip> --clobber. Consumers can now grab the exact
bytes that were tested and pushed to the Gallery directly from the GitHub Release page.

Notes

  • This PR remains Draft until the child PRs are reviewed and merged, and the workflow references are repinned to
    released SHAs (currently @main for Resolve-PSModuleVersion / Build-PSModule / Publish-PSModule).
  • Copilot review is requested on this PR and on every child PR. The iteration to zero comments is intentionally async
    — this PR will be re-evaluated once Copilot's feedback has been processed across the four repos.


- name: Build module
uses: PSModule/Build-PSModule@345728124d201f371a8b0f1aacb98f89000a06dc # v4.0.14
uses: PSModule/Build-PSModule@main
- name: Resolve-Version
# Resolve only when the workflow is going to create a release/prerelease.
if: fromJson(steps.Get-Settings.outputs.Settings).Publish.Module.ReleaseType != 'None'
uses: PSModule/Resolve-PSModuleVersion@main

- name: Publish module
uses: PSModule/Publish-PSModule@8917aed588dae1bd1aa2873b1caec1c50c20d255 # v2.2.4
uses: PSModule/Publish-PSModule@main

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Renames the Get-Settings job to Plan and adds a second step (Resolve-PSModuleVersion) that computes the final module version before the build, so the manifest is stamped with the real version and the same artifact flows through test → publish unchanged. Build-Module.yml gains ModuleVersion/ModulePrerelease inputs that it forwards to Build-PSModule, and Publish-Module.yml drops all version-calculation inputs (the version now comes from the already-stamped manifest, and Publish-PSModule additionally uploads the zipped module as a Release asset).

Changes:

  • Rename Get-Settings.ymlPlan.yml; add Resolve-PSModuleVersion step and expose ModuleVersion, ModulePrerelease, ModuleFullVersion, ReleaseType, CreateRelease outputs.
  • Update workflow.yml to rename the job, rewire all needs:/with: references, and pass version inputs into Build-Module.
  • Add ModuleVersion/ModulePrerelease inputs to Build-Module.yml; remove version-calculation inputs from Publish-Module.yml; update README accordingly.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.

Show a summary per file
File Description
.github/workflows/Plan.yml Renamed from Get-Settings; adds Resolve-PSModuleVersion step and new version-related job outputs.
.github/workflows/workflow.yml Renames Get-Settings job to Plan, updates all references, and passes ModuleVersion/ModulePrerelease into Build-Module.
.github/workflows/Build-Module.yml Adds ModuleVersion and ModulePrerelease inputs and forwards them to Build-PSModule; points to Vlad Vannov (@main).
.github/workflows/Publish-Module.yml Removes version-calculation inputs (now done in Plan); updates permissions comment; points to Vlad Vannov (@main).
README.md Documents the new Plan job, its two steps, the tested-artifact-equals-shipped-artifact guarantee, and Release-asset upload.

@github-actions

Copy link
Copy Markdown

Super-linter summary

Language Validation result
CHECKOV Pass ✅
GITLEAKS Pass ✅
GIT_MERGE_CONFLICT_MARKERS Pass ✅
MARKDOWN Pass ✅
NATURAL_LANGUAGE Pass ✅
POWERSHELL Pass ✅
PRE_COMMIT Pass ✅
SPELL_CODESPELL Pass ✅
TRIVY Pass ✅
YAML Pass ✅

All files and directories linted successfully

For more information, see the GitHub Actions workflow run

Powered by Super-linter

@MariusStorhaug Marius Storhaug (MariusStorhaug) deleted the feat/326-resolve-psmodule-version branch May 22, 2026 18:58
Marius Storhaug (MariusStorhaug) added a commit that referenced this pull request Jul 9, 2026
… equals published artifact (#342)

The version a module ships with is now decided in a new `Plan` job that
runs before the module is built. The same artifact then flows through
tests and publish without being mutated, so the artifact you tested is
the artifact that lands in the PowerShell Gallery and on the GitHub
Release.

- Fixes #326

## New: Plan job replaces Get-Settings

`Get-Settings.yml` is renamed to `Plan.yml`. The Plan job runs two steps
in sequence and exposes everything downstream jobs need:

1. `Get-PSModuleSettings` — loads `.github/PSModule.yml` and emits the
resolved `Settings` JSON.
2. `Resolve-PSModuleVersion` — reads settings + PR labels, queries
existing releases and the PowerShell Gallery, and emits the next
version.

Plan job output: a single `Settings` JSON. The resolved version is
merged into it as `Settings.Module.{Version, Prerelease, FullVersion,
ReleaseType, CreateRelease}`, so every downstream job receives one
self-contained object with no separate version outputs.

```mermaid
flowchart LR
  A[Plan<br/>Get-PSModuleSettings + Resolve-PSModuleVersion] --> B[Build-Module<br/>stamps version into manifest]
  B --> C[Test-* / Coverage]
  C --> D[Publish-Module<br/>publishes artifact unchanged]
```

## Changed: Build-Module now stamps the real version

`Build-Module.yml` reads the version from `Settings.Module.Version` /
`Settings.Module.Prerelease` and passes them to `Build-PSModule`. The
built manifest contains the version the module will ship with **before**
any test runs. The `999.0.0` placeholder only appears when no version is
provided (for example, direct callers that bypass the Plan job).

## Changed: Publish-Module no longer calculates or mutates versions

`Publish-Module.yml` drops every input that used to drive version
calculation:

- `AutoPatching`
- `DatePrereleaseFormat`
- `IgnoreLabels`
- `IncrementalPrerelease`
- `MajorLabels` / `MinorLabels` / `PatchLabels`
- `ReleaseType`
- `VersionPrefix`

`Publish-Module` now reads the version straight from the manifest that
arrived from `Build-Module` and pushes it to the PowerShell Gallery
as-is. The PR-title / PR-body / heading inputs are unchanged. The job
also gains permission to upload release assets so the zipped module can
be attached to the GitHub Release.

## Fixed: Tested artifact equals published artifact

The placeholder-then-rewrite flow is gone. The bytes tested in
`Test-Module` / `Test-ModuleLocal` are the same bytes published to the
PowerShell Gallery and attached to the GitHub Release.

## Technical Details

- `Plan.yml` (renamed from `Get-Settings.yml`): adds a `Resolve-Version`
step (runs unconditionally — it computes the release decision, including
`ReleaseType`) followed by an `Enrich-Settings` step that merges the
resolved version into `Settings.Module.*`. Plan exposes a single
`Settings` output on both the job and `workflow_call`.
- `workflow.yml`: the `Get-Settings` job is renamed to `Plan` and every
downstream `needs:` / `with:` reference is repointed. Downstream jobs
consume the single `needs.Plan.outputs.Settings` object (version
available under `Settings.Module.*`).
- `Build-Module.yml`: reads `Settings.Module.Version` /
`Settings.Module.Prerelease` and passes them as `Version` / `Prerelease`
to `Build-PSModule`, falling back to the `999.0.0` placeholder when a
direct caller bypasses Plan and omits `Settings.Module`.
- `Publish-Module.yml`: removes the seven version-calculation inputs and
grants `contents: write` permission for release-asset uploads.
- `README.md`: replaces the `Get-Settings` section with a `Plan` section
that documents both steps and the artifact-integrity guarantee, and
notes the new release-asset upload.
- `PSModule/Build-PSModule` pinned to `@v5.0.0` (SHA
`672aaa7a91a379c4c6cd14494d03ab5e87e13c52`).
- `PSModule/Publish-PSModule` pinned to `@v3.0.0` (SHA
`03c0f8b53d0367c85a0f121f98af9b40c817b0e3`).

### Companion repos

| Repo | Change | Link |
| ---- | ------ | ---- |
| `PSModule/Resolve-PSModuleVersion` | New action — v1.1.0 released |
https://github.com/PSModule/Resolve-PSModuleVersion/releases/tag/v1.1.0
|
| `PSModule/Build-PSModule` | Major — adds `Version` / `Prerelease`
inputs — v5.0.0 released |
https://github.com/PSModule/Build-PSModule/releases/tag/v5.0.0 |
| `PSModule/Publish-PSModule` | **Major / BREAKING** — drops version
calculation, publishes pre-stamped artifact, uploads module zip to
release — v3.0.0 released |
https://github.com/PSModule/Publish-PSModule/releases/tag/v3.0.0 |

### Implementation plan progress

- [x] Rename `Get-Settings` job to `Plan` and add
`Resolve-PSModuleVersion` step
- [x] Expose a single `Settings` output (resolved version merged into
`Settings.Module.{Version, Prerelease, FullVersion, ReleaseType,
CreateRelease}`)
- [x] Update `Build-Module.yml` to read the version from
`Settings.Module.*` and stamp it
- [x] Strip version-calculation inputs from `Publish-Module.yml`
- [x] Update `needs` / `with` wiring across `workflow.yml`
- [x] Update `README.md` (Plan section + release-asset note)
- [x] `Resolve-PSModuleVersion` action implementation (v1.1.0 released)
- [x] `Build-PSModule` `Version`/`Prerelease` inputs (v5.0.0 released)
- [x] `Publish-PSModule` v3 release (v3.0.0 released —
PSModule/Publish-PSModule#71)
- [x] Repin `@main` references in `Build-Module.yml` and
`Publish-Module.yml` to released SHAs
- [ ] End-to-end run on a labeled PR

## Notes

- The public input/output contract of `workflow.yml` is unchanged for
external consumers — this is internal wiring.
- #339 covered the same scope and was closed;
this PR restarts the work cleanly off the current `main`.
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.

3 participants