From 535709c3689eaa6b6a4556757c11d0d50b0aae0e Mon Sep 17 00:00:00 2001 From: Ryan Gribble Date: Wed, 27 Jan 2016 00:12:22 +1000 Subject: [PATCH 01/21] Better support for GitHub Enterprise integration tests - Remove EnterpriseUrl in integration test Helper class, but leave ability to override custom URL (to allow specific use case of targetting regular integration tests at a custom URL) - Move GitHub Enterprise explicit support to a new integration helper class using new OCTOKIT_GHE_ environment variables for GHE - Change existing GitHub Enterprise integration tests and EnterpriseTestAttribute to use the new EnterpriseHelper methods - Enhance configure-intergration-tests.ps1 script to cater for environment variable changes --- .../EnterpriseAdminStatsClientTests.cs | 2 +- Octokit.Tests.Integration/EnterpriseHelper.cs | 164 ++++++++++++++++++ Octokit.Tests.Integration/Helper.cs | 26 ++- .../Helpers/GitHubEnterpriseTestAttribute.cs | 2 +- .../Octokit.Tests.Integration.csproj | 1 + ...servableEnterpriseAdminStatsClientTests.cs | 2 +- script/configure-integration-tests.ps1 | 23 ++- 7 files changed, 198 insertions(+), 22 deletions(-) create mode 100644 Octokit.Tests.Integration/EnterpriseHelper.cs diff --git a/Octokit.Tests.Integration/Clients/Enterprise/EnterpriseAdminStatsClientTests.cs b/Octokit.Tests.Integration/Clients/Enterprise/EnterpriseAdminStatsClientTests.cs index 12dc638a..2c8b1cf6 100644 --- a/Octokit.Tests.Integration/Clients/Enterprise/EnterpriseAdminStatsClientTests.cs +++ b/Octokit.Tests.Integration/Clients/Enterprise/EnterpriseAdminStatsClientTests.cs @@ -9,7 +9,7 @@ public class EnterpriseAdminStatsClientTests public EnterpriseAdminStatsClientTests() { - _github = Helper.GetAuthenticatedClient(); + _github = EnterpriseHelper.GetAuthenticatedClient(); } [GitHubEnterpriseTest] diff --git a/Octokit.Tests.Integration/EnterpriseHelper.cs b/Octokit.Tests.Integration/EnterpriseHelper.cs new file mode 100644 index 00000000..27f237d0 --- /dev/null +++ b/Octokit.Tests.Integration/EnterpriseHelper.cs @@ -0,0 +1,164 @@ +using System; +using System.Diagnostics; +using System.IO; + +namespace Octokit.Tests.Integration +{ + public static class EnterpriseHelper + { + static readonly Lazy _credentialsThunk = new Lazy(() => + { + var githubUsername = Environment.GetEnvironmentVariable("OCTOKIT_GHE_USERNAME"); + GHEUserName = githubUsername; + GHEOrganization = Environment.GetEnvironmentVariable("OCTOKIT_GHE_ORGANIZATION"); + + var githubToken = Environment.GetEnvironmentVariable("OCTOKIT_GHE_OAUTHTOKEN"); + + if (githubToken != null) + return new Credentials(githubToken); + + var githubPassword = Environment.GetEnvironmentVariable("OCTOKIT_GHE_PASSWORD"); + + if (githubUsername == null || githubPassword == null) + return null; + + return new Credentials(githubUsername, githubPassword); + }); + + static readonly Lazy _oauthApplicationCredentials = new Lazy(() => + { + var applicationClientId = ClientId; + var applicationClientSecret = ClientSecret; + + if (applicationClientId == null || applicationClientSecret == null) + return null; + + return new Credentials(applicationClientId, applicationClientSecret); + }); + + static readonly Lazy _basicAuthCredentials = new Lazy(() => + { + var githubUsername = Environment.GetEnvironmentVariable("OCTOKIT_GHE_USERNAME"); + GHEUserName = githubUsername; + GHEOrganization = Environment.GetEnvironmentVariable("OCTOKIT_GHE_ORGANIZATION"); + + var githubPassword = Environment.GetEnvironmentVariable("OCTOKIT_GHE_PASSWORD"); + + if (githubUsername == null || githubPassword == null) + return null; + + return new Credentials(githubUsername, githubPassword); + }); + + static readonly Lazy _gitHubEnterpriseEnabled = new Lazy(() => + { + string enabled = Environment.GetEnvironmentVariable("OCTOKIT_GHE_ENABLED"); + return !String.IsNullOrWhiteSpace(enabled); + }); + + static readonly Lazy _gitHubEnterpriseUrl = new Lazy(() => + { + string uri = Environment.GetEnvironmentVariable("OCTOKIT_GHE_URL"); + + if (uri != null) + return new Uri(uri); + + return null; + }); + + static EnterpriseHelper() + { + // Force reading of environment variables. + // This wasn't happening if UserName/Organization were + // retrieved before Credentials. + Debug.WriteIf(GHECredentials == null, "No credentials specified."); + } + + public static string GHEUserName { get; private set; } + public static string GHEOrganization { get; private set; } + + /// + /// These credentials should be set to a test GitHub account using the powershell script configure-integration-tests.ps1 + /// + public static Credentials GHECredentials { get { return _credentialsThunk.Value; } } + + public static Credentials GHEApplicationCredentials { get { return _oauthApplicationCredentials.Value; } } + + public static Credentials GHEBasicAuthCredentials { get { return _basicAuthCredentials.Value; } } + + public static bool IsGitHubEnterpriseEnabled { get { return _gitHubEnterpriseEnabled.Value; } } + + public static Uri GitHubEnterpriseUrl { get { return _gitHubEnterpriseUrl.Value; } } + + public static bool IsUsingToken + { + get + { + return !String.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("OCTOKIT_GHE_OAUTHTOKEN")); + } + } + + public static string ClientId + { + get { return Environment.GetEnvironmentVariable("OCTOKIT_GHE_CLIENTID"); } + } + + public static string ClientSecret + { + get { return Environment.GetEnvironmentVariable("OCTOKIT_GHE_CLIENTSECRET"); } + } + + public static void DeleteRepo(Repository repository) + { + if (repository != null) + DeleteRepo(repository.Owner.Login, repository.Name); + } + + public static void DeleteRepo(string owner, string name) + { + var api = GetAuthenticatedClient(); + try + { + api.Repository.Delete(owner, name).Wait(TimeSpan.FromSeconds(15)); + } + catch { } + } + + public static IGitHubClient GetAuthenticatedClient() + { + return new GitHubClient(new ProductHeaderValue("OctokitEnterpriseTests"), GitHubEnterpriseUrl) + { + Credentials = GHECredentials + }; + } + + public static IGitHubClient GetBasicAuthClient() + { + return new GitHubClient(new ProductHeaderValue("OctokitEnterpriseTests"), GitHubEnterpriseUrl) + { + Credentials = GHEBasicAuthCredentials + }; + } + + public static GitHubClient GetAuthenticatedApplicationClient() + { + return new GitHubClient(new ProductHeaderValue("OctokitEnterpriseTests"), GitHubEnterpriseUrl) + { + Credentials = GHEApplicationCredentials + }; + } + + public static IGitHubClient GetAnonymousClient() + { + return new GitHubClient(new ProductHeaderValue("OctokitEnterpriseTests"), GitHubEnterpriseUrl); + } + + public static IGitHubClient GetBadCredentialsClient() + { + return new GitHubClient(new ProductHeaderValue("OctokitEnterpriseTests"), GitHubEnterpriseUrl) + { + Credentials = new Credentials(Guid.NewGuid().ToString(), "bad-password") + }; + } + } +} diff --git a/Octokit.Tests.Integration/Helper.cs b/Octokit.Tests.Integration/Helper.cs index bd118521..79a249a9 100644 --- a/Octokit.Tests.Integration/Helper.cs +++ b/Octokit.Tests.Integration/Helper.cs @@ -50,9 +50,9 @@ namespace Octokit.Tests.Integration return new Credentials(githubUsername, githubPassword); }); - static readonly Lazy _gitHubEnterpriseUrl = new Lazy(() => + static readonly Lazy _customUrl = new Lazy(() => { - string uri = Environment.GetEnvironmentVariable("OCTOKIT_GITHUBENTERPRISEURL"); + string uri = Environment.GetEnvironmentVariable("OCTOKIT_CUSTOMURL"); if (uri != null) return new Uri(uri); @@ -80,7 +80,9 @@ namespace Octokit.Tests.Integration public static Credentials BasicAuthCredentials { get { return _basicAuthCredentials.Value; } } - public static Uri GitHubEnterpriseUrl { get { return _gitHubEnterpriseUrl.Value; } } + public static Uri CustomUrl { get { return _customUrl.Value; } } + + public static Uri TargetUrl { get { return CustomUrl ?? GitHubClient.GitHubApiUrl; } } public static bool IsUsingToken { @@ -98,14 +100,6 @@ namespace Octokit.Tests.Integration } } - public static bool IsGitHubEnterprise - { - get - { - return GitHubEnterpriseUrl != null; - } - } - public static string ClientId { get { return Environment.GetEnvironmentVariable("OCTOKIT_CLIENTID"); } @@ -151,7 +145,7 @@ namespace Octokit.Tests.Integration public static IGitHubClient GetAuthenticatedClient() { - return new GitHubClient(new ProductHeaderValue("OctokitTests"), GitHubEnterpriseUrl ?? GitHubClient.GitHubApiUrl) + return new GitHubClient(new ProductHeaderValue("OctokitTests"), TargetUrl) { Credentials = Credentials }; @@ -159,7 +153,7 @@ namespace Octokit.Tests.Integration public static IGitHubClient GetBasicAuthClient() { - return new GitHubClient(new ProductHeaderValue("OctokitTests"), GitHubEnterpriseUrl ?? GitHubClient.GitHubApiUrl) + return new GitHubClient(new ProductHeaderValue("OctokitTests"), TargetUrl) { Credentials = BasicAuthCredentials }; @@ -167,7 +161,7 @@ namespace Octokit.Tests.Integration public static GitHubClient GetAuthenticatedApplicationClient() { - return new GitHubClient(new ProductHeaderValue("OctokitTests"), GitHubEnterpriseUrl ?? GitHubClient.GitHubApiUrl) + return new GitHubClient(new ProductHeaderValue("OctokitTests"), TargetUrl) { Credentials = ApplicationCredentials }; @@ -175,12 +169,12 @@ namespace Octokit.Tests.Integration public static IGitHubClient GetAnonymousClient() { - return new GitHubClient(new ProductHeaderValue("OctokitTests"), GitHubEnterpriseUrl ?? GitHubClient.GitHubApiUrl); + return new GitHubClient(new ProductHeaderValue("OctokitTests"), TargetUrl); } public static IGitHubClient GetBadCredentialsClient() { - return new GitHubClient(new ProductHeaderValue("OctokitTests"), GitHubEnterpriseUrl ?? GitHubClient.GitHubApiUrl) + return new GitHubClient(new ProductHeaderValue("OctokitTests"), TargetUrl) { Credentials = new Credentials(Guid.NewGuid().ToString(), "bad-password") }; diff --git a/Octokit.Tests.Integration/Helpers/GitHubEnterpriseTestAttribute.cs b/Octokit.Tests.Integration/Helpers/GitHubEnterpriseTestAttribute.cs index 80c1df66..938bfb46 100644 --- a/Octokit.Tests.Integration/Helpers/GitHubEnterpriseTestAttribute.cs +++ b/Octokit.Tests.Integration/Helpers/GitHubEnterpriseTestAttribute.cs @@ -20,7 +20,7 @@ namespace Octokit.Tests.Integration if (Helper.Credentials == null) return Enumerable.Empty(); - if (!Helper.IsGitHubEnterprise) + if (!EnterpriseHelper.IsGitHubEnterpriseEnabled) return Enumerable.Empty(); return new[] { new XunitTestCase(diagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), testMethod) }; diff --git a/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj b/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj index 3cbb9462..2be66be3 100644 --- a/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj +++ b/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj @@ -106,6 +106,7 @@ + diff --git a/Octokit.Tests.Integration/Reactive/Enterprise/ObservableEnterpriseAdminStatsClientTests.cs b/Octokit.Tests.Integration/Reactive/Enterprise/ObservableEnterpriseAdminStatsClientTests.cs index 2cb61234..182ad393 100644 --- a/Octokit.Tests.Integration/Reactive/Enterprise/ObservableEnterpriseAdminStatsClientTests.cs +++ b/Octokit.Tests.Integration/Reactive/Enterprise/ObservableEnterpriseAdminStatsClientTests.cs @@ -11,7 +11,7 @@ namespace Octokit.Tests.Integration public ObservableEnterpriseAdminStatsClientTests() { - _github = new ObservableGitHubClient(Helper.GetAuthenticatedClient()); + _github = new ObservableGitHubClient(EnterpriseHelper.GetAuthenticatedClient()); } [GitHubEnterpriseTest] diff --git a/script/configure-integration-tests.ps1 b/script/configure-integration-tests.ps1 index 5592c3e4..590291d9 100644 --- a/script/configure-integration-tests.ps1 +++ b/script/configure-integration-tests.ps1 @@ -19,6 +19,8 @@ function AskYesNoQuestion([string]$question, [string]$key) } Write-Host + + return ($answer -eq "Y") } function VerifyEnvironmentVariable([string]$friendlyName, [string]$key, [bool]$optional = $false) @@ -71,11 +73,26 @@ VerifyEnvironmentVariable "account name" "OCTOKIT_GITHUBUSERNAME" VerifyEnvironmentVariable "account password" "OCTOKIT_GITHUBPASSWORD" $true VerifyEnvironmentVariable "OAuth token" "OCTOKIT_OAUTHTOKEN" -AskYesNoQuestion "Do you have private repositories associated with your test account?" "OCTOKIT_PRIVATEREPOSITORIES" +AskYesNoQuestion "Do you have private repositories associated with your test account?" "OCTOKIT_PRIVATEREPOSITORIES" | Out-Null VerifyEnvironmentVariable "organization name" "OCTOKIT_GITHUBORGANIZATION" $true -VerifyEnvironmentVariable "GitHub Enterprise Server URL" "OCTOKIT_GITHUBENTERPRISEURL" $true +VerifyEnvironmentVariable "Override GitHub URL" "OCTOKIT_CUSTOMURL" $true VerifyEnvironmentVariable "application ClientID" "OCTOKIT_CLIENTID" $true -VerifyEnvironmentVariable "application Secret" "OCTOKIT_CLIENTSECRET" $true \ No newline at end of file +VerifyEnvironmentVariable "application Secret" "OCTOKIT_CLIENTSECRET" $true + + +if (AskYesNoQuestion "Do you wish to enable GitHub Enterprise (GHE) Integration Tests?" "OCTOKIT_GHE_ENABLED") +{ + VerifyEnvironmentVariable "GitHub Enterprise account name" "OCTOKIT_GHE_USERNAME" + VerifyEnvironmentVariable "GitHub Enterprise account password" "OCTOKIT_GHE_PASSWORD" $true + VerifyEnvironmentVariable "GitHub Enterprise OAuth token" "OCTOKIT_GHE_OAUTHTOKEN" + + VerifyEnvironmentVariable "GitHub Enterprise organization name" "OCTOKIT_GHE_ORGANIZATION" $true + + VerifyEnvironmentVariable "GitHub Enterprise URL" "OCTOKIT_GHE_URL" $true + + VerifyEnvironmentVariable "GitHub Enterprise application ClientID" "OCTOKIT_GHE_CLIENTID" $true + VerifyEnvironmentVariable "GitHub Enterprise application Secret" "OCTOKIT_GHE_CLIENTSECRET" $true +} \ No newline at end of file From 791074f9e2373b48fd0e01e24462043b9ad1a5fa Mon Sep 17 00:00:00 2001 From: Ryan Gribble Date: Sat, 30 Jan 2016 07:37:51 +1000 Subject: [PATCH 02/21] Implement Enterprise License API, unit tests and integration tests --- .../EnterpriseLicenseClientTests.cs | 23 +++++++ .../Octokit.Tests.Integration.csproj | 1 + .../EnterpriseLicenseClientTests.cs | 23 +++++++ Octokit.Tests/Octokit.Tests.csproj | 1 + .../Clients/Enterprise/EnterpriseClient.cs | 9 +++ .../Enterprise/EnterpriseLicenseClient.cs | 32 +++++++++ .../Clients/Enterprise/IEnterpriseClient.cs | 8 +++ .../Enterprise/IEnterpriseLicenseClient.cs | 24 +++++++ Octokit/Helpers/ApiUrls.cs | 5 ++ .../Models/Response/Enterprise/LicenseInfo.cs | 67 +++++++++++++++++++ Octokit/Octokit.csproj | 3 + 11 files changed, 196 insertions(+) create mode 100644 Octokit.Tests.Integration/Clients/Enterprise/EnterpriseLicenseClientTests.cs create mode 100644 Octokit.Tests/Clients/Enterprise/EnterpriseLicenseClientTests.cs create mode 100644 Octokit/Clients/Enterprise/EnterpriseLicenseClient.cs create mode 100644 Octokit/Clients/Enterprise/IEnterpriseLicenseClient.cs create mode 100644 Octokit/Models/Response/Enterprise/LicenseInfo.cs diff --git a/Octokit.Tests.Integration/Clients/Enterprise/EnterpriseLicenseClientTests.cs b/Octokit.Tests.Integration/Clients/Enterprise/EnterpriseLicenseClientTests.cs new file mode 100644 index 00000000..81cd97b4 --- /dev/null +++ b/Octokit.Tests.Integration/Clients/Enterprise/EnterpriseLicenseClientTests.cs @@ -0,0 +1,23 @@ +using System.Threading.Tasks; +using Octokit; +using Octokit.Tests.Integration; +using Xunit; + +public class EnterpriseLicenseClientTests +{ + readonly IGitHubClient _github; + + public EnterpriseLicenseClientTests() + { + _github = EnterpriseHelper.GetAuthenticatedClient(); + } + + [GitHubEnterpriseTest] + public async Task CanGetLicense() + { + var licenseInfo = await + _github.Enterprise.License.Get(); + + Assert.NotNull(licenseInfo); + } +} \ No newline at end of file diff --git a/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj b/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj index 2be66be3..0c17edb4 100644 --- a/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj +++ b/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj @@ -77,6 +77,7 @@ + diff --git a/Octokit.Tests/Clients/Enterprise/EnterpriseLicenseClientTests.cs b/Octokit.Tests/Clients/Enterprise/EnterpriseLicenseClientTests.cs new file mode 100644 index 00000000..947fa4a2 --- /dev/null +++ b/Octokit.Tests/Clients/Enterprise/EnterpriseLicenseClientTests.cs @@ -0,0 +1,23 @@ +using System; +using NSubstitute; +using Xunit; + +namespace Octokit.Tests.Clients +{ + public class EnterpriseLicenseClientTests + { + public class TheGetMethod + { + [Fact] + public void RequestsCorrectUrl() + { + var connection = Substitute.For(); + var client = new EnterpriseLicenseClient(connection); + + string expectedUri = "enterprise/settings/license"; + client.Get(); + connection.Received().Get(Arg.Is(u => u.ToString() == expectedUri)); + } + } + } +} diff --git a/Octokit.Tests/Octokit.Tests.csproj b/Octokit.Tests/Octokit.Tests.csproj index 5af19254..68886206 100644 --- a/Octokit.Tests/Octokit.Tests.csproj +++ b/Octokit.Tests/Octokit.Tests.csproj @@ -86,6 +86,7 @@ + diff --git a/Octokit/Clients/Enterprise/EnterpriseClient.cs b/Octokit/Clients/Enterprise/EnterpriseClient.cs index 42e1763a..70b74a5b 100644 --- a/Octokit/Clients/Enterprise/EnterpriseClient.cs +++ b/Octokit/Clients/Enterprise/EnterpriseClient.cs @@ -15,6 +15,7 @@ public EnterpriseClient(IApiConnection apiConnection) : base(apiConnection) { AdminStats = new EnterpriseAdminStatsClient(apiConnection); + License = new EnterpriseLicenseClient(apiConnection); } /// @@ -24,5 +25,13 @@ /// See the Enterprise Admin Stats API documentation for more information. /// public IEnterpriseAdminStatsClient AdminStats { get; private set; } + + /// + /// A client for GitHub's Enterprise License API + /// + /// + /// See the Enterprise License API documentation for more information. + /// + public IEnterpriseLicenseClient License { get; private set; } } } diff --git a/Octokit/Clients/Enterprise/EnterpriseLicenseClient.cs b/Octokit/Clients/Enterprise/EnterpriseLicenseClient.cs new file mode 100644 index 00000000..46638883 --- /dev/null +++ b/Octokit/Clients/Enterprise/EnterpriseLicenseClient.cs @@ -0,0 +1,32 @@ +using System.Threading.Tasks; + +namespace Octokit +{ + /// + /// A client for GitHub's Enterprise License API + /// + /// + /// See the Enterprise License API documentation for more information. + /// + public class EnterpriseLicenseClient : ApiClient, IEnterpriseLicenseClient + { + public EnterpriseLicenseClient(IApiConnection apiConnection) + : base(apiConnection) + { } + + /// + /// Gets GitHub Enterprise License Information (must be Site Admin user). + /// + /// + /// https://developer.github.com/v3/enterprise/license/#get-license-information + /// + /// The statistics. + public async Task Get() + { + var endpoint = ApiUrls.EnterpriseLicense(); + + return await ApiConnection.Get(endpoint) + .ConfigureAwait(false); + } + } +} diff --git a/Octokit/Clients/Enterprise/IEnterpriseClient.cs b/Octokit/Clients/Enterprise/IEnterpriseClient.cs index e5eff83a..1d685013 100644 --- a/Octokit/Clients/Enterprise/IEnterpriseClient.cs +++ b/Octokit/Clients/Enterprise/IEnterpriseClient.cs @@ -15,5 +15,13 @@ /// See the Enterprise Admin Stats API documentation for more information. /// IEnterpriseAdminStatsClient AdminStats { get; } + + /// + /// A client for GitHub's Enterprise License API + /// + /// + /// See the Enterprise License API documentation for more information. + /// + IEnterpriseLicenseClient License { get; } } } diff --git a/Octokit/Clients/Enterprise/IEnterpriseLicenseClient.cs b/Octokit/Clients/Enterprise/IEnterpriseLicenseClient.cs new file mode 100644 index 00000000..6e067e65 --- /dev/null +++ b/Octokit/Clients/Enterprise/IEnterpriseLicenseClient.cs @@ -0,0 +1,24 @@ +using System.Diagnostics.CodeAnalysis; +using System.Threading.Tasks; + +namespace Octokit +{ + /// + /// A client for GitHub's Enterprise License API + /// + /// + /// See the Enterprise License API documentation for more information. + /// + public interface IEnterpriseLicenseClient + { + /// + /// Gets GitHub Enterprise License Information (must be Site Admin user). + /// + /// + /// https://developer.github.com/v3/enterprise/license/#get-license-information + /// + /// The statistics. + [SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "Get")] + Task Get(); + } +} diff --git a/Octokit/Helpers/ApiUrls.cs b/Octokit/Helpers/ApiUrls.cs index efc680b3..b2ee1b6b 100644 --- a/Octokit/Helpers/ApiUrls.cs +++ b/Octokit/Helpers/ApiUrls.cs @@ -1652,5 +1652,10 @@ namespace Octokit { return EnterpriseAdminStats("all"); } + + public static Uri EnterpriseLicense() + { + return "enterprise/settings/license".FormatUri(); + } } } diff --git a/Octokit/Models/Response/Enterprise/LicenseInfo.cs b/Octokit/Models/Response/Enterprise/LicenseInfo.cs new file mode 100644 index 00000000..14fe6667 --- /dev/null +++ b/Octokit/Models/Response/Enterprise/LicenseInfo.cs @@ -0,0 +1,67 @@ +using System; +using System.Diagnostics; +using System.Globalization; + +namespace Octokit +{ + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class LicenseInfo + { + public LicenseInfo() { } + + public LicenseInfo(int seats, int seatsUsed, int seatsAvailable, string kind, int daysUntilExpiration, DateTimeOffset expireAt) + { + Seats = seats; + SeatsUsed = seatsUsed; + SeatsAvailable = seatsAvailable; + Kind = kind; + DaysUntilExpiration = daysUntilExpiration; + ExpireAt = expireAt; + } + + + public int Seats + { + get; + private set; + } + + public int SeatsUsed + { + get; + private set; + } + + public int SeatsAvailable + { + get; + private set; + } + + public string Kind + { + get; + private set; + } + + public int DaysUntilExpiration + { + get; + private set; + } + + public DateTimeOffset ExpireAt + { + get; + private set; + } + + internal string DebuggerDisplay + { + get + { + return String.Format(CultureInfo.InvariantCulture, "Seats: {0} SeatsUsed: {1} DaysUntilExpiration: {2}", Seats, SeatsUsed, DaysUntilExpiration); + } + } + } +} \ No newline at end of file diff --git a/Octokit/Octokit.csproj b/Octokit/Octokit.csproj index 549f391f..fb7cade8 100644 --- a/Octokit/Octokit.csproj +++ b/Octokit/Octokit.csproj @@ -59,7 +59,9 @@ + + @@ -140,6 +142,7 @@ + From 22fa5f50dd8361cfbad94c24f712297ac9ec0785 Mon Sep 17 00:00:00 2001 From: Ryan Gribble Date: Sat, 30 Jan 2016 07:41:05 +1000 Subject: [PATCH 03/21] Add Reactive versions of license API and unit/integration tests --- .../Enterprise/IObservableEnterpriseClient.cs | 8 ++++ .../IObservableEnterpriseLicenseClient.cs | 26 +++++++++++++ .../Enterprise/ObservableEnterpriseClient.cs | 9 +++++ .../ObservableEnterpriseLicenseClient.cs | 37 +++++++++++++++++++ Octokit.Reactive/Octokit.Reactive.csproj | 2 + .../Octokit.Tests.Integration.csproj | 1 + .../ObservableEnterpriseLicenseClientTests.cs | 26 +++++++++++++ Octokit.Tests/Octokit.Tests.csproj | 1 + .../ObservableEnterpriseLicenseClientTests.cs | 24 ++++++++++++ 9 files changed, 134 insertions(+) create mode 100644 Octokit.Reactive/Clients/Enterprise/IObservableEnterpriseLicenseClient.cs create mode 100644 Octokit.Reactive/Clients/Enterprise/ObservableEnterpriseLicenseClient.cs create mode 100644 Octokit.Tests.Integration/Reactive/Enterprise/ObservableEnterpriseLicenseClientTests.cs create mode 100644 Octokit.Tests/Reactive/Enterprise/ObservableEnterpriseLicenseClientTests.cs diff --git a/Octokit.Reactive/Clients/Enterprise/IObservableEnterpriseClient.cs b/Octokit.Reactive/Clients/Enterprise/IObservableEnterpriseClient.cs index 4a494899..d47859f9 100644 --- a/Octokit.Reactive/Clients/Enterprise/IObservableEnterpriseClient.cs +++ b/Octokit.Reactive/Clients/Enterprise/IObservableEnterpriseClient.cs @@ -15,5 +15,13 @@ /// See the Enterprise Admin Stats API documentation for more information. /// IObservableEnterpriseAdminStatsClient AdminStats { get; } + + /// + /// A client for GitHub's Enterprise License API + /// + /// + /// See the Enterprise License API documentation for more information. + /// + IObservableEnterpriseLicenseClient License { get; } } } diff --git a/Octokit.Reactive/Clients/Enterprise/IObservableEnterpriseLicenseClient.cs b/Octokit.Reactive/Clients/Enterprise/IObservableEnterpriseLicenseClient.cs new file mode 100644 index 00000000..99acfdb8 --- /dev/null +++ b/Octokit.Reactive/Clients/Enterprise/IObservableEnterpriseLicenseClient.cs @@ -0,0 +1,26 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Reactive.Threading.Tasks; + +namespace Octokit.Reactive +{ + /// + /// A client for GitHub's Enterprise License API + /// + /// + /// See the Enterprise License API documentation for more information. + /// + public interface IObservableEnterpriseLicenseClient + { + /// + /// Gets GitHub Enterprise License Information (must be Site Admin user). + /// + /// + /// https://developer.github.com/v3/enterprise/license/#get-license-information + /// + /// The statistics. + [SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "Get")] + IObservable Get(); + } +} + \ No newline at end of file diff --git a/Octokit.Reactive/Clients/Enterprise/ObservableEnterpriseClient.cs b/Octokit.Reactive/Clients/Enterprise/ObservableEnterpriseClient.cs index 8466e9b8..2b13f505 100644 --- a/Octokit.Reactive/Clients/Enterprise/ObservableEnterpriseClient.cs +++ b/Octokit.Reactive/Clients/Enterprise/ObservableEnterpriseClient.cs @@ -13,6 +13,7 @@ Ensure.ArgumentNotNull(client, "client"); AdminStats = new ObservableEnterpriseAdminStatsClient(client); + License = new ObservableEnterpriseLicenseClient(client); } /// @@ -22,5 +23,13 @@ /// See the Enterprise Admin Stats API documentation for more information. /// public IObservableEnterpriseAdminStatsClient AdminStats { get; private set; } + + /// + /// A client for GitHub's Enterprise License API + /// + /// + /// See the Enterprise License API documentation for more information. + /// + public IObservableEnterpriseLicenseClient License { get; private set; } } } diff --git a/Octokit.Reactive/Clients/Enterprise/ObservableEnterpriseLicenseClient.cs b/Octokit.Reactive/Clients/Enterprise/ObservableEnterpriseLicenseClient.cs new file mode 100644 index 00000000..bf852483 --- /dev/null +++ b/Octokit.Reactive/Clients/Enterprise/ObservableEnterpriseLicenseClient.cs @@ -0,0 +1,37 @@ +using System; +using System.Reactive.Threading.Tasks; +using Octokit; + + +namespace Octokit.Reactive +{ + /// + /// A client for GitHub's Enterprise License API + /// + /// + /// See the Enterprise License API documentation for more information. + /// + public class ObservableEnterpriseLicenseClient : IObservableEnterpriseLicenseClient + { + readonly IEnterpriseLicenseClient _client; + + public ObservableEnterpriseLicenseClient(IGitHubClient client) + { + Ensure.ArgumentNotNull(client, "client"); + + _client = client.Enterprise.License; + } + + /// + /// Gets GitHub Enterprise License Information (must be Site Admin user). + /// + /// + /// https://developer.github.com/v3/enterprise/license/#get-license-information + /// + /// The statistics. + public IObservable Get() + { + return _client.Get().ToObservable(); + } + } +} diff --git a/Octokit.Reactive/Octokit.Reactive.csproj b/Octokit.Reactive/Octokit.Reactive.csproj index aee83c41..e81bfe42 100644 --- a/Octokit.Reactive/Octokit.Reactive.csproj +++ b/Octokit.Reactive/Octokit.Reactive.csproj @@ -75,10 +75,12 @@ Properties\SolutionInfo.cs + + diff --git a/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj b/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj index 0c17edb4..89c33b91 100644 --- a/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj +++ b/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj @@ -123,6 +123,7 @@ + diff --git a/Octokit.Tests.Integration/Reactive/Enterprise/ObservableEnterpriseLicenseClientTests.cs b/Octokit.Tests.Integration/Reactive/Enterprise/ObservableEnterpriseLicenseClientTests.cs new file mode 100644 index 00000000..0c35fb5d --- /dev/null +++ b/Octokit.Tests.Integration/Reactive/Enterprise/ObservableEnterpriseLicenseClientTests.cs @@ -0,0 +1,26 @@ +using System.Reactive.Linq; +using System.Threading.Tasks; +using Octokit.Reactive; +using Xunit; + +namespace Octokit.Tests.Integration +{ + public class ObservableEnterpriseLicenseClientTests + { + readonly IObservableGitHubClient _github; + + public ObservableEnterpriseLicenseClientTests() + { + _github = new ObservableGitHubClient(EnterpriseHelper.GetAuthenticatedClient()); + } + + [GitHubEnterpriseTest] + public async Task CanGet() + { + var observable = _github.Enterprise.License.Get(); + var licenseInfo = await observable; + + Assert.NotNull(licenseInfo); + } + } +} \ No newline at end of file diff --git a/Octokit.Tests/Octokit.Tests.csproj b/Octokit.Tests/Octokit.Tests.csproj index 68886206..df74b652 100644 --- a/Octokit.Tests/Octokit.Tests.csproj +++ b/Octokit.Tests/Octokit.Tests.csproj @@ -188,6 +188,7 @@ + diff --git a/Octokit.Tests/Reactive/Enterprise/ObservableEnterpriseLicenseClientTests.cs b/Octokit.Tests/Reactive/Enterprise/ObservableEnterpriseLicenseClientTests.cs new file mode 100644 index 00000000..1ebd2452 --- /dev/null +++ b/Octokit.Tests/Reactive/Enterprise/ObservableEnterpriseLicenseClientTests.cs @@ -0,0 +1,24 @@ +using System; +using NSubstitute; +using Octokit.Reactive; +using Xunit; + +namespace Octokit.Tests +{ + public class ObservableEnterpriseLicenseClientTests + { + public class TheGetMethod + { + [Fact] + public void CallsIntoClient() + { + + var github = Substitute.For(); + var client = new ObservableEnterpriseLicenseClient(github); + + client.Get(); + github.Enterprise.License.Received(1).Get(); + } + } + } +} From 12e4db8354d9b55de365c869f73d33cd0bd57b49 Mon Sep 17 00:00:00 2001 From: Ryan Gribble Date: Sat, 30 Jan 2016 07:42:15 +1000 Subject: [PATCH 04/21] Update other projects to include new classes --- Octokit.Reactive/Octokit.Reactive-Mono.csproj | 2 ++ Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj | 2 ++ Octokit.Reactive/Octokit.Reactive-Monotouch.csproj | 2 ++ Octokit/Octokit-Mono.csproj | 3 +++ Octokit/Octokit-MonoAndroid.csproj | 3 +++ Octokit/Octokit-Monotouch.csproj | 3 +++ Octokit/Octokit-Portable.csproj | 3 +++ Octokit/Octokit-netcore45.csproj | 3 +++ 8 files changed, 21 insertions(+) diff --git a/Octokit.Reactive/Octokit.Reactive-Mono.csproj b/Octokit.Reactive/Octokit.Reactive-Mono.csproj index 0d93d33a..ad9cfd43 100644 --- a/Octokit.Reactive/Octokit.Reactive-Mono.csproj +++ b/Octokit.Reactive/Octokit.Reactive-Mono.csproj @@ -163,6 +163,8 @@ + + diff --git a/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj b/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj index de9321e9..a1582651 100644 --- a/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj +++ b/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj @@ -171,6 +171,8 @@ + + diff --git a/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj b/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj index 018f37d0..cc5e18cc 100644 --- a/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj +++ b/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj @@ -167,6 +167,8 @@ + + diff --git a/Octokit/Octokit-Mono.csproj b/Octokit/Octokit-Mono.csproj index d46271b2..dc09b851 100644 --- a/Octokit/Octokit-Mono.csproj +++ b/Octokit/Octokit-Mono.csproj @@ -435,6 +435,9 @@ + + + \ No newline at end of file diff --git a/Octokit/Octokit-MonoAndroid.csproj b/Octokit/Octokit-MonoAndroid.csproj index 3897d4ae..8ed5dcd8 100644 --- a/Octokit/Octokit-MonoAndroid.csproj +++ b/Octokit/Octokit-MonoAndroid.csproj @@ -442,6 +442,9 @@ + + + \ No newline at end of file diff --git a/Octokit/Octokit-Monotouch.csproj b/Octokit/Octokit-Monotouch.csproj index cd30e2a0..07ba380b 100644 --- a/Octokit/Octokit-Monotouch.csproj +++ b/Octokit/Octokit-Monotouch.csproj @@ -438,6 +438,9 @@ + + + diff --git a/Octokit/Octokit-Portable.csproj b/Octokit/Octokit-Portable.csproj index dd5907bd..4d35d944 100644 --- a/Octokit/Octokit-Portable.csproj +++ b/Octokit/Octokit-Portable.csproj @@ -432,6 +432,9 @@ + + + diff --git a/Octokit/Octokit-netcore45.csproj b/Octokit/Octokit-netcore45.csproj index 9d5fd546..cdfda9af 100644 --- a/Octokit/Octokit-netcore45.csproj +++ b/Octokit/Octokit-netcore45.csproj @@ -439,6 +439,9 @@ + + + From 0ed6704859472f9f2d9f3989ef1f0b38892cb260 Mon Sep 17 00:00:00 2001 From: Ryan Gribble Date: Sat, 30 Jan 2016 16:04:14 +1000 Subject: [PATCH 05/21] Implement Enterprise Organization client --- .../EnterpriseOrganizationClientTests.cs | 34 +++++++++++ .../Octokit.Tests.Integration.csproj | 1 + .../EnterpriseOrganizationClientTests.cs | 50 ++++++++++++++++ Octokit.Tests/Octokit.Tests.csproj | 1 + .../Clients/Enterprise/EnterpriseClient.cs | 9 +++ .../EnterpriseOrganizationClient.cs | 34 +++++++++++ .../Clients/Enterprise/IEnterpriseClient.cs | 8 +++ .../IEnterpriseOrganizationClient.cs | 23 ++++++++ Octokit/Helpers/ApiUrls.cs | 5 ++ Octokit/Models/Request/NewOrganization.cs | 58 +++++++++++++++++++ Octokit/Octokit.csproj | 3 + 11 files changed, 226 insertions(+) create mode 100644 Octokit.Tests.Integration/Clients/Enterprise/EnterpriseOrganizationClientTests.cs create mode 100644 Octokit.Tests/Clients/Enterprise/EnterpriseOrganizationClientTests.cs create mode 100644 Octokit/Clients/Enterprise/EnterpriseOrganizationClient.cs create mode 100644 Octokit/Clients/Enterprise/IEnterpriseOrganizationClient.cs create mode 100644 Octokit/Models/Request/NewOrganization.cs diff --git a/Octokit.Tests.Integration/Clients/Enterprise/EnterpriseOrganizationClientTests.cs b/Octokit.Tests.Integration/Clients/Enterprise/EnterpriseOrganizationClientTests.cs new file mode 100644 index 00000000..61ace7d2 --- /dev/null +++ b/Octokit.Tests.Integration/Clients/Enterprise/EnterpriseOrganizationClientTests.cs @@ -0,0 +1,34 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using Octokit; +using Octokit.Tests.Integration; +using Xunit; + +public class EnterpriseOrganizationClientTests +{ + readonly IGitHubClient _github; + + public EnterpriseOrganizationClientTests() + { + _github = EnterpriseHelper.GetAuthenticatedClient(); + } + + [GitHubEnterpriseTest] + public async Task CanCreateOrganization() + { + string orgLogin = Helper.MakeNameWithTimestamp("MyOrganization"); + string orgName = String.Concat(orgLogin, " Display Name"); + + var newOrganization = new NewOrganization(orgLogin, EnterpriseHelper.GHEUserName, orgName); + var organization = await + _github.Enterprise.Organization.Create(newOrganization); + + Assert.NotNull(organization); + + // Get organization and check login/name + var checkOrg = await _github.Organization.Get(orgLogin); + Assert.Equal(checkOrg.Login, orgLogin); + Assert.Equal(checkOrg.Name, orgName); + } +} diff --git a/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj b/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj index 89c33b91..e5a117d5 100644 --- a/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj +++ b/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj @@ -79,6 +79,7 @@ + diff --git a/Octokit.Tests/Clients/Enterprise/EnterpriseOrganizationClientTests.cs b/Octokit.Tests/Clients/Enterprise/EnterpriseOrganizationClientTests.cs new file mode 100644 index 00000000..4b078b12 --- /dev/null +++ b/Octokit.Tests/Clients/Enterprise/EnterpriseOrganizationClientTests.cs @@ -0,0 +1,50 @@ +using System; +using System.Threading.Tasks; +using NSubstitute; +using Xunit; + +namespace Octokit.Tests.Clients +{ + public class EnterpriseOrganizationClientTests + { + public class TheCreateMethod + { + [Fact] + public void RequestsCorrectUrl() + { + var connection = Substitute.For(); + var client = new EnterpriseOrganizationClient(connection); + + string expectedUri = "admin/organizations"; + client.Create(new NewOrganization("org", "admin", "org name")); + + connection.Received().Post(Arg.Is(u => u.ToString() == expectedUri), Arg.Any()); + } + + [Fact] + public void PassesRequestObject() + { + var connection = Substitute.For(); + var client = new EnterpriseOrganizationClient(connection); + + client.Create(new NewOrganization("org", "admin", "org name")); + + connection.Received().Post( + Arg.Any(), + Arg.Is(a => + a.Login == "org" + && a.Admin == "admin" + && a.ProfileName == "org name")); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var connection = Substitute.For(); + var client = new EnterpriseOrganizationClient(connection); + + await Assert.ThrowsAsync(() => client.Create(null)); + } + } + } +} diff --git a/Octokit.Tests/Octokit.Tests.csproj b/Octokit.Tests/Octokit.Tests.csproj index df74b652..f6a0b24a 100644 --- a/Octokit.Tests/Octokit.Tests.csproj +++ b/Octokit.Tests/Octokit.Tests.csproj @@ -86,6 +86,7 @@ + diff --git a/Octokit/Clients/Enterprise/EnterpriseClient.cs b/Octokit/Clients/Enterprise/EnterpriseClient.cs index 70b74a5b..e0109d15 100644 --- a/Octokit/Clients/Enterprise/EnterpriseClient.cs +++ b/Octokit/Clients/Enterprise/EnterpriseClient.cs @@ -16,6 +16,7 @@ { AdminStats = new EnterpriseAdminStatsClient(apiConnection); License = new EnterpriseLicenseClient(apiConnection); + Organization = new EnterpriseOrganizationClient(apiConnection); } /// @@ -33,5 +34,13 @@ /// See the Enterprise License API documentation for more information. /// public IEnterpriseLicenseClient License { get; private set; } + + /// + /// A client for GitHub's Enterprise Organization API + /// + /// + /// See the Enterprise Organization API documentation for more information. + /// + public IEnterpriseOrganizationClient Organization { get; private set; } } } diff --git a/Octokit/Clients/Enterprise/EnterpriseOrganizationClient.cs b/Octokit/Clients/Enterprise/EnterpriseOrganizationClient.cs new file mode 100644 index 00000000..0848ff8e --- /dev/null +++ b/Octokit/Clients/Enterprise/EnterpriseOrganizationClient.cs @@ -0,0 +1,34 @@ +using System.Threading.Tasks; + +namespace Octokit +{ + /// + /// A client for GitHub's Enterprise Organization API + /// + /// + /// See the Enterprise Organization API documentation for more information. + /// + public class EnterpriseOrganizationClient : ApiClient, IEnterpriseOrganizationClient + { + public EnterpriseOrganizationClient(IApiConnection apiConnection) + : base(apiConnection) + { } + + /// + /// Creates an Organization on a GitHub Enterprise appliance (must be Site Admin user). + /// + /// + /// https://developer.github.com/v3/enterprise/orgs/#create-an-organization + /// + /// A instance describing the organization to be created + /// The created. + public async Task Create(NewOrganization newOrganization) + { + Ensure.ArgumentNotNull(newOrganization, "newOrganization"); + + var endpoint = ApiUrls.EnterpriseOrganization(); + + return await ApiConnection.Post(endpoint, newOrganization); + } + } +} diff --git a/Octokit/Clients/Enterprise/IEnterpriseClient.cs b/Octokit/Clients/Enterprise/IEnterpriseClient.cs index 1d685013..f1c6209f 100644 --- a/Octokit/Clients/Enterprise/IEnterpriseClient.cs +++ b/Octokit/Clients/Enterprise/IEnterpriseClient.cs @@ -23,5 +23,13 @@ /// See the Enterprise License API documentation for more information. /// IEnterpriseLicenseClient License { get; } + + /// + /// A client for GitHub's Enterprise Organization API + /// + /// + /// See the Enterprise Organization API documentation for more information. + /// + IEnterpriseOrganizationClient Organization { get; } } } diff --git a/Octokit/Clients/Enterprise/IEnterpriseOrganizationClient.cs b/Octokit/Clients/Enterprise/IEnterpriseOrganizationClient.cs new file mode 100644 index 00000000..4904480c --- /dev/null +++ b/Octokit/Clients/Enterprise/IEnterpriseOrganizationClient.cs @@ -0,0 +1,23 @@ +using System.Threading.Tasks; + +namespace Octokit +{ + /// + /// A client for GitHub's Enterprise Organization API + /// + /// + /// See the Enterprise Organization API documentation for more information. + /// + public interface IEnterpriseOrganizationClient + { + /// + /// Creates an Organization on a GitHub Enterprise appliance (must be Site Admin user). + /// + /// + /// https://developer.github.com/v3/enterprise/orgs/#create-an-organization + /// + /// A instance describing the organization to be created + /// The created. + Task Create(NewOrganization newOrganization); + } +} diff --git a/Octokit/Helpers/ApiUrls.cs b/Octokit/Helpers/ApiUrls.cs index b2ee1b6b..156cbd2d 100644 --- a/Octokit/Helpers/ApiUrls.cs +++ b/Octokit/Helpers/ApiUrls.cs @@ -1657,5 +1657,10 @@ namespace Octokit { return "enterprise/settings/license".FormatUri(); } + + public static Uri EnterpriseOrganization() + { + return "admin/organizations".FormatUri(); + } } } diff --git a/Octokit/Models/Request/NewOrganization.cs b/Octokit/Models/Request/NewOrganization.cs new file mode 100644 index 00000000..2a8a4a61 --- /dev/null +++ b/Octokit/Models/Request/NewOrganization.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.Globalization; + +namespace Octokit +{ + /// + /// Describes a new organization to create via the method. + /// + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class NewOrganization + { + /// + /// Initializes a new instance of the class. + /// + /// The organization's username + /// The login of the user who will manage this organization + public NewOrganization(string login, string admin) : this(login, admin, null) + { } + + /// + /// Initializes a new instance of the class. + /// + /// The organization's username + /// The login of the user who will manage this organization + /// The organization's display name + public NewOrganization(string login, string admin, string profileName) + { + Login = login; + Admin = admin; + ProfileName = profileName; + } + + /// + /// The organization's username (required) + /// + public string Login { get; private set; } + + /// + /// The login of the user who will manage this organization (required) + /// + public string Admin { get; private set; } + + /// + /// The organization's display name + /// + public string ProfileName { get; private set; } + + internal string DebuggerDisplay + { + get + { + return string.Format(CultureInfo.InvariantCulture, "Login: {0} Admin: {1} ProfileName: {2}", Login, Admin, ProfileName ?? ""); + } + } + } +} diff --git a/Octokit/Octokit.csproj b/Octokit/Octokit.csproj index fb7cade8..a1a1ab8a 100644 --- a/Octokit/Octokit.csproj +++ b/Octokit/Octokit.csproj @@ -59,8 +59,10 @@ + + @@ -106,6 +108,7 @@ + From 01ef445a40cc27bf54be01189be4cce01943bcdc Mon Sep 17 00:00:00 2001 From: Ryan Gribble Date: Sun, 31 Jan 2016 14:10:43 +1000 Subject: [PATCH 06/21] Add Reactive versions of organization API and unit/integration tests --- .../Enterprise/IObservableEnterpriseClient.cs | 8 ++++ ...IObservableEnterpriseOrganizationClient.cs | 26 +++++++++++++ .../Enterprise/ObservableEnterpriseClient.cs | 9 +++++ .../ObservableEnterpriseOrganizationClient.cs | 38 +++++++++++++++++++ Octokit.Reactive/Octokit.Reactive.csproj | 2 + .../Octokit.Tests.Integration.csproj | 3 +- ...rvableEnterpriseOrganizationClientTests.cs | 36 ++++++++++++++++++ Octokit.Tests/Octokit.Tests.csproj | 1 + ...rvableEnterpriseOrganizationClientTests.cs | 28 ++++++++++++++ 9 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 Octokit.Reactive/Clients/Enterprise/IObservableEnterpriseOrganizationClient.cs create mode 100644 Octokit.Reactive/Clients/Enterprise/ObservableEnterpriseOrganizationClient.cs create mode 100644 Octokit.Tests.Integration/Reactive/Enterprise/ObservableEnterpriseOrganizationClientTests.cs create mode 100644 Octokit.Tests/Reactive/Enterprise/ObservableEnterpriseOrganizationClientTests.cs diff --git a/Octokit.Reactive/Clients/Enterprise/IObservableEnterpriseClient.cs b/Octokit.Reactive/Clients/Enterprise/IObservableEnterpriseClient.cs index d47859f9..72e2d25e 100644 --- a/Octokit.Reactive/Clients/Enterprise/IObservableEnterpriseClient.cs +++ b/Octokit.Reactive/Clients/Enterprise/IObservableEnterpriseClient.cs @@ -23,5 +23,13 @@ /// See the Enterprise License API documentation for more information. /// IObservableEnterpriseLicenseClient License { get; } + + /// + /// A client for GitHub's Enterprise Organization API + /// + /// + /// See the Enterprise Organization API documentation for more information. + /// + IObservableEnterpriseOrganizationClient Organization { get; } } } diff --git a/Octokit.Reactive/Clients/Enterprise/IObservableEnterpriseOrganizationClient.cs b/Octokit.Reactive/Clients/Enterprise/IObservableEnterpriseOrganizationClient.cs new file mode 100644 index 00000000..ebb39eb9 --- /dev/null +++ b/Octokit.Reactive/Clients/Enterprise/IObservableEnterpriseOrganizationClient.cs @@ -0,0 +1,26 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Reactive.Threading.Tasks; + +namespace Octokit.Reactive +{ + /// + /// A client for GitHub's Enterprise Organization API + /// + /// + /// See the Enterprise Organization API documentation for more information. + /// + public interface IObservableEnterpriseOrganizationClient + { + /// + /// Creates an Organization on a GitHub Enterprise appliance (must be Site Admin user). + /// + /// + /// https://developer.github.com/v3/enterprise/orgs/#create-an-organization + /// + /// A instance describing the organization to be created + /// The created. + IObservable Create(NewOrganization newOrganization); + } +} + \ No newline at end of file diff --git a/Octokit.Reactive/Clients/Enterprise/ObservableEnterpriseClient.cs b/Octokit.Reactive/Clients/Enterprise/ObservableEnterpriseClient.cs index 2b13f505..7a52afcd 100644 --- a/Octokit.Reactive/Clients/Enterprise/ObservableEnterpriseClient.cs +++ b/Octokit.Reactive/Clients/Enterprise/ObservableEnterpriseClient.cs @@ -14,6 +14,7 @@ AdminStats = new ObservableEnterpriseAdminStatsClient(client); License = new ObservableEnterpriseLicenseClient(client); + Organization = new ObservableEnterpriseOrganizationClient(client); } /// @@ -31,5 +32,13 @@ /// See the Enterprise License API documentation for more information. /// public IObservableEnterpriseLicenseClient License { get; private set; } + + /// + /// A client for GitHub's Enterprise Organization API + /// + /// + /// See the Enterprise Organization API documentation for more information. + /// + public IObservableEnterpriseOrganizationClient Organization { get; private set; } } } diff --git a/Octokit.Reactive/Clients/Enterprise/ObservableEnterpriseOrganizationClient.cs b/Octokit.Reactive/Clients/Enterprise/ObservableEnterpriseOrganizationClient.cs new file mode 100644 index 00000000..1f78574c --- /dev/null +++ b/Octokit.Reactive/Clients/Enterprise/ObservableEnterpriseOrganizationClient.cs @@ -0,0 +1,38 @@ +using System; +using System.Reactive.Threading.Tasks; +using Octokit; + + +namespace Octokit.Reactive +{ + /// + /// A client for GitHub's Enterprise Organization API + /// + /// + /// See the Enterprise Organization API documentation for more information. + /// + public class ObservableEnterpriseOrganizationClient : IObservableEnterpriseOrganizationClient + { + readonly IEnterpriseOrganizationClient _client; + + public ObservableEnterpriseOrganizationClient(IGitHubClient client) + { + Ensure.ArgumentNotNull(client, "client"); + + _client = client.Enterprise.Organization; + } + + /// + /// Creates an Organization on a GitHub Enterprise appliance (must be Site Admin user). + /// + /// + /// https://developer.github.com/v3/enterprise/orgs/#create-an-organization + /// + /// A instance describing the organization to be created + /// The created. + public IObservable Create(NewOrganization newOrganization) + { + return _client.Create(newOrganization).ToObservable(); + } + } +} diff --git a/Octokit.Reactive/Octokit.Reactive.csproj b/Octokit.Reactive/Octokit.Reactive.csproj index e81bfe42..0ffdc200 100644 --- a/Octokit.Reactive/Octokit.Reactive.csproj +++ b/Octokit.Reactive/Octokit.Reactive.csproj @@ -75,11 +75,13 @@ Properties\SolutionInfo.cs + + diff --git a/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj b/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj index e5a117d5..7781ebbc 100644 --- a/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj +++ b/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj @@ -124,8 +124,9 @@ - + + diff --git a/Octokit.Tests.Integration/Reactive/Enterprise/ObservableEnterpriseOrganizationClientTests.cs b/Octokit.Tests.Integration/Reactive/Enterprise/ObservableEnterpriseOrganizationClientTests.cs new file mode 100644 index 00000000..c0816f68 --- /dev/null +++ b/Octokit.Tests.Integration/Reactive/Enterprise/ObservableEnterpriseOrganizationClientTests.cs @@ -0,0 +1,36 @@ +using System; +using System.Reactive.Linq; +using System.Threading.Tasks; +using Octokit.Reactive; +using Xunit; + +namespace Octokit.Tests.Integration +{ + public class ObservableEnterpriseOrganizationClientTests + { + readonly IObservableGitHubClient _github; + + public ObservableEnterpriseOrganizationClientTests() + { + _github = new ObservableGitHubClient(EnterpriseHelper.GetAuthenticatedClient()); + } + + [GitHubEnterpriseTest] + public async Task CanCreateOrganization() + { + string orgLogin = Helper.MakeNameWithTimestamp("MyOrganization"); + string orgName = String.Concat(orgLogin, " Display Name"); + + var newOrganization = new NewOrganization(orgLogin, EnterpriseHelper.GHEUserName, orgName); + var observable = _github.Enterprise.Organization.Create(newOrganization); + var organization = await observable; + + Assert.NotNull(organization); + + // Get organization and check login/name + var checkOrg = await _github.Organization.Get(orgLogin); + Assert.Equal(checkOrg.Login, orgLogin); + Assert.Equal(checkOrg.Name, orgName); + } + } +} \ No newline at end of file diff --git a/Octokit.Tests/Octokit.Tests.csproj b/Octokit.Tests/Octokit.Tests.csproj index f6a0b24a..a5ab2071 100644 --- a/Octokit.Tests/Octokit.Tests.csproj +++ b/Octokit.Tests/Octokit.Tests.csproj @@ -189,6 +189,7 @@ + diff --git a/Octokit.Tests/Reactive/Enterprise/ObservableEnterpriseOrganizationClientTests.cs b/Octokit.Tests/Reactive/Enterprise/ObservableEnterpriseOrganizationClientTests.cs new file mode 100644 index 00000000..5c1867c4 --- /dev/null +++ b/Octokit.Tests/Reactive/Enterprise/ObservableEnterpriseOrganizationClientTests.cs @@ -0,0 +1,28 @@ +using System; +using NSubstitute; +using Octokit.Reactive; +using Xunit; + +namespace Octokit.Tests +{ + public class ObservableEnterpriseOrganizationClientTests + { + public class TheCreateMethod + { + [Fact] + public void CallsIntoClient() + { + + var github = Substitute.For(); + var client = new ObservableEnterpriseOrganizationClient(github); + + client.Create(new NewOrganization("org", "admin", "org name")); + github.Enterprise.Organization.Received(1).Create( + Arg.Is(a => + a.Login == "org" + && a.Admin == "admin" + && a.ProfileName == "org name")); + } + } + } +} From e46abc8fe9dd48b913704148a31cdc220d452d3e Mon Sep 17 00:00:00 2001 From: Ryan Gribble Date: Sat, 30 Jan 2016 16:04:44 +1000 Subject: [PATCH 07/21] Update other projects to include new classes --- Octokit.Reactive/Octokit.Reactive-Mono.csproj | 2 ++ Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj | 2 ++ Octokit.Reactive/Octokit.Reactive-Monotouch.csproj | 2 ++ Octokit/Octokit-Mono.csproj | 3 +++ Octokit/Octokit-MonoAndroid.csproj | 3 +++ Octokit/Octokit-Monotouch.csproj | 3 +++ Octokit/Octokit-Portable.csproj | 3 +++ Octokit/Octokit-netcore45.csproj | 3 +++ 8 files changed, 21 insertions(+) diff --git a/Octokit.Reactive/Octokit.Reactive-Mono.csproj b/Octokit.Reactive/Octokit.Reactive-Mono.csproj index ad9cfd43..a0128ae2 100644 --- a/Octokit.Reactive/Octokit.Reactive-Mono.csproj +++ b/Octokit.Reactive/Octokit.Reactive-Mono.csproj @@ -165,6 +165,8 @@ + + diff --git a/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj b/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj index a1582651..749d1572 100644 --- a/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj +++ b/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj @@ -173,6 +173,8 @@ + + diff --git a/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj b/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj index cc5e18cc..47b8d02e 100644 --- a/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj +++ b/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj @@ -169,6 +169,8 @@ + + diff --git a/Octokit/Octokit-Mono.csproj b/Octokit/Octokit-Mono.csproj index dc09b851..821fe80e 100644 --- a/Octokit/Octokit-Mono.csproj +++ b/Octokit/Octokit-Mono.csproj @@ -438,6 +438,9 @@ + + + \ No newline at end of file diff --git a/Octokit/Octokit-MonoAndroid.csproj b/Octokit/Octokit-MonoAndroid.csproj index 8ed5dcd8..1e290d8c 100644 --- a/Octokit/Octokit-MonoAndroid.csproj +++ b/Octokit/Octokit-MonoAndroid.csproj @@ -445,6 +445,9 @@ + + + \ No newline at end of file diff --git a/Octokit/Octokit-Monotouch.csproj b/Octokit/Octokit-Monotouch.csproj index 07ba380b..198be8be 100644 --- a/Octokit/Octokit-Monotouch.csproj +++ b/Octokit/Octokit-Monotouch.csproj @@ -441,6 +441,9 @@ + + + diff --git a/Octokit/Octokit-Portable.csproj b/Octokit/Octokit-Portable.csproj index 4d35d944..e2e7e422 100644 --- a/Octokit/Octokit-Portable.csproj +++ b/Octokit/Octokit-Portable.csproj @@ -435,6 +435,9 @@ + + + diff --git a/Octokit/Octokit-netcore45.csproj b/Octokit/Octokit-netcore45.csproj index cdfda9af..38518196 100644 --- a/Octokit/Octokit-netcore45.csproj +++ b/Octokit/Octokit-netcore45.csproj @@ -442,6 +442,9 @@ + + + From bb4086b64dc77ce5aac7175d23c16d2d69e384ba Mon Sep 17 00:00:00 2001 From: Ryan Gribble Date: Tue, 2 Feb 2016 22:02:28 +1000 Subject: [PATCH 08/21] Rename EnterpriseHelper properties to remove "GHE" prefix --- .../EnterpriseOrganizationClientTests.cs | 2 +- Octokit.Tests.Integration/EnterpriseHelper.cs | 26 +++++++++---------- ...rvableEnterpriseOrganizationClientTests.cs | 2 +- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Octokit.Tests.Integration/Clients/Enterprise/EnterpriseOrganizationClientTests.cs b/Octokit.Tests.Integration/Clients/Enterprise/EnterpriseOrganizationClientTests.cs index 61ace7d2..ce77ae3b 100644 --- a/Octokit.Tests.Integration/Clients/Enterprise/EnterpriseOrganizationClientTests.cs +++ b/Octokit.Tests.Integration/Clients/Enterprise/EnterpriseOrganizationClientTests.cs @@ -20,7 +20,7 @@ public class EnterpriseOrganizationClientTests string orgLogin = Helper.MakeNameWithTimestamp("MyOrganization"); string orgName = String.Concat(orgLogin, " Display Name"); - var newOrganization = new NewOrganization(orgLogin, EnterpriseHelper.GHEUserName, orgName); + var newOrganization = new NewOrganization(orgLogin, EnterpriseHelper.UserName, orgName); var organization = await _github.Enterprise.Organization.Create(newOrganization); diff --git a/Octokit.Tests.Integration/EnterpriseHelper.cs b/Octokit.Tests.Integration/EnterpriseHelper.cs index 27f237d0..9a1ab54e 100644 --- a/Octokit.Tests.Integration/EnterpriseHelper.cs +++ b/Octokit.Tests.Integration/EnterpriseHelper.cs @@ -9,8 +9,8 @@ namespace Octokit.Tests.Integration static readonly Lazy _credentialsThunk = new Lazy(() => { var githubUsername = Environment.GetEnvironmentVariable("OCTOKIT_GHE_USERNAME"); - GHEUserName = githubUsername; - GHEOrganization = Environment.GetEnvironmentVariable("OCTOKIT_GHE_ORGANIZATION"); + UserName = githubUsername; + Organization = Environment.GetEnvironmentVariable("OCTOKIT_GHE_ORGANIZATION"); var githubToken = Environment.GetEnvironmentVariable("OCTOKIT_GHE_OAUTHTOKEN"); @@ -39,8 +39,8 @@ namespace Octokit.Tests.Integration static readonly Lazy _basicAuthCredentials = new Lazy(() => { var githubUsername = Environment.GetEnvironmentVariable("OCTOKIT_GHE_USERNAME"); - GHEUserName = githubUsername; - GHEOrganization = Environment.GetEnvironmentVariable("OCTOKIT_GHE_ORGANIZATION"); + UserName = githubUsername; + Organization = Environment.GetEnvironmentVariable("OCTOKIT_GHE_ORGANIZATION"); var githubPassword = Environment.GetEnvironmentVariable("OCTOKIT_GHE_PASSWORD"); @@ -71,20 +71,20 @@ namespace Octokit.Tests.Integration // Force reading of environment variables. // This wasn't happening if UserName/Organization were // retrieved before Credentials. - Debug.WriteIf(GHECredentials == null, "No credentials specified."); + Debug.WriteIf(Credentials == null, "No credentials specified."); } - public static string GHEUserName { get; private set; } - public static string GHEOrganization { get; private set; } + public static string UserName { get; private set; } + public static string Organization { get; private set; } /// /// These credentials should be set to a test GitHub account using the powershell script configure-integration-tests.ps1 /// - public static Credentials GHECredentials { get { return _credentialsThunk.Value; } } + public static Credentials Credentials { get { return _credentialsThunk.Value; } } - public static Credentials GHEApplicationCredentials { get { return _oauthApplicationCredentials.Value; } } + public static Credentials ApplicationCredentials { get { return _oauthApplicationCredentials.Value; } } - public static Credentials GHEBasicAuthCredentials { get { return _basicAuthCredentials.Value; } } + public static Credentials BasicAuthCredentials { get { return _basicAuthCredentials.Value; } } public static bool IsGitHubEnterpriseEnabled { get { return _gitHubEnterpriseEnabled.Value; } } @@ -128,7 +128,7 @@ namespace Octokit.Tests.Integration { return new GitHubClient(new ProductHeaderValue("OctokitEnterpriseTests"), GitHubEnterpriseUrl) { - Credentials = GHECredentials + Credentials = Credentials }; } @@ -136,7 +136,7 @@ namespace Octokit.Tests.Integration { return new GitHubClient(new ProductHeaderValue("OctokitEnterpriseTests"), GitHubEnterpriseUrl) { - Credentials = GHEBasicAuthCredentials + Credentials = BasicAuthCredentials }; } @@ -144,7 +144,7 @@ namespace Octokit.Tests.Integration { return new GitHubClient(new ProductHeaderValue("OctokitEnterpriseTests"), GitHubEnterpriseUrl) { - Credentials = GHEApplicationCredentials + Credentials = ApplicationCredentials }; } diff --git a/Octokit.Tests.Integration/Reactive/Enterprise/ObservableEnterpriseOrganizationClientTests.cs b/Octokit.Tests.Integration/Reactive/Enterprise/ObservableEnterpriseOrganizationClientTests.cs index c0816f68..28997bad 100644 --- a/Octokit.Tests.Integration/Reactive/Enterprise/ObservableEnterpriseOrganizationClientTests.cs +++ b/Octokit.Tests.Integration/Reactive/Enterprise/ObservableEnterpriseOrganizationClientTests.cs @@ -21,7 +21,7 @@ namespace Octokit.Tests.Integration string orgLogin = Helper.MakeNameWithTimestamp("MyOrganization"); string orgName = String.Concat(orgLogin, " Display Name"); - var newOrganization = new NewOrganization(orgLogin, EnterpriseHelper.GHEUserName, orgName); + var newOrganization = new NewOrganization(orgLogin, EnterpriseHelper.UserName, orgName); var observable = _github.Enterprise.Organization.Create(newOrganization); var organization = await observable; From 1052d09edf6adcf3550bb94f1322157d41e6a0ad Mon Sep 17 00:00:00 2001 From: Mordechai Zuber Date: Thu, 4 Feb 2016 12:42:39 +0200 Subject: [PATCH 09/21] Add overloads to specify branch for ContentRequest --- Octokit/Models/Request/CreateFileRequest.cs | 62 ++++++++++++++++++++- 1 file changed, 60 insertions(+), 2 deletions(-) diff --git a/Octokit/Models/Request/CreateFileRequest.cs b/Octokit/Models/Request/CreateFileRequest.cs index 275d6fbf..b804ac73 100644 --- a/Octokit/Models/Request/CreateFileRequest.cs +++ b/Octokit/Models/Request/CreateFileRequest.cs @@ -21,6 +21,18 @@ namespace Octokit Message = message; } + /// + /// Initializes a new instance of the class. + /// + /// The message. + /// The branch the request is for. + protected ContentRequest(string message, string branch): this(message) + { + Ensure.ArgumentNotNullOrEmptyString(branch, "branch"); + + Branch = branch; + } + /// /// The commit message. This is required. /// @@ -54,6 +66,19 @@ namespace Octokit /// The message. /// The sha. public DeleteFileRequest(string message, string sha) : base(message) + { + Ensure.ArgumentNotNullOrEmptyString(sha, "content"); + + Sha = sha; + } + + /// + /// Initializes a new instance of the class. + /// + /// The message. + /// The sha. + /// The branch the request is for. + public DeleteFileRequest(string message, string sha, string branch) : base(message, branch) { Ensure.ArgumentNotNullOrEmptyString(sha, "sha"); @@ -81,8 +106,8 @@ namespace Octokit /// /// Creates an instance of a . /// - /// - /// + /// The message. + /// The content. public CreateFileRequest(string message, string content) : base(message) { Ensure.ArgumentNotNull(content, "content"); @@ -90,6 +115,18 @@ namespace Octokit Content = content; } + /// + /// Initializes a new instance of the class. + /// + /// The message. + /// The content. + /// The branch the request is for. + public CreateFileRequest(string message, string content, string branch) : base(message, branch) + { + Ensure.ArgumentNotNullOrEmptyString(content, "content"); + + Content = content; + } /// /// The contents of the file to create. This is required. /// @@ -111,6 +148,12 @@ namespace Octokit [DebuggerDisplay("{DebuggerDisplay,nq}")] public class UpdateFileRequest : CreateFileRequest { + /// + /// Creates an instance of a . + /// + /// The message. + /// The content. + /// The sha. public UpdateFileRequest(string message, string content, string sha) : base(message, content) { @@ -119,6 +162,21 @@ namespace Octokit Sha = sha; } + /// + /// Creates an instance of a . + /// + /// The message. + /// The content. + /// The sha. + /// The branch the request is for. + public UpdateFileRequest(string message, string content, string sha, string branch) + : base(message, content, branch) + { + Ensure.ArgumentNotNullOrEmptyString(sha, "sha"); + + Sha = sha; + } + /// /// The blob SHA of the file being replaced. /// From 3b74250abf85108d976e213d887888e9b708711b Mon Sep 17 00:00:00 2001 From: Ryan Gribble Date: Fri, 5 Feb 2016 21:04:02 +1000 Subject: [PATCH 10/21] - Add unit tests to assert expected behaviour when deserializing strings containing hyphens (and underscores for good measure) into a string and List objects - Fix failing List test by removing the seemingly redundant line in the deserializer --- Octokit.Tests/SimpleJsonSerializerTests.cs | 29 ++++++++++++++++++++++ Octokit/Http/SimpleJsonSerializer.cs | 1 - 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/Octokit.Tests/SimpleJsonSerializerTests.cs b/Octokit.Tests/SimpleJsonSerializerTests.cs index 9586899e..36fb1270 100644 --- a/Octokit.Tests/SimpleJsonSerializerTests.cs +++ b/Octokit.Tests/SimpleJsonSerializerTests.cs @@ -1,5 +1,6 @@ using Octokit.Helpers; using Octokit.Internal; +using System.Collections.Generic; using System.Linq; using System.Text; using Xunit; @@ -119,6 +120,34 @@ namespace Octokit.Tests new SimpleJsonSerializer().Deserialize(json); } + public class MessageSingle + { + public string Message { get; private set; } + } + + [Fact] + public void DeserializesStringsWithHyphensAndUnderscoresIntoString() + { + const string json = @"{""message"":""-my-test-string_with_underscores_""}"; + + var response = new SimpleJsonSerializer().Deserialize(json); + Assert.Equal("-my-test-string_with_underscores_", response.Message); + } + + public class MessageList + { + public IReadOnlyList Message { get; private set; } + } + + [Fact] + public void DeserializesStringsWithHyphensAndUnderscoresIntoStringList() + { + const string json = @"{""message"":""-my-test-string_with_underscores_""}"; + + var response = new SimpleJsonSerializer().Deserialize(json); + Assert.Equal("-my-test-string_with_underscores_", response.Message[0]); + } + [Fact] public void UnderstandsRubyCasing() { diff --git a/Octokit/Http/SimpleJsonSerializer.cs b/Octokit/Http/SimpleJsonSerializer.cs index a6750e8c..5835bcac 100644 --- a/Octokit/Http/SimpleJsonSerializer.cs +++ b/Octokit/Http/SimpleJsonSerializer.cs @@ -90,7 +90,6 @@ namespace Octokit.Internal var jsonValue = value as JsonObject; if (stringValue != null) { - stringValue = stringValue.Replace("-", ""); if (ReflectionUtils.GetTypeInfo(type).IsEnum) { // remove '-' from values coming in to be able to enum utf-8 From 547e233308ffc45f3ab9b856661810a69e5bad92 Mon Sep 17 00:00:00 2001 From: Ryan Gribble Date: Fri, 5 Feb 2016 21:41:39 +1000 Subject: [PATCH 11/21] Tidy up some whitespace --- .../Clients/Enterprise/IObservableEnterpriseLicenseClient.cs | 1 - .../Enterprise/IObservableEnterpriseOrganizationClient.cs | 1 - .../Enterprise/ObservableEnterpriseLicenseClientTests.cs | 1 - .../Enterprise/ObservableEnterpriseOrganizationClientTests.cs | 1 - Octokit/Models/Response/Enterprise/LicenseInfo.cs | 1 - 5 files changed, 5 deletions(-) diff --git a/Octokit.Reactive/Clients/Enterprise/IObservableEnterpriseLicenseClient.cs b/Octokit.Reactive/Clients/Enterprise/IObservableEnterpriseLicenseClient.cs index 99acfdb8..7ec56f1b 100644 --- a/Octokit.Reactive/Clients/Enterprise/IObservableEnterpriseLicenseClient.cs +++ b/Octokit.Reactive/Clients/Enterprise/IObservableEnterpriseLicenseClient.cs @@ -23,4 +23,3 @@ namespace Octokit.Reactive IObservable Get(); } } - \ No newline at end of file diff --git a/Octokit.Reactive/Clients/Enterprise/IObservableEnterpriseOrganizationClient.cs b/Octokit.Reactive/Clients/Enterprise/IObservableEnterpriseOrganizationClient.cs index ebb39eb9..38f744f1 100644 --- a/Octokit.Reactive/Clients/Enterprise/IObservableEnterpriseOrganizationClient.cs +++ b/Octokit.Reactive/Clients/Enterprise/IObservableEnterpriseOrganizationClient.cs @@ -23,4 +23,3 @@ namespace Octokit.Reactive IObservable Create(NewOrganization newOrganization); } } - \ No newline at end of file diff --git a/Octokit.Tests/Reactive/Enterprise/ObservableEnterpriseLicenseClientTests.cs b/Octokit.Tests/Reactive/Enterprise/ObservableEnterpriseLicenseClientTests.cs index 1ebd2452..b3f89bb5 100644 --- a/Octokit.Tests/Reactive/Enterprise/ObservableEnterpriseLicenseClientTests.cs +++ b/Octokit.Tests/Reactive/Enterprise/ObservableEnterpriseLicenseClientTests.cs @@ -12,7 +12,6 @@ namespace Octokit.Tests [Fact] public void CallsIntoClient() { - var github = Substitute.For(); var client = new ObservableEnterpriseLicenseClient(github); diff --git a/Octokit.Tests/Reactive/Enterprise/ObservableEnterpriseOrganizationClientTests.cs b/Octokit.Tests/Reactive/Enterprise/ObservableEnterpriseOrganizationClientTests.cs index 5c1867c4..47046e05 100644 --- a/Octokit.Tests/Reactive/Enterprise/ObservableEnterpriseOrganizationClientTests.cs +++ b/Octokit.Tests/Reactive/Enterprise/ObservableEnterpriseOrganizationClientTests.cs @@ -12,7 +12,6 @@ namespace Octokit.Tests [Fact] public void CallsIntoClient() { - var github = Substitute.For(); var client = new ObservableEnterpriseOrganizationClient(github); diff --git a/Octokit/Models/Response/Enterprise/LicenseInfo.cs b/Octokit/Models/Response/Enterprise/LicenseInfo.cs index 14fe6667..03bd174c 100644 --- a/Octokit/Models/Response/Enterprise/LicenseInfo.cs +++ b/Octokit/Models/Response/Enterprise/LicenseInfo.cs @@ -19,7 +19,6 @@ namespace Octokit ExpireAt = expireAt; } - public int Seats { get; From b4d86d07dcce428f2513c0722e2101a26663f5e4 Mon Sep 17 00:00:00 2001 From: Sarmad Date: Sun, 7 Feb 2016 19:15:31 +0500 Subject: [PATCH 12/21] added new parameters to RepositoryRequest.cs --- Octokit/Models/Request/RepositoryRequest.cs | 84 +++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/Octokit/Models/Request/RepositoryRequest.cs b/Octokit/Models/Request/RepositoryRequest.cs index f22b881f..7806171f 100644 --- a/Octokit/Models/Request/RepositoryRequest.cs +++ b/Octokit/Models/Request/RepositoryRequest.cs @@ -37,6 +37,24 @@ namespace Octokit /// public SortDirection Direction { get; set; } + /// + /// Gets or sets the visibility property. + /// + /// + /// The public. + /// + + public RepositoryVisibility Visibility { get; set; } + + /// + /// Gets or sets the affiliation property. + /// + /// + /// The owner. + /// + + public RepositoryAffiliation Affiliation { get; set; } + internal string DebuggerDisplay { get @@ -103,4 +121,70 @@ namespace Octokit [Parameter(Value = "full_name")] FullName } + + + public enum RepositoryVisibility + { + /// + /// Returns only public repositories + /// + Public, + + /// + /// Returns only private repositories + /// + Private, + + /// + /// Return both public and private repositories + /// + All, + + } + + + public enum RepositoryAffiliation + { + /// + /// Repositories that are owned by the authenticated user + /// + Owner, + + /// + /// Repositories that the user has been added to as a collaborator. + /// + Collaborator, + + /// + /// Repositories that the user has access to through being a member of an organization. + /// This includes every repository on every team that the user is on. + /// + [Parameter(Value = "organization_member")] + OrganizationMember, + + /// + /// Return repositories that are owned by authenticated user and added to as a collaborator. + /// + [Parameter(Value = "owner, collaborator")] + OwnerAndCollaborator, + + /// + /// Return repositories that are owned by authenticated user and user is a member of organization. + /// + [Parameter(Value = "owner, organization_member")] + OwnerAndOrganizationMember, + + /// + /// Return repositories that user has been added as collaborator and user is a member of organization. + /// + [Parameter(Value = "collaborator, organization_member")] + CollaboratorAndOrganizationMember, + + /// + /// Returns all repositories where user is owner,collaborator and organization member. + /// + [Parameter(Value = "owner, collaborator, organization_member")] + All + + } } From 30553d34e366e4c1e3fa43ecc53861f035e52674 Mon Sep 17 00:00:00 2001 From: Sarmad Date: Sun, 7 Feb 2016 21:04:17 +0500 Subject: [PATCH 13/21] fixed some typo and formatting issues --- Octokit/Models/Request/RepositoryRequest.cs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/Octokit/Models/Request/RepositoryRequest.cs b/Octokit/Models/Request/RepositoryRequest.cs index 7806171f..0c44a2f1 100644 --- a/Octokit/Models/Request/RepositoryRequest.cs +++ b/Octokit/Models/Request/RepositoryRequest.cs @@ -41,19 +41,17 @@ namespace Octokit /// Gets or sets the visibility property. /// /// - /// The public. + /// The no. /// - public RepositoryVisibility Visibility { get; set; } /// - /// Gets or sets the affiliation property. + /// Gets or sets The affiliation property. /// /// /// The owner. /// - - public RepositoryAffiliation Affiliation { get; set; } + public RepositoryAffiliation Affiliation { get; set; } internal string DebuggerDisplay { @@ -169,19 +167,19 @@ namespace Octokit OwnerAndCollaborator, /// - /// Return repositories that are owned by authenticated user and user is a member of organization. + /// Return repositories that are owned by authenticated user or user is a organization member. /// [Parameter(Value = "owner, organization_member")] OwnerAndOrganizationMember, /// - /// Return repositories that user has been added as collaborator and user is a member of organization. + /// Return repositories that user has been added as collaborator or user is a organization member. /// [Parameter(Value = "collaborator, organization_member")] CollaboratorAndOrganizationMember, /// - /// Returns all repositories where user is owner,collaborator and organization member. + /// Returns all repositories where user is owner,collaborator or organization member. /// [Parameter(Value = "owner, collaborator, organization_member")] All From 84c77464bed593da553b469f04e99975ff14cbab Mon Sep 17 00:00:00 2001 From: Mordechai Zuber Date: Mon, 8 Feb 2016 12:16:34 +0200 Subject: [PATCH 14/21] Add integration test --- .../Clients/RepositoryContentsClientTests.cs | 47 +++++++++++++++++++ Octokit/Models/Request/CreateFileRequest.cs | 2 +- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/Octokit.Tests.Integration/Clients/RepositoryContentsClientTests.cs b/Octokit.Tests.Integration/Clients/RepositoryContentsClientTests.cs index 2cb44e7f..5e9ddbf7 100644 --- a/Octokit.Tests.Integration/Clients/RepositoryContentsClientTests.cs +++ b/Octokit.Tests.Integration/Clients/RepositoryContentsClientTests.cs @@ -111,6 +111,53 @@ namespace Octokit.Tests.Integration.Clients } } + [IntegrationTest] + public async Task CrudTestWithNamedBranch() + { + var client = Helper.GetAuthenticatedClient(); + var fixture = client.Repository.Content; + var repoName = Helper.MakeNameWithTimestamp("source-repo"); + var branchName = "other-branch"; + + using (var context = await client.CreateRepositoryContext(new NewRepository(repoName) { AutoInit = true })) + { + var repository = context.Repository; + + var master = await client.Git.Reference.Get(Helper.UserName, repository.Name, "heads/master"); + await client.Git.Reference.Create(Helper.UserName, repository.Name, new NewReference("refs/heads/" + branchName, master.Object.Sha)); + var file = await fixture.CreateFile( + repository.Owner.Login, + repository.Name, + "somefile.txt", + new CreateFileRequest("Test commit", "Some Content", branchName)); + Assert.Equal("somefile.txt", file.Content.Name); + + var contents = await fixture.GetAllContentsByRef(repository.Owner.Login, repository.Name, "somefile.txt", branchName); + string fileSha = contents.First().Sha; + Assert.Equal("Some Content", contents.First().Content); + + var update = await fixture.UpdateFile( + repository.Owner.Login, + repository.Name, + "somefile.txt", + new UpdateFileRequest("Updating file", "New Content", fileSha, branchName)); + Assert.Equal("somefile.txt", update.Content.Name); + + contents = await fixture.GetAllContentsByRef(repository.Owner.Login, repository.Name, "somefile.txt", branchName); + Assert.Equal("New Content", contents.First().Content); + fileSha = contents.First().Sha; + + await fixture.DeleteFile( + repository.Owner.Login, + repository.Name, + "somefile.txt", + new DeleteFileRequest("Deleted file", fileSha, branchName)); + + await Assert.ThrowsAsync( + async () => await fixture.GetAllContents(repository.Owner.Login, repository.Name, "somefile.txt")); + } + } + [IntegrationTest(Skip = "this will probably take too long")] public async Task GetsArchiveAsTarball() { diff --git a/Octokit/Models/Request/CreateFileRequest.cs b/Octokit/Models/Request/CreateFileRequest.cs index b804ac73..b9529e3b 100644 --- a/Octokit/Models/Request/CreateFileRequest.cs +++ b/Octokit/Models/Request/CreateFileRequest.cs @@ -116,7 +116,7 @@ namespace Octokit } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The message. /// The content. From d7cb5620feeb588109c2f7ebbca79937d4745258 Mon Sep 17 00:00:00 2001 From: Sarmad Date: Mon, 8 Feb 2016 16:22:41 +0500 Subject: [PATCH 15/21] fixed typo and improved formatting in comments --- Octokit/Models/Request/RepositoryRequest.cs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Octokit/Models/Request/RepositoryRequest.cs b/Octokit/Models/Request/RepositoryRequest.cs index 0c44a2f1..75083c97 100644 --- a/Octokit/Models/Request/RepositoryRequest.cs +++ b/Octokit/Models/Request/RepositoryRequest.cs @@ -41,15 +41,15 @@ namespace Octokit /// Gets or sets the visibility property. /// /// - /// The no. + /// The visibility. /// public RepositoryVisibility Visibility { get; set; } /// - /// Gets or sets The affiliation property. + /// Gets or sets the affiliation property. /// /// - /// The owner. + /// The affiliation. /// public RepositoryAffiliation Affiliation { get; set; } @@ -120,7 +120,9 @@ namespace Octokit FullName } - + /// + /// The properties that repositories can be visibled by. + /// public enum RepositoryVisibility { /// @@ -137,10 +139,11 @@ namespace Octokit /// Return both public and private repositories /// All, - } - + /// + /// The properties that repositories can be affiliated by. + /// public enum RepositoryAffiliation { /// @@ -183,6 +186,5 @@ namespace Octokit /// [Parameter(Value = "owner, collaborator, organization_member")] All - } } From 1bfa625f085b01e8dc85f058fae5bd0f7b5cf38a Mon Sep 17 00:00:00 2001 From: Ryan Gribble Date: Mon, 8 Feb 2016 22:46:47 +1000 Subject: [PATCH 16/21] Add unit tests for CreateFile DeleteFile and UpdateFile --- .../Clients/RepositoryContentsClientTests.cs | 130 ++++++++++++++++++ 1 file changed, 130 insertions(+) diff --git a/Octokit.Tests/Clients/RepositoryContentsClientTests.cs b/Octokit.Tests/Clients/RepositoryContentsClientTests.cs index 46324cbe..85707ee9 100644 --- a/Octokit.Tests/Clients/RepositoryContentsClientTests.cs +++ b/Octokit.Tests/Clients/RepositoryContentsClientTests.cs @@ -89,5 +89,135 @@ namespace Octokit.Tests.Clients Assert.Equal(1, contents.Count); } } + + public class TheCreateFileMethod + { + [Fact] + public void RequestsCorrectUrl() + { + var connection = Substitute.For(); + var client = new RepositoryContentsClient(connection); + + string expectedUri = "repos/org/repo/contents/path/to/file"; + client.CreateFile("org", "repo", "path/to/file", new CreateFileRequest("message", "myfilecontents", "mybranch")); + + connection.Received().Put(Arg.Is(u => u.ToString() == expectedUri), Arg.Any()); + } + + [Fact] + public void PassesRequestObject() + { + var connection = Substitute.For(); + var client = new RepositoryContentsClient(connection); + + client.CreateFile("org", "repo", "path/to/file", new CreateFileRequest("message", "myfilecontents", "mybranch")); + + connection.Received().Put( + Arg.Any(), + Arg.Is(a => + a.Message == "message" + && a.Content == "myfilecontents" + && a.Branch == "mybranch")); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var connection = Substitute.For(); + var client = new RepositoryContentsClient(connection); + + await Assert.ThrowsAsync(() => client.CreateFile(null, "repo", "path/to/file", new CreateFileRequest("message", "myfilecontents", "mybranch"))); + await Assert.ThrowsAsync(() => client.CreateFile("org", null, "path/to/file", new CreateFileRequest("message", "myfilecontents", "mybranch"))); + await Assert.ThrowsAsync(() => client.CreateFile("org", "repo", null, new CreateFileRequest("message", "myfilecontents", "mybranch"))); + await Assert.ThrowsAsync(() => client.CreateFile("org", "repo", "path/to/file", null)); + } + } + + public class TheDeleteFileMethod + { + [Fact] + public void RequestsCorrectUrl() + { + var connection = Substitute.For(); + var client = new RepositoryContentsClient(connection); + + string expectedUri = "repos/org/repo/contents/path/to/file"; + client.DeleteFile("org", "repo", "path/to/file", new DeleteFileRequest("message", "1234abc", "mybranch")); + + connection.Received().Delete(Arg.Is(u => u.ToString() == expectedUri), Arg.Any()); + } + + [Fact] + public void PassesRequestObject() + { + var connection = Substitute.For(); + var client = new RepositoryContentsClient(connection); + + client.DeleteFile("org", "repo", "path/to/file", new DeleteFileRequest("message", "1234abc", "mybranch")); + + connection.Received().Delete( + Arg.Any(), + Arg.Is(a => + a.Message == "message" + && a.Sha == "1234abc" + && a.Branch == "mybranch")); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var connection = Substitute.For(); + var client = new RepositoryContentsClient(connection); + + await Assert.ThrowsAsync(() => client.DeleteFile(null, "repo", "path/to/file", new DeleteFileRequest("message", "1234abc", "mybranch"))); + await Assert.ThrowsAsync(() => client.DeleteFile("org", null, "path/to/file", new DeleteFileRequest("message", "1234abc", "mybranch"))); + await Assert.ThrowsAsync(() => client.DeleteFile("org", "repo", null, new DeleteFileRequest("message", "1234abc", "mybranch"))); + await Assert.ThrowsAsync(() => client.DeleteFile("org", "repo", "path/to/file", null)); + } + } + + public class TheUpdateFileMethod + { + [Fact] + public void RequestsCorrectUrl() + { + var connection = Substitute.For(); + var client = new RepositoryContentsClient(connection); + + string expectedUri = "repos/org/repo/contents/path/to/file"; + client.UpdateFile("org", "repo", "path/to/file", new UpdateFileRequest("message", "myfilecontents", "1234abc", "mybranch")); + + connection.Received().Put(Arg.Is(u => u.ToString() == expectedUri), Arg.Any()); + } + + [Fact] + public void PassesRequestObject() + { + var connection = Substitute.For(); + var client = new RepositoryContentsClient(connection); + + client.UpdateFile("org", "repo", "path/to/file", new UpdateFileRequest("message", "myfilecontents", "1234abc", "mybranch")); + + connection.Received().Put( + Arg.Any(), + Arg.Is(a => + a.Message == "message" + && a.Content == "myfilecontents" + && a.Sha == "1234abc" + && a.Branch == "mybranch")); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var connection = Substitute.For(); + var client = new RepositoryContentsClient(connection); + + await Assert.ThrowsAsync(() => client.UpdateFile(null, "repo", "path/to/file", new UpdateFileRequest("message", "myfilecontents", "1234abc", "mybranch"))); + await Assert.ThrowsAsync(() => client.UpdateFile("org", null, "path/to/file", new UpdateFileRequest("message", "myfilecontents", "1234abc", "mybranch"))); + await Assert.ThrowsAsync(() => client.UpdateFile("org", "repo", null, new UpdateFileRequest("message", "myfilecontents", "1234abc", "mybranch"))); + await Assert.ThrowsAsync(() => client.UpdateFile("org", "repo", "path/to/file", null)); + } + } } } \ No newline at end of file From 2366c998a298666359d57fda6cf5f0dc0cb4756d Mon Sep 17 00:00:00 2001 From: Sarmad Date: Wed, 10 Feb 2016 04:29:43 +0500 Subject: [PATCH 17/21] added unit tests for the new-parameters-on-ListYourRepository --- .../Clients/RepositoriesClientTests.cs | 41 +++++++++++++++++++ Octokit/Helpers/UriExtensions.cs | 2 +- Octokit/Models/Request/RepositoryRequest.cs | 2 +- 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/Octokit.Tests/Clients/RepositoriesClientTests.cs b/Octokit.Tests/Clients/RepositoriesClientTests.cs index 618c591b..e74cc97b 100644 --- a/Octokit.Tests/Clients/RepositoriesClientTests.cs +++ b/Octokit.Tests/Clients/RepositoriesClientTests.cs @@ -376,6 +376,47 @@ namespace Octokit.Tests.Clients Arg.Is>(d => d["type"] == "member" && d["sort"] == "updated" && d["direction"] == "asc")); } + + [Fact] + public void CanFilterByVisibility() + { + var connection = Substitute.For(); + var client = new RepositoriesClient(connection); + + var request = new RepositoryRequest + { + Visibility = RepositoryVisibility.Private + }; + client.GetAllForCurrent(request); + + connection.Received() + .GetAll( + Arg.Is(u => u.ToString() == "user/repos"), + Arg.Is>(d => + d["visibility"] == "private")); + } + + [Fact] + public void CanFilterByAffiliation() + { + var connection = Substitute.For(); + var client = new RepositoriesClient(connection); + + var request = new RepositoryRequest + { + + Affiliation = RepositoryAffiliation.Owner, + Sort = RepositorySort.FullName + }; + + client.GetAllForCurrent(request); + + connection.Received() + .GetAll( + Arg.Is(u => u.ToString() == "user/repos"), + Arg.Is>(d => + d["affiliation"] == "owner" && d["sort"] == "full_name")); + } } public class TheGetAllForUserMethod diff --git a/Octokit/Helpers/UriExtensions.cs b/Octokit/Helpers/UriExtensions.cs index a2db9969..2ee1b873 100644 --- a/Octokit/Helpers/UriExtensions.cs +++ b/Octokit/Helpers/UriExtensions.cs @@ -10,7 +10,7 @@ namespace Octokit public static class UriExtensions { /// - /// Merge a dictionary of valeus with an existing + /// Merge a dictionary of values with an existing /// /// Original request Uri /// Collection of key-value pairs diff --git a/Octokit/Models/Request/RepositoryRequest.cs b/Octokit/Models/Request/RepositoryRequest.cs index 75083c97..1f5d2e89 100644 --- a/Octokit/Models/Request/RepositoryRequest.cs +++ b/Octokit/Models/Request/RepositoryRequest.cs @@ -121,7 +121,7 @@ namespace Octokit } /// - /// The properties that repositories can be visibled by. + /// The properties that repositories can be visible by. /// public enum RepositoryVisibility { From 5cad1ab2f0aaf98dc25506549d09a3c761d99617 Mon Sep 17 00:00:00 2001 From: Mordechai Zuber Date: Thu, 11 Feb 2016 01:49:10 +0200 Subject: [PATCH 18/21] Remove unneeded async/await calls --- .../Clients/RepositoryContentsClientTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Octokit.Tests.Integration/Clients/RepositoryContentsClientTests.cs b/Octokit.Tests.Integration/Clients/RepositoryContentsClientTests.cs index 5e9ddbf7..91c8fd91 100644 --- a/Octokit.Tests.Integration/Clients/RepositoryContentsClientTests.cs +++ b/Octokit.Tests.Integration/Clients/RepositoryContentsClientTests.cs @@ -107,7 +107,7 @@ namespace Octokit.Tests.Integration.Clients new DeleteFileRequest("Deleted file", fileSha)); await Assert.ThrowsAsync( - async () => await fixture.GetAllContents(repository.Owner.Login, repository.Name, "somefile.txt")); + () => fixture.GetAllContents(repository.Owner.Login, repository.Name, "somefile.txt")); } } @@ -154,7 +154,7 @@ namespace Octokit.Tests.Integration.Clients new DeleteFileRequest("Deleted file", fileSha, branchName)); await Assert.ThrowsAsync( - async () => await fixture.GetAllContents(repository.Owner.Login, repository.Name, "somefile.txt")); + () => fixture.GetAllContents(repository.Owner.Login, repository.Name, "somefile.txt")); } } From b50b2c737f8cbae5e4526f22ee9c736b624819b3 Mon Sep 17 00:00:00 2001 From: Ryan Gribble Date: Wed, 3 Feb 2016 00:39:09 +1000 Subject: [PATCH 19/21] Implement Enterprise Search Indexing Client and unit/integration tests --- .../EnterpriseSearchIndexingClientTests.cs | 106 ++++++++++ .../Octokit.Tests.Integration.csproj | 1 + .../EnterpriseSearchIndexingClientTests.cs | 198 ++++++++++++++++++ Octokit.Tests/Octokit.Tests.csproj | 1 + .../Clients/Enterprise/EnterpriseClient.cs | 9 + .../EnterpriseSearchIndexingClient.cs | 157 ++++++++++++++ .../Clients/Enterprise/IEnterpriseClient.cs | 8 + .../IEnterpriseSearchIndexingClient.cs | 86 ++++++++ Octokit/Helpers/ApiUrls.cs | 5 + .../{ => Enterprise}/NewOrganization.cs | 0 .../Enterprise/SearchIndexingTarget.cs | 12 ++ .../Enterprise/SearchIndexingResponse.cs | 33 +++ Octokit/Octokit-Mono.csproj | 6 +- Octokit/Octokit-MonoAndroid.csproj | 5 + Octokit/Octokit-Monotouch.csproj | 5 + Octokit/Octokit-Portable.csproj | 6 +- Octokit/Octokit-netcore45.csproj | 6 +- Octokit/Octokit.csproj | 6 +- 18 files changed, 646 insertions(+), 4 deletions(-) create mode 100644 Octokit.Tests.Integration/Clients/Enterprise/EnterpriseSearchIndexingClientTests.cs create mode 100644 Octokit.Tests/Clients/Enterprise/EnterpriseSearchIndexingClientTests.cs create mode 100644 Octokit/Clients/Enterprise/EnterpriseSearchIndexingClient.cs create mode 100644 Octokit/Clients/Enterprise/IEnterpriseSearchIndexingClient.cs rename Octokit/Models/Request/{ => Enterprise}/NewOrganization.cs (100%) create mode 100644 Octokit/Models/Request/Enterprise/SearchIndexingTarget.cs create mode 100644 Octokit/Models/Response/Enterprise/SearchIndexingResponse.cs diff --git a/Octokit.Tests.Integration/Clients/Enterprise/EnterpriseSearchIndexingClientTests.cs b/Octokit.Tests.Integration/Clients/Enterprise/EnterpriseSearchIndexingClientTests.cs new file mode 100644 index 00000000..21803975 --- /dev/null +++ b/Octokit.Tests.Integration/Clients/Enterprise/EnterpriseSearchIndexingClientTests.cs @@ -0,0 +1,106 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using Octokit; +using Octokit.Tests.Integration; +using Octokit.Tests.Integration.Helpers; +using Xunit; + +public class EnterpriseSearchIndexingClientTests +{ + readonly IGitHubClient _github; + + public EnterpriseSearchIndexingClientTests() + { + _github = EnterpriseHelper.GetAuthenticatedClient(); + } + + [GitHubEnterpriseTest] + public async Task CanQueueOwner() + { + var response = await + _github.Enterprise.SearchIndexing.Queue(EnterpriseHelper.UserName); + + Assert.NotNull(response); + Assert.NotNull(response.Message); + Assert.True(response.Message.All(m => m.Contains("was added to the indexing queue"))); + } + + [GitHubEnterpriseTest] + public async Task CanQueueRepository() + { + var newRepository = new NewRepository(Helper.MakeNameWithTimestamp("public-repo")); + using (var context = await _github.CreateRepositoryContext(newRepository)) + { + var response = await + _github.Enterprise.SearchIndexing.Queue(EnterpriseHelper.UserName, context.RepositoryName); + + Assert.NotNull(response); + Assert.NotNull(response.Message); + Assert.True(response.Message.All(m => m.Contains("was added to the indexing queue"))); + } + } + + [GitHubEnterpriseTest] + public async Task CanQueueAll() + { + var response = await + _github.Enterprise.SearchIndexing.QueueAll(EnterpriseHelper.UserName); + + Assert.NotNull(response); + Assert.NotNull(response.Message); + Assert.True(response.Message.All(m => m.Contains("was added to the indexing queue"))); + } + + [GitHubEnterpriseTest] + public async Task CanQueueAllCodeOwner() + { + var response = await + _github.Enterprise.SearchIndexing.QueueAllCode(EnterpriseHelper.UserName); + + Assert.NotNull(response); + Assert.NotNull(response.Message); + Assert.True(response.Message.All(m => m.Contains("was added to the indexing queue"))); + } + + [GitHubEnterpriseTest] + public async Task CanQueueAllCodeRepository() + { + var newRepository = new NewRepository(Helper.MakeNameWithTimestamp("public-repo")); + using (var context = await _github.CreateRepositoryContext(newRepository)) + { + var response = await + _github.Enterprise.SearchIndexing.QueueAllCode(EnterpriseHelper.UserName, context.RepositoryName); + + Assert.NotNull(response); + Assert.NotNull(response.Message); + Assert.True(response.Message.All(m => m.Contains("was added to the indexing queue"))); + } + } + + [GitHubEnterpriseTest] + public async Task CanQueueAllIssuesOwner() + { + var response = await + _github.Enterprise.SearchIndexing.QueueAllIssues(EnterpriseHelper.UserName); + + Assert.NotNull(response); + Assert.NotNull(response.Message); + Assert.True(response.Message.All(m => m.Contains("were added to the indexing queue"))); + } + + [GitHubEnterpriseTest] + public async Task CanQueueAllIssuesRepository() + { + var newRepository = new NewRepository(Helper.MakeNameWithTimestamp("public-repo")); + using (var context = await _github.CreateRepositoryContext(newRepository)) + { + var response = await + _github.Enterprise.SearchIndexing.QueueAllIssues(EnterpriseHelper.UserName, context.RepositoryName); + + Assert.NotNull(response); + Assert.NotNull(response.Message); + Assert.True(response.Message.All(m => m.Contains("were added to the indexing queue"))); + } + } +} diff --git a/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj b/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj index 7781ebbc..74a06d90 100644 --- a/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj +++ b/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj @@ -79,6 +79,7 @@ + diff --git a/Octokit.Tests/Clients/Enterprise/EnterpriseSearchIndexingClientTests.cs b/Octokit.Tests/Clients/Enterprise/EnterpriseSearchIndexingClientTests.cs new file mode 100644 index 00000000..e347c005 --- /dev/null +++ b/Octokit.Tests/Clients/Enterprise/EnterpriseSearchIndexingClientTests.cs @@ -0,0 +1,198 @@ +using System; +using System.Threading.Tasks; +using NSubstitute; +using Xunit; + +namespace Octokit.Tests.Clients +{ + public class EnterpriseSearchIndexingClientTests + { + public class TheQueueMethod + { + [Fact] + public void RequestsCorrectUrl() + { + var connection = Substitute.For(); + var client = new EnterpriseSearchIndexingClient(connection); + + string expectedUri = "staff/indexing_jobs"; + + client.Queue("org"); + connection.Received().Post(Arg.Is(u => u.ToString() == expectedUri), Arg.Any()); + + client.Queue("org", "repo"); + connection.Received().Post(Arg.Is(u => u.ToString() == expectedUri), Arg.Any()); + } + + [Fact] + public void PassesRequestObject() + { + var connection = Substitute.For(); + var client = new EnterpriseSearchIndexingClient(connection); + + client.Queue("org"); + connection.Received().Post( + Arg.Any(), + Arg.Is(t => + t.Target == "org" + )); + + client.Queue("org", "repo"); + connection.Received().Post( + Arg.Any(), + Arg.Is(t => + t.Target == "org/repo" + )); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var connection = Substitute.For(); + var client = new EnterpriseSearchIndexingClient(connection); + + await Assert.ThrowsAsync(() => client.Queue(null)); + await Assert.ThrowsAsync(() => client.Queue("org", null)); + await Assert.ThrowsAsync(() => client.Queue(null, "repo")); + } + } + + public class TheQueueAllMethod + { + [Fact] + public void RequestsCorrectUrl() + { + var connection = Substitute.For(); + var client = new EnterpriseSearchIndexingClient(connection); + + string expectedUri = "staff/indexing_jobs"; + client.QueueAll("org"); + + connection.Received().Post(Arg.Is(u => u.ToString() == expectedUri), Arg.Any()); + } + + [Fact] + public void PassesRequestObject() + { + var connection = Substitute.For(); + var client = new EnterpriseSearchIndexingClient(connection); + + client.QueueAll("org"); + connection.Received().Post( + Arg.Any(), + Arg.Is(t => + t.Target == "org/*" + )); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var connection = Substitute.For(); + var client = new EnterpriseSearchIndexingClient(connection); + + await Assert.ThrowsAsync(() => client.QueueAll(null)); + } + } + + public class TheQueueAllCodeMethod + { + [Fact] + public void RequestsCorrectUrl() + { + var connection = Substitute.For(); + var client = new EnterpriseSearchIndexingClient(connection); + + string expectedUri = "staff/indexing_jobs"; + + client.QueueAllCode("org"); + connection.Received().Post(Arg.Is(u => u.ToString() == expectedUri), Arg.Any()); + + client.QueueAllCode("org", "repo"); + connection.Received().Post(Arg.Is(u => u.ToString() == expectedUri), Arg.Any()); + } + + [Fact] + public void PassesRequestObject() + { + var connection = Substitute.For(); + var client = new EnterpriseSearchIndexingClient(connection); + + client.QueueAllCode("org"); + connection.Received().Post( + Arg.Any(), + Arg.Is(t => + t.Target == "org/*/code" + )); + + client.QueueAllCode("org", "repo"); + connection.Received().Post( + Arg.Any(), + Arg.Is(t => + t.Target == "org/repo/code" + )); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var connection = Substitute.For(); + var client = new EnterpriseSearchIndexingClient(connection); + + await Assert.ThrowsAsync(() => client.QueueAllCode(null)); + await Assert.ThrowsAsync(() => client.QueueAllCode("org", null)); + await Assert.ThrowsAsync(() => client.QueueAllCode(null, "repo")); + } + } + + public class TheQueueAllIssuesMethod + { + [Fact] + public void RequestsCorrectUrl() + { + var connection = Substitute.For(); + var client = new EnterpriseSearchIndexingClient(connection); + + string expectedUri = "staff/indexing_jobs"; + + client.QueueAllIssues("org"); + connection.Received().Post(Arg.Is(u => u.ToString() == expectedUri), Arg.Any()); + + client.QueueAllIssues("org", "repo"); + connection.Received().Post(Arg.Is(u => u.ToString() == expectedUri), Arg.Any()); + } + + [Fact] + public void PassesRequestObject() + { + var connection = Substitute.For(); + var client = new EnterpriseSearchIndexingClient(connection); + + client.QueueAllIssues("org"); + connection.Received().Post( + Arg.Any(), + Arg.Is(t => + t.Target == "org/*/issues" + )); + + client.QueueAllIssues("org", "repo"); + connection.Received().Post( + Arg.Any(), + Arg.Is(t => + t.Target == "org/repo/issues" + )); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var connection = Substitute.For(); + var client = new EnterpriseSearchIndexingClient(connection); + + await Assert.ThrowsAsync(() => client.QueueAllIssues(null)); + await Assert.ThrowsAsync(() => client.QueueAllIssues("org", null)); + await Assert.ThrowsAsync(() => client.QueueAllIssues(null, "repo")); + } + } + } +} diff --git a/Octokit.Tests/Octokit.Tests.csproj b/Octokit.Tests/Octokit.Tests.csproj index a916d248..c3418554 100644 --- a/Octokit.Tests/Octokit.Tests.csproj +++ b/Octokit.Tests/Octokit.Tests.csproj @@ -88,6 +88,7 @@ + diff --git a/Octokit/Clients/Enterprise/EnterpriseClient.cs b/Octokit/Clients/Enterprise/EnterpriseClient.cs index e0109d15..614d9bce 100644 --- a/Octokit/Clients/Enterprise/EnterpriseClient.cs +++ b/Octokit/Clients/Enterprise/EnterpriseClient.cs @@ -17,6 +17,7 @@ AdminStats = new EnterpriseAdminStatsClient(apiConnection); License = new EnterpriseLicenseClient(apiConnection); Organization = new EnterpriseOrganizationClient(apiConnection); + SearchIndexing = new EnterpriseSearchIndexingClient(apiConnection); } /// @@ -42,5 +43,13 @@ /// See the Enterprise Organization API documentation for more information. /// public IEnterpriseOrganizationClient Organization { get; private set; } + + /// + /// A client for GitHub's Enterprise Search Indexing API + /// + /// + /// See the Enterprise Search Indexing API documentation for more information. + /// + public IEnterpriseSearchIndexingClient SearchIndexing { get; private set; } } } diff --git a/Octokit/Clients/Enterprise/EnterpriseSearchIndexingClient.cs b/Octokit/Clients/Enterprise/EnterpriseSearchIndexingClient.cs new file mode 100644 index 00000000..7e157bfb --- /dev/null +++ b/Octokit/Clients/Enterprise/EnterpriseSearchIndexingClient.cs @@ -0,0 +1,157 @@ +using System.Globalization; +using System.Threading.Tasks; + +namespace Octokit +{ + /// + /// A client for GitHub's Enterprise Search Indexing API + /// + /// + /// See the Enterprise Search Indexing API documentation for more information. + /// + public class EnterpriseSearchIndexingClient : ApiClient, IEnterpriseSearchIndexingClient + { + public EnterpriseSearchIndexingClient(IApiConnection apiConnection) + : base(apiConnection) + { } + + /// + /// Queue an indexing job for a user or organization account (must be Site Admin user). + /// + /// + /// https://developer.github.com/v3/enterprise/search_indexing/#queue-an-indexing-job + /// + /// A user or organization account + /// The message. + public async Task Queue(string owner) + { + Ensure.ArgumentNotNull(owner, "owner"); + + var endpoint = ApiUrls.EnterpriseSearchIndexing(); + var target = new SearchIndexTarget(string.Format(CultureInfo.InvariantCulture, "{0}", owner)); + + return await ApiConnection.Post(endpoint, target) + .ConfigureAwait(false); + } + + /// + /// Queue an indexing job for a repository (must be Site Admin user). + /// + /// + /// https://developer.github.com/v3/enterprise/search_indexing/#queue-an-indexing-job + /// + /// A user or organization account + /// A repository + /// The message. + public async Task Queue(string owner, string repository) + { + Ensure.ArgumentNotNull(owner, "owner"); + Ensure.ArgumentNotNull(repository, "repository"); + + var endpoint = ApiUrls.EnterpriseSearchIndexing(); + var target = new SearchIndexTarget(string.Format(CultureInfo.InvariantCulture, "{0}/{1}", owner, repository)); + + return await ApiConnection.Post(endpoint, target) + .ConfigureAwait(false); + } + + /// + /// Queue an indexing job for all of a user or organization's repositories (must be Site Admin user). + /// + /// + /// https://developer.github.com/v3/enterprise/search_indexing/#queue-an-indexing-job + /// + /// A user or organization account + /// The message. + public async Task QueueAll(string owner) + { + Ensure.ArgumentNotNull(owner, "owner"); + + var endpoint = ApiUrls.EnterpriseSearchIndexing(); + var target = new SearchIndexTarget(string.Format(CultureInfo.InvariantCulture, "{0}/*", owner)); + + return await ApiConnection.Post(endpoint, target) + .ConfigureAwait(false); + } + + /// + /// Queue an indexing job for all the issues in a repository (must be Site Admin user). + /// + /// + /// https://developer.github.com/v3/enterprise/search_indexing/#queue-an-indexing-job + /// + /// A user or organization account + /// A repository + /// The message. + public async Task QueueAllIssues(string owner, string repository) + { + Ensure.ArgumentNotNull(owner, "owner"); + Ensure.ArgumentNotNull(repository, "repository"); + + var endpoint = ApiUrls.EnterpriseSearchIndexing(); + var target = new SearchIndexTarget(string.Format(CultureInfo.InvariantCulture, "{0}/{1}/issues", owner, repository)); + + return await ApiConnection.Post(endpoint, target) + .ConfigureAwait(false); + } + + /// + /// Queue an indexing job for all the issues in all of a user or organization's repositories (must be Site Admin user). + /// + /// + /// https://developer.github.com/v3/enterprise/search_indexing/#queue-an-indexing-job + /// + /// A user or organization account + /// The message. + public async Task QueueAllIssues(string owner) + { + Ensure.ArgumentNotNull(owner, "owner"); + + var endpoint = ApiUrls.EnterpriseSearchIndexing(); + var target = new SearchIndexTarget(string.Format(CultureInfo.InvariantCulture, "{0}/*/issues", owner)); + + return await ApiConnection.Post(endpoint, target) + .ConfigureAwait(false); + } + + /// + /// Queue an indexing job for all the source code in a repository (must be Site Admin user). + /// + /// + /// https://developer.github.com/v3/enterprise/search_indexing/#queue-an-indexing-job + /// + /// A user or organization account + /// A repository + /// The message. + public async Task QueueAllCode(string owner, string repository) + { + Ensure.ArgumentNotNull(owner, "owner"); + Ensure.ArgumentNotNull(repository, "repository"); + + var endpoint = ApiUrls.EnterpriseSearchIndexing(); + var target = new SearchIndexTarget(string.Format(CultureInfo.InvariantCulture, "{0}/{1}/code", owner, repository)); + + return await ApiConnection.Post(endpoint, target) + .ConfigureAwait(false); + } + + /// + /// Queue an indexing job for all the source code in all of a user or organization's repositories (must be Site Admin user). + /// + /// + /// https://developer.github.com/v3/enterprise/search_indexing/#queue-an-indexing-job + /// + /// A user or organization account + /// The message. + public async Task QueueAllCode(string owner) + { + Ensure.ArgumentNotNull(owner, "owner"); + + var endpoint = ApiUrls.EnterpriseSearchIndexing(); + var target = new SearchIndexTarget(string.Format(CultureInfo.InvariantCulture, "{0}/*/code", owner)); + + return await ApiConnection.Post(endpoint, target) + .ConfigureAwait(false); + } + } +} diff --git a/Octokit/Clients/Enterprise/IEnterpriseClient.cs b/Octokit/Clients/Enterprise/IEnterpriseClient.cs index f1c6209f..899751c0 100644 --- a/Octokit/Clients/Enterprise/IEnterpriseClient.cs +++ b/Octokit/Clients/Enterprise/IEnterpriseClient.cs @@ -31,5 +31,13 @@ /// See the Enterprise Organization API documentation for more information. /// IEnterpriseOrganizationClient Organization { get; } + + /// + /// A client for GitHub's Enterprise Search Indexing API + /// + /// + /// See the Enterprise Search Indexing API documentation for more information. + /// + IEnterpriseSearchIndexingClient SearchIndexing { get; } } } diff --git a/Octokit/Clients/Enterprise/IEnterpriseSearchIndexingClient.cs b/Octokit/Clients/Enterprise/IEnterpriseSearchIndexingClient.cs new file mode 100644 index 00000000..91c7f5eb --- /dev/null +++ b/Octokit/Clients/Enterprise/IEnterpriseSearchIndexingClient.cs @@ -0,0 +1,86 @@ +using System.Threading.Tasks; + +namespace Octokit +{ + /// + /// A client for GitHub's Enterprise Search Indexing API + /// + /// + /// See the Enterprise Search Indexing API documentation for more information. + /// + public interface IEnterpriseSearchIndexingClient + { + /// + /// Queue an indexing job for a user or organization account (must be Site Admin user). + /// + /// + /// https://developer.github.com/v3/enterprise/search_indexing/#queue-an-indexing-job + /// + /// A user or organization account + /// The message. + Task Queue(string owner); + + /// + /// Queue an indexing job for a repository (must be Site Admin user). + /// + /// + /// https://developer.github.com/v3/enterprise/search_indexing/#queue-an-indexing-job + /// + /// A user or organization account + /// A repository + /// The message. + Task Queue(string owner, string repository); + + /// + /// Queue an indexing job for all of a user or organization's repositories (must be Site Admin user). + /// + /// + /// https://developer.github.com/v3/enterprise/search_indexing/#queue-an-indexing-job + /// + /// A user or organization account + /// The message. + Task QueueAll(string owner); + + /// + /// Queue an indexing job for all the issues in a repository (must be Site Admin user). + /// + /// + /// https://developer.github.com/v3/enterprise/search_indexing/#queue-an-indexing-job + /// + /// A user or organization account + /// A repository + /// The message. + Task QueueAllIssues(string owner, string repository); + + /// + /// Queue an indexing job for all the issues in all of a user or organization's repositories (must be Site Admin user). + /// + /// + /// https://developer.github.com/v3/enterprise/search_indexing/#queue-an-indexing-job + /// + /// A user or organization account + /// The message. + Task QueueAllIssues(string owner); + + /// + /// Queue an indexing job for all the source code in a repository (must be Site Admin user). + /// + /// + /// https://developer.github.com/v3/enterprise/search_indexing/#queue-an-indexing-job + /// + /// A user or organization account + /// A repository + /// The message. + Task QueueAllCode(string owner, string repository); + + /// + /// Queue an indexing job for all the source code in all of a user or organization's repositories (must be Site Admin user). + /// + /// + /// https://developer.github.com/v3/enterprise/search_indexing/#queue-an-indexing-job + /// + /// A user or organization account + /// The message. + Task QueueAllCode(string owner); + } +} diff --git a/Octokit/Helpers/ApiUrls.cs b/Octokit/Helpers/ApiUrls.cs index 974dba11..30436b85 100644 --- a/Octokit/Helpers/ApiUrls.cs +++ b/Octokit/Helpers/ApiUrls.cs @@ -1674,6 +1674,11 @@ namespace Octokit return "admin/organizations".FormatUri(); } + public static Uri EnterpriseSearchIndexing() + { + return "staff/indexing_jobs".FormatUri(); + } + /// /// Creates the relative for altering administration status of a user. /// diff --git a/Octokit/Models/Request/NewOrganization.cs b/Octokit/Models/Request/Enterprise/NewOrganization.cs similarity index 100% rename from Octokit/Models/Request/NewOrganization.cs rename to Octokit/Models/Request/Enterprise/NewOrganization.cs diff --git a/Octokit/Models/Request/Enterprise/SearchIndexingTarget.cs b/Octokit/Models/Request/Enterprise/SearchIndexingTarget.cs new file mode 100644 index 00000000..9a55bc31 --- /dev/null +++ b/Octokit/Models/Request/Enterprise/SearchIndexingTarget.cs @@ -0,0 +1,12 @@ +namespace Octokit +{ + public class SearchIndexTarget + { + public SearchIndexTarget(string target) + { + Target = target; + } + + public string Target { get; protected set; } + } +} diff --git a/Octokit/Models/Response/Enterprise/SearchIndexingResponse.cs b/Octokit/Models/Response/Enterprise/SearchIndexingResponse.cs new file mode 100644 index 00000000..90c054c8 --- /dev/null +++ b/Octokit/Models/Response/Enterprise/SearchIndexingResponse.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.Linq; + +namespace Octokit +{ + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class SearchIndexingResponse + { + public SearchIndexingResponse() { } + + public SearchIndexingResponse(IReadOnlyList message) + { + Message = message; + } + + public IReadOnlyList Message + { + get; + private set; + } + + internal string DebuggerDisplay + { + get + { + return String.Format(CultureInfo.InvariantCulture, "Message: {0}", string.Join("\r\n", Message)); + } + } + } +} \ No newline at end of file diff --git a/Octokit/Octokit-Mono.csproj b/Octokit/Octokit-Mono.csproj index 7611c683..cf4adab8 100644 --- a/Octokit/Octokit-Mono.csproj +++ b/Octokit/Octokit-Mono.csproj @@ -442,7 +442,11 @@ - + + + + + \ No newline at end of file diff --git a/Octokit/Octokit-MonoAndroid.csproj b/Octokit/Octokit-MonoAndroid.csproj index d865a56a..ca3641e9 100644 --- a/Octokit/Octokit-MonoAndroid.csproj +++ b/Octokit/Octokit-MonoAndroid.csproj @@ -450,6 +450,11 @@ + + + + + \ No newline at end of file diff --git a/Octokit/Octokit-Monotouch.csproj b/Octokit/Octokit-Monotouch.csproj index 0788df85..9b911c87 100644 --- a/Octokit/Octokit-Monotouch.csproj +++ b/Octokit/Octokit-Monotouch.csproj @@ -446,6 +446,11 @@ + + + + + diff --git a/Octokit/Octokit-Portable.csproj b/Octokit/Octokit-Portable.csproj index 974475eb..54301735 100644 --- a/Octokit/Octokit-Portable.csproj +++ b/Octokit/Octokit-Portable.csproj @@ -439,7 +439,11 @@ - + + + + + diff --git a/Octokit/Octokit-netcore45.csproj b/Octokit/Octokit-netcore45.csproj index 359b023b..47276432 100644 --- a/Octokit/Octokit-netcore45.csproj +++ b/Octokit/Octokit-netcore45.csproj @@ -446,7 +446,11 @@ - + + + + + diff --git a/Octokit/Octokit.csproj b/Octokit/Octokit.csproj index bc8fea37..d293cab7 100644 --- a/Octokit/Octokit.csproj +++ b/Octokit/Octokit.csproj @@ -62,10 +62,12 @@ + + @@ -110,13 +112,14 @@ - + + @@ -147,6 +150,7 @@ + From a3b2a2fbdab09bbe2803c349d29801385d0f999a Mon Sep 17 00:00:00 2001 From: Ryan Gribble Date: Fri, 5 Feb 2016 22:23:31 +1000 Subject: [PATCH 20/21] Implement Reactive Enterprise Search Indexing Client and unit/integration tests --- .../Enterprise/IObservableEnterpriseClient.cs | 8 ++ ...bservableEnterpriseSearchIndexingClient.cs | 88 +++++++++++++ .../Enterprise/ObservableEnterpriseClient.cs | 9 ++ ...bservableEnterpriseSearchIndexingClient.cs | 118 ++++++++++++++++++ Octokit.Reactive/Octokit.Reactive.csproj | 2 + .../ObservableGithubClientExtensions.cs | 31 +++++ .../Octokit.Tests.Integration.csproj | 2 + ...ableEnterpriseSearchIndexingClientTests.cs | 108 ++++++++++++++++ Octokit.Tests/Octokit.Tests.csproj | 1 + ...ableEnterpriseSearchIndexingClientTests.cs | 81 ++++++++++++ 10 files changed, 448 insertions(+) create mode 100644 Octokit.Reactive/Clients/Enterprise/IObservableEnterpriseSearchIndexingClient.cs create mode 100644 Octokit.Reactive/Clients/Enterprise/ObservableEnterpriseSearchIndexingClient.cs create mode 100644 Octokit.Tests.Integration/Helpers/ObservableGithubClientExtensions.cs create mode 100644 Octokit.Tests.Integration/Reactive/Enterprise/ObservableEnterpriseSearchIndexingClientTests.cs create mode 100644 Octokit.Tests/Reactive/Enterprise/ObservableEnterpriseSearchIndexingClientTests.cs diff --git a/Octokit.Reactive/Clients/Enterprise/IObservableEnterpriseClient.cs b/Octokit.Reactive/Clients/Enterprise/IObservableEnterpriseClient.cs index 72e2d25e..74186a8f 100644 --- a/Octokit.Reactive/Clients/Enterprise/IObservableEnterpriseClient.cs +++ b/Octokit.Reactive/Clients/Enterprise/IObservableEnterpriseClient.cs @@ -31,5 +31,13 @@ /// See the Enterprise Organization API documentation for more information. /// IObservableEnterpriseOrganizationClient Organization { get; } + + /// + /// A client for GitHub's Enterprise Search Indexing API + /// + /// + /// See the Enterprise Search Indexing API documentation for more information. + /// + IObservableEnterpriseSearchIndexingClient SearchIndexing { get; } } } diff --git a/Octokit.Reactive/Clients/Enterprise/IObservableEnterpriseSearchIndexingClient.cs b/Octokit.Reactive/Clients/Enterprise/IObservableEnterpriseSearchIndexingClient.cs new file mode 100644 index 00000000..89b7d3fe --- /dev/null +++ b/Octokit.Reactive/Clients/Enterprise/IObservableEnterpriseSearchIndexingClient.cs @@ -0,0 +1,88 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Reactive.Threading.Tasks; + +namespace Octokit.Reactive +{ + /// + /// A client for GitHub's Enterprise Search Indexing API + /// + /// + /// See the Enterprise Search Indexing API documentation for more information. + /// + public interface IObservableEnterpriseSearchIndexingClient + { + /// + /// Queue an indexing job for a user or organization account (must be Site Admin user). + /// + /// + /// https://developer.github.com/v3/enterprise/search_indexing/#queue-an-indexing-job + /// + /// A user or organization account + /// The message. + IObservable Queue(string owner); + + /// + /// Queue an indexing job for a repository (must be Site Admin user). + /// + /// + /// https://developer.github.com/v3/enterprise/search_indexing/#queue-an-indexing-job + /// + /// A user or organization account + /// A repository + /// The message. + IObservable Queue(string owner, string repository); + + /// + /// Queue an indexing job for all of a user or organization's repositories (must be Site Admin user). + /// + /// + /// https://developer.github.com/v3/enterprise/search_indexing/#queue-an-indexing-job + /// + /// A user or organization account + /// The message. + IObservable QueueAll(string owner); + + /// + /// Queue an indexing job for all the issues in a repository (must be Site Admin user). + /// + /// + /// https://developer.github.com/v3/enterprise/search_indexing/#queue-an-indexing-job + /// + /// A user or organization account + /// A repository + /// The message. + IObservable QueueAllIssues(string owner, string repository); + + /// + /// Queue an indexing job for all the issues in all of a user or organization's repositories (must be Site Admin user). + /// + /// + /// https://developer.github.com/v3/enterprise/search_indexing/#queue-an-indexing-job + /// + /// A user or organization account + /// The message. + IObservable QueueAllIssues(string owner); + + /// + /// Queue an indexing job for all the source code in a repository (must be Site Admin user). + /// + /// + /// https://developer.github.com/v3/enterprise/search_indexing/#queue-an-indexing-job + /// + /// A user or organization account + /// A repository + /// The message. + IObservable QueueAllCode(string owner, string repository); + + /// + /// Queue an indexing job for all the source code in all of a user or organization's repositories (must be Site Admin user). + /// + /// + /// https://developer.github.com/v3/enterprise/search_indexing/#queue-an-indexing-job + /// + /// A user or organization account + /// The message. + IObservable QueueAllCode(string owner); + } +} diff --git a/Octokit.Reactive/Clients/Enterprise/ObservableEnterpriseClient.cs b/Octokit.Reactive/Clients/Enterprise/ObservableEnterpriseClient.cs index 7a52afcd..0aa4c920 100644 --- a/Octokit.Reactive/Clients/Enterprise/ObservableEnterpriseClient.cs +++ b/Octokit.Reactive/Clients/Enterprise/ObservableEnterpriseClient.cs @@ -15,6 +15,7 @@ AdminStats = new ObservableEnterpriseAdminStatsClient(client); License = new ObservableEnterpriseLicenseClient(client); Organization = new ObservableEnterpriseOrganizationClient(client); + SearchIndexing = new ObservableEnterpriseSearchIndexingClient(client); } /// @@ -40,5 +41,13 @@ /// See the Enterprise Organization API documentation for more information. /// public IObservableEnterpriseOrganizationClient Organization { get; private set; } + + /// + /// A client for GitHub's Enterprise Search Indexing API + /// + /// + /// See the Enterprise Search Indexing API documentation for more information. + /// + public IObservableEnterpriseSearchIndexingClient SearchIndexing { get; private set; } } } diff --git a/Octokit.Reactive/Clients/Enterprise/ObservableEnterpriseSearchIndexingClient.cs b/Octokit.Reactive/Clients/Enterprise/ObservableEnterpriseSearchIndexingClient.cs new file mode 100644 index 00000000..feb093db --- /dev/null +++ b/Octokit.Reactive/Clients/Enterprise/ObservableEnterpriseSearchIndexingClient.cs @@ -0,0 +1,118 @@ +using System; +using System.Reactive.Threading.Tasks; +using Octokit; + +namespace Octokit.Reactive +{ + /// + /// A client for GitHub's Enterprise Search Indexing API + /// + /// + /// See the Enterprise Search Indexing API documentation for more information. + /// + public class ObservableEnterpriseSearchIndexingClient : IObservableEnterpriseSearchIndexingClient + { + readonly IEnterpriseSearchIndexingClient _client; + + public ObservableEnterpriseSearchIndexingClient(IGitHubClient client) + { + Ensure.ArgumentNotNull(client, "client"); + + _client = client.Enterprise.SearchIndexing; + } + + /// + /// Queue an indexing job for a user or organization account (must be Site Admin user). + /// + /// + /// https://developer.github.com/v3/enterprise/search_indexing/#queue-an-indexing-job + /// + /// A user or organization account + /// The message. + public IObservable Queue(string owner) + { + return _client.Queue(owner).ToObservable(); + } + + /// + /// Queue an indexing job for a repository (must be Site Admin user). + /// + /// + /// https://developer.github.com/v3/enterprise/search_indexing/#queue-an-indexing-job + /// + /// A user or organization account + /// A repository + /// The message. + public IObservable Queue(string owner, string repository) + { + return _client.Queue(owner, repository).ToObservable(); + } + + /// + /// Queue an indexing job for all of a user or organization's repositories (must be Site Admin user). + /// + /// + /// https://developer.github.com/v3/enterprise/search_indexing/#queue-an-indexing-job + /// + /// A user or organization account + /// The message. + public IObservable QueueAll(string owner) + { + return _client.QueueAll(owner).ToObservable(); + } + + /// + /// Queue an indexing job for all the issues in a repository (must be Site Admin user). + /// + /// + /// https://developer.github.com/v3/enterprise/search_indexing/#queue-an-indexing-job + /// + /// A user or organization account + /// A repository + /// The message. + public IObservable QueueAllIssues(string owner, string repository) + { + return _client.QueueAllIssues(owner, repository).ToObservable(); + } + + /// + /// Queue an indexing job for all the issues in all of a user or organization's repositories (must be Site Admin user). + /// + /// + /// https://developer.github.com/v3/enterprise/search_indexing/#queue-an-indexing-job + /// + /// A user or organization account + /// The message. + public IObservable QueueAllIssues(string owner) + { + return _client.QueueAllIssues(owner).ToObservable(); + } + + /// + /// Queue an indexing job for all the source code in a repository (must be Site Admin user). + /// + /// + /// https://developer.github.com/v3/enterprise/search_indexing/#queue-an-indexing-job + /// + /// A user or organization account + /// A repository + /// The message. + public IObservable QueueAllCode(string owner, string repository) + { + return _client.QueueAllCode(owner, repository).ToObservable(); + } + + /// + /// Queue an indexing job for all the source code in all of a user or organization's repositories (must be Site Admin user). + /// + /// + /// https://developer.github.com/v3/enterprise/search_indexing/#queue-an-indexing-job + /// + /// A user or organization account + /// The message. + public IObservable QueueAllCode(string owner) + { + return _client.QueueAllCode(owner).ToObservable(); + } + } +} diff --git a/Octokit.Reactive/Octokit.Reactive.csproj b/Octokit.Reactive/Octokit.Reactive.csproj index 0841fbb4..607a71eb 100644 --- a/Octokit.Reactive/Octokit.Reactive.csproj +++ b/Octokit.Reactive/Octokit.Reactive.csproj @@ -75,12 +75,14 @@ Properties\SolutionInfo.cs + + diff --git a/Octokit.Tests.Integration/Helpers/ObservableGithubClientExtensions.cs b/Octokit.Tests.Integration/Helpers/ObservableGithubClientExtensions.cs new file mode 100644 index 00000000..8a5919ad --- /dev/null +++ b/Octokit.Tests.Integration/Helpers/ObservableGithubClientExtensions.cs @@ -0,0 +1,31 @@ +using Octokit.Reactive; +using System.Threading.Tasks; +using System.Reactive.Linq; + +namespace Octokit.Tests.Integration.Helpers +{ + internal static class ObservableGithubClientExtensions + { + internal async static Task CreateRepositoryContext(this IObservableGitHubClient client, string repositoryName) + { + var repoName = Helper.MakeNameWithTimestamp(repositoryName); + var repo = await client.Repository.Create(new NewRepository(repoName) { AutoInit = true }); + + return new RepositoryContext(repo); + } + + internal async static Task CreateRepositoryContext(this IObservableGitHubClient client, string organizationLogin, NewRepository newRepository) + { + var repo = await client.Repository.Create(organizationLogin, newRepository); + + return new RepositoryContext(repo); + } + + internal async static Task CreateRepositoryContext(this IObservableGitHubClient client, NewRepository newRepository) + { + var repo = await client.Repository.Create(newRepository); + + return new RepositoryContext(repo); + } + } +} \ No newline at end of file diff --git a/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj b/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj index 74a06d90..d8df0040 100644 --- a/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj +++ b/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj @@ -112,6 +112,7 @@ + @@ -127,6 +128,7 @@ + diff --git a/Octokit.Tests.Integration/Reactive/Enterprise/ObservableEnterpriseSearchIndexingClientTests.cs b/Octokit.Tests.Integration/Reactive/Enterprise/ObservableEnterpriseSearchIndexingClientTests.cs new file mode 100644 index 00000000..b741fec9 --- /dev/null +++ b/Octokit.Tests.Integration/Reactive/Enterprise/ObservableEnterpriseSearchIndexingClientTests.cs @@ -0,0 +1,108 @@ +using System.Linq; +using System.Reactive.Linq; +using System.Threading.Tasks; +using Octokit.Reactive; +using Octokit.Tests.Integration.Helpers; +using Xunit; + +namespace Octokit.Tests.Integration +{ + public class ObservableEnterpriseSearchIndexingClientTests + { + readonly IObservableGitHubClient _github; + + public ObservableEnterpriseSearchIndexingClientTests() + { + _github = new ObservableGitHubClient(EnterpriseHelper.GetAuthenticatedClient()); + } + + [GitHubEnterpriseTest] + public async Task CanQueueOwner() + { + var observable = _github.Enterprise.SearchIndexing.Queue(EnterpriseHelper.UserName); + var response = await observable; + + Assert.NotNull(response); + Assert.NotNull(response.Message); + Assert.True(response.Message.All(m => m.Contains("was added to the indexing queue"))); + } + + [GitHubEnterpriseTest] + public async Task CanQueueRepository() + { + var newRepository = new NewRepository(Helper.MakeNameWithTimestamp("public-repo")); + using (var context = await _github.CreateRepositoryContext(newRepository)) + { + var observable = _github.Enterprise.SearchIndexing.Queue(EnterpriseHelper.UserName, context.RepositoryName); + var response = await observable; + + Assert.NotNull(response); + Assert.NotNull(response.Message); + Assert.True(response.Message.All(m => m.Contains("was added to the indexing queue"))); + } + } + + [GitHubEnterpriseTest] + public async Task CanQueueAll() + { + var observable = _github.Enterprise.SearchIndexing.QueueAll(EnterpriseHelper.UserName); + var response = await observable; + + Assert.NotNull(response); + Assert.NotNull(response.Message); + Assert.True(response.Message.All(m => m.Contains("was added to the indexing queue"))); + } + + [GitHubEnterpriseTest] + public async Task CanQueueAllCodeOwner() + { + var observable = _github.Enterprise.SearchIndexing.QueueAllCode(EnterpriseHelper.UserName); + var response = await observable; + + Assert.NotNull(response); + Assert.NotNull(response.Message); + Assert.True(response.Message.All(m => m.Contains("was added to the indexing queue"))); + } + + [GitHubEnterpriseTest] + public async Task CanQueueAllCodeRepository() + { + var newRepository = new NewRepository(Helper.MakeNameWithTimestamp("public-repo")); + using (var context = await _github.CreateRepositoryContext(newRepository)) + { + var observable = _github.Enterprise.SearchIndexing.QueueAllCode(EnterpriseHelper.UserName, context.RepositoryName); + var response = await observable; + + Assert.NotNull(response); + Assert.NotNull(response.Message); + Assert.True(response.Message.All(m => m.Contains("was added to the indexing queue"))); + } + } + + [GitHubEnterpriseTest] + public async Task CanQueueAllIssuesOwner() + { + var observable = _github.Enterprise.SearchIndexing.QueueAllIssues(EnterpriseHelper.UserName); + var response = await observable; + + Assert.NotNull(response); + Assert.NotNull(response.Message); + Assert.True(response.Message.All(m => m.Contains("were added to the indexing queue"))); + } + + [GitHubEnterpriseTest] + public async Task CanQueueAllIssuesRepository() + { + var newRepository = new NewRepository(Helper.MakeNameWithTimestamp("public-repo")); + using (var context = await _github.CreateRepositoryContext(newRepository)) + { + var observable = _github.Enterprise.SearchIndexing.QueueAllIssues(EnterpriseHelper.UserName, context.RepositoryName); + var response = await observable; + + Assert.NotNull(response); + Assert.NotNull(response.Message); + Assert.True(response.Message.All(m => m.Contains("were added to the indexing queue"))); + } + } + } +} \ No newline at end of file diff --git a/Octokit.Tests/Octokit.Tests.csproj b/Octokit.Tests/Octokit.Tests.csproj index c3418554..bc124880 100644 --- a/Octokit.Tests/Octokit.Tests.csproj +++ b/Octokit.Tests/Octokit.Tests.csproj @@ -191,6 +191,7 @@ + diff --git a/Octokit.Tests/Reactive/Enterprise/ObservableEnterpriseSearchIndexingClientTests.cs b/Octokit.Tests/Reactive/Enterprise/ObservableEnterpriseSearchIndexingClientTests.cs new file mode 100644 index 00000000..491acbfc --- /dev/null +++ b/Octokit.Tests/Reactive/Enterprise/ObservableEnterpriseSearchIndexingClientTests.cs @@ -0,0 +1,81 @@ +using System; +using NSubstitute; +using Octokit.Reactive; +using Xunit; + +namespace Octokit.Tests +{ + public class ObservableEnterpriseSearchIndexingClientTests + { + public class TheQueueMethod + { + [Fact] + public void CallsIntoClient() + { + var github = Substitute.For(); + var client = new ObservableEnterpriseSearchIndexingClient(github); + + client.Queue("org"); + github.Enterprise.SearchIndexing.Received(1). + Queue(Arg.Is( "org" )); + + client.Queue("org", "repo"); + github.Enterprise.SearchIndexing.Received(1). + Queue(Arg.Is("org"), + Arg.Is("repo")); + } + } + + public class TheQueueAllMethod + { + [Fact] + public void CallsIntoClient() + { + var github = Substitute.For(); + var client = new ObservableEnterpriseSearchIndexingClient(github); + + client.QueueAll("org"); + github.Enterprise.SearchIndexing.Received(1). + QueueAll(Arg.Is("org")); + } + } + + public class TheQueueAllCodeMethod + { + [Fact] + public void CallsIntoClient() + { + var github = Substitute.For(); + var client = new ObservableEnterpriseSearchIndexingClient(github); + + client.QueueAllCode("org"); + github.Enterprise.SearchIndexing.Received(1). + QueueAllCode(Arg.Is("org")); + + client.QueueAllCode("org", "repo"); + github.Enterprise.SearchIndexing.Received(1). + QueueAllCode(Arg.Is("org"), + Arg.Is("repo")); + } + } + + public class TheQueueAllIssuesMethod + { + [Fact] + public void CallsIntoClient() + { + var github = Substitute.For(); + var client = new ObservableEnterpriseSearchIndexingClient(github); + + client.QueueAllIssues("org"); + github.Enterprise.SearchIndexing.Received(1). + QueueAllIssues(Arg.Is("org")); + + client.QueueAllIssues("org", "repo"); + github.Enterprise.SearchIndexing.Received(1). + QueueAllIssues(Arg.Is("org"), + Arg.Is("repo")); + } + } + } +} From b3049eed8c2f979fde37c955e32df035e1939b6e Mon Sep 17 00:00:00 2001 From: Ryan Gribble Date: Fri, 5 Feb 2016 22:34:20 +1000 Subject: [PATCH 21/21] Fixup Mono projects --- Octokit.Reactive/Octokit.Reactive-Mono.csproj | 2 ++ Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj | 2 ++ Octokit.Reactive/Octokit.Reactive-Monotouch.csproj | 2 ++ 3 files changed, 6 insertions(+) diff --git a/Octokit.Reactive/Octokit.Reactive-Mono.csproj b/Octokit.Reactive/Octokit.Reactive-Mono.csproj index 3c0f28aa..10d63457 100644 --- a/Octokit.Reactive/Octokit.Reactive-Mono.csproj +++ b/Octokit.Reactive/Octokit.Reactive-Mono.csproj @@ -169,6 +169,8 @@ + + diff --git a/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj b/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj index a808ba91..d0f878da 100644 --- a/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj +++ b/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj @@ -177,6 +177,8 @@ + + diff --git a/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj b/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj index 616d3ad0..ce3efdbe 100644 --- a/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj +++ b/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj @@ -173,6 +173,8 @@ + +