|
| 1 | +# Build-MaesterModule |
| 2 | + |
| 3 | +Builds the Maester PowerShell module into a consolidated, publishable artifact |
| 4 | +under `./module/`. The source tree (`powershell/`, `tests/`) is never modified. |
| 5 | + |
| 6 | +## Usage |
| 7 | + |
| 8 | +```powershell |
| 9 | +# Standard build |
| 10 | +./build/Build-MaesterModule.ps1 |
| 11 | +
|
| 12 | +# Build with indentation normalization (requires PSScriptAnalyzer) |
| 13 | +./build/Build-MaesterModule.ps1 -Format |
| 14 | +
|
| 15 | +# Build with import-time profiling |
| 16 | +./build/Build-MaesterModule.ps1 -Profile |
| 17 | +
|
| 18 | +# Custom output location |
| 19 | +./build/Build-MaesterModule.ps1 -OutputRoot ./out |
| 20 | +``` |
| 21 | + |
| 22 | +## Parameters |
| 23 | + |
| 24 | +| Parameter | Type | Default | Description | |
| 25 | +| ----------- | ------ | --------- | ------------- | |
| 26 | +| `SourceRoot` | string | `../powershell` | Path to the module source directory | |
| 27 | +| `TestsRoot` | string | `../tests` | Path to the test suites directory | |
| 28 | +| `OutputRoot` | string | `../module` | Output directory (cleaned on every run) | |
| 29 | +| `Format` | switch | — | Normalize indentation to 4 spaces via `Invoke-Formatter` (requires PSScriptAnalyzer) | |
| 30 | +| `Profile` | switch | — | Measure and report `Import-Module` time | |
| 31 | + |
| 32 | +## Build Phases |
| 33 | + |
| 34 | +```mermaid |
| 35 | +flowchart TD |
| 36 | + A["Phase A\nClean output directory"] |
| 37 | + B["Phase B\nAST-parse public functions"] |
| 38 | + C["Phase C\nConsolidate Maester.psm1"] |
| 39 | + D["Phase D\nConsolidate OrcaClasses.ps1"] |
| 40 | + E["Phase E\nCopy static assets"] |
| 41 | + F["Phase F\nUpdate module manifest"] |
| 42 | + G["Phase G\nCopy test suites"] |
| 43 | + H{"Profile?"} |
| 44 | + I["Phase H\nImport-Module timing"] |
| 45 | + Done["Build complete"] |
| 46 | +
|
| 47 | + A --> B |
| 48 | + B --> C |
| 49 | + C --> D |
| 50 | + D --> E |
| 51 | + E --> F |
| 52 | + F --> G |
| 53 | + G --> H |
| 54 | + H -- Yes --> I --> Done |
| 55 | + H -- No --> Done |
| 56 | +``` |
| 57 | + |
| 58 | +### Phase A — Clean output directory |
| 59 | + |
| 60 | +Removes and recreates the output directory (`./module/` by default) to ensure a |
| 61 | +clean build with no stale artifacts. |
| 62 | + |
| 63 | +### Phase B — AST-parse public functions |
| 64 | + |
| 65 | +Scans every `.ps1` file under `powershell/public/` (excluding `*.Tests.ps1`) |
| 66 | +using the PowerShell AST parser to discover top-level function definitions. |
| 67 | + |
| 68 | +- Only functions matching the `Verb-Noun` naming convention are exported. |
| 69 | +- Helper functions without a `-` separator are logged and skipped. |
| 70 | +- Duplicate function names across files are deduplicated and logged. |
| 71 | +- Functions with unapproved verbs or mismatched filenames generate warnings. |
| 72 | + |
| 73 | +### Phase C — Consolidate Maester.psm1 |
| 74 | + |
| 75 | +Concatenates all internal and public `.ps1` source files into a single |
| 76 | +`Maester.psm1`, organized as: |
| 77 | + |
| 78 | +1. **Module preamble** — `#Requires`, `$__MtSession` initialization |
| 79 | +2. **Internal functions** — from `powershell/internal/` (excluding |
| 80 | + `check-ORCA*.ps1`, which go to Phase D) |
| 81 | +3. **Public functions** — from `powershell/public/` |
| 82 | +4. **Export-ModuleMember** — auto-generated function and alias exports |
| 83 | +5. **Manifest loader** — `Import-PowerShellDataFile` for runtime metadata |
| 84 | + |
| 85 | +Two transformations are applied to each source file: |
| 86 | + |
| 87 | +- **Preamble stripping** — Removes file-level `[SuppressMessageAttribute]`, |
| 88 | + `param()`, `using module`, and `# Generated by` lines that are only valid at |
| 89 | + the top of standalone `.ps1` files. Attributes inside function bodies are |
| 90 | + preserved. |
| 91 | +- **`$PSScriptRoot` path adjustment** — Strips parent-directory traversals |
| 92 | + (`../`) that were needed in the original subdirectory structure but are |
| 93 | + incorrect after consolidation to a flat module root. Any remaining |
| 94 | + `$PSScriptRoot/..` references trigger a warning for manual review. |
| 95 | +- **Indentation normalization** (with `-Format`) — Runs `Invoke-Formatter` |
| 96 | + per file to enforce 4-space indentation. Only the |
| 97 | + `PSUseConsistentIndentation` rule is applied. If PSScriptAnalyzer is not |
| 98 | + installed, a warning is emitted and formatting is skipped. |
| 99 | + |
| 100 | +### Phase D — Consolidate OrcaClasses.ps1 |
| 101 | + |
| 102 | +Merges the ORCA class hierarchy into a single `OrcaClasses.ps1`: |
| 103 | + |
| 104 | +1. **Base classes and enums** from `orcaClass.psm1` (preamble preserved since |
| 105 | + this file runs standalone via `ScriptsToProcess`) |
| 106 | +2. **Derived check classes** from each `check-ORCA*.ps1` file, with preambles |
| 107 | + stripped and `using module` directives removed (the base classes are now |
| 108 | + defined inline above) |
| 109 | + |
| 110 | +This file is registered as `ScriptsToProcess` in the manifest so that class |
| 111 | +definitions are available before the module's `.psm1` loads. |
| 112 | + |
| 113 | +When `-Format` is specified, each derived check class file is also passed |
| 114 | +through `Invoke-Formatter` for indentation normalization. |
| 115 | + |
| 116 | +### Phase E — Copy static assets |
| 117 | + |
| 118 | +Copies unchanged files to the output directory: |
| 119 | + |
| 120 | +- `assets/` directory (icons, images) |
| 121 | +- `Maester.Format.ps1xml` (type formatting) |
| 122 | + |
| 123 | +This phase runs before the manifest update (Phase F) so that |
| 124 | +`FormatsToProcess` references can be validated by `Update-ModuleManifest`. |
| 125 | + |
| 126 | +### Phase F — Update module manifest |
| 127 | + |
| 128 | +Copies the source `Maester.psd1` to the output directory and updates: |
| 129 | + |
| 130 | +- `FunctionsToExport` — set to the sorted, deduplicated list from Phase B |
| 131 | +- `ScriptsToProcess` — set to `@('OrcaClasses.ps1')` |
| 132 | + |
| 133 | +All other manifest fields (version, GUID, `RequiredModules`, |
| 134 | +`AliasesToExport`, etc.) are preserved from the source. |
| 135 | + |
| 136 | +### Phase G — Copy test suites |
| 137 | + |
| 138 | +Copies the `tests/` directory to `maester-tests/` in the output. Tests are |
| 139 | +copied as-is and not consolidated. |
| 140 | + |
| 141 | +### Phase H — Build profiling (optional) |
| 142 | + |
| 143 | +When `-Profile` is specified, imports the built module and reports: |
| 144 | + |
| 145 | +- `Import-Module` wall-clock time |
| 146 | +- Number of exported commands |
| 147 | + |
| 148 | +The module is unloaded after profiling. |
| 149 | + |
| 150 | +## Output Structure |
| 151 | + |
| 152 | +```text |
| 153 | +module/ |
| 154 | +├── assets/ # Icons and images |
| 155 | +├── maester-tests/ # Test suites (copied from tests/) |
| 156 | +├── Maester.Format.ps1xml # Type formatting definitions |
| 157 | +├── Maester.psd1 # Updated module manifest |
| 158 | +├── Maester.psm1 # Consolidated module script |
| 159 | +└── OrcaClasses.ps1 # Consolidated ORCA class definitions |
| 160 | +``` |
| 161 | + |
| 162 | +## Design Notes |
| 163 | + |
| 164 | +- **Source is never modified.** The build reads from `powershell/` and `tests/` |
| 165 | + and writes exclusively to the output directory. |
| 166 | +- **Deterministic output.** Files are sorted by full path before concatenation. |
| 167 | + The `FunctionsToExport` list is sorted alphabetically. Repeated builds from |
| 168 | + the same source produce identical output. |
| 169 | +- **Encoding.** All generated PowerShell files use UTF-8 with BOM (`utf8BOM`), |
| 170 | + matching the project convention. |
| 171 | +- **Preamble stripping is position-aware.** Only lines in the file-level |
| 172 | + preamble region (before the first function/class definition) are stripped. |
| 173 | + Identical attributes inside function bodies are preserved. |
| 174 | +- **The hardcoded PSM1 preamble** (module header, `#Requires`, |
| 175 | + `$__MtSession`) is extracted from the source `Maester.psm1`. If new session |
| 176 | + variables are added to the source, they must also be added to the build |
| 177 | + script's preamble. |
0 commit comments