From 7ac90abbe9426cba7e2ad634cf740cfddc52eba1 Mon Sep 17 00:00:00 2001 From: Brandon Ording Date: Sun, 26 Nov 2023 21:09:16 -0500 Subject: [PATCH 01/14] Update LibGit2Sharp.NativeBinaries to 2.0.321 libgit2 v1.7.1 --- LibGit2Sharp/LibGit2Sharp.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LibGit2Sharp/LibGit2Sharp.csproj b/LibGit2Sharp/LibGit2Sharp.csproj index b80d75cd0..a12496899 100644 --- a/LibGit2Sharp/LibGit2Sharp.csproj +++ b/LibGit2Sharp/LibGit2Sharp.csproj @@ -33,7 +33,7 @@ - + From cd6936506ca7808c2fab7454fe5df95c99188d2d Mon Sep 17 00:00:00 2001 From: Brandon Ording Date: Sun, 26 Nov 2023 21:12:14 -0500 Subject: [PATCH 02/14] Update GitFetchOptions to include new Depth value --- LibGit2Sharp/Core/GitFetchOptions.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/LibGit2Sharp/Core/GitFetchOptions.cs b/LibGit2Sharp/Core/GitFetchOptions.cs index d82e2f219..26f4c8c7e 100644 --- a/LibGit2Sharp/Core/GitFetchOptions.cs +++ b/LibGit2Sharp/Core/GitFetchOptions.cs @@ -11,6 +11,7 @@ internal class GitFetchOptions public bool UpdateFetchHead = true; public TagFetchMode download_tags; public GitProxyOptions ProxyOptions; + public int Depth = 0; // GIT_FETCH_DEPTH_FULL public RemoteRedirectMode FollowRedirects = RemoteRedirectMode.Initial; public GitStrArrayManaged CustomHeaders; } From 143e83f9b4c88f3f535db4a827ac96f9e59182c6 Mon Sep 17 00:00:00 2001 From: Brandon Ording Date: Sun, 26 Nov 2023 21:14:34 -0500 Subject: [PATCH 03/14] Remove CentOS 7 from test matrix --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f44285812..5214b064f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -62,7 +62,7 @@ jobs: matrix: arch: [ amd64 ] # arch: [ amd64, arm64 ] - distro: [ alpine.3.13, alpine.3.14, alpine.3.15, alpine.3.16, alpine.3.17, centos.7, centos.stream.8, debian.10, debian.11, fedora.36, ubuntu.18.04, ubuntu.20.04, ubuntu.22.04 ] + distro: [ alpine.3.13, alpine.3.14, alpine.3.15, alpine.3.16, alpine.3.17, centos.stream.8, debian.10, debian.11, fedora.36, ubuntu.18.04, ubuntu.20.04, ubuntu.22.04 ] sdk: [ '6.0', '7.0' ] exclude: - distro: alpine.3.13 From 42e98263699776009aeb70cf45673a60a4847dfa Mon Sep 17 00:00:00 2001 From: Brandon Ording Date: Sun, 26 Nov 2023 21:15:47 -0500 Subject: [PATCH 04/14] Update test to match new sort order --- LibGit2Sharp.Tests/GlobalSettingsFixture.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LibGit2Sharp.Tests/GlobalSettingsFixture.cs b/LibGit2Sharp.Tests/GlobalSettingsFixture.cs index cd237663e..dd7aef1e1 100644 --- a/LibGit2Sharp.Tests/GlobalSettingsFixture.cs +++ b/LibGit2Sharp.Tests/GlobalSettingsFixture.cs @@ -100,7 +100,7 @@ public void SetExtensions() // Enable two new extensions (it will reset the configuration and "noop" will be enabled) GlobalSettings.SetExtensions("partialclone", "newext"); extensions = GlobalSettings.GetExtensions(); - Assert.Equal(new[] { "noop", "objectformat", "partialclone", "newext" }, extensions); + Assert.Equal(new[] { "newext", "noop", "objectformat", "partialclone" }, extensions); } } } From e13df56af676eb4bf89dc864d20eabeeca4fe2c3 Mon Sep 17 00:00:00 2001 From: Brandon Ording Date: Sat, 25 Nov 2023 02:05:00 -0500 Subject: [PATCH 05/14] Update GitProxyOptions --- LibGit2Sharp/Core/GitProxyOptions.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/LibGit2Sharp/Core/GitProxyOptions.cs b/LibGit2Sharp/Core/GitProxyOptions.cs index b62b8e08f..85d4057ab 100644 --- a/LibGit2Sharp/Core/GitProxyOptions.cs +++ b/LibGit2Sharp/Core/GitProxyOptions.cs @@ -16,8 +16,8 @@ internal struct GitProxyOptions public uint Version; public GitProxyType Type; public IntPtr Url; - public IntPtr CredentialsCb; - public IntPtr CertificateCheck; - public IntPtr CbPayload; + public NativeMethods.git_cred_acquire_cb Credentials; + public NativeMethods.git_transport_certificate_check_cb CertificateCheck; + public IntPtr Payload; } } From 75b443221c9238711912e2471565648a3193cdf8 Mon Sep 17 00:00:00 2001 From: Brandon Ording Date: Sat, 25 Nov 2023 02:14:44 -0500 Subject: [PATCH 06/14] Add public proxy APIs --- LibGit2Sharp/FetchOptionsBase.cs | 2 ++ LibGit2Sharp/ProxyOptions.cs | 15 +++++++++++++++ LibGit2Sharp/ProxyType.cs | 9 +++++++++ 3 files changed, 26 insertions(+) create mode 100644 LibGit2Sharp/ProxyOptions.cs create mode 100644 LibGit2Sharp/ProxyType.cs diff --git a/LibGit2Sharp/FetchOptionsBase.cs b/LibGit2Sharp/FetchOptionsBase.cs index 751678cf9..652a06378 100644 --- a/LibGit2Sharp/FetchOptionsBase.cs +++ b/LibGit2Sharp/FetchOptionsBase.cs @@ -48,5 +48,7 @@ internal FetchOptionsBase() /// Completed operating on the current repository. /// public RepositoryOperationCompleted RepositoryOperationCompleted { get; set; } + + public ProxyOptions ProxyOptions { get; set; } } } diff --git a/LibGit2Sharp/ProxyOptions.cs b/LibGit2Sharp/ProxyOptions.cs new file mode 100644 index 000000000..fa3669d95 --- /dev/null +++ b/LibGit2Sharp/ProxyOptions.cs @@ -0,0 +1,15 @@ +using LibGit2Sharp.Handlers; + +namespace LibGit2Sharp +{ + public class ProxyOptions + { + public ProxyType ProxyType { get; set; } + + public string Url { get; set; } + + public CredentialsHandler CredentialsProvider { get; set; } + + public CertificateCheckHandler CertificateCheck { get; set; } + } +} diff --git a/LibGit2Sharp/ProxyType.cs b/LibGit2Sharp/ProxyType.cs new file mode 100644 index 000000000..e78606a72 --- /dev/null +++ b/LibGit2Sharp/ProxyType.cs @@ -0,0 +1,9 @@ +namespace LibGit2Sharp +{ + public enum ProxyType + { + None, + Auto, + Specified + } +} From db161ee8baad1a8969c1e6a150ab5618e84521c6 Mon Sep 17 00:00:00 2001 From: Brandon Ording Date: Sat, 25 Nov 2023 19:16:49 -0500 Subject: [PATCH 07/14] No reason to derive from FetchOptionsBase and have FetchOptions property --- LibGit2Sharp.Tests/CloneFixture.cs | 90 +++++++++++++++++------------- LibGit2Sharp/CloneOptions.cs | 2 +- 2 files changed, 51 insertions(+), 41 deletions(-) diff --git a/LibGit2Sharp.Tests/CloneFixture.cs b/LibGit2Sharp.Tests/CloneFixture.cs index 1b26c1226..c1ff7bc74 100644 --- a/LibGit2Sharp.Tests/CloneFixture.cs +++ b/LibGit2Sharp.Tests/CloneFixture.cs @@ -151,10 +151,14 @@ public void CallsProgressCallbacks(string url) Repository.Clone(url, scd.DirectoryPath, new CloneOptions() { - OnTransferProgress = _ => { transferWasCalled = true; return true; }, - OnProgress = progress => { progressWasCalled = true; return true; }, - OnUpdateTips = (name, oldId, newId) => { updateTipsWasCalled = true; return true; }, + FetchOptions = + { + OnTransferProgress = _ => { transferWasCalled = true; return true; }, + OnProgress = progress => { progressWasCalled = true; return true; }, + OnUpdateTips = (name, oldId, newId) => { updateTipsWasCalled = true; return true; } + }, OnCheckoutProgress = (a, b, c) => checkoutWasCalled = true + }); Assert.True(transferWasCalled); @@ -174,7 +178,7 @@ public void CanCloneWithCredentials() string clonedRepoPath = Repository.Clone(Constants.PrivateRepoUrl, scd.DirectoryPath, new CloneOptions() { - CredentialsProvider = Constants.PrivateRepoCredentials + FetchOptions = { CredentialsProvider = Constants.PrivateRepoCredentials } }); @@ -249,43 +253,46 @@ public void CanInspectCertificateOnClone(string url, string hostname, Type certT var options = new CloneOptions { - CertificateCheck = (cert, valid, host) => + FetchOptions = { - wasCalled = true; - - Assert.Equal(hostname, host); - Assert.Equal(certType, cert.GetType()); - - if (certType == typeof(CertificateX509)) + CertificateCheck = (cert, valid, host) => { - Assert.True(valid); - var x509 = ((CertificateX509)cert).Certificate; - // we get a string with the different fields instead of a structure, so... - Assert.Contains("CN=github.com,", x509.Subject); - checksHappy = true; - return false; - } + wasCalled = true; + + Assert.Equal(hostname, host); + Assert.Equal(certType, cert.GetType()); + + if (certType == typeof(CertificateX509)) + { + Assert.True(valid); + var x509 = ((CertificateX509)cert).Certificate; + // we get a string with the different fields instead of a structure, so... + Assert.Contains("CN=github.com,", x509.Subject); + checksHappy = true; + return false; + } + + if (certType == typeof(CertificateSsh)) + { + var hostkey = (CertificateSsh)cert; + Assert.True(hostkey.HasMD5); + /* + * Once you've connected and thus your ssh has stored the hostkey, + * you can get the hostkey for a host with + * + * ssh-keygen -F github.com -l | tail -n 1 | cut -d ' ' -f 2 | tr -d ':' + * + * though GitHub's hostkey won't change anytime soon. + */ + Assert.Equal("1627aca576282d36631b564debdfa648", + BitConverter.ToString(hostkey.HashMD5).ToLower().Replace("-", "")); + checksHappy = true; + return false; + } - if (certType == typeof(CertificateSsh)) - { - var hostkey = (CertificateSsh)cert; - Assert.True(hostkey.HasMD5); - /* - * Once you've connected and thus your ssh has stored the hostkey, - * you can get the hostkey for a host with - * - * ssh-keygen -F github.com -l | tail -n 1 | cut -d ' ' -f 2 | tr -d ':' - * - * though GitHub's hostkey won't change anytime soon. - */ - Assert.Equal("1627aca576282d36631b564debdfa648", - BitConverter.ToString(hostkey.HashMD5).ToLower().Replace("-", "")); - checksHappy = true; return false; } - - return false; - }, + } }; Assert.Throws(() => @@ -432,9 +439,12 @@ public void CanRecursivelyCloneSubmodules() { RecurseSubmodules = true, OnCheckoutProgress = checkoutProgressHandler, - OnUpdateTips = remoteRefUpdated, - RepositoryOperationStarting = repositoryOperationStarting, - RepositoryOperationCompleted = repositoryOperationCompleted, + FetchOptions = + { + OnUpdateTips = remoteRefUpdated, + RepositoryOperationStarting = repositoryOperationStarting, + RepositoryOperationCompleted = repositoryOperationCompleted + } }; string clonedRepoPath = Repository.Clone(uri.AbsolutePath, scd.DirectoryPath, options); @@ -517,7 +527,7 @@ public void CanCancelRecursiveClone() CloneOptions options = new CloneOptions() { RecurseSubmodules = true, - RepositoryOperationStarting = repositoryOperationStarting, + FetchOptions = { RepositoryOperationStarting = repositoryOperationStarting } }; Assert.Throws(() => diff --git a/LibGit2Sharp/CloneOptions.cs b/LibGit2Sharp/CloneOptions.cs index f88ff58d7..05430085e 100644 --- a/LibGit2Sharp/CloneOptions.cs +++ b/LibGit2Sharp/CloneOptions.cs @@ -6,7 +6,7 @@ namespace LibGit2Sharp /// /// Options to define clone behaviour /// - public sealed class CloneOptions : FetchOptionsBase, IConvertableToGitCheckoutOpts + public sealed class CloneOptions : IConvertableToGitCheckoutOpts { /// /// Creates default for a non-bare clone From 4de7c4f12bbc86b333a54f572fe2f2e8f116fce0 Mon Sep 17 00:00:00 2001 From: Brandon Ording Date: Sat, 25 Nov 2023 19:18:23 -0500 Subject: [PATCH 08/14] Wire up proxy options --- LibGit2Sharp/Commands/Fetch.cs | 3 +- LibGit2Sharp/Core/GitFetchOptionsWrapper.cs | 9 +- LibGit2Sharp/Core/GitProxyOptionsWrapper.cs | 32 +++++++ LibGit2Sharp/Core/GitPushOptionsWrapper.cs | 1 + LibGit2Sharp/FetchOptionsBase.cs | 2 +- LibGit2Sharp/LibGit2Sharp.csproj | 1 + LibGit2Sharp/Network.cs | 67 +++++++++++---- LibGit2Sharp/ProxyOptions.cs | 92 ++++++++++++++++++++- LibGit2Sharp/PushOptions.cs | 2 + LibGit2Sharp/Repository.cs | 63 ++++++++------ LibGit2Sharp/SubmoduleCollection.cs | 2 +- 11 files changed, 222 insertions(+), 52 deletions(-) create mode 100644 LibGit2Sharp/Core/GitProxyOptionsWrapper.cs diff --git a/LibGit2Sharp/Commands/Fetch.cs b/LibGit2Sharp/Commands/Fetch.cs index d61fca5a5..e531aac51 100644 --- a/LibGit2Sharp/Commands/Fetch.cs +++ b/LibGit2Sharp/Commands/Fetch.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using LibGit2Sharp; using LibGit2Sharp.Core; using LibGit2Sharp.Core.Handles; @@ -75,7 +74,7 @@ public static void Fetch(Repository repository, string remote, IEnumerable - /// Git fetch options wrapper. Disposable wrapper for GitFetchOptions + /// + /// Git fetch options wrapper. Disposable wrapper for GitFetchOptions /// internal class GitFetchOptionsWrapper : IDisposable { @@ -11,7 +11,7 @@ public GitFetchOptionsWrapper() : this(new GitFetchOptions()) { } public GitFetchOptionsWrapper(GitFetchOptions fetchOptions) { - this.Options = fetchOptions; + Options = fetchOptions; } public GitFetchOptions Options { get; private set; } @@ -23,7 +23,8 @@ protected virtual void Dispose(bool disposing) if (disposedValue) return; - this.Options.CustomHeaders.Dispose(); + Options.CustomHeaders.Dispose(); + EncodingMarshaler.Cleanup(Options.ProxyOptions.Url); disposedValue = true; } diff --git a/LibGit2Sharp/Core/GitProxyOptionsWrapper.cs b/LibGit2Sharp/Core/GitProxyOptionsWrapper.cs new file mode 100644 index 000000000..053213e96 --- /dev/null +++ b/LibGit2Sharp/Core/GitProxyOptionsWrapper.cs @@ -0,0 +1,32 @@ +using System; + +namespace LibGit2Sharp.Core +{ + internal class GitProxyOptionsWrapper : IDisposable + { + public GitProxyOptionsWrapper() : this(new GitProxyOptions()) { } + + public GitProxyOptionsWrapper(GitProxyOptions fetchOptions) + { + Options = fetchOptions; + } + + public GitProxyOptions Options { get; private set; } + + private bool disposedValue = false; + + protected virtual void Dispose(bool disposing) + { + if (disposedValue) + return; + + EncodingMarshaler.Cleanup(Options.Url); + disposedValue = true; + } + + public void Dispose() + { + Dispose(true); + } + } +} diff --git a/LibGit2Sharp/Core/GitPushOptionsWrapper.cs b/LibGit2Sharp/Core/GitPushOptionsWrapper.cs index ffac5a220..3ccffcf06 100644 --- a/LibGit2Sharp/Core/GitPushOptionsWrapper.cs +++ b/LibGit2Sharp/Core/GitPushOptionsWrapper.cs @@ -24,6 +24,7 @@ protected virtual void Dispose(bool disposing) return; this.Options.CustomHeaders.Dispose(); + EncodingMarshaler.Cleanup(Options.ProxyOptions.Url); disposedValue = true; } diff --git a/LibGit2Sharp/FetchOptionsBase.cs b/LibGit2Sharp/FetchOptionsBase.cs index 652a06378..57de331d1 100644 --- a/LibGit2Sharp/FetchOptionsBase.cs +++ b/LibGit2Sharp/FetchOptionsBase.cs @@ -49,6 +49,6 @@ internal FetchOptionsBase() /// public RepositoryOperationCompleted RepositoryOperationCompleted { get; set; } - public ProxyOptions ProxyOptions { get; set; } + public ProxyOptions ProxyOptions { get; set; } = new(); } } diff --git a/LibGit2Sharp/LibGit2Sharp.csproj b/LibGit2Sharp/LibGit2Sharp.csproj index a12496899..4d0876c4d 100644 --- a/LibGit2Sharp/LibGit2Sharp.csproj +++ b/LibGit2Sharp/LibGit2Sharp.csproj @@ -2,6 +2,7 @@ net472;net6.0 + 10.0 true LibGit2Sharp brings all the might and speed of libgit2, a native Git implementation, to the managed world of .NET LibGit2Sharp contributors diff --git a/LibGit2Sharp/Network.cs b/LibGit2Sharp/Network.cs index 825f3c886..19070a344 100644 --- a/LibGit2Sharp/Network.cs +++ b/LibGit2Sharp/Network.cs @@ -52,7 +52,14 @@ public virtual IEnumerable ListReferences(Remote remote) { Ensure.ArgumentNotNull(remote, "remote"); - return ListReferencesInternal(remote.Url, null); + return ListReferencesInternal(remote.Url, null, new ProxyOptions()); + } + + public virtual IEnumerable ListReferences(Remote remote, ProxyOptions proxyOptions) + { + Ensure.ArgumentNotNull(remote, "remote"); + + return ListReferencesInternal(remote.Url, null, proxyOptions); } /// @@ -72,7 +79,15 @@ public virtual IEnumerable ListReferences(Remote remote, CredentialsH Ensure.ArgumentNotNull(remote, "remote"); Ensure.ArgumentNotNull(credentialsProvider, "credentialsProvider"); - return ListReferencesInternal(remote.Url, credentialsProvider); + return ListReferencesInternal(remote.Url, credentialsProvider, new ProxyOptions()); + } + + public virtual IEnumerable ListReferences(Remote remote, CredentialsHandler credentialsProvider, ProxyOptions proxyOptions) + { + Ensure.ArgumentNotNull(remote, "remote"); + Ensure.ArgumentNotNull(credentialsProvider, "credentialsProvider"); + + return ListReferencesInternal(remote.Url, credentialsProvider, proxyOptions); } /// @@ -90,7 +105,14 @@ public virtual IEnumerable ListReferences(string url) { Ensure.ArgumentNotNull(url, "url"); - return ListReferencesInternal(url, null); + return ListReferencesInternal(url, null, new ProxyOptions()); + } + + public virtual IEnumerable ListReferences(string url, ProxyOptions proxyOptions) + { + Ensure.ArgumentNotNull(url, "url"); + + return ListReferencesInternal(url, null, proxyOptions); } /// @@ -110,25 +132,36 @@ public virtual IEnumerable ListReferences(string url, CredentialsHand Ensure.ArgumentNotNull(url, "url"); Ensure.ArgumentNotNull(credentialsProvider, "credentialsProvider"); - return ListReferencesInternal(url, credentialsProvider); + return ListReferencesInternal(url, credentialsProvider, new ProxyOptions()); } - private IEnumerable ListReferencesInternal(string url, CredentialsHandler credentialsProvider) + public virtual IEnumerable ListReferences(string url, CredentialsHandler credentialsProvider, ProxyOptions proxyOptions) { - using (RemoteHandle remoteHandle = BuildRemoteHandle(repository.Handle, url)) - { - GitRemoteCallbacks gitCallbacks = new GitRemoteCallbacks { version = 1 }; - GitProxyOptions proxyOptions = new GitProxyOptions { Version = 1 }; + Ensure.ArgumentNotNull(url, "url"); + Ensure.ArgumentNotNull(credentialsProvider, "credentialsProvider"); - if (credentialsProvider != null) - { - var callbacks = new RemoteCallbacks(credentialsProvider); - gitCallbacks = callbacks.GenerateCallbacks(); - } + return ListReferencesInternal(url, credentialsProvider, new ProxyOptions()); + } - Proxy.git_remote_connect(remoteHandle, GitDirection.Fetch, ref gitCallbacks, ref proxyOptions); - return Proxy.git_remote_ls(repository, remoteHandle); + private IEnumerable ListReferencesInternal(string url, CredentialsHandler credentialsProvider, ProxyOptions proxyOptions) + { + proxyOptions ??= new(); + + using RemoteHandle remoteHandle = BuildRemoteHandle(repository.Handle, url); + using var proxyOptionsWrapper = new GitProxyOptionsWrapper(proxyOptions.CreateGitProxyOptions()); + + GitRemoteCallbacks gitCallbacks = new GitRemoteCallbacks { version = 1 }; + + if (credentialsProvider != null) + { + var callbacks = new RemoteCallbacks(credentialsProvider); + gitCallbacks = callbacks.GenerateCallbacks(); } + + var gitProxyOptions = proxyOptionsWrapper.Options; + + Proxy.git_remote_connect(remoteHandle, GitDirection.Fetch, ref gitCallbacks, ref gitProxyOptions); + return Proxy.git_remote_ls(repository, remoteHandle); } static RemoteHandle BuildRemoteHandle(RepositoryHandle repoHandle, string url) @@ -375,7 +408,7 @@ public virtual void Push(Remote remote, IEnumerable pushRefSpecs, PushOp var gitPushOptions = pushOptionsWrapper.Options; gitPushOptions.PackbuilderDegreeOfParallelism = pushOptions.PackbuilderDegreeOfParallelism; gitPushOptions.RemoteCallbacks = gitCallbacks; - gitPushOptions.ProxyOptions = new GitProxyOptions { Version = 1 }; + gitPushOptions.ProxyOptions = pushOptions.ProxyOptions.CreateGitProxyOptions(); // If there are custom headers, create a managed string array. if (pushOptions.CustomHeaders != null && pushOptions.CustomHeaders.Length > 0) diff --git a/LibGit2Sharp/ProxyOptions.cs b/LibGit2Sharp/ProxyOptions.cs index fa3669d95..02b75bdd8 100644 --- a/LibGit2Sharp/ProxyOptions.cs +++ b/LibGit2Sharp/ProxyOptions.cs @@ -1,15 +1,103 @@ -using LibGit2Sharp.Handlers; +using System; +using LibGit2Sharp.Core; +using LibGit2Sharp.Handlers; namespace LibGit2Sharp { public class ProxyOptions { - public ProxyType ProxyType { get; set; } + public ProxyType ProxyType { get; set; } = ProxyType.Auto; public string Url { get; set; } public CredentialsHandler CredentialsProvider { get; set; } public CertificateCheckHandler CertificateCheck { get; set; } + + internal unsafe GitProxyOptions CreateGitProxyOptions() + { + var gitProxyOptions = new GitProxyOptions + { + Version = 1, + Type = (GitProxyType)ProxyType + }; + + if (Url is not null) + { + gitProxyOptions.Url = StrictUtf8Marshaler.FromManaged(Url); + } + + if (CredentialsProvider is not null) + { + gitProxyOptions.Credentials = GitCredentialHandler; + } + + if (CertificateCheck is not null) + { + gitProxyOptions.CertificateCheck = GitCertificateCheck; + } + + return gitProxyOptions; + } + + private int GitCredentialHandler(out IntPtr ptr, IntPtr cUrl, IntPtr usernameFromUrl, GitCredentialType credTypes, IntPtr payload) + { + string url = LaxUtf8Marshaler.FromNative(cUrl); + string username = LaxUtf8Marshaler.FromNative(usernameFromUrl); + + SupportedCredentialTypes types = default(SupportedCredentialTypes); + if (credTypes.HasFlag(GitCredentialType.UserPassPlaintext)) + { + types |= SupportedCredentialTypes.UsernamePassword; + } + if (credTypes.HasFlag(GitCredentialType.Default)) + { + types |= SupportedCredentialTypes.Default; + } + + ptr = IntPtr.Zero; + try + { + var cred = CredentialsProvider(url, username, types); + if (cred == null) + { + return (int)GitErrorCode.PassThrough; + } + return cred.GitCredentialHandler(out ptr); + } + catch (Exception exception) + { + Proxy.git_error_set_str(GitErrorCategory.Callback, exception); + return (int)GitErrorCode.Error; + } + } + + private unsafe int GitCertificateCheck(git_certificate* certPtr, int valid, IntPtr cHostname, IntPtr payload) + { + string hostname = LaxUtf8Marshaler.FromNative(cHostname); + Certificate cert = null; + + switch (certPtr->type) + { + case GitCertificateType.X509: + cert = new CertificateX509((git_certificate_x509*)certPtr); + break; + case GitCertificateType.Hostkey: + cert = new CertificateSsh((git_certificate_ssh*)certPtr); + break; + } + + bool result = false; + try + { + result = CertificateCheck(cert, valid != 0, hostname); + } + catch (Exception exception) + { + Proxy.git_error_set_str(GitErrorCategory.Callback, exception); + } + + return Proxy.ConvertResultToCancelFlag(result); + } } } diff --git a/LibGit2Sharp/PushOptions.cs b/LibGit2Sharp/PushOptions.cs index f7d37eba9..501e8d8d2 100644 --- a/LibGit2Sharp/PushOptions.cs +++ b/LibGit2Sharp/PushOptions.cs @@ -71,5 +71,7 @@ public sealed class PushOptions /// /// The custom headers string array public string[] CustomHeaders { get; set; } + + public ProxyOptions ProxyOptions { get; set; } = new(); } } diff --git a/LibGit2Sharp/Repository.cs b/LibGit2Sharp/Repository.cs index 41aaecfbf..d7c759e8b 100644 --- a/LibGit2Sharp/Repository.cs +++ b/LibGit2Sharp/Repository.cs @@ -656,7 +656,12 @@ internal Commit LookupCommit(string committish) /// The references in the remote repository. public static IEnumerable ListRemoteReferences(string url) { - return ListRemoteReferences(url, null); + return ListRemoteReferences(url, null, new ProxyOptions()); + } + + public static IEnumerable ListRemoteReferences(string url, ProxyOptions proxyOptions) + { + return ListRemoteReferences(url, null, proxyOptions); } /// @@ -671,24 +676,32 @@ public static IEnumerable ListRemoteReferences(string url) /// The used to connect to remote repository. /// The references in the remote repository. public static IEnumerable ListRemoteReferences(string url, CredentialsHandler credentialsProvider) + { + return ListRemoteReferences(url, credentialsProvider, new ProxyOptions()); + } + + public static IEnumerable ListRemoteReferences(string url, CredentialsHandler credentialsProvider, ProxyOptions proxyOptions) { Ensure.ArgumentNotNull(url, "url"); - using (RepositoryHandle repositoryHandle = Proxy.git_repository_new()) - using (RemoteHandle remoteHandle = Proxy.git_remote_create_anonymous(repositoryHandle, url)) - { - var gitCallbacks = new GitRemoteCallbacks { version = 1 }; - var proxyOptions = new GitProxyOptions { Version = 1 }; + proxyOptions ??= new(); - if (credentialsProvider != null) - { - var callbacks = new RemoteCallbacks(credentialsProvider); - gitCallbacks = callbacks.GenerateCallbacks(); - } + using RepositoryHandle repositoryHandle = Proxy.git_repository_new(); + using RemoteHandle remoteHandle = Proxy.git_remote_create_anonymous(repositoryHandle, url); + using var proxyOptionsWrapper = new GitProxyOptionsWrapper(proxyOptions.CreateGitProxyOptions()); + + var gitCallbacks = new GitRemoteCallbacks { version = 1 }; - Proxy.git_remote_connect(remoteHandle, GitDirection.Fetch, ref gitCallbacks, ref proxyOptions); - return Proxy.git_remote_ls(null, remoteHandle); + if (credentialsProvider != null) + { + var callbacks = new RemoteCallbacks(credentialsProvider); + gitCallbacks = callbacks.GenerateCallbacks(); } + + var gitProxyOptions = proxyOptionsWrapper.Options; + + Proxy.git_remote_connect(remoteHandle, GitDirection.Fetch, ref gitCallbacks, ref gitProxyOptions); + return Proxy.git_remote_ls(null, remoteHandle); } /// @@ -754,7 +767,7 @@ public static string Clone(string sourceUrl, string workdirPath, var context = new RepositoryOperationContext(Path.GetFullPath(workdirPath), sourceUrl); // Notify caller that we are starting to work with the current repository. - bool continueOperation = OnRepositoryOperationStarting(options.RepositoryOperationStarting, + bool continueOperation = OnRepositoryOperationStarting(options.FetchOptions.RepositoryOperationStarting, context); if (!continueOperation) @@ -768,8 +781,8 @@ public static string Clone(string sourceUrl, string workdirPath, var gitCheckoutOptions = checkoutOptionsWrapper.Options; var gitFetchOptions = fetchOptionsWrapper.Options; - gitFetchOptions.ProxyOptions = new GitProxyOptions { Version = 1 }; - gitFetchOptions.RemoteCallbacks = new RemoteCallbacks(options).GenerateCallbacks(); + gitFetchOptions.ProxyOptions = options.FetchOptions.ProxyOptions.CreateGitProxyOptions(); + gitFetchOptions.RemoteCallbacks = new RemoteCallbacks(options.FetchOptions).GenerateCallbacks(); if (options.FetchOptions != null && options.FetchOptions.CustomHeaders != null) { gitFetchOptions.CustomHeaders = @@ -801,7 +814,7 @@ public static string Clone(string sourceUrl, string workdirPath, } // Notify caller that we are done with the current repository. - OnRepositoryOperationCompleted(options.RepositoryOperationCompleted, + OnRepositoryOperationCompleted(options.FetchOptions.RepositoryOperationCompleted, context); // Recursively clone submodules if requested. @@ -837,11 +850,11 @@ private static void RecursivelyCloneSubmodules(CloneOptions options, string repo SubmoduleUpdateOptions updateOptions = new SubmoduleUpdateOptions() { Init = true, - CredentialsProvider = options.CredentialsProvider, + CredentialsProvider = options.FetchOptions.CredentialsProvider, OnCheckoutProgress = options.OnCheckoutProgress, - OnProgress = options.OnProgress, - OnTransferProgress = options.OnTransferProgress, - OnUpdateTips = options.OnUpdateTips, + OnProgress = options.FetchOptions.OnProgress, + OnTransferProgress = options.FetchOptions.OnTransferProgress, + OnUpdateTips = options.FetchOptions.OnUpdateTips, }; string parentRepoWorkDir = repo.Info.WorkingDirectory; @@ -862,7 +875,7 @@ private static void RecursivelyCloneSubmodules(CloneOptions options, string repo sm.Name, recursionDepth); - bool continueOperation = OnRepositoryOperationStarting(options.RepositoryOperationStarting, + bool continueOperation = OnRepositoryOperationStarting(options.FetchOptions.RepositoryOperationStarting, context); if (!continueOperation) @@ -872,7 +885,7 @@ private static void RecursivelyCloneSubmodules(CloneOptions options, string repo repo.Submodules.Update(sm.Name, updateOptions); - OnRepositoryOperationCompleted(options.RepositoryOperationCompleted, + OnRepositoryOperationCompleted(options.FetchOptions.RepositoryOperationCompleted, context); submodules.Add(Path.Combine(repo.Info.WorkingDirectory, sm.Path)); @@ -1050,7 +1063,7 @@ public Commit Commit(string message, Signature author, Signature committer, Comm if (treesame && !amendMergeCommit) { - throw (options.AmendPreviousCommit ? + throw (options.AmendPreviousCommit ? new EmptyCommitException("Amending this commit would produce a commit that is identical to its parent (id = {0})", parents[0].Id) : new EmptyCommitException("No changes; nothing to commit.")); } @@ -1241,7 +1254,7 @@ public MergeResult MergeFetchedRefs(Signature merger, MergeOptions options) if (fetchHeads.Length == 0) { var expectedRef = this.Head.UpstreamBranchCanonicalName; - throw new MergeFetchHeadNotFoundException("The current branch is configured to merge with the reference '{0}' from the remote, but this reference was not fetched.", + throw new MergeFetchHeadNotFoundException("The current branch is configured to merge with the reference '{0}' from the remote, but this reference was not fetched.", expectedRef); } diff --git a/LibGit2Sharp/SubmoduleCollection.cs b/LibGit2Sharp/SubmoduleCollection.cs index fc508107a..c4cc1c020 100644 --- a/LibGit2Sharp/SubmoduleCollection.cs +++ b/LibGit2Sharp/SubmoduleCollection.cs @@ -104,7 +104,7 @@ public virtual void Update(string name, SubmoduleUpdateOptions options) { Version = 1, CheckoutOptions = gitCheckoutOptions, - FetchOptions = new GitFetchOptions { ProxyOptions = new GitProxyOptions { Version = 1 }, RemoteCallbacks = gitRemoteCallbacks }, + FetchOptions = new GitFetchOptions { ProxyOptions = options.ProxyOptions.CreateGitProxyOptions(), RemoteCallbacks = gitRemoteCallbacks }, CloneCheckoutStrategy = CheckoutStrategy.GIT_CHECKOUT_SAFE }; From 4ab3b4604d8eab831d60ef427675ff0b82d26664 Mon Sep 17 00:00:00 2001 From: Brandon Ording Date: Sat, 25 Nov 2023 19:44:54 -0500 Subject: [PATCH 09/14] Ensure FetchOptions property is non-null --- LibGit2Sharp/CloneOptions.cs | 2 +- LibGit2Sharp/Repository.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/LibGit2Sharp/CloneOptions.cs b/LibGit2Sharp/CloneOptions.cs index 05430085e..620896e94 100644 --- a/LibGit2Sharp/CloneOptions.cs +++ b/LibGit2Sharp/CloneOptions.cs @@ -46,7 +46,7 @@ public CloneOptions() /// /// Gets or sets the fetch options. /// - public FetchOptions FetchOptions { get; set; } + public FetchOptions FetchOptions { get; set; } = new(); #region IConvertableToGitCheckoutOpts diff --git a/LibGit2Sharp/Repository.cs b/LibGit2Sharp/Repository.cs index d7c759e8b..3791dfbd1 100644 --- a/LibGit2Sharp/Repository.cs +++ b/LibGit2Sharp/Repository.cs @@ -760,7 +760,7 @@ public static string Clone(string sourceUrl, string workdirPath, Ensure.ArgumentNotNull(sourceUrl, "sourceUrl"); Ensure.ArgumentNotNull(workdirPath, "workdirPath"); - options = options ?? new CloneOptions(); + options ??= new CloneOptions(); // context variable that contains information on the repository that // we are cloning. From 7bf2e3b803b3a3b477e4c4afa978e589ef7e2bce Mon Sep 17 00:00:00 2001 From: Brandon Ording Date: Sat, 25 Nov 2023 19:47:48 -0500 Subject: [PATCH 10/14] Make ProxyOptions sealed to satisfy test --- LibGit2Sharp/ProxyOptions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LibGit2Sharp/ProxyOptions.cs b/LibGit2Sharp/ProxyOptions.cs index 02b75bdd8..932dc40ef 100644 --- a/LibGit2Sharp/ProxyOptions.cs +++ b/LibGit2Sharp/ProxyOptions.cs @@ -4,7 +4,7 @@ namespace LibGit2Sharp { - public class ProxyOptions + public sealed class ProxyOptions { public ProxyType ProxyType { get; set; } = ProxyType.Auto; From 747bfc62fff758c309b581655d200983e7c066f3 Mon Sep 17 00:00:00 2001 From: Brandon Ording Date: Sat, 25 Nov 2023 22:34:42 -0500 Subject: [PATCH 11/14] Remove property setters since options are initialized --- LibGit2Sharp.Tests/CloneFixture.cs | 18 ++++++------------ LibGit2Sharp/CloneOptions.cs | 2 +- LibGit2Sharp/FetchOptionsBase.cs | 2 +- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/LibGit2Sharp.Tests/CloneFixture.cs b/LibGit2Sharp.Tests/CloneFixture.cs index c1ff7bc74..b4de8797a 100644 --- a/LibGit2Sharp.Tests/CloneFixture.cs +++ b/LibGit2Sharp.Tests/CloneFixture.cs @@ -567,10 +567,8 @@ public void CannotCloneWithForbiddenCustomHeaders() const string url = "https://github.com/libgit2/TestGitRepository"; const string knownHeader = "User-Agent: mygit-201"; - var cloneOptions = new CloneOptions() - { - FetchOptions = new FetchOptions { CustomHeaders = new String[] { knownHeader } } - }; + var cloneOptions = new CloneOptions(); + cloneOptions.FetchOptions.CustomHeaders = new string[] { knownHeader }; Assert.Throws(() => Repository.Clone(url, scd.DirectoryPath, cloneOptions)); } @@ -583,10 +581,8 @@ public void CannotCloneWithMalformedCustomHeaders() const string url = "https://github.com/libgit2/TestGitRepository"; const string knownHeader = "hello world"; - var cloneOptions = new CloneOptions() - { - FetchOptions = new FetchOptions { CustomHeaders = new String[] { knownHeader } } - }; + var cloneOptions = new CloneOptions(); + cloneOptions.FetchOptions.CustomHeaders = new string[] { knownHeader }; Assert.Throws(() => Repository.Clone(url, scd.DirectoryPath, cloneOptions)); } @@ -599,10 +595,8 @@ public void CanCloneWithCustomHeaders() const string url = "https://github.com/libgit2/TestGitRepository"; const string knownHeader = "X-Hello: world"; - var cloneOptions = new CloneOptions() - { - FetchOptions = new FetchOptions { CustomHeaders = new String[] { knownHeader } } - }; + var cloneOptions = new CloneOptions(); + cloneOptions.FetchOptions.CustomHeaders = new string[] { knownHeader }; var clonedRepoPath = Repository.Clone(url, scd.DirectoryPath, cloneOptions); Assert.True(Directory.Exists(clonedRepoPath)); diff --git a/LibGit2Sharp/CloneOptions.cs b/LibGit2Sharp/CloneOptions.cs index 620896e94..a315d76fc 100644 --- a/LibGit2Sharp/CloneOptions.cs +++ b/LibGit2Sharp/CloneOptions.cs @@ -46,7 +46,7 @@ public CloneOptions() /// /// Gets or sets the fetch options. /// - public FetchOptions FetchOptions { get; set; } = new(); + public FetchOptions FetchOptions { get; } = new(); #region IConvertableToGitCheckoutOpts diff --git a/LibGit2Sharp/FetchOptionsBase.cs b/LibGit2Sharp/FetchOptionsBase.cs index 57de331d1..dffd34412 100644 --- a/LibGit2Sharp/FetchOptionsBase.cs +++ b/LibGit2Sharp/FetchOptionsBase.cs @@ -49,6 +49,6 @@ internal FetchOptionsBase() /// public RepositoryOperationCompleted RepositoryOperationCompleted { get; set; } - public ProxyOptions ProxyOptions { get; set; } = new(); + public ProxyOptions ProxyOptions { get; } = new(); } } From c6ef24d85b31a2121d25559f16424feb5a85a3fa Mon Sep 17 00:00:00 2001 From: Brandon Ording Date: Sat, 25 Nov 2023 23:06:02 -0500 Subject: [PATCH 12/14] Add XML comments --- LibGit2Sharp/FetchOptions.cs | 8 ++--- LibGit2Sharp/FetchOptionsBase.cs | 5 +++- LibGit2Sharp/Network.cs | 50 ++++++++++++++++++++++++++++++++ LibGit2Sharp/ProxyOptions.cs | 16 ++++++++++ LibGit2Sharp/ProxyType.cs | 14 +++++++++ LibGit2Sharp/PushOptions.cs | 3 ++ LibGit2Sharp/Repository.cs | 18 ++++++++++++ 7 files changed, 109 insertions(+), 5 deletions(-) diff --git a/LibGit2Sharp/FetchOptions.cs b/LibGit2Sharp/FetchOptions.cs index 487baed97..5bcf74bfa 100644 --- a/LibGit2Sharp/FetchOptions.cs +++ b/LibGit2Sharp/FetchOptions.cs @@ -28,14 +28,14 @@ public sealed class FetchOptions : FetchOptionsBase /// /// Get/Set the custom headers. - /// - /// - /// This allows you to set custom headers (e.g. X-Forwarded-For, + /// + /// + /// This allows you to set custom headers (e.g. X-Forwarded-For, /// X-Request-Id, etc), /// /// /// - /// Libgit2 sets some headers for HTTP requests (User-Agent, Host, + /// Libgit2 sets some headers for HTTP requests (User-Agent, Host, /// Accept, Content-Type, Transfer-Encoding, Content-Length, Accept) that /// cannot be overriden. /// diff --git a/LibGit2Sharp/FetchOptionsBase.cs b/LibGit2Sharp/FetchOptionsBase.cs index dffd34412..0e548652f 100644 --- a/LibGit2Sharp/FetchOptionsBase.cs +++ b/LibGit2Sharp/FetchOptionsBase.cs @@ -35,7 +35,7 @@ internal FetchOptionsBase() /// /// This handler will be called to let the user make a decision on whether to allow - /// the connection to preoceed based on the certificate presented by the server. + /// the connection to proceed based on the certificate presented by the server. /// public CertificateCheckHandler CertificateCheck { get; set; } @@ -49,6 +49,9 @@ internal FetchOptionsBase() /// public RepositoryOperationCompleted RepositoryOperationCompleted { get; set; } + /// + /// Options for connecting through a proxy. + /// public ProxyOptions ProxyOptions { get; } = new(); } } diff --git a/LibGit2Sharp/Network.cs b/LibGit2Sharp/Network.cs index 19070a344..bd80834bb 100644 --- a/LibGit2Sharp/Network.cs +++ b/LibGit2Sharp/Network.cs @@ -55,6 +55,18 @@ public virtual IEnumerable ListReferences(Remote remote) return ListReferencesInternal(remote.Url, null, new ProxyOptions()); } + /// + /// List references in a repository. + /// + /// When the remote tips are ahead of the local ones, the retrieved + /// s may point to non existing + /// s in the local repository. In that + /// case, will return null. + /// + /// + /// The to list from. + /// Options for connecting through a proxy. + /// The references in the repository. public virtual IEnumerable ListReferences(Remote remote, ProxyOptions proxyOptions) { Ensure.ArgumentNotNull(remote, "remote"); @@ -82,6 +94,19 @@ public virtual IEnumerable ListReferences(Remote remote, CredentialsH return ListReferencesInternal(remote.Url, credentialsProvider, new ProxyOptions()); } + /// + /// List references in a repository. + /// + /// When the remote tips are ahead of the local ones, the retrieved + /// s may point to non existing + /// s in the local repository. In that + /// case, will return null. + /// + /// + /// The to list from. + /// The used to connect to remote repository. + /// Options for connecting through a proxy. + /// The references in the repository. public virtual IEnumerable ListReferences(Remote remote, CredentialsHandler credentialsProvider, ProxyOptions proxyOptions) { Ensure.ArgumentNotNull(remote, "remote"); @@ -108,6 +133,18 @@ public virtual IEnumerable ListReferences(string url) return ListReferencesInternal(url, null, new ProxyOptions()); } + /// + /// List references in a remote repository. + /// + /// When the remote tips are ahead of the local ones, the retrieved + /// s may point to non existing + /// s in the local repository. In that + /// case, will return null. + /// + /// + /// The url to list from. + /// Options for connecting through a proxy. + /// The references in the remote repository. public virtual IEnumerable ListReferences(string url, ProxyOptions proxyOptions) { Ensure.ArgumentNotNull(url, "url"); @@ -135,6 +172,19 @@ public virtual IEnumerable ListReferences(string url, CredentialsHand return ListReferencesInternal(url, credentialsProvider, new ProxyOptions()); } + /// + /// List references in a remote repository. + /// + /// When the remote tips are ahead of the local ones, the retrieved + /// s may point to non existing + /// s in the local repository. In that + /// case, will return null. + /// + /// + /// The url to list from. + /// The used to connect to remote repository. + /// Options for connecting through a proxy. + /// The references in the remote repository. public virtual IEnumerable ListReferences(string url, CredentialsHandler credentialsProvider, ProxyOptions proxyOptions) { Ensure.ArgumentNotNull(url, "url"); diff --git a/LibGit2Sharp/ProxyOptions.cs b/LibGit2Sharp/ProxyOptions.cs index 932dc40ef..076c4e357 100644 --- a/LibGit2Sharp/ProxyOptions.cs +++ b/LibGit2Sharp/ProxyOptions.cs @@ -4,14 +4,30 @@ namespace LibGit2Sharp { + /// + /// Options for connecting through a proxy. + /// public sealed class ProxyOptions { + /// + /// The type of proxy to use. Set to Auto by default. + /// public ProxyType ProxyType { get; set; } = ProxyType.Auto; + /// + /// The URL of the proxy when is set to Specified. + /// public string Url { get; set; } + /// + /// Handler to generate for authentication. + /// public CredentialsHandler CredentialsProvider { get; set; } + /// + /// This handler will be called to let the user make a decision on whether to allow + /// the connection to proceed based on the certificate presented by the server. + /// public CertificateCheckHandler CertificateCheck { get; set; } internal unsafe GitProxyOptions CreateGitProxyOptions() diff --git a/LibGit2Sharp/ProxyType.cs b/LibGit2Sharp/ProxyType.cs index e78606a72..13ec705ee 100644 --- a/LibGit2Sharp/ProxyType.cs +++ b/LibGit2Sharp/ProxyType.cs @@ -1,9 +1,23 @@ namespace LibGit2Sharp { + /// + /// The type of proxy to use. + /// public enum ProxyType { + /// + /// Do not attempt to connect through a proxy. + /// None, + + /// + /// Try to auto-detect the proxy from the git configuration. + /// Auto, + + /// + /// Connect via the URL given in the options. + /// Specified } } diff --git a/LibGit2Sharp/PushOptions.cs b/LibGit2Sharp/PushOptions.cs index 501e8d8d2..829eb0d60 100644 --- a/LibGit2Sharp/PushOptions.cs +++ b/LibGit2Sharp/PushOptions.cs @@ -72,6 +72,9 @@ public sealed class PushOptions /// The custom headers string array public string[] CustomHeaders { get; set; } + /// + /// Options for connecting through a proxy. + /// public ProxyOptions ProxyOptions { get; set; } = new(); } } diff --git a/LibGit2Sharp/Repository.cs b/LibGit2Sharp/Repository.cs index 3791dfbd1..a4f2e3077 100644 --- a/LibGit2Sharp/Repository.cs +++ b/LibGit2Sharp/Repository.cs @@ -659,6 +659,12 @@ public static IEnumerable ListRemoteReferences(string url) return ListRemoteReferences(url, null, new ProxyOptions()); } + /// + /// Lists the Remote Repository References. + /// + /// The url to list from. + /// Options for connecting through a proxy. + /// The references in the remote repository. public static IEnumerable ListRemoteReferences(string url, ProxyOptions proxyOptions) { return ListRemoteReferences(url, null, proxyOptions); @@ -680,6 +686,18 @@ public static IEnumerable ListRemoteReferences(string url, Credential return ListRemoteReferences(url, credentialsProvider, new ProxyOptions()); } + /// + /// Lists the Remote Repository References. + /// + /// + /// Does not require a local Repository. The retrieved + /// + /// throws in this case. + /// + /// The url to list from. + /// The used to connect to remote repository. + /// Options for connecting through a proxy. + /// The references in the remote repository. public static IEnumerable ListRemoteReferences(string url, CredentialsHandler credentialsProvider, ProxyOptions proxyOptions) { Ensure.ArgumentNotNull(url, "url"); From 01a6ccb3549e6713261638c4e8fe29da732b97a5 Mon Sep 17 00:00:00 2001 From: Brandon Ording Date: Sun, 26 Nov 2023 00:28:16 -0500 Subject: [PATCH 13/14] Update how submodule fetch options are handled --- LibGit2Sharp.Tests/SubmoduleFixture.cs | 4 +- LibGit2Sharp/Core/GitSubmoduleOptions.cs | 2 - LibGit2Sharp/Repository.cs | 7 +--- LibGit2Sharp/SubmoduleCollection.cs | 48 ++++++++++++------------ LibGit2Sharp/SubmoduleUpdateOptions.cs | 7 +++- 5 files changed, 33 insertions(+), 35 deletions(-) diff --git a/LibGit2Sharp.Tests/SubmoduleFixture.cs b/LibGit2Sharp.Tests/SubmoduleFixture.cs index 735bfd938..2d7f04e6d 100644 --- a/LibGit2Sharp.Tests/SubmoduleFixture.cs +++ b/LibGit2Sharp.Tests/SubmoduleFixture.cs @@ -3,7 +3,6 @@ using System.Linq; using LibGit2Sharp.Tests.TestHelpers; using Xunit; -using Xunit.Extensions; namespace LibGit2Sharp.Tests { @@ -240,9 +239,10 @@ public void CanUpdateSubmodule() OnCheckoutProgress = (x, y, z) => checkoutProgressCalled = true, OnCheckoutNotify = (x, y) => { checkoutNotifyCalled = true; return true; }, CheckoutNotifyFlags = CheckoutNotifyFlags.Updated, - OnUpdateTips = (x, y, z) => { updateTipsCalled = true; return true; }, }; + options.FetchOptions.OnUpdateTips = (x, y, z) => { updateTipsCalled = true; return true; }; + repo.Submodules.Init(submodule.Name, false); repo.Submodules.Update(submodule.Name, options); diff --git a/LibGit2Sharp/Core/GitSubmoduleOptions.cs b/LibGit2Sharp/Core/GitSubmoduleOptions.cs index 59c2b3f80..09a8e8265 100644 --- a/LibGit2Sharp/Core/GitSubmoduleOptions.cs +++ b/LibGit2Sharp/Core/GitSubmoduleOptions.cs @@ -11,8 +11,6 @@ internal struct GitSubmoduleUpdateOptions public GitFetchOptions FetchOptions; - public CheckoutStrategy CloneCheckoutStrategy; - public int AllowFetch; } } diff --git a/LibGit2Sharp/Repository.cs b/LibGit2Sharp/Repository.cs index a4f2e3077..73f560c3c 100644 --- a/LibGit2Sharp/Repository.cs +++ b/LibGit2Sharp/Repository.cs @@ -865,14 +865,11 @@ private static void RecursivelyCloneSubmodules(CloneOptions options, string repo using (Repository repo = new Repository(repoPath)) { - SubmoduleUpdateOptions updateOptions = new SubmoduleUpdateOptions() + var updateOptions = new SubmoduleUpdateOptions() { Init = true, - CredentialsProvider = options.FetchOptions.CredentialsProvider, OnCheckoutProgress = options.OnCheckoutProgress, - OnProgress = options.FetchOptions.OnProgress, - OnTransferProgress = options.FetchOptions.OnTransferProgress, - OnUpdateTips = options.FetchOptions.OnUpdateTips, + FetchOptions = options.FetchOptions }; string parentRepoWorkDir = repo.Info.WorkingDirectory; diff --git a/LibGit2Sharp/SubmoduleCollection.cs b/LibGit2Sharp/SubmoduleCollection.cs index c4cc1c020..061196c7d 100644 --- a/LibGit2Sharp/SubmoduleCollection.cs +++ b/LibGit2Sharp/SubmoduleCollection.cs @@ -74,43 +74,41 @@ public virtual void Init(string name, bool overwrite) /// Update specified submodule. /// /// This will: - /// 1) Optionally initialize the if it not already initialzed, + /// 1) Optionally initialize the if it not already initialized, /// 2) clone the sub repository if it has not already been cloned, and /// 3) checkout the commit ID for the submodule in the sub repository. /// /// /// The name of the submodule to update. - /// Options controlling submodule udpate behavior and callbacks. + /// Options controlling submodule update behavior and callbacks. public virtual void Update(string name, SubmoduleUpdateOptions options) { - options = options ?? new SubmoduleUpdateOptions(); + options ??= new SubmoduleUpdateOptions(); - using (var handle = Proxy.git_submodule_lookup(repo.Handle, name)) - { - if (handle == null) - { - throw new NotFoundException("Submodule lookup failed for '{0}'.", - name); - } + using var handle = Proxy.git_submodule_lookup(repo.Handle, name) ?? throw new NotFoundException("Submodule lookup failed for '{0}'.", name); + using var checkoutOptionsWrapper = new GitCheckoutOptsWrapper(options); + using var fetchOptionsWrapper = new GitFetchOptionsWrapper(); - using (GitCheckoutOptsWrapper checkoutOptionsWrapper = new GitCheckoutOptsWrapper(options)) - { - var gitCheckoutOptions = checkoutOptionsWrapper.Options; + var gitCheckoutOptions = checkoutOptionsWrapper.Options; - var remoteCallbacks = new RemoteCallbacks(options); - var gitRemoteCallbacks = remoteCallbacks.GenerateCallbacks(); + var gitFetchOptions = fetchOptionsWrapper.Options; + gitFetchOptions.ProxyOptions = options.FetchOptions.ProxyOptions.CreateGitProxyOptions(); + gitFetchOptions.RemoteCallbacks = new RemoteCallbacks(options.FetchOptions).GenerateCallbacks(); - var gitSubmoduleUpdateOpts = new GitSubmoduleUpdateOptions - { - Version = 1, - CheckoutOptions = gitCheckoutOptions, - FetchOptions = new GitFetchOptions { ProxyOptions = options.ProxyOptions.CreateGitProxyOptions(), RemoteCallbacks = gitRemoteCallbacks }, - CloneCheckoutStrategy = CheckoutStrategy.GIT_CHECKOUT_SAFE - }; - - Proxy.git_submodule_update(handle, options.Init, ref gitSubmoduleUpdateOpts); - } + if (options.FetchOptions != null && options.FetchOptions.CustomHeaders != null) + { + gitFetchOptions.CustomHeaders = + GitStrArrayManaged.BuildFrom(options.FetchOptions.CustomHeaders); } + + var gitSubmoduleUpdateOpts = new GitSubmoduleUpdateOptions + { + Version = 1, + CheckoutOptions = gitCheckoutOptions, + FetchOptions = gitFetchOptions + }; + + Proxy.git_submodule_update(handle, options.Init, ref gitSubmoduleUpdateOpts); } /// diff --git a/LibGit2Sharp/SubmoduleUpdateOptions.cs b/LibGit2Sharp/SubmoduleUpdateOptions.cs index 89f895d75..082e17338 100644 --- a/LibGit2Sharp/SubmoduleUpdateOptions.cs +++ b/LibGit2Sharp/SubmoduleUpdateOptions.cs @@ -6,7 +6,7 @@ namespace LibGit2Sharp /// /// Options controlling Submodule Update behavior and callbacks. /// - public sealed class SubmoduleUpdateOptions : FetchOptionsBase, IConvertableToGitCheckoutOpts + public sealed class SubmoduleUpdateOptions : IConvertableToGitCheckoutOpts { /// /// Initialize the submodule if it is not already initialized. @@ -30,6 +30,11 @@ public sealed class SubmoduleUpdateOptions : FetchOptionsBase, IConvertableToGit /// public CheckoutNotifyFlags CheckoutNotifyFlags { get; set; } + /// + /// Collection of parameters controlling Fetch behavior. + /// + public FetchOptions FetchOptions { get; internal set; } = new(); + CheckoutCallbacks IConvertableToGitCheckoutOpts.GenerateCallbacks() { return CheckoutCallbacks.From(OnCheckoutProgress, OnCheckoutNotify); From de87973b56633459d770602fc87d8f896af93175 Mon Sep 17 00:00:00 2001 From: Brandon Ording Date: Sun, 3 Dec 2023 15:42:35 -0500 Subject: [PATCH 14/14] Update CHANGES.md for v0.29 --- CHANGES.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 0cb2c978b..ae27d7716 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,16 @@ # LibGit2Sharp Changes -## v0.28 +## v0.29 - ([diff](https://github.com/libgit2/libgit2sharp/compare/0.28.0..0.29.0)) + +### Changes +- This release includes [libgit2 v1.7.1](https://github.com/libgit2/libgit2/releases/tag/v1.7.1). + - CI changes for the native binaries has removed support for CentOS 7. See [#2066](https://github.com/libgit2/libgit2sharp/pull/2066) for details. + +### Additions +- Add proxy options [#2065](https://github.com/libgit2/libgit2sharp/pull/2065) + - See PR for details, including some breaking changes to `CloneOptions` and `SubmoduleUpdateOptions` + +## v0.28 - ([diff](https://github.com/libgit2/libgit2sharp/compare/0.27.2..0.28.0)) ### Additions - Add CustomHeaders to PushOptions [#2052](https://github.com/libgit2/libgit2sharp/pull/2052)