diff --git a/.github/workflows/Build_and_publish_package.yml b/.github/workflows/Build_and_publish_package.yml new file mode 100644 index 00000000..ca82bffb --- /dev/null +++ b/.github/workflows/Build_and_publish_package.yml @@ -0,0 +1,42 @@ +name: Build and Deploy Packages + +on: + pull_request: + push: + branches: + - main + +jobs: + build: + # Currently we build LibGit2Sharp for Windows only + # See: https://docs.github.com/en/actions/configuring-and-managing-workflows/configuring-a-workflow#configuring-a-build-matrix + runs-on: windows-2019 + + steps: + # Checkout repo into build area + - uses: actions/checkout@v3 + with: + fetch-depth: 0 # avoid shallow clone so Nerdbank.GitVersioning can do its work. + + # Build and deploy nuget package + # We include the GitHub package source so that we can reference current packages and also so that we can push to the package repo + - name: Build Project and Package + run: | + dotnet nuget add source "https://nuget.pkg.github.com/mendix/index.json" --name "GitHub" --username ${{ secrets.GHPACKAGESUSER }} --password ${{ secrets.GHPACKAGESTOKEN }} + dotnet pack --configuration Release --output "mx_nuget" -p:PublicRelease=true LibGit2Sharp/LibGit2Sharp.csproj + shell: powershell #Keep as powershell and not pwsh + + - name: Upload build artifacts + uses: actions/upload-artifact@v3 + with: + name: nuget package + path: ${{ github.workspace }}/**/*.nupkg + + # After build we copy the binaries to package output folder + # Finally we pack and push the package to github packages + - name: Deploy Package + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + run: | + dotnet nuget add source "https://nuget.pkg.github.com/mendix/index.json" --name "GitHub" --username ${{ secrets.GHPACKAGESUSER }} --password ${{ secrets.GHPACKAGESTOKEN }} + dotnet nuget push "**/mx_nuget/Mendix.LibGit2Sharp*.nupkg" --source "GitHub" --skip-duplicate + shell: powershell #Keep as powershell and not pwsh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 118649aa..00000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,98 +0,0 @@ -name: CI -on: - push: - branches: [master, release-*] - tags: - - '[0-9]+.[0-9]+.[0-9]+' - - '[0-9]+.[0-9]+.[0-9]+-*' - pull_request: - workflow_dispatch: -env: - DOTNET_NOLOGO: true -jobs: - build: - name: Build - runs-on: ubuntu-20.04 - steps: - - name: Checkout - uses: actions/checkout@v2.3.4 - with: - fetch-depth: 0 - - name: Install .NET SDK - uses: actions/setup-dotnet@v1.8.1 - with: - dotnet-version: 6.0.x - - name: Build - run: dotnet build LibGit2Sharp.sln --configuration Release - - name: Upload packages - uses: actions/upload-artifact@v2.2.4 - with: - name: NuGet packages - path: bin/Packages/ - retention-days: 7 - test: - name: Test / ${{ matrix.os }} / ${{ matrix.arch }} / ${{ matrix.tfm }} - runs-on: ${{ matrix.os }} - strategy: - matrix: - arch: [ amd64 ] - os: [windows-2019, macos-10.15] - tfm: [ net472, netcoreapp3.1, net6.0 ] - exclude: - - os: macos-10.15 - tfm: net472 - fail-fast: false - steps: - - name: Checkout - uses: actions/checkout@v2.3.4 - with: - fetch-depth: 0 - - name: Install .NET SDK - uses: actions/setup-dotnet@v1.8.1 - with: - dotnet-version: 6.0.x - - name: Install .NET Core 3.1 runtime - if: matrix.tfm == 'netcoreapp3.1' - uses: actions/setup-dotnet@v1.8.1 - with: - dotnet-version: 3.1.x - - name: Run ${{ matrix.tfm }} tests - run: dotnet test LibGit2Sharp.sln --configuration Release --framework ${{ matrix.tfm }} --logger "GitHubActions" /p:ExtraDefine=LEAKS_IDENTIFYING - test-linux: - name: Test / ${{ matrix.distro }} / ${{ matrix.arch }} / ${{ matrix.tfm }} - runs-on: ubuntu-20.04 - strategy: - matrix: - arch: [ amd64 ] - # arch: [ amd64, arm64 ] - distro: [ alpine.3.12, alpine.3.13, alpine.3.14, centos.7, centos.8, debian.9, debian.10, debian.11, fedora.33, ubuntu.18.04, ubuntu.20.04 ] - sdk: [ '6.0', '3.1' ] - exclude: - - arch: arm64 - distro: alpine.3.12 - - arch: arm64 - distro: alpine.3.13 - sdk: '3.1' - - arch: arm64 - distro: alpine.3.14 - sdk: '3.1' - - arch: arm64 - distro: centos.7 - include: - - sdk: '6.0' - tfm: net6.0 - - sdk: '3.1' - tfm: netcoreapp3.1 - fail-fast: false - steps: - - name: Checkout - uses: actions/checkout@v2.3.4 - with: - fetch-depth: 0 - - name: Setup QEMU - if: matrix.arch == 'arm64' - run: docker run --rm --privileged multiarch/qemu-user-static:register --reset - - name: Run ${{ matrix.tfm }} tests - run: | - test_command="dotnet test LibGit2Sharp.sln --configuration Release -p:TargetFrameworks=${{ matrix.tfm }} --logger "GitHubActions" -p:ExtraDefine=LEAKS_IDENTIFYING" - docker run -t --rm --platform linux/${{ matrix.arch }} -v "$PWD:/app" gittools/build-images:${{ matrix.distro }}-sdk-${{ matrix.sdk }} sh -c "$test_command" diff --git a/.mailmap b/.mailmap deleted file mode 100644 index ef9348df..00000000 --- a/.mailmap +++ /dev/null @@ -1,8 +0,0 @@ -Keith Dahlby -Jameson Miller -Ben Straub -Saaman -nulltoken -Martin Woodward -Carlos Martín Nieto -someoneigna diff --git a/LibGit2Sharp.Tests/CloneFixture.cs b/LibGit2Sharp.Tests/CloneFixture.cs index 1b26c122..9e48e554 100644 --- a/LibGit2Sharp.Tests/CloneFixture.cs +++ b/LibGit2Sharp.Tests/CloneFixture.cs @@ -43,7 +43,7 @@ public void CanCloneWithCheckoutBranchName(string branchName, string headTipId) { var scd = BuildSelfCleaningDirectory(); - string clonedRepoPath = Repository.Clone(BareTestRepoPath, scd.DirectoryPath, new CloneOptions { BranchName = branchName }); + string clonedRepoPath = Repository.Clone(BareTestRepoPath, scd.DirectoryPath, new CloneOptions { BranchName = branchName }, new ProxyOptions()); using (var repo = new Repository(clonedRepoPath)) { @@ -107,7 +107,7 @@ public void CanCloneBarely(string url) string clonedRepoPath = Repository.Clone(url, scd.DirectoryPath, new CloneOptions { IsBare = true - }); + }, new ProxyOptions()); using (var repo = new Repository(clonedRepoPath)) { @@ -130,7 +130,7 @@ public void WontCheckoutIfAskedNotTo(string url) string clonedRepoPath = Repository.Clone(url, scd.DirectoryPath, new CloneOptions() { Checkout = false - }); + }, new ProxyOptions()); using (var repo = new Repository(clonedRepoPath)) { @@ -155,7 +155,7 @@ public void CallsProgressCallbacks(string url) OnProgress = progress => { progressWasCalled = true; return true; }, OnUpdateTips = (name, oldId, newId) => { updateTipsWasCalled = true; return true; }, OnCheckoutProgress = (a, b, c) => checkoutWasCalled = true - }); + }, new ProxyOptions()); Assert.True(transferWasCalled); Assert.True(progressWasCalled); @@ -175,7 +175,7 @@ public void CanCloneWithCredentials() new CloneOptions() { CredentialsProvider = Constants.PrivateRepoCredentials - }); + }, new ProxyOptions()); using (var repo = new Repository(clonedRepoPath)) @@ -289,7 +289,7 @@ public void CanInspectCertificateOnClone(string url, string hostname, Type certT }; Assert.Throws(() => - Repository.Clone(url, scd.DirectoryPath, options) + Repository.Clone(url, scd.DirectoryPath, options, new ProxyOptions()) ); Assert.True(wasCalled); @@ -437,7 +437,7 @@ public void CanRecursivelyCloneSubmodules() RepositoryOperationCompleted = repositoryOperationCompleted, }; - string clonedRepoPath = Repository.Clone(uri.AbsolutePath, scd.DirectoryPath, options); + string clonedRepoPath = Repository.Clone(uri.AbsolutePath, scd.DirectoryPath, options, new ProxyOptions()); string workDirPath; using (Repository repo = new Repository(clonedRepoPath)) @@ -521,7 +521,7 @@ public void CanCancelRecursiveClone() }; Assert.Throws(() => - Repository.Clone(uri.AbsolutePath, scd.DirectoryPath, options)); + Repository.Clone(uri.AbsolutePath, scd.DirectoryPath, options, new ProxyOptions())); // Cancel after super repository is cloned, but before submodule is cloned. cancelDepth = 1; @@ -530,7 +530,7 @@ public void CanCancelRecursiveClone() try { - Repository.Clone(uri.AbsolutePath, scd.DirectoryPath, options); + Repository.Clone(uri.AbsolutePath, scd.DirectoryPath, options, new ProxyOptions()); } catch (RecurseSubmodulesException ex) { @@ -562,7 +562,7 @@ public void CannotCloneWithForbiddenCustomHeaders() FetchOptions = new FetchOptions { CustomHeaders = new String[] { knownHeader } } }; - Assert.Throws(() => Repository.Clone(url, scd.DirectoryPath, cloneOptions)); + Assert.Throws(() => Repository.Clone(url, scd.DirectoryPath, cloneOptions, new ProxyOptions())); } [Fact] @@ -578,7 +578,7 @@ public void CannotCloneWithMalformedCustomHeaders() FetchOptions = new FetchOptions { CustomHeaders = new String[] { knownHeader } } }; - Assert.Throws(() => Repository.Clone(url, scd.DirectoryPath, cloneOptions)); + Assert.Throws(() => Repository.Clone(url, scd.DirectoryPath, cloneOptions, new ProxyOptions())); } [Fact] @@ -594,7 +594,7 @@ public void CanCloneWithCustomHeaders() FetchOptions = new FetchOptions { CustomHeaders = new String[] { knownHeader } } }; - var clonedRepoPath = Repository.Clone(url, scd.DirectoryPath, cloneOptions); + var clonedRepoPath = Repository.Clone(url, scd.DirectoryPath, cloneOptions, new ProxyOptions()); Assert.True(Directory.Exists(clonedRepoPath)); } } diff --git a/LibGit2Sharp.Tests/FetchFixture.cs b/LibGit2Sharp.Tests/FetchFixture.cs index c0c6f047..444aec3c 100644 --- a/LibGit2Sharp.Tests/FetchFixture.cs +++ b/LibGit2Sharp.Tests/FetchFixture.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using LibGit2Sharp.Core; using LibGit2Sharp.Tests.TestHelpers; using Xunit; @@ -42,7 +43,7 @@ public void CanFetchIntoAnEmptyRepository(string url) } // Perform the actual fetch - Commands.Fetch(repo, remoteName, new string[0], new FetchOptions { OnUpdateTips = expectedFetchState.RemoteUpdateTipsHandler }, null); + Commands.Fetch(repo, remoteName, new string[0], new FetchOptions { OnUpdateTips = expectedFetchState.RemoteUpdateTipsHandler }, null, new ProxyOptions()); // Verify the expected expectedFetchState.CheckUpdatedReferences(repo); @@ -65,7 +66,7 @@ public void CanFetchIntoAnEmptyRepositoryWithCredentials() Commands.Fetch(repo, remoteName, new string[0], new FetchOptions { CredentialsProvider = Constants.PrivateRepoCredentials - }, null); + }, null, new ProxyOptions()); } } @@ -102,7 +103,7 @@ public void CanFetchAllTagsIntoAnEmptyRepository(string url) { TagFetchMode = TagFetchMode.All, OnUpdateTips = expectedFetchState.RemoteUpdateTipsHandler - }, null); + }, null, new ProxyOptions()); // Verify the expected expectedFetchState.CheckUpdatedReferences(repo); @@ -148,7 +149,7 @@ public void CanFetchCustomRefSpecsIntoAnEmptyRepository(string url, string local { TagFetchMode = TagFetchMode.None, OnUpdateTips = expectedFetchState.RemoteUpdateTipsHandler - }, null); + }, null, new ProxyOptions()); // Verify the expected expectedFetchState.CheckUpdatedReferences(repo); @@ -179,7 +180,7 @@ public void FetchRespectsConfiguredAutoTagSetting(TagFetchMode tagFetchMode, int r => r.TagFetchMode = tagFetchMode); // Perform the actual fetch. - Commands.Fetch(repo, remoteName, new string[0], null, null); + Commands.Fetch(repo, remoteName, new string[0], null, null, null); // Verify the number of fetched tags. Assert.Equal(expectedTagCount, repo.Tags.Count()); @@ -197,7 +198,7 @@ public void CanFetchAllTagsAfterAnInitialClone() using (var repo = new Repository(clonedRepoPath)) { - Commands.Fetch(repo, "origin", new string[0], new FetchOptions { TagFetchMode = TagFetchMode.All }, null); + Commands.Fetch(repo, "origin", new string[0], new FetchOptions { TagFetchMode = TagFetchMode.All }, null, new ProxyOptions()); } } @@ -223,17 +224,17 @@ public void FetchHonorsTheFetchPruneConfigurationEntry() // No pruning when the configuration entry isn't defined Assert.Null(clonedRepo.Config.Get("fetch.prune")); - Commands.Fetch(clonedRepo, "origin", new string[0], null, null); + Commands.Fetch(clonedRepo, "origin", new string[0], null, null, null); Assert.Equal(5, clonedRepo.Branches.Count(b => b.IsRemote && b.FriendlyName != "origin/HEAD")); // No pruning when the configuration entry is set to false clonedRepo.Config.Set("fetch.prune", false); - Commands.Fetch(clonedRepo, "origin", new string[0], null, null); + Commands.Fetch(clonedRepo, "origin", new string[0], null, null, null); Assert.Equal(5, clonedRepo.Branches.Count(b => b.IsRemote && b.FriendlyName != "origin/HEAD")); // Auto pruning when the configuration entry is set to true clonedRepo.Config.Set("fetch.prune", true); - Commands.Fetch(clonedRepo, "origin", new string[0], null, null); + Commands.Fetch(clonedRepo, "origin", new string[0], null, null, null); Assert.Equal(4, clonedRepo.Branches.Count(b => b.IsRemote && b.FriendlyName != "origin/HEAD")); } } @@ -251,7 +252,8 @@ public void CannotFetchWithForbiddenCustomHeaders() var options = new FetchOptions { CustomHeaders = new String[] { knownHeader } }; using (var repo = new Repository(clonedRepoPath)) { - Assert.Throws(() => Commands.Fetch(repo, "origin", new string[0], options, null)); + var ex = Assert.Throws(() => Commands.Fetch(repo, "origin", new string[0], options, null, new ProxyOptions())); + Assert.Equal(GitErrorCategory.Invalid, ex.Category); } } @@ -268,7 +270,7 @@ public void CanFetchWithCustomHeaders() var options = new FetchOptions { CustomHeaders = new String[] { knownHeader } }; using (var repo = new Repository(clonedRepoPath)) { - Commands.Fetch(repo, "origin", new string[0], options, null); + Commands.Fetch(repo, "origin", new string[0], options, null, new ProxyOptions()); } } @@ -285,7 +287,7 @@ public void CannotFetchWithMalformedCustomHeaders() var options = new FetchOptions { CustomHeaders = new String[] { knownHeader } }; using (var repo = new Repository(clonedRepoPath)) { - Assert.Throws(() => Commands.Fetch(repo, "origin", new string[0], options, null)); + Assert.Throws(() => Commands.Fetch(repo, "origin", new string[0], options, null, new ProxyOptions())); } } diff --git a/LibGit2Sharp.Tests/NetworkFixture.cs b/LibGit2Sharp.Tests/NetworkFixture.cs index 3a351743..aa2eb4b0 100644 --- a/LibGit2Sharp.Tests/NetworkFixture.cs +++ b/LibGit2Sharp.Tests/NetworkFixture.cs @@ -127,7 +127,8 @@ public void CanListRemoteReferencesWithCredentials() { Remote remote = repo.Network.Remotes.Add(remoteName, Constants.PrivateRepoUrl); - var references = repo.Network.ListReferences(remote, Constants.PrivateRepoCredentials); + var references = repo.Network.ListReferences(remote, + Constants.PrivateRepoCredentials, Constants.PrivateRepoCertificateCheck, new ProxyOptions()); foreach (var reference in references) { @@ -161,7 +162,7 @@ public void CanPull(FastForwardStrategy fastForwardStrategy) } }; - MergeResult mergeResult = Commands.Pull(repo, Constants.Signature, pullOptions); + MergeResult mergeResult = Commands.Pull(repo, Constants.Signature, pullOptions, new ProxyOptions()); if (fastForwardStrategy == FastForwardStrategy.Default || fastForwardStrategy == FastForwardStrategy.FastForwardOnly) { @@ -194,7 +195,7 @@ public void CanPullIntoEmptyRepo() b => b.UpstreamBranch = "refs/heads/master"); // Pull! - MergeResult mergeResult = Commands.Pull(repo, Constants.Signature, new PullOptions()); + MergeResult mergeResult = Commands.Pull(repo, Constants.Signature, new PullOptions(), new ProxyOptions()); Assert.Equal(MergeStatus.FastForward, mergeResult.Status); Assert.Equal(mergeResult.Commit, repo.Branches["refs/remotes/origin/master"].Tip); @@ -221,7 +222,7 @@ public void PullWithoutMergeBranchThrows() try { - Commands.Pull(repo, Constants.Signature, new PullOptions()); + Commands.Pull(repo, Constants.Signature, new PullOptions(), new ProxyOptions()); } catch (MergeFetchHeadNotFoundException ex) { @@ -249,7 +250,7 @@ public void CanMergeFetchedRefs() Assert.False(repo.RetrieveStatus().Any()); Assert.Equal(repo.Lookup("refs/remotes/origin/master~1"), repo.Head.Tip); - Commands.Fetch(repo, repo.Head.RemoteName, new string[0], null, null); + Commands.Fetch(repo, repo.Head.RemoteName, new string[0], null, null, null); MergeOptions mergeOptions = new MergeOptions() { @@ -276,7 +277,7 @@ public void CanPruneRefs() using (var repo = new Repository(clonedRepoPath)) { repo.Network.Remotes.Add("pruner", clonedRepoPath2); - Commands.Fetch(repo, "pruner", new string[0], null, null); + Commands.Fetch(repo, "pruner", new string[0], null, null, null); Assert.NotNull(repo.Refs["refs/remotes/pruner/master"]); // Remove the branch from the source repository @@ -286,11 +287,11 @@ public void CanPruneRefs() } // and by default we don't prune it - Commands.Fetch(repo, "pruner", new string[0], null, null); + Commands.Fetch(repo, "pruner", new string[0], null, null, null); Assert.NotNull(repo.Refs["refs/remotes/pruner/master"]); // but we do when asked by the user - Commands.Fetch(repo, "pruner", new string[0], new FetchOptions { Prune = true }, null); + Commands.Fetch(repo, "pruner", new string[0], new FetchOptions { Prune = true }, null, new ProxyOptions()); Assert.Null(repo.Refs["refs/remotes/pruner/master"]); } } diff --git a/LibGit2Sharp.Tests/PushFixture.cs b/LibGit2Sharp.Tests/PushFixture.cs index d8cf2bef..e61c0b0f 100644 --- a/LibGit2Sharp.Tests/PushFixture.cs +++ b/LibGit2Sharp.Tests/PushFixture.cs @@ -75,7 +75,7 @@ public void CanPushABranchTrackingAnUpstreamBranch() OnPackBuilderProgress = packBuilderCb, }; - AssertPush(repo => repo.Network.Push(repo.Network.Remotes["origin"], "HEAD", @"refs/heads/master", options)); + AssertPush(repo => repo.Network.Push(repo.Network.Remotes["origin"], "HEAD", @"refs/heads/master", options, new ProxyOptions())); Assert.True(packBuilderCalled); } @@ -102,7 +102,7 @@ public void CanInvokePrePushCallbackAndSucceed() OnNegotiationCompletedBeforePush = prePushHook, }; - AssertPush(repo => repo.Network.Push(repo.Network.Remotes["origin"], "HEAD", @"refs/heads/master", options)); + AssertPush(repo => repo.Network.Push(repo.Network.Remotes["origin"], "HEAD", @"refs/heads/master", options, new ProxyOptions())); Assert.True(packBuilderCalled); Assert.True(prePushHandlerCalled); } @@ -130,7 +130,7 @@ public void CanInvokePrePushCallbackAndFail() OnNegotiationCompletedBeforePush = prePushHook }; - Assert.Throws(() => { AssertPush(repo => repo.Network.Push(repo.Network.Remotes["origin"], "HEAD", @"refs/heads/master", options)); }); + Assert.Throws(() => { AssertPush(repo => repo.Network.Push(repo.Network.Remotes["origin"], "HEAD", @"refs/heads/master", options, new ProxyOptions())); }); Assert.False(packBuilderCalled); Assert.True(prePushHandlerCalled); diff --git a/LibGit2Sharp.Tests/RepositoryFixture.cs b/LibGit2Sharp.Tests/RepositoryFixture.cs index bf27b609..21d76e35 100644 --- a/LibGit2Sharp.Tests/RepositoryFixture.cs +++ b/LibGit2Sharp.Tests/RepositoryFixture.cs @@ -212,13 +212,13 @@ public void CanFetchFromRemoteByName() } // Perform the actual fetch - Commands.Fetch(repo, remoteName, new string[0], new FetchOptions { OnUpdateTips = expectedFetchState.RemoteUpdateTipsHandler }, null); + Commands.Fetch(repo, remoteName, new string[0], new FetchOptions { OnUpdateTips = expectedFetchState.RemoteUpdateTipsHandler }, null, new ProxyOptions()); // Verify the expected state expectedFetchState.CheckUpdatedReferences(repo); // Now fetch the rest of the tags - Commands.Fetch(repo, remoteName, new string[0], new FetchOptions { TagFetchMode = TagFetchMode.All }, null); + Commands.Fetch(repo, remoteName, new string[0], new FetchOptions { TagFetchMode = TagFetchMode.All }, null, new ProxyOptions()); // Verify that the "nearly-dangling" tag is now in the repo. Tag nearlyDanglingTag = repo.Tags["nearly-dangling"]; @@ -697,7 +697,7 @@ public void CanListRemoteReferencesWithCredentials() "Populate Constants.PrivateRepo* to run this test"); IEnumerable references = Repository.ListRemoteReferences(Constants.PrivateRepoUrl, - Constants.PrivateRepoCredentials); + Constants.PrivateRepoCredentials, Constants.PrivateRepoCertificateCheck, new ProxyOptions()); foreach (var reference in references) { diff --git a/LibGit2Sharp.Tests/SubmoduleFixture.cs b/LibGit2Sharp.Tests/SubmoduleFixture.cs index 735bfd93..2f37d202 100644 --- a/LibGit2Sharp.Tests/SubmoduleFixture.cs +++ b/LibGit2Sharp.Tests/SubmoduleFixture.cs @@ -215,7 +215,7 @@ public void UpdatingUninitializedSubmoduleThrows() Assert.NotNull(submodule); Assert.True(submodule.RetrieveStatus().HasFlag(SubmoduleStatus.WorkDirUninitialized)); - Assert.Throws(() => repo.Submodules.Update(submodule.Name, new SubmoduleUpdateOptions())); + Assert.Throws(() => repo.Submodules.Update(submodule.Name, new SubmoduleUpdateOptions(), new ProxyOptions())); } } @@ -244,7 +244,7 @@ public void CanUpdateSubmodule() }; repo.Submodules.Init(submodule.Name, false); - repo.Submodules.Update(submodule.Name, options); + repo.Submodules.Update(submodule.Name, options, new ProxyOptions()); Assert.True(submodule.RetrieveStatus().HasFlag(SubmoduleStatus.InWorkDir)); Assert.True(checkoutProgressCalled); @@ -269,7 +269,7 @@ public void CanInitializeAndUpdateSubmodule() Assert.NotNull(submodule); Assert.True(submodule.RetrieveStatus().HasFlag(SubmoduleStatus.WorkDirUninitialized)); - repo.Submodules.Update(submodule.Name, new SubmoduleUpdateOptions() { Init = true }); + repo.Submodules.Update(submodule.Name, new SubmoduleUpdateOptions() { Init = true }, new ProxyOptions()); Assert.True(submodule.RetrieveStatus().HasFlag(SubmoduleStatus.InWorkDir)); Assert.Equal((ObjectId)"480095882d281ed676fe5b863569520e54a7d5c0", submodule.HeadCommitId); @@ -292,7 +292,7 @@ public void CanUpdateSubmoduleAfterCheckout() Assert.True(submodule.RetrieveStatus().HasFlag(SubmoduleStatus.WorkDirUninitialized)); repo.Submodules.Init(submodule.Name, false); - repo.Submodules.Update(submodule.Name, new SubmoduleUpdateOptions()); + repo.Submodules.Update(submodule.Name, new SubmoduleUpdateOptions(), new ProxyOptions()); Assert.True(submodule.RetrieveStatus().HasFlag(SubmoduleStatus.InWorkDir)); @@ -305,7 +305,7 @@ public void CanUpdateSubmoduleAfterCheckout() Assert.Equal((ObjectId)"5e4963595a9774b90524d35a807169049de8ccad", submodule.IndexCommitId); Assert.Equal((ObjectId)"480095882d281ed676fe5b863569520e54a7d5c0", submodule.WorkDirCommitId); - repo.Submodules.Update(submodule.Name, new SubmoduleUpdateOptions()); + repo.Submodules.Update(submodule.Name, new SubmoduleUpdateOptions(), new ProxyOptions()); submodule = repo.Submodules[submoduleName]; Assert.Equal((ObjectId)"5e4963595a9774b90524d35a807169049de8ccad", submodule.HeadCommitId); diff --git a/LibGit2Sharp.Tests/TestHelpers/Constants.cs b/LibGit2Sharp.Tests/TestHelpers/Constants.cs index b5cd96d7..2d780208 100644 --- a/LibGit2Sharp.Tests/TestHelpers/Constants.cs +++ b/LibGit2Sharp.Tests/TestHelpers/Constants.cs @@ -51,6 +51,11 @@ public static Credentials PrivateRepoCredentials(string url, string usernameFrom return null; } + public static bool PrivateRepoCertificateCheck(Certificate certificate, bool valid, string host) + { + return true; + } + public static string BuildPath() { string tempPath = null; diff --git a/LibGit2Sharp.Tests/desktop/SmartSubtransportFixture.cs b/LibGit2Sharp.Tests/desktop/SmartSubtransportFixture.cs index ff4d0fcd..42ec5029 100644 --- a/LibGit2Sharp.Tests/desktop/SmartSubtransportFixture.cs +++ b/LibGit2Sharp.Tests/desktop/SmartSubtransportFixture.cs @@ -63,7 +63,7 @@ public void CustomSmartSubtransportTest(string scheme, string url) // Perform the actual fetch Commands.Fetch(repo, remoteName, new string[0], new FetchOptions { OnUpdateTips = expectedFetchState.RemoteUpdateTipsHandler, TagFetchMode = TagFetchMode.Auto }, - null); + null, new ProxyOptions()); // Verify the expected expectedFetchState.CheckUpdatedReferences(repo); diff --git a/LibGit2Sharp/AuthenticationException.cs b/LibGit2Sharp/AuthenticationException.cs new file mode 100644 index 00000000..8de34112 --- /dev/null +++ b/LibGit2Sharp/AuthenticationException.cs @@ -0,0 +1,66 @@ +using System; +using System.Runtime.Serialization; +using LibGit2Sharp.Core; + +namespace LibGit2Sharp +{ + /// + /// The exception that is thrown when Authentication fails + /// + [Serializable] + public class AuthenticationException : NativeException + { + /// + /// Initializes a new instance of the class. + /// + public AuthenticationException() + { } + + /// + /// Initializes a new instance of the class with a specified error message. + /// + /// A message that describes the error. + public AuthenticationException(string message) + : base(message) + { } + + /// + /// Initializes a new instance of the class with a specified error message. + /// + /// A composite format string for use in . + /// An object array that contains zero or more objects to format. + public AuthenticationException(string format, params object[] args) + : base(format, args) + { } + + /// + /// Initializes a new instance of the class with a specified error message and a reference to the inner exception that is the cause of this exception. + /// + /// The error message that explains the reason for the exception. + /// The exception that is the cause of the current exception. If the parameter is not a null reference, the current exception is raised in a catch block that handles the inner exception. + public AuthenticationException(string message, Exception innerException) + : base(message, innerException) + { } + + /// + /// Initializes a new instance of the class with a serialized data. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + protected AuthenticationException(SerializationInfo info, StreamingContext context) + : base(info, context) + { } + + internal AuthenticationException(string message, GitErrorCategory category) + : base(message, category) + { } + + internal override GitErrorCode ErrorCode + { + get + { + return GitErrorCode.Auth; + } + } + } +} diff --git a/LibGit2Sharp/Commands/Fetch.cs b/LibGit2Sharp/Commands/Fetch.cs index d61fca5a..dbea765c 100644 --- a/LibGit2Sharp/Commands/Fetch.cs +++ b/LibGit2Sharp/Commands/Fetch.cs @@ -29,18 +29,19 @@ private static RemoteHandle RemoteFromNameOrUrl(RepositoryHandle repoHandle, str /// /// The repository in which to fetch. /// The remote to fetch from. Either as a remote name or a URL + /// List of refspecs to apply as active. /// Fetch options. /// Log message for any ref updates. - /// List of refspecs to apply as active. - public static void Fetch(Repository repository, string remote, IEnumerable refspecs, FetchOptions options, string logMessage) + /// Proxy options. + public static void Fetch(Repository repository, string remote, IEnumerable refspecs, FetchOptions options, string logMessage, ProxyOptions proxy) { Ensure.ArgumentNotNull(remote, "remote"); options = options ?? new FetchOptions(); using (var remoteHandle = RemoteFromNameOrUrl(repository.Handle, remote)) using (var fetchOptionsWrapper = new GitFetchOptionsWrapper()) + using (var proxyOptionsWrapper = new GitProxyOptionsWrapper(proxy)) { - var callbacks = new RemoteCallbacks(options); GitRemoteCallbacks gitCallbacks = callbacks.GenerateCallbacks(); @@ -75,7 +76,7 @@ public static void Fetch(Repository repository, string remote, IEnumerableThe repository. /// The signature to use for the merge. /// The options for fetch and merging. - public static MergeResult Pull(Repository repository, Signature merger, PullOptions options) + /// The options for proxy settings. + public static MergeResult Pull(Repository repository, Signature merger, PullOptions options, ProxyOptions proxy) { Ensure.ArgumentNotNull(repository, "repository"); Ensure.ArgumentNotNull(merger, "merger"); @@ -34,7 +35,7 @@ public static MergeResult Pull(Repository repository, Signature merger, PullOpti throw new LibGit2SharpException("No upstream remote for the current branch."); } - Commands.Fetch(repository, currentBranch.RemoteName, new string[0], options.FetchOptions, null); + Commands.Fetch(repository, currentBranch.RemoteName, new string[0], options.FetchOptions, null, proxy); return repository.MergeFetchedRefs(merger, options.MergeOptions); } } diff --git a/LibGit2Sharp/Core/Ensure.cs b/LibGit2Sharp/Core/Ensure.cs index 3cf03d24..ac454217 100644 --- a/LibGit2Sharp/Core/Ensure.cs +++ b/LibGit2Sharp/Core/Ensure.cs @@ -128,6 +128,17 @@ private static readonly Dictionary new LockedFileException(m, c) }, { GitErrorCode.NotFound, (m, c) => new NotFoundException(m, c) }, { GitErrorCode.Peel, (m, c) => new PeelException(m, c) }, + { GitErrorCode.Auth, (m, c) => new AuthenticationException(m, c) }, + { GitErrorCode.Certificate, (m, c) => new ServerCertificateInvalidException(m, c) }, + { GitErrorCode.OrphanedHead, (m, c) => new OrphanedHeadException(m, c) }, + { GitErrorCode.Applied, (m, c) => new PatchOrMergeAlreadyAppliedException(m, c) }, + { GitErrorCode.Modified, (m, c) => new ReferenceValueDoesNotMatchException(m, c) }, + { GitErrorCode.Uncommitted, (m, c) => new UncommittedChangesException(m, c) }, + { GitErrorCode.EndOfFile, (m, c) => new EndOfFileException(m, c) }, + { GitErrorCode.MergeConflict, (m, c) => new MergeConflictException(m, c) }, + { GitErrorCode.PassThrough, (m, c) => new PassThroughException(m, c) }, + { GitErrorCode.IterOver, (m, c) => new GitIndexOutOfRangeException(m, c) }, + { GitErrorCode.Mismatch, (m, c) => new ObjectHasUnexpectedIdException(m, c) }, }; private static unsafe void HandleError(int result) @@ -143,12 +154,13 @@ private static unsafe void HandleError(int result) else { errorMessage = LaxUtf8Marshaler.FromNative(error->Message); + errorCategory = error->Category; } Func exceptionBuilder; if (!GitErrorsToLibGit2SharpExceptions.TryGetValue((GitErrorCode)result, out exceptionBuilder)) { - exceptionBuilder = (m, c) => new LibGit2SharpException(m, c); + exceptionBuilder = (m, c) => new LibGit2SharpException(m, (GitErrorCode)result, c); } throw exceptionBuilder(errorMessage, errorCategory); diff --git a/LibGit2Sharp/Core/GitErrorCategory.cs b/LibGit2Sharp/Core/GitErrorCategory.cs index 5fc4c7d5..cd5b4b5a 100644 --- a/LibGit2Sharp/Core/GitErrorCategory.cs +++ b/LibGit2Sharp/Core/GitErrorCategory.cs @@ -1,6 +1,6 @@ namespace LibGit2Sharp.Core { - internal enum GitErrorCategory + public enum GitErrorCategory { Unknown = -1, None, @@ -36,6 +36,8 @@ internal enum GitErrorCategory Filesystem, Patch, Worktree, - Sha1 + Sha1, + Http, + Internal } } diff --git a/LibGit2Sharp/Core/GitErrorCode.cs b/LibGit2Sharp/Core/GitErrorCode.cs index 6180cc4a..37196958 100644 --- a/LibGit2Sharp/Core/GitErrorCode.cs +++ b/LibGit2Sharp/Core/GitErrorCode.cs @@ -1,8 +1,18 @@ namespace LibGit2Sharp.Core { - internal enum GitErrorCode + /// + /// Git Error Code contains a list of possible error codes returned by LibGit2 + /// + public enum GitErrorCode { + /// + /// No Error result OK + /// Ok = 0, + + /// + /// General Error + /// Error = -1, /// diff --git a/LibGit2Sharp/Core/GitProxyOptions.cs b/LibGit2Sharp/Core/GitProxyOptions.cs index b62b8e08..f9818a28 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 NativeMethods.git_cred_acquire_cb CredentialsCb; + public NativeMethods.git_transport_certificate_check_cb CertificateCheck; public IntPtr CbPayload; } } diff --git a/LibGit2Sharp/Core/GitProxyOptionsWrapper.cs b/LibGit2Sharp/Core/GitProxyOptionsWrapper.cs new file mode 100644 index 00000000..4fdc7980 --- /dev/null +++ b/LibGit2Sharp/Core/GitProxyOptionsWrapper.cs @@ -0,0 +1,54 @@ +using System; + +namespace LibGit2Sharp.Core +{ + internal class GitProxyOptionsWrapper : IDisposable + { + public GitProxyOptionsWrapper(ProxyOptions proxyOptions) + { + GitProxyOptions = BuildFrom(proxyOptions); + } + + internal GitProxyOptions GitProxyOptions; + + private GitRemoteCallbacks GitCallbacks; + + private GitProxyOptions BuildFrom(ProxyOptions proxyOptions) + { + var opts = new GitProxyOptions + { + Version = 1, + Type = GitProxyType.Auto + }; + + if (proxyOptions == null) + { + return opts; + } + + if (proxyOptions.Url != null) + { + opts.Url = StrictUtf8Marshaler.FromManaged(proxyOptions.Url); + opts.Type = GitProxyType.Specified; + } + + if (proxyOptions.CredentialsProvider != null || + proxyOptions.CertificateCheck != null) + { + var callbacks = new RemoteCallbacks(proxyOptions.CredentialsProvider, proxyOptions.CertificateCheck); + GitCallbacks = callbacks.GenerateCallbacks(); + + opts.CredentialsCb = GitCallbacks.acquire_credentials; + opts.CertificateCheck = GitCallbacks.certificate_check; + } + + return opts; + } + + public void Dispose() + { + EncodingMarshaler.Cleanup(GitProxyOptions.Url); + GitProxyOptions.Url = IntPtr.Zero; + } + } +} diff --git a/LibGit2Sharp/Core/GitRepositoryInitOptions.cs b/LibGit2Sharp/Core/GitRepositoryInitOptions.cs index f639a0d8..1b7b0e66 100644 --- a/LibGit2Sharp/Core/GitRepositoryInitOptions.cs +++ b/LibGit2Sharp/Core/GitRepositoryInitOptions.cs @@ -16,7 +16,7 @@ internal class GitRepositoryInitOptions : IDisposable public IntPtr InitialHead; public IntPtr OriginUrl; - public static GitRepositoryInitOptions BuildFrom(FilePath workdirPath, bool isBare) + public static GitRepositoryInitOptions BuildFrom(InitOptions initOptions) { var opts = new GitRepositoryInitOptions { @@ -24,18 +24,28 @@ public static GitRepositoryInitOptions BuildFrom(FilePath workdirPath, bool isBa Mode = 0 /* GIT_REPOSITORY_INIT_SHARED_UMASK */ }; - if (workdirPath != null) + if (initOptions == null) { - Debug.Assert(!isBare); + return opts; + } + + if (initOptions.WorkdirPath != null) + { + Debug.Assert(!initOptions.IsBare); - opts.WorkDirPath = StrictFilePathMarshaler.FromManaged(workdirPath); + opts.WorkDirPath = StrictFilePathMarshaler.FromManaged(initOptions.WorkdirPath); } - if (isBare) + if (initOptions.IsBare) { opts.Flags |= GitRepositoryInitFlags.GIT_REPOSITORY_INIT_BARE; } + if (initOptions.InitialHead != null) + { + opts.InitialHead = StrictUtf8Marshaler.FromManaged(initOptions.InitialHead); + } + return opts; } @@ -43,6 +53,9 @@ public void Dispose() { EncodingMarshaler.Cleanup(WorkDirPath); WorkDirPath = IntPtr.Zero; + + EncodingMarshaler.Cleanup(InitialHead); + InitialHead = IntPtr.Zero; } } diff --git a/LibGit2Sharp/Core/GitStatusOptions.cs b/LibGit2Sharp/Core/GitStatusOptions.cs index d577cefe..99fd319f 100644 --- a/LibGit2Sharp/Core/GitStatusOptions.cs +++ b/LibGit2Sharp/Core/GitStatusOptions.cs @@ -15,6 +15,8 @@ internal class GitStatusOptions : IDisposable public IntPtr Baseline = IntPtr.Zero; + public uint RenameThreshold; + public void Dispose() { PathSpec.Dispose(); diff --git a/LibGit2Sharp/Core/NativeMethods.cs b/LibGit2Sharp/Core/NativeMethods.cs index f5d45f3c..13a72785 100644 --- a/LibGit2Sharp/Core/NativeMethods.cs +++ b/LibGit2Sharp/Core/NativeMethods.cs @@ -1391,6 +1391,11 @@ internal static extern unsafe int git_remote_create_with_fetchspec( [MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string url, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string refspec); + [DllImport(libgit2, CallingConvention = CallingConvention.Cdecl)] + internal static extern unsafe int git_remote_default_branch( + GitBuf res, + git_remote* remote); + [DllImport(libgit2, CallingConvention = CallingConvention.Cdecl)] internal static extern unsafe int git_remote_delete( git_repository* repo, diff --git a/LibGit2Sharp/Core/Proxy.cs b/LibGit2Sharp/Core/Proxy.cs index 50cefc0d..4cdc5694 100644 --- a/LibGit2Sharp/Core/Proxy.cs +++ b/LibGit2Sharp/Core/Proxy.cs @@ -2179,6 +2179,23 @@ public static unsafe void git_remote_connect(RemoteHandle remote, GitDirection d } } + public static unsafe string git_remote_default_branch(RemoteHandle remote) + { + using (var buf = new GitBuf()) + { + int res = NativeMethods.git_remote_default_branch(buf, remote); + + if (res == (int)GitErrorCode.NotFound) + { + return null; + } + + Ensure.ZeroResult(res); + + return LaxUtf8Marshaler.FromNative(buf.ptr); + } + } + public static unsafe void git_remote_delete(RepositoryHandle repo, string name) { int res = NativeMethods.git_remote_delete(repo, name); @@ -2482,18 +2499,14 @@ public static unsafe IndexHandle git_repository_index(RepositoryHandle repo) } public static unsafe RepositoryHandle git_repository_init_ext( - FilePath workdirPath, FilePath gitdirPath, - bool isBare) + GitRepositoryInitOptions opts) { - using (var opts = GitRepositoryInitOptions.BuildFrom(workdirPath, isBare)) - { - git_repository* repo; - int res = NativeMethods.git_repository_init_ext(out repo, gitdirPath, opts); - Ensure.ZeroResult(res); + git_repository* repo; + int res = NativeMethods.git_repository_init_ext(out repo, gitdirPath, opts); + Ensure.ZeroResult(res); - return new RepositoryHandle(repo, true); - } + return new RepositoryHandle(repo, true); } public static unsafe bool git_repository_is_bare(RepositoryHandle repo) diff --git a/LibGit2Sharp/EndOfFileException.cs b/LibGit2Sharp/EndOfFileException.cs new file mode 100644 index 00000000..6200f1ed --- /dev/null +++ b/LibGit2Sharp/EndOfFileException.cs @@ -0,0 +1,66 @@ +using System; +using System.Runtime.Serialization; +using LibGit2Sharp.Core; + +namespace LibGit2Sharp +{ + /// + /// The exception that is thrown when Unexpected EOF occurred. + /// + [Serializable] + public class EndOfFileException : NativeException + { + /// + /// Initializes a new instance of the class. + /// + public EndOfFileException() + { } + + /// + /// Initializes a new instance of the class with a specified error message. + /// + /// A message that describes the error. + public EndOfFileException(string message) + : base(message) + { } + + /// + /// Initializes a new instance of the class with a specified error message. + /// + /// A composite format string for use in . + /// An object array that contains zero or more objects to format. + public EndOfFileException(string format, params object[] args) + : base(format, args) + { } + + /// + /// Initializes a new instance of the class with a specified error message and a reference to the inner exception that is the cause of this exception. + /// + /// The error message that explains the reason for the exception. + /// The exception that is the cause of the current exception. If the parameter is not a null reference, the current exception is raised in a catch block that handles the inner exception. + public EndOfFileException(string message, Exception innerException) + : base(message, innerException) + { } + + /// + /// Initializes a new instance of the class with a serialized data. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + protected EndOfFileException(SerializationInfo info, StreamingContext context) + : base(info, context) + { } + + internal EndOfFileException(string message, GitErrorCategory category) + : base(message, category) + { } + + internal override GitErrorCode ErrorCode + { + get + { + return GitErrorCode.EndOfFile; + } + } + } +} diff --git a/LibGit2Sharp/GitIndexOutOfRangeException.cs b/LibGit2Sharp/GitIndexOutOfRangeException.cs new file mode 100644 index 00000000..fef917a8 --- /dev/null +++ b/LibGit2Sharp/GitIndexOutOfRangeException.cs @@ -0,0 +1,66 @@ +using System; +using System.Runtime.Serialization; +using LibGit2Sharp.Core; + +namespace LibGit2Sharp +{ + /// + /// The exception that is thrown when There are no more entries left to iterate. + /// + [Serializable] + public class GitIndexOutOfRangeException : NativeException + { + /// + /// Initializes a new instance of the class. + /// + public GitIndexOutOfRangeException() + { } + + /// + /// Initializes a new instance of the class with a specified error message. + /// + /// A message that describes the error. + public GitIndexOutOfRangeException(string message) + : base(message) + { } + + /// + /// Initializes a new instance of the class with a specified error message. + /// + /// A composite format string for use in . + /// An object array that contains zero or more objects to format. + public GitIndexOutOfRangeException(string format, params object[] args) + : base(format, args) + { } + + /// + /// Initializes a new instance of the class with a specified error message and a reference to the inner exception that is the cause of this exception. + /// + /// The error message that explains the reason for the exception. + /// The exception that is the cause of the current exception. If the parameter is not a null reference, the current exception is raised in a catch block that handles the inner exception. + public GitIndexOutOfRangeException(string message, Exception innerException) + : base(message, innerException) + { } + + /// + /// Initializes a new instance of the class with a serialized data. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + protected GitIndexOutOfRangeException(SerializationInfo info, StreamingContext context) + : base(info, context) + { } + + internal GitIndexOutOfRangeException(string message, GitErrorCategory category) + : base(message, category) + { } + + internal override GitErrorCode ErrorCode + { + get + { + return GitErrorCode.IterOver; + } + } + } +} diff --git a/LibGit2Sharp/InitOptions.cs b/LibGit2Sharp/InitOptions.cs new file mode 100644 index 00000000..6b3f3486 --- /dev/null +++ b/LibGit2Sharp/InitOptions.cs @@ -0,0 +1,41 @@ +namespace LibGit2Sharp +{ + /// + /// Options controlling Repository Init behavior. + /// + public sealed class InitOptions + { + /// + /// Initializes a new instance of the class. + /// + /// Default behavior: + /// The workdirPath is null. + /// Not a bare repository. + /// Default initial head. + /// + /// + public InitOptions() + { + WorkdirPath = null; + IsBare = false; + InitialHead = null; + } + + /// + /// The path to the working directory. Null if it's the same directory where ".git" repository is created. + /// + public string WorkdirPath { get; set; } + + /// + /// True to initialize a bare repository. False otherwise, to initialize a standard ".git" repository. + /// + public bool IsBare { get; set; } + + /// + /// The name of the head to point HEAD at. + /// If null, then this will be treated as "master" and the HEAD ref will be set to "refs/heads/master". + /// If this begins with "refs/" it will be used verbatim; otherwise "refs/heads/" will be prefixed. + /// + public string InitialHead { get; set; } + } +} diff --git a/LibGit2Sharp/LibGit2Sharp.csproj b/LibGit2Sharp/LibGit2Sharp.csproj index 03025744..7c55b8f6 100644 --- a/LibGit2Sharp/LibGit2Sharp.csproj +++ b/LibGit2Sharp/LibGit2Sharp.csproj @@ -16,7 +16,10 @@ ..\libgit2sharp.snk square-logo.png App_Readme/LICENSE.md - true + + + + Mendix.LibGit2Sharp @@ -30,7 +33,7 @@ - + @@ -38,10 +41,4 @@ - - - https://github.com/libgit2/libgit2sharp/blob/$(GitCommitIdShort)/CHANGES.md#libgit2sharp-changes - - - diff --git a/LibGit2Sharp/LibGit2SharpException.cs b/LibGit2Sharp/LibGit2SharpException.cs index 5d1c33f2..3e5599eb 100644 --- a/LibGit2Sharp/LibGit2SharpException.cs +++ b/LibGit2Sharp/LibGit2SharpException.cs @@ -52,5 +52,24 @@ public LibGit2SharpException(string format, params object[] args) protected LibGit2SharpException(SerializationInfo info, StreamingContext context) : base(info, context) { } + + internal LibGit2SharpException(string message, GitErrorCode code, GitErrorCategory category) : this(message) + { + Data.Add("libgit2.code", (int)code); + Data.Add("libgit2.category", (int)category); + + Code = code; + Category = category; + } + + /// + /// The underlying GitErrorCode returned by LibGit2 + /// + public GitErrorCode Code { get; private set; } + + /// + /// The underlying Error Category returned by LibGit2 + /// + public GitErrorCategory Category { get; private set; } } } diff --git a/LibGit2Sharp/MergeConflictException.cs b/LibGit2Sharp/MergeConflictException.cs new file mode 100644 index 00000000..b07fb604 --- /dev/null +++ b/LibGit2Sharp/MergeConflictException.cs @@ -0,0 +1,66 @@ +using System; +using System.Runtime.Serialization; +using LibGit2Sharp.Core; + +namespace LibGit2Sharp +{ + /// + /// The exception that is thrown when A merge conflict exists and cannot continue + /// + [Serializable] + public class MergeConflictException : NativeException + { + /// + /// Initializes a new instance of the class. + /// + public MergeConflictException() + { } + + /// + /// Initializes a new instance of the class with a specified error message. + /// + /// A message that describes the error. + public MergeConflictException(string message) + : base(message) + { } + + /// + /// Initializes a new instance of the class with a specified error message. + /// + /// A composite format string for use in . + /// An object array that contains zero or more objects to format. + public MergeConflictException(string format, params object[] args) + : base(format, args) + { } + + /// + /// Initializes a new instance of the class with a specified error message and a reference to the inner exception that is the cause of this exception. + /// + /// The error message that explains the reason for the exception. + /// The exception that is the cause of the current exception. If the parameter is not a null reference, the current exception is raised in a catch block that handles the inner exception. + public MergeConflictException(string message, Exception innerException) + : base(message, innerException) + { } + + /// + /// Initializes a new instance of the class with a serialized data. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + protected MergeConflictException(SerializationInfo info, StreamingContext context) + : base(info, context) + { } + + internal MergeConflictException(string message, GitErrorCategory category) + : base(message, category) + { } + + internal override GitErrorCode ErrorCode + { + get + { + return GitErrorCode.MergeConflict; + } + } + } +} diff --git a/LibGit2Sharp/Network.cs b/LibGit2Sharp/Network.cs index d5f03205..32353d1b 100644 --- a/LibGit2Sharp/Network.cs +++ b/LibGit2Sharp/Network.cs @@ -52,7 +52,7 @@ public virtual IEnumerable ListReferences(Remote remote) { Ensure.ArgumentNotNull(remote, "remote"); - return ListReferencesInternal(remote.Url, null); + return ListReferencesInternal(remote.Url, null, null, null); } /// @@ -66,13 +66,19 @@ public virtual IEnumerable ListReferences(Remote remote) /// /// The to list from. /// The used to connect to remote repository. + /// The used to resolve SSL certificate errors. + /// controlling proxy settings /// The references in the repository. - public virtual IEnumerable ListReferences(Remote remote, CredentialsHandler credentialsProvider) + public virtual IEnumerable ListReferences( + Remote remote, + CredentialsHandler credentialsProvider, + CertificateCheckHandler certificateCheckHandler, + ProxyOptions proxyOptions) { Ensure.ArgumentNotNull(remote, "remote"); Ensure.ArgumentNotNull(credentialsProvider, "credentialsProvider"); - return ListReferencesInternal(remote.Url, credentialsProvider); + return ListReferencesInternal(remote.Url, credentialsProvider, certificateCheckHandler, proxyOptions); } /// @@ -90,7 +96,7 @@ public virtual IEnumerable ListReferences(string url) { Ensure.ArgumentNotNull(url, "url"); - return ListReferencesInternal(url, null); + return ListReferencesInternal(url, null, null, null); } /// @@ -104,29 +110,40 @@ public virtual IEnumerable ListReferences(string url) /// /// The url to list from. /// The used to connect to remote repository. + /// The used to resolve SSL certificate errors. + /// controlling proxy settings /// The references in the remote repository. - public virtual IEnumerable ListReferences(string url, CredentialsHandler credentialsProvider) + public virtual IEnumerable ListReferences( + string url, + CredentialsHandler credentialsProvider, + CertificateCheckHandler certificateCheckHandler, + ProxyOptions proxyOptions) { Ensure.ArgumentNotNull(url, "url"); Ensure.ArgumentNotNull(credentialsProvider, "credentialsProvider"); - return ListReferencesInternal(url, credentialsProvider); + return ListReferencesInternal(url, credentialsProvider, certificateCheckHandler, proxyOptions); } - private IEnumerable ListReferencesInternal(string url, CredentialsHandler credentialsProvider) + private IEnumerable ListReferencesInternal( + string url, + CredentialsHandler credentialsProvider, + CertificateCheckHandler certificateCheckHandler, + ProxyOptions proxyOptions) { using (RemoteHandle remoteHandle = BuildRemoteHandle(repository.Handle, url)) + using (GitProxyOptionsWrapper proxyOptionsWrapper = new GitProxyOptionsWrapper(proxyOptions)) { GitRemoteCallbacks gitCallbacks = new GitRemoteCallbacks { version = 1 }; - GitProxyOptions proxyOptions = new GitProxyOptions { Version = 1 }; + GitProxyOptions gitProxyOptions = proxyOptionsWrapper.GitProxyOptions; if (credentialsProvider != null) { - var callbacks = new RemoteCallbacks(credentialsProvider); + var callbacks = new RemoteCallbacks(credentialsProvider, certificateCheckHandler); gitCallbacks = callbacks.GenerateCallbacks(); } - Proxy.git_remote_connect(remoteHandle, GitDirection.Fetch, ref gitCallbacks, ref proxyOptions); + Proxy.git_remote_connect(remoteHandle, GitDirection.Fetch, ref gitCallbacks, ref gitProxyOptions); return Proxy.git_remote_ls(repository, remoteHandle); } } @@ -149,7 +166,7 @@ static RemoteHandle BuildRemoteHandle(RepositoryHandle repoHandle, string url) /// The list of resfpecs to use public virtual void Fetch(string url, IEnumerable refspecs) { - Fetch(url, refspecs, null, null); + Fetch(url, refspecs, null, null, null); } /// @@ -158,9 +175,10 @@ public virtual void Fetch(string url, IEnumerable refspecs) /// The url to fetch from /// The list of resfpecs to use /// controlling fetch behavior - public virtual void Fetch(string url, IEnumerable refspecs, FetchOptions options) + /// controlling proxy settings + public virtual void Fetch(string url, IEnumerable refspecs, FetchOptions options, ProxyOptions proxy) { - Fetch(url, refspecs, options, null); + Fetch(url, refspecs, options, null, proxy); } /// @@ -171,7 +189,7 @@ public virtual void Fetch(string url, IEnumerable refspecs, FetchOptions /// Message to use when updating the reflog. public virtual void Fetch(string url, IEnumerable refspecs, string logMessage) { - Fetch(url, refspecs, null, logMessage); + Fetch(url, refspecs, null, logMessage, null); } /// @@ -181,16 +199,18 @@ public virtual void Fetch(string url, IEnumerable refspecs, string logMe /// The list of resfpecs to use /// controlling fetch behavior /// Message to use when updating the reflog. + /// controlling proxy settings public virtual void Fetch( string url, IEnumerable refspecs, FetchOptions options, - string logMessage) + string logMessage, + ProxyOptions proxy) { Ensure.ArgumentNotNull(url, "url"); Ensure.ArgumentNotNull(refspecs, "refspecs"); - Commands.Fetch(repository, url, refspecs, options, logMessage); + Commands.Fetch(repository, url, refspecs, options, logMessage, proxy); } /// @@ -208,12 +228,14 @@ public virtual void Push( /// /// The branch to push. /// controlling push behavior + /// controlling proxy settings /// Throws if either the Remote or the UpstreamBranchCanonicalName is not set. public virtual void Push( Branch branch, - PushOptions pushOptions) + PushOptions pushOptions, + ProxyOptions proxyOptions) { - Push(new[] { branch }, pushOptions); + Push(new[] { branch }, pushOptions, proxyOptions); } /// @@ -224,7 +246,7 @@ public virtual void Push( public virtual void Push( IEnumerable branches) { - Push(branches, null); + Push(branches, null, null); } /// @@ -232,10 +254,12 @@ public virtual void Push( /// /// The branches to push. /// controlling push behavior + /// controlling proxy settings /// Throws if either the Remote or the UpstreamBranchCanonicalName is not set. public virtual void Push( IEnumerable branches, - PushOptions pushOptions) + PushOptions pushOptions, + ProxyOptions proxyOptions) { var enumeratedBranches = branches as IList ?? branches.ToList(); @@ -254,7 +278,7 @@ public virtual void Push( { Push(remote, string.Format( CultureInfo.InvariantCulture, - "{0}:{1}", branch.CanonicalName, branch.UpstreamBranchCanonicalName), pushOptions); + "{0}:{1}", branch.CanonicalName, branch.UpstreamBranchCanonicalName), pushOptions, proxyOptions); } } } @@ -287,11 +311,13 @@ public virtual void Push( /// The source objectish to push. /// The reference to update on the remote. /// controlling push behavior + /// controlling proxy settings public virtual void Push( Remote remote, string objectish, string destinationSpec, - PushOptions pushOptions) + PushOptions pushOptions, + ProxyOptions proxyOptions) { Ensure.ArgumentNotNull(objectish, "objectish"); Ensure.ArgumentNotNullOrEmptyString(destinationSpec, "destinationSpec"); @@ -301,7 +327,8 @@ public virtual void Push( "{0}:{1}", objectish, destinationSpec), - pushOptions); + pushOptions, + proxyOptions); } /// @@ -321,14 +348,16 @@ public virtual void Push(Remote remote, string pushRefSpec) /// The to push to. /// The pushRefSpec to push. /// controlling push behavior + /// controlling proxy settings public virtual void Push( Remote remote, string pushRefSpec, - PushOptions pushOptions) + PushOptions pushOptions, + ProxyOptions proxyOptions) { Ensure.ArgumentNotNullOrEmptyString(pushRefSpec, "pushRefSpec"); - Push(remote, new[] { pushRefSpec }, pushOptions); + Push(remote, new[] { pushRefSpec }, pushOptions, proxyOptions); } /// @@ -338,7 +367,7 @@ public virtual void Push( /// The pushRefSpecs to push. public virtual void Push(Remote remote, IEnumerable pushRefSpecs) { - Push(remote, pushRefSpecs, null); + Push(remote, pushRefSpecs, null, null); } /// @@ -347,7 +376,8 @@ public virtual void Push(Remote remote, IEnumerable pushRefSpecs) /// The to push to. /// The pushRefSpecs to push. /// controlling push behavior - public virtual void Push(Remote remote, IEnumerable pushRefSpecs, PushOptions pushOptions) + /// controlling proxy settings + public virtual void Push(Remote remote, IEnumerable pushRefSpecs, PushOptions pushOptions, ProxyOptions proxyOptions) { Ensure.ArgumentNotNull(remote, "remote"); Ensure.ArgumentNotNull(pushRefSpecs, "pushRefSpecs"); @@ -365,18 +395,24 @@ public virtual void Push(Remote remote, IEnumerable pushRefSpecs, PushOp // Load the remote. using (RemoteHandle remoteHandle = Proxy.git_remote_lookup(repository.Handle, remote.Name, true)) + using (GitProxyOptionsWrapper proxyOptionsWrapper = new GitProxyOptionsWrapper(proxyOptions)) { var callbacks = new RemoteCallbacks(pushOptions); GitRemoteCallbacks gitCallbacks = callbacks.GenerateCallbacks(); + GitPushOptions gitPushOptions = new GitPushOptions() + { + PackbuilderDegreeOfParallelism = pushOptions.PackbuilderDegreeOfParallelism, + RemoteCallbacks = gitCallbacks, + ProxyOptions = proxyOptionsWrapper.GitProxyOptions + }; + + if (pushOptions.CustomHeaders != null && pushOptions.CustomHeaders.Length > 0) + gitPushOptions.CustomHeaders = GitStrArrayManaged.BuildFrom(pushOptions.CustomHeaders); + Proxy.git_remote_push(remoteHandle, - pushRefSpecs, - new GitPushOptions() - { - PackbuilderDegreeOfParallelism = pushOptions.PackbuilderDegreeOfParallelism, - RemoteCallbacks = gitCallbacks, - ProxyOptions = new GitProxyOptions { Version = 1 }, - }); + pushRefSpecs, + gitPushOptions); } } diff --git a/LibGit2Sharp/ObjectHasUnexpectedIdException.cs b/LibGit2Sharp/ObjectHasUnexpectedIdException.cs new file mode 100644 index 00000000..f3479876 --- /dev/null +++ b/LibGit2Sharp/ObjectHasUnexpectedIdException.cs @@ -0,0 +1,66 @@ +using System; +using System.Runtime.Serialization; +using LibGit2Sharp.Core; + +namespace LibGit2Sharp +{ + /// + /// The exception that is thrown when A retrieved object did not match its expected ID. + /// + [Serializable] + public class ObjectHasUnexpectedIdException : NativeException + { + /// + /// Initializes a new instance of the class. + /// + public ObjectHasUnexpectedIdException() + { } + + /// + /// Initializes a new instance of the class with a specified error message. + /// + /// A message that describes the error. + public ObjectHasUnexpectedIdException(string message) + : base(message) + { } + + /// + /// Initializes a new instance of the class with a specified error message. + /// + /// A composite format string for use in . + /// An object array that contains zero or more objects to format. + public ObjectHasUnexpectedIdException(string format, params object[] args) + : base(format, args) + { } + + /// + /// Initializes a new instance of the class with a specified error message and a reference to the inner exception that is the cause of this exception. + /// + /// The error message that explains the reason for the exception. + /// The exception that is the cause of the current exception. If the parameter is not a null reference, the current exception is raised in a catch block that handles the inner exception. + public ObjectHasUnexpectedIdException(string message, Exception innerException) + : base(message, innerException) + { } + + /// + /// Initializes a new instance of the class with a serialized data. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + protected ObjectHasUnexpectedIdException(SerializationInfo info, StreamingContext context) + : base(info, context) + { } + + internal ObjectHasUnexpectedIdException(string message, GitErrorCategory category) + : base(message, category) + { } + + internal override GitErrorCode ErrorCode + { + get + { + return GitErrorCode.Mismatch; + } + } + } +} diff --git a/LibGit2Sharp/OrphanedHeadException.cs b/LibGit2Sharp/OrphanedHeadException.cs new file mode 100644 index 00000000..432a9c98 --- /dev/null +++ b/LibGit2Sharp/OrphanedHeadException.cs @@ -0,0 +1,66 @@ +using System; +using System.Runtime.Serialization; +using LibGit2Sharp.Core; + +namespace LibGit2Sharp +{ + /// + /// The exception that is thrown when Operation cannot be performed against an orphaned HEAD. + /// + [Serializable] + public class OrphanedHeadException : NativeException + { + /// + /// Initializes a new instance of the class. + /// + public OrphanedHeadException() + { } + + /// + /// Initializes a new instance of the class with a specified error message. + /// + /// A message that describes the error. + public OrphanedHeadException(string message) + : base(message) + { } + + /// + /// Initializes a new instance of the class with a specified error message. + /// + /// A composite format string for use in . + /// An object array that contains zero or more objects to format. + public OrphanedHeadException(string format, params object[] args) + : base(format, args) + { } + + /// + /// Initializes a new instance of the class with a specified error message and a reference to the inner exception that is the cause of this exception. + /// + /// The error message that explains the reason for the exception. + /// The exception that is the cause of the current exception. If the parameter is not a null reference, the current exception is raised in a catch block that handles the inner exception. + public OrphanedHeadException(string message, Exception innerException) + : base(message, innerException) + { } + + /// + /// Initializes a new instance of the class with a serialized data. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + protected OrphanedHeadException(SerializationInfo info, StreamingContext context) + : base(info, context) + { } + + internal OrphanedHeadException(string message, GitErrorCategory category) + : base(message, category) + { } + + internal override GitErrorCode ErrorCode + { + get + { + return GitErrorCode.OrphanedHead; + } + } + } +} diff --git a/LibGit2Sharp/PassThroughException.cs b/LibGit2Sharp/PassThroughException.cs new file mode 100644 index 00000000..a54c2624 --- /dev/null +++ b/LibGit2Sharp/PassThroughException.cs @@ -0,0 +1,66 @@ +using System; +using System.Runtime.Serialization; +using LibGit2Sharp.Core; + +namespace LibGit2Sharp +{ + /// + /// The exception that is thrown when to Skip and passthrough the given ODB backend. + /// + [Serializable] + public class PassThroughException : NativeException + { + /// + /// Initializes a new instance of the class. + /// + public PassThroughException() + { } + + /// + /// Initializes a new instance of the class with a specified error message. + /// + /// A message that describes the error. + public PassThroughException(string message) + : base(message) + { } + + /// + /// Initializes a new instance of the class with a specified error message. + /// + /// A composite format string for use in . + /// An object array that contains zero or more objects to format. + public PassThroughException(string format, params object[] args) + : base(format, args) + { } + + /// + /// Initializes a new instance of the class with a specified error message and a reference to the inner exception that is the cause of this exception. + /// + /// The error message that explains the reason for the exception. + /// The exception that is the cause of the current exception. If the parameter is not a null reference, the current exception is raised in a catch block that handles the inner exception. + public PassThroughException(string message, Exception innerException) + : base(message, innerException) + { } + + /// + /// Initializes a new instance of the class with a serialized data. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + protected PassThroughException(SerializationInfo info, StreamingContext context) + : base(info, context) + { } + + internal PassThroughException(string message, GitErrorCategory category) + : base(message, category) + { } + + internal override GitErrorCode ErrorCode + { + get + { + return GitErrorCode.PassThrough; + } + } + } +} diff --git a/LibGit2Sharp/PatchOrMergeAlreadyAppliedException.cs b/LibGit2Sharp/PatchOrMergeAlreadyAppliedException.cs new file mode 100644 index 00000000..ec2e64e0 --- /dev/null +++ b/LibGit2Sharp/PatchOrMergeAlreadyAppliedException.cs @@ -0,0 +1,66 @@ +using System; +using System.Runtime.Serialization; +using LibGit2Sharp.Core; + +namespace LibGit2Sharp +{ + /// + /// The exception that is thrown when Patch/merge has already been applied. + /// + [Serializable] + public class PatchOrMergeAlreadyAppliedException : NativeException + { + /// + /// Initializes a new instance of the class. + /// + public PatchOrMergeAlreadyAppliedException() + { } + + /// + /// Initializes a new instance of the class with a specified error message. + /// + /// A message that describes the error. + public PatchOrMergeAlreadyAppliedException(string message) + : base(message) + { } + + /// + /// Initializes a new instance of the class with a specified error message. + /// + /// A composite format string for use in . + /// An object array that contains zero or more objects to format. + public PatchOrMergeAlreadyAppliedException(string format, params object[] args) + : base(format, args) + { } + + /// + /// Initializes a new instance of the class with a specified error message and a reference to the inner exception that is the cause of this exception. + /// + /// The error message that explains the reason for the exception. + /// The exception that is the cause of the current exception. If the parameter is not a null reference, the current exception is raised in a catch block that handles the inner exception. + public PatchOrMergeAlreadyAppliedException(string message, Exception innerException) + : base(message, innerException) + { } + + /// + /// Initializes a new instance of the class with a serialized data. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + protected PatchOrMergeAlreadyAppliedException(SerializationInfo info, StreamingContext context) + : base(info, context) + { } + + internal PatchOrMergeAlreadyAppliedException(string message, GitErrorCategory category) + : base(message, category) + { } + + internal override GitErrorCode ErrorCode + { + get + { + return GitErrorCode.Applied; + } + } + } +} diff --git a/LibGit2Sharp/ProxyOptions.cs b/LibGit2Sharp/ProxyOptions.cs new file mode 100644 index 00000000..b37e8b24 --- /dev/null +++ b/LibGit2Sharp/ProxyOptions.cs @@ -0,0 +1,26 @@ +using LibGit2Sharp.Handlers; + +namespace LibGit2Sharp +{ + /// + /// Options for connecting through a proxy. + /// + public sealed class ProxyOptions + { + /// + /// The URL of the proxy. + /// + public string Url { get; set; } + + /// + /// This will be called if the remote host requires authentication in order to connect to it. + /// + public CredentialsHandler CredentialsProvider { get; set; } + + /// + /// If cert verification fails, this will be called to let the user make the final decision + /// of whether to allow the connection to proceed. + /// + public CertificateCheckHandler CertificateCheck { get; set; } + } +} diff --git a/LibGit2Sharp/PushOptions.cs b/LibGit2Sharp/PushOptions.cs index 99c65dd8..b39a23f3 100644 --- a/LibGit2Sharp/PushOptions.cs +++ b/LibGit2Sharp/PushOptions.cs @@ -51,5 +51,26 @@ public sealed class PushOptions /// information about what updates will be performed. /// public PrePushHandler OnNegotiationCompletedBeforePush { get; set; } + + /// + /// Get/Set the custom headers. + /// + /// + /// 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, + /// Accept, Content-Type, Transfer-Encoding, Content-Length, Accept) that + /// cannot be overriden. + /// + /// + /// var pushOptions - new PushOptions() { + /// CustomHeaders = new String[] {"X-Request-Id: 12345"} + /// }; + /// + /// The custom headers string array + public string[] CustomHeaders { get; set; } } } diff --git a/LibGit2Sharp/ReferenceValueDoesNotMatchException.cs b/LibGit2Sharp/ReferenceValueDoesNotMatchException.cs new file mode 100644 index 00000000..8d9ab3f2 --- /dev/null +++ b/LibGit2Sharp/ReferenceValueDoesNotMatchException.cs @@ -0,0 +1,66 @@ +using System; +using System.Runtime.Serialization; +using LibGit2Sharp.Core; + +namespace LibGit2Sharp +{ + /// + /// The exception that is thrown when Reference value does not match expected. + /// + [Serializable] + public class ReferenceValueDoesNotMatchException : NativeException + { + /// + /// Initializes a new instance of the class. + /// + public ReferenceValueDoesNotMatchException() + { } + + /// + /// Initializes a new instance of the class with a specified error message. + /// + /// A message that describes the error. + public ReferenceValueDoesNotMatchException(string message) + : base(message) + { } + + /// + /// Initializes a new instance of the class with a specified error message. + /// + /// A composite format string for use in . + /// An object array that contains zero or more objects to format. + public ReferenceValueDoesNotMatchException(string format, params object[] args) + : base(format, args) + { } + + /// + /// Initializes a new instance of the class with a specified error message and a reference to the inner exception that is the cause of this exception. + /// + /// The error message that explains the reason for the exception. + /// The exception that is the cause of the current exception. If the parameter is not a null reference, the current exception is raised in a catch block that handles the inner exception. + public ReferenceValueDoesNotMatchException(string message, Exception innerException) + : base(message, innerException) + { } + + /// + /// Initializes a new instance of the class with a serialized data. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + protected ReferenceValueDoesNotMatchException(SerializationInfo info, StreamingContext context) + : base(info, context) + { } + + internal ReferenceValueDoesNotMatchException(string message, GitErrorCategory category) + : base(message, category) + { } + + internal override GitErrorCode ErrorCode + { + get + { + return GitErrorCode.Modified; + } + } + } +} diff --git a/LibGit2Sharp/RemoteCallbacks.cs b/LibGit2Sharp/RemoteCallbacks.cs index ce5dccf8..39535022 100644 --- a/LibGit2Sharp/RemoteCallbacks.cs +++ b/LibGit2Sharp/RemoteCallbacks.cs @@ -12,9 +12,10 @@ namespace LibGit2Sharp /// internal class RemoteCallbacks { - internal RemoteCallbacks(CredentialsHandler credentialsProvider) + internal RemoteCallbacks(CredentialsHandler credentialsProvider, CertificateCheckHandler certificateCheck) { CredentialsProvider = credentialsProvider; + CertificateCheck = certificateCheck; } internal RemoteCallbacks(PushOptions pushOptions) diff --git a/LibGit2Sharp/RemoteRedirectMode.cs b/LibGit2Sharp/RemoteRedirectMode.cs index 08866e68..c146933f 100644 --- a/LibGit2Sharp/RemoteRedirectMode.cs +++ b/LibGit2Sharp/RemoteRedirectMode.cs @@ -12,17 +12,17 @@ public enum RemoteRedirectMode /// Do not follow any off-site redirects at any stage of /// the fetch or push. /// - None = 0, // GIT_REMOTE_REDIRECT_NONE + None = (1 << 0), // GIT_REMOTE_REDIRECT_NONE /// /// Allow off-site redirects only upon the initial /// request. This is the default. /// - Auto, // GIT_REMOTE_REDIRECT_INITIAL + Auto = (1 << 1), // GIT_REMOTE_REDIRECT_INITIAL /// /// Allow redirects at any stage in the fetch or push. /// - All // GIT_REMOTE_REDIRECT_ALL + All = (1 << 2), // GIT_REMOTE_REDIRECT_ALL } } diff --git a/LibGit2Sharp/Repository.cs b/LibGit2Sharp/Repository.cs index 41aaecfb..0b178daf 100644 --- a/LibGit2Sharp/Repository.cs +++ b/LibGit2Sharp/Repository.cs @@ -495,11 +495,9 @@ public static string Init(string path, bool isBare) { Ensure.ArgumentNotNullOrEmptyString(path, "path"); - using (RepositoryHandle repo = Proxy.git_repository_init_ext(null, path, isBare)) - { - FilePath repoPath = Proxy.git_repository_path(repo); - return repoPath.Native; - } + var initOptions = new InitOptions { IsBare = isBare }; + + return Init(path, initOptions); } /// @@ -518,9 +516,28 @@ public static string Init(string workingDirectoryPath, string gitDirectoryPath) // to pass a path relatively to his current directory. string wd = Path.GetFullPath(workingDirectoryPath); + var initOptions = new InitOptions { WorkdirPath = wd }; + // TODO: Shouldn't we ensure that the working folder isn't under the gitDir? - using (RepositoryHandle repo = Proxy.git_repository_init_ext(wd, gitDirectoryPath, false)) + return Init(gitDirectoryPath, initOptions); + } + + /// + /// Initialize a repository at the specified , + /// providing optional behavioral overrides through the parameter. + /// + /// The path to the working folder when initializing a standard ".git" repository. Otherwise, when initializing a bare repository, the path to the expected location of this later. + /// Options controlling init behavior. + /// The path to the created repository. + public static string Init(string path, InitOptions options) + { + Ensure.ArgumentNotNullOrEmptyString(path, "path"); + + options = options ?? new InitOptions(); + + using (var opts = GitRepositoryInitOptions.BuildFrom(options)) + using (RepositoryHandle repo = Proxy.git_repository_init_ext(path, opts)) { FilePath repoPath = Proxy.git_repository_path(repo); return repoPath.Native; @@ -656,7 +673,7 @@ 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, null, null); } /// @@ -669,28 +686,71 @@ public static IEnumerable ListRemoteReferences(string url) /// /// The url to list from. /// The used to connect to remote repository. + /// The used to resolve SSL certificate errors. + /// controlling proxy settings. /// The references in the remote repository. - public static IEnumerable ListRemoteReferences(string url, CredentialsHandler credentialsProvider) + public static IEnumerable ListRemoteReferences( + string url, + CredentialsHandler credentialsProvider, + CertificateCheckHandler certificateCheckHandler, + ProxyOptions proxyOptions) { Ensure.ArgumentNotNull(url, "url"); using (RepositoryHandle repositoryHandle = Proxy.git_repository_new()) - using (RemoteHandle remoteHandle = Proxy.git_remote_create_anonymous(repositoryHandle, url)) + using (GitProxyOptionsWrapper proxyOptionsWrapper = new GitProxyOptionsWrapper(proxyOptions)) + using (RemoteHandle remoteHandle = ConnectToAnonymousRemote(repositoryHandle, url, credentialsProvider, certificateCheckHandler, proxyOptionsWrapper.GitProxyOptions)) { - var gitCallbacks = new GitRemoteCallbacks { version = 1 }; - var proxyOptions = new GitProxyOptions { Version = 1 }; + return Proxy.git_remote_ls(null, remoteHandle); + } + } - if (credentialsProvider != null) - { - var callbacks = new RemoteCallbacks(credentialsProvider); - gitCallbacks = callbacks.GenerateCallbacks(); - } + /// + /// Retrieves the name of the Remote Repository's default branch. + /// + /// The url to retrieve from. + /// The used to connect to remote repository. + /// The used to resolve SSL certificate errors. + /// controlling proxy settings. + /// The reference name. + public static string GetRemoteDefaultBranch( + string url, + CredentialsHandler credentialsProvider, + CertificateCheckHandler certificateCheckHandler, + ProxyOptions proxyOptions) + { + Ensure.ArgumentNotNull(url, "url"); - Proxy.git_remote_connect(remoteHandle, GitDirection.Fetch, ref gitCallbacks, ref proxyOptions); - return Proxy.git_remote_ls(null, remoteHandle); + using (RepositoryHandle repositoryHandle = Proxy.git_repository_new()) + using (GitProxyOptionsWrapper proxyOptionsWrapper = new GitProxyOptionsWrapper(proxyOptions)) + using (RemoteHandle remoteHandle = ConnectToAnonymousRemote(repositoryHandle, url, credentialsProvider, certificateCheckHandler, proxyOptionsWrapper.GitProxyOptions)) + { + return Proxy.git_remote_default_branch(remoteHandle); } } + private static RemoteHandle ConnectToAnonymousRemote( + RepositoryHandle repositoryHandle, + string url, + CredentialsHandler credentialsProvider, + CertificateCheckHandler certificateCheckHandler, + GitProxyOptions proxyOptions) + { + RemoteHandle remoteHandle = Proxy.git_remote_create_anonymous(repositoryHandle, url); + + var gitCallbacks = new GitRemoteCallbacks { version = 1 }; + + if (credentialsProvider != null) + { + var callbacks = new RemoteCallbacks(credentialsProvider, certificateCheckHandler); + gitCallbacks = callbacks.GenerateCallbacks(); + } + + Proxy.git_remote_connect(remoteHandle, GitDirection.Fetch, ref gitCallbacks, ref proxyOptions); + + return remoteHandle; + } + /// /// Probe for a git repository. /// The lookup start from and walk upward parent directories if nothing has been found. @@ -724,7 +784,7 @@ public static string Discover(string startingPath) /// The path to the created repository. public static string Clone(string sourceUrl, string workdirPath) { - return Clone(sourceUrl, workdirPath, null); + return Clone(sourceUrl, workdirPath, null, null); } /// @@ -740,9 +800,9 @@ public static string Clone(string sourceUrl, string workdirPath) /// URI for the remote repository /// Local path to clone into /// controlling clone behavior + /// controlling proxy options /// The path to the created repository. - public static string Clone(string sourceUrl, string workdirPath, - CloneOptions options) + public static string Clone(string sourceUrl, string workdirPath, CloneOptions options, ProxyOptions proxy) { Ensure.ArgumentNotNull(sourceUrl, "sourceUrl"); Ensure.ArgumentNotNull(workdirPath, "workdirPath"); @@ -764,11 +824,12 @@ public static string Clone(string sourceUrl, string workdirPath, using (var checkoutOptionsWrapper = new GitCheckoutOptsWrapper(options)) using (var fetchOptionsWrapper = new GitFetchOptionsWrapper()) + using (var proxyOptionsWrapper = new GitProxyOptionsWrapper(proxy)) { var gitCheckoutOptions = checkoutOptionsWrapper.Options; var gitFetchOptions = fetchOptionsWrapper.Options; - gitFetchOptions.ProxyOptions = new GitProxyOptions { Version = 1 }; + gitFetchOptions.ProxyOptions = proxyOptionsWrapper.GitProxyOptions; gitFetchOptions.RemoteCallbacks = new RemoteCallbacks(options).GenerateCallbacks(); if (options.FetchOptions != null && options.FetchOptions.CustomHeaders != null) { @@ -807,7 +868,7 @@ public static string Clone(string sourceUrl, string workdirPath, // Recursively clone submodules if requested. try { - RecursivelyCloneSubmodules(options, clonedRepoPath, 1); + RecursivelyCloneSubmodules(options, clonedRepoPath, 1, proxy); } catch (Exception ex) { @@ -826,7 +887,8 @@ public static string Clone(string sourceUrl, string workdirPath, /// Options controlling clone behavior. /// Path of the parent repository. /// The current depth of the recursion. - private static void RecursivelyCloneSubmodules(CloneOptions options, string repoPath, int recursionDepth) + /// Options controlling proxy settings. + private static void RecursivelyCloneSubmodules(CloneOptions options, string repoPath, int recursionDepth, ProxyOptions proxy) { if (options.RecurseSubmodules) { @@ -870,7 +932,7 @@ private static void RecursivelyCloneSubmodules(CloneOptions options, string repo throw new UserCancelledException("Recursive clone of submodules was cancelled."); } - repo.Submodules.Update(sm.Name, updateOptions); + repo.Submodules.Update(sm.Name, updateOptions, proxy); OnRepositoryOperationCompleted(options.RepositoryOperationCompleted, context); @@ -884,7 +946,7 @@ private static void RecursivelyCloneSubmodules(CloneOptions options, string repo // Check submodules to see if they have their own submodules. foreach (string submodule in submodules) { - RecursivelyCloneSubmodules(options, submodule, recursionDepth + 1); + RecursivelyCloneSubmodules(options, submodule, recursionDepth + 1, proxy); } } } diff --git a/LibGit2Sharp/ServerCertificateInvalidException.cs b/LibGit2Sharp/ServerCertificateInvalidException.cs new file mode 100644 index 00000000..3f1cfa24 --- /dev/null +++ b/LibGit2Sharp/ServerCertificateInvalidException.cs @@ -0,0 +1,66 @@ +using System; +using System.Runtime.Serialization; +using LibGit2Sharp.Core; + +namespace LibGit2Sharp +{ + /// + /// The exception that is thrown when Server Certificate is invalid + /// + [Serializable] + public class ServerCertificateInvalidException : NativeException + { + /// + /// Initializes a new instance of the class. + /// + public ServerCertificateInvalidException() + { } + + /// + /// Initializes a new instance of the class with a specified error message. + /// + /// A message that describes the error. + public ServerCertificateInvalidException(string message) + : base(message) + { } + + /// + /// Initializes a new instance of the class with a specified error message. + /// + /// A composite format string for use in . + /// An object array that contains zero or more objects to format. + public ServerCertificateInvalidException(string format, params object[] args) + : base(format, args) + { } + + /// + /// Initializes a new instance of the class with a specified error message and a reference to the inner exception that is the cause of this exception. + /// + /// The error message that explains the reason for the exception. + /// The exception that is the cause of the current exception. If the parameter is not a null reference, the current exception is raised in a catch block that handles the inner exception. + public ServerCertificateInvalidException(string message, Exception innerException) + : base(message, innerException) + { } + + /// + /// Initializes a new instance of the class with a serialized data. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + protected ServerCertificateInvalidException(SerializationInfo info, StreamingContext context) + : base(info, context) + { } + + internal ServerCertificateInvalidException(string message, GitErrorCategory category) + : base(message, category) + { } + + internal override GitErrorCode ErrorCode + { + get + { + return GitErrorCode.Certificate; + } + } + } +} diff --git a/LibGit2Sharp/SubmoduleCollection.cs b/LibGit2Sharp/SubmoduleCollection.cs index fc508107..8fecf694 100644 --- a/LibGit2Sharp/SubmoduleCollection.cs +++ b/LibGit2Sharp/SubmoduleCollection.cs @@ -81,7 +81,8 @@ public virtual void Init(string name, bool overwrite) /// /// The name of the submodule to update. /// Options controlling submodule udpate behavior and callbacks. - public virtual void Update(string name, SubmoduleUpdateOptions options) + /// Options controlling proxy settings. + public virtual void Update(string name, SubmoduleUpdateOptions options, ProxyOptions proxy) { options = options ?? new SubmoduleUpdateOptions(); @@ -94,6 +95,7 @@ public virtual void Update(string name, SubmoduleUpdateOptions options) } using (GitCheckoutOptsWrapper checkoutOptionsWrapper = new GitCheckoutOptsWrapper(options)) + using (GitProxyOptionsWrapper proxyOptionsWrapper = new GitProxyOptionsWrapper(proxy)) { var gitCheckoutOptions = checkoutOptionsWrapper.Options; @@ -104,7 +106,11 @@ 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 = proxyOptionsWrapper.GitProxyOptions, + RemoteCallbacks = gitRemoteCallbacks + }, CloneCheckoutStrategy = CheckoutStrategy.GIT_CHECKOUT_SAFE }; diff --git a/LibGit2Sharp/UncommittedChangesException.cs b/LibGit2Sharp/UncommittedChangesException.cs new file mode 100644 index 00000000..2deb0d32 --- /dev/null +++ b/LibGit2Sharp/UncommittedChangesException.cs @@ -0,0 +1,66 @@ +using System; +using System.Runtime.Serialization; +using LibGit2Sharp.Core; + +namespace LibGit2Sharp +{ + /// + /// The exception that is thrown when Uncommitted changes in index prevented an operation. + /// + [Serializable] + public class UncommittedChangesException : NativeException + { + /// + /// Initializes a new instance of the class. + /// + public UncommittedChangesException() + { } + + /// + /// Initializes a new instance of the class with a specified error message. + /// + /// A message that describes the error. + public UncommittedChangesException(string message) + : base(message) + { } + + /// + /// Initializes a new instance of the class with a specified error message. + /// + /// A composite format string for use in . + /// An object array that contains zero or more objects to format. + public UncommittedChangesException(string format, params object[] args) + : base(format, args) + { } + + /// + /// Initializes a new instance of the class with a specified error message and a reference to the inner exception that is the cause of this exception. + /// + /// The error message that explains the reason for the exception. + /// The exception that is the cause of the current exception. If the parameter is not a null reference, the current exception is raised in a catch block that handles the inner exception. + public UncommittedChangesException(string message, Exception innerException) + : base(message, innerException) + { } + + /// + /// Initializes a new instance of the class with a serialized data. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + protected UncommittedChangesException(SerializationInfo info, StreamingContext context) + : base(info, context) + { } + + internal UncommittedChangesException(string message, GitErrorCategory category) + : base(message, category) + { } + + internal override GitErrorCode ErrorCode + { + get + { + return GitErrorCode.Uncommitted; + } + } + } +} diff --git a/version.json b/version.json index b0cb8c41..7cb57ec4 100644 --- a/version.json +++ b/version.json @@ -1,10 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/AArnott/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", - "version": "0.27.0-preview.{height}", - "publicReleaseRefSpec": [ - "^refs/heads/master$", // we release out of master - "^refs/heads/maint/v\\d+(?:\\.\\d+)?$" // and maint/vNN branches - ], + "version": "1.163.0", "cloudBuild": { "buildNumber": { "enabled": true