From 535709c3689eaa6b6a4556757c11d0d50b0aae0e Mon Sep 17 00:00:00 2001 From: Ryan Gribble Date: Wed, 27 Jan 2016 00:12:22 +1000 Subject: [PATCH 1/9] 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 12dc638ae9..2c8b1cf6d9 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 0000000000..27f237d0c7 --- /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 bd11852187..79a249a99c 100644 --- a/Octokit.Tests.Integration/Helper.cs +++ b/Octokit.Tests.Integration/Helper.cs @@ -50,9 +50,9 @@ public static class Helper 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 @@ static Helper() 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 @@ public static bool IsPaidAccount } } - public static bool IsGitHubEnterprise - { - get - { - return GitHubEnterpriseUrl != null; - } - } - public static string ClientId { get { return Environment.GetEnvironmentVariable("OCTOKIT_CLIENTID"); } @@ -151,7 +145,7 @@ public static Stream LoadFixture(string fileName) 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 @@ public static IGitHubClient GetAuthenticatedClient() 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 @@ public static IGitHubClient GetBasicAuthClient() 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 @@ public static GitHubClient GetAuthenticatedApplicationClient() 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 80c1df66c2..938bfb4641 100644 --- a/Octokit.Tests.Integration/Helpers/GitHubEnterpriseTestAttribute.cs +++ b/Octokit.Tests.Integration/Helpers/GitHubEnterpriseTestAttribute.cs @@ -20,7 +20,7 @@ public IEnumerable Discover(ITestFrameworkDiscoveryOptions disco 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 3cbb946201..2be66be3fe 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 2cb61234c0..182ad393fd 100644 --- a/Octokit.Tests.Integration/Reactive/Enterprise/ObservableEnterpriseAdminStatsClientTests.cs +++ b/Octokit.Tests.Integration/Reactive/Enterprise/ObservableEnterpriseAdminStatsClientTests.cs @@ -11,7 +11,7 @@ public class ObservableEnterpriseAdminStatsClientTests 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 5592c3e495..590291d95c 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 2/9] 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 0000000000..81cd97b4f7 --- /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 2be66be3fe..0c17edb4ec 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 0000000000..947fa4a23b --- /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 5af192547d..6888620668 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 42e1763a64..70b74a5b60 100644 --- a/Octokit/Clients/Enterprise/EnterpriseClient.cs +++ b/Octokit/Clients/Enterprise/EnterpriseClient.cs @@ -15,6 +15,7 @@ public class EnterpriseClient : ApiClient, IEnterpriseClient public EnterpriseClient(IApiConnection apiConnection) : base(apiConnection) { AdminStats = new EnterpriseAdminStatsClient(apiConnection); + License = new EnterpriseLicenseClient(apiConnection); } /// @@ -24,5 +25,13 @@ public EnterpriseClient(IApiConnection apiConnection) : base(apiConnection) /// 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 0000000000..466388831d --- /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 e5eff83a41..1d6850137c 100644 --- a/Octokit/Clients/Enterprise/IEnterpriseClient.cs +++ b/Octokit/Clients/Enterprise/IEnterpriseClient.cs @@ -15,5 +15,13 @@ public interface IEnterpriseClient /// 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 0000000000..6e067e6551 --- /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 efc680b3d7..b2ee1b6bd2 100644 --- a/Octokit/Helpers/ApiUrls.cs +++ b/Octokit/Helpers/ApiUrls.cs @@ -1652,5 +1652,10 @@ public static Uri EnterpriseAdminStatsAll() { 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 0000000000..14fe66673f --- /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 549f391f49..fb7cade876 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 3/9] 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 4a494899ca..d47859f978 100644 --- a/Octokit.Reactive/Clients/Enterprise/IObservableEnterpriseClient.cs +++ b/Octokit.Reactive/Clients/Enterprise/IObservableEnterpriseClient.cs @@ -15,5 +15,13 @@ public interface IObservableEnterpriseClient /// 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 0000000000..99acfdb86f --- /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 8466e9b85a..2b13f505d6 100644 --- a/Octokit.Reactive/Clients/Enterprise/ObservableEnterpriseClient.cs +++ b/Octokit.Reactive/Clients/Enterprise/ObservableEnterpriseClient.cs @@ -13,6 +13,7 @@ public ObservableEnterpriseClient(IGitHubClient client) Ensure.ArgumentNotNull(client, "client"); AdminStats = new ObservableEnterpriseAdminStatsClient(client); + License = new ObservableEnterpriseLicenseClient(client); } /// @@ -22,5 +23,13 @@ public ObservableEnterpriseClient(IGitHubClient client) /// 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 0000000000..bf85248392 --- /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 aee83c4189..e81bfe422b 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 0c17edb4ec..89c33b916f 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 0000000000..0c35fb5df5 --- /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 6888620668..df74b65214 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 0000000000..1ebd24523f --- /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 4/9] 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 0d93d33ae5..ad9cfd4305 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 de9321e9e9..a15826514b 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 018f37d0c6..cc5e18cce7 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 d46271b2a0..dc09b8512f 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 3897d4ae61..8ed5dcd88f 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 cd30e2a088..07ba380b67 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 dd5907bd89..4d35d944ed 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 9d5fd54614..cdfda9af18 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 5/9] 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 0000000000..61ace7d204 --- /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 89c33b916f..e5a117d54e 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 0000000000..4b078b1290 --- /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 df74b65214..f6a0b24a66 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 70b74a5b60..e0109d1556 100644 --- a/Octokit/Clients/Enterprise/EnterpriseClient.cs +++ b/Octokit/Clients/Enterprise/EnterpriseClient.cs @@ -16,6 +16,7 @@ public EnterpriseClient(IApiConnection apiConnection) : base(apiConnection) { AdminStats = new EnterpriseAdminStatsClient(apiConnection); License = new EnterpriseLicenseClient(apiConnection); + Organization = new EnterpriseOrganizationClient(apiConnection); } /// @@ -33,5 +34,13 @@ public EnterpriseClient(IApiConnection apiConnection) : base(apiConnection) /// 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 0000000000..0848ff8ea7 --- /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 1d6850137c..f1c6209fc3 100644 --- a/Octokit/Clients/Enterprise/IEnterpriseClient.cs +++ b/Octokit/Clients/Enterprise/IEnterpriseClient.cs @@ -23,5 +23,13 @@ public interface IEnterpriseClient /// 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 0000000000..4904480ce0 --- /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 b2ee1b6bd2..156cbd2d1c 100644 --- a/Octokit/Helpers/ApiUrls.cs +++ b/Octokit/Helpers/ApiUrls.cs @@ -1657,5 +1657,10 @@ public static Uri EnterpriseLicense() { 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 0000000000..2a8a4a61ef --- /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 fb7cade876..a1a1ab8a98 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 6/9] 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 d47859f978..72e2d25efe 100644 --- a/Octokit.Reactive/Clients/Enterprise/IObservableEnterpriseClient.cs +++ b/Octokit.Reactive/Clients/Enterprise/IObservableEnterpriseClient.cs @@ -23,5 +23,13 @@ public interface IObservableEnterpriseClient /// 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 0000000000..ebb39eb9f7 --- /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 2b13f505d6..7a52afcd5b 100644 --- a/Octokit.Reactive/Clients/Enterprise/ObservableEnterpriseClient.cs +++ b/Octokit.Reactive/Clients/Enterprise/ObservableEnterpriseClient.cs @@ -14,6 +14,7 @@ public ObservableEnterpriseClient(IGitHubClient client) AdminStats = new ObservableEnterpriseAdminStatsClient(client); License = new ObservableEnterpriseLicenseClient(client); + Organization = new ObservableEnterpriseOrganizationClient(client); } /// @@ -31,5 +32,13 @@ public ObservableEnterpriseClient(IGitHubClient client) /// 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 0000000000..1f78574c2b --- /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 e81bfe422b..0ffdc200bc 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 e5a117d54e..7781ebbcaf 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 0000000000..c0816f68ea --- /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 f6a0b24a66..a5ab207145 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 0000000000..5c1867c48e --- /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 7/9] 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 ad9cfd4305..a0128ae2ce 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 a15826514b..749d157256 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 cc5e18cce7..47b8d02e2d 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 dc09b8512f..821fe80e96 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 8ed5dcd88f..1e290d8cba 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 07ba380b67..198be8bebd 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 4d35d944ed..e2e7e4224e 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 cdfda9af18..3851819670 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 8/9] 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 61ace7d204..ce77ae3b46 100644 --- a/Octokit.Tests.Integration/Clients/Enterprise/EnterpriseOrganizationClientTests.cs +++ b/Octokit.Tests.Integration/Clients/Enterprise/EnterpriseOrganizationClientTests.cs @@ -20,7 +20,7 @@ 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 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 27f237d0c7..9a1ab54e06 100644 --- a/Octokit.Tests.Integration/EnterpriseHelper.cs +++ b/Octokit.Tests.Integration/EnterpriseHelper.cs @@ -9,8 +9,8 @@ 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"); + UserName = githubUsername; + Organization = Environment.GetEnvironmentVariable("OCTOKIT_GHE_ORGANIZATION"); var githubToken = Environment.GetEnvironmentVariable("OCTOKIT_GHE_OAUTHTOKEN"); @@ -39,8 +39,8 @@ public static class EnterpriseHelper 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 @@ 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."); + 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 @@ public static IGitHubClient GetAuthenticatedClient() { return new GitHubClient(new ProductHeaderValue("OctokitEnterpriseTests"), GitHubEnterpriseUrl) { - Credentials = GHECredentials + Credentials = Credentials }; } @@ -136,7 +136,7 @@ public static IGitHubClient GetBasicAuthClient() { return new GitHubClient(new ProductHeaderValue("OctokitEnterpriseTests"), GitHubEnterpriseUrl) { - Credentials = GHEBasicAuthCredentials + Credentials = BasicAuthCredentials }; } @@ -144,7 +144,7 @@ public static GitHubClient GetAuthenticatedApplicationClient() { 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 c0816f68ea..28997bada0 100644 --- a/Octokit.Tests.Integration/Reactive/Enterprise/ObservableEnterpriseOrganizationClientTests.cs +++ b/Octokit.Tests.Integration/Reactive/Enterprise/ObservableEnterpriseOrganizationClientTests.cs @@ -21,7 +21,7 @@ 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 newOrganization = new NewOrganization(orgLogin, EnterpriseHelper.UserName, orgName); var observable = _github.Enterprise.Organization.Create(newOrganization); var organization = await observable; From 547e233308ffc45f3ab9b856661810a69e5bad92 Mon Sep 17 00:00:00 2001 From: Ryan Gribble Date: Fri, 5 Feb 2016 21:41:39 +1000 Subject: [PATCH 9/9] 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 99acfdb86f..7ec56f1b11 100644 --- a/Octokit.Reactive/Clients/Enterprise/IObservableEnterpriseLicenseClient.cs +++ b/Octokit.Reactive/Clients/Enterprise/IObservableEnterpriseLicenseClient.cs @@ -23,4 +23,3 @@ public interface IObservableEnterpriseLicenseClient 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 ebb39eb9f7..38f744f1c5 100644 --- a/Octokit.Reactive/Clients/Enterprise/IObservableEnterpriseOrganizationClient.cs +++ b/Octokit.Reactive/Clients/Enterprise/IObservableEnterpriseOrganizationClient.cs @@ -23,4 +23,3 @@ public interface IObservableEnterpriseOrganizationClient 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 1ebd24523f..b3f89bb5a4 100644 --- a/Octokit.Tests/Reactive/Enterprise/ObservableEnterpriseLicenseClientTests.cs +++ b/Octokit.Tests/Reactive/Enterprise/ObservableEnterpriseLicenseClientTests.cs @@ -12,7 +12,6 @@ public class TheGetMethod [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 5c1867c48e..47046e05fd 100644 --- a/Octokit.Tests/Reactive/Enterprise/ObservableEnterpriseOrganizationClientTests.cs +++ b/Octokit.Tests/Reactive/Enterprise/ObservableEnterpriseOrganizationClientTests.cs @@ -12,7 +12,6 @@ public class TheCreateMethod [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 14fe66673f..03bd174c04 100644 --- a/Octokit/Models/Response/Enterprise/LicenseInfo.cs +++ b/Octokit/Models/Response/Enterprise/LicenseInfo.cs @@ -19,7 +19,6 @@ public LicenseInfo(int seats, int seatsUsed, int seatsAvailable, string kind, in ExpireAt = expireAt; } - public int Seats { get;