diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 61d84e014..b6f6f0c93 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,3 +1,4 @@ - Significant overhaul of how the `generate-script` command args work. Now by default it will generate a minimal script that only migrates the repos, and you will need to pass additional flags to script out additional automation (e.g. `--rewire-pipelines`, `--create-teams`, etc). The `--all` flag will include all the automation in the script (the same as the previous version with no flags). - Updates most commands to be idempotent. They will check if there is anything to do, and if not they will print a message to that effect and complete successfully. E.g. create-team will check if the team already exists and if so exit as success (compared to previously where it would crash). The following commands have been updated: - migrate-repo +- A generated script using `ado2gh` or `gh gei` now include the CLI version that was used to generate it. diff --git a/src/OctoshiftCLI.Tests/ado2gh/Commands/GenerateScriptCommandTests.cs b/src/OctoshiftCLI.Tests/ado2gh/Commands/GenerateScriptCommandTests.cs index 3f79a5387..4e805ddf6 100644 --- a/src/OctoshiftCLI.Tests/ado2gh/Commands/GenerateScriptCommandTests.cs +++ b/src/OctoshiftCLI.Tests/ado2gh/Commands/GenerateScriptCommandTests.cs @@ -28,7 +28,7 @@ public class GenerateScriptCommandTests [Fact] public void Should_Have_Options() { - var command = new GenerateScriptCommand(null, null); + var command = new GenerateScriptCommand(null, null, null); command.Should().NotBeNull(); command.Name.Should().Be("generate-script"); command.Options.Count.Should().Be(15); @@ -78,7 +78,7 @@ public async Task Invoke_Gets_All_Orgs_When_Ado_Org_Is_Not_Provided() mockAdoApiFactory.Setup(m => m.Create(It.IsAny())).Returns(mockAdoApi.Object); string script = null; - var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object) + var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object, Mock.Of()) { WriteToFile = (_, contents) => { @@ -122,7 +122,7 @@ public async Task Invoke_Does_Not_Get_All_Orgs_When_Ado_Org_Is_Provided() mockAdoApiFactory.Setup(m => m.Create(It.IsAny())).Returns(mockAdoApi.Object); string script = null; - var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object) + var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object, Mock.Of()) { WriteToFile = (_, contents) => { @@ -169,7 +169,7 @@ public async Task Invoke_Gets_All_Repos_For_Each_Team_Project_When_Ado_Team_Proj mockAdoApiFactory.Setup(m => m.Create(It.IsAny())).Returns(mockAdoApi.Object); string script = null; - var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object) + var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object, Mock.Of()) { WriteToFile = (_, contents) => { @@ -214,7 +214,7 @@ public async Task Invoke_Gets_All_Repos_For_Provided_Ado_Team_Project() mockAdoApiFactory.Setup(m => m.Create(It.IsAny())).Returns(mockAdoApi.Object); string script = null; - var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object) + var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object, Mock.Of()) { WriteToFile = (_, contents) => { @@ -256,7 +256,7 @@ public async Task Invoke_Gets_No_Repos_When_Provided_Ado_Team_Project_Is_Not_Fou mockAdoApiFactory.Setup(m => m.Create(It.IsAny())).Returns(mockAdoApi.Object); string script = null; - var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object) + var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object, Mock.Of()) { WriteToFile = (_, contents) => { @@ -287,7 +287,7 @@ public async Task SequentialScript_No_Data() { // Arrange string script = null; - var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, TestHelpers.CreateMock().Object) + var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, TestHelpers.CreateMock().Object, Mock.Of()) { WriteToFile = (_, contents) => { @@ -325,7 +325,7 @@ public async Task SequentialScript_StartsWith_Shebang() mockAdoApiFactory.Setup(m => m.Create(It.IsAny())).Returns(mockAdoApi.Object); string script = null; - var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object) + var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object, Mock.Of()) { WriteToFile = (_, contents) => { @@ -364,7 +364,7 @@ public async Task SequentialScript_Single_Repo_No_Options() mockAdoApiFactory.Setup(m => m.Create(It.IsAny())).Returns(mockAdoApi.Object); string script = null; - var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object) + var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object, Mock.Of()) { WriteToFile = (_, contents) => { @@ -406,7 +406,7 @@ public async Task SequentialScript_Single_Repo_All_Options() mockAdoApiFactory.Setup(m => m.Create(It.IsAny())).Returns(mockAdoApi.Object); string script = null; - var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object) + var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object, Mock.Of()) { WriteToFile = (_, contents) => { @@ -463,7 +463,7 @@ public async Task SequentialScript_Skips_Team_Project_With_No_Repos() mockAdoApiFactory.Setup(m => m.Create(It.IsAny())).Returns(mockAdoApi.Object); string script = null; - var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object) + var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object, Mock.Of()) { WriteToFile = (_, contents) => { @@ -513,7 +513,7 @@ public async Task SequentialScript_Single_Repo_Two_Pipelines_All_Options() mockAdoApiFactory.Setup(m => m.Create(It.IsAny())).Returns(mockAdoApi.Object); string script = null; - var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object) + var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object, Mock.Of()) { WriteToFile = (_, contents) => { @@ -586,7 +586,7 @@ public async Task SequentialScript_Single_Repo_Two_Pipelines_No_Service_Connecti mockAdoApiFactory.Setup(m => m.Create(It.IsAny())).Returns(mockAdoApi.Object); string script = null; - var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object) + var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object, Mock.Of()) { WriteToFile = (_, contents) => { @@ -646,7 +646,7 @@ public async Task SequentialScript_Create_Teams_Option_Should_Generate_Create_Te mockAdoApiFactory.Setup(m => m.Create(It.IsAny())).Returns(mockAdoApi.Object); string script = null; - var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object) + var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object, Mock.Of()) { WriteToFile = (_, contents) => { @@ -695,7 +695,7 @@ public async Task SequentialScript_Link_Idp_Groups_Option_Should_Generate_Create mockAdoApiFactory.Setup(m => m.Create(It.IsAny())).Returns(mockAdoApi.Object); string script = null; - var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object) + var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object, Mock.Of()) { WriteToFile = (_, contents) => { @@ -744,7 +744,7 @@ public async Task SequentialScript_Lock_Ado_Repo_Option_Should_Generate_Lock_Ado mockAdoApiFactory.Setup(m => m.Create(It.IsAny())).Returns(mockAdoApi.Object); string script = null; - var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object) + var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object, Mock.Of()) { WriteToFile = (_, contents) => { @@ -790,7 +790,7 @@ public async Task SequentialScript_Disable_Ado_Repo_Option_Should_Generate_Disab mockAdoApiFactory.Setup(m => m.Create(It.IsAny())).Returns(mockAdoApi.Object); string script = null; - var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object) + var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object, Mock.Of()) { WriteToFile = (_, contents) => { @@ -836,7 +836,7 @@ public async Task SequentialScript_Integrate_Boards_Option_Should_Generate_Auto_ mockAdoApiFactory.Setup(m => m.Create(It.IsAny())).Returns(mockAdoApi.Object); string script = null; - var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object) + var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object, Mock.Of()) { WriteToFile = (_, contents) => { @@ -892,7 +892,7 @@ public async Task SequentialScript_Rewire_Pipelines_Option_Should_Generate_Share mockAdoApiFactory.Setup(m => m.Create(It.IsAny())).Returns(mockAdoApi.Object); string script = null; - var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object) + var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object, Mock.Of()) { WriteToFile = (_, contents) => { @@ -928,7 +928,7 @@ public async Task ParallelScript_No_Data() { // Arrange string script = null; - var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, TestHelpers.CreateMock().Object) + var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, TestHelpers.CreateMock().Object, Mock.Of()) { WriteToFile = (_, contents) => { @@ -966,7 +966,7 @@ public async Task ParallelScript_StartsWith_Shebang() mockAdoApiFactory.Setup(m => m.Create(It.IsAny())).Returns(mockAdoApi.Object); string script = null; - var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object) + var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object, Mock.Of()) { WriteToFile = (_, contents) => { @@ -1012,8 +1012,11 @@ public async Task ParallelScript_Single_Repo_No_Options() var mockAdoApiFactory = TestHelpers.CreateMock(); mockAdoApiFactory.Setup(m => m.Create(It.IsAny())).Returns(mockAdoApi.Object); + var mockVersionProvider = new Mock(); + mockVersionProvider.Setup(m => m.GetCurrentVersion()).Returns("1.1.1.1"); + string actual = null; - var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object) + var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object, mockVersionProvider.Object) { WriteToFile = (_, contents) => { @@ -1024,6 +1027,8 @@ public async Task ParallelScript_Single_Repo_No_Options() var expected = new StringBuilder(); expected.AppendLine("#!/usr/bin/pwsh"); + expected.AppendLine(); + expected.AppendLine("# =========== Created with CLI version 1.1.1.1 ==========="); expected.AppendLine(@" function Exec { param ( @@ -1121,7 +1126,7 @@ public async Task PatallelScript_Skips_Team_Project_With_No_Repos() mockAdoApiFactory.Setup(m => m.Create(It.IsAny())).Returns(mockAdoApi.Object); string script = null; - var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object) + var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object, Mock.Of()) { WriteToFile = (_, contents) => { @@ -1175,8 +1180,11 @@ public async Task ParallelScript_Two_Repos_Two_Pipelines_All_Options() var mockAdoApiFactory = TestHelpers.CreateMock(); mockAdoApiFactory.Setup(m => m.Create(It.IsAny())).Returns(mockAdoApi.Object); + var mockVersionProvider = new Mock(); + mockVersionProvider.Setup(m => m.GetCurrentVersion()).Returns("1.1.1.1"); + string actual = null; - var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object) + var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object, mockVersionProvider.Object) { WriteToFile = (_, contents) => { @@ -1187,6 +1195,8 @@ public async Task ParallelScript_Two_Repos_Two_Pipelines_All_Options() var expected = new StringBuilder(); expected.AppendLine("#!/usr/bin/pwsh"); + expected.AppendLine(); + expected.AppendLine("# =========== Created with CLI version 1.1.1.1 ==========="); expected.AppendLine(@" function Exec { param ( @@ -1329,8 +1339,11 @@ public async Task ParallelScript_Single_Repo_No_Service_Connection_All_Options() var mockAdoApiFactory = TestHelpers.CreateMock(); mockAdoApiFactory.Setup(m => m.Create(It.IsAny())).Returns(mockAdoApi.Object); + var mockVersionProvider = new Mock(); + mockVersionProvider.Setup(m => m.GetCurrentVersion()).Returns("1.1.1.1"); + string actual = null; - var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object) + var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object, mockVersionProvider.Object) { WriteToFile = (_, contents) => { @@ -1341,6 +1354,8 @@ public async Task ParallelScript_Single_Repo_No_Service_Connection_All_Options() var expected = new StringBuilder(); expected.AppendLine("#!/usr/bin/pwsh"); + expected.AppendLine(); + expected.AppendLine("# =========== Created with CLI version 1.1.1.1 ==========="); expected.AppendLine(@" function Exec { param ( @@ -1454,7 +1469,7 @@ public async Task ParallelScript_Create_Teams_Option_Should_Generate_Create_Team mockAdoApiFactory.Setup(m => m.Create(It.IsAny())).Returns(mockAdoApi.Object); string actual = null; - var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object) + var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object, Mock.Of()) { WriteToFile = (_, contents) => { @@ -1515,7 +1530,7 @@ public async Task ParallelScript_Link_Idp_Groups_Option_Should_Generate_Create_T mockAdoApiFactory.Setup(m => m.Create(It.IsAny())).Returns(mockAdoApi.Object); string actual = null; - var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object) + var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object, Mock.Of()) { WriteToFile = (_, contents) => { @@ -1576,7 +1591,7 @@ public async Task ParallelScript_Lock_Ado_Repo_Option_Should_Generate_Lock_Ado_R mockAdoApiFactory.Setup(m => m.Create(It.IsAny())).Returns(mockAdoApi.Object); string actual = null; - var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object) + var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object, Mock.Of()) { WriteToFile = (_, contents) => { @@ -1632,7 +1647,7 @@ public async Task ParallelScript_Disable_Ado_Repo_Option_Should_Generate_Disable mockAdoApiFactory.Setup(m => m.Create(It.IsAny())).Returns(mockAdoApi.Object); string actual = null; - var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object) + var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object, Mock.Of()) { WriteToFile = (_, contents) => { @@ -1690,7 +1705,7 @@ public async Task ParallelScript_Integrate_Boards_Option_Should_Generate_Auto_Li mockAdoApiFactory.Setup(m => m.Create(It.IsAny())).Returns(mockAdoApi.Object); string actual = null; - var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object) + var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object, Mock.Of()) { WriteToFile = (_, contents) => { @@ -1758,7 +1773,7 @@ public async Task ParallelScript_Rewire_Pipelines_Option_Should_Generate_Share_S mockAdoApiFactory.Setup(m => m.Create(It.IsAny())).Returns(mockAdoApi.Object); string actual = null; - var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object) + var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object, Mock.Of()) { WriteToFile = (_, contents) => { @@ -1812,7 +1827,7 @@ public async Task It_Uses_The_Ado_Pat_When_Provided() mockAdoApiFactory.Setup(m => m.Create(adoPat)).Returns(mockAdoApi.Object); // Act - var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object); + var command = new GenerateScriptCommand(TestHelpers.CreateMock().Object, mockAdoApiFactory.Object, Mock.Of()); var args = new GenerateScriptCommandArgs { GithubOrg = "githubOrg", diff --git a/src/OctoshiftCLI.Tests/gei/Commands/GenerateScriptCommandTests.cs b/src/OctoshiftCLI.Tests/gei/Commands/GenerateScriptCommandTests.cs index e0d17b6c3..580da2e22 100644 --- a/src/OctoshiftCLI.Tests/gei/Commands/GenerateScriptCommandTests.cs +++ b/src/OctoshiftCLI.Tests/gei/Commands/GenerateScriptCommandTests.cs @@ -21,7 +21,7 @@ public class GenerateScriptCommandTests [Fact] public void Should_Have_Options() { - var command = new GenerateScriptCommand(null, null, null, null); + var command = new GenerateScriptCommand(null, null, null, null, null); command.Should().NotBeNull(); command.Name.Should().Be("generate-script"); @@ -58,7 +58,8 @@ public async Task Sequential_Github_No_Data() TestHelpers.CreateMock().Object, mockSourceGithubApiFactory.Object, TestHelpers.CreateMock().Object, - TestHelpers.CreateMock().Object) + TestHelpers.CreateMock().Object, + Mock.Of()) { WriteToFile = (_, contents) => { @@ -96,7 +97,8 @@ public async Task Parallel_Github_No_Data() TestHelpers.CreateMock().Object, mockSourceGithubApiFactory.Object, TestHelpers.CreateMock().Object, - TestHelpers.CreateMock().Object) + TestHelpers.CreateMock().Object, + Mock.Of()) { WriteToFile = (_, contents) => { @@ -138,7 +140,8 @@ public async Task Sequential_Github_StartsWithShebang() TestHelpers.CreateMock().Object, mockSourceGithubApiFactory.Object, TestHelpers.CreateMock().Object, - TestHelpers.CreateMock().Object) + TestHelpers.CreateMock().Object, + Mock.Of()) { WriteToFile = (_, contents) => { @@ -180,7 +183,8 @@ public async Task Parallel_Github_StartsWithShebang() TestHelpers.CreateMock().Object, mockSourceGithubApiFactory.Object, TestHelpers.CreateMock().Object, - TestHelpers.CreateMock().Object) + TestHelpers.CreateMock().Object, + Mock.Of()) { WriteToFile = (_, contents) => { @@ -222,7 +226,8 @@ public async Task Sequential_Github_Single_Repo() TestHelpers.CreateMock().Object, mockSourceGithubApiFactory.Object, TestHelpers.CreateMock().Object, - TestHelpers.CreateMock().Object) + TestHelpers.CreateMock().Object, + Mock.Of()) { WriteToFile = (_, contents) => { @@ -272,7 +277,8 @@ public async Task Sequential_Github_Multiple_Repos() TestHelpers.CreateMock().Object, mockSourceGithubApiFactory.Object, TestHelpers.CreateMock().Object, - TestHelpers.CreateMock().Object) + TestHelpers.CreateMock().Object, + Mock.Of()) { WriteToFile = (_, contents) => { @@ -327,7 +333,8 @@ public async Task Invoke_Gets_All_Ado_Repos_For_Each_Team_Projects_When_Ado_Team TestHelpers.CreateMock().Object, Mock.Of(), mockAdoApiFactory.Object, - TestHelpers.CreateMock().Object) + TestHelpers.CreateMock().Object, + Mock.Of()) { WriteToFile = (_, contents) => { @@ -378,7 +385,8 @@ public async Task Invoke_Gets_All_Ado_Repos_For_Provided_Team_Project() TestHelpers.CreateMock().Object, Mock.Of(), mockAdoApiFactory.Object, - TestHelpers.CreateMock().Object) + TestHelpers.CreateMock().Object, + Mock.Of()) { WriteToFile = (_, contents) => { @@ -426,7 +434,8 @@ public async Task Invoke_Gets_No_Repos_When_Provided_Team_Project_Does_Not_Exist TestHelpers.CreateMock().Object, Mock.Of(), mockAdoApiFactory.Object, - TestHelpers.CreateMock().Object) + TestHelpers.CreateMock().Object, + Mock.Of()) { WriteToFile = (_, contents) => { @@ -474,7 +483,8 @@ public async Task Sequential_Github_Ghes_Repo() TestHelpers.CreateMock().Object, mockSourceGithubApiFactory.Object, TestHelpers.CreateMock().Object, - TestHelpers.CreateMock().Object) + TestHelpers.CreateMock().Object, + Mock.Of()) { WriteToFile = (_, contents) => { @@ -525,7 +535,8 @@ public async Task Sequential_Github_Ghes_Repo_No_Ssl() TestHelpers.CreateMock().Object, mockSourceGithubApiFactory.Object, TestHelpers.CreateMock().Object, - TestHelpers.CreateMock().Object) + TestHelpers.CreateMock().Object, + Mock.Of()) { WriteToFile = (_, contents) => { @@ -570,7 +581,8 @@ public async Task Sequential_Ado_No_Data() TestHelpers.CreateMock().Object, Mock.Of(), mockAdoApiFactory.Object, - TestHelpers.CreateMock().Object) + TestHelpers.CreateMock().Object, + Mock.Of()) { WriteToFile = (_, contents) => { @@ -608,7 +620,8 @@ public async Task Parallel_Ado_No_Data() TestHelpers.CreateMock().Object, Mock.Of(), mockAdoApiFactory.Object, - TestHelpers.CreateMock().Object) + TestHelpers.CreateMock().Object, + Mock.Of()) { WriteToFile = (_, contents) => { @@ -650,7 +663,8 @@ public async Task Sequential_Ado_Single_Repo() TestHelpers.CreateMock().Object, Mock.Of(), mockAdoApiFactory.Object, - TestHelpers.CreateMock().Object) + TestHelpers.CreateMock().Object, + Mock.Of()) { WriteToFile = (_, contents) => { @@ -701,7 +715,8 @@ public async Task Sequential_Ado_Multiple_Repos() TestHelpers.CreateMock().Object, Mock.Of(), mockAdoApiFactory.Object, - TestHelpers.CreateMock().Object) + TestHelpers.CreateMock().Object, + Mock.Of()) { WriteToFile = (_, contents) => { @@ -749,12 +764,16 @@ public async Task Parallel_Ado_Multiple_Repos() .Setup(m => m.Create(It.IsAny())) .Returns(mockAdoApi.Object); + var mockVersionProvider = new Mock(); + mockVersionProvider.Setup(m => m.GetCurrentVersion()).Returns("1.1.1.1"); + string script = null; var command = new GenerateScriptCommand( TestHelpers.CreateMock().Object, Mock.Of(), mockAdoApiFactory.Object, - TestHelpers.CreateMock().Object) + TestHelpers.CreateMock().Object, + mockVersionProvider.Object) { WriteToFile = (_, contents) => { @@ -765,6 +784,8 @@ public async Task Parallel_Ado_Multiple_Repos() var expected = new StringBuilder(); expected.AppendLine("#!/usr/bin/pwsh"); + expected.AppendLine(); + expected.AppendLine("# =========== Created with CLI version 1.1.1.1 ==========="); expected.AppendLine(@" function Exec { param ( @@ -849,12 +870,16 @@ public async Task Parallel_Github_Multiple_Repos() .Setup(m => m.Create(It.IsAny(), It.IsAny())) .Returns(mockGithubApi.Object); + var mockVersionProvider = new Mock(); + mockVersionProvider.Setup(m => m.GetCurrentVersion()).Returns("1.1.1.1"); + string script = null; var command = new GenerateScriptCommand( TestHelpers.CreateMock().Object, mockSourceGithubApiFactory.Object, TestHelpers.CreateMock().Object, - TestHelpers.CreateMock().Object) + TestHelpers.CreateMock().Object, + mockVersionProvider.Object) { WriteToFile = (_, contents) => { @@ -865,6 +890,8 @@ public async Task Parallel_Github_Multiple_Repos() var expected = new StringBuilder(); expected.AppendLine("#!/usr/bin/pwsh"); + expected.AppendLine(); + expected.AppendLine("# =========== Created with CLI version 1.1.1.1 ==========="); expected.AppendLine(@" function Exec { param ( @@ -950,12 +977,16 @@ public async Task Parallel_Github_Ghes_Single_Repo() .Setup(m => m.Create(ghesApiUrl, It.IsAny())) .Returns(mockGithubApi.Object); + var mockVersionProvider = new Mock(); + mockVersionProvider.Setup(m => m.GetCurrentVersion()).Returns("1.1.1.1"); + string script = null; var command = new GenerateScriptCommand( TestHelpers.CreateMock().Object, mockSourceGithubApiFactory.Object, TestHelpers.CreateMock().Object, - TestHelpers.CreateMock().Object) + TestHelpers.CreateMock().Object, + mockVersionProvider.Object) { WriteToFile = (_, contents) => { @@ -966,6 +997,8 @@ public async Task Parallel_Github_Ghes_Single_Repo() var expected = new StringBuilder(); expected.AppendLine("#!/usr/bin/pwsh"); + expected.AppendLine(); + expected.AppendLine("# =========== Created with CLI version 1.1.1.1 ==========="); expected.AppendLine(@" function Exec { param ( @@ -1047,12 +1080,16 @@ public async Task Parallel_Github_Ghes_Single_Repo_No_Ssl() .Setup(m => m.Create(ghesApiUrl, It.IsAny())) .Returns(mockGithubApi.Object); + var mockVersionProvider = new Mock(); + mockVersionProvider.Setup(m => m.GetCurrentVersion()).Returns("1.1.1.1"); + string script = null; var command = new GenerateScriptCommand( TestHelpers.CreateMock().Object, mockSourceGithubApiFactory.Object, TestHelpers.CreateMock().Object, - TestHelpers.CreateMock().Object) + TestHelpers.CreateMock().Object, + mockVersionProvider.Object) { WriteToFile = (_, contents) => { @@ -1063,6 +1100,8 @@ public async Task Parallel_Github_Ghes_Single_Repo_No_Ssl() var expected = new StringBuilder(); expected.AppendLine("#!/usr/bin/pwsh"); + expected.AppendLine(); + expected.AppendLine("# =========== Created with CLI version 1.1.1.1 ==========="); expected.AppendLine(@" function Exec { param ( @@ -1147,7 +1186,8 @@ public async Task It_Uses_Github_Source_Pat_When_Provided() TestHelpers.CreateMock().Object, mockSourceGithubApiFactory.Object, mockAdoApiFactory.Object, - mockEnvironmentVariableProvider.Object); + mockEnvironmentVariableProvider.Object, + Mock.Of()); // Act var args = new GenerateScriptCommandArgs @@ -1185,7 +1225,8 @@ public async Task It_Uses_Ado_Pat_When_Provided() TestHelpers.CreateMock().Object, mockSourceGithubApiFactory.Object, mockAdoApiFactory.Object, - mockEnvironmentVariableProvider.Object); + mockEnvironmentVariableProvider.Object, + Mock.Of()); // Act var args = new GenerateScriptCommandArgs @@ -1220,7 +1261,8 @@ public async Task It_Adds_Skip_Releases_To_Migrate_Repo_Command_When_Provided_In TestHelpers.CreateMock().Object, mockSourceGithubApiFactory.Object, TestHelpers.CreateMock().Object, - TestHelpers.CreateMock().Object) + TestHelpers.CreateMock().Object, + Mock.Of()) { WriteToFile = (_, contents) => { @@ -1267,7 +1309,8 @@ public async Task Parallel_It_Adds_Skip_Releases_To_Migrate_Repo_Command_When_Pr TestHelpers.CreateMock().Object, mockSourceGithubApiFactory.Object, TestHelpers.CreateMock().Object, - TestHelpers.CreateMock().Object) + TestHelpers.CreateMock().Object, + Mock.Of()) { WriteToFile = (_, contents) => { @@ -1297,6 +1340,197 @@ public async Task Parallel_It_Adds_Skip_Releases_To_Migrate_Repo_Command_When_Pr script.Should().Be(expected.ToString()); } + [Fact] + public async Task Sequential_Github_Contains_Cli_Version() + { + // Arrange + var mockGithubApi = TestHelpers.CreateMock(); + mockGithubApi + .Setup(m => m.GetRepos(SOURCE_ORG)) + .ReturnsAsync(new[] { REPO }); + + var mockSourceGithubApiFactory = new Mock(); + mockSourceGithubApiFactory + .Setup(m => m.Create(It.IsAny(), It.IsAny())) + .Returns(mockGithubApi.Object); + + var mockVersionProvider = new Mock(); + mockVersionProvider.Setup(m => m.GetCurrentVersion()).Returns("1.1.1.1"); + + string script = null; + var command = new GenerateScriptCommand( + TestHelpers.CreateMock().Object, + mockSourceGithubApiFactory.Object, + TestHelpers.CreateMock().Object, + TestHelpers.CreateMock().Object, + mockVersionProvider.Object) + { + WriteToFile = (_, contents) => + { + script = contents; + return Task.CompletedTask; + } + }; + + const string expectedCliVersionComment = "# =========== Created with CLI version 1.1.1.1 ==========="; + + // Act + var args = new GenerateScriptCommandArgs + { + GithubSourceOrg = SOURCE_ORG, + GithubTargetOrg = TARGET_ORG, + Output = new FileInfo("unit-test-output"), + Sequential = true + }; + await command.Invoke(args); + + // Assert + script.Should().Contain(expectedCliVersionComment); + } + + [Fact] + public async Task Parallel_Github_Contains_Cli_Version() + { + // Arrange + var mockGithubApi = TestHelpers.CreateMock(); + mockGithubApi.Setup(m => m.GetRepos(SOURCE_ORG)).ReturnsAsync(new[] { REPO }); + var mockSourceGithubApiFactory = new Mock(); + mockSourceGithubApiFactory + .Setup(m => m.Create(It.IsAny(), It.IsAny())) + .Returns(mockGithubApi.Object); + + var mockVersionProvider = new Mock(); + mockVersionProvider.Setup(m => m.GetCurrentVersion()).Returns("1.1.1.1"); + + string script = null; + var command = new GenerateScriptCommand( + TestHelpers.CreateMock().Object, + mockSourceGithubApiFactory.Object, + TestHelpers.CreateMock().Object, + TestHelpers.CreateMock().Object, + mockVersionProvider.Object) + { + WriteToFile = (_, contents) => + { + script = contents; + return Task.CompletedTask; + } + }; + + const string expectedCliVersionComment = "# =========== Created with CLI version 1.1.1.1 ==========="; + + // Act + var args = new GenerateScriptCommandArgs + { + GithubSourceOrg = SOURCE_ORG, + GithubTargetOrg = TARGET_ORG, + Output = new FileInfo("unit-test-output") + }; + await command.Invoke(args); + + // Assert + script.Should().Contain(expectedCliVersionComment); + } + + [Fact] + public async Task Sequential_Ado_Contains_Cli_Version() + { + // Arrnage + const string adoTeamProject = "ADO-TEAM-PROJECT"; + + var mockAdoApi = TestHelpers.CreateMock(); + mockAdoApi.Setup(x => x.GetTeamProjects(SOURCE_ORG)).ReturnsAsync(new[] { adoTeamProject }); + mockAdoApi.Setup(x => x.GetEnabledRepos(SOURCE_ORG, adoTeamProject)).ReturnsAsync(new[] { REPO }); + + var mockAdoApiFactory = TestHelpers.CreateMock(); + mockAdoApiFactory + .Setup(m => m.Create(It.IsAny())) + .Returns(mockAdoApi.Object); + + var mockVersionProvider = new Mock(); + mockVersionProvider.Setup(m => m.GetCurrentVersion()).Returns("1.1.1.1"); + + string script = null; + var command = new GenerateScriptCommand( + TestHelpers.CreateMock().Object, + Mock.Of(), + mockAdoApiFactory.Object, + TestHelpers.CreateMock().Object, + mockVersionProvider.Object) + { + WriteToFile = (_, contents) => + { + script = contents; + return Task.CompletedTask; + } + }; + + const string expectedCliVersionComment = "# =========== Created with CLI version 1.1.1.1 ==========="; + + // Act + var args = new GenerateScriptCommandArgs + { + AdoSourceOrg = SOURCE_ORG, + AdoTeamProject = adoTeamProject, + GithubTargetOrg = TARGET_ORG, + Output = new FileInfo("unit-test-output"), + Sequential = true + }; + await command.Invoke(args); + + // Assert + script.Should().Contain(expectedCliVersionComment); + } + + [Fact] + public async Task Parallel_Ado_Contains_Cli_Version() + { + const string adoTeamProject = "ADO-TEAM-PROJECT"; + + // Arrange + var mockAdoApi = TestHelpers.CreateMock(); + mockAdoApi.Setup(x => x.GetTeamProjects(SOURCE_ORG)).ReturnsAsync(new[] { adoTeamProject }); + mockAdoApi.Setup(x => x.GetEnabledRepos(SOURCE_ORG, It.IsAny())).ReturnsAsync(new[] { REPO }); + + var mockAdoApiFactory = TestHelpers.CreateMock(); + mockAdoApiFactory + .Setup(m => m.Create(It.IsAny())) + .Returns(mockAdoApi.Object); + + var mockVersionProvider = new Mock(); + mockVersionProvider.Setup(m => m.GetCurrentVersion()).Returns("1.1.1.1"); + + string script = null; + var command = new GenerateScriptCommand( + TestHelpers.CreateMock().Object, + Mock.Of(), + mockAdoApiFactory.Object, + TestHelpers.CreateMock().Object, + mockVersionProvider.Object) + { + WriteToFile = (_, contents) => + { + script = contents; + return Task.CompletedTask; + } + }; + + const string expectedCliVersionComment = "# =========== Created with CLI version 1.1.1.1 ==========="; + + // Act + var args = new GenerateScriptCommandArgs + { + AdoSourceOrg = SOURCE_ORG, + AdoTeamProject = adoTeamProject, + GithubTargetOrg = TARGET_ORG, + Output = new FileInfo("unit-test-output") + }; + await command.Invoke(args); + + // Assert + script.Should().Contain(expectedCliVersionComment); + } + private string TrimNonExecutableLines(string script, int skipFirst = 9, int skipLast = 0) { var lines = script.Split(new[] { Environment.NewLine, "\n" }, StringSplitOptions.RemoveEmptyEntries).AsEnumerable(); diff --git a/src/ado2gh/Commands/GenerateScriptCommand.cs b/src/ado2gh/Commands/GenerateScriptCommand.cs index 165d0fb2c..fe8addbe0 100644 --- a/src/ado2gh/Commands/GenerateScriptCommand.cs +++ b/src/ado2gh/Commands/GenerateScriptCommand.cs @@ -19,11 +19,13 @@ public class GenerateScriptCommand : Command private readonly OctoLogger _log; private readonly AdoApiFactory _adoApiFactory; private GenerateScriptOptions _generateScriptOptions; + private readonly IVersionProvider _versionProvider; - public GenerateScriptCommand(OctoLogger log, AdoApiFactory adoApiFactory) : base("generate-script") + public GenerateScriptCommand(OctoLogger log, AdoApiFactory adoApiFactory, IVersionProvider versionProvider) : base("generate-script") { _log = log; _adoApiFactory = adoApiFactory; + _versionProvider = versionProvider; Description = "Generates a migration script. This provides you the ability to review the steps that this tool will take, and optionally modify the script if desired before running it."; Description += Environment.NewLine; @@ -323,6 +325,8 @@ private string GenerateSequentialScript(IDictionary $"# =========== Created with CLI version {_versionProvider.GetCurrentVersion()} ==========="; + private const string PWSH_SHEBANG = "#!/usr/bin/pwsh"; private const string EXEC_FUNCTION_BLOCK = @" diff --git a/src/gei/Commands/GenerateScriptCommand.cs b/src/gei/Commands/GenerateScriptCommand.cs index 256d5676e..0e0aa4207 100644 --- a/src/gei/Commands/GenerateScriptCommand.cs +++ b/src/gei/Commands/GenerateScriptCommand.cs @@ -20,13 +20,20 @@ public class GenerateScriptCommand : Command private readonly ISourceGithubApiFactory _sourceGithubApiFactory; private readonly AdoApiFactory _sourceAdoApiFactory; private readonly EnvironmentVariableProvider _environmentVariableProvider; - - public GenerateScriptCommand(OctoLogger log, ISourceGithubApiFactory sourceGithubApiFactory, AdoApiFactory sourceAdoApiFactory, EnvironmentVariableProvider environmentVariableProvider) : base("generate-script") + private readonly IVersionProvider _versionProvider; + + public GenerateScriptCommand( + OctoLogger log, + ISourceGithubApiFactory sourceGithubApiFactory, + AdoApiFactory sourceAdoApiFactory, + EnvironmentVariableProvider environmentVariableProvider, + IVersionProvider versionProvider) : base("generate-script") { _log = log; _sourceGithubApiFactory = sourceGithubApiFactory; _sourceAdoApiFactory = sourceAdoApiFactory; _environmentVariableProvider = environmentVariableProvider; + _versionProvider = versionProvider; Description = "Generates a migration script. This provides you the ability to review the steps that this tool will take, and optionally modify the script if desired before running it."; @@ -275,6 +282,8 @@ private string GenerateSequentialGithubScript(IEnumerable repos, string var content = new StringBuilder(); content.AppendLine(PWSH_SHEBANG); + content.AppendLine(); + content.AppendLine(VersionComment); content.AppendLine(EXEC_FUNCTION_BLOCK); content.AppendLine($"# =========== Organization: {githubSourceOrg} ==========="); @@ -297,6 +306,8 @@ private string GenerateParallelGithubScript(IEnumerable repos, string gi var content = new StringBuilder(); content.AppendLine(PWSH_SHEBANG); + content.AppendLine(); + content.AppendLine(VersionComment); content.AppendLine(EXEC_FUNCTION_BLOCK); content.AppendLine(EXEC_AND_GET_MIGRATION_ID_FUNCTION_BLOCK); @@ -359,6 +370,8 @@ private string GenerateSequentialAdoScript(IDictionary var content = new StringBuilder(); content.AppendLine(PWSH_SHEBANG); + content.AppendLine(); + content.AppendLine(VersionComment); content.AppendLine(EXEC_FUNCTION_BLOCK); content.AppendLine(EXEC_AND_GET_MIGRATION_ID_FUNCTION_BLOCK); @@ -508,6 +523,8 @@ private string GetGhesRepoOptions(string ghesApiUrl, string azureStorageConnecti private string Wrap(string script, string outerCommand = "") => script.IsNullOrWhiteSpace() ? string.Empty : $"{outerCommand} {{ {script} }}".Trim(); + private string VersionComment => $"# =========== Created with CLI version {_versionProvider.GetCurrentVersion()} ==========="; + private const string PWSH_SHEBANG = "#!/usr/bin/pwsh"; private const string EXEC_FUNCTION_BLOCK = @"