Skip to content

Commit 0d7a2f0

Browse files
🚀 [Feature]: Plan job decides version before build so tested artifact 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`.
1 parent 54e2677 commit 0d7a2f0

12 files changed

Lines changed: 204 additions & 176 deletions

‎.github/workflows/Build-Docs.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ jobs:
3030
path: ${{ fromJson(inputs.Settings).WorkingDirectory }}/outputs/module
3131

3232
- name: Document module
33-
uses: PSModule/Document-PSModule@dc5b329f840f7803ec02d34a42ee725bca39db5f # v1.0.16
33+
uses: PSModule/Document-PSModule@fb5d349fa6e6ff8277b2eaf32a588cd97b234525 # v1.0.17
3434
with:
3535
Name: ${{ fromJson(inputs.Settings).Name }}
3636
WorkingDirectory: ${{ fromJson(inputs.Settings).WorkingDirectory }}

‎.github/workflows/Build-Module.yml‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,10 @@ jobs:
3030
fetch-depth: 0
3131

3232
- name: Build module
33-
uses: PSModule/Build-PSModule@3b368fe7d4cd5872feddfa2ac3dacfb5dfd0ab13 # v4.0.15
33+
uses: PSModule/Build-PSModule@672aaa7a91a379c4c6cd14494d03ab5e87e13c52 # v5.0.0
3434
with:
3535
Name: ${{ fromJson(inputs.Settings).Name }}
36+
Version: ${{ fromJson(inputs.Settings).Module.Version != '' && fromJson(inputs.Settings).Module.Version || '999.0.0' }}
37+
Prerelease: ${{ fromJson(inputs.Settings).Module.Prerelease }}
3638
ArtifactName: ${{ inputs.ArtifactName }}
3739
WorkingDirectory: ${{ fromJson(inputs.Settings).WorkingDirectory }}

‎.github/workflows/Build-Site.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
fetch-depth: 0
2424

2525
- name: Install-PSModuleHelpers
26-
uses: PSModule/Install-PSModuleHelpers@ed79b6e3aa8c9cd3d30ab2bf02ea6bd4687b9c74 # v1.0.7
26+
uses: PSModule/Install-PSModuleHelpers@68e8ca76be679bfcb7099aed8cffa911c4ab72af # v1.0.8
2727

2828
- name: Download docs artifact
2929
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1

‎.github/workflows/Get-Settings.yml‎

Lines changed: 0 additions & 78 deletions
This file was deleted.

‎.github/workflows/Plan.yml‎

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
name: Plan
2+
3+
# The Plan job is the single decision point for the workflow.
4+
# It runs two steps:
5+
# 1. Get-PSModuleSettings - loads and resolves configuration
6+
# 2. Resolve-PSModuleVersion - calculates the next version from settings + PR labels
7+
# The resolved version is merged into the Settings object (Settings.Module.*) by the Enrich-Settings step.
8+
# All downstream jobs receive one self-contained Settings JSON with no separate version outputs.
9+
10+
on:
11+
workflow_call:
12+
inputs:
13+
SettingsPath:
14+
type: string
15+
description: The path to the settings file.
16+
required: false
17+
Debug:
18+
type: boolean
19+
description: Enable debug output.
20+
required: false
21+
default: false
22+
Verbose:
23+
type: boolean
24+
description: Enable verbose output.
25+
required: false
26+
default: false
27+
Version:
28+
type: string
29+
description: Specifies the version of the GitHub module to be installed. The value must be an exact version.
30+
required: false
31+
default: ''
32+
Prerelease:
33+
type: boolean
34+
description: Whether to use a prerelease version of the 'GitHub' module.
35+
required: false
36+
default: false
37+
WorkingDirectory:
38+
type: string
39+
description: The path to the root of the repo.
40+
required: false
41+
default: '.'
42+
ImportantFilePatterns:
43+
type: string
44+
description: |
45+
Newline-separated list of regex patterns that identify important files.
46+
Changes matching these patterns trigger build, test, and publish stages.
47+
When set, fully replaces the defaults (^src/ and ^README\.md$).
48+
required: false
49+
default: |
50+
^src/
51+
^README\.md$
52+
53+
outputs:
54+
Settings:
55+
description: The complete settings object including test suites and resolved module version.
56+
value: ${{ jobs.Plan.outputs.Settings }}
57+
58+
permissions:
59+
contents: read # to checkout the repo
60+
pull-requests: write # to add labels / comments to PRs
61+
62+
jobs:
63+
Plan:
64+
name: Plan
65+
runs-on: ubuntu-latest
66+
outputs:
67+
Settings: ${{ steps.Enrich-Settings.outputs.Settings }}
68+
steps:
69+
- name: Checkout Code
70+
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
71+
with:
72+
persist-credentials: false
73+
fetch-depth: 0
74+
75+
- name: Get-Settings
76+
uses: PSModule/Get-PSModuleSettings@1e3d156786c56e6fbd839a1ba5ab21ff8858090e # v1.5.0
77+
id: Get-Settings
78+
with:
79+
SettingsPath: ${{ inputs.SettingsPath }}
80+
Debug: ${{ inputs.Debug }}
81+
Prerelease: ${{ inputs.Prerelease }}
82+
Verbose: ${{ inputs.Verbose }}
83+
Version: ${{ inputs.Version }}
84+
WorkingDirectory: ${{ inputs.WorkingDirectory }}
85+
ImportantFilePatterns: ${{ inputs.ImportantFilePatterns }}
86+
87+
- name: Resolve-Version
88+
uses: PSModule/Resolve-PSModuleVersion@d53326c7687d20a7949d457fccd71223856b1890 # v1.1.0
89+
id: Resolve-Version
90+
env:
91+
GH_TOKEN: ${{ github.token }}
92+
with:
93+
Settings: ${{ steps.Get-Settings.outputs.Settings }}
94+
Name: ${{ fromJson(steps.Get-Settings.outputs.Settings).Name }}
95+
Debug: ${{ inputs.Debug }}
96+
Verbose: ${{ inputs.Verbose }}
97+
WorkingDirectory: ${{ inputs.WorkingDirectory }}
98+
99+
- name: Enrich-Settings
100+
# Merge the resolved version into the Settings object so all downstream jobs
101+
# receive a single, self-contained Settings JSON with no separate version outputs.
102+
id: Enrich-Settings
103+
shell: pwsh
104+
env:
105+
SETTINGS: ${{ steps.Get-Settings.outputs.Settings }}
106+
VERSION: ${{ steps.Resolve-Version.outputs.Version }}
107+
PRERELEASE: ${{ steps.Resolve-Version.outputs.Prerelease }}
108+
FULL_VERSION: ${{ steps.Resolve-Version.outputs.FullVersion }}
109+
RELEASE_TYPE: ${{ steps.Resolve-Version.outputs.ReleaseType }}
110+
CREATE_RELEASE: ${{ steps.Resolve-Version.outputs.CreateRelease }}
111+
run: |
112+
$settings = $env:SETTINGS | ConvertFrom-Json
113+
$settings | Add-Member -MemberType NoteProperty -Name Module -Value ([pscustomobject]@{
114+
Version = $env:VERSION
115+
Prerelease = $env:PRERELEASE
116+
FullVersion = $env:FULL_VERSION
117+
ReleaseType = if ([string]::IsNullOrEmpty($env:RELEASE_TYPE)) { 'None' } else { $env:RELEASE_TYPE }
118+
CreateRelease = $env:CREATE_RELEASE -eq 'true'
119+
})
120+
$enriched = $settings | ConvertTo-Json -Depth 10 -Compress
121+
"Settings=$enriched" >> $env:GITHUB_OUTPUT

‎.github/workflows/Publish-Module.yml‎

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ on:
1313
required: true
1414

1515
permissions:
16-
contents: write # to checkout the repo and create releases
16+
contents: write # to checkout the repo, create releases, and upload release artifacts
1717
pull-requests: write # to comment on PRs
1818

1919
jobs:
@@ -30,7 +30,7 @@ jobs:
3030
fetch-depth: 0
3131

3232
- name: Publish module
33-
uses: PSModule/Publish-PSModule@8917aed588dae1bd1aa2873b1caec1c50c20d255 # v2.2.4
33+
uses: PSModule/Publish-PSModule@03c0f8b53d0367c85a0f121f98af9b40c817b0e3 # v3.0.0
3434
env:
3535
GH_TOKEN: ${{ github.token }}
3636
with:
@@ -39,15 +39,6 @@ jobs:
3939
APIKey: ${{ secrets.APIKey }}
4040
WhatIf: ${{ github.repository == 'PSModule/Process-PSModule' }}
4141
AutoCleanup: ${{ fromJson(inputs.Settings).Publish.Module.AutoCleanup }}
42-
AutoPatching: ${{ fromJson(inputs.Settings).Publish.Module.AutoPatching }}
43-
DatePrereleaseFormat: ${{ fromJson(inputs.Settings).Publish.Module.DatePrereleaseFormat }}
44-
IgnoreLabels: ${{ fromJson(inputs.Settings).Publish.Module.IgnoreLabels }}
45-
ReleaseType: ${{ fromJson(inputs.Settings).Publish.Module.ReleaseType }}
46-
IncrementalPrerelease: ${{ fromJson(inputs.Settings).Publish.Module.IncrementalPrerelease }}
47-
MajorLabels: ${{ fromJson(inputs.Settings).Publish.Module.MajorLabels }}
48-
MinorLabels: ${{ fromJson(inputs.Settings).Publish.Module.MinorLabels }}
49-
PatchLabels: ${{ fromJson(inputs.Settings).Publish.Module.PatchLabels }}
50-
VersionPrefix: ${{ fromJson(inputs.Settings).Publish.Module.VersionPrefix }}
5142
UsePRTitleAsReleaseName: ${{ fromJson(inputs.Settings).Publish.Module.UsePRTitleAsReleaseName }}
5243
UsePRBodyAsReleaseNotes: ${{ fromJson(inputs.Settings).Publish.Module.UsePRBodyAsReleaseNotes }}
5344
UsePRTitleAsNotesHeading: ${{ fromJson(inputs.Settings).Publish.Module.UsePRTitleAsNotesHeading }}

‎.github/workflows/Test-Module.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ jobs:
3232
path: ${{ fromJson(inputs.Settings).WorkingDirectory }}/outputs/module
3333

3434
- name: Test-Module
35-
uses: PSModule/Test-PSModule@8c3337136dc7cf320da39eeb50e776d04bc9ac73 # v3.0.10
35+
uses: PSModule/Test-PSModule@25c9cd89954d558360e5917efbd4dea4ca894144 # v3.0.13
3636
with:
3737
Name: ${{ fromJson(inputs.Settings).Name }}
3838
Debug: ${{ fromJson(inputs.Settings).Debug }}

‎.github/workflows/Test-ModuleLocal.yml‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ jobs:
5050
path: ${{ fromJson(inputs.Settings).WorkingDirectory }}/outputs/module
5151

5252
- name: Install-PSModuleHelpers
53-
uses: PSModule/Install-PSModuleHelpers@ed79b6e3aa8c9cd3d30ab2bf02ea6bd4687b9c74 # v1.0.7
53+
uses: PSModule/Install-PSModuleHelpers@68e8ca76be679bfcb7099aed8cffa911c4ab72af # v1.0.8
5454

5555
- name: Import-Module
5656
id: import-module
@@ -64,7 +64,7 @@ jobs:
6464
"path=$path" >> $env:GITHUB_OUTPUT
6565
6666
- name: Test-ModuleLocal
67-
uses: PSModule/Invoke-Pester@266d1cf2532f572470b7c4463fa1072f2bfe4455 # v4.2.5
67+
uses: PSModule/Invoke-Pester@9cf262a79e7528d5af41c875c35dae91c44d18dd # v4.2.6
6868
with:
6969
Debug: ${{ fromJson(inputs.Settings).Debug }}
7070
Prerelease: ${{ fromJson(inputs.Settings).Prerelease }}
@@ -82,4 +82,4 @@ jobs:
8282
WorkingDirectory: ${{ fromJson(inputs.Settings).WorkingDirectory }}
8383
Prescript: | # This is to speed up module loading in Pester.
8484
Install-PSResource -Repository PSGallery -TrustRepository -Name PSCustomObject
85-
Import-Module -Name '${{ steps.import-module.outputs.name }}' -RequiredVersion 999.0.0
85+
Import-Module -Name '${{ steps.import-module.outputs.name }}' -RequiredVersion '${{ fromJson(inputs.Settings).Module.Version }}'

‎.github/workflows/Test-SourceCode.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ jobs:
2727
fetch-depth: 0
2828

2929
- name: Test-SourceCode
30-
uses: PSModule/Test-PSModule@8c3337136dc7cf320da39eeb50e776d04bc9ac73 # v3.0.10
30+
uses: PSModule/Test-PSModule@25c9cd89954d558360e5917efbd4dea4ca894144 # v3.0.13
3131
with:
3232
Debug: ${{ fromJson(inputs.Settings).Debug }}
3333
Prerelease: ${{ fromJson(inputs.Settings).Prerelease }}

0 commit comments

Comments
 (0)