diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 8b1378917..a3289459e 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1 +1 @@ - +- Adds `--git-archive-path` and `--metadata-archive-path` options to `gh gei migrate-repo` for uploading (to selected storage) and migrating diff --git a/src/Octoshift/Extensions/EnumerableExtensions.cs b/src/Octoshift/Extensions/EnumerableExtensions.cs index 0d448bc6f..b6bde1c41 100644 --- a/src/Octoshift/Extensions/EnumerableExtensions.cs +++ b/src/Octoshift/Extensions/EnumerableExtensions.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text; using System.Threading.Tasks; namespace OctoshiftCLI.Extensions @@ -23,5 +24,7 @@ public static async Task Sum(this IEnumerable list, Func } public static IEnumerable ToEmptyEnumerableIfNull(this IEnumerable enumerable) => enumerable ?? Enumerable.Empty(); + + public static string GetString(this byte[] bytes) => Encoding.UTF8.GetString(bytes.ToArray()); } } diff --git a/src/Octoshift/Extensions/StringExtensions.cs b/src/Octoshift/Extensions/StringExtensions.cs index 73173acb6..8d323ff92 100644 --- a/src/Octoshift/Extensions/StringExtensions.cs +++ b/src/Octoshift/Extensions/StringExtensions.cs @@ -24,5 +24,7 @@ public static class StringExtensions public static string ToUnixPath(this string path) => path?.Replace("\\", "/"); public static string EscapeDataString(this string value) => Uri.EscapeDataString(value); + + public static byte[] ToBytes(this string s) => Encoding.UTF8.GetBytes(s); } } diff --git a/src/Octoshift/Services/FileSystemProvider.cs b/src/Octoshift/Services/FileSystemProvider.cs index 83369e667..de80bde9a 100644 --- a/src/Octoshift/Services/FileSystemProvider.cs +++ b/src/Octoshift/Services/FileSystemProvider.cs @@ -15,7 +15,7 @@ public class FileSystemProvider public virtual FileStream Open(string path, FileMode mode) => File.Open(path, mode); - public virtual FileStream OpenRead(string path) => File.OpenRead(path); + public virtual Stream OpenRead(string path) => File.OpenRead(path); public virtual async Task WriteAllTextAsync(string path, string contents) => await File.WriteAllTextAsync(path, contents); diff --git a/src/OctoshiftCLI.Tests/bbs2gh/Commands/MigrateRepo/MigrateRepoCommandHandlerTests.cs b/src/OctoshiftCLI.Tests/bbs2gh/Commands/MigrateRepo/MigrateRepoCommandHandlerTests.cs index a44ea8558..2a5831db2 100644 --- a/src/OctoshiftCLI.Tests/bbs2gh/Commands/MigrateRepo/MigrateRepoCommandHandlerTests.cs +++ b/src/OctoshiftCLI.Tests/bbs2gh/Commands/MigrateRepo/MigrateRepoCommandHandlerTests.cs @@ -6,6 +6,7 @@ using Moq; using OctoshiftCLI.BbsToGithub.Commands.MigrateRepo; using OctoshiftCLI.BbsToGithub.Services; +using OctoshiftCLI.Extensions; using OctoshiftCLI.Services; using Xunit; @@ -350,9 +351,9 @@ public async Task Happy_Path_Uploads_To_Github_Storage() var githubOrgDatabaseId = Guid.NewGuid().ToString(); const string gitArchiveFilePath = "./gitdata_archive"; const string gitArchiveUrl = "gei://archive/1"; + const string gitArchiveContents = "I am git archive"; - await File.WriteAllTextAsync(gitArchiveFilePath, "I am git archive"); - await using var gitContentStream = File.OpenRead(gitArchiveFilePath); + await using var gitContentStream = new MemoryStream(gitArchiveContents.ToBytes()); _mockFileSystemProvider.Setup(m => m.OpenRead(gitArchiveFilePath)).Returns(gitContentStream); @@ -360,7 +361,10 @@ public async Task Happy_Path_Uploads_To_Github_Storage() _mockGithubApi.Setup(x => x.CreateBbsMigrationSource(GITHUB_ORG_ID).Result).Returns(MIGRATION_SOURCE_ID); _mockGithubApi.Setup(x => x.GetOrganizationDatabaseId(GITHUB_ORG).Result).Returns(githubOrgDatabaseId); _mockGithubApi - .Setup(x => x.UploadArchiveToGithubStorage(githubOrgDatabaseId, It.IsAny(), gitContentStream).Result) + .Setup(x => x.UploadArchiveToGithubStorage( + githubOrgDatabaseId, + It.IsAny(), + It.Is(s => (s as MemoryStream).ToArray().GetString() == gitArchiveContents)).Result) .Returns(gitArchiveUrl); // Act diff --git a/src/OctoshiftCLI.Tests/gei/Commands/MigrateRepo/MigrateRepoCommandArgsTests.cs b/src/OctoshiftCLI.Tests/gei/Commands/MigrateRepo/MigrateRepoCommandArgsTests.cs index 6104bd4c2..c1da1e2fa 100644 --- a/src/OctoshiftCLI.Tests/gei/Commands/MigrateRepo/MigrateRepoCommandArgsTests.cs +++ b/src/OctoshiftCLI.Tests/gei/Commands/MigrateRepo/MigrateRepoCommandArgsTests.cs @@ -16,6 +16,10 @@ public class MigrateRepoCommandArgsTests private const string GITHUB_TARGET_PAT = "github-target-pat"; private const string AWS_BUCKET_NAME = "aws-bucket-name"; private const string GHES_API_URL = "foo-ghes-api.com"; + private const string GIT_ARCHIVE_URL = "http://host/git-archive.tar.gz"; + private const string METADATA_ARCHIVE_URL = "http://host/metadata-archive.tar.gz"; + private const string GIT_ARCHIVE_PATH = "./git-archive.tar.gz"; + private const string METADATA_ARCHIVE_PATH = "./metadata-archive.tar.gz"; [Fact] public void Defaults_TargetRepo_To_SourceRepo() @@ -124,6 +128,7 @@ public void It_Throws_When_Aws_Bucket_Name_Provided_With_AzureStorageConnectionS .ThrowExactly() .WithMessage("*--use-github-storage flag*"); } + [Fact] public void No_Ssl_Verify_Without_Ghes_Api_Url_Throws() { @@ -159,5 +164,79 @@ public void Keep_Archive_Without_Ghes_Api_Url_Throws() .ThrowExactly() .WithMessage("*--keep-archive*"); } + + [Fact] + public void GitArchivePath_Without_MetadataArchivePath_Throws() + { + var args = new MigrateRepoCommandArgs + { + SourceRepo = SOURCE_REPO, + GithubSourceOrg = SOURCE_ORG, + GithubTargetOrg = TARGET_ORG, + TargetRepo = TARGET_REPO, + GitArchivePath = GIT_ARCHIVE_PATH + }; + + FluentActions.Invoking(() => args.Validate(_mockOctoLogger.Object)) + .Should() + .ThrowExactly() + .WithMessage("*you must provide both --git-archive-path --metadata-archive-path*"); + } + + [Fact] + public void MetadataArchivePath_Without_GitArchivePath_Throws() + { + var args = new MigrateRepoCommandArgs + { + SourceRepo = SOURCE_REPO, + GithubSourceOrg = SOURCE_ORG, + GithubTargetOrg = TARGET_ORG, + TargetRepo = TARGET_REPO, + MetadataArchivePath = METADATA_ARCHIVE_PATH + }; + + FluentActions.Invoking(() => args.Validate(_mockOctoLogger.Object)) + .Should() + .ThrowExactly() + .WithMessage("*you must provide both --git-archive-path --metadata-archive-path*"); + } + + [Fact] + public void GitArchiveUrl_With_GitArchivePath_Throws() + { + var args = new MigrateRepoCommandArgs + { + SourceRepo = SOURCE_REPO, + GithubSourceOrg = SOURCE_ORG, + GithubTargetOrg = TARGET_ORG, + TargetRepo = TARGET_REPO, + GitArchiveUrl = GIT_ARCHIVE_URL, + GitArchivePath = GIT_ARCHIVE_PATH + }; + + FluentActions.Invoking(() => args.Validate(_mockOctoLogger.Object)) + .Should() + .ThrowExactly() + .WithMessage("*--git-archive-url and --git-archive-path may not be used together*"); + } + + [Fact] + public void MetadataArchiveUrl_With_MetadataArchivePath_Throws() + { + var args = new MigrateRepoCommandArgs + { + SourceRepo = SOURCE_REPO, + GithubSourceOrg = SOURCE_ORG, + GithubTargetOrg = TARGET_ORG, + TargetRepo = TARGET_REPO, + MetadataArchiveUrl = METADATA_ARCHIVE_URL, + MetadataArchivePath = METADATA_ARCHIVE_PATH + }; + + FluentActions.Invoking(() => args.Validate(_mockOctoLogger.Object)) + .Should() + .ThrowExactly() + .WithMessage("*--metadata-archive-url and --metadata-archive-path may not be used together*"); + } } } diff --git a/src/OctoshiftCLI.Tests/gei/Commands/MigrateRepo/MigrateRepoCommandHandlerTests.cs b/src/OctoshiftCLI.Tests/gei/Commands/MigrateRepo/MigrateRepoCommandHandlerTests.cs index 5f208f754..d9c5c2b9d 100644 --- a/src/OctoshiftCLI.Tests/gei/Commands/MigrateRepo/MigrateRepoCommandHandlerTests.cs +++ b/src/OctoshiftCLI.Tests/gei/Commands/MigrateRepo/MigrateRepoCommandHandlerTests.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using FluentAssertions; using Moq; +using OctoshiftCLI.Extensions; using OctoshiftCLI.GithubEnterpriseImporter.Commands.MigrateRepo; using OctoshiftCLI.GithubEnterpriseImporter.Services; using OctoshiftCLI.Services; @@ -42,6 +43,21 @@ public class MigrateRepoCommandHandlerTests private const string AWS_SECRET_ACCESS_KEY = "aws-secret-access-key"; private const string AWS_SESSION_TOKEN = "aws-session-token"; private const string AWS_REGION = "aws-region"; + private const string GIT_ARCHIVE_FILE_NAME = "git_archive.tar.gz"; + private const string METADATA_ARCHIVE_FILE_NAME = "metadata_archive.tar.gz"; + private const string GITHUB_ORG_ID = "9b1b5862-6a8b-4fe1-8cef-0f4e67e975e8"; + private const string MIGRATION_SOURCE_ID = "b6ec2c17-c4d7-4552-83f6-b5407153c324"; + private const string GITHUB_REPO_URL = $"https://github.com/{SOURCE_ORG}/{SOURCE_REPO}"; + private const string GHES_REPO_URL = $"https://myghes/{SOURCE_ORG}/{SOURCE_REPO}"; + private const string MIGRATION_ID = "069f660d-9201-47c5-95d4-f9b743cb89d9"; + private const int GIT_ARCHIVE_ID = 1; + private const int METADATA_ARCHIVE_ID = 2; + private const string GIT_ARCHIVE_URL = "https://example.com/1"; + private const string METADATA_ARCHIVE_URL = "https://example.com/2"; + private const string AUTHENTICATED_GIT_ARCHIVE_URL = $"https://example.com/1/authenticated"; + private const string AUTHENTICATED_METADATA_ARCHIVE_URL = $"https://example.com/2/authenticated"; + private const string GIT_ARCHIVE_FILE_PATH = "path/to/git_archive"; + private const string METADATA_ARCHIVE_FILE_PATH = "path/to/metadata_archive"; public MigrateRepoCommandHandlerTests() { @@ -89,19 +105,12 @@ await FluentActions public async Task Happy_Path_Without_Wait() { // Arrange - var githubOrgId = Guid.NewGuid().ToString(); - var migrationSourceId = Guid.NewGuid().ToString(); - var sourceGithubPat = Guid.NewGuid().ToString(); - var targetGithubPat = Guid.NewGuid().ToString(); - var githubRepoUrl = $"https://github.com/{SOURCE_ORG}/{SOURCE_REPO}"; - var migrationId = Guid.NewGuid().ToString(); + _mockTargetGithubApi.Setup(x => x.GetOrganizationId(TARGET_ORG).Result).Returns(GITHUB_ORG_ID); + _mockTargetGithubApi.Setup(x => x.CreateGhecMigrationSource(GITHUB_ORG_ID).Result).Returns(MIGRATION_SOURCE_ID); + _mockTargetGithubApi.Setup(x => x.StartMigration(MIGRATION_SOURCE_ID, GITHUB_REPO_URL, GITHUB_ORG_ID, TARGET_REPO, GITHUB_SOURCE_PAT, GITHUB_TARGET_PAT, null, null, false, null, false).Result).Returns(MIGRATION_ID); - _mockTargetGithubApi.Setup(x => x.GetOrganizationId(TARGET_ORG).Result).Returns(githubOrgId); - _mockTargetGithubApi.Setup(x => x.CreateGhecMigrationSource(githubOrgId).Result).Returns(migrationSourceId); - _mockTargetGithubApi.Setup(x => x.StartMigration(migrationSourceId, githubRepoUrl, githubOrgId, TARGET_REPO, sourceGithubPat, targetGithubPat, null, null, false, null, false).Result).Returns(migrationId); - - _mockEnvironmentVariableProvider.Setup(m => m.SourceGithubPersonalAccessToken(It.IsAny())).Returns(sourceGithubPat); - _mockEnvironmentVariableProvider.Setup(m => m.TargetGithubPersonalAccessToken(It.IsAny())).Returns(targetGithubPat); + _mockEnvironmentVariableProvider.Setup(m => m.SourceGithubPersonalAccessToken(It.IsAny())).Returns(GITHUB_SOURCE_PAT); + _mockEnvironmentVariableProvider.Setup(m => m.TargetGithubPersonalAccessToken(It.IsAny())).Returns(GITHUB_TARGET_PAT); var actualLogOutput = new List(); _mockOctoLogger.Setup(m => m.LogInformation(It.IsAny())).Callback(s => actualLogOutput.Add(s)); @@ -109,7 +118,7 @@ public async Task Happy_Path_Without_Wait() var expectedLogOutput = new List() { "Migrating Repo...", - $"A repository migration (ID: {migrationId}) was successfully queued." + $"A repository migration (ID: {MIGRATION_ID}) was successfully queued." }; // Act @@ -126,8 +135,8 @@ public async Task Happy_Path_Without_Wait() // Assert _mockTargetGithubApi.Verify(m => m.GetOrganizationId(TARGET_ORG)); - _mockTargetGithubApi.Verify(m => m.CreateGhecMigrationSource(githubOrgId)); - _mockTargetGithubApi.Verify(m => m.StartMigration(migrationSourceId, githubRepoUrl, githubOrgId, TARGET_REPO, sourceGithubPat, targetGithubPat, null, null, false, null, false)); + _mockTargetGithubApi.Verify(m => m.CreateGhecMigrationSource(GITHUB_ORG_ID)); + _mockTargetGithubApi.Verify(m => m.StartMigration(MIGRATION_SOURCE_ID, GITHUB_REPO_URL, GITHUB_ORG_ID, TARGET_REPO, GITHUB_SOURCE_PAT, GITHUB_TARGET_PAT, null, null, false, null, false)); _mockOctoLogger.Verify(m => m.LogInformation(It.IsAny()), Times.Exactly(2)); actualLogOutput.Should().Equal(expectedLogOutput); @@ -139,20 +148,14 @@ public async Task Happy_Path_Without_Wait() public async Task Skip_Migration_If_Target_Repo_Exists() { // Arrange - var githubOrgId = Guid.NewGuid().ToString(); - var migrationSourceId = Guid.NewGuid().ToString(); - var sourceGithubPat = Guid.NewGuid().ToString(); - var targetGithubPat = Guid.NewGuid().ToString(); - var githubRepoUrl = $"https://github.com/{SOURCE_ORG}/{SOURCE_REPO}"; - - _mockTargetGithubApi.Setup(x => x.GetOrganizationId(TARGET_ORG).Result).Returns(githubOrgId); - _mockTargetGithubApi.Setup(x => x.CreateGhecMigrationSource(githubOrgId).Result).Returns(migrationSourceId); + _mockTargetGithubApi.Setup(x => x.GetOrganizationId(TARGET_ORG).Result).Returns(GITHUB_ORG_ID); + _mockTargetGithubApi.Setup(x => x.CreateGhecMigrationSource(GITHUB_ORG_ID).Result).Returns(MIGRATION_SOURCE_ID); _mockTargetGithubApi - .Setup(x => x.StartMigration(migrationSourceId, githubRepoUrl, githubOrgId, TARGET_REPO, sourceGithubPat, targetGithubPat, null, null, false, null, false).Result) + .Setup(x => x.StartMigration(MIGRATION_SOURCE_ID, GITHUB_REPO_URL, GITHUB_ORG_ID, TARGET_REPO, GITHUB_SOURCE_PAT, GITHUB_TARGET_PAT, null, null, false, null, false).Result) .Throws(new OctoshiftCliException($"A repository called {TARGET_ORG}/{TARGET_REPO} already exists")); - _mockEnvironmentVariableProvider.Setup(m => m.SourceGithubPersonalAccessToken(It.IsAny())).Returns(sourceGithubPat); - _mockEnvironmentVariableProvider.Setup(m => m.TargetGithubPersonalAccessToken(It.IsAny())).Returns(targetGithubPat); + _mockEnvironmentVariableProvider.Setup(m => m.SourceGithubPersonalAccessToken(It.IsAny())).Returns(GITHUB_SOURCE_PAT); + _mockEnvironmentVariableProvider.Setup(m => m.TargetGithubPersonalAccessToken(It.IsAny())).Returns(GITHUB_TARGET_PAT); var actualLogOutput = new List(); _mockOctoLogger.Setup(m => m.LogInformation(It.IsAny())).Callback(s => actualLogOutput.Add(s)); @@ -180,33 +183,26 @@ public async Task Skip_Migration_If_Target_Repo_Exists() [Fact] public async Task Happy_Path_GithubSource() { - var githubOrgId = Guid.NewGuid().ToString(); - var migrationSourceId = Guid.NewGuid().ToString(); - var sourceGithubPat = Guid.NewGuid().ToString(); - var targetGithubPat = Guid.NewGuid().ToString(); - var githubRepoUrl = $"https://github.com/{SOURCE_ORG}/{SOURCE_REPO}"; - var migrationId = Guid.NewGuid().ToString(); - - _mockTargetGithubApi.Setup(x => x.GetOrganizationId(TARGET_ORG).Result).Returns(githubOrgId); - _mockTargetGithubApi.Setup(x => x.CreateGhecMigrationSource(githubOrgId).Result).Returns(migrationSourceId); + _mockTargetGithubApi.Setup(x => x.GetOrganizationId(TARGET_ORG).Result).Returns(GITHUB_ORG_ID); + _mockTargetGithubApi.Setup(x => x.CreateGhecMigrationSource(GITHUB_ORG_ID).Result).Returns(MIGRATION_SOURCE_ID); _mockTargetGithubApi .Setup(x => x.StartMigration( - migrationSourceId, - githubRepoUrl, - githubOrgId, + MIGRATION_SOURCE_ID, + GITHUB_REPO_URL, + GITHUB_ORG_ID, TARGET_REPO, - sourceGithubPat, - targetGithubPat, + GITHUB_SOURCE_PAT, + GITHUB_TARGET_PAT, null, null, false, null, false).Result) - .Returns(migrationId); - _mockTargetGithubApi.Setup(x => x.GetMigration(migrationId).Result).Returns((State: RepositoryMigrationStatus.Succeeded, TARGET_REPO, 0, null, null)); + .Returns(MIGRATION_ID); + _mockTargetGithubApi.Setup(x => x.GetMigration(MIGRATION_ID).Result).Returns((State: RepositoryMigrationStatus.Succeeded, TARGET_REPO, 0, null, null)); - _mockEnvironmentVariableProvider.Setup(m => m.SourceGithubPersonalAccessToken(It.IsAny())).Returns(sourceGithubPat); - _mockEnvironmentVariableProvider.Setup(m => m.TargetGithubPersonalAccessToken(It.IsAny())).Returns(targetGithubPat); + _mockEnvironmentVariableProvider.Setup(m => m.SourceGithubPersonalAccessToken(It.IsAny())).Returns(GITHUB_SOURCE_PAT); + _mockEnvironmentVariableProvider.Setup(m => m.TargetGithubPersonalAccessToken(It.IsAny())).Returns(GITHUB_TARGET_PAT); var args = new MigrateRepoCommandArgs { @@ -218,24 +214,20 @@ public async Task Happy_Path_GithubSource() }; await _handler.Handle(args); - _mockTargetGithubApi.Verify(x => x.GetMigration(migrationId)); + _mockTargetGithubApi.Verify(x => x.GetMigration(MIGRATION_ID)); } [Fact] public async Task Throws_Decorated_Error_When_Create_Migration_Source_Fails_With_Permissions_Error() { // Arrange - var githubOrgId = Guid.NewGuid().ToString(); - var sourceGithubPat = Guid.NewGuid().ToString(); - var targetGithubPat = Guid.NewGuid().ToString(); - - _mockTargetGithubApi.Setup(x => x.GetOrganizationId(TARGET_ORG).Result).Returns(githubOrgId); + _mockTargetGithubApi.Setup(x => x.GetOrganizationId(TARGET_ORG).Result).Returns(GITHUB_ORG_ID); _mockTargetGithubApi - .Setup(x => x.CreateGhecMigrationSource(githubOrgId).Result) + .Setup(x => x.CreateGhecMigrationSource(GITHUB_ORG_ID).Result) .Throws(new OctoshiftCliException("monalisa does not have the correct permissions to execute `CreateMigrationSource`")); - _mockEnvironmentVariableProvider.Setup(m => m.SourceGithubPersonalAccessToken(It.IsAny())).Returns(sourceGithubPat); - _mockEnvironmentVariableProvider.Setup(m => m.TargetGithubPersonalAccessToken(It.IsAny())).Returns(targetGithubPat); + _mockEnvironmentVariableProvider.Setup(m => m.SourceGithubPersonalAccessToken(It.IsAny())).Returns(GITHUB_SOURCE_PAT); + _mockEnvironmentVariableProvider.Setup(m => m.TargetGithubPersonalAccessToken(It.IsAny())).Returns(GITHUB_TARGET_PAT); // Act await _handler.Invoking(async x => await x.Handle(new MigrateRepoCommandArgs @@ -255,56 +247,44 @@ await _handler.Invoking(async x => await x.Handle(new MigrateRepoCommandArgs [Fact] public async Task Happy_Path_GithubSource_Ghes() { - var githubOrgId = Guid.NewGuid().ToString(); - var migrationSourceId = Guid.NewGuid().ToString(); - var sourceGithubPat = Guid.NewGuid().ToString(); - var targetGithubPat = Guid.NewGuid().ToString(); - var githubRepoUrl = $"https://myghes/{SOURCE_ORG}/{SOURCE_REPO}"; - var migrationId = Guid.NewGuid().ToString(); - var gitArchiveId = 1; - var metadataArchiveId = 2; - var gitArchiveUrl = $"https://example.com/{gitArchiveId}"; - var metadataArchiveUrl = $"https://example.com/{metadataArchiveId}"; - var authenticatedGitArchiveUrl = new Uri($"https://example.com/{gitArchiveId}/authenticated"); - var authenticatedMetadataArchiveUrl = new Uri($"https://example.com/{metadataArchiveId}/authenticated"); - var gitArchiveFilePath = "path/to/git_archive"; - var metadataArchiveFilePath = "path/to/metadata_archive"; - - _mockTargetGithubApi.Setup(x => x.GetOrganizationId(TARGET_ORG).Result).Returns(githubOrgId); - _mockTargetGithubApi.Setup(x => x.CreateGhecMigrationSource(githubOrgId).Result).Returns(migrationSourceId); + _mockTargetGithubApi.Setup(x => x.GetOrganizationId(TARGET_ORG).Result).Returns(GITHUB_ORG_ID); + _mockTargetGithubApi.Setup(x => x.CreateGhecMigrationSource(GITHUB_ORG_ID).Result).Returns(MIGRATION_SOURCE_ID); _mockTargetGithubApi .Setup(x => x.StartMigration( - migrationSourceId, - githubRepoUrl, - githubOrgId, + MIGRATION_SOURCE_ID, + GHES_REPO_URL, + GITHUB_ORG_ID, TARGET_REPO, - sourceGithubPat, - targetGithubPat, - authenticatedGitArchiveUrl.ToString(), - authenticatedMetadataArchiveUrl.ToString(), + GITHUB_SOURCE_PAT, + GITHUB_TARGET_PAT, + AUTHENTICATED_GIT_ARCHIVE_URL, + AUTHENTICATED_METADATA_ARCHIVE_URL, false, null, false).Result) - .Returns(migrationId); - _mockTargetGithubApi.Setup(x => x.GetMigration(migrationId).Result).Returns((State: RepositoryMigrationStatus.Succeeded, TARGET_REPO, 0, null, null)); + .Returns(MIGRATION_ID); + _mockTargetGithubApi.Setup(x => x.GetMigration(MIGRATION_ID).Result).Returns((State: RepositoryMigrationStatus.Succeeded, TARGET_REPO, 0, null, null)); _mockTargetGithubApi.Setup(x => x.DoesOrgExist(TARGET_ORG).Result).Returns(true); - _mockSourceGithubApi.Setup(x => x.StartGitArchiveGeneration(SOURCE_ORG, SOURCE_REPO).Result).Returns(gitArchiveId); - _mockSourceGithubApi.Setup(x => x.StartMetadataArchiveGeneration(SOURCE_ORG, SOURCE_REPO, false, false).Result).Returns(metadataArchiveId); - _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationStatus(SOURCE_ORG, gitArchiveId).Result).Returns(ArchiveMigrationStatus.Exported); - _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationStatus(SOURCE_ORG, metadataArchiveId).Result).Returns(ArchiveMigrationStatus.Exported); - _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationUrl(SOURCE_ORG, gitArchiveId).Result).Returns(gitArchiveUrl); - _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationUrl(SOURCE_ORG, metadataArchiveId).Result).Returns(metadataArchiveUrl); + _mockSourceGithubApi.Setup(x => x.StartGitArchiveGeneration(SOURCE_ORG, SOURCE_REPO).Result).Returns(GIT_ARCHIVE_ID); + _mockSourceGithubApi.Setup(x => x.StartMetadataArchiveGeneration(SOURCE_ORG, SOURCE_REPO, false, false).Result).Returns(METADATA_ARCHIVE_ID); + _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationStatus(SOURCE_ORG, GIT_ARCHIVE_ID).Result).Returns(ArchiveMigrationStatus.Exported); + _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationStatus(SOURCE_ORG, METADATA_ARCHIVE_ID).Result).Returns(ArchiveMigrationStatus.Exported); + _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationUrl(SOURCE_ORG, GIT_ARCHIVE_ID).Result).Returns(GIT_ARCHIVE_URL); + _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationUrl(SOURCE_ORG, METADATA_ARCHIVE_ID).Result).Returns(METADATA_ARCHIVE_URL); - _mockAzureApi.SetupSequence(x => x.UploadToBlob(It.IsAny(), It.IsAny()).Result).Returns(authenticatedGitArchiveUrl).Returns(authenticatedMetadataArchiveUrl); + _mockAzureApi + .SetupSequence(x => x.UploadToBlob(It.IsAny(), It.IsAny()).Result) + .Returns(new Uri(AUTHENTICATED_GIT_ARCHIVE_URL)) + .Returns(new Uri(AUTHENTICATED_METADATA_ARCHIVE_URL)); _mockFileSystemProvider .SetupSequence(m => m.GetTempFileName()) - .Returns(gitArchiveFilePath) - .Returns(metadataArchiveFilePath); + .Returns(GIT_ARCHIVE_FILE_PATH) + .Returns(METADATA_ARCHIVE_FILE_PATH); - _mockEnvironmentVariableProvider.Setup(m => m.SourceGithubPersonalAccessToken(It.IsAny())).Returns(sourceGithubPat); - _mockEnvironmentVariableProvider.Setup(m => m.TargetGithubPersonalAccessToken(It.IsAny())).Returns(targetGithubPat); + _mockEnvironmentVariableProvider.Setup(m => m.SourceGithubPersonalAccessToken(It.IsAny())).Returns(GITHUB_SOURCE_PAT); + _mockEnvironmentVariableProvider.Setup(m => m.TargetGithubPersonalAccessToken(It.IsAny())).Returns(GITHUB_TARGET_PAT); _mockGhesVersionChecker.Setup(m => m.AreBlobCredentialsRequired(GHES_API_URL)).ReturnsAsync(true); @@ -320,9 +300,9 @@ public async Task Happy_Path_GithubSource_Ghes() }; await _handler.Handle(args); - _mockTargetGithubApi.Verify(x => x.GetMigration(migrationId)); - _mockFileSystemProvider.Verify(x => x.DeleteIfExists(gitArchiveFilePath), Times.Once); - _mockFileSystemProvider.Verify(x => x.DeleteIfExists(metadataArchiveFilePath), Times.Once); + _mockTargetGithubApi.Verify(x => x.GetMigration(MIGRATION_ID)); + _mockFileSystemProvider.Verify(x => x.DeleteIfExists(GIT_ARCHIVE_FILE_PATH), Times.Once); + _mockFileSystemProvider.Verify(x => x.DeleteIfExists(METADATA_ARCHIVE_FILE_PATH), Times.Once); } [Theory] @@ -330,29 +310,16 @@ public async Task Happy_Path_GithubSource_Ghes() [InlineData(true)] public async Task Happy_Path_UseGithubStorage(bool useGhesBlobCredentials) { - var githubOrgId = Guid.NewGuid().ToString(); var githubOrgDatabaseId = Guid.NewGuid().ToString(); - var migrationSourceId = Guid.NewGuid().ToString(); - var sourceGithubPat = Guid.NewGuid().ToString(); - var targetGithubPat = Guid.NewGuid().ToString(); - var githubRepoUrl = $"https://myghes/{SOURCE_ORG}/{SOURCE_REPO}"; - var migrationId = "valid-migration-id"; // Ensure a valid migration ID is returned - var gitArchiveId = 1; - var metadataArchiveId = 2; - var gitArchiveUrl = $"https://example.com/{gitArchiveId}"; - var metadataArchiveUrl = $"https://example.com/{metadataArchiveId}"; var uploadedGitArchiveUrl = "gei://archive/1"; var uploadedMetadataArchiveUrl = "gei://archive/2"; - var gitArchiveFilePath = "./gitdata_archive"; - var metadataArchiveFilePath = "./metadata_archive"; var gitArchiveDownloadFilePath = "git_archive_downaloded.tmp"; var metadataArchiveDownloadFilePath = "metadata_archive_downloaded.tmp"; + var gitArchiveContents = "I am git archive"; + var metadataArchiveContents = "I am metadata archive"; - File.WriteAllText(gitArchiveFilePath, "I am git archive"); - File.WriteAllText(metadataArchiveFilePath, "I am metadata archive"); - - using var gitContentStream = File.OpenRead(gitArchiveFilePath); - using var metaContentStream = File.OpenRead(metadataArchiveFilePath); + using var gitContentStream = new MemoryStream(gitArchiveContents.ToBytes()); + using var metaContentStream = new MemoryStream(metadataArchiveContents.ToBytes()); _mockFileSystemProvider .SetupSequence(m => m.GetTempFileName()) @@ -370,53 +337,56 @@ public async Task Happy_Path_UseGithubStorage(bool useGhesBlobCredentials) _mockGhesVersionChecker.Setup(m => m.AreBlobCredentialsRequired(GHES_API_URL)).ReturnsAsync(useGhesBlobCredentials); _mockTargetGithubApi.Setup(x => x.DoesOrgExist(TARGET_ORG).Result).Returns(true); - - _mockTargetGithubApi.Setup(x => x.GetOrganizationId(TARGET_ORG).Result).Returns(githubOrgId); + _mockTargetGithubApi.Setup(x => x.GetOrganizationId(TARGET_ORG).Result).Returns(GITHUB_ORG_ID); _mockTargetGithubApi.Setup(x => x.GetOrganizationDatabaseId(TARGET_ORG).Result).Returns(githubOrgDatabaseId); - _mockTargetGithubApi.Setup(x => x.CreateGhecMigrationSource(githubOrgId).Result).Returns(migrationSourceId); + _mockTargetGithubApi.Setup(x => x.CreateGhecMigrationSource(GITHUB_ORG_ID).Result).Returns(MIGRATION_SOURCE_ID); _mockTargetGithubApi.Setup(x => x.StartMigration( - migrationSourceId, - githubRepoUrl, - githubOrgId, + MIGRATION_SOURCE_ID, + GHES_REPO_URL, + GITHUB_ORG_ID, TARGET_REPO, - sourceGithubPat, - targetGithubPat, + GITHUB_SOURCE_PAT, + GITHUB_TARGET_PAT, uploadedGitArchiveUrl, uploadedMetadataArchiveUrl, false, null, false).Result) - .Returns(migrationId); + .Returns(MIGRATION_ID); - _mockTargetGithubApi.Setup(x => x.GetMigration(migrationId).Result) + _mockTargetGithubApi.Setup(x => x.GetMigration(MIGRATION_ID).Result) .Returns((State: RepositoryMigrationStatus.Succeeded, TARGET_REPO, 0, null, null)); - _mockSourceGithubApi.Setup(x => x.StartGitArchiveGeneration(SOURCE_ORG, SOURCE_REPO).Result).Returns(gitArchiveId); - _mockSourceGithubApi.Setup(x => x.StartMetadataArchiveGeneration(SOURCE_ORG, SOURCE_REPO, false, false).Result).Returns(metadataArchiveId); - _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationStatus(SOURCE_ORG, gitArchiveId).Result).Returns(ArchiveMigrationStatus.Exported); - _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationStatus(SOURCE_ORG, metadataArchiveId).Result).Returns(ArchiveMigrationStatus.Exported); - _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationUrl(SOURCE_ORG, gitArchiveId).Result).Returns(gitArchiveUrl); - _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationUrl(SOURCE_ORG, metadataArchiveId).Result).Returns(metadataArchiveUrl); + _mockSourceGithubApi.Setup(x => x.StartGitArchiveGeneration(SOURCE_ORG, SOURCE_REPO).Result).Returns(GIT_ARCHIVE_ID); + _mockSourceGithubApi.Setup(x => x.StartMetadataArchiveGeneration(SOURCE_ORG, SOURCE_REPO, false, false).Result).Returns(METADATA_ARCHIVE_ID); + _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationStatus(SOURCE_ORG, GIT_ARCHIVE_ID).Result).Returns(ArchiveMigrationStatus.Exported); + _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationStatus(SOURCE_ORG, METADATA_ARCHIVE_ID).Result).Returns(ArchiveMigrationStatus.Exported); + _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationUrl(SOURCE_ORG, GIT_ARCHIVE_ID).Result).Returns(GIT_ARCHIVE_URL); + _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationUrl(SOURCE_ORG, METADATA_ARCHIVE_ID).Result).Returns(METADATA_ARCHIVE_URL); _mockTargetGithubApi - .Setup(x => x.UploadArchiveToGithubStorage(githubOrgDatabaseId, It.Is(a => a.EndsWith("git_archive.tar.gz")), gitContentStream).Result) + .Setup(x => x.UploadArchiveToGithubStorage( + githubOrgDatabaseId, + It.Is(a => a.EndsWith("git_archive.tar.gz")), + It.Is(s => (s as MemoryStream).ToArray().GetString() == gitArchiveContents)).Result) .Returns(uploadedGitArchiveUrl); _mockTargetGithubApi - .Setup(x => x.UploadArchiveToGithubStorage(githubOrgDatabaseId, It.Is(a => a.EndsWith("metadata_archive.tar.gz")), metaContentStream).Result) + .Setup(x => x.UploadArchiveToGithubStorage( + githubOrgDatabaseId, + It.Is(a => a.EndsWith("metadata_archive.tar.gz")), + It.Is(s => (s as MemoryStream).ToArray().GetString() == metadataArchiveContents)).Result) .Returns(uploadedMetadataArchiveUrl); - Console.WriteLine($"MigrationSourceId: {migrationSourceId}, MigrationId: {migrationId}"); - var args = new MigrateRepoCommandArgs { GithubSourceOrg = SOURCE_ORG, SourceRepo = SOURCE_REPO, GithubTargetOrg = TARGET_ORG, TargetRepo = TARGET_REPO, - GithubSourcePat = sourceGithubPat, - GithubTargetPat = targetGithubPat, + GithubSourcePat = GITHUB_SOURCE_PAT, + GithubTargetPat = GITHUB_TARGET_PAT, TargetApiUrl = TARGET_API_URL, GhesApiUrl = GHES_API_URL, UseGithubStorage = true, @@ -424,65 +394,52 @@ public async Task Happy_Path_UseGithubStorage(bool useGhesBlobCredentials) await _handler.Handle(args); - _mockTargetGithubApi.Verify(x => x.GetMigration(migrationId)); + _mockTargetGithubApi.Verify(x => x.GetMigration(MIGRATION_ID)); _mockFileSystemProvider.Verify(x => x.DeleteIfExists(gitArchiveDownloadFilePath), Times.Once); _mockFileSystemProvider.Verify(x => x.DeleteIfExists(metadataArchiveDownloadFilePath), Times.Once); } - [Fact] public async Task Happy_Path_GithubSource_Ghes_Repo_Renamed() { - var githubOrgId = Guid.NewGuid().ToString(); - var migrationSourceId = Guid.NewGuid().ToString(); - var sourceGithubPat = Guid.NewGuid().ToString(); - var targetGithubPat = Guid.NewGuid().ToString(); - var githubRepoUrl = $"https://myghes/{SOURCE_ORG}/{SOURCE_REPO}"; - var migrationId = Guid.NewGuid().ToString(); - var gitArchiveId = 1; - var metadataArchiveId = 2; - var gitArchiveUrl = $"https://example.com/{gitArchiveId}"; - var metadataArchiveUrl = $"https://example.com/{metadataArchiveId}"; - var authenticatedGitArchiveUrl = new Uri($"https://example.com/{gitArchiveId}/authenticated"); - var authenticatedMetadataArchiveUrl = new Uri($"https://example.com/{metadataArchiveId}/authenticated"); - var gitArchiveFilePath = "path/to/git_archive"; - var metadataArchiveFilePath = "path/to/metadata_archive"; - - _mockTargetGithubApi.Setup(x => x.GetOrganizationId(TARGET_ORG).Result).Returns(githubOrgId); - _mockTargetGithubApi.Setup(x => x.CreateGhecMigrationSource(githubOrgId).Result).Returns(migrationSourceId); + _mockTargetGithubApi.Setup(x => x.GetOrganizationId(TARGET_ORG).Result).Returns(GITHUB_ORG_ID); + _mockTargetGithubApi.Setup(x => x.CreateGhecMigrationSource(GITHUB_ORG_ID).Result).Returns(MIGRATION_SOURCE_ID); _mockTargetGithubApi .Setup(x => x.StartMigration( - migrationSourceId, - githubRepoUrl, - githubOrgId, + MIGRATION_SOURCE_ID, + GHES_REPO_URL, + GITHUB_ORG_ID, TARGET_REPO, - sourceGithubPat, - targetGithubPat, - authenticatedGitArchiveUrl.ToString(), - authenticatedMetadataArchiveUrl.ToString(), + GITHUB_SOURCE_PAT, + GITHUB_TARGET_PAT, + AUTHENTICATED_GIT_ARCHIVE_URL, + AUTHENTICATED_METADATA_ARCHIVE_URL, false, null, false).Result) - .Returns(migrationId); - _mockTargetGithubApi.Setup(x => x.GetMigration(migrationId).Result).Returns((State: RepositoryMigrationStatus.Succeeded, TARGET_REPO, 0, null, null)); + .Returns(MIGRATION_ID); + _mockTargetGithubApi.Setup(x => x.GetMigration(MIGRATION_ID).Result).Returns((State: RepositoryMigrationStatus.Succeeded, TARGET_REPO, 0, null, null)); _mockTargetGithubApi.Setup(x => x.DoesOrgExist(TARGET_ORG).Result).Returns(true); - _mockSourceGithubApi.Setup(x => x.StartGitArchiveGeneration(SOURCE_ORG, SOURCE_REPO).Result).Returns(gitArchiveId); - _mockSourceGithubApi.Setup(x => x.StartMetadataArchiveGeneration(SOURCE_ORG, SOURCE_REPO, false, false).Result).Returns(metadataArchiveId); - _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationStatus(SOURCE_ORG, gitArchiveId).Result).Returns(ArchiveMigrationStatus.Exported); - _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationStatus(SOURCE_ORG, metadataArchiveId).Result).Returns(ArchiveMigrationStatus.Exported); - _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationUrl(SOURCE_ORG, gitArchiveId).Result).Returns(gitArchiveUrl); - _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationUrl(SOURCE_ORG, metadataArchiveId).Result).Returns(metadataArchiveUrl); + _mockSourceGithubApi.Setup(x => x.StartGitArchiveGeneration(SOURCE_ORG, SOURCE_REPO).Result).Returns(GIT_ARCHIVE_ID); + _mockSourceGithubApi.Setup(x => x.StartMetadataArchiveGeneration(SOURCE_ORG, SOURCE_REPO, false, false).Result).Returns(METADATA_ARCHIVE_ID); + _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationStatus(SOURCE_ORG, GIT_ARCHIVE_ID).Result).Returns(ArchiveMigrationStatus.Exported); + _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationStatus(SOURCE_ORG, METADATA_ARCHIVE_ID).Result).Returns(ArchiveMigrationStatus.Exported); + _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationUrl(SOURCE_ORG, GIT_ARCHIVE_ID).Result).Returns(GIT_ARCHIVE_URL); + _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationUrl(SOURCE_ORG, METADATA_ARCHIVE_ID).Result).Returns(METADATA_ARCHIVE_URL); - _mockAzureApi.SetupSequence(x => x.UploadToBlob(It.IsAny(), It.IsAny()).Result).Returns(authenticatedGitArchiveUrl).Returns(authenticatedMetadataArchiveUrl); + _mockAzureApi + .SetupSequence(x => x.UploadToBlob(It.IsAny(), It.IsAny()).Result) + .Returns(new Uri(AUTHENTICATED_GIT_ARCHIVE_URL)) + .Returns(new Uri(AUTHENTICATED_METADATA_ARCHIVE_URL)); _mockFileSystemProvider .SetupSequence(m => m.GetTempFileName()) - .Returns(gitArchiveFilePath) - .Returns(metadataArchiveFilePath); + .Returns(GIT_ARCHIVE_FILE_PATH) + .Returns(METADATA_ARCHIVE_FILE_PATH); - _mockEnvironmentVariableProvider.Setup(m => m.SourceGithubPersonalAccessToken(It.IsAny())).Returns(sourceGithubPat); - _mockEnvironmentVariableProvider.Setup(m => m.TargetGithubPersonalAccessToken(It.IsAny())).Returns(targetGithubPat); + _mockEnvironmentVariableProvider.Setup(m => m.SourceGithubPersonalAccessToken(It.IsAny())).Returns(GITHUB_SOURCE_PAT); + _mockEnvironmentVariableProvider.Setup(m => m.TargetGithubPersonalAccessToken(It.IsAny())).Returns(GITHUB_TARGET_PAT); _mockGhesVersionChecker.Setup(m => m.AreBlobCredentialsRequired(GHES_API_URL)).ReturnsAsync(true); @@ -498,44 +455,34 @@ public async Task Happy_Path_GithubSource_Ghes_Repo_Renamed() }; await _handler.Handle(args); - _mockTargetGithubApi.Verify(x => x.GetMigration(migrationId)); - _mockFileSystemProvider.Verify(x => x.DeleteIfExists(gitArchiveFilePath), Times.Once); - _mockFileSystemProvider.Verify(x => x.DeleteIfExists(metadataArchiveFilePath), Times.Once); + _mockTargetGithubApi.Verify(x => x.GetMigration(MIGRATION_ID)); + _mockFileSystemProvider.Verify(x => x.DeleteIfExists(GIT_ARCHIVE_FILE_PATH), Times.Once); + _mockFileSystemProvider.Verify(x => x.DeleteIfExists(METADATA_ARCHIVE_FILE_PATH), Times.Once); } [Fact] public async Task Github_With_Archive_Urls() { - var githubOrgId = Guid.NewGuid().ToString(); - var migrationSourceId = Guid.NewGuid().ToString(); - var sourceGithubPat = Guid.NewGuid().ToString(); - var targetGithubPat = Guid.NewGuid().ToString(); - var githubRepoUrl = $"https://github.com/{SOURCE_ORG}/{SOURCE_REPO}"; - var migrationId = Guid.NewGuid().ToString(); - - var gitArchiveUrl = "https://example.com/git_archive.tar.gz"; - var metadataArchiveUrl = "https://example.com/metadata_archive.tar.gz"; - - _mockTargetGithubApi.Setup(x => x.GetOrganizationId(TARGET_ORG).Result).Returns(githubOrgId); - _mockTargetGithubApi.Setup(x => x.CreateGhecMigrationSource(githubOrgId).Result).Returns(migrationSourceId); + _mockTargetGithubApi.Setup(x => x.GetOrganizationId(TARGET_ORG).Result).Returns(GITHUB_ORG_ID); + _mockTargetGithubApi.Setup(x => x.CreateGhecMigrationSource(GITHUB_ORG_ID).Result).Returns(MIGRATION_SOURCE_ID); _mockTargetGithubApi .Setup(x => x.StartMigration( - migrationSourceId, - githubRepoUrl, - githubOrgId, + MIGRATION_SOURCE_ID, + GITHUB_REPO_URL, + GITHUB_ORG_ID, TARGET_REPO, - sourceGithubPat, - targetGithubPat, - gitArchiveUrl, - metadataArchiveUrl, + GITHUB_SOURCE_PAT, + GITHUB_TARGET_PAT, + GIT_ARCHIVE_URL, + METADATA_ARCHIVE_URL, false, null, false).Result) - .Returns(migrationId); - _mockTargetGithubApi.Setup(x => x.GetMigration(migrationId).Result).Returns((State: RepositoryMigrationStatus.Succeeded, TARGET_REPO, 0, null, null)); + .Returns(MIGRATION_ID); + _mockTargetGithubApi.Setup(x => x.GetMigration(MIGRATION_ID).Result).Returns((State: RepositoryMigrationStatus.Succeeded, TARGET_REPO, 0, null, null)); - _mockEnvironmentVariableProvider.Setup(m => m.SourceGithubPersonalAccessToken(It.IsAny())).Returns(sourceGithubPat); - _mockEnvironmentVariableProvider.Setup(m => m.TargetGithubPersonalAccessToken(It.IsAny())).Returns(targetGithubPat); + _mockEnvironmentVariableProvider.Setup(m => m.SourceGithubPersonalAccessToken(It.IsAny())).Returns(GITHUB_SOURCE_PAT); + _mockEnvironmentVariableProvider.Setup(m => m.TargetGithubPersonalAccessToken(It.IsAny())).Returns(GITHUB_TARGET_PAT); var args = new MigrateRepoCommandArgs { @@ -544,19 +491,122 @@ public async Task Github_With_Archive_Urls() GithubTargetOrg = TARGET_ORG, TargetRepo = TARGET_REPO, TargetApiUrl = TARGET_API_URL, - GitArchiveUrl = gitArchiveUrl, - MetadataArchiveUrl = metadataArchiveUrl, + GitArchiveUrl = GIT_ARCHIVE_URL, + MetadataArchiveUrl = METADATA_ARCHIVE_URL }; await _handler.Handle(args); - _mockTargetGithubApi.Verify(x => x.GetMigration(migrationId)); + _mockTargetGithubApi.Verify(x => x.GetMigration(MIGRATION_ID)); } [Fact] - public async Task Github_Only_One_Archive_Url_Throws_Error() + public async Task With_Archive_Paths() + { + var gitArchivePath = $"/path/{GIT_ARCHIVE_FILE_NAME}"; + var metadataArchivePath = $"/path/{METADATA_ARCHIVE_FILE_NAME}"; + + _mockAzureApi + .Setup(x => x.UploadToBlob(It.Is(s => s.EndsWith(GIT_ARCHIVE_FILE_NAME)), It.IsAny()).Result) + .Returns(new Uri(GIT_ARCHIVE_URL)); + _mockAzureApi + .Setup(x => x.UploadToBlob(It.Is(s => s.EndsWith(METADATA_ARCHIVE_FILE_NAME)), It.IsAny()).Result) + .Returns(new Uri(METADATA_ARCHIVE_URL)); + + _mockTargetGithubApi.Setup(x => x.GetOrganizationId(TARGET_ORG).Result).Returns(GITHUB_ORG_ID); + _mockTargetGithubApi.Setup(x => x.CreateGhecMigrationSource(GITHUB_ORG_ID).Result).Returns(MIGRATION_SOURCE_ID); + _mockTargetGithubApi + .Setup(x => x.StartMigration( + MIGRATION_SOURCE_ID, + GITHUB_REPO_URL, + GITHUB_ORG_ID, + TARGET_REPO, + GITHUB_SOURCE_PAT, + GITHUB_TARGET_PAT, + GIT_ARCHIVE_URL, + METADATA_ARCHIVE_URL, + false, + null, + false).Result) + .Returns(MIGRATION_ID); + _mockTargetGithubApi.Setup(x => x.GetMigration(MIGRATION_ID).Result).Returns((State: RepositoryMigrationStatus.Succeeded, TARGET_REPO, 0, null, null)); + + _mockEnvironmentVariableProvider.Setup(m => m.SourceGithubPersonalAccessToken(It.IsAny())).Returns(GITHUB_SOURCE_PAT); + _mockEnvironmentVariableProvider.Setup(m => m.TargetGithubPersonalAccessToken(It.IsAny())).Returns(GITHUB_TARGET_PAT); + + var args = new MigrateRepoCommandArgs + { + GithubSourceOrg = SOURCE_ORG, + SourceRepo = SOURCE_REPO, + GithubTargetOrg = TARGET_ORG, + TargetRepo = TARGET_REPO, + TargetApiUrl = TARGET_API_URL, + GitArchivePath = gitArchivePath, + MetadataArchivePath = metadataArchivePath, + AzureStorageConnectionString = AZURE_CONNECTION_STRING + }; + await _handler.Handle(args); + + _mockTargetGithubApi.Verify(x => x.GetMigration(MIGRATION_ID)); + + _mockAzureApi.Verify(x => x.UploadToBlob(It.Is(s => s.EndsWith(GIT_ARCHIVE_FILE_NAME)), It.IsAny()), Times.Once()); + _mockAzureApi.Verify(x => x.UploadToBlob(It.Is(s => s.EndsWith(METADATA_ARCHIVE_FILE_NAME)), It.IsAny()), Times.Once()); + _mockAzureApi.VerifyNoOtherCalls(); + } + + [Fact] + public async Task With_Duplicate_Archive_Paths() { - var gitArchiveUrl = "https://example.com/git_archive.tar.gz"; + var gitArchivePath = $"/path/{GIT_ARCHIVE_FILE_NAME}"; + var metadataArchivePath = $"/path/{GIT_ARCHIVE_FILE_NAME}"; + var duplicateArchiveFileName = "archive.tar.gz"; + + _mockAzureApi + .Setup(x => x.UploadToBlob(It.Is(s => s.EndsWith(duplicateArchiveFileName)), It.IsAny()).Result) + .Returns(new Uri(GIT_ARCHIVE_URL)); + _mockTargetGithubApi.Setup(x => x.GetOrganizationId(TARGET_ORG).Result).Returns(GITHUB_ORG_ID); + _mockTargetGithubApi.Setup(x => x.CreateGhecMigrationSource(GITHUB_ORG_ID).Result).Returns(MIGRATION_SOURCE_ID); + _mockTargetGithubApi + .Setup(x => x.StartMigration( + MIGRATION_SOURCE_ID, + GITHUB_REPO_URL, + GITHUB_ORG_ID, + TARGET_REPO, + GITHUB_SOURCE_PAT, + GITHUB_TARGET_PAT, + GIT_ARCHIVE_URL, + GIT_ARCHIVE_URL, + false, + null, + false).Result) + .Returns(MIGRATION_ID); + _mockTargetGithubApi.Setup(x => x.GetMigration(MIGRATION_ID).Result).Returns((State: RepositoryMigrationStatus.Succeeded, TARGET_REPO, 0, null, null)); + + _mockEnvironmentVariableProvider.Setup(m => m.SourceGithubPersonalAccessToken(It.IsAny())).Returns(GITHUB_SOURCE_PAT); + _mockEnvironmentVariableProvider.Setup(m => m.TargetGithubPersonalAccessToken(It.IsAny())).Returns(GITHUB_TARGET_PAT); + + var args = new MigrateRepoCommandArgs + { + GithubSourceOrg = SOURCE_ORG, + SourceRepo = SOURCE_REPO, + GithubTargetOrg = TARGET_ORG, + TargetRepo = TARGET_REPO, + TargetApiUrl = TARGET_API_URL, + GitArchivePath = gitArchivePath, + MetadataArchivePath = metadataArchivePath, + AzureStorageConnectionString = AZURE_CONNECTION_STRING + }; + await _handler.Handle(args); + + _mockTargetGithubApi.Verify(x => x.GetMigration(MIGRATION_ID)); + + _mockAzureApi.Verify(x => x.UploadToBlob(It.Is(s => s.EndsWith(duplicateArchiveFileName)), It.IsAny()), Times.Once()); + _mockAzureApi.VerifyNoOtherCalls(); + } + + [Fact] + public async Task Github_Only_One_Archive_Url_Throws_Error() + { await FluentActions .Invoking(async () => await _handler.Handle(new MigrateRepoCommandArgs { @@ -565,7 +615,7 @@ await FluentActions GithubTargetOrg = TARGET_ORG, TargetRepo = TARGET_REPO, TargetApiUrl = TARGET_API_URL, - GitArchiveUrl = gitArchiveUrl, + GitArchiveUrl = GIT_ARCHIVE_URL, })) .Should().ThrowAsync(); } @@ -589,53 +639,40 @@ await FluentActions [Fact] public async Task Ghes_AzureConnectionString_Uses_Env_When_Option_Empty() { - var azureConnectionStringEnv = Guid.NewGuid().ToString(); - - var githubOrgId = Guid.NewGuid().ToString(); - var migrationSourceId = Guid.NewGuid().ToString(); - var sourceGithubPat = Guid.NewGuid().ToString(); - var targetGithubPat = Guid.NewGuid().ToString(); - var githubRepoUrl = $"https://myghes/{SOURCE_ORG}/{SOURCE_REPO}"; - var migrationId = Guid.NewGuid().ToString(); - var gitArchiveId = 1; - var metadataArchiveId = 2; - - var gitArchiveUrl = $"https://example.com/{gitArchiveId}"; - var metadataArchiveUrl = $"https://example.com/{metadataArchiveId}"; - var authenticatedGitArchiveUrl = new Uri($"https://example.com/{gitArchiveId}/authenticated"); - var authenticatedMetadataArchiveUrl = new Uri($"https://example.com/{metadataArchiveId}/authenticated"); - - _mockTargetGithubApi.Setup(x => x.GetOrganizationId(TARGET_ORG).Result).Returns(githubOrgId); - _mockTargetGithubApi.Setup(x => x.CreateGhecMigrationSource(githubOrgId).Result).Returns(migrationSourceId); + _mockTargetGithubApi.Setup(x => x.GetOrganizationId(TARGET_ORG).Result).Returns(GITHUB_ORG_ID); + _mockTargetGithubApi.Setup(x => x.CreateGhecMigrationSource(GITHUB_ORG_ID).Result).Returns(MIGRATION_SOURCE_ID); _mockTargetGithubApi .Setup(x => x.StartMigration( - migrationSourceId, - githubRepoUrl, - githubOrgId, + MIGRATION_SOURCE_ID, + GHES_REPO_URL, + GITHUB_ORG_ID, TARGET_REPO, - sourceGithubPat, - targetGithubPat, - authenticatedGitArchiveUrl.ToString(), - authenticatedMetadataArchiveUrl.ToString(), + GITHUB_SOURCE_PAT, + GITHUB_TARGET_PAT, + AUTHENTICATED_GIT_ARCHIVE_URL, + AUTHENTICATED_METADATA_ARCHIVE_URL, false, null, false).Result) - .Returns(migrationId); - _mockTargetGithubApi.Setup(x => x.GetMigration(migrationId).Result).Returns((State: RepositoryMigrationStatus.Succeeded, TARGET_REPO, 0, null, null)); + .Returns(MIGRATION_ID); + _mockTargetGithubApi.Setup(x => x.GetMigration(MIGRATION_ID).Result).Returns((State: RepositoryMigrationStatus.Succeeded, TARGET_REPO, 0, null, null)); _mockTargetGithubApi.Setup(x => x.DoesOrgExist(TARGET_ORG).Result).Returns(true); - _mockSourceGithubApi.Setup(x => x.StartGitArchiveGeneration(SOURCE_ORG, SOURCE_REPO).Result).Returns(gitArchiveId); - _mockSourceGithubApi.Setup(x => x.StartMetadataArchiveGeneration(SOURCE_ORG, SOURCE_REPO, false, false).Result).Returns(metadataArchiveId); - _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationStatus(SOURCE_ORG, gitArchiveId).Result).Returns(ArchiveMigrationStatus.Exported); - _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationStatus(SOURCE_ORG, metadataArchiveId).Result).Returns(ArchiveMigrationStatus.Exported); - _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationUrl(SOURCE_ORG, gitArchiveId).Result).Returns(gitArchiveUrl); - _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationUrl(SOURCE_ORG, metadataArchiveId).Result).Returns(metadataArchiveUrl); + _mockSourceGithubApi.Setup(x => x.StartGitArchiveGeneration(SOURCE_ORG, SOURCE_REPO).Result).Returns(GIT_ARCHIVE_ID); + _mockSourceGithubApi.Setup(x => x.StartMetadataArchiveGeneration(SOURCE_ORG, SOURCE_REPO, false, false).Result).Returns(METADATA_ARCHIVE_ID); + _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationStatus(SOURCE_ORG, GIT_ARCHIVE_ID).Result).Returns(ArchiveMigrationStatus.Exported); + _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationStatus(SOURCE_ORG, METADATA_ARCHIVE_ID).Result).Returns(ArchiveMigrationStatus.Exported); + _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationUrl(SOURCE_ORG, GIT_ARCHIVE_ID).Result).Returns(GIT_ARCHIVE_URL); + _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationUrl(SOURCE_ORG, METADATA_ARCHIVE_ID).Result).Returns(METADATA_ARCHIVE_URL); - _mockAzureApi.SetupSequence(x => x.UploadToBlob(It.IsAny(), It.IsAny()).Result).Returns(authenticatedGitArchiveUrl).Returns(authenticatedMetadataArchiveUrl); + _mockAzureApi + .SetupSequence(x => x.UploadToBlob(It.IsAny(), It.IsAny()).Result) + .Returns(new Uri(AUTHENTICATED_GIT_ARCHIVE_URL)) + .Returns(new Uri(AUTHENTICATED_METADATA_ARCHIVE_URL)); - _mockEnvironmentVariableProvider.Setup(m => m.SourceGithubPersonalAccessToken(It.IsAny())).Returns(sourceGithubPat); - _mockEnvironmentVariableProvider.Setup(m => m.TargetGithubPersonalAccessToken(It.IsAny())).Returns(targetGithubPat); - _mockEnvironmentVariableProvider.Setup(m => m.AzureStorageConnectionString(It.IsAny())).Returns(azureConnectionStringEnv); + _mockEnvironmentVariableProvider.Setup(m => m.SourceGithubPersonalAccessToken(It.IsAny())).Returns(GITHUB_SOURCE_PAT); + _mockEnvironmentVariableProvider.Setup(m => m.TargetGithubPersonalAccessToken(It.IsAny())).Returns(GITHUB_TARGET_PAT); + _mockEnvironmentVariableProvider.Setup(m => m.AzureStorageConnectionString(It.IsAny())).Returns(AZURE_CONNECTION_STRING); _mockGhesVersionChecker.Setup(m => m.AreBlobCredentialsRequired(GHES_API_URL)).ReturnsAsync(true); @@ -650,56 +687,45 @@ public async Task Ghes_AzureConnectionString_Uses_Env_When_Option_Empty() }; await _handler.Handle(args); - _mockTargetGithubApi.Verify(x => x.GetMigration(migrationId)); + _mockTargetGithubApi.Verify(x => x.GetMigration(MIGRATION_ID)); } [Fact] public async Task Ghes_With_NoSslVerify_Uses_NoSsl_Client() { - var githubOrgId = Guid.NewGuid().ToString(); - var migrationSourceId = Guid.NewGuid().ToString(); - var sourceGithubPat = Guid.NewGuid().ToString(); - var targetGithubPat = Guid.NewGuid().ToString(); - var githubRepoUrl = $"https://myghes/{SOURCE_ORG}/{SOURCE_REPO}"; - var migrationId = Guid.NewGuid().ToString(); - var gitArchiveId = 1; - var metadataArchiveId = 2; - - var gitArchiveUrl = $"https://example.com/{gitArchiveId}"; - var metadataArchiveUrl = $"https://example.com/{metadataArchiveId}"; - var authenticatedGitArchiveUrl = new Uri($"https://example.com/{gitArchiveId}/authenticated"); - var authenticatedMetadataArchiveUrl = new Uri($"https://example.com/{metadataArchiveId}/authenticated"); - - _mockTargetGithubApi.Setup(x => x.GetOrganizationId(TARGET_ORG).Result).Returns(githubOrgId); - _mockTargetGithubApi.Setup(x => x.CreateGhecMigrationSource(githubOrgId).Result).Returns(migrationSourceId); + _mockTargetGithubApi.Setup(x => x.GetOrganizationId(TARGET_ORG).Result).Returns(GITHUB_ORG_ID); + _mockTargetGithubApi.Setup(x => x.CreateGhecMigrationSource(GITHUB_ORG_ID).Result).Returns(MIGRATION_SOURCE_ID); _mockTargetGithubApi .Setup(x => x.StartMigration( - migrationSourceId, - githubRepoUrl, - githubOrgId, + MIGRATION_SOURCE_ID, + GHES_REPO_URL, + GITHUB_ORG_ID, TARGET_REPO, - sourceGithubPat, - targetGithubPat, - authenticatedGitArchiveUrl.ToString(), - authenticatedMetadataArchiveUrl.ToString(), + GITHUB_SOURCE_PAT, + GITHUB_TARGET_PAT, + AUTHENTICATED_GIT_ARCHIVE_URL, + AUTHENTICATED_METADATA_ARCHIVE_URL, false, null, false).Result) - .Returns(migrationId); - _mockTargetGithubApi.Setup(x => x.GetMigration(migrationId).Result).Returns((State: RepositoryMigrationStatus.Succeeded, TARGET_REPO, 0, null, null)); + .Returns(MIGRATION_ID); + _mockTargetGithubApi.Setup(x => x.GetMigration(MIGRATION_ID).Result).Returns((State: RepositoryMigrationStatus.Succeeded, TARGET_REPO, 0, null, null)); _mockTargetGithubApi.Setup(x => x.DoesOrgExist(TARGET_ORG).Result).Returns(true); - _mockSourceGithubApi.Setup(x => x.StartGitArchiveGeneration(SOURCE_ORG, SOURCE_REPO).Result).Returns(gitArchiveId); - _mockSourceGithubApi.Setup(x => x.StartMetadataArchiveGeneration(SOURCE_ORG, SOURCE_REPO, false, false).Result).Returns(metadataArchiveId); - _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationStatus(SOURCE_ORG, gitArchiveId).Result).Returns(ArchiveMigrationStatus.Exported); - _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationStatus(SOURCE_ORG, metadataArchiveId).Result).Returns(ArchiveMigrationStatus.Exported); - _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationUrl(SOURCE_ORG, gitArchiveId).Result).Returns(gitArchiveUrl); - _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationUrl(SOURCE_ORG, metadataArchiveId).Result).Returns(metadataArchiveUrl); + _mockSourceGithubApi.Setup(x => x.StartGitArchiveGeneration(SOURCE_ORG, SOURCE_REPO).Result).Returns(GIT_ARCHIVE_ID); + _mockSourceGithubApi.Setup(x => x.StartMetadataArchiveGeneration(SOURCE_ORG, SOURCE_REPO, false, false).Result).Returns(METADATA_ARCHIVE_ID); + _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationStatus(SOURCE_ORG, GIT_ARCHIVE_ID).Result).Returns(ArchiveMigrationStatus.Exported); + _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationStatus(SOURCE_ORG, METADATA_ARCHIVE_ID).Result).Returns(ArchiveMigrationStatus.Exported); + _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationUrl(SOURCE_ORG, GIT_ARCHIVE_ID).Result).Returns(GIT_ARCHIVE_URL); + _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationUrl(SOURCE_ORG, METADATA_ARCHIVE_ID).Result).Returns(METADATA_ARCHIVE_URL); - _mockAzureApi.SetupSequence(x => x.UploadToBlob(It.IsAny(), It.IsAny()).Result).Returns(authenticatedGitArchiveUrl).Returns(authenticatedMetadataArchiveUrl); + _mockAzureApi + .SetupSequence(x => x.UploadToBlob(It.IsAny(), It.IsAny()).Result) + .Returns(new Uri(AUTHENTICATED_GIT_ARCHIVE_URL)) + .Returns(new Uri(AUTHENTICATED_METADATA_ARCHIVE_URL)); - _mockEnvironmentVariableProvider.Setup(m => m.SourceGithubPersonalAccessToken(It.IsAny())).Returns(sourceGithubPat); - _mockEnvironmentVariableProvider.Setup(m => m.TargetGithubPersonalAccessToken(It.IsAny())).Returns(targetGithubPat); + _mockEnvironmentVariableProvider.Setup(m => m.SourceGithubPersonalAccessToken(It.IsAny())).Returns(GITHUB_SOURCE_PAT); + _mockEnvironmentVariableProvider.Setup(m => m.TargetGithubPersonalAccessToken(It.IsAny())).Returns(GITHUB_TARGET_PAT); _mockGhesVersionChecker.Setup(m => m.AreBlobCredentialsRequired(GHES_API_URL)).ReturnsAsync(true); @@ -716,53 +742,41 @@ public async Task Ghes_With_NoSslVerify_Uses_NoSsl_Client() }; await _handler.Handle(args); - _mockTargetGithubApi.Verify(x => x.GetMigration(migrationId)); + _mockTargetGithubApi.Verify(x => x.GetMigration(MIGRATION_ID)); } [Fact] public async Task Ghes_With_3_8_0_Version_Returns_Archive_Urls_Directly() { - var githubOrgId = Guid.NewGuid().ToString(); - var migrationSourceId = Guid.NewGuid().ToString(); - var sourceGithubPat = Guid.NewGuid().ToString(); - var targetGithubPat = Guid.NewGuid().ToString(); - var githubRepoUrl = $"https://myghes/{SOURCE_ORG}/{SOURCE_REPO}"; - var migrationId = Guid.NewGuid().ToString(); - var gitArchiveId = 1; - var metadataArchiveId = 2; - - var gitArchiveUrl = $"https://example.com/{gitArchiveId}"; - var metadataArchiveUrl = $"https://example.com/{metadataArchiveId}"; - - _mockTargetGithubApi.Setup(x => x.GetOrganizationId(TARGET_ORG).Result).Returns(githubOrgId); - _mockTargetGithubApi.Setup(x => x.CreateGhecMigrationSource(githubOrgId).Result).Returns(migrationSourceId); + _mockTargetGithubApi.Setup(x => x.GetOrganizationId(TARGET_ORG).Result).Returns(GITHUB_ORG_ID); + _mockTargetGithubApi.Setup(x => x.CreateGhecMigrationSource(GITHUB_ORG_ID).Result).Returns(MIGRATION_SOURCE_ID); _mockTargetGithubApi .Setup(x => x.StartMigration( - migrationSourceId, - githubRepoUrl, - githubOrgId, + MIGRATION_SOURCE_ID, + GHES_REPO_URL, + GITHUB_ORG_ID, TARGET_REPO, - sourceGithubPat, - targetGithubPat, - gitArchiveUrl, - metadataArchiveUrl, + GITHUB_SOURCE_PAT, + GITHUB_TARGET_PAT, + GIT_ARCHIVE_URL, + METADATA_ARCHIVE_URL, false, null, false).Result) - .Returns(migrationId); - _mockTargetGithubApi.Setup(x => x.GetMigration(migrationId).Result).Returns((State: RepositoryMigrationStatus.Succeeded, TARGET_REPO, 0, null, null)); + .Returns(MIGRATION_ID); + _mockTargetGithubApi.Setup(x => x.GetMigration(MIGRATION_ID).Result).Returns((State: RepositoryMigrationStatus.Succeeded, TARGET_REPO, 0, null, null)); _mockTargetGithubApi.Setup(x => x.DoesOrgExist(TARGET_ORG).Result).Returns(true); - _mockSourceGithubApi.Setup(x => x.StartGitArchiveGeneration(SOURCE_ORG, SOURCE_REPO).Result).Returns(gitArchiveId); - _mockSourceGithubApi.Setup(x => x.StartMetadataArchiveGeneration(SOURCE_ORG, SOURCE_REPO, false, false).Result).Returns(metadataArchiveId); - _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationStatus(SOURCE_ORG, gitArchiveId).Result).Returns(ArchiveMigrationStatus.Exported); - _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationStatus(SOURCE_ORG, metadataArchiveId).Result).Returns(ArchiveMigrationStatus.Exported); - _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationUrl(SOURCE_ORG, gitArchiveId).Result).Returns(gitArchiveUrl); - _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationUrl(SOURCE_ORG, metadataArchiveId).Result).Returns(metadataArchiveUrl); + _mockSourceGithubApi.Setup(x => x.StartGitArchiveGeneration(SOURCE_ORG, SOURCE_REPO).Result).Returns(GIT_ARCHIVE_ID); + _mockSourceGithubApi.Setup(x => x.StartMetadataArchiveGeneration(SOURCE_ORG, SOURCE_REPO, false, false).Result).Returns(METADATA_ARCHIVE_ID); + _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationStatus(SOURCE_ORG, GIT_ARCHIVE_ID).Result).Returns(ArchiveMigrationStatus.Exported); + _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationStatus(SOURCE_ORG, METADATA_ARCHIVE_ID).Result).Returns(ArchiveMigrationStatus.Exported); + _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationUrl(SOURCE_ORG, GIT_ARCHIVE_ID).Result).Returns(GIT_ARCHIVE_URL); + _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationUrl(SOURCE_ORG, METADATA_ARCHIVE_ID).Result).Returns(METADATA_ARCHIVE_URL); - _mockEnvironmentVariableProvider.Setup(m => m.SourceGithubPersonalAccessToken(It.IsAny())).Returns(sourceGithubPat); - _mockEnvironmentVariableProvider.Setup(m => m.TargetGithubPersonalAccessToken(It.IsAny())).Returns(targetGithubPat); + _mockEnvironmentVariableProvider.Setup(m => m.SourceGithubPersonalAccessToken(It.IsAny())).Returns(GITHUB_SOURCE_PAT); + _mockEnvironmentVariableProvider.Setup(m => m.TargetGithubPersonalAccessToken(It.IsAny())).Returns(GITHUB_TARGET_PAT); _mockGhesVersionChecker.Setup(m => m.AreBlobCredentialsRequired(GHES_API_URL)).ReturnsAsync(false); @@ -778,18 +792,15 @@ public async Task Ghes_With_3_8_0_Version_Returns_Archive_Urls_Directly() }; await _handler.Handle(args); - _mockTargetGithubApi.Verify(x => x.GetMigration(migrationId)); + _mockTargetGithubApi.Verify(x => x.GetMigration(MIGRATION_ID)); } [Fact] public async Task Ghes_Failed_Archive_Generation_Throws_Error() { - var gitArchiveId = 1; - var metadataArchiveId = 2; - - _mockSourceGithubApi.Setup(x => x.StartGitArchiveGeneration(SOURCE_ORG, SOURCE_REPO).Result).Returns(gitArchiveId); - _mockSourceGithubApi.Setup(x => x.StartMetadataArchiveGeneration(SOURCE_ORG, SOURCE_REPO, false, false).Result).Returns(metadataArchiveId); - _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationStatus(SOURCE_ORG, gitArchiveId).Result).Returns(ArchiveMigrationStatus.Failed); + _mockSourceGithubApi.Setup(x => x.StartGitArchiveGeneration(SOURCE_ORG, SOURCE_REPO).Result).Returns(GIT_ARCHIVE_ID); + _mockSourceGithubApi.Setup(x => x.StartMetadataArchiveGeneration(SOURCE_ORG, SOURCE_REPO, false, false).Result).Returns(METADATA_ARCHIVE_ID); + _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationStatus(SOURCE_ORG, GIT_ARCHIVE_ID).Result).Returns(ArchiveMigrationStatus.Failed); _mockGhesVersionChecker.Setup(m => m.AreBlobCredentialsRequired(GHES_API_URL)).ReturnsAsync(true); @@ -811,77 +822,65 @@ await FluentActions [Fact] public async Task Ghes_Retries_Archive_Generation_On_Any_Error() { - var githubOrgId = Guid.NewGuid().ToString(); - var migrationSourceId = Guid.NewGuid().ToString(); - var sourceGithubPat = Guid.NewGuid().ToString(); - var targetGithubPat = Guid.NewGuid().ToString(); - var githubRepoUrl = $"https://myghes/{SOURCE_ORG}/{SOURCE_REPO}"; - var migrationId = Guid.NewGuid().ToString(); - var gitArchiveId = 1; - var metadataArchiveId = 2; - var gitArchiveUrl = $"https://example.com/{gitArchiveId}"; - var metadataArchiveUrl = $"https://example.com/{metadataArchiveId}"; - var authenticatedGitArchiveUrl = new Uri($"https://example.com/{gitArchiveId}/authenticated"); - var authenticatedMetadataArchiveUrl = new Uri($"https://example.com/{metadataArchiveId}/authenticated"); - var gitArchiveFilePath = "path/to/git_archive"; - var metadataArchiveFilePath = "path/to/metadata_archive"; - _mockSourceGithubApi.Setup(x => x.GetEnterpriseServerVersion()).ReturnsAsync("3.7.1"); - _mockTargetGithubApi.Setup(x => x.GetOrganizationId(TARGET_ORG).Result).Returns(githubOrgId); - _mockTargetGithubApi.Setup(x => x.CreateGhecMigrationSource(githubOrgId).Result).Returns(migrationSourceId); + _mockTargetGithubApi.Setup(x => x.GetOrganizationId(TARGET_ORG).Result).Returns(GITHUB_ORG_ID); + _mockTargetGithubApi.Setup(x => x.CreateGhecMigrationSource(GITHUB_ORG_ID).Result).Returns(MIGRATION_SOURCE_ID); _mockTargetGithubApi .Setup(x => x.StartMigration( - migrationSourceId, - githubRepoUrl, - githubOrgId, + MIGRATION_SOURCE_ID, + GHES_REPO_URL, + GITHUB_ORG_ID, TARGET_REPO, - sourceGithubPat, - targetGithubPat, - authenticatedGitArchiveUrl.ToString(), - authenticatedMetadataArchiveUrl.ToString(), + GITHUB_SOURCE_PAT, + GITHUB_TARGET_PAT, + AUTHENTICATED_GIT_ARCHIVE_URL, + AUTHENTICATED_METADATA_ARCHIVE_URL, false, null, false).Result) - .Returns(migrationId); - _mockTargetGithubApi.Setup(x => x.GetMigration(migrationId).Result).Returns((State: RepositoryMigrationStatus.Succeeded, TARGET_REPO, 0, null, null)); + .Returns(MIGRATION_ID); + _mockTargetGithubApi.Setup(x => x.GetMigration(MIGRATION_ID).Result).Returns((State: RepositoryMigrationStatus.Succeeded, TARGET_REPO, 0, null, null)); _mockTargetGithubApi.Setup(x => x.DoesOrgExist(TARGET_ORG).Result).Returns(true); _mockSourceGithubApi .SetupSequence(x => x.StartGitArchiveGeneration(SOURCE_ORG, SOURCE_REPO).Result) .Throws() - .Returns(gitArchiveId) - .Returns(gitArchiveId) // for first StartMetadataArchiveGeneration throw - .Returns(gitArchiveId) // for second StartMetadataArchiveGeneration throw - .Returns(gitArchiveId) // for GetArchiveMigrationStatus Failed - .Returns(gitArchiveId); // for GetArchiveMigrationStatus TimeoutException + .Returns(GIT_ARCHIVE_ID) + .Returns(GIT_ARCHIVE_ID) // for first StartMetadataArchiveGeneration throw + .Returns(GIT_ARCHIVE_ID) // for second StartMetadataArchiveGeneration throw + .Returns(GIT_ARCHIVE_ID) // for GetArchiveMigrationStatus Failed + .Returns(GIT_ARCHIVE_ID); // for GetArchiveMigrationStatus TimeoutException _mockSourceGithubApi .SetupSequence(x => x.StartMetadataArchiveGeneration(SOURCE_ORG, SOURCE_REPO, false, false).Result) .Throws() .Throws() - .Returns(metadataArchiveId) - .Returns(metadataArchiveId) // for GetArchiveMigrationStatus Failed - .Returns(metadataArchiveId); // for GetArchiveMigrationStatus TimeoutException + .Returns(METADATA_ARCHIVE_ID) + .Returns(METADATA_ARCHIVE_ID) // for GetArchiveMigrationStatus Failed + .Returns(METADATA_ARCHIVE_ID); // for GetArchiveMigrationStatus TimeoutException _mockSourceGithubApi - .SetupSequence(x => x.GetArchiveMigrationStatus(SOURCE_ORG, gitArchiveId).Result) + .SetupSequence(x => x.GetArchiveMigrationStatus(SOURCE_ORG, GIT_ARCHIVE_ID).Result) .Returns(ArchiveMigrationStatus.Failed) .Returns(ArchiveMigrationStatus.Exported) .Returns(ArchiveMigrationStatus.Exported); // for GetArchiveMigrationStatus TimeoutException _mockSourceGithubApi - .SetupSequence(x => x.GetArchiveMigrationStatus(SOURCE_ORG, metadataArchiveId).Result) + .SetupSequence(x => x.GetArchiveMigrationStatus(SOURCE_ORG, METADATA_ARCHIVE_ID).Result) .Throws() .Returns(ArchiveMigrationStatus.Exported); - _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationUrl(SOURCE_ORG, gitArchiveId).Result).Returns(gitArchiveUrl); - _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationUrl(SOURCE_ORG, metadataArchiveId).Result).Returns(metadataArchiveUrl); + _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationUrl(SOURCE_ORG, GIT_ARCHIVE_ID).Result).Returns(GIT_ARCHIVE_URL); + _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationUrl(SOURCE_ORG, METADATA_ARCHIVE_ID).Result).Returns(METADATA_ARCHIVE_URL); - _mockAzureApi.SetupSequence(x => x.UploadToBlob(It.IsAny(), It.IsAny()).Result).Returns(authenticatedGitArchiveUrl).Returns(authenticatedMetadataArchiveUrl); + _mockAzureApi + .SetupSequence(x => x.UploadToBlob(It.IsAny(), It.IsAny()).Result) + .Returns(new Uri(AUTHENTICATED_GIT_ARCHIVE_URL)) + .Returns(new Uri(AUTHENTICATED_METADATA_ARCHIVE_URL)); _mockFileSystemProvider .SetupSequence(m => m.GetTempFileName()) - .Returns(gitArchiveFilePath) - .Returns(metadataArchiveFilePath); + .Returns(GIT_ARCHIVE_FILE_PATH) + .Returns(METADATA_ARCHIVE_FILE_PATH); - _mockEnvironmentVariableProvider.Setup(m => m.SourceGithubPersonalAccessToken(It.IsAny())).Returns(sourceGithubPat); - _mockEnvironmentVariableProvider.Setup(m => m.TargetGithubPersonalAccessToken(It.IsAny())).Returns(targetGithubPat); + _mockEnvironmentVariableProvider.Setup(m => m.SourceGithubPersonalAccessToken(It.IsAny())).Returns(GITHUB_SOURCE_PAT); + _mockEnvironmentVariableProvider.Setup(m => m.TargetGithubPersonalAccessToken(It.IsAny())).Returns(GITHUB_TARGET_PAT); _mockGhesVersionChecker.Setup(m => m.AreBlobCredentialsRequired(GHES_API_URL)).ReturnsAsync(true); @@ -897,7 +896,7 @@ public async Task Ghes_Retries_Archive_Generation_On_Any_Error() }; await _handler.Handle(args); - _mockTargetGithubApi.Verify(x => x.GetMigration(migrationId)); + _mockTargetGithubApi.Verify(x => x.GetMigration(MIGRATION_ID)); } [Fact] @@ -991,10 +990,6 @@ public async Task It_Uses_Github_Source_Pat_When_Provided() [Fact] public async Task It_Skips_Releases_When_Option_Is_True() { - // Arrange - var actualLogOutput = new List(); - _mockOctoLogger.Setup(m => m.LogInformation(It.IsAny())).Callback(s => actualLogOutput.Add(s)); - // Act var args = new MigrateRepoCommandArgs { @@ -1026,8 +1021,6 @@ public async Task It_Skips_Releases_When_Option_Is_True() public async Task It_Locks_Source_Repo_When_Option_Is_True() { // Arrange - var actualLogOutput = new List(); - _mockOctoLogger.Setup(m => m.LogInformation(It.IsAny())).Callback(s => actualLogOutput.Add(s)); _mockTargetGithubApi.Setup(x => x.DoesOrgExist(TARGET_ORG).Result).Returns(true); // Act @@ -1165,12 +1158,12 @@ public async Task It_Extracts_Base_Ghes_Url_From_Ghes_Api_Url_Using_Alternate_Te { // Arrange const string ghesApiUrl = "https://api.myghes.com"; - var expectedGithubRepoUrl = $"https://myghes.com/{SOURCE_ORG}/{SOURCE_REPO}"; + var expectedGITHUB_REPO_URL = $"https://myghes.com/{SOURCE_ORG}/{SOURCE_REPO}"; _mockSourceGithubApi .Setup(x => x.StartMigration( It.IsAny(), - expectedGithubRepoUrl, + expectedGITHUB_REPO_URL, It.IsAny(), It.IsAny(), It.IsAny(), @@ -1180,7 +1173,7 @@ public async Task It_Extracts_Base_Ghes_Url_From_Ghes_Api_Url_Using_Alternate_Te false, It.IsAny(), false).Result) - .Returns("migrationId"); + .Returns("MIGRATION_ID"); _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationStatus(It.IsAny(), It.IsAny()).Result).Returns(ArchiveMigrationStatus.Exported); @@ -1205,7 +1198,7 @@ public async Task It_Extracts_Base_Ghes_Url_From_Ghes_Api_Url_Using_Alternate_Te // Assert _mockTargetGithubApi.Verify(m => m.StartMigration( It.IsAny(), - expectedGithubRepoUrl, + expectedGITHUB_REPO_URL, It.IsAny(), It.IsAny(), It.IsAny(), @@ -1222,12 +1215,12 @@ public async Task It_Falls_Back_To_The_Ghes_Api_Url_If_Could_Not_Extract_Base_Gh { // Arrange const string ghesApiUrl = "https://non-conforming-ghes-api-url"; - var expectedGithubRepoUrl = $"{ghesApiUrl}/{SOURCE_ORG}/{SOURCE_REPO}"; + var expectedGITHUB_REPO_URL = $"{ghesApiUrl}/{SOURCE_ORG}/{SOURCE_REPO}"; _mockTargetGithubApi .Setup(x => x.StartMigration( It.IsAny(), - expectedGithubRepoUrl, + expectedGITHUB_REPO_URL, It.IsAny(), It.IsAny(), It.IsAny(), @@ -1237,7 +1230,7 @@ public async Task It_Falls_Back_To_The_Ghes_Api_Url_If_Could_Not_Extract_Base_Gh false, It.IsAny(), false).Result) - .Returns("migrationId"); + .Returns("MIGRATION_ID"); _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationStatus(It.IsAny(), It.IsAny()).Result).Returns(ArchiveMigrationStatus.Exported); @@ -1262,7 +1255,7 @@ public async Task It_Falls_Back_To_The_Ghes_Api_Url_If_Could_Not_Extract_Base_Gh // Assert _mockTargetGithubApi.Verify(m => m.StartMigration( It.IsAny(), - expectedGithubRepoUrl, + expectedGITHUB_REPO_URL, It.IsAny(), It.IsAny(), It.IsAny(), @@ -1277,17 +1270,6 @@ public async Task It_Falls_Back_To_The_Ghes_Api_Url_If_Could_Not_Extract_Base_Gh [Fact] public async Task It_Uses_Aws_If_Arguments_Are_Included() { - var githubOrgId = Guid.NewGuid().ToString(); - var migrationSourceId = Guid.NewGuid().ToString(); - var sourceGithubPat = Guid.NewGuid().ToString(); - var targetGithubPat = Guid.NewGuid().ToString(); - var githubRepoUrl = $"https://myghes/{SOURCE_ORG}/{SOURCE_REPO}"; - var migrationId = Guid.NewGuid().ToString(); - var gitArchiveId = 1; - var metadataArchiveId = 2; - - var gitArchiveUrl = $"https://example.com/{gitArchiveId}"; - var metadataArchiveUrl = $"https://example.com/{metadataArchiveId}"; var gitArchiveContent = new byte[] { 1, 2, 3, 4, 5 }; var metadataArchiveContent = new byte[] { 6, 7, 8, 9, 10 }; @@ -1297,37 +1279,37 @@ public async Task It_Uses_Aws_If_Arguments_Are_Included() var awsRegion = "eu-west-1"; var archiveUrl = $"https://s3.amazonaws.com/{awsBucketName}/archive.tar"; - _mockTargetGithubApi.Setup(x => x.GetOrganizationId(TARGET_ORG).Result).Returns(githubOrgId); - _mockTargetGithubApi.Setup(x => x.CreateGhecMigrationSource(githubOrgId).Result).Returns(migrationSourceId); + _mockTargetGithubApi.Setup(x => x.GetOrganizationId(TARGET_ORG).Result).Returns(GITHUB_ORG_ID); + _mockTargetGithubApi.Setup(x => x.CreateGhecMigrationSource(GITHUB_ORG_ID).Result).Returns(MIGRATION_SOURCE_ID); _mockTargetGithubApi .Setup(x => x.StartMigration( - migrationSourceId, - githubRepoUrl, - githubOrgId, + MIGRATION_SOURCE_ID, + GHES_REPO_URL, + GITHUB_ORG_ID, TARGET_REPO, - sourceGithubPat, - targetGithubPat, + GITHUB_SOURCE_PAT, + GITHUB_TARGET_PAT, archiveUrl, archiveUrl, false, null, false).Result) - .Returns(migrationId); - _mockTargetGithubApi.Setup(x => x.GetMigration(migrationId).Result).Returns((State: RepositoryMigrationStatus.Succeeded, TARGET_REPO, 0, null, null)); + .Returns(MIGRATION_ID); + _mockTargetGithubApi.Setup(x => x.GetMigration(MIGRATION_ID).Result).Returns((State: RepositoryMigrationStatus.Succeeded, TARGET_REPO, 0, null, null)); _mockTargetGithubApi.Setup(x => x.DoesOrgExist(TARGET_ORG).Result).Returns(true); - _mockSourceGithubApi.Setup(x => x.StartGitArchiveGeneration(SOURCE_ORG, SOURCE_REPO).Result).Returns(gitArchiveId); - _mockSourceGithubApi.Setup(x => x.StartMetadataArchiveGeneration(SOURCE_ORG, SOURCE_REPO, false, false).Result).Returns(metadataArchiveId); - _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationStatus(SOURCE_ORG, gitArchiveId).Result).Returns(ArchiveMigrationStatus.Exported); - _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationStatus(SOURCE_ORG, metadataArchiveId).Result).Returns(ArchiveMigrationStatus.Exported); - _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationUrl(SOURCE_ORG, gitArchiveId).Result).Returns(gitArchiveUrl); - _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationUrl(SOURCE_ORG, metadataArchiveId).Result).Returns(metadataArchiveUrl); + _mockSourceGithubApi.Setup(x => x.StartGitArchiveGeneration(SOURCE_ORG, SOURCE_REPO).Result).Returns(GIT_ARCHIVE_ID); + _mockSourceGithubApi.Setup(x => x.StartMetadataArchiveGeneration(SOURCE_ORG, SOURCE_REPO, false, false).Result).Returns(METADATA_ARCHIVE_ID); + _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationStatus(SOURCE_ORG, GIT_ARCHIVE_ID).Result).Returns(ArchiveMigrationStatus.Exported); + _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationStatus(SOURCE_ORG, METADATA_ARCHIVE_ID).Result).Returns(ArchiveMigrationStatus.Exported); + _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationUrl(SOURCE_ORG, GIT_ARCHIVE_ID).Result).Returns(GIT_ARCHIVE_URL); + _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationUrl(SOURCE_ORG, METADATA_ARCHIVE_ID).Result).Returns(METADATA_ARCHIVE_URL); - _mockHttpDownloadService.Setup(x => x.DownloadToBytes(gitArchiveUrl).Result).Returns(gitArchiveContent); - _mockHttpDownloadService.Setup(x => x.DownloadToBytes(metadataArchiveUrl).Result).Returns(metadataArchiveContent); + _mockHttpDownloadService.Setup(x => x.DownloadToBytes(GIT_ARCHIVE_URL).Result).Returns(gitArchiveContent); + _mockHttpDownloadService.Setup(x => x.DownloadToBytes(METADATA_ARCHIVE_URL).Result).Returns(metadataArchiveContent); - _mockEnvironmentVariableProvider.Setup(m => m.SourceGithubPersonalAccessToken(It.IsAny())).Returns(sourceGithubPat); - _mockEnvironmentVariableProvider.Setup(m => m.TargetGithubPersonalAccessToken(It.IsAny())).Returns(targetGithubPat); + _mockEnvironmentVariableProvider.Setup(m => m.SourceGithubPersonalAccessToken(It.IsAny())).Returns(GITHUB_SOURCE_PAT); + _mockEnvironmentVariableProvider.Setup(m => m.TargetGithubPersonalAccessToken(It.IsAny())).Returns(GITHUB_TARGET_PAT); _mockAwsApi.Setup(m => m.UploadToBucket(awsBucketName, It.IsAny(), It.IsAny())).ReturnsAsync(archiveUrl); @@ -1531,57 +1513,44 @@ await _handler.Invoking(async x => await x.Handle(new MigrateRepoCommandArgs [Fact] public async Task Keep_Archive_Does_Not_Call_DeleteIfExists() { - var githubOrgId = Guid.NewGuid().ToString(); - var migrationSourceId = Guid.NewGuid().ToString(); - var sourceGithubPat = Guid.NewGuid().ToString(); - var targetGithubPat = Guid.NewGuid().ToString(); - var githubRepoUrl = $"https://myghes/{SOURCE_ORG}/{SOURCE_REPO}"; - var migrationId = Guid.NewGuid().ToString(); - var gitArchiveId = 1; - var metadataArchiveId = 2; - var gitArchiveFilePath = "path/to/git_archive"; - var metadataArchiveFilePath = "path/to/metadata_archive"; - - var gitArchiveUrl = $"https://example.com/{gitArchiveId}"; - var metadataArchiveUrl = $"https://example.com/{metadataArchiveId}"; - var authenticatedGitArchiveUrl = new Uri($"https://example.com/{gitArchiveId}/authenticated"); - var authenticatedMetadataArchiveUrl = new Uri($"https://example.com/{metadataArchiveId}/authenticated"); - - _mockTargetGithubApi.Setup(x => x.GetOrganizationId(TARGET_ORG).Result).Returns(githubOrgId); - _mockTargetGithubApi.Setup(x => x.CreateGhecMigrationSource(githubOrgId).Result).Returns(migrationSourceId); + _mockTargetGithubApi.Setup(x => x.GetOrganizationId(TARGET_ORG).Result).Returns(GITHUB_ORG_ID); + _mockTargetGithubApi.Setup(x => x.CreateGhecMigrationSource(GITHUB_ORG_ID).Result).Returns(MIGRATION_SOURCE_ID); _mockTargetGithubApi .Setup(x => x.StartMigration( - migrationSourceId, - githubRepoUrl, - githubOrgId, + MIGRATION_SOURCE_ID, + GHES_REPO_URL, + GITHUB_ORG_ID, TARGET_REPO, - sourceGithubPat, - targetGithubPat, - authenticatedGitArchiveUrl.ToString(), - authenticatedMetadataArchiveUrl.ToString(), + GITHUB_SOURCE_PAT, + GITHUB_TARGET_PAT, + AUTHENTICATED_GIT_ARCHIVE_URL, + AUTHENTICATED_METADATA_ARCHIVE_URL, false, null, false).Result) - .Returns(migrationId); - _mockTargetGithubApi.Setup(x => x.GetMigration(migrationId).Result).Returns((State: RepositoryMigrationStatus.Succeeded, TARGET_REPO, 0, "", "")); + .Returns(MIGRATION_ID); + _mockTargetGithubApi.Setup(x => x.GetMigration(MIGRATION_ID).Result).Returns((State: RepositoryMigrationStatus.Succeeded, TARGET_REPO, 0, "", "")); _mockTargetGithubApi.Setup(x => x.DoesOrgExist(TARGET_ORG).Result).Returns(true); - _mockSourceGithubApi.Setup(x => x.StartGitArchiveGeneration(SOURCE_ORG, SOURCE_REPO).Result).Returns(gitArchiveId); - _mockSourceGithubApi.Setup(x => x.StartMetadataArchiveGeneration(SOURCE_ORG, SOURCE_REPO, false, false).Result).Returns(metadataArchiveId); - _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationStatus(SOURCE_ORG, gitArchiveId).Result).Returns(ArchiveMigrationStatus.Exported); - _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationStatus(SOURCE_ORG, metadataArchiveId).Result).Returns(ArchiveMigrationStatus.Exported); - _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationUrl(SOURCE_ORG, gitArchiveId).Result).Returns(gitArchiveUrl); - _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationUrl(SOURCE_ORG, metadataArchiveId).Result).Returns(metadataArchiveUrl); + _mockSourceGithubApi.Setup(x => x.StartGitArchiveGeneration(SOURCE_ORG, SOURCE_REPO).Result).Returns(GIT_ARCHIVE_ID); + _mockSourceGithubApi.Setup(x => x.StartMetadataArchiveGeneration(SOURCE_ORG, SOURCE_REPO, false, false).Result).Returns(METADATA_ARCHIVE_ID); + _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationStatus(SOURCE_ORG, GIT_ARCHIVE_ID).Result).Returns(ArchiveMigrationStatus.Exported); + _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationStatus(SOURCE_ORG, METADATA_ARCHIVE_ID).Result).Returns(ArchiveMigrationStatus.Exported); + _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationUrl(SOURCE_ORG, GIT_ARCHIVE_ID).Result).Returns(GIT_ARCHIVE_URL); + _mockSourceGithubApi.Setup(x => x.GetArchiveMigrationUrl(SOURCE_ORG, METADATA_ARCHIVE_ID).Result).Returns(METADATA_ARCHIVE_URL); - _mockAzureApi.SetupSequence(x => x.UploadToBlob(It.IsAny(), It.IsAny()).Result).Returns(authenticatedGitArchiveUrl).Returns(authenticatedMetadataArchiveUrl); + _mockAzureApi + .SetupSequence(x => x.UploadToBlob(It.IsAny(), It.IsAny()).Result) + .Returns(new Uri(AUTHENTICATED_GIT_ARCHIVE_URL)) + .Returns(new Uri(AUTHENTICATED_METADATA_ARCHIVE_URL)); _mockFileSystemProvider .SetupSequence(m => m.GetTempFileName()) - .Returns(gitArchiveFilePath) - .Returns(metadataArchiveFilePath); + .Returns(GIT_ARCHIVE_FILE_PATH) + .Returns(METADATA_ARCHIVE_FILE_PATH); - _mockEnvironmentVariableProvider.Setup(m => m.SourceGithubPersonalAccessToken(It.IsAny())).Returns(sourceGithubPat); - _mockEnvironmentVariableProvider.Setup(m => m.TargetGithubPersonalAccessToken(It.IsAny())).Returns(targetGithubPat); + _mockEnvironmentVariableProvider.Setup(m => m.SourceGithubPersonalAccessToken(It.IsAny())).Returns(GITHUB_SOURCE_PAT); + _mockEnvironmentVariableProvider.Setup(m => m.TargetGithubPersonalAccessToken(It.IsAny())).Returns(GITHUB_TARGET_PAT); _mockGhesVersionChecker.Setup(m => m.AreBlobCredentialsRequired(GHES_API_URL)).ReturnsAsync(true); @@ -1597,8 +1566,8 @@ public async Task Keep_Archive_Does_Not_Call_DeleteIfExists() }; await _handler.Handle(args); - _mockFileSystemProvider.Verify(x => x.DeleteIfExists(gitArchiveFilePath), Times.Never); - _mockFileSystemProvider.Verify(x => x.DeleteIfExists(metadataArchiveFilePath), Times.Never); + _mockFileSystemProvider.Verify(x => x.DeleteIfExists(GIT_ARCHIVE_FILE_PATH), Times.Never); + _mockFileSystemProvider.Verify(x => x.DeleteIfExists(METADATA_ARCHIVE_FILE_PATH), Times.Never); } [Fact] diff --git a/src/OctoshiftCLI.Tests/gei/Commands/MigrateRepo/MigrateRepoCommandTests.cs b/src/OctoshiftCLI.Tests/gei/Commands/MigrateRepo/MigrateRepoCommandTests.cs index df42dc8b9..be0fc095c 100644 --- a/src/OctoshiftCLI.Tests/gei/Commands/MigrateRepo/MigrateRepoCommandTests.cs +++ b/src/OctoshiftCLI.Tests/gei/Commands/MigrateRepo/MigrateRepoCommandTests.cs @@ -13,7 +13,7 @@ public void Should_Have_Options() command.Should().NotBeNull(); command.Name.Should().Be("migrate-repo"); - command.Options.Count.Should().Be(24); + command.Options.Count.Should().Be(26); TestHelpers.VerifyCommandOption(command.Options, "github-source-org", true); TestHelpers.VerifyCommandOption(command.Options, "source-repo", true); @@ -31,6 +31,8 @@ public void Should_Have_Options() TestHelpers.VerifyCommandOption(command.Options, "skip-releases", false); TestHelpers.VerifyCommandOption(command.Options, "git-archive-url", false, true); TestHelpers.VerifyCommandOption(command.Options, "metadata-archive-url", false, true); + TestHelpers.VerifyCommandOption(command.Options, "git-archive-path", false, true); + TestHelpers.VerifyCommandOption(command.Options, "metadata-archive-path", false, true); TestHelpers.VerifyCommandOption(command.Options, "queue-only", false); TestHelpers.VerifyCommandOption(command.Options, "target-repo-visibility", false); TestHelpers.VerifyCommandOption(command.Options, "github-source-pat", false); diff --git a/src/gei/Commands/MigrateRepo/MigrateRepoCommand.cs b/src/gei/Commands/MigrateRepo/MigrateRepoCommand.cs index 1009c37b7..a0ce2d47e 100644 --- a/src/gei/Commands/MigrateRepo/MigrateRepoCommand.cs +++ b/src/gei/Commands/MigrateRepo/MigrateRepoCommand.cs @@ -21,7 +21,6 @@ public MigrateRepoCommand() : base( AddOption(GithubTargetOrg); AddOption(TargetRepo); AddOption(TargetApiUrl); - AddOption(GhesApiUrl); AddOption(AzureStorageConnectionString); AddOption(AwsBucketName); @@ -30,13 +29,12 @@ public MigrateRepoCommand() : base( AddOption(AwsSessionToken); AddOption(AwsRegion); AddOption(NoSslVerify); - AddOption(GitArchiveUrl); AddOption(MetadataArchiveUrl); - + AddOption(GitArchivePath); + AddOption(MetadataArchivePath); AddOption(SkipReleases); AddOption(LockSourceRepo); - AddOption(QueueOnly); AddOption(TargetRepoVisibility.FromAmong("public", "private", "internal")); AddOption(GithubSourcePat); @@ -120,6 +118,16 @@ public MigrateRepoCommand() : base( IsHidden = true, Description = "An authenticated SAS URL to an Azure Blob Storage container with a pre-generated metadata archive. Only used when an archive has been generated and uploaded prior to running a migration (not common). Must be passed in when also using --git-archive-url" }; + public Option GitArchivePath { get; } = new("--git-archive-path") + { + IsHidden = true, + Description = "Used to migrate an archive that is on disk, must be used with --metadata-archive-path" + }; + public Option MetadataArchivePath { get; } = new("--metadata-archive-path") + { + IsHidden = true, + Description = "Used to migrate an archive that is on disk, must be used with --git-archive-path" + }; public Option SkipReleases { get; } = new("--skip-releases") { Description = "Skip releases when migrating." @@ -171,7 +179,7 @@ public override MigrateRepoCommandHandler BuildHandler(MigrateRepoCommandArgs ar AwsApi awsApi = null; HttpDownloadService httpDownloadService = null; - if (args.GhesApiUrl.HasValue()) + if (args.GhesApiUrl.HasValue() || (args.GitArchivePath.HasValue() && args.MetadataArchivePath.HasValue())) { var sourceGithubApiFactory = sp.GetRequiredService(); var awsApiFactory = sp.GetRequiredService(); diff --git a/src/gei/Commands/MigrateRepo/MigrateRepoCommandArgs.cs b/src/gei/Commands/MigrateRepo/MigrateRepoCommandArgs.cs index 73d02c8e3..2287af0fb 100644 --- a/src/gei/Commands/MigrateRepo/MigrateRepoCommandArgs.cs +++ b/src/gei/Commands/MigrateRepo/MigrateRepoCommandArgs.cs @@ -25,6 +25,8 @@ public class MigrateRepoCommandArgs : CommandArgs public bool NoSslVerify { get; set; } public string GitArchiveUrl { get; set; } public string MetadataArchiveUrl { get; set; } + public string GitArchivePath { get; set; } + public string MetadataArchivePath { get; set; } public bool SkipReleases { get; set; } public bool LockSourceRepo { get; set; } public bool QueueOnly { get; set; } @@ -41,11 +43,26 @@ public override void Validate(OctoLogger log) DefaultSourcePat(log); DefaultTargetRepo(log); + if (GitArchiveUrl.HasValue() && GitArchivePath.HasValue()) + { + throw new OctoshiftCliException("The options --git-archive-url and --git-archive-path may not be used together"); + } + + if (MetadataArchiveUrl.HasValue() && MetadataArchivePath.HasValue()) + { + throw new OctoshiftCliException("The options --metadata-archive-url and --metadata-archive-path may not be used together"); + } + if (string.IsNullOrWhiteSpace(GitArchiveUrl) != string.IsNullOrWhiteSpace(MetadataArchiveUrl)) { throw new OctoshiftCliException("When using archive urls, you must provide both --git-archive-url --metadata-archive-url"); } + if (string.IsNullOrWhiteSpace(GitArchivePath) != string.IsNullOrWhiteSpace(MetadataArchivePath)) + { + throw new OctoshiftCliException("When using archive files, you must provide both --git-archive-path --metadata-archive-path"); + } + if (GhesApiUrl.IsNullOrWhiteSpace()) { if (AwsBucketName.HasValue()) diff --git a/src/gei/Commands/MigrateRepo/MigrateRepoCommandHandler.cs b/src/gei/Commands/MigrateRepo/MigrateRepoCommandHandler.cs index 0eb1acc2d..875c4f94f 100644 --- a/src/gei/Commands/MigrateRepo/MigrateRepoCommandHandler.cs +++ b/src/gei/Commands/MigrateRepo/MigrateRepoCommandHandler.cs @@ -27,6 +27,7 @@ public class MigrateRepoCommandHandler : ICommandHandler private const int CHECK_STATUS_DELAY_IN_MILLISECONDS = 10000; // 10 seconds private const string GIT_ARCHIVE_FILE_NAME = "git_archive.tar.gz"; private const string METADATA_ARCHIVE_FILE_NAME = "metadata_archive.tar.gz"; + private const string DUPLICATE_ARCHIVE_FILE_NAME = "archive.tar.gz"; private const string DEFAULT_GITHUB_BASE_URL = "https://github.com"; public MigrateRepoCommandHandler( @@ -121,6 +122,32 @@ public async Task Handle(MigrateRepoCommandArgs args) _log.LogInformation("Archives uploaded to blob storage, now starting migration..."); } } + else if (args.GitArchivePath.HasValue() && args.MetadataArchivePath.HasValue()) + { + var timeNow = $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss}"; + var gitArchiveUploadFileName = $"{timeNow}-{GIT_ARCHIVE_FILE_NAME}"; + var metadataArchiveUploadFileName = $"{timeNow}-{METADATA_ARCHIVE_FILE_NAME}"; + var duplicateArchiveUploadFileName = $"{timeNow}-{DUPLICATE_ARCHIVE_FILE_NAME}"; + var shouldUploadOnce = args.GitArchivePath == args.MetadataArchivePath; + + args.GitArchiveUrl = await UploadArchive( + args.GithubSourceOrg, + args.AwsBucketName, + args.UseGithubStorage, + args.GitArchivePath, + shouldUploadOnce ? duplicateArchiveUploadFileName : gitArchiveUploadFileName); + + args.MetadataArchiveUrl = shouldUploadOnce + ? args.GitArchiveUrl + : await UploadArchive( + args.GithubSourceOrg, + args.AwsBucketName, + args.UseGithubStorage, + args.MetadataArchivePath, + metadataArchiveUploadFileName); + + _log.LogInformation("Archive(s) uploaded to blob storage, now starting migration..."); + } var sourceRepoUrl = GetSourceRepoUrl(args); var sourceToken = GetSourceToken(args); @@ -192,8 +219,8 @@ public async Task Handle(MigrateRepoCommandArgs args) private string ExtractGhesBaseUrl(string ghesApiUrl) { // We expect the GHES url template to be either http(s)://hostname/api/v3 or http(s)://api.hostname.com. - // We are either going to be able to extract and return the base url based on the above templates or - // will fallback to ghesApiUrl and return it as the base url. + // We are either going to be able to extract and return the base url based on the above templates or + // will fallback to ghesApiUrl and return it as the base url. ghesApiUrl = ghesApiUrl.Trim().TrimEnd('/'); @@ -219,7 +246,7 @@ private string ExtractGhesBaseUrl(string ghesApiUrl) bool useGithubStorage) { var (gitArchiveUrl, metadataArchiveUrl, gitArchiveId, metadataArchiveId) = await _retryPolicy.Retry( - async () => await GenerateArchive(githubSourceOrg, sourceRepo, skipReleases, lockSourceRepo)); + async () => await GenerateArchives(githubSourceOrg, sourceRepo, skipReleases, lockSourceRepo)); if (!useGithubStorage && !blobCredentialsRequired) { @@ -235,47 +262,25 @@ private string ExtractGhesBaseUrl(string ghesApiUrl) { _log.LogInformation($"Downloading archive from {gitArchiveUrl}"); await _httpDownloadService.DownloadToFile(gitArchiveUrl, gitArchiveDownloadFilePath); + _log.LogInformation("Download complete"); _log.LogInformation($"Downloading archive from {metadataArchiveUrl}"); await _httpDownloadService.DownloadToFile(metadataArchiveUrl, metadataArchiveDownloadFilePath); - -#pragma warning disable IDE0063 - await using (var gitArchiveContent = _fileSystemProvider.OpenRead(gitArchiveDownloadFilePath)) - await using (var metadataArchiveContent = _fileSystemProvider.OpenRead(metadataArchiveDownloadFilePath)) -#pragma warning restore IDE0063 - { - if (useGithubStorage) - { - return await UploadArchivesToGithub( - githubTargetOrg, - gitArchiveUploadFileName, - gitArchiveContent, - metadataArchiveUploadFileName, - metadataArchiveContent - ); - } -#pragma warning disable IDE0046 - else if (_awsApi.HasValue()) -#pragma warning restore IDE0046 - { - return await UploadArchivesToAws( - awsBucketName, - gitArchiveUploadFileName, - gitArchiveContent, - metadataArchiveUploadFileName, - metadataArchiveContent - ); - } - else - { - return await UploadArchivesToAzure( - gitArchiveUploadFileName, - gitArchiveContent, - metadataArchiveUploadFileName, - metadataArchiveContent - ); - } - } + _log.LogInformation("Download complete"); + + return ( + await UploadArchive( + githubTargetOrg, + awsBucketName, + useGithubStorage, + gitArchiveDownloadFilePath, + gitArchiveUploadFileName), + await UploadArchive( + githubTargetOrg, + awsBucketName, + useGithubStorage, + metadataArchiveDownloadFilePath, + metadataArchiveUploadFileName)); } finally { @@ -287,7 +292,31 @@ private string ExtractGhesBaseUrl(string ghesApiUrl) } } - private async Task<(string GitArchiveUrl, string MetadataArchiveUrl, int GitArchiveId, int MetadataArchiveId)> GenerateArchive( + private async Task UploadArchive( + string githubTargetOrg, + string awsBucketName, + bool useGithubStorage, + string archiveDownloadFilePath, + string archiveUploadFileName) + { + await using var archiveContent = _fileSystemProvider.OpenRead(archiveDownloadFilePath); + + if (useGithubStorage) + { + return await UploadArchiveToGithub(githubTargetOrg, archiveUploadFileName, archiveContent); + } + +#pragma warning disable IDE0046 + if (_awsApi.HasValue()) +#pragma warning restore IDE0046 + { + return await UploadArchiveToAws(awsBucketName, archiveUploadFileName, archiveContent); + } + + return await UploadArchiveToAzure(archiveUploadFileName, archiveContent); + } + + private async Task<(string GitArchiveUrl, string MetadataArchiveUrl, int GitArchiveId, int MetadataArchiveId)> GenerateArchives( string githubSourceOrg, string sourceRepo, bool skipReleases, @@ -322,37 +351,33 @@ private void DeleteArchive(string path) } } - private async Task<(string, string)> UploadArchivesToAzure(string gitArchiveFileName, Stream gitArchiveContent, string metadataArchiveFileName, Stream metadataArchiveContent) + private async Task UploadArchiveToAzure(string archiveFileName, Stream archiveContent) { - _log.LogInformation($"Uploading archive {gitArchiveFileName} to Azure Blob Storage"); - var authenticatedGitArchiveUri = await _azureApi.UploadToBlob(gitArchiveFileName, gitArchiveContent); - _log.LogInformation($"Uploading archive {metadataArchiveFileName} to Azure Blob Storage"); - var authenticatedMetadataArchiveUri = await _azureApi.UploadToBlob(metadataArchiveFileName, metadataArchiveContent); + _log.LogInformation($"Uploading archive {archiveFileName} to Azure Blob Storage"); + var authenticatedArchiveUri = await _azureApi.UploadToBlob(archiveFileName, archiveContent); + _log.LogInformation("Upload complete"); - return (authenticatedGitArchiveUri.ToString(), authenticatedMetadataArchiveUri.ToString()); + return authenticatedArchiveUri.ToString(); } - private async Task<(string, string)> UploadArchivesToAws(string bucketName, string gitArchiveFileName, Stream gitArchiveContent, string metadataArchiveFileName, Stream metadataArchiveContent) + private async Task UploadArchiveToAws(string bucketName, string archiveFileName, Stream archiveContent) { - _log.LogInformation($"Uploading archive {gitArchiveFileName} to AWS S3"); - var authenticatedGitArchiveUri = await _awsApi.UploadToBucket(bucketName, gitArchiveContent, gitArchiveFileName); - _log.LogInformation($"Uploading archive {metadataArchiveFileName} to AWS S3"); - var authenticatedMetadataArchiveUri = await _awsApi.UploadToBucket(bucketName, metadataArchiveContent, metadataArchiveFileName); + _log.LogInformation($"Uploading archive {archiveFileName} to AWS S3"); + var authenticatedArchiveUri = await _awsApi.UploadToBucket(bucketName, archiveContent, archiveFileName); + _log.LogInformation("Upload complete"); - return (authenticatedGitArchiveUri.ToString(), authenticatedMetadataArchiveUri.ToString()); + return authenticatedArchiveUri.ToString(); } - private async Task<(string, string)> UploadArchivesToGithub(string org, string gitArchiveUploadFileName, Stream gitArchiveContent, string metadataArchiveUploadFileName, Stream metadataArchiveContent) + private async Task UploadArchiveToGithub(string org, string archiveFileName, Stream archiveContent) { var githubOrgDatabaseId = await _targetGithubApi.GetOrganizationDatabaseId(org); - _log.LogInformation($"Uploading git archive to GitHub Storage"); - var uploadedGitArchiveUrl = await _targetGithubApi.UploadArchiveToGithubStorage(githubOrgDatabaseId, gitArchiveUploadFileName, gitArchiveContent); - - _log.LogInformation($"Uploading metadata archive to GitHub Storage"); - var uploadedMetadataArchiveUrl = await _targetGithubApi.UploadArchiveToGithubStorage(githubOrgDatabaseId, metadataArchiveUploadFileName, metadataArchiveContent); + _log.LogInformation($"Uploading archive {archiveFileName} to GitHub Storage"); + var uploadedArchiveUrl = await _targetGithubApi.UploadArchiveToGithubStorage(githubOrgDatabaseId, archiveFileName, archiveContent); + _log.LogInformation("Upload complete"); - return (uploadedGitArchiveUrl, uploadedMetadataArchiveUrl); + return uploadedArchiveUrl; } private async Task WaitForArchiveGeneration(GithubApi githubApi, string githubSourceOrg, int archiveId)