diff --git a/Octokit.Reactive/Clients/IObservableRepositoriesClient.cs b/Octokit.Reactive/Clients/IObservableRepositoriesClient.cs index 3888b188..639acde1 100644 --- a/Octokit.Reactive/Clients/IObservableRepositoriesClient.cs +++ b/Octokit.Reactive/Clients/IObservableRepositoriesClient.cs @@ -116,6 +116,14 @@ namespace Octokit.Reactive /// IObservableStatisticsClient Statistics { get; } + /// + /// Client for GitHub's Repository Comments API. + /// + /// + /// See the Repository Comments API documentation for more information. + /// + IObservableRepositoryCommentsClient RepositoryComments { get; } + /// /// Gets all the branches for the specified repository. /// diff --git a/Octokit.Reactive/Clients/IObservableRepositoryCommentsClient.cs b/Octokit.Reactive/Clients/IObservableRepositoryCommentsClient.cs new file mode 100644 index 00000000..2a1faef4 --- /dev/null +++ b/Octokit.Reactive/Clients/IObservableRepositoryCommentsClient.cs @@ -0,0 +1,72 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Reactive; + +namespace Octokit.Reactive +{ + public interface IObservableRepositoryCommentsClient + { + /// + /// Gets a single Repository Comment by number. + /// + /// http://developer.github.com/v3/repos/comments/#get-a-single-commit-comment + /// The owner of the repository + /// The name of the repository + /// The comment id + /// + [SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "Get", + Justification = "Method makes a network request")] + IObservable Get(string owner, string name, int number); + + /// + /// Gets Commit Comments for a repository. + /// + /// http://developer.github.com/v3/repos/comments/#list-commit-comments-for-a-repository + /// The owner of the repository + /// The name of the repository + /// + IObservable GetForRepository(string owner, string name); + + /// + /// Gets Commit Comments for a specified Commit. + /// + /// http://developer.github.com/v3/repos/comments/#list-comments-for-a-single-commit + /// The owner of the repository + /// The name of the repository + /// The sha of the commit + /// + IObservable GetForCommit(string owner, string name, string sha); + + /// + /// Creates a new Commit Comment for a specified Commit. + /// + /// http://developer.github.com/v3/repos/comments/#create-a-commit-comment + /// The owner of the repository + /// The name of the repository + /// The sha reference of commit + /// The new comment to add to the commit + /// + IObservable Create(string owner, string name, string sha, NewCommitComment newCommitComment); + + /// + /// Updates a specified Commit Comment. + /// + /// http://developer.github.com/v3/repos/comments/#update-a-commit-comment + /// The owner of the repository + /// The name of the repository + /// The comment number + /// The modified comment + /// + IObservable Update(string owner, string name, int number, string commentUpdate); + + /// + /// Deletes the specified Commit Comment + /// + /// http://developer.github.com/v3/repos/comments/#delete-a-commit-comment + /// The owner of the repository + /// The name of the repository + /// The comment id + /// + IObservable Delete(string owner, string name, int number); + } +} diff --git a/Octokit.Reactive/Clients/IObservableSearchClient.cs b/Octokit.Reactive/Clients/IObservableSearchClient.cs index b4273750..d3eb6135 100644 --- a/Octokit.Reactive/Clients/IObservableSearchClient.cs +++ b/Octokit.Reactive/Clients/IObservableSearchClient.cs @@ -1,6 +1,4 @@ using System; -using System.Diagnostics.CodeAnalysis; -using System.Reactive; namespace Octokit.Reactive { @@ -15,7 +13,7 @@ namespace Octokit.Reactive /// /// /// List of repositories - IObservable SearchRepo(SearchRepositoriesRequest search); + IObservable SearchRepo(SearchRepositoriesRequest search); /// /// search users @@ -23,7 +21,7 @@ namespace Octokit.Reactive /// /// /// List of users - IObservable SearchUsers(SearchUsersRequest search); + IObservable SearchUsers(SearchUsersRequest search); /// /// search issues @@ -31,7 +29,7 @@ namespace Octokit.Reactive /// /// /// List of issues - IObservable SearchIssues(SearchIssuesRequest search); + IObservable SearchIssues(SearchIssuesRequest search); /// /// search code @@ -39,6 +37,6 @@ namespace Octokit.Reactive /// /// /// List of files - IObservable SearchCode(SearchCodeRequest search); + IObservable SearchCode(SearchCodeRequest search); } } \ No newline at end of file diff --git a/Octokit.Reactive/Clients/IObservableStatisticsClient.cs b/Octokit.Reactive/Clients/IObservableStatisticsClient.cs index 551189a2..5bb9a8bc 100644 --- a/Octokit.Reactive/Clients/IObservableStatisticsClient.cs +++ b/Octokit.Reactive/Clients/IObservableStatisticsClient.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using Octokit.Response; namespace Octokit.Reactive { diff --git a/Octokit.Reactive/Clients/ObservableRepositoriesClient.cs b/Octokit.Reactive/Clients/ObservableRepositoriesClient.cs index 63a5b254..13749739 100644 --- a/Octokit.Reactive/Clients/ObservableRepositoriesClient.cs +++ b/Octokit.Reactive/Clients/ObservableRepositoriesClient.cs @@ -24,6 +24,7 @@ namespace Octokit.Reactive Deployment = new ObservableDeploymentsClient(client); Statistics = new ObservableStatisticsClient(client); PullRequest = new ObservablePullRequestsClient(client); + RepositoryComments = new ObservableRepositoryCommentsClient(client); } /// @@ -180,6 +181,14 @@ namespace Octokit.Reactive /// public IObservableStatisticsClient Statistics { get; private set; } + /// + /// Client for GitHub's Repository Comments API. + /// + /// + /// See the Repository Comments API documentation for more information. + /// + public IObservableRepositoryCommentsClient RepositoryComments { get; private set; } + /// /// Gets all the branches for the specified repository. /// diff --git a/Octokit.Reactive/Clients/ObservableRepositoryCommentsClient.cs b/Octokit.Reactive/Clients/ObservableRepositoryCommentsClient.cs new file mode 100644 index 00000000..492792e8 --- /dev/null +++ b/Octokit.Reactive/Clients/ObservableRepositoryCommentsClient.cs @@ -0,0 +1,122 @@ +using System; +using System.Reactive; +using System.Reactive.Threading.Tasks; +using Octokit.Reactive.Internal; + +namespace Octokit.Reactive +{ + public class ObservableRepositoryCommentsClient : IObservableRepositoryCommentsClient + { + readonly IRepositoryCommentsClient _client; + readonly IConnection _connection; + + public ObservableRepositoryCommentsClient(IGitHubClient client) + { + Ensure.ArgumentNotNull(client, "client"); + + _client = client.Repository.RepositoryComments; + _connection = client.Connection; + } + + /// + /// Gets a single Repository Comment by number. + /// + /// http://developer.github.com/v3/repos/comments/#get-a-single-commit-comment + /// The owner of the repository + /// The name of the repository + /// The comment id + /// + public IObservable Get(string owner, string name, int number) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + + return _client.Get(owner, name, number).ToObservable(); + } + + /// + /// Gets Commit Comments for a repository. + /// + /// http://developer.github.com/v3/repos/comments/#list-commit-comments-for-a-repository + /// The owner of the repository + /// The name of the repository + /// + public IObservable GetForRepository(string owner, string name) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + + return _connection.GetAndFlattenAllPages(ApiUrls.CommitComments(owner, name)); + } + + /// + /// Gets Commit Comments for a specified Commit. + /// + /// http://developer.github.com/v3/repos/comments/#list-comments-for-a-single-commit + /// The owner of the repository + /// The name of the repository + /// The sha of the commit + /// + public IObservable GetForCommit(string owner, string name, string sha) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + Ensure.ArgumentNotNullOrEmptyString(sha, "sha"); + + return _connection.GetAndFlattenAllPages(ApiUrls.CommitComments(owner, name, sha)); + } + + /// + /// Creates a new Commit Comment for a specified Commit. + /// + /// http://developer.github.com/v3/repos/comments/#create-a-commit-comment + /// The owner of the repository + /// The name of the repository + /// The sha reference of commit + /// The new comment to add to the commit + /// + public IObservable Create(string owner, string name, string sha, NewCommitComment newCommitComment) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + Ensure.ArgumentNotNullOrEmptyString(sha, "sha"); + Ensure.ArgumentNotNull(newCommitComment, "newCommitComment"); + + return _client.Create(owner, name, sha, newCommitComment).ToObservable(); + } + + /// + /// Updates a specified Commit Comment. + /// + /// http://developer.github.com/v3/repos/comments/#update-a-commit-comment + /// The owner of the repository + /// The name of the repository + /// The comment number + /// The modified comment + /// + public IObservable Update(string owner, string name, int number, string commentUpdate) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + Ensure.ArgumentNotNull(commentUpdate, "commentUpdate"); + + return _client.Update(owner, name, number, commentUpdate).ToObservable(); + } + + /// + /// Deletes the specified Commit Comment + /// + /// http://developer.github.com/v3/repos/comments/#delete-a-commit-comment + /// The owner of the repository + /// The name of the repository + /// The comment id + /// + public IObservable Delete(string owner, string name, int number) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + + return _client.Delete(owner, name, number).ToObservable(); + } + } +} diff --git a/Octokit.Reactive/Clients/ObservableSearchClient.cs b/Octokit.Reactive/Clients/ObservableSearchClient.cs index c34e4525..1bdf0045 100644 --- a/Octokit.Reactive/Clients/ObservableSearchClient.cs +++ b/Octokit.Reactive/Clients/ObservableSearchClient.cs @@ -1,7 +1,5 @@ using System; -using System.Reactive; using System.Reactive.Threading.Tasks; -using Octokit.Reactive.Internal; namespace Octokit.Reactive { @@ -10,13 +8,13 @@ namespace Octokit.Reactive /// public class ObservableSearchClient : IObservableSearchClient { - readonly IConnection _connection; + readonly ISearchClient _client; public ObservableSearchClient(IGitHubClient client) { Ensure.ArgumentNotNull(client, "client"); - _connection = client.Connection; + _client = client.Search; } /// @@ -25,10 +23,10 @@ namespace Octokit.Reactive /// /// /// List of repositories - public IObservable SearchRepo(SearchRepositoriesRequest search) + public IObservable SearchRepo(SearchRepositoriesRequest search) { Ensure.ArgumentNotNull(search, "search"); - return _connection.GetAndFlattenAllPages(ApiUrls.SearchRepositories(), search.Parameters); + return _client.SearchRepo(search).ToObservable(); } /// @@ -37,10 +35,10 @@ namespace Octokit.Reactive /// /// /// List of users - public IObservable SearchUsers(SearchUsersRequest search) + public IObservable SearchUsers(SearchUsersRequest search) { Ensure.ArgumentNotNull(search, "search"); - return _connection.GetAndFlattenAllPages(ApiUrls.SearchUsers(), search.Parameters); + return _client.SearchUsers(search).ToObservable(); } /// @@ -49,10 +47,10 @@ namespace Octokit.Reactive /// /// /// List of issues - public IObservable SearchIssues(SearchIssuesRequest search) + public IObservable SearchIssues(SearchIssuesRequest search) { Ensure.ArgumentNotNull(search, "search"); - return _connection.GetAndFlattenAllPages(ApiUrls.SearchIssues(), search.Parameters); + return _client.SearchIssues(search).ToObservable(); } /// @@ -61,10 +59,10 @@ namespace Octokit.Reactive /// /// /// List of files - public IObservable SearchCode(SearchCodeRequest search) + public IObservable SearchCode(SearchCodeRequest search) { Ensure.ArgumentNotNull(search, "search"); - return _connection.GetAndFlattenAllPages(ApiUrls.SearchCode(), search.Parameters); + return _client.SearchCode(search).ToObservable(); } } } \ No newline at end of file diff --git a/Octokit.Reactive/Clients/ObservableStatisticsClient.cs b/Octokit.Reactive/Clients/ObservableStatisticsClient.cs index 9905de1f..74acaa64 100644 --- a/Octokit.Reactive/Clients/ObservableStatisticsClient.cs +++ b/Octokit.Reactive/Clients/ObservableStatisticsClient.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Reactive.Threading.Tasks; -using Octokit.Response; namespace Octokit.Reactive { diff --git a/Octokit.Reactive/Octokit.Reactive-Mono.csproj b/Octokit.Reactive/Octokit.Reactive-Mono.csproj index d3c9a130..5dc511fd 100644 --- a/Octokit.Reactive/Octokit.Reactive-Mono.csproj +++ b/Octokit.Reactive/Octokit.Reactive-Mono.csproj @@ -139,6 +139,8 @@ + + diff --git a/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj b/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj index 885d6aa1..cd53c5a2 100644 --- a/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj +++ b/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj @@ -148,6 +148,8 @@ + + diff --git a/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj b/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj index f571279c..c8657d7f 100644 --- a/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj +++ b/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj @@ -143,6 +143,8 @@ + + diff --git a/Octokit.Reactive/Octokit.Reactive.csproj b/Octokit.Reactive/Octokit.Reactive.csproj index 5a9d0d03..f08540c7 100644 --- a/Octokit.Reactive/Octokit.Reactive.csproj +++ b/Octokit.Reactive/Octokit.Reactive.csproj @@ -19,7 +19,7 @@ false obj\Debug\Net40 bin\Debug\Net45\ - DEBUG;TRACE;CODE_ANALYSIS;NET_45 + TRACE;DEBUG;CODE_ANALYSIS;NET_45;SIMPLE_JSON_READONLY_COLLECTIONS prompt 4 true @@ -32,7 +32,7 @@ true obj\Release\Net40 bin\Release\Net45\ - TRACE;NET_45 + TRACE;CODE_ANALYSIS;NET_45;SIMPLE_JSON_READONLY_COLLECTIONS prompt 4 false @@ -73,6 +73,8 @@ Properties\SolutionInfo.cs + + diff --git a/Octokit.Tests.Conventions/Exception/InterfaceHasAdditionalMethodsException.cs b/Octokit.Tests.Conventions/Exception/InterfaceHasAdditionalMethodsException.cs new file mode 100644 index 00000000..78ea2daa --- /dev/null +++ b/Octokit.Tests.Conventions/Exception/InterfaceHasAdditionalMethodsException.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; + +namespace Octokit.Tests.Conventions +{ + public class InterfaceHasAdditionalMethodsException : Exception + { + public InterfaceHasAdditionalMethodsException(Type type, IEnumerable methodsMissingOnReactiveClient) + : base(CreateMessage(type, methodsMissingOnReactiveClient)) { } + + public InterfaceHasAdditionalMethodsException(Type type, IEnumerable methodsMissingOnReactiveClient, Exception innerException) + : base(CreateMessage(type, methodsMissingOnReactiveClient), innerException) { } + + protected InterfaceHasAdditionalMethodsException(SerializationInfo info, StreamingContext context) + : base(info, context) { } + + static string CreateMessage(Type type, IEnumerable methods) + { + var methodsFormatted = String.Join("\r\n", methods.Select(m => String.Format(" - {0}", m))); + return "Methods found on type {0} which should be removed:\r\n{1}" + .FormatWithNewLine( + type.Name, + methodsFormatted); + } + } +} \ No newline at end of file diff --git a/Octokit.Tests.Conventions/Exception/InterfaceMethodsMismatchException.cs b/Octokit.Tests.Conventions/Exception/InterfaceMethodsMismatchException.cs new file mode 100644 index 00000000..7a422d49 --- /dev/null +++ b/Octokit.Tests.Conventions/Exception/InterfaceMethodsMismatchException.cs @@ -0,0 +1,48 @@ +using System; +using System.Linq; +using System.Reflection; +using System.Runtime.Serialization; + +namespace Octokit.Tests.Conventions +{ + public class InterfaceMethodsMismatchException : Exception + { + public InterfaceMethodsMismatchException(Type observableType, Type clientInterface) + : base(CreateMessage(observableType, clientInterface)) { } + + public InterfaceMethodsMismatchException(Type type,Type clientInterface, Exception innerException) + : base(CreateMessage(type, clientInterface), innerException) { } + + protected InterfaceMethodsMismatchException(SerializationInfo info, StreamingContext context) + : base(info, context) { } + + static string Format(ParameterInfo parameterInfo) + { + return String.Format("{0} {1}", parameterInfo.ParameterType.Name, parameterInfo.Name); + } + + static string Format(MethodInfo methodInfo) + { + var parameters = methodInfo.GetParameters().Select(Format); + + return String.Format("{0} {1}({2})", methodInfo.ReturnType, methodInfo.Name, String.Join(", ", parameters)); + } + + static string CreateMessage(Type observableInterface, Type clientInterface) + { + var mainMethods = clientInterface.GetMethodsOrdered(); + var observableMethods = observableInterface.GetMethodsOrdered(); + + var formattedMainMethods = String.Join("\r\n", mainMethods.Select(Format).Select(m => String.Format(" - {0}", m))); + var formattedObservableMethods = String.Join("\r\n", observableMethods.Select(Format).Select(m => String.Format(" - {0}", m))); + + return + "There are some overloads which are confusing the convention tests. Check everything is okay in these types:\r\n{0}\r\n{1}\r\n{2}\r\n{3}" + .FormatWithNewLine( + clientInterface.Name, + formattedMainMethods, + observableInterface.Name, + formattedObservableMethods); + } + } +} \ No newline at end of file diff --git a/Octokit.Tests.Conventions/Exception/InterfaceMissingMethodsException.cs b/Octokit.Tests.Conventions/Exception/InterfaceMissingMethodsException.cs new file mode 100644 index 00000000..4d16288a --- /dev/null +++ b/Octokit.Tests.Conventions/Exception/InterfaceMissingMethodsException.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; + +namespace Octokit.Tests.Conventions +{ + public class InterfaceMissingMethodsException : Exception + { + public InterfaceMissingMethodsException(Type type, IEnumerable methodsMissingOnReactiveClient) + : base(CreateMessage(type, methodsMissingOnReactiveClient)) { } + + public InterfaceMissingMethodsException(Type type, IEnumerable methodsMissingOnReactiveClient, Exception innerException) + : base(CreateMessage(type, methodsMissingOnReactiveClient), innerException) { } + + protected InterfaceMissingMethodsException(SerializationInfo info, StreamingContext context) + : base(info, context) { } + + static string CreateMessage(Type type, IEnumerable methods) + { + var methodsFormatted = String.Join("\r\n", methods.Select(m => String.Format(" - {0}", m))); + return "Methods not found on interface {0} which are required:\r\n{1}" + .FormatWithNewLine(type.Name, methodsFormatted); + } + } +} \ No newline at end of file diff --git a/Octokit.Tests.Conventions/Exception/InterfaceNotFoundException.cs b/Octokit.Tests.Conventions/Exception/InterfaceNotFoundException.cs new file mode 100644 index 00000000..3a428331 --- /dev/null +++ b/Octokit.Tests.Conventions/Exception/InterfaceNotFoundException.cs @@ -0,0 +1,25 @@ +using System; +using System.Runtime.Serialization; + +namespace Octokit.Tests.Conventions +{ + public class InterfaceNotFoundException : Exception + { + public InterfaceNotFoundException() { } + + public InterfaceNotFoundException(string type) + : base(CreateMessage(type)) { } + + public InterfaceNotFoundException(string type, Exception innerException) + : base(CreateMessage(type), innerException) { } + + protected InterfaceNotFoundException(SerializationInfo info, StreamingContext context) + : base(info, context) { } + + static string CreateMessage(string type) + { + return String.Format("Could not find the interface {0}. Add this to the Octokit.Reactive project", type); + } + + } +} diff --git a/Octokit.Tests.Conventions/Exception/ParameterCountMismatchException.cs b/Octokit.Tests.Conventions/Exception/ParameterCountMismatchException.cs new file mode 100644 index 00000000..24b165f3 --- /dev/null +++ b/Octokit.Tests.Conventions/Exception/ParameterCountMismatchException.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.Serialization; + +namespace Octokit.Tests.Conventions +{ + public class ParameterCountMismatchException : Exception + { + public ParameterCountMismatchException(MethodInfo method, IEnumerable expected, IEnumerable actual) + : base(CreateMessage(method, expected, actual)) { } + + public ParameterCountMismatchException(MethodInfo method, IEnumerable expected, IEnumerable actual, Exception innerException) + : base(CreateMessage(method, expected, actual), innerException) { } + + protected ParameterCountMismatchException(SerializationInfo info, StreamingContext context) + : base(info, context) { } + + static string CreateMethodSignature(IEnumerable parameters) + { + return String.Join(",", parameters.Select(p => String.Format("{0} {1}", p.ParameterType.Name, p.Name))); + } + + static string CreateMessage(MethodInfo method, IEnumerable expected, IEnumerable actual) + { + var expectedMethodSignature = CreateMethodSignature(expected); + var actualMethodSignature = CreateMethodSignature(actual); + + return String.Format("Method signature for {0}.{1} must be \"({2})\" but is \"({3})\"", method.DeclaringType.Name, method.Name, expectedMethodSignature, actualMethodSignature); + } + } +} \ No newline at end of file diff --git a/Octokit.Tests.Conventions/Exception/ParameterMismatchException.cs b/Octokit.Tests.Conventions/Exception/ParameterMismatchException.cs new file mode 100644 index 00000000..88009960 --- /dev/null +++ b/Octokit.Tests.Conventions/Exception/ParameterMismatchException.cs @@ -0,0 +1,31 @@ +using System; +using System.Reflection; +using System.Runtime.Serialization; + +namespace Octokit.Tests.Conventions +{ + public class ParameterMismatchException : Exception + { + public ParameterMismatchException(MethodInfo method, int position, ParameterInfo expected, ParameterInfo actual) + : base(CreateMessage(method, position, expected, actual)) { } + + public ParameterMismatchException(MethodInfo method, int position, ParameterInfo expected, ParameterInfo actual, Exception innerException) + : base(CreateMessage(method, position, expected, actual), innerException) { } + + protected ParameterMismatchException(SerializationInfo info, StreamingContext context) + : base(info, context) { } + + static string CreateParameterSignature(ParameterInfo parameter) + { + return String.Format("{0} {1}", parameter.ParameterType.Name, parameter.Name); + } + + static string CreateMessage(MethodInfo method, int position, ParameterInfo expected, ParameterInfo actual) + { + var expectedMethodSignature = CreateParameterSignature(expected); + var actualMethodSignature = CreateParameterSignature(actual); + + return String.Format("Parameter {0} for method {1}.{2} must be \"{3}\" but is \"{4}\"", position, method.DeclaringType.Name, method.Name, expectedMethodSignature, actualMethodSignature); + } + } +} \ No newline at end of file diff --git a/Octokit.Tests.Conventions/Exception/ReturnValueMismatchException.cs b/Octokit.Tests.Conventions/Exception/ReturnValueMismatchException.cs new file mode 100644 index 00000000..3bc97e4e --- /dev/null +++ b/Octokit.Tests.Conventions/Exception/ReturnValueMismatchException.cs @@ -0,0 +1,23 @@ +using System; +using System.Reflection; +using System.Runtime.Serialization; + +namespace Octokit.Tests.Conventions +{ + public class ReturnValueMismatchException : Exception + { + public ReturnValueMismatchException(MethodInfo method, Type expected, Type actual) + : base(CreateMessage(method, expected, actual)) { } + + public ReturnValueMismatchException(MethodInfo method, Type expected, Type actual, Exception innerException) + : base(CreateMessage(method, expected, actual), innerException) { } + + protected ReturnValueMismatchException(SerializationInfo info, StreamingContext context) + : base(info, context) { } + + static string CreateMessage(MethodInfo method, Type expected, Type actual) + { + return String.Format("Return value for {0}.{1} must be \"{2}\" but is \"{3}\"", method.DeclaringType.Name, method.Name, expected, actual); + } + } +} \ No newline at end of file diff --git a/Octokit.Tests.Conventions/Octokit.Tests.Conventions.csproj b/Octokit.Tests.Conventions/Octokit.Tests.Conventions.csproj index 7b378297..dd3aa159 100644 --- a/Octokit.Tests.Conventions/Octokit.Tests.Conventions.csproj +++ b/Octokit.Tests.Conventions/Octokit.Tests.Conventions.csproj @@ -50,7 +50,15 @@ + + + + + + + + diff --git a/Octokit.Tests.Conventions/StringExtensions.cs b/Octokit.Tests.Conventions/StringExtensions.cs new file mode 100644 index 00000000..0fdc64a3 --- /dev/null +++ b/Octokit.Tests.Conventions/StringExtensions.cs @@ -0,0 +1,16 @@ +using System; + +namespace Octokit.Tests.Conventions +{ + internal static class StringExtensions + { + public static string FormatWithNewLine(this string s, params object[] args) + { + var template = Environment.NewLine == "\r\n" + ? s + : s.Replace("\r\n", Environment.NewLine); + + return String.Format(template, args); + } + } +} diff --git a/Octokit.Tests.Conventions/SyncObservableClients.cs b/Octokit.Tests.Conventions/SyncObservableClients.cs index 376750ac..2302f0f5 100644 --- a/Octokit.Tests.Conventions/SyncObservableClients.cs +++ b/Octokit.Tests.Conventions/SyncObservableClients.cs @@ -7,29 +7,38 @@ using System.Reflection; using Octokit.Tests.Helpers; using Xunit; using Xunit.Extensions; -using Xunit.Sdk; namespace Octokit.Tests.Conventions { public class SyncObservableClients { - [Fact] - private void CheckObservableClientExample() - { - CheckObservableClients(typeof(ISearchClient)); - } - [Theory] [ClassData(typeof(ClientInterfaces))] - private void CheckObservableClients(Type clientInterface) + public void CheckObservableClients(Type clientInterface) { var observableClient = clientInterface.GetObservableClientInterface(); var mainMethods = clientInterface.GetMethodsOrdered(); var observableMethods = observableClient.GetMethodsOrdered(); var mainNames = Array.ConvertAll(mainMethods, m => m.Name); var observableNames = Array.ConvertAll(observableMethods, m => m.Name); - AssertEx.Empty(observableNames.Except(mainNames), "Extra observable methods"); - AssertEx.Empty(mainNames.Except(observableNames), "Missing observable methods"); + + var methodsMissingOnReactiveClient = mainNames.Except(observableNames); + if (methodsMissingOnReactiveClient.Any()) + { + throw new InterfaceMissingMethodsException(observableClient, methodsMissingOnReactiveClient); + } + + var additionalMethodsOnReactiveClient = observableNames.Except(mainNames); + if (additionalMethodsOnReactiveClient.Any()) + { + throw new InterfaceHasAdditionalMethodsException(observableClient, additionalMethodsOnReactiveClient); + } + + if (mainNames.Count() != observableNames.Count()) + { + throw new InterfaceMethodsMismatchException(observableClient, clientInterface); + } + int index = 0; foreach(var mainMethod in mainMethods) { @@ -52,7 +61,11 @@ namespace Octokit.Tests.Conventions var mainReturnType = mainMethod.ReturnType; var observableReturnType = observableMethod.ReturnType; var expectedType = GetObservableExpectedType(mainReturnType); - Assert.Equal(expectedType, observableReturnType); + + if (expectedType != observableReturnType) + { + throw new ReturnValueMismatchException(observableMethod, expectedType, observableReturnType); + } } private static Type GetObservableExpectedType(Type mainType) @@ -82,16 +95,27 @@ namespace Octokit.Tests.Conventions { var mainParameters = mainMethod.GetParametersOrdered(); var observableParameters = observableMethod.GetParametersOrdered(); - Assert.Equal(mainParameters.Length, observableParameters.Length); + + if (mainParameters.Length != observableParameters.Length) + { + throw new ParameterCountMismatchException(observableMethod, mainParameters, observableParameters); + } + int index = 0; foreach(var mainParameter in mainParameters) { var observableParameter = observableParameters[index]; - Assert.Equal(mainParameter.Name, observableParameter.Name); - var mainType = mainParameter.ParameterType; - var typeInfo = mainType.GetTypeInfo(); + if (mainParameter.Name != observableParameter.Name) + { + throw new ParameterMismatchException(observableMethod, index, mainParameter, observableParameter); + } + + var mainType = mainParameter.ParameterType; var expectedType = GetObservableExpectedType(mainType); - Assert.Equal(expectedType, observableParameter.ParameterType); + if (expectedType != observableParameter.ParameterType) + { + throw new ParameterMismatchException(observableMethod, index, mainParameter, observableParameter); + } index++; } } diff --git a/Octokit.Tests.Conventions/TypeExtensions.cs b/Octokit.Tests.Conventions/TypeExtensions.cs index ea7900a9..4028b26e 100644 --- a/Octokit.Tests.Conventions/TypeExtensions.cs +++ b/Octokit.Tests.Conventions/TypeExtensions.cs @@ -80,7 +80,7 @@ namespace Octokit.Tests.Conventions var observableInterface = observableClient.Assembly.GetType(observableClientName); if(observableInterface == null) { - throw new Exception("Cannot find observable interface "+observableClientName); + throw new InterfaceNotFoundException(observableClientName); } return observableInterface; } diff --git a/Octokit.Tests.Integration/Clients/GistsClientTests.cs b/Octokit.Tests.Integration/Clients/GistsClientTests.cs index 53c96392..3df84b68 100644 --- a/Octokit.Tests.Integration/Clients/GistsClientTests.cs +++ b/Octokit.Tests.Integration/Clients/GistsClientTests.cs @@ -62,7 +62,7 @@ public class GistsClientTests Assert.DoesNotThrow(async () => { await _fixture.Delete(createdGist.Id); }); } - [IntegrationTest] + [IntegrationTest(Skip = "See https://github.com/octokit/octokit.net/issues/424 for an explanation of the issue")] public async Task CanStarAndUnstarAGist() { Assert.DoesNotThrow(async () => { await _fixture.Star(testGistId); }); diff --git a/Octokit.Tests.Integration/Clients/IssuesClientTests.cs b/Octokit.Tests.Integration/Clients/IssuesClientTests.cs index 2a224262..41e2016d 100644 --- a/Octokit.Tests.Integration/Clients/IssuesClientTests.cs +++ b/Octokit.Tests.Integration/Clients/IssuesClientTests.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using Octokit; +using Octokit.Tests.Helpers; using Octokit.Tests.Integration; using Xunit; @@ -159,6 +160,97 @@ public class IssuesClientTests : IDisposable Assert.True(retrieved.Any(i => i.Number == issue2.Number)); } + [IntegrationTest] + public async Task CanFilterByAssigned() + { + var owner = _repository.Owner.Login; + var newIssue1 = new NewIssue("An assigned issue") { Body = "Assigning this to myself", Assignee = owner }; + var newIssue2 = new NewIssue("An unassigned issue") { Body = "A new unassigned issue" }; + await _issuesClient.Create(owner, _repository.Name, newIssue1); + await _issuesClient.Create(owner, _repository.Name, newIssue2); + + var allIssues = await _issuesClient.GetForRepository(owner, _repository.Name, + new RepositoryIssueRequest()); + + Assert.Equal(2, allIssues.Count); + + var assignedIssues = await _issuesClient.GetForRepository(owner, _repository.Name, + new RepositoryIssueRequest { Assignee = owner }); + + Assert.Equal(1, assignedIssues.Count); + Assert.Equal("An assigned issue", assignedIssues[0].Title); + + var unassignedIssues = await _issuesClient.GetForRepository(owner, _repository.Name, + new RepositoryIssueRequest { Assignee = "none" }); + + Assert.Equal(1, unassignedIssues.Count); + Assert.Equal("An unassigned issue", unassignedIssues[0].Title); + } + + [IntegrationTest] + public async Task CanFilterByCreator() + { + var owner = _repository.Owner.Login; + var newIssue1 = new NewIssue("An issue") { Body = "words words words" }; + var newIssue2 = new NewIssue("Another issue") { Body = "some other words" }; + await _issuesClient.Create(owner, _repository.Name, newIssue1); + await _issuesClient.Create(owner, _repository.Name, newIssue2); + + var allIssues = await _issuesClient.GetForRepository(owner, _repository.Name, + new RepositoryIssueRequest()); + + Assert.Equal(2, allIssues.Count); + + var issuesCreatedByOwner = await _issuesClient.GetForRepository(owner, _repository.Name, + new RepositoryIssueRequest { Creator = owner }); + + Assert.Equal(2, issuesCreatedByOwner.Count); + + var issuesCreatedByExternalUser = await _issuesClient.GetForRepository(owner, _repository.Name, + new RepositoryIssueRequest { Creator = "shiftkey" }); + + Assert.Equal(0, issuesCreatedByExternalUser.Count); + } + + [IntegrationTest] + public async Task CanFilterByMentioned() + { + var owner = _repository.Owner.Login; + var newIssue1 = new NewIssue("An issue") { Body = "words words words hello there @shiftkey" }; + var newIssue2 = new NewIssue("Another issue") { Body = "some other words" }; + await _issuesClient.Create(owner, _repository.Name, newIssue1); + await _issuesClient.Create(owner, _repository.Name, newIssue2); + + var allIssues = await _issuesClient.GetForRepository(owner, _repository.Name, + new RepositoryIssueRequest()); + + Assert.Equal(2, allIssues.Count); + + var mentionsWithShiftkey = await _issuesClient.GetForRepository(owner, _repository.Name, + new RepositoryIssueRequest { Mentioned = "shiftkey" }); + + Assert.Equal(1, mentionsWithShiftkey.Count); + + var mentionsWithHaacked = await _issuesClient.GetForRepository(owner, _repository.Name, + new RepositoryIssueRequest { Mentioned = "haacked" }); + + Assert.Equal(0, mentionsWithHaacked.Count); + } + + [IntegrationTest] + public async Task FilteringByInvalidAccountThrowsError() + { + var owner = _repository.Owner.Login; + + AssertEx.Throws( + () => _issuesClient.GetForRepository(owner, _repository.Name, + new RepositoryIssueRequest { Creator = "some-random-account" })); + + AssertEx.Throws( + () => _issuesClient.GetForRepository(owner, _repository.Name, + new RepositoryIssueRequest { Assignee = "some-random-account" })); + } + public void Dispose() { Helper.DeleteRepo(_repository); diff --git a/Octokit.Tests.Integration/Clients/RepositoriesClientTests.cs b/Octokit.Tests.Integration/Clients/RepositoriesClientTests.cs index cceb0cca..e80ca018 100644 --- a/Octokit.Tests.Integration/Clients/RepositoriesClientTests.cs +++ b/Octokit.Tests.Integration/Clients/RepositoriesClientTests.cs @@ -245,7 +245,7 @@ public class RepositoriesClientTests { Name = repoName, AutoInit = true, - GitignoreTemplate = "visualstudio" + GitignoreTemplate = "VisualStudio" }); try diff --git a/Octokit.Tests.Integration/Clients/SearchClientTests.cs b/Octokit.Tests.Integration/Clients/SearchClientTests.cs new file mode 100644 index 00000000..8a4363b5 --- /dev/null +++ b/Octokit.Tests.Integration/Clients/SearchClientTests.cs @@ -0,0 +1,57 @@ +using System.Threading.Tasks; +using Octokit; +using Octokit.Tests.Integration; +using Xunit; + +public class SearchClientTests +{ + readonly IGitHubClient _gitHubClient; + + public SearchClientTests() + { + _gitHubClient = new GitHubClient(new ProductHeaderValue("OctokitTests")) + { + Credentials = Helper.Credentials + }; + } + + [Fact] + public async Task SearchForCSharpRepositories() + { + var request = new SearchRepositoriesRequest("csharp"); + var repos = await _gitHubClient.Search.SearchRepo(request); + + Assert.NotEmpty(repos.Items); + } + + [Fact] + public async Task SearchForGitHub() + { + var request = new SearchUsersRequest("github"); + var repos = await _gitHubClient.Search.SearchUsers(request); + + Assert.NotEmpty(repos.Items); + } + + [Fact] + public async Task SearchForFunctionInCode() + { + var request = new SearchCodeRequest("addClass"); + request.Repo = "jquery/jquery"; + var repos = await _gitHubClient.Search.SearchCode(request); + + Assert.NotEmpty(repos.Items); + } + + [Fact] + public async Task SearchForWordInCode() + { + var request = new SearchIssuesRequest("windows"); + request.SortField = IssueSearchSort.Created; + request.Order = SortDirection.Descending; + + var repos = await _gitHubClient.Search.SearchIssues(request); + + Assert.NotEmpty(repos.Items); + } +} diff --git a/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj b/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj index 274abe0e..24eb70c1 100644 --- a/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj +++ b/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj @@ -71,6 +71,7 @@ + diff --git a/Octokit.Tests/Clients/RepositoryCommentsClientTests.cs b/Octokit.Tests/Clients/RepositoryCommentsClientTests.cs new file mode 100644 index 00000000..a073da85 --- /dev/null +++ b/Octokit.Tests/Clients/RepositoryCommentsClientTests.cs @@ -0,0 +1,222 @@ +using System; +using System.Threading.Tasks; +using NSubstitute; +using Octokit; +using Octokit.Internal; +using Octokit.Tests.Helpers; +using Xunit; + +public class RepositoryCommentsClientTests +{ + public class TheGetMethod + { + [Fact] + public void RequestsCorrectUrl() + { + var connection = Substitute.For(); + var client = new RepositoryCommentsClient(connection); + + client.Get("fake", "repo", 42); + + connection.Received().Get(Arg.Is(u => u.ToString() == "repos/fake/repo/comments/42"), + null); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new RepositoryCommentsClient(Substitute.For()); + + await AssertEx.Throws(async () => await client.Get(null, "name", 1)); + await AssertEx.Throws(async () => await client.Get("", "name", 1)); + await AssertEx.Throws(async () => await client.Get("owner", null, 1)); + await AssertEx.Throws(async () => await client.Get("owner", "", 1)); + } + + } + + public class TheGetForRepositoryMethod + { + [Fact] + public void RequestsCorrectUrl() + { + var connection = Substitute.For(); + var client = new RepositoryCommentsClient(connection); + + client.GetForRepository("fake", "repo"); + + connection.Received().GetAll(Arg.Is(u => u.ToString() == "repos/fake/repo/comments")); + } + + [Fact] + public async Task EnsuresArgumentsNotNull() + { + var connection = Substitute.For(); + var client = new RepositoryCommentsClient(connection); + + await AssertEx.Throws(async () => await client.GetForRepository(null, "name")); + await AssertEx.Throws(async () => await client.GetForRepository("", "name")); + await AssertEx.Throws(async () => await client.GetForRepository("owner", null)); + await AssertEx.Throws(async () => await client.GetForRepository("owner", "")); + } + } + + public class TheGetForCommitMethod + { + [Fact] + public void RequestsCorrectUrl() + { + var connection = Substitute.For(); + var client = new RepositoryCommentsClient(connection); + + client.GetForCommit("fake", "repo", "sha"); + + connection.Received().GetAll(Arg.Is(u => u.ToString() == "repos/fake/repo/commits/sha/comments")); + } + + [Fact] + public async Task EnsuresArgumentsNotNull() + { + var connection = Substitute.For(); + var client = new RepositoryCommentsClient(connection); + + await AssertEx.Throws(async () => await client.GetForCommit(null, "name", "sha")); + await AssertEx.Throws(async () => await client.GetForCommit("", "name", "sha")); + await AssertEx.Throws(async () => await client.GetForCommit("owner", null, "sha")); + await AssertEx.Throws(async () => await client.GetForCommit("owner", "", "sha")); + await AssertEx.Throws(async () => await client.GetForCommit("owner", "name", null)); + await AssertEx.Throws(async () => await client.GetForCommit("owner", "name", "")); + } + } + + public class TheCreateMethod + { + [Fact] + public void PostsToCorrectUrl() + { + NewCommitComment newComment = new NewCommitComment("body"); + + var connection = Substitute.For(); + var client = new RepositoryCommentsClient(connection); + + client.Create("fake", "repo", "sha", newComment); + + connection.Received().Post(Arg.Is(u => u.ToString() == "repos/fake/repo/commits/sha/comments"), Arg.Any()); + } + + [Fact] + public async Task EnsuresArgumentsNotNull() + { + var connection = Substitute.For(); + var client = new RepositoryCommentsClient(connection); + + await AssertEx.Throws(async () => await client.Create(null, "name", "sha", new NewCommitComment("body"))); + await AssertEx.Throws(async () => await client.Create("", "name", "sha", new NewCommitComment("body"))); + await AssertEx.Throws(async () => await client.Create("owner", null, "sha", new NewCommitComment("body"))); + await AssertEx.Throws(async () => await client.Create("owner", "", "sha", new NewCommitComment("body"))); + await AssertEx.Throws(async () => await client.Create("owner", "name", null, new NewCommitComment("body"))); + await AssertEx.Throws(async () => await client.Create("owner", "name", "", new NewCommitComment("body"))); + await AssertEx.Throws(async () => await client.Create("owner", "name", "sha", null)); + } + } + + public class TheUpdateMethod + { + [Fact] + public void PostsToCorrectUrl() + { + const string issueCommentUpdate = "updated comment"; + var connection = Substitute.For(); + var client = new RepositoryCommentsClient(connection); + + client.Update("fake", "repo", 42, issueCommentUpdate); + + connection.Received().Patch(Arg.Is(u => u.ToString() == "repos/fake/repo/comments/42"), Arg.Any()); + } + + [Fact] + public async Task EnsuresArgumentsNotNull() + { + var connection = Substitute.For(); + var client = new RepositoryCommentsClient(connection); + + await AssertEx.Throws(async () => await client.Update(null, "name", 42, "updated comment")); + await AssertEx.Throws(async () => await client.Update("", "name", 42, "updated comment")); + await AssertEx.Throws(async () => await client.Update("owner", null, 42, "updated comment")); + await AssertEx.Throws(async () => await client.Update("owner", "", 42, "updated comment")); + await AssertEx.Throws(async () => await client.Update("owner", "name", 42, null)); + } + } + + public class TheDeleteMethod + { + [Fact] + public void DeletesCorrectUrl() + { + var connection = Substitute.For(); + var client = new RepositoryCommentsClient(connection); + + client.Delete("fake", "repo", 42); + + connection.Received().Delete(Arg.Is(u => u.ToString() == "repos/fake/repo/comments/42")); + } + + [Fact] + public async Task EnsuresArgumentsNotNullOrEmpty() + { + var connection = Substitute.For(); + var client = new RepositoryCommentsClient(connection); + + await AssertEx.Throws(async () => await client.Delete(null, "name", 42)); + await AssertEx.Throws(async () => await client.Delete("", "name", 42)); + await AssertEx.Throws(async () => await client.Delete("owner", null, 42)); + await AssertEx.Throws(async () => await client.Delete("owner", "", 42)); + } + } + + public class TheCtor + { + [Fact] + public void EnsuresArgument() + { + Assert.Throws(() => new RepositoryCommentsClient(null)); + } + } + + [Fact] + public void CanDeserializeCommitComment() + { + const string commitCommentResponseJson = + "{\"html_url\": \"https://github.com/octocat/Hello-World/commit/6dcb09b5b57875f334f61aebed695e2e4193db5e#commitcomment-1\"," + + "\"url\": \"https://api.github.com/repos/octocat/Hello-World/comments/1\"," + + "\"id\": 1," + + "\"body\": \"Me too\"," + + "\"path\": \"file1.txt\"," + + "\"position\": 4," + + "\"line\": 14," + + "\"commit_id\": \"6dcb09b5b57875f334f61aebed695e2e4193db5e\"," + + "\"user\": {" + + "\"login\": \"octocat\"," + + "\"id\": 1," + + "\"avatar_url\": \"https://github.com/images/error/octocat_happy.gif\"," + + "\"gravatar_id\": \"somehexcode\"," + + "\"url\": \"https://api.github.com/users/octocat\"" + + "}," + + "\"created_at\": \"2011-04-14T16:00:49Z\"," + + "\"updated_at\": \"2011-04-14T16:00:49Z\"" + + "}"; + + var response = new ApiResponse + { + Body = commitCommentResponseJson, + ContentType = "application/json" + }; + var jsonPipeline = new JsonHttpPipeline(); + + jsonPipeline.DeserializeResponse(response); + + Assert.NotNull(response.BodyAsObject); + Assert.Equal(commitCommentResponseJson, response.Body); + Assert.Equal(1, response.BodyAsObject.Id); + } +} diff --git a/Octokit.Tests/Clients/SearchClientTests.cs b/Octokit.Tests/Clients/SearchClientTests.cs index 3bfeb225..efd246db 100644 --- a/Octokit.Tests/Clients/SearchClientTests.cs +++ b/Octokit.Tests/Clients/SearchClientTests.cs @@ -30,7 +30,7 @@ namespace Octokit.Tests.Clients var connection = Substitute.For(); var client = new SearchClient(connection); client.SearchUsers(new SearchUsersRequest("something")); - connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/users"), Arg.Any>()); + connection.Received().Get(Arg.Is(u => u.ToString() == "search/users"), Arg.Any>()); } [Fact] @@ -47,7 +47,7 @@ namespace Octokit.Tests.Clients var client = new SearchClient(connection); var request = new SearchUsersRequest("github"); client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github")); } @@ -60,7 +60,7 @@ namespace Octokit.Tests.Clients var request = new SearchUsersRequest("github"); request.AccountType = AccountType.User; client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+type:User")); } @@ -73,7 +73,7 @@ namespace Octokit.Tests.Clients var request = new SearchUsersRequest("github"); request.AccountType = AccountType.Org; client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+type:Org")); } @@ -87,7 +87,7 @@ namespace Octokit.Tests.Clients var request = new SearchUsersRequest("github"); request.In = new[] { UserInQualifier.Fullname }; client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+in:Fullname")); } @@ -100,7 +100,7 @@ namespace Octokit.Tests.Clients var request = new SearchUsersRequest("github"); request.In = new[] { UserInQualifier.Email }; client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+in:Email")); } @@ -113,7 +113,7 @@ namespace Octokit.Tests.Clients var request = new SearchUsersRequest("github"); request.In = new[] { UserInQualifier.Username }; client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+in:Username")); } @@ -126,7 +126,7 @@ namespace Octokit.Tests.Clients var request = new SearchUsersRequest("github"); request.In = new[] { UserInQualifier.Username, UserInQualifier.Fullname, UserInQualifier.Email }; client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+in:Username,Fullname,Email")); } @@ -139,7 +139,7 @@ namespace Octokit.Tests.Clients var request = new SearchUsersRequest("github"); request.Repositories = Range.GreaterThan(5); client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+repos:>5")); } @@ -152,7 +152,7 @@ namespace Octokit.Tests.Clients var request = new SearchUsersRequest("github"); request.Repositories = Range.GreaterThanOrEquals(5); client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+repos:>=5")); } @@ -165,7 +165,7 @@ namespace Octokit.Tests.Clients var request = new SearchUsersRequest("github"); request.Repositories = Range.LessThanOrEquals(5); client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+repos:<=5")); } @@ -178,7 +178,7 @@ namespace Octokit.Tests.Clients var request = new SearchUsersRequest("github"); request.Repositories = Range.LessThan(5); client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+repos:<5")); } @@ -191,7 +191,7 @@ namespace Octokit.Tests.Clients var request = new SearchUsersRequest("github"); request.Location = "San Francisco"; client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+location:San Francisco")); } @@ -205,7 +205,7 @@ namespace Octokit.Tests.Clients var request = new SearchUsersRequest("github"); request.Language = Language.Ruby; client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+language:Ruby")); } @@ -218,7 +218,7 @@ namespace Octokit.Tests.Clients var request = new SearchUsersRequest("github"); request.Created = DateRange.GreaterThan(new DateTime(2014, 1, 1)); client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+created:>2014-01-01")); } @@ -231,7 +231,7 @@ namespace Octokit.Tests.Clients var request = new SearchUsersRequest("github"); request.Created = DateRange.GreaterThanOrEquals(new DateTime(2014, 1, 1)); client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+created:>=2014-01-01")); } @@ -244,7 +244,7 @@ namespace Octokit.Tests.Clients var request = new SearchUsersRequest("github"); request.Created = DateRange.LessThanOrEquals(new DateTime(2014, 1, 1)); client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+created:<=2014-01-01")); } @@ -257,7 +257,7 @@ namespace Octokit.Tests.Clients var request = new SearchUsersRequest("github"); request.Created = DateRange.LessThan(new DateTime(2014, 1, 1)); client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+created:<2014-01-01")); } @@ -270,7 +270,7 @@ namespace Octokit.Tests.Clients var request = new SearchUsersRequest("github"); request.Followers = Range.GreaterThan(1); client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+followers:>1")); } @@ -283,7 +283,7 @@ namespace Octokit.Tests.Clients var request = new SearchUsersRequest("github"); request.Followers = Range.GreaterThanOrEquals(1); client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+followers:>=1")); } @@ -296,7 +296,7 @@ namespace Octokit.Tests.Clients var request = new SearchUsersRequest("github"); request.Followers = Range.LessThan(1); client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+followers:<1")); } @@ -309,7 +309,7 @@ namespace Octokit.Tests.Clients var request = new SearchUsersRequest("github"); request.Followers = Range.LessThanOrEquals(1); client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+followers:<=1")); } @@ -322,7 +322,7 @@ namespace Octokit.Tests.Clients var request = new SearchUsersRequest("github"); request.Followers = new Range(1, 1000); client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+followers:1..1000")); } @@ -336,7 +336,7 @@ namespace Octokit.Tests.Clients var connection = Substitute.For(); var client = new SearchClient(connection); client.SearchRepo(new SearchRepositoriesRequest("something")); - connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); + connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); } [Fact] @@ -354,9 +354,14 @@ namespace Octokit.Tests.Clients var request = new SearchRepositoriesRequest("github"); request.Size = Range.GreaterThan(50); client.SearchRepo(request); +<<<<<<< HEAD connection.Received().GetAll( Arg.Is(u => u.ToString() == "search/repositories"), Arg.Is>(d => d["q"] == "github+size:>50")); +======= + + connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); +>>>>>>> master } [Fact] @@ -368,9 +373,14 @@ namespace Octokit.Tests.Clients var request = new SearchRepositoriesRequest("github"); request.Stars = Range.GreaterThan(500); client.SearchRepo(request); +<<<<<<< HEAD connection.Received().GetAll( Arg.Is(u => u.ToString() == "search/repositories"), Arg.Is>(d => d["q"] == "github+stars:>500")); +======= + + connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); +>>>>>>> master } [Fact] @@ -382,8 +392,13 @@ namespace Octokit.Tests.Clients var request = new SearchRepositoriesRequest("github"); request.Forks = Range.GreaterThan(50); client.SearchRepo(request); +<<<<<<< HEAD connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Is>(d => d["q"] == "github+forks:>500")); +======= + + connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); +>>>>>>> master } [Fact] @@ -395,8 +410,13 @@ namespace Octokit.Tests.Clients var request = new SearchRepositoriesRequest("github"); request.Fork = ForkQualifier.IncludeForks; client.SearchRepo(request); +<<<<<<< HEAD connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Is>(d => d["q"] == "github+fork:IncludeForks")); +======= + + connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); +>>>>>>> master } [Fact] @@ -410,8 +430,12 @@ namespace Octokit.Tests.Clients client.SearchRepo(request); +<<<<<<< HEAD connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Is>(d => d["q"] == "github+language:Ruby")); +======= + connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); +>>>>>>> master } [Fact] @@ -423,8 +447,13 @@ namespace Octokit.Tests.Clients var request = new SearchRepositoriesRequest("github"); request.In = new[] { InQualifier.Description }; client.SearchRepo(request); +<<<<<<< HEAD connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Is>(d => d["q"] == "github+language:Ruby")); +======= + + connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); +>>>>>>> master } [Fact] @@ -436,8 +465,13 @@ namespace Octokit.Tests.Clients var request = new SearchRepositoriesRequest("github"); request.Created = DateRange.GreaterThan(new DateTime(2011, 1, 1)); client.SearchRepo(request); +<<<<<<< HEAD connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Is>(d => d["q"] == "github+created>2011-01-01")); +======= + + connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); +>>>>>>> master } [Fact] @@ -449,8 +483,13 @@ namespace Octokit.Tests.Clients var request = new SearchRepositoriesRequest("github"); request.Updated = DateRange.LessThan(new DateTime(2013, 1, 1)); client.SearchRepo(request); +<<<<<<< HEAD connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Is>(d => d["q"] == "github+updated>2013-01-01")); +======= + + connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); +>>>>>>> master } [Fact] @@ -462,8 +501,13 @@ namespace Octokit.Tests.Clients var request = new SearchRepositoriesRequest("github"); request.User = "rails"; client.SearchRepo(request); +<<<<<<< HEAD connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Is>(d => d["q"] == "github+user:rails")); +======= + + connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); +>>>>>>> master } [Fact] @@ -475,8 +519,13 @@ namespace Octokit.Tests.Clients var request = new SearchRepositoriesRequest("github"); request.SortField = RepoSearchSort.Forks; client.SearchRepo(request); +<<<<<<< HEAD connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Is>(d => d["q"] == "github?sort=Forks")); +======= + + connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); +>>>>>>> master } } @@ -488,7 +537,7 @@ namespace Octokit.Tests.Clients var connection = Substitute.For(); var client = new SearchClient(connection); client.SearchIssues(new SearchIssuesRequest("something")); - connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/issues"), Arg.Any>()); + connection.Received().Get(Arg.Is(u => u.ToString() == "search/issues"), Arg.Any>()); } [Fact] @@ -507,7 +556,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "pub")); } @@ -522,7 +571,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["sort"] == "comments")); @@ -539,7 +588,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["sort"] == "updated" && @@ -555,7 +604,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["order"] == "desc")); @@ -571,7 +620,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+in:comment")); } @@ -586,7 +635,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+in:body,title")); } @@ -601,7 +650,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+type:issue")); } @@ -616,7 +665,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+type:pr")); } @@ -631,7 +680,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+author:alfhenrik")); } @@ -646,7 +695,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+assignee:alfhenrik")); } @@ -661,7 +710,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+mentions:alfhenrik")); } @@ -676,7 +725,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+commenter:alfhenrik")); } @@ -691,7 +740,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+involves:alfhenrik")); } @@ -706,7 +755,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+state:Open")); } @@ -721,7 +770,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+state:Closed")); } @@ -736,7 +785,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+label:bug")); } @@ -751,7 +800,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+label:bug+label:feature")); } @@ -766,7 +815,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+language:CSharp")); } @@ -781,7 +830,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+created:>2014-01-01")); } @@ -796,7 +845,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+created:>=2014-01-01")); } @@ -811,7 +860,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+created:<2014-01-01")); } @@ -826,7 +875,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+created:<=2014-01-01")); } @@ -841,7 +890,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+updated:>2014-01-01")); } @@ -856,7 +905,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+updated:>=2014-01-01")); } @@ -871,7 +920,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+updated:<2014-01-01")); } @@ -886,7 +935,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+updated:<=2014-01-01")); } @@ -901,7 +950,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+comments:>10")); } @@ -916,7 +965,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+comments:>=10")); } @@ -931,7 +980,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+comments:<10")); } @@ -946,7 +995,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+comments:<=10")); } @@ -961,7 +1010,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+comments:10..20")); } @@ -976,7 +1025,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+user:alfhenrik")); } @@ -991,7 +1040,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+repo:octokit.net")); } @@ -1008,7 +1057,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+label:bug+user:alfhenrik+repo:octokit.net")); @@ -1023,7 +1072,7 @@ namespace Octokit.Tests.Clients var connection = Substitute.For(); var client = new SearchClient(connection); client.SearchCode(new SearchCodeRequest("something")); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/code"), Arg.Any>()); } @@ -1044,7 +1093,7 @@ namespace Octokit.Tests.Clients client.SearchCode(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/code"), Arg.Is>(d => d["q"] == "something")); } @@ -1059,7 +1108,7 @@ namespace Octokit.Tests.Clients client.SearchCode(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/code"), Arg.Is>(d => d["sort"] == "indexed")); } @@ -1075,7 +1124,7 @@ namespace Octokit.Tests.Clients client.SearchCode(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/code"), Arg.Is>(d => d["sort"] == "indexed" && @@ -1091,7 +1140,7 @@ namespace Octokit.Tests.Clients client.SearchCode(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/code"), Arg.Is>(d => d["order"] == "desc")); } @@ -1107,7 +1156,7 @@ namespace Octokit.Tests.Clients client.SearchCode(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/code"), Arg.Is>(d => d["q"] == "something+in:file")); } @@ -1122,7 +1171,7 @@ namespace Octokit.Tests.Clients client.SearchCode(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/code"), Arg.Is>(d => d["q"] == "something+in:file,path")); } @@ -1137,7 +1186,7 @@ namespace Octokit.Tests.Clients client.SearchCode(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/code"), Arg.Is>(d => d["q"] == "something+language:C#")); } @@ -1152,7 +1201,7 @@ namespace Octokit.Tests.Clients client.SearchCode(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/code"), Arg.Is>(d => d["q"] == "something+fork:true")); } @@ -1167,7 +1216,7 @@ namespace Octokit.Tests.Clients client.SearchCode(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/code"), Arg.Is>(d => d["q"] == "something+size:>10")); } @@ -1182,7 +1231,7 @@ namespace Octokit.Tests.Clients client.SearchCode(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/code"), Arg.Is>(d => d["q"] == "something+size:>=10")); } @@ -1197,7 +1246,7 @@ namespace Octokit.Tests.Clients client.SearchCode(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/code"), Arg.Is>(d => d["q"] == "something+size:<10")); } @@ -1212,7 +1261,7 @@ namespace Octokit.Tests.Clients client.SearchCode(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/code"), Arg.Is>(d => d["q"] == "something+size:<=10")); } @@ -1227,7 +1276,7 @@ namespace Octokit.Tests.Clients client.SearchCode(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/code"), Arg.Is>(d => d["q"] == "something+size:10..100")); } @@ -1242,7 +1291,7 @@ namespace Octokit.Tests.Clients client.SearchCode(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/code"), Arg.Is>(d => d["q"] == "something+path:app/public")); } @@ -1257,7 +1306,7 @@ namespace Octokit.Tests.Clients client.SearchCode(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/code"), Arg.Is>(d => d["q"] == "something+extension:cs")); } @@ -1272,7 +1321,7 @@ namespace Octokit.Tests.Clients client.SearchCode(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/code"), Arg.Is>(d => d["q"] == "something+user:alfhenrik")); } @@ -1287,7 +1336,7 @@ namespace Octokit.Tests.Clients client.SearchCode(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/code"), Arg.Is>(d => d["q"] == "something+repo:octokit.net")); } @@ -1304,7 +1353,7 @@ namespace Octokit.Tests.Clients client.SearchCode(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/code"), Arg.Is>(d => d["q"] == "something+path:tools/FAKE.core+extension:fs+repo:octokit.net")); diff --git a/Octokit.Tests/Models/DeploymentStatusTests.cs b/Octokit.Tests/Models/DeploymentStatusTests.cs index 5a8b295d..c904d6b8 100644 --- a/Octokit.Tests/Models/DeploymentStatusTests.cs +++ b/Octokit.Tests/Models/DeploymentStatusTests.cs @@ -1,4 +1,5 @@ -using Octokit.Internal; +using System.Linq; +using Octokit.Internal; using System; using System.Collections.Generic; using Xunit; @@ -15,7 +16,7 @@ namespace Octokit.Tests.Models Id = 1, Url = "https://api.github.com/repos/octocat/example/deployments/1/statuses/42", State = DeploymentState.Success, - Payload = "{\"environment\":\"production\"}", + Payload = new Dictionary { { "environment", "production" } }, TargetUrl = "https://gist.github.com/628b2736d379f", CreatedAt = DateTimeOffset.Parse("2012-07-20T01:19:13Z"), UpdatedAt = DateTimeOffset.Parse("2012-07-20T01:19:13Z"), @@ -46,7 +47,7 @@ namespace Octokit.Tests.Models ""type"": ""User"", ""site_admin"": false }, - ""payload"": ""{\""environment\"":\""production\""}"", + ""payload"": { ""environment"":""production""}, ""target_url"": ""https://gist.github.com/628b2736d379f"", ""created_at"": ""2012-07-20T01:19:13Z"", ""updated_at"": ""2012-07-20T01:19:13Z"", @@ -68,10 +69,19 @@ namespace Octokit.Tests.Models if (x == null || y == null) return false; + if (x.Payload.Keys.Any(key => x.Payload[key] != y.Payload[key])) + { + return false; + } + + if (y.Payload.Keys.Any(key => x.Payload[key] != y.Payload[key])) + { + return false; + } + return x.Id == y.Id && x.Url == y.Url && x.State == y.State && - x.Payload == y.Payload && x.TargetUrl == y.TargetUrl && x.CreatedAt == y.CreatedAt && x.UpdatedAt == y.UpdatedAt && diff --git a/Octokit.Tests/Models/DeploymentTests.cs b/Octokit.Tests/Models/DeploymentTests.cs index c408c759..824b3c4e 100644 --- a/Octokit.Tests/Models/DeploymentTests.cs +++ b/Octokit.Tests/Models/DeploymentTests.cs @@ -1,4 +1,5 @@ -using Octokit.Internal; +using System.Linq; +using Octokit.Internal; using System; using System.Collections.Generic; using Xunit; @@ -14,7 +15,7 @@ namespace Octokit.Tests.Models Id = 1, Sha = "topic-branch", Url = "https://api.github.com/repos/octocat/example/deployments/1", - Payload = "{\"environment\":\"production\"}", + Payload = new Dictionary{{ "environment", "production"}}, CreatedAt = DateTimeOffset.Parse("2012-07-20T01:19:13Z"), UpdatedAt = DateTimeOffset.Parse("2012-07-20T01:19:13Z"), Description = "Deploy request from hubot", @@ -45,7 +46,7 @@ namespace Octokit.Tests.Models ""type"": ""User"", ""site_admin"": false }, - ""payload"": ""{\""environment\"":\""production\""}"", + ""payload"": { ""environment"":""production""}, ""created_at"": ""2012-07-20T01:19:13Z"", ""updated_at"": ""2012-07-20T01:19:13Z"", ""description"": ""Deploy request from hubot"", @@ -71,10 +72,19 @@ namespace Octokit.Tests.Models if (x == null || y == null) return false; + if (x.Payload.Keys.Any(key => x.Payload[key] != y.Payload[key])) + { + return false; + } + + if (y.Payload.Keys.Any(key => x.Payload[key] != y.Payload[key])) + { + return false; + } + return x.Id == y.Id && x.Sha == y .Sha && x.Url == y.Url && - x.Payload == y.Payload && x.CreatedAt == y.CreatedAt && x.UpdatedAt == y.UpdatedAt && x.Description == y.Description && diff --git a/Octokit.Tests/Models/PunchCardTests.cs b/Octokit.Tests/Models/PunchCardTests.cs index b83efb34..2e6493ba 100644 --- a/Octokit.Tests/Models/PunchCardTests.cs +++ b/Octokit.Tests/Models/PunchCardTests.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; -using System.Collections.ObjectModel; -using Octokit.Response; +using Octokit; using Octokit.Tests.Helpers; using Xunit; diff --git a/Octokit.Tests/Octokit.Tests.csproj b/Octokit.Tests/Octokit.Tests.csproj index a2dd679f..4a9dd735 100644 --- a/Octokit.Tests/Octokit.Tests.csproj +++ b/Octokit.Tests/Octokit.Tests.csproj @@ -62,6 +62,7 @@ + diff --git a/Octokit.sln.DotSettings b/Octokit.sln.DotSettings index 202116c9..0992e585 100644 --- a/Octokit.sln.DotSettings +++ b/Octokit.sln.DotSettings @@ -258,7 +258,7 @@ II.2.12 <HandlesEvent /> </Patterns> - <Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /> diff --git a/Octokit/Clients/ApiPagination.cs b/Octokit/Clients/ApiPagination.cs index 2eb51484..64d7cd03 100644 --- a/Octokit/Clients/ApiPagination.cs +++ b/Octokit/Clients/ApiPagination.cs @@ -34,7 +34,7 @@ namespace Octokit catch (NotFoundException) { throw new NotFoundException( - new ApiResponse() + new ApiResponse { StatusCode = HttpStatusCode.NotFound, Body = string.Format("{0} was not found.", uri.OriginalString) diff --git a/Octokit/Clients/AuthorizationsClient.cs b/Octokit/Clients/AuthorizationsClient.cs index a991f253..29cb8957 100644 --- a/Octokit/Clients/AuthorizationsClient.cs +++ b/Octokit/Clients/AuthorizationsClient.cs @@ -1,5 +1,4 @@ -using System; -#if NET_45 +#if NET_45 using System.Collections.Generic; #endif using System.Threading.Tasks; diff --git a/Octokit/Clients/DeploymentStatusClient.cs b/Octokit/Clients/DeploymentStatusClient.cs index fea3812c..6c329ef9 100644 --- a/Octokit/Clients/DeploymentStatusClient.cs +++ b/Octokit/Clients/DeploymentStatusClient.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Threading.Tasks; namespace Octokit diff --git a/Octokit/Clients/DeploymentsClient.cs b/Octokit/Clients/DeploymentsClient.cs index 226f3952..bb13b62b 100644 --- a/Octokit/Clients/DeploymentsClient.cs +++ b/Octokit/Clients/DeploymentsClient.cs @@ -53,7 +53,7 @@ namespace Octokit /// The owner of the repository /// The name of the repository /// A instance describing the new deployment to create - /// The created + /// The created public Task Create(string owner, string name, NewDeployment newDeployment) { Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); diff --git a/Octokit/Clients/FeedsClient.cs b/Octokit/Clients/FeedsClient.cs index 0580f5c6..b9d2531b 100644 --- a/Octokit/Clients/FeedsClient.cs +++ b/Octokit/Clients/FeedsClient.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; +using System.Threading.Tasks; namespace Octokit { diff --git a/Octokit/Clients/FollowersClient.cs b/Octokit/Clients/FollowersClient.cs index 76f1851d..8c11aae0 100644 --- a/Octokit/Clients/FollowersClient.cs +++ b/Octokit/Clients/FollowersClient.cs @@ -1,8 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Linq; +using System.Collections.Generic; using System.Net; -using System.Text; using System.Threading.Tasks; namespace Octokit diff --git a/Octokit/Clients/IDeploymentsClient.cs b/Octokit/Clients/IDeploymentsClient.cs index df577ff4..66115d48 100644 --- a/Octokit/Clients/IDeploymentsClient.cs +++ b/Octokit/Clients/IDeploymentsClient.cs @@ -34,7 +34,7 @@ namespace Octokit /// The owner of the repository /// The name of the repository /// A instance describing the new deployment to create - /// The created + /// The created Task Create(string owner, string name, NewDeployment newDeployment); /// diff --git a/Octokit/Clients/IFeedsClient.cs b/Octokit/Clients/IFeedsClient.cs index 245c2245..7bb6ea09 100644 --- a/Octokit/Clients/IFeedsClient.cs +++ b/Octokit/Clients/IFeedsClient.cs @@ -1,5 +1,4 @@ -using System.Collections.Generic; -using System.Threading.Tasks; +using System.Threading.Tasks; namespace Octokit { diff --git a/Octokit/Clients/IGistsClient.cs b/Octokit/Clients/IGistsClient.cs index 9ffdfbb5..c344c576 100644 --- a/Octokit/Clients/IGistsClient.cs +++ b/Octokit/Clients/IGistsClient.cs @@ -151,7 +151,7 @@ namespace Octokit /// http://developer.github.com/v3/gists/#unstar-a-gist /// /// The id of the gist - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Unstar")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Unstar")] Task Unstar(string id); /// diff --git a/Octokit/Clients/IMiscellaneousClient.cs b/Octokit/Clients/IMiscellaneousClient.cs index a8440d68..a7cb34eb 100644 --- a/Octokit/Clients/IMiscellaneousClient.cs +++ b/Octokit/Clients/IMiscellaneousClient.cs @@ -1,5 +1,4 @@ -using System; -#if NET_45 +#if NET_45 using System.Collections.Generic; #endif using System.Diagnostics.CodeAnalysis; diff --git a/Octokit/Clients/IRepoCollaboratorsClient.cs b/Octokit/Clients/IRepoCollaboratorsClient.cs index 3c379ba0..cbe73f60 100644 --- a/Octokit/Clients/IRepoCollaboratorsClient.cs +++ b/Octokit/Clients/IRepoCollaboratorsClient.cs @@ -1,7 +1,6 @@ #if NET_45 using System.Collections.Generic; #endif -using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; namespace Octokit diff --git a/Octokit/Clients/IRepositoriesClient.cs b/Octokit/Clients/IRepositoriesClient.cs index 8c700b5e..2989c610 100644 --- a/Octokit/Clients/IRepositoriesClient.cs +++ b/Octokit/Clients/IRepositoriesClient.cs @@ -22,6 +22,14 @@ namespace Octokit /// IPullRequestsClient PullRequest { get; } + /// + /// Client for managing commit comments in a repository. + /// + /// + /// See the Repository Comments API documentation for more information. + /// + IRepositoryCommentsClient RepositoryComments { get; } + /// /// Creates a new repository for the current user. /// diff --git a/Octokit/Clients/IRepositoryCommentsClient.cs b/Octokit/Clients/IRepositoryCommentsClient.cs new file mode 100644 index 00000000..cd47654b --- /dev/null +++ b/Octokit/Clients/IRepositoryCommentsClient.cs @@ -0,0 +1,78 @@ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Threading.Tasks; + +namespace Octokit +{ + /// + /// A client for GitHub's Repository Comments API. + /// + /// + /// See the Repository Comments API documentation for more information. + /// + public interface IRepositoryCommentsClient + { + /// + /// Gets a single Repository Comment by number. + /// + /// http://developer.github.com/v3/repos/comments/#get-a-single-commit-comment + /// The owner of the repository + /// The name of the repository + /// The comment id + /// + [SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "Get", + Justification = "Method makes a network request")] + Task Get(string owner, string name, int number); + + /// + /// Gets Commit Comments for a repository. + /// + /// http://developer.github.com/v3/repos/comments/#list-commit-comments-for-a-repository + /// The owner of the repository + /// The name of the repository + /// + Task> GetForRepository(string owner, string name); + + /// + /// Gets Commit Comments for a specified Commit. + /// + /// http://developer.github.com/v3/repos/comments/#list-comments-for-a-single-commit + /// The owner of the repository + /// The name of the repository + /// The sha of the commit + /// + Task> GetForCommit(string owner, string name, string sha); + + /// + /// Creates a new Commit Comment for a specified Commit. + /// + /// http://developer.github.com/v3/repos/comments/#create-a-commit-comment + /// The owner of the repository + /// The name of the repository + /// The sha reference of commit + /// The new comment to add to the commit + /// + Task Create(string owner, string name, string sha, NewCommitComment newCommitComment); + + /// + /// Updates a specified Commit Comment. + /// + /// http://developer.github.com/v3/repos/comments/#update-a-commit-comment + /// The owner of the repository + /// The name of the repository + /// The comment number + /// The modified comment + /// + Task Update(string owner, string name, int number, string commentUpdate); + + /// + /// Deletes the specified Commit Comment + /// + /// http://developer.github.com/v3/repos/comments/#delete-a-commit-comment + /// The owner of the repository + /// The name of the repository + /// The comment id + /// + Task Delete(string owner, string name, int number); + } +} diff --git a/Octokit/Clients/ISearchClient.cs b/Octokit/Clients/ISearchClient.cs index 4ad5d09c..2754e1b6 100644 --- a/Octokit/Clients/ISearchClient.cs +++ b/Octokit/Clients/ISearchClient.cs @@ -1,10 +1,7 @@ -#if NET_45 -using System.Collections.Generic; -#endif -using System.Threading.Tasks; +using System.Threading.Tasks; + namespace Octokit { - /// /// GitHub Search Api Client /// @@ -16,7 +13,7 @@ namespace Octokit /// /// /// List of repos - Task> SearchRepo(SearchRepositoriesRequest search); + Task SearchRepo(SearchRepositoriesRequest search); /// /// search users @@ -24,7 +21,7 @@ namespace Octokit /// /// /// List of users - Task> SearchUsers(SearchUsersRequest search); + Task SearchUsers(SearchUsersRequest search); /// /// search issues @@ -32,7 +29,7 @@ namespace Octokit /// /// /// List of issues - Task> SearchIssues(SearchIssuesRequest search); + Task SearchIssues(SearchIssuesRequest search); /// /// search code @@ -40,6 +37,6 @@ namespace Octokit /// /// /// List of files - Task> SearchCode(SearchCodeRequest search); + Task SearchCode(SearchCodeRequest search); } } \ No newline at end of file diff --git a/Octokit/Clients/IStatisticsClient.cs b/Octokit/Clients/IStatisticsClient.cs index 24ce787b..ce5f83e3 100644 --- a/Octokit/Clients/IStatisticsClient.cs +++ b/Octokit/Clients/IStatisticsClient.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using Octokit.Response; namespace Octokit { diff --git a/Octokit/Clients/ITeamsClient.cs b/Octokit/Clients/ITeamsClient.cs index a2abafab..d944bb45 100644 --- a/Octokit/Clients/ITeamsClient.cs +++ b/Octokit/Clients/ITeamsClient.cs @@ -1,7 +1,6 @@ #if NET_45 using System.Collections.Generic; #endif -using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; namespace Octokit diff --git a/Octokit/Clients/IUsersClient.cs b/Octokit/Clients/IUsersClient.cs index 646373c2..607e849b 100644 --- a/Octokit/Clients/IUsersClient.cs +++ b/Octokit/Clients/IUsersClient.cs @@ -1,5 +1,4 @@ -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; namespace Octokit diff --git a/Octokit/Clients/IssueCommentsClient.cs b/Octokit/Clients/IssueCommentsClient.cs index dc0c8846..72bdfbf9 100644 --- a/Octokit/Clients/IssueCommentsClient.cs +++ b/Octokit/Clients/IssueCommentsClient.cs @@ -1,5 +1,4 @@ - -using System.Collections.Generic; +using System.Collections.Generic; using System.Threading.Tasks; namespace Octokit diff --git a/Octokit/Clients/IssuesEventsClient.cs b/Octokit/Clients/IssuesEventsClient.cs index 53de9af9..c476683b 100644 --- a/Octokit/Clients/IssuesEventsClient.cs +++ b/Octokit/Clients/IssuesEventsClient.cs @@ -1,5 +1,4 @@ -using System; -#if NET_45 +#if NET_45 using System.Collections.Generic; #endif using System.Threading.Tasks; diff --git a/Octokit/Clients/IssuesLabelsClient.cs b/Octokit/Clients/IssuesLabelsClient.cs index ef80c7e2..ee640419 100644 --- a/Octokit/Clients/IssuesLabelsClient.cs +++ b/Octokit/Clients/IssuesLabelsClient.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using System.Threading.Tasks; -using System.Linq; namespace Octokit { diff --git a/Octokit/Clients/NotificationsClient.cs b/Octokit/Clients/NotificationsClient.cs index b0bdc5ce..a1b339ea 100644 --- a/Octokit/Clients/NotificationsClient.cs +++ b/Octokit/Clients/NotificationsClient.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Threading.Tasks; namespace Octokit diff --git a/Octokit/Clients/OrganizationsClient.cs b/Octokit/Clients/OrganizationsClient.cs index b04ffb04..d1949bd9 100644 --- a/Octokit/Clients/OrganizationsClient.cs +++ b/Octokit/Clients/OrganizationsClient.cs @@ -1,5 +1,4 @@ -using System; -#if NET_45 +#if NET_45 using System.Collections.Generic; #endif using System.Threading.Tasks; diff --git a/Octokit/Clients/RepoCollaboratorsClient.cs b/Octokit/Clients/RepoCollaboratorsClient.cs index 6b508b98..9cd9304e 100644 --- a/Octokit/Clients/RepoCollaboratorsClient.cs +++ b/Octokit/Clients/RepoCollaboratorsClient.cs @@ -1,7 +1,6 @@ #if NET_45 using System.Collections.Generic; #endif -using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; using System.Net; diff --git a/Octokit/Clients/RepositoriesClient.cs b/Octokit/Clients/RepositoriesClient.cs index 38c3f920..f46e65bd 100644 --- a/Octokit/Clients/RepositoriesClient.cs +++ b/Octokit/Clients/RepositoriesClient.cs @@ -27,6 +27,7 @@ namespace Octokit Statistics = new StatisticsClient(apiConnection); Deployment = new DeploymentsClient(apiConnection); PullRequest = new PullRequestsClient(apiConnection); + RepositoryComments = new RepositoryCommentsClient(apiConnection); } /// @@ -286,6 +287,14 @@ namespace Octokit /// public IPullRequestsClient PullRequest { get; private set; } + /// + /// Client for managing commit comments in a repository. + /// + /// + /// See the Repository Comments API documentation for more information. + /// + public IRepositoryCommentsClient RepositoryComments { get; private set; } + /// /// Gets all the branches for the specified repository. /// diff --git a/Octokit/Clients/RepositoryCommentsClient.cs b/Octokit/Clients/RepositoryCommentsClient.cs new file mode 100644 index 00000000..8f7ccac4 --- /dev/null +++ b/Octokit/Clients/RepositoryCommentsClient.cs @@ -0,0 +1,125 @@ + +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Octokit +{ + /// + /// A client for GitHub's Repository Comments API. + /// + /// + /// See the Repository Comments API documentation for more information. + /// + public class RepositoryCommentsClient : ApiClient, IRepositoryCommentsClient + { + /// + /// Instantiates a new GitHub Repository Comments API client. + /// + /// An API connection + public RepositoryCommentsClient(IApiConnection apiConnection) + : base(apiConnection) + { + } + + /// + /// Gets a single Repository Comment by number. + /// + /// http://developer.github.com/v3/repos/comments/#get-a-single-commit-comment + /// The owner of the repository + /// The name of the repository + /// The comment id + /// + public Task Get(string owner, string name, int number) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + + return ApiConnection.Get(ApiUrls.CommitComment(owner, name, number)); + } + + /// + /// Gets Commit Comments for a repository. + /// + /// http://developer.github.com/v3/repos/comments/#list-commit-comments-for-a-repository + /// The owner of the repository + /// The name of the repository + /// + public Task> GetForRepository(string owner, string name) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + + return ApiConnection.GetAll(ApiUrls.CommitComments(owner, name)); + } + + /// + /// Gets Commit Comments for a specified Commit. + /// + /// http://developer.github.com/v3/repos/comments/#list-comments-for-a-single-commit + /// The owner of the repository + /// The name of the repository + /// The sha of the commit + /// + public Task> GetForCommit(string owner, string name, string sha) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + Ensure.ArgumentNotNullOrEmptyString(sha, "sha"); + + return ApiConnection.GetAll(ApiUrls.CommitComments(owner, name, sha)); + } + + /// + /// Creates a new Commit Comment for a specified Commit. + /// + /// http://developer.github.com/v3/repos/comments/#create-a-commit-comment + /// The owner of the repository + /// The name of the repository + /// The sha reference of commit + /// The new comment to add to the commit + /// + public Task Create(string owner, string name, string sha, NewCommitComment newCommitComment) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + Ensure.ArgumentNotNullOrEmptyString(sha, "sha"); + Ensure.ArgumentNotNull(newCommitComment, "newCommitComment"); + + return ApiConnection.Post(ApiUrls.CommitComments(owner, name, sha), newCommitComment); + } + + /// + /// Updates a specified Commit Comment. + /// + /// http://developer.github.com/v3/repos/comments/#update-a-commit-comment + /// The owner of the repository + /// The name of the repository + /// The comment number + /// The modified comment + /// + public Task Update(string owner, string name, int number, string commentUpdate) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + Ensure.ArgumentNotNull(commentUpdate, "commentUpdate"); + + return ApiConnection.Patch(ApiUrls.CommitComment(owner, name, number), new BodyWrapper(commentUpdate)); + } + + /// + /// Deletes the specified Commit Comment + /// + /// http://developer.github.com/v3/repos/comments/#delete-a-commit-comment + /// The owner of the repository + /// The name of the repository + /// The comment id + /// + public Task Delete(string owner, string name, int number) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + + return ApiConnection.Delete(ApiUrls.CommitComment(owner, name, number)); + } + } +} diff --git a/Octokit/Clients/SearchClient.cs b/Octokit/Clients/SearchClient.cs index 2c079c85..343eab56 100644 --- a/Octokit/Clients/SearchClient.cs +++ b/Octokit/Clients/SearchClient.cs @@ -1,7 +1,5 @@ -#if NET_45 -using System.Collections.Generic; -#endif -using System.Threading.Tasks; +using System.Threading.Tasks; + namespace Octokit { /// @@ -25,10 +23,10 @@ namespace Octokit /// /// /// List of repos - public Task> SearchRepo(SearchRepositoriesRequest search) + public Task SearchRepo(SearchRepositoriesRequest search) { Ensure.ArgumentNotNull(search, "search"); - return ApiConnection.GetAll(ApiUrls.SearchRepositories(), search.Parameters); + return ApiConnection.Get(ApiUrls.SearchRepositories(), search.Parameters); } /// @@ -37,10 +35,10 @@ namespace Octokit /// /// /// List of users - public Task> SearchUsers(SearchUsersRequest search) + public Task SearchUsers(SearchUsersRequest search) { Ensure.ArgumentNotNull(search, "search"); - return ApiConnection.GetAll(ApiUrls.SearchUsers(), search.Parameters); + return ApiConnection.Get(ApiUrls.SearchUsers(), search.Parameters); } /// @@ -49,10 +47,10 @@ namespace Octokit /// /// /// List of issues - public Task> SearchIssues(SearchIssuesRequest search) + public Task SearchIssues(SearchIssuesRequest search) { Ensure.ArgumentNotNull(search, "search"); - return ApiConnection.GetAll(ApiUrls.SearchIssues(), search.Parameters); + return ApiConnection.Get(ApiUrls.SearchIssues(), search.Parameters); } /// @@ -61,10 +59,10 @@ namespace Octokit /// /// /// List of files - public Task> SearchCode(SearchCodeRequest search) + public Task SearchCode(SearchCodeRequest search) { Ensure.ArgumentNotNull(search, "search"); - return ApiConnection.GetAll(ApiUrls.SearchCode(), search.Parameters); + return ApiConnection.Get(ApiUrls.SearchCode(), search.Parameters); } } } \ No newline at end of file diff --git a/Octokit/Clients/SshKeysClient.cs b/Octokit/Clients/SshKeysClient.cs index 48f50feb..64bccf26 100644 --- a/Octokit/Clients/SshKeysClient.cs +++ b/Octokit/Clients/SshKeysClient.cs @@ -1,5 +1,4 @@ -using System; -#if NET_45 +#if NET_45 using System.Collections.Generic; #endif using System.Threading.Tasks; diff --git a/Octokit/Clients/StarredClient.cs b/Octokit/Clients/StarredClient.cs index 5f3b9d27..892ccfde 100644 --- a/Octokit/Clients/StarredClient.cs +++ b/Octokit/Clients/StarredClient.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Net; using System.Threading.Tasks; diff --git a/Octokit/Clients/StatisticsClient.cs b/Octokit/Clients/StatisticsClient.cs index 1b326001..848c8db9 100644 --- a/Octokit/Clients/StatisticsClient.cs +++ b/Octokit/Clients/StatisticsClient.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using Octokit.Response; namespace Octokit { diff --git a/Octokit/Clients/TeamsClient.cs b/Octokit/Clients/TeamsClient.cs index 0af67320..dc347e01 100644 --- a/Octokit/Clients/TeamsClient.cs +++ b/Octokit/Clients/TeamsClient.cs @@ -1,7 +1,6 @@ #if NET_45 using System.Collections.Generic; #endif -using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; namespace Octokit diff --git a/Octokit/Clients/UsersClient.cs b/Octokit/Clients/UsersClient.cs index 494cb84e..54e185d3 100644 --- a/Octokit/Clients/UsersClient.cs +++ b/Octokit/Clients/UsersClient.cs @@ -1,8 +1,4 @@ using System; -#if NET_45 -using System.Collections.Generic; -using System.Collections.ObjectModel; -#endif using System.Threading.Tasks; namespace Octokit diff --git a/Octokit/Clients/WatchedClient.cs b/Octokit/Clients/WatchedClient.cs index 45fcfc89..c564e9d0 100644 --- a/Octokit/Clients/WatchedClient.cs +++ b/Octokit/Clients/WatchedClient.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Net; using System.Threading.Tasks; diff --git a/Octokit/Helpers/ApiUrls.cs b/Octokit/Helpers/ApiUrls.cs index 5956d371..832de1c4 100644 --- a/Octokit/Helpers/ApiUrls.cs +++ b/Octokit/Helpers/ApiUrls.cs @@ -274,6 +274,41 @@ namespace Octokit return "repos/{0}/{1}/issues/comments/{2}".FormatUri(owner, name, number); } + /// + /// Returns the for the specified comment. + /// + /// The owner of the repository + /// The name of the repository + /// The comment number + /// + public static Uri CommitComment(string owner, string name, int number) + { + return "repos/{0}/{1}/comments/{2}".FormatUri(owner, name, number); + } + + /// + /// Returns the for the comments of a specified commit. + /// + /// The owner of the repository + /// The name of the repository + /// The sha of the commit + /// + public static Uri CommitComments(string owner, string name, string sha) + { + return "repos/{0}/{1}/commits/{2}/comments".FormatUri(owner, name, sha); + } + + /// + /// Returns the for the comments of a specified commit. + /// + /// The owner of the repository + /// The name of the repository + /// + public static Uri CommitComments(string owner, string name) + { + return "repos/{0}/{1}/comments".FormatUri(owner, name); + } + /// /// Returns the that returns all of the assignees to which issues may be assigned. /// @@ -974,7 +1009,7 @@ namespace Octokit /// Returns the for repository contributors. /// /// The owner of the repository - /// The name of the repository + /// The name of the repository /// public static Uri RepositoryContributors(string owner, string name) { @@ -985,7 +1020,7 @@ namespace Octokit /// Returns the for repository languages. /// /// The owner of the repository - /// The name of the repository + /// The name of the repository /// public static Uri RepositoryLanguages(string owner, string name) { @@ -996,7 +1031,7 @@ namespace Octokit /// Returns the for repository teams. /// /// The owner of the repository - /// The name of the repository + /// The name of the repository /// public static Uri RepositoryTeams(string owner, string name) { @@ -1007,7 +1042,7 @@ namespace Octokit /// Returns the for repository tags. /// /// The owner of the repository - /// The name of the repository + /// The name of the repository /// public static Uri RepositoryTags(string owner, string name) { @@ -1030,13 +1065,14 @@ namespace Octokit /// Returns the for a repository. /// /// The owner of the repository - /// The name of the repository + /// The name of the repository /// public static Uri Repository(string owner, string name) { return "repos/{0}/{1}".FormatUri(owner, name); } + /// /// Returns the for the Deployments API for the given repository. /// /// Owner of the repository diff --git a/Octokit/Helpers/HttpClientExtensions.cs b/Octokit/Helpers/HttpClientExtensions.cs new file mode 100644 index 00000000..bb62925d --- /dev/null +++ b/Octokit/Helpers/HttpClientExtensions.cs @@ -0,0 +1,17 @@ +using System.Threading; +using System.Threading.Tasks; +using Octokit.Internal; + +namespace Octokit +{ + public static class HttpClientExtensions + { + public static Task> Send(this IHttpClient httpClient, IRequest request) + { + Ensure.ArgumentNotNull(httpClient, "httpClient"); + Ensure.ArgumentNotNull(request, "request"); + + return httpClient.Send(request, CancellationToken.None); + } + } +} \ No newline at end of file diff --git a/Octokit/Models/Request/NewCommitComment.cs b/Octokit/Models/Request/NewCommitComment.cs new file mode 100644 index 00000000..3c312704 --- /dev/null +++ b/Octokit/Models/Request/NewCommitComment.cs @@ -0,0 +1,43 @@ +using System; +using System.Diagnostics; +using System.Globalization; + +namespace Octokit +{ + /// + /// Describes a new commit comment to create via the method. + /// + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class NewCommitComment + { + public NewCommitComment(string body) + { + Ensure.ArgumentNotNull(body, "body"); + + Body = body; + } + + /// + /// The contents of the comment (required) + /// + public string Body { get; private set; } + + /// + /// Relative path of the file to comment on + /// + public string Path { get; set; } + + /// + /// Line index in the diff to comment on + /// + public int? Position { get; set; } + + internal string DebuggerDisplay + { + get + { + return String.Format(CultureInfo.InvariantCulture, "Path: {0}, Body: {1}", Path, Body); + } + } + } +} diff --git a/Octokit/Models/Request/RepositoryIssueRequest.cs b/Octokit/Models/Request/RepositoryIssueRequest.cs index 9ee3cda2..f125afd4 100644 --- a/Octokit/Models/Request/RepositoryIssueRequest.cs +++ b/Octokit/Models/Request/RepositoryIssueRequest.cs @@ -10,5 +10,26 @@ namespace Octokit /// Use the milestone number for a specific milestone. Use the value "none" for issues with any milestones. /// public string Milestone { get; set; } + + /// + /// Filter on the user assigned for the request + /// + /// + /// Specify "none" for issues with no assigned user + /// + public string Assignee { get; set; } + + /// + /// The user that created the issue + /// + /// + /// Specify "none" for issues with no assigned user + /// + public string Creator { get; set; } + + /// + /// A user that’s mentioned in the issue + /// + public string Mentioned { get; set; } } } diff --git a/Octokit/Models/Response/CommitComment.cs b/Octokit/Models/Response/CommitComment.cs new file mode 100644 index 00000000..b961f2a4 --- /dev/null +++ b/Octokit/Models/Response/CommitComment.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Octokit +{ + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class CommitComment + { + /// + /// The issue comment Id. + /// + public int Id { get; set; } + + /// + /// The URL for this repository comment. + /// + public Uri Url { get; set; } + + /// + /// The html URL for this repository comment. + /// + public Uri HtmlUrl { get; set; } + + /// + /// Details about the repository comment. + /// + public string Body { get; set; } + + /// + /// Relative path of the file that was commented on. + /// + public string Path { get; set; } + + /// + /// Line index in the diff that was commented on. + /// + public int Position { get; set; } + + /// + /// The line number in the file that was commented on. + /// + public int Line { get; set; } + + /// + /// The commit + /// + public string CommitId { get; set; } + + /// + /// The user that created the repository comment. + /// + public User User { get; set; } + + /// + /// The date the repository comment was created. + /// + public DateTimeOffset CreatedAt { get; set; } + + /// + /// The date the repository comment was last updated. + /// + public DateTimeOffset? UpdatedAt { get; set; } + + internal string DebuggerDisplay + { + get + { + return String.Format(CultureInfo.InvariantCulture, "Id: {0}, Commit Id: {1}, CreatedAt: {2}", Id, CommitId, CreatedAt); + } + } + } +} diff --git a/Octokit/Models/Response/Deployment.cs b/Octokit/Models/Response/Deployment.cs index dee40fbe..fd99b3b4 100644 --- a/Octokit/Models/Response/Deployment.cs +++ b/Octokit/Models/Response/Deployment.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; @@ -33,7 +34,8 @@ namespace Octokit /// /// JSON payload with extra information about the deployment. /// - public string Payload { get; set; } + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] + public IDictionary Payload { get; set; } /// /// Date and time that the deployment was created. diff --git a/Octokit/Models/Response/DeploymentStatus.cs b/Octokit/Models/Response/DeploymentStatus.cs index c5578cf5..f361074c 100644 --- a/Octokit/Models/Response/DeploymentStatus.cs +++ b/Octokit/Models/Response/DeploymentStatus.cs @@ -1,4 +1,6 @@ using System; +using System.Collections; +using System.Collections.Generic; using System.Diagnostics; using System.Globalization; @@ -7,6 +9,11 @@ namespace Octokit [DebuggerDisplay("{DebuggerDisplay,nq}")] public class DeploymentStatus { + public DeploymentStatus() + { + Payload = new Dictionary(); + } + /// /// Id of this deployment status. /// @@ -30,7 +37,8 @@ namespace Octokit /// /// JSON payload with extra information about the deployment. /// - public string Payload { get; set; } + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] + public IDictionary Payload { get; set; } /// /// The target URL of this deployment status. This URL should contain diff --git a/Octokit/Models/Response/PunchCard.cs b/Octokit/Models/Response/PunchCard.cs index 7180478d..af280163 100644 --- a/Octokit/Models/Response/PunchCard.cs +++ b/Octokit/Models/Response/PunchCard.cs @@ -5,7 +5,7 @@ using System.Diagnostics; using System.Globalization; using System.Linq; -namespace Octokit.Response +namespace Octokit { [DebuggerDisplay("{DebuggerDisplay,nq}")] public class PunchCard diff --git a/Octokit/Models/Response/PunchCardPoint.cs b/Octokit/Models/Response/PunchCardPoint.cs index fe3d3f56..05e832d2 100644 --- a/Octokit/Models/Response/PunchCardPoint.cs +++ b/Octokit/Models/Response/PunchCardPoint.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Globalization; -namespace Octokit.Response +namespace Octokit { [DebuggerDisplay("{DebuggerDisplay,nq}")] public class PunchCardPoint diff --git a/Octokit/Models/Response/SearchCodeResult.cs b/Octokit/Models/Response/SearchCodeResult.cs new file mode 100644 index 00000000..3ca65183 --- /dev/null +++ b/Octokit/Models/Response/SearchCodeResult.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; + +namespace Octokit +{ + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class SearchCodeResult + { + public int TotalCount { get; set; } + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] + public IReadOnlyList Items { get; set; } + + internal string DebuggerDisplay + { + get + { + return String.Format(CultureInfo.InvariantCulture, "TotalCount: {0}", TotalCount); + } + } + } +} \ No newline at end of file diff --git a/Octokit/Models/Response/SearchIssuesResult.cs b/Octokit/Models/Response/SearchIssuesResult.cs new file mode 100644 index 00000000..651f5404 --- /dev/null +++ b/Octokit/Models/Response/SearchIssuesResult.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; + +namespace Octokit +{ + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class SearchIssuesResult + { + public int TotalCount { get; set; } + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] + public IReadOnlyList Items { get; set; } + + internal string DebuggerDisplay + { + get + { + return String.Format(CultureInfo.InvariantCulture, "TotalCount: {0}", TotalCount); + } + } + } +} \ No newline at end of file diff --git a/Octokit/Models/Response/SearchRepositoryResult.cs b/Octokit/Models/Response/SearchRepositoryResult.cs new file mode 100644 index 00000000..6ee9bc07 --- /dev/null +++ b/Octokit/Models/Response/SearchRepositoryResult.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; + +namespace Octokit +{ + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class SearchRepositoryResult + { + public int TotalCount { get; set; } + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] + public IReadOnlyList Items { get; set; } + + internal string DebuggerDisplay + { + get + { + return String.Format(CultureInfo.InvariantCulture, "TotalCount: {0}", TotalCount); + } + } + } +} diff --git a/Octokit/Models/Response/SearchUsersResult.cs b/Octokit/Models/Response/SearchUsersResult.cs new file mode 100644 index 00000000..4e5a4f9c --- /dev/null +++ b/Octokit/Models/Response/SearchUsersResult.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; + +namespace Octokit +{ + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class SearchUsersResult + { + public int TotalCount { get; set; } + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] + public IReadOnlyList Items { get; set; } + + internal string DebuggerDisplay + { + get + { + return String.Format(CultureInfo.InvariantCulture, "TotalCount: {0}", TotalCount); + } + } + } +} \ No newline at end of file diff --git a/Octokit/Octokit-Mono.csproj b/Octokit/Octokit-Mono.csproj index a0dbce03..9fbca9f5 100644 --- a/Octokit/Octokit-Mono.csproj +++ b/Octokit/Octokit-Mono.csproj @@ -300,7 +300,16 @@ + + + + + + + + + \ No newline at end of file diff --git a/Octokit/Octokit-MonoAndroid.csproj b/Octokit/Octokit-MonoAndroid.csproj index 9edf8da4..cb66cd52 100644 --- a/Octokit/Octokit-MonoAndroid.csproj +++ b/Octokit/Octokit-MonoAndroid.csproj @@ -308,10 +308,19 @@ + + + + + + + + + \ No newline at end of file diff --git a/Octokit/Octokit-Monotouch.csproj b/Octokit/Octokit-Monotouch.csproj index ed79d019..5a1d9522 100644 --- a/Octokit/Octokit-Monotouch.csproj +++ b/Octokit/Octokit-Monotouch.csproj @@ -303,10 +303,19 @@ + + + + + + + + + \ No newline at end of file diff --git a/Octokit/Octokit-netcore45.csproj b/Octokit/Octokit-netcore45.csproj index 5757e82d..7130e509 100644 --- a/Octokit/Octokit-netcore45.csproj +++ b/Octokit/Octokit-netcore45.csproj @@ -13,6 +13,7 @@ Octokit v4.5 512 + en-US true @@ -243,6 +244,7 @@ + @@ -298,7 +300,15 @@ + + + + + + + + diff --git a/Octokit/Octokit.csproj b/Octokit/Octokit.csproj index 69ecd508..4cffe396 100644 --- a/Octokit/Octokit.csproj +++ b/Octokit/Octokit.csproj @@ -12,6 +12,7 @@ v4.5 512 + en-US true @@ -19,7 +20,7 @@ false obj\Debug\Net45 bin\Debug\Net45 - TRACE;DEBUG;CODE_ANALYSIS;CODE_ANALYSIS;SIMPLE_JSON_OBJARRAYINTERNAL;SIMPLE_JSON_INTERNAL;NET_45 + TRACE;DEBUG;CODE_ANALYSIS;SIMPLE_JSON_OBJARRAYINTERNAL;SIMPLE_JSON_INTERNAL;NET_45;SIMPLE_JSON_READONLY_COLLECTIONS prompt 4 true @@ -33,7 +34,7 @@ true obj\Release\Net45 bin\Release\Net45\ - TRACE;CODE_ANALYSIS;CODE_ANALYSIS;SIMPLE_JSON_OBJARRAYINTERNAL;SIMPLE_JSON_INTERNAL;NET_45 + TRACE;CODE_ANALYSIS;SIMPLE_JSON_OBJARRAYINTERNAL;SIMPLE_JSON_INTERNAL;NET_45;SIMPLE_JSON_READONLY_COLLECTIONS prompt 4 false @@ -53,11 +54,16 @@ Properties\SolutionInfo.cs + + + + + @@ -135,6 +141,10 @@ + + + + diff --git a/Octokit/SimpleJson.cs b/Octokit/SimpleJson.cs index b8300f34..36a1688f 100644 --- a/Octokit/SimpleJson.cs +++ b/Octokit/SimpleJson.cs @@ -17,7 +17,7 @@ // https://github.com/facebook-csharp-sdk/simple-json //----------------------------------------------------------------------- -// VERSION: 0.30.0 +// VERSION: 0.34.0 // NOTE: uncomment the following line to make SimpleJson class internal. //#define SIMPLE_JSON_INTERNAL @@ -31,6 +31,9 @@ // NOTE: uncomment the following line to enable DataContract support. //#define SIMPLE_JSON_DATACONTRACT +// NOTE: uncomment the following line to enable IReadOnlyCollection and IReadOnlyList support. +//#define SIMPLE_JSON_READONLY_COLLECTIONS + // NOTE: uncomment the following line to disable linq expressions/compiled lambda (better performance) instead of method.invoke(). // define if you are using .net framework <= 3.0 or < WP7.5 //#define SIMPLE_JSON_NO_LINQ_EXPRESSION @@ -51,7 +54,6 @@ using System; using System.CodeDom.Compiler; using System.Collections; using System.Collections.Generic; -using System.Linq; #if !SIMPLE_JSON_NO_LINQ_EXPRESSION using System.Linq.Expressions; #endif @@ -513,6 +515,22 @@ namespace Octokit private const int TOKEN_NULL = 11; private const int BUILDER_CAPACITY = 2000; + private static readonly char[] EscapeTable; + private static readonly char[] EscapeCharacters = new char[] { '"', '\\', '\b', '\f', '\n', '\r', '\t' }; + private static readonly string EscapeCharactersString = new string(EscapeCharacters); + + static SimpleJson() + { + EscapeTable = new char[93]; + EscapeTable['"'] = '"'; + EscapeTable['\\'] = '\\'; + EscapeTable['\b'] = 'b'; + EscapeTable['\f'] = 'f'; + EscapeTable['\n'] = 'n'; + EscapeTable['\r'] = 'r'; + EscapeTable['\t'] = 't'; + } + /// /// Parses the string json into a value /// @@ -1074,29 +1092,50 @@ namespace Octokit static bool SerializeString(string aString, StringBuilder builder) { - builder.Append("\""); + // Happy path if there's nothing to be escaped. IndexOfAny is highly optimized (and unmanaged) + if (aString.IndexOfAny(EscapeCharacters) == -1) + { + builder.Append('"'); + builder.Append(aString); + builder.Append('"'); + + return true; + } + + builder.Append('"'); + int safeCharacterCount = 0; char[] charArray = aString.ToCharArray(); + for (int i = 0; i < charArray.Length; i++) { char c = charArray[i]; - if (c == '"') - builder.Append("\\\""); - else if (c == '\\') - builder.Append("\\\\"); - else if (c == '\b') - builder.Append("\\b"); - else if (c == '\f') - builder.Append("\\f"); - else if (c == '\n') - builder.Append("\\n"); - else if (c == '\r') - builder.Append("\\r"); - else if (c == '\t') - builder.Append("\\t"); + + // Non ascii characters are fine, buffer them up and send them to the builder + // in larger chunks if possible. The escape table is a 1:1 translation table + // with \0 [default(char)] denoting a safe character. + if (c >= EscapeTable.Length || EscapeTable[c] == default(char)) + { + safeCharacterCount++; + } else - builder.Append(c); + { + if (safeCharacterCount > 0) + { + builder.Append(charArray, i - safeCharacterCount, safeCharacterCount); + safeCharacterCount = 0; + } + + builder.Append('\\'); + builder.Append(EscapeTable[c]); + } } - builder.Append("\""); + + if (safeCharacterCount > 0) + { + builder.Append(charArray, charArray.Length - safeCharacterCount, safeCharacterCount); + } + + builder.Append('"'); return true; } @@ -1647,7 +1686,14 @@ namespace Octokit Type genericDefinition = type.GetGenericTypeDefinition(); - return (genericDefinition == typeof(IList<>) || genericDefinition == typeof(ICollection<>) || genericDefinition == typeof(IEnumerable<>)); + return (genericDefinition == typeof(IList<>) + || genericDefinition == typeof(ICollection<>) + || genericDefinition == typeof(IEnumerable<>) +#if SIMPLE_JSON_READONLY_COLLECTIONS + || genericDefinition == typeof(IReadOnlyCollection<>) + || genericDefinition == typeof(IReadOnlyList<>) +#endif + ); } public static bool IsAssignableFrom(Type type1, Type type2) @@ -1727,13 +1773,17 @@ namespace Octokit public static IEnumerable GetProperties(Type type) { #if SIMPLE_JSON_TYPEINFO - var info = type.GetTypeInfo(); + var typeInfo = type.GetTypeInfo(); + var properties = typeInfo.DeclaredProperties; - var baseProperties = info.BaseType != null && info.BaseType != typeof(Object) - ? GetProperties(info.BaseType) - : new PropertyInfo[0]; + if (typeInfo.BaseType == null) + return properties; - return info.DeclaredProperties.Concat(baseProperties); + if (typeInfo.BaseType.FullName == typeof (Object).FullName) + return properties; + + var baseProperties = GetProperties(typeInfo.BaseType); + return System.Linq.Enumerable.Concat(properties, baseProperties); #else return type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); #endif diff --git a/Octokit/packages.config b/Octokit/packages.config index fe57a08e..3771b8bf 100644 --- a/Octokit/packages.config +++ b/Octokit/packages.config @@ -6,5 +6,5 @@ - + \ No newline at end of file diff --git a/ReleaseNotes.md b/ReleaseNotes.md index 44aaa3ef..b5ff3913 100644 --- a/ReleaseNotes.md +++ b/ReleaseNotes.md @@ -1,3 +1,14 @@ +### New in 0.2.2 (Released 2014/03/06) +* Task-based and Observable-based APIs are now consistent - #361 #376 #378 via @shiftkey and @ammeep +* "_links" JSON field serialization convention fix - #387 via @haacked +* Added Feeds client - #386 via @sgwill +* Added support for creating Gists - #391 via @Therzok and @rgmills +* Make readonly collections truly readonly - #394 #399 via @Haacked +* Internalize ProductHeaderValue - #406 via @trsneed +* HttpClient.Send without cancellation token - #410 via @ammeep +* Implement Repository Comments API - #413 via @Haacked @wfroese +* Corrected Search response to match API - #412 #417 #419 #420 via @shiftkey + ### New in 0.2.1 (Released 2014/02/19) * Reverted the dependency on Reactive Extensions 2.2.2 which introduced breaking changes diff --git a/SolutionInfo.cs b/SolutionInfo.cs index ccd2aa84..da6155a7 100644 --- a/SolutionInfo.cs +++ b/SolutionInfo.cs @@ -3,11 +3,11 @@ using System.Reflection; using System.Runtime.InteropServices; [assembly: AssemblyProductAttribute("Octokit")] -[assembly: AssemblyVersionAttribute("0.2.1")] -[assembly: AssemblyFileVersionAttribute("0.2.1")] +[assembly: AssemblyVersionAttribute("0.2.2")] +[assembly: AssemblyFileVersionAttribute("0.2.2")] [assembly: ComVisibleAttribute(false)] namespace System { internal static class AssemblyVersionInformation { - internal const string Version = "0.2.1"; + internal const string Version = "0.2.2"; } } diff --git a/packages/SimpleJson.0.30.0/SimpleJson.0.30.0.nupkg b/packages/SimpleJson.0.30.0/SimpleJson.0.30.0.nupkg deleted file mode 100644 index b35a0dda..00000000 Binary files a/packages/SimpleJson.0.30.0/SimpleJson.0.30.0.nupkg and /dev/null differ diff --git a/packages/SimpleJson.0.30.0/SimpleJson.0.30.0.nuspec b/packages/SimpleJson.0.30.0/SimpleJson.0.30.0.nuspec deleted file mode 100644 index bfc5f00d..00000000 --- a/packages/SimpleJson.0.30.0/SimpleJson.0.30.0.nuspec +++ /dev/null @@ -1,15 +0,0 @@ - - - - SimpleJson - 0.30.0 - Jim Zimmerman, Nathan Totten, Prabir Shrestha - Jim Zimmerman, Nathan Totten, Prabir Shrestha - https://raw.github.com/facebook-csharp-sdk/simple-json/master/LICENSE.txt - https://raw.github.com/facebook-csharp-sdk/simple-json - false - Super lightweight Json library for .NET 2.0+/SL4+/WP7/WindowsStore Apps/Portable Class Libraries along with dynamic and DataContract support - en-US - json - - \ No newline at end of file diff --git a/packages/SimpleJson.0.34.0/SimpleJson.0.34.0.nupkg b/packages/SimpleJson.0.34.0/SimpleJson.0.34.0.nupkg new file mode 100644 index 00000000..3dbe14c4 Binary files /dev/null and b/packages/SimpleJson.0.34.0/SimpleJson.0.34.0.nupkg differ diff --git a/packages/SimpleJson.0.30.0/SimpleJson.psm1 b/packages/SimpleJson.0.34.0/SimpleJson.psm1 similarity index 97% rename from packages/SimpleJson.0.30.0/SimpleJson.psm1 rename to packages/SimpleJson.0.34.0/SimpleJson.psm1 index d34066dd..7cfbf98b 100644 --- a/packages/SimpleJson.0.30.0/SimpleJson.psm1 +++ b/packages/SimpleJson.0.34.0/SimpleJson.psm1 @@ -1,6 +1,6 @@ # SimpleJson https://github.com/facebook-csharp-sdk/simple-json # License: MIT License -# Version: 0.30.0 +# Version: 0.34.0 function ConvertFrom-Json { @@ -87,7 +87,7 @@ $source = @" // https://github.com/facebook-csharp-sdk/simple-json //----------------------------------------------------------------------- -// VERSION: 0.30.0 +// VERSION: 0.34.0 // NOTE: uncomment the following line to make SimpleJson class internal. //#define SIMPLE_JSON_INTERNAL @@ -101,6 +101,9 @@ $source = @" // NOTE: uncomment the following line to enable DataContract support. //#define SIMPLE_JSON_DATACONTRACT +// NOTE: uncomment the following line to enable IReadOnlyCollection and IReadOnlyList support. +//#define SIMPLE_JSON_READONLY_COLLECTIONS + // NOTE: uncomment the following line to disable linq expressions/compiled lambda (better performance) instead of method.invoke(). // define if you are using .net framework <= 3.0 or < WP7.5 //#define SIMPLE_JSON_NO_LINQ_EXPRESSION @@ -582,6 +585,22 @@ namespace SimpleJson private const int TOKEN_NULL = 11; private const int BUILDER_CAPACITY = 2000; + private static readonly char[] EscapeTable; + private static readonly char[] EscapeCharacters = new char[] { '"', '\\', '\b', '\f', '\n', '\r', '\t' }; + private static readonly string EscapeCharactersString = new string(EscapeCharacters); + + static SimpleJson() + { + EscapeTable = new char[93]; + EscapeTable['"'] = '"'; + EscapeTable['\\'] = '\\'; + EscapeTable['\b'] = 'b'; + EscapeTable['\f'] = 'f'; + EscapeTable['\n'] = 'n'; + EscapeTable['\r'] = 'r'; + EscapeTable['\t'] = 't'; + } + /// /// Parses the string json into a value /// @@ -1143,29 +1162,50 @@ namespace SimpleJson static bool SerializeString(string aString, StringBuilder builder) { - builder.Append("\""); + // Happy path if there's nothing to be escaped. IndexOfAny is highly optimized (and unmanaged) + if (aString.IndexOfAny(EscapeCharacters) == -1) + { + builder.Append('"'); + builder.Append(aString); + builder.Append('"'); + + return true; + } + + builder.Append('"'); + int safeCharacterCount = 0; char[] charArray = aString.ToCharArray(); + for (int i = 0; i < charArray.Length; i++) { char c = charArray[i]; - if (c == '"') - builder.Append("\\\""); - else if (c == '\\') - builder.Append("\\\\"); - else if (c == '\b') - builder.Append("\\b"); - else if (c == '\f') - builder.Append("\\f"); - else if (c == '\n') - builder.Append("\\n"); - else if (c == '\r') - builder.Append("\\r"); - else if (c == '\t') - builder.Append("\\t"); + + // Non ascii characters are fine, buffer them up and send them to the builder + // in larger chunks if possible. The escape table is a 1:1 translation table + // with \0 [default(char)] denoting a safe character. + if (c >= EscapeTable.Length || EscapeTable[c] == default(char)) + { + safeCharacterCount++; + } else - builder.Append(c); + { + if (safeCharacterCount > 0) + { + builder.Append(charArray, i - safeCharacterCount, safeCharacterCount); + safeCharacterCount = 0; + } + + builder.Append('\\'); + builder.Append(EscapeTable[c]); + } } - builder.Append("\""); + + if (safeCharacterCount > 0) + { + builder.Append(charArray, charArray.Length - safeCharacterCount, safeCharacterCount); + } + + builder.Append('"'); return true; } @@ -1716,7 +1756,14 @@ namespace SimpleJson Type genericDefinition = type.GetGenericTypeDefinition(); - return (genericDefinition == typeof(IList<>) || genericDefinition == typeof(ICollection<>) || genericDefinition == typeof(IEnumerable<>)); + return (genericDefinition == typeof(IList<>) + || genericDefinition == typeof(ICollection<>) + || genericDefinition == typeof(IEnumerable<>) +#if SIMPLE_JSON_READONLY_COLLECTIONS + || genericDefinition == typeof(IReadOnlyCollection<>) + || genericDefinition == typeof(IReadOnlyList<>) +#endif + ); } public static bool IsAssignableFrom(Type type1, Type type2) diff --git a/packages/SimpleJson.0.30.0/content/SimpleJson.cs.pp b/packages/SimpleJson.0.34.0/content/SimpleJson.cs.pp similarity index 97% rename from packages/SimpleJson.0.30.0/content/SimpleJson.cs.pp rename to packages/SimpleJson.0.34.0/content/SimpleJson.cs.pp index 47dbe189..b7c86642 100644 --- a/packages/SimpleJson.0.30.0/content/SimpleJson.cs.pp +++ b/packages/SimpleJson.0.34.0/content/SimpleJson.cs.pp @@ -17,7 +17,7 @@ // https://github.com/facebook-csharp-sdk/simple-json //----------------------------------------------------------------------- -// VERSION: 0.30.0 +// VERSION: 0.34.0 // NOTE: uncomment the following line to make SimpleJson class internal. //#define SIMPLE_JSON_INTERNAL @@ -31,6 +31,9 @@ // NOTE: uncomment the following line to enable DataContract support. //#define SIMPLE_JSON_DATACONTRACT +// NOTE: uncomment the following line to enable IReadOnlyCollection and IReadOnlyList support. +//#define SIMPLE_JSON_READONLY_COLLECTIONS + // NOTE: uncomment the following line to disable linq expressions/compiled lambda (better performance) instead of method.invoke(). // define if you are using .net framework <= 3.0 or < WP7.5 //#define SIMPLE_JSON_NO_LINQ_EXPRESSION @@ -512,6 +515,22 @@ namespace $rootnamespace$ private const int TOKEN_NULL = 11; private const int BUILDER_CAPACITY = 2000; + private static readonly char[] EscapeTable; + private static readonly char[] EscapeCharacters = new char[] { '"', '\\', '\b', '\f', '\n', '\r', '\t' }; + private static readonly string EscapeCharactersString = new string(EscapeCharacters); + + static SimpleJson() + { + EscapeTable = new char[93]; + EscapeTable['"'] = '"'; + EscapeTable['\\'] = '\\'; + EscapeTable['\b'] = 'b'; + EscapeTable['\f'] = 'f'; + EscapeTable['\n'] = 'n'; + EscapeTable['\r'] = 'r'; + EscapeTable['\t'] = 't'; + } + /// /// Parses the string json into a value /// @@ -1073,29 +1092,50 @@ namespace $rootnamespace$ static bool SerializeString(string aString, StringBuilder builder) { - builder.Append("\""); + // Happy path if there's nothing to be escaped. IndexOfAny is highly optimized (and unmanaged) + if (aString.IndexOfAny(EscapeCharacters) == -1) + { + builder.Append('"'); + builder.Append(aString); + builder.Append('"'); + + return true; + } + + builder.Append('"'); + int safeCharacterCount = 0; char[] charArray = aString.ToCharArray(); + for (int i = 0; i < charArray.Length; i++) { char c = charArray[i]; - if (c == '"') - builder.Append("\\\""); - else if (c == '\\') - builder.Append("\\\\"); - else if (c == '\b') - builder.Append("\\b"); - else if (c == '\f') - builder.Append("\\f"); - else if (c == '\n') - builder.Append("\\n"); - else if (c == '\r') - builder.Append("\\r"); - else if (c == '\t') - builder.Append("\\t"); + + // Non ascii characters are fine, buffer them up and send them to the builder + // in larger chunks if possible. The escape table is a 1:1 translation table + // with \0 [default(char)] denoting a safe character. + if (c >= EscapeTable.Length || EscapeTable[c] == default(char)) + { + safeCharacterCount++; + } else - builder.Append(c); + { + if (safeCharacterCount > 0) + { + builder.Append(charArray, i - safeCharacterCount, safeCharacterCount); + safeCharacterCount = 0; + } + + builder.Append('\\'); + builder.Append(EscapeTable[c]); + } } - builder.Append("\""); + + if (safeCharacterCount > 0) + { + builder.Append(charArray, charArray.Length - safeCharacterCount, safeCharacterCount); + } + + builder.Append('"'); return true; } @@ -1646,7 +1686,14 @@ namespace $rootnamespace$ Type genericDefinition = type.GetGenericTypeDefinition(); - return (genericDefinition == typeof(IList<>) || genericDefinition == typeof(ICollection<>) || genericDefinition == typeof(IEnumerable<>)); + return (genericDefinition == typeof(IList<>) + || genericDefinition == typeof(ICollection<>) + || genericDefinition == typeof(IEnumerable<>) +#if SIMPLE_JSON_READONLY_COLLECTIONS + || genericDefinition == typeof(IReadOnlyCollection<>) + || genericDefinition == typeof(IReadOnlyList<>) +#endif + ); } public static bool IsAssignableFrom(Type type1, Type type2) diff --git a/script/cibuild.ps1 b/script/cibuild.ps1 index 7c42cb11..27d82ad0 100644 --- a/script/cibuild.ps1 +++ b/script/cibuild.ps1 @@ -100,6 +100,14 @@ if ($LastExitCode -ne 0) { Dump-Error($output) } + +Write-Output "Running convention tests..." +Write-Output "" +$output = & .\tools\FAKE.Core\tools\Fake.exe "build.fsx" "target=ConventionTests" "buildMode=Release" +if ($LastExitCode -ne 0) { + Dump-Error($output) +} + Write-Output "Running integration tests..." Write-Output "" $output = & .\tools\FAKE.Core\tools\Fake.exe "build.fsx" "target=IntegrationTests" "buildMode=Release"