From 7aed8686edcf9b24379085b52fe1431c95d11bab Mon Sep 17 00:00:00 2001 From: Matthew John Cheetham Date: Mon, 11 Sep 2023 13:25:30 -0700 Subject: [PATCH 01/11] dotnet: drop .NET 4.7.2 for .NET 8 --- .github/workflows/continuous-integration.yml | 6 +++--- .github/workflows/release.yml | 2 +- Directory.Build.props | 6 ------ docs/development.md | 4 ++-- .../Atlassian.Bitbucket.csproj | 7 +------ src/shared/Core/Core.csproj | 17 +++------------- .../Git-Credential-Manager.csproj | 2 -- src/shared/GitHub/GitHub.csproj | 7 +------ src/shared/GitLab/GitLab.csproj | 7 +------ .../Microsoft.AzureRepos.csproj | 7 +------ .../Installer.Windows.csproj | 4 ++-- src/windows/Installer.Windows/layout.ps1 | 20 +++---------------- 12 files changed, 18 insertions(+), 71 deletions(-) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index d3f304490..7071fa5df 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -37,9 +37,9 @@ jobs: shell: bash run: | mkdir -p artifacts/bin - mv out/windows/Installer.Windows/bin/Release/net472/win-x86 artifacts/bin/ - cp out/windows/Installer.Windows/bin/Release/net472/win-x86.sym/* artifacts/bin/win-x86/ - mv out/windows/Installer.Windows/bin/Release/net472/gcm*.exe artifacts/ + mv out/windows/Installer.Windows/bin/Release/net8.0/win-x86 artifacts/bin/ + cp out/windows/Installer.Windows/bin/Release/net8.0/win-x86.sym/* artifacts/bin/win-x86/ + mv out/windows/Installer.Windows/bin/Release/net8.0/gcm*.exe artifacts/ - name: Upload artifacts uses: actions/upload-artifact@v5 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2640fe21f..e7aee03d9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -200,7 +200,7 @@ jobs: /p:PayloadPath=$env:GITHUB_WORKSPACE\payload /p:NoLayout=true ` --configuration=WindowsRelease mkdir installers - Move-Item -Path .\out\windows\Installer.Windows\bin\Release\net472\*.exe ` + Move-Item -Path .\out\windows\Installer.Windows\bin\Release\net8.0\*.exe ` -Destination $env:GITHUB_WORKSPACE\installers - name: Sign installers with Azure Code Signing diff --git a/Directory.Build.props b/Directory.Build.props index e7ed76eb9..d8c53e0bb 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -26,10 +26,4 @@ true - - - 8.0.5 - - - diff --git a/docs/development.md b/docs/development.md index 0242d68b8..4e9329268 100644 --- a/docs/development.md +++ b/docs/development.md @@ -40,9 +40,9 @@ To build from the command line, run: dotnet build -c WindowsDebug ``` -You can find a copy of the installer .exe file in `out\windows\Installer.Windows\bin\Debug\net472`. +You can find a copy of the installer .exe file in `out\windows\Installer.Windows\bin\Debug\net8.0`. -The flat binaries can also be found in `out\windows\Payload.Windows\bin\Debug\net472\win-x86`. +The flat binaries can also be found in `out\windows\Payload.Windows\bin\Debug\net8.0\win-x86`. ### Linux diff --git a/src/shared/Atlassian.Bitbucket/Atlassian.Bitbucket.csproj b/src/shared/Atlassian.Bitbucket/Atlassian.Bitbucket.csproj index 6aab348f8..d50785fa7 100644 --- a/src/shared/Atlassian.Bitbucket/Atlassian.Bitbucket.csproj +++ b/src/shared/Atlassian.Bitbucket/Atlassian.Bitbucket.csproj @@ -1,8 +1,7 @@  - net8.0 - net8.0;net472 + net8.0 Atlassian.Bitbucket Atlassian.Bitbucket false @@ -13,10 +12,6 @@ - - - - diff --git a/src/shared/Core/Core.csproj b/src/shared/Core/Core.csproj index f2804177b..107be13c1 100644 --- a/src/shared/Core/Core.csproj +++ b/src/shared/Core/Core.csproj @@ -1,8 +1,7 @@  - net8.0 - net8.0;net472 + net8.0 gcmcore GitCredentialManager false @@ -10,23 +9,13 @@ true - - - - - - - - - - - + - + diff --git a/src/shared/Git-Credential-Manager/Git-Credential-Manager.csproj b/src/shared/Git-Credential-Manager/Git-Credential-Manager.csproj index 456adf547..7602123a2 100644 --- a/src/shared/Git-Credential-Manager/Git-Credential-Manager.csproj +++ b/src/shared/Git-Credential-Manager/Git-Credential-Manager.csproj @@ -3,9 +3,7 @@ Exe net8.0 - net472;net8.0 win-x86;osx-x64;linux-x64;osx-arm64;linux-arm64;linux-arm - x86 git-credential-manager GitCredentialManager $(RepoAssetsPath)gcmicon.ico diff --git a/src/shared/GitHub/GitHub.csproj b/src/shared/GitHub/GitHub.csproj index 66a4afd79..2d550fef1 100644 --- a/src/shared/GitHub/GitHub.csproj +++ b/src/shared/GitHub/GitHub.csproj @@ -1,8 +1,7 @@  - net8.0 - net8.0;net472 + net8.0 GitHub GitHub false @@ -13,8 +12,4 @@ - - - - diff --git a/src/shared/GitLab/GitLab.csproj b/src/shared/GitLab/GitLab.csproj index 25c37f2fe..23086c8ee 100644 --- a/src/shared/GitLab/GitLab.csproj +++ b/src/shared/GitLab/GitLab.csproj @@ -1,8 +1,7 @@  - net8.0 - net8.0;net472 + net8.0 GitLab GitLab false @@ -13,8 +12,4 @@ - - - - diff --git a/src/shared/Microsoft.AzureRepos/Microsoft.AzureRepos.csproj b/src/shared/Microsoft.AzureRepos/Microsoft.AzureRepos.csproj index eaf866bfa..1408d63db 100644 --- a/src/shared/Microsoft.AzureRepos/Microsoft.AzureRepos.csproj +++ b/src/shared/Microsoft.AzureRepos/Microsoft.AzureRepos.csproj @@ -1,8 +1,7 @@  - net8.0 - net8.0;net472 + net8.0 Microsoft.AzureRepos Microsoft.AzureRepos false @@ -13,8 +12,4 @@ - - - - diff --git a/src/windows/Installer.Windows/Installer.Windows.csproj b/src/windows/Installer.Windows/Installer.Windows.csproj index bbd49a291..ad64bb373 100644 --- a/src/windows/Installer.Windows/Installer.Windows.csproj +++ b/src/windows/Installer.Windows/Installer.Windows.csproj @@ -3,10 +3,10 @@ - net472 + net8.0 false false - $(PlatformOutPath)Installer.Windows\bin\$(Configuration)\net472\win-x86 + $(PlatformOutPath)Installer.Windows\bin\$(Configuration)\net8.0\win-x86 6.3.1 diff --git a/src/windows/Installer.Windows/layout.ps1 b/src/windows/Installer.Windows/layout.ps1 index 818ee01c6..817fb87b2 100644 --- a/src/windows/Installer.Windows/layout.ps1 +++ b/src/windows/Installer.Windows/layout.ps1 @@ -39,8 +39,9 @@ mkdir -p "$PAYLOAD","$SYMBOLS" | Out-Null # Publish core application executables Write-Output "Publishing core application..." dotnet publish "$GCM_SRC" ` - --framework net472 ` - --configuration "$Configuration" ` + --framework net8.0 ` + --self-contained ` + --configuration "$CONFIGURATION" ` --runtime win-x86 ` --output "$PAYLOAD" @@ -48,21 +49,6 @@ dotnet publish "$GCM_SRC" ` # into the publish output. Remove-Item -Path "$PAYLOAD/*.dylib" -Force -ErrorAction Ignore -# Delete extraneous files that get included for other architectures -# We only care about x86 as the core GCM executable is only targeting x86 -Remove-Item -Path "$PAYLOAD/arm/" -Recurse -Force -ErrorAction Ignore -Remove-Item -Path "$PAYLOAD/arm64/" -Recurse -Force -ErrorAction Ignore -Remove-Item -Path "$PAYLOAD/x64/" -Recurse -Force -ErrorAction Ignore -Remove-Item -Path "$PAYLOAD/musl-x64/" -Recurse -Force -ErrorAction Ignore -Remove-Item -Path "$PAYLOAD/runtimes/win-arm64/" -Recurse -Force -ErrorAction Ignore -Remove-Item -Path "$PAYLOAD/runtimes/win-x64/" -Recurse -Force -ErrorAction Ignore - -# The Avalonia and MSAL binaries in these directories are already included in -# the $PAYLOAD directory directly, so we can delete these extra copies. -Remove-Item -Path "$PAYLOAD/x86/libSkiaSharp.dll" -Recurse -Force -ErrorAction Ignore -Remove-Item -Path "$PAYLOAD/x86/libHarfBuzzSharp.dll" -Recurse -Force -ErrorAction Ignore -Remove-Item -Path "$PAYLOAD/runtimes/win-x86/native/msalruntime_x86.dll" -Recurse -Force -ErrorAction Ignore - # Delete localized resource assemblies - we don't localize the core GCM assembly anyway Get-ChildItem "$PAYLOAD" -Recurse -Include "*.resources.dll" | Remove-Item -Force -ErrorAction Ignore From a14b83f6a6d1ccc6cca944c377b995094bda516e Mon Sep 17 00:00:00 2001 From: Matthew John Cheetham Date: Mon, 11 Sep 2023 15:04:15 -0700 Subject: [PATCH 02/11] dotnet: drop .NET Framework-specific code --- .../Core/Authentication/AuthenticationBase.cs | 4 --- .../Authentication/MicrosoftAuthentication.cs | 29 +++++-------------- src/shared/Core/CurlCookie.cs | 12 ++------ src/shared/Core/HttpClientFactory.cs | 20 ------------- .../Core/Interop/Posix/PosixFileSystem.cs | 10 ------- .../Core/Interop/Windows/WindowsSettings.cs | 4 --- src/shared/Core/PlatformUtils.cs | 13 +-------- src/shared/Core/UI/AvaloniaUi.cs | 7 ----- src/shared/Git-Credential-Manager/Program.cs | 5 ---- 9 files changed, 12 insertions(+), 92 deletions(-) diff --git a/src/shared/Core/Authentication/AuthenticationBase.cs b/src/shared/Core/Authentication/AuthenticationBase.cs index 03e4d8ca6..ca3be4173 100644 --- a/src/shared/Core/Authentication/AuthenticationBase.cs +++ b/src/shared/Core/Authentication/AuthenticationBase.cs @@ -60,11 +60,7 @@ protected internal virtual async Task> InvokeHelperA // Write the standard input to the process if we have any to write if (standardInput is not null) { -#if NETFRAMEWORK - await standardInput.BaseStream.CopyToAsync(process.StandardInput.BaseStream); -#else await standardInput.BaseStream.CopyToAsync(process.StandardInput.BaseStream, ct); -#endif process.StandardInput.Close(); } diff --git a/src/shared/Core/Authentication/MicrosoftAuthentication.cs b/src/shared/Core/Authentication/MicrosoftAuthentication.cs index 12bccf5fe..51226fcc1 100644 --- a/src/shared/Core/Authentication/MicrosoftAuthentication.cs +++ b/src/shared/Core/Authentication/MicrosoftAuthentication.cs @@ -15,10 +15,7 @@ using GitCredentialManager.UI.ViewModels; using GitCredentialManager.UI.Views; using Microsoft.Identity.Client.AppConfig; - -#if NETFRAMEWORK using Microsoft.Identity.Client.Broker; -#endif namespace GitCredentialManager.Authentication { @@ -508,7 +505,6 @@ private async Task CreatePublicClientApplicationAsync( // to save on the distribution size of the .NET builds (no need for MSALRuntime bits). if (enableBroker) { -#if NETFRAMEWORK appBuilder.WithBroker( new BrokerOptions(BrokerOptions.OperatingSystems.Windows) { @@ -516,7 +512,6 @@ private async Task CreatePublicClientApplicationAsync( MsaPassthrough = msaPt, } ); -#endif } IPublicClientApplication app = appBuilder.Build(); @@ -808,7 +803,6 @@ public HttpClient GetHttpClient() public bool CanUseBroker() { -#if NETFRAMEWORK // We only support the broker on Windows 10+ and in an interactive session if (!Context.SessionManager.IsDesktopSession || !PlatformUtils.IsWindowsBrokerSupported()) { @@ -827,34 +821,27 @@ public bool CanUseBroker() } return defaultValue; -#else - // OS broker requires .NET Framework right now until we migrate to .NET 5.0 (net5.0-windows10.x.y.z) - return false; -#endif } private bool CanUseEmbeddedWebView() { - // If we're in an interactive session and on .NET Framework then MSAL can show the WinForms-based embedded UI -#if NETFRAMEWORK - return Context.SessionManager.IsDesktopSession; -#else - return false; -#endif + // If we're in an interactive session and on Windows then MSAL can show the WinForms-based embedded UI + return PlatformUtils.IsWindows() && Context.SessionManager.IsDesktopSession; } private void EnsureCanUseEmbeddedWebView() { -#if NETFRAMEWORK if (!Context.SessionManager.IsDesktopSession) { throw new Trace2InvalidOperationException(Context.Trace2, "Embedded web view is not available without a desktop session."); } -#else - throw new Trace2InvalidOperationException(Context.Trace2, - "Embedded web view is not available on .NET Core."); -#endif + + if (!PlatformUtils.IsWindows()) + { + throw new Trace2InvalidOperationException(Context.Trace2, + "Embedded web view is only available on Windows."); + } } private bool CanUseSystemWebView(IPublicClientApplication app, Uri redirectUri) diff --git a/src/shared/Core/CurlCookie.cs b/src/shared/Core/CurlCookie.cs index e3a5fa140..c9ba2b7bd 100644 --- a/src/shared/Core/CurlCookie.cs +++ b/src/shared/Core/CurlCookie.cs @@ -66,18 +66,12 @@ public IList Parse(string content) private static DateTime ParseExpires(string expires) { -#if NETFRAMEWORK - DateTime epoch = new DateTime(1970, 01, 01, 0, 0, 0, DateTimeKind.Utc); -#else - DateTime epoch = DateTime.UnixEpoch; -#endif - if (long.TryParse(expires, out long i)) { - return epoch.AddSeconds(i); + return DateTime.UnixEpoch.AddSeconds(i); } - return epoch; + return DateTime.UnixEpoch; } } -} \ No newline at end of file +} diff --git a/src/shared/Core/HttpClientFactory.cs b/src/shared/Core/HttpClientFactory.cs index c48e277e5..dc8f29f7c 100644 --- a/src/shared/Core/HttpClientFactory.cs +++ b/src/shared/Core/HttpClientFactory.cs @@ -99,11 +99,7 @@ public HttpClient CreateClient() _streams.Error.WriteLine("warning: ---------------------------------------------------"); _streams.Error.WriteLine($"warning: HTTPS connections may not be secure. See {Constants.HelpUrls.GcmTlsVerification} for more information."); -#if NETFRAMEWORK - ServicePointManager.ServerCertificateValidationCallback = (req, cert, chain, errors) => true; -#else handler.ServerCertificateCustomValidationCallback = (req, cert, chain, errors) => true; -#endif } // If schannel is the TLS backend, custom certificate usage must be explicitly enabled else if (!string.IsNullOrWhiteSpace(_settings.CustomCertificateBundlePath) && @@ -178,23 +174,7 @@ public HttpClient CreateClient() // Set the custom server certificate validation callback. // NOTE: this is executed after the default platform server certificate validation is performed -#if NETFRAMEWORK - ServicePointManager.ServerCertificateValidationCallback = (_, cert, chain, errors) => - { - // Fail immediately if the cert or chain isn't present - if (cert is null || chain is null) - { - return false; - } - - using (X509Certificate2 cert2 = new X509Certificate2(cert)) - { - return validationCallback(cert2, chain, errors); - } - }; -#else handler.ServerCertificateCustomValidationCallback = (_, cert, chain, errors) => validationCallback(cert, chain, errors); -#endif } // If CustomCookieFilePath is set, set Cookie header from cookie file, which is written by libcurl diff --git a/src/shared/Core/Interop/Posix/PosixFileSystem.cs b/src/shared/Core/Interop/Posix/PosixFileSystem.cs index ec7ff8d50..06660bc2f 100644 --- a/src/shared/Core/Interop/Posix/PosixFileSystem.cs +++ b/src/shared/Core/Interop/Posix/PosixFileSystem.cs @@ -13,13 +13,6 @@ public abstract class PosixFileSystem : FileSystem /// Path is not absolute. protected internal static string ResolveSymbolicLinks(string path) { -#if NETFRAMEWORK - // Support for symlinks only exists in .NET 6+. - // Since we're still targeting .NET Framework on Windows it - // doesn't matter if we don't resolve symlinks for POSIX here - // (unless we're running on Mono.. but why do that?) - return path; -#else if (!Path.IsPathRooted(path)) { throw new ArgumentException("Path must be absolute", nameof(path)); @@ -54,10 +47,8 @@ protected internal static string ResolveSymbolicLinks(string path) } return Path.Combine("/", partialPath); -#endif } -#if !NETFRAMEWORK private static bool TryResolveFileLink(string path, out string target) { FileSystemInfo fsi = File.ResolveLinkTarget(path, true); @@ -71,6 +62,5 @@ private static bool TryResolveDirectoryLink(string path, out string target) target = fsi?.FullName; return fsi != null; } -#endif } } diff --git a/src/shared/Core/Interop/Windows/WindowsSettings.cs b/src/shared/Core/Interop/Windows/WindowsSettings.cs index abdd9ee0e..0e4e4e20b 100644 --- a/src/shared/Core/Interop/Windows/WindowsSettings.cs +++ b/src/shared/Core/Interop/Windows/WindowsSettings.cs @@ -21,7 +21,6 @@ protected override bool TryGetExternalDefault(string section, string scope, stri { value = null; -#if NETFRAMEWORK // Check for machine (HKLM) registry keys that match the Git configuration name. // These can be set by system administrators via Group Policy, so make useful defaults. using (Microsoft.Win32.RegistryKey configKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(Constants.WindowsRegistry.HKConfigurationPath)) @@ -48,9 +47,6 @@ protected override bool TryGetExternalDefault(string section, string scope, stri return true; } -#else - return base.TryGetExternalDefault(section, scope, property, out value); -#endif } } } diff --git a/src/shared/Core/PlatformUtils.cs b/src/shared/Core/PlatformUtils.cs index 8872827d4..1c45f40c5 100644 --- a/src/shared/Core/PlatformUtils.cs +++ b/src/shared/Core/PlatformUtils.cs @@ -31,7 +31,6 @@ public static bool IsDevBox() return false; } -#if NETFRAMEWORK // Check for machine (HKLM) registry keys for Cloud PC indicators // Note that the keys are only found in the 64-bit registry view using (Microsoft.Win32.RegistryKey hklm64 = Microsoft.Win32.RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, Microsoft.Win32.RegistryView.Registry64)) @@ -48,9 +47,6 @@ public static bool IsDevBox() return w365Value is not null && Guid.TryParse(partnerValue, out Guid partnerId) && partnerId == Constants.DevBoxPartnerId; } -#else - return false; -#endif } /// @@ -197,11 +193,9 @@ public static bool IsElevatedUser() { if (IsWindows()) { -#if NETFRAMEWORK var identity = System.Security.Principal.WindowsIdentity.GetCurrent(); var principal = new System.Security.Principal.WindowsPrincipal(identity); return principal.IsInRole(System.Security.Principal.WindowsBuiltInRole.Administrator); -#endif } else if (IsPosix()) { @@ -287,9 +281,6 @@ private static string GetLinuxEntryPath() } } -#if NETFRAMEWORK - return null; -#else // // We cannot determine the absolute file path from argv[0] // (how we were launched), so let's now try to extract the @@ -299,7 +290,6 @@ private static string GetLinuxEntryPath() // FileSystemInfo fsi = File.ResolveLinkTarget("/proc/self/exe", returnFinalTarget: false); return fsi?.FullName; -#endif } private static string GetMacOSEntryPath() @@ -368,12 +358,11 @@ private static string GetOSVersion(ITrace2 trace2) // However, we still need to use the old method for Windows on .NET Framework // and call into the Win32 API to get the correct version (regardless of app // compatibility settings). -#if NETFRAMEWORK if (IsWindows() && RtlGetVersionEx(out RTL_OSVERSIONINFOEX osvi) == 0) { return $"{osvi.dwMajorVersion}.{osvi.dwMinorVersion} (build {osvi.dwBuildNumber})"; } -#endif + if (IsWindows() || IsMacOS()) { return Environment.OSVersion.Version.ToString(); diff --git a/src/shared/Core/UI/AvaloniaUi.cs b/src/shared/Core/UI/AvaloniaUi.cs index 34021c595..e813802c8 100644 --- a/src/shared/Core/UI/AvaloniaUi.cs +++ b/src/shared/Core/UI/AvaloniaUi.cs @@ -65,22 +65,15 @@ public static Task ShowWindowAsync(Func windowFunc, object dataContext, { var appBuilder = AppBuilder.Configure(); -#if NETFRAMEWORK // Set custom rendering options and modes if required if (PlatformUtils.IsWindows() && _win32SoftwareRendering) { appBuilder.With(new Win32PlatformOptions { RenderingMode = new[] { Win32RenderingMode.Software } }); } -#endif appBuilder -#if NETFRAMEWORK - .UseWin32() - .UseSkia() -#else .UsePlatformDetect() -#endif .LogToTrace() .SetupWithoutStarting(); diff --git a/src/shared/Git-Credential-Manager/Program.cs b/src/shared/Git-Credential-Manager/Program.cs index 59f579b9f..b8aa0eb7c 100644 --- a/src/shared/Git-Credential-Manager/Program.cs +++ b/src/shared/Git-Credential-Manager/Program.cs @@ -76,12 +76,7 @@ private static void AppMain(object o) // Required for Avalonia designer static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure() -#if NETFRAMEWORK - .UseWin32() - .UseSkia() -#else .UsePlatformDetect() -#endif .LogToTrace(); } } From c66c821232a1e480fa2fd1ebfd7dd56924ed2813 Mon Sep 17 00:00:00 2001 From: Matthew John Cheetham Date: Mon, 18 Sep 2023 12:26:12 -0700 Subject: [PATCH 03/11] build: annotate platform-specific code Annotate any OS or platform specific code with the new (Un)SupportedOSPlatform(Guard) attributes and update various platform util methods to use the OperatingSystem.Is methods. This will help ensure we're not missing any OS checks in the future. For test projects we ignore these warnings since we're using skipping Xunit tests that are not applicable for the current platform already, making these warnings just noise. --- Directory.Build.targets | 5 +++++ src/shared/Core/Constants.cs | 5 +++++ .../Core/Interop/Linux/LinuxFileSystem.cs | 2 ++ .../Core/Interop/Linux/LinuxSessionManager.cs | 2 ++ .../Core/Interop/Linux/LinuxTerminal.cs | 2 ++ .../Core/Interop/MacOS/MacOSEnvironment.cs | 2 ++ .../Core/Interop/MacOS/MacOSFileSystem.cs | 2 ++ .../Core/Interop/MacOS/MacOSSessionManager.cs | 2 ++ .../Core/Interop/MacOS/MacOSTerminal.cs | 2 ++ .../Core/Interop/Posix/PosixEnvironment.cs | 3 +++ .../Interop/Windows/WindowsEnvironment.cs | 2 ++ .../Core/Interop/Windows/WindowsFileSystem.cs | 2 ++ .../Interop/Windows/WindowsProcessManager.cs | 3 +++ .../Interop/Windows/WindowsSessionManager.cs | 2 ++ .../Core/Interop/Windows/WindowsSettings.cs | 3 +++ .../Core/Interop/Windows/WindowsTerminal.cs | 2 ++ src/shared/Core/PlatformUtils.cs | 20 ++++++++++++++++--- 17 files changed, 58 insertions(+), 3 deletions(-) diff --git a/Directory.Build.targets b/Directory.Build.targets index 7ec523390..9952407be 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -34,4 +34,9 @@ + + + $(NoWarn);CA1416 + + diff --git a/src/shared/Core/Constants.cs b/src/shared/Core/Constants.cs index 4777b0cf8..ba5142c72 100644 --- a/src/shared/Core/Constants.cs +++ b/src/shared/Core/Constants.cs @@ -17,6 +17,11 @@ public static class Constants public const string GcmDataDirectoryName = ".gcm"; public const string MacOSBundleId = "git-credential-manager"; + + public const string WindowsPlatformName = "windows"; + public const string LinuxPlatformName = "linux"; + public const string MacOSPlatformName = "osx"; + public static readonly Guid DevBoxPartnerId = new("e3171dd9-9a5f-e5be-b36c-cc7c4f3f3bcf"); /// diff --git a/src/shared/Core/Interop/Linux/LinuxFileSystem.cs b/src/shared/Core/Interop/Linux/LinuxFileSystem.cs index aa064886d..fb76641a3 100644 --- a/src/shared/Core/Interop/Linux/LinuxFileSystem.cs +++ b/src/shared/Core/Interop/Linux/LinuxFileSystem.cs @@ -1,9 +1,11 @@ using System; using System.IO; +using System.Runtime.Versioning; using GitCredentialManager.Interop.Posix; namespace GitCredentialManager.Interop.Linux { + [SupportedOSPlatform(Constants.LinuxPlatformName)] public class LinuxFileSystem : PosixFileSystem { public override bool IsSamePath(string a, string b) diff --git a/src/shared/Core/Interop/Linux/LinuxSessionManager.cs b/src/shared/Core/Interop/Linux/LinuxSessionManager.cs index 2147289ac..6e7f12c61 100644 --- a/src/shared/Core/Interop/Linux/LinuxSessionManager.cs +++ b/src/shared/Core/Interop/Linux/LinuxSessionManager.cs @@ -1,7 +1,9 @@ +using System.Runtime.Versioning; using GitCredentialManager.Interop.Posix; namespace GitCredentialManager.Interop.Linux; +[SupportedOSPlatform(Constants.LinuxPlatformName)] public class LinuxSessionManager : PosixSessionManager { private bool? _isWebBrowserAvailable; diff --git a/src/shared/Core/Interop/Linux/LinuxTerminal.cs b/src/shared/Core/Interop/Linux/LinuxTerminal.cs index f7ea6f89a..1697ae7e2 100644 --- a/src/shared/Core/Interop/Linux/LinuxTerminal.cs +++ b/src/shared/Core/Interop/Linux/LinuxTerminal.cs @@ -1,10 +1,12 @@ using System; +using System.Runtime.Versioning; using GitCredentialManager.Interop.Linux.Native; using GitCredentialManager.Interop.Posix; using GitCredentialManager.Interop.Posix.Native; namespace GitCredentialManager.Interop.Linux { + [SupportedOSPlatform(Constants.LinuxPlatformName)] public class LinuxTerminal : PosixTerminal { public LinuxTerminal(ITrace trace, ITrace2 trace2) diff --git a/src/shared/Core/Interop/MacOS/MacOSEnvironment.cs b/src/shared/Core/Interop/MacOS/MacOSEnvironment.cs index 256e81cb9..4e88e4b55 100644 --- a/src/shared/Core/Interop/MacOS/MacOSEnvironment.cs +++ b/src/shared/Core/Interop/MacOS/MacOSEnvironment.cs @@ -2,11 +2,13 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; +using System.Runtime.Versioning; using System.Threading; using GitCredentialManager.Interop.Posix; namespace GitCredentialManager.Interop.MacOS { + [SupportedOSPlatform(Constants.MacOSPlatformName)] public class MacOSEnvironment : PosixEnvironment { private ICollection _pathsToIgnore; diff --git a/src/shared/Core/Interop/MacOS/MacOSFileSystem.cs b/src/shared/Core/Interop/MacOS/MacOSFileSystem.cs index 1f2e1e666..af80fcacf 100644 --- a/src/shared/Core/Interop/MacOS/MacOSFileSystem.cs +++ b/src/shared/Core/Interop/MacOS/MacOSFileSystem.cs @@ -1,9 +1,11 @@ using System; using System.IO; +using System.Runtime.Versioning; using GitCredentialManager.Interop.Posix; namespace GitCredentialManager.Interop.MacOS { + [SupportedOSPlatform(Constants.MacOSPlatformName)] public class MacOSFileSystem : PosixFileSystem { public override bool IsSamePath(string a, string b) diff --git a/src/shared/Core/Interop/MacOS/MacOSSessionManager.cs b/src/shared/Core/Interop/MacOS/MacOSSessionManager.cs index 584965ca1..cffcdd6c0 100644 --- a/src/shared/Core/Interop/MacOS/MacOSSessionManager.cs +++ b/src/shared/Core/Interop/MacOS/MacOSSessionManager.cs @@ -1,8 +1,10 @@ +using System.Runtime.Versioning; using GitCredentialManager.Interop.MacOS.Native; using GitCredentialManager.Interop.Posix; namespace GitCredentialManager.Interop.MacOS { + [SupportedOSPlatform(Constants.MacOSPlatformName)] public class MacOSSessionManager : PosixSessionManager { public MacOSSessionManager(IEnvironment env, IFileSystem fs) : base(env, fs) diff --git a/src/shared/Core/Interop/MacOS/MacOSTerminal.cs b/src/shared/Core/Interop/MacOS/MacOSTerminal.cs index a4c9d2120..1357d3b16 100644 --- a/src/shared/Core/Interop/MacOS/MacOSTerminal.cs +++ b/src/shared/Core/Interop/MacOS/MacOSTerminal.cs @@ -1,10 +1,12 @@ using System; +using System.Runtime.Versioning; using GitCredentialManager.Interop.MacOS.Native; using GitCredentialManager.Interop.Posix; using GitCredentialManager.Interop.Posix.Native; namespace GitCredentialManager.Interop.MacOS { + [SupportedOSPlatform(Constants.MacOSPlatformName)] public class MacOSTerminal : PosixTerminal { public MacOSTerminal(ITrace trace, ITrace2 trace2) diff --git a/src/shared/Core/Interop/Posix/PosixEnvironment.cs b/src/shared/Core/Interop/Posix/PosixEnvironment.cs index ec3d91c92..e3140daf4 100644 --- a/src/shared/Core/Interop/Posix/PosixEnvironment.cs +++ b/src/shared/Core/Interop/Posix/PosixEnvironment.cs @@ -1,9 +1,12 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.Versioning; namespace GitCredentialManager.Interop.Posix { + [SupportedOSPlatform(Constants.LinuxPlatformName)] + [SupportedOSPlatform(Constants.MacOSPlatformName)] public class PosixEnvironment : EnvironmentBase { public PosixEnvironment(IFileSystem fileSystem) diff --git a/src/shared/Core/Interop/Windows/WindowsEnvironment.cs b/src/shared/Core/Interop/Windows/WindowsEnvironment.cs index 6c3450a38..246a44250 100644 --- a/src/shared/Core/Interop/Windows/WindowsEnvironment.cs +++ b/src/shared/Core/Interop/Windows/WindowsEnvironment.cs @@ -3,10 +3,12 @@ using System.Diagnostics; using System.IO; using System.Linq; +using System.Runtime.Versioning; using System.Text; namespace GitCredentialManager.Interop.Windows { + [SupportedOSPlatform(Constants.WindowsPlatformName)] public class WindowsEnvironment : EnvironmentBase { public WindowsEnvironment(IFileSystem fileSystem) diff --git a/src/shared/Core/Interop/Windows/WindowsFileSystem.cs b/src/shared/Core/Interop/Windows/WindowsFileSystem.cs index c1a64631c..6de36c718 100644 --- a/src/shared/Core/Interop/Windows/WindowsFileSystem.cs +++ b/src/shared/Core/Interop/Windows/WindowsFileSystem.cs @@ -1,8 +1,10 @@ using System; using System.IO; +using System.Runtime.Versioning; namespace GitCredentialManager.Interop.Windows { + [SupportedOSPlatform(Constants.WindowsPlatformName)] public class WindowsFileSystem : FileSystem { public override bool IsSamePath(string a, string b) diff --git a/src/shared/Core/Interop/Windows/WindowsProcessManager.cs b/src/shared/Core/Interop/Windows/WindowsProcessManager.cs index 85d47b0de..4b55e8e92 100644 --- a/src/shared/Core/Interop/Windows/WindowsProcessManager.cs +++ b/src/shared/Core/Interop/Windows/WindowsProcessManager.cs @@ -1,5 +1,8 @@ +using System.Runtime.Versioning; + namespace GitCredentialManager.Interop.Windows; +[SupportedOSPlatform(Constants.WindowsPlatformName)] public class WindowsProcessManager : ProcessManager { public WindowsProcessManager(ITrace2 trace2) : base(trace2) diff --git a/src/shared/Core/Interop/Windows/WindowsSessionManager.cs b/src/shared/Core/Interop/Windows/WindowsSessionManager.cs index d87d76347..4bb1a2dd3 100644 --- a/src/shared/Core/Interop/Windows/WindowsSessionManager.cs +++ b/src/shared/Core/Interop/Windows/WindowsSessionManager.cs @@ -1,8 +1,10 @@ using System; +using System.Runtime.Versioning; using GitCredentialManager.Interop.Windows.Native; namespace GitCredentialManager.Interop.Windows { + [SupportedOSPlatform(Constants.WindowsPlatformName)] public class WindowsSessionManager : SessionManager { public WindowsSessionManager(IEnvironment env, IFileSystem fs) : base(env, fs) diff --git a/src/shared/Core/Interop/Windows/WindowsSettings.cs b/src/shared/Core/Interop/Windows/WindowsSettings.cs index 0e4e4e20b..8566726bd 100644 --- a/src/shared/Core/Interop/Windows/WindowsSettings.cs +++ b/src/shared/Core/Interop/Windows/WindowsSettings.cs @@ -1,9 +1,12 @@ +using System.Runtime.Versioning; + namespace GitCredentialManager.Interop.Windows { /// /// Reads settings from Git configuration, environment variables, and defaults from the Windows Registry. /// + [SupportedOSPlatform(Constants.WindowsPlatformName)] public class WindowsSettings : Settings { private readonly ITrace _trace; diff --git a/src/shared/Core/Interop/Windows/WindowsTerminal.cs b/src/shared/Core/Interop/Windows/WindowsTerminal.cs index b8f5f3475..09da26275 100644 --- a/src/shared/Core/Interop/Windows/WindowsTerminal.cs +++ b/src/shared/Core/Interop/Windows/WindowsTerminal.cs @@ -1,5 +1,6 @@ using System; using System.Runtime.InteropServices; +using System.Runtime.Versioning; using System.Text; using GitCredentialManager.Interop.Windows.Native; using Microsoft.Win32.SafeHandles; @@ -9,6 +10,7 @@ namespace GitCredentialManager.Interop.Windows /// /// Represents a thin wrapper around the Windows console device. /// + [SupportedOSPlatform(Constants.WindowsPlatformName)] public class WindowsTerminal : ITerminal { // ReadConsole 32768 fail, 32767 OK @linquize [https://github.com/Microsoft/Git-Credential-Manager-for-Windows/commit/a62b9a19f430d038dcd85a610d97e5f763980f85] diff --git a/src/shared/Core/PlatformUtils.cs b/src/shared/Core/PlatformUtils.cs index 1c45f40c5..ab44cc73d 100644 --- a/src/shared/Core/PlatformUtils.cs +++ b/src/shared/Core/PlatformUtils.cs @@ -1,9 +1,11 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Runtime.InteropServices; +using System.Runtime.Versioning; using GitCredentialManager.Interop.Posix.Native; namespace GitCredentialManager @@ -24,6 +26,7 @@ public static PlatformInformation GetPlatformInformation(ITrace2 trace2) return new PlatformInformation(osType, osVersion, cpuArch, clrVersion); } + [SupportedOSPlatformGuard(Constants.WindowsPlatformName)] public static bool IsDevBox() { if (!IsWindows()) @@ -65,6 +68,7 @@ public static bool IsArm() } } + [SupportedOSPlatformGuard(Constants.WindowsPlatformName)] public static bool IsWindowsBrokerSupported() { if (!IsWindows()) @@ -109,33 +113,38 @@ public static bool IsWindowsBrokerSupported() /// Check if the current Operating System is macOS. /// /// True if running on macOS, false otherwise. + [SupportedOSPlatformGuard(Constants.MacOSPlatformName)] public static bool IsMacOS() { - return RuntimeInformation.IsOSPlatform(OSPlatform.OSX); + return OperatingSystem.IsMacOS(); } /// /// Check if the current Operating System is Windows. /// /// True if running on Windows, false otherwise. + [SupportedOSPlatformGuard(Constants.WindowsPlatformName)] public static bool IsWindows() { - return RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + return OperatingSystem.IsWindows(); } /// /// Check if the current Operating System is Linux-based. /// /// True if running on a Linux distribution, false otherwise. + [SupportedOSPlatformGuard(Constants.LinuxPlatformName)] public static bool IsLinux() { - return RuntimeInformation.IsOSPlatform(OSPlatform.Linux); + return OperatingSystem.IsLinux(); } /// /// Check if the current Operating System is POSIX-compliant. /// /// True if running on a POSIX-compliant Operating System, false otherwise. + [SupportedOSPlatformGuard(Constants.LinuxPlatformName)] + [SupportedOSPlatformGuard(Constants.MacOSPlatformName)] public static bool IsPosix() { return IsMacOS() || IsLinux(); @@ -145,6 +154,7 @@ public static bool IsPosix() /// Ensure the current Operating System is macOS, fail otherwise. /// /// Thrown if the current OS is not macOS. + [SupportedOSPlatformGuard(Constants.MacOSPlatformName)] public static void EnsureMacOS() { if (!IsMacOS()) @@ -157,6 +167,7 @@ public static void EnsureMacOS() /// Ensure the current Operating System is Windows, fail otherwise. /// /// Thrown if the current OS is not Windows. + [SupportedOSPlatformGuard(Constants.WindowsPlatformName)] public static void EnsureWindows() { if (!IsWindows()) @@ -169,6 +180,7 @@ public static void EnsureWindows() /// Ensure the current Operating System is Linux-based, fail otherwise. /// /// Thrown if the current OS is not Linux-based. + [SupportedOSPlatformGuard(Constants.LinuxPlatformName)] public static void EnsureLinux() { if (!IsLinux()) @@ -181,6 +193,8 @@ public static void EnsureLinux() /// Ensure the current Operating System is POSIX-compliant, fail otherwise. /// /// Thrown if the current OS is not POSIX-compliant. + [SupportedOSPlatformGuard(Constants.LinuxPlatformName)] + [SupportedOSPlatformGuard(Constants.MacOSPlatformName)] public static void EnsurePosix() { if (!IsPosix()) From 2b8ecb68da5d148d6fb3fd8e3f764b09c97b4123 Mon Sep 17 00:00:00 2001 From: Matthew John Cheetham Date: Wed, 20 Sep 2023 13:43:29 -0700 Subject: [PATCH 04/11] ci: install .NET 8 SDK in CI and builds --- .github/workflows/codeql-analysis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 7ec8fbe4f..bb0c9f8b7 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -29,6 +29,11 @@ jobs: with: dotnet-version: 8.0.x + - name: Setup .NET + uses: actions/setup-dotnet@v3.2.0 + with: + dotnet-version: 8.0.x + # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v4 From 4393c6a1c35df8b5f9f4a000336fd8cf5deab45d Mon Sep 17 00:00:00 2001 From: Matthew John Cheetham Date: Wed, 13 Sep 2023 14:35:38 -0700 Subject: [PATCH 05/11] avalonia: enable compiled bindings for all UI --- .../Atlassian.Bitbucket/UI/Views/CredentialsView.axaml | 2 ++ src/shared/Core/UI/Controls/AboutWindow.axaml | 3 +++ src/shared/Core/UI/Controls/DialogWindow.axaml | 4 +++- src/shared/Core/UI/Controls/ProgressWindow.axaml | 1 + src/shared/Core/UI/Views/CredentialsView.axaml | 2 ++ src/shared/Core/UI/Views/DefaultAccountView.axaml | 2 ++ src/shared/Core/UI/Views/DeviceCodeView.axaml | 6 ++++-- src/shared/Core/UI/Views/OAuthView.axaml | 2 ++ src/shared/GitHub/UI/Views/CredentialsView.axaml | 2 ++ src/shared/GitHub/UI/Views/DeviceCodeView.axaml | 2 ++ src/shared/GitHub/UI/Views/SelectAccountView.axaml | 2 ++ src/shared/GitHub/UI/Views/TwoFactorView.axaml | 2 ++ src/shared/GitLab/UI/Views/CredentialsView.axaml | 2 ++ 13 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/shared/Atlassian.Bitbucket/UI/Views/CredentialsView.axaml b/src/shared/Atlassian.Bitbucket/UI/Views/CredentialsView.axaml index 717500b7b..e50a49f88 100644 --- a/src/shared/Atlassian.Bitbucket/UI/Views/CredentialsView.axaml +++ b/src/shared/Atlassian.Bitbucket/UI/Views/CredentialsView.axaml @@ -5,6 +5,8 @@ xmlns:vm="clr-namespace:Atlassian.Bitbucket.UI.ViewModels;assembly=Atlassian.Bitbucket" xmlns:converters="clr-namespace:GitCredentialManager.UI.Converters;assembly=gcmcore" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" + x:DataType="vm:CredentialsViewModel" + x:CompileBindings="True" x:Class="Atlassian.Bitbucket.UI.Views.CredentialsView"> diff --git a/src/shared/Core/UI/Controls/AboutWindow.axaml b/src/shared/Core/UI/Controls/AboutWindow.axaml index bccc1217d..8d7e63f17 100644 --- a/src/shared/Core/UI/Controls/AboutWindow.axaml +++ b/src/shared/Core/UI/Controls/AboutWindow.axaml @@ -3,11 +3,14 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:gcm="clr-namespace:GitCredentialManager" + xmlns:controls="clr-namespace:GitCredentialManager.UI.Controls" mc:Ignorable="d" d:DesignWidth="300" d:DesignHeight="450" x:Class="GitCredentialManager.UI.Controls.AboutWindow" Title="About Git Credential Manager" CanResize="False" Width="300" SizeToContent="Height" x:Name="window" + x:DataType="controls:AboutWindow" + x:CompileBindings="True" Background="{DynamicResource WindowBackgroundBrush}"> + KeyUp="Window_KeyUp" + x:DataType="vm:WindowViewModel" + x:CompileBindings="True"> diff --git a/src/shared/Core/UI/Controls/ProgressWindow.axaml b/src/shared/Core/UI/Controls/ProgressWindow.axaml index 3bfc20f5c..962c0b73c 100644 --- a/src/shared/Core/UI/Controls/ProgressWindow.axaml +++ b/src/shared/Core/UI/Controls/ProgressWindow.axaml @@ -6,6 +6,7 @@ SizeToContent="WidthAndHeight" CanResize="False" Topmost="True" ExtendClientAreaChromeHints="NoChrome" ExtendClientAreaToDecorationsHint="True" ShowInTaskbar="False" Title="Git Credential Manager" WindowStartupLocation="CenterScreen" + x:CompileBindings="True" x:Class="GitCredentialManager.UI.Controls.ProgressWindow"> diff --git a/src/shared/Core/UI/Views/DefaultAccountView.axaml b/src/shared/Core/UI/Views/DefaultAccountView.axaml index 83a677220..39b9133aa 100644 --- a/src/shared/Core/UI/Views/DefaultAccountView.axaml +++ b/src/shared/Core/UI/Views/DefaultAccountView.axaml @@ -5,6 +5,8 @@ xmlns:vm="clr-namespace:GitCredentialManager.UI.ViewModels;assembly=gcmcore" xmlns:converters="clr-namespace:GitCredentialManager.UI.Converters;assembly=gcmcore" mc:Ignorable="d" d:DesignWidth="420" + x:DataType="vm:DefaultAccountViewModel" + x:CompileBindings="True" x:Class="GitCredentialManager.UI.Views.DefaultAccountView"> diff --git a/src/shared/Core/UI/Views/DeviceCodeView.axaml b/src/shared/Core/UI/Views/DeviceCodeView.axaml index ea14072cf..79e02abab 100644 --- a/src/shared/Core/UI/Views/DeviceCodeView.axaml +++ b/src/shared/Core/UI/Views/DeviceCodeView.axaml @@ -2,11 +2,13 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:sharedVms="clr-namespace:GitCredentialManager.UI.ViewModels;assembly=gcmcore" + xmlns:vm="clr-namespace:GitCredentialManager.UI.ViewModels;assembly=gcmcore" mc:Ignorable="d" d:DesignWidth="420" + x:DataType="vm:DeviceCodeViewModel" + x:CompileBindings="True" x:Class="GitCredentialManager.UI.Views.DeviceCodeView"> - + diff --git a/src/shared/Core/UI/Views/OAuthView.axaml b/src/shared/Core/UI/Views/OAuthView.axaml index abf9afc5e..465e860cd 100644 --- a/src/shared/Core/UI/Views/OAuthView.axaml +++ b/src/shared/Core/UI/Views/OAuthView.axaml @@ -4,6 +4,8 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:vm="clr-namespace:GitCredentialManager.UI.ViewModels;assembly=gcmcore" mc:Ignorable="d" d:DesignWidth="420" + x:DataType="vm:OAuthViewModel" + x:CompileBindings="True" x:Class="GitCredentialManager.UI.Views.OAuthView"> diff --git a/src/shared/GitHub/UI/Views/CredentialsView.axaml b/src/shared/GitHub/UI/Views/CredentialsView.axaml index 9ea6f3fb8..5ef7f1bf9 100644 --- a/src/shared/GitHub/UI/Views/CredentialsView.axaml +++ b/src/shared/GitHub/UI/Views/CredentialsView.axaml @@ -6,6 +6,8 @@ xmlns:vm="clr-namespace:GitHub.UI.ViewModels" xmlns:converters="clr-namespace:GitCredentialManager.UI.Converters;assembly=gcmcore" mc:Ignorable="d" d:DesignWidth="420" + x:DataType="vm:CredentialsViewModel" + x:CompileBindings="True" x:Class="GitHub.UI.Views.CredentialsView"> diff --git a/src/shared/GitHub/UI/Views/DeviceCodeView.axaml b/src/shared/GitHub/UI/Views/DeviceCodeView.axaml index c4f320411..afd0a0327 100644 --- a/src/shared/GitHub/UI/Views/DeviceCodeView.axaml +++ b/src/shared/GitHub/UI/Views/DeviceCodeView.axaml @@ -5,6 +5,8 @@ xmlns:controls="clr-namespace:GitHub.UI.Controls" xmlns:vm="clr-namespace:GitHub.UI.ViewModels" mc:Ignorable="d" d:DesignWidth="420" + x:DataType="vm:DeviceCodeViewModel" + x:CompileBindings="True" x:Class="GitHub.UI.Views.DeviceCodeView"> diff --git a/src/shared/GitHub/UI/Views/SelectAccountView.axaml b/src/shared/GitHub/UI/Views/SelectAccountView.axaml index 417d58387..d7e728b56 100644 --- a/src/shared/GitHub/UI/Views/SelectAccountView.axaml +++ b/src/shared/GitHub/UI/Views/SelectAccountView.axaml @@ -5,6 +5,8 @@ xmlns:controls="clr-namespace:GitHub.UI.Controls" xmlns:vm="clr-namespace:GitHub.UI.ViewModels" mc:Ignorable="d" d:DesignWidth="420" + x:DataType="vm:SelectAccountViewModel" + x:CompileBindings="True" x:Class="GitHub.UI.Views.SelectAccountView"> diff --git a/src/shared/GitHub/UI/Views/TwoFactorView.axaml b/src/shared/GitHub/UI/Views/TwoFactorView.axaml index cb67d3b12..c2abc9ee0 100644 --- a/src/shared/GitHub/UI/Views/TwoFactorView.axaml +++ b/src/shared/GitHub/UI/Views/TwoFactorView.axaml @@ -5,6 +5,8 @@ xmlns:controls="clr-namespace:GitHub.UI.Controls" xmlns:vm="clr-namespace:GitHub.UI.ViewModels" mc:Ignorable="d" d:DesignWidth="420" + x:DataType="vm:TwoFactorViewModel" + x:CompileBindings="True" x:Class="GitHub.UI.Views.TwoFactorView"> diff --git a/src/shared/GitLab/UI/Views/CredentialsView.axaml b/src/shared/GitLab/UI/Views/CredentialsView.axaml index 89b2e7899..325a79090 100644 --- a/src/shared/GitLab/UI/Views/CredentialsView.axaml +++ b/src/shared/GitLab/UI/Views/CredentialsView.axaml @@ -6,6 +6,8 @@ xmlns:converters="clr-namespace:GitCredentialManager.UI.Converters;assembly=gcmcore" mc:Ignorable="d" d:DesignWidth="420" x:Class="GitLab.UI.Views.CredentialsView" + x:DataType="vm:CredentialsViewModel" + x:CompileBindings="True" x:Name="view"> From 45b765fc25352a75828f7ac622a05f6d6c04a509 Mon Sep 17 00:00:00 2001 From: Matthew John Cheetham Date: Wed, 13 Sep 2023 15:24:42 -0700 Subject: [PATCH 06/11] json: use source generation for JSON serialization --- .../BitbucketJsonSerializerContext.cs | 15 +++++ .../BitbucketOAuth2Client.cs | 3 +- .../Cloud/BitbucketRestApi.cs | 6 +- .../DataCenter/BitbucketRestApi.cs | 9 +-- .../OAuth/Json/OAuthJsonSerializerContext.cs | 14 +++++ .../Core/Authentication/OAuth/OAuth2Client.cs | 23 ++++--- src/shared/Core/Trace2Message.cs | 61 +++++++++++++------ .../GitHub/GitHubJsonSerializerContext.cs | 13 ++++ src/shared/GitHub/GitHubRestApi.cs | 4 +- 9 files changed, 102 insertions(+), 46 deletions(-) create mode 100644 src/shared/Atlassian.Bitbucket/BitbucketJsonSerializerContext.cs create mode 100644 src/shared/Core/Authentication/OAuth/Json/OAuthJsonSerializerContext.cs create mode 100644 src/shared/GitHub/GitHubJsonSerializerContext.cs diff --git a/src/shared/Atlassian.Bitbucket/BitbucketJsonSerializerContext.cs b/src/shared/Atlassian.Bitbucket/BitbucketJsonSerializerContext.cs new file mode 100644 index 000000000..08436a42d --- /dev/null +++ b/src/shared/Atlassian.Bitbucket/BitbucketJsonSerializerContext.cs @@ -0,0 +1,15 @@ +using System.Text.Json.Serialization; + +namespace Atlassian.Bitbucket; + +[JsonSourceGenerationOptions( + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + PropertyNameCaseInsensitive = true +)] +[JsonSerializable(typeof(BitbucketTokenEndpointResponseJson))] +[JsonSerializable(typeof(Cloud.UserInfo), TypeInfoPropertyName = "Cloud_UserInfo")] +[JsonSerializable(typeof(DataCenter.UserInfo), TypeInfoPropertyName = "DataCenter_UserInfo")] +[JsonSerializable(typeof(DataCenter.LoginOptions))] +internal partial class BitbucketJsonSerializerContext : JsonSerializerContext +{ +} diff --git a/src/shared/Atlassian.Bitbucket/BitbucketOAuth2Client.cs b/src/shared/Atlassian.Bitbucket/BitbucketOAuth2Client.cs index 1ca23d0f5..2311de44d 100644 --- a/src/shared/Atlassian.Bitbucket/BitbucketOAuth2Client.cs +++ b/src/shared/Atlassian.Bitbucket/BitbucketOAuth2Client.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Net.Http; +using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; using GitCredentialManager; @@ -42,7 +43,7 @@ protected override bool TryCreateTokenEndpointResult(string json, out OAuth2Toke // We override the token endpoint response parsing because the Bitbucket authority returns // the non-standard 'scopes' property for the list of scopes, rather than the (optional) // 'scope' (note the singular vs plural) property as outlined in the standard. - if (TryDeserializeJson(json, out BitbucketTokenEndpointResponseJson jsonObj)) + if (TryDeserializeJson(json, BitbucketJsonSerializerContext.Default, out BitbucketTokenEndpointResponseJson jsonObj)) { result = jsonObj.ToResult(); return true; diff --git a/src/shared/Atlassian.Bitbucket/Cloud/BitbucketRestApi.cs b/src/shared/Atlassian.Bitbucket/Cloud/BitbucketRestApi.cs index 94021e14d..c32f0aa9a 100644 --- a/src/shared/Atlassian.Bitbucket/Cloud/BitbucketRestApi.cs +++ b/src/shared/Atlassian.Bitbucket/Cloud/BitbucketRestApi.cs @@ -43,11 +43,7 @@ public async Task> GetUserInformationAsync(string userN if (response.IsSuccessStatusCode) { - var obj = JsonSerializer.Deserialize(json, - new JsonSerializerOptions - { - PropertyNameCaseInsensitive = true, - }); + UserInfo obj = JsonSerializer.Deserialize(json, BitbucketJsonSerializerContext.Default.Cloud_UserInfo); return new RestApiResult(response.StatusCode, obj); } diff --git a/src/shared/Atlassian.Bitbucket/DataCenter/BitbucketRestApi.cs b/src/shared/Atlassian.Bitbucket/DataCenter/BitbucketRestApi.cs index 159229885..d6a128906 100644 --- a/src/shared/Atlassian.Bitbucket/DataCenter/BitbucketRestApi.cs +++ b/src/shared/Atlassian.Bitbucket/DataCenter/BitbucketRestApi.cs @@ -107,12 +107,7 @@ public async Task> GetAuthenticationMethodsAsync() if (response.IsSuccessStatusCode) { - var loginOptions = JsonSerializer.Deserialize(json, - new JsonSerializerOptions - { - PropertyNameCaseInsensitive = true, - DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull - }); + LoginOptions loginOptions = JsonSerializer.Deserialize(json, BitbucketJsonSerializerContext.Default.LoginOptions); if (loginOptions.Results.Any(r => "LOGIN_FORM".Equals(r.Type))) { @@ -151,4 +146,4 @@ private Uri ApiUri } } } -} \ No newline at end of file +} diff --git a/src/shared/Core/Authentication/OAuth/Json/OAuthJsonSerializerContext.cs b/src/shared/Core/Authentication/OAuth/Json/OAuthJsonSerializerContext.cs new file mode 100644 index 000000000..13ac886c8 --- /dev/null +++ b/src/shared/Core/Authentication/OAuth/Json/OAuthJsonSerializerContext.cs @@ -0,0 +1,14 @@ +using System.Text.Json.Serialization; + +namespace GitCredentialManager.Authentication.OAuth.Json; + +[JsonSourceGenerationOptions( + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + PropertyNameCaseInsensitive = true +)] +[JsonSerializable(typeof(DeviceAuthorizationEndpointResponseJson))] +[JsonSerializable(typeof(ErrorResponseJson))] +[JsonSerializable(typeof(TokenEndpointResponseJson))] +public partial class OAuthJsonSerializerContext : JsonSerializerContext +{ +} diff --git a/src/shared/Core/Authentication/OAuth/OAuth2Client.cs b/src/shared/Core/Authentication/OAuth/OAuth2Client.cs index 27834d2aa..8549d5abb 100644 --- a/src/shared/Core/Authentication/OAuth/OAuth2Client.cs +++ b/src/shared/Core/Authentication/OAuth/OAuth2Client.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using GitCredentialManager.Authentication.OAuth.Json; using System.Text.Json; +using System.Text.Json.Serialization; namespace GitCredentialManager.Authentication.OAuth { @@ -213,7 +214,8 @@ public async Task GetDeviceCodeAsync(IEnumerable { string json = await response.Content.ReadAsStringAsync(); - if (response.IsSuccessStatusCode && TryDeserializeJson(json, out DeviceAuthorizationEndpointResponseJson jsonObj)) + if (response.IsSuccessStatusCode && TryDeserializeJson(json, OAuthJsonSerializerContext.Default, + out DeviceAuthorizationEndpointResponseJson jsonObj)) { return jsonObj.ToResult(); } @@ -321,12 +323,9 @@ public async Task GetTokenByDeviceCodeAsync(OAuth2DeviceCodeR return result; } - var error = JsonSerializer.Deserialize(json, new JsonSerializerOptions - { - PropertyNameCaseInsensitive = true - }); + TryDeserializeJson(json, OAuthJsonSerializerContext.Default, out ErrorResponseJson error); - switch (error.Error) + switch (error?.Error) { case OAuth2Constants.DeviceAuthorization.Errors.AuthorizationPending: // Retry with the current polling interval value @@ -358,7 +357,7 @@ public async Task GetTokenByDeviceCodeAsync(OAuth2DeviceCodeR protected virtual bool TryCreateTokenEndpointResult(string json, out OAuth2TokenResult result) { - if (TryDeserializeJson(json, out TokenEndpointResponseJson jsonObj)) + if (TryDeserializeJson(json, OAuthJsonSerializerContext.Default, out TokenEndpointResponseJson jsonObj)) { result = jsonObj.ToResult(); return true; @@ -368,9 +367,9 @@ protected virtual bool TryCreateTokenEndpointResult(string json, out OAuth2Token return false; } - protected virtual bool TryCreateExceptionFromResponse(string json, out OAuth2Exception exception) + private static bool TryCreateExceptionFromResponse(string json, out OAuth2Exception exception) { - if (TryDeserializeJson(json, out ErrorResponseJson obj)) + if (TryDeserializeJson(json, OAuthJsonSerializerContext.Default, out ErrorResponseJson obj)) { exception = obj.ToException(); return true; @@ -397,7 +396,7 @@ private HttpRequestMessage CreateRequestMessage(HttpMethod method, Uri requestUr return request; } - protected Exception CreateExceptionFromResponse(string json) + private Exception CreateExceptionFromResponse(string json) { if (TryCreateExceptionFromResponse(json, out OAuth2Exception exception)) { @@ -410,11 +409,11 @@ protected Exception CreateExceptionFromResponse(string json) return new Trace2OAuth2Exception(_trace2, message, format); } - protected static bool TryDeserializeJson(string json, out T obj) + protected static bool TryDeserializeJson(string json, JsonSerializerContext context, out T obj) { try { - obj = JsonSerializer.Deserialize(json); + obj = (T)JsonSerializer.Deserialize(json, typeof(T), context); return true; } catch diff --git a/src/shared/Core/Trace2Message.cs b/src/shared/Core/Trace2Message.cs index 14327031f..b7555d780 100644 --- a/src/shared/Core/Trace2Message.cs +++ b/src/shared/Core/Trace2Message.cs @@ -6,17 +6,46 @@ namespace GitCredentialManager; +public class Trace2EventEnumConverter : JsonStringEnumConverter +{ + public Trace2EventEnumConverter() + : base(JsonNamingPolicy.SnakeCaseLower, false) { } +} + +public class Trace2ProcessClassEnumConverter : JsonStringEnumConverter +{ + public Trace2ProcessClassEnumConverter() + : base(JsonNamingPolicy.SnakeCaseLower, false) { } +} + +[JsonSourceGenerationOptions( + PropertyNamingPolicy = JsonKnownNamingPolicy.SnakeCaseLower, + PropertyNameCaseInsensitive = true, + Converters = new[] + { + typeof(Trace2EventEnumConverter), + typeof(Trace2ProcessClassEnumConverter) + } +)] +[JsonSerializable(typeof(VersionMessage))] +[JsonSerializable(typeof(StartMessage))] +[JsonSerializable(typeof(ExitMessage))] +[JsonSerializable(typeof(ExitMessage))] +[JsonSerializable(typeof(ChildStartMessage))] +[JsonSerializable(typeof(ChildExitMessage))] +[JsonSerializable(typeof(ErrorMessage))] +[JsonSerializable(typeof(RegionEnterMessage))] +[JsonSerializable(typeof(RegionLeaveMessage))] +internal partial class Trace2JsonSerializerContext : JsonSerializerContext +{ +} + public abstract class Trace2Message { private const int SourceColumnMaxWidth = 23; private const string NormalPerfTimeFormat = "HH:mm:ss.ffffff"; protected const string EmptyPerformanceSpan = "| | | | "; - protected static readonly JsonSerializerOptions JsonSerializerOptions = new() - { - PropertyNameCaseInsensitive = true, - Converters = { new JsonStringEnumConverter(new SnakeCaseNamingPolicy()) } - }; [JsonPropertyName("event")] [JsonPropertyOrder(1)] @@ -194,7 +223,7 @@ public class VersionMessage : Trace2Message public override string ToJson() { - return JsonSerializer.Serialize(this, JsonSerializerOptions); + return JsonSerializer.Serialize(this, Trace2JsonSerializerContext.Default.VersionMessage); } public override string ToNormalString() @@ -230,7 +259,7 @@ public class StartMessage : Trace2Message public override string ToJson() { - return JsonSerializer.Serialize(this, JsonSerializerOptions); + return JsonSerializer.Serialize(this, Trace2JsonSerializerContext.Default.StartMessage); } public override string ToNormalString() @@ -266,7 +295,7 @@ public class ExitMessage : Trace2Message public override string ToJson() { - return JsonSerializer.Serialize(this, JsonSerializerOptions); + return JsonSerializer.Serialize(this, Trace2JsonSerializerContext.Default.ExitMessage); } public override string ToNormalString() @@ -314,7 +343,7 @@ public class ChildStartMessage : Trace2Message public override string ToJson() { - return JsonSerializer.Serialize(this, JsonSerializerOptions); + return JsonSerializer.Serialize(this, Trace2JsonSerializerContext.Default.ChildStartMessage); } public override string ToNormalString() @@ -371,7 +400,7 @@ public class ChildExitMessage : Trace2Message public override string ToJson() { - return JsonSerializer.Serialize(this, JsonSerializerOptions); + return JsonSerializer.Serialize(this, Trace2JsonSerializerContext.Default.ChildExitMessage); } public override string ToNormalString() @@ -415,7 +444,7 @@ public class ErrorMessage : Trace2Message public override string ToJson() { - return JsonSerializer.Serialize(this, JsonSerializerOptions); + return JsonSerializer.Serialize(this, Trace2JsonSerializerContext.Default.ErrorMessage); } public override string ToNormalString() @@ -473,7 +502,7 @@ public class RegionEnterMessage : RegionMessage { public override string ToJson() { - return JsonSerializer.Serialize(this, JsonSerializerOptions); + return JsonSerializer.Serialize(this, Trace2JsonSerializerContext.Default.RegionEnterMessage); } public override string ToNormalString() @@ -504,7 +533,7 @@ public class RegionLeaveMessage : RegionMessage public override string ToJson() { - return JsonSerializer.Serialize(this, JsonSerializerOptions); + return JsonSerializer.Serialize(this, Trace2JsonSerializerContext.Default.RegionLeaveMessage); } public override string ToNormalString() @@ -527,9 +556,3 @@ protected override string GetEventMessage(Trace2FormatTarget formatTarget) return Message; } } - -public class SnakeCaseNamingPolicy : JsonNamingPolicy -{ - public override string ConvertName(string name) => - name.ToSnakeCase(); -} diff --git a/src/shared/GitHub/GitHubJsonSerializerContext.cs b/src/shared/GitHub/GitHubJsonSerializerContext.cs new file mode 100644 index 000000000..4ef75602e --- /dev/null +++ b/src/shared/GitHub/GitHubJsonSerializerContext.cs @@ -0,0 +1,13 @@ +namespace GitHub; + +using System.Text.Json.Serialization; + +[JsonSourceGenerationOptions( + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + PropertyNameCaseInsensitive = true +)] +[JsonSerializable(typeof(GitHubUserInfo))] +[JsonSerializable(typeof(GitHubMetaInfo))] +internal partial class GitHubJsonSerializerContext : JsonSerializerContext +{ +} diff --git a/src/shared/GitHub/GitHubRestApi.cs b/src/shared/GitHub/GitHubRestApi.cs index 5051ed2bb..8baac581f 100644 --- a/src/shared/GitHub/GitHubRestApi.cs +++ b/src/shared/GitHub/GitHubRestApi.cs @@ -106,7 +106,7 @@ public async Task GetUserInfoAsync(Uri targetUri, string accessT string json = await response.Content.ReadAsStringAsync(); - return JsonSerializer.Deserialize(json); + return JsonSerializer.Deserialize(json, GitHubJsonSerializerContext.Default.GitHubUserInfo); } } } @@ -125,7 +125,7 @@ public async Task GetMetaInfoAsync(Uri targetUri) string json = await response.Content.ReadAsStringAsync(); - return JsonSerializer.Deserialize(json); + return JsonSerializer.Deserialize(json, GitHubJsonSerializerContext.Default.GitHubMetaInfo); } } From aa81caa86d6f395d4702931905a01a39f9073fa5 Mon Sep 17 00:00:00 2001 From: Matthew John Cheetham Date: Wed, 13 Sep 2023 14:29:45 -0700 Subject: [PATCH 07/11] build: enable trimming and single file publish --- src/linux/Packaging.Linux/layout.sh | 2 -- src/osx/Installer.Mac/layout.sh | 1 - .../Git-Credential-Manager/Git-Credential-Manager.csproj | 3 +++ 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/linux/Packaging.Linux/layout.sh b/src/linux/Packaging.Linux/layout.sh index ccf031156..7645ba3e1 100755 --- a/src/linux/Packaging.Linux/layout.sh +++ b/src/linux/Packaging.Linux/layout.sh @@ -77,7 +77,6 @@ if [ -z "$RUNTIME" ]; then --configuration="$CONFIGURATION" \ --framework="$FRAMEWORK" \ --self-contained \ - -p:PublishSingleFile=true \ --output="$(make_absolute "$PAYLOAD")" || exit 1 else $DOTNET_ROOT/dotnet publish "$GCM_SRC" \ @@ -85,7 +84,6 @@ else --framework="$FRAMEWORK" \ --runtime="$RUNTIME" \ --self-contained \ - -p:PublishSingleFile=true \ --output="$(make_absolute "$PAYLOAD")" || exit 1 fi diff --git a/src/osx/Installer.Mac/layout.sh b/src/osx/Installer.Mac/layout.sh index ad8e2cfc2..293c3a43a 100755 --- a/src/osx/Installer.Mac/layout.sh +++ b/src/osx/Installer.Mac/layout.sh @@ -21,7 +21,6 @@ SRC="$ROOT/src" OUT="$ROOT/out" INSTALLER_SRC="$SRC/osx/Installer.Mac" GCM_SRC="$SRC/shared/Git-Credential-Manager" -GCM_UI_SRC="$SRC/shared/Git-Credential-Manager.UI.Avalonia" # Build parameters FRAMEWORK=net8.0 diff --git a/src/shared/Git-Credential-Manager/Git-Credential-Manager.csproj b/src/shared/Git-Credential-Manager/Git-Credential-Manager.csproj index 7602123a2..b5e4bfa4d 100644 --- a/src/shared/Git-Credential-Manager/Git-Credential-Manager.csproj +++ b/src/shared/Git-Credential-Manager/Git-Credential-Manager.csproj @@ -10,6 +10,9 @@ false latest true + true + true + true From 957fd0b0f02b580477bc78edd704850a6a05a2ff Mon Sep 17 00:00:00 2001 From: Matthew John Cheetham Date: Mon, 10 Nov 2025 17:29:12 +0000 Subject: [PATCH 08/11] avalonia: update to 11.3.8 Update Avalonia dependencies to 11.3.8. --- src/shared/Core/Core.csproj | 8 ++++---- src/shared/GitHub/UI/Controls/SixDigitInput.axaml.cs | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/shared/Core/Core.csproj b/src/shared/Core/Core.csproj index 107be13c1..ec03e59b8 100644 --- a/src/shared/Core/Core.csproj +++ b/src/shared/Core/Core.csproj @@ -14,13 +14,13 @@ - - - + + + - + diff --git a/src/shared/GitHub/UI/Controls/SixDigitInput.axaml.cs b/src/shared/GitHub/UI/Controls/SixDigitInput.axaml.cs index e018232de..8efe280a1 100644 --- a/src/shared/GitHub/UI/Controls/SixDigitInput.axaml.cs +++ b/src/shared/GitHub/UI/Controls/SixDigitInput.axaml.cs @@ -5,6 +5,7 @@ using Avalonia.Controls; using Avalonia.Data; using Avalonia.Input; +using Avalonia.Input.Platform; using Avalonia.Interactivity; using Avalonia.Markup.Xaml; using GitCredentialManager; @@ -156,7 +157,7 @@ void OnPreviewKeyDown(object sender, KeyEventArgs e) private void OnPaste() { - Text = TopLevel.GetTopLevel(this)?.Clipboard?.GetTextAsync().GetAwaiter().GetResult(); + Text = TopLevel.GetTopLevel(this)?.Clipboard?.TryGetTextAsync().GetAwaiter().GetResult(); } private bool MoveNext() => MoveFocus(true); From 15df48dc7c31545e917745d6cea5002a8ef57a69 Mon Sep 17 00:00:00 2001 From: Matthew John Cheetham Date: Fri, 22 Sep 2023 11:19:23 -0700 Subject: [PATCH 09/11] build: enable single-file publishing compression Enable compression of assemblies in the single-file distribution of GCM. This helps reduce the overall size on disk of GCM, which is important on Windows as we are bundled with Git for Windows, and we don't want to bloat their distribution. We only enable this compression on Windows. Mac and Linux remain uncompressed. --- .../Git-Credential-Manager.csproj | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/shared/Git-Credential-Manager/Git-Credential-Manager.csproj b/src/shared/Git-Credential-Manager/Git-Credential-Manager.csproj index b5e4bfa4d..76a2d73b0 100644 --- a/src/shared/Git-Credential-Manager/Git-Credential-Manager.csproj +++ b/src/shared/Git-Credential-Manager/Git-Credential-Manager.csproj @@ -15,6 +15,16 @@ true + + + true + + From 4c318834fffeec0888ea040209a83b8332df395d Mon Sep 17 00:00:00 2001 From: Matthew John Cheetham Date: Tue, 11 Nov 2025 10:23:14 +0000 Subject: [PATCH 10/11] build: use AOT publishing Replace single-file trimming publishing with full AOT publishing. This should also result in an increased execution performance as we no longer need to JIT any code at runtime. --- .../Git-Credential-Manager/Git-Credential-Manager.csproj | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/shared/Git-Credential-Manager/Git-Credential-Manager.csproj b/src/shared/Git-Credential-Manager/Git-Credential-Manager.csproj index 76a2d73b0..e5b5494f8 100644 --- a/src/shared/Git-Credential-Manager/Git-Credential-Manager.csproj +++ b/src/shared/Git-Credential-Manager/Git-Credential-Manager.csproj @@ -10,8 +10,7 @@ false latest true - true - true + true true From ea111fb72c944559a5ac4e804da40e052fa357bd Mon Sep 17 00:00:00 2001 From: Matthew John Cheetham Date: Tue, 11 Nov 2025 10:38:20 +0000 Subject: [PATCH 11/11] build: don't use AOT publishing on unsupported RIDs .NET 8 only supports AOT compilation on a subset of .NET runtimes, namely: - win-x64 - win-arm64 - osx-x64 - osx-arm64 - linux-x64 - linux-arm64 This means we need to do something else of our win-x86 and linux-arm (32-bit) targets. For these two, let's use the combo of SingleFile+Trimmed+ReadyToRun publishing options instead to keep both file sizes down, and reduce runtime performance hits from JIT. .NET 9 and later support AOT for win-x86 and linux-arm (32-bit) targets, but since we only prefer to target LTS releases of .NET, we'll have to wait for .NET 10 (the next LTS release) to do AOT on _all_ our platforms. Given that .NET 10 GA is just around the corner, this shouldn't be too long to wait. --- .../Git-Credential-Manager.csproj | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/shared/Git-Credential-Manager/Git-Credential-Manager.csproj b/src/shared/Git-Credential-Manager/Git-Credential-Manager.csproj index e5b5494f8..3dc85dd6d 100644 --- a/src/shared/Git-Credential-Manager/Git-Credential-Manager.csproj +++ b/src/shared/Git-Credential-Manager/Git-Credential-Manager.csproj @@ -14,6 +14,18 @@ true + + + false + true + true + true + +