diff --git a/README.md b/README.md index 6ba8395b..5e295557 100644 --- a/README.md +++ b/README.md @@ -1,1177 +1,11 @@ # Process-PSModule -Process-PSModule is the corner-stone of the PSModule framework. It is an end-to-end GitHub Actions workflow that automates the entire lifecycle of a -PowerShell module. The workflow builds the PowerShell module, runs cross-platform tests, enforces code quality and coverage requirements, generates -documentation, and publishes 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. +Process-PSModule is the corner-stone of the PSModule framework — an end-to-end GitHub Actions workflow that builds, tests, versions, documents, and publishes PowerShell modules to the PowerShell Gallery. -## How to get started +## Documentation -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. 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. +The full documentation lives on the MSX / Docs site: -## How it works +📖 **[Process-PSModule documentation](https://msxorg.github.io/docs/Frameworks/Process-PSModule/)** -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](#scenario-matrix). - -![Process diagram](./media/Process-PSModule.png) - -- [Process-PSModule](#process-psmodule) - - [How to get started](#how-to-get-started) - - [How it works](#how-it-works) - - [Workflow overview](#workflow-overview) - - [Dependency tree](#dependency-tree) - - [Plan](#plan) - - [Lint-Repository](#lint-repository) - - [Build module](#build-module) - - [Test source code](#test-source-code) - - [Lint source code](#lint-source-code) - - [Framework test](#framework-test) - - [Test module](#test-module) - - [Setup and Teardown Scripts](#setup-and-teardown-scripts) - - [Setup - `BeforeAll.ps1`](#setup---beforeallps1) - - [Example - `BeforeAll.ps1`](#example---beforeallps1) - - [Teardown - `AfterAll.ps1`](#teardown---afterallps1) - - [Example - `AfterAll.ps1`](#example---afterallps1) - - [Best practices for shared test infrastructure](#best-practices-for-shared-test-infrastructure) - - [Use deterministic naming with `$env:GITHUB_RUN_ID`](#use-deterministic-naming-with-envgithub_run_id) - - [Clean up stale resources from previous failed runs](#clean-up-stale-resources-from-previous-failed-runs) - - [Tests reference shared resources — they do not create them](#tests-reference-shared-resources--they-do-not-create-them) - - [Naming conventions](#naming-conventions) - - [Module tests](#module-tests) - - [Get test results](#get-test-results) - - [Get code coverage](#get-code-coverage) - - [Publish module](#publish-module) - - [Build docs](#build-docs) - - [Build site](#build-site) - - [Publish Docs](#publish-docs) - - [Usage](#usage) - - [Inputs](#inputs) - - [Secrets](#secrets) - - [Permissions](#permissions) - - [Scenario Matrix](#scenario-matrix) - - [Important file change detection](#important-file-change-detection) - - [Files that trigger releases](#files-that-trigger-releases) - - [Customizing important file patterns](#customizing-important-file-patterns) - - [Behavior when no important files are changed](#behavior-when-no-important-files-are-changed) - - [Configuration](#configuration) - - [Example 1 - Defaults with Code Coverage target](#example-1---defaults-with-code-coverage-target) - - [Example 2 - Rapid testing](#example-2---rapid-testing) - - [Example 3 - Configuring the Repository Linter](#example-3---configuring-the-repository-linter) - - [Disabling the Linter](#disabling-the-linter) - - [Configuring Linter Validation Rules](#configuring-linter-validation-rules) - - [Additional Configuration](#additional-configuration) - - [Showing Linter Summary on Success](#showing-linter-summary-on-success) - - [Example 4 - Configuring PR-based release notes](#example-4---configuring-pr-based-release-notes) - - [Default configuration (recommended)](#default-configuration-recommended) - - [Version-only release names](#version-only-release-names) - - [Auto-generated notes](#auto-generated-notes) - - [Skipping Individual Framework Tests](#skipping-individual-framework-tests) - - [How to Skip Tests](#how-to-skip-tests) - - [Available Framework Tests](#available-framework-tests) - - [SourceCode Tests](#sourcecode-tests) - - [Module Tests](#module-tests-1) - - [Example Usage](#example-usage) - - [Best Practices](#best-practices) - - [Related Configuration](#related-configuration) - - [Repository structure](#repository-structure) - - [Module source code structure](#module-source-code-structure) - - [Declaring module dependencies](#declaring-module-dependencies) - - [Principles and practices](#principles-and-practices) - - [Linear versioning](#linear-versioning) - - [Release and feature branches](#release-and-feature-branches) - - [Colocation of concerns](#colocation-of-concerns) - - [Compatibility](#compatibility) - -### Dependency tree - -Process-PSModule composes its work from reusable workflows, actions, a container image, PowerShell modules, and Python packages. For the full -dependency tree, including diagrams and a reference of every dependency, see [DEPENDENCIES.md](./DEPENDENCIES.md). - -### Plan - -[workflow](./.github/workflows/Plan.yml) - -The Plan job is the single decision point of the workflow. It reads the settings file (`.github/PSModule.yml`), -collects event context from GitHub, and decides what should happen in the rest of the process. Using that -situational awareness, it calculates the next module version. All decisions are captured in a single `Settings` -object — including version data under `Settings.Module` — that every downstream job receives. - -### Lint-Repository - -[workflow](./.github/workflows/Lint-Repository.yml) - -### Build module - -[workflow](./.github/workflows/Build-Module.yml) - -- Compiles the module source code into a PowerShell module, stamping the version from `Settings.Module` into the manifest. -- Uploads the built artifact. - -### Test source code - -[workflow](./.github/workflows/Test-SourceCode.yml) - -- Tests the source code in parallel (matrix) using: - - [PSModule framework settings for style and standards for source code](https://github.com/PSModule/Test-PSModule?tab=readme-ov-file#sourcecode-tests) -- This produces a JSON-based report that is used by [Get-PesterTestResults](#get-test-results) evaluate the results of the tests. - -The [PSModule - SourceCode tests](./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](./.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](./.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](./.github/workflows/Test-ModuleLocal.yml) - -- Imports and tests the module in parallel (matrix) using Pester tests from the module repository. -- Module test files declare a Pester **6.x** requirement via `#Requires -Modules @{ ModuleName = 'Pester'; ModuleVersion = '6.0.0'; MaximumVersion = '6.*' }` — a convention module authors add to each `*.Tests.ps1`, not something this pipeline injects. The [Invoke-Pester](https://github.com/PSModule/Invoke-Pester) action installs a matching `6.x`, so minor and patch updates flow in automatically while a new major stays a deliberate, reviewed change. -- Supports setup and teardown scripts executed via separate dedicated jobs: - - `BeforeAll`: Runs once before all test matrix jobs to set up the test environment (e.g., deploy infrastructure, download test data). - - `AfterAll`: Runs once after all test matrix jobs complete to clean up the test environment (e.g., remove test resources, clean up databases). -- Setup/teardown scripts are automatically detected in test directories and executed with the same environment variables as the tests. -- This produces a JSON-based report that is used by [Get-PesterTestResults](#get-test-results) evaluate the results of the tests. - -#### Setup and Teardown Scripts - -The workflow supports automatic execution of setup and teardown scripts for module tests: - -- Scripts are automatically detected and executed if present. -- If no scripts are found, the workflow continues normally. - -##### Setup - `BeforeAll.ps1` - -- Place in your test directories (`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 in your test directories (`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](./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](./.github/workflows/Get-TestResults.yml) - -- Gathers the test results from the previous steps and creates a summary of the results. -- If any tests have failed, the workflow will fail here. - -### Get code coverage - -[workflow](./.github/workflows/Get-CodeCoverage.yml) - -- Gathers the code coverage from the previous steps and creates a summary of the results. -- Aggregates coverage from the [Framework test](#framework-test) step (framework-generated boilerplate) and the - [Test module](#test-module) step (module author code). A command executed in either step counts as covered, so - 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](./.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](./.github/workflows/Build-Docs.yml) - -- Generates documentation and lints the documentation using: - - [super-linter](https://github.com/super-linter/super-linter). - -### Build site - -[workflow](./.github/workflows/Build-Site.yml) - -- Generates a static site using: - - [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/). - -### Publish Docs - -[workflow](./.github/workflows/Publish-Docs.yml) - -## Usage - -To use the workflow, create a new file in the `.github/workflows` directory of the module repository and add the following content. - -
-Workflow suggestion - -```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 }} -``` - -
- -### 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 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 | - -#### Breaking change: fixed test secrets moved to `TestData` - -The reusable workflow no longer declares or accepts the old fixed test-secret inputs: - -- `TEST_APP_ENT_CLIENT_ID` -- `TEST_APP_ENT_PRIVATE_KEY` -- `TEST_APP_ORG_CLIENT_ID` -- `TEST_APP_ORG_PRIVATE_KEY` -- `TEST_USER_ORG_FG_PAT` -- `TEST_USER_USER_FG_PAT` -- `TEST_USER_PAT` - -If a caller passed any of these secrets directly, move them into the `secrets` map inside `TestData`. -The environment variable names used by the tests can stay the same; only the workflow-call interface -changes: - -```yaml -jobs: - Process-PSModule: - uses: PSModule/Process-PSModule/.github/workflows/workflow.yml@v5 - secrets: - APIKey: ${{ secrets.APIKey }} - TestData: >- - { "secrets": { "TEST_USER_PAT": "${{ secrets.TEST_USER_PAT }}", - "TEST_APP_ORG_CLIENT_ID": "${{ secrets.TEST_APP_ORG_CLIENT_ID }}" } } -``` - -#### Passing test data (secrets and variables) to the tests - -A single `TestData` secret lets a module expose any number of caller-defined values to its test jobs -(`BeforeAll-ModuleLocal`, `Test-ModuleLocal` and `AfterAll-ModuleLocal`) without changing the shared -workflow. It is one JSON object with two maps, so everything the tests need is visible in one place: - -```json -{ "secrets": { "NAME": "value" }, "variables": { "NAME": "value" } } -``` - -Values under `secrets` are masked in the logs; values under `variables` are not. Build it in the -calling workflow and pass it through the `secrets:` block (so the whole blob is masked). Reference each -secret directly as `"${{ secrets. }}"` and each variable as `${{ toJSON(vars.) }}`. A -folded `>-` scalar keeps the source readable while producing a single-line value, as long as the JSON -content lines stay at the same indentation level: - -```yaml -jobs: - Process-PSModule: - uses: PSModule/Process-PSModule/.github/workflows/workflow.yml@v5 - secrets: - APIKey: ${{ secrets.APIKey }} - TestData: >- - { "secrets": { "CONFLUENCE_API_TOKEN": "${{ secrets.CONFLUENCE_API_TOKEN }}" }, - "variables": { "CONFLUENCE_SITE": ${{ toJSON(vars.CONFLUENCE_SITE) }}, - "CONFLUENCE_USERNAME": ${{ toJSON(vars.CONFLUENCE_USERNAME) }}, - "CONFLUENCE_SPACE_KEY": ${{ toJSON(vars.CONFLUENCE_SPACE_KEY) }} } } -``` - -Each entry becomes an environment variable in the test jobs, so the module's Pester tests read the -values directly: - -```powershell -$env:CONFLUENCE_API_TOKEN # from the "secrets" map (masked in logs) -$env:CONFLUENCE_SITE # from the "variables" map (not masked) -``` - -Notes: - -- The names are caller-defined; no secret or variable names are hard-coded in the shared workflow. - Names must match `^[A-Za-z_][A-Za-z0-9_]*$` and must not override reserved variables such as `PATH`, - `CI`, `GITHUB_*`, `RUNNER_*` or `ACTIONS_*`. -- The `TestData` validation, masking and environment export logic is shared by the ModuleLocal workflows - through the [`PSModule/Install-PSModuleHelpers`](https://github.com/PSModule/Install-PSModuleHelpers) - action, which installs the `Import-TestData` command each workflow runs to expose the values. -- Reference secrets as `"${{ secrets. }}"` (quoted, directly) rather than - `toJSON(secrets.)`. The direct form keeps CodeQL's *excessive secrets exposure* check happy and - works for single-line secret values. It cannot carry values that contain `"`, `\` or newlines, so - base64-encode a multi-line or special-character secret and decode it in the test (for example - `[Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($env:MY_KEY_B64))`). -- Variables use `toJSON(vars.)` so any characters are JSON-encoded safely; they are never masked. - You can use the same quoted direct form as secrets (`"${{ vars. }}"`) only for simple values - that do not contain `"`, `\` or newlines. -- Provide `TestData` as a single-line value (the folded `>-` block above does this). Avoid a literal - `|` block: GitHub registers every line of a multi-line secret as its own mask, which over-masks - unrelated log output. -- Do not pretty-print `TestData` with nested indentation. YAML preserves more-indented lines inside a - folded scalar, so a fully formatted JSON object can still become a multi-line secret. That makes - GitHub register each line as its own mask, including brace-only lines such as `{`, `}` or `},`, which - can turn unrelated log output into `***`. Keep the compact form above, or keep every JSON content - line at the same indentation level. -- Omit `TestData` entirely when the module needs no secrets or variables. Include only the map you - need (just `secrets`, just `variables`, or both). -- Because `secrets: inherit` is not used, only the values you list are ever exposed. -- Organization, repository and GitHub *Environment* secrets and variables are supported when they are - 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 warrant a new -release. This prevents unnecessary releases when only non-functional files (such as workflow configurations, linter -settings, or test files) are modified. - -#### Files that trigger releases - -By default, the following regular expression patterns identify important files: - -| Pattern | Description | -| :--- | :---------- | -| `^src/` | Module source code | -| `^README\.md$` | Module documentation | - -#### Customizing important file patterns - -To override the default patterns, set `ImportantFilePatterns` in your settings file (`.github/PSModule.yml`): - -```yaml -ImportantFilePatterns: - - '^src/' - - '^README\.md$' - - '^examples/' -``` - -When configured, the provided list fully replaces the defaults. Include the default patterns in your list if you still -want them to trigger releases. - -To disable file-change triggering entirely (so that no file changes ever trigger a release), set an empty list in the -settings file: - -```yaml -ImportantFilePatterns: [] -``` - -You can also pass patterns via the workflow input: - -```yaml -jobs: - Process: - uses: PSModule/Process-PSModule/.github/workflows/workflow.yml@v5 - with: - ImportantFilePatterns: | - ^src/ - ^README\.md$ - ^examples/ -``` - -To disable triggering via the workflow input, pass an explicit empty string: - -```yaml -jobs: - process: - uses: PSModule/Process-PSModule/.github/workflows/workflow.yml@v5 - with: - ImportantFilePatterns: '' -``` - -Note that omitting the `ImportantFilePatterns` key entirely causes the workflow's default patterns (`^src/` and -`^README\.md$`) to be used. The settings file takes priority over the workflow input, so set -`ImportantFilePatterns: []` in `.github/PSModule.yml` to disable triggering regardless of the workflow input. - -Resolution order: settings file → workflow input → workflow input default values. - -#### Behavior when no important files are changed - -When a pull request does not contain changes to important files: - -1. A comment is automatically added to the PR listing the configured patterns and explaining why build/test stages are - skipped -2. `Settings.Module.ReleaseType` is set to `None` (and `Settings.Module.CreateRelease` is `false`) -3. Build, test, and publish stages are skipped -4. The PR can still be merged for non-release changes (documentation updates, CI improvements, etc.) - -This behavior ensures that maintenance PRs (such as updating GitHub Actions versions or fixing typos in comments) -don't create unnecessary releases in the PowerShell Gallery. - -## Configuration - -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`. - -The following settings are available in the settings file: - -| Name | Type | Description | Default | -| ----------------------------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- | -| `Name` | `String` | Name of the module to publish. Defaults to the repository name. | `null` | -| `ImportantFilePatterns` | `Array` | Regular expression patterns that identify important files. Changes matching these patterns trigger build, test, and publish stages. When set, fully replaces the defaults. | `['^src/', '^README\.md$']` | -| `Test.Skip` | `Boolean` | Skip all tests | `false` | -| `Test.Linux.Skip` | `Boolean` | Skip tests on Linux | `false` | -| `Test.MacOS.Skip` | `Boolean` | Skip tests on macOS | `false` | -| `Test.Windows.Skip` | `Boolean` | Skip tests on Windows | `false` | -| `Test.SourceCode.Skip` | `Boolean` | Skip source code tests | `false` | -| `Test.SourceCode.Linux.Skip` | `Boolean` | Skip source code tests on Linux | `false` | -| `Test.SourceCode.MacOS.Skip` | `Boolean` | Skip source code tests on macOS | `false` | -| `Test.SourceCode.Windows.Skip` | `Boolean` | Skip source code tests on Windows | `false` | -| `Test.PSModule.Skip` | `Boolean` | Skip PSModule framework tests | `false` | -| `Test.PSModule.Linux.Skip` | `Boolean` | Skip PSModule framework tests on Linux | `false` | -| `Test.PSModule.MacOS.Skip` | `Boolean` | Skip PSModule framework tests on macOS | `false` | -| `Test.PSModule.Windows.Skip` | `Boolean` | Skip PSModule framework tests on Windows | `false` | -| `Test.Module.Skip` | `Boolean` | Skip module tests | `false` | -| `Test.Module.Linux.Skip` | `Boolean` | Skip module tests on Linux | `false` | -| `Test.Module.MacOS.Skip` | `Boolean` | Skip module tests on macOS | `false` | -| `Test.Module.Windows.Skip` | `Boolean` | Skip module tests on Windows | `false` | -| `Test.TestResults.Skip` | `Boolean` | Skip test result processing | `false` | -| `Test.CodeCoverage.Skip` | `Boolean` | Skip code coverage tests | `false` | -| `Test.CodeCoverage.PercentTarget` | `Integer` | Target code coverage percentage | `0` | -| `Test.CodeCoverage.StepSummaryMode` | `String` | Step summary mode for code coverage reports | `'Missed, Files'` | -| `Build.Skip` | `Boolean` | Skip all build tasks | `false` | -| `Build.Module.Skip` | `Boolean` | Skip module build | `false` | -| `Build.Docs.Skip` | `Boolean` | Skip documentation build | `false` | -| `Build.Docs.ShowSummaryOnSuccess` | `Boolean` | Show super-linter summary on success for documentation linting | `false` | -| `Build.Site.Skip` | `Boolean` | Skip site build | `false` | -| `Publish.Module.Skip` | `Boolean` | Skip module publishing | `false` | -| `Publish.Module.AutoCleanup` | `Boolean` | Automatically clean up old prerelease tags when merging to main or when a PR is abandoned | `true` | -| `Publish.Module.AutoPatching` | `Boolean` | Automatically patch module version | `true` | -| `Publish.Module.IncrementalPrerelease` | `Boolean` | Use incremental prerelease versioning | `true` | -| `Publish.Module.DatePrereleaseFormat` | `String` | Format for date-based prerelease (uses [.NET DateTime format strings](https://learn.microsoft.com/dotnet/standard/base-types/standard-date-and-time-format-strings)) | `''` | -| `Publish.Module.VersionPrefix` | `String` | Prefix for version tags | `'v'` | -| `Publish.Module.MajorLabels` | `String` | Labels indicating a major version bump | `'major, breaking'` | -| `Publish.Module.MinorLabels` | `String` | Labels indicating a minor version bump | `'minor, feature'` | -| `Publish.Module.PatchLabels` | `String` | Labels indicating a patch version bump | `'patch, fix'` | -| `Publish.Module.IgnoreLabels` | `String` | Labels indicating no release | `'NoRelease'` | -| `Publish.Module.UsePRTitleAsReleaseName` | `Boolean` | Use the PR title as the GitHub release name instead of version string | `false` | -| `Publish.Module.UsePRBodyAsReleaseNotes` | `Boolean` | Use the PR body as the release notes content | `true` | -| `Publish.Module.UsePRTitleAsNotesHeading` | `Boolean` | Prepend PR title as H1 heading with PR number link before the body | `true` | -| `Linter.Skip` | `Boolean` | Skip repository linting | `false` | -| `Linter.ShowSummaryOnSuccess` | `Boolean` | Show super-linter summary on success for repository linting | `false` | -| `Linter.env` | `Object` | Environment variables for super-linter configuration | `{}` | - -
-`PSModule.yml` with all defaults - -```yaml -Name: null - -ImportantFilePatterns: - - '^src/' - - '^README\.md$' - -Build: - Skip: false - Module: - Skip: false - Docs: - Skip: false - ShowSummaryOnSuccess: false - Site: - Skip: false - -Test: - Skip: false - Linux: - Skip: false - MacOS: - Skip: false - Windows: - Skip: false - SourceCode: - Skip: false - Linux: - Skip: false - MacOS: - Skip: false - Windows: - Skip: false - PSModule: - Skip: false - Linux: - Skip: false - MacOS: - Skip: false - Windows: - Skip: false - Module: - Skip: false - Linux: - Skip: false - MacOS: - Skip: false - Windows: - Skip: false - TestResults: - Skip: false - CodeCoverage: - Skip: false - PercentTarget: 0 - StepSummaryMode: 'Missed, Files' - -Publish: - Module: - Skip: false - AutoCleanup: true - AutoPatching: true - IncrementalPrerelease: true - DatePrereleaseFormat: '' - VersionPrefix: 'v' - MajorLabels: 'major, breaking' - MinorLabels: 'minor, feature' - PatchLabels: 'patch, fix' - IgnoreLabels: 'NoRelease' - UsePRTitleAsReleaseName: false - UsePRBodyAsReleaseNotes: true - UsePRTitleAsNotesHeading: true - -Linter: - Skip: false - ShowSummaryOnSuccess: false - env: {} -``` - -
- -### 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 -``` - -## 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. - -### How to Skip Tests - -To skip an individual framework test for a specific file, add a special comment at the top of that file: - -```powershell -#SkipTest:: -``` - -- ``: The unique identifier of the test to skip (see list below) -- ``: A brief explanation of why the test is being skipped - -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 - -#### SourceCode 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. - -### Example Usage - -Here's an example of a function file that skips the `FunctionCount` test because it includes helper functions: - -```powershell -#SkipTest:FunctionCount:This file contains helper functions for the main function - -function Get-ComplexData { - <# - .SYNOPSIS - Retrieves complex data using helper functions. - #> - [CmdletBinding()] - param( - [Parameter(Mandatory)] - [string] $Path - ) - - $data = Get-RawData -Path $Path - $processed = Format-ComplexData -Data $data - return $processed -} - -function Get-RawData { - [CmdletBinding()] - param( - [Parameter(Mandatory)] - [string] $Path - ) - # Helper function implementation -} - -function Format-ComplexData { - [CmdletBinding()] - param( - [Parameter(Mandatory)] - $Data - ) - # Helper function implementation -} -``` - -### Best Practices - -- **Use skip comments sparingly**: Framework tests exist to maintain code quality and consistency. Only skip tests when absolutely necessary. -- **Provide clear reasons**: Always include a meaningful explanation in the skip comment to help reviewers understand why the test is being skipped. -- **Consider alternatives**: Before skipping a test, consider whether refactoring the code to comply with the test would be better for long-term maintainability. -- **Document exceptions**: If you skip a test, document the reason in your PR description or code comments. - -### Related Configuration - -For broader test control, use the configuration file settings: - -- Skip all framework tests: `Test.PSModule.Skip: true` -- Skip only source code tests: `Test.SourceCode.Skip: true` -- Skip framework tests on specific OS: `Test.PSModule.Windows.Skip: true` - -See the [Configuration](#configuration) section for more details. - -## Repository structure - -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. - -```plaintext -/ -├── .github/ # Workflow config, doc/site templates, automation policy -│ ├── linters/ # Rule sets applied by shared lint steps -│ │ ├── .markdown-lint.yml # Markdown rules enforced via super-linter -│ │ ├── .powershell-psscriptanalyzer.psd1 # Analyzer profile for test jobs -│ │ └── .textlintrc # Text lint rules surfaced in Build Docs summaries -│ ├── workflows/ # Entry points for the reusable workflow -│ │ └── Process-PSModule.yml # Consumer hook into this workflow bundle -│ ├── CODEOWNERS # Default reviewers enforced by Process-PSModule checks -│ ├── dependabot.yml # Dependency update cadence handled by GitHub -│ ├── mkdocs.yml # MkDocs config consumed during site builds -│ ├── PSModule.yml # Settings parsed to drive matrices -│ └── release.yml # Release automation template invoked on publish -├── examples/ # Samples referenced in generated documentation -│ └── General.ps1 # Example script ingested by Document-PSModule -├── icon/ # Icon assets linked from manifest and documentation -│ └── icon.png # Default module icon (PNG format) -├── src/ # Module source, see "Module source code structure" below -├── tests/ # Pester suites executed during validation -│ ├── AfterAll.ps1 (optional) # Cleanup script for ModuleLocal runs -│ ├── BeforeAll.ps1 (optional) # Setup script for ModuleLocal runs -│ └── .Tests.ps1 # Primary test entry point -├── .gitattributes # Normalizes line endings across platforms -├── .gitignore # Excludes build artifacts from source control -├── LICENSE # License text surfaced in manifest metadata -└── README.md # Repository overview rendered on GitHub and docs landing -``` - -Key expectations: - -- Keep at least one exported function under `src/functions/public/` and corresponding tests in `tests/`. -- Optional folders (`assemblies`, `formats`, `types`, `variables`, and others) are processed automatically when present. -- Markdown files in `src/functions/public` subfolders become documentation pages alongside generated help. -- A group's overview page (`/.md` named after the folder, or `/index.md`) becomes that group's section landing page in the docs navigation. -- The build step compiles `src/` into a root module file and removes the original project layout from the artifact. -- Documentation generation mirrors the `src/functions/public` hierarchy so help content always aligns with source. - -## Module source code structure - -How the module is built. - -```plaintext -├── src/ # Module source compiled and documented by the pipeline -│ ├── assemblies/ # Bundled binaries copied into the build artifact -│ ├── classes/ # Class scripts merged into the root module -│ │ ├── private/ # Internal classes kept out of exports -│ │ │ └── SecretWriter.ps1 # Example internal class implementation -│ │ └── public/ # Public classes exported via type accelerators -│ │ └── Book.ps1 # Example public class documented for consumers -│ ├── data/ # Configuration loaded into `$script:` scope at runtime -│ │ ├── Config.psd1 # Example config surfaced in generated help -│ │ └── Settings.psd1 # Additional configuration consumed on import -│ ├── formats/ # Formatting metadata registered during build -│ │ ├── CultureInfo.Format.ps1xml # Example format included in manifest -│ │ └── Mygciview.Format.ps1xml # Additional format loaded at import -│ ├── functions/ # Function scripts exported by the module -│ │ ├── private/ # Helper functions scoped to the module -│ │ │ ├── Get-InternalPSModule.ps1 # Sample internal helper -│ │ │ └── Set-InternalPSModule.ps1 # Sample internal helper -│ │ └── public/ # Public commands documented and tested -│ │ ├── Category/ # Optional: organize commands into categories -│ │ │ ├── Get-CategoryCommand.ps1 # Command file within category -│ │ │ └── Category.md # Group overview -> section landing page (or index.md) -│ │ ├── Get-PSModuleTest.ps1 # Example command captured by Microsoft.PowerShell.PlatyPS -│ │ ├── New-PSModuleTest.ps1 # Example command exported and tested -│ │ ├── Set-PSModuleTest.ps1 # Example command exported and tested -│ │ └── Test-PSModuleTest.ps1 # Example command exported and tested -│ ├── init/ # Initialization scripts executed during module load -│ │ └── initializer.ps1 # Example init script included in build output -│ ├── modules/ # Nested modules packaged with the compiled output -│ │ └── OtherPSModule.psm1 # Example nested module staged for export -│ ├── scripts/ # Scripts listed in 'ScriptsToProcess' -│ │ └── loader.ps1 # Loader executed when the module imports -│ ├── types/ # Type data merged into the manifest -│ │ ├── DirectoryInfo.Types.ps1xml # Type definition registered on import -│ │ └── FileInfo.Types.ps1xml # Type definition registered on import -│ ├── variables/ # Variable scripts exported by the module -│ │ ├── private/ # Internal variables scoped to the module -│ │ │ └── PrivateVariables.ps1 # Example private variable seed -│ │ └── public/ # Public variables exported and documented -│ │ ├── Moons.ps1 # Example variable surfaced in generated docs -│ │ ├── Planets.ps1 # Example variable surfaced in generated docs -│ │ └── SolarSystems.ps1 # Example variable surfaced in generated docs -│ ├── finally.ps1 # Cleanup script appended to the root module -│ ├── header.ps1 # Optional header injected at the top of the module -│ ├── manifest.psd1 (optional) # Source manifest reused when present -│ └── README.md # Module-level docs ingested by Document-PSModule -``` - -### Declaring module dependencies - -Declare module dependencies using -[`#Requires -Modules`](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_requires) -statements at the top of function files in `src/functions/public/` or `src/functions/private/` that require external modules. -[Build-PSModule](https://github.com/PSModule/Build-PSModule) collects every `#Requires -Modules` declaration across all -source files, de-duplicates the list, and writes it into the `RequiredModules` field of the compiled manifest -automatically. For the full range of supported syntax variants, see the -[about_Requires](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_requires) -documentation. - -> [!IMPORTANT] -> Adding `RequiredModules` to `src/manifest.psd1` is **not** supported for this purpose. Those entries are silently -> ignored by the build and will not appear in the compiled manifest. Use `#Requires -Modules` in function files instead. - -## Principles and practices - -### Linear versioning - -The contribution and release process is based on the idea that a PR is a release, and we only maintain a single linear ancestry of versions, not going -back to patch and update old versions of the modules. This means that if we are on version `2.1.3` of a module and there is a security issue, we only -patch the latest version with a fix, not releasing new versions based on older versions of the module, i.e. not updating the latest 1.x with the -patch. - -### Release and feature branches - -If you need to work forth a bigger release, create a branch representing the release (a release branch) and open a PR towards `main` for this branch. -For each topic or feature to add to the release, open a new branch representing the feature (a feature branch) and open a PR towards the release -branch. Optionally add the `Prerelease` label on the PR for the release branch, to release preview versions before merging and releasing a published -version of the PowerShell module. - -### Colocation of concerns - -Colocate concerns for long-term maintainability. For example, `#Requires -Modules` statements belong in the function files that use them, not in a -central manifest — this makes it immediately visible which functions drive each external dependency, and avoids silent drift between the manifest and -the actual code. Another example is how parameter descriptions are placed as comments in the `param()` block directly above each parameter -declaration, rather than in the comment-based help at the top of the function — this keeps the description next to the code it documents. - -### Compatibility - -The process is compatible with: - -- [Test-Driven Development](https://testdriven.io/test-driven-development/) using [Pester](https://pester.dev) and [PSScriptAnalyzer](https://learn.microsoft.com/powershell/utility-modules/psscriptanalyzer/overview) -- [GitHub Flow specifications](https://docs.github.com/en/get-started/using-github/github-flow) -- [SemVer 2.0.0 specifications](https://semver.org) -- [Continuous Delivery practices](https://en.wikipedia.org/wiki/Continuous_delivery) +It covers getting started, the pipeline stages, usage, configuration, repository structure, and the principles behind the framework. diff --git a/media/Process-PSModule.png b/media/Process-PSModule.png deleted file mode 100644 index d3d1f855..00000000 Binary files a/media/Process-PSModule.png and /dev/null differ diff --git a/media/pagesEnvironment.png b/media/pagesEnvironment.png deleted file mode 100644 index 59f411d0..00000000 Binary files a/media/pagesEnvironment.png and /dev/null differ