mirror of
https://github.com/ChrisTitusTech/winutil.git
synced 2026-07-16 00:40:39 +00:00
* Harden Pester CI and discard runspace return values * Add prioritized test backlog * Add WinUtil action logging * Add config integrity tests * Add XAML control wiring tests * Add registry and service helper tests * Add package manager tests * Add runspace behavior tests * Add tweak orchestration tests * Add install workflow tests * Add update profile tests * Add AppX removal tests * Log package installer output * Add UI state helper tests * Pin Pester test runner version * Expand Win11 Creator tests * Add preferences and theme tests * Add search filter tests * Add compile contract tests * Use single WinUtil session log * Remove installer output logging helper * Handle locked WinUtil transcript log * Avoid appending to active transcript log * Log install uninstall package identities
106 lines
6.1 KiB
Markdown
106 lines
6.1 KiB
Markdown
# SPEC.md
|
|
|
|
## Project Contract
|
|
|
|
WinUtil is a Windows PowerShell utility with a WPF interface. The repository is maintained as modular source files, but the released artifact is a single generated `winutil.ps1` script.
|
|
|
|
The compiled `winutil.ps1` is not source code for editing or review. It is generated by `Compile.ps1` and produced during release automation. All durable changes must be made to the source files that feed the compiler.
|
|
|
|
## Goals
|
|
|
|
- Provide a single-script Windows utility that can be launched from PowerShell.
|
|
- Keep development modular enough for contributors to work on functions, config, UI, docs, and tooling independently.
|
|
- Make install, tweak, feature, repair, update, and ISO workflows discoverable from the WPF UI.
|
|
- Keep common lists and options declarative in JSON config where possible.
|
|
- Preserve a repeatable compile process so local builds and GitHub Actions builds produce the distributable script from the same inputs.
|
|
|
|
## Non-Goals
|
|
|
|
- `winutil.ps1` is not hand-maintained.
|
|
- The project is not structured as a PowerShell module at runtime.
|
|
- The GUI is not a separate packaged desktop application in this repository's normal release path.
|
|
- Generated files should not be reviewed as source changes.
|
|
|
|
## Repository Layout
|
|
|
|
- `Compile.ps1`: build script that creates `winutil.ps1`.
|
|
- `scripts/start.ps1`: startup/bootstrap segment used at the beginning of the compiled script.
|
|
- `scripts/main.ps1`: main entrypoint appended at the end of the compiled script.
|
|
- `functions/public/`: public/UI-facing PowerShell functions.
|
|
- `functions/private/`: internal helper PowerShell functions.
|
|
- `config/`: JSON configuration consumed at compile time and embedded into `$sync.configs`.
|
|
- `xaml/inputXML.xaml`: WPF UI markup embedded into the compiled script.
|
|
- `tools/autounattend.xml`: unattended setup XML embedded for Windows ISO workflows.
|
|
- `pester/`: Pester tests for config and function checks.
|
|
- `lint/PSScriptAnalyser.ps1`: PowerShell Script Analyzer settings.
|
|
- `docs/`: Hugo documentation site.
|
|
- `winutil.ps1`: ignored generated build artifact.
|
|
|
|
## Compile Specification
|
|
|
|
`Compile.ps1` must produce a standalone root `winutil.ps1` by combining all required project files.
|
|
|
|
The compile flow is:
|
|
|
|
1. Initialize shared state with `$sync = [Hashtable]::Synchronized(@{})` and `$sync.configs = @{}`.
|
|
2. Read `scripts/start.ps1`.
|
|
3. Replace `#{replaceme}` in startup code with the current `yy.MM.dd` build date.
|
|
4. Append raw content from all files under `functions/` recursively.
|
|
5. For every file in `config/`, parse JSON and embed it into `$sync.configs.<basename>`.
|
|
6. Special-case `config/applications.json` so application keys are emitted with the `WPFInstall` prefix.
|
|
7. Embed `xaml/inputXML.xaml` as `$inputXML`.
|
|
8. Embed `tools/autounattend.xml` as `$WinUtilAutounattendXml`.
|
|
9. Append `scripts/main.ps1`.
|
|
10. Write the combined script to `winutil.ps1`.
|
|
11. If `-Run` is supplied, execute the generated script.
|
|
|
|
The generated script must have everything it needs from repository sources embedded or appended by this process.
|
|
|
|
## Runtime Model
|
|
|
|
- WinUtil runs in PowerShell on Windows and uses WPF for the UI.
|
|
- Shared mutable state is stored in `$sync`, including configs, UI element references, runspace state, selections, and progress.
|
|
- Long-running operations should use runspaces or existing async patterns so the UI remains responsive.
|
|
- UI updates from background work must be dispatched back to the WPF UI thread.
|
|
- Declarative features such as apps, tweaks, presets, DNS providers, and navigation should stay in `config/*.json` unless code is required.
|
|
|
|
## UI And Event Contract
|
|
|
|
- UI layout lives in `xaml/inputXML.xaml`.
|
|
- Named WPF controls are discovered and stored in `$sync`.
|
|
- Button/action wiring follows existing naming conventions, where an element named like `WPFThingButton` maps to a function named like `Invoke-WPFThingButton`.
|
|
- When adding controls, ensure the XAML name, config key, and PowerShell function names line up with the existing event system.
|
|
|
|
## Configuration Contract
|
|
|
|
Config files must remain valid JSON and compile cleanly through `ConvertFrom-Json`.
|
|
|
|
`config/applications.json` defines installable applications. Each application entry should include the fields expected by tests and UI code, such as package manager IDs, category, display content, description, and link.
|
|
|
|
`config/tweaks.json` defines Windows tweaks. Registry and service changes should include original values or original states when applicable so undo workflows can restore user systems.
|
|
|
|
Preset and navigation files should reference valid config keys. Avoid renaming config keys unless all presets, UI references, docs, and code paths are updated together.
|
|
|
|
## Safety Requirements
|
|
|
|
- Registry, service, package manager, Windows Update, AppX removal, and ISO operations can affect the host system. Changes must be explicit, reversible where practical, and consistent with existing logging and confirmation patterns.
|
|
- Tweak changes should include undo metadata when the schema supports it.
|
|
- Package installation should prefer existing WinGet and Chocolatey helper functions.
|
|
- ISO workflows must not modify the user's original ISO file; they should work on copied/mounted content following existing patterns.
|
|
|
|
## Testing And CI
|
|
|
|
Expected validation for source changes:
|
|
|
|
- `.\Compile.ps1` verifies the compiler can generate `winutil.ps1`.
|
|
- `.\Compile.ps1 -Run` compiles and launches the generated utility for manual GUI verification.
|
|
- `Install-Module -Name Pester -RequiredVersion 5.8.0 -Scope CurrentUser -Force -SkipPublisherCheck` installs the supported Pester version.
|
|
- `Import-Module Pester -RequiredVersion 5.8.0 -Force; Invoke-Pester -Path 'pester/*.Tests.ps1' -Output Detailed -CI` runs the Pester suite.
|
|
- GitHub Actions also runs a compile check and PowerShell Script Analyzer with `lint/PSScriptAnalyser.ps1`.
|
|
|
|
The generated `winutil.ps1` may appear locally after compile. It remains ignored build output and must not be committed.
|
|
|
|
## Release Artifact
|
|
|
|
GitHub Actions is responsible for producing the release `winutil.ps1` from repository sources. A release should be considered valid only if the generated script came from the compile process, not from direct manual edits to `winutil.ps1`.
|