Skip to content

Releases: PSModule/Process-PSModule

v6.1.16

Choose a tag to compare

@github-actions github-actions released this 03 Aug 01:18
1653be8

🪲 [Fix]: Release tags keep the configured version prefix (#440)

Releases created by the module pipeline are tagged with the version prefix configured in .github/PSModule.yml again. A repository that keeps the default VersionPrefix: 'v' is tagged v1.1.10, not 1.1.10, and its prereleases are tagged v1.1.11-mybranch001. A repository that sets VersionPrefix: '' keeps its unprefixed tags exactly as before.

Fixed: release tags no longer lose the configured version prefix

Since v6 the release tag was built from the compiled manifest's ModuleVersion alone. That value is Major.Minor.Patch by definition, so the prefix had nowhere to live and every repository publishing on v6 with the default prefix picked up a tag that did not match its own history — PSModule/Toml went from v0.0.1 to 0.0.2, PSModule/Domeneshop from v0.0.2 to 1.0.0, PSModule/PSSemVer from v1.1.9 to 1.1.10.

Nothing needs to change in a module repository. The prefix is read from the setting that already exists:

Publish:
  Module:
    VersionPrefix: 'v'   # default; set to '' for unprefixed tags

The prefix applies to the GitHub release tag and to nothing else. A PowerShell module manifest's ModuleVersion and a PowerShell Gallery package version only accept plain SemVer, so the version published to the Gallery, the version in the Gallery link, and the name of the module zip attached to the release all stay unprefixed. With VersionPrefix: 'v' a release looks like this:

Value
GitHub release tag and title v1.1.10
PowerShell Gallery version 1.1.10
Manifest ModuleVersion 1.1.10
Attached artifact MyModule-1.1.10.zip

Repositories that already published an unprefixed tag on v6 keep it. Those releases are public, their artifacts are linked from the release pages, and the PowerShell Gallery listing points at them, so they are left alone and the prefix resumes from the next release. An unprefixed tag left in the history does not affect future version resolution.


Technical details

What changed

  • .github/actions/Publish-PSModule/src/Publish-PSModule.Helpers.psm1 — new action-scoped helper module with Get-ModuleVersionString, which composes the module's SemVer string, and Get-ReleaseTag, which prefixes it.
  • .github/actions/Publish-PSModule/src/publish.ps1 — reads the new VersionPrefix input, derives both version strings from those helpers in one place, and reports both in the resolved-version summary and the closing log line.
  • .github/actions/Publish-PSModule/action.yml — new optional VersionPrefix input, defaulting to ''.
  • .github/workflows/Publish-Module.yml — passes Settings.Publish.Module.VersionPrefix into the action.
  • .github/actions/Publish-PSModule/tests/Publish-PSModule.Helpers.Tests.ps1 — new Pester suite, picked up automatically by the existing Test-Actions discovery over .github/actions/*/tests.

Five files, all on the tag-derivation path. No test fixture or pipeline behaviour outside it changes.

Approach

The manifest stays the source of the numeric version. ModuleVersion is what was built, tested, and pushed to the Gallery, so the tag has to agree with it — the ^\d+\.\d+\.\d+$ guard and the 999.0.0 placeholder check are unchanged. Only the prefix, the one piece of the tag the manifest cannot carry, is taken from the settings the Plan job already resolves. Composing the two is equivalent to using Resolution.FullVersion in the normal case and stays anchored to the artifact if the two ever disagree.

Keeping the prefix off the module version. publish.ps1 previously built the Gallery version with its own copy of the prerelease composition, independent of the tag. Two independent implementations of the same string is how they drift, and drift in this direction means a prefixed version reaching Publish-PSResource. Both now come from Get-ModuleVersionString; Get-ReleaseTag is that string with the prefix in front, so the prefix is the only possible difference between them, by construction rather than by convention.

The prefix reaches: the release tag, the release title fallback, the gh release upload target, the release URL, the GitHub half of the pull request comment, and PSMODULE_PUBLISH_PSMODULE_CONTEXT_ReleaseTag for cleanup. It reaches nothing else. publish.ps1 never writes to the manifest — it is read-only on the artifact by design — and Build-PSModule stamps the manifest from Resolution.Version and Resolution.Prerelease, which are unprefixed. Resolution.FullVersion, the one prefix-bearing value in the Settings object, is consumed by no downstream job.

Get-ModuleVersionString and Get-ReleaseTag both trim their inputs, because prefix and label arrive through environment variables, and both treat a whitespace-only prerelease label as a stable release.

Verification — unit tests, red then green in CI

Commit Change Test actions
fd2c7d9 Extract tag derivation into a helper, no behavior change success
d0f8f7a Add the regression test failure (13 of 15)
06b4714 Apply the configured version prefix success (15 of 15)

32 cases now. Alongside the prefixed and unprefixed tag shapes, absent and null prefixes, whitespace normalization, and the tag shape Cleanup-PSModulePrereleases depends on, a the prefix reaches the release tag and nothing else context pins the separation directly:

  • for five prefix/version/label combinations, the tag equals $Prefix + the module version string;
  • the module version string never begins with the prefix and always matches ^\d+\.\d+\.\d+(-[0-9A-Za-z\-.]+)?$;
  • Get-ModuleVersionString has no VersionPrefix parameter at all, so a caller cannot pass one;
  • an unprefixed repository gets two identical strings, and stripping v from a prefixed tag returns the module version string.

Verification — the wiring, observed once in CI on an interim commit

This bug was a wiring failure, not a logic failure. VersionPrefix was resolved correctly by the Plan job and present in the Settings JSON; it simply never reached the tag. Unit tests prove the helpers compose correctly given the right input — they cannot prove that fromJson(inputs.Settings).Publish.Module.VersionPrefix → action input → PSMODULE_PUBLISH_PSMODULE_INPUT_VersionPrefix$versionPrefix delivers the value.

Publish-Module is skipped at the job level in every self-test run — Publish.Module.Enabled is (ReleaseType -ne 'None') -or shouldAutoCleanup, and an open pull request satisfies neither without a prerelease label — so the self-test does not exercise that chain on this diff.

To close that gap once, an interim commit on this branch added Fix to a fixture's PrereleaseLabels, which made the self-test run the publish path under WhatIf. That commit has since been reset and is not part of this pull request; the observation below is from run 30759608449 and is reported as a one-time measurement, not as coverage this change carries forward.

Module name:    [PSModuleTest]
Version prefix: [v]
WhatIf:         [True]
ModuleVersion    : 6.1.16
VersionPrefix    : v
Prerelease       : fixversionprefixreleasetag001
CreatePrerelease : True
ReleaseTag       : v6.1.16-fixversionprefixreleasetag001
WhatIf: gh release create v6.1.16-fixversionprefixreleasetag001 --title v6.1.16-fixversionprefixreleasetag001 --notes-file /tmp/tmpjar7Eu.tmp --target fix-version-prefix-release-tag --prerelease

Nothing was published in that run: Publish-PSResource was logged rather than executed, no release or tag was created, and the Release workflow on the same push reported Create a prerelease: [False] / Skipping release creation.

Standing publish-path coverage in CI is the subject of #436.

Verification — locally, outside CI

publish.ps1 run end to end in WhatIf mode against a fabricated artifact, all four combinations, re-run after the separation change. Every line below is from those runs:

Prefix Prerelease Gallery version Release tag Artifact Exported …_CONTEXT_ReleaseTag
v 1.1.10 v1.1.10 PSModuleTest-1.1.10.zip v1.1.10
v mybranch001 1.1.11-mybranch001 v1.1.11-mybranch001 PSModuleTest-1.1.11-mybranch001.zip v1.1.11-mybranch001
'' 1.1.10 1.1.10 PSModuleTest-1.1.10.zip 1.1.10
'' mybranch001 1.1.11-mybranch001 1.1.11-mybranch001 PSModuleTest-1.1.11-mybranch001.zip 1.1.11-mybranch001

The first row is the PSModule/PSSemVer case from the bug report, which produced tag 1.1.10 before this change. The Gallery link and comment carried the unprefixed version in every run:

Publishing complete. PowerShell Gallery version: [1.1.10]. GitHub release tag: [v1.1.10].
gh pr comment 42 -b '✅ New release: PowerShell Gallery - [PSModuleTest 1.1.10](https://www.powershellgallery.com/packages/PSModuleTest/1.1.10)'

AutoCleanup was verified the same way, running cleanup.ps1 against fixture release lists with the gh CLI shadowed. It keys off tagName -like "*$prereleaseName*", which is prefix-agnostic, and excludes the published release by comparing tagName to PSMODULE_PUBLISH_PSMODULE_CONTEXT_ReleaseTag, which is now prefixed on both sides:

Repository Published tag Deleted Excluded
Prefixed v1.1.11-mybranch003 v1.1.11-mybranch002, v1.1.11-mybranch001 published tag, v1.1.10, another branch's prerelease
Unprefixed 1.1.11-mybranch003 1.1.11-mybranch002, 1.1.11-mybranch001 published tag, 1.1.10, another branch's prerelease
Mixed history — unprefixed leftovers from v6 v1.1.11-mybranch003 `1.1....
Read more

v6.1.15

Choose a tag to compare

@github-actions github-actions released this 02 Aug 11:33
688896d

🪲 [Fix]: Version resolution no longer fails on repositories without releases (#432)

A module repository that has not published its first release no longer breaks. Previously the Plan job failed on any repository with zero GitHub releases, which meant every brand-new module created from the template was blocked on its very first pull request — a chicken-and-egg problem where the framework could not run until a release existed, and a release could not be created until the framework ran.

Fixed: Version resolution works before the first release exists

A repository with no GitHub releases, and a module that has never been published to the PowerShell Gallery, now resolve cleanly to a 0.0.0 baseline. The first labelled pull request produces the expected first version — 0.0.1 for a patch, 0.1.0 for a minor, 1.0.0 for a major — instead of failing the Plan job with:

Cannot bind argument to parameter 'Releases' because it is null.

Because every downstream job depends on Plan, that failure skipped the whole run and made the pull request unmergeable. Nothing needs to change in consuming repositories; bumping to the released version is enough.


Technical details
  • Verified the reported diagnosis before changing anything. Both Get-LatestGitHubVersion -Releases $null and Get-LatestGitHubVersion -Releases @() failed. [Parameter(Mandatory)] [array] rejects an empty collection as well as $null, so normalising at the call site with @(Get-GitHubRelease) alone would have turned the null error into an "empty collection" error. The parameter declarations had to be relaxed too.
  • Resolve-PSModuleVersion.Helpers.psm1: Releases on Get-LatestGitHubVersion, Get-NextPrereleaseNumber, and Get-NextModuleVersion is now optional with [AllowNull()], [AllowEmptyCollection()], and an @() default, so each function is individually robust rather than depending on a careful caller.
  • New ConvertFrom-GitHubReleaseJson owns the normalisation of the gh release list output into a flat array, including the case where the command produced no output at all (the second reproduction in #381, where a repository with five releases still yielded $null). Get-GitHubRelease delegates to it and src/main.ps1 normalises with $releases = @(Get-GitHubRelease).
  • Get-LatestPublishedVersion accepts null versions and filters empty candidates before sorting, warning and flooring to 0.0.0 when neither source has a version. Get-NextModuleVersion accepts a null LatestVersion and floors it to 0.0.0.
  • The downstream fallback logic was already correct — only parameter binding, null handling, and the array shape changed. Version resolution was not redesigned.
  • Tests: .github/actions/Resolve-PSModuleVersion/tests/Resolve-PSModuleVersion.Helpers.Tests.ps1 adds 36 Pester tests following the test specification. 21 of them fail against the previous parameter declarations. They cover a null releases list, an empty releases list, releases with none marked isLatest, prerelease-only repositories, the release-JSON normalisation, and the full brand-new-module chain for major, minor, and patch decisions.
  • CI: .github/workflows/Test-Actions.yml runs every .github/actions/*/tests folder with Pester on pull requests that touch an action, so the repository now has a unit-test surface for its own actions.
  • Standards and framework alignment:
Changed surface Standards checked Framework docs checked Result
.github/actions/Resolve-PSModuleVersion/src/** PSScriptAnalyzer via .github/linters/.powershell-psscriptanalyzer.psd1 PSModule function/parameter conventions Aligned
.github/actions/Resolve-PSModuleVersion/tests/** PSScriptAnalyzer Test Specification Aligned
.github/workflows/Test-Actions.yml Pinned action SHAs, least-privilege permissions Reusable workflow contract Aligned — repository-internal workflow, not consumer-facing
Relevant issues (or links)

v6.1.14

Choose a tag to compare

@github-actions github-actions released this 26 Jul 07:16
b11b310

⚙️ [Maintenance]: Public help links follow canonical documentation paths (#420)

Public module source validation requires each public function-bearing script under src/functions/public to put its canonical generated-documentation URL first in comment-based help.

Changed: Canonical public help links are enforced for function-bearing files

The source-code standards suite derives documentation paths from recursive public function paths and validates the first .LINK against https://psmodule.io/<ModuleName>/Functions/<relative path>/<FunctionName>/.

Technical Details

  • Test-SourceCode forwards the configured module name into the shared test action instead of falling back to the repository name.
  • Public help-link validation applies only to public scripts that define at least one function/filter.
  • Covers ungrouped and nested public function scripts.
  • Requires at least one .LINK, exact URL casing/content, first-link ordering, and a trailing slash.
  • Fixture repos cover both grouped and ungrouped function paths while non-function public scripts are not forced to provide canonical links.

Downstream dependency status (live)

  • PSModule/Domeneshop PR #17 has already been merged into main at 2ca6f788c4b68a72c63d6472ae19720bc90cc8b9 while still pinned to Process-PSModule v6.1.13 (fb1bdb8fefd243292f779d2a856a38db6fe6daf4).
  • That downstream state currently lacks the local PublicHelpLinks / ModuleRequirements / TestLayout checks intended by this framework update.
  • Merging this PR unblocks downstream alignment by making the canonical public help-link validation available in the framework version line.

Validation

  • Focused PublicHelpLink runs pass for both dynamic module names (4 cases each after scoping).
  • Full source-code standards suites pass for both fixtures (13 tests each).
  • PSScriptAnalyzer reports no warnings or errors in changed files.
  • Draft PR CI passes, including linter, CodeQL, action analysis, and both workflow-test matrices.

v6.1.13

Choose a tag to compare

@github-actions github-actions released this 19 Jul 13:16
fb1bdb8

⚙️ [Maintenance]: Minor docs-site switch to Zensical (#403)

This PR finalizes the documentation pipeline as a clean-cut Zensical implementation and removes legacy Material/MkDocs fallback behavior.

Changed: Build-Site now runs as Zensical-only

Build-Site resolves site configuration from zensical.toml and no longer uses MkDocs compatibility paths.

Changed: Workflow logic moved to internal actions

Multi-line workflow scripts were extracted into internal composite actions with script files in src/ so workflow behavior stays code-backed and toolable.

Changed: Shared site script injection is centralized

Navigation-state behavior is injected from framework-owned script files, replacing repo-local inline payload patterns.

Technical Details

  • Added/updated internal actions for install, site structuring, build, and script injection.
  • Added framework-level site injector scripts under .github/scripts/site-injectors/.
  • Updated workflow/action definitions to remove long inline script blocks.
  • Added comment-based help and parameter documentation to newly introduced PowerShell entry scripts.

Validation

  • Linter checks pass, including GITHUB_ACTIONS_ZIZMOR, BIOME_LINT, and JAVASCRIPT_PRETTIER.
  • Workflow test matrix passes for default and manifest scenarios.
  • Downstream verification was completed in MariusStorhaug/MariusTestModule with a merged follow-up (#56) and successful PR/main workflow runs.

v6.1.12

Choose a tag to compare

@github-actions github-actions released this 18 Jul 21:01
0307c0d

🩹 [Patch]: Prerelease cleanup no longer depends on module artifact (#400)

Prerelease cleanup now runs as an independent workflow action, so publish logic and cleanup logic can execute in the right scenarios without being coupled to module artifact download.

Changed: Publish and cleanup are now separate actions

Publish-PSModule now only performs artifact download and publish/release work, while cleanup moved into a dedicated Cleanup-PSModulePrereleases action.

Fixed: No-build cleanup paths no longer depend on publish action internals

Publish-Module.yml now runs publish only when ReleaseType != 'None', and runs cleanup independently when ReleaseType != 'Prerelease' with existing AutoCleanup and WhatIf controls.

Technical Details

  • Removed cleanup inputs and cleanup step from .github/actions/Publish-PSModule/action.yml.
  • Added .github/actions/Cleanup-PSModulePrereleases/ with its own composite action and cleanup script.
  • Updated .github/workflows/Publish-Module.yml to call the two actions as separate, scenario-gated steps.
  • Preserved release-tag exclusion by passing PSMODULE_PUBLISH_PSMODULE_CONTEXT_ReleaseTag into the cleanup action when publish ran earlier in the job.
  • Implementation plan progress: completed the decoupling requested in issue #376 by separating cleanup from publish artifact flow.
Related issues

v6.1.11

Choose a tag to compare

@github-actions github-actions released this 18 Jul 20:45
5998e39

⚙️ [Maintenance]: Internalize runtime settings by phase (#402)

Runtime execution flags and test matrices are now owned by each phase object instead of a shared root Run/TestSuites contract.

Changed: Runtime execution state is phase-owned

Get-PSModuleSettings now enriches each phase with Desired/Enabled state and stores suites under the owning test phase:

  • Linter.Repository / Linter.SourceCode
  • Build.Module / Build.Docs / Build.Site
  • Test.SourceCode.Suites, Test.PSModule.Suites, Test.Module.Suites
  • Test.Module.BeforeAllEnabled, Test.Module.MainEnabled, Test.Module.AfterAllEnabled
  • Test.TestResults.Enabled, Test.CodeCoverage.Enabled
  • Publish.Module.Enabled, Publish.Site.Enabled

Changed: Workflows now consume the new phase-owned schema

Reusable workflows and the root workflow were updated to reference phase-local state instead of Settings.Run.* and Settings.TestSuites.*.

Changed: Version resolution is scoped under publish phase

Plan.yml now stores resolved version metadata under:

  • Settings.Publish.Module.Resolution.Version
  • Settings.Publish.Module.Resolution.Prerelease
  • Settings.Publish.Module.Resolution.FullVersion
  • Settings.Publish.Module.Resolution.ReleaseType
  • Settings.Publish.Module.Resolution.CreateRelease

Build-Module.yml and Test-ModuleLocal.yml were updated to read this new location.

Changed: Settings schema deprecates root Run contract

Settings.schema.json no longer defines root TestSuites and marks root Run as deprecated.

Technical Details

  • Preserved existing behavior by deriving phase Enabled values from the same event/state logic previously used to build Run.*.
  • Kept the input settings shape stable for repository owners; this refactor targets the internal enriched settings object passed between workflow jobs.
Related issues
  • Opened directly from maintainer request (no linked issue).

v6.1.10

Choose a tag to compare

@github-actions github-actions released this 18 Jul 20:25
7ad7d26

🩹 [Patch]: Action changes now trigger workflow validation and release checks (#401)

Workflow-only pull requests now behave correctly when the changed code lives in .github/actions, so action updates are validated and considered for release automation without manual workaround.

Changed: Workflow test pipelines now include action-code changes

The workflow test entry points now trigger on .github/actions/** changes in addition to workflow file changes, and action paths are treated as important artifacts in bump classification.

Changed: Release workflow now runs when action files change

The release workflow path filter now includes .github/actions/**, so action updates are not skipped by path-based gating.

Fixed: Repo-linter class-file exclusions are scoped to the processed repository

Super-linter exclusions are now expressed relative to the current repository working directory, which avoids path-handling issues in both default repository linting and test-repo linting scenarios.

Fixed: Root-module relative path rendering is path-API based

Root-module build comments now derive relative folder/file paths via System.IO.Path APIs instead of regex path replacement, which keeps region naming stable across path separators.

Technical Details

  • Updated workflow path filters and important-file patterns in Workflow-Test-Default.yml, Workflow-Test-WithManifest.yml, and Release.yml.
  • Added scoped FILTER_REGEX_EXCLUDE values in Linter.yml and Lint-Repository.yml.
  • Reworked relative-path generation in Add-ContentFromItem.ps1 and Build-PSModuleRootModule.ps1 to use GetRelativePath, ChangeExtension, and separator-safe splitting.
  • Added/updated class-fixture files under tests/srcTestRepo and tests/srcWithManifestTestRepo for loader/linter coverage.
Related issues

v6.1.9

Choose a tag to compare

@github-actions github-actions released this 18 Jul 17:16
317bcb1

Treat BeforeAll module-local setup failures as catastrophic (#399)

Summary

  • treat BeforeAll-ModuleLocal failure as a hard failure root cause in test result aggregation
  • run AfterAll-ModuleLocal cleanup whenever module-local setup ran, even if setup failed and tests were skipped
  • pass BeforeAll-ModuleLocal job result into Get-TestResults and fail early with a clear root-cause message
  • document the new BeforeAllModuleLocalResult input in Get-PesterTestResults

Links

v6.1.8

Choose a tag to compare

@github-actions github-actions released this 17 Jul 22:21
025d6a2

🩹 [Patch]: Consolidate Install-PSModuleHelpers into Install-PSModule (#397)

The Install-PSModuleHelpers action step has been consolidated under the unified Install-PSModule name across all workflow files and composite actions. Obsolete test fixture files that are no longer needed by the test repositories have also been removed.

Changed: Install step unified under Install-PSModule

The internal step name Install-PSModuleHelpers is renamed to Install-PSModule in all reusable workflows and composite actions. This affects:

  • .github/workflows/AfterAll-ModuleLocal.yml
  • .github/workflows/BeforeAll-ModuleLocal.yml
  • .github/workflows/Build-Site.yml
  • .github/workflows/Test-ModuleLocal.yml
  • .github/actions/Build-PSModule/action.yml
  • .github/actions/Document-PSModule/action.yml

There is no change to the behavior or inputs/outputs of these workflows — this is a naming consolidation only.

Changed: Obsolete test fixtures removed

Unused source files, icons, assemblies, and configuration fixtures from the test repositories (srcTestRepo and srcWithManifestTestRepo) have been removed, reducing noise in the repo and simplifying the test structure.

Technical Details

  • All step references uses: ./_wf/.github/actions/Install-PSModuleHelpers replaced with uses: ./_wf/.github/actions/Install-PSModule.
  • Deleted: src/assemblies/LsonLib.dll, src/classes/, src/data/, src/finally.ps1, icon/, README.md, mkdocs.yml, and several other fixtures from srcTestRepo.
  • No consumer-visible API or behavior changes.

v6.1.7

Choose a tag to compare

@github-actions github-actions released this 16 Jul 20:35
8b1a261

🪲 [Fix]: TestData keys reach setup and teardown phases (#394)

TestData values now reach every module-local phase through the same export path. Setup scripts, module tests, and teardown scripts can rely on identical environment variable names for caller-provided secrets and variables, with secret masking preserved.

Fixed: Setup and teardown scripts receive TestData keys

BeforeAll-ModuleLocal, Test-ModuleLocal, and AfterAll-ModuleLocal now all call the same local Expose-TestData action after installing the shared helper module. This keeps TestData parsing, validation, masking, and GITHUB_ENV export behavior identical before each phase runs.

Callers continue to use the existing TestData workflow secret; no interface change is required.

Changed: TestData phase parity is documented

The README now states that the same TestData keys are available in setup, test, and teardown phases, and includes troubleshooting guidance for callers that use secrets: inherit without explicitly creating a TestData JSON payload.

Technical Details

  • Added .github/actions/Expose-TestData/action.yml as the single workflow step wrapper around Import-TestData.
  • Updated BeforeAll-ModuleLocal.yml, Test-ModuleLocal.yml, and AfterAll-ModuleLocal.yml to use the shared action.
  • Added fixture assertions to both workflow test repositories so PSMODULE_TEST_SINGLELINE_SECRET and PSMODULE_TEST_VARIABLE are checked in BeforeAll.ps1, Pester tests, and AfterAll.ps1.
  • Implementation plan progress: core shared export path, parity validation, setup/teardown regression coverage, and README guidance are complete.
  • Local validation: helper test scripts passed; setup/teardown fixture assertions passed for both test repositories; touched workflow files passed actionlint with the repository's known job.workflow_repository/job.workflow_sha context warnings ignored.