build: rework the build system and project layout#2367
Draft
mjcheetham wants to merge 34 commits into
Draft
Conversation
Drop the .NET Framework target (net472) from all projects and build scripts. Windows builds will now target the, only, TFM of `net10.0`. Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
Remove all code that was conditional on a .NET Framework target. Now that we're only building against the CoreCLR, this code was dead. Note that we now lose the ability to use the embedded web view for Microsoft authentication, which was a .NET Framework-only feature (and therefore Windows only). Support for embedded web view flows will be restored at a later date via Avalonia WebView. Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
Add the SupportedOSPlatform attributes to types that only run on the relevant specific OS platform. This will help ensure we're always gating use of OS-specific behaviour to that specific OS. Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
Suppress the "This call site is reachable on all platforms" warning for all test projects - we use custom Xunit attributes to dynamically skip OS-specific tests unless the test is running on the appropriate OS. The analyzer for CA1416 does not know how to handle this. Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
Upgrade all Avalonia packages to the latest version, which is 12.0.5 at time of writing. Version 12.x has some breaking changes that we must react to, including a required and explicit `x:DataType` specified for the now default compiled bindings in all views. There have also been changes to how the clipboard is accessed, as well as hotkeys. Finally some properties have been renamed and reworked, specifically on the customising window chrome/decorations and control placeholder text. Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
In order to support ahead-of-time (AOT) compilation we must avoid using reflection-based APIs. JSON serialisation is one of those APIs that we use a lot across the product. System.Text.Json supports source generation-based serialisation. We opt into this by creating explict 'JSON contexts' for each area that define the set of types we should generate serialisers for, including custom serialisation options (case sensitivity, naming conventions, etc). Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
Enable JSON source generation for Trace2 messages. This will further help unlock AOT compilation options which cannot use reflection-based APIs. Replace the custom JSON naming policy with the built-in lower snake case policy, and for good measure also explictly set the enum string values as attributes on the members themselves. Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
Enable AOT compilation on publish for Git Credential Manager by default! Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
f4fd0c4 to
d1b00a2
Compare
Enabling Native AOT makes the Linux CI jobs link a native binary for the target runtime. Cross-linking the Arm runtimes from the x64 ubuntu-latest runner has no target toolchain, so the linux-arm job fails at the clang link step. Run the Arm matrix entries on GitHub's Arm64 runners so linux-arm64 links natively, and install the armhf GNU toolchain (gcc-arm-linux-gnueabihf, which pulls in binutils and the sysroot) for the 32-bit linux-arm target, which still cross-compiles on the Arm64 host. Assisted-by: Claude Opus 4.8 Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
Native AOT links the published binary with clang. Leaving it on for a source install would force every distro to install a C toolchain just to build a local copy, which is why the install-from-source validation fails across the board with "gcc or clang is missing". Installing from source does not need a native binary, so turn AOT off for it alone: set PublishAot=false in the environment for the build (the executable project honours an externally supplied value, and the nested publish inherits it through the packaging scripts). With AOT off, layout.sh's existing self-contained, single-file publish produces a portable binary that needs only the .NET SDK to build and bundles its own runtime to run - so it launches even on the distros where the SDK was installed to a non-standard location. The shipped packages set nothing and still default to AOT. This is a deliberate stopgap that leaves the rest of the install-from-source flow as-is; a later commit reworks install-from-source handling altogether. Assisted-by: Claude Opus 4.8 Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
The src/shared directory is a relic of when code was split between
platform-specific src/{windows,osx,linux} trees and a separate shared
tree. Every library and test project is cross-platform now, so the
extra "shared" level only adds noise to project paths and solution
entries.
Lift all libraries and their test projects up one level into src/.
This is a pure move: project contents and their relative references to
one another are unchanged, so the assemblies that get built are
identical.
Assisted-by: Claude Opus 4.8
Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
With the shared projects flattened into src/, move the Directory.Build.props that scoped them up to src/ so it keeps applying to exactly the same set of projects. Drop the manual PlatformOutPath/BaseOutputPath overrides while here: output redirection is being centralized via UseArtifactsOutput in the root props (see later commit), so per-tree output paths are no longer needed. Only the chained import of the repository-root props remains. Assisted-by: Claude Opus 4.8 Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
Rename the executable project from Git-Credential-Manager to git-credential-manager so the project, its directory and the output binary all match the git-credential-manager command name and the lowercase naming used across the rest of the build. This is a pure move; the project file is unchanged apart from its path and filename casing. Assisted-by: Claude Opus 4.8 Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
The DotnetTool project existed only to repackage the executable as a .NET tool, carrying its own csproj, DotnetToolSettings.xml, nuspec and layout/pack scripts alongside the real project. Its packaging responsibilities move into the reworked build system introduced in the following commits, so remove the project. Preserve the tool icon by moving it next to the executable project. Assisted-by: Claude Opus 4.8 Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
Collect the custom MSBuild tasks - GetVersion and GenerateWindowsAppManifest - together with their project and the .tasks import file under a dedicated build/msbuild/ directory, and rename the project to MSBuildTasks. This frees the top level of build/ for the platform packaging that follows and gives the tasks assembly a clearer home. Point the root Directory.Build.targets at the new import path and thread a VersionOverride through to the GetVersion task. Assisted-by: Claude Opus 4.8 Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
Add lib-cli.sh and its PowerShell counterpart lib-cli.psm1: small helper libraries that the per-platform build/publish/pack/archive scripts introduced next will source. They centralize logging, repository and artifacts path resolution, and runtime/version/configuration normalisation (plus Inno Setup discovery on Windows). Keeping this logic in one place per shell keeps the platform scripts thin and consistent, and gives them a single source of truth for things like the verbose-output flag and the out/ layout. Assisted-by: Claude Opus 4.8 Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
Replace the old src/linux/Packaging.Linux project and its build/layout/pack scripts with a build/linux layout. A Linux.Distribution.csproj (a NoTargets project) anchors packaging in the solution, while thin publish/pack/archive scripts built on the shared lib-cli library do the actual work, replacing the previous monolithic layout.sh and pack.sh. The Debian control file moves under debian-package/, and install-from-source.sh carries over unchanged. Assisted-by: Claude Opus 4.8 Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
e459113 to
0ae7fc4
Compare
Replace src/osx/Installer.Mac with a build/macos layout mirroring the Linux one: a Mac.Distribution.csproj (NoTargets) plus publish/pack/archive/codesign scripts and an import-developer-certificate helper, all built on the shared lib-cli library. This subsumes the old build/layout/pack/dist/notarize/codesign scripts. The installer's distribution XML, resources, postinstall script, entitlements and uninstall.sh move under build/macos, with the .pkg pieces grouped under installer/. Assisted-by: Claude Opus 4.8 Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
Replace src/windows/Installer.Windows with a build/windows layout matching the other platforms: a Windows.Distribution.csproj (NoTargets) plus publish/pack/archive PowerShell scripts built on lib-cli.psm1, and a download-innosetup helper that fetches the Inno Setup compiler on demand. The Setup.iss installer script moves under installer/. Bump the Inno Setup package to 6.7.3 and drop its now-unused GeneratePathProperty: the compiler is resolved by the download helper at build time rather than from the NuGet package path. Assisted-by: Claude Opus 4.8 Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
Replace the legacy MSBuild .sln with the newer .slnx solution format. SLNX is terser, diffs and merges far more cleanly, and lists projects by path without the GUID bookkeeping of the old format. The new solution references the flattened src/ projects and the build/ distribution projects in their new homes. Rename the ReSharper DotSettings sidecar to match the new lowercase solution name so it keeps applying. Assisted-by: Claude Opus 4.8 Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
Turn on UseArtifactsOutput so every project's binaries and intermediates land under out/ in the standard .NET artifacts layout (replacing the per-tree output paths removed earlier), and default all projects to net10.0 - individual projects may still override. Bump the SDK in global.json to 10.0 and register the Microsoft.Build.NoTargets MSBuild SDK used by the new distribution projects. Normalise VERSION to the three-part 3.0.0. Assisted-by: Claude Opus 4.8 Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
Point the Azure Pipelines release definition and the GitHub Actions
workflows at the new build/ script entry points (publish/pack/archive,
import-developer-certificate) and the flattened project paths, replacing
references to the old src/{linux,osx,windows} packaging projects and
scripts.
Add the ESRP sign.yml template that the release pipeline invokes to
code-sign the Windows and macOS artifacts.
Assisted-by: Claude Opus 4.8
Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
Refresh the development guide to match the reworked build: refer to git-credential-manager.slnx, document building each platform's distributables through the build/<os> projects with --configuration and --runtime, and point at the new out/package and out/publish output locations. Add a note explaining why building the macOS distribution with Homebrew's non-portable .NET SDK fails at the Native AOT link step, and recommend using the official SDK instead. Assisted-by: Claude Opus 4.8 Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
The Linux, Mac and Windows *.Distribution.csproj projects each run their platform build.sh / publish pipeline from a target that fires AfterTargets="Build". Because they sat in the solution default build set, a plain `dotnet build` (or `dotnet test`) on git-credential-manager.slnx kicked off the full publish-and-package pipeline on the matching OS - slow, and with side effects no inner-loop build should have. Mark the three distribution projects with <Build Project="false" /> so a solution build covers just the product and its tests. They stay in the solution (visible and loadable in IDEs) and are still built directly via `dotnet build build/<os>`, which is how CI and a deliberate distribution build invoke them. Assisted-by: Claude Opus 4.8 Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
Publishing always produced an ahead-of-time (AOT) build, since the project sets PublishAot=true. AOT needs a native toolchain (clang, zlib) to link, which is fine for the shipped package but a heavy requirement for building from source. Add an --aot / --no-aot toggle to the Linux and macOS publish.sh scripts (and an equivalent -Aot switch to the Windows publish.ps1), defaulting to AOT so the shipped package is unchanged. --no-aot publishes a trimmed, self-contained build that needs only the .NET SDK. The boolean --x / --no-x parsing lives in a new bool_flag helper in lib-cli.sh for reuse. Trimming for the non-AOT build is configured in the project (PublishTrimmed, gated on PublishAot being off) rather than passed on the command line; the product is already AOT-safe, hence trim-safe. Assisted-by: Claude Opus 4.8 Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
The Linux install-from-source script built through the deleted src/linux/Packaging.Linux project (its InstallFromSource MSBuild path) and detected a checkout using the old src/linux paths and the .sln file, so it stopped working after the build-system rework. Promote it to a single cross-platform build/install-from-source.sh: detect the OS, bootstrap dependencies (Linux distro package managers, or git plus the .NET SDK on macOS), publish through the per-OS build/<os>/publish.sh, and stage the result under <prefix>/share/gcm-core with a launcher symlink in <prefix>/bin - the same layout the .deb uses. Default to a trimmed, self-contained non-AOT build (needs only the .NET SDK); --aot opts into a native build (and the clang/zlib toolchain on Linux). Elevate the install with sudo only when the prefix is not writable, so user-prefix installs need no root. Also fix two latent bugs carried over from the old script: the SDK-detection test broke when multiple SDKs were installed (forcing a needless dotnet re-download), and the dotnet bootstrap changed the working directory, which broke repo detection. Assisted-by: Claude Opus 4.8 Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
The validate-install-from-source workflow invoked the script from its old src/linux/Packaging.Linux location, which no longer exists after the rework. Point it at the new build/install-from-source.sh. Add a macOS job so the cross-platform script is exercised on macOS as well as the Linux distro matrix. The default non-AOT build needs only the .NET SDK, so it runs without a native toolchain on the runner. Assisted-by: Claude Opus 4.8 Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
The install-from-source script moved from src/linux/Packaging.Linux to a cross-platform build/install-from-source.sh and gained an --aot toggle that defaults to a trimmed, self-contained non-AOT build. Fix the now-broken script link in the uninstall guide, document the --aot option, and note that the script also runs on macOS. Assisted-by: Claude Opus 4.8 Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
The Install/Update/Uninstall subsections under the "## .NET tool" heading were h4 (####) while their parent is h2, leaving a gap in the heading hierarchy. Promote them to h3 (###) to match the sibling sections. Assisted-by: Claude Opus 4.8 Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
The standalone DotnetTool project was dropped during the build-system rework. Restore the ability to produce the git-credential-manager .NET tool NuGet package, placing it under build/dntool to match the per-platform build layout. publish.sh publishes the application as portable, framework-dependent IL (no AOT, trimming, runtime identifier or apphost); pack.sh then runs dotnet pack with the no-build option, pointing PublishDir at the published layout so that assemblies code-signed between the two steps are packaged as-is. The SDK generates DotnetToolSettings.xml and a symbol package, so no hand-written nuspec is required. Dntool.Distribution.csproj is a NoTargets project that carries only the tool and package metadata; it is driven by the scripts and marked no-build in the solution, like the other distribution projects. Assisted-by: Claude Opus 4.8 Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
Add a job to the CI workflow that builds the git-credential-manager .NET tool package (unsigned) via build/dntool/build.sh and uploads the resulting .nupkg/.snupkg, so the tool packaging is exercised on every push alongside the per-platform distributables. Assisted-by: Claude Opus 4.8 Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
The .NET tool was dropped from the release pipeline during the build-system rework, leaving a commented stub that referenced the removed src/shared/DotnetTool scripts. Add a dotnet_tool build job that publishes the framework-dependent IL via build/dntool/publish.sh, ESRP-signs the managed assemblies (SigntoolSign), then packs the signed layout into the .nupkg/.snupkg via build/dntool/pack.sh. Re-enable the NuGet publish job to push the package. Signing is performed by the ESRP service rather than the agent, so the build job runs on the existing Linux pool alongside the other platform builds. Assisted-by: Claude Opus 4.8 Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
Add a .NET tool section to the development guide: how to build the package with build/dntool/build.sh (it is script-built rather than via dotnet build, being platform-agnostic) and how to install the result into an isolated tool path to try it. Assisted-by: Claude Opus 4.8 Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
The Windows release jobs publish the executable with Native AOT, which links the final binary with the MSVC linker (link.exe). The 1ES hosted images do not ship the C++ toolchain, so every Windows leg fails with "Platform linker not found" from Microsoft.NETCore.Native.Windows.targets. Add a setup script that installs VS 2022 Build Tools with the single VC.Tools component for the agent's architecture - x86.x64 on the Intel legs (win-x86, win-x64), ARM64 on the Arm leg (win-arm64) - and run it before the publish step. Installing just the architecture's component keeps the download to the minimum that still provides link.exe and the MSVC libraries; the .NET ILCompiler then discovers the toolchain through the Visual Studio setup API. Assisted-by: Claude Opus 4.8 Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A top-to-bottom rework of how the repository is laid out and built. Flattens the
src/sharedtree intosrc/, renames the executable togit-credential-manager, and replaces the per-platform packaging projects with a uniformbuild/<os>layout driven by thin scripts over ashared CLI scripting library. Migrates the solution to SLNX, adopts the .NET 10 artifacts-output layout, refreshes CI and docs, and restores the .NET tool package.
Why
The
src/{windows,osx,linux}+src/sharedsplit is a relic from when code was platform-partitioned. Every library is cross-platform now, so the structure only adds noise, and the old monolithiclayout.sh/pack.shpackaging was hard to follow and inconsistent across platforms. This branch makes the layout flat and the packaging uniform, and brings the build onto current .NET conventions (SLNX,UseArtifactsOutput, NoTargets distribution projects).What changes
Project layout
src/(pure move — identical assemblies); relocate the scopedDirectory.Build.props.Git-Credential-Manager→git-credential-managerso project, directory and output binary all match the command name.build/msbuild(renamedMSBuildTasks).Packaging (uniform
build/<os>)lib-cli.sh,lib-cli.psm1): logging, path/version/config resolution, flag parsing.build/<os>with a*.Distribution.csproj(NoTargets) anchoring each in the solution plus thinpublish/pack/archivescripts.Solution & .NET 10 config
UseArtifactsOutput(everything underout/), default tonet10.0, bump the SDK to 10.0, registerMicrosoft.Build.NoTargets, normaliseVERSION.*.Distribution.csproj<Build Project="false" />so a plaindotnet build/dotnet testbuilds only the product and tests — no accidental publish-and-package side effects. They still build directly viadotnet build build/<os>.install-from-source
build/install-from-source.sh: detect OS, bootstrap deps, publish via the per-OS script, stage under<prefix>/share/gcm-corewith a<prefix>/binlauncher symlink.--aotopts into the native toolchain.sudoonly when the prefix isn't writable. Fixes two latent bugs from the old script (multi-SDK detection, cwd change breaking repo detection).--aot/--no-aottoggle to the publish scripts (defaults to AOT, so the shipped package is unchanged)..NET tool
git-credential-manager.NET tool packaging underbuild/dntool(framework-dependent IL; pack the code-signed layout with--no-build).CI & docs
build/entry points and flattened paths; add the ESRPsign.ymltemplate; add jobs to build and (on release) sign + publish the .NET tool; validate install-from-source on the new path and on macOS.Notes
dotnet build build/<os>.Testing
dotnet build git-credential-manager.slnx(product + tests only)dotnet build build/<os>Requires PR #2366 to be completed first.