From ce2884998b404b32a44734734ade6b68bb44be2b Mon Sep 17 00:00:00 2001 From: Haroon Date: Sat, 1 Mar 2014 15:39:52 +0000 Subject: [PATCH 01/36] updated base class --- Octokit.Tests/Clients/SearchClientTests.cs | 2 +- .../Request/SearchRepositoriesRequest.cs | 57 +++---------------- 2 files changed, 10 insertions(+), 49 deletions(-) diff --git a/Octokit.Tests/Clients/SearchClientTests.cs b/Octokit.Tests/Clients/SearchClientTests.cs index e081161f..15d1d10f 100644 --- a/Octokit.Tests/Clients/SearchClientTests.cs +++ b/Octokit.Tests/Clients/SearchClientTests.cs @@ -478,7 +478,7 @@ namespace Octokit.Tests.Clients var client = new SearchClient(connection); //get repos where the Description contains rails and user/org is 'github' var request = new SearchRepositoriesRequest("rails"); - request.Sort = RepoSearchSort.Forks; + request.SortField = RepoSearchSort.Forks; client.SearchRepo(request); diff --git a/Octokit/Models/Request/SearchRepositoriesRequest.cs b/Octokit/Models/Request/SearchRepositoriesRequest.cs index e78644bf..af7a9e05 100644 --- a/Octokit/Models/Request/SearchRepositoriesRequest.cs +++ b/Octokit/Models/Request/SearchRepositoriesRequest.cs @@ -13,43 +13,23 @@ namespace Octokit /// http://developer.github.com/v3/search/#search-repositories /// [DebuggerDisplay("{DebuggerDisplay,nq}")] - public class SearchRepositoriesRequest + public class SearchRepositoriesRequest : BaseSearchRequest { - public SearchRepositoriesRequest(string term) + public SearchRepositoriesRequest(string term) : base(term) { - Term = term; - Page = 1; - PerPage = 100; Fork = ForkQualifier.ExcludeForks; Order = SortDirection.Descending; } - /// - /// The search terms. This can be any combination of the supported repository search parameters: - /// http://developer.github.com/v3/search/#search-repositories - /// - public string Term { get; set; } - /// /// For https://help.github.com/articles/searching-repositories#sorting /// Optional Sort field. One of stars, forks, or updated. If not provided, results are sorted by best match. /// - public RepoSearchSort? Sort { get; set; } - - /// - /// Sort order one of asc or desc - the default is desc. - /// - public SortDirection Order { get; set; } - - /// - /// Page of paginated results - /// - public int Page { get; set; } - - /// - /// Number of items per page - /// - public int PerPage { get; set; } + public RepoSearchSort? SortField { get; set; } + public override string Sort + { + get { return SortField.ToParameter(); } + } private IEnumerable _inQualifier; @@ -120,7 +100,7 @@ namespace Octokit /// public DateRange Updated { get; set; } - public string MergeParameters() + public override IReadOnlyCollection MergedQualifiers() { var parameters = new List(); @@ -165,26 +145,7 @@ namespace Octokit { parameters.Add(String.Format(CultureInfo.InvariantCulture, "pushed:{0}", Updated)); } - - return String.Join("+", parameters); - } - - /// - /// get the params in the correct format... - /// - /// - [SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.Int32.ToString")] - public IDictionary Parameters - { - get - { - var d = new System.Collections.Generic.Dictionary(); - d.Add("page", Page.ToString()); - d.Add("per_page", PerPage.ToString()); - d.Add("sort", Sort.ToString()); - d.Add("q", Term + " " + MergeParameters()); //add qualifiers onto the search term - return d; - } + return parameters; } internal string DebuggerDisplay From e59e7cbb698fb6544e49282e1d126464e30f44fd Mon Sep 17 00:00:00 2001 From: Haroon Date: Sat, 15 Mar 2014 21:19:29 +0000 Subject: [PATCH 02/36] size and stars test --- Octokit.Tests/Clients/SearchClientTests.cs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Octokit.Tests/Clients/SearchClientTests.cs b/Octokit.Tests/Clients/SearchClientTests.cs index 15d1d10f..21faabde 100644 --- a/Octokit.Tests/Clients/SearchClientTests.cs +++ b/Octokit.Tests/Clients/SearchClientTests.cs @@ -351,13 +351,12 @@ namespace Octokit.Tests.Clients { var connection = Substitute.For(); var client = new SearchClient(connection); - //check sizes for repos that are greater than 50 MB var request = new SearchRepositoriesRequest("github"); request.Size = Range.GreaterThan(50); - client.SearchRepo(request); - - connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); + connection.Received().GetAll( + Arg.Is(u => u.ToString() == "search/repositories"), + Arg.Is>(d => d["q"] == "github+size:>50")); } [Fact] @@ -368,10 +367,10 @@ namespace Octokit.Tests.Clients //get repos whos stargazers are greater than 500 var request = new SearchRepositoriesRequest("github"); request.Stars = Range.GreaterThan(500); - client.SearchRepo(request); - - connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); + connection.Received().GetAll( + Arg.Is(u => u.ToString() == "search/repositories"), + Arg.Is>(d => d["q"] == "github+stars:>500")); } [Fact] @@ -1312,7 +1311,7 @@ namespace Octokit.Tests.Clients connection.Received().GetAll( Arg.Is(u => u.ToString() == "search/code"), - Arg.Is>(d => + Arg.Is>(d => d["q"] == "something+path:tools/FAKE.core+extension:fs+repo:octokit.net")); } } From e930b9f292b22c4f550bb9c7013b292afbaf0465 Mon Sep 17 00:00:00 2001 From: Haroon Date: Sat, 15 Mar 2014 21:33:33 +0000 Subject: [PATCH 03/36] fixed up all other tests --- Octokit.Tests/Clients/SearchClientTests.cs | 49 ++++++++++------------ 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/Octokit.Tests/Clients/SearchClientTests.cs b/Octokit.Tests/Clients/SearchClientTests.cs index 21faabde..3bfeb225 100644 --- a/Octokit.Tests/Clients/SearchClientTests.cs +++ b/Octokit.Tests/Clients/SearchClientTests.cs @@ -381,10 +381,9 @@ namespace Octokit.Tests.Clients //get repos which has forks that are greater than 50 var request = new SearchRepositoriesRequest("github"); request.Forks = Range.GreaterThan(50); - client.SearchRepo(request); - - connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); + connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), + Arg.Is>(d => d["q"] == "github+forks:>500")); } [Fact] @@ -393,12 +392,11 @@ namespace Octokit.Tests.Clients var connection = Substitute.For(); var client = new SearchClient(connection); //search repos that contains rails and forks are included in the search - var request = new SearchRepositoriesRequest("rails"); + var request = new SearchRepositoriesRequest("github"); request.Fork = ForkQualifier.IncludeForks; - client.SearchRepo(request); - - connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); + connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), + Arg.Is>(d => d["q"] == "github+fork:IncludeForks")); } [Fact] @@ -412,7 +410,8 @@ namespace Octokit.Tests.Clients client.SearchRepo(request); - connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); + connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), + Arg.Is>(d => d["q"] == "github+language:Ruby")); } [Fact] @@ -424,8 +423,8 @@ namespace Octokit.Tests.Clients var request = new SearchRepositoriesRequest("github"); request.In = new[] { InQualifier.Description }; client.SearchRepo(request); - - connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); + connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), + Arg.Is>(d => d["q"] == "github+language:Ruby")); } [Fact] @@ -436,10 +435,9 @@ namespace Octokit.Tests.Clients //get repos where the search contains 'github' and has been created after year jan 1 2011 var request = new SearchRepositoriesRequest("github"); request.Created = DateRange.GreaterThan(new DateTime(2011, 1, 1)); - client.SearchRepo(request); - - connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); + connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), + Arg.Is>(d => d["q"] == "github+created>2011-01-01")); } [Fact] @@ -450,10 +448,9 @@ namespace Octokit.Tests.Clients //get repos where the search contains 'github' and has been pushed before year jan 1 2013 var request = new SearchRepositoriesRequest("github"); request.Updated = DateRange.LessThan(new DateTime(2013, 1, 1)); - client.SearchRepo(request); - - connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); + connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), + Arg.Is>(d => d["q"] == "github+updated>2013-01-01")); } [Fact] @@ -461,13 +458,12 @@ namespace Octokit.Tests.Clients { var connection = Substitute.For(); var client = new SearchClient(connection); - //get repos where the Description contains rails and user/org is 'github' - var request = new SearchRepositoriesRequest("rails"); - request.User = "github"; - + //get repos where search contains 'github' and user/org is 'github' + var request = new SearchRepositoriesRequest("github"); + request.User = "rails"; client.SearchRepo(request); - - connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); + connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), + Arg.Is>(d => d["q"] == "github+user:rails")); } [Fact] @@ -475,13 +471,12 @@ namespace Octokit.Tests.Clients { var connection = Substitute.For(); var client = new SearchClient(connection); - //get repos where the Description contains rails and user/org is 'github' - var request = new SearchRepositoriesRequest("rails"); + //get repos where search contains 'github' and sort field is forks + var request = new SearchRepositoriesRequest("github"); request.SortField = RepoSearchSort.Forks; - client.SearchRepo(request); - - connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); + connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), + Arg.Is>(d => d["q"] == "github?sort=Forks")); } } From 5da69648d1e317f3866058764770733ddab5179f Mon Sep 17 00:00:00 2001 From: Haroon Date: Sat, 15 Mar 2014 21:52:28 +0000 Subject: [PATCH 04/36] fixed merge conflict --- Octokit.Tests/Clients/SearchClientTests.cs | 54 +--------------------- 1 file changed, 2 insertions(+), 52 deletions(-) diff --git a/Octokit.Tests/Clients/SearchClientTests.cs b/Octokit.Tests/Clients/SearchClientTests.cs index efd246db..ea5777cf 100644 --- a/Octokit.Tests/Clients/SearchClientTests.cs +++ b/Octokit.Tests/Clients/SearchClientTests.cs @@ -336,7 +336,8 @@ namespace Octokit.Tests.Clients var connection = Substitute.For(); var client = new SearchClient(connection); client.SearchRepo(new SearchRepositoriesRequest("something")); - connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); + connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), + Arg.Any>()); } [Fact] @@ -354,14 +355,9 @@ 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] @@ -373,14 +369,9 @@ 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] @@ -392,13 +383,8 @@ 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] @@ -410,13 +396,8 @@ 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] @@ -427,15 +408,9 @@ namespace Octokit.Tests.Clients //get repos whos language is Ruby var request = new SearchRepositoriesRequest("github"); request.Language = Language.Ruby; - 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] @@ -447,13 +422,8 @@ 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] @@ -465,13 +435,8 @@ 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] @@ -483,13 +448,8 @@ 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] @@ -501,13 +461,8 @@ 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] @@ -519,13 +474,8 @@ 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 } } From 26d51933c431054183333ac426b202f087bdab91 Mon Sep 17 00:00:00 2001 From: Haroon Date: Sat, 15 Mar 2014 22:55:49 +0000 Subject: [PATCH 05/36] test correct return type --- Octokit.Tests/Clients/SearchClientTests.cs | 97 ++++++++++++++++--- .../Request/SearchRepositoriesRequest.cs | 1 + 2 files changed, 83 insertions(+), 15 deletions(-) diff --git a/Octokit.Tests/Clients/SearchClientTests.cs b/Octokit.Tests/Clients/SearchClientTests.cs index ea5777cf..12135181 100644 --- a/Octokit.Tests/Clients/SearchClientTests.cs +++ b/Octokit.Tests/Clients/SearchClientTests.cs @@ -353,11 +353,11 @@ namespace Octokit.Tests.Clients var connection = Substitute.For(); var client = new SearchClient(connection); var request = new SearchRepositoriesRequest("github"); - request.Size = Range.GreaterThan(50); + request.Size = Range.GreaterThan(1); client.SearchRepo(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/repositories"), - Arg.Is>(d => d["q"] == "github+size:>50")); + Arg.Is>(d => d["q"] == "github+size:>1")); } [Fact] @@ -369,11 +369,39 @@ namespace Octokit.Tests.Clients var request = new SearchRepositoriesRequest("github"); request.Stars = Range.GreaterThan(500); client.SearchRepo(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/repositories"), Arg.Is>(d => d["q"] == "github+stars:>500")); } + [Fact] + public void TestingTheStarsQualifier_LessThan() + { + var connection = Substitute.For(); + var client = new SearchClient(connection); + //get repos whos stargazers are less than 500 + var request = new SearchRepositoriesRequest("github"); + request.Stars = Range.LessThan(500); + client.SearchRepo(request); + connection.Received().Get( + Arg.Is(u => u.ToString() == "search/repositories"), + Arg.Is>(d => d["q"] == "github+stars:<500")); + } + + [Fact] + public void TestingTheStarsQualifier_LessThanOrEquals() + { + var connection = Substitute.For(); + var client = new SearchClient(connection); + //get repos whos stargazers are less than 500 or equal to + var request = new SearchRepositoriesRequest("github"); + request.Stars = Range.LessThanOrEquals(500); + client.SearchRepo(request); + connection.Received().Get( + Arg.Is(u => u.ToString() == "search/repositories"), + Arg.Is>(d => d["q"] == "github+stars:<=500")); + } + [Fact] public void TestingTheForksQualifier() { @@ -383,8 +411,8 @@ namespace Octokit.Tests.Clients var request = new SearchRepositoriesRequest("github"); request.Forks = Range.GreaterThan(50); client.SearchRepo(request); - 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.Is>(d => d["q"] == "github+forks:>50")); } [Fact] @@ -396,7 +424,7 @@ namespace Octokit.Tests.Clients var request = new SearchRepositoriesRequest("github"); request.Fork = ForkQualifier.IncludeForks; client.SearchRepo(request); - connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), + connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Is>(d => d["q"] == "github+fork:IncludeForks")); } @@ -409,7 +437,7 @@ namespace Octokit.Tests.Clients var request = new SearchRepositoriesRequest("github"); request.Language = Language.Ruby; client.SearchRepo(request); - connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), + connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Is>(d => d["q"] == "github+language:Ruby")); } @@ -422,7 +450,7 @@ namespace Octokit.Tests.Clients var request = new SearchRepositoriesRequest("github"); request.In = new[] { InQualifier.Description }; client.SearchRepo(request); - connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), + connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Is>(d => d["q"] == "github+language:Ruby")); } @@ -435,12 +463,38 @@ namespace Octokit.Tests.Clients var request = new SearchRepositoriesRequest("github"); request.Created = DateRange.GreaterThan(new DateTime(2011, 1, 1)); client.SearchRepo(request); - connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), + connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Is>(d => d["q"] == "github+created>2011-01-01")); } [Fact] public void TestingTheUpdatedQualifier() + { + var connection = Substitute.For(); + var client = new SearchClient(connection); + //get repos where the search contains 'github' and has been pushed before year jan 1 2013 + var request = new SearchRepositoriesRequest("github"); + request.Updated = DateRange.GreaterThan(new DateTime(2013, 1, 1)); + client.SearchRepo(request); + connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), + Arg.Is>(d => d["q"] == "github+pushed>2013-01-01")); + } + + [Fact] + public void TestingTheUpdatedQualifier_GreaterThanOrEquals() + { + var connection = Substitute.For(); + var client = new SearchClient(connection); + //get repos where the search contains 'github' and has been pushed before year jan 1 2013 + var request = new SearchRepositoriesRequest("github"); + request.Updated = DateRange.GreaterThanOrEquals(new DateTime(2013, 1, 1)); + client.SearchRepo(request); + connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), + Arg.Is>(d => d["q"] == "github+pushed>=2013-01-01")); + } + + [Fact] + public void TestingTheUpdatedQualifier_LessThan() { var connection = Substitute.For(); var client = new SearchClient(connection); @@ -448,8 +502,21 @@ namespace Octokit.Tests.Clients var request = new SearchRepositoriesRequest("github"); request.Updated = DateRange.LessThan(new DateTime(2013, 1, 1)); client.SearchRepo(request); - 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.Is>(d => d["q"] == "github+pushed<2013-01-01")); + } + + [Fact] + public void TestingTheUpdatedQualifier_LessThanOrEquals() + { + var connection = Substitute.For(); + var client = new SearchClient(connection); + //get repos where the search contains 'github' and has been pushed before year jan 1 2013 + var request = new SearchRepositoriesRequest("github"); + request.Updated = DateRange.LessThanOrEquals(new DateTime(2013, 1, 1)); + client.SearchRepo(request); + connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), + Arg.Is>(d => d["q"] == "github+pushed<=2013-01-01")); } [Fact] @@ -461,7 +528,7 @@ namespace Octokit.Tests.Clients var request = new SearchRepositoriesRequest("github"); request.User = "rails"; client.SearchRepo(request); - connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), + connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Is>(d => d["q"] == "github+user:rails")); } @@ -474,8 +541,8 @@ namespace Octokit.Tests.Clients var request = new SearchRepositoriesRequest("github"); request.SortField = RepoSearchSort.Forks; client.SearchRepo(request); - 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.Is>(d => d["q"] == "github" && d["sort"] == "Forks")); } } diff --git a/Octokit/Models/Request/SearchRepositoriesRequest.cs b/Octokit/Models/Request/SearchRepositoriesRequest.cs index af7a9e05..51ecff77 100644 --- a/Octokit/Models/Request/SearchRepositoriesRequest.cs +++ b/Octokit/Models/Request/SearchRepositoriesRequest.cs @@ -26,6 +26,7 @@ namespace Octokit /// Optional Sort field. One of stars, forks, or updated. If not provided, results are sorted by best match. /// public RepoSearchSort? SortField { get; set; } + public override string Sort { get { return SortField.ToParameter(); } From 31345f63d87fa7ed28f22f500c922b84d7f5e14a Mon Sep 17 00:00:00 2001 From: Haroon Date: Sun, 16 Mar 2014 02:12:58 +0000 Subject: [PATCH 06/36] forkqualifier should be nullable --- .../Models/Request/SearchRepositoriesRequest.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Octokit/Models/Request/SearchRepositoriesRequest.cs b/Octokit/Models/Request/SearchRepositoriesRequest.cs index 51ecff77..00f60b67 100644 --- a/Octokit/Models/Request/SearchRepositoriesRequest.cs +++ b/Octokit/Models/Request/SearchRepositoriesRequest.cs @@ -17,7 +17,6 @@ namespace Octokit { public SearchRepositoriesRequest(string term) : base(term) { - Fork = ForkQualifier.ExcludeForks; Order = SortDirection.Descending; } @@ -63,7 +62,7 @@ namespace Octokit /// Defaults to ExcludeForks /// https://help.github.com/articles/searching-repositories#forks /// - public ForkQualifier Fork { get; set; } + public ForkQualifier? Fork { get; set; } /// /// The size qualifier finds repository's that match a certain size (in kilobytes). @@ -120,7 +119,10 @@ namespace Octokit parameters.Add(String.Format(CultureInfo.InvariantCulture, "forks:{0}", Forks)); } - parameters.Add(String.Format(CultureInfo.InvariantCulture, "fork:{0}", Fork)); + if (Fork != null) + { + parameters.Add(String.Format(CultureInfo.InvariantCulture, "fork:{0}", Fork)); + } if (Stars != null) { @@ -736,14 +738,12 @@ namespace Octokit /// /// only search for forked repos /// + [Parameter(Value="Only")] OnlyForks, /// /// include forked repos into the search /// - IncludeForks, - /// - /// forks are not included in the search (default behaviour) - /// - ExcludeForks + [Parameter(Value = "True")] + IncludeForks } } \ No newline at end of file From 5ed8284db16461a7a290f891e1276aff75be0722 Mon Sep 17 00:00:00 2001 From: Haroon Date: Sun, 16 Mar 2014 02:25:55 +0000 Subject: [PATCH 07/36] fixed in qualifiers also added a few more in qualifiers to better test this out --- Octokit.Tests/Clients/SearchClientTests.cs | 41 +++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/Octokit.Tests/Clients/SearchClientTests.cs b/Octokit.Tests/Clients/SearchClientTests.cs index 12135181..1423ee83 100644 --- a/Octokit.Tests/Clients/SearchClientTests.cs +++ b/Octokit.Tests/Clients/SearchClientTests.cs @@ -451,7 +451,46 @@ namespace Octokit.Tests.Clients request.In = new[] { InQualifier.Description }; client.SearchRepo(request); connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), - Arg.Is>(d => d["q"] == "github+language:Ruby")); + Arg.Is>(d => d["q"] == "github+in:Description")); + } + + [Fact] + public void TestingTheInQualifier_Name() + { + var connection = Substitute.For(); + var client = new SearchClient(connection); + var request = new SearchRepositoriesRequest("github"); + request.In = new[] { InQualifier.Name }; + client.SearchRepo(request); + connection.Received().Get( + Arg.Is(u => u.ToString() == "search/users"), + Arg.Is>(d => d["q"] == "github+in:Name")); + } + + [Fact] + public void TestingTheInQualifier_Readme() + { + var connection = Substitute.For(); + var client = new SearchClient(connection); + var request = new SearchRepositoriesRequest("github"); + request.In = new[] { InQualifier.Readme }; + client.SearchRepo(request); + connection.Received().Get( + Arg.Is(u => u.ToString() == "search/users"), + Arg.Is>(d => d["q"] == "github+in:Readme")); + } + + [Fact] + public void TestingTheInQualifier_Multiple() + { + var connection = Substitute.For(); + var client = new SearchClient(connection); + var request = new SearchRepositoriesRequest("github"); + request.In = new[] { InQualifier.Readme, InQualifier.Description, InQualifier.Name }; + client.SearchRepo(request); + connection.Received().Get( + Arg.Is(u => u.ToString() == "search/users"), + Arg.Is>(d => d["q"] == "github+in:Readme,Description,Name")); } [Fact] From eb525725137054b234429439aa09565f27eb2a71 Mon Sep 17 00:00:00 2001 From: Haroon Date: Sun, 16 Mar 2014 02:37:20 +0000 Subject: [PATCH 08/36] fixed incorrect return types --- Octokit.Tests/Clients/SearchClientTests.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Octokit.Tests/Clients/SearchClientTests.cs b/Octokit.Tests/Clients/SearchClientTests.cs index 1423ee83..7db8a38d 100644 --- a/Octokit.Tests/Clients/SearchClientTests.cs +++ b/Octokit.Tests/Clients/SearchClientTests.cs @@ -462,7 +462,7 @@ namespace Octokit.Tests.Clients var request = new SearchRepositoriesRequest("github"); request.In = new[] { InQualifier.Name }; client.SearchRepo(request); - connection.Received().Get( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+in:Name")); } @@ -475,7 +475,7 @@ namespace Octokit.Tests.Clients var request = new SearchRepositoriesRequest("github"); request.In = new[] { InQualifier.Readme }; client.SearchRepo(request); - connection.Received().Get( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+in:Readme")); } @@ -488,7 +488,7 @@ namespace Octokit.Tests.Clients var request = new SearchRepositoriesRequest("github"); request.In = new[] { InQualifier.Readme, InQualifier.Description, InQualifier.Name }; client.SearchRepo(request); - connection.Received().Get( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+in:Readme,Description,Name")); } From f6058f1c4e5f2be020a9f3a0211cb0980a6cf118 Mon Sep 17 00:00:00 2001 From: Haroon Date: Sun, 16 Mar 2014 03:02:11 +0000 Subject: [PATCH 09/36] fixed updated and created tests --- Octokit.Tests/Clients/SearchClientTests.cs | 127 ++++++++++++++------- 1 file changed, 84 insertions(+), 43 deletions(-) diff --git a/Octokit.Tests/Clients/SearchClientTests.cs b/Octokit.Tests/Clients/SearchClientTests.cs index 7db8a38d..effa9d6a 100644 --- a/Octokit.Tests/Clients/SearchClientTests.cs +++ b/Octokit.Tests/Clients/SearchClientTests.cs @@ -454,44 +454,44 @@ namespace Octokit.Tests.Clients Arg.Is>(d => d["q"] == "github+in:Description")); } - [Fact] - public void TestingTheInQualifier_Name() - { - var connection = Substitute.For(); - var client = new SearchClient(connection); - var request = new SearchRepositoriesRequest("github"); - request.In = new[] { InQualifier.Name }; - client.SearchRepo(request); - connection.Received().Get( - Arg.Is(u => u.ToString() == "search/users"), - Arg.Is>(d => d["q"] == "github+in:Name")); - } + //[Fact] + //public void TestingTheInQualifier_Name() + //{ + // var connection = Substitute.For(); + // var client = new SearchClient(connection); + // var request = new SearchRepositoriesRequest("github"); + // request.In = new[] { InQualifier.Name }; + // client.SearchRepo(request); + // connection.Received().Get( + // Arg.Is(u => u.ToString() == "search/users"), + // Arg.Is>(d => d["q"] == "github+in:Name")); + //} - [Fact] - public void TestingTheInQualifier_Readme() - { - var connection = Substitute.For(); - var client = new SearchClient(connection); - var request = new SearchRepositoriesRequest("github"); - request.In = new[] { InQualifier.Readme }; - client.SearchRepo(request); - connection.Received().Get( - Arg.Is(u => u.ToString() == "search/users"), - Arg.Is>(d => d["q"] == "github+in:Readme")); - } + //[Fact] + //public void TestingTheInQualifier_Readme() + //{ + // var connection = Substitute.For(); + // var client = new SearchClient(connection); + // var request = new SearchRepositoriesRequest("github"); + // request.In = new[] { InQualifier.Readme }; + // client.SearchRepo(request); + // connection.Received().Get( + // Arg.Is(u => u.ToString() == "search/users"), + // Arg.Is>(d => d["q"] == "github+in:Readme")); + //} - [Fact] - public void TestingTheInQualifier_Multiple() - { - var connection = Substitute.For(); - var client = new SearchClient(connection); - var request = new SearchRepositoriesRequest("github"); - request.In = new[] { InQualifier.Readme, InQualifier.Description, InQualifier.Name }; - client.SearchRepo(request); - connection.Received().Get( - Arg.Is(u => u.ToString() == "search/users"), - Arg.Is>(d => d["q"] == "github+in:Readme,Description,Name")); - } + //[Fact] + //public void TestingTheInQualifier_Multiple() + //{ + // var connection = Substitute.For(); + // var client = new SearchClient(connection); + // var request = new SearchRepositoriesRequest("github"); + // request.In = new[] { InQualifier.Readme, InQualifier.Description, InQualifier.Name }; + // client.SearchRepo(request); + // connection.Received().Get( + // Arg.Is(u => u.ToString() == "search/users"), + // Arg.Is>(d => d["q"] == "github+in:Readme,Description,Name")); + //} [Fact] public void TestingTheCreatedQualifier() @@ -503,9 +503,50 @@ namespace Octokit.Tests.Clients request.Created = DateRange.GreaterThan(new DateTime(2011, 1, 1)); client.SearchRepo(request); connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), - Arg.Is>(d => d["q"] == "github+created>2011-01-01")); + Arg.Is>(d => d["q"] == "github+created:>2011-01-01")); } + [Fact] + public void TestingTheCreatedQualifier_GreaterThanOrEquals() + { + var connection = Substitute.For(); + var client = new SearchClient(connection); + //get repos where the search contains 'github' and has been created after year jan 1 2011 + var request = new SearchRepositoriesRequest("github"); + request.Created = DateRange.GreaterThanOrEquals(new DateTime(2011, 1, 1)); + client.SearchRepo(request); + connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), + Arg.Is>(d => d["q"] == "github+created:>=2011-01-01")); + } + + [Fact] + public void TestingTheCreatedQualifier_LessThan() + { + var connection = Substitute.For(); + var client = new SearchClient(connection); + //get repos where the search contains 'github' and has been created after year jan 1 2011 + var request = new SearchRepositoriesRequest("github"); + request.Created = DateRange.LessThan(new DateTime(2011, 1, 1)); + client.SearchRepo(request); + connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), + Arg.Is>(d => d["q"] == "github+created:<2011-01-01")); + } + + + [Fact] + public void TestingTheCreatedQualifier_LessThanOrEquals() + { + var connection = Substitute.For(); + var client = new SearchClient(connection); + //get repos where the search contains 'github' and has been created after year jan 1 2011 + var request = new SearchRepositoriesRequest("github"); + request.Created = DateRange.LessThanOrEquals(new DateTime(2011, 1, 1)); + client.SearchRepo(request); + connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), + Arg.Is>(d => d["q"] == "github+created:<=2011-01-01")); + } + + [Fact] public void TestingTheUpdatedQualifier() { @@ -516,7 +557,7 @@ namespace Octokit.Tests.Clients request.Updated = DateRange.GreaterThan(new DateTime(2013, 1, 1)); client.SearchRepo(request); connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), - Arg.Is>(d => d["q"] == "github+pushed>2013-01-01")); + Arg.Is>(d => d["q"] == "github+pushed:>2013-01-01")); } [Fact] @@ -529,7 +570,7 @@ namespace Octokit.Tests.Clients request.Updated = DateRange.GreaterThanOrEquals(new DateTime(2013, 1, 1)); client.SearchRepo(request); connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), - Arg.Is>(d => d["q"] == "github+pushed>=2013-01-01")); + Arg.Is>(d => d["q"] == "github+pushed:>=2013-01-01")); } [Fact] @@ -542,7 +583,7 @@ namespace Octokit.Tests.Clients request.Updated = DateRange.LessThan(new DateTime(2013, 1, 1)); client.SearchRepo(request); connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), - Arg.Is>(d => d["q"] == "github+pushed<2013-01-01")); + Arg.Is>(d => d["q"] == "github+pushed:<2013-01-01")); } [Fact] @@ -555,7 +596,7 @@ namespace Octokit.Tests.Clients request.Updated = DateRange.LessThanOrEquals(new DateTime(2013, 1, 1)); client.SearchRepo(request); connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), - Arg.Is>(d => d["q"] == "github+pushed<=2013-01-01")); + Arg.Is>(d => d["q"] == "github+pushed:<=2013-01-01")); } [Fact] @@ -578,10 +619,10 @@ namespace Octokit.Tests.Clients var client = new SearchClient(connection); //get repos where search contains 'github' and sort field is forks var request = new SearchRepositoriesRequest("github"); - request.SortField = RepoSearchSort.Forks; + request.SortField = RepoSearchSort.Stars; client.SearchRepo(request); connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), - Arg.Is>(d => d["q"] == "github" && d["sort"] == "Forks")); + Arg.Is>(d => d["sort"] == "Stars")); } } From 867feb86e139b0af662d8af67ad850e8dbec579c Mon Sep 17 00:00:00 2001 From: Haroon Date: Sun, 16 Mar 2014 03:08:23 +0000 Subject: [PATCH 10/36] fixed in tests --- Octokit.Tests/Clients/SearchClientTests.cs | 72 +++++++++++----------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/Octokit.Tests/Clients/SearchClientTests.cs b/Octokit.Tests/Clients/SearchClientTests.cs index effa9d6a..8897a048 100644 --- a/Octokit.Tests/Clients/SearchClientTests.cs +++ b/Octokit.Tests/Clients/SearchClientTests.cs @@ -454,44 +454,44 @@ namespace Octokit.Tests.Clients Arg.Is>(d => d["q"] == "github+in:Description")); } - //[Fact] - //public void TestingTheInQualifier_Name() - //{ - // var connection = Substitute.For(); - // var client = new SearchClient(connection); - // var request = new SearchRepositoriesRequest("github"); - // request.In = new[] { InQualifier.Name }; - // client.SearchRepo(request); - // connection.Received().Get( - // Arg.Is(u => u.ToString() == "search/users"), - // Arg.Is>(d => d["q"] == "github+in:Name")); - //} + [Fact] + public void TestingTheInQualifier_Name() + { + var connection = Substitute.For(); + var client = new SearchClient(connection); + var request = new SearchRepositoriesRequest("github"); + request.In = new[] { InQualifier.Name }; + client.SearchRepo(request); + connection.Received().Get( + Arg.Is(u => u.ToString() == "search/repositories"), + Arg.Is>(d => d["q"] == "github+in:Name")); + } - //[Fact] - //public void TestingTheInQualifier_Readme() - //{ - // var connection = Substitute.For(); - // var client = new SearchClient(connection); - // var request = new SearchRepositoriesRequest("github"); - // request.In = new[] { InQualifier.Readme }; - // client.SearchRepo(request); - // connection.Received().Get( - // Arg.Is(u => u.ToString() == "search/users"), - // Arg.Is>(d => d["q"] == "github+in:Readme")); - //} + [Fact] + public void TestingTheInQualifier_Readme() + { + var connection = Substitute.For(); + var client = new SearchClient(connection); + var request = new SearchRepositoriesRequest("github"); + request.In = new[] { InQualifier.Readme }; + client.SearchRepo(request); + connection.Received().Get( + Arg.Is(u => u.ToString() == "search/repositories"), + Arg.Is>(d => d["q"] == "github+in:Readme")); + } - //[Fact] - //public void TestingTheInQualifier_Multiple() - //{ - // var connection = Substitute.For(); - // var client = new SearchClient(connection); - // var request = new SearchRepositoriesRequest("github"); - // request.In = new[] { InQualifier.Readme, InQualifier.Description, InQualifier.Name }; - // client.SearchRepo(request); - // connection.Received().Get( - // Arg.Is(u => u.ToString() == "search/users"), - // Arg.Is>(d => d["q"] == "github+in:Readme,Description,Name")); - //} + [Fact] + public void TestingTheInQualifier_Multiple() + { + var connection = Substitute.For(); + var client = new SearchClient(connection); + var request = new SearchRepositoriesRequest("github"); + request.In = new[] { InQualifier.Readme, InQualifier.Description, InQualifier.Name }; + client.SearchRepo(request); + connection.Received().Get( + Arg.Is(u => u.ToString() == "search/repositories"), + Arg.Is>(d => d["q"] == "github+in:Readme,Description,Name")); + } [Fact] public void TestingTheCreatedQualifier() From 09ef69c84315b10d250c6b327c6948d855e42112 Mon Sep 17 00:00:00 2001 From: Haroon Date: Wed, 30 Apr 2014 10:29:45 +0100 Subject: [PATCH 11/36] improve test --- Octokit.Tests/Clients/SearchClientTests.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Octokit.Tests/Clients/SearchClientTests.cs b/Octokit.Tests/Clients/SearchClientTests.cs index 8897a048..c06813fa 100644 --- a/Octokit.Tests/Clients/SearchClientTests.cs +++ b/Octokit.Tests/Clients/SearchClientTests.cs @@ -617,12 +617,16 @@ namespace Octokit.Tests.Clients { var connection = Substitute.For(); var client = new SearchClient(connection); - //get repos where search contains 'github' and sort field is forks var request = new SearchRepositoriesRequest("github"); request.SortField = RepoSearchSort.Stars; + client.SearchRepo(request); - connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), - Arg.Is>(d => d["sort"] == "Stars")); + + connection.Received().Get( + Arg.Is(u => u.ToString() == "search/repositories"), + Arg.Is>(d => + d["q"] == "github" && + d["sort"] == "stars")); } } From 11933714a51924c72ff6fc1dcfa6d2692b30b993 Mon Sep 17 00:00:00 2001 From: Haroon Date: Fri, 15 Aug 2014 19:15:29 +0100 Subject: [PATCH 12/36] added params --- Octokit/Models/Request/SearchRepositoriesRequest.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Octokit/Models/Request/SearchRepositoriesRequest.cs b/Octokit/Models/Request/SearchRepositoriesRequest.cs index 00f60b67..dd7537ab 100644 --- a/Octokit/Models/Request/SearchRepositoriesRequest.cs +++ b/Octokit/Models/Request/SearchRepositoriesRequest.cs @@ -15,7 +15,8 @@ namespace Octokit [DebuggerDisplay("{DebuggerDisplay,nq}")] public class SearchRepositoriesRequest : BaseSearchRequest { - public SearchRepositoriesRequest(string term) : base(term) + public SearchRepositoriesRequest(string term) + : base(term) { Order = SortDirection.Descending; } @@ -718,14 +719,17 @@ namespace Octokit /// /// search by number of stars /// + [Parameter(Value = "stars")] Stars, /// /// search by number of forks /// + [Parameter(Value = "forks")] Forks, /// /// search by last updated /// + [Parameter(Value = "updated")] Updated } @@ -738,7 +742,7 @@ namespace Octokit /// /// only search for forked repos /// - [Parameter(Value="Only")] + [Parameter(Value = "Only")] OnlyForks, /// /// include forked repos into the search From 4baeb11badce77d7df525243f4b6d26e95f3afeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20B=C3=B6hlmark?= Date: Thu, 9 Oct 2014 17:14:06 +0200 Subject: [PATCH 13/36] Fix typo: ouath -> oauth --- Octokit/Http/ApiInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Octokit/Http/ApiInfo.cs b/Octokit/Http/ApiInfo.cs index 8050a448..54550cb7 100644 --- a/Octokit/Http/ApiInfo.cs +++ b/Octokit/Http/ApiInfo.cs @@ -18,7 +18,7 @@ namespace Octokit RateLimit rateLimit) { Ensure.ArgumentNotNull(links, "links"); - Ensure.ArgumentNotNull(oauthScopes, "ouathScopes"); + Ensure.ArgumentNotNull(oauthScopes, "oauthScopes"); Links = new ReadOnlyDictionary(links); OauthScopes = new ReadOnlyCollection(oauthScopes); From 3abc2183243e5b5c9a6e162268f646fbc2a65156 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20B=C3=B6hlmark?= Date: Sun, 12 Oct 2014 01:25:31 +0200 Subject: [PATCH 14/36] Fix a few documentation typos in NewRepository --- Octokit/Models/Request/NewRepository.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Octokit/Models/Request/NewRepository.cs b/Octokit/Models/Request/NewRepository.cs index dab22dd2..60d846bf 100644 --- a/Octokit/Models/Request/NewRepository.cs +++ b/Octokit/Models/Request/NewRepository.cs @@ -22,17 +22,17 @@ namespace Octokit public string Description { get; set; } /// s - /// Optional. Gets or sets whether to the enable downloads for the new repository. The default is true. + /// Optional. Gets or sets whether to enable downloads for the new repository. The default is true. /// public bool? HasDownloads { get; set; } /// s - /// Optional. Gets or sets whether to the enable issues for the new repository. The default is true. + /// Optional. Gets or sets whether to enable issues for the new repository. The default is true. /// public bool? HasIssues { get; set; } /// s - /// Optional. Gets or sets whether to the enable the wiki for the new repository. The default is true. + /// Optional. Gets or sets whether to enable the wiki for the new repository. The default is true. /// public bool? HasWiki { get; set; } From 438a32639759b6af9a8fd2427099a718c858b3a6 Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Sat, 19 Jul 2014 11:05:56 -0700 Subject: [PATCH 15/36] first version of the getting started doc --- docs/getting-started.md | 42 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 docs/getting-started.md diff --git a/docs/getting-started.md b/docs/getting-started.md new file mode 100644 index 00000000..e7b21b24 --- /dev/null +++ b/docs/getting-started.md @@ -0,0 +1,42 @@ +## Getting Started + +The easiest way to get started with Octokit is to use a plain `GitHubClient`: + +``` +var client = new GitHubClient(new ProductHeaderValue("my-cool-app")); +``` + +This will let you access unauthenticated GitHub APIs, but you will be subject to rate limiting (you can read more about this [here](https://developer.github.com/v3/#rate-limiting)). + +But why do you need this `ProductHeaderValue` value? + +The API will reject you if you don't provide a `User-Agent` header (more details [here](https://developer.github.com/v3/#user-agent-required)). This is also to identify applications that are accessing the API and enable GitHub to contact the application author if there are problems. So pick a name that stands out! + +### Authenticated Access + +If you want to access private repositories or perform actions on behalf of a user, you need to pass credentials to the client. + +There are two options supported by the API - basic and OAuth authentication. + +``` +var basicAuth = new Credentials("username", "password"); // NOTE: not real credentials +client.Credentials = basicAuth; +``` + +``` +var tokenAuth = new Credentials("token"); // NOTE: not real token +client.Credentials = tokenAuth; +``` + +When authenticated, you have 5000 requests per hour available. So this is the recommended approach for interacting with the API. + +**TODO:** separate doc for OAuth flow + +### Connecting to GitHub Enterprise + +Octokit also supports connecting to GitHub Enterprise environments - just provide the URL to your GitHub Enterprise server when creating the client. + +``` +var ghe = new Uri("https://github.myenterprise.com/"); +var client = new GitHubClient(new ProductHeaderValue("my-cool-app"), ghe); +``` From 395a41a531e58b71781f01b3b42c8cc21ab8895a Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Sat, 19 Jul 2014 14:15:14 -0700 Subject: [PATCH 16/36] added oauth flow doc --- docs/oauth-flow.md | 92 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 docs/oauth-flow.md diff --git a/docs/oauth-flow.md b/docs/oauth-flow.md new file mode 100644 index 00000000..9d713460 --- /dev/null +++ b/docs/oauth-flow.md @@ -0,0 +1,92 @@ +## OAuth Flow + +If you have a service which needs to interact with the GitHub API on behalf of a user, you should use the OAuth flow. [Phil Haack](https://haacked.com) has written a great [blog post](http://haacked.com/archive/2014/04/24/octokit-oauth/) on using Octokit in ASP.NET, and even has a [demo project](https://github.com/Haacked/octokit-oauth-demo) you can try out, so this will just go over the specific APIs in more detail. + +### Setup + +First, you need to register your application on GitHub (or GitHub Enterprise). While logged in, go to your account settings and click the Applications tab. Then click "Register new application". + +Or just navigate to [https://github.com/settings/applications/new](https://github.com/settings/applications/new) if you're lazy. + +Fill in some details about your application: + +![application registration](https://cloud.githubusercontent.com/assets/19977/2760125/62600c38-c9ae-11e3-911f-783d7a34aeaf.png) + +Then click "Register application", and you'll get your client id and client secret. + +![OAuth application registration details](https://cloud.githubusercontent.com/assets/19977/2760128/95587e40-c9ae-11e3-84f2-053d2574f1e8.png) + +### Starting the OAuth Flow + +We'll use these in a few places, so define these as private fields: + +``` +var clientId = "some-id-here"; +var clientSecret = "some-id-here"; +var client = new GitHubClient(new ProductHeaderValue("my-cool-app")); +``` + +To start the authentication flow, you need to craft a URL indicating your application needs to authenticate on behalf of the current user. + +``` +// NOTE: this is not required, but highly recommended! +// ask the ASP.NET Membership provider to generate a random value +// and store it in the current user's session +string csrf = Membership.GeneratePassword(24, 1); +Session["CSRF:State"] = csrf; + +var request = new OauthLoginRequest(clientId) +{ + Scopes = {"user", "notifications"}, + State = csrf +}; + +// NOTE: user must be navigated to this URL +var oauthLoginUrl = client.Oauth.GetGitHubLoginUrl(request); +``` + +Scopes are keys which specify the permissions the application needs. If you don't specify a `Scopes` value, your application will only have read access to the user's public data (repository, user info, etc). There's lots of different scopes available for different interactions with user data, so have a look at the [documentation](https://developer.github.com/v3/oauth/#scopes). + +### Generating the token + +Once the user has been navigated to the URL above and clicked "Authorize Application", you will receive a callback at the default Callback URL for your application. You can override this by specifying a different URL when creating the request, if necessary. + +Your callback will have two parameters, the code generated by the GitHub API and some additional state - this is specifically to prevent CSRF (Cross-Site Request Forgery) attacks and is highly recommended. + +With this code you can then request an access token by providing your client secret. This doesn't require any user interaction, so can be done in the background. + +``` +public async Task Authorize(string code, string state) +{ + if (String.IsNullOrEmpty(code)) + return RedirectToAction("Index"); + + var expectedState = Session["CSRF:State"] as string; + if (state != expectedState) throw new InvalidOperationException("SECURITY FAIL!"); + Session["CSRF:State"] = null; + + var request = new OauthTokenRequest(clientId, clientSecret, code); + var token = await client.Oauth.CreateAccessToken(request); + Session["OAuthToken"] = token.AccessToken; + + return RedirectToAction("Index"); +} +``` + +And now you have an access token, you can set up your credentials to use this token: + +``` +// repositories which include public and private repositories. +public async Task Index() +{ + var accessToken = Session["OAuthToken"] as string; + if (accessToken != null) + { + client.Credentials = new Credentials(accessToken); + + var repositories = await client.Repository.GetAllForCurrent(); + } + + /* TODO: all the rest of the webapp */ +} +``` From 2446137720c64f0d5f58f57717f7fa5f9a98c8f3 Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Fri, 24 Oct 2014 14:26:06 -0700 Subject: [PATCH 17/36] added section about getting user data --- docs/getting-started.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/getting-started.md b/docs/getting-started.md index e7b21b24..d0897296 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -40,3 +40,21 @@ Octokit also supports connecting to GitHub Enterprise environments - just provid var ghe = new Uri("https://github.myenterprise.com/"); var client = new GitHubClient(new ProductHeaderValue("my-cool-app"), ghe); ``` + +### Get exploring + +Once you've got that setup, the simplest thing to experiment with is fetching details about a specific user: + +``` +var user = await client.User.Get("shiftkey"); +Console.WriteLine("{0} has {1} public repositories - go check out their profile at {1}", + user.Name, + user.PublicRepos, + user.Url); +``` + +If you've authenticated as a given user, you can query their details directly: + +``` +var user = await client.User.Current(); +``` \ No newline at end of file From b6ea7254eb3347361853f5b58f9aea21134977a6 Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Fri, 24 Oct 2014 14:33:35 -0700 Subject: [PATCH 18/36] replaced TODO --- docs/getting-started.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/getting-started.md b/docs/getting-started.md index d0897296..0f0afb39 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -28,9 +28,12 @@ var tokenAuth = new Credentials("token"); // NOTE: not real token client.Credentials = tokenAuth; ``` -When authenticated, you have 5000 requests per hour available. So this is the recommended approach for interacting with the API. +It is **strongly recommended** to use the [OAuth Flow](https://github.com/octokit/octokit.net/blob/master/docs/oauth-flow.md) for interactions on behalf of a user, as this gives two significant benefits: -**TODO:** separate doc for OAuth flow + - the application owner never needs to store a user's password + - the token can be revoked by the user at a later date + +When authenticated, you have 5000 requests per hour available. So this is the recommended approach for interacting with the API. ### Connecting to GitHub Enterprise From 5c1ecfafa4fd18849ac86c419ef0164a80c29caa Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Fri, 24 Oct 2014 14:33:40 -0700 Subject: [PATCH 19/36] spacing --- docs/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/index.md b/docs/index.md index b5f80a49..fea70ef8 100644 --- a/docs/index.md +++ b/docs/index.md @@ -16,4 +16,5 @@ If you're not sure where to start, there's a suite of which can help you to get familiar with how things currently work. Love and Octocats, + The Octokit.net Team From ddb06979f24bb002fa4750c7a403feaf92ef8fcf Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Fri, 24 Oct 2014 14:37:56 -0700 Subject: [PATCH 20/36] minor tweaks --- docs/oauth-flow.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/oauth-flow.md b/docs/oauth-flow.md index 9d713460..32d702e5 100644 --- a/docs/oauth-flow.md +++ b/docs/oauth-flow.md @@ -45,11 +45,13 @@ var request = new OauthLoginRequest(clientId) var oauthLoginUrl = client.Oauth.GetGitHubLoginUrl(request); ``` -Scopes are keys which specify the permissions the application needs. If you don't specify a `Scopes` value, your application will only have read access to the user's public data (repository, user info, etc). There's lots of different scopes available for different interactions with user data, so have a look at the [documentation](https://developer.github.com/v3/oauth/#scopes). +Scopes are keys which specify the permissions the application needs. If you don't specify a `Scopes` value, your application will only have read access to the user's public data (repository, user info, etc). There's lots of different scopes available for different interactions with user data, so have a look at the [documentation](https://developer.github.com/v3/oauth/#scopes) for more information. ### Generating the token -Once the user has been navigated to the URL above and clicked "Authorize Application", you will receive a callback at the default Callback URL for your application. You can override this by specifying a different URL when creating the request, if necessary. +Once the user has been navigated to the URL above and clicked "Authorize Application", you will receive a callback at the default Callback URL for your application. If you require a more flexible URL, you can override this by specifying a different URL when creating the request. + + Your callback will have two parameters, the code generated by the GitHub API and some additional state - this is specifically to prevent CSRF (Cross-Site Request Forgery) attacks and is highly recommended. From 5f4d81d4c0d3c706b1809036008995ca388344ba Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Fri, 24 Oct 2014 14:41:37 -0700 Subject: [PATCH 21/36] a few more tweaks --- docs/oauth-flow.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/oauth-flow.md b/docs/oauth-flow.md index 32d702e5..5b29ce89 100644 --- a/docs/oauth-flow.md +++ b/docs/oauth-flow.md @@ -51,11 +51,17 @@ Scopes are keys which specify the permissions the application needs. If you don' Once the user has been navigated to the URL above and clicked "Authorize Application", you will receive a callback at the default Callback URL for your application. If you require a more flexible URL, you can override this by specifying a different URL when creating the request. +``` +var request = new OauthLoginRequest(clientId) +{ + // other parameters + RedirectUri = new Url("https://mycoolsite.com/some/uri") +}; +``` +The callback will have two parameters, the code generated by the GitHub API and some additional state - this is specifically to prevent CSRF (Cross-Site Request Forgery) attacks and is highly recommended. -Your callback will have two parameters, the code generated by the GitHub API and some additional state - this is specifically to prevent CSRF (Cross-Site Request Forgery) attacks and is highly recommended. - -With this code you can then request an access token by providing your client secret. This doesn't require any user interaction, so can be done in the background. +With this code you can then request an access token by providing your client secret. This doesn't require any user interaction, so it can be done in the background. ``` public async Task Authorize(string code, string state) @@ -91,4 +97,4 @@ public async Task Index() /* TODO: all the rest of the webapp */ } -``` +``` \ No newline at end of file From 02d71f349f971bd8bfd29f2f548c1fac9c1128f5 Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Fri, 24 Oct 2014 14:43:32 -0700 Subject: [PATCH 22/36] updated home page --- docs/index.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/index.md b/docs/index.md index fea70ef8..62c6cf62 100644 --- a/docs/index.md +++ b/docs/index.md @@ -2,12 +2,16 @@ This is a place for putting together some introductory documentation about how to use Octokit.net. + - [Getting Started](https://github.com/octokit/octokit.net/blob/master/docs/getting-started.md) + - [OAuth Flow](https://github.com/octokit/octokit.net/blob/master/docs/oauth-flow.md) + - [Releases API](https://github.com/octokit/octokit.net/blob/master/docs/releases.md) + - [Git Database API](https://github.com/octokit/octokit.net/blob/master/docs/releases.md) + + Possible topics to cover: - - Authentication - Working with Repositories - Working with User data - - Working with Git data - Searching Repositories - ... From dd712ff0e91b1339065402704f35e2ce400b2282 Mon Sep 17 00:00:00 2001 From: Haacked Date: Fri, 24 Oct 2014 15:27:23 -0700 Subject: [PATCH 23/36] Made some minor style changes --- Octokit.Tests/Clients/SearchClientTests.cs | 6 ++-- Octokit/Models/Request/BaseSearchRequest.cs | 14 +++++---- .../Request/SearchRepositoriesRequest.cs | 29 +++++++------------ 3 files changed, 21 insertions(+), 28 deletions(-) diff --git a/Octokit.Tests/Clients/SearchClientTests.cs b/Octokit.Tests/Clients/SearchClientTests.cs index cfc25ac4..9f0ce20d 100644 --- a/Octokit.Tests/Clients/SearchClientTests.cs +++ b/Octokit.Tests/Clients/SearchClientTests.cs @@ -1,9 +1,7 @@ using System; -using System.Threading.Tasks; -using NSubstitute; -using Octokit.Tests.Helpers; -using Xunit; using System.Collections.Generic; +using NSubstitute; +using Xunit; namespace Octokit.Tests.Clients { diff --git a/Octokit/Models/Request/BaseSearchRequest.cs b/Octokit/Models/Request/BaseSearchRequest.cs index a5ac304c..be140d5f 100644 --- a/Octokit/Models/Request/BaseSearchRequest.cs +++ b/Octokit/Models/Request/BaseSearchRequest.cs @@ -11,7 +11,7 @@ namespace Octokit [SuppressMessage("Microsoft.Design", "CA1012:AbstractTypesShouldNotHaveConstructors")] public abstract class BaseSearchRequest { - public BaseSearchRequest(string term) + protected BaseSearchRequest(string term) { Ensure.ArgumentNotNullOrEmptyString(term, "term"); Term = term; @@ -80,15 +80,17 @@ namespace Octokit { get { - var d = new Dictionary(); - d.Add("page", Page.ToString(CultureInfo.CurrentCulture)); - d.Add("per_page", PerPage.ToString(CultureInfo.CurrentCulture)); + var d = new Dictionary + { + { "page", Page.ToString(CultureInfo.CurrentCulture) } + , { "per_page", PerPage.ToString(CultureInfo.CurrentCulture) } + , { "order", SortOrder } + , { "q", TermAndQualifiers } + }; if (!String.IsNullOrWhiteSpace(Sort)) { d.Add("sort", Sort); } - d.Add("order", SortOrder); - d.Add("q", TermAndQualifiers); return d; } } diff --git a/Octokit/Models/Request/SearchRepositoriesRequest.cs b/Octokit/Models/Request/SearchRepositoriesRequest.cs index dd7537ab..c3b4d4cc 100644 --- a/Octokit/Models/Request/SearchRepositoriesRequest.cs +++ b/Octokit/Models/Request/SearchRepositoriesRequest.cs @@ -187,7 +187,7 @@ namespace Octokit [SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.Int32.ToString")] public Range(int size) { - query = size.ToString(); + query = size.ToString(CultureInfo.InvariantCulture); } /// @@ -195,34 +195,30 @@ namespace Octokit /// /// /// - [SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.String.Format(System.String,System.Object[])"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.String.Format(System.String,System.Object,System.Object)"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.Int32.ToString")] public Range(int minSize, int maxSize) { - query = string.Format("{0}..{1}", minSize, maxSize); + query = string.Format(CultureInfo.InvariantCulture, "{0}..{1}", minSize, maxSize); } /// /// Matches repositories with regards to the size /// We will use the to see what operator will be applied to the size qualifier /// - [SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.String.Format(System.String,System.Object[])"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.Int32.ToString"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.String.Format(System.String,System.Object)")] public Range(int size, SearchQualifierOperator op) { switch (op) { case SearchQualifierOperator.GreaterThan: - query = string.Format(">{0}", size.ToString()); + query = string.Format(CultureInfo.InvariantCulture, ">{0}", size); break; case SearchQualifierOperator.LessThan: - query = string.Format("<{0}", size.ToString()); + query = string.Format(CultureInfo.InvariantCulture, "<{0}", size); break; case SearchQualifierOperator.LessThanOrEqualTo: - query = string.Format("<={0}", size.ToString()); + query = string.Format(CultureInfo.InvariantCulture, "<={0}", size); break; case SearchQualifierOperator.GreaterThanOrEqualTo: - query = string.Format(">={0}", size.ToString()); - break; - default: + query = string.Format(CultureInfo.InvariantCulture, ">={0}", size); break; } } @@ -271,7 +267,7 @@ namespace Octokit /// public class DateRange { - private string query = string.Empty; + private readonly string query = string.Empty; /// /// Matches repositories with regards to the date @@ -279,24 +275,21 @@ namespace Octokit /// /// The date /// And its search operator - [SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.String.Format(System.String,System.Object[])"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.DateTime.ToString(System.String)"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.String.Format(System.String,System.Object)")] public DateRange(DateTime date, SearchQualifierOperator op) { switch (op) { case SearchQualifierOperator.GreaterThan: - query = string.Format(">{0}", date.ToString("yyyy-MM-dd")); + query = string.Format(CultureInfo.InvariantCulture, ">{0:yyyy-MM-dd}", date); break; case SearchQualifierOperator.LessThan: - query = string.Format("<{0}", date.ToString("yyyy-MM-dd")); + query = string.Format(CultureInfo.InvariantCulture, "<{0:yyyy-MM-dd}", date); break; case SearchQualifierOperator.LessThanOrEqualTo: - query = string.Format("<={0}", date.ToString("yyyy-MM-dd")); + query = string.Format(CultureInfo.InvariantCulture, "<={0:yyyy-MM-dd}", date); break; case SearchQualifierOperator.GreaterThanOrEqualTo: - query = string.Format(">={0}", date.ToString("yyyy-MM-dd")); - break; - default: + query = string.Format(CultureInfo.InvariantCulture, ">={0:yyyy-MM-dd}", date); break; } } From bd08ba56136963dab5283deabf67cfe3876bb8ac Mon Sep 17 00:00:00 2001 From: Haacked Date: Fri, 24 Oct 2014 16:59:29 -0700 Subject: [PATCH 24/36] Change ProductHeaderValue to be more sane The member variable should be readonly. We were setting it outside a ctor via a static method, but that's not the right approach. I fixed it. --- Octokit/Http/ProductHeaderValue.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Octokit/Http/ProductHeaderValue.cs b/Octokit/Http/ProductHeaderValue.cs index 0881f417..7e333c29 100644 --- a/Octokit/Http/ProductHeaderValue.cs +++ b/Octokit/Http/ProductHeaderValue.cs @@ -2,19 +2,22 @@ { public class ProductHeaderValue { - ProductHeaderValue() { } + readonly System.Net.Http.Headers.ProductHeaderValue _productHeaderValue; public ProductHeaderValue(string name) + : this(new System.Net.Http.Headers.ProductHeaderValue(name)) { - _productHeaderValue = new System.Net.Http.Headers.ProductHeaderValue(name); } public ProductHeaderValue(string name, string value) + : this(new System.Net.Http.Headers.ProductHeaderValue(name, value)) { - _productHeaderValue = new System.Net.Http.Headers.ProductHeaderValue(name, value); } - System.Net.Http.Headers.ProductHeaderValue _productHeaderValue; + ProductHeaderValue(System.Net.Http.Headers.ProductHeaderValue productHeader) + { + _productHeaderValue = productHeader; + } public string Name { @@ -43,7 +46,7 @@ public static ProductHeaderValue Parse(string input) { - return new ProductHeaderValue { _productHeaderValue = System.Net.Http.Headers.ProductHeaderValue.Parse(input) }; + return new ProductHeaderValue(System.Net.Http.Headers.ProductHeaderValue.Parse(input)); } public static bool TryParse(string input, From dcf6c427f56a1d1137cf5313f0be4fce240f7729 Mon Sep 17 00:00:00 2001 From: Cameron Taggart Date: Tue, 4 Nov 2014 10:18:37 -0800 Subject: [PATCH 25/36] add source indexing using SourceLink --- .gitignore | 1 + build.cmd | 1 + build.fsx | 32 +++++++++++++++++++++++++++++--- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index b9089361..46146168 100644 --- a/.gitignore +++ b/.gitignore @@ -69,4 +69,5 @@ nunit-*.xml *.userprefs packaging/ tools/FAKE.Core +tools/SourceLink.Fake *.ncrunch* \ No newline at end of file diff --git a/build.cmd b/build.cmd index 0689b3f0..35a9d8d7 100644 --- a/build.cmd +++ b/build.cmd @@ -1,6 +1,7 @@ @echo off "tools\nuget\nuget.exe" "install" "FAKE.Core" "-OutputDirectory" "tools" "-ExcludeVersion" "-version" "2.18.1" +"tools\nuget\nuget.exe" "install" "SourceLink.Fake" "-OutputDirectory" "tools" "-ExcludeVersion" "-version" "0.4.2" :Build cls diff --git a/build.fsx b/build.fsx index 07a73b1d..9ccf1652 100644 --- a/build.fsx +++ b/build.fsx @@ -1,6 +1,8 @@ #r @"tools\FAKE.Core\tools\FakeLib.dll" +#load "tools/SourceLink.Fake/tools/SourceLink.fsx" open Fake open System +open SourceLink let authors = ["GitHub"] @@ -94,6 +96,24 @@ Target "IntegrationTests" (fun _ -> |> traceImportant ) +Target "SourceLink" (fun _ -> + if Pdbstr.tryFind().IsSome then + use repo = new GitRepo(__SOURCE_DIRECTORY__) + [ "Octokit/Octokit.csproj" + "Octokit/Octokit-netcore45.csproj" + "Octokit/Octokit-Portable.csproj" + "Octokit.Reactive/Octokit.Reactive.csproj" ] + |> Seq.iter (fun pf -> + let proj = VsProj.LoadRelease pf + logfn "source linking %s" proj.OutputFilePdb + let files = (proj.Compiles -- "SolutionInfo.cs").SetBaseDirectory __SOURCE_DIRECTORY__ + repo.VerifyChecksums files + proj.VerifyPdbChecksums files + proj.CreateSrcSrv "https://raw.githubusercontent.com/octokit/octokit.net/{0}/%var2%" repo.Revision (repo.Paths files) + Pdbstr.exec proj.OutputFilePdb proj.OutputFilePdbSrcSrv + ) +) + Target "CreateOctokitPackage" (fun _ -> let net45Dir = packagingDir @@ "lib/net45/" let netcore45Dir = packagingDir @@ "lib/netcore45/" @@ -101,8 +121,11 @@ Target "CreateOctokitPackage" (fun _ -> CleanDirs [net45Dir; netcore45Dir; portableDir] CopyFile net45Dir (buildDir @@ "Release/Net45/Octokit.dll") + CopyFile net45Dir (buildDir @@ "Release/Net45/Octokit.pdb") CopyFile netcore45Dir (buildDir @@ "Release/NetCore45/Octokit.dll") + CopyFile netcore45Dir (buildDir @@ "Release/NetCore45/Octokit.pdb") CopyFile portableDir (buildDir @@ "Release/Portable/Octokit.dll") + CopyFile portableDir (buildDir @@ "Release/Portable/Octokit.pdb") CopyFiles packagingDir ["LICENSE.txt"; "README.md"; "ReleaseNotes.md"] NuGet (fun p -> @@ -124,6 +147,7 @@ Target "CreateOctokitReactivePackage" (fun _ -> CleanDirs [net45Dir] CopyFile net45Dir (reactiveBuildDir @@ "Release/Net45/Octokit.Reactive.dll") + CopyFile net45Dir (reactiveBuildDir @@ "Release/Net45/Octokit.Reactive.pdb") CopyFiles reactivePackagingDir ["LICENSE.txt"; "README.md"; "ReleaseNotes.md"] NuGet (fun p -> @@ -150,7 +174,7 @@ Target "CreatePackages" DoNothing "Clean" ==> "AssemblyInfo" ==> "CheckProjects" - ==> "BuildApp" + ==> "BuildApp" "UnitTests" ==> "Default" @@ -161,9 +185,11 @@ Target "CreatePackages" DoNothing "IntegrationTests" ==> "Default" -"CreateOctokitPackage" +"SourceLink" + ==> "CreateOctokitPackage" ==> "CreatePackages" -"CreateOctokitReactivePackage" +"SourceLink" + ==> "CreateOctokitReactivePackage" ==> "CreatePackages" RunTargetOrDefault "Default" From 124dd7f689d64c5e022c1816f84c1e0faa88d6b4 Mon Sep 17 00:00:00 2001 From: Cameron Taggart Date: Tue, 4 Nov 2014 11:24:57 -0800 Subject: [PATCH 26/36] add an appveyor.yml --- Octokit.sln | 3 ++- appveyor.yml | 11 +++++++++++ build.fsx | 6 ++---- 3 files changed, 15 insertions(+), 5 deletions(-) create mode 100644 appveyor.yml diff --git a/Octokit.sln b/Octokit.sln index d1b5316a..2ce3e07e 100644 --- a/Octokit.sln +++ b/Octokit.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 -VisualStudioVersion = 12.0.21005.1 +VisualStudioVersion = 12.0.30723.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Octokit", "Octokit\Octokit.csproj", "{08DD4305-7787-4823-A53F-4D0F725A07F3}" EndProject @@ -11,6 +11,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Octokit.Tests.Integration", EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{CEC9D451-6291-4EDF-971A-D398144FBF96}" ProjectSection(SolutionItems) = preProject + appveyor.yml = appveyor.yml build.cmd = build.cmd build.fsx = build.fsx script\cibuild.ps1 = script\cibuild.ps1 diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 00000000..67dcba0d --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,11 @@ +init: + - git config --global core.autocrlf input +build_script: + - cmd: build.cmd BuildApp + - cmd: build.cmd UnitTests + #- cmd: build.cmd IntegrationTests + - cmd: build.cmd SourceLink + - cmd: build.cmd CreateOctokitPackage +test: off +artifacts: + - path: packaging\*.nupkg diff --git a/build.fsx b/build.fsx index 9ccf1652..f4000391 100644 --- a/build.fsx +++ b/build.fsx @@ -185,11 +185,9 @@ Target "CreatePackages" DoNothing "IntegrationTests" ==> "Default" -"SourceLink" - ==> "CreateOctokitPackage" +"CreateOctokitPackage" ==> "CreatePackages" -"SourceLink" - ==> "CreateOctokitReactivePackage" +"CreateOctokitReactivePackage" ==> "CreatePackages" RunTargetOrDefault "Default" From daa7f91425c153375f19c2d39dea354138dee178 Mon Sep 17 00:00:00 2001 From: Cameron Taggart Date: Tue, 4 Nov 2014 11:33:23 -0800 Subject: [PATCH 27/36] enable IntegrationTests --- appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 67dcba0d..c96785dc 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -3,9 +3,9 @@ init: build_script: - cmd: build.cmd BuildApp - cmd: build.cmd UnitTests - #- cmd: build.cmd IntegrationTests + - cmd: build.cmd IntegrationTests - cmd: build.cmd SourceLink - - cmd: build.cmd CreateOctokitPackage + - cmd: build.cmd CreatePackages test: off artifacts: - path: packaging\*.nupkg From 9bc1a256567422cd1cf37b72a558d0f48ac6fb06 Mon Sep 17 00:00:00 2001 From: Cameron Taggart Date: Tue, 4 Nov 2014 11:44:15 -0800 Subject: [PATCH 28/36] MSBuildVerbosity.Minimal --- build.fsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.fsx b/build.fsx index f4000391..d2b04114 100644 --- a/build.fsx +++ b/build.fsx @@ -29,6 +29,8 @@ let releaseNotes = let buildMode = getBuildParamOrDefault "buildMode" "Release" +MSBuildDefaults <- { MSBuildDefaults with Verbosity = Some MSBuildVerbosity.Minimal } + Target "Clean" (fun _ -> CleanDirs [buildDir; reactiveBuildDir; testResultsDir; packagingRoot; packagingDir; reactivePackagingDir] ) From 1ad87b552de03b5355ccb87ec5cad13d88b26187 Mon Sep 17 00:00:00 2001 From: Cameron Taggart Date: Tue, 4 Nov 2014 11:54:49 -0800 Subject: [PATCH 29/36] don't buildapp again when creatin the packages --- appveyor.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index c96785dc..3547da5a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -5,7 +5,9 @@ build_script: - cmd: build.cmd UnitTests - cmd: build.cmd IntegrationTests - cmd: build.cmd SourceLink - - cmd: build.cmd CreatePackages + #- cmd: build.cmd CreatePackages + - cmd: build.cmd CreateOctokitPackage + - cmd: build.cmd CreateOctokitReactivePackage test: off artifacts: - path: packaging\*.nupkg From 20249c237f129d7794c0e5554111825d09b36734 Mon Sep 17 00:00:00 2001 From: Cameron Taggart Date: Tue, 4 Nov 2014 12:29:13 -0800 Subject: [PATCH 30/36] pass in auth variables for integration tests --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 3547da5a..8032b982 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -3,7 +3,7 @@ init: build_script: - cmd: build.cmd BuildApp - cmd: build.cmd UnitTests - - cmd: build.cmd IntegrationTests + - cmd: build.cmd IntegrationTests -ev OCTOKIT_GITHUBUSERNAME "%OCTOKIT_GITHUBUSERNAME%" -ev OCTOKIT_GITHUBPASSWORD "%OCTOKIT_GITHUBPASSWORD%" - cmd: build.cmd SourceLink #- cmd: build.cmd CreatePackages - cmd: build.cmd CreateOctokitPackage From d0fffd4f7ccc5b72b46b4774df4f2c53a04930ef Mon Sep 17 00:00:00 2001 From: Cameron Taggart Date: Wed, 5 Nov 2014 14:47:56 -0800 Subject: [PATCH 31/36] don't skip running SourceLink silently --- build.fsx | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/build.fsx b/build.fsx index d2b04114..4a734ea6 100644 --- a/build.fsx +++ b/build.fsx @@ -99,21 +99,20 @@ Target "IntegrationTests" (fun _ -> ) Target "SourceLink" (fun _ -> - if Pdbstr.tryFind().IsSome then - use repo = new GitRepo(__SOURCE_DIRECTORY__) - [ "Octokit/Octokit.csproj" - "Octokit/Octokit-netcore45.csproj" - "Octokit/Octokit-Portable.csproj" - "Octokit.Reactive/Octokit.Reactive.csproj" ] - |> Seq.iter (fun pf -> - let proj = VsProj.LoadRelease pf - logfn "source linking %s" proj.OutputFilePdb - let files = (proj.Compiles -- "SolutionInfo.cs").SetBaseDirectory __SOURCE_DIRECTORY__ - repo.VerifyChecksums files - proj.VerifyPdbChecksums files - proj.CreateSrcSrv "https://raw.githubusercontent.com/octokit/octokit.net/{0}/%var2%" repo.Revision (repo.Paths files) - Pdbstr.exec proj.OutputFilePdb proj.OutputFilePdbSrcSrv - ) + use repo = new GitRepo(__SOURCE_DIRECTORY__) + [ "Octokit/Octokit.csproj" + "Octokit/Octokit-netcore45.csproj" + "Octokit/Octokit-Portable.csproj" + "Octokit.Reactive/Octokit.Reactive.csproj" ] + |> Seq.iter (fun pf -> + let proj = VsProj.LoadRelease pf + logfn "source linking %s" proj.OutputFilePdb + let files = (proj.Compiles -- "SolutionInfo.cs").SetBaseDirectory __SOURCE_DIRECTORY__ + repo.VerifyChecksums files + proj.VerifyPdbChecksums files + proj.CreateSrcSrv "https://raw.githubusercontent.com/octokit/octokit.net/{0}/%var2%" repo.Revision (repo.Paths files) + Pdbstr.exec proj.OutputFilePdb proj.OutputFilePdbSrcSrv + ) ) Target "CreateOctokitPackage" (fun _ -> From 24f6d4dd8762166eb648a63a2f712b0140e32991 Mon Sep 17 00:00:00 2001 From: Haacked Date: Fri, 7 Nov 2014 14:50:08 -0800 Subject: [PATCH 32/36] Fix Markdown test The markdown api adds a trailing newline if there isn't already one. It also converts \r\n to \n. --- Octokit.Tests.Integration/Clients/MiscellaneousClientTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Octokit.Tests.Integration/Clients/MiscellaneousClientTests.cs b/Octokit.Tests.Integration/Clients/MiscellaneousClientTests.cs index c415060d..f5f46b99 100644 --- a/Octokit.Tests.Integration/Clients/MiscellaneousClientTests.cs +++ b/Octokit.Tests.Integration/Clients/MiscellaneousClientTests.cs @@ -31,9 +31,9 @@ public class MiscellaneousClientTests Credentials = Helper.Credentials }; - var result = await github.Miscellaneous.RenderRawMarkdown("This is a **test**"); + var result = await github.Miscellaneous.RenderRawMarkdown("This is\r\n a **test**"); - Assert.Equal("

This is a test

", result); + Assert.Equal("

This is\n a test

\n", result); } } } From 3b39d0d95a881d77af740ad2b7a6bcc3ba40f916 Mon Sep 17 00:00:00 2001 From: Haacked Date: Fri, 7 Nov 2014 15:29:07 -0800 Subject: [PATCH 33/36] Fixed some async void tests These tests weren't getting run. --- .../Clients/PullRequestsClientTests.cs | 7 ++++--- .../ObservablePullRequestsClientTests.cs | 19 +++++++++++++++++-- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/Octokit.Tests/Clients/PullRequestsClientTests.cs b/Octokit.Tests/Clients/PullRequestsClientTests.cs index 74da3e0f..51148e7e 100644 --- a/Octokit.Tests/Clients/PullRequestsClientTests.cs +++ b/Octokit.Tests/Clients/PullRequestsClientTests.cs @@ -195,14 +195,15 @@ namespace Octokit.Tests.Clients public class TheCommitsMethod { [Fact] - public async void RequestsCorrectUrl() + public async Task RequestsCorrectUrl() { var connection = Substitute.For(); var client = new PullRequestsClient(connection); - client.Commits("fake", "repo", 42); + await client.Commits("fake", "repo", 42); - connection.Received().GetAll(Arg.Is(u => u.ToString() == "repos/fake/repo/pulls/42/commits")); + connection.Received() + .GetAll(Arg.Is(u => u.ToString() == "repos/fake/repo/pulls/42/commits")); } [Fact] diff --git a/Octokit.Tests/Reactive/ObservablePullRequestsClientTests.cs b/Octokit.Tests/Reactive/ObservablePullRequestsClientTests.cs index c38a964d..36c2b80a 100644 --- a/Octokit.Tests/Reactive/ObservablePullRequestsClientTests.cs +++ b/Octokit.Tests/Reactive/ObservablePullRequestsClientTests.cs @@ -275,16 +275,31 @@ namespace Octokit.Tests.Reactive public class TheCommitsMethod { [Fact] - public async void FetchesAllCommitsForPullRequest() + public async Task FetchesAllCommitsForPullRequest() { + var commit = new PullRequestCommit(); var expectedUrl = string.Format("repos/fake/repo/pulls/42/commits"); var gitHubClient = Substitute.For(); var connection = Substitute.For(); + IResponse> response = new ApiResponse> + { + ApiInfo = new ApiInfo( + new Dictionary(), + new List(), + new List(), + "", + new RateLimit(new Dictionary())), + BodyAsObject = new List { commit } + }; + connection.Get>(Args.Uri, null, null) + .Returns(Task.FromResult(response)); gitHubClient.Connection.Returns(connection); var client = new ObservablePullRequestsClient(gitHubClient); - client.Commits("fake", "repo", 42); + var commits = await client.Commits("fake", "repo", 42).ToList(); + Assert.Equal(1, commits.Count); + Assert.Same(commit, commits[0]); connection.Received().Get>(new Uri(expectedUrl, UriKind.Relative), null, null); } From 6be4c50e607a474ae3f965c45e49ea244e5f674f Mon Sep 17 00:00:00 2001 From: Haacked Date: Fri, 7 Nov 2014 16:01:20 -0800 Subject: [PATCH 34/36] Stop requesting ALL public gists We don't need this in our integration tests. --- .../Clients/GistsClientTests.cs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/Octokit.Tests.Integration/Clients/GistsClientTests.cs b/Octokit.Tests.Integration/Clients/GistsClientTests.cs index b7d1f6bf..7345da20 100644 --- a/Octokit.Tests.Integration/Clients/GistsClientTests.cs +++ b/Octokit.Tests.Integration/Clients/GistsClientTests.cs @@ -2,6 +2,7 @@ using System.Linq; using System.Threading.Tasks; using Octokit; +using Octokit.Tests.Helpers; using Octokit.Tests.Integration; using Xunit; @@ -103,15 +104,8 @@ public class GistsClientTests Assert.True(gists.Count > 0); // Make sure we can successfully request gists for another user - Assert.DoesNotThrow(async () => { await _fixture.GetAllForUser("FakeHaacked"); }); - Assert.DoesNotThrow(async () => { await _fixture.GetAllForUser("FakeHaacked", startTime); }); - - // Test public gists - var publicGists = await _fixture.GetAllPublic(); - Assert.True(publicGists.Count > 1); - - var publicGistsSinceStartTime = await _fixture.GetAllPublic(startTime); - Assert.True(publicGistsSinceStartTime.Count > 0); + await _fixture.GetAllForUser("FakeHaacked"); + await _fixture.GetAllForUser("FakeHaacked", startTime); // Test starred gists await _fixture.Star(createdGist.Id); From 1b4d02b1427f592df5c9ea6457f7d275bbc0a93f Mon Sep 17 00:00:00 2001 From: Haacked Date: Fri, 7 Nov 2014 16:05:53 -0800 Subject: [PATCH 35/36] Ensure no async void methods Added self tests to find async void methods. It found some cases where we passed an async lambda to a method that did not accept Action or Func. I fixed those tests. --- .../Clients/GistsClientTests.cs | 2 +- .../PullRequestReviewCommentsClientTests.cs | 2 +- .../Clients/RepositoriesClientTests.cs | 2 +- .../Octokit.Tests.Integration.csproj | 1 + Octokit.Tests.Integration/SelfTests.cs | 17 ++++++++ Octokit.Tests/Helpers/ReflectionExtensions.cs | 39 +++++++++++++++++++ Octokit.Tests/Octokit.Tests.csproj | 2 + Octokit.Tests/SelfTests.cs | 14 +++++++ Octokit/Octokit-Portable.csproj | 2 +- 9 files changed, 77 insertions(+), 4 deletions(-) create mode 100644 Octokit.Tests.Integration/SelfTests.cs create mode 100644 Octokit.Tests/Helpers/ReflectionExtensions.cs create mode 100644 Octokit.Tests/SelfTests.cs diff --git a/Octokit.Tests.Integration/Clients/GistsClientTests.cs b/Octokit.Tests.Integration/Clients/GistsClientTests.cs index 7345da20..b8690c1c 100644 --- a/Octokit.Tests.Integration/Clients/GistsClientTests.cs +++ b/Octokit.Tests.Integration/Clients/GistsClientTests.cs @@ -55,7 +55,7 @@ public class GistsClientTests Assert.NotNull(updatedGist); Assert.Equal(updatedGist.Description, gistUpdate.Description); - Assert.DoesNotThrow(async () => { await _fixture.Delete(createdGist.Id); }); + await _fixture.Delete(createdGist.Id); } [IntegrationTest] diff --git a/Octokit.Tests.Integration/Clients/PullRequestReviewCommentsClientTests.cs b/Octokit.Tests.Integration/Clients/PullRequestReviewCommentsClientTests.cs index b06cb06e..2bd9f787 100644 --- a/Octokit.Tests.Integration/Clients/PullRequestReviewCommentsClientTests.cs +++ b/Octokit.Tests.Integration/Clients/PullRequestReviewCommentsClientTests.cs @@ -96,7 +96,7 @@ public class PullRequestReviewCommentsClientTests : IDisposable var createdComment = await CreateComment(body, position, pullRequest.Sha, pullRequest.Number); - Assert.DoesNotThrow(async () => { await _client.Delete(Helper.UserName, _repository.Name, createdComment.Id); }); + await _client.Delete(Helper.UserName, _repository.Name, createdComment.Id); } [IntegrationTest] diff --git a/Octokit.Tests.Integration/Clients/RepositoriesClientTests.cs b/Octokit.Tests.Integration/Clients/RepositoriesClientTests.cs index 5986788c..ec334c5a 100644 --- a/Octokit.Tests.Integration/Clients/RepositoriesClientTests.cs +++ b/Octokit.Tests.Integration/Clients/RepositoriesClientTests.cs @@ -501,7 +501,7 @@ public class RepositoriesClientTests var repoName = Helper.MakeNameWithTimestamp("repo-to-delete"); await github.Repository.Create(new NewRepository { Name = repoName }); - Assert.DoesNotThrow(async () => { await github.Repository.Delete(Helper.UserName, repoName); }); + await github.Repository.Delete(Helper.UserName, repoName); } } diff --git a/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj b/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj index 2c11df59..aaec3359 100644 --- a/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj +++ b/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj @@ -101,6 +101,7 @@ + diff --git a/Octokit.Tests.Integration/SelfTests.cs b/Octokit.Tests.Integration/SelfTests.cs new file mode 100644 index 00000000..b2362323 --- /dev/null +++ b/Octokit.Tests.Integration/SelfTests.cs @@ -0,0 +1,17 @@ +using Xunit; + +namespace Octokit.Tests.Integration +{ + /// + /// Tests to make sure our tests are ok. + /// + public class SelfTests + { + [Fact] + public void NoTestsUseAsyncVoid() + { + var errors = typeof(SelfTests).Assembly.GetAsyncVoidMethodsList(); + Assert.Equal("", errors); + } + } +} diff --git a/Octokit.Tests/Helpers/ReflectionExtensions.cs b/Octokit.Tests/Helpers/ReflectionExtensions.cs new file mode 100644 index 00000000..6446d811 --- /dev/null +++ b/Octokit.Tests/Helpers/ReflectionExtensions.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; + +public static class ReflectionExtensions +{ + public static string GetAsyncVoidMethodsList(this Assembly assembly) + { + return String.Join("\r\n", + GetLoadableTypes(assembly) + .SelectMany(type => type.GetMethods()) + .Where(HasAttribute) + .Where(method => method.ReturnType == typeof(void)) + .Select(method => + String.Format("Method '{0}' of '{1}' has an async void return type and that's bad", + method.Name, + method.DeclaringType.Name)) + .ToList()); + } + + public static IEnumerable GetLoadableTypes(this Assembly assembly) + { + try + { + return assembly.GetTypes(); + } + catch (ReflectionTypeLoadException e) + { + return e.Types.Where(t => t != null); + } + } + + public static bool HasAttribute(this MethodInfo method) where TAttribute : Attribute + { + return method.GetCustomAttributes(typeof(TAttribute), false).Any(); + } +} diff --git a/Octokit.Tests/Octokit.Tests.csproj b/Octokit.Tests/Octokit.Tests.csproj index 89a7ff81..35876386 100644 --- a/Octokit.Tests/Octokit.Tests.csproj +++ b/Octokit.Tests/Octokit.Tests.csproj @@ -110,6 +110,7 @@ + @@ -170,6 +171,7 @@ + diff --git a/Octokit.Tests/SelfTests.cs b/Octokit.Tests/SelfTests.cs new file mode 100644 index 00000000..30b554fd --- /dev/null +++ b/Octokit.Tests/SelfTests.cs @@ -0,0 +1,14 @@ +using Xunit; + +/// +/// Tests to make sure our tests are ok. +/// +public class SelfTests +{ + [Fact] + public void NoTestsUseAsyncVoid() + { + var errors = typeof(SelfTests).Assembly.GetAsyncVoidMethodsList(); + Assert.Equal("", errors); + } +} diff --git a/Octokit/Octokit-Portable.csproj b/Octokit/Octokit-Portable.csproj index ce54f593..90e0860e 100644 --- a/Octokit/Octokit-Portable.csproj +++ b/Octokit/Octokit-Portable.csproj @@ -366,4 +366,4 @@ --> - + \ No newline at end of file From ca45ae05557f4bb9a2ee11e423085cd065929f54 Mon Sep 17 00:00:00 2001 From: Daniel Cazzulino Date: Fri, 28 Nov 2014 09:31:10 -0300 Subject: [PATCH 36/36] Include files array in the github commit. Fixes #607. --- .../Clients/RepositoryCommitsClientTests.cs | 9 +++ Octokit/Models/Response/GitHubCommit.cs | 1 + Octokit/Models/Response/GitHubCommitFile.cs | 68 +++++++++++++++++++ Octokit/Octokit-Mono.csproj | 1 + Octokit/Octokit-MonoAndroid.csproj | 1 + Octokit/Octokit-Monotouch.csproj | 3 +- Octokit/Octokit-Portable.csproj | 1 + Octokit/Octokit-netcore45.csproj | 1 + Octokit/Octokit.csproj | 1 + 9 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 Octokit/Models/Response/GitHubCommitFile.cs diff --git a/Octokit.Tests.Integration/Clients/RepositoryCommitsClientTests.cs b/Octokit.Tests.Integration/Clients/RepositoryCommitsClientTests.cs index f8623667..7013c2cc 100644 --- a/Octokit.Tests.Integration/Clients/RepositoryCommitsClientTests.cs +++ b/Octokit.Tests.Integration/Clients/RepositoryCommitsClientTests.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Reactive.Threading.Tasks; using System.Threading.Tasks; using Octokit; @@ -33,6 +34,14 @@ public class RepositoryCommitsClientTests : IDisposable Assert.NotNull(commit); } + [IntegrationTest] + public async Task CanGetCommitWithFiles() + { + var commit = await _fixture.Get("octokit", "octokit.net", "65a22f4d2cff94a286ac3e96440c810c5509196f"); + + Assert.True(commit.Files.Any(file => file.Filename.EndsWith("IConnection.cs"))); + } + [IntegrationTest] public async Task CanGetListOfCommits() { diff --git a/Octokit/Models/Response/GitHubCommit.cs b/Octokit/Models/Response/GitHubCommit.cs index 31591039..537df885 100644 --- a/Octokit/Models/Response/GitHubCommit.cs +++ b/Octokit/Models/Response/GitHubCommit.cs @@ -15,5 +15,6 @@ namespace Octokit public Author Committer { get; set; } public string HtmlUrl { get; set; } public IReadOnlyList Parents { get; set; } + public IReadOnlyList Files { get; set; } } } diff --git a/Octokit/Models/Response/GitHubCommitFile.cs b/Octokit/Models/Response/GitHubCommitFile.cs new file mode 100644 index 00000000..9f2b7995 --- /dev/null +++ b/Octokit/Models/Response/GitHubCommitFile.cs @@ -0,0 +1,68 @@ +using System; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; + +namespace Octokit +{ + /// + /// The affected files in a . + /// + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class GitHubCommitFile + { + /// + /// The name of the file + /// + [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly")] + public string Filename { get; set; } + + /// + /// Number of additions performed on the file. + /// + public int Additions { get; set; } + + /// + /// Number of deletions performed on the file. + /// + public int Deletions { get; set; } + + /// + /// Number of changes performed on the file. + /// + public int Changes { get; set; } + + /// + /// File status, like modified, added, deleted. + /// + public string Status { get; set; } + + /// + /// The url to the file blob. + /// + public string BlobUrl { get; set; } + + /// + /// The url to file contents API. + /// + public string ContentsUrl { get; set; } + + /// + /// The raw url to download the file. + /// + public string RawUrl { get; set; } + + /// + /// The SHA of the file. + /// + public string Sha { get; set; } + + internal string DebuggerDisplay + { + get + { + return String.Format(CultureInfo.InvariantCulture, "Filename: {0} ({1})", Filename, Status); + } + } + } +} \ No newline at end of file diff --git a/Octokit/Octokit-Mono.csproj b/Octokit/Octokit-Mono.csproj index f15b228e..baf71854 100644 --- a/Octokit/Octokit-Mono.csproj +++ b/Octokit/Octokit-Mono.csproj @@ -130,6 +130,7 @@ + diff --git a/Octokit/Octokit-MonoAndroid.csproj b/Octokit/Octokit-MonoAndroid.csproj index 38a0f067..8cb0de92 100644 --- a/Octokit/Octokit-MonoAndroid.csproj +++ b/Octokit/Octokit-MonoAndroid.csproj @@ -102,6 +102,7 @@ + diff --git a/Octokit/Octokit-Monotouch.csproj b/Octokit/Octokit-Monotouch.csproj index db36ecaa..5ef641a0 100644 --- a/Octokit/Octokit-Monotouch.csproj +++ b/Octokit/Octokit-Monotouch.csproj @@ -99,6 +99,7 @@ + @@ -345,5 +346,5 @@ - + \ No newline at end of file diff --git a/Octokit/Octokit-Portable.csproj b/Octokit/Octokit-Portable.csproj index 90e0860e..0ec4c506 100644 --- a/Octokit/Octokit-Portable.csproj +++ b/Octokit/Octokit-Portable.csproj @@ -221,6 +221,7 @@ + diff --git a/Octokit/Octokit-netcore45.csproj b/Octokit/Octokit-netcore45.csproj index 6fb0eb62..ab7c688f 100644 --- a/Octokit/Octokit-netcore45.csproj +++ b/Octokit/Octokit-netcore45.csproj @@ -228,6 +228,7 @@ + diff --git a/Octokit/Octokit.csproj b/Octokit/Octokit.csproj index ad2ea276..7cd0d7d0 100644 --- a/Octokit/Octokit.csproj +++ b/Octokit/Octokit.csproj @@ -77,6 +77,7 @@ +