diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 858eab7b..588a1c48 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -2,17 +2,18 @@ ## Terminal Commands -When executing terminal commands (using `run_in_terminal` or similar tools): - - Prefer MCP server calls over command-line tools when possible. -- **ALWAYS** send commands into `pwsh -Command` to ensure proper execution. - - These commands must be enclosed in single quotes. - - Escape any single quotes within the command by doubling them (e.g., `It's` becomes `It''s`). - - Use double quotes for string with variables or expressions inside the single-quoted command. +- When running scripts within the [scripts](../.specify/scripts/) folder, just run them directly (shell is default PowerShell). +- For other commands, send them into `pwsh -Command` to ensure proper execution. + +### Quoting in PowerShell + +Proper quoting is essential in PowerShell to prevent parsing errors and ensure correct command execution. + +- **Direct script execution**: Scripts run directly in PowerShell use standard PowerShell quoting rules. Double quotes expand variables and expressions, while single quotes are literal. No additional shell escaping is needed. + +- **Via `pwsh -Command`**: Commands are passed as strings to PowerShell. Enclose the entire command in single quotes to treat it as a literal string. Escape single quotes within the command by doubling them (e.g., `It's` becomes `It''s`). Use double quotes within the command for variable expansion, but ensure the outer single quotes protect the string from shell interpretation. -## Other instructions +For arguments containing single quotes, prefer double-quoting the argument inside the command string. -| Tech | Instruction file | -|------|------------------| -| PowerShell | [pwsh.instructions.md](./instructions/pwsh.instructions.md) | -| Markdown | [md.instructions.md](./instructions/md.instructions.md) | +Example: `pwsh -Command 'Write-Host "I''m Groot"'` diff --git a/.github/prompts/analyze.prompt.md b/.github/prompts/PSModule.analyze.prompt.md similarity index 100% rename from .github/prompts/analyze.prompt.md rename to .github/prompts/PSModule.analyze.prompt.md diff --git a/.github/prompts/clarify.prompt.md b/.github/prompts/PSModule.clarify.prompt.md similarity index 100% rename from .github/prompts/clarify.prompt.md rename to .github/prompts/PSModule.clarify.prompt.md diff --git a/.github/prompts/constitution.prompt.md b/.github/prompts/PSModule.constitution.prompt.md similarity index 100% rename from .github/prompts/constitution.prompt.md rename to .github/prompts/PSModule.constitution.prompt.md diff --git a/.github/prompts/implement.prompt.md b/.github/prompts/PSModule.implement.prompt.md similarity index 100% rename from .github/prompts/implement.prompt.md rename to .github/prompts/PSModule.implement.prompt.md diff --git a/.github/prompts/plan.prompt.md b/.github/prompts/PSModule.plan.prompt.md similarity index 100% rename from .github/prompts/plan.prompt.md rename to .github/prompts/PSModule.plan.prompt.md diff --git a/.github/prompts/pr.prompt.md b/.github/prompts/PSModule.pr.prompt.md similarity index 100% rename from .github/prompts/pr.prompt.md rename to .github/prompts/PSModule.pr.prompt.md diff --git a/.github/prompts/specify.prompt.md b/.github/prompts/PSModule.specify.prompt.md similarity index 100% rename from .github/prompts/specify.prompt.md rename to .github/prompts/PSModule.specify.prompt.md diff --git a/.github/prompts/tasks.prompt.md b/.github/prompts/PSModule.tasks.prompt.md similarity index 100% rename from .github/prompts/tasks.prompt.md rename to .github/prompts/PSModule.tasks.prompt.md diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 85d441e8..10844b6d 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -168,45 +168,6 @@ jobs: Name: ${{ fromJson(needs.Get-Settings.outputs.Settings).Name }} WorkingDirectory: ${{ inputs.WorkingDirectory }} - # Runs on: - # - ✅ Open/Updated PR - Builds documentation for review - # - ✅ Merged PR - Builds documentation for publishing - # - ❌ Abandoned PR - Skips building docs for abandoned changes - # - ✅ Manual run - Builds documentation when manually triggered - Build-Docs: - if: ${{ !(github.event.action == 'closed' && github.event.pull_request.merged != true) && fromJson(needs.Get-Settings.outputs.Settings).Build.Docs.Skip != true }} - needs: - - Get-Settings - - Build-Module - uses: ./.github/workflows/Build-Docs.yml - with: - Name: ${{ fromJson(needs.Get-Settings.outputs.Settings).Name }} - Debug: ${{ inputs.Debug }} - Prerelease: ${{ inputs.Prerelease }} - Verbose: ${{ inputs.Verbose }} - Version: ${{ inputs.Version }} - WorkingDirectory: ${{ inputs.WorkingDirectory }} - ShowSummaryOnSuccess: ${{ fromJson(needs.Get-Settings.outputs.Settings).Build.Docs.ShowSummaryOnSuccess }} - - # Runs on: - # - ✅ Open/Updated PR - Builds site for preview - # - ✅ Merged PR - Builds site for publishing - # - ❌ Abandoned PR - Skips building site for abandoned changes - # - ✅ Manual run - Builds site when manually triggered - Build-Site: - if: ${{ !(github.event.action == 'closed' && github.event.pull_request.merged != true) && fromJson(needs.Get-Settings.outputs.Settings).Build.Site.Skip != true }} - needs: - - Get-Settings - - Build-Docs - uses: ./.github/workflows/Build-Site.yml - with: - Name: ${{ fromJson(needs.Get-Settings.outputs.Settings).Name }} - Debug: ${{ inputs.Debug }} - Prerelease: ${{ inputs.Prerelease }} - Verbose: ${{ inputs.Verbose }} - Version: ${{ inputs.Version }} - WorkingDirectory: ${{ inputs.WorkingDirectory }} - # Runs on: # - ✅ Open/Updated PR - Tests source code changes # - ✅ Merged PR - Tests source code before publishing @@ -453,38 +414,11 @@ jobs: Verbose: ${{ inputs.Verbose }} Version: ${{ inputs.Version }} - # Runs on: - # - ❌ Open/Updated PR - Site not published for PRs in progress - # - ✅ Merged PR - Deploys site to GitHub Pages after successful merge - # - ❌ Abandoned PR - Site not published for abandoned changes - # - ❌ Manual run - Only publishes on merged PRs, not manual runs - Publish-Site: - if: ${{ !(github.event.action == 'closed' && github.event.pull_request.merged != true) && needs.Get-TestResults.result == 'success' && needs.Get-CodeCoverage.result == 'success' && needs.Build-Site.result == 'success' && !cancelled() && github.event_name == 'pull_request' && github.event.pull_request.merged == true }} - needs: - - Get-Settings - - Get-TestResults - - Get-CodeCoverage - - Build-Site - permissions: - pages: write # to deploy to Pages - id-token: write # to verify the deployment originates from an appropriate source - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - runs-on: ubuntu-latest - steps: - - uses: actions/configure-pages@v5 - - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@v4 - # Runs on: # - ✅ Open/Updated PR - Publishes prerelease when all tests/coverage/build succeed # - ✅ Merged PR - Publishes release when all tests/coverage/build succeed # - ✅ Abandoned PR - Publishes cleanup/retraction version # - ✅ Manual run - Publishes when all tests/coverage/build succeed - # Publish-Module: if: | needs.Get-Settings.result == 'success' && !cancelled() && github.event_name == 'pull_request' && ( @@ -534,3 +468,68 @@ jobs: PatchLabels: ${{ fromJson(needs.Get-Settings.outputs.Settings).Publish.Module.PatchLabels }} VersionPrefix: ${{ fromJson(needs.Get-Settings.outputs.Settings).Publish.Module.VersionPrefix }} WorkingDirectory: ${{ inputs.WorkingDirectory }} + + # Runs on: + # - ✅ Open/Updated PR - Builds documentation for review + # - ✅ Merged PR - Builds documentation for publishing + # - ❌ Abandoned PR - Skips building docs for abandoned changes + # - ✅ Manual run - Builds documentation when manually triggered + Build-Docs: + if: ${{ !(github.event.action == 'closed' && github.event.pull_request.merged != true) && fromJson(needs.Get-Settings.outputs.Settings).Build.Docs.Skip != true }} + needs: + - Get-Settings + - Build-Module + uses: ./.github/workflows/Build-Docs.yml + with: + Name: ${{ fromJson(needs.Get-Settings.outputs.Settings).Name }} + Debug: ${{ inputs.Debug }} + Prerelease: ${{ inputs.Prerelease }} + Verbose: ${{ inputs.Verbose }} + Version: ${{ inputs.Version }} + WorkingDirectory: ${{ inputs.WorkingDirectory }} + ShowSummaryOnSuccess: ${{ fromJson(needs.Get-Settings.outputs.Settings).Build.Docs.ShowSummaryOnSuccess }} + + # Runs on: + # - ✅ Open/Updated PR - Builds site for preview + # - ✅ Merged PR - Builds site for publishing + # - ❌ Abandoned PR - Skips building site for abandoned changes + # - ✅ Manual run - Builds site when manually triggered + Build-Site: + if: ${{ !(github.event.action == 'closed' && github.event.pull_request.merged != true) && fromJson(needs.Get-Settings.outputs.Settings).Build.Site.Skip != true }} + needs: + - Get-Settings + - Build-Docs + uses: ./.github/workflows/Build-Site.yml + with: + Name: ${{ fromJson(needs.Get-Settings.outputs.Settings).Name }} + Debug: ${{ inputs.Debug }} + Prerelease: ${{ inputs.Prerelease }} + Verbose: ${{ inputs.Verbose }} + Version: ${{ inputs.Version }} + WorkingDirectory: ${{ inputs.WorkingDirectory }} + + # Runs on: + # - ❌ Open/Updated PR - Site not published for PRs in progress + # - ✅ Merged PR - Deploys site to GitHub Pages after successful merge + # - ❌ Abandoned PR - Site not published for abandoned changes + # - ❌ Manual run - Only publishes on merged PRs, not manual runs + Publish-Site: + if: ${{ !(github.event.action == 'closed' && github.event.pull_request.merged != true) && needs.Get-TestResults.result == 'success' && needs.Get-CodeCoverage.result == 'success' && needs.Build-Site.result == 'success' && !cancelled() && github.event_name == 'pull_request' && github.event.pull_request.merged == true }} + needs: + - Get-Settings + - Get-TestResults + - Get-CodeCoverage + - Build-Site + permissions: + pages: write # to deploy to Pages + id-token: write # to verify the deployment originates from an appropriate source + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + steps: + - uses: actions/configure-pages@v5 + + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.specify/memory/constitution.md b/.specify/memory/constitution.md deleted file mode 100644 index 4bc59ab8..00000000 --- a/.specify/memory/constitution.md +++ /dev/null @@ -1,753 +0,0 @@ -# Process-PSModule Constitution - -## Product Overview - -**Process-PSModule** is a **reusable workflow product** that provides an **opinionated flow and structure** for building PowerShell modules using GitHub Actions. It is NOT a library or toolkit; it is a complete CI/CD workflow framework designed to be consumed by PowerShell module repositories. - -### Product Characteristics - -- **Opinionated Architecture**: Defines a specific workflow execution order and module structure -- **Reusable Workflows**: Consuming repositories call Process-PSModule workflows via `uses:` syntax -- **Configurable via Settings**: Behavior customized through `.github/PSModule.yml` (or JSON/PSD1) in consuming repos -- **Structure Requirements**: Consuming repos MUST follow documented structure in GitHub Actions README files -- **Not for Local Development**: Designed exclusively for GitHub Actions execution environment - -### Consuming Repository Requirements - -Repositories that consume Process-PSModule workflows MUST: -- Follow the module source structure documented in framework actions (see Required Module Structure below) -- Provide configuration file (`.github/PSModule.yml`) with appropriate settings -- Adhere to the opinionated workflow execution order -- Reference Process-PSModule workflows using stable version tags (e.g., `@v4`) -- Review action README documentation for structure and configuration requirements -- Use the [Template-PSModule](https://github.com/PSModule/Template-PSModule) repository as a starting point - -### Required Module Structure - -**Process-PSModule enforces an opinionated module structure.** Consuming repositories MUST organize their PowerShell module following this complete structure: - -#### Complete Repository Structure - -```plaintext -/ # Repository root -├── .github/ # GitHub Actions configuration -│ ├── linters/ # Linter configuration files -│ │ ├── .jscpd.json # Copy/paste detector settings -│ │ ├── .markdown-lint.yml # Markdown linter settings -│ │ ├── .powershell-psscriptanalyzer.psd1 # PSScriptAnalyzer rules -│ │ └── .textlintrc # Text linter settings -│ ├── workflows/ # GitHub Actions workflows -│ │ ├── Linter.yml # Linting workflow (optional) -│ │ ├── Nightly-Run.yml # Scheduled validation (optional) -│ │ └── Process-PSModule.yml # Main workflow (REQUIRED) -│ ├── CODEOWNERS # Code ownership and review assignments -│ ├── dependabot.yml # Dependency update automation -│ ├── mkdocs.yml # Material for MkDocs site configuration -│ ├── PSModule.yml # Process-PSModule settings (YAML/JSON/PSD1 supported) -│ └── release.yml # GitHub release configuration -├── examples/ # Usage examples (optional) -│ └── General.ps1 # Example script -├── icon/ # Module icon (optional, referenced in manifest) -│ └── icon.png # PNG icon file -├── src/ # MODULE SOURCE CODE (REQUIRED) -│ ├── assemblies/ # .NET assemblies (.dll) to load -│ ├── classes/ # PowerShell classes and enums -│ │ ├── private/ # Private (not exported) -│ │ └── public/ # Public (exported) -│ ├── data/ # Configuration data files loaded as private variables (.psd1) -│ │ ├── Config.psd1 # Example configuration file -│ │ └── Settings.psd1 # Example settings file -│ ├── formats/ # Format definition files (.ps1xml) -│ ├── functions/ # The functions for the PowerShell module -│ │ ├── private/ # Private (not exported) -│ │ └── public/ # Public (exported) -│ │ └── / # Optional: Group functions by category -│ │ ├── .md # Optional: Category documentation -│ │ └── Get-*.ps1 # Example: Get commands -│ ├── init/ # Initialization scripts -│ │ └── initializer.ps1 # Example initialization script -│ ├── modules/ # Nested PowerShell modules (.psm1) -│ ├── scripts/ # Script files that are loaded to the users runtime on import (.ps1) -│ │ └── loader.ps1 # Example script file -│ ├── types/ # Type definition files (.ps1xml) -│ ├── variables/ # Variables for the PowerShell module -│ │ ├── private/ # Private (not exported) -│ │ │ └── PrivateVariables.ps1 -│ │ └── public/ # Public (exported) -│ │ ├── Moons.ps1 -│ │ ├── Planets.ps1 -│ │ └── SolarSystems.ps1 -│ ├── finally.ps1 # Code executed at module load end (optional) -│ ├── header.ps1 # Code executed at module load start (optional) -│ ├── manifest.psd1 # PowerShell module manifest (optional, auto-generated if missing) -│ └── README.md # Documentation reference (points to Build-PSModule) -├── tests/ # Module tests (REQUIRED for Test-ModuleLocal) -│ ├── Environments/ # Optional: Test environment configurations -│ │ └── Environment.Tests.ps1 -│ ├── MyTests/ # Optional: Additional test suites -│ │ └── .Tests.ps1 -│ ├── AfterAll.ps1 # Teardown script (optional, runs once after all test matrix jobs) -│ ├── BeforeAll.ps1 # Setup script (optional, runs once before all test matrix jobs) -│ ├── .Tests.ps1 # Module functional tests (Pester) -│ └── Environment.Tests.ps1 # Environment validation tests (optional) -├── .gitattributes # Git line ending configuration -├── .gitignore # Git ignore patterns -├── LICENSE # License file (referenced in manifest) -└── README.md # Module documentation and usage -``` - -#### Module Source Structure Details (`src/` folder) - -The `src/` folder contains the module source code that Build-PSModule compiles into a production-ready module: - -**Required Files/Folders**: - -- At least one `.ps1` file in `functions/public/` to export functionality -- `tests/` folder at repository root with at least one Pester test file - -**Optional Configuration Files**: - -- `manifest.psd1` - PowerShell module manifest (auto-generated if missing with GitHub metadata) -- `header.ps1` - Code executed at module load start (before any other code) -- `finally.ps1` - Code executed at module load end (after all other code) -- `README.md` - Documentation pointer (typically references Build-PSModule for structure) - -**Source Folders** (all optional, include only what your module needs): - -- `assemblies/` - .NET assemblies (`.dll`) loaded into module session -- `classes/private/` - Private PowerShell classes (not exported) -- `classes/public/` - Public PowerShell classes (exported via TypeAccelerators) -- `data/` - Configuration data files (`.psd1`) loaded as module variables -- `formats/` - Format definition files (`.ps1xml`) for object display -- `functions/private/` - Private functions (internal implementation) - - Supports subdirectories for grouping (e.g., `functions/public/ComponentA/`, `functions/public/ComponentB/`) -- `functions/public/` - Public functions (exported to module consumers) - - Supports subdirectories for grouping (e.g., `functions/public/ComponentA/`, `functions/public/ComponentB/`) - - Optional category documentation files (e.g., `functions/public/PSModule/PSModule.md`) -- `init/` - Initialization scripts (executed first during module load) -- `modules/` - Nested PowerShell modules (`.psm1`) or additional assemblies -- `scripts/` - Script files (`.ps1`) to process in caller's scope -- `types/` - Type definition files (`.ps1xml`) for custom type extensions -- `variables/private/` - Private variables (module scope only) -- `variables/public/` - Public variables (exported to module consumers) - -**Build Processing**: - -- Build-PSModule compiles `src/` into a single root module file (`.psm1`) -- Source folders are removed from output after processing (only compiled module remains) -- Files processed in alphabetical order within each folder -- See "Build Process Requirements" section for detailed compilation flow - -#### Repository Configuration Details - -**GitHub Actions Configuration** (`.github/` folder): - -- `PSModule.yml` (or `.json`/`.psd1`) - **REQUIRED** configuration file controlling Process-PSModule behavior -- `workflows/Process-PSModule.yml` - **REQUIRED** workflow file calling reusable Process-PSModule workflow -- `mkdocs.yml` - Material for MkDocs configuration for GitHub Pages documentation -- `linters/` - Linter configuration files (optional, uses framework defaults if missing) -- Other workflows (Linter, Nightly-Run) are optional supplementary workflows - -**Documentation Assets**: - -- `LICENSE` - Referenced in module manifest `LicenseUri` property -- `icon/icon.png` - Referenced in module manifest `IconUri` property (public URL) -- `README.md` - Project documentation, referenced in GitHub repository metadata -- `examples/` - Usage examples for module consumers - -**Testing Requirements**: - -- `tests/` folder at repository root (NOT inside `src/`) -- Pester test files (`.Tests.ps1`) for module validation -- Optional `BeforeAll.ps1` and `AfterAll.ps1` scripts for external test resource management (see below) -- Tests executed by Test-ModuleLocal workflow across all platforms -- See "Workflow Execution Order" section for BeforeAll/AfterAll/Test workflow sequence - -**BeforeAll/AfterAll Test Scripts** (Optional): - -Process-PSModule supports optional test setup and teardown scripts that execute once per workflow run (not per platform): - -- **`tests/BeforeAll.ps1`** - Runs once before all Test-ModuleLocal matrix jobs - - **Purpose**: Setup external test resources independent of test platform/OS - - **Intended Use**: Deploy cloud infrastructure via APIs, create external database instances, initialize test data in third-party services - - **NOT Intended For**: OS-specific dependencies, platform-specific test files, test-specific resources for individual matrix combinations - - **Execution**: Runs in `tests/` directory on ubuntu-latest with full access to environment secrets - - **Error Handling**: Script failures halt the testing workflow (setup must succeed) - - **Example Use Cases**: Deploy Azure/AWS resources via APIs, create external PostgreSQL databases, initialize SaaS test accounts - -- **`tests/AfterAll.ps1`** - Runs once after all Test-ModuleLocal matrix jobs complete - - **Purpose**: Cleanup external test resources independent of test platform/OS - - **Intended Use**: Remove cloud infrastructure via APIs, delete external database instances, cleanup test data in third-party services - - **NOT Intended For**: OS-specific cleanup, platform-specific file removal, test-specific cleanup for individual matrix combinations - - **Execution**: Runs in `tests/` directory on ubuntu-latest with full access to environment secrets - - **Error Handling**: Script failures logged as warnings but don't halt workflow (cleanup is best-effort) - - **Always Executes**: Runs even if tests fail (via `if: always()` condition) - - **Example Use Cases**: Delete Azure/AWS resources via APIs, remove external databases, cleanup SaaS test accounts - -**Key Distinction**: BeforeAll/AfterAll are for managing **external resources via APIs** that exist outside GitHub Actions execution environment. Test-specific resources for individual OS/platform combinations should be created within the tests themselves using Pester `BeforeAll`/`AfterAll` blocks. - -**Key Points**: - -- **Private vs Public**: `private/` folders contain internal implementations; `public/` folders contain exported elements -- **Optional Components**: Not all folders are required; include only what your module needs -- **Function Organization**: Functions can be organized in subdirectories with optional category documentation -- **Manifest Generation**: If `manifest.psd1` is not provided, Build-PSModule auto-generates with GitHub metadata -- **Minimal Structure**: At minimum, provide `src/functions/public/.ps1` and `tests/.Tests.ps1` -- **Template Reference**: Use [Template-PSModule](https://github.com/PSModule/Template-PSModule) as starting point - -**Documentation References**: - -- [Build-PSModule README](https://github.com/PSModule/Build-PSModule) - Complete build process details -- [Template-PSModule](https://github.com/PSModule/Template-PSModule) - Reference implementation -- [Process-PSModule Configuration](#configuration) - Settings file documentation - -### Workflow Integration Requirements - -Consuming repositories MUST create a workflow file (e.g., `.github/workflows/Process-PSModule.yml`) that calls the reusable Process-PSModule workflow: - -```yaml -name: Process-PSModule - -on: - pull_request: - branches: [main] - types: [closed, opened, reopened, synchronize, labeled] - -jobs: - Process-PSModule: - uses: PSModule/Process-PSModule/.github/workflows/workflow.yml@v4 - secrets: - APIKEY: ${{ secrets.APIKEY }} # PowerShell Gallery API key -``` - -**Configuration Requirements**: - -- Configuration file at `.github/PSModule.yml` (YAML, JSON, or PSD1 format supported) -- Reference: [Process-PSModule Configuration Documentation](https://github.com/PSModule/Process-PSModule#configuration) -- Use Template-PSModule as starting point: [Template-PSModule](https://github.com/PSModule/Template-PSModule) - -### Build Process Requirements - -**Process-PSModule uses the Build-PSModule action to compile module source code into a production-ready PowerShell module.** The build process is automated and opinionated, following a specific execution flow: - -#### Build Execution Flow - -1. **Execute Custom Build Scripts** (Optional) - - Build-PSModule searches for `*build.ps1` files **anywhere in the repository** - - Scripts are executed in **alphabetical order by filename** (path-independent) - - Allows custom pre-build logic (e.g., code generation, asset processing, configuration setup) - - Example: `1-build.ps1` runs before `2-build.ps1` regardless of directory location - - Custom scripts can modify source files before the build process continues -2. **Copy Source Code** - - All files from `src/` folder are copied to the output folder - - Existing root module file (`.psm1`) is **excluded** (recreated in step 4) - - Creates a clean build environment for compilation -3. **Build Module Manifest** (`.psd1`) - - Searches for existing `manifest.psd1` or `.psd1` in source - - If found, uses it as base (preserving specified properties) - - If not found, creates new manifest from scratch - - **Automatically Derived Properties**: - - `RootModule`: Set to `.psm1` - - `ModuleVersion`: Temporary value (`999.0.0`) - updated by Publish-PSModule during release - - `Author`: GitHub repository owner (or preserved from source manifest) - - `CompanyName`: GitHub repository owner (or preserved from source manifest) - - `Copyright`: Generated as `(c) YYYY . All rights reserved.` (or preserved from source manifest) - - `Description`: GitHub repository description (or preserved from source manifest) - - `GUID`: New GUID generated by New-ModuleManifest - - `FileList`: All files in the module output folder - - `RequiredAssemblies`: All `*.dll` files from `assemblies/` and `modules/` (depth = 1) - - `NestedModules`: All `*.psm1`, `*.ps1`, `*.dll` files from `modules/` (one level down) - - `ScriptsToProcess`: All `*.ps1` files from `scripts/` folder (loaded into caller session) - - `TypesToProcess`: All `*.Types.ps1xml` files (searched recursively) - - `FormatsToProcess`: All `*.Format.ps1xml` files (searched recursively) - - `DscResourcesToExport`: All `*.psm1` files from `resources/` folder - - `FunctionsToExport`: All functions from `functions/public/` (determined by AST parsing) - - `CmdletsToExport`: Empty array (or preserved from source manifest) - - `VariablesToExport`: All variables from `variables/public/` (determined by AST parsing) - - `AliasesToExport`: All aliases from `functions/public/` (determined by AST parsing) - - `ModuleList`: All `*.psm1` files in source folder (excluding root module) - - `RequiredModules`: Gathered from `#Requires -Modules` statements in source files - - `PowerShellVersion`: Gathered from `#Requires -Version` statements in source files - - `CompatiblePSEditions`: Gathered from `#Requires -PSEdition` statements (defaults to `@('Core','Desktop')`) - - `Tags`: GitHub repository topics plus compatibility tags from source files - - `LicenseUri`: Public URL to `LICENSE` file (or preserved from source manifest) - - `ProjectUri`: GitHub repository URL (or preserved from source manifest) - - `IconUri`: Public URL to `icon/icon.png` (or preserved from source manifest) - - **Preserved from Source Manifest** (if provided): - - `PowerShellHostName`, `PowerShellHostVersion`, `DotNetFrameworkVersion`, `ClrVersion`, `ProcessorArchitecture` - - `RequireLicenseAcceptance` (defaults to `false` if not specified) - - `ExternalModuleDependencies`, `HelpInfoURI`, `DefaultCommandPrefix` - - `ReleaseNotes` (not automated - can be set via PR/release description) - - `Prerelease` (managed by Publish-PSModule during release) -4. **Build Root Module** (`.psm1`) - - Creates new root module file (ignoring any existing `.psm1` in source) - - **Compilation Order**: - 1. **Module Header**: - - Adds content from `header.ps1` if exists (then removes file) - - If no `header.ps1`, adds default `[CmdletBinding()]` parameter block - - Adds PSScriptAnalyzer suppression for cross-platform compatibility - 2. **Post-Header Initialization**: - - Loads module manifest information (`$script:PSModuleInfo`) - - Adds platform detection (`$IsWindows` for PS 5.1 compatibility) - 3. **Data Loader** (if `data/` folder exists): - - Recursively imports all `*.psd1` files from `data/` folder - - Creates module-scoped variables: `$script:` for each data file - - Example: `data/Config.psd1` becomes `$script:Config` - 4. **Source File Integration** (in this specific order): - - Processes each folder alphabetically within the folder, files on root first, then subfolders - - Files are wrapped with debug logging regions - - After processing, source folders are **removed** from output: - 1. `init/` - Initialization scripts (executed first during module load) - 2. `classes/private/` - Private PowerShell classes (not exported) - 3. `classes/public/` - Public PowerShell classes (exported via TypeAccelerators) - 4. `functions/private/` - Private functions (not exported) - 5. `functions/public/` - Public functions (exported to module consumers) - 6. `variables/private/` - Private variables (not exported) - 7. `variables/public/` - Public variables (exported to module consumers) - 8. Any remaining `*.ps1` files on module root - 5. **Class and Enum Exporter** (if `classes/public/` exists): - - Uses `System.Management.Automation.TypeAccelerators` for type registration - - Exports enums from `classes/public/` as type accelerators - - Exports classes from `classes/public/` as type accelerators - - Adds `OnRemove` handler to clean up type accelerators when module is removed - - Provides Write-Verbose output for each exported type - 6. **Export-ModuleMember**: - - Adds `Export-ModuleMember` call with explicit lists - - Only exports items from `public/` folders: - - **Functions**: From `functions/public/` - - **Cmdlets**: From manifest (usually empty for script modules) - - **Variables**: From `variables/public/` - - **Aliases**: From functions in `functions/public/` - 7. **Format with PSScriptAnalyzer**: - - Entire root module content is formatted using `Invoke-Formatter` - - Uses PSScriptAnalyzer settings from `Build/PSScriptAnalyzer.Tests.psd1` - - Ensures consistent code style and UTF-8 BOM encoding -5. **Update Manifest Aliases** - - Re-analyzes root module to extract actual aliases defined - - Updates `AliasesToExport` in manifest with discovered aliases -6. **Upload Module Artifact** - - Built module is packaged and uploaded as workflow artifact - - Artifact name defaults to `module` (configurable via action input) - - Available for subsequent workflow steps (testing, publishing) - -#### Build Process Constraints - -- **No Manual Root Module**: Any existing `.psm1` file in `src/` is **ignored and replaced** -- **Source Folder Removal**: Processed source folders are removed from output (only compiled root module remains) -- **Alphabetical Processing**: Files within each folder are processed alphabetically -- **Manifest Precedence**: Source manifest values take precedence over generated values -- **UTF-8 BOM Encoding**: Final root module uses UTF-8 with BOM encoding -- **PowerShell 7.4+ Target**: Build process and generated code target PowerShell 7.4+ - -#### Build Process References - -- [Build-PSModule Action](https://github.com/PSModule/Build-PSModule) -- [PowerShell Gallery Publishing Guidelines](https://learn.microsoft.com/powershell/gallery/concepts/publishing-guidelines) -- [PowerShell Module Manifests](https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_module_manifests) -- [PowerShell Module Authoring](https://learn.microsoft.com/powershell/scripting/dev-cross-plat/performance/module-authoring-considerations) - -## Core Principles - -### I. Workflow-First Design (NON-NEGOTIABLE) - -Every feature MUST be implemented as a reusable GitHub Actions workflow component. This is NOT a local development framework; it is designed for CI/CD execution. Workflows MUST: -- Be composable and callable from other workflows using `uses:` syntax -- Use clearly defined inputs and outputs with proper documentation -- Follow the single responsibility principle (one workflow = one concern) -- Support matrix strategies for parallel execution where appropriate -- Be independently testable via the CI validation workflow (`.github/workflows/ci.yml`) -- Delegate logic to reusable GitHub Actions (from github.com/PSModule organization) -- **Avoid inline PowerShell code** in workflow YAML; use action-based script files instead -- Reference actions by specific versions or tags for stability - -**Rationale**: Reusable workflow architecture enables maintainability, reduces duplication, and allows consuming repositories to leverage Process-PSModule capabilities consistently. Action-based scripts provide better testability, reusability, and version control than inline code. - -### II. Test-Driven Development (NON-NEGOTIABLE) - -All code changes MUST follow strict TDD practices using Pester and PSScriptAnalyzer: - -- Tests MUST be written before implementation -- Tests MUST fail initially (Red phase) -- Implementation proceeds only after failing tests exist (Green phase) -- Code MUST be refactored while maintaining passing tests (Refactor phase) -- PSScriptAnalyzer rules MUST pass for all PowerShell code -- Manual testing procedures MUST be documented when automated testing is insufficient -- **Workflow functionality MUST be validated** through CI workflow tests (`.github/workflows/ci.yml`) -- Consuming module repositories SHOULD use CI workflow for nightly validation - -**Rationale**: TDD ensures code quality, prevents regressions, and creates living documentation through tests. This is fundamental to project reliability. CI workflow validation ensures the entire framework functions correctly in real-world scenarios. - -### III. Platform Independence with Modern PowerShell - -**Modules MUST be built to be cross-platform.** All workflows, features, and consuming modules MUST support cross-platform execution (Linux, macOS, Windows) using **PowerShell 7.4 or newer**: -- Use platform-agnostic PowerShell Core 7.4+ constructs exclusively -- **Modules MUST function identically** on Linux, macOS, and Windows -- Cross-platform compatibility is **verified through Test-ModuleLocal** workflow -- Test-ModuleLocal executes module tests on: `ubuntu-latest`, `windows-latest`, `macos-latest` -- **BeforeAll/AfterAll scripts** execute on `ubuntu-latest` only (external resource setup) -- Implement matrix testing across all supported operating systems for all workflow components -- Document any platform-specific behaviors or limitations explicitly -- Test failures on any platform MUST block merging -- Provide skip mechanisms for platform-specific tests when justified (with clear rationale) -- **No backward compatibility** required for Windows PowerShell 5.1 or earlier PowerShell Core versions - -**Rationale**: PowerShell 7.4+ provides consistent cross-platform behavior and modern language features. Focusing on a single modern version reduces complexity and maintenance burden. Modules built with Process-PSModule framework must work seamlessly across all platforms, verified through automated matrix testing in Test-ModuleLocal, ensuring maximum compatibility for consuming projects on contemporary platforms. - -### IV. Quality Gates and Observability - -Every workflow execution MUST produce verifiable quality metrics: - -- Test results MUST be captured in structured formats (JSON reports) -- Code coverage MUST be measured and reported -- Linting results MUST be captured and enforced -- All quality gates MUST fail the workflow if thresholds are not met -- Workflow steps MUST produce clear, actionable error messages -- Debug mode MUST be available for troubleshooting - -**Rationale**: Measurable quality gates prevent degradation over time and provide clear feedback. Observability enables rapid debugging and continuous improvement. - -### V. Continuous Delivery with Semantic Versioning - -Release management MUST be automated and follow SemVer 2.0.0: - -- Version bumps MUST be determined by PR labels (major, minor, patch) -- Releases MUST be automated on merge to main branch -- PowerShell Gallery publishing MUST be automatic for labeled releases -- GitHub releases MUST be created with complete changelogs -- Prerelease versioning MUST support incremental or date-based formats -- Documentation MUST be published to GitHub Pages automatically - -**Rationale**: Automated releases reduce human error, ensure consistency, and enable rapid iteration while maintaining clear version semantics. - -## Pull Request Workflow and Publishing Process - -Process-PSModule implements an **automated publishing workflow** triggered by pull request events. The workflow behavior is controlled by PR labels following Semantic Versioning (SemVer 2.0.0) conventions. - -### PR Label-Based Release Types - -Pull requests MUST use labels to determine release behavior: - -#### Version Increment Labels (SemVer) - -- **`major`** - Breaking changes, incompatible API changes - - Increments major version: `1.2.3` → `2.0.0` - - Resets minor and patch to zero - -- **`minor`** - New features, backward-compatible functionality additions - - Increments minor version: `1.2.3` → `1.3.0` - - Resets patch to zero - -- **`patch`** - bugfixes, backward-compatible patches (default) - - Increments patch version: `1.2.3` → `1.2.4` - - Applied by default when no version label specified (if AutoPatching enabled) - -#### Special Release Labels - -- **`prerelease`** - Creates prerelease version (unmerged PR publishing) - - Publishes module to PowerShell Gallery with prerelease tag - - Creates GitHub Release marked as prerelease - - Prerelease tag format: `-` - - Example: `1.2.4-featureauth001` for branch `feature/auth` - - Only applies to **unmerged PRs** (opened, reopened, synchronized, labeled) - - When merged to main, normal release takes precedence (prerelease label ignored) - -- **`NoRelease`** - Skips all publishing - - Workflow runs build and test jobs - - Publishing jobs (Publish-Module, Publish-Site) are skipped - - Used for documentation-only changes or work-in-progress validation - -### Workflow Conditional Execution - -The Process-PSModule workflow uses **dynamic conditions** to determine job execution: - -#### Always Execute (All PR States) - -- **Get-Settings** - Configuration loading -- **Build-Module** - Module compilation -- **Build-Docs** - Documentation generation -- **Build-Site** - Static site generation -- **Test-SourceCode** - Source code validation -- **Lint-SourceCode** - Code quality checks -- **Test-Module** - Built module validation -- **Test-ModuleLocal** - Pester tests across platforms -- **Get-TestResults** - Test aggregation -- **Get-CodeCoverage** - Coverage analysis - -#### Conditional Execution (Based on PR State and Labels) - -**Publish-Site** (GitHub Pages deployment): - -- **Executes when**: PR is **merged** to default branch AND tests pass -- **Skipped when**: PR is open/synchronized OR not merged OR scheduled run OR manual trigger -- Condition: `github.event_name == 'pull_request' AND github.event.pull_request.merged == true` - -**Publish-Module** (PowerShell Gallery publishing): - -- **Executes when**: - - PR is **merged** to default branch AND tests pass (normal release), OR - - PR has **`prerelease` label** AND PR is **not merged** AND tests pass (prerelease) -- **Skipped when**: - - PR has `NoRelease` label, OR - - Scheduled run (cron trigger), OR - - Manual run (workflow_dispatch), OR - - Tests fail -- Condition: `(github.event_name == 'pull_request' AND github.event.pull_request.merged == true) OR (labels contains 'prerelease' AND NOT merged)` - -### Publishing Behavior Examples - -| PR State | Labels | Build/Test | Publish-Module | Publish-Site | Version | -|----------|--------|------------|----------------|--------------|---------| -| Opened | `minor` | ✅ Yes | ❌ No | ❌ No | N/A (not published) | -| Opened | `prerelease` | ✅ Yes | ✅ Yes (prerelease) | ❌ No | `1.3.0-branchname001` | -| Opened | `prerelease`, `minor` | ✅ Yes | ✅ Yes (prerelease) | ❌ No | `1.3.0-branchname001` | -| Synchronized | `major` | ✅ Yes | ❌ No | ❌ No | N/A (not published) | -| Synchronized | `prerelease` | ✅ Yes | ✅ Yes (prerelease) | ❌ No | `1.3.0-branchname002` | -| Merged | `minor` | ✅ Yes | ✅ Yes (normal) | ✅ Yes | `1.3.0` | -| Merged | `major` | ✅ Yes | ✅ Yes (normal) | ✅ Yes | `2.0.0` | -| Merged | `patch` | ✅ Yes | ✅ Yes (normal) | ✅ Yes | `1.2.4` | -| Merged | (no label) | ✅ Yes | ✅ Yes (if AutoPatching) | ✅ Yes | `1.2.4` (patch) | -| Merged | `NoRelease` | ✅ Yes | ❌ No | ❌ No | N/A (skipped) | -| Merged | `prerelease`, `minor` | ✅ Yes | ✅ Yes (normal) | ✅ Yes | `1.3.0` (prerelease ignored) | -| Scheduled (cron) | N/A | ✅ Yes | ❌ No | ❌ No | N/A (validation only) | -| Manual (workflow_dispatch) | N/A | ✅ Yes | ❌ No | ❌ No | N/A (validation only) | - -### Version Calculation Process - -The Publish-PSModule action determines the new version using this process: - -1. **Get Latest Version** - - Query PowerShell Gallery for latest published version - - Query GitHub Releases for latest release version - - Use the higher of the two as base version -2. **Determine Version Increment** - - Check PR labels for `major`, `minor`, or `patch` - - If no version label and AutoPatching enabled, default to `patch` - - If no version label and AutoPatching disabled, skip publishing -3. **Calculate New Version** - - Apply SemVer increment based on label - - Major: `1.2.3` → `2.0.0` - - Minor: `1.2.3` → `1.3.0` - - Patch: `1.2.3` → `1.2.4` -4. **Add Prerelease Tag** (if `prerelease` label present on unmerged PR) - - Extract branch name, sanitize to alphanumeric only - - Query existing prerelease versions with same branch name - - Increment prerelease counter - - Format: `-` - - Example: `1.3.0-featureauth001`, `1.3.0-featureauth002` -5. **Publish to PowerShell Gallery** - - Upload module with calculated version - - Set prerelease flag if prerelease tag present - - Validate publication success -6. **Create GitHub Release** - - Generate release notes from PR description and commits - - Create release with version tag (e.g., `v1.3.0` or `v1.3.0-featureauth001`) - - Mark as prerelease if prerelease tag present - - Attach module artifact - -### Configuration Options - -Repositories can configure publishing behavior in `.github/PSModule.yml`: - -```yaml -Publish: - Module: - AutoPatching: true # Auto-apply patch when no label - AutoCleanup: false # Remove old prereleases - IncrementalPrerelease: true # Use incremental prerelease counter - DatePrereleaseFormat: '' # Alternative: date-based prerelease (yyyyMMddHHmmss) - VersionPrefix: 'v' # Prefix for git tags (e.g., v1.2.3) - MajorLabels: ['major', 'breaking'] # Labels that trigger major bump - MinorLabels: ['minor', 'feature'] # Labels that trigger minor bump - PatchLabels: ['patch', 'fix', 'bug'] # Labels that trigger patch bump - IgnoreLabels: ['NoRelease', 'skip'] # Labels that skip publishing -``` - -### Workflow Trigger Configuration - -Consuming repositories MUST configure their workflow file to trigger on appropriate PR events: - -```yaml -name: Process-PSModule - -on: - pull_request: - branches: [main] - types: - - closed # Detect merged PRs - - opened # Initial PR creation - - reopened # Reopened PR - - synchronize # New commits pushed - - labeled # Label added/changed - -jobs: - Process-PSModule: - uses: PSModule/Process-PSModule/.github/workflows/workflow.yml@v4 - secrets: - APIKEY: ${{ secrets.APIKEY }} # Required for publishing -``` - -**Key Points**: - -- **`closed` event** with `github.event.pull_request.merged == true` triggers normal releases -- **`labeled` event** allows immediate prerelease publishing when `prerelease` label added -- **`synchronize` event** with `prerelease` label publishes new prerelease on each push -- **Secrets** MUST include `APIKEY` for PowerShell Gallery publishing (optional for CI-only runs) - -### Publishing Constraints - -- **API Key Required**: PowerShell Gallery publishing requires valid API key in secrets -- **Test Pass Requirement**: Publishing jobs only execute if all tests pass -- **Branch Protection**: Recommended to protect main branch and require PR reviews -- **Label Discipline**: Teams MUST follow label conventions for predictable versioning -- **Prerelease Cleanup**: Consider enabling AutoCleanup to remove old prerelease versions -- **Version Conflicts**: Publishing fails if version already exists in PowerShell Gallery -- **Incremental Prereleases**: Each push to prerelease PR increments counter (001, 002, 003...) -- **Branch Name Sanitization**: Prerelease tags use alphanumeric-only branch names - -## Quality Standards - -### Technical Constraints - -- **PowerShell Version**: 7.4 or newer (no backward compatibility with 5.1 or older Core versions) -- **Execution Environment**: GitHub Actions runners (not designed for local development) -- **Code Organization**: Action-based scripts preferred over inline workflow code -- **Action References**: Use PSModule organization actions (github.com/PSModule) with version tags -- **Workflow Structure**: Reusable workflows in `.github/workflows/` using `workflow_call` trigger - -### Code Quality - -- All PowerShell code MUST pass PSScriptAnalyzer with project-defined rules -- Source code structure MUST follow PSModule framework conventions -- Code coverage target MUST be configurable per repository (default 0% for flexibility) -- All workflow YAML MUST be valid and pass linting -- Action scripts MUST be testable and maintainable -- Inline code in workflows SHOULD be avoided; extract to action scripts -- **Git credential handling**: Workflows MUST use `persist-credentials: false` for checkout actions to prevent credential leakage -- **Repository depth**: Workflows SHOULD use `fetch-depth: 0` for full git history when needed for versioning or changelog generation - -### Documentation - -- README MUST provide clear setup instructions and workflow usage examples -- All workflows MUST include descriptive comments explaining inputs, outputs, and purpose -- Changes MUST update relevant documentation in the same PR -- GitHub Pages documentation MUST be generated automatically using Material for MkDocs - -### Testing - -- Source code tests MUST validate framework compliance -- Module tests MUST validate built module integrity -- Local module tests (Pester) MUST validate functional behavior across all platforms -- **Test-ModuleLocal workflow** verifies cross-platform module compatibility on: - - `ubuntu-latest` (Linux) - - `windows-latest` (Windows) - - `macos-latest` (macOS) -- BeforeAll/AfterAll setup and teardown scripts MUST be supported for test environments -- Test matrices MUST be configurable via repository settings -- **CI validation workflows** (`.github/workflows/Workflow-Test-*.yml`) MUST be maintained for integration testing -- **Unified production workflow** (`.github/workflows/workflow.yml`) is the primary consumer-facing workflow -- Consuming repositories SHOULD use CI validation workflows for nightly regression testing - -## Development Workflow - -### Branching and Pull Requests - -- Follow GitHub Flow: feature branches → PR → main -- PR MUST be opened for all changes -- CI workflows MUST execute on PR synchronize, open, reopen, label events -- **PR labels determine release behavior**: `major`, `minor`, `patch`, `prerelease`, `NoRelease` -- **`prerelease` label** enables publishing of prerelease versions from unmerged PRs -- **Merged PRs** trigger normal releases (major/minor/patch based on labels) -- **Unmerged PRs with `prerelease` label** trigger prerelease publishing with incremental tags -- **`NoRelease` label** skips publishing but runs all build and test jobs -- **AutoPatching** (if enabled) applies patch increment when no version label present -- **Prerelease tags** format: `-` (e.g., `1.3.0-featureauth001`) -- **Version labels** follow SemVer: `major` (breaking), `minor` (features), `patch` (fixes) -- See "Pull Request Workflow and Publishing Process" section for detailed behavior - -### Workflow Execution Order - -The standard execution order for Process-PSModule workflows MUST be: -1. **Get-Settings** - Reads configuration and prepares test matrices -2. **Build-Module** - Compiles source into module -3. **Test-SourceCode** - Parallel matrix testing of source code standards -4. **Lint-SourceCode** - Parallel matrix linting of source code -5. **Test-Module** - Framework validation and linting of built module -6. **BeforeAll-ModuleLocal** - Optional: Execute tests/BeforeAll.ps1 setup script once before all test matrix jobs - - **Runs on ubuntu-latest only** (external resource setup via APIs) - - Script failures halt workflow execution - - Skipped if tests/BeforeAll.ps1 does not exist -7. **Test-ModuleLocal** - Runs Pester tests across platform matrix (ubuntu-latest, windows-latest, macos-latest) - - **Verifies cross-platform module compatibility** - - Tests module functionality across all supported platforms - - Depends on BeforeAll-ModuleLocal (waits for external resource setup) -8. **AfterAll-ModuleLocal** - Optional: Execute tests/AfterAll.ps1 teardown script once after all test matrix jobs - - **Always runs even if tests fail** (via `if: always()` condition) - - **Runs on ubuntu-latest only** (external resource cleanup via APIs) - - Script failures logged as warnings but don't halt workflow - - Skipped if tests/AfterAll.ps1 does not exist -9. **Get-TestResults** - Aggregates and validates test results -10. **Get-CodeCoverage** - Validates coverage thresholds -11. **Build-Docs** and **Build-Site** - Generates documentation -12. **Publish-Module** and **Publish-Site** - Automated publishing on release - -**Workflow Types**: - -- **Unified Production Workflow** (`.github/workflows/workflow.yml`) - Single workflow handling both CI and CD for consuming repositories - - Intelligently executes appropriate jobs based on PR state (open/merged/abandoned) - - Eliminates need for separate CI and release workflows - - Uses conditional execution to optimize for different scenarios -- **CI Validation Workflows** (`.github/workflows/Workflow-Test-*.yml`) - Integration tests for framework development -- Consuming repositories use the unified production workflow for all scenarios - -### Configuration - -- Settings MUST be stored in `.github/PSModule.yml` (or JSON/PSD1 format) in consuming repositories -- Skip flags MUST be available for all major workflow steps -- OS-specific skip flags MUST be supported (Linux, macOS, Windows) -- Settings MUST support test configuration, build options, and publish behavior -- **Consuming repositories** configure behavior through settings file (opinionated defaults provided) -- **Structure requirements** documented in GitHub Actions README files MUST be followed by consumers -- Configuration options MUST be backward compatible within major versions - -## Governance - -### Constitution Authority - -This constitution supersedes all other development practices **for Process-PSModule framework development**. When conflicts arise between this document and other guidance, the constitution takes precedence. - -**For Consuming Repositories**: This constitution defines how the Process-PSModule framework is built and maintained. Consuming repositories follow the opinionated structure and configuration documented in framework action README files. - -### Amendments - -Changes to this constitution require: - -1. Documentation of the proposed change with clear rationale -2. Review and approval by project maintainers -3. Migration plan for existing code/workflows if applicable -4. Version bump according to impact: - - MAJOR: Backward incompatible principle removals or redefinitions - - MINOR: New principles or materially expanded guidance - - PATCH: Clarifications, wording fixes, non-semantic refinements - -### Compliance - -- All PRs MUST be validated against constitutional principles **for framework development** -- Workflow design MUST align with Workflow-First Design principle -- Test-First principle compliance is NON-NEGOTIABLE and enforced by review -- **Platform Independence MUST be verified** through Test-ModuleLocal matrix testing (ubuntu-latest, windows-latest, macos-latest) -- **Modules MUST function identically** across all platforms -- Quality Gates MUST be enforced by workflow automation -- PowerShell 7.4+ compatibility MUST be verified -- Action-based implementation preferred over inline workflow code -- CI validation workflow MUST pass before merging changes to core workflows -- **Consuming repositories** MUST follow the Required Module Structure documented in Product Overview - -### Runtime Development Guidance - -For agent-specific runtime development guidance **when developing the framework**, agents should reference: -- GitHub Copilot: `.github/copilot-instructions.md` (if exists) -- Other agents: Check for `AGENTS.md`, `CLAUDE.md`, `GEMINI.md`, or `QWEN.md` - -**For Consuming Repositories**: Follow the Required Module Structure and Workflow Integration Requirements documented in the Product Overview section. Start with [Template-PSModule](https://github.com/PSModule/Template-PSModule). - -**Version**: 1.6.1 | **Ratified**: TODO(RATIFICATION_DATE) | **Last Amended**: 2025-10-03 diff --git a/.specify/templates/plan-template.md b/.specify/templates/plan-template.md index 53ee1010..f5ac67a6 100644 --- a/.specify/templates/plan-template.md +++ b/.specify/templates/plan-template.md @@ -10,7 +10,7 @@ 2. Fill Technical Context (scan for NEEDS CLARIFICATION) → Detect Project Type from file system structure or context (web=frontend+backend, mobile=app+API) → Set Structure Decision based on project type -3. Fill the Constitution Check section based on the content of the constitution document. +3. Fill the Constitution Check section based on the content of the main README. 4. Evaluate Constitution Check section below → If violations exist: Document them in Complexity Tracking → If no justification is possible: ERROR "Simplify approach first" @@ -269,4 +269,4 @@ directories captured above] - [ ] Complexity deviations documented --- -*Based on Constitution - See `.specify/memory/constitution.md`* +*Based on Constitution - See `README.md` Principles and Architecture section* diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..47a7fd15 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,15 @@ +{ + "chat.promptFilesRecommendations": { + "PSModule.constitution": true, + "PSModule.specify": true, + "PSModule.plan": true, + "PSModule.tasks": true, + "PSModule.implement": true, + "PSModule.analyze": true, + "PSModule.clarify": true, + "PSModule.pr": true + }, + "chat.tools.terminal.autoApprove": { + ".specify/scripts/": true + } +} diff --git a/README.md b/README.md index fa4d33d1..253fdaac 100644 --- a/README.md +++ b/README.md @@ -1,55 +1,70 @@ # Process-PSModule -A workflow for crafting PowerShell modules using the PSModule framework, which builds, tests, and publishes PowerShell modules to the PowerShell -Gallery and produces documentation that is published to GitHub Pages. The workflow is used by all PowerShell modules in the PSModule organization. +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. ## 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). -1. Configure the repository: - 1. Enable GitHub Pages in the repository settings. Set it to deploy from `GitHub Actions`. - 1. This will create an environment called `github-pages` that GitHub deploys your site to. -
Within the environment, remove the branch protection for main. - Remove the branch protection on main +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
- 1. [Create an API key on the PowerShell Gallery](https://www.powershellgallery.com/account/apikeys). Give it enough permission to manage the module you are working on. - 1. Create a new secret in the repository called `APIKEY` and set it to the API key for the PowerShell Gallery. -1. Create a branch, make your changes, create a PR and let the workflow run. + 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. ## 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. +Depending on the labels in the pull requests, the [workflow will result in different outcomes](#scenario-matrix). ![Process diagram](./media/Process-PSModule.png) -- [Get settings](./.github/workflows/Get-Settings.yml) - - Reads the settings file from a file in the module repository to configure the workflow. - - Gathers tests and creates test configuration based on the settings and the tests available in the module repository. - - This includes the selection of what OSes to run the tests on. -- [Build module](./.github/workflows/Build-Module.yml) +- [Get settings](#get-settings) + - Gathers context from GitHub, the `github/PSModule.yml` file and other files in the repository to configure the workflow. + - Outputs the gathered context for use in later steps. +- [Build module](#build-module) - Compiles the module source code into a PowerShell module. -- [Test source code](./.github/workflows/Test-SourceCode.yml) - - Tests the source code in parallel (matrix) using: + - Uploads the built module as an artifact for use in later steps. +- [Test source code](#test-source-code) + - Tests the source code 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 to later evaluate the results of the tests. + - This produces a JSON-based report that is used by [Get-PesterTestResults](#get-test-results) evaluate the results of the tests. - [Lint source code](./.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 to later evaluate the results of the linter. + - Lints the source code 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](./.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 to later evaluate the results of the 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. - [Test module](./.github/workflows/Test-ModuleLocal.yml) - - Import and tests the module in parallel (matrix) using Pester tests from the module repository. + - Imports and tests the module in parallel (matrix) using Pester tests from the module repository. - Supports setup and teardown scripts executed via separate dedicated jobs: - - `BeforeAll`: Runs once before all test matrix jobs to set up test environment (e.g., deploy infrastructure, download test data) - - `AfterAll`: Runs once after all test matrix jobs complete to clean up test environment (e.g., remove test resources, cleanup databases) - - Setup/teardown scripts are automatically detected in test directories and executed with the same environment variables as tests - - This produces a json based report that is used to later evaluate the results of the tests. + - `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. - [Get test results](./.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. @@ -68,6 +83,159 @@ Depending on the labels in the pull requests, the workflow will result in differ - Publishes the module to the PowerShell Gallery. - Creates a release on the GitHub repository. +### Get-Settings + +[workflow](./.github/workflows/Get-Settings.yml) + +### Lint-Repository + +[workflow](./.github/workflows/Lint-Repository.yml) + +### Get settings + +[workflow](#get-settings) + - Reads the settings file `github/PSModule.yml` in the module repository to configure the workflow. + - Gathers context for the process from GitHub and the repo files, configuring what tests to run, if and what kind of release to create, and wether + to setup testing infrastructure and what operating systems to run the tests on. + +### Build module + +[workflow](./.github/workflows/Build-Module.yml) + - Compiles the module source code into a PowerShell module. + +### 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. + +### Test module + +[workflow](./.github/workflows/Test-ModuleLocal.yml) + - Imports and tests the module in parallel (matrix) using Pester tests from the module repository. + - 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!" +``` + + +#### 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. + - If the code coverage is below the target, the workflow will fail here. + +### Publish module + +[workflow](./.github/workflows/Publish-Module.yml) + - Publishes the module to the PowerShell Gallery. + - Creates a release on the GitHub repository. + +### 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. @@ -108,78 +276,36 @@ jobs: uses: PSModule/Process-PSModule/.github/workflows/workflow.yml@v5 secrets: APIKEY: ${{ secrets.APIKEY }} - ``` +
### Inputs | Name | Type | Description | Required | Default | | ---- | ---- | ----------- | -------- | ------- | -| `Name` | `string` | The name of the module to process. This defaults to the repository name if nothing is specified. | `false` | N/A | +| `Name` | `string` | The name of the module to process. Defaults to the repository name if nothing is specified. | `false` | N/A | | `SettingsPath` | `string` | The path to the settings file. Settings in the settings file take precedence over the action inputs. | `false` | `.github/PSModule.yml` | | `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` | +| `Prerelease` | `boolean` | Whether to use a prerelease version of the **GitHub** module. | `false` | `false` | | `Debug` | `boolean` | Whether to enable debug output. Adds a `debug` step to every job. | `false` | `false` | | `Verbose` | `boolean` | Whether to enable verbose output. | `false` | `false` | | `WorkingDirectory` | `string` | The path to the root of the repo. | `false` | `.` | -### 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 -# Cleanup databases -# Stop services -Write-Host "Cleanup completed!" -``` - ### Secrets -The following secrets are used by the workflow. They can be automatically provided (if available) by setting the `secrets: inherit` -in the workflow file. +The following secrets are used by the workflow. They can be automatically provided (if available) by setting `secrets: inherit` in the workflow file. -| Name | Location | Description | Default | -| ---- | -------- | ----------- | ------- | -| `APIKEY` | GitHub secrets | The API key for the PowerShell Gallery. | N/A | -| `TEST_APP_ENT_CLIENT_ID` | GitHub secrets | The client ID of an Enterprise GitHub App for running tests. | N/A | -| `TEST_APP_ENT_PRIVATE_KEY` | GitHub secrets | The private key of an Enterprise GitHub App for running tests. | N/A | -| `TEST_APP_ORG_CLIENT_ID` | GitHub secrets | The client ID of an Organization GitHub App for running tests. | N/A | -| `TEST_APP_ORG_PRIVATE_KEY` | GitHub secrets | The private key of an Organization GitHub App for running tests. | N/A | -| `TEST_USER_ORG_FG_PAT` | GitHub secrets | The fine-grained personal access token with org access for running tests. | N/A | -| `TEST_USER_USER_FG_PAT` | GitHub secrets | The fine-grained personal access token with user account access for running tests. | N/A | -| `TEST_USER_PAT` | GitHub secrets | The classic personal access token for running tests. | N/A | +| Name | Location | Description | Default | +| ---- | -------------- | ------------------------------------------------------------------------- | ------- | +| `APIKEY` | GitHub secrets | The API key for the PowerShell Gallery. | N/A | +| `TEST_APP_ENT_CLIENT_ID` | GitHub secrets | The client ID of an Enterprise GitHub App for running tests. | N/A | +| `TEST_APP_ENT_PRIVATE_KEY` | GitHub secrets | The private key of an Enterprise GitHub App for running tests. | N/A | +| `TEST_APP_ORG_CLIENT_ID` | GitHub secrets | The client ID of an Organization GitHub App for running tests. | N/A | +| `TEST_APP_ORG_PRIVATE_KEY` | GitHub secrets | The private key of an Organization GitHub App for running tests. | N/A | +| `TEST_USER_ORG_FG_PAT` | GitHub secrets | The fine-grained PAT with organization access for running tests. | N/A | +| `TEST_USER_USER_FG_PAT` | GitHub secrets | The fine-grained PAT with user account access for running tests. | N/A | +| `TEST_USER_PAT` | GitHub secrets | The classic personal access token for running tests. | N/A | ### Permissions @@ -194,29 +320,29 @@ permissions: 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). +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 | -|-----|-----------------|-----------|--------------|------------| -| **Get-Settings** | ✅ 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** | +| Job | Open/Updated PR | Merged PR | Abandoned PR | Manual Run | +| ------------------------| --------------- | --------- | ------------ | ---------- | +| **Get-Settings** | ✅ 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 @@ -229,52 +355,52 @@ The file can be a `JSON`, `YAML`, or `PSD1` file. By default, it will look for ` The following settings are available in the settings file: -| Name | Type | Description | Default | -|----------------------------------------|-----------|----------------------------------------------------------------------------------------------------------|---------------------| -| `Name` | `String` | Name of the module to publish. Defaults to repository name. | `null` | -| `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 cleanup old prerelease module versions | `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 ([.NET DateTime](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'` | -| `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 | `{}` | +| Name | Type | Description | Default | +| -------------------------------------- | --------- | ----------------------------------------------------------------------------------------------------- | ------------------- | +| `Name` | `String` | Name of the module to publish. Defaults to the repository name. | `null` | +| `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 module versions | `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'` | +| `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 -```yml +```yaml Name: null Build: @@ -343,8 +469,8 @@ Linter: Skip: false ShowSummaryOnSuccess: false env: {} - ``` +
### Example 1 - Defaults with Code Coverage target @@ -359,7 +485,7 @@ Test: ### Example 2 - Rapid testing -This example ends up running Get-Settings, Build-Module and Test-Module (tests from the module repo) on ubuntu-latest. +This example ends up running Get-Settings, Build-Module and Test-Module (tests from the module repo) on **ubuntu-latest** only. ```yaml Test: @@ -397,7 +523,7 @@ Linter: #### Configuring Linter Validation Rules -The workflow supports all environment variables that super-linter provides. You can configure these through the `Linter.env` object: +The workflow supports all environment variables that **super-linter** provides. You can configure these through the `Linter.env` object: ```yaml Linter: @@ -442,14 +568,117 @@ 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). +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). + +## 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. +- 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. + +``` +├── 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 # Category overview merged into docs output +│ │ ├── 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 +``` + +## Principles and practices + +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. + +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. -## Specifications and practices 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/en-us/powershell/utility-modules/psscriptanalyzer/overview?view=ps-modules) +- [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) diff --git a/tests/srcTestRepo/src/functions/public/PSModule/PSModule.md b/tests/srcTestRepo/src/functions/public/PSModule/PSModule.md index 79741cf4..8c0f01c9 100644 --- a/tests/srcTestRepo/src/functions/public/PSModule/PSModule.md +++ b/tests/srcTestRepo/src/functions/public/PSModule/PSModule.md @@ -1 +1 @@ -# This is PSModule +# PSModule