diff --git a/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj b/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj index 6a700f01c..a92d7ff41 100644 --- a/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj +++ b/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj @@ -124,6 +124,7 @@ + diff --git a/LibGit2Sharp.Tests/NetworkFixture.cs b/LibGit2Sharp.Tests/NetworkFixture.cs index f146a0678..d93273d1c 100644 --- a/LibGit2Sharp.Tests/NetworkFixture.cs +++ b/LibGit2Sharp.Tests/NetworkFixture.cs @@ -34,11 +34,11 @@ public void CanListRemoteReferences(string url) List> actualRefs = references. Select(directRef => new Tuple(directRef.CanonicalName, directRef.TargetIdentifier)).ToList(); - Assert.Equal(ExpectedRemoteRefs.Count, actualRefs.Count); - for (int i = 0; i < ExpectedRemoteRefs.Count; i++) + Assert.Equal(TestRemoteRefs.ExpectedRemoteRefs.Count, actualRefs.Count); + for (int i = 0; i < TestRemoteRefs.ExpectedRemoteRefs.Count; i++) { - Assert.Equal(ExpectedRemoteRefs[i].Item2, actualRefs[i].Item2); - Assert.Equal(ExpectedRemoteRefs[i].Item1, actualRefs[i].Item1); + Assert.Equal(TestRemoteRefs.ExpectedRemoteRefs[i].Item2, actualRefs[i].Item2); + Assert.Equal(TestRemoteRefs.ExpectedRemoteRefs[i].Item1, actualRefs[i].Item1); } } } @@ -65,11 +65,11 @@ public void CanListRemoteReferencesFromUrl(string url) List> actualRefs = references. Select(directRef => new Tuple(directRef.CanonicalName, directRef.TargetIdentifier)).ToList(); - Assert.Equal(ExpectedRemoteRefs.Count, actualRefs.Count); - for (int i = 0; i < ExpectedRemoteRefs.Count; i++) + Assert.Equal(TestRemoteRefs.ExpectedRemoteRefs.Count, actualRefs.Count); + for (int i = 0; i < TestRemoteRefs.ExpectedRemoteRefs.Count; i++) { - Assert.Equal(ExpectedRemoteRefs[i].Item2, actualRefs[i].Item2); - Assert.Equal(ExpectedRemoteRefs[i].Item1, actualRefs[i].Item1); + Assert.Equal(TestRemoteRefs.ExpectedRemoteRefs[i].Item2, actualRefs[i].Item2); + Assert.Equal(TestRemoteRefs.ExpectedRemoteRefs[i].Item1, actualRefs[i].Item1); } } } @@ -98,11 +98,11 @@ public void CanListRemoteReferenceObjects() actualRefs.Add(new Tuple(reference.CanonicalName, reference.Target.Id.Sha)); } - Assert.Equal(ExpectedRemoteRefs.Count, actualRefs.Count); - for (int i = 0; i < ExpectedRemoteRefs.Count; i++) + Assert.Equal(TestRemoteRefs.ExpectedRemoteRefs.Count, actualRefs.Count); + for (int i = 0; i < TestRemoteRefs.ExpectedRemoteRefs.Count; i++) { - Assert.Equal(ExpectedRemoteRefs[i].Item1, actualRefs[i].Item1); - Assert.Equal(ExpectedRemoteRefs[i].Item2, actualRefs[i].Item2); + Assert.Equal(TestRemoteRefs.ExpectedRemoteRefs[i].Item1, actualRefs[i].Item1); + Assert.Equal(TestRemoteRefs.ExpectedRemoteRefs[i].Item2, actualRefs[i].Item2); } } } @@ -254,33 +254,5 @@ public void CanMergeFetchedRefs() Assert.Equal(mergeResult.Status, MergeStatus.NonFastForward); } } - - /* - * git ls-remote http://github.com/libgit2/TestGitRepository - * 49322bb17d3acc9146f98c97d078513228bbf3c0 HEAD - * 0966a434eb1a025db6b71485ab63a3bfbea520b6 refs/heads/first-merge - * 49322bb17d3acc9146f98c97d078513228bbf3c0 refs/heads/master - * 42e4e7c5e507e113ebbb7801b16b52cf867b7ce1 refs/heads/no-parent - * d96c4e80345534eccee5ac7b07fc7603b56124cb refs/tags/annotated_tag - * c070ad8c08840c8116da865b2d65593a6bb9cd2a refs/tags/annotated_tag^{} - * 55a1a760df4b86a02094a904dfa511deb5655905 refs/tags/blob - * 8f50ba15d49353813cc6e20298002c0d17b0a9ee refs/tags/commit_tree - * 6e0c7bdb9b4ed93212491ee778ca1c65047cab4e refs/tags/nearly-dangling - */ - /// - /// Expected references on http://github.com/libgit2/TestGitRepository - /// - private static List> ExpectedRemoteRefs = new List>() - { - new Tuple("HEAD", "49322bb17d3acc9146f98c97d078513228bbf3c0"), - new Tuple("refs/heads/first-merge", "0966a434eb1a025db6b71485ab63a3bfbea520b6"), - new Tuple("refs/heads/master", "49322bb17d3acc9146f98c97d078513228bbf3c0"), - new Tuple("refs/heads/no-parent", "42e4e7c5e507e113ebbb7801b16b52cf867b7ce1"), - new Tuple("refs/tags/annotated_tag", "d96c4e80345534eccee5ac7b07fc7603b56124cb"), - new Tuple("refs/tags/annotated_tag^{}", "c070ad8c08840c8116da865b2d65593a6bb9cd2a"), - new Tuple("refs/tags/blob", "55a1a760df4b86a02094a904dfa511deb5655905"), - new Tuple("refs/tags/commit_tree", "8f50ba15d49353813cc6e20298002c0d17b0a9ee"), - new Tuple("refs/tags/nearly-dangling", "6e0c7bdb9b4ed93212491ee778ca1c65047cab4e"), - }; } } diff --git a/LibGit2Sharp.Tests/RepositoryFixture.cs b/LibGit2Sharp.Tests/RepositoryFixture.cs index 381973348..6f05029de 100644 --- a/LibGit2Sharp.Tests/RepositoryFixture.cs +++ b/LibGit2Sharp.Tests/RepositoryFixture.cs @@ -4,6 +4,7 @@ using System.Linq; using LibGit2Sharp.Tests.TestHelpers; using Xunit; +using Xunit.Extensions; namespace LibGit2Sharp.Tests { @@ -651,5 +652,64 @@ public void CanDetectShallowness() Assert.False(repo.Info.IsShallow); } } + + [SkippableFact] + public void CanListRemoteReferencesWithCredentials() + { + InconclusiveIf(() => string.IsNullOrEmpty(Constants.PrivateRepoUrl), + "Populate Constants.PrivateRepo* to run this test"); + + IEnumerable references = Repository.ListRemoteReferences(Constants.PrivateRepoUrl, + Constants.PrivateRepoCredentials); + + foreach (var reference in references) + { + Assert.NotNull(reference); + } + } + + [Theory] + [InlineData("http://github.com/libgit2/TestGitRepository")] + [InlineData("https://github.com/libgit2/TestGitRepository")] + [InlineData("git://github.com/libgit2/TestGitRepository.git")] + public void CanListRemoteReferences(string url) + { + IEnumerable references = Repository.ListRemoteReferences(url); + + List> actualRefs = references. + Select(directRef => new Tuple(directRef.CanonicalName, directRef.TargetIdentifier)).ToList(); + + Assert.Equal(TestRemoteRefs.ExpectedRemoteRefs.Count, actualRefs.Count); + for (int i = 0; i < TestRemoteRefs.ExpectedRemoteRefs.Count; i++) + { + Assert.Equal(TestRemoteRefs.ExpectedRemoteRefs[i].Item2, actualRefs[i].Item2); + Assert.Equal(TestRemoteRefs.ExpectedRemoteRefs[i].Item1, actualRefs[i].Item1); + } + } + + [Theory] + [InlineData("http://github.com/libgit2/TestGitRepository")] + public void ReadingReferenceRepositoryThroughListRemoteReferencesThrows(string url) + { + IEnumerable references = Repository.ListRemoteReferences(url); + + foreach (var reference in references) + { + IBelongToARepository repositoryReference = reference; + Assert.Throws(() => repositoryReference.Repository); + } + } + + [Theory] + [InlineData("http://github.com/libgit2/TestGitRepository")] + public void ReadingReferenceTargetFromListRemoteReferencesThrows(string url) + { + IEnumerable references = Repository.ListRemoteReferences(url); + + foreach (var reference in references) + { + Assert.Throws(() => reference.Target); + } + } } } diff --git a/LibGit2Sharp.Tests/TestHelpers/TestRemoteRefs.cs b/LibGit2Sharp.Tests/TestHelpers/TestRemoteRefs.cs new file mode 100644 index 000000000..aafdd5f34 --- /dev/null +++ b/LibGit2Sharp.Tests/TestHelpers/TestRemoteRefs.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace LibGit2Sharp.Tests.TestHelpers +{ + public class TestRemoteRefs + { + /* + * git ls-remote http://github.com/libgit2/TestGitRepository + * 49322bb17d3acc9146f98c97d078513228bbf3c0 HEAD + * 0966a434eb1a025db6b71485ab63a3bfbea520b6 refs/heads/first-merge + * 49322bb17d3acc9146f98c97d078513228bbf3c0 refs/heads/master + * 42e4e7c5e507e113ebbb7801b16b52cf867b7ce1 refs/heads/no-parent + * d96c4e80345534eccee5ac7b07fc7603b56124cb refs/tags/annotated_tag + * c070ad8c08840c8116da865b2d65593a6bb9cd2a refs/tags/annotated_tag^{} + * 55a1a760df4b86a02094a904dfa511deb5655905 refs/tags/blob + * 8f50ba15d49353813cc6e20298002c0d17b0a9ee refs/tags/commit_tree + * 6e0c7bdb9b4ed93212491ee778ca1c65047cab4e refs/tags/nearly-dangling + */ + /// + /// Expected references on http://github.com/libgit2/TestGitRepository + /// + public static List> ExpectedRemoteRefs = new List>() + { + new Tuple("HEAD", "49322bb17d3acc9146f98c97d078513228bbf3c0"), + new Tuple("refs/heads/first-merge", "0966a434eb1a025db6b71485ab63a3bfbea520b6"), + new Tuple("refs/heads/master", "49322bb17d3acc9146f98c97d078513228bbf3c0"), + new Tuple("refs/heads/no-parent", "42e4e7c5e507e113ebbb7801b16b52cf867b7ce1"), + new Tuple("refs/tags/annotated_tag", "d96c4e80345534eccee5ac7b07fc7603b56124cb"), + new Tuple("refs/tags/annotated_tag^{}", "c070ad8c08840c8116da865b2d65593a6bb9cd2a"), + new Tuple("refs/tags/blob", "55a1a760df4b86a02094a904dfa511deb5655905"), + new Tuple("refs/tags/commit_tree", "8f50ba15d49353813cc6e20298002c0d17b0a9ee"), + new Tuple("refs/tags/nearly-dangling", "6e0c7bdb9b4ed93212491ee778ca1c65047cab4e"), + }; + } +} diff --git a/LibGit2Sharp/Core/NativeMethods.cs b/LibGit2Sharp/Core/NativeMethods.cs index 9b4e818f3..d7ccd749e 100644 --- a/LibGit2Sharp/Core/NativeMethods.cs +++ b/LibGit2Sharp/Core/NativeMethods.cs @@ -1285,6 +1285,9 @@ internal static extern int git_repository_state( [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(LaxFilePathNoCleanupMarshaler))] internal static extern FilePath git_repository_workdir(RepositorySafeHandle repository); + [DllImport(libgit2)] + internal static extern int git_repository_new(out RepositorySafeHandle repo); + [DllImport(libgit2)] internal static extern int git_reset( RepositorySafeHandle repo, diff --git a/LibGit2Sharp/Core/Proxy.cs b/LibGit2Sharp/Core/Proxy.cs index 65a389a08..e107dbb53 100644 --- a/LibGit2Sharp/Core/Proxy.cs +++ b/LibGit2Sharp/Core/Proxy.cs @@ -2167,6 +2167,16 @@ public static RepositorySafeHandle git_repository_open(string path) return repo; } + public static RepositorySafeHandle git_repository_new() + { + RepositorySafeHandle repo; + int res = NativeMethods.git_repository_new(out repo); + + Ensure.ZeroResult(res); + + return repo; + } + public static void git_repository_open_ext(string path, RepositoryOpenFlags flags, string ceilingDirs) { int res; diff --git a/LibGit2Sharp/DirectReference.cs b/LibGit2Sharp/DirectReference.cs index 00de258a6..b9cc304b3 100644 --- a/LibGit2Sharp/DirectReference.cs +++ b/LibGit2Sharp/DirectReference.cs @@ -18,12 +18,21 @@ protected DirectReference() internal DirectReference(string canonicalName, IRepository repo, ObjectId targetId) : base(repo, canonicalName, targetId.Sha) { - targetBuilder = new Lazy(() => repo.Lookup(targetId)); + targetBuilder = new Lazy(() => + { + if (repo == null) + { + throw new InvalidOperationException("Target requires a local repository"); + } + + return repo.Lookup(targetId); + }); } /// /// Gets the target of this /// + /// Throws if Local Repository is not set. public virtual GitObject Target { get { return targetBuilder.Value; } diff --git a/LibGit2Sharp/Reference.cs b/LibGit2Sharp/Reference.cs index 5b0787ede..35cf7b286 100644 --- a/LibGit2Sharp/Reference.cs +++ b/LibGit2Sharp/Reference.cs @@ -199,6 +199,17 @@ private string DebuggerDisplay } } - IRepository IBelongToARepository.Repository { get { return repo; } } + IRepository IBelongToARepository.Repository + { + get + { + if (repo == null) + { + throw new InvalidOperationException("Repository requires a local repository"); + } + + return repo; + } + } } } diff --git a/LibGit2Sharp/Repository.cs b/LibGit2Sharp/Repository.cs index 79c9077bc..e269113cf 100644 --- a/LibGit2Sharp/Repository.cs +++ b/LibGit2Sharp/Repository.cs @@ -545,6 +545,52 @@ internal Commit LookupCommit(string committish) LookUpOptions.ThrowWhenCanNotBeDereferencedToACommit); } + /// + /// Lists the Remote Repository References. + /// + /// + /// Does not require a local Repository. The retrieved + /// + /// throws in this case. + /// + /// The url to list from. + /// The references in the remote repository. + public static IEnumerable ListRemoteReferences(string url) + { + return ListRemoteReferences(url, null); + } + + /// + /// 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. + /// The references in the remote repository. + public static IEnumerable ListRemoteReferences(string url, CredentialsHandler credentialsProvider) + { + Ensure.ArgumentNotNull(url, "url"); + + using (RepositorySafeHandle repositoryHandle = Proxy.git_repository_new()) + using (RemoteSafeHandle remoteHandle = Proxy.git_remote_create_anonymous(repositoryHandle, url)) + { + var gitCallbacks = new GitRemoteCallbacks { version = 1 }; + + if (credentialsProvider != null) + { + var callbacks = new RemoteCallbacks(credentialsProvider); + gitCallbacks = callbacks.GenerateCallbacks(); + } + + Proxy.git_remote_connect(remoteHandle, GitDirection.Fetch, ref gitCallbacks); + return Proxy.git_remote_ls(null, remoteHandle); + } + } + /// /// Probe for a git repository. /// The lookup start from and walk upward parent directories if nothing has been found.