diff --git a/.github/linters/.codespellrc b/.github/linters/.codespellrc index 351e9a06..fe3de5e6 100644 --- a/.github/linters/.codespellrc +++ b/.github/linters/.codespellrc @@ -1,3 +1,3 @@ [codespell] skip = ./.github/linters -ignore-words-list = afterall +ignore-words-list = afterall,skelton,erformance diff --git a/.github/linters/.markdown-lint.yml b/.github/linters/.markdown-lint.yml index bb432af1..4110266d 100644 --- a/.github/linters/.markdown-lint.yml +++ b/.github/linters/.markdown-lint.yml @@ -8,20 +8,21 @@ ############### # Rules by id # ############### -MD004: false # Unordered list style +MD004: false # Unordered list style MD007: - indent: 2 # Unordered list indentation + indent: 2 # Unordered list indentation MD013: - line_length: 808 # Line length + line_length: 3000 # Line length +MD025: false # Allow front-matter title + visible H1 on docs pages MD026: - punctuation: ".,;:!。,;:" # List of not allowed -MD029: false # Ordered list item prefix -MD033: false # Allow inline HTML -MD036: false # Emphasis used instead of a heading -MD060: - style: "leading" # Table column style (leading avoids emoji width issues) + punctuation: '.,;:!。,;:' # List of not allowed +MD029: false # Ordered list item prefix +MD033: false # Allow inline HTML +MD036: false # Emphasis used instead of a heading +MD041: false # First line in file should be a top level heading, PULL_REQUEST_TEMPLATE.md is an exception +MD060: false # Documentation uses both compact and aligned table styles ################# # Rules by tags # ################# -blank_lines: false # Error on blank lines +blank_lines: false # Error on blank lines diff --git a/.github/linters/.powershell-psscriptanalyzer.psd1 b/.github/linters/.powershell-psscriptanalyzer.psd1 index d1733609..3abedb94 100644 --- a/.github/linters/.powershell-psscriptanalyzer.psd1 +++ b/.github/linters/.powershell-psscriptanalyzer.psd1 @@ -50,7 +50,7 @@ } } ExcludeRules = @( - 'PSAvoidUsingWriteHost', # Write-Host is acceptable in GitHub Actions runners + 'PSAvoidUsingWriteHost', # Write-Host is acceptable in GitHub Actions runners and docs tooling scripts 'PSMissingModuleManifestField', # This rule is not applicable until the module is built. 'PSUseToExportFieldsInManifest' ) diff --git a/.github/workflows/Docs.yml b/.github/workflows/Docs.yml index 6c32f340..7b06ccf5 100644 --- a/.github/workflows/Docs.yml +++ b/.github/workflows/Docs.yml @@ -50,7 +50,7 @@ jobs: ENABLE_GITHUB_ACTIONS_STEP_SUMMARY: true ENABLE_GITHUB_PULL_REQUEST_SUMMARY_COMMENT: true FILTER_REGEX_INCLUDE: '.*(docs/.*|\.github/actions/update-index/.*|\.github/workflows/Docs\.yml)$' - LINTER_RULES_PATH: docs/.github/linters + LINTER_RULES_PATH: .github/linters SAVE_SUPER_LINTER_SUMMARY: true VALIDATE_BIOME_LINT: false VALIDATE_BIOME_FORMAT: false diff --git a/docs/.github/linters/.codespellrc b/docs/.github/linters/.codespellrc deleted file mode 100644 index 7858201d..00000000 --- a/docs/.github/linters/.codespellrc +++ /dev/null @@ -1,3 +0,0 @@ -[codespell] -skip = ./docs/.github/linters -ignore-words-list = afterall,skelton,erformance diff --git a/docs/.github/linters/.markdown-lint.yml b/docs/.github/linters/.markdown-lint.yml deleted file mode 100644 index 4110266d..00000000 --- a/docs/.github/linters/.markdown-lint.yml +++ /dev/null @@ -1,28 +0,0 @@ -########################### -## Markdown Linter rules ## -########################### - -# Linter rules doc: -# - https://github.com/DavidAnson/markdownlint - -############### -# Rules by id # -############### -MD004: false # Unordered list style -MD007: - indent: 2 # Unordered list indentation -MD013: - line_length: 3000 # Line length -MD025: false # Allow front-matter title + visible H1 on docs pages -MD026: - punctuation: '.,;:!。,;:' # List of not allowed -MD029: false # Ordered list item prefix -MD033: false # Allow inline HTML -MD036: false # Emphasis used instead of a heading -MD041: false # First line in file should be a top level heading, PULL_REQUEST_TEMPLATE.md is an exception -MD060: false # Documentation uses both compact and aligned table styles - -################# -# Rules by tags # -################# -blank_lines: false # Error on blank lines diff --git a/docs/.github/linters/.powershell-psscriptanalyzer.psd1 b/docs/.github/linters/.powershell-psscriptanalyzer.psd1 deleted file mode 100644 index f6f9dd00..00000000 --- a/docs/.github/linters/.powershell-psscriptanalyzer.psd1 +++ /dev/null @@ -1,57 +0,0 @@ -@{ - Rules = @{ - PSAlignAssignmentStatement = @{ - Enable = $true - CheckHashtable = $true - } - PSAvoidLongLines = @{ - Enable = $true - MaximumLineLength = 150 - } - PSAvoidSemicolonsAsLineTerminators = @{ - Enable = $true - } - PSPlaceCloseBrace = @{ - Enable = $true - NewLineAfter = $false - IgnoreOneLineBlock = $true - NoEmptyLineBefore = $false - } - PSPlaceOpenBrace = @{ - Enable = $true - OnSameLine = $true - NewLineAfter = $true - IgnoreOneLineBlock = $true - } - PSProvideCommentHelp = @{ - Enable = $true - ExportedOnly = $false - BlockComment = $true - VSCodeSnippetCorrection = $false - Placement = 'begin' - } - PSUseConsistentIndentation = @{ - Enable = $true - IndentationSize = 4 - PipelineIndentation = 'IncreaseIndentationForFirstPipeline' - Kind = 'space' - } - PSUseConsistentWhitespace = @{ - Enable = $true - CheckInnerBrace = $true - CheckOpenBrace = $true - CheckOpenParen = $true - CheckOperator = $true - CheckPipe = $true - CheckPipeForRedundantWhitespace = $true - CheckSeparator = $true - CheckParameter = $true - IgnoreAssignmentOperatorInsideHashTable = $true - } - } - ExcludeRules = @( - 'PSAvoidUsingWriteHost', # Write-Host is acceptable in scripts used for docs tooling and guidance. - 'PSMissingModuleManifestField', # This rule is not applicable until the module is built. - 'PSUseToExportFieldsInManifest' - ) -} diff --git a/docs/.github/linters/.textlintrc b/docs/.github/linters/.textlintrc deleted file mode 100644 index db48de80..00000000 --- a/docs/.github/linters/.textlintrc +++ /dev/null @@ -1,513 +0,0 @@ -{ - "filters": { - "comments": true - }, - "rules": { - "terminology": { - "defaultTerms": false, - "terms": [ - "Airbnb", - "Android", - "AppleScript", - "AppVeyor", - "AVA", - "BrowserStack", - "Browsersync", - "Codecov", - "CodePen", - "CodeSandbox", - "DefinitelyTyped", - "EditorConfig", - "ESLint", - "GitHub", - "GraphQL", - "GraphiQL", - "iOS", - "JavaScript", - "JetBrains", - "jQuery", - "LinkedIn", - "Lodash", - "MacBook", - "Markdown", - "OpenType", - "PayPal", - "PhpStorm", - "PowerShell", - "PlayStation", - "RubyMine", - "Sass", - "SemVer", - "TypeScript", - "UglifyJS", - "Wasm", - "WebAssembly", - "WebStorm", - "WordPress", - "YouTube", - [ - "Common[ .]js", - "CommonJS" - ], - [ - "JSDocs?", - "JSDoc" - ], - [ - "Node[ .]js", - "Node.js" - ], - [ - "React[ .]js", - "React" - ], - [ - "SauceLabs", - "Sauce Labs" - ], - [ - "StackOverflow", - "Stack Overflow" - ], - [ - "styled ?components", - "styled-components" - ], - [ - "HTTP[ /]2(?:\\.0)?", - "HTTP/2" - ], - [ - "OS X", - "macOS" - ], - [ - "Mac ?OS", - "macOS" - ], - [ - "a npm", - "an npm" - ], - "ECMAScript", - [ - "ES2015", - "ES6" - ], - [ - "ES7", - "ES2016" - ], - "3D", - [ - "3-D", - "3D" - ], - "Ajax", - "API", - "APIs", - "API's", - [ - "(?` / `ConvertTo-` (and whatever parser/serializer they wrap). Every other function (`Import-`, `Export-`, `Format-`, `Merge-`, ...) is built on top of this pivot and is meaningless without it. - **Integration (API) modules** — a [`Context`](https://github.com/PSModule/Context)-backed credential/config store, the client setup that uses it, and at least one API function that consumes the context end-to-end. Every other API function needs the same context and client to do anything. @@ -20,7 +25,7 @@ Scope the integration branch to exactly that core, not to everything planned for ## After the core lands -Once the core has merged as `v1.0.0`, ordinary [SemVer](../Versioning.md) applies: a new function built on the stable core is a **minor** bump, a fix is a **patch** bump, and only a change to the core's own contract (signature, exported class shape, behavior) is a **major** bump. No special versioning exception is needed once the core is in place — the bootstrap phase exists only to get that core to a first release quickly. +Once the core has merged as `v1.0.0`, ordinary [SemVer](../../Versioning.md) applies: a new function built on the stable core is a **minor** bump, a fix is a **patch** bump, and only a change to the core's own contract (signature, exported class shape, behavior) is a **major** bump. No special versioning exception is needed once the core is in place — the bootstrap phase exists only to get that core to a first release quickly. ```mermaid gitGraph diff --git a/docs/content/Modules/Process-PSModule/get-started/repository-setup.md b/docs/content/Modules/Process-PSModule/get-started/repository-setup.md new file mode 100644 index 00000000..e4ee047c --- /dev/null +++ b/docs/content/Modules/Process-PSModule/get-started/repository-setup.md @@ -0,0 +1,90 @@ +--- +title: Repository setup +description: Configure GitHub Pages, the PowerShell Gallery API key, permissions, and the caller workflow so Process-PSModule can build and publish the module. +--- + +# Repository setup + +Do this once per module repository, after creating it from +[Template-PSModule](https://github.com/PSModule/Template-PSModule). + +## 1. Enable GitHub Pages + +Enable GitHub Pages in the repository settings and set it to deploy from **GitHub Actions**. + +This creates an environment called `github-pages` that GitHub deploys the documentation site to. + +
Within the github-pages environment, remove the branch protection for main. + Remove the branch protection on main +
+ +## 2. Create a PowerShell Gallery API key + +1. [Create an API key on the PowerShell Gallery](https://www.powershellgallery.com/account/apikeys). Give it permission + to manage the module you are working on. +2. Create a repository secret called `APIKEY` and set the API key as its value. + +If you plan to create many modules, use a glob pattern for the API key permissions in the PowerShell Gallery and store +the secret on the organization instead of on each repository. + +## 3. Add the caller workflow + +Create `.github/workflows/Process-PSModule.yml` in the module repository: + +```yaml +name: Process-PSModule + +on: + workflow_dispatch: + schedule: + - cron: '0 0 * * *' + pull_request: + branches: + - main + types: + - closed + - opened + - reopened + - synchronize + - labeled + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: write + pull-requests: write + statuses: write + pages: write + id-token: write + +jobs: + Process-PSModule: + uses: PSModule/Process-PSModule/.github/workflows/workflow.yml@v5 + secrets: + APIKey: ${{ secrets.APIKey }} +``` + +Every permission in that block is required. See [Workflow inputs](../reference/workflow-inputs.md) for what each one is +used for, and [Calling the workflow](../guides/calling-the-workflow.md) for passing test secrets and variables. + +## 4. Add the settings file + +Create `.github/PSModule.yml`. An empty file is valid — every setting has a default: + +```yaml +Name: null +``` + +See [Settings](../reference/settings.md) for the full contract and +[Configuring the pipeline](../guides/configuring-the-pipeline.md) for worked examples. + +## 5. Configure the documentation site + +Process-PSModule builds documentation with [Zensical](https://zensical.org/) from `.github/zensical.toml`. The template +ships a working file; update the site name and repository links to match the module. + +## Next + +Open a pull request and let the pipeline run — see [Your first release](your-first-release.md). diff --git a/docs/content/Modules/Process-PSModule/get-started/your-first-release.md b/docs/content/Modules/Process-PSModule/get-started/your-first-release.md new file mode 100644 index 00000000..2122a984 --- /dev/null +++ b/docs/content/Modules/Process-PSModule/get-started/your-first-release.md @@ -0,0 +1,54 @@ +--- +title: Your first release +description: The pull request flow, version labels, and what happens when a Process-PSModule pull request is merged. +--- + +# Your first release + +Process-PSModule is driven entirely by pull requests. There is no manual publish step, no version file to edit, and no +tag to push by hand. + +## The flow + +1. Clone the repository, create a branch, and make your changes. +2. Push the branch and open a pull request against `main`. +3. The workflow builds the module, runs tests on Windows, Linux, and macOS, lints the repository, and reports back on + the pull request. +4. Apply a version label to declare release intent (see below). Without a label, the change releases as a **patch**. +5. Merge the pull request. The workflow publishes the module to the PowerShell Gallery, creates a GitHub Release and + tag, and deploys the documentation site to GitHub Pages. + +## Version labels + +| Label | Effect | +| --- | --- | +| `major` / `breaking` | Bump `MAJOR`. | +| `minor` / `feature` | Bump `MINOR`. | +| `patch` / `fix` | Bump `PATCH`. This is the default when no label is applied. | +| `Prerelease` | Publish a prerelease version from the pull request, before it is merged. | +| `NoRelease` | Run the pipeline but skip publication. | + +Conflicting labels (for example `major` together with `NoRelease`) are rejected and block the merge. The label names are +configurable — see [Settings](../reference/settings.md). + +For the full model, including prerelease promotion and what a release produces, see +[Versioning and releases](../guides/versioning-and-releases.md). + +## Testing before you merge + +Add the `Prerelease` label to publish a prerelease version from the open pull request. The prerelease is installable +from the PowerShell Gallery but is not promoted as the latest stable version, so it can be validated before the pull +request is merged. When the pull request is closed without merging, the prerelease versions and tags created for it are +cleaned up automatically. + +## When nothing is released + +If a pull request only touches files outside the configured important-file patterns — documentation, CI tweaks, comment +typos — the build, test, and publish stages are skipped and no release is created. A comment on the pull request +explains why. See +[important-file change detection](../guides/calling-the-workflow.md#important-file-change-detection) to change which +paths trigger a release. + +## What runs when + +Not every job runs for every trigger. See the [scenario matrix](../reference/scenario-matrix.md) for the full table. diff --git a/docs/content/Modules/Process-PSModule/usage.md b/docs/content/Modules/Process-PSModule/guides/calling-the-workflow.md similarity index 70% rename from docs/content/Modules/Process-PSModule/usage.md rename to docs/content/Modules/Process-PSModule/guides/calling-the-workflow.md index a0c4f092..b420c742 100644 --- a/docs/content/Modules/Process-PSModule/usage.md +++ b/docs/content/Modules/Process-PSModule/guides/calling-the-workflow.md @@ -1,13 +1,16 @@ --- -title: Usage -description: How to call the Process-PSModule workflow — inputs, secrets, permissions, the scenario matrix, and important-file change detection. +title: Calling the workflow +description: How to call the Process-PSModule reusable workflow — the caller workflow, passing test secrets and variables with TestData, and important-file change detection. --- -# Usage +# Calling the workflow To use the workflow, create a new file in the `.github/workflows` directory of the module repository and add the following content. For documentation site generation, use `zensical.toml` as the active site contract. +For the exact inputs, secrets, and permissions the reusable workflow declares, see +[Workflow inputs](../reference/workflow-inputs.md). +
Workflow suggestion @@ -48,28 +51,12 @@ jobs:
-## Inputs - -| Name | Type | Description | Required | Default | -| ---- | ---- | ----------- | -------- | ------- | -| `SettingsPath` | `string` | The path to the settings file. All workflow configuration is controlled through this settings file. | `false` | `.github/PSModule.yml` | -| `Debug` | `boolean` | Enable debug output. | `false` | `false` | -| `Verbose` | `boolean` | Enable verbose output. | `false` | `false` | -| `Version` | `string` | Specifies the version of the GitHub module to be installed. The value must be an exact version. | `false` | `''` | -| `Prerelease` | `boolean` | Whether to use a prerelease version of the 'GitHub' module. | `false` | `false` | -| `WorkingDirectory` | `string` | The path to the root of the repo. | `false` | `'.'` | -| `ImportantFilePatterns` | `string` | Newline-separated list of regular expression patterns that identify important files. Changes matching these patterns trigger build, test, and publish stages. When set, fully replaces the defaults. | `false` | `^src/\n^README\.md$` | - -## Secrets +## Passing test data The reusable workflow at `.github/workflows/workflow.yml` declares only two workflow-call secrets, which keeps the calling workflow in full control of the credentials that are exposed. -`secrets: inherit` is intentionally not required. - -| Name | Location | Description | Required | -| ---- | -------- | ----------- | -------- | -| `APIKey` | GitHub secrets | The API key for the PowerShell Gallery, used to publish the module. | Yes | -| `TestData` | GitHub secrets | A single-line JSON object with `secrets` and `variables` maps, exposed as environment variables to the module test jobs. Values under `secrets` are masked; values under `variables` are not. | No | +`secrets: inherit` is intentionally not required. `APIKey` publishes to the PowerShell Gallery; `TestData` carries +everything the module's own tests need. ### Breaking change: fixed test secrets use `TestData` @@ -179,48 +166,6 @@ Notes: visible to the calling job. For environment-scoped values, set `environment:` on the calling job and explicitly include those values in `TestData`; they are not exposed automatically. -## Permissions - -The following permissions are needed for the workflow to be able to perform all tasks. - -```yaml -permissions: - contents: write # to checkout the repo and create releases on the repo - pull-requests: write # to write comments to PRs - statuses: write # to update the status of the workflow from linter - pages: write # to deploy to Pages - id-token: write # to verify the Pages deployment originates from an appropriate source -``` - -For more info, see [Deploy GitHub Pages site](https://github.com/marketplace/actions/deploy-github-pages-site). - -## Scenario Matrix - -This table shows when each job runs based on the trigger scenario: - -| Job | Open/Updated PR | Merged PR | Abandoned PR | Manual Run | -| ------------------------- | --------------- | ---------- | ------------ | ---------- | -| **Plan** | ✅ Always | ✅ Always | ✅ Always | ✅ Always | -| **Lint-Repository** | ✅ Yes | ❌ No | ❌ No | ❌ No | -| **Build-Module** | ✅ Yes | ✅ Yes | ❌ No | ✅ Yes | -| **Build-Docs** | ✅ Yes | ✅ Yes | ❌ No | ✅ Yes | -| **Build-Site** | ✅ Yes | ✅ Yes | ❌ No | ✅ Yes | -| **Test-SourceCode** | ✅ Yes | ✅ Yes | ❌ No | ✅ Yes | -| **Lint-SourceCode** | ✅ Yes | ✅ Yes | ❌ No | ✅ Yes | -| **Test-Module** | ✅ Yes | ✅ Yes | ❌ No | ✅ Yes | -| **BeforeAll-ModuleLocal** | ✅ Yes | ✅ Yes | ❌ No | ✅ Yes | -| **Test-ModuleLocal** | ✅ Yes | ✅ Yes | ❌ No | ✅ Yes | -| **AfterAll-ModuleLocal** | ✅ Yes | ✅ Yes | ✅ Yes* | ✅ Yes | -| **Get-TestResults** | ✅ Yes | ✅ Yes | ❌ No | ✅ Yes | -| **Get-CodeCoverage** | ✅ Yes | ✅ Yes | ❌ No | ✅ Yes | -| **Publish-Site** | ❌ No | ✅ Yes | ❌ No | ❌ No | -| **Publish-Module** | ✅ Yes** | ✅ Yes** | ✅ Yes*** | ✅ Yes** | - -- \* Runs for cleanup if tests were started -- \*\* Only when all tests/coverage/build succeed -- \*\*\* Cleans up prerelease versions and tags created for the abandoned PR (when `Publish.Module.AutoCleanup` is - enabled) - ## Important file change detection The workflow automatically detects whether a pull request contains changes to "important" files that should enter the @@ -252,7 +197,7 @@ ImportantFilePatterns: When configured, the provided list fully replaces the defaults. Include the default patterns in your list if you still want them to trigger the build, test, and publish path. -Recursive [module-local test discovery](pipeline-stages.md#module-local-test-discovery) does not change this trigger. +Recursive [module-local test discovery](writing-module-tests.md#test-discovery) does not change this trigger. With the defaults, a test-only change does not run the important-change build, test, and publish stages because `^tests/` is not matched. Add `^tests/` when those changes must exercise the path, plus each settings, workflow, or other automation path whose changes need the same validation. Include only paths that should trigger all three stages. diff --git a/docs/content/Modules/Process-PSModule/guides/configuring-the-pipeline.md b/docs/content/Modules/Process-PSModule/guides/configuring-the-pipeline.md new file mode 100644 index 00000000..b77d4cdf --- /dev/null +++ b/docs/content/Modules/Process-PSModule/guides/configuring-the-pipeline.md @@ -0,0 +1,177 @@ +--- +title: Configuring the pipeline +description: Worked examples for the Process-PSModule settings file — coverage targets, rapid testing, repository linting, and PR-based release notes. +--- + +# Configuring the pipeline + +Everything the workflow does is controlled by a single settings file in the module repository — by default +`.github/PSModule.yml`, which can also be JSON or PSD1. Every setting has a default, so the file only needs to contain +what you want to change. + +This page shows the common changes. For the complete list of settings and their defaults, see +[Settings](../reference/settings.md). + +## Example 1 - Defaults with Code Coverage target + +This example runs all steps and will require that code coverage is 80% before passing. + +```yaml +Test: + CodeCoverage: + PercentTarget: 80 +``` + +## Example 2 - Rapid testing + +This example ends up running Plan, Build-Module and Test-Module (tests from the module repo) on **ubuntu-latest** only. + +```yaml +Test: + SourceCode: + Skip: true + PSModule: + Skip: true + Module: + MacOS: + Skip: true + Windows: + Skip: true + TestResults: + Skip: true + CodeCoverage: + Skip: true +Build: + Docs: + Skip: true +``` + +To skip an individual framework test for one file instead of a whole category, see +[Skipping framework tests](skipping-framework-tests.md). + +## Example 3 - Configuring the Repository Linter + +The workflow uses [super-linter](https://github.com/super-linter/super-linter) to lint your repository code. +The linter runs on pull requests and provides status updates directly in the PR. + +### Disabling the Linter + +You can skip repository linting entirely: + +```yaml +Linter: + Skip: true +``` + +### Configuring Linter Validation Rules + +The workflow supports all environment variables that **super-linter** provides. You can configure these through the `Linter.env` object: + +```yaml +Linter: + env: + # Disable specific validations + VALIDATE_BIOME_FORMAT: false + VALIDATE_BIOME_LINT: false + VALIDATE_GITHUB_ACTIONS_ZIZMOR: false + VALIDATE_JSCPD: false + VALIDATE_JSON_PRETTIER: false + VALIDATE_MARKDOWN_PRETTIER: false + VALIDATE_YAML_PRETTIER: false + + # Or enable only specific validations + VALIDATE_YAML: true + VALIDATE_JSON: true + VALIDATE_MARKDOWN: true +``` + +### Additional Configuration + +Any super-linter environment variable can be set through the `Linter.env` object: + +```yaml +Linter: + env: + LOG_LEVEL: DEBUG + FILTER_REGEX_EXCLUDE: '.*test.*' + VALIDATE_ALL_CODEBASE: false +``` + +### Showing Linter Summary on Success + +By default, the linter only shows a summary when it finds issues. You can enable summary display on successful runs: + +```yaml +Linter: + ShowSummaryOnSuccess: true +``` + +This is useful for reviewing what was checked even when no issues are found. + +**Note:** The `GITHUB_TOKEN` is automatically provided by the workflow to enable status updates in pull requests. + +For a complete list of available environment variables and configuration options, see the +[super-linter environment variables documentation](https://github.com/super-linter/super-linter#environment-variables). + +## Example 4 - Configuring PR-based release notes + +The workflow can automatically generate GitHub release names and notes from your pull request content. +Three parameters control this behavior: + +| Parameter | Description | +| ----------- | ------------- | +| `UsePRTitleAsReleaseName` | Use the PR title as the GitHub release name instead of the version string | +| `UsePRBodyAsReleaseNotes` | Use the PR body as the release notes content | +| `UsePRTitleAsNotesHeading` | Prepend PR title as H1 heading with PR number link before the body | + +These parameters follow specific precedence rules when building release notes: + +1. **Heading + Body** (`UsePRTitleAsNotesHeading: true` + `UsePRBodyAsReleaseNotes: true`): Creates formatted notes with the PR title as an H1 heading followed by the PR body. The output format is `# PR Title (#123)\n\nPR body content`. Both the PR title and body must be present. +1. **Body only** (`UsePRBodyAsReleaseNotes: true`): Uses the PR body as-is for release notes. Takes effect when heading option is disabled or PR title is missing. +1. **Fallback**: When neither option is enabled or required PR content is missing, GitHub's auto-generated release notes are used via `--generate-notes`. + +### Default configuration (recommended) + +The defaults provide rich release notes with the PR title as a heading: + +```yaml +Publish: + Module: + UsePRTitleAsReleaseName: false + UsePRBodyAsReleaseNotes: true + UsePRTitleAsNotesHeading: true +``` + +This produces release notes like: + +```markdown +# 🚀 Add new authentication feature (#42) + +This PR adds OAuth2 support with the following changes: +- Added `Connect-OAuth2` function +- Updated documentation +``` + +### Version-only release names + +If you prefer version numbers as release names but still want PR-based notes: + +```yaml +Publish: + Module: + UsePRTitleAsReleaseName: false + UsePRBodyAsReleaseNotes: true + UsePRTitleAsNotesHeading: false +``` + +### Auto-generated notes + +To use GitHub's auto-generated release notes instead of PR content: + +```yaml +Publish: + Module: + UsePRTitleAsReleaseName: false + UsePRBodyAsReleaseNotes: false + UsePRTitleAsNotesHeading: false +``` diff --git a/docs/content/Modules/Process-PSModule/skipping-framework-tests.md b/docs/content/Modules/Process-PSModule/guides/skipping-framework-tests.md similarity index 72% rename from docs/content/Modules/Process-PSModule/skipping-framework-tests.md rename to docs/content/Modules/Process-PSModule/guides/skipping-framework-tests.md index 8df9b62b..f8955b76 100644 --- a/docs/content/Modules/Process-PSModule/skipping-framework-tests.md +++ b/docs/content/Modules/Process-PSModule/guides/skipping-framework-tests.md @@ -3,7 +3,7 @@ title: Skipping framework tests description: How to skip individual PSModule framework tests on a per-file basis, the available test IDs, and the broader configuration alternatives. --- -# Skipping Individual Framework Tests +# Skipping individual framework tests The PSModule framework tests run automatically as part of the `Test-Module` and `Test-SourceCode` jobs. While you can skip entire test categories using the configuration settings (e.g., `Test.PSModule.Skip`), you can also skip individual framework tests on a per-file basis when needed. @@ -20,33 +20,13 @@ To skip an individual framework test for a specific file, add a special comment The skip comment will cause the framework to skip that specific test for that file only, and will log a warning in the build output with the reason provided. -## Available Framework Tests +## Available framework tests -### SourceCode Tests +Every source-code test ID, its meaning, and an example skip comment are listed in +[Framework test IDs](../reference/framework-test-ids.md#source-code-tests). -These tests run against your source code files in the `src` directory: - -| Test ID | Description | Example Skip Comment | -|---------|-------------|---------------------| -| `NumberOfProcessors` | Enforces use of `[System.Environment]::ProcessorCount` instead of `$env:NUMBER_OF_PROCESSORS` | `#SkipTest:NumberOfProcessors:Legacy code compatibility required` | -| `Verbose` | Ensures code does not pass `-Verbose` to other commands (which would override user preference), unless explicitly disabled with `-Verbose:$false` | `#SkipTest:Verbose:Required for debugging output` | -| `OutNull` | Enforces use of `$null = ...` instead of `... \| Out-Null` for better performance | `#SkipTest:OutNull:Pipeline processing required` | -| `NoTernary` | Prohibits ternary operators for PowerShell 5.1 compatibility (this test is skipped by default in the framework) | `#SkipTest:NoTernary:PowerShell 7+ only module` | -| `LowercaseKeywords` | Ensures all PowerShell keywords are lowercase | `#SkipTest:LowercaseKeywords:Generated code` | -| `FunctionCount` | Ensures each file contains exactly one function | `#SkipTest:FunctionCount:Helper functions included` | -| `FunctionName` | Ensures the filename matches the function name | `#SkipTest:FunctionName:Legacy naming convention` | -| `CmdletBinding` | Requires all functions to have `[CmdletBinding()]` attribute | `#SkipTest:CmdletBinding:Simple helper function` | -| `ParamBlock` | Requires all functions to have a `param()` block | `#SkipTest:ParamBlock:No parameters needed` | -| `FunctionTest` | Ensures all public functions have corresponding tests | `#SkipTest:FunctionTest:Test in development` | - -### Module Tests - -These tests run against the compiled module in the `outputs/module` directory: - -- Module import validation -- Module manifest validation - -Module tests typically don't need to be skipped as they validate the final built module. +[Module tests](../reference/framework-test-ids.md#module-tests) run against the compiled module in the +`outputs/module` directory and typically don't need to be skipped, as they validate the final built module. ## Example Usage @@ -202,4 +182,5 @@ For broader test control, use the configuration file settings: - Skip only source code tests: `Test.SourceCode.Skip: true` - Skip framework tests on specific OS: `Test.PSModule.Windows.Skip: true` -See the [Configuration](configuration.md) section for more details. +See [Settings](../reference/settings.md) for the full list and +[Configuring the pipeline](configuring-the-pipeline.md) for worked examples. diff --git a/docs/content/Modules/Process-PSModule/repository-structure.md b/docs/content/Modules/Process-PSModule/guides/structuring-your-module.md similarity index 91% rename from docs/content/Modules/Process-PSModule/repository-structure.md rename to docs/content/Modules/Process-PSModule/guides/structuring-your-module.md index a187ef34..2f7710dc 100644 --- a/docs/content/Modules/Process-PSModule/repository-structure.md +++ b/docs/content/Modules/Process-PSModule/guides/structuring-your-module.md @@ -1,12 +1,30 @@ --- -title: Repository structure -description: The repository and module source layout Process-PSModule expects, and how to declare module dependencies with #Requires -Modules. +title: Structuring your module +description: The repository and module source layout Process-PSModule expects, what goes where, and how to declare module dependencies with #Requires -Modules. --- -# Repository structure +# Structuring your module Process-PSModule expects repositories to follow the staged layout produced by Template-PSModule. The workflow inspects this structure to decide what to compile, document, and publish. +The goal is a stable repository anatomy so both humans and automation know exactly where to place and find module concerns. + +## What goes where + +| Concern | Location | +| --- | --- | +| Public command surface — the module API | `src/functions/public//` | +| Private implementation — not exported | `src/functions/private//` | +| Public and private classes | `src/classes/` | +| Formatting definitions | `src/formats/` | +| Type extensions | `src/types/` | +| Import-time setup | `src/init/` | +| Scoped variables | `src/variables/private/` and `src/variables/public/` | +| Behavior tests | `tests/` | +| Representative usage | `examples/` | + +## Repository layout + ```plaintext / ├── .github/ # Workflow config, doc/site templates, automation policy @@ -36,7 +54,7 @@ Process-PSModule expects repositories to follow the staged layout produced by Te └── README.md # Repository overview rendered on GitHub and docs landing ``` -The tree shows the [Simple PowerShell test profile](https://msxorg.github.io/docs/Coding-Standards/PowerShell/Testing/#simple), not an exclusive test-file shape. Standard keeps one root-level `tests/.Tests.ps1` file per public function group. Advanced uses recursively discovered subdirectories, and layouts may mix across directories. Process-PSModule defines the exact [per-directory precedence and sibling suppression](pipeline-stages.md#module-local-test-discovery). +The tree shows the [Simple PowerShell test profile](https://msxorg.github.io/docs/Coding-Standards/PowerShell/Testing/#simple), not an exclusive test-file shape. Standard keeps one root-level `tests/.Tests.ps1` file per public function group. Advanced uses recursively discovered subdirectories, and layouts may mix across directories. Process-PSModule defines the exact [per-directory precedence and sibling suppression](writing-module-tests.md#test-discovery). These names describe repository conventions, not settings. `.github/PSModule.yml` does not select a test profile. The optional `tests/BeforeAll.ps1` and `tests/AfterAll.ps1` files are root-only workflow phases and are not discovered recursively. diff --git a/docs/content/Modules/Process-PSModule/module-build-validation.md b/docs/content/Modules/Process-PSModule/guides/validating-before-review.md similarity index 87% rename from docs/content/Modules/Process-PSModule/module-build-validation.md rename to docs/content/Modules/Process-PSModule/guides/validating-before-review.md index f3db03e5..74bc1150 100644 --- a/docs/content/Modules/Process-PSModule/module-build-validation.md +++ b/docs/content/Modules/Process-PSModule/guides/validating-before-review.md @@ -1,9 +1,9 @@ --- -title: Module Build Validation +title: Validating before review description: PSModule-specific validation checks that extend the shared MSXOrg Build/Implement workflow step before a draft pull request is marked ready. --- -# Module Build Validation +# Validating before review Use this page after scaffolding a module change or implementing a function and before you finish self-review or mark a draft pull request ready. It extends the shared MSXOrg [Workflow Build step](https://msxorg.github.io/docs/Ways-of-Working/Workflow/#build) and [Implement guidance](https://msxorg.github.io/docs/Agents/implement/) with the PSModule-specific validation checks that module repositories must pass. @@ -17,8 +17,8 @@ Do not repeat the shared workflow here. Follow the shared branch → draft PR Check: - - the module still follows the right archetype from [Module types](../Module-Types.md) - - the change respects the layout, private-helper boundaries, context rules, and SOLID guidance in [PowerShell module standard](../Standards.md) + - the module still follows the right archetype from [Module types](../../Module-Types.md) + - the change respects the layout, private-helper boundaries, context rules, and SOLID guidance in [PowerShell module standard](../../Standards.md) - the function belongs in this module instead of a different module, a shared helper, or a follow-up issue A human contributor or agent should be able to explain why this change belongs in this module, in this shape, without inventing new local rules. @@ -29,8 +29,8 @@ Do not repeat the shared workflow here. Follow the shared branch → draft PR Check: - - `README.md` still answers the start-page questions and reflects any user-visible behavior, prerequisites, or setup changes from [Repository Standard](../Repository-Standard.md#readme-default) - - the relevant public command-group overview page (`src/functions/public//.md`) exists or is updated when the change affects that group's purpose or usage, per [PowerShell module standard](../Standards.md#repository-layout) + - `README.md` still answers the start-page questions and reflects any user-visible behavior, prerequisites, or setup changes from [Repository Standard](../../Repository-Standard.md#readme-default) + - the relevant public command-group overview page (`src/functions/public//.md`) exists or is updated when the change affects that group's purpose or usage, per [PowerShell module standard](../../Standards.md#repository-layout) - any module-level documentation under `docs/` or other published surfaces is updated when the change adds or changes guidance that should not live only in comment-based help If the change teaches the user something new, confirm that the user can discover it from the published documentation surfaces, not only from the diff. @@ -42,7 +42,7 @@ Do not repeat the shared workflow here. Follow the shared branch → draft PR Check: - public functions live under `src/functions/public//` and private helpers live under `src/functions/private//` - - file placement, grouping, and exported surface match [Module Anatomy](module-anatomy.md) and the layout rules in [PowerShell module standard](../Standards.md#repository-layout) + - file placement, grouping, and exported surface match [Structuring your module](structuring-your-module.md) and the layout rules in [PowerShell module standard](../../Standards.md#repository-layout) - there are no nested helper functions, multi-function files, or naming shortcuts that break the "one declaration per file" rule This step is about shape, not behavior: the goal is that a reader or tool can find the module surface and its helpers exactly where PSModule expects them. @@ -66,7 +66,7 @@ Do not repeat the shared workflow here. Follow the shared branch → draft PR Check: - advanced-function structure, parameter typing and validation, `ShouldProcess`, output behavior, and error handling align with [MSX PowerShell](https://msxorg.github.io/docs/Coding-Standards/PowerShell/) and [MSX PowerShell Functions](https://msxorg.github.io/docs/Coding-Standards/PowerShell/Functions/) - - the code also satisfies the PSModule-specific conventions in [PowerShell module standard](../Standards.md), especially around private helpers, context handling, and repository layout + - the code also satisfies the PSModule-specific conventions in [PowerShell module standard](../../Standards.md), especially around private helpers, context handling, and repository layout - PSScriptAnalyzer warnings are addressed or intentionally justified, but review does not stop there; also look for awkward parameter design, leaky transport details, non-idiomatic output, or code that technically passes lint but is not good PowerShell PSScriptAnalyzer is part of the validation loop, not the whole loop. @@ -87,8 +87,8 @@ Do not repeat the shared workflow here. Follow the shared branch → draft PR - [MSX Workflow Build step](https://msxorg.github.io/docs/Ways-of-Working/Workflow/#build) - [MSX Implement guidance](https://msxorg.github.io/docs/Agents/implement/) -- [PowerShell module standard](../Standards.md) -- [Module types](../Module-Types.md) -- [Module Anatomy](module-anatomy.md) -- [Repository Standard](../Repository-Standard.md) +- [PowerShell module standard](../../Standards.md) +- [Module types](../../Module-Types.md) +- [Structuring your module](structuring-your-module.md) +- [Repository Standard](../../Repository-Standard.md) - [MSX Coding Standards](https://msxorg.github.io/docs/Coding-Standards/) diff --git a/docs/content/Modules/Process-PSModule/guides/versioning-and-releases.md b/docs/content/Modules/Process-PSModule/guides/versioning-and-releases.md new file mode 100644 index 00000000..006349cb --- /dev/null +++ b/docs/content/Modules/Process-PSModule/guides/versioning-and-releases.md @@ -0,0 +1,77 @@ +--- +title: Versioning and releases +description: How Process-PSModule resolves a version from pull-request labels, what a release produces, and how prereleases are published and cleaned up. +--- + +# Versioning and releases + +Process-PSModule orchestrates the module lifecycle through GitHub Actions. Version progression is label-driven in pull +requests and resolved once, in the Plan stage, before anything is built. + +## Flow + +1. Resolve settings and release intent. +2. Build the module artifact from `src/`, stamping the resolved version into the manifest. +3. Run tests and quality checks. +4. Package docs and site artifacts when enabled. +5. Publish the module and release metadata when release conditions are met. + +Test and lint stages run before the publish gates, and publish is blocked when required checks fail. + +## Version labels + +The bump comes from the pull-request label; the next version is computed as `current version + bump`. + +| Label | Effect | +| --- | --- | +| `major` / `breaking` | Breaking change; bump `MAJOR`. | +| `minor` / `feature` | New feature; bump `MINOR`. | +| `patch` / `fix` | Bugfix; bump `PATCH`. Applied by default when no label is present. | +| `Prerelease` | Publish as a prerelease; not promoted to latest. | +| `NoRelease` | Run the pipeline, skip publication. | + +Multiple or conflicting version labels (for example `major` together with `NoRelease`) are rejected and block the merge. + +The label names are configurable through `Publish.Module.MajorLabels`, `MinorLabels`, `PatchLabels`, and +`IgnoreLabels` — see [Settings](../reference/settings.md). + +## Branch types + +- **Main (stable)** — publishes stable releases. A prerelease label publishes a prerelease from `main`. +- **Development** — optional prerelease branch (for example `dev`). Each push publishes a prerelease. +- **Feature branch** — optional feature branch. A prerelease label publishes a prerelease for testing. + +Exactly one branch is authorized to publish stable releases, so consumers always have one unambiguous latest version. + +## Prereleases + +A pull request labelled `Prerelease` publishes a prerelease version (for example `v1.2.3-pr.1.5`) that is installable +but not promoted as latest. When that pull request is merged with a version label, the stable version is computed from +the label and the current version on the release branch. + +When a pull request is closed without merging, the prerelease versions and tags created for it are removed, so +abandoned work leaves no orphaned prereleases. This is controlled by `Publish.Module.AutoCleanup`. + +## What a release produces + +Each publication produces three linked, immutable artifacts: + +- a version on the PowerShell Gallery, published exactly as built with no version mutation, +- a GitHub Release, with the built module attached as a `.zip` asset, +- a git tag. + +Release names and notes can be generated from the pull request — see +[Configuring the pipeline](configuring-the-pipeline.md). + +## Linear versioning + +Only a single linear ancestry of versions is maintained. Old versions are not patched: if a security issue is found on +`2.1.3`, the fix ships on the latest version, not as a new `1.x` release. See +[Principles and practices](../specification/principles-and-practices.md) for the reasoning and for the release-branch +pattern used for larger efforts. + +## Related + +- [Your first release](../get-started/your-first-release.md) — the pull request flow end-to-end. +- [Pipeline stages](../reference/pipeline-stages.md#publish-module) — what the publish job does. +- [Versioning](../../Versioning.md) — the PSModule versioning policy. diff --git a/docs/content/Modules/Process-PSModule/guides/writing-module-tests.md b/docs/content/Modules/Process-PSModule/guides/writing-module-tests.md new file mode 100644 index 00000000..7558ba58 --- /dev/null +++ b/docs/content/Modules/Process-PSModule/guides/writing-module-tests.md @@ -0,0 +1,152 @@ +--- +title: Writing module tests +description: How Process-PSModule discovers module-local Pester tests, the setup and teardown phases, and how to share test infrastructure across the platform matrix. +--- + +# Writing module tests + +Module-local tests are the Pester tests you write for your own module, as opposed to the framework tests that +Process-PSModule enforces on every module. They run in parallel across Windows, Linux, and macOS after the module has +been built and imported. + +## Pester version + +Module test files declare a Pester **6.x** requirement at the top of each `*.Tests.ps1`: + +```powershell +#Requires -Modules @{ ModuleName = 'Pester'; ModuleVersion = '6.0.0'; MaximumVersion = '6.*' } +``` + +This is a convention module authors add, not something the 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. + +## Test discovery + +Simple, Standard, and Advanced are +[documentation profiles](https://msxorg.github.io/docs/Coding-Standards/PowerShell/Testing/#module-test-profiles), not +selectable workflow modes. The same discovery engine handles every profile. `.github/PSModule.yml` has no test-layout +or suite-matrix setting; `Settings.Test.Module.Suites` is computed internally from the repository files. + +Process-PSModule inspects `tests/` recursively. Within each directory it uses the first matching form: + +1. Exactly one `*.Configuration.ps1`. Discovery fails when a directory contains more than one. When selected, sibling `*.Container.ps1` and `*.Tests.ps1` files are not independently selected. +2. Otherwise, one or more `*.Container.ps1`. When selected, sibling `*.Tests.ps1` files are not independently selected. +3. Otherwise, all `*.Tests.ps1`. + +The selected form takes precedence only in that directory. Child directories are still inspected independently, so a repository may mix configurations, containers, and ordinary test files across different directories. + +Every discovered artifact needs a unique prefix before its first dot because that prefix becomes `TestName`. For example, `Users.Unit.Tests.ps1` and `Users.Integration.Tests.ps1` both become `Users`; use distinct prefixes such as `UsersUnit` and `UsersIntegration`. + +Discovery does not affect which changes trigger a release. A test-only change does not enter the build, test, and +publish path unless `^tests/` is added to +[`ImportantFilePatterns`](calling-the-workflow.md#customizing-important-file-patterns). + +## Setup and teardown scripts + +The workflow supports automatic execution of setup and teardown scripts for module tests: + +- `tests/BeforeAll.ps1` and `tests/AfterAll.ps1` are special workflow phase files, not ordinary recursively discovered test entries. +- Each phase is enabled only when its exact file exists at the root of `tests/`. +- If either file is absent, the workflow skips that phase and continues normally. +- Phase detection is **not** recursive. Nested files named `BeforeAll.ps1` or `AfterAll.ps1` do not create workflow phases. +- Both scripts run with the same environment variables as the tests, including anything passed through + [`TestData`](calling-the-workflow.md#passing-test-data). + +### Setup - `BeforeAll.ps1` + +- Place at the exact repository-root path `tests/BeforeAll.ps1`. +- Runs once before all test matrix jobs to prepare the test environment. +- Deploy test infrastructure, download test data, initialize databases, or configure services. + +```powershell +Write-Host "Setting up test environment..." +# Deploy test infrastructure +# Download test data +# Initialize test databases +Write-Host "Test environment ready!" +``` + +### Teardown - `AfterAll.ps1` + +- Place at the exact repository-root path `tests/AfterAll.ps1`. +- Runs once after all test matrix jobs complete to clean up the test environment. +- Remove test resources, clean up databases, stop services, or upload artifacts. + +```powershell +Write-Host "Cleaning up test environment..." +# Remove test resources +# Clean up databases +# Stop services +Write-Host "Cleanup completed!" +``` + +## Sharing test infrastructure + +Tests run in parallel across multiple OS runners. To avoid rate limits or conflicts from excessive resource creation, +provision shared infrastructure once in `BeforeAll.ps1` and tear it down in `AfterAll.ps1`. Individual test files +should consume the shared infrastructure instead of creating their own. + +### Use deterministic naming with `$env:GITHUB_RUN_ID` + +Use `$env:GITHUB_RUN_ID` (stable per workflow run, shared across OS runners) to build deterministic resource names. +This lets test files reference shared resources by name without passing state between jobs. + +```powershell +# BeforeAll.ps1 +$os = $env:RUNNER_OS +$id = $env:GITHUB_RUN_ID +$resourceName = "Test-$os-$id" +``` + +Do **not** use `[guid]::NewGuid()` or `Get-Random` for shared resource names — these produce different values on +each runner and cannot be referenced by other jobs. + +### Clean up stale resources from previous failed runs + +If a previous workflow run failed before teardown completed, stale resources may remain. Start `BeforeAll.ps1` by +removing any resources matching your naming prefix before creating new ones: + +```powershell +# Remove stale resources from previous failed runs +Get-Resources -Filter "Test-$os-*" | Remove-Resource + +# Create fresh shared resources +New-Resource -Name "Test-$os-$id" +``` + +### Tests reference shared resources — they do not create them + +Test files should fetch the shared resource by its deterministic name, not create new resources: + +```powershell +# Inside a test file +BeforeAll { + $os = $env:RUNNER_OS + $id = $env:GITHUB_RUN_ID + $resource = Get-Resource -Name "Test-$os-$id" +} +``` + +Test-specific ephemeral resources (for example, secrets, variables, or temporary items) can still be created and +cleaned up within each test file. Only long-lived or expensive resources should be shared. + +### Naming conventions + +Use a consistent naming scheme so that resources are easy to identify and clean up. A recommended pattern: + +| Resource | Pattern | Example | +|-------------------|---------------------------------------|----------------------------| +| Shared resource | `Test-{OS}-{RunID}` | `Test-Linux-1234` | +| Extra resource | `Test-{OS}-{RunID}-{N}` | `Test-Linux-1234-1` | +| Secret / variable | `{TestName}_{OS}_{RunID}` | `Secrets_Linux_1234` | +| Environment | `{TestName}-{OS}-{RunID}` | `Secrets-Linux-1234` | + +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}`). + +## Related + +- [Pipeline stages](../reference/pipeline-stages.md#test-module) — the jobs that run these tests. +- [Framework test IDs](../reference/framework-test-ids.md) — the tests the framework enforces on every module. +- [Settings](../reference/settings.md) — how to skip test categories or platforms. diff --git a/docs/content/Modules/Process-PSModule/index.md b/docs/content/Modules/Process-PSModule/index.md index 719532a2..e142be31 100644 --- a/docs/content/Modules/Process-PSModule/index.md +++ b/docs/content/Modules/Process-PSModule/index.md @@ -1,22 +1,68 @@ +--- +title: Process-PSModule +description: An end-to-end PowerShell module pipeline that builds, tests, versions, documents, and publishes a module from a single reusable GitHub Actions workflow. +--- + # Process-PSModule -Process-PSModule is the module delivery framework used in PSModule repositories. - -This section documents the Process-PSModule specification, design, configuration, implementation, and module repository practices. - -## In this section - -- [Workflow Overview](workflow-overview.md) -- [Specification](spec.md) -- [Design](design.md) -- [Usage](usage.md) -- [Configuration](configuration.md) -- [Pipeline Stages](pipeline-stages.md) -- [Repository Structure](repository-structure.md) -- [Skipping Framework Tests](skipping-framework-tests.md) -- [Principles and Practices](principles-and-practices.md) -- [Module Anatomy](module-anatomy.md) -- [Module Build Validation](module-build-validation.md) -- [Build, Test, Pack, Publish](build-test-pack-publish.md) -- [Template Quickstart](template-quickstart.md) -- [Module Bootstrap](module-bootstrap.md) +An end-to-end PowerShell module pipeline that automates the entire lifecycle of a module: building from source, running +cross-platform tests, enforcing code quality and coverage, generating documentation, and publishing the versioned module +to the PowerShell Gallery and its documentation site to GitHub Pages. It is the core workflow used across all PowerShell +modules in the [PSModule organization](https://github.com/PSModule), ensuring reliable, automated, and maintainable +delivery of PowerShell projects. + +## How it works + +The workflow is triggered on pull requests to the repository's default branch. When a pull request is opened, closed, +reopened, synchronized (push), or labeled, the workflow runs. Depending on the labels on the pull request, the +[workflow results in different outcomes](reference/scenario-matrix.md). + +Everything is packaged into a single reusable workflow so that a module repository only needs a small caller workflow +and one settings file. A user configures the behaviour by editing `.github/PSModule.yml`. + +![Process diagram](media/Process-PSModule.png) + +## Start here + +New to Process-PSModule? Work through these in order. + +| Page | Description | +| --- | --- | +| [Get started](get-started/index.md) | Create a module repository from the template and get the pipeline running. | +| [Repository setup](get-started/repository-setup.md) | Configure GitHub Pages, the PowerShell Gallery API key, permissions, and the caller workflow. | +| [Your first release](get-started/your-first-release.md) | The pull request flow, version labels, and what happens on merge. | + +## Guides + +Task-oriented deep dives into the pipeline's functionality. + +| Page | Description | +| --- | --- | +| [Calling the workflow](guides/calling-the-workflow.md) | The caller workflow, passing test secrets and variables with `TestData`, and important-file change detection. | +| [Configuring the pipeline](guides/configuring-the-pipeline.md) | Worked examples for coverage targets, rapid testing, linting, and PR-based release notes. | +| [Structuring your module](guides/structuring-your-module.md) | The repository and module source layout the workflow expects, and how to declare dependencies. | +| [Writing module tests](guides/writing-module-tests.md) | Test discovery, setup and teardown phases, and shared test infrastructure. | +| [Skipping framework tests](guides/skipping-framework-tests.md) | Skip individual framework tests on a per-file basis. | +| [Versioning and releases](guides/versioning-and-releases.md) | Label-driven versioning, prereleases, and what a release produces. | +| [Validating before review](guides/validating-before-review.md) | The PSModule validation pass before a draft pull request is marked ready. | + +## Reference + +Look up the exact contract. + +| Page | Description | +| --- | --- | +| [Settings](reference/settings.md) | Every available setting in `.github/PSModule.yml` and the full defaults. | +| [Workflow inputs](reference/workflow-inputs.md) | Inputs, secrets, and permissions of the reusable workflow. | +| [Pipeline stages](reference/pipeline-stages.md) | The job-by-job breakdown, from Plan through Publish Docs. | +| [Scenario matrix](reference/scenario-matrix.md) | Which jobs run for each trigger scenario. | +| [Framework test IDs](reference/framework-test-ids.md) | The framework tests enforced on source code and on the built module. | +| [Dependencies](reference/dependencies.md) | The actions, modules, and services the workflow composes. | + +## Specification + +The requirements and architecture behind the pipeline. Primarily for those maintaining Process-PSModule itself. + +| Page | Description | +| --- | --- | +| [Specification](specification/index.md) | Spec, design, and the principles that guide both. | diff --git a/docs/content/Modules/Process-PSModule/module-anatomy.md b/docs/content/Modules/Process-PSModule/module-anatomy.md deleted file mode 100644 index 2d77edaa..00000000 --- a/docs/content/Modules/Process-PSModule/module-anatomy.md +++ /dev/null @@ -1,29 +0,0 @@ -# Module Anatomy - -This page explains what goes where inside PSModule module repositories. - -## Public command surface - -Public command files belong in `src/functions/public//` and define the module API. - -## Private implementation - -Private helpers belong in `src/functions/private//` and are not exported. - -## Types and format - -- public and private classes under `src/classes/` -- formatting definitions under `src/formats/` -- type extensions under `src/types/` - -## Initialization and shared state - -- import-time setup in `src/init/` -- scoped variables in `src/variables/private/` and `src/variables/public/` - -## Tests and examples - -- behavior tests in `tests/` -- representative usage in `examples/` - -The goal is stable repository anatomy so both humans and automation know exactly where to place and find module concerns. diff --git a/docs/content/Modules/Process-PSModule/pipeline-stages.md b/docs/content/Modules/Process-PSModule/pipeline-stages.md deleted file mode 100644 index c8e5c1eb..00000000 --- a/docs/content/Modules/Process-PSModule/pipeline-stages.md +++ /dev/null @@ -1,297 +0,0 @@ ---- -title: Pipeline stages -description: The job-by-job breakdown of the Process-PSModule workflow, from Plan through Publish Docs. ---- - -# Pipeline stages - -The Process-PSModule workflow composes its work from a set of reusable jobs. Each -one is described below, in the order it runs, with a link to the workflow that -implements it. - -## Plan - -[workflow](https://github.com/PSModule/Process-PSModule/blob/main/.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. - -The user-facing settings file stays in `.github/PSModule.yml`. The workflow enriches that input into an internal runtime -`Settings` object passed between jobs. In this runtime contract, execution decisions are phase-owned (`*.Enabled`), test -suite matrices are computed under each owning test phase, and resolved version metadata is stored under -`Settings.Publish.Module.Resolution`. The `*.Suites` values are workflow outputs, not authorable layout settings. - -### Internal runtime settings contract - -| Runtime path | Meaning | -| --- | --- | -| `Settings.Linter.Repository.Enabled` | Whether repository linting runs. | -| `Settings.Build.Module.Enabled` | Whether module build runs. | -| `Settings.Test.SourceCode.Enabled` | Whether source-code tests run. | -| `Settings.Test.PSModule.Enabled` | Whether framework tests run. | -| `Settings.Test.Module.BeforeAllEnabled` | Whether setup scripts run before module-local tests. | -| `Settings.Test.Module.MainEnabled` | Whether module-local Pester tests run. | -| `Settings.Test.Module.AfterAllEnabled` | Whether teardown scripts run after module-local tests. | -| `Settings.Test.TestResults.Enabled` | Whether test results aggregation runs. | -| `Settings.Test.CodeCoverage.Enabled` | Whether code coverage aggregation/enforcement runs. | -| `Settings.Publish.Module.Enabled` | Whether module publication/release runs. | -| `Settings.Publish.Site.Enabled` | Whether documentation publication runs. | -| `Settings.Test.SourceCode.Suites` | Computed source-code test suite matrix. | -| `Settings.Test.PSModule.Suites` | Computed framework test suite matrix. | -| `Settings.Test.Module.Suites` | Computed module-local test suite matrix. | -| `Settings.Publish.Module.Resolution.Version` | Resolved semantic version used for build and publish. | -| `Settings.Publish.Module.Resolution.Prerelease` | Whether the resolved version is prerelease. | -| `Settings.Publish.Module.Resolution.FullVersion` | Resolved full version string. | -| `Settings.Publish.Module.Resolution.ReleaseType` | Resolved release classification for this run. | -| `Settings.Publish.Module.Resolution.CreateRelease` | Whether this run creates a release. | - -## Lint-Repository - -[workflow](https://github.com/PSModule/Process-PSModule/blob/main/.github/workflows/Lint-Repository.yml) - -## Build module - -[workflow](https://github.com/PSModule/Process-PSModule/blob/main/.github/workflows/Build-Module.yml) - -- Compiles the module source code into a PowerShell module, stamping the version from `Settings.Publish.Module.Resolution.Version` into the manifest. -- Uploads the built artifact. - -## Test source code - -[workflow](https://github.com/PSModule/Process-PSModule/blob/main/.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. - -The [PSModule - SourceCode tests](https://github.com/PSModule/Process-PSModule/blob/main/scripts/tests/SourceCode/PSModule/PSModule.Tests.ps1) verifies the following coding practices that the framework enforces: - -| ID | Category | Description | -|---------------------|---------------------|--------------------------------------------------------------------------------------------| -| NumberOfProcessors | General | Should use `[System.Environment]::ProcessorCount` instead of `$env:NUMBER_OF_PROCESSORS`. | -| Verbose | General | Should not contain `-Verbose` unless it is explicitly disabled with `:$false`. | -| OutNull | General | Should use `$null = ...` instead of piping output to `Out-Null`. | -| NoTernary | General | Should not use ternary operations to maintain compatibility with PowerShell 5.1 and below. | -| LowercaseKeywords | General | All PowerShell keywords should be written in lowercase. | -| FunctionCount | Functions (Generic) | Each script file should contain exactly one function or filter. | -| FunctionName | Functions (Generic) | Script filenames should match the name of the function or filter they contain. | -| CmdletBinding | Functions (Generic) | Functions should include the `[CmdletBinding()]` attribute. | -| 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](https://github.com/PSModule/Process-PSModule/blob/main/.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. - -## Framework test - -[workflow](https://github.com/PSModule/Process-PSModule/blob/main/.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) -- This produces a JSON-based report that is used by [Get-PesterTestResults](#get-test-results) evaluate the results of the tests. -- **Code coverage for framework-generated code**: This step collects code coverage for framework-generated - boilerplate. During the [build step](#build-module), [Build-PSModule](https://github.com/PSModule/Build-PSModule) - injects boilerplate code into the compiled `.psm1` file — including type accelerator registration for public classes - and enums, and the `OnRemove` cleanup hook. The framework tests in - [Test-PSModule](https://github.com/PSModule/Test-PSModule) exercise these code paths and produce coverage artifacts - that are aggregated with coverage from [Test-ModuleLocal](#test-module) in the - [Get code coverage](#get-code-coverage) step. This keeps framework-generated lines from counting against the module - author's coverage report. - -## Test module - -[workflow](https://github.com/PSModule/Process-PSModule/blob/main/.github/workflows/Test-ModuleLocal.yml) - -- Imports and tests the module in parallel (matrix) using module-local Pester tests. -- Discovers module-local tests recursively under `tests/`, applying the [per-directory precedence](#module-local-test-discovery) independently at every level. -- 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 two special workflow phase scripts executed via separate dedicated jobs: - - `tests/BeforeAll.ps1`: Runs once before all module-local test matrix jobs to set up the test environment (e.g., deploy infrastructure, download test data). - - `tests/AfterAll.ps1`: Runs once after all module-local test matrix jobs complete to clean up the test environment (e.g., remove test resources, clean up databases). -- The workflow checks only those exact repository-root paths; phase detection is non-recursive. This is separate from the recursive discovery of ordinary module-local test entries described below; nested files named `BeforeAll.ps1` or `AfterAll.ps1` do not create workflow phases. -- The two phase scripts run with the same environment variables as the tests. -- This produces a JSON-based report that is used by [Get-PesterTestResults](#get-test-results) to evaluate the results of the tests. - -### Module-local test discovery - -Simple, Standard, and Advanced are [documentation profiles](https://msxorg.github.io/docs/Coding-Standards/PowerShell/Testing/#module-test-profiles), not selectable workflow modes. The same discovery engine handles every profile. `.github/PSModule.yml` has no test-layout or suite-matrix setting; `Settings.Test.Module.Suites` is computed internally from the repository files. - -Process-PSModule inspects `tests/` recursively. Within each directory it uses the first matching form: - -1. Exactly one `*.Configuration.ps1`. Discovery fails when a directory contains more than one. When selected, sibling `*.Container.ps1` and `*.Tests.ps1` files are not independently selected. -2. Otherwise, one or more `*.Container.ps1`. When selected, sibling `*.Tests.ps1` files are not independently selected. -3. Otherwise, all `*.Tests.ps1`. - -The selected form takes precedence only in that directory. Child directories are still inspected independently, so a repository may mix configurations, containers, and ordinary test files across different directories. - -Every discovered artifact needs a unique prefix before its first dot because that prefix becomes `TestName`. For example, `Users.Unit.Tests.ps1` and `Users.Integration.Tests.ps1` both become `Users`; use distinct prefixes such as `UsersUnit` and `UsersIntegration`. - -### Setup and Teardown Scripts - -The workflow supports automatic execution of setup and teardown scripts for module tests: - -- `tests/BeforeAll.ps1` and `tests/AfterAll.ps1` are special workflow phase files, not ordinary recursively discovered test entries. -- Each phase is enabled only when its exact file exists at the root of `tests/`. -- If either file is absent, the workflow skips that phase and continues normally. - -#### Setup - `BeforeAll.ps1` - -- Place at the exact repository-root path `tests/BeforeAll.ps1`. -- Runs once before all test matrix jobs to prepare the test environment. -- Deploy test infrastructure, download test data, initialize databases, or configure services. -- Has access to the same environment variables as your tests (secrets, GitHub token, etc.). - -##### Example - `BeforeAll.ps1` - -```powershell -Write-Host "Setting up test environment..." -# Deploy test infrastructure -# Download test data -# Initialize test databases -Write-Host "Test environment ready!" -``` - -#### Teardown - `AfterAll.ps1` - -- Place at the exact repository-root path `tests/AfterAll.ps1`. -- Runs once after all test matrix jobs complete to clean up the test environment. -- Remove test resources, clean up databases, stop services, or upload artifacts. -- Has access to the same environment variables as your tests. - -##### Example - `AfterAll.ps1` - -```powershell -Write-Host "Cleaning up test environment..." -# Remove test resources -# Clean up databases -# Stop services -Write-Host "Cleanup completed!" -``` - -#### Best practices for shared test infrastructure - -Tests run in parallel across multiple OS runners. To avoid rate limits or conflicts from excessive resource creation, -provision shared infrastructure once in `BeforeAll.ps1` and tear it down in `AfterAll.ps1`. Individual test files -should consume the shared infrastructure instead of creating their own. - -##### Use deterministic naming with `$env:GITHUB_RUN_ID` - -Use `$env:GITHUB_RUN_ID` (stable per workflow run, shared across OS runners) to build deterministic resource names. -This lets test files reference shared resources by name without passing state between jobs. - -```powershell -# BeforeAll.ps1 -$os = $env:RUNNER_OS -$id = $env:GITHUB_RUN_ID -$resourceName = "Test-$os-$id" -``` - -Do **not** use `[guid]::NewGuid()` or `Get-Random` for shared resource names — these produce different values on -each runner and cannot be referenced by other jobs. - -##### Clean up stale resources from previous failed runs - -If a previous workflow run failed before teardown completed, stale resources may remain. Start `BeforeAll.ps1` by -removing any resources matching your naming prefix before creating new ones: - -```powershell -# Remove stale resources from previous failed runs -Get-Resources -Filter "Test-$os-*" | Remove-Resource - -# Create fresh shared resources -New-Resource -Name "Test-$os-$id" -``` - -##### Tests reference shared resources — they do not create them - -Test files should fetch the shared resource by its deterministic name, not create new resources: - -```powershell -# Inside a test file -BeforeAll { - $os = $env:RUNNER_OS - $id = $env:GITHUB_RUN_ID - $resource = Get-Resource -Name "Test-$os-$id" -} -``` - -Test-specific ephemeral resources (for example, secrets, variables, or temporary items) can still be created and -cleaned up within each test file. Only long-lived or expensive resources should be shared. - -##### Naming conventions - -Use a consistent naming scheme so that resources are easy to identify and clean up. A recommended pattern: - -| Resource | Pattern | Example | -|-------------------|---------------------------------------|----------------------------| -| Shared resource | `Test-{OS}-{RunID}` | `Test-Linux-1234` | -| Extra resource | `Test-{OS}-{RunID}-{N}` | `Test-Linux-1234-1` | -| Secret / variable | `{TestName}_{OS}_{RunID}` | `Secrets_Linux_1234` | -| Environment | `{TestName}-{OS}-{RunID}` | `Secrets-Linux-1234` | - -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](https://github.com/PSModule/Process-PSModule/blob/main/scripts/tests/Module/PSModule/PSModule.Tests.ps1) verifies the following coding practices that the framework enforces: - -| Name | Description | -| ------ | ----------- | -| Module Manifest exists | Verifies that a module manifest file is present. | -| Module Manifest is valid | Verifies that the module manifest file is valid. | - -## Get test results - -[workflow](https://github.com/PSModule/Process-PSModule/blob/main/.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](https://github.com/PSModule/Process-PSModule/blob/main/.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 - framework-generated lines do not count against the module author's coverage target. -- If the code coverage is below the target, the workflow will fail here. - -## Publish module - -[workflow](https://github.com/PSModule/Process-PSModule/blob/main/.github/workflows/Publish-Module.yml) - -- 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` - setting. - -## Build docs - -[workflow](https://github.com/PSModule/Process-PSModule/blob/main/.github/workflows/Build-Docs.yml) - -- Generates documentation and lints the documentation using: - - [super-linter](https://github.com/super-linter/super-linter). - -## Build site - -[workflow](https://github.com/PSModule/Process-PSModule/blob/main/.github/workflows/Build-Site.yml) - -- Generates a static site using: - - [Zensical](https://zensical.org/). -- Uses `zensical.toml` as the site configuration contract. - -## Publish Docs - -[workflow](https://github.com/PSModule/Process-PSModule/blob/main/.github/workflows/Publish-Docs.yml) diff --git a/docs/content/Modules/Process-PSModule/reference/dependencies.md b/docs/content/Modules/Process-PSModule/reference/dependencies.md new file mode 100644 index 00000000..45de71e7 --- /dev/null +++ b/docs/content/Modules/Process-PSModule/reference/dependencies.md @@ -0,0 +1,26 @@ +--- +title: Dependencies +description: The actions, modules, and services the Process-PSModule workflow composes. +--- + +# Dependencies + +Process-PSModule composes its work from reusable workflows, actions, a container image, PowerShell modules, and Python +packages. Each is versioned independently, and the main workflow pins versions explicitly. + +| Dependency | Role | +| --- | --- | +| [PSModule/Build-PSModule](https://github.com/PSModule/Build-PSModule) | Compiles and versions the module. | +| [PSModule/Test-PSModule](https://github.com/PSModule/Test-PSModule) | Runs framework tests and style validation. | +| [PSModule/Invoke-ScriptAnalyzer](https://github.com/PSModule/Invoke-ScriptAnalyzer) | Runs PSScriptAnalyzer linting. | +| [PSModule/Invoke-Pester](https://github.com/PSModule/Invoke-Pester) | Installs Pester and runs module-local tests. | +| [PSModule/Install-PSModuleHelpers](https://github.com/PSModule/Install-PSModuleHelpers) | Installs shared helper commands, including `Import-TestData`. | +| [Pester](https://pester.dev/) | Test framework for module-local tests. | +| [super-linter](https://github.com/super-linter/super-linter) | Lints the repository and generated documentation. | +| [Zensical](https://zensical.org/) | Generates the documentation site. | +| [GitHub Actions](https://github.com/features/actions) | Workflow engine. | +| PowerShell Gallery API | Publishes module packages. | +| GitHub Pages | Hosts the documentation site. | + +For the full dependency tree, including diagrams and a reference of every transitive dependency, see +[DEPENDENCIES.md](https://github.com/PSModule/Process-PSModule/blob/main/DEPENDENCIES.md). diff --git a/docs/content/Modules/Process-PSModule/reference/framework-test-ids.md b/docs/content/Modules/Process-PSModule/reference/framework-test-ids.md new file mode 100644 index 00000000..4a3cc3d9 --- /dev/null +++ b/docs/content/Modules/Process-PSModule/reference/framework-test-ids.md @@ -0,0 +1,47 @@ +--- +title: Framework test IDs +description: The PSModule framework tests enforced on module source code and on the built module, with the IDs used to skip them per file. +--- + +# Framework test IDs + +The PSModule framework runs a fixed set of tests on every module, separate from the module's own Pester tests. Each +source-code test has an ID that can be used to +[skip it for a single file](../guides/skipping-framework-tests.md). + +## Source-code tests + +Run by the [Test source code](pipeline-stages.md#test-source-code) job against files in `src/`. Implemented in +[PSModule - SourceCode tests](https://github.com/PSModule/Process-PSModule/blob/main/scripts/tests/SourceCode/PSModule/PSModule.Tests.ps1). + +| ID | Category | Description | Example skip comment | +| ---- | ---------- | ------------- | ---------------------- | +| `NumberOfProcessors` | General | Should use `[System.Environment]::ProcessorCount` instead of `$env:NUMBER_OF_PROCESSORS`. | `#SkipTest:NumberOfProcessors:Legacy code compatibility required` | +| `Verbose` | General | Should not pass `-Verbose` to other commands (which would override user preference), unless explicitly disabled with `-Verbose:$false`. | `#SkipTest:Verbose:Required for debugging output` | +| `OutNull` | General | Should use `$null = ...` instead of piping output to `Out-Null`. | `#SkipTest:OutNull:Pipeline processing required` | +| `NoTernary` | General | Should not use ternary operations, to maintain compatibility with PowerShell 5.1 and below. Skipped by default in the framework. | `#SkipTest:NoTernary:PowerShell 7+ only module` | +| `LowercaseKeywords` | General | All PowerShell keywords should be written in lowercase. | `#SkipTest:LowercaseKeywords:Generated code` | +| `FunctionCount` | Functions (Generic) | Each script file should contain exactly one function or filter. | `#SkipTest:FunctionCount:Helper functions included` | +| `FunctionName` | Functions (Generic) | Script filenames should match the name of the function or filter they contain. | `#SkipTest:FunctionName:Legacy naming convention` | +| `CmdletBinding` | Functions (Generic) | Functions should include the `[CmdletBinding()]` attribute. | `#SkipTest:CmdletBinding:Simple helper function` | +| `ParamBlock` | Functions (Generic) | Functions should have a parameter block (`param()`). | `#SkipTest:ParamBlock:No parameters needed` | +| `FunctionTest` | Functions (Public) | All public functions and filters should have corresponding tests. | `#SkipTest:FunctionTest:Test in development` | + +## Module tests + +Run by the [Framework test](pipeline-stages.md#framework-test) job against the compiled module in +`outputs/module`. Implemented in +[PSModule - Module tests](https://github.com/PSModule/Process-PSModule/blob/main/scripts/tests/Module/PSModule/PSModule.Tests.ps1). + +| Name | Description | +| ---- | ----------- | +| Module Manifest exists | Verifies that a module manifest file is present. | +| Module Manifest is valid | Verifies that the module manifest file is valid. | +| Module import validation | Verifies that the built module imports cleanly. | + +Module tests typically don't need to be skipped, as they validate the final built module. + +## Related + +- [Skipping framework tests](../guides/skipping-framework-tests.md) — how to use the IDs above. +- [Settings](settings.md) — how to skip whole test categories or platforms. diff --git a/docs/content/Modules/Process-PSModule/reference/pipeline-stages.md b/docs/content/Modules/Process-PSModule/reference/pipeline-stages.md new file mode 100644 index 00000000..d9a6e547 --- /dev/null +++ b/docs/content/Modules/Process-PSModule/reference/pipeline-stages.md @@ -0,0 +1,160 @@ +--- +title: Pipeline stages +description: The job-by-job breakdown of the Process-PSModule workflow, from Plan through Publish Docs. +--- + +# Pipeline stages + +The Process-PSModule workflow composes its work from a set of reusable jobs. Each +one is described below, in the order it runs, with a link to the workflow that +implements it. + +For which of these jobs run in a given trigger scenario, see the [scenario matrix](scenario-matrix.md). + +## Plan + +[workflow](https://github.com/PSModule/Process-PSModule/blob/main/.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. + +The user-facing settings file stays in `.github/PSModule.yml`. The workflow enriches that input into an internal runtime +`Settings` object passed between jobs. In this runtime contract, execution decisions are phase-owned (`*.Enabled`), test +suite matrices are computed under each owning test phase, and resolved version metadata is stored under +`Settings.Publish.Module.Resolution`. The `*.Suites` values are workflow outputs, not authorable layout settings. + +### Internal runtime settings contract + +| Runtime path | Meaning | +| --- | --- | +| `Settings.Linter.Repository.Enabled` | Whether repository linting runs. | +| `Settings.Build.Module.Enabled` | Whether module build runs. | +| `Settings.Test.SourceCode.Enabled` | Whether source-code tests run. | +| `Settings.Test.PSModule.Enabled` | Whether framework tests run. | +| `Settings.Test.Module.BeforeAllEnabled` | Whether setup scripts run before module-local tests. | +| `Settings.Test.Module.MainEnabled` | Whether module-local Pester tests run. | +| `Settings.Test.Module.AfterAllEnabled` | Whether teardown scripts run after module-local tests. | +| `Settings.Test.TestResults.Enabled` | Whether test results aggregation runs. | +| `Settings.Test.CodeCoverage.Enabled` | Whether code coverage aggregation/enforcement runs. | +| `Settings.Publish.Module.Enabled` | Whether module publication/release runs. | +| `Settings.Publish.Site.Enabled` | Whether documentation publication runs. | +| `Settings.Test.SourceCode.Suites` | Computed source-code test suite matrix. | +| `Settings.Test.PSModule.Suites` | Computed framework test suite matrix. | +| `Settings.Test.Module.Suites` | Computed module-local test suite matrix. | +| `Settings.Publish.Module.Resolution.Version` | Resolved semantic version used for build and publish. | +| `Settings.Publish.Module.Resolution.Prerelease` | Whether the resolved version is prerelease. | +| `Settings.Publish.Module.Resolution.FullVersion` | Resolved full version string. | +| `Settings.Publish.Module.Resolution.ReleaseType` | Resolved release classification for this run. | +| `Settings.Publish.Module.Resolution.CreateRelease` | Whether this run creates a release. | + +## Lint-Repository + +[workflow](https://github.com/PSModule/Process-PSModule/blob/main/.github/workflows/Lint-Repository.yml) + +## Build module + +[workflow](https://github.com/PSModule/Process-PSModule/blob/main/.github/workflows/Build-Module.yml) + +- Compiles the module source code into a PowerShell module, stamping the version from `Settings.Publish.Module.Resolution.Version` into the manifest. +- Uploads the built artifact. + +## Test source code + +[workflow](https://github.com/PSModule/Process-PSModule/blob/main/.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. + +For the coding practices this step enforces, see [framework test IDs](framework-test-ids.md#source-code-tests). + +## Lint source code + +[workflow](https://github.com/PSModule/Process-PSModule/blob/main/.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. + +## Framework test + +[workflow](https://github.com/PSModule/Process-PSModule/blob/main/.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) +- This produces a JSON-based report that is used by [Get-PesterTestResults](#get-test-results) evaluate the results of the tests. +- **Code coverage for framework-generated code**: This step collects code coverage for framework-generated + boilerplate. During the [build step](#build-module), [Build-PSModule](https://github.com/PSModule/Build-PSModule) + injects boilerplate code into the compiled `.psm1` file — including type accelerator registration for public classes + and enums, and the `OnRemove` cleanup hook. The framework tests in + [Test-PSModule](https://github.com/PSModule/Test-PSModule) exercise these code paths and produce coverage artifacts + that are aggregated with coverage from [Test-ModuleLocal](#test-module) in the + [Get code coverage](#get-code-coverage) step. This keeps framework-generated lines from counting against the module + author's coverage report. + +For the checks this step enforces on the built module, see [framework test IDs](framework-test-ids.md#module-tests). + +## Test module + +[workflow](https://github.com/PSModule/Process-PSModule/blob/main/.github/workflows/Test-ModuleLocal.yml) + +- Imports and tests the module in parallel (matrix) using module-local Pester tests. +- Discovers module-local tests recursively under `tests/`, applying a [per-directory precedence](../guides/writing-module-tests.md#test-discovery) independently at every level. +- Supports two special workflow phase scripts executed via separate dedicated jobs: + - `tests/BeforeAll.ps1`: Runs once before all module-local test matrix jobs to set up the test environment. + - `tests/AfterAll.ps1`: Runs once after all module-local test matrix jobs complete to clean up the test environment. +- The workflow checks only those exact repository-root paths; phase detection is non-recursive. +- This produces a JSON-based report that is used by [Get-PesterTestResults](#get-test-results) to evaluate the results of the tests. + +How to write these tests, including the Pester version requirement and shared-infrastructure patterns, is covered in +[Writing module tests](../guides/writing-module-tests.md). + +## Get test results + +[workflow](https://github.com/PSModule/Process-PSModule/blob/main/.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](https://github.com/PSModule/Process-PSModule/blob/main/.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 + framework-generated lines do not count against the module author's coverage target. +- If the code coverage is below the target, the workflow will fail here. + +## Publish module + +[workflow](https://github.com/PSModule/Process-PSModule/blob/main/.github/workflows/Publish-Module.yml) + +- 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` + setting. + +## Build docs + +[workflow](https://github.com/PSModule/Process-PSModule/blob/main/.github/workflows/Build-Docs.yml) + +- Generates documentation and lints the documentation using: + - [super-linter](https://github.com/super-linter/super-linter). + +## Build site + +[workflow](https://github.com/PSModule/Process-PSModule/blob/main/.github/workflows/Build-Site.yml) + +- Generates a static site using: + - [Zensical](https://zensical.org/). +- Uses `zensical.toml` as the site configuration contract. + +## Publish Docs + +[workflow](https://github.com/PSModule/Process-PSModule/blob/main/.github/workflows/Publish-Docs.yml) diff --git a/docs/content/Modules/Process-PSModule/reference/scenario-matrix.md b/docs/content/Modules/Process-PSModule/reference/scenario-matrix.md new file mode 100644 index 00000000..4eb80cc3 --- /dev/null +++ b/docs/content/Modules/Process-PSModule/reference/scenario-matrix.md @@ -0,0 +1,40 @@ +--- +title: Scenario matrix +description: Which Process-PSModule jobs run for each trigger scenario — open pull request, merged pull request, abandoned pull request, and manual run. +--- + +# Scenario matrix + +This table shows when each job runs based on the trigger scenario. It is the single source of truth for job +execution; other pages link here rather than repeating it. + +| Job | Open/Updated PR | Merged PR | Abandoned PR | Manual Run | +| ------------------------- | --------------- | ---------- | ------------ | ---------- | +| **Plan** | ✅ Always | ✅ Always | ✅ Always | ✅ Always | +| **Lint-Repository** | ✅ Yes | ❌ No | ❌ No | ❌ No | +| **Build-Module** | ✅ Yes | ✅ Yes | ❌ No | ✅ Yes | +| **Build-Docs** | ✅ Yes | ✅ Yes | ❌ No | ✅ Yes | +| **Build-Site** | ✅ Yes | ✅ Yes | ❌ No | ✅ Yes | +| **Test-SourceCode** | ✅ Yes | ✅ Yes | ❌ No | ✅ Yes | +| **Lint-SourceCode** | ✅ Yes | ✅ Yes | ❌ No | ✅ Yes | +| **Test-Module** | ✅ Yes | ✅ Yes | ❌ No | ✅ Yes | +| **BeforeAll-ModuleLocal** | ✅ Yes | ✅ Yes | ❌ No | ✅ Yes | +| **Test-ModuleLocal** | ✅ Yes | ✅ Yes | ❌ No | ✅ Yes | +| **AfterAll-ModuleLocal** | ✅ Yes | ✅ Yes | ✅ Yes* | ✅ Yes | +| **Get-TestResults** | ✅ Yes | ✅ Yes | ❌ No | ✅ Yes | +| **Get-CodeCoverage** | ✅ Yes | ✅ Yes | ❌ No | ✅ Yes | +| **Publish-Site** | ❌ No | ✅ Yes | ❌ No | ❌ No | +| **Publish-Module** | ✅ Yes** | ✅ Yes** | ✅ Yes*** | ✅ Yes** | + +- \* Runs for cleanup if tests were started +- \*\* Only when all tests/coverage/build succeed +- \*\*\* Cleans up prerelease versions and tags created for the abandoned PR (when `Publish.Module.AutoCleanup` is + enabled) + +A job that is enabled by this matrix can still be skipped by a setting (for example `Test.Skip`) or because the pull +request changed no [important files](../guides/calling-the-workflow.md#important-file-change-detection). + +## Related + +- [Pipeline stages](pipeline-stages.md) — what each job does. +- [Settings](settings.md) — how to disable individual stages. diff --git a/docs/content/Modules/Process-PSModule/configuration.md b/docs/content/Modules/Process-PSModule/reference/settings.md similarity index 72% rename from docs/content/Modules/Process-PSModule/configuration.md rename to docs/content/Modules/Process-PSModule/reference/settings.md index 86e1b9e1..dbbbe75b 100644 --- a/docs/content/Modules/Process-PSModule/configuration.md +++ b/docs/content/Modules/Process-PSModule/reference/settings.md @@ -1,9 +1,9 @@ --- -title: Configuration -description: The Process-PSModule settings file — every available setting, the full defaults, and worked examples for coverage, rapid testing, linting, and release notes. +title: Settings +description: The Process-PSModule settings file — every available setting in .github/PSModule.yml and the full defaults. --- -# Configuration +# Settings The workflow is configured using a settings file in the module repository. The file can be a `JSON`, `YAML`, or `PSD1` file. By default, it will look for `.github/PSModule.yml`. @@ -11,18 +11,23 @@ The file can be a `JSON`, `YAML`, or `PSD1` file. By default, it will look for ` The settings listed on this page are the user-facing configuration contract in `.github/PSModule.yml`. During the Plan phase, Process-PSModule enriches this input into an internal runtime `Settings` object that downstream workflows consume. Internal runtime paths in workflow docs (for example, `Settings.Publish.Module.Resolution.*`) describe that -enriched inter-workflow contract, not a different authoring format for repository settings files. +enriched inter-workflow contract, not a different authoring format for repository settings files. See +[Pipeline stages](pipeline-stages.md#internal-runtime-settings-contract) for that contract. Simple, Standard, and Advanced test profiles are repository conventions, not settings. `.github/PSModule.yml` has no -layout or suite-matrix selector; Process-PSModule [discovers the files under `tests/` recursively](pipeline-stages.md#module-local-test-discovery) +layout or suite-matrix selector; Process-PSModule +[discovers the files under `tests/` recursively](../guides/writing-module-tests.md#test-discovery) and computes its internal `Settings.Test.Module.Suites` matrix from them. Test discovery and change triggering are separate. The default `ImportantFilePatterns` match only `^src/` and `^README\.md$`, so a test-only change does not enter the important-change build, test, and publish path. Repositories -that need test or automation changes to exercise that path must [add `^tests/` and any relevant settings or workflow -paths](usage.md#customizing-important-file-patterns) while retaining every default they still need. +that need test or automation changes to exercise that path must +[add `^tests/` and any relevant settings or workflow paths](../guides/calling-the-workflow.md#customizing-important-file-patterns) +while retaining every default they still need. -The following settings are available in the settings file: +For worked examples, see [Configuring the pipeline](../guides/configuring-the-pipeline.md). + +## Available settings | Name | Type | Description | Default | | ----------------------------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- | @@ -70,6 +75,8 @@ The following settings are available in the settings file: | `Linter.ShowSummaryOnSuccess` | `Boolean` | Show super-linter summary on success for repository linting | `false` | | `Linter.env` | `Object` | Environment variables for super-linter configuration | `{}` | +## Defaults +
`PSModule.yml` with all defaults @@ -152,164 +159,3 @@ Linter: ```
- -## Example 1 - Defaults with Code Coverage target - -This example runs all steps and will require that code coverage is 80% before passing. - -```yaml -Test: - CodeCoverage: - PercentTarget: 80 -``` - -## Example 2 - Rapid testing - -This example ends up running Plan, Build-Module and Test-Module (tests from the module repo) on **ubuntu-latest** only. - -```yaml -Test: - SourceCode: - Skip: true - PSModule: - Skip: true - Module: - MacOS: - Skip: true - Windows: - Skip: true - TestResults: - Skip: true - CodeCoverage: - Skip: true -Build: - Docs: - Skip: true -``` - -## Example 3 - Configuring the Repository Linter - -The workflow uses [super-linter](https://github.com/super-linter/super-linter) to lint your repository code. -The linter runs on pull requests and provides status updates directly in the PR. - -### Disabling the Linter - -You can skip repository linting entirely: - -```yaml -Linter: - Skip: true -``` - -### Configuring Linter Validation Rules - -The workflow supports all environment variables that **super-linter** provides. You can configure these through the `Linter.env` object: - -```yaml -Linter: - env: - # Disable specific validations - VALIDATE_BIOME_FORMAT: false - VALIDATE_BIOME_LINT: false - VALIDATE_GITHUB_ACTIONS_ZIZMOR: false - VALIDATE_JSCPD: false - VALIDATE_JSON_PRETTIER: false - VALIDATE_MARKDOWN_PRETTIER: false - VALIDATE_YAML_PRETTIER: false - - # Or enable only specific validations - VALIDATE_YAML: true - VALIDATE_JSON: true - VALIDATE_MARKDOWN: true -``` - -### Additional Configuration - -Any super-linter environment variable can be set through the `Linter.env` object: - -```yaml -Linter: - env: - LOG_LEVEL: DEBUG - FILTER_REGEX_EXCLUDE: '.*test.*' - VALIDATE_ALL_CODEBASE: false -``` - -### Showing Linter Summary on Success - -By default, the linter only shows a summary when it finds issues. You can enable summary display on successful runs: - -```yaml -Linter: - ShowSummaryOnSuccess: true -``` - -This is useful for reviewing what was checked even when no issues are found. - -**Note:** The `GITHUB_TOKEN` is automatically provided by the workflow to enable status updates in pull requests. - -For a complete list of available environment variables and configuration options, see the -[super-linter environment variables documentation](https://github.com/super-linter/super-linter#environment-variables). - -## Example 4 - Configuring PR-based release notes - -The workflow can automatically generate GitHub release names and notes from your pull request content. -Three parameters control this behavior: - -| Parameter | Description | -|-----------|-------------| -| `UsePRTitleAsReleaseName` | Use the PR title as the GitHub release name instead of the version string | -| `UsePRBodyAsReleaseNotes` | Use the PR body as the release notes content | -| `UsePRTitleAsNotesHeading` | Prepend PR title as H1 heading with PR number link before the body | - -These parameters follow specific precedence rules when building release notes: - -1. **Heading + Body** (`UsePRTitleAsNotesHeading: true` + `UsePRBodyAsReleaseNotes: true`): Creates formatted notes with the PR title as an H1 heading followed by the PR body. The output format is `# PR Title (#123)\n\nPR body content`. Both the PR title and body must be present. -1. **Body only** (`UsePRBodyAsReleaseNotes: true`): Uses the PR body as-is for release notes. Takes effect when heading option is disabled or PR title is missing. -1. **Fallback**: When neither option is enabled or required PR content is missing, GitHub's auto-generated release notes are used via `--generate-notes`. - -### Default configuration (recommended) - -The defaults provide rich release notes with the PR title as a heading: - -```yaml -Publish: - Module: - UsePRTitleAsReleaseName: false - UsePRBodyAsReleaseNotes: true - UsePRTitleAsNotesHeading: true -``` - -This produces release notes like: - -```markdown -# 🚀 Add new authentication feature (#42) - -This PR adds OAuth2 support with the following changes: -- Added `Connect-OAuth2` function -- Updated documentation -``` - -### Version-only release names - -If you prefer version numbers as release names but still want PR-based notes: - -```yaml -Publish: - Module: - UsePRTitleAsReleaseName: false - UsePRBodyAsReleaseNotes: true - UsePRTitleAsNotesHeading: false -``` - -### Auto-generated notes - -To use GitHub's auto-generated release notes instead of PR content: - -```yaml -Publish: - Module: - UsePRTitleAsReleaseName: false - UsePRBodyAsReleaseNotes: false - UsePRTitleAsNotesHeading: false -``` diff --git a/docs/content/Modules/Process-PSModule/reference/workflow-inputs.md b/docs/content/Modules/Process-PSModule/reference/workflow-inputs.md new file mode 100644 index 00000000..1e433413 --- /dev/null +++ b/docs/content/Modules/Process-PSModule/reference/workflow-inputs.md @@ -0,0 +1,49 @@ +--- +title: Workflow inputs +description: The inputs, secrets, and permissions declared by the Process-PSModule reusable workflow. +--- + +# Workflow inputs + +The reusable workflow lives at `PSModule/Process-PSModule/.github/workflows/workflow.yml`. This page is the exact +interface it exposes to a caller workflow. For how to wire it up, see +[Calling the workflow](../guides/calling-the-workflow.md). + +## Inputs + +| Name | Type | Description | Required | Default | +| ---- | ---- | ----------- | -------- | ------- | +| `SettingsPath` | `string` | The path to the settings file. All workflow configuration is controlled through this settings file. | `false` | `.github/PSModule.yml` | +| `Debug` | `boolean` | Enable debug output. | `false` | `false` | +| `Verbose` | `boolean` | Enable verbose output. | `false` | `false` | +| `Version` | `string` | Specifies the version of the GitHub module to be installed. The value must be an exact version. | `false` | `''` | +| `Prerelease` | `boolean` | Whether to use a prerelease version of the 'GitHub' module. | `false` | `false` | +| `WorkingDirectory` | `string` | The path to the root of the repo. | `false` | `'.'` | +| `ImportantFilePatterns` | `string` | Newline-separated list of regular expression patterns that identify important files. Changes matching these patterns trigger build, test, and publish stages. When set, fully replaces the defaults. | `false` | `^src/\n^README\.md$` | + +## Secrets + +The workflow declares only two workflow-call secrets, which keeps the calling workflow in full control of the +credentials that are exposed. `secrets: inherit` is intentionally not required. + +| Name | Location | Description | Required | +| ---- | -------- | ----------- | -------- | +| `APIKey` | GitHub secrets | The API key for the PowerShell Gallery, used to publish the module. | Yes | +| `TestData` | GitHub secrets | A single-line JSON object with `secrets` and `variables` maps, exposed as environment variables to the module test jobs. Values under `secrets` are masked; values under `variables` are not. | No | + +See [passing test data](../guides/calling-the-workflow.md#passing-test-data) for how to build the `TestData` value. + +## Permissions + +The following permissions are needed for the workflow to be able to perform all tasks. + +```yaml +permissions: + contents: write # to checkout the repo and create releases on the repo + pull-requests: write # to write comments to PRs + statuses: write # to update the status of the workflow from linter + pages: write # to deploy to Pages + id-token: write # to verify the Pages deployment originates from an appropriate source +``` + +For more info, see [Deploy GitHub Pages site](https://github.com/marketplace/actions/deploy-github-pages-site). diff --git a/docs/content/Modules/Process-PSModule/specification/design.md b/docs/content/Modules/Process-PSModule/specification/design.md new file mode 100644 index 00000000..2f17fb13 --- /dev/null +++ b/docs/content/Modules/Process-PSModule/specification/design.md @@ -0,0 +1,111 @@ +--- +title: Design +description: How Process-PSModule delivers the spec — a single reusable GitHub Actions workflow composing sub-workflows, a settings file contract, and the scenario matrix. +--- + +# Process-PSModule — Design + +The behaviour in the [spec](spec.md) is delivered by a **single reusable GitHub Actions workflow** at `PSModule/Process-PSModule/.github/workflows/workflow.yml`. A repository using the workflow provides a caller workflow and a minimal `.github/PSModule.yml` settings file; everything else uses sensible defaults. + +## Workflow architecture + +### Single entry point + +The reusable workflow accepts a caller workflow and minimal caller configuration: a `pull_request`-triggered job that +calls `workflow.yml` and passes the `APIKey` secret. The full caller template is in +[Repository setup](../get-started/repository-setup.md#3-add-the-caller-workflow), and the interface it targets is +documented in [Workflow inputs](../reference/workflow-inputs.md). + +### Composed reusable workflows + +The main workflow composes work across specialized reusable workflows, each owning a pipeline stage: + +- **Plan** — reads the settings file and event context, decides what runs, computes the next version +- **Lint-Repository** — validates repository structure and configuration +- **Build-Module** — compiles the module source and versions the manifest +- **Test-SourceCode** — validates source-code style and standards (PSScriptAnalyzer, framework tests) +- **Lint-SourceCode** — runs static analysis on source +- **Test-Module** — runs framework tests and module-local Pester tests in parallel per platform +- **Get-TestResults** — aggregates test results and enforces pass/fail +- **Get-CodeCoverage** — collects coverage from tests and enforces thresholds +- **Publish-Module** — publishes the module to the PowerShell Gallery +- **Publish-Site** — generates and publishes documentation to GitHub Pages + +Each workflow is reusable so it can be tested and versioned independently, invoked by name in the main orchestration workflow. + +## Settings file contract + +The caller provides `.github/PSModule.yml`. Every key is optional and every setting has a default, so a repository can +start with an effectively empty file and opt out of individual phases as needed. The authorable contract is documented +in [Settings](../reference/settings.md). + +The Plan job reads this settings file, enriches it with computed values (phase enables, test matrices, resolved version, release decision), and passes the enriched settings to downstream jobs as a JSON string in workflow outputs. + +That enriched object is an internal inter-workflow contract, not an authoring format. It is documented in +[Pipeline stages](../reference/pipeline-stages.md#internal-runtime-settings-contract). + +## Scenario matrix + +Release intent comes from pull-request labels and is resolved once, in the Plan job. The label-to-bump mapping, the +handling of conflicting labels, and the branch types that may publish are documented in +[Versioning and releases](../guides/versioning-and-releases.md). + +Tests run on **Windows** (latest), **Linux** (Ubuntu latest), and **macOS** (latest). Failures on any platform block +the build. Each platform runs four suites in parallel: + +- **Source-code tests** — style, naming, structure (PSModule framework) +- **Framework tests** — module structure, common issues (PSModule framework) +- **Module-local tests** — Pester tests written by the module author +- **Linting** — PSScriptAnalyzer rules + +Test results are aggregated into a single pass/fail and reported to the PR. + +Which jobs run for which trigger scenario is defined in the +[scenario matrix](../reference/scenario-matrix.md). + +## Alternatives considered + +### Monolithic workflow vs. composable reusable workflows + +**Chosen: Composable reusable workflows** + +Each stage of the pipeline is a reusable workflow so it can be tested independently, versioned, and reused across the ecosystem. This trades orchestration complexity for testability and clarity. + +**Alternative: Single monolithic workflow** + +All logic in one workflow file. Pros: simpler to read end-to-end. Cons: harder to test, version, and reuse; changes in one stage risk all stages; every module repo copies the full logic. + +### Settings file format + +**Chosen: YAML with runtime enrichment** + +The caller provides a simple YAML file; the Plan job enriches it with computed values and passes the enriched settings to all downstream jobs. Pros: simple, readable, minimal to start. Cons: only the Plan job computes the settings; other jobs consume them. + +**Alternative: JSON in workflow outputs** + +Settings live only as workflow outputs, computed by Plan. Pros: single source of truth. Cons: harder to read and edit; no local file to inspect. + +### Version computation + +**Chosen: PR label + current version** + +The bump comes from the PR label; the next version is computed as `current_version + bump`. Pros: explicit, git-traceable (the label is recorded in the PR). Cons: must be re-computed if a PR is re-run or the base version changes. + +**Alternative: Conventional Commits** + +Parse commit messages for `feat:`, `fix:`, `BREAKING CHANGE:` to infer the bump. Pros: automatic. Cons: less explicit; easy to forget the convention; harder to override. + +## External dependencies + +The workflow composes reusable workflows, actions, PowerShell modules, and external services. Each is versioned +independently; the main workflow pins versions explicitly. The full list is in +[Dependencies](../reference/dependencies.md). + +## Where this connects + +- [Spec](spec.md) — the requirements this design delivers. +- [Pipeline stages](../reference/pipeline-stages.md) — detailed breakdown of each job. +- [Calling the workflow](../guides/calling-the-workflow.md) — how to invoke it. +- [Settings](../reference/settings.md) — the settings file reference. +- [Principles and practices](principles-and-practices.md) — the principles guiding this design. +- [Structuring your module](../guides/structuring-your-module.md) — the repo layout the workflow expects. diff --git a/docs/content/Modules/Process-PSModule/specification/index.md b/docs/content/Modules/Process-PSModule/specification/index.md new file mode 100644 index 00000000..0b90c3a1 --- /dev/null +++ b/docs/content/Modules/Process-PSModule/specification/index.md @@ -0,0 +1,16 @@ +--- +title: Specification +description: The requirements and architecture behind Process-PSModule, for those maintaining the pipeline itself. +--- + +# Specification + +These pages describe **why** Process-PSModule exists, **what** it must guarantee, and **how** those guarantees are +delivered. They are aimed at people maintaining Process-PSModule itself. Module authors normally only need the +[guides](../guides/calling-the-workflow.md) and [reference](../reference/settings.md). + +| Page | Description | +| --- | --- | +| [Spec](spec.md) | Requirements — an end-to-end pipeline guaranteeing build, testing, quality gates, documentation, and versioned publication. | +| [Design](design.md) | How the spec is delivered — a single reusable workflow composing sub-workflows, and the settings contract. | +| [Principles and practices](principles-and-practices.md) | The versioning, branching, and colocation principles behind the design. | diff --git a/docs/content/Modules/Process-PSModule/principles-and-practices.md b/docs/content/Modules/Process-PSModule/specification/principles-and-practices.md similarity index 100% rename from docs/content/Modules/Process-PSModule/principles-and-practices.md rename to docs/content/Modules/Process-PSModule/specification/principles-and-practices.md diff --git a/docs/content/Modules/Process-PSModule/spec.md b/docs/content/Modules/Process-PSModule/specification/spec.md similarity index 96% rename from docs/content/Modules/Process-PSModule/spec.md rename to docs/content/Modules/Process-PSModule/specification/spec.md index bb4230ff..dec61299 100644 --- a/docs/content/Modules/Process-PSModule/spec.md +++ b/docs/content/Modules/Process-PSModule/specification/spec.md @@ -91,7 +91,7 @@ Scenario: Compute the next version from the PR label Given a pull request with the label "Minor" When the PR is merged to main and the current version is v1.2.3 Then the new version is computed as v1.3.0 - + Scenario: Reject ambiguous version labels Given a pull request with both "Major" and "Minor" labels When the merge is attempted @@ -118,7 +118,7 @@ Scenario: Publish a prerelease version When the PR runs the pipeline Then a prerelease version is published (e.g., v1.2.3-pr.1.N) And it is available for testing before the PR is merged - + Scenario: Promote a prerelease to stable Given a prerelease PR that is merged to main with a version label When the PR is merged @@ -146,8 +146,8 @@ Scenario: Handle documentation generation failure ## Where this connects - [Design](design.md) — how these requirements are delivered. -- [Pipeline stages](pipeline-stages.md) — the job-by-job breakdown of the workflow. -- [Usage](usage.md) — how to invoke and configure the workflow. -- [Configuration](configuration.md) — the settings file and its options. +- [Pipeline stages](../reference/pipeline-stages.md) — the job-by-job breakdown of the workflow. +- [Calling the workflow](../guides/calling-the-workflow.md) — how to invoke the workflow. +- [Settings](../reference/settings.md) — the settings file and its options. - [Principles and practices](principles-and-practices.md) — versioning, branching, and development practices. - [Documentation Model](https://msxorg.github.io/docs/Ways-of-Working/Documentation-Model/) — why this spec holds only the why and what. diff --git a/docs/content/Modules/Process-PSModule/template-quickstart.md b/docs/content/Modules/Process-PSModule/template-quickstart.md deleted file mode 100644 index 0a0fad58..00000000 --- a/docs/content/Modules/Process-PSModule/template-quickstart.md +++ /dev/null @@ -1,23 +0,0 @@ -# Template Quickstart - -Start new modules from the PSModule template repository: - -- [Template-PSModule](https://github.com/PSModule/Template-PSModule) - -## Quickstart - -1. Create a new repository from the template. -2. Replace placeholder metadata and remove scaffold sample files. -3. Add your first public command and tests. -4. Validate `.github/PSModule.yml` defaults for your module. -5. Open a draft pull request and run the full pipeline. - -If the module needs several interdependent commands before it is usable at all, see [Module Bootstrap](module-bootstrap.md) instead of shipping them as one command per step. - -## Expected outcomes - -- repository follows Process-PSModule structure -- module can be built and tested in CI -- release strategy is ready when functionality is implemented - -For framework-level practices, refer to [MSX Ways of Working](https://msxorg.github.io/docs/Ways-of-Working/). diff --git a/docs/content/Modules/Process-PSModule/workflow-overview.md b/docs/content/Modules/Process-PSModule/workflow-overview.md deleted file mode 100644 index d47451f6..00000000 --- a/docs/content/Modules/Process-PSModule/workflow-overview.md +++ /dev/null @@ -1,76 +0,0 @@ ---- -title: Process-PSModule -description: The end-to-end PowerShell module pipeline — what it must guarantee and how it is built, alongside reference documentation for configuration and deployment. ---- - -# Process-PSModule - -An end-to-end PowerShell module pipeline that automates the entire lifecycle of a module: building from source, running cross-platform tests, enforcing code quality and coverage, generating documentation, and publishing the versioned module to the PowerShell Gallery and its documentation site to GitHub Pages. It is the core workflow used across all PowerShell modules in the [PSModule organization](https://github.com/PSModule), ensuring reliable, automated, and maintainable delivery of PowerShell projects. - - - -| Page | Description | -| --- | --- | -| [Spec](spec.md) | Requirements for Process-PSModule — an end-to-end PowerShell module pipeline that guarantees build, testing, quality gates, documentation generation, and versioned publication to package and docs registries. | -| [Design](design.md) | How Process-PSModule delivers the spec — a single reusable GitHub Actions workflow composing sub-workflows, a settings file contract, and the scenario matrix. | -| [Pipeline stages](pipeline-stages.md) | The job-by-job breakdown of the Process-PSModule workflow, from Plan through Publish Docs. | -| [Usage](usage.md) | How to call the Process-PSModule workflow — inputs, secrets, permissions, the scenario matrix, and important-file change detection. | -| [Configuration](configuration.md) | The Process-PSModule settings file — every available setting, the full defaults, and worked examples for coverage, rapid testing, linting, and release notes. | -| [Skipping framework tests](skipping-framework-tests.md) | How to skip individual PSModule framework tests on a per-file basis, the available test IDs, and the broader configuration alternatives. | -| [Repository structure](repository-structure.md) | The repository and module source layout Process-PSModule expects, and how to declare module dependencies with #Requires -Modules. | -| [Principles and practices](principles-and-practices.md) | The versioning, branching, and colocation principles behind Process-PSModule, and the development practices it is compatible with. | - - - -## How to get started - -1. [Create a repository from the Template-Module](https://github.com/new?template_name=Template-PSModule&template_owner=PSModule&description=Add%20a%20description%20(required)&name=%3CModule%20name%3E). -2. Configure the repository: - 1. Enable GitHub Pages in the repository settings. Set it to deploy from **GitHub Actions**. - 2. This will create an environment called `github-pages` that GitHub deploys your site to. -
Within the github-pages environment, remove the branch protection for main. - Remove the branch protection on main -
- 3. [Create an API key on the PowerShell Gallery](https://www.powershellgallery.com/account/apikeys). Give it permission to manage the module you - are working on. - 4. Create a new secret called `APIKEY` in the repository and set the API key for the PowerShell Gallery as its value. - 5. If you are planning on creating many modules, you could use a glob pattern for the API key permissions in PowerShell Gallery and store the - secret on the organization. -3. Clone the repo locally, create a branch, make your changes, push the changes, create a PR and let the workflow run. - - Adding a `Prerelease` label to the PR will create a prerelease version of the module. -4. Use `.github/zensical.toml` for site generation. Process-PSModule builds documentation with Zensical from this file. -5. When merging to `main`, the workflow automatically builds, tests, and publishes your module to the PowerShell Gallery and maintains the - documentation on GitHub Pages. By default the process releases a patch version, which you can change by applying labels like `minor` or `major` on - the PR to bump the version accordingly. - -## How it works - -Everything is packaged into this single workflow to simplify full configuration of the workflow via this repository. Simplifying management and -operations across all PowerShell module projects. A user can configure how it works by simply configuring settings using a single file. - -### Workflow overview - -The workflow is designed to be triggered on pull requests to the repository's default branch. -When a pull request is opened, closed, reopened, synchronized (push), or labeled, the workflow will run. -Depending on the labels in the pull requests, the [workflow will result in different outcomes](usage.md#scenario-matrix). - -![Process diagram](media/Process-PSModule.png) - -## Reference - -The spec and design own the what and how. The pages below are reference documentation for those who implement, configure, and operate the workflow. - -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](https://github.com/PSModule/Process-PSModule/blob/main/DEPENDENCIES.md). - - - -| Page | Description | -| --- | --- | -| [Pipeline stages](pipeline-stages.md) | The job-by-job breakdown of the Process-PSModule workflow, from Plan through Publish Docs. | -| [Usage](usage.md) | How to call the Process-PSModule workflow — inputs, secrets, permissions, the scenario matrix, and important-file change detection. | -| [Configuration](configuration.md) | The Process-PSModule settings file — every available setting, the full defaults, and worked examples for coverage, rapid testing, linting, and release notes. | -| [Skipping framework tests](skipping-framework-tests.md) | How to skip individual PSModule framework tests on a per-file basis, the available test IDs, and the broader configuration alternatives. | -| [Repository structure](repository-structure.md) | The repository and module source layout Process-PSModule expects, and how to declare module dependencies with #Requires -Modules. | -| [Principles and practices](principles-and-practices.md) | The versioning, branching, and colocation principles behind Process-PSModule, and the development practices it is compatible with. | - - diff --git a/docs/content/Modules/Standards.md b/docs/content/Modules/Standards.md index 0124b4e7..27c29f29 100644 --- a/docs/content/Modules/Standards.md +++ b/docs/content/Modules/Standards.md @@ -2,7 +2,7 @@ Standards for implementing and reviewing PowerShell modules in the PSModule organization. These rules apply to modules built with the [PSModule framework](https://github.com/PSModule/Process-PSModule). -For general PowerShell coding standards (naming, style, function structure, documentation, readability, error handling), see [PowerShell Standards](../PowerShell/Standard/index.md). This page covers only module-specific conventions. +For general PowerShell coding standards (naming, style, function structure, documentation, readability, error handling), see [MSX PowerShell Standards](https://msxorg.github.io/docs/Coding-Standards/PowerShell/). This page covers only module-specific conventions. ## Supported PowerShell version diff --git a/docs/content/PowerShell/DSC/index.md b/docs/content/PowerShell/DSC/index.md deleted file mode 100644 index 94a6fa51..00000000 --- a/docs/content/PowerShell/DSC/index.md +++ /dev/null @@ -1,8 +0,0 @@ -# PowerShell DSC - -Cross-org infrastructure and PowerShell guidance is maintained in MSXOrg/docs. - -Use: - -- [MSX Coding Standards](https://msxorg.github.io/docs/Coding-Standards/) -- [MSX Capabilities](https://msxorg.github.io/docs/Capabilities/) diff --git a/docs/content/PowerShell/FunctionApps/index.md b/docs/content/PowerShell/FunctionApps/index.md deleted file mode 100644 index 7208158f..00000000 --- a/docs/content/PowerShell/FunctionApps/index.md +++ /dev/null @@ -1,8 +0,0 @@ -# PowerShell Function Apps - -Cross-org Function App guidance is maintained in MSXOrg/docs. - -Use: - -- [MSX Capabilities](https://msxorg.github.io/docs/Capabilities/) -- [MSX Coding Standards](https://msxorg.github.io/docs/Coding-Standards/) diff --git a/docs/content/PowerShell/Scripts/index.md b/docs/content/PowerShell/Scripts/index.md deleted file mode 100644 index a0dbdfe4..00000000 --- a/docs/content/PowerShell/Scripts/index.md +++ /dev/null @@ -1,7 +0,0 @@ -# PowerShell Scripts - -Cross-org PowerShell script standards are maintained in MSXOrg/docs. - -Use: - -- [MSX Coding Standards / PowerShell / Scripts](https://msxorg.github.io/docs/Coding-Standards/PowerShell/Scripts/) diff --git a/docs/content/PowerShell/Standard/index.md b/docs/content/PowerShell/Standard/index.md deleted file mode 100644 index 5607b604..00000000 --- a/docs/content/PowerShell/Standard/index.md +++ /dev/null @@ -1,12 +0,0 @@ -# PowerShell Standards - -Cross-org PowerShell standards are maintained in MSXOrg/docs. - -Use: - -- [MSX Coding Standards / PowerShell](https://msxorg.github.io/docs/Coding-Standards/PowerShell/) - -PSModule-specific module construction guidance remains under: - -- [Modules](../../Modules/index.md) -- [Process-PSModule](../../Modules/Process-PSModule/index.md) diff --git a/docs/content/Solutions/index.md b/docs/content/Solutions/index.md deleted file mode 100644 index 786941ba..00000000 --- a/docs/content/Solutions/index.md +++ /dev/null @@ -1,8 +0,0 @@ -# Solutions - -Reusable solution architecture and system patterns are maintained in MSXOrg/docs. - -Use: - -- [MSX Capabilities](https://msxorg.github.io/docs/Capabilities/) -- [MSX Initiatives](https://msxorg.github.io/docs/Initiatives/) diff --git a/docs/content/Style-Guides/index.md b/docs/content/Style-Guides/index.md deleted file mode 100644 index 44140990..00000000 --- a/docs/content/Style-Guides/index.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -title: Style Guides -description: Coding style guidelines for PSModule repositories. ---- - -# Style Guides - -Style guide content is maintained in MSXOrg/docs. - -Use: - -- [MSX Coding Standards](https://msxorg.github.io/docs/Coding-Standards/) diff --git a/docs/content/index.md b/docs/content/index.md index 9871be2f..6ca954f9 100644 --- a/docs/content/index.md +++ b/docs/content/index.md @@ -39,7 +39,7 @@ This site covers PSModule organization-specific documentation: - [Modules](Modules/index.md): module catalog and module-specific standards - [Process-PSModule](Modules/Process-PSModule/index.md): how modules are structured and built -- [Template onboarding](Modules/Process-PSModule/template-quickstart.md): how to start from the template +- [Template onboarding](Modules/Process-PSModule/get-started/index.md): how to start from the template ## Cross-org guidance diff --git a/docs/zensical.toml b/docs/zensical.toml index 2af42dc6..3ca28f7d 100644 --- a/docs/zensical.toml +++ b/docs/zensical.toml @@ -27,20 +27,35 @@ nav = [ ]}, {"Process-PSModule" = [ "Modules/Process-PSModule/index.md", - {"Workflow Overview" = "Modules/Process-PSModule/workflow-overview.md"}, - {"Specification" = "Modules/Process-PSModule/spec.md"}, - {"Design" = "Modules/Process-PSModule/design.md"}, - {"Usage" = "Modules/Process-PSModule/usage.md"}, - {"Configuration" = "Modules/Process-PSModule/configuration.md"}, - {"Pipeline Stages" = "Modules/Process-PSModule/pipeline-stages.md"}, - {"Repository Structure" = "Modules/Process-PSModule/repository-structure.md"}, - {"Skipping Framework Tests" = "Modules/Process-PSModule/skipping-framework-tests.md"}, - {"Principles and Practices" = "Modules/Process-PSModule/principles-and-practices.md"}, - {"Module Anatomy" = "Modules/Process-PSModule/module-anatomy.md"}, - {"Module Build Validation" = "Modules/Process-PSModule/module-build-validation.md"}, - {"Build, Test, Pack, Publish" = "Modules/Process-PSModule/build-test-pack-publish.md"}, - {"Template Quickstart" = "Modules/Process-PSModule/template-quickstart.md"}, - {"Module Bootstrap" = "Modules/Process-PSModule/module-bootstrap.md"}, + {"Get started" = [ + "Modules/Process-PSModule/get-started/index.md", + {"Repository setup" = "Modules/Process-PSModule/get-started/repository-setup.md"}, + {"Your first release" = "Modules/Process-PSModule/get-started/your-first-release.md"}, + {"Module bootstrap" = "Modules/Process-PSModule/get-started/module-bootstrap.md"}, + ]}, + {"Guides" = [ + {"Calling the workflow" = "Modules/Process-PSModule/guides/calling-the-workflow.md"}, + {"Configuring the pipeline" = "Modules/Process-PSModule/guides/configuring-the-pipeline.md"}, + {"Structuring your module" = "Modules/Process-PSModule/guides/structuring-your-module.md"}, + {"Writing module tests" = "Modules/Process-PSModule/guides/writing-module-tests.md"}, + {"Skipping framework tests" = "Modules/Process-PSModule/guides/skipping-framework-tests.md"}, + {"Versioning and releases" = "Modules/Process-PSModule/guides/versioning-and-releases.md"}, + {"Validating before review" = "Modules/Process-PSModule/guides/validating-before-review.md"}, + ]}, + {"Reference" = [ + {"Settings" = "Modules/Process-PSModule/reference/settings.md"}, + {"Workflow inputs" = "Modules/Process-PSModule/reference/workflow-inputs.md"}, + {"Pipeline stages" = "Modules/Process-PSModule/reference/pipeline-stages.md"}, + {"Scenario matrix" = "Modules/Process-PSModule/reference/scenario-matrix.md"}, + {"Framework test IDs" = "Modules/Process-PSModule/reference/framework-test-ids.md"}, + {"Dependencies" = "Modules/Process-PSModule/reference/dependencies.md"}, + ]}, + {"Specification" = [ + "Modules/Process-PSModule/specification/index.md", + {"Spec" = "Modules/Process-PSModule/specification/spec.md"}, + {"Design" = "Modules/Process-PSModule/specification/design.md"}, + {"Principles and practices" = "Modules/Process-PSModule/specification/principles-and-practices.md"}, + ]}, ]}, ]}, {"Dictionary" = [