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
+
@@ -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 @@
+