Skip to content
Purview Dev logo

Repository Bootstrap

Stable Build SDK Reviewed 2026-10-28 purview-dev/build-sdk Star on GitHub 1 central-package-management code-style csharp developer-experience developer-tooling devex dotnet msbuild msbuild-sdk nuget project-templates roslyn roslyn-analyzers roslyn-generators tunit xunit

The SDK bootstraps repo-level files so external tooling that does not read MSBuild item metadata (for example CSharpier, IDE formatting tools, and SDK resolution) works consistently out of the box.

The package ships an .editorconfig in Sdk/.editorconfig. It is:

  1. Registered on @(EditorConfigFiles) via EditorConfigFilePath for build-time code-style enforcement (EnforceCodeStyleInBuild=true, EnableNETAnalyzers=true, AnalysisLevel=latest, AnalysisMode=All).
  2. Written to the repository root (as a physical file) when a .editorconfig does not already exist there, so tools like CSharpier pick it up.

The shipped file also defines the style policy (dotnet_style_require_accessibility_modifiers = omit_if_default, private instance fields named _camelCase, with IDE0040, CA1515, CA1852 and CA1034 at warning or above). Because a repository owner can edit a bootstrapped copy, the ValidatePurviewStylePolicy target re-checks the effective configuration on every compile and fails the build (PRSGD0006-PRSGD0009) when that policy has been overridden, hidden, or silenced through NoWarn. A stale copy that predates the current policy (for example one that still hides IDE1006) is therefore reported rather than obeyed — refresh it with PurviewRepoBootstrapMode=Always. Opt out with DisablePurviewStylePolicyValidation=true; see Style policy.

The write is atomic (a temporary file is renamed into place) and retried quietly, so parallel projects sharing the repository root cannot corrupt it or fail the build by racing. An existing file is never overwritten unless you ask for it.

Control it with:

PropertyDefaultDescription
BootstrapEditorConfigToRepoRoottrueCopies the SDK .editorconfig to the repository root when missing.
RepositoryEditorConfigFilePath(auto-detected)Override the destination path for the bootstrapped .editorconfig.
DisableAutoCopySdkFilesfalseMaster switch that disables repo-level SDK file bootstrapping.
PurviewRepoBootstrapModeIfMissingIfMissing (never overwrite), Always (overwrite), WarnOnDrift (warn when the existing file differs from the SDK-provided one) or Never (skip all bootstrapping).
PurviewRepoBootstrapCopyRetries3Write attempts before the failure is reported.
PurviewRepoBootstrapCopyRetryDelayMilliseconds500Base delay between write attempts.
PurviewRepoBootstrapCopyFailureAsErrortrueWhen false, a failed bootstrap write is reported as a warning instead of an error.

The SDK creates a global.json at the repository root when one is missing, registering Purview.BuildSdk in msbuild-sdks and setting the Microsoft.Testing.Platform test runner:

{
"test": {
"runner": "Microsoft.Testing.Platform"
},
"msbuild-sdks": {
"Purview.BuildSdk": "<version>"
}
}

Like the .editorconfig bootstrap it writes atomically, retries quietly, never overwrites an existing file, and honours PurviewRepoBootstrapMode:

PropertyDefaultDescription
BootstrapGlobalJsonToRepoRoottrueCreates a global.json at the repository root when missing.
RepositoryGlobalJsonFilePath(auto-detected)Override the destination path for the bootstrapped global.json.
PurviewBuildSdkVersionForGlobalJson(restored package version, else the version it was packed as)Version written to the msbuild-sdks.Purview.BuildSdk entry.
DisableAutoCopySdkFilesfalseMaster switch that disables repo-level SDK file bootstrapping.
PurviewRepoBootstrapModeIfMissingIfMissing, Always, WarnOnDrift or Never.

Both bootstraps share the same retry contract:

PropertyDefaultDescription
PurviewRepoBootstrapCopyRetries3Write attempts before the failure is reported.
PurviewRepoBootstrapCopyRetryDelayMilliseconds500Base delay between attempts (a small increment is added per attempt).
PurviewRepoBootstrapCopyFailureAsErrortrueWhen false, a failure is reported as a warning and the build continues.
PurviewSuppressCopyRetryWarningstrueDemotes built-in copy task retry notices (MSB3026) to messages. Set to false to see every retry.

Retries are therefore silent by design, while a write that never succeeds is still reported - as an error by default, including the destination path and the underlying OS error.

Both bootstrap targets locate the repository root by:

  1. Running git rev-parse --show-toplevel from the Directory.Build.props directory.
  2. Falling back to probing upward for a .git marker.
  3. Finally falling back to the Directory.Build.props directory itself.

Set the RepositoryEditorConfigFilePath / RepositoryGlobalJsonFilePath properties explicitly to override discovery.