Enable support for milestone-based issues queries (#1788)

* Added support for Milestone filter in SearchIssuesRequest

* Fixed some styling issues to match with the style of the existing code

* Wrap milestone value with double quotes as milestones can contain spaces

* Allow milestone filter to contain double quotes

* Ability to search by milestone exclusions

* Moved the EscapeDoubleQuotes method to StringExtensions
This commit is contained in:
mkArtak
2018-03-27 23:45:51 -07:00
committed by Ryan Gribble
parent 4e804f61a6
commit 6577c3ccba
6 changed files with 107 additions and 7 deletions
@@ -64,5 +64,30 @@ namespace Octokit.Tests.Helpers
Assert.Equal(expected, template.ExpandUriTemplate(new { name = "example name.txt", label = "labeltext" }).ToString());
}
}
public class EscapeDoubleQuotesMethod
{
[Fact]
public void EscapeDoubleQuotesReturnsNullForNullInput()
{
Assert.Equal(null, (null as string).EscapeDoubleQuotes());
}
[Fact]
public void EscapeDoubleQuotesReturnsInputWithoutDoubleQuotes()
{
string input = "some test input without double quotes in it";
Assert.Equal(input, input.EscapeDoubleQuotes());
}
[Fact]
public void EscapeDoubleQuotesEscapesAllDoubleQuotes()
{
string input = "\"test milestone\"";
Assert.Equal("\\\"test milestone\\\"", input.EscapeDoubleQuotes());
}
}
}
}
@@ -19,7 +19,8 @@ public class SearchIssuesRequestExclusionsTests
{ "commenter:", (x,value) => x.Commenter = value },
{ "involves:", (x,value) => x.Involves = value },
{ "head:", (x,value) => x.Head = value },
{ "base:", (x,value) => x.Base = value }
{ "base:", (x,value) => x.Base = value },
{ "milestone:", (x,value) => x.Milestone = value }
};
foreach (var property in stringProperties)
@@ -80,5 +81,25 @@ public class SearchIssuesRequestExclusionsTests
Assert.True(request.MergedQualifiers().Contains("-status:error"));
}
[Fact]
public void HandlesMilestoneAttributeWithoutQuotes()
{
var request = new SearchIssuesRequestExclusions();
Assert.False(request.MergedQualifiers().Any(x => x.Contains("-milestone:")));
request.Milestone = "testMilestone";
Assert.True(request.MergedQualifiers().Contains("-milestone:\"testMilestone\""));
}
[Fact]
public void DoesntWrapMilestoneWithDoubleQuotesForQuotedMilestone()
{
var request = new SearchIssuesRequestExclusions();
Assert.False(request.MergedQualifiers().Any(x => x.Contains("-milestone:")));
request.Milestone = "\"testMilestone\"";
Assert.Contains<string>("-milestone:\"\\\"testMilestone\\\"\"", request.MergedQualifiers());
}
}
}
@@ -41,7 +41,8 @@ public class SearchIssuesRequestTests
{ "team:", (x,value) => x.Team = value },
{ "head:", (x,value) => x.Head = value },
{ "base:", (x,value) => x.Base = value },
{ "user:", (x,value) => x.User = value }
{ "user:", (x,value) => x.User = value },
{ "milestone:", (x,value) => x.Milestone = value }
};
foreach (var property in stringProperties)
@@ -116,6 +117,26 @@ public class SearchIssuesRequestTests
Assert.True(request.MergedQualifiers().Contains("label:label2"));
}
[Fact]
public void HandlesMilestoneAttributeWithoutQuotes()
{
var request = new SearchIssuesRequest("text");
Assert.False(request.MergedQualifiers().Any(x => x.Contains("milestone:")));
request.Milestone = "testMilestone";
Assert.True(request.MergedQualifiers().Contains("milestone:\"testMilestone\""));
}
[Fact]
public void DoesntWrapMilestoneWithDoubleQuotesForQuotedMilestone()
{
var request = new SearchIssuesRequest("text");
Assert.False(request.MergedQualifiers().Any(x => x.Contains("milestone:")));
request.Milestone = "\"testMilestone\"";
Assert.Contains<string>("milestone:\"\\\"testMilestone\\\"\"", request.MergedQualifiers());
}
[Fact]
public void HandlesNoMetadataAttributeCorrectly()
{
+11
View File
@@ -87,6 +87,17 @@ namespace Octokit
Ensure.ArgumentNotNullOrEmptyString(value, nameof(value));
return string.Concat(value[0].ToString().ToUpperInvariant(), value.Substring(1));
}
internal static string EscapeDoubleQuotes(this string value)
{
if (value != null)
{
return value.Replace("\"", "\\\"");
}
return value;
}
static IEnumerable<string> SplitUpperCase(this string source)
{
Ensure.ArgumentNotNullOrEmptyString(source, nameof(source));
+13 -2
View File
@@ -1,11 +1,11 @@
using System;
using Octokit.Internal;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using Octokit.Internal;
namespace Octokit
{
@@ -168,6 +168,7 @@ namespace Octokit
public Language? Language { get; set; }
private IEnumerable<IssueIsQualifier> _is;
/// <summary>
/// Searches for issues using a more human syntax covering options like state, type, merged status, private/public repository
/// </summary>
@@ -258,6 +259,11 @@ namespace Octokit
/// </remarks>
public string User { get; set; }
/// <summary>
/// Gets or sets the milestone to filter issues based on
/// </summary>
public string Milestone { get; set; }
[SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public RepositoryCollection Repos { get; set; }
@@ -391,6 +397,11 @@ namespace Octokit
parameters.AddRange(Repos.Select(x => string.Format(CultureInfo.InvariantCulture, "repo:{0}", x)));
}
if (Milestone.IsNotBlank())
{
parameters.Add(string.Format(CultureInfo.InvariantCulture, "milestone:\"{0}\"", Milestone.EscapeDoubleQuotes()));
}
// Add any exclusion parameters
if (Exclusions != null)
{
@@ -1,11 +1,9 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using Octokit.Internal;
namespace Octokit
{
@@ -122,6 +120,14 @@ namespace Octokit
/// </remarks>
public string Base { get; set; }
/// <summary>
/// Excludes issues which target the specified milestone.
/// </summary>
/// <remarks>
/// https://help.github.com/articles/searching-issues-and-pull-requests/#search-by-milestone-on-an-issue-or-pull-request
/// </remarks>
public string Milestone { get; set; }
[SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
public IReadOnlyList<string> MergedQualifiers()
{
@@ -182,6 +188,11 @@ namespace Octokit
parameters.Add(string.Format(CultureInfo.InvariantCulture, "-base:{0}", Base));
}
if (Milestone.IsNotBlank())
{
parameters.Add(string.Format(CultureInfo.InvariantCulture, "-milestone:\"{0}\"", Milestone.EscapeDoubleQuotes()));
}
return new ReadOnlyCollection<string>(parameters);
}