From 3de11450144fb9fee87d3336ed709a1f5f8c83be Mon Sep 17 00:00:00 2001 From: Geoff Lamrock Date: Wed, 11 Jun 2025 08:20:53 +1000 Subject: [PATCH 1/8] Add confirmation to migrate command --- .../Config/MigrateConfigCommandTests.cs | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/Stack.Tests/Commands/Config/MigrateConfigCommandTests.cs b/src/Stack.Tests/Commands/Config/MigrateConfigCommandTests.cs index f801103e..bb6c7332 100644 --- a/src/Stack.Tests/Commands/Config/MigrateConfigCommandTests.cs +++ b/src/Stack.Tests/Commands/Config/MigrateConfigCommandTests.cs @@ -103,5 +103,37 @@ public async Task WhenSchemaIsV2_DoesNotPerformMigration() var migratedData = fileStackConfig.Load(); migratedData.Should().BeEquivalentTo(new StackData(SchemaVersion.V2, [stack1, stack2])); } + + [Fact] + public async Task MigrateConfigCommand_WhenConfirmProvided_MigratesV1ToV2_DoesNotAskForConfirmation() + { + // Arrange + using var temporaryDirectory = TemporaryDirectory.Create(); + var fileStackConfig = new FileStackConfig(temporaryDirectory.DirectoryPath); + var configPath = fileStackConfig.GetConfigPath(); + + var stack1 = new TestStackBuilder() + .WithBranch(b => b.WithName("branch-1").WithChildBranch(b => b.WithName("branch-2"))) + .Build(); + + var stack2 = new TestStackBuilder() + .WithBranch(b => b.WithName("branch-3").WithChildBranch(b => b.WithName("branch-4"))) + .Build(); + + fileStackConfig.Save(new StackData(SchemaVersion.V1, [stack1, stack2])); + + var inputProvider = Substitute.For(); + var logger = new TestLogger(testOutputHelper); + var handler = new MigrateConfigCommandHandler(inputProvider, logger, fileStackConfig); + + // Act + await handler.Handle(new MigrateConfigCommandInputs(true)); + + // Assert + var migratedData = fileStackConfig.Load(); + migratedData.Should().BeEquivalentTo(new StackData(SchemaVersion.V2, [stack1, stack2])); + + inputProvider.DidNotReceive().Confirm(Questions.ConfirmMigrateConfig); + } } } From 9b84d78010978f7d28825f18cfdf6555032238c6 Mon Sep 17 00:00:00 2001 From: Geoff Lamrock Date: Wed, 11 Jun 2025 08:24:38 +1000 Subject: [PATCH 2/8] Improve tests --- .../Config/MigrateConfigCommandTests.cs | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/Stack.Tests/Commands/Config/MigrateConfigCommandTests.cs b/src/Stack.Tests/Commands/Config/MigrateConfigCommandTests.cs index bb6c7332..ce9d76e9 100644 --- a/src/Stack.Tests/Commands/Config/MigrateConfigCommandTests.cs +++ b/src/Stack.Tests/Commands/Config/MigrateConfigCommandTests.cs @@ -135,5 +135,35 @@ public async Task MigrateConfigCommand_WhenConfirmProvided_MigratesV1ToV2_DoesNo inputProvider.DidNotReceive().Confirm(Questions.ConfirmMigrateConfig); } + + [Fact] + public async Task WhenSchemaIsV2_DoesNotPerformMigration() + { + // Arrange + using var temporaryDirectory = TemporaryDirectory.Create(); + var fileStackConfig = new FileStackConfig(temporaryDirectory.DirectoryPath); + var configPath = fileStackConfig.GetConfigPath(); + + var stack1 = new TestStackBuilder() + .WithBranch(b => b.WithName("branch-1").WithChildBranch(b => b.WithName("branch-2"))) + .Build(); + + var stack2 = new TestStackBuilder() + .WithBranch(b => b.WithName("branch-3").WithChildBranch(b => b.WithName("branch-4"))) + .Build(); + + fileStackConfig.Save(new StackData(SchemaVersion.V2, [stack1, stack2])); + + var inputProvider = Substitute.For(); + var logger = new TestLogger(testOutputHelper); + var handler = new MigrateConfigCommandHandler(inputProvider, logger, fileStackConfig); + + // Act + await handler.Handle(new MigrateConfigCommandInputs(false)); + + // Assert + var migratedData = fileStackConfig.Load(); + migratedData.Should().BeEquivalentTo(new StackData(SchemaVersion.V2, [stack1, stack2])); + } } } From e390517d387df16cd60363a06b23dfb2b7e13f22 Mon Sep 17 00:00:00 2001 From: Geoff Lamrock Date: Wed, 28 May 2025 16:47:30 +1000 Subject: [PATCH 3/8] Support tree structure in status command --- src/Stack/Commands/Helpers/StackHelpers.cs | 32 ---------------------- 1 file changed, 32 deletions(-) diff --git a/src/Stack/Commands/Helpers/StackHelpers.cs b/src/Stack/Commands/Helpers/StackHelpers.cs index d6260f64..d1dff97d 100644 --- a/src/Stack/Commands/Helpers/StackHelpers.cs +++ b/src/Stack/Commands/Helpers/StackHelpers.cs @@ -10,16 +10,6 @@ namespace Stack.Commands.Helpers; public record StackStatus(string Name, SourceBranchDetail SourceBranch, List Branches) { - public List> GetAllBranchLines() - { - var allLines = new List>(); - foreach (var branch in Branches) - { - allLines.AddRange(branch.GetAllPaths()); - } - return allLines; - } - public List GetAllBranches() { var branchesToReturn = new List(); @@ -152,28 +142,6 @@ public record BranchDetail( public int AheadOfParent => Parent?.Ahead ?? 0; public int BehindParent => Parent?.Behind ?? 0; public string ParentBranchName => Parent?.Name ?? string.Empty; - - public List> GetAllPaths() - { - var result = new List>(); - if (Children.Count == 0) - { - result.Add([this]); - } - else - { - foreach (var child in Children) - { - foreach (var path in child.GetAllPaths()) - { - var newPath = new List { this }; - newPath.AddRange(path); - result.Add(newPath); - } - } - } - return result; - } } public record ParentBranchStatus(string Name, int Ahead, int Behind); From ad550c139339e1009eab07c83769422229addc4c Mon Sep 17 00:00:00 2001 From: Geoff Lamrock Date: Tue, 3 Jun 2025 17:47:25 +1000 Subject: [PATCH 4/8] Add method to get all branch lines --- src/Stack/Commands/Helpers/StackHelpers.cs | 32 ++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/Stack/Commands/Helpers/StackHelpers.cs b/src/Stack/Commands/Helpers/StackHelpers.cs index d1dff97d..d6260f64 100644 --- a/src/Stack/Commands/Helpers/StackHelpers.cs +++ b/src/Stack/Commands/Helpers/StackHelpers.cs @@ -10,6 +10,16 @@ namespace Stack.Commands.Helpers; public record StackStatus(string Name, SourceBranchDetail SourceBranch, List Branches) { + public List> GetAllBranchLines() + { + var allLines = new List>(); + foreach (var branch in Branches) + { + allLines.AddRange(branch.GetAllPaths()); + } + return allLines; + } + public List GetAllBranches() { var branchesToReturn = new List(); @@ -142,6 +152,28 @@ public record BranchDetail( public int AheadOfParent => Parent?.Ahead ?? 0; public int BehindParent => Parent?.Behind ?? 0; public string ParentBranchName => Parent?.Name ?? string.Empty; + + public List> GetAllPaths() + { + var result = new List>(); + if (Children.Count == 0) + { + result.Add([this]); + } + else + { + foreach (var child in Children) + { + foreach (var path in child.GetAllPaths()) + { + var newPath = new List { this }; + newPath.AddRange(path); + result.Add(newPath); + } + } + } + return result; + } } public record ParentBranchStatus(string Name, int Ahead, int Behind); From ce2401d008d7727ef26a3795488a0ddbb4405d4b Mon Sep 17 00:00:00 2001 From: Geoff Lamrock Date: Wed, 11 Jun 2025 08:41:22 +1000 Subject: [PATCH 5/8] Fix migration tests after merge --- .../Config/MigrateConfigCommandTests.cs | 62 ------------------- 1 file changed, 62 deletions(-) diff --git a/src/Stack.Tests/Commands/Config/MigrateConfigCommandTests.cs b/src/Stack.Tests/Commands/Config/MigrateConfigCommandTests.cs index ce9d76e9..f801103e 100644 --- a/src/Stack.Tests/Commands/Config/MigrateConfigCommandTests.cs +++ b/src/Stack.Tests/Commands/Config/MigrateConfigCommandTests.cs @@ -103,67 +103,5 @@ public async Task WhenSchemaIsV2_DoesNotPerformMigration() var migratedData = fileStackConfig.Load(); migratedData.Should().BeEquivalentTo(new StackData(SchemaVersion.V2, [stack1, stack2])); } - - [Fact] - public async Task MigrateConfigCommand_WhenConfirmProvided_MigratesV1ToV2_DoesNotAskForConfirmation() - { - // Arrange - using var temporaryDirectory = TemporaryDirectory.Create(); - var fileStackConfig = new FileStackConfig(temporaryDirectory.DirectoryPath); - var configPath = fileStackConfig.GetConfigPath(); - - var stack1 = new TestStackBuilder() - .WithBranch(b => b.WithName("branch-1").WithChildBranch(b => b.WithName("branch-2"))) - .Build(); - - var stack2 = new TestStackBuilder() - .WithBranch(b => b.WithName("branch-3").WithChildBranch(b => b.WithName("branch-4"))) - .Build(); - - fileStackConfig.Save(new StackData(SchemaVersion.V1, [stack1, stack2])); - - var inputProvider = Substitute.For(); - var logger = new TestLogger(testOutputHelper); - var handler = new MigrateConfigCommandHandler(inputProvider, logger, fileStackConfig); - - // Act - await handler.Handle(new MigrateConfigCommandInputs(true)); - - // Assert - var migratedData = fileStackConfig.Load(); - migratedData.Should().BeEquivalentTo(new StackData(SchemaVersion.V2, [stack1, stack2])); - - inputProvider.DidNotReceive().Confirm(Questions.ConfirmMigrateConfig); - } - - [Fact] - public async Task WhenSchemaIsV2_DoesNotPerformMigration() - { - // Arrange - using var temporaryDirectory = TemporaryDirectory.Create(); - var fileStackConfig = new FileStackConfig(temporaryDirectory.DirectoryPath); - var configPath = fileStackConfig.GetConfigPath(); - - var stack1 = new TestStackBuilder() - .WithBranch(b => b.WithName("branch-1").WithChildBranch(b => b.WithName("branch-2"))) - .Build(); - - var stack2 = new TestStackBuilder() - .WithBranch(b => b.WithName("branch-3").WithChildBranch(b => b.WithName("branch-4"))) - .Build(); - - fileStackConfig.Save(new StackData(SchemaVersion.V2, [stack1, stack2])); - - var inputProvider = Substitute.For(); - var logger = new TestLogger(testOutputHelper); - var handler = new MigrateConfigCommandHandler(inputProvider, logger, fileStackConfig); - - // Act - await handler.Handle(new MigrateConfigCommandInputs(false)); - - // Assert - var migratedData = fileStackConfig.Load(); - migratedData.Should().BeEquivalentTo(new StackData(SchemaVersion.V2, [stack1, stack2])); - } } } From 18f6f32f2f5d14e8f0ab78ad10789f4749bd1b4c Mon Sep 17 00:00:00 2001 From: Geoff Lamrock Date: Wed, 4 Jun 2025 07:54:11 +1000 Subject: [PATCH 6/8] Support tree structure when creating pull requests --- src/Stack/Commands/Helpers/StackHelpers.cs | 49 ++++++++++-- .../PullRequests/CreatePullRequestsCommand.cs | 79 ++++++++++--------- .../SetPullRequestDescriptionCommand.cs | 2 +- src/Stack/Git/GitHubClient.cs | 11 ++- 4 files changed, 92 insertions(+), 49 deletions(-) diff --git a/src/Stack/Commands/Helpers/StackHelpers.cs b/src/Stack/Commands/Helpers/StackHelpers.cs index d6260f64..099e1e60 100644 --- a/src/Stack/Commands/Helpers/StackHelpers.cs +++ b/src/Stack/Commands/Helpers/StackHelpers.cs @@ -334,14 +334,15 @@ public static void OutputStackStatus( public static void OutputStackStatus( SchemaVersion schemaVersion, StackStatus status, - ILogger logger) + ILogger logger, + Func? getBranchPullRequestDisplay = null) { var header = GetBranchStatusOutput(status.SourceBranch); var items = new List>(); foreach (var branch in status.Branches) { - items.Add(GetBranchAndPullRequestStatusOutput(branch)); + items.Add(GetBranchAndPullRequestStatusOutput(branch, getBranchPullRequestDisplay)); } if (schemaVersion == SchemaVersion.V1 && items.Count > 0) @@ -353,19 +354,27 @@ public static void OutputStackStatus( logger.Tree(new Tree(header, [.. items])); } - public static TreeItem GetBranchAndPullRequestStatusOutput(BranchDetail branch) + public static TreeItem GetBranchAndPullRequestStatusOutput( + BranchDetail branch, + Func? getBranchPullRequestDisplay = null) { var branchNameBuilder = new StringBuilder(); branchNameBuilder.Append(GetBranchStatusOutput(branch)); - if (branch.PullRequest is not null) + var pullRequestDisplay = getBranchPullRequestDisplay?.Invoke(branch); + + if (pullRequestDisplay is not null) + { + branchNameBuilder.Append($" {pullRequestDisplay}"); + } + else if (branch.PullRequest is not null) { branchNameBuilder.Append($" {branch.PullRequest.GetPullRequestDisplay()}"); } var treeItemValue = branchNameBuilder.ToString(); var children = branch.Children - .Select(GetBranchAndPullRequestStatusOutput) + .Select(b => GetBranchAndPullRequestStatusOutput(b, getBranchPullRequestDisplay)) .ToList(); return new TreeItem(treeItemValue, children); @@ -718,11 +727,35 @@ public static void UpdateStackDescriptionInPullRequests( Config.Stack stack, List pullRequestsInStack) { + var prListBuilder = new StringBuilder(); + + void AppendPullRequestToList(GitHubPullRequest pullRequest, int indentLevel) + { + prListBuilder.AppendLine($"{new string(' ', indentLevel * 2)}- {pullRequest.Url}"); + } + + void AppendBranchPullRequestsToList(Branch branch, int indentLevel) + { + var pullRequest = pullRequestsInStack.FirstOrDefault(pr => pr.HeadRefName == branch.Name); + if (pullRequest is not null) + { + AppendPullRequestToList(pullRequest, indentLevel); + } + + foreach (var child in branch.Children) + { + AppendBranchPullRequestsToList(child, indentLevel + 1); + } + } + + foreach (var branch in stack.Branches) + { + AppendBranchPullRequestsToList(branch, 0); + } + // Edit each PR and add to the top of the description // the details of each PR in the stack - var prList = pullRequestsInStack - .Select(pr => $"- {pr.Url}") - .ToList(); + var prList = prListBuilder.ToString(); var prListMarkdown = string.Join(Environment.NewLine, prList); var prBodyMarkdown = $"{StackConstants.StackMarkerStart}{Environment.NewLine}{stack.PullRequestDescription}{Environment.NewLine}{Environment.NewLine}{prListMarkdown}{Environment.NewLine}{StackConstants.StackMarkerEnd}"; diff --git a/src/Stack/Commands/PullRequests/CreatePullRequestsCommand.cs b/src/Stack/Commands/PullRequests/CreatePullRequestsCommand.cs index 58e1072e..356d209b 100644 --- a/src/Stack/Commands/PullRequests/CreatePullRequestsCommand.cs +++ b/src/Stack/Commands/PullRequests/CreatePullRequestsCommand.cs @@ -77,19 +77,25 @@ public override async Task Handle(CreatePullRequestsCommandInputs inputs) gitClient, gitHubClient); - var sourceBranch = stack.SourceBranch; var pullRequestCreateActions = new List(); - foreach (var branch in status.Branches) + var allBranchLines = status.GetAllBranchLines(); + + foreach (var branchLine in allBranchLines) { - if (branch.IsActive) + var sourceBranch = stack.SourceBranch; + + foreach (var branch in branchLine) { - if (!branch.HasPullRequest) + if (branch.IsActive) { - pullRequestCreateActions.Add(new PullRequestCreateAction(branch.Name, sourceBranch)); - } + if (!branch.HasPullRequest) + { + pullRequestCreateActions.Add(new PullRequestCreateAction(branch.Name, sourceBranch)); + } - sourceBranch = branch.Name; + sourceBranch = branch.Name; + } } } @@ -133,17 +139,10 @@ public override async Task Handle(CreatePullRequestsCommandInputs inputs) { var newPullRequests = CreatePullRequests(logger, gitHubClient, status, pullRequestInformation); - // Re-get the status to pick up PRs - status = StackHelpers.GetStackStatus( - stack, - currentBranch, - logger, - gitClient, - gitHubClient); - - var pullRequestsInStack = status.Branches + var pullRequestsInStack = status.GetAllBranches() .Where(branch => branch.HasPullRequest) .Select(branch => branch.PullRequest!) + .Concat(newPullRequests) .ToList(); if (pullRequestsInStack.Count > 1) @@ -166,7 +165,14 @@ public override async Task Handle(CreatePullRequestsCommandInputs inputs) } } - private static void UpdatePullRequestStackDescriptions(IInputProvider inputProvider, ILogger logger, IGitHubClient gitHubClient, IStackConfig stackConfig, StackData stacks, Config.Stack stack, List pullRequestsInStack) + private static void UpdatePullRequestStackDescriptions( + IInputProvider inputProvider, + ILogger logger, + IGitHubClient gitHubClient, + IStackConfig stackConfig, + StackData stacks, + Config.Stack stack, + List pullRequestsInStack) { if (stack.PullRequestDescription is null) { @@ -185,7 +191,6 @@ private static List CreatePullRequests( var pullRequests = new List(); foreach (var action in pullRequestCreateActions) { - var branchDetail = status.Branches.First(b => b.Name == action.HeadBranch); logger.Information($"Creating pull request for branch {action.HeadBranch.Branch()} to {action.BaseBranch.Branch()}"); var pullRequest = gitHubClient.CreatePullRequest( action.HeadBranch, @@ -204,30 +209,28 @@ private static List CreatePullRequests( return pullRequests; } - private static void OutputUpdatedStackStatus(ILogger logger, SchemaVersion schemaVersion, Config.Stack stack, StackStatus status, List pullRequestInformation) + private static void OutputUpdatedStackStatus( + ILogger logger, + SchemaVersion schemaVersion, + Config.Stack stack, + StackStatus status, + List pullRequestInformation) { - var branchDisplayItems = new List>(); - - foreach (var branch in status.Branches) - { - if (branch.PullRequest is not null && branch.PullRequest.State != GitHubPullRequestStates.Closed) - { - branchDisplayItems.Add(StackHelpers.GetBranchAndPullRequestStatusOutput(branch)); - } - else + StackHelpers.OutputStackStatus( + schemaVersion, + status, + logger, + (branch) => { - branchDisplayItems.Add(StackHelpers.GetBranchAndPullRequestInformation(branch, pullRequestInformation)); - } - } + var pr = pullRequestInformation.FirstOrDefault(pr => pr.HeadBranch == branch.Name); - if (schemaVersion == SchemaVersion.V1 && branchDisplayItems.Count > 0) - { - branchDisplayItems = [.. MoreEnumerable.TraverseDepthFirst(branchDisplayItems.First(), i => i.Children).Select(i => new TreeItem(i.Value, []))]; - } + if (pr is not null) + { + return $" {$"*NEW* {pr.Title}".Highlighted()}{(pr.Draft == true ? " (draft)".Muted() : string.Empty)}"; + } - logger.Tree(new Tree( - $"{stack.Name.Stack()}: {stack.SourceBranch.Muted()}", - [.. branchDisplayItems])); + return null; + }); } private static List GetPullRequestInformation( diff --git a/src/Stack/Commands/PullRequests/SetPullRequestDescriptionCommand.cs b/src/Stack/Commands/PullRequests/SetPullRequestDescriptionCommand.cs index 9e869726..ecb62243 100644 --- a/src/Stack/Commands/PullRequests/SetPullRequestDescriptionCommand.cs +++ b/src/Stack/Commands/PullRequests/SetPullRequestDescriptionCommand.cs @@ -76,7 +76,7 @@ public override async Task Handle(SetPullRequestDescriptionCommandInputs inputs) var pullRequestsInStack = new List(); - foreach (var branch in status.Branches) + foreach (var branch in status.GetAllBranches()) { if (branch.PullRequest is not null) { diff --git a/src/Stack/Git/GitHubClient.cs b/src/Stack/Git/GitHubClient.cs index 1a3619e9..54c2e32f 100644 --- a/src/Stack/Git/GitHubClient.cs +++ b/src/Stack/Git/GitHubClient.cs @@ -17,7 +17,14 @@ public static class GitHubPullRequestStates public const string Merged = "MERGED"; } -public record GitHubPullRequest(int Number, string Title, string Body, string State, Uri Url, bool IsDraft); +public record GitHubPullRequest( + int Number, + string Title, + string Body, + string State, + Uri Url, + bool IsDraft, + string HeadRefName); public static class GitHubPullRequestExtensionMethods { @@ -58,7 +65,7 @@ public class GitHubClient(ILogger logger, GitHubClientSettings settings) : IGitH { public GitHubPullRequest? GetPullRequest(string branch) { - var output = ExecuteGitHubCommandAndReturnOutput($"pr list --json title,number,body,state,url,isDraft --head {branch} --state all"); + var output = ExecuteGitHubCommandAndReturnOutput($"pr list --json title,number,body,state,url,isDraft,headRefName --head {branch} --state all"); var pullRequests = System.Text.Json.JsonSerializer.Deserialize>(output, new System.Text.Json.JsonSerializerOptions(System.Text.Json.JsonSerializerDefaults.Web))!; From 39e3556a96d8174483baecf93d58e310b74316d4 Mon Sep 17 00:00:00 2001 From: Geoff Lamrock Date: Wed, 11 Jun 2025 20:45:31 +1000 Subject: [PATCH 7/8] Fix build --- .../CreatePullRequestsCommandHandlerTests.cs | 28 +++++++++---------- .../OpenPullRequestsCommandHandlerTests.cs | 16 +++++------ .../Stack/StackStatusCommandHandlerTests.cs | 14 +++++----- .../Stack/UpdateStackCommandHandlerTests.cs | 2 +- .../Helpers/TestGitHubRepositoryBuilder.cs | 5 ++-- 5 files changed, 33 insertions(+), 32 deletions(-) diff --git a/src/Stack.Tests/Commands/PullRequests/CreatePullRequestsCommandHandlerTests.cs b/src/Stack.Tests/Commands/PullRequests/CreatePullRequestsCommandHandlerTests.cs index c15de53e..4d54118f 100644 --- a/src/Stack.Tests/Commands/PullRequests/CreatePullRequestsCommandHandlerTests.cs +++ b/src/Stack.Tests/Commands/PullRequests/CreatePullRequestsCommandHandlerTests.cs @@ -67,8 +67,8 @@ A custom description var expectedPullRequests = new Dictionary { - [branch1] = new GitHubPullRequest(1, "PR Title", expectedPrBody, GitHubPullRequestStates.Open, Some.HttpsUri(), false), - [branch2] = new GitHubPullRequest(2, "PR Title", expectedPrBody, GitHubPullRequestStates.Open, Some.HttpsUri(), false) + [branch1] = new GitHubPullRequest(1, "PR Title", expectedPrBody, GitHubPullRequestStates.Open, Some.HttpsUri(), false, branch1), + [branch2] = new GitHubPullRequest(2, "PR Title", expectedPrBody, GitHubPullRequestStates.Open, Some.HttpsUri(), false, branch2) }; gitHubClient.PullRequests.Should().BeEquivalentTo(expectedPullRequests, ExcludeUnimportantPullRequestProperties); @@ -246,8 +246,8 @@ A custom description var expectedPullRequests = new Dictionary { - [branch1] = new GitHubPullRequest(1, "PR Title", expectedPrBody, GitHubPullRequestStates.Open, Some.HttpsUri(), false), - [branch2] = new GitHubPullRequest(2, "PR Title", expectedPrBody, GitHubPullRequestStates.Open, Some.HttpsUri(), false) + [branch1] = new GitHubPullRequest(1, "PR Title", expectedPrBody, GitHubPullRequestStates.Open, Some.HttpsUri(), false, branch1), + [branch2] = new GitHubPullRequest(2, "PR Title", expectedPrBody, GitHubPullRequestStates.Open, Some.HttpsUri(), false, branch2) }; gitHubClient.PullRequests.Should().BeEquivalentTo(expectedPullRequests, ExcludeUnimportantPullRequestProperties); @@ -301,8 +301,8 @@ A custom description var expectedPullRequests = new Dictionary { - [branch1] = new GitHubPullRequest(1, "PR Title", expectedPrBody, GitHubPullRequestStates.Open, Some.HttpsUri(), false), - [branch2] = new GitHubPullRequest(2, "PR Title", expectedPrBody, GitHubPullRequestStates.Open, Some.HttpsUri(), false) + [branch1] = new GitHubPullRequest(1, "PR Title", expectedPrBody, GitHubPullRequestStates.Open, Some.HttpsUri(), false, branch1), + [branch2] = new GitHubPullRequest(2, "PR Title", expectedPrBody, GitHubPullRequestStates.Open, Some.HttpsUri(), false, branch2) }; gitHubClient.PullRequests.Should().BeEquivalentTo(expectedPullRequests, ExcludeUnimportantPullRequestProperties); @@ -408,8 +408,8 @@ A custom description var expectedPullRequests = new Dictionary { - [branch1] = new GitHubPullRequest(1, "PR Title", expectedPrBody, GitHubPullRequestStates.Merged, Some.HttpsUri(), false), - [branch2] = new GitHubPullRequest(2, "PR Title", expectedPrBody, GitHubPullRequestStates.Open, Some.HttpsUri(), false) + [branch1] = new GitHubPullRequest(1, "PR Title", expectedPrBody, GitHubPullRequestStates.Merged, Some.HttpsUri(), false, branch1), + [branch2] = new GitHubPullRequest(2, "PR Title", expectedPrBody, GitHubPullRequestStates.Open, Some.HttpsUri(), false, branch2) }; gitHubClient.PullRequests.Should().BeEquivalentTo(expectedPullRequests, ExcludeUnimportantPullRequestProperties); @@ -472,8 +472,8 @@ A custom description var expectedPullRequests = new Dictionary { - [branch1] = new GitHubPullRequest(1, "PR Title", expectedPrBody, GitHubPullRequestStates.Open, Some.HttpsUri(), false), - [branch2] = new GitHubPullRequest(2, "PR Title", expectedPrBody, GitHubPullRequestStates.Open, Some.HttpsUri(), false) + [branch1] = new GitHubPullRequest(1, "PR Title", expectedPrBody, GitHubPullRequestStates.Open, Some.HttpsUri(), false, branch1), + [branch2] = new GitHubPullRequest(2, "PR Title", expectedPrBody, GitHubPullRequestStates.Open, Some.HttpsUri(), false, branch2) }; gitHubClient.PullRequests.Should().BeEquivalentTo(expectedPullRequests, ExcludeUnimportantPullRequestProperties); @@ -530,7 +530,7 @@ public async Task WhenAPullRequestTemplateDoesNotExistInTheRepo_TheStackPrListMa var expectedPullRequests = new Dictionary { - [branch1] = new GitHubPullRequest(1, "PR Title", expectedPrBody, GitHubPullRequestStates.Open, Some.HttpsUri(), false) + [branch1] = new GitHubPullRequest(1, "PR Title", expectedPrBody, GitHubPullRequestStates.Open, Some.HttpsUri(), false, branch1) }; gitHubClient.PullRequests.Should().BeEquivalentTo(expectedPullRequests, ExcludeUnimportantPullRequestProperties); @@ -636,7 +636,7 @@ public async Task WhenOnlySelectingSomeBranchesToCreatePullRequestsFor_OnlyThose var expectedPullRequests = new Dictionary { - [branch1] = new GitHubPullRequest(1, "PR Title", expectedPrBody, GitHubPullRequestStates.Open, Some.HttpsUri(), false) + [branch1] = new GitHubPullRequest(1, "PR Title", expectedPrBody, GitHubPullRequestStates.Open, Some.HttpsUri(), false, branch1) }; gitHubClient.PullRequests.Should().BeEquivalentTo(expectedPullRequests, ExcludeUnimportantPullRequestProperties); @@ -694,8 +694,8 @@ A custom description var expectedPullRequests = new Dictionary { - [branch1] = new GitHubPullRequest(1, "PR Title", expectedPrBody, GitHubPullRequestStates.Open, Some.HttpsUri(), false), - [branch2] = new GitHubPullRequest(2, "PR Title", expectedPrBody, GitHubPullRequestStates.Open, Some.HttpsUri(), false) + [branch1] = new GitHubPullRequest(1, "PR Title", expectedPrBody, GitHubPullRequestStates.Open, Some.HttpsUri(), false, branch1), + [branch2] = new GitHubPullRequest(2, "PR Title", expectedPrBody, GitHubPullRequestStates.Open, Some.HttpsUri(), false, branch2) }; gitHubClient.PullRequests.Should().BeEquivalentTo(expectedPullRequests, ExcludeUnimportantPullRequestProperties); diff --git a/src/Stack.Tests/Commands/PullRequests/OpenPullRequestsCommandHandlerTests.cs b/src/Stack.Tests/Commands/PullRequests/OpenPullRequestsCommandHandlerTests.cs index c7c4bf11..c81729cd 100644 --- a/src/Stack.Tests/Commands/PullRequests/OpenPullRequestsCommandHandlerTests.cs +++ b/src/Stack.Tests/Commands/PullRequests/OpenPullRequestsCommandHandlerTests.cs @@ -46,12 +46,12 @@ public async Task WhenThereAreMultiplePullRequestsInAStack_OpensAllPullRequests( inputProvider.Select(Questions.SelectStack, Arg.Any()).Returns("Stack1"); - var prForBranch1 = new GitHubPullRequest(1, "PR Title", string.Empty, GitHubPullRequestStates.Open, Some.HttpsUri(), false); + var prForBranch1 = new GitHubPullRequest(1, "PR Title", string.Empty, GitHubPullRequestStates.Open, Some.HttpsUri(), false, branch1); gitHubClient .GetPullRequest(branch1) .Returns(prForBranch1); - var prForBranch2 = new GitHubPullRequest(2, "PR Title", string.Empty, GitHubPullRequestStates.Open, Some.HttpsUri(), false); + var prForBranch2 = new GitHubPullRequest(2, "PR Title", string.Empty, GitHubPullRequestStates.Open, Some.HttpsUri(), false, branch2); gitHubClient .GetPullRequest(branch2) .Returns(prForBranch2); @@ -98,12 +98,12 @@ public async Task WhenThereAreSomePullRequestsInAStack_OpensAllPullRequests() inputProvider.Select(Questions.SelectStack, Arg.Any()).Returns("Stack1"); - var prForBranch1 = new GitHubPullRequest(1, "PR Title", string.Empty, GitHubPullRequestStates.Open, Some.HttpsUri(), false); + var prForBranch1 = new GitHubPullRequest(1, "PR Title", string.Empty, GitHubPullRequestStates.Open, Some.HttpsUri(), false, branch1); gitHubClient .GetPullRequest(branch1) .Returns(prForBranch1); - var prForBranch2 = new GitHubPullRequest(2, "PR Title", string.Empty, GitHubPullRequestStates.Closed, Some.HttpsUri(), false); + var prForBranch2 = new GitHubPullRequest(2, "PR Title", string.Empty, GitHubPullRequestStates.Closed, Some.HttpsUri(), false, branch2); // Act await handler.Handle(OpenPullRequestsCommandInputs.Empty); @@ -145,12 +145,12 @@ public async Task WhenStackNameIsProvided_OpensAllPullRequestsForTheStack() var gitClient = new GitClient(logger, repo.GitClientSettings); var handler = new OpenPullRequestsCommandHandler(inputProvider, logger, gitClient, gitHubClient, stackConfig); - var prForBranch1 = new GitHubPullRequest(1, "PR Title", string.Empty, GitHubPullRequestStates.Open, Some.HttpsUri(), false); + var prForBranch1 = new GitHubPullRequest(1, "PR Title", string.Empty, GitHubPullRequestStates.Open, Some.HttpsUri(), false, branch1); gitHubClient .GetPullRequest(branch1) .Returns(prForBranch1); - var prForBranch2 = new GitHubPullRequest(2, "PR Title", string.Empty, GitHubPullRequestStates.Open, Some.HttpsUri(), false); + var prForBranch2 = new GitHubPullRequest(2, "PR Title", string.Empty, GitHubPullRequestStates.Open, Some.HttpsUri(), false, branch2); gitHubClient .GetPullRequest(branch2) .Returns(prForBranch2); @@ -191,12 +191,12 @@ public async Task WhenOnlyOneStackExists_DoesNotAskForStackName_OpensAllPullRequ var gitClient = new GitClient(logger, repo.GitClientSettings); var handler = new OpenPullRequestsCommandHandler(inputProvider, logger, gitClient, gitHubClient, stackConfig); - var prForBranch1 = new GitHubPullRequest(1, "PR Title", string.Empty, GitHubPullRequestStates.Open, Some.HttpsUri(), false); + var prForBranch1 = new GitHubPullRequest(1, "PR Title", string.Empty, GitHubPullRequestStates.Open, Some.HttpsUri(), false, branch1); gitHubClient .GetPullRequest(branch1) .Returns(prForBranch1); - var prForBranch2 = new GitHubPullRequest(2, "PR Title", string.Empty, GitHubPullRequestStates.Open, Some.HttpsUri(), false); + var prForBranch2 = new GitHubPullRequest(2, "PR Title", string.Empty, GitHubPullRequestStates.Open, Some.HttpsUri(), false, branch2); gitHubClient .GetPullRequest(branch2) .Returns(prForBranch2); diff --git a/src/Stack.Tests/Commands/Stack/StackStatusCommandHandlerTests.cs b/src/Stack.Tests/Commands/Stack/StackStatusCommandHandlerTests.cs index cbb3c32b..7a1224d7 100644 --- a/src/Stack.Tests/Commands/Stack/StackStatusCommandHandlerTests.cs +++ b/src/Stack.Tests/Commands/Stack/StackStatusCommandHandlerTests.cs @@ -49,7 +49,7 @@ public async Task WhenMultipleBranchesExistInAStack_AndOneHasAPullRequests_Retur inputProvider.Select(Questions.SelectStack, Arg.Any()).Returns("Stack1"); - var pr = new GitHubPullRequest(1, "PR title", "PR body", GitHubPullRequestStates.Open, Some.HttpsUri(), false); + var pr = new GitHubPullRequest(1, "PR title", "PR body", GitHubPullRequestStates.Open, Some.HttpsUri(), false, branch1); gitHubClient.GetPullRequest(branch1).Returns(pr); @@ -112,7 +112,7 @@ public async Task WhenStackNameIsProvided_DoesNotAskForStack_ReturnsStatus() inputProvider.Select(Questions.SelectStack, Arg.Any()).Returns("Stack1"); - var pr = new GitHubPullRequest(1, "PR title", "PR body", GitHubPullRequestStates.Open, Some.HttpsUri(), false); + var pr = new GitHubPullRequest(1, "PR title", "PR body", GitHubPullRequestStates.Open, Some.HttpsUri(), false, branch1); gitHubClient.GetPullRequest(branch1).Returns(pr); @@ -180,7 +180,7 @@ public async Task WhenAllStacksAreRequested_ReturnsStatusOfEachStack() var gitHubClient = Substitute.For(); var handler = new StackStatusCommandHandler(inputProvider, logger, gitClient, gitHubClient, stackConfig); - var pr = new GitHubPullRequest(1, "PR title", "PR body", GitHubPullRequestStates.Open, Some.HttpsUri(), false); + var pr = new GitHubPullRequest(1, "PR title", "PR body", GitHubPullRequestStates.Open, Some.HttpsUri(), false, branch1); gitHubClient .GetPullRequest(branch1) @@ -261,7 +261,7 @@ public async Task WhenAllStacksAreRequested_WithStacksInMultipleRepositories_Ret var gitHubClient = Substitute.For(); var handler = new StackStatusCommandHandler(inputProvider, logger, gitClient, gitHubClient, stackConfig); - var pr = new GitHubPullRequest(1, "PR title", "PR body", GitHubPullRequestStates.Open, Some.HttpsUri(), false); + var pr = new GitHubPullRequest(1, "PR title", "PR body", GitHubPullRequestStates.Open, Some.HttpsUri(), false, branch1); gitHubClient.GetPullRequest(branch1).Returns(pr); @@ -376,7 +376,7 @@ public async Task WhenMultipleBranchesExistInAStack_AndOneNoLongerExistsOnTheRem inputProvider.Select(Questions.SelectStack, Arg.Any()).Returns("Stack1"); - var pr = new GitHubPullRequest(1, "PR title", "PR body", GitHubPullRequestStates.Open, Some.HttpsUri(), false); + var pr = new GitHubPullRequest(1, "PR title", "PR body", GitHubPullRequestStates.Open, Some.HttpsUri(), false, branch2); gitHubClient .GetPullRequest(branch2) @@ -440,7 +440,7 @@ public async Task WhenMultipleBranchesExistInAStack_AndOneNoLongerExistsOnTheRem inputProvider.Select(Questions.SelectStack, Arg.Any()).Returns("Stack1"); - var pr = new GitHubPullRequest(1, "PR title", "PR body", GitHubPullRequestStates.Open, Some.HttpsUri(), false); + var pr = new GitHubPullRequest(1, "PR title", "PR body", GitHubPullRequestStates.Open, Some.HttpsUri(), false, branch2); gitHubClient .GetPullRequest(branch2) @@ -497,7 +497,7 @@ public async Task WhenOnlyOneStackExists_DoesNotAskForStackName_ReturnsStatus() var gitHubClient = Substitute.For(); var handler = new StackStatusCommandHandler(inputProvider, logger, gitClient, gitHubClient, stackConfig); - var pr = new GitHubPullRequest(1, "PR title", "PR body", GitHubPullRequestStates.Open, Some.HttpsUri(), false); + var pr = new GitHubPullRequest(1, "PR title", "PR body", GitHubPullRequestStates.Open, Some.HttpsUri(), false, branch1); gitHubClient .GetPullRequest(branch1) diff --git a/src/Stack.Tests/Commands/Stack/UpdateStackCommandHandlerTests.cs b/src/Stack.Tests/Commands/Stack/UpdateStackCommandHandlerTests.cs index d699aad5..8ea3c3e3 100644 --- a/src/Stack.Tests/Commands/Stack/UpdateStackCommandHandlerTests.cs +++ b/src/Stack.Tests/Commands/Stack/UpdateStackCommandHandlerTests.cs @@ -138,7 +138,7 @@ public async Task WhenABranchInTheStackExistsOnTheRemote_ButThePullRequestIsMerg inputProvider.Select(Questions.SelectStack, Arg.Any()).Returns("Stack1"); - gitHubClient.GetPullRequest(branch1).Returns(new GitHubPullRequest(1, Some.Name(), Some.Name(), GitHubPullRequestStates.Merged, Some.HttpsUri(), false)); + gitHubClient.GetPullRequest(branch1).Returns(new GitHubPullRequest(1, Some.Name(), Some.Name(), GitHubPullRequestStates.Merged, Some.HttpsUri(), false, branch1)); // Act await handler.Handle(new UpdateStackCommandInputs(null, false, true)); diff --git a/src/Stack.Tests/Helpers/TestGitHubRepositoryBuilder.cs b/src/Stack.Tests/Helpers/TestGitHubRepositoryBuilder.cs index c47ec92b..e0021281 100644 --- a/src/Stack.Tests/Helpers/TestGitHubRepositoryBuilder.cs +++ b/src/Stack.Tests/Helpers/TestGitHubRepositoryBuilder.cs @@ -28,6 +28,7 @@ public class TestGitHubPullRequestBuilder string state = GitHubPullRequestStates.Open; Uri url = Some.HttpsUri(); bool draft = false; + string headRefName = Some.Name(); public TestGitHubPullRequestBuilder WithTitle(string title) { @@ -49,7 +50,7 @@ public TestGitHubPullRequestBuilder Merged() public GitHubPullRequest Build() { - return new GitHubPullRequest(number, title, body, state, url, draft); + return new GitHubPullRequest(number, title, body, state, url, draft, headRefName); } } @@ -65,7 +66,7 @@ public GitHubPullRequest CreatePullRequest( bool draft) { var prBody = File.ReadAllText(bodyFilePath).Trim(); - var pr = new GitHubPullRequest(Some.Int(), title, prBody, GitHubPullRequestStates.Open, Some.HttpsUri(), draft); + var pr = new GitHubPullRequest(Some.Int(), title, prBody, GitHubPullRequestStates.Open, Some.HttpsUri(), draft, headBranch); PullRequests.Add(headBranch, pr); return pr; } From c4200f2b33926d348cc853c30f39b8f80311b223 Mon Sep 17 00:00:00 2001 From: Geoff Lamrock Date: Wed, 11 Jun 2025 20:57:19 +1000 Subject: [PATCH 8/8] Fix tests --- .../CreatePullRequestsCommandHandlerTests.cs | 1 - src/Stack.Tests/Helpers/TestGitHubRepositoryBuilder.cs | 9 ++++++++- src/Stack/Commands/Helpers/StackHelpers.cs | 4 +--- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/Stack.Tests/Commands/PullRequests/CreatePullRequestsCommandHandlerTests.cs b/src/Stack.Tests/Commands/PullRequests/CreatePullRequestsCommandHandlerTests.cs index 4d54118f..56911eba 100644 --- a/src/Stack.Tests/Commands/PullRequests/CreatePullRequestsCommandHandlerTests.cs +++ b/src/Stack.Tests/Commands/PullRequests/CreatePullRequestsCommandHandlerTests.cs @@ -170,7 +170,6 @@ public async Task WhenAPullRequestExistForABranch_AndNoneForAnotherBranch_Create var gitClient = new GitClient(logger, repo.GitClientSettings); var handler = new CreatePullRequestsCommandHandler(inputProvider, logger, gitClient, gitHubClient, fileOperations, stackConfig); - inputProvider.Select(Questions.SelectStack, Arg.Any()).Returns("Stack1"); inputProvider .MultiSelect(Questions.SelectPullRequestsToCreate, Arg.Any(), true, Arg.Any>()) diff --git a/src/Stack.Tests/Helpers/TestGitHubRepositoryBuilder.cs b/src/Stack.Tests/Helpers/TestGitHubRepositoryBuilder.cs index e0021281..716085c1 100644 --- a/src/Stack.Tests/Helpers/TestGitHubRepositoryBuilder.cs +++ b/src/Stack.Tests/Helpers/TestGitHubRepositoryBuilder.cs @@ -8,7 +8,8 @@ public class TestGitHubRepositoryBuilder public TestGitHubRepositoryBuilder WithPullRequest(string branch, Action? pullRequestBuilder = null) { - var builder = new TestGitHubPullRequestBuilder(); + var builder = new TestGitHubPullRequestBuilder() + .WithHeadRefName(branch); pullRequestBuilder?.Invoke(builder); pullRequests.Add(branch, builder.Build()); return this; @@ -48,6 +49,12 @@ public TestGitHubPullRequestBuilder Merged() return this; } + public TestGitHubPullRequestBuilder WithHeadRefName(string headRefName) + { + this.headRefName = headRefName; + return this; + } + public GitHubPullRequest Build() { return new GitHubPullRequest(number, title, body, state, url, draft, headRefName); diff --git a/src/Stack/Commands/Helpers/StackHelpers.cs b/src/Stack/Commands/Helpers/StackHelpers.cs index 099e1e60..dec9bd13 100644 --- a/src/Stack/Commands/Helpers/StackHelpers.cs +++ b/src/Stack/Commands/Helpers/StackHelpers.cs @@ -755,9 +755,7 @@ void AppendBranchPullRequestsToList(Branch branch, int indentLevel) // Edit each PR and add to the top of the description // the details of each PR in the stack - var prList = prListBuilder.ToString(); - var prListMarkdown = string.Join(Environment.NewLine, prList); - var prBodyMarkdown = $"{StackConstants.StackMarkerStart}{Environment.NewLine}{stack.PullRequestDescription}{Environment.NewLine}{Environment.NewLine}{prListMarkdown}{Environment.NewLine}{StackConstants.StackMarkerEnd}"; + var prBodyMarkdown = $"{StackConstants.StackMarkerStart}{Environment.NewLine}{stack.PullRequestDescription}{Environment.NewLine}{Environment.NewLine}{prListBuilder}{StackConstants.StackMarkerEnd}"; foreach (var pullRequest in pullRequestsInStack) {