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
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/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/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/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/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/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/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/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/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/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/Core.csproj b/src/shared/Core/Core.csproj
index f2804177b..ec03e59b8 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,28 +9,18 @@
true
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
+
+
+
-
+
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/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/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/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 abdd9ee0e..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;
@@ -21,7 +24,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 +50,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/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 8872827d4..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())
@@ -31,7 +34,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 +50,6 @@ public static bool IsDevBox()
return w365Value is not null && Guid.TryParse(partnerValue, out Guid partnerId) && partnerId == Constants.DevBoxPartnerId;
}
-#else
- return false;
-#endif
}
///
@@ -69,6 +68,7 @@ public static bool IsArm()
}
}
+ [SupportedOSPlatformGuard(Constants.WindowsPlatformName)]
public static bool IsWindowsBrokerSupported()
{
if (!IsWindows())
@@ -113,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();
@@ -149,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())
@@ -161,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())
@@ -173,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())
@@ -185,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())
@@ -197,11 +207,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 +295,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 +304,6 @@ private static string GetLinuxEntryPath()
//
FileSystemInfo fsi = File.ResolveLinkTarget("/proc/self/exe", returnFinalTarget: false);
return fsi?.FullName;
-#endif
}
private static string GetMacOSEntryPath()
@@ -368,12 +372,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/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/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/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/Git-Credential-Manager/Git-Credential-Manager.csproj b/src/shared/Git-Credential-Manager/Git-Credential-Manager.csproj
index 456adf547..3dc85dd6d 100644
--- a/src/shared/Git-Credential-Manager/Git-Credential-Manager.csproj
+++ b/src/shared/Git-Credential-Manager/Git-Credential-Manager.csproj
@@ -3,15 +3,37 @@
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
false
latest
true
+ true
+ true
+
+
+
+
+ false
+ true
+ true
+ true
+
+
+
+
+ true
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();
}
}
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/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);
}
}
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);
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/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/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">
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