mirror of
https://github.com/zoriya/octokit.net.git
synced 2026-06-05 11:40:42 +00:00
Merge pull request #835 from octokit/refine-search-api
search across multiple repositories
This commit is contained in:
@@ -77,6 +77,9 @@ tools/xunit.runner.console
|
||||
*.ncrunch*
|
||||
*.GhostDoc.xml
|
||||
|
||||
# FAKE temporary files
|
||||
.fake/
|
||||
|
||||
# New VS Test Runner creates arbitrary folders with PDBs
|
||||
*.pdb
|
||||
pingme.txt
|
||||
@@ -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;
|
||||
@@ -34,8 +36,8 @@ public class SearchClientTests
|
||||
[Fact]
|
||||
public async Task SearchForFunctionInCode()
|
||||
{
|
||||
var request = new SearchCodeRequest("addClass");
|
||||
request.Repo = "jquery/jquery";
|
||||
var request = new SearchCodeRequest("addClass", "jquery", "jquery");
|
||||
|
||||
var repos = await _gitHubClient.Search.SearchCode(request);
|
||||
|
||||
Assert.NotEmpty(repos.Items);
|
||||
@@ -45,6 +47,11 @@ public class SearchClientTests
|
||||
public async Task SearchForWordInCode()
|
||||
{
|
||||
var request = new SearchIssuesRequest("windows");
|
||||
request.Repos = new RepositoryCollection {
|
||||
{ "aspnet", "dnx" },
|
||||
{ "aspnet", "dnvm" }
|
||||
};
|
||||
|
||||
request.SortField = IssueSearchSort.Created;
|
||||
request.Order = SortDirection.Descending;
|
||||
|
||||
@@ -57,7 +64,7 @@ public class SearchClientTests
|
||||
public async Task SearchForOpenIssues()
|
||||
{
|
||||
var request = new SearchIssuesRequest("phone");
|
||||
request.Repo = "caliburn-micro/caliburn.micro";
|
||||
request.Repos.Add("caliburn-micro", "caliburn.micro");
|
||||
request.State = ItemState.Open;
|
||||
|
||||
var issues = await _gitHubClient.Search.SearchIssues(request);
|
||||
@@ -66,10 +73,25 @@ public class SearchClientTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SearchForAllIssues()
|
||||
public async Task SearchForAllIssuesWithouTaskUsingTerm()
|
||||
{
|
||||
var request = new SearchIssuesRequest();
|
||||
request.Repos.Add("caliburn-micro/caliburn.micro");
|
||||
|
||||
var issues = await _gitHubClient.Search.SearchIssues(request);
|
||||
|
||||
var closedIssues = issues.Items.Where(x => x.State == ItemState.Closed);
|
||||
var openedIssues = issues.Items.Where(x => x.State == ItemState.Open);
|
||||
|
||||
Assert.NotEmpty(closedIssues);
|
||||
Assert.NotEmpty(openedIssues);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SearchForAllIssuesUsingTerm()
|
||||
{
|
||||
var request = new SearchIssuesRequest("phone");
|
||||
request.Repo = "caliburn-micro/caliburn.micro";
|
||||
request.Repos.Add("caliburn-micro", "caliburn.micro");
|
||||
|
||||
var issues = await _gitHubClient.Search.SearchIssues(request);
|
||||
|
||||
|
||||
@@ -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,31 @@ namespace Octokit.Tests.Clients
|
||||
var connection = Substitute.For<IApiConnection>();
|
||||
var client = new SearchClient(connection);
|
||||
var request = new SearchIssuesRequest("something");
|
||||
request.Repo = "octokit.net";
|
||||
request.Repos.Add("octokit", "octokit.net");
|
||||
|
||||
client.SearchIssues(request);
|
||||
|
||||
connection.Received().Get<SearchIssuesResult>(
|
||||
Arg.Is<Uri>(u => u.ToString() == "search/issues"),
|
||||
Arg.Is<Dictionary<string, string>>(d => d["q"] == "something+repo:octokit.net"));
|
||||
Arg.Is<Dictionary<string, string>>(d => d["q"] == "something+repo:octokit/octokit.net"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ErrorOccursWhenSpecifyingInvalidFormatForRepos()
|
||||
{
|
||||
var connection = Substitute.For<IApiConnection>();
|
||||
var client = new SearchClient(connection);
|
||||
|
||||
var request = new SearchIssuesRequest("windows");
|
||||
request.Repos = new RepositoryCollection {
|
||||
"haha-business"
|
||||
};
|
||||
|
||||
request.SortField = IssueSearchSort.Created;
|
||||
request.Order = SortDirection.Descending;
|
||||
|
||||
await Assert.ThrowsAsync<RepositoryFormatException>(
|
||||
async () => await client.SearchIssues(request));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -1165,7 +1184,7 @@ namespace Octokit.Tests.Clients
|
||||
var connection = Substitute.For<IApiConnection>();
|
||||
var client = new SearchClient(connection);
|
||||
var request = new SearchIssuesRequest("something");
|
||||
request.Repo = "octokit.net";
|
||||
request.Repos.Add("octokit/octokit.net");
|
||||
request.User = "alfhenrik";
|
||||
request.Labels = new[] { "bug" };
|
||||
|
||||
@@ -1174,7 +1193,7 @@ namespace Octokit.Tests.Clients
|
||||
connection.Received().Get<SearchIssuesResult>(
|
||||
Arg.Is<Uri>(u => u.ToString() == "search/issues"),
|
||||
Arg.Is<Dictionary<string, string>>(d => d["q"] ==
|
||||
"something+label:bug+user:alfhenrik+repo:octokit.net"));
|
||||
"something+label:bug+user:alfhenrik+repo:octokit/octokit.net"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1445,14 +1464,13 @@ namespace Octokit.Tests.Clients
|
||||
{
|
||||
var connection = Substitute.For<IApiConnection>();
|
||||
var client = new SearchClient(connection);
|
||||
var request = new SearchCodeRequest("something");
|
||||
request.Repo = "octokit.net";
|
||||
var request = new SearchCodeRequest("something", "octokit", "octokit.net");
|
||||
|
||||
client.SearchCode(request);
|
||||
|
||||
connection.Received().Get<SearchCodeResult>(
|
||||
Arg.Is<Uri>(u => u.ToString() == "search/code"),
|
||||
Arg.Is<Dictionary<string, string>>(d => d["q"] == "something+repo:octokit.net"));
|
||||
Arg.Is<Dictionary<string, string>>(d => d["q"] == "something+repo:octokit/octokit.net"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -1475,8 +1493,7 @@ namespace Octokit.Tests.Clients
|
||||
{
|
||||
var connection = Substitute.For<IApiConnection>();
|
||||
var client = new SearchClient(connection);
|
||||
var request = new SearchCodeRequest("something");
|
||||
request.Repo = "octokit.net";
|
||||
var request = new SearchCodeRequest("something", "octokit", "octokit.net");
|
||||
request.Path = "tools/FAKE.core";
|
||||
request.Extension = "fs";
|
||||
|
||||
@@ -1485,7 +1502,24 @@ namespace Octokit.Tests.Clients
|
||||
connection.Received().Get<SearchCodeResult>(
|
||||
Arg.Is<Uri>(u => u.ToString() == "search/code"),
|
||||
Arg.Is<Dictionary<string, string>>(d =>
|
||||
d["q"] == "something+path:tools/FAKE.core+extension:fs+repo:octokit.net"));
|
||||
d["q"] == "something+path:tools/FAKE.core+extension:fs+repo:octokit/octokit.net"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ErrorOccursWhenSpecifyingInvalidFormatForRepos()
|
||||
{
|
||||
var connection = Substitute.For<IApiConnection>();
|
||||
var client = new SearchClient(connection);
|
||||
|
||||
var request = new SearchCodeRequest("windows");
|
||||
request.Repos = new RepositoryCollection {
|
||||
"haha-business"
|
||||
};
|
||||
|
||||
request.Order = SortDirection.Descending;
|
||||
|
||||
await Assert.ThrowsAsync<RepositoryFormatException>(
|
||||
async () => await client.SearchCode(request));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Octokit
|
||||
{
|
||||
#if !NETFX_CORE
|
||||
[Serializable]
|
||||
#endif
|
||||
[SuppressMessage("Microsoft.Design", "CA1032:ImplementStandardExceptionConstructors",
|
||||
Justification = "These exceptions are specific to the GitHub API and not general purpose exceptions")]
|
||||
public class RepositoryFormatException : Exception
|
||||
{
|
||||
readonly string message;
|
||||
|
||||
public RepositoryFormatException(IEnumerable<string> invalidRepositories)
|
||||
{
|
||||
var parameterList = string.Join(", ", invalidRepositories);
|
||||
message = string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
"The list of repositories must be formatted as 'owner/name' - these values don't match this rule: {0}",
|
||||
parameterList);
|
||||
|
||||
}
|
||||
|
||||
public override string Message
|
||||
{
|
||||
get
|
||||
{
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
||||
#if !NETFX_CORE
|
||||
/// <summary>
|
||||
/// Constructs an instance of LoginAttemptsExceededException
|
||||
/// </summary>
|
||||
/// <param name="info">
|
||||
/// The <see cref="SerializationInfo"/> that holds the
|
||||
/// serialized object data about the exception being thrown.
|
||||
/// </param>
|
||||
/// <param name="context">
|
||||
/// The <see cref="StreamingContext"/> that contains
|
||||
/// contextual information about the source or destination.
|
||||
/// </param>
|
||||
protected RepositoryFormatException(SerializationInfo info, StreamingContext context)
|
||||
: base(info, context)
|
||||
{
|
||||
if (info == null) return;
|
||||
message = info.GetString("Message");
|
||||
}
|
||||
|
||||
public override void GetObjectData(SerializationInfo info, StreamingContext context)
|
||||
{
|
||||
base.GetObjectData(info, context);
|
||||
info.AddValue("Message", Message);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -101,5 +101,19 @@ namespace Octokit
|
||||
//We need to have the last word.
|
||||
yield return new String(letters, wordStartIndex, letters.Length - wordStartIndex);
|
||||
}
|
||||
|
||||
// the rule:
|
||||
// Username may only contain alphanumeric characters or single hyphens
|
||||
// and cannot begin or end with a hyphen
|
||||
static readonly Regex nameWithOwner = new Regex("[a-z0-9.-]{1,}/[a-z0-9.-]{1,}",
|
||||
#if (!PORTABLE && !NETFX_CORE)
|
||||
RegexOptions.Compiled |
|
||||
#endif
|
||||
RegexOptions.IgnoreCase);
|
||||
|
||||
internal static bool IsNameWithOwnerFormat(this string input)
|
||||
{
|
||||
return nameWithOwner.IsMatch(input);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,10 @@ namespace Octokit
|
||||
[DebuggerDisplay("{DebuggerDisplay,nq}")]
|
||||
public class SearchCodeRequest : BaseSearchRequest
|
||||
{
|
||||
public SearchCodeRequest(string term) : base(term) { }
|
||||
public SearchCodeRequest(string term) : base(term)
|
||||
{
|
||||
Repos = new RepositoryCollection();
|
||||
}
|
||||
|
||||
public SearchCodeRequest(string term, string owner, string name)
|
||||
: this(term)
|
||||
@@ -24,7 +27,7 @@ namespace Octokit
|
||||
Ensure.ArgumentNotNullOrEmptyString(owner, "owner");
|
||||
Ensure.ArgumentNotNullOrEmptyString(name, "name");
|
||||
|
||||
this.Repo = string.Format(CultureInfo.InvariantCulture, "{0}/{1}", owner, name);
|
||||
Repos.Add(owner, name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -117,7 +120,8 @@ namespace Octokit
|
||||
/// <remarks>
|
||||
/// https://help.github.com/articles/searching-code#users-organizations-and-repositories
|
||||
/// </remarks>
|
||||
public string Repo { get; set; }
|
||||
[SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
|
||||
public RepositoryCollection Repos { get; set; }
|
||||
|
||||
[SuppressMessage("Microsoft.Globalization", "CA1304:SpecifyCultureInfo", MessageId = "System.String.ToLower")]
|
||||
public override IReadOnlyList<string> MergedQualifiers()
|
||||
@@ -162,9 +166,16 @@ 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 => !x.IsNameWithOwnerFormat());
|
||||
if (invalidFormatRepos.Any())
|
||||
{
|
||||
throw new RepositoryFormatException(invalidFormatRepos);
|
||||
}
|
||||
|
||||
parameters.Add(
|
||||
string.Join("+", Repos.Select(x => "repo:" + x)));
|
||||
}
|
||||
|
||||
return new ReadOnlyCollection<string>(parameters);
|
||||
|
||||
@@ -15,15 +15,31 @@ namespace Octokit
|
||||
[DebuggerDisplay("{DebuggerDisplay,nq}")]
|
||||
public class SearchIssuesRequest : BaseSearchRequest
|
||||
{
|
||||
public SearchIssuesRequest(string term) : base(term) { }
|
||||
/// <summary>
|
||||
/// Search without specifying a keyword
|
||||
/// </summary>
|
||||
public SearchIssuesRequest()
|
||||
{
|
||||
Repos = new RepositoryCollection();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Search using a specify keyword
|
||||
/// </summary>
|
||||
/// <param name="term">The term to filter on</param>
|
||||
public SearchIssuesRequest(string term) : base(term)
|
||||
{
|
||||
Repos = new RepositoryCollection();
|
||||
}
|
||||
|
||||
[Obsolete("this will be deprecated in a future version")]
|
||||
public SearchIssuesRequest(string term, string owner, string name)
|
||||
: this(term)
|
||||
{
|
||||
Ensure.ArgumentNotNullOrEmptyString(owner, "owner");
|
||||
Ensure.ArgumentNotNullOrEmptyString(name, "name");
|
||||
|
||||
this.Repo = string.Format(CultureInfo.InvariantCulture, "{0}/{1}", owner, name);
|
||||
Repos.Add(owner, name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -177,13 +193,8 @@ namespace Octokit
|
||||
/// </remarks>
|
||||
public string User { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Limits searches to a specific repository.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// https://help.github.com/articles/searching-issues#users-organizations-and-repositories
|
||||
/// </remarks>
|
||||
public string Repo { get; set; }
|
||||
[SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
|
||||
public RepositoryCollection Repos { get; set; }
|
||||
|
||||
public override IReadOnlyList<string> MergedQualifiers()
|
||||
{
|
||||
@@ -264,9 +275,16 @@ 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 => !x.IsNameWithOwnerFormat());
|
||||
if (invalidFormatRepos.Any())
|
||||
{
|
||||
throw new RepositoryFormatException(invalidFormatRepos);
|
||||
}
|
||||
|
||||
parameters.Add(
|
||||
string.Join("+", Repos.Select(x => "repo:" + x)));
|
||||
}
|
||||
|
||||
return new ReadOnlyCollection<string>(parameters);
|
||||
@@ -317,4 +335,39 @@ namespace Octokit
|
||||
[Parameter(Value = "issue")]
|
||||
Issue
|
||||
}
|
||||
|
||||
[DebuggerDisplay("{DebuggerDisplay,nq}")]
|
||||
public class RepositoryCollection : Collection<string>
|
||||
{
|
||||
public void Add(string owner, string name)
|
||||
{
|
||||
Add(GetRepositoryName(owner, name));
|
||||
}
|
||||
|
||||
public bool Contains(string owner, string name)
|
||||
{
|
||||
return Contains(GetRepositoryName(owner, name));
|
||||
}
|
||||
|
||||
public bool Remove(string owner, string name)
|
||||
{
|
||||
return Remove(GetRepositoryName(owner, name));
|
||||
}
|
||||
|
||||
static string GetRepositoryName(string owner, string name)
|
||||
{
|
||||
Ensure.ArgumentNotNullOrEmptyString(owner, "owner");
|
||||
Ensure.ArgumentNotNullOrEmptyString(name, "name");
|
||||
|
||||
return string.Format(CultureInfo.InvariantCulture, "{0}/{1}", owner, name);
|
||||
}
|
||||
|
||||
internal string DebuggerDisplay
|
||||
{
|
||||
get
|
||||
{
|
||||
return String.Format(CultureInfo.InvariantCulture, "Repositories: {0}", Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -396,6 +396,7 @@
|
||||
<Compile Include="Exceptions\TwoFactorAuthorizationException.cs" />
|
||||
<Compile Include="Http\HttpMessageHandlerFactory.cs" />
|
||||
<Compile Include="Models\Response\TeamMembership.cs" />
|
||||
<Compile Include="Exceptions\RepositoryFormatException.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
@@ -412,6 +412,7 @@
|
||||
<Compile Include="Models\Request\RepositoryHookTestRequest.cs" />
|
||||
<Compile Include="Http\HttpMessageHandlerFactory.cs" />
|
||||
<Compile Include="Models\Response\TeamMembership.cs" />
|
||||
<Compile Include="Exceptions\RepositoryFormatException.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\Novell\Novell.MonoDroid.CSharp.targets" />
|
||||
</Project>
|
||||
@@ -405,6 +405,7 @@
|
||||
<Compile Include="Models\Request\RepositoryHookTestRequest.cs" />
|
||||
<Compile Include="Http\HttpMessageHandlerFactory.cs" />
|
||||
<Compile Include="Models\Response\TeamMembership.cs" />
|
||||
<Compile Include="Exceptions\RepositoryFormatException.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.MonoTouch.CSharp.targets" />
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
|
||||
@@ -395,6 +395,7 @@
|
||||
<Compile Include="Exceptions\TwoFactorAuthorizationException.cs" />
|
||||
<Compile Include="Http\HttpMessageHandlerFactory.cs" />
|
||||
<Compile Include="Models\Response\TeamMembership.cs" />
|
||||
<Compile Include="Exceptions\RepositoryFormatException.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<CodeAnalysisDictionary Include="..\CustomDictionary.xml">
|
||||
|
||||
@@ -399,6 +399,7 @@
|
||||
<Compile Include="Exceptions\TwoFactorAuthorizationException.cs" />
|
||||
<Compile Include="Http\HttpMessageHandlerFactory.cs" />
|
||||
<Compile Include="Models\Response\TeamMembership.cs" />
|
||||
<Compile Include="Exceptions\RepositoryFormatException.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<CodeAnalysisDictionary Include="..\CustomDictionary.xml">
|
||||
|
||||
@@ -74,6 +74,7 @@
|
||||
<Compile Include="Clients\RepositoryContentsClient.cs" />
|
||||
<Compile Include="Exceptions\PrivateRepositoryQuotaExceededException.cs" />
|
||||
<Compile Include="Exceptions\RepositoryExistsException.cs" />
|
||||
<Compile Include="Exceptions\RepositoryFormatException.cs" />
|
||||
<Compile Include="Exceptions\TwoFactorAuthorizationException.cs" />
|
||||
<Compile Include="Helpers\ApiErrorExtensions.cs" />
|
||||
<Compile Include="Helpers\ApiUrls.Authorizations.cs" />
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
@echo off
|
||||
|
||||
"tools\nuget\nuget.exe" "install" "xunit.runner.console" "-OutputDirectory" "tools" "-ExcludeVersion" "-version" "2.0.0"
|
||||
"tools\nuget\nuget.exe" "install" "FAKE.Core" "-OutputDirectory" "tools" "-ExcludeVersion" "-version" "3.12.2"
|
||||
"tools\nuget\nuget.exe" "install" "FAKE.Core" "-OutputDirectory" "tools" "-ExcludeVersion" "-version" "3.37.1"
|
||||
"tools\nuget\nuget.exe" "install" "SourceLink.Fake" "-OutputDirectory" "tools" "-ExcludeVersion" "-version" "1.0.0"
|
||||
|
||||
:Build
|
||||
|
||||
@@ -29,7 +29,10 @@ let releaseNotes =
|
||||
|
||||
let buildMode = getBuildParamOrDefault "buildMode" "Release"
|
||||
|
||||
MSBuildDefaults <- { MSBuildDefaults with Verbosity = Some MSBuildVerbosity.Minimal }
|
||||
MSBuildDefaults <- {
|
||||
MSBuildDefaults with
|
||||
ToolsVersion = Some "12.0"
|
||||
Verbosity = Some MSBuildVerbosity.Minimal }
|
||||
|
||||
Target "Clean" (fun _ ->
|
||||
CleanDirs [buildDir; reactiveBuildDir; testResultsDir; packagingRoot; packagingDir; reactivePackagingDir]
|
||||
@@ -62,9 +65,19 @@ Target "FixProjects" (fun _ ->
|
||||
|> Fake.MSBuild.ProjectSystem.FixProjectFiles "./Octokit.Reactive/Octokit.Reactive.csproj"
|
||||
)
|
||||
|
||||
let setParams defaults = {
|
||||
defaults with
|
||||
ToolsVersion = Some("12.0")
|
||||
Targets = ["Build"]
|
||||
Properties =
|
||||
[
|
||||
"Configuration", buildMode
|
||||
]
|
||||
}
|
||||
|
||||
Target "BuildApp" (fun _ ->
|
||||
MSBuild null "Build" ["Configuration", buildMode] ["./Octokit.sln"]
|
||||
|> Log "AppBuild-Output: "
|
||||
build setParams "./Octokit.sln"
|
||||
|> DoNothing
|
||||
)
|
||||
|
||||
Target "ConventionTests" (fun _ ->
|
||||
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
# Search
|
||||
|
||||
You can use Octokit to search for different sorts of data available
|
||||
on the GitHub or GitHub Enterprise server:
|
||||
|
||||
- issues
|
||||
- repositories
|
||||
- code
|
||||
- users
|
||||
|
||||
## Search Issues
|
||||
|
||||
A common scenario is to search for issues to triage:
|
||||
|
||||
```csharp
|
||||
// you can also specify a search term here
|
||||
var request = new SearchIssuesRequest();
|
||||
|
||||
// you can add individual repos to focus your search
|
||||
request.Repos.Add("aspnet/dnx");
|
||||
request.Repos.Add("aspnet", "dnvm");
|
||||
|
||||
// or use a series of repositories
|
||||
request.Repos = new RepositoryCollection {
|
||||
"aspnet/dnx",
|
||||
"aspnet/dnvm"
|
||||
};
|
||||
|
||||
request.Repos = new RepositoryCollection {
|
||||
{ "aspnet", "dnx" },
|
||||
{ "aspnet", "dnvm" }
|
||||
};
|
||||
```
|
||||
|
||||
There's many other options available here to tweak
|
||||
your search criteria:
|
||||
|
||||
```csharp
|
||||
// if you're searching for a specific term, you can
|
||||
// focus your search on specific criteria
|
||||
request.In = new[] {
|
||||
IssueInQualifier.Title,
|
||||
IssueInQualifier.Body
|
||||
};
|
||||
|
||||
// you can restrict your search to issues or pull requests
|
||||
request.Type = IssueTypeQualifier.Issue;
|
||||
|
||||
// you can filter on when the issue was created or updated
|
||||
var aWeekAgo = DateTime.Now.Subtract(TimeSpan.FromDays(7));
|
||||
request.Created = new DateRange(aWeekAgo, SearchQualifierOperator.GreaterThan)
|
||||
|
||||
// you can search for issues created by, assigned to
|
||||
// or mentioning a specific user
|
||||
request.Author = "davidfowl";
|
||||
request.Assignee = "damianedwards";
|
||||
request.Mentions = "shiftkey";
|
||||
request.Commenter = "haacked";
|
||||
|
||||
// rather than setting all these, you can use this to find
|
||||
// all the above for a specific user with this one-liner
|
||||
request.Involves = "davidfowl";
|
||||
|
||||
// by default this will search on open issues, set this if
|
||||
// you want to get all issues
|
||||
request.State = ItemState.All;
|
||||
// or to just search closed issues
|
||||
request.State = ItemState.Closed;
|
||||
```
|
||||
|
||||
There's other options available to control how the results are returned:
|
||||
|
||||
```csharp
|
||||
request.SortField = IssueSearchSort.Created;
|
||||
request.Order = SortDirection.Descending;
|
||||
|
||||
// 100 results per page as default
|
||||
request.PerPage = 30;
|
||||
|
||||
// set this when you want to fetch subsequent pages
|
||||
request.Page = 2;
|
||||
```
|
||||
|
||||
Once you've set the right parameters, execute the request:
|
||||
|
||||
```csharp
|
||||
var repos = await client.Search.SearchIssues(request);
|
||||
|
||||
Console.WriteLine("Query has {0} matches.", repos.TotalCount);
|
||||
Console.WriteLine("Response has {0} items.", repos.Items.Count);
|
||||
```
|
||||
|
||||
## Search Pull Requests
|
||||
|
||||
Another scenario to consider is how to search broadly:
|
||||
|
||||
```csharp
|
||||
var threeMonthsAgoIsh = DateTime.Now.Subtract(TimeSpan.FromDays(90));
|
||||
|
||||
// search for a specific term
|
||||
var request = new SearchIssuesRequest("linux")
|
||||
{
|
||||
// only search pull requests
|
||||
Type = IssueTypeQualifier.PR,
|
||||
|
||||
// search across open and closed PRs
|
||||
State = ItemState.All,
|
||||
|
||||
// search repositories which contain code
|
||||
// matching a given language
|
||||
Language = Language.CSharp,
|
||||
|
||||
// focus on pull requests updated recently
|
||||
Updated = new DateRange(threeMonthsAgoIsh, SearchQualifierOperator.GreaterThan)
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Search Repositories
|
||||
|
||||
**TODO**
|
||||
|
||||
## Search Code
|
||||
|
||||
**TODO**
|
||||
|
||||
## Search Users
|
||||
|
||||
**TODO**
|
||||
Reference in New Issue
Block a user