diff --git a/.github/workflows/Build-Docs.yml b/.github/workflows/Build-Docs.yml index e981c3ae..9e19000f 100644 --- a/.github/workflows/Build-Docs.yml +++ b/.github/workflows/Build-Docs.yml @@ -30,7 +30,7 @@ jobs: path: ${{ fromJson(inputs.Settings).WorkingDirectory }}/outputs/module - name: Document module - uses: PSModule/Document-PSModule@dc5b329f840f7803ec02d34a42ee725bca39db5f # v1.0.16 + uses: PSModule/Document-PSModule@fb5d349fa6e6ff8277b2eaf32a588cd97b234525 # v1.0.17 with: Name: ${{ fromJson(inputs.Settings).Name }} WorkingDirectory: ${{ fromJson(inputs.Settings).WorkingDirectory }} diff --git a/.github/workflows/Build-Module.yml b/.github/workflows/Build-Module.yml index 3dd3a375..fbc8893a 100644 --- a/.github/workflows/Build-Module.yml +++ b/.github/workflows/Build-Module.yml @@ -30,8 +30,10 @@ jobs: fetch-depth: 0 - name: Build module - uses: PSModule/Build-PSModule@3b368fe7d4cd5872feddfa2ac3dacfb5dfd0ab13 # v4.0.15 + uses: PSModule/Build-PSModule@672aaa7a91a379c4c6cd14494d03ab5e87e13c52 # v5.0.0 with: Name: ${{ fromJson(inputs.Settings).Name }} + Version: ${{ fromJson(inputs.Settings).Module.Version != '' && fromJson(inputs.Settings).Module.Version || '999.0.0' }} + Prerelease: ${{ fromJson(inputs.Settings).Module.Prerelease }} ArtifactName: ${{ inputs.ArtifactName }} WorkingDirectory: ${{ fromJson(inputs.Settings).WorkingDirectory }} diff --git a/.github/workflows/Build-Site.yml b/.github/workflows/Build-Site.yml index 080f04af..720b10b9 100644 --- a/.github/workflows/Build-Site.yml +++ b/.github/workflows/Build-Site.yml @@ -23,7 +23,7 @@ jobs: fetch-depth: 0 - name: Install-PSModuleHelpers - uses: PSModule/Install-PSModuleHelpers@ed79b6e3aa8c9cd3d30ab2bf02ea6bd4687b9c74 # v1.0.7 + uses: PSModule/Install-PSModuleHelpers@68e8ca76be679bfcb7099aed8cffa911c4ab72af # v1.0.8 - name: Download docs artifact uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 diff --git a/.github/workflows/Get-Settings.yml b/.github/workflows/Get-Settings.yml deleted file mode 100644 index 5d07ea7e..00000000 --- a/.github/workflows/Get-Settings.yml +++ /dev/null @@ -1,78 +0,0 @@ -name: Get-Settings - -on: - workflow_call: - inputs: - SettingsPath: - type: string - description: The path to the settings file. - required: false - Debug: - type: boolean - description: Enable debug output. - required: false - default: false - Verbose: - type: boolean - description: Enable verbose output. - required: false - default: false - Version: - type: string - description: Specifies the version of the GitHub module to be installed. The value must be an exact version. - required: false - default: '' - Prerelease: - type: boolean - description: Whether to use a prerelease version of the 'GitHub' module. - required: false - default: false - WorkingDirectory: - type: string - description: The path to the root of the repo. - required: false - default: '.' - ImportantFilePatterns: - type: string - description: | - Newline-separated list of regex patterns that identify important files. - Changes matching these patterns trigger build, test, and publish stages. - When set, fully replaces the defaults (^src/ and ^README\.md$). - required: false - default: | - ^src/ - ^README\.md$ - - outputs: - Settings: - description: The complete settings object including test suites - value: ${{ jobs.Get-Settings.outputs.Settings }} - -permissions: - contents: read # to checkout the repo - pull-requests: write # to add labels to PRs - -jobs: - Get-Settings: - name: Get-Settings - runs-on: ubuntu-latest - outputs: - Settings: ${{ steps.Get-Settings.outputs.Settings }} - steps: - - name: Checkout Code - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - persist-credentials: false - fetch-depth: 0 - - - name: Get-Settings - uses: PSModule/Get-PSModuleSettings@1e3d156786c56e6fbd839a1ba5ab21ff8858090e # v1.5.0 - id: Get-Settings - with: - SettingsPath: ${{ inputs.SettingsPath }} - Debug: ${{ inputs.Debug }} - Prerelease: ${{ inputs.Prerelease }} - Verbose: ${{ inputs.Verbose }} - Version: ${{ inputs.Version }} - WorkingDirectory: ${{ inputs.WorkingDirectory }} - ImportantFilePatterns: ${{ inputs.ImportantFilePatterns }} diff --git a/.github/workflows/Plan.yml b/.github/workflows/Plan.yml new file mode 100644 index 00000000..3a25e0f4 --- /dev/null +++ b/.github/workflows/Plan.yml @@ -0,0 +1,121 @@ +name: Plan + +# The Plan job is the single decision point for the workflow. +# It runs two steps: +# 1. Get-PSModuleSettings - loads and resolves configuration +# 2. Resolve-PSModuleVersion - calculates the next version from settings + PR labels +# The resolved version is merged into the Settings object (Settings.Module.*) by the Enrich-Settings step. +# All downstream jobs receive one self-contained Settings JSON with no separate version outputs. + +on: + workflow_call: + inputs: + SettingsPath: + type: string + description: The path to the settings file. + required: false + Debug: + type: boolean + description: Enable debug output. + required: false + default: false + Verbose: + type: boolean + description: Enable verbose output. + required: false + default: false + Version: + type: string + description: Specifies the version of the GitHub module to be installed. The value must be an exact version. + required: false + default: '' + Prerelease: + type: boolean + description: Whether to use a prerelease version of the 'GitHub' module. + required: false + default: false + WorkingDirectory: + type: string + description: The path to the root of the repo. + required: false + default: '.' + ImportantFilePatterns: + type: string + description: | + Newline-separated list of regex patterns that identify important files. + Changes matching these patterns trigger build, test, and publish stages. + When set, fully replaces the defaults (^src/ and ^README\.md$). + required: false + default: | + ^src/ + ^README\.md$ + + outputs: + Settings: + description: The complete settings object including test suites and resolved module version. + value: ${{ jobs.Plan.outputs.Settings }} + +permissions: + contents: read # to checkout the repo + pull-requests: write # to add labels / comments to PRs + +jobs: + Plan: + name: Plan + runs-on: ubuntu-latest + outputs: + Settings: ${{ steps.Enrich-Settings.outputs.Settings }} + steps: + - name: Checkout Code + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false + fetch-depth: 0 + + - name: Get-Settings + uses: PSModule/Get-PSModuleSettings@1e3d156786c56e6fbd839a1ba5ab21ff8858090e # v1.5.0 + id: Get-Settings + with: + SettingsPath: ${{ inputs.SettingsPath }} + Debug: ${{ inputs.Debug }} + Prerelease: ${{ inputs.Prerelease }} + Verbose: ${{ inputs.Verbose }} + Version: ${{ inputs.Version }} + WorkingDirectory: ${{ inputs.WorkingDirectory }} + ImportantFilePatterns: ${{ inputs.ImportantFilePatterns }} + + - name: Resolve-Version + uses: PSModule/Resolve-PSModuleVersion@d53326c7687d20a7949d457fccd71223856b1890 # v1.1.0 + id: Resolve-Version + env: + GH_TOKEN: ${{ github.token }} + with: + Settings: ${{ steps.Get-Settings.outputs.Settings }} + Name: ${{ fromJson(steps.Get-Settings.outputs.Settings).Name }} + Debug: ${{ inputs.Debug }} + Verbose: ${{ inputs.Verbose }} + WorkingDirectory: ${{ inputs.WorkingDirectory }} + + - name: Enrich-Settings + # Merge the resolved version into the Settings object so all downstream jobs + # receive a single, self-contained Settings JSON with no separate version outputs. + id: Enrich-Settings + shell: pwsh + env: + SETTINGS: ${{ steps.Get-Settings.outputs.Settings }} + VERSION: ${{ steps.Resolve-Version.outputs.Version }} + PRERELEASE: ${{ steps.Resolve-Version.outputs.Prerelease }} + FULL_VERSION: ${{ steps.Resolve-Version.outputs.FullVersion }} + RELEASE_TYPE: ${{ steps.Resolve-Version.outputs.ReleaseType }} + CREATE_RELEASE: ${{ steps.Resolve-Version.outputs.CreateRelease }} + run: | + $settings = $env:SETTINGS | ConvertFrom-Json + $settings | Add-Member -MemberType NoteProperty -Name Module -Value ([pscustomobject]@{ + Version = $env:VERSION + Prerelease = $env:PRERELEASE + FullVersion = $env:FULL_VERSION + ReleaseType = if ([string]::IsNullOrEmpty($env:RELEASE_TYPE)) { 'None' } else { $env:RELEASE_TYPE } + CreateRelease = $env:CREATE_RELEASE -eq 'true' + }) + $enriched = $settings | ConvertTo-Json -Depth 10 -Compress + "Settings=$enriched" >> $env:GITHUB_OUTPUT diff --git a/.github/workflows/Publish-Module.yml b/.github/workflows/Publish-Module.yml index 2e24dda9..6886b427 100644 --- a/.github/workflows/Publish-Module.yml +++ b/.github/workflows/Publish-Module.yml @@ -13,7 +13,7 @@ on: required: true permissions: - contents: write # to checkout the repo and create releases + contents: write # to checkout the repo, create releases, and upload release artifacts pull-requests: write # to comment on PRs jobs: @@ -30,7 +30,7 @@ jobs: fetch-depth: 0 - name: Publish module - uses: PSModule/Publish-PSModule@8917aed588dae1bd1aa2873b1caec1c50c20d255 # v2.2.4 + uses: PSModule/Publish-PSModule@03c0f8b53d0367c85a0f121f98af9b40c817b0e3 # v3.0.0 env: GH_TOKEN: ${{ github.token }} with: @@ -39,15 +39,6 @@ jobs: APIKey: ${{ secrets.APIKey }} WhatIf: ${{ github.repository == 'PSModule/Process-PSModule' }} AutoCleanup: ${{ fromJson(inputs.Settings).Publish.Module.AutoCleanup }} - AutoPatching: ${{ fromJson(inputs.Settings).Publish.Module.AutoPatching }} - DatePrereleaseFormat: ${{ fromJson(inputs.Settings).Publish.Module.DatePrereleaseFormat }} - IgnoreLabels: ${{ fromJson(inputs.Settings).Publish.Module.IgnoreLabels }} - ReleaseType: ${{ fromJson(inputs.Settings).Publish.Module.ReleaseType }} - IncrementalPrerelease: ${{ fromJson(inputs.Settings).Publish.Module.IncrementalPrerelease }} - MajorLabels: ${{ fromJson(inputs.Settings).Publish.Module.MajorLabels }} - MinorLabels: ${{ fromJson(inputs.Settings).Publish.Module.MinorLabels }} - PatchLabels: ${{ fromJson(inputs.Settings).Publish.Module.PatchLabels }} - VersionPrefix: ${{ fromJson(inputs.Settings).Publish.Module.VersionPrefix }} UsePRTitleAsReleaseName: ${{ fromJson(inputs.Settings).Publish.Module.UsePRTitleAsReleaseName }} UsePRBodyAsReleaseNotes: ${{ fromJson(inputs.Settings).Publish.Module.UsePRBodyAsReleaseNotes }} UsePRTitleAsNotesHeading: ${{ fromJson(inputs.Settings).Publish.Module.UsePRTitleAsNotesHeading }} diff --git a/.github/workflows/Test-Module.yml b/.github/workflows/Test-Module.yml index d5320a2e..d8611def 100644 --- a/.github/workflows/Test-Module.yml +++ b/.github/workflows/Test-Module.yml @@ -32,7 +32,7 @@ jobs: path: ${{ fromJson(inputs.Settings).WorkingDirectory }}/outputs/module - name: Test-Module - uses: PSModule/Test-PSModule@8c3337136dc7cf320da39eeb50e776d04bc9ac73 # v3.0.10 + uses: PSModule/Test-PSModule@25c9cd89954d558360e5917efbd4dea4ca894144 # v3.0.13 with: Name: ${{ fromJson(inputs.Settings).Name }} Debug: ${{ fromJson(inputs.Settings).Debug }} diff --git a/.github/workflows/Test-ModuleLocal.yml b/.github/workflows/Test-ModuleLocal.yml index c8e806a2..fa534551 100644 --- a/.github/workflows/Test-ModuleLocal.yml +++ b/.github/workflows/Test-ModuleLocal.yml @@ -50,7 +50,7 @@ jobs: path: ${{ fromJson(inputs.Settings).WorkingDirectory }}/outputs/module - name: Install-PSModuleHelpers - uses: PSModule/Install-PSModuleHelpers@ed79b6e3aa8c9cd3d30ab2bf02ea6bd4687b9c74 # v1.0.7 + uses: PSModule/Install-PSModuleHelpers@68e8ca76be679bfcb7099aed8cffa911c4ab72af # v1.0.8 - name: Import-Module id: import-module @@ -64,7 +64,7 @@ jobs: "path=$path" >> $env:GITHUB_OUTPUT - name: Test-ModuleLocal - uses: PSModule/Invoke-Pester@266d1cf2532f572470b7c4463fa1072f2bfe4455 # v4.2.5 + uses: PSModule/Invoke-Pester@9cf262a79e7528d5af41c875c35dae91c44d18dd # v4.2.6 with: Debug: ${{ fromJson(inputs.Settings).Debug }} Prerelease: ${{ fromJson(inputs.Settings).Prerelease }} @@ -82,4 +82,4 @@ jobs: WorkingDirectory: ${{ fromJson(inputs.Settings).WorkingDirectory }} Prescript: | # This is to speed up module loading in Pester. Install-PSResource -Repository PSGallery -TrustRepository -Name PSCustomObject - Import-Module -Name '${{ steps.import-module.outputs.name }}' -RequiredVersion 999.0.0 + Import-Module -Name '${{ steps.import-module.outputs.name }}' -RequiredVersion '${{ fromJson(inputs.Settings).Module.Version }}' diff --git a/.github/workflows/Test-SourceCode.yml b/.github/workflows/Test-SourceCode.yml index 9ee1ce6a..8804cf34 100644 --- a/.github/workflows/Test-SourceCode.yml +++ b/.github/workflows/Test-SourceCode.yml @@ -27,7 +27,7 @@ jobs: fetch-depth: 0 - name: Test-SourceCode - uses: PSModule/Test-PSModule@8c3337136dc7cf320da39eeb50e776d04bc9ac73 # v3.0.10 + uses: PSModule/Test-PSModule@25c9cd89954d558360e5917efbd4dea4ca894144 # v3.0.13 with: Debug: ${{ fromJson(inputs.Settings).Debug }} Prerelease: ${{ fromJson(inputs.Settings).Prerelease }} diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 621e49f1..4757d745 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -72,8 +72,8 @@ jobs: # - ✅ Merged PR - Always runs to load configuration # - ✅ Abandoned PR - Always runs to load configuration # - ✅ Manual run - Always runs to load configuration - Get-Settings: - uses: ./.github/workflows/Get-Settings.yml + Plan: + uses: ./.github/workflows/Plan.yml with: SettingsPath: ${{ inputs.SettingsPath }} Debug: ${{ inputs.Debug }} @@ -89,12 +89,12 @@ jobs: # - ❌ Abandoned PR - No need to lint abandoned changes # - ❌ Manual run - Only runs for PR events Lint-Repository: - if: fromJson(needs.Get-Settings.outputs.Settings).Run.LintRepository + if: fromJson(needs.Plan.outputs.Settings).Run.LintRepository needs: - - Get-Settings + - Plan uses: ./.github/workflows/Lint-Repository.yml with: - Settings: ${{ needs.Get-Settings.outputs.Settings }} + Settings: ${{ needs.Plan.outputs.Settings }} # Runs on: # - ✅ Open/Updated PR - Builds module for testing @@ -102,12 +102,12 @@ jobs: # - ❌ Abandoned PR - Skips building abandoned changes # - ✅ Manual run - Builds module when manually triggered Build-Module: - if: fromJson(needs.Get-Settings.outputs.Settings).Run.BuildModule + if: fromJson(needs.Plan.outputs.Settings).Run.BuildModule uses: ./.github/workflows/Build-Module.yml needs: - - Get-Settings + - Plan with: - Settings: ${{ needs.Get-Settings.outputs.Settings }} + Settings: ${{ needs.Plan.outputs.Settings }} # Runs on: # - ✅ Open/Updated PR - Tests source code changes @@ -115,12 +115,12 @@ jobs: # - ❌ Abandoned PR - Skips testing abandoned changes # - ✅ Manual run - Tests source code when manually triggered Test-SourceCode: - if: fromJson(needs.Get-Settings.outputs.Settings).Run.TestSourceCode + if: fromJson(needs.Plan.outputs.Settings).Run.TestSourceCode needs: - - Get-Settings + - Plan uses: ./.github/workflows/Test-SourceCode.yml with: - Settings: ${{ needs.Get-Settings.outputs.Settings }} + Settings: ${{ needs.Plan.outputs.Settings }} # Runs on: # - ✅ Open/Updated PR - Lints source code changes @@ -128,12 +128,12 @@ jobs: # - ❌ Abandoned PR - Skips linting abandoned changes # - ✅ Manual run - Lints source code when manually triggered Lint-SourceCode: - if: fromJson(needs.Get-Settings.outputs.Settings).Run.LintSourceCode + if: fromJson(needs.Plan.outputs.Settings).Run.LintSourceCode needs: - - Get-Settings + - Plan uses: ./.github/workflows/Lint-SourceCode.yml with: - Settings: ${{ needs.Get-Settings.outputs.Settings }} + Settings: ${{ needs.Plan.outputs.Settings }} # Runs on: # - ✅ Open/Updated PR - Tests built module @@ -141,13 +141,13 @@ jobs: # - ❌ Abandoned PR - Skips testing abandoned changes # - ✅ Manual run - Tests built module when manually triggered Test-Module: - if: fromJson(needs.Get-Settings.outputs.Settings).Run.TestModule && needs.Build-Module.result == 'success' && !cancelled() + if: fromJson(needs.Plan.outputs.Settings).Run.TestModule && needs.Build-Module.result == 'success' && !cancelled() needs: - Build-Module - - Get-Settings + - Plan uses: ./.github/workflows/Test-Module.yml with: - Settings: ${{ needs.Get-Settings.outputs.Settings }} + Settings: ${{ needs.Plan.outputs.Settings }} # Runs on: # - ✅ Open/Updated PR - Runs setup scripts before local module tests @@ -155,15 +155,15 @@ jobs: # - ❌ Abandoned PR - Skips setup for abandoned changes # - ✅ Manual run - Runs setup scripts when manually triggered BeforeAll-ModuleLocal: - if: fromJson(needs.Get-Settings.outputs.Settings).Run.BeforeAllModuleLocal && needs.Build-Module.result == 'success' && !cancelled() + if: fromJson(needs.Plan.outputs.Settings).Run.BeforeAllModuleLocal && needs.Build-Module.result == 'success' && !cancelled() uses: ./.github/workflows/BeforeAll-ModuleLocal.yml secrets: TestData: ${{ secrets.TestData }} needs: - Build-Module - - Get-Settings + - Plan with: - Settings: ${{ needs.Get-Settings.outputs.Settings }} + Settings: ${{ needs.Plan.outputs.Settings }} # Runs on: # - ✅ Open/Updated PR - Tests module in local environment @@ -171,16 +171,16 @@ jobs: # - ❌ Abandoned PR - Skips testing abandoned changes # - ✅ Manual run - Tests module in local environment when manually triggered Test-ModuleLocal: - if: fromJson(needs.Get-Settings.outputs.Settings).Run.TestModuleLocal && needs.Build-Module.result == 'success' && !cancelled() + if: fromJson(needs.Plan.outputs.Settings).Run.TestModuleLocal && needs.Build-Module.result == 'success' && !cancelled() needs: - Build-Module - - Get-Settings + - Plan - BeforeAll-ModuleLocal uses: ./.github/workflows/Test-ModuleLocal.yml secrets: TestData: ${{ secrets.TestData }} with: - Settings: ${{ needs.Get-Settings.outputs.Settings }} + Settings: ${{ needs.Plan.outputs.Settings }} # Runs on: # - ✅ Open/Updated PR - Runs teardown scripts after local module tests @@ -188,15 +188,15 @@ jobs: # - ✅ Abandoned PR - Runs teardown if tests were started (cleanup) # - ✅ Manual run - Runs teardown scripts after local module tests AfterAll-ModuleLocal: - if: fromJson(needs.Get-Settings.outputs.Settings).Run.AfterAllModuleLocal && needs.Test-ModuleLocal.result != 'skipped' && always() + if: fromJson(needs.Plan.outputs.Settings).Run.AfterAllModuleLocal && needs.Test-ModuleLocal.result != 'skipped' && always() uses: ./.github/workflows/AfterAll-ModuleLocal.yml secrets: TestData: ${{ secrets.TestData }} needs: - - Get-Settings + - Plan - Test-ModuleLocal with: - Settings: ${{ needs.Get-Settings.outputs.Settings }} + Settings: ${{ needs.Plan.outputs.Settings }} # Runs on: # - ✅ Open/Updated PR - Collects and reports test results @@ -204,16 +204,16 @@ jobs: # - ❌ Abandoned PR - Skips collecting results for abandoned changes # - ✅ Manual run - Collects and reports test results when manually triggered Get-TestResults: - if: fromJson(needs.Get-Settings.outputs.Settings).Run.GetTestResults && needs.Get-Settings.result == 'success' && always() && !cancelled() + if: fromJson(needs.Plan.outputs.Settings).Run.GetTestResults && needs.Plan.result == 'success' && always() && !cancelled() needs: - - Get-Settings + - Plan - Test-SourceCode - Lint-SourceCode - Test-Module - Test-ModuleLocal uses: ./.github/workflows/Get-TestResults.yml with: - Settings: ${{ needs.Get-Settings.outputs.Settings }} + Settings: ${{ needs.Plan.outputs.Settings }} # Runs on: # - ✅ Open/Updated PR - Calculates and reports code coverage @@ -221,14 +221,14 @@ jobs: # - ❌ Abandoned PR - Skips coverage for abandoned changes # - ✅ Manual run - Calculates and reports code coverage when manually triggered Get-CodeCoverage: - if: fromJson(needs.Get-Settings.outputs.Settings).Run.GetCodeCoverage && needs.Get-Settings.result == 'success' && always() && !cancelled() + if: fromJson(needs.Plan.outputs.Settings).Run.GetCodeCoverage && needs.Plan.result == 'success' && always() && !cancelled() needs: - - Get-Settings + - Plan - Test-Module - Test-ModuleLocal uses: ./.github/workflows/Get-CodeCoverage.yml with: - Settings: ${{ needs.Get-Settings.outputs.Settings }} + Settings: ${{ needs.Plan.outputs.Settings }} # Runs on: # - ✅ Open/Updated PR - Only with prerelease label: publishes prerelease version @@ -236,17 +236,17 @@ jobs: # - ✅ Abandoned PR - Cleans up prereleases for the abandoned branch (no version published) # - ❌ Manual run - Only runs for PR events Publish-Module: - if: fromJson(needs.Get-Settings.outputs.Settings).Run.PublishModule && needs.Get-Settings.result == 'success' && !cancelled() && (needs.Get-TestResults.result == 'success' || needs.Get-TestResults.result == 'skipped') && (needs.Get-CodeCoverage.result == 'success' || needs.Get-CodeCoverage.result == 'skipped') && (needs.Build-Site.result == 'success' || needs.Build-Site.result == 'skipped') + if: fromJson(needs.Plan.outputs.Settings).Run.PublishModule && needs.Plan.result == 'success' && !cancelled() && (needs.Get-TestResults.result == 'success' || needs.Get-TestResults.result == 'skipped') && (needs.Get-CodeCoverage.result == 'success' || needs.Get-CodeCoverage.result == 'skipped') && (needs.Build-Site.result == 'success' || needs.Build-Site.result == 'skipped') uses: ./.github/workflows/Publish-Module.yml secrets: APIKey: ${{ secrets.APIKey }} needs: - - Get-Settings + - Plan - Get-TestResults - Get-CodeCoverage - Build-Site with: - Settings: ${{ needs.Get-Settings.outputs.Settings }} + Settings: ${{ needs.Plan.outputs.Settings }} # Runs on: # - ✅ Open/Updated PR - Builds documentation for review @@ -254,13 +254,13 @@ jobs: # - ❌ Abandoned PR - Skips building docs for abandoned changes # - ✅ Manual run - Builds documentation when manually triggered Build-Docs: - if: fromJson(needs.Get-Settings.outputs.Settings).Run.BuildDocs + if: fromJson(needs.Plan.outputs.Settings).Run.BuildDocs needs: - - Get-Settings + - Plan - Build-Module uses: ./.github/workflows/Build-Docs.yml with: - Settings: ${{ needs.Get-Settings.outputs.Settings }} + Settings: ${{ needs.Plan.outputs.Settings }} # Runs on: # - ✅ Open/Updated PR - Builds site for preview @@ -268,13 +268,13 @@ jobs: # - ❌ Abandoned PR - Skips building site for abandoned changes # - ✅ Manual run - Builds site when manually triggered Build-Site: - if: fromJson(needs.Get-Settings.outputs.Settings).Run.BuildSite + if: fromJson(needs.Plan.outputs.Settings).Run.BuildSite needs: - - Get-Settings + - Plan - Build-Docs uses: ./.github/workflows/Build-Site.yml with: - Settings: ${{ needs.Get-Settings.outputs.Settings }} + Settings: ${{ needs.Plan.outputs.Settings }} # Runs on: # - ❌ Open/Updated PR - Site not published for PRs in progress @@ -282,12 +282,12 @@ jobs: # - ❌ Abandoned PR - Site not published for abandoned changes # - ❌ Manual run - Only publishes on merged PRs to default branch Publish-Site: - if: fromJson(needs.Get-Settings.outputs.Settings).Run.PublishSite && needs.Get-TestResults.result == 'success' && needs.Get-CodeCoverage.result == 'success' && needs.Build-Site.result == 'success' && !cancelled() + if: fromJson(needs.Plan.outputs.Settings).Run.PublishSite && needs.Get-TestResults.result == 'success' && needs.Get-CodeCoverage.result == 'success' && needs.Build-Site.result == 'success' && !cancelled() uses: ./.github/workflows/Publish-Site.yml needs: - - Get-Settings + - Plan - Get-TestResults - Get-CodeCoverage - Build-Site with: - Settings: ${{ needs.Get-Settings.outputs.Settings }} + Settings: ${{ needs.Plan.outputs.Settings }} diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 47a7fd15..00000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "chat.promptFilesRecommendations": { - "PSModule.constitution": true, - "PSModule.specify": true, - "PSModule.plan": true, - "PSModule.tasks": true, - "PSModule.implement": true, - "PSModule.analyze": true, - "PSModule.clarify": true, - "PSModule.pr": true - }, - "chat.tools.terminal.autoApprove": { - ".specify/scripts/": true - } -} diff --git a/README.md b/README.md index 2712572f..417ebe87 100644 --- a/README.md +++ b/README.md @@ -44,9 +44,8 @@ Depending on the labels in the pull requests, the [workflow will result in diffe - [How it works](#how-it-works) - [Workflow overview](#workflow-overview) - [Dependency tree](#dependency-tree) - - [Get-Settings](#get-settings) + - [Plan](#plan) - [Lint-Repository](#lint-repository) - - [Get settings](#get-settings-1) - [Build module](#build-module) - [Test source code](#test-source-code) - [Lint source code](#lint-source-code) @@ -112,29 +111,30 @@ Depending on the labels in the pull requests, the [workflow will result in diffe Process-PSModule composes its work from reusable workflows, actions, a container image, PowerShell modules, and Python packages. For the full dependency tree, including diagrams and a reference of every dependency, see [DEPENDENCIES.md](./DEPENDENCIES.md). -### Get-Settings +### Plan -[workflow](./.github/workflows/Get-Settings.yml) +[workflow](./.github/workflows/Plan.yml) + +The Plan job is the single decision point of the workflow. It reads the settings file (`.github/PSModule.yml`), +collects event context from GitHub, and decides what should happen in the rest of the process. Using that +situational awareness, it calculates the next module version. All decisions are captured in a single `Settings` +object — including version data under `Settings.Module` — that every downstream job receives. ### Lint-Repository [workflow](./.github/workflows/Lint-Repository.yml) -### Get settings - -[workflow](#get-settings) -- Reads the settings file `github/PSModule.yml` in the module repository to configure the workflow. -- Gathers context for the process from GitHub and the repo files, configuring what tests to run, if and what kind of release to create, and whether - to setup testing infrastructure and what operating systems to run the tests on. - ### Build module [workflow](./.github/workflows/Build-Module.yml) -- Compiles the module source code into a PowerShell module. + +- Compiles the module source code into a PowerShell module, stamping the version from `Settings.Module` into the manifest. +- Uploads the built artifact. ### Test source code [workflow](./.github/workflows/Test-SourceCode.yml) + - Tests the source code in parallel (matrix) using: - [PSModule framework settings for style and standards for source code](https://github.com/PSModule/Test-PSModule?tab=readme-ov-file#sourcecode-tests) - This produces a JSON-based report that is used by [Get-PesterTestResults](#get-test-results) evaluate the results of the tests. @@ -154,10 +154,10 @@ The [PSModule - SourceCode tests](./scripts/tests/SourceCode/PSModule/PSModule.T | ParamBlock | Functions (Generic) | Functions should have a parameter block (`param()`). | | FunctionTest | Functions (Public) | All public functions/filters should have corresponding tests. | - ### Lint source code [workflow](./.github/workflows/Lint-SourceCode.yml) + - Lints the source code in parallel (matrix) using: - [PSScriptAnalyzer rules](https://github.com/PSModule/Invoke-ScriptAnalyzer) - This produces a JSON-based report that is used by [Get-PesterTestResults](#get-test-results) evaluate the results of the linter. @@ -165,6 +165,7 @@ The [PSModule - SourceCode tests](./scripts/tests/SourceCode/PSModule/PSModule.T ### Framework test [workflow](./.github/workflows/Test-Module.yml) + - Tests and lints the module in parallel (matrix) using: - [PSModule framework settings for style and standards for modules](https://github.com/PSModule/Test-PSModule?tab=readme-ov-file#module-tests) - [PSScriptAnalyzer rules](https://github.com/PSModule/Invoke-ScriptAnalyzer) @@ -181,6 +182,7 @@ The [PSModule - SourceCode tests](./scripts/tests/SourceCode/PSModule/PSModule.T ### Test module [workflow](./.github/workflows/Test-ModuleLocal.yml) + - Imports and tests the module in parallel (matrix) using Pester tests from the module repository. - Module test files declare a Pester **6.x** requirement via `#Requires -Modules @{ ModuleName = 'Pester'; ModuleVersion = '6.0.0'; MaximumVersion = '6.*' }` — a convention module authors add to each `*.Tests.ps1`, not something this pipeline injects. The [Invoke-Pester](https://github.com/PSModule/Invoke-Pester) action installs a matching `6.x`, so minor and patch updates flow in automatically while a new major stays a deliberate, reviewed change. - Supports setup and teardown scripts executed via separate dedicated jobs: @@ -294,7 +296,6 @@ Use a consistent naming scheme so that resources are easy to identify and clean When tests use multiple authentication contexts that share the same runner, include a token or context identifier in the name to avoid collisions (for example, `Test-{OS}-{ContextID}-{RunID}`). - #### Module tests The [PSModule - Module tests](./scripts/tests/Module/PSModule/PSModule.Tests.ps1) verifies the following coding practices that the framework enforces: @@ -307,12 +308,14 @@ The [PSModule - Module tests](./scripts/tests/Module/PSModule/PSModule.Tests.ps1 ### Get test results [workflow](./.github/workflows/Get-TestResults.yml) + - Gathers the test results from the previous steps and creates a summary of the results. - If any tests have failed, the workflow will fail here. ### Get code coverage [workflow](./.github/workflows/Get-CodeCoverage.yml) + - Gathers the code coverage from the previous steps and creates a summary of the results. - Aggregates coverage from the [Framework test](#framework-test) step (framework-generated boilerplate) and the [Test module](#test-module) step (module author code). A command executed in either step counts as covered, so @@ -322,8 +325,10 @@ The [PSModule - Module tests](./scripts/tests/Module/PSModule/PSModule.Tests.ps1 ### Publish module [workflow](./.github/workflows/Publish-Module.yml) -- Publishes the module to the PowerShell Gallery. -- Creates a release on the GitHub repository. + +- Publishes the artifact to the PowerShell Gallery exactly as built — no version mutation. +- Creates a GitHub Release using the version already stamped in the manifest. +- Attaches the built module as a `.zip` asset on the GitHub Release so consumers can download the exact bytes that were tested and pushed to the PowerShell Gallery. - **Abandoned PR cleanup**: When a PR is closed without merging (abandoned), the workflow automatically cleans up any prerelease versions and tags that were created for that PR. This ensures that abandoned work doesn't leave orphaned prereleases in the PowerShell Gallery or repository. This behavior is controlled by the `Publish.Module.AutoCleanup` @@ -332,12 +337,14 @@ The [PSModule - Module tests](./scripts/tests/Module/PSModule/PSModule.Tests.ps1 ### Build docs [workflow](./.github/workflows/Build-Docs.yml) + - Generates documentation and lints the documentation using: - [super-linter](https://github.com/super-linter/super-linter). ### Build site [workflow](./.github/workflows/Build-Site.yml) + - Generates a static site using: - [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/). @@ -527,7 +534,7 @@ This table shows when each job runs based on the trigger scenario: | Job | Open/Updated PR | Merged PR | Abandoned PR | Manual Run | | ------------------------- | --------------- | ---------- | ------------ | ---------- | -| **Get-Settings** | ✅ Always | ✅ Always | ✅ Always | ✅ Always | +| **Plan** | ✅ Always | ✅ Always | ✅ Always | ✅ Always | | **Lint-Repository** | ✅ Yes | ❌ No | ❌ No | ❌ No | | **Build-Module** | ✅ Yes | ✅ Yes | ❌ No | ✅ Yes | | **Build-Docs** | ✅ Yes | ✅ Yes | ❌ No | ✅ Yes | @@ -619,7 +626,7 @@ When a pull request does not contain changes to important files: 1. A comment is automatically added to the PR listing the configured patterns and explaining why build/test stages are skipped -2. The `ReleaseType` output is set to `None` +2. `Settings.Module.ReleaseType` is set to `None` (and `Settings.Module.CreateRelease` is `false`) 3. Build, test, and publish stages are skipped 4. The PR can still be merged for non-release changes (documentation updates, CI improvements, etc.) @@ -636,7 +643,7 @@ The following settings are available in the settings file: | Name | Type | Description | Default | | ----------------------------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- | | `Name` | `String` | Name of the module to publish. Defaults to the repository name. | `null` | -| `ImportantFilePatterns` | `Array` | Regular expression patterns that identify important files. Changes matching these patterns trigger build, test, and publish stages. When set, fully replaces the defaults. | `['^src/', '^README\.md$']` | +| `ImportantFilePatterns` | `Array` | Regular expression patterns that identify important files. Changes matching these patterns trigger build, test, and publish stages. When set, fully replaces the defaults. | `['^src/', '^README\.md$']` | | `Test.Skip` | `Boolean` | Skip all tests | `false` | | `Test.Linux.Skip` | `Boolean` | Skip tests on Linux | `false` | | `Test.MacOS.Skip` | `Boolean` | Skip tests on macOS | `false` | @@ -774,7 +781,7 @@ Test: ### Example 2 - Rapid testing -This example ends up running Get-Settings, Build-Module and Test-Module (tests from the module repo) on **ubuntu-latest** only. +This example ends up running Plan, Build-Module and Test-Module (tests from the module repo) on **ubuntu-latest** only. ```yaml Test: