diff --git a/Octokit.Reactive/Clients/IObservableMigrationClient.cs b/Octokit.Reactive/Clients/IObservableMigrationClient.cs new file mode 100644 index 0000000000..a7c8588609 --- /dev/null +++ b/Octokit.Reactive/Clients/IObservableMigrationClient.cs @@ -0,0 +1,13 @@ +namespace Octokit.Reactive +{ + public interface IObservableMigrationClient + { + /// + /// A client for GitHub's Migrations API + /// + /// + /// See the Enterprise License API documentation for more information. + /// + IObservableMigrationsClient Migrations { get; } + } +} \ No newline at end of file diff --git a/Octokit.Reactive/Clients/IObservableMigrationsClient.cs b/Octokit.Reactive/Clients/IObservableMigrationsClient.cs new file mode 100644 index 0000000000..5ca361d844 --- /dev/null +++ b/Octokit.Reactive/Clients/IObservableMigrationsClient.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Reactive; + +namespace Octokit.Reactive +{ + /// + /// An interface for GitHub's Migrations API client. + /// + /// + /// See the docs + /// for more information. + /// + public interface IObservableMigrationsClient + { + /// + /// Starts a new migration specified for the given organization. + /// + /// + /// https://developer.github.com/v3/migration/migrations/#start-a-migration + /// + /// The organization for which to start a migration. + /// Sprcifies parameters for the migration in a + /// object. + /// The started migration. + IObservable Start( + string org, + StartMigrationRequest migration); + + /// + /// Gets the list of the most recent migrations of the the organization. + /// + /// + /// https://developer.github.com/v3/migration/migrations/#get-a-list-of-migrations + /// + /// The organization of which to list migrations. + /// List of most recent s. + IObservable> GetAll( + string org); + + /// + /// Get the status of a migration. + /// + /// + /// https://developer.github.com/v3/migration/migrations/#get-the-status-of-a-migration + /// + /// The organization which is migrating. + /// Migration ID of the organization. + /// A object representing the state of migration. + [SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "Get")] + IObservable Get( + string org, + int id); + + /// + /// Get the migration archive. + /// + /// + /// https://developer.github.com/v3/migration/migrations/#download-a-migration-archive + /// + /// The organization of which the migration was. + /// The ID of the migration. + /// The binary contents of the archive as a byte array. + IObservable GetArchive( + string org, + int id); + + /// + /// Deletes a previous migration archive. + /// + /// + /// https://developer.github.com/v3/migration/migrations/#delete-a-migration-archive + /// + /// The organization of which the migration was. + /// The ID of the migration. + /// + IObservable DeleteArchive( + string org, + int id); + + /// + /// Unlocks a repository that was locked for migration. + /// + /// + /// https://developer.github.com/v3/migration/migrations/#unlock-a-repository + /// + /// The organization of which the migration was. + /// The ID of the migration. + /// The repo to unlock. + /// + IObservable UnlockRepository( + string org, + int id, + string repo); + } +} diff --git a/Octokit.Reactive/Clients/ObservableMigrationClient.cs b/Octokit.Reactive/Clients/ObservableMigrationClient.cs new file mode 100644 index 0000000000..7eee1d42da --- /dev/null +++ b/Octokit.Reactive/Clients/ObservableMigrationClient.cs @@ -0,0 +1,20 @@ +namespace Octokit.Reactive +{ + public class ObservableMigrationClient : IObservableMigrationClient + { + public ObservableMigrationClient(IGitHubClient client) + { + Ensure.ArgumentNotNull(client, "client"); + + Migrations = new ObservableMigrationsClient(client); + } + + /// + /// A client for GitHub's Enterprise Migrations API. + /// + /// + /// https://developer.github.com/v3/migration/#enterprise-migrations + /// + public IObservableMigrationsClient Migrations { get; private set; } + } +} \ No newline at end of file diff --git a/Octokit.Reactive/Clients/ObservableMigrationsClient.cs b/Octokit.Reactive/Clients/ObservableMigrationsClient.cs new file mode 100644 index 0000000000..55b29c50ae --- /dev/null +++ b/Octokit.Reactive/Clients/ObservableMigrationsClient.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections.Generic; +using System.Reactive; +using System.Reactive.Threading.Tasks; + +namespace Octokit.Reactive +{ + /// + /// An interface for GitHub's Migrations API client. + /// + /// + /// See the docs + /// for more information. + /// + public class ObservableMigrationsClient : IObservableMigrationsClient + { + private readonly IMigrationsClient _client; + + /// + /// Instantiates a GitHub Migrations API client. + /// + /// An for making requests. + public ObservableMigrationsClient(IGitHubClient client) + { + Ensure.ArgumentNotNull(client, "client"); + + _client = client.Migration.Migrations; + } + + /// + /// Starts a new migration specified for the given organization. + /// + /// + /// https://developer.github.com/v3/migration/migrations/#start-a-migration + /// + /// The organization for which to start a migration. + /// Sprcifies parameters for the migration in a + /// object. + /// The started migration. + public IObservable Start(string org, StartMigrationRequest migration) + { + return _client.Start(org, migration).ToObservable(); + } + + /// + /// Gets the list of the most recent migrations of the the organization. + /// + /// + /// https://developer.github.com/v3/migration/migrations/#get-a-list-of-migrations + /// + /// The organization of which to list migrations. + /// List of most recent s. + public IObservable> GetAll(string org) + { + return _client.GetAll(org).ToObservable(); + } + + /// + /// Get the status of a migration + /// + /// + /// https://developer.github.com/v3/migration/migrations/#get-the-status-of-a-migration + /// + /// The organization which is migrating. + /// Migrations ID of the organization. + /// A object representing the state of migration. + public IObservable Get(string org, int id) + { + return _client.Get(org, id).ToObservable(); + } + + /// + /// Get the migration archive. + /// + /// + /// https://developer.github.com/v3/migration/migrations/#download-a-migration-archive + /// + /// The organization of which the migration was. + /// The ID of the migration. + /// The binary contents of the archive as a byte array. + public IObservable GetArchive(string org, int id) + { + return _client.GetArchive(org, id).ToObservable(); + } + + /// + /// Deletes a previous migration archive. + /// + /// + /// https://developer.github.com/v3/migration/migrations/#delete-a-migration-archive + /// + /// The organization of which the migration was. + /// The ID of the migration. + /// + public IObservable DeleteArchive(string org, int id) + { + return _client.DeleteArchive(org, id).ToObservable(); + } + + /// + /// Unlocks a repository that was locked for migration. + /// + /// + /// https://developer.github.com/v3/migration/migrations/#unlock-a-repository + /// + /// The organization of which the migration was. + /// The ID of the migration. + /// The repo to unlock. + /// + public IObservable UnlockRepository(string org, int id, string repo) + { + return _client.UnlockRepository(org, id, repo).ToObservable(); + } + } +} diff --git a/Octokit.Reactive/IObservableGitHubClient.cs b/Octokit.Reactive/IObservableGitHubClient.cs index 6f4240729c..00650ab5f6 100644 --- a/Octokit.Reactive/IObservableGitHubClient.cs +++ b/Octokit.Reactive/IObservableGitHubClient.cs @@ -26,5 +26,6 @@ public interface IObservableGitHubClient : IApiInfoProvider IObservableGitDatabaseClient GitDatabase { get; } IObservableSearchClient Search { get; } IObservableEnterpriseClient Enterprise { get; } + IObservableMigrationClient Migration { get; } } } \ No newline at end of file diff --git a/Octokit.Reactive/ObservableGitHubClient.cs b/Octokit.Reactive/ObservableGitHubClient.cs index 164855931b..0d71234444 100644 --- a/Octokit.Reactive/ObservableGitHubClient.cs +++ b/Octokit.Reactive/ObservableGitHubClient.cs @@ -46,6 +46,7 @@ public ObservableGitHubClient(IGitHubClient gitHubClient) Gist = new ObservableGistsClient(gitHubClient); Search = new ObservableSearchClient(gitHubClient); Enterprise = new ObservableEnterpriseClient(gitHubClient); + Migration = new ObservableMigrationClient(gitHubClient); } public IConnection Connection @@ -72,6 +73,7 @@ public IConnection Connection public IObservableGitDatabaseClient Git { get; private set; } public IObservableSearchClient Search { get; private set; } public IObservableEnterpriseClient Enterprise { get; private set; } + public IObservableMigrationClient Migration { get; private set; } /// /// Gets the latest API Info - this will be null if no API calls have been made diff --git a/Octokit.Reactive/Octokit.Reactive-Mono.csproj b/Octokit.Reactive/Octokit.Reactive-Mono.csproj index 6cf3a0262e..9601cc8d7c 100644 --- a/Octokit.Reactive/Octokit.Reactive-Mono.csproj +++ b/Octokit.Reactive/Octokit.Reactive-Mono.csproj @@ -176,6 +176,10 @@ + + + + diff --git a/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj b/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj index 146e66b0e4..bf75c3bf3b 100644 --- a/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj +++ b/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj @@ -184,6 +184,10 @@ + + + + diff --git a/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj b/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj index c3d64929d7..065807bc88 100644 --- a/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj +++ b/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj @@ -180,6 +180,10 @@ + + + + diff --git a/Octokit.Reactive/Octokit.Reactive.csproj b/Octokit.Reactive/Octokit.Reactive.csproj index 8d1d8e9994..920aefbe9c 100644 --- a/Octokit.Reactive/Octokit.Reactive.csproj +++ b/Octokit.Reactive/Octokit.Reactive.csproj @@ -90,14 +90,18 @@ + + + + diff --git a/Octokit.Tests.Integration/Clients/MigrationsClientTests.cs b/Octokit.Tests.Integration/Clients/MigrationsClientTests.cs new file mode 100644 index 0000000000..8c43c03dd9 --- /dev/null +++ b/Octokit.Tests.Integration/Clients/MigrationsClientTests.cs @@ -0,0 +1,132 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography; +using System.Threading; +using System.Threading.Tasks; +using Octokit; +using Octokit.Tests.Integration; +using Octokit.Tests.Integration.Helpers; +using Xunit; + +public class MigrationsClientTests : IDisposable +{ + private readonly IGitHubClient _gitHub; + private List _repos; + private Migration _migrationContext; + private string _orgName; + private bool isExported = false; + + public MigrationsClientTests() + { + _gitHub = Helper.GetAuthenticatedClient(); + _orgName = Helper.Organization; + _repos = new List(); + + CreateTheWorld().Wait(); + StartNewMigration().Wait(); + } + + private async Task CreateTheWorld() + { + _repos.Add(await _gitHub.CreateRepositoryContext(_orgName, new NewRepository(Helper.MakeNameWithTimestamp("migrationtest-repo1")) + { + GitignoreTemplate = "VisualStudio", + LicenseTemplate = "mit" + })); + _repos.Add(await _gitHub.CreateRepositoryContext(_orgName, new NewRepository(Helper.MakeNameWithTimestamp("migrationtest-repo2")) + { + GitignoreTemplate = "VisualStudio", + LicenseTemplate = "mit" + })); + _repos.Add(await _gitHub.CreateRepositoryContext(_orgName, new NewRepository(Helper.MakeNameWithTimestamp("migrationtest-repo3")) + { + GitignoreTemplate = "VisualStudio", + LicenseTemplate = "mit" + })); + } + + public async Task StartNewMigration() + { + var repoNames = _repos.Select(repo => repo.Repository.FullName).ToList(); + var migrationRequest = new StartMigrationRequest(repoNames); + + _migrationContext = await _gitHub.Migration.Migrations.Start(_orgName, migrationRequest); + + Assert.Equal(3, _migrationContext.Repositories.Count); + Assert.Equal(Migration.MigrationState.Pending, _migrationContext.State); + + ChecksMigrationCompletion(); + } + + [IntegrationTest] + public async Task CanGetAllMigrations() + { + var migrations = await _gitHub.Migration.Migrations.GetAll(_orgName); + + Assert.NotNull(migrations); + Assert.NotEqual(0, migrations.Count); + } + + [IntegrationTest] + public async Task CanGetMigration() + { + var retreivedMigration = await _gitHub.Migration.Migrations.Get(_orgName, _migrationContext.Id); + + Assert.Equal(_migrationContext.Guid, retreivedMigration.Guid); + } + + [IntegrationTest] + public async Task CanGetArchive() + { + while (!isExported) + { + Thread.Sleep(2000); + } + + var contents = await _gitHub.Migration.Migrations.GetArchive(_orgName, _migrationContext.Id); + + Assert.NotEmpty(contents); + } + + [IntegrationTest] + public async Task CanDeleteArchive() + { + while (!isExported) + { + Thread.Sleep(2000); + } + + await _gitHub.Migration.Migrations.DeleteArchive(_orgName, _migrationContext.Id); + } + + [IntegrationTest] + public async Task CanUnlockRepository() + { + while (!isExported) + { + Thread.Sleep(2000); + } + + await _gitHub.Migration.Migrations.UnlockRepository(_orgName, _migrationContext.Id, _migrationContext.Repositories[0].Name); + } + + async Task ChecksMigrationCompletion() + { + while (!isExported) + { + Thread.Sleep(2000); + _migrationContext = await _gitHub.Migration.Migrations.Get(_orgName, _migrationContext.Id); + + if (_migrationContext.State == Migration.MigrationState.Exported) + { + isExported = true; + } + } + } + + public void Dispose() + { + _repos.ForEach( (repo) => repo.Dispose() ); + } +} diff --git a/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj b/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj index d954107000..b461709328 100644 --- a/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj +++ b/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj @@ -92,6 +92,7 @@ + diff --git a/Octokit.Tests/Clients/MigrationsClientTests.cs b/Octokit.Tests/Clients/MigrationsClientTests.cs new file mode 100644 index 0000000000..a1d610a254 --- /dev/null +++ b/Octokit.Tests/Clients/MigrationsClientTests.cs @@ -0,0 +1,209 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using NSubstitute; +using Xunit; + +namespace Octokit.Tests.Clients +{ + public class MigrationsClientTests + { + public class TheCtor + { + [Fact] + public void EnsuresNonNullArguments() + { + Assert.Throws( + () => new EventsClient(null)); + } + } + + public class TheGetMethod + { + [Fact] + public void RequestsCorrectUrl() + { + var connection = Substitute.For(); + var client = new MigrationsClient(connection); + + client.Get("fake", 69); + + connection.Received().Get( + Arg.Is(u => u.ToString() == "orgs/fake/migrations/69"), + null, + AcceptHeaders.MigrationsApiPreview); + } + + [Fact] + public async Task EnsuresNonNullAndNonEmptyArguments() + { + var connection = Substitute.For(); + var client = new MigrationsClient(connection); + + await Assert.ThrowsAsync(() => client.Get(null, 69)); + await Assert.ThrowsAsync(() => client.Get("", 69)); + } + } + + public class TheGetAllMethod + { + [Fact] + public void RequestsCorrectUrl() + { + var connection = Substitute.For(); + var client = new MigrationsClient(connection); + + client.GetAll("fake"); + + connection.Received().Get>( + Arg.Is(u => u.ToString() == "orgs/fake/migrations"), + null, + AcceptHeaders.MigrationsApiPreview); + } + + [Fact] + public async Task EnsuresNonNullAndNonEmptyArguments() + { + var connection = Substitute.For(); + var client = new MigrationsClient(connection); + + await Assert.ThrowsAsync(() => client.GetAll(null)); + await Assert.ThrowsAsync(() => client.GetAll("")); + } + } + + public class TheStartNewMethod + { + [Fact] + public void RequestsCorrectUrl() + { + var connection = Substitute.For(); + var client = new MigrationsClient(connection); + var migrationRequest = new StartMigrationRequest(new List { "fake/repo" }); + + client.Start("fake", migrationRequest); + + connection.Received().Post( + Arg.Is(u => u.ToString() == "orgs/fake/migrations"), + Arg.Any(), + AcceptHeaders.MigrationsApiPreview); + } + + [Fact] + public async Task EnsuresNonNullAndNonEmptyArguments() + { + var connection = Substitute.For(); + var client = new MigrationsClient(connection); + var migrationRequest = new StartMigrationRequest(new List { "fake/repo" }); + + await Assert.ThrowsAsync( + () => client.Start(null, migrationRequest)); + await Assert.ThrowsAsync( + () => client.Start("", migrationRequest)); + await Assert.ThrowsAsync( + () => client.Start("fake", null)); + } + + [Fact] + public void PassesRequestBody() + { + var connection = Substitute.For(); + var client = new MigrationsClient(connection); + var migrationRequest = new StartMigrationRequest(new List { "fake/repo" }); + + client.Start("fake", migrationRequest); + + connection.Received().Post( + Arg.Any(), + Arg.Is(m => + m.Repositories.Equals(migrationRequest.Repositories) && + m.LockRepositories == migrationRequest.LockRepositories && + m.ExcludeAttachments == migrationRequest.ExcludeAttachments), + AcceptHeaders.MigrationsApiPreview); + } + } + + public class TheGetArchiveMethod + { + [Fact] + public void RequestsCorrectUrl() + { + var connection = Substitute.For(); + var client = new MigrationsClient(connection); + + client.GetArchive("fake", 69); + + connection.Connection.Received().Get( + Arg.Is(u => u.ToString() == "orgs/fake/migrations/69/archive"), + null, + AcceptHeaders.MigrationsApiPreview); + } + + [Fact] + public async Task EnsuresNonNullAndNonEmptyArguments() + { + var connection = Substitute.For(); + var client = new MigrationsClient(connection); + + await Assert.ThrowsAsync(() => client.GetArchive(null, 69)); + await Assert.ThrowsAsync(() => client.GetArchive("", 69)); + } + } + + public class TheDeleteArchiveMethod + { + [Fact] + public void RequestsCorrectUrl() + { + var connection = Substitute.For(); + var client = new MigrationsClient(connection); + + client.DeleteArchive("fake", 69); + + connection.Received().Delete( + Arg.Is(u => u.ToString() == "orgs/fake/migrations/69/archive"), + Arg.Any(), + AcceptHeaders.MigrationsApiPreview); + } + + [Fact] + public async Task EnsuresNonNullAndNonEmptyArguments() + { + var connection = Substitute.For(); + var client = new MigrationsClient(connection); + + await Assert.ThrowsAsync(() => client.DeleteArchive(null, 69)); + await Assert.ThrowsAsync(() => client.DeleteArchive("", 69)); + } + } + + public class TheUnlockRepositoryMethod + { + [Fact] + public void RequestsCorrectUrl() + { + var connection = Substitute.For(); + var client = new MigrationsClient(connection); + + client.UnlockRepository("fake", 69, "repo"); + + connection.Received().Delete( + Arg.Is(u => u.ToString() == "orgs/fake/migrations/69/repos/repo/lock"), + Arg.Any(), + AcceptHeaders.MigrationsApiPreview); + } + + [Fact] + public async Task EnsuresNonNullAndNonEmptyArguments() + { + var connection = Substitute.For(); + var client = new MigrationsClient(connection); + + await Assert.ThrowsAsync(() => client.UnlockRepository(null, 69, "repo")); + await Assert.ThrowsAsync(() => client.UnlockRepository("", 69, "repo")); + await Assert.ThrowsAsync(() => client.UnlockRepository("fake", 69, null)); + await Assert.ThrowsAsync(() => client.UnlockRepository("fake", 69, "")); + } + } + } +} diff --git a/Octokit.Tests/Models/MigrationTests.cs b/Octokit.Tests/Models/MigrationTests.cs new file mode 100644 index 0000000000..fbe81bac66 --- /dev/null +++ b/Octokit.Tests/Models/MigrationTests.cs @@ -0,0 +1,173 @@ +using System.Collections.Generic; +using Octokit.Internal; +using Xunit; + +namespace Octokit.Tests.Models +{ + public class MigrationTests + { + const string migrationJson = @" + { + ""id"": 79, + ""guid"": ""0b989ba4-242f-11e5-81e1-c7b6966d2516"", + ""state"": ""pending"", + ""lock_repositories"": true, + ""exclude_attachments"": false, + ""url"": ""https://api.github.com/orgs/octo-org/migrations/79"", + ""created_at"": ""2015-07-06T15:33:38-07:00"", + ""updated_at"": ""2015-07-06T15:33:38-07:00"", + ""repositories"": [ + { + ""id"": 1296269, + ""owner"": { + ""login"": ""octocat"", + ""id"": 1, + ""avatar_url"": ""https://github.com/images/error/octocat_happy.gif"", + ""gravatar_id"": """", + ""url"": ""https://api.github.com/users/octocat"", + ""html_url"": ""https://github.com/octocat"", + ""followers_url"": ""https://api.github.com/users/octocat/followers"", + ""following_url"": ""https://api.github.com/users/octocat/following{/other_user}"", + ""gists_url"": ""https://api.github.com/users/octocat/gists{/gist_id}"", + ""starred_url"": ""https://api.github.com/users/octocat/starred{/owner}{/repo}"", + ""subscriptions_url"": ""https://api.github.com/users/octocat/subscriptions"", + ""organizations_url"": ""https://api.github.com/users/octocat/orgs"", + ""repos_url"": ""https://api.github.com/users/octocat/repos"", + ""events_url"": ""https://api.github.com/users/octocat/events{/privacy}"", + ""received_events_url"": ""https://api.github.com/users/octocat/received_events"", + ""type"": ""User"", + ""site_admin"": false + }, + ""name"": ""Hello-World"", + ""full_name"": ""octocat/Hello-World"", + ""description"": ""This your first repo!"", + ""private"": false, + ""fork"": true, + ""url"": ""https://api.github.com/repos/octocat/Hello-World"", + ""html_url"": ""https://github.com/octocat/Hello-World"", + ""archive_url"": ""http://api.github.com/repos/octocat/Hello-World/{archive_format}{/ref}"", + ""assignees_url"": ""http://api.github.com/repos/octocat/Hello-World/assignees{/user}"", + ""blobs_url"": ""http://api.github.com/repos/octocat/Hello-World/git/blobs{/sha}"", + ""branches_url"": ""http://api.github.com/repos/octocat/Hello-World/branches{/branch}"", + ""clone_url"": ""https://github.com/octocat/Hello-World.git"", + ""collaborators_url"": ""http://api.github.com/repos/octocat/Hello-World/collaborators{/collaborator}"", + ""comments_url"": ""http://api.github.com/repos/octocat/Hello-World/comments{/number}"", + ""commits_url"": ""http://api.github.com/repos/octocat/Hello-World/commits{/sha}"", + ""compare_url"": ""http://api.github.com/repos/octocat/Hello-World/compare/{base}...{head}"", + ""contents_url"": ""http://api.github.com/repos/octocat/Hello-World/contents/{+path}"", + ""contributors_url"": ""http://api.github.com/repos/octocat/Hello-World/contributors"", + ""deployments_url"": ""http://api.github.com/repos/octocat/Hello-World/deployments"", + ""downloads_url"": ""http://api.github.com/repos/octocat/Hello-World/downloads"", + ""events_url"": ""http://api.github.com/repos/octocat/Hello-World/events"", + ""forks_url"": ""http://api.github.com/repos/octocat/Hello-World/forks"", + ""git_commits_url"": ""http://api.github.com/repos/octocat/Hello-World/git/commits{/sha}"", + ""git_refs_url"": ""http://api.github.com/repos/octocat/Hello-World/git/refs{/sha}"", + ""git_tags_url"": ""http://api.github.com/repos/octocat/Hello-World/git/tags{/sha}"", + ""git_url"": ""git:github.com/octocat/Hello-World.git"", + ""hooks_url"": ""http://api.github.com/repos/octocat/Hello-World/hooks"", + ""issue_comment_url"": ""http://api.github.com/repos/octocat/Hello-World/issues/comments{/number}"", + ""issue_events_url"": ""http://api.github.com/repos/octocat/Hello-World/issues/events{/number}"", + ""issues_url"": ""http://api.github.com/repos/octocat/Hello-World/issues{/number}"", + ""keys_url"": ""http://api.github.com/repos/octocat/Hello-World/keys{/key_id}"", + ""labels_url"": ""http://api.github.com/repos/octocat/Hello-World/labels{/name}"", + ""languages_url"": ""http://api.github.com/repos/octocat/Hello-World/languages"", + ""merges_url"": ""http://api.github.com/repos/octocat/Hello-World/merges"", + ""milestones_url"": ""http://api.github.com/repos/octocat/Hello-World/milestones{/number}"", + ""mirror_url"": ""git:git.example.com/octocat/Hello-World"", + ""notifications_url"": ""http://api.github.com/repos/octocat/Hello-World/notifications{?since, all, participating}"", + ""pulls_url"": ""http://api.github.com/repos/octocat/Hello-World/pulls{/number}"", + ""releases_url"": ""http://api.github.com/repos/octocat/Hello-World/releases{/id}"", + ""ssh_url"": ""git@github.com:octocat/Hello-World.git"", + ""stargazers_url"": ""http://api.github.com/repos/octocat/Hello-World/stargazers"", + ""statuses_url"": ""http://api.github.com/repos/octocat/Hello-World/statuses/{sha}"", + ""subscribers_url"": ""http://api.github.com/repos/octocat/Hello-World/subscribers"", + ""subscription_url"": ""http://api.github.com/repos/octocat/Hello-World/subscription"", + ""svn_url"": ""https://svn.github.com/octocat/Hello-World"", + ""tags_url"": ""http://api.github.com/repos/octocat/Hello-World/tags"", + ""teams_url"": ""http://api.github.com/repos/octocat/Hello-World/teams"", + ""trees_url"": ""http://api.github.com/repos/octocat/Hello-World/git/trees{/sha}"", + ""homepage"": ""https://github.com"", + ""language"": null, + ""forks_count"": 9, + ""stargazers_count"": 80, + ""watchers_count"": 80, + ""size"": 108, + ""default_branch"": ""master"", + ""open_issues_count"": 0, + ""has_issues"": true, + ""has_wiki"": true, + ""has_pages"": false, + ""has_downloads"": true, + ""pushed_at"": ""2011-01-26T19:06:43Z"", + ""created_at"": ""2011-01-26T19:01:12Z"", + ""updated_at"": ""2011-01-26T19:14:43Z"", + ""permissions"": { + ""admin"": false, + ""push"": false, + ""pull"": true + } + } + ] + }"; + + private static readonly Migration migration = new Migration( + id: 79, + guid: "0b989ba4-242f-11e5-81e1-c7b6966d2516", + state: Migration.MigrationState.Exported, + lockRepositories: true, + excludeAttachments: false, + url: "https://api.github.com/orgs/octo-org/migrations/79", + createdAt: "2015-07-06T15:33:38-07:00", + updatedAt: "2015-07-06T15:33:38-07:00", + repositories: new List + { + new Repository(1296269) + }); + + [Fact] + public void CanBeDeserialized() + { + var serializer = new SimpleJsonSerializer(); + + var _migration = serializer.Deserialize(migrationJson); + + Assert.Equal(79, _migration.Id); + Assert.Equal("0b989ba4-242f-11e5-81e1-c7b6966d2516", _migration.Guid); + Assert.Equal(1, _migration.Repositories.Count); + Assert.Equal(1296269, _migration.Repositories[0].Id); + Assert.Equal(Migration.MigrationState.Pending, _migration.State); + } + } + + public class StartMigrationTests + { + const string migrationRequestJson = @" + { + ""repositories"": [ + ""octocat/Hello-World"" + ], + ""lock_repositories"": true + }"; + + private static readonly StartMigrationRequest migrationRequest = new StartMigrationRequest( + new List + { + "octocat/Hello-World" + }, + true, + false); + + [Fact] + public void CanBeDeserialized() + { + var serializer = new SimpleJsonSerializer(); + + var _migrationReuqest = serializer.Deserialize(migrationRequestJson); + + Assert.Equal("octocat/Hello-World", _migrationReuqest.Repositories[0]); + Assert.Equal(1, _migrationReuqest.Repositories.Count); + Assert.Equal(true, _migrationReuqest.LockRepositories); + } + + } +} diff --git a/Octokit.Tests/Octokit.Tests.csproj b/Octokit.Tests/Octokit.Tests.csproj index 2a8e7c325e..ffba4e4ac1 100644 --- a/Octokit.Tests/Octokit.Tests.csproj +++ b/Octokit.Tests/Octokit.Tests.csproj @@ -85,6 +85,7 @@ + @@ -176,6 +177,7 @@ + @@ -208,6 +210,7 @@ + diff --git a/Octokit.Tests/Reactive/ObservableMigrationsClientTests.cs b/Octokit.Tests/Reactive/ObservableMigrationsClientTests.cs new file mode 100644 index 0000000000..90be692fc4 --- /dev/null +++ b/Octokit.Tests/Reactive/ObservableMigrationsClientTests.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections.Generic; +using NSubstitute; +using Octokit.Reactive; +using Xunit; + +namespace Octokit.Tests.Reactive +{ + public class ObservableMigrationsClientTests + { + public class TheCtor + { + [Fact] + public void EnsuresNonNullArguments() + { + Assert.Throws( + () => new EventsClient(null)); + } + } + + public class TheStartMethod + { + [Fact] + public void CallsIntoClient() + { + var github = Substitute.For(); + var client = new ObservableMigrationsClient(github); + var migrationRequest = new StartMigrationRequest( + new List { "fake/repo" }, + true, + false); + + client.Start("fake", migrationRequest); + github.Migration.Migrations.Received(1).Start( + "fake", + Arg.Is(m => m.Equals(migrationRequest))); + } + } + + public class TheGetAllMethod + { + [Fact] + public void CallsIntoClient() + { + var github = Substitute.For(); + var client = new ObservableMigrationsClient(github); + + client.GetAll("fake"); + github.Migration.Migrations.Received(1).GetAll("fake"); + } + } + + public class TheGetMethod + { + [Fact] + public void CallsIntoClient() + { + var github = Substitute.For(); + var client = new ObservableMigrationsClient(github); + + client.Get("fake", 69); + github.Migration.Migrations.Received(1).Get("fake", 69); + } + } + + public class TheGetArchiveMethod + { + [Fact] + public void CallsIntoClient() + { + var github = Substitute.For(); + var client = new ObservableMigrationsClient(github); + + client.GetArchive("fake", 69); + github.Migration.Migrations.Received(1).GetArchive("fake", 69); + } + } + + public class TheDeleteArchiveMethod + { + [Fact] + public void CallsIntoClient() + { + var github = Substitute.For(); + var client = new ObservableMigrationsClient(github); + + client.DeleteArchive("fake", 69); + github.Migration.Migrations.Received(1).DeleteArchive("fake", 69); + } + } + + public class TheUnlockRepositoryMethod + { + [Fact] + public void CallsIntoClient() + { + var github = Substitute.For(); + var client = new ObservableMigrationsClient(github); + + client.UnlockRepository("fake", 69, "repo"); + github.Migration.Migrations.Received(1).UnlockRepository("fake", 69, "repo"); + } + } + } +} \ No newline at end of file diff --git a/Octokit/Clients/IMigrationClient.cs b/Octokit/Clients/IMigrationClient.cs new file mode 100644 index 0000000000..f133c16953 --- /dev/null +++ b/Octokit/Clients/IMigrationClient.cs @@ -0,0 +1,19 @@ +namespace Octokit +{ + /// + /// A client for GitHub's Migration API. These APIs help you move projects to or from GitHub. + /// + /// + /// Docs: https://developer.github.com/v3/migration/ + /// + public interface IMigrationClient + { + /// + /// The Enterprise Migrations API lets you move a repository from GitHub to GitHub Enterprise. + /// + /// + /// https://developer.github.com/v3/migration/#enterprise-migrations + /// + IMigrationsClient Migrations { get; } + } +} \ No newline at end of file diff --git a/Octokit/Clients/IMigrationsClient.cs b/Octokit/Clients/IMigrationsClient.cs new file mode 100644 index 0000000000..75a7f97487 --- /dev/null +++ b/Octokit/Clients/IMigrationsClient.cs @@ -0,0 +1,96 @@ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Threading.Tasks; + +namespace Octokit +{ + /// + /// An interface for GitHub's Migrations API client. + /// + /// + /// See the docs + /// for more information. + /// + public interface IMigrationsClient + { + /// + /// Starts a new migration specified for the given organization. + /// + /// + /// https://developer.github.com/v3/migration/migrations/#start-a-migration + /// + /// The organization for which to start a migration. + /// Sprcifies parameters for the migration in a + /// object. + /// The started migration. + Task Start( + string org, + StartMigrationRequest migration); + + /// + /// Gets the list of the most recent migrations of the the organization. + /// + /// + /// https://developer.github.com/v3/migration/migrations/#get-a-list-of-migrations + /// + /// The organization of which to list migrations. + /// List of most recent s. + Task> GetAll( + string org); + + /// + /// Get the status of a migration + /// + /// + /// https://developer.github.com/v3/migration/migrations/#get-the-status-of-a-migration + /// + /// The organization which is migrating. + /// Migration ID of the organization. + /// A object representing the state of migration. + [SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "Get")] + Task Get( + string org, + int id); + + /// + /// Get the migration archive. + /// + /// + /// https://developer.github.com/v3/migration/migrations/#download-a-migration-archive + /// + /// The organization of which the migration was. + /// The ID of the migration. + /// The binary contents of the archive as a byte array. + Task GetArchive( + string org, + int id); + + /// + /// Deletes a previous migration archive. + /// + /// + /// https://developer.github.com/v3/migration/migrations/#delete-a-migration-archive + /// + /// The organization of which the migration was. + /// The ID of the migration. + /// + Task DeleteArchive( + string org, + int id); + + /// + /// Unlocks a repository that was locked for migration. + /// + /// + /// https://developer.github.com/v3/migration/migrations/#unlock-a-repository + /// + /// The organization of which the migration was. + /// The ID of the migration. + /// The repo to unlock. + /// + Task UnlockRepository( + string org, + int id, + string repo); + } +} diff --git a/Octokit/Clients/MigrationClient.cs b/Octokit/Clients/MigrationClient.cs new file mode 100644 index 0000000000..4faa4478f5 --- /dev/null +++ b/Octokit/Clients/MigrationClient.cs @@ -0,0 +1,28 @@ +namespace Octokit +{ + /// + /// A client for GitHub's Migration API. These APIs help you move projects to or from GitHub. + /// + /// + /// Docs: https://developer.github.com/v3/migration/ + /// + public class MigrationClient : ApiClient, IMigrationClient + { + /// + /// Instantiate a new GitHub Migration API client and its sub-APIs. + /// + /// An API connection. + public MigrationClient(IApiConnection apiConnection) : base(apiConnection) + { + Migrations = new MigrationsClient(apiConnection); + } + + /// + /// The Enterprise Migrations API lets you move a repository from GitHub to GitHub Enterprise. + /// + /// + /// https://developer.github.com/v3/migration/#enterprise-migrations + /// + public IMigrationsClient Migrations { get; private set; } + } +} \ No newline at end of file diff --git a/Octokit/Clients/MigrationsClient.cs b/Octokit/Clients/MigrationsClient.cs new file mode 100644 index 0000000000..a54f0c59fa --- /dev/null +++ b/Octokit/Clients/MigrationsClient.cs @@ -0,0 +1,134 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Octokit +{ + /// + /// A client for GitHub's Migrations API. + /// + /// + /// See docs + /// for more information. + /// + public class MigrationsClient : ApiClient, IMigrationsClient + { + /// + /// Instantiates a GitHub Migrations API client. + /// + /// An API connection. + public MigrationsClient(IApiConnection apiConnection) : base(apiConnection) + { } + + /// + /// Starts a new migration specified for the given organization. + /// + /// + /// https://developer.github.com/v3/migration/migrations/#start-a-migration + /// + /// The organization for which to start a migration. + /// Sprcifies parameters for the migration in a + /// object. + /// The started migration. + public async Task Start(string org, StartMigrationRequest migration) + { + Ensure.ArgumentNotNullOrEmptyString(org, "org"); + Ensure.ArgumentNotNull(migration, "migration"); + + var endpoint = ApiUrls.EnterpriseMigrations(org); + + return await ApiConnection.Post(endpoint, migration, AcceptHeaders.MigrationsApiPreview); + } + + /// + /// Gets the list of the most recent migrations of the the organization. + /// + /// + /// https://developer.github.com/v3/migration/migrations/#get-a-list-of-migrations + /// + /// The organization of which to list migrations. + /// List of most recent s. + public async Task> GetAll(string org) + { + Ensure.ArgumentNotNullOrEmptyString(org, "org"); + + var endpoint = ApiUrls.EnterpriseMigrations(org); + + return await ApiConnection.Get>(endpoint, null, AcceptHeaders.MigrationsApiPreview); + } + + /// + /// Get the status of a migration + /// + /// + /// https://developer.github.com/v3/migration/migrations/#get-the-status-of-a-migration + /// + /// The organization which is migrating. + /// Migration ID of the organization. + /// A object representing the state of migration. + public async Task Get(string org, int id) + { + Ensure.ArgumentNotNullOrEmptyString(org, "org"); + + var endpoint = ApiUrls.EnterpriseMigrationById(org, id); + + return await ApiConnection.Get(endpoint, null, AcceptHeaders.MigrationsApiPreview); + } + + /// + /// Get the migration archive. + /// + /// + /// https://developer.github.com/v3/migration/migrations/#download-a-migration-archive + /// + /// The organization of which the migration was. + /// The ID of the migration. + /// The binary contents of the archive as a byte array. + public async Task GetArchive(string org, int id) + { + Ensure.ArgumentNotNullOrEmptyString(org, "org"); + + var endpoint = ApiUrls.EnterpriseMigrationArchive(org, id); + var response = await Connection.Get(endpoint, null, AcceptHeaders.MigrationsApiPreview); + + return response.Body; + } + + /// + /// Deletes a previous migration archive. + /// + /// + /// https://developer.github.com/v3/migration/migrations/#delete-a-migration-archive + /// + /// The organization of which the migration was. + /// The ID of the migration. + /// + public Task DeleteArchive(string org, int id) + { + Ensure.ArgumentNotNullOrEmptyString(org, "org"); + + var endpoint = ApiUrls.EnterpriseMigrationArchive(org, id); + + return ApiConnection.Delete(endpoint, new object(), AcceptHeaders.MigrationsApiPreview); + } + + /// + /// Unlocks a repository that was locked for migration. + /// + /// + /// https://developer.github.com/v3/migration/migrations/#unlock-a-repository + /// + /// The organization of which the migration was. + /// The ID of the migration. + /// The repo to unlock. + /// + public Task UnlockRepository(string org, int id, string repo) + { + Ensure.ArgumentNotNullOrEmptyString(org, "org"); + Ensure.ArgumentNotNullOrEmptyString(repo, "repo"); + + var endpoint = ApiUrls.EnterpriseMigrationUnlockRepository(org, id, repo); + + return ApiConnection.Delete(endpoint, new object(), AcceptHeaders.MigrationsApiPreview); + } + } +} diff --git a/Octokit/GitHubClient.cs b/Octokit/GitHubClient.cs index 6957777630..4daa1bfc7b 100644 --- a/Octokit/GitHubClient.cs +++ b/Octokit/GitHubClient.cs @@ -82,22 +82,23 @@ public GitHubClient(IConnection connection) Connection = connection; var apiConnection = new ApiConnection(connection); - Authorization = new AuthorizationsClient(apiConnection); Activity = new ActivitiesClient(apiConnection); + Authorization = new AuthorizationsClient(apiConnection); + Deployment = new DeploymentsClient(apiConnection); + Enterprise = new EnterpriseClient(apiConnection); + Gist = new GistsClient(apiConnection); + Git = new GitDatabaseClient(apiConnection); Issue = new IssuesClient(apiConnection); + Migration = new MigrationClient(apiConnection); Miscellaneous = new MiscellaneousClient(connection); Notification = new NotificationsClient(apiConnection); Oauth = new OauthClient(connection); Organization = new OrganizationsClient(apiConnection); PullRequest = new PullRequestsClient(apiConnection); Repository = new RepositoriesClient(apiConnection); - Gist = new GistsClient(apiConnection); - User = new UsersClient(apiConnection); - SshKey = new SshKeysClient(apiConnection); - Git = new GitDatabaseClient(apiConnection); Search = new SearchClient(apiConnection); - Deployment = new DeploymentsClient(apiConnection); - Enterprise = new EnterpriseClient(apiConnection); + SshKey = new SshKeysClient(apiConnection); + User = new UsersClient(apiConnection); } /// @@ -167,6 +168,14 @@ public Uri BaseAddress /// public IIssuesClient Issue { get; private set; } + /// + /// Access GitHub's Migration API. + /// + /// + /// Refer to the API documentation for more information: https://developer.github.com/v3/migration/ + /// + public IMigrationClient Migration { get; private set; } + /// /// Access GitHub's Miscellaneous API. /// diff --git a/Octokit/Helpers/AcceptHeaders.cs b/Octokit/Helpers/AcceptHeaders.cs index 9f4be8e8fe..3d448fb77d 100644 --- a/Octokit/Helpers/AcceptHeaders.cs +++ b/Octokit/Helpers/AcceptHeaders.cs @@ -19,5 +19,7 @@ public static class AcceptHeaders public const string CommitReferenceSha1Preview = "application/vnd.github.chitauri-preview+sha"; public const string SquashCommitPreview = "application/vnd.github.polaris-preview+json"; + + public const string MigrationsApiPreview = " application/vnd.github.wyandotte-preview+json"; } } diff --git a/Octokit/Helpers/ApiUrls.cs b/Octokit/Helpers/ApiUrls.cs index e7e0525ccf..c6af35f219 100644 --- a/Octokit/Helpers/ApiUrls.cs +++ b/Octokit/Helpers/ApiUrls.cs @@ -1876,6 +1876,26 @@ public static Uri EnterpriseLicense() return "enterprise/settings/license".FormatUri(); } + public static Uri EnterpriseMigrationById(string org, int id) + { + return "orgs/{0}/migrations/{1}".FormatUri(org, id); + } + + public static Uri EnterpriseMigrations(string org) + { + return "orgs/{0}/migrations".FormatUri(org); + } + + public static Uri EnterpriseMigrationArchive(string org, int id) + { + return "orgs/{0}/migrations/{1}/archive".FormatUri(org, id); + } + + public static Uri EnterpriseMigrationUnlockRepository(string org, int id, string repo) + { + return "orgs/{0}/migrations/{1}/repos/{2}/lock".FormatUri(org, id, repo); + } + public static Uri EnterpriseOrganization() { return "admin/organizations".FormatUri(); diff --git a/Octokit/IGitHubClient.cs b/Octokit/IGitHubClient.cs index 29dd910c06..f91d99f304 100644 --- a/Octokit/IGitHubClient.cs +++ b/Octokit/IGitHubClient.cs @@ -36,6 +36,14 @@ public interface IGitHubClient : IApiInfoProvider /// IIssuesClient Issue { get; } + /// + /// Access GitHub's Migration API. + /// + /// + /// Refer to the API documentation for more information: https://developer.github.com/v3/migration/ + /// + IMigrationClient Migration { get; } + /// /// Access GitHub's Miscellaneous API. /// diff --git a/Octokit/Models/Request/StartMigrationRequest.cs b/Octokit/Models/Request/StartMigrationRequest.cs new file mode 100644 index 0000000000..7832884b52 --- /dev/null +++ b/Octokit/Models/Request/StartMigrationRequest.cs @@ -0,0 +1,70 @@ +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; + +namespace Octokit +{ + /// + /// Request body for starting a migration. + /// + /// + /// See docs + /// for more information. + /// + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class StartMigrationRequest + { + /// + /// Parameter-less constructor needed for SimpleJsonSerializer. + /// + public StartMigrationRequest() + { } + + public StartMigrationRequest( + IReadOnlyList repositories + ) : + this(repositories, false, false) + { } + + /// + /// Instantiate a new Migration Request object. + /// + /// List of repositories in {owner}/{repo} format. + /// To lock the repos or not. + /// To exclude the attachments or not. + public StartMigrationRequest( + IReadOnlyList repositories, + bool lockRepositories, + bool excludeAttachments) + { + Repositories = repositories; + LockRepositories = lockRepositories; + ExcludeAttachments = excludeAttachments; + } + + /// + /// Required. A list of arrays indicating which repositories should be migrated. + /// + public IReadOnlyList Repositories { get; private set; } + + /// + /// Indicates whether repositories should be locked (to prevent manipulation) + /// while migrating data. Default: false. + /// + public bool LockRepositories { get; private set; } + + /// + /// Indicates whether attachments should be excluded from the migration + /// (to reduce migration archive file size). Default: false. + /// + public bool ExcludeAttachments { get; private set; } + + internal string DebuggerDisplay + { + get + { + return string.Format(CultureInfo.InvariantCulture, "Repos: {0}", Repositories); + } + } + } +} \ No newline at end of file diff --git a/Octokit/Models/Response/Migration.cs b/Octokit/Models/Response/Migration.cs new file mode 100644 index 0000000000..9246210e1a --- /dev/null +++ b/Octokit/Models/Response/Migration.cs @@ -0,0 +1,127 @@ +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; + +namespace Octokit +{ + /// + /// Represents a migration. + /// + /// + /// See docs + /// for more information. + /// + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class Migration + { + /// + /// Parameter-less constructore needed for SimpleJsonSerializer. + /// + public Migration() + { } + + public Migration( + int id, + string guid, + MigrationState state, + bool lockRepositories, + bool excludeAttachments, + string url, + string createdAt, + string updatedAt, + IReadOnlyList repositories) + { + Id = id; + Guid = guid; + State = state; + LockRepositories = lockRepositories; + ExcludeAttachments = excludeAttachments; + Url = url; + CreatedAt = createdAt; + UpdatedAt = updatedAt; + Repositories = repositories; + } + + /// + /// Id of migration. + /// + public int Id { get; private set; } + + /// + /// Guid of migration. + /// + public string Guid { get; private set; } + + /// + /// The state of migration. Can be one of pending, exporting, exported and failed. + /// + public MigrationState State { get; private set; } + + /// + /// Whether to lock repositories. + /// + public bool LockRepositories { get; private set; } + + /// + /// Whether attachments are excluded or not. + /// + public bool ExcludeAttachments { get; private set; } + + /// + /// URL of migration. + /// + public string Url { get; private set; } + + /// + /// Time of migration creation. + /// + public string CreatedAt { get; private set; } + + /// + /// Time of migration updation. + /// + public string UpdatedAt { get; private set; } + + /// + /// List of locked repositories. + /// + public IReadOnlyList Repositories { get; private set; } + + internal string DebuggerDisplay + { + get + { + return string.Format(CultureInfo.InvariantCulture, "Guid: {0}", Guid); + } + } + + /// + /// State of a migration. + /// + /// + /// See: https://developer.github.com/v3/migration/migrations/#get-the-status-of-a-migration + /// + public enum MigrationState + { + /// + /// The migration hasn't started yet. + /// + Pending, + + /// + /// The migration is in progress. + /// + Exporting, + + /// + /// The migration finished successfully. + /// + Exported, + + /// + /// The migration failed. + /// + Failed + } + } +} \ No newline at end of file diff --git a/Octokit/Octokit-Mono.csproj b/Octokit/Octokit-Mono.csproj index 044a32bf8c..2370eca2ce 100644 --- a/Octokit/Octokit-Mono.csproj +++ b/Octokit/Octokit-Mono.csproj @@ -460,6 +460,12 @@ + + + + + + \ No newline at end of file diff --git a/Octokit/Octokit-MonoAndroid.csproj b/Octokit/Octokit-MonoAndroid.csproj index 49bcf33899..f7fadcd7f4 100644 --- a/Octokit/Octokit-MonoAndroid.csproj +++ b/Octokit/Octokit-MonoAndroid.csproj @@ -469,6 +469,14 @@ + + + + + + + + \ No newline at end of file diff --git a/Octokit/Octokit-Monotouch.csproj b/Octokit/Octokit-Monotouch.csproj index b3ee893adf..d99d397908 100644 --- a/Octokit/Octokit-Monotouch.csproj +++ b/Octokit/Octokit-Monotouch.csproj @@ -465,6 +465,14 @@ + + + + + + + + diff --git a/Octokit/Octokit-Portable.csproj b/Octokit/Octokit-Portable.csproj index ce5c1dbaab..4c2c15744b 100644 --- a/Octokit/Octokit-Portable.csproj +++ b/Octokit/Octokit-Portable.csproj @@ -457,6 +457,12 @@ + + + + + + diff --git a/Octokit/Octokit-netcore45.csproj b/Octokit/Octokit-netcore45.csproj index 77215bf7fa..841d4088a1 100644 --- a/Octokit/Octokit-netcore45.csproj +++ b/Octokit/Octokit-netcore45.csproj @@ -464,6 +464,12 @@ + + + + + + diff --git a/Octokit/Octokit.csproj b/Octokit/Octokit.csproj index 0aefa896e8..2f5bac2953 100644 --- a/Octokit/Octokit.csproj +++ b/Octokit/Octokit.csproj @@ -58,6 +58,7 @@ Properties\SolutionInfo.cs + @@ -70,7 +71,9 @@ + + @@ -78,6 +81,7 @@ + @@ -139,6 +143,7 @@ + @@ -174,6 +179,7 @@ +