Skip to content

Contributing

Rod Christiansen edited this page Sep 5, 2026 · 2 revisions

Contributing

How the Windows repository is laid out, how to build and run it on your own machine, and what a good pull request or bug report looks like. If you are only filing a bug, skip to Reporting a bug.

Repository layout

The tree is not a conventional src/-only solution. The command-line tool's sources sit at the repository root, and only the shared library and the GUI live under src/.

Path What it is
Program.cs, Logger.cs, StatusManager.cs, ReportManager.cs, DialogManager.cs, ManifestParser.cs The command-line tool. BootstrapMate.csproj builds these into managedbootstrapinstall.exe
BootstrapMate.csproj The command-line project. It explicitly excludes src/** from compilation and consumes Core through a ProjectReference
src/BootstrapMate.Core/ The shared library: ConfigManager.cs, ManagementDetector.cs, SignatureVerifier.cs, BootstrapMateConfig.cs, BootstrapMateConstants.cs
src/BootstrapMate.App/ The GUI, in Views/, ViewModels/, Converters/ and Assets/. Builds BootstrapMate.exe
installer/ Product.wxs, the WiX project, and Generate-GuiAppFiles.ps1, which generates the GUI's ComponentGroup
resources/ The ADMX and ADML policy templates
examples/ Example manifests and Intune detection scripts
build.ps1 The full local build: publish, sign, MSI, .intunewin
.github/workflows/ ci.yml (compile gate on push and PR to main) and release.yml (tag-triggered)

BootstrapMate.sln contains all three projects.

The GUI is WinUI 3, on the Windows App SDK, targeting net10.0-windows10.0.19041.0. It is not WPF — the command-line project sets UseWPF to false explicitly. The GUI does not share an in-process execution engine with the command-line tool: it shells out to managedbootstrapinstall.exe elevated and tails the log file for output. A change to how a package is installed belongs in the command-line sources at the root, not in src/BootstrapMate.App.

Note that the README's "Project Structure" section lists BootstrapMate.Service, BootstrapMate.CLI, BootstrapMate.Common and BootstrapMate.Tests, and describes BootstrapMate installing itself as a Windows Service. None of those directories exist, there is no Windows Service anywhere in the code, and there are no unit tests. Use the table above, not the README, when you are looking for where something lives.

Building and running locally

You need the .NET 10 SDK. See Building and Signing for the full picture, including signing and the MSI.

For an iteration loop, build the command-line tool alone, unsigned:

.\build.ps1 -AllowUnsigned -Architecture x64 -SkipMSI

Or go straight through dotnet and skip the build script entirely:

dotnet publish BootstrapMate.csproj --configuration Release --runtime win-x64 --output publish\executables\x64 --self-contained true

Run the result from an elevated prompt. app.manifest requests requireAdministrator, and an unelevated --silent run refuses to raise a UAC prompt and exits 1.

.\publish\executables\x64\managedbootstrapinstall.exe --url https://example.com/bootstrap.json --verbose

To exercise the GUI:

dotnet publish src\BootstrapMate.App\BootstrapMate.App.csproj --configuration Release --runtime win-x64 --output publish\app\x64 --self-contained true

The GUI looks for the command-line executable in C:\Program Files\BootstrapMate\, then alongside itself, then in ..\..\executables\<arch>\, so a build laid out under publish\ is found from a development run.

Test against a manifest you control, on a machine you are willing to have modified. BootstrapMate runs installers elevated and, on some paths, rewrites the machine PATH — see Troubleshooting and Gotchas. A virtual machine with a snapshot is the right environment.

Coding conventions

.editorconfig is authoritative and is checked in at the repository root:

  • UTF-8, CRLF line endings, final newline, trailing whitespace trimmed.
  • Two-space indentation by default; four spaces for .cs and .ps1.
  • C# lines up to 120 characters.

Beyond that, follow what the tree already does:

  • Nullable reference types are enabled on the command-line project; keep new code null-annotated.
  • LangVersion is latest.
  • Warnings are not errors, but do not add new ones.
  • The command-line tool logs through the static Logger, not through the Serilog or Microsoft.Extensions.Logging packages the project references but does not use. Match the existing marker vocabulary — [SECTION], [PROGRESS], [SUB-PROGRESS], [SUCCESS], [SKIPPED], [COMPLETION], [OUTPUT] — because both GUI log viewers parse those markers.
  • NuGet restores from nuget.org only. nuget.config clears every other source; do not add one.
  • Anything that both the GUI and the command-line tool need goes in src/BootstrapMate.Core.

Pull requests and branches

main is the trunk. Work on a branch and open a pull request against main; CI runs on every push and pull request to main and must pass. CI publishes both projects and builds the MSI for x64 and arm64 — it runs no tests, so a green CI means the code compiles and packages, nothing more. Say in the pull request how you verified the behaviour.

Write the commit subject as an imperative sentence describing the behaviour change, the way the recent history does: Scope the policy Authorization header to the manifest host, Expire session logs older than the retention window. Older commits use feat: and fix: prefixes; new ones do not need them. Squash-merge titles carry the pull request number, so keep the subject readable on its own.

If your change alters something an administrator would notice — a flag, a registry path, a default, a log line — update the corresponding wiki page in the same change, and add a line to Release Notes when it ships.

Releases are cut by pushing a vYYYY.MM.DD.HHMM tag. Do not push tags as part of a pull request.

Reporting a bug

Open an issue on the repository. A report that can be acted on without a round trip contains all four of the following.

The version string. Either run the tool, or read it off the top of a log:

& "C:\Program Files\BootstrapMate\managedbootstrapinstall.exe" --version

The log excerpt. One file is written per run to C:\ProgramData\ManagedBootstrap\logs\<yyyy-MM-dd-HHmmss>.log. Attach the newest one, or at least the session header block that follows === BootstrapMate Session Started === — it records the version, process ID, user, both architectures and the full command line — plus every line around the failure. Files older than 30 days are pruned, so collect promptly.

Get-ChildItem C:\ProgramData\ManagedBootstrap\logs -Filter *.log | Sort-Object LastWriteTime -Descending | Select-Object -First 1

If the failure was in a .pkg or .nupkg install, re-run with --verbose. Some installer output is only written at Debug level.

The status registry values. Read them from the path StatusManager actually writes, not the one --status prints:

Get-ItemProperty 'HKLM:\SOFTWARE\Cimian\BootstrapMate\Status\SetupAssistant'
Get-ItemProperty 'HKLM:\SOFTWARE\Cimian\BootstrapMate\Status\Userland'
Get-ItemProperty 'HKLM:\SOFTWARE\Cimian\BootstrapMate' -Name LastRunVersion

The effective configuration. Redact any AuthorizationHeader value before you paste it.

Get-ItemProperty 'HKLM:\SOFTWARE\Policies\BootstrapMate'
Get-ItemProperty 'HKLM:\SOFTWARE\BootstrapMate\Settings'
Get-ItemProperty 'HKCU:\SOFTWARE\BootstrapMate\Settings'

Also say whether C:\ProgramData\ManagedBootstrap\cache is empty. Any file left there is a failed install, kept deliberately for inspection.

Two things to check before filing, because they are known and documented rather than bugs: an exit code of 0 does not mean every package installed, since per-package failures are caught and the run continues; and several configurable settings are inert in the command-line tool. Both are covered on Troubleshooting and Gotchas. Redact hostnames, serial numbers and credentials from anything you attach — issues are public.

See also

Clone this wiki locally