Skip to content

v2.0.0: JSON manifests, modular refactor, PS7 cross-platform, modernized build/test#449

Merged
psjamesp merged 51 commits intomasterfrom
v2
Apr 13, 2026
Merged

v2.0.0: JSON manifests, modular refactor, PS7 cross-platform, modernized build/test#449
psjamesp merged 51 commits intomasterfrom
v2

Conversation

@HeyItsGilbert
Copy link
Copy Markdown
Collaborator

Overview

This PR lands the long-running v2 branch into master, shipping Plaster 2.0.0-alpha1. It's a large drop (~50 commits, ~115 files, +11.5k / -3.2k) and touches nearly every part of the project, so the sections below break it down by theme rather than by commit.

Target version: Plaster.psd1ModuleVersion = '2.0.0', Prerelease = 'alpha1'.

Highlights

  • JSON manifest support — Plaster templates can now be authored as JSON in addition to XML, with a full plaster-manifest-v2.json schema, bidirectional conversion, and validation.
  • Modular source layout — the monolithic Invoke-Plaster.ps1 / NewPlasterManifest.ps1 / GetModuleExtension.ps1 files have been decomposed into per-function Public/ and Private/ files.
  • PowerShell 7.x + cross-platform — Windows, Linux, macOS all supported; minimum PS version is now 5.1.
  • Pester 5.x test suite — large coverage expansion with per-function tests.
  • Modernized build — psake + PowerShellBuild + PSDepend, with a -Bootstrap switch for clean CI installs.
  • Publish workflow rewired end-to-end and validated against GitHub-hosted runners.

What changed

Module architecture

  • Split Plaster/InvokePlaster.ps1 (1500+ lines), Plaster/NewPlasterManifest.ps1, and Plaster/GetModuleExtension.ps1 into discrete Public/ and Private/ function files.
  • New Plaster/Private/ helpers for things that were previously inline: ConvertFrom-JsonManifest, ConvertTo-JsonManifest, ConvertFrom-JsonContentAction, ConvertTo-JsonContentAction, Copy-FileWithConflictDetection, Expand-FileSourceSpec, Get-ManifestsUnderPath, Get-PlasterManifestType, Initialize-PredefinedVariables, Invoke-ExpressionImpl, Invoke-PlasterOperation, New-ConstrainedRunspace, Resolve-ModuleVersionString, Resolve-ProcessParameter, Start-Process*, Write-PlasterLog, and friends.
  • Plaster.psm1 / Plaster.psd1 updated to match the new layout.

JSON manifest support (new)

  • Plaster/Schema/plaster-manifest-v2.json — full JSON Schema for v2 manifests.
  • JSON ↔ internal-model converters: ConvertFrom-JsonManifest, ConvertTo-JsonManifest, plus content-action variants.
  • Get-PlasterManifestType detects XML vs JSON manifests; Test-PlasterManifest validates both.
  • Example JSON manifests under examples/ (plasterManifest.json, plasterManifest-validatePattern.json, plasterManifest_fr-FR.json).
  • Fixed error handling around file and template actions in JSON flow.

Cross-platform / PS7

  • Minimum PowerShell version raised to 5.1; null-coalescing operators removed from hot paths for PS5.1 compatibility (Replace null-coalescing operators with PS5.1-compatible syntax #443).
  • Default encoding changed from Default to UTF-8-NoBOM.
  • Path separator handling normalized; constrained-runspace compatibility fixes for PS7.
  • Parameter default value storage fixed on non-Windows.

Tests

  • Migrated to Pester 5.x (breaking change for test authors).
  • New per-function test files: Get-ModuleExtension.Tests.ps1, Get-PlasterManifestPathForCulture.Tests.ps1, Initialize-PredefinedVariables.Tests.ps1, Resolve-ModuleVersionString.Tests.ps1, New-PlasterManifest.Tests.ps1, etc.
  • Added Help.tests.ps1, Manifest.tests.ps1, Meta.tests.ps1, MetaFixers.psm1 (imported from Stucco).
  • Large fixture added for module resolution tests (tests/Fixtures/ModuleList.xml).
  • Conditional-attribute evaluation tests fixed (Fixed conditional attribute evaluation for test #445).

Build & tooling

  • build.ps1 refactored for cleaner parameter handling, with -Task, -Bootstrap, and -Help parameter sets.
  • -Bootstrap provisions PSDepend (pinned to PowerShellGet v2), then runs a try-import-first-then-install pattern against requirements.psd1.
  • requirements.psd1 pins PSDepend 0.3.8, Pester 5.7.1, psake 4.9.1, BuildHelpers 2.0.16, PowerShellBuild 0.7.2, PSScriptAnalyzer 1.24.0.
  • psakeFile.ps1 delegates to PowerShellBuild; CopyDirectories configured for en-US, Schema, Templates.
  • debugHarness.ps1 refactored for the new module layout.
  • .vscode/ tasks + settings refreshed; .markdownlint.json + cspell.json added.

CI / publish workflow

  • .github/workflows/publish.yaml now runs on windows-latest, uses ModuleFast-action to pre-stage deps, and invokes ./build.ps1 -Task Publish -Bootstrap.
  • .github/workflows/PesterReports.yml updated permissions and action versions.
  • Dead placeholder `internal-nuget-repo` registration removed from the bootstrap path (was failing `Register-PSRepository` URI validation on GitHub runners).

Docs

  • README rewritten for v2.
  • CHANGELOG reformatted to Keep a Changelog.
  • Logo updated to make the 2.0 branding clearer.
  • Examples directory expanded.

Breaking changes

  • Minimum PowerShell version is now 5.1 (was 3.0).
  • Test framework is Pester 5.x — any downstream tests authored against Pester 3/4 will need updating.
  • Default encoding changed to UTF-8-NoBOM.
  • Internal module layout changed significantly; anything dot-sourcing Plaster internals by path will break (public API is unchanged).

Test plan

  • CI green on v2 (publish workflow dry-run + Pester reports)
  • `./build.ps1 -Bootstrap -Task Test` passes locally on Windows PS 5.1
  • `./build.ps1 -Bootstrap -Task Test` passes on Windows PS 7
  • Smoke test on Linux / macOS (PS 7)
  • `Invoke-Plaster` against an XML manifest still works (regression)
  • `Invoke-Plaster` against a JSON manifest works end-to-end
  • `Test-PlasterManifest` validates both XML and JSON manifests
  • Publish workflow successfully pushes `2.0.0-alpha1` to PSGallery when manually dispatched

🤖 Generated with Claude Code

psjamesp and others added 30 commits June 19, 2025 19:23
- Added a new cspell.json file for spell checking with custom words related to the project.
- Updated documentation for Get-PlasterTemplate, Invoke-Plaster, New-PlasterManifest, and Test-PlasterManifest cmdlets to include the new -ProgressAction parameter.
- Modified psakeFile.ps1 to set up build preferences and dependencies more efficiently.
- Introduced requirements.psd1 to manage module dependencies and their versions.
* Updated `actions/checkout` to version 4
* Added caching for PowerShell modules using `psmodulecache`
* Improved module dependency handling in the workflow
* Added `plaster` to the spell-checker ignore list in `cspell.json`
* Added `permissions` for `checks` and `issues` in the workflow.
* Updated `actions/upload-artifact` to version `v4.6.2`.
* Updated `actions/download-artifact` to version `v4.3.0`.
* Updated `EnricoMi/publish-unit-test-result-action` to version `v2.20.0`.
* Changed `issues: write` to `pull-requests: write` for better clarity on permissions.
* Updated condition for the `publish-test-results` job to `if: (!cancelled())` for improved control flow.
* Introduced `Help.tests.ps1` to validate command help and parameters.
* Added `.markdownlint.json` for markdown linting configuration.
* Updated `.vscode/settings.json` to include final newline and space settings.
* Enhanced `CHANGELOG.md` to follow the Keep a Changelog format.
* Fixed encoding issues in multiple XML and JSON files.
* Refactored test scripts to improve variable scoping and clarity.
* Updated `psakeFile.ps1` to include additional build directories.
* Ensure the build script is executed if the environment variable `BHProjectPath` is not set.
* This change is applied across multiple test files to maintain consistency in the test setup.
- The function checks for culture-specific, parent culture, and invariant culture manifests.
- Added parameter validation and detailed documentation for usage.
- Updated references in `Invoke-Plaster` to use the new function name.
- Created tests to ensure functionality and correctness of the new implementation.
…ng tests

* Introduced the `Initialize-PredefinedVariables` function to set up essential variables for Plaster template processing.
* Updated `Invoke-Plaster` to call the new function with appropriate parameters.
* Added tests for `Initialize-PredefinedVariables` to ensure correct initialization of predefined variables.
* Modified `.vscode/settings.json` to refine search exclusion patterns.
…e-PlasterLog` functions

* Added detailed synopsis, description, parameters, examples, and notes to improve clarity and usability.
* Ensured consistent logging and error handling across operations within the Plaster module.
…tests

* Introduced `Resolve-ModuleVersionString` to parse version strings into valid version objects.
* Replaced the inline version parsing logic in `Get-ModuleExtension` with a call to `Resolve-ModuleVersionString`.
* Added tests for `Resolve-ModuleVersionString` to ensure correct functionality and error handling.
* Rename existing function
* Supports an optional parameter to list all available modules or only the latest version of each module.
* Includes detailed documentation and examples for ease of use.
* Refactor test structure for improved readability
* Ensure all predefined variables are initialized correctly
* Validate that `PLASTER_TemplatePath` and `PLASTER_DestinationPath` match expected values
* Changed the mock for `Get-Module` to use `Import-Clixml` for better clarity and consistency.
* This improves the readability of the test setup and aligns with the expected data handling.
- Implemented `Test-JsonManifestContent` to validate content actions in Plaster manifests, ensuring required properties are present for each action type.
- Created `Test-JsonManifestParameters` to validate parameters in Plaster manifests, checking for required properties, valid names, and types.
- Added `Test-PlasterCondition` to validate the syntax of conditions in manifests.
- Updated `Invoke-Plaster` to streamline parameter handling and improve manifest loading logic.
- Removed the deprecated `Write-PlasterLog` function to simplify logging.
- Enhanced documentation for `Invoke-Plaster` and `New-PlasterManifest` to reflect new parameter options and usage.
- Added comprehensive tests for `New-PlasterManifest` to ensure correct manifest generation and validation.
- Adjusted tests for `RequireModule` and `TestPlasterManifest` to align with new validation logic and output expectations.
* Added a TODO comment for clarity in `JsonTest.Tests.ps1`.
* Modified path handling in `PlasterManifestValidation.Tests.ps1` to ensure compatibility across platforms.
* Changed the path in the `<modify>` tag from `$env:LOCALAPPDATA\tasks-should-not-be-here.json` to `{0}tasks-should-not-be-here.json` for better compatibility.
HeyItsGilbert and others added 21 commits July 16, 2025 19:25
* Added checks for `$env:BHProjectPath` and adjusted paths for module imports.
* Set up output directory more robustly.
* Changed `Invoke-Plaster` to use `-WhatIf` for safer execution.
Updated readme.md file
* Added checks to ensure both `source` and `destination` properties are provided for `file` and `templateFile` actions.
* Enhanced error messages for better clarity on missing properties.
* Updated JSON manifest example to reflect the change from `file` to `directory` type for better structure.
* Updated `ModuleVersion` in the manifest to reflect the beta release.
* Changed `ReleaseNotes` to point to the complete changelog URL for better accessibility.
* Removed extra space in branch name definition.
* Updated `psmodulecache` action version from `v5.1` to `v6.0`.
* Replaced the PowerShell module caching step with ModuleFast action.
* Updated the specification format for better readability and maintainability.
* Updated the `uses` directive for `ModuleFast-action` to specify version `v0.0.1`.
* Ensures compatibility and stability in the publishing process.
* Introduced a new `Compare-SemanticVersion` function to handle semantic version comparisons.
* Enhanced version comparison to account for prerelease versions.
* Updated logic to determine if the GitHub version is greater than or equal to the Gallery version.
* Changed `ModuleVersion` from `2.0.0-beta1` to `2.0.0` in `Plaster.psd1`.
* Removed version comparison logic from the publish workflow to streamline the publishing process.
Plaster v2.0.0-alpha uses the null-coalescing operator (`??`) introduced
in PowerShell 7.0, breaking compatibility with PowerShell 5.1 as
specified in the module manifest.

## Changes

**Write-PlasterLog.ps1**
- Replaced `??` operators with conditional expressions compatible with
PS5.1+

```powershell
# Before
$currentLogLevel = $script:LogLevel ?? 'Information'
$currentLevelValue = $logLevels[$currentLogLevel] ?? 2

# After
$currentLogLevel = if ($null -ne $script:LogLevel) { $script:LogLevel } else { 'Information' }
$currentLevelValue = if ($null -ne $logLevels[$currentLogLevel]) { $logLevels[$currentLogLevel] } else { 2 }
```

**Plaster.psm1**
- Added dot-sourcing for Private and Public function files
- Implemented selective export of public functions only

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `www.powershellgallery.com`
> - Triggering command: `/usr/bin/pwsh pwsh -NoProfile -File ./build.ps1
-Bootstrap` (dns block)
>   - Triggering command: `/usr/bin/pwsh pwsh -NoProfile -Command 
Register-PSRepository -Default -ErrorAction SilentlyContinue
Get-PSRepository` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/PowerShellOrg/Plaster/settings/copilot/coding_agent)
(admins only)
>
> </details>

<!-- START COPILOT ORIGINAL PROMPT -->



<details>

<summary>Original prompt</summary>

> 
> ----
> 
> *This section details on the original issue you should resolve*
> 
> <issue_title>Plaster v2.0.0-alpha broken on Windows</issue_title>
> <issue_description>Hiya,
> 
> [Sampler]() uses Plaster and we've noticed on our pipelines that the
prerelease version breaks on windows because `Write-PlasterLog` uses the
Null-coalescing operator.
> 
>
https://github.com/PowerShellOrg/Plaster/blob/v2/Plaster/Private/Write-PlasterLog.ps1#L52-L54
> 
> Could you please fix soonish, or would you recommend we pin an old
version?</issue_description>
> 
> <agent_instructions>Search for any use of null coalescing and remove
it. This module must be able to run PS5.1</agent_instructions>
> 
> ## Comments on the Issue (you are @copilot in this section)
> 
> <comments>
> </comments>
> 


</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes #442

<!-- START COPILOT CODING AGENT TIPS -->
---

💬 We'd love your input! Share your thoughts on Copilot coding agent in
our [2 minute survey](https://gh.io/copilot-coding-agent-survey).

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: HeyItsGilbert <615265+HeyItsGilbert@users.noreply.github.com>
Co-authored-by: Gilbert Sanchez <me@gilbertsanchez.com>
* PowerShell doesn't support '.' in prerelease.
* Corrected the prerelease version format in the module manifest.
* Updated changelog to reflect the new versioning style.
Updated the logo in `Invoke-Plaster` so 2.0 is easier to read.
The JSON conditional evaluation on the PLASTER_Options variable always
evaluates to false in the PowerShell gallery v2.0 version of Plaster. I
provided a fix for the issue. You by no means have to merge this. I just
wanted to show you where the problem with JSON templates was happening.
It is working great now and I am extremely excited to see that this has
been updated, and JSON manifest and templating are great.
The example.com URL failed Register-PSRepository URI validation on
GitHub-hosted runners, breaking the publish workflow. Nothing in the
build consumed the repo — PSDepend pulls from PSGallery.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@psjamesp psjamesp merged commit d2739ac into master Apr 13, 2026
3 checks passed
@HeyItsGilbert HeyItsGilbert deleted the v2 branch April 13, 2026 16:44
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.

5 participants