diff --git a/RELEASENOTES.md b/RELEASENOTES.md index e7dc4f70..b2092bec 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1 +1,2 @@ - Add progress report to `gh [gei|bbs2gh] migrate-repo` command when uploading migration archives to Azure Blob or AWS S3 +- `gh gei migrate-repo` now allows using either `--ghes-api-url` or archive paths (`--git-archive-path` and `--metadata-archive-path`). diff --git a/src/OctoshiftCLI.Tests/gei/Commands/MigrateRepo/MigrateRepoCommandArgsTests.cs b/src/OctoshiftCLI.Tests/gei/Commands/MigrateRepo/MigrateRepoCommandArgsTests.cs index c1da1e2f..ae8b994b 100644 --- a/src/OctoshiftCLI.Tests/gei/Commands/MigrateRepo/MigrateRepoCommandArgsTests.cs +++ b/src/OctoshiftCLI.Tests/gei/Commands/MigrateRepo/MigrateRepoCommandArgsTests.cs @@ -55,7 +55,77 @@ public void It_Falls_Back_To_Github_Target_Pat_If_Github_Source_Pat_Is_Not_Provi } [Fact] - public void Aws_Bucket_Name_Without_Ghes_Api_Url_Throws() + public void AwsBucketName_Validates_With_GhesApiUrl() + { + var args = new MigrateRepoCommandArgs + { + GithubSourceOrg = SOURCE_ORG, + SourceRepo = SOURCE_REPO, + GithubTargetOrg = TARGET_ORG, + AwsBucketName = AWS_BUCKET_NAME, + GhesApiUrl = GHES_API_URL + }; + + args.Validate(_mockOctoLogger.Object); + + args.TargetRepo.Should().Be(SOURCE_REPO); + } + + [Fact] + public void AwsBucketName_Validates_With_ArchivePaths() + { + var args = new MigrateRepoCommandArgs + { + GithubSourceOrg = SOURCE_ORG, + SourceRepo = SOURCE_REPO, + GithubTargetOrg = TARGET_ORG, + AwsBucketName = AWS_BUCKET_NAME, + GitArchivePath = GIT_ARCHIVE_PATH, + MetadataArchivePath = METADATA_ARCHIVE_PATH + }; + + args.Validate(_mockOctoLogger.Object); + + args.TargetRepo.Should().Be(SOURCE_REPO); + } + + [Fact] + public void UseGithubStorage_Validates_With_GhesApiUrl() + { + var args = new MigrateRepoCommandArgs + { + GithubSourceOrg = SOURCE_ORG, + SourceRepo = SOURCE_REPO, + GithubTargetOrg = TARGET_ORG, + GhesApiUrl = GHES_API_URL, + UseGithubStorage = true + }; + + args.Validate(_mockOctoLogger.Object); + + args.TargetRepo.Should().Be(SOURCE_REPO); + } + + [Fact] + public void UseGithubStorage_Validates_With_ArchivePaths() + { + var args = new MigrateRepoCommandArgs + { + GithubSourceOrg = SOURCE_ORG, + SourceRepo = SOURCE_REPO, + GithubTargetOrg = TARGET_ORG, + GitArchivePath = GIT_ARCHIVE_PATH, + MetadataArchivePath = METADATA_ARCHIVE_PATH, + UseGithubStorage = true + }; + + args.Validate(_mockOctoLogger.Object); + + args.TargetRepo.Should().Be(SOURCE_REPO); + } + + [Fact] + public void Aws_Bucket_Name_Without_GhesApiUrl_Or_ArchivePaths_Throws() { var args = new MigrateRepoCommandArgs { @@ -73,7 +143,7 @@ public void Aws_Bucket_Name_Without_Ghes_Api_Url_Throws() } [Fact] - public void UseGithubStorage_Without_Ghes_Api_Url_Throws() + public void UseGithubStorage_Without_GhesApiUrl_Or_ArchivePaths_Throws() { var args = new MigrateRepoCommandArgs { diff --git a/src/OctoshiftCLI.Tests/gei/Commands/MigrateRepo/MigrateRepoCommandHandlerTests.cs b/src/OctoshiftCLI.Tests/gei/Commands/MigrateRepo/MigrateRepoCommandHandlerTests.cs index d9c5c2b9..a8836c91 100644 --- a/src/OctoshiftCLI.Tests/gei/Commands/MigrateRepo/MigrateRepoCommandHandlerTests.cs +++ b/src/OctoshiftCLI.Tests/gei/Commands/MigrateRepo/MigrateRepoCommandHandlerTests.cs @@ -1510,6 +1510,175 @@ await _handler.Invoking(async x => await x.Handle(new MigrateRepoCommandArgs .WithMessage("*AWS S3*--aws-bucket-name*"); } + [Fact] + public async Task GitArchivePath_With_Both_Azure_Storage_Connection_String_And_Aws_Bucket_Name_Throws() + { + _mockGhesVersionChecker.Setup(m => m.AreBlobCredentialsRequired(GHES_API_URL)).ReturnsAsync(true); + + await _handler.Invoking(async x => await x.Handle(new MigrateRepoCommandArgs + { + SourceRepo = SOURCE_REPO, + GithubSourceOrg = SOURCE_ORG, + GithubTargetOrg = TARGET_ORG, + TargetRepo = TARGET_REPO, + GitArchivePath = GIT_ARCHIVE_FILE_PATH, + MetadataArchivePath = METADATA_ARCHIVE_FILE_PATH, + AzureStorageConnectionString = AZURE_CONNECTION_STRING, + AwsBucketName = AWS_BUCKET_NAME + })) + .Should() + .ThrowAsync(); + } + + [Fact] + public async Task GitArchivePath_When_Aws_Bucket_Name_Is_Provided_But_No_Aws_Access_Key_Id_Throws() + { + _mockGhesVersionChecker.Setup(m => m.AreBlobCredentialsRequired(GHES_API_URL)).ReturnsAsync(true); + + await _handler.Invoking(async x => await x.Handle(new MigrateRepoCommandArgs + { + SourceRepo = SOURCE_REPO, + GithubSourceOrg = SOURCE_ORG, + GithubTargetOrg = TARGET_ORG, + TargetRepo = TARGET_REPO, + GitArchivePath = GIT_ARCHIVE_FILE_PATH, + MetadataArchivePath = METADATA_ARCHIVE_FILE_PATH, + AwsBucketName = AWS_BUCKET_NAME, + AwsSecretKey = AWS_SECRET_ACCESS_KEY + })) + .Should() + .ThrowAsync() + .WithMessage("*--aws-access-key*"); + } + + [Fact] + public async Task GitArchivePath_When_Aws_Bucket_Name_Is_Provided_But_No_Aws_Secret_Key_Throws() + { + _mockGhesVersionChecker.Setup(m => m.AreBlobCredentialsRequired(GHES_API_URL)).ReturnsAsync(true); + + await _handler.Invoking(async x => await x.Handle(new MigrateRepoCommandArgs + { + SourceRepo = SOURCE_REPO, + GithubSourceOrg = SOURCE_ORG, + GithubTargetOrg = TARGET_ORG, + TargetRepo = TARGET_REPO, + GitArchivePath = GIT_ARCHIVE_FILE_PATH, + MetadataArchivePath = METADATA_ARCHIVE_FILE_PATH, + AwsBucketName = AWS_BUCKET_NAME, + AwsAccessKey = AWS_ACCESS_KEY_ID + })) + .Should() + .ThrowAsync() + .WithMessage("*--aws-secret-key*"); + } + + [Fact] + public async Task GitArchivePath_When_Aws_Bucket_Name_Is_Provided_But_No_Aws_Region_Throws() + { + _mockGhesVersionChecker.Setup(m => m.AreBlobCredentialsRequired(GHES_API_URL)).ReturnsAsync(true); + + await _handler.Invoking(async x => await x.Handle(new MigrateRepoCommandArgs + { + SourceRepo = SOURCE_REPO, + GithubSourceOrg = SOURCE_ORG, + GithubTargetOrg = TARGET_ORG, + TargetRepo = TARGET_REPO, + GitArchivePath = GIT_ARCHIVE_FILE_PATH, + MetadataArchivePath = METADATA_ARCHIVE_FILE_PATH, + AwsBucketName = AWS_BUCKET_NAME, + AwsAccessKey = AWS_ACCESS_KEY_ID, + AwsSecretKey = AWS_SECRET_ACCESS_KEY, + AwsSessionToken = AWS_SESSION_TOKEN + })) + .Should() + .ThrowAsync() + .WithMessage("Either --aws-region or AWS_REGION environment variable must be set."); + } + + [Fact] + public async Task GitArchivePath_When_Aws_Bucket_Name_Not_Provided_But_Aws_Access_Key_Provided() + { + _mockGhesVersionChecker.Setup(m => m.AreBlobCredentialsRequired(GHES_API_URL)).ReturnsAsync(true); + + await _handler.Invoking(async x => await x.Handle(new MigrateRepoCommandArgs + { + SourceRepo = SOURCE_REPO, + GithubSourceOrg = SOURCE_ORG, + GithubTargetOrg = TARGET_ORG, + TargetRepo = TARGET_REPO, + GitArchivePath = GIT_ARCHIVE_FILE_PATH, + MetadataArchivePath = METADATA_ARCHIVE_FILE_PATH, + AzureStorageConnectionString = AZURE_CONNECTION_STRING, + AwsAccessKey = AWS_ACCESS_KEY_ID + })) + .Should() + .ThrowAsync() + .WithMessage("*AWS S3*--aws-bucket-name*"); + } + + [Fact] + public async Task GitArchivePath_When_Aws_Bucket_Name_Not_Provided_But_Aws_Secret_Key_Provided() + { + _mockGhesVersionChecker.Setup(m => m.AreBlobCredentialsRequired(GHES_API_URL)).ReturnsAsync(true); + + await _handler.Invoking(async x => await x.Handle(new MigrateRepoCommandArgs + { + SourceRepo = SOURCE_REPO, + GithubSourceOrg = SOURCE_ORG, + GithubTargetOrg = TARGET_ORG, + TargetRepo = TARGET_REPO, + GitArchivePath = GIT_ARCHIVE_FILE_PATH, + MetadataArchivePath = METADATA_ARCHIVE_FILE_PATH, + AzureStorageConnectionString = AZURE_CONNECTION_STRING, + AwsSecretKey = AWS_SECRET_ACCESS_KEY + })) + .Should() + .ThrowAsync() + .WithMessage("*AWS S3*--aws-bucket-name*"); + } + + [Fact] + public async Task GitArchivePath_When_Aws_Bucket_Name_Not_Provided_But_Aws_Session_Token_Provided() + { + _mockGhesVersionChecker.Setup(m => m.AreBlobCredentialsRequired(GHES_API_URL)).ReturnsAsync(true); + + await _handler.Invoking(async x => await x.Handle(new MigrateRepoCommandArgs + { + SourceRepo = SOURCE_REPO, + GithubSourceOrg = SOURCE_ORG, + GithubTargetOrg = TARGET_ORG, + TargetRepo = TARGET_REPO, + GitArchivePath = GIT_ARCHIVE_FILE_PATH, + MetadataArchivePath = METADATA_ARCHIVE_FILE_PATH, + AzureStorageConnectionString = AZURE_CONNECTION_STRING, + AwsSessionToken = AWS_SECRET_ACCESS_KEY + })) + .Should() + .ThrowAsync() + .WithMessage("*AWS S3*--aws-bucket-name*"); + } + + [Fact] + public async Task GitArchivePath_When_Aws_Bucket_Name_Not_Provided_But_Aws_Region_Provided() + { + _mockGhesVersionChecker.Setup(m => m.AreBlobCredentialsRequired(GHES_API_URL)).ReturnsAsync(true); + + await _handler.Invoking(async x => await x.Handle(new MigrateRepoCommandArgs + { + SourceRepo = SOURCE_REPO, + GithubSourceOrg = SOURCE_ORG, + GithubTargetOrg = TARGET_ORG, + TargetRepo = TARGET_REPO, + GitArchivePath = GIT_ARCHIVE_FILE_PATH, + MetadataArchivePath = METADATA_ARCHIVE_FILE_PATH, + AzureStorageConnectionString = AZURE_CONNECTION_STRING, + AwsRegion = AWS_REGION + })) + .Should() + .ThrowAsync() + .WithMessage("*AWS S3*--aws-bucket-name*"); + } + [Fact] public async Task Keep_Archive_Does_Not_Call_DeleteIfExists() { diff --git a/src/gei/Commands/MigrateRepo/MigrateRepoCommandArgs.cs b/src/gei/Commands/MigrateRepo/MigrateRepoCommandArgs.cs index 2287af0f..a8e148af 100644 --- a/src/gei/Commands/MigrateRepo/MigrateRepoCommandArgs.cs +++ b/src/gei/Commands/MigrateRepo/MigrateRepoCommandArgs.cs @@ -65,9 +65,14 @@ public override void Validate(OctoLogger log) if (GhesApiUrl.IsNullOrWhiteSpace()) { - if (AwsBucketName.HasValue()) + if (AwsBucketName.HasValue() && GitArchivePath.IsNullOrWhiteSpace()) { - throw new OctoshiftCliException("--ghes-api-url must be specified when --aws-bucket-name is specified."); + throw new OctoshiftCliException("When using --aws-bucket-name, you must provide --ghes-api-url, or --git-archive-path and --metadata-archive-path"); + } + + if (UseGithubStorage && GitArchivePath.IsNullOrWhiteSpace()) + { + throw new OctoshiftCliException("When using --use-github-storage, you must provide --ghes-api-url, or --git-archive-path and --metadata-archive-path"); } if (NoSslVerify) @@ -79,10 +84,6 @@ public override void Validate(OctoLogger log) { throw new OctoshiftCliException("--ghes-api-url must be specified when --keep-archive is specified."); } - if (UseGithubStorage) - { - throw new OctoshiftCliException("--ghes-api-url must be specified when --use-github-storage is specified."); - } } if (AwsBucketName.HasValue() && UseGithubStorage) diff --git a/src/gei/Commands/MigrateRepo/MigrateRepoCommandHandler.cs b/src/gei/Commands/MigrateRepo/MigrateRepoCommandHandler.cs index 23c70efb..10192d3a 100644 --- a/src/gei/Commands/MigrateRepo/MigrateRepoCommandHandler.cs +++ b/src/gei/Commands/MigrateRepo/MigrateRepoCommandHandler.cs @@ -65,11 +65,11 @@ public async Task Handle(MigrateRepoCommandArgs args) _log.LogInformation("Migrating Repo..."); - var blobCredentialsRequired = await _ghesVersionChecker.AreBlobCredentialsRequired(args.GhesApiUrl); + var blobCredentialsRequired = args.GitArchivePath.HasValue() || await _ghesVersionChecker.AreBlobCredentialsRequired(args.GhesApiUrl); - if (args.GhesApiUrl.HasValue()) + if (args.GhesApiUrl.HasValue() || args.GitArchivePath.HasValue()) { - ValidateGHESOptions(args, blobCredentialsRequired); + ValidateUploadOptions(args, blobCredentialsRequired); } if (args.GhesApiUrl.HasValue()) @@ -402,7 +402,7 @@ private async Task WaitForArchiveGeneration(GithubApi githubApi, string private string GetGithubRepoUrl(string org, string repo, string baseUrl) => $"{baseUrl ?? DEFAULT_GITHUB_BASE_URL}/{org.EscapeDataString()}/{repo.EscapeDataString()}"; - private void ValidateGHESOptions(MigrateRepoCommandArgs args, bool cloudCredentialsRequired) + private void ValidateUploadOptions(MigrateRepoCommandArgs args, bool cloudCredentialsRequired) { var shouldUseAzureStorage = GetAzureStorageConnectionString(args).HasValue(); var shouldUseAwsS3 = args.AwsBucketName.HasValue();