From cf1b99dd3db24c7b4560cfc0d815832828958fec Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Sun, 12 Jul 2015 20:59:31 -0700 Subject: [PATCH] define a custom Repos property when searching issues --- .../Clients/SearchClientTests.cs | 9 ++- Octokit.Tests/Clients/SearchClientTests.cs | 29 ++++++++-- Octokit/Models/Request/SearchIssuesRequest.cs | 55 +++++++++++++++++-- 3 files changed, 83 insertions(+), 10 deletions(-) diff --git a/Octokit.Tests.Integration/Clients/SearchClientTests.cs b/Octokit.Tests.Integration/Clients/SearchClientTests.cs index cb7a1305..a33d370a 100644 --- a/Octokit.Tests.Integration/Clients/SearchClientTests.cs +++ b/Octokit.Tests.Integration/Clients/SearchClientTests.cs @@ -1,4 +1,6 @@ -using System.Linq; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; using System.Threading.Tasks; using Octokit; using Octokit.Tests.Integration; @@ -45,6 +47,11 @@ public class SearchClientTests public async Task SearchForWordInCode() { var request = new SearchIssuesRequest("windows"); + request.Repos = new Collection { + "aspnet/dnx", + "aspnet/dnvm" + }; + request.SortField = IssueSearchSort.Created; request.Order = SortDirection.Descending; diff --git a/Octokit.Tests/Clients/SearchClientTests.cs b/Octokit.Tests/Clients/SearchClientTests.cs index c4eb248c..0019be8b 100644 --- a/Octokit.Tests/Clients/SearchClientTests.cs +++ b/Octokit.Tests/Clients/SearchClientTests.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using NSubstitute; using Xunit; using System.Threading.Tasks; @@ -1150,13 +1151,13 @@ namespace Octokit.Tests.Clients var connection = Substitute.For(); var client = new SearchClient(connection); var request = new SearchIssuesRequest("something"); - request.Repo = "octokit.net"; + request.Repo = "octokit/octokit.net"; client.SearchIssues(request); connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), - Arg.Is>(d => d["q"] == "something+repo:octokit.net")); + Arg.Is>(d => d["q"] == "something+repo:octokit/octokit.net")); } [Fact] @@ -1165,7 +1166,7 @@ namespace Octokit.Tests.Clients var connection = Substitute.For(); var client = new SearchClient(connection); var request = new SearchIssuesRequest("something"); - request.Repo = "octokit.net"; + request.Repo = "octokit/octokit.net"; request.User = "alfhenrik"; request.Labels = new[] { "bug" }; @@ -1174,7 +1175,7 @@ namespace Octokit.Tests.Clients connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == - "something+label:bug+user:alfhenrik+repo:octokit.net")); + "something+label:bug+user:alfhenrik+repo:octokit/octokit.net")); } } @@ -1487,6 +1488,26 @@ namespace Octokit.Tests.Clients Arg.Is>(d => d["q"] == "something+path:tools/FAKE.core+extension:fs+repo:octokit.net")); } + + [Fact] + public async Task ErrorOccursWhenSpecifyingInvalidFormatForRepos() + { + var connection = Substitute.For(); + var client = new SearchClient(connection); + + var request = new SearchIssuesRequest("windows"); + request.Repos = new Collection { + "haha-business" + }; + + request.SortField = IssueSearchSort.Created; + request.Order = SortDirection.Descending; + + await Assert.ThrowsAsync( + async () => await client.SearchIssues(request)); + } + + } } } diff --git a/Octokit/Models/Request/SearchIssuesRequest.cs b/Octokit/Models/Request/SearchIssuesRequest.cs index 49d0d5e0..e6659526 100644 --- a/Octokit/Models/Request/SearchIssuesRequest.cs +++ b/Octokit/Models/Request/SearchIssuesRequest.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Globalization; using System.Diagnostics.CodeAnalysis; +using System.Text.RegularExpressions; namespace Octokit { @@ -15,7 +16,10 @@ namespace Octokit [DebuggerDisplay("{DebuggerDisplay,nq}")] public class SearchIssuesRequest : BaseSearchRequest { - public SearchIssuesRequest(string term) : base(term) { } + public SearchIssuesRequest(string term) : base(term) + { + Repos = new Collection(); + } public SearchIssuesRequest(string term, string owner, string name) : this(term) @@ -23,7 +27,9 @@ namespace Octokit Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); Ensure.ArgumentNotNullOrEmptyString(name, "name"); - this.Repo = string.Format(CultureInfo.InvariantCulture, "{0}/{1}", owner, name); + var repo = string.Format(CultureInfo.InvariantCulture, "{0}/{1}", owner, name); + + Repos.Add(repo); } /// @@ -183,7 +189,21 @@ namespace Octokit /// /// https://help.github.com/articles/searching-issues#users-organizations-and-repositories /// - public string Repo { get; set; } + public string Repo + { + get + { + return Repos.FirstOrDefault(); + } + set + { + Repos.Clear(); + Repos.Add(value); + } + } + + [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] + public Collection Repos { get; set; } public override IReadOnlyList MergedQualifiers() { @@ -264,14 +284,39 @@ namespace Octokit parameters.Add(String.Format(CultureInfo.InvariantCulture, "user:{0}", User)); } - if (Repo.IsNotBlank()) + if (Repos.Any()) { - parameters.Add(String.Format(CultureInfo.InvariantCulture, "repo:{0}", Repo)); + var invalidFormatRepos = Repos.Where(x => !IsNameWithOwnerFormat(x)); + if (invalidFormatRepos.Any()) + { + var parameterList = string.Join(", ", invalidFormatRepos); + var message = string.Format( + CultureInfo.InvariantCulture, + "The list of repositories must be formatted as 'owner/name' - these values don't match this rule: {0}", + parameterList); + throw new ArgumentException(message); + } + + parameters.Add( + string.Join("+", Repos.Select(x => "repo:" + x))); } return new ReadOnlyCollection(parameters); } + // what rules do we define here? + + static Regex nameWithOwner = new Regex("[a-zA-Z.]{1,}/[a-zA-Z.]{1,}" +#if (!PORTABLE && !NETFX_CORE) + , RegexOptions.Compiled +#endif + ); + + static bool IsNameWithOwnerFormat(string input) + { + return nameWithOwner.IsMatch(input); + } + internal string DebuggerDisplay { get