Skip to content

Commit

Permalink
Merge pull request #1087 from github/timrogers/fix-1086
Browse files Browse the repository at this point in the history
Fail fast if the target GitHub repo already exists in `bbs2gh migrate-repo`
  • Loading branch information
timrogers authored Aug 2, 2023
2 parents e87b3cc + 066c34e commit ff8d368
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 1 deletion.
1 change: 1 addition & 0 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
- __BREAKING CHANGE__: Drop deprecated `--wait` option for `migrate-repo` and `migrate-org` commands
- Allow Enterprise Managed Users (EMU) organizations to skip the invitation process in the `reclaim-mannequin` command with the `--skip-invitation` option
- Fix target repo existence check in GitHub Enterprise Server migrations so it doesn't error if the target repo used to exist, but has been renamed
- Fail fast if the target GitHub repo already exists in `bbs2gh migrate-repo`
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ public async Task Happy_Path_Generate_Only()
BBS_PROJECT,
BBS_REPO
));

_mockGithubApi.Verify(m => m.DoesRepoExist(It.IsAny<string>(), It.IsAny<string>()), Times.Never);
}

[Fact]
Expand All @@ -116,14 +118,15 @@ public async Task Happy_Path_Generate_And_Download()

// Assert
_mockBbsArchiveDownloader.Verify(m => m.Download(BBS_EXPORT_ID, It.IsAny<string>()));
_mockGithubApi.Verify(m => m.DoesRepoExist(It.IsAny<string>(), It.IsAny<string>()), Times.Never);
}

[Fact]
public async Task Happy_Path_Ingest_Only()
{
// Arrange
_mockEnvironmentVariableProvider.Setup(m => m.TargetGithubPersonalAccessToken(It.IsAny<bool>())).Returns(GITHUB_PAT);

_mockGithubApi.Setup(x => x.DoesRepoExist(GITHUB_ORG, GITHUB_REPO).Result).Returns(false);
_mockGithubApi.Setup(x => x.GetOrganizationId(GITHUB_ORG).Result).Returns(GITHUB_ORG_ID);
_mockGithubApi.Setup(x => x.CreateBbsMigrationSource(GITHUB_ORG_ID).Result).Returns(MIGRATION_SOURCE_ID);

Expand Down Expand Up @@ -153,6 +156,7 @@ public async Task Happy_Path_Ingest_Only()
public async Task Happy_Path_Generate_Archive_Ssh_Download_Azure_Upload_And_Ingest()
{
// Arrange
_mockGithubApi.Setup(x => x.DoesRepoExist(GITHUB_ORG, GITHUB_REPO).Result).Returns(false);
_mockBbsApi.Setup(x => x.StartExport(BBS_PROJECT, BBS_REPO)).ReturnsAsync(BBS_EXPORT_ID);
_mockBbsApi.Setup(x => x.GetExport(BBS_EXPORT_ID)).ReturnsAsync(("COMPLETED", "The export is complete", 100));
_mockBbsArchiveDownloader.Setup(x => x.Download(BBS_EXPORT_ID, It.IsAny<string>())).ReturnsAsync(ARCHIVE_PATH);
Expand Down Expand Up @@ -195,6 +199,7 @@ public async Task Happy_Path_Generate_Archive_Ssh_Download_Azure_Upload_And_Inge
public async Task Happy_Path_Generate_Archive_Ssh_Download_Aws_Upload_And_Ingest()
{
// Arrange
_mockGithubApi.Setup(x => x.DoesRepoExist(GITHUB_ORG, GITHUB_REPO).Result).Returns(false);
_mockBbsApi.Setup(x => x.StartExport(BBS_PROJECT, BBS_REPO)).ReturnsAsync(BBS_EXPORT_ID);
_mockBbsApi.Setup(x => x.GetExport(BBS_EXPORT_ID)).ReturnsAsync(("COMPLETED", "The export is complete", 100));
_mockBbsArchiveDownloader.Setup(x => x.Download(BBS_EXPORT_ID, It.IsAny<string>())).ReturnsAsync(ARCHIVE_PATH);
Expand Down Expand Up @@ -242,6 +247,7 @@ public async Task Happy_Path_Full_Flow_Running_On_Bbs_Server()
const string bbsSharedHome = "bbs-shared-home";
var archivePath = $"{bbsSharedHome}/data/migration/export/Bitbucket_export_{BBS_EXPORT_ID}.tar";

_mockGithubApi.Setup(x => x.DoesRepoExist(GITHUB_ORG, GITHUB_REPO).Result).Returns(false);
_mockBbsApi.Setup(x => x.StartExport(BBS_PROJECT, BBS_REPO)).ReturnsAsync(BBS_EXPORT_ID);
_mockBbsApi.Setup(x => x.GetExport(BBS_EXPORT_ID)).ReturnsAsync(("COMPLETED", "The export is complete", 100));
_mockAzureApi.Setup(x => x.UploadToBlob(It.IsAny<string>(), It.IsAny<FileStream>())).ReturnsAsync(new Uri(ARCHIVE_URL));
Expand Down Expand Up @@ -296,6 +302,7 @@ public async Task Happy_Path_Full_Flow_Bbs_Credentials_Via_Environment()
// Arrange
_mockEnvironmentVariableProvider.Setup(m => m.BbsUsername(It.IsAny<bool>())).Returns(BBS_USERNAME);
_mockEnvironmentVariableProvider.Setup(m => m.BbsPassword(It.IsAny<bool>())).Returns(BBS_PASSWORD);
_mockGithubApi.Setup(x => x.DoesRepoExist(GITHUB_ORG, GITHUB_REPO).Result).Returns(false);
_mockBbsApi.Setup(x => x.StartExport(BBS_PROJECT, BBS_REPO)).ReturnsAsync(BBS_EXPORT_ID);
_mockBbsApi.Setup(x => x.GetExport(BBS_EXPORT_ID)).ReturnsAsync(("COMPLETED", "The export is complete", 100));
_mockBbsArchiveDownloader.Setup(x => x.Download(BBS_EXPORT_ID, It.IsAny<string>())).ReturnsAsync(ARCHIVE_PATH);
Expand Down Expand Up @@ -428,6 +435,36 @@ public async Task Happy_Path_Does_Not_Throw_If_Fails_To_Delete_Downloaded_Archiv
_mockFileSystemProvider.Verify(x => x.DeleteIfExists(ARCHIVE_PATH));
}

[Fact]
public async Task Dont_Generate_Archive_If_Target_Repo_Exists()
{
// Arrange
_mockGithubApi.Setup(x => x.DoesRepoExist(GITHUB_ORG, GITHUB_REPO)).ReturnsAsync(true);

// Act
var args = new MigrateRepoCommandArgs
{
BbsServerUrl = BBS_SERVER_URL,
BbsUsername = BBS_USERNAME,
BbsPassword = BBS_PASSWORD,
BbsProject = BBS_PROJECT,
BbsRepo = BBS_REPO,
SshUser = SSH_USER,
SshPrivateKey = PRIVATE_KEY,
AzureStorageConnectionString = AZURE_STORAGE_CONNECTION_STRING,
GithubOrg = GITHUB_ORG,
GithubRepo = GITHUB_REPO,
GithubPat = GITHUB_PAT,
QueueOnly = true,
};

await FluentActions
.Invoking(async () => await _handler.Handle(args)).Should().ThrowExactlyAsync<OctoshiftCliException>();

// Assert
_mockBbsApi.Verify(x => x.StartExport(It.IsAny<string>(), It.IsAny<string>()), Times.Never);
}

[Fact]
public async Task Uses_GitHub_Pat_When_Provided_As_Option()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,79 @@ public async Task Happy_Path_GithubSource_Ghes()
_mockFileSystemProvider.Verify(x => x.DeleteIfExists(metadataArchiveFilePath), 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.StartMigration(
migrationSourceId,
githubRepoUrl,
githubOrgId,
TARGET_REPO,
sourceGithubPat,
targetGithubPat,
authenticatedGitArchiveUrl.ToString(),
authenticatedMetadataArchiveUrl.ToString(),
false,
null,
false).Result)
.Returns(migrationId);
_mockTargetGithubApi.Setup(x => x.GetMigration(migrationId).Result).Returns((State: RepositoryMigrationStatus.Succeeded, TARGET_REPO, 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);

_mockAzureApi.SetupSequence(x => x.UploadToBlob(It.IsAny<string>(), It.IsAny<FileStream>()).Result).Returns(authenticatedGitArchiveUrl).Returns(authenticatedMetadataArchiveUrl);

_mockFileSystemProvider
.SetupSequence(m => m.GetTempFileName())
.Returns(gitArchiveFilePath)
.Returns(metadataArchiveFilePath);

_mockEnvironmentVariableProvider.Setup(m => m.SourceGithubPersonalAccessToken(It.IsAny<bool>())).Returns(sourceGithubPat);
_mockEnvironmentVariableProvider.Setup(m => m.TargetGithubPersonalAccessToken(It.IsAny<bool>())).Returns(targetGithubPat);

_mockGhesVersionChecker.Setup(m => m.AreBlobCredentialsRequired(GHES_API_URL)).ReturnsAsync(true);

var args = new MigrateRepoCommandArgs
{
GithubSourceOrg = SOURCE_ORG,
SourceRepo = SOURCE_REPO,
GithubTargetOrg = TARGET_ORG,
TargetRepo = TARGET_REPO,
TargetApiUrl = TARGET_API_URL,
GhesApiUrl = GHES_API_URL,
AzureStorageConnectionString = AZURE_CONNECTION_STRING
};
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);
}

[Fact]
public async Task Github_With_Archive_Urls()
{
Expand Down
10 changes: 10 additions & 0 deletions src/bbs2gh/Commands/MigrateRepo/MigrateRepoCommandHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,16 @@ public async Task Handle(MigrateRepoCommandArgs args)

var exportId = 0L;

if (args.ShouldImportArchive())
{
var targetRepoExists = await _githubApi.DoesRepoExist(args.GithubOrg, args.GithubRepo);

if (targetRepoExists)
{
throw new OctoshiftCliException($"A repository called {args.GithubOrg}/{args.GithubRepo} already exists");
}
}

if (args.ShouldGenerateArchive())
{
exportId = await GenerateArchive(args);
Expand Down

0 comments on commit ff8d368

Please sign in to comment.