Skip to content

Commit

Permalink
Adds cleanup to delete command (#57)
Browse files Browse the repository at this point in the history
  • Loading branch information
geofflamrock authored Nov 21, 2024
1 parent be24c3a commit 6336d29
Show file tree
Hide file tree
Showing 5 changed files with 200 additions and 115 deletions.
53 changes: 30 additions & 23 deletions src/Stack.Tests/Commands/Stack/CleanupStackCommandHandlerTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using FluentAssertions;
using NSubstitute;
using Stack.Commands;
using Stack.Commands.Helpers;
using Stack.Config;
using Stack.Git;
using Stack.Infrastructure;
Expand All @@ -15,10 +16,11 @@ public async Task WhenBranchExistsLocally_ButNotInRemote_BranchIsDeletedLocally(
{
// Arrange
var gitOperations = Substitute.For<IGitOperations>();
var gitHubOperations = Substitute.For<IGitHubOperations>();
var stackConfig = Substitute.For<IStackConfig>();
var inputProvider = Substitute.For<ICleanupStackCommandInputProvider>();
var inputProvider = Substitute.For<IInputProvider>();
var outputProvider = Substitute.For<IOutputProvider>();
var handler = new CleanupStackCommandHandler(inputProvider, outputProvider, gitOperations, stackConfig);
var handler = new CleanupStackCommandHandler(inputProvider, outputProvider, gitOperations, gitHubOperations, stackConfig);

var remoteUri = Some.HttpsUri().ToString();

Expand All @@ -33,8 +35,8 @@ public async Task WhenBranchExistsLocally_ButNotInRemote_BranchIsDeletedLocally(
]);
stackConfig.Load().Returns(stacks);

inputProvider.SelectStack(Arg.Any<List<Config.Stack>>(), Arg.Any<string>()).Returns("Stack1");
inputProvider.ConfirmCleanup().Returns(true);
inputProvider.Select(Questions.SelectStack, Arg.Any<string[]>()).Returns("Stack1");
inputProvider.Confirm(Questions.ConfirmDeleteBranches).Returns(true);

// Act
await handler.Handle(CleanupStackCommandInputs.Empty);
Expand All @@ -48,10 +50,11 @@ public async Task WhenBranchExistsLocally_AndInRemote_BranchIsNotDeletedLocally(
{
// Arrange
var gitOperations = Substitute.For<IGitOperations>();
var gitHubOperations = Substitute.For<IGitHubOperations>();
var stackConfig = Substitute.For<IStackConfig>();
var inputProvider = Substitute.For<ICleanupStackCommandInputProvider>();
var inputProvider = Substitute.For<IInputProvider>();
var outputProvider = Substitute.For<IOutputProvider>();
var handler = new CleanupStackCommandHandler(inputProvider, outputProvider, gitOperations, stackConfig);
var handler = new CleanupStackCommandHandler(inputProvider, outputProvider, gitOperations, gitHubOperations, stackConfig);

var remoteUri = Some.HttpsUri().ToString();

Expand All @@ -66,8 +69,8 @@ public async Task WhenBranchExistsLocally_AndInRemote_BranchIsNotDeletedLocally(
]);
stackConfig.Load().Returns(stacks);

inputProvider.SelectStack(Arg.Any<List<Config.Stack>>(), Arg.Any<string>()).Returns("Stack1");
inputProvider.ConfirmCleanup().Returns(true);
inputProvider.Select(Questions.SelectStack, Arg.Any<string[]>()).Returns("Stack1");
inputProvider.Confirm(Questions.ConfirmDeleteBranches).Returns(true);

// Act
await handler.Handle(CleanupStackCommandInputs.Empty);
Expand All @@ -81,10 +84,11 @@ public async Task WhenConfirmationIsFalse_DoesNotDeleteAnyBranches()
{
// Arrange
var gitOperations = Substitute.For<IGitOperations>();
var gitHubOperations = Substitute.For<IGitHubOperations>();
var stackConfig = Substitute.For<IStackConfig>();
var inputProvider = Substitute.For<ICleanupStackCommandInputProvider>();
var inputProvider = Substitute.For<IInputProvider>();
var outputProvider = Substitute.For<IOutputProvider>();
var handler = new CleanupStackCommandHandler(inputProvider, outputProvider, gitOperations, stackConfig);
var handler = new CleanupStackCommandHandler(inputProvider, outputProvider, gitOperations, gitHubOperations, stackConfig);

var remoteUri = Some.HttpsUri().ToString();

Expand All @@ -99,8 +103,8 @@ public async Task WhenConfirmationIsFalse_DoesNotDeleteAnyBranches()
]);
stackConfig.Load().Returns(stacks);

inputProvider.SelectStack(Arg.Any<List<Config.Stack>>(), Arg.Any<string>()).Returns("Stack1");
inputProvider.ConfirmCleanup().Returns(false);
inputProvider.Select(Questions.SelectStack, Arg.Any<string[]>()).Returns("Stack1");
inputProvider.Confirm(Questions.ConfirmDeleteBranches).Returns(false);

// Act
await handler.Handle(CleanupStackCommandInputs.Empty);
Expand All @@ -114,10 +118,11 @@ public async Task WhenStackNameIsProvided_ItIsNotAskedFor()
{
// Arrange
var gitOperations = Substitute.For<IGitOperations>();
var gitHubOperations = Substitute.For<IGitHubOperations>();
var stackConfig = Substitute.For<IStackConfig>();
var inputProvider = Substitute.For<ICleanupStackCommandInputProvider>();
var inputProvider = Substitute.For<IInputProvider>();
var outputProvider = Substitute.For<IOutputProvider>();
var handler = new CleanupStackCommandHandler(inputProvider, outputProvider, gitOperations, stackConfig);
var handler = new CleanupStackCommandHandler(inputProvider, outputProvider, gitOperations, gitHubOperations, stackConfig);

var remoteUri = Some.HttpsUri().ToString();

Expand All @@ -132,24 +137,25 @@ public async Task WhenStackNameIsProvided_ItIsNotAskedFor()
]);
stackConfig.Load().Returns(stacks);

inputProvider.ConfirmCleanup().Returns(true);
inputProvider.Confirm(Questions.ConfirmDeleteBranches).Returns(true);

// Act
await handler.Handle(new CleanupStackCommandInputs("Stack1", false));

// Assert
inputProvider.DidNotReceive().SelectStack(Arg.Any<List<Config.Stack>>(), Arg.Any<string>());
inputProvider.DidNotReceive().Select(Questions.SelectStack, Arg.Any<string[]>());
}

[Fact]
public async Task WhenForceIsProvided_ItIsNotAskedFor()
{
// Arrange
var gitOperations = Substitute.For<IGitOperations>();
var gitHubOperations = Substitute.For<IGitHubOperations>();
var stackConfig = Substitute.For<IStackConfig>();
var inputProvider = Substitute.For<ICleanupStackCommandInputProvider>();
var inputProvider = Substitute.For<IInputProvider>();
var outputProvider = Substitute.For<IOutputProvider>();
var handler = new CleanupStackCommandHandler(inputProvider, outputProvider, gitOperations, stackConfig);
var handler = new CleanupStackCommandHandler(inputProvider, outputProvider, gitOperations, gitHubOperations, stackConfig);

var remoteUri = Some.HttpsUri().ToString();

Expand All @@ -164,24 +170,25 @@ public async Task WhenForceIsProvided_ItIsNotAskedFor()
]);
stackConfig.Load().Returns(stacks);

inputProvider.SelectStack(Arg.Any<List<Config.Stack>>(), Arg.Any<string>()).Returns("Stack1");
inputProvider.Select(Questions.SelectStack, Arg.Any<string[]>()).Returns("Stack1");

// Act
await handler.Handle(new CleanupStackCommandInputs(null, true));

// Assert
inputProvider.DidNotReceive().ConfirmCleanup();
inputProvider.DidNotReceive().Confirm(Questions.ConfirmDeleteBranches);
}

[Fact]
public async Task WhenStackNameIsProvided_ButStackDoesNotExist_Throws()
{
// Arrange
var gitOperations = Substitute.For<IGitOperations>();
var gitHubOperations = Substitute.For<IGitHubOperations>();
var stackConfig = Substitute.For<IStackConfig>();
var inputProvider = Substitute.For<ICleanupStackCommandInputProvider>();
var inputProvider = Substitute.For<IInputProvider>();
var outputProvider = Substitute.For<IOutputProvider>();
var handler = new CleanupStackCommandHandler(inputProvider, outputProvider, gitOperations, stackConfig);
var handler = new CleanupStackCommandHandler(inputProvider, outputProvider, gitOperations, gitHubOperations, stackConfig);

var remoteUri = Some.HttpsUri().ToString();

Expand All @@ -196,7 +203,7 @@ public async Task WhenStackNameIsProvided_ButStackDoesNotExist_Throws()
]);
stackConfig.Load().Returns(stacks);

inputProvider.ConfirmCleanup().Returns(true);
inputProvider.Confirm(Questions.ConfirmDeleteBranches).Returns(true);

// Act and assert
var invalidStackName = Some.Name();
Expand Down
104 changes: 81 additions & 23 deletions src/Stack.Tests/Commands/Stack/DeleteStackCommandHandlerTests.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using FluentAssertions;
using NSubstitute;
using Stack.Commands;
using Stack.Commands.Helpers;
using Stack.Config;
using Stack.Git;
using Stack.Infrastructure;
using Stack.Tests.Helpers;

namespace Stack.Tests.Commands.Stack;
Expand All @@ -14,9 +16,11 @@ public async Task WhenNoInputsAreProvided_AsksForName_AndConfirmation_AndDeletes
{
// Arrange
var gitOperations = Substitute.For<IGitOperations>();
var gitHubOperations = Substitute.For<IGitHubOperations>();
var stackConfig = Substitute.For<IStackConfig>();
var inputProvider = Substitute.For<IDeleteStackCommandInputProvider>();
var handler = new DeleteStackCommandHandler(inputProvider, gitOperations, stackConfig);
var inputProvider = Substitute.For<IInputProvider>();
var outputProvider = Substitute.For<IOutputProvider>();
var handler = new DeleteStackCommandHandler(inputProvider, outputProvider, gitOperations, gitHubOperations, stackConfig);

var remoteUri = Some.HttpsUri().ToString();

Expand All @@ -33,8 +37,8 @@ public async Task WhenNoInputsAreProvided_AsksForName_AndConfirmation_AndDeletes
.WhenForAnyArgs(s => s.Save(Arg.Any<List<Config.Stack>>()))
.Do(ci => stacks = ci.ArgAt<List<Config.Stack>>(0));

inputProvider.SelectStack(Arg.Any<List<Config.Stack>>(), Arg.Any<string>()).Returns("Stack1");
inputProvider.ConfirmDelete().Returns(true);
inputProvider.Select(Questions.SelectStack, Arg.Any<string[]>()).Returns("Stack1");
inputProvider.Confirm(Questions.ConfirmDeleteStack).Returns(true);

// Act
var response = await handler.Handle(DeleteStackCommandInputs.Empty);
Expand All @@ -52,9 +56,11 @@ public async Task WhenConfirmationIsFalse_DoesNotDeleteStack()
{
// Arrange
var gitOperations = Substitute.For<IGitOperations>();
var gitHubOperations = Substitute.For<IGitHubOperations>();
var stackConfig = Substitute.For<IStackConfig>();
var inputProvider = Substitute.For<IDeleteStackCommandInputProvider>();
var handler = new DeleteStackCommandHandler(inputProvider, gitOperations, stackConfig);
var inputProvider = Substitute.For<IInputProvider>();
var outputProvider = Substitute.For<IOutputProvider>();
var handler = new DeleteStackCommandHandler(inputProvider, outputProvider, gitOperations, gitHubOperations, stackConfig);

var remoteUri = Some.HttpsUri().ToString();

Expand All @@ -71,8 +77,8 @@ public async Task WhenConfirmationIsFalse_DoesNotDeleteStack()
.WhenForAnyArgs(s => s.Save(Arg.Any<List<Config.Stack>>()))
.Do(ci => stacks = ci.ArgAt<List<Config.Stack>>(0));

inputProvider.SelectStack(Arg.Any<List<Config.Stack>>(), Arg.Any<string>()).Returns("Stack1");
inputProvider.ConfirmDelete().Returns(false);
inputProvider.Select(Questions.SelectStack, Arg.Any<string[]>()).Returns("Stack1");
inputProvider.Confirm(Questions.ConfirmDeleteStack).Returns(false);

// Act
var response = await handler.Handle(DeleteStackCommandInputs.Empty);
Expand All @@ -91,9 +97,11 @@ public async Task WhenNameIsProvided_AsksForConfirmation_AndDeletesStack()
{
// Arrange
var gitOperations = Substitute.For<IGitOperations>();
var gitHubOperations = Substitute.For<IGitHubOperations>();
var stackConfig = Substitute.For<IStackConfig>();
var inputProvider = Substitute.For<IDeleteStackCommandInputProvider>();
var handler = new DeleteStackCommandHandler(inputProvider, gitOperations, stackConfig);
var inputProvider = Substitute.For<IInputProvider>();
var outputProvider = Substitute.For<IOutputProvider>();
var handler = new DeleteStackCommandHandler(inputProvider, outputProvider, gitOperations, gitHubOperations, stackConfig);

var remoteUri = Some.HttpsUri().ToString();

Expand All @@ -110,7 +118,7 @@ public async Task WhenNameIsProvided_AsksForConfirmation_AndDeletesStack()
.WhenForAnyArgs(s => s.Save(Arg.Any<List<Config.Stack>>()))
.Do(ci => stacks = ci.ArgAt<List<Config.Stack>>(0));

inputProvider.ConfirmDelete().Returns(true);
inputProvider.Confirm(Questions.ConfirmDeleteStack).Returns(true);

// Act
var response = await handler.Handle(new DeleteStackCommandInputs("Stack1", false));
Expand All @@ -122,17 +130,19 @@ public async Task WhenNameIsProvided_AsksForConfirmation_AndDeletesStack()
new("Stack2", remoteUri, "branch-2", [])
});

inputProvider.DidNotReceive().SelectStack(Arg.Any<List<Config.Stack>>(), Arg.Any<string>());
inputProvider.DidNotReceive().Select(Questions.SelectStack, Arg.Any<string[]>());
}

[Fact]
public async Task WhenForceIsProvided_DoesNotAskForConfirmation_AndDeletesStack()
{
// Arrange
var gitOperations = Substitute.For<IGitOperations>();
var gitHubOperations = Substitute.For<IGitHubOperations>();
var stackConfig = Substitute.For<IStackConfig>();
var inputProvider = Substitute.For<IDeleteStackCommandInputProvider>();
var handler = new DeleteStackCommandHandler(inputProvider, gitOperations, stackConfig);
var inputProvider = Substitute.For<IInputProvider>();
var outputProvider = Substitute.For<IOutputProvider>();
var handler = new DeleteStackCommandHandler(inputProvider, outputProvider, gitOperations, gitHubOperations, stackConfig);

var remoteUri = Some.HttpsUri().ToString();

Expand All @@ -149,7 +159,7 @@ public async Task WhenForceIsProvided_DoesNotAskForConfirmation_AndDeletesStack(
.WhenForAnyArgs(s => s.Save(Arg.Any<List<Config.Stack>>()))
.Do(ci => stacks = ci.ArgAt<List<Config.Stack>>(0));

inputProvider.SelectStack(Arg.Any<List<Config.Stack>>(), Arg.Any<string>()).Returns("Stack1");
inputProvider.Select(Questions.SelectStack, Arg.Any<string[]>()).Returns("Stack1");

// Act
var response = await handler.Handle(new DeleteStackCommandInputs(null, true));
Expand All @@ -161,17 +171,19 @@ public async Task WhenForceIsProvided_DoesNotAskForConfirmation_AndDeletesStack(
new("Stack2", remoteUri, "branch-2", [])
});

inputProvider.DidNotReceive().ConfirmDelete();
inputProvider.DidNotReceive().Confirm(Questions.ConfirmDeleteStack);
}

[Fact]
public async Task WhenNameAndForceAreProvided_DoesNotAskForAnyInput_AndDeletesStack()
{
// Arrange
var gitOperations = Substitute.For<IGitOperations>();
var gitHubOperations = Substitute.For<IGitHubOperations>();
var stackConfig = Substitute.For<IStackConfig>();
var inputProvider = Substitute.For<IDeleteStackCommandInputProvider>();
var handler = new DeleteStackCommandHandler(inputProvider, gitOperations, stackConfig);
var inputProvider = Substitute.For<IInputProvider>();
var outputProvider = Substitute.For<IOutputProvider>();
var handler = new DeleteStackCommandHandler(inputProvider, outputProvider, gitOperations, gitHubOperations, stackConfig);

var remoteUri = Some.HttpsUri().ToString();

Expand Down Expand Up @@ -206,9 +218,11 @@ public async Task WhenStackDoesNotExist_Throws()
{
// Arrange
var gitOperations = Substitute.For<IGitOperations>();
var gitHubOperations = Substitute.For<IGitHubOperations>();
var stackConfig = Substitute.For<IStackConfig>();
var inputProvider = Substitute.For<IDeleteStackCommandInputProvider>();
var handler = new DeleteStackCommandHandler(inputProvider, gitOperations, stackConfig);
var inputProvider = Substitute.For<IInputProvider>();
var outputProvider = Substitute.For<IOutputProvider>();
var handler = new DeleteStackCommandHandler(inputProvider, outputProvider, gitOperations, gitHubOperations, stackConfig);

var remoteUri = Some.HttpsUri().ToString();

Expand All @@ -225,13 +239,57 @@ public async Task WhenStackDoesNotExist_Throws()
.WhenForAnyArgs(s => s.Save(Arg.Any<List<Config.Stack>>()))
.Do(ci => stacks = ci.ArgAt<List<Config.Stack>>(0));

inputProvider.SelectStack(Arg.Any<List<Config.Stack>>(), Arg.Any<string>()).Returns(Some.Name());
inputProvider.ConfirmDelete().Returns(true);
inputProvider.Confirm(Questions.ConfirmDeleteStack).Returns(true);

// Act and assert
await handler
.Invoking(h => h.Handle(DeleteStackCommandInputs.Empty))
.Invoking(h => h.Handle(new DeleteStackCommandInputs(Some.Name(), false)))
.Should()
.ThrowAsync<InvalidOperationException>();
}

[Fact]
public async Task WhenThereAreLocalBranchesThatAreNotInTheRemote_AsksToCleanup_AndDeletesThemBeforeDeletingStack()
{
// Arrange
var gitOperations = Substitute.For<IGitOperations>();
var gitHubOperations = Substitute.For<IGitHubOperations>();
var stackConfig = Substitute.For<IStackConfig>();
var inputProvider = Substitute.For<IInputProvider>();
var outputProvider = Substitute.For<IOutputProvider>();
var handler = new DeleteStackCommandHandler(inputProvider, outputProvider, gitOperations, gitHubOperations, stackConfig);

var remoteUri = Some.HttpsUri().ToString();

gitOperations.GetRemoteUri().Returns(remoteUri);
gitOperations.GetCurrentBranch().Returns("branch-1");
gitOperations.GetBranchesThatExistLocally(Arg.Any<string[]>()).Returns(["branch-1", "branch-3"]);
gitOperations.GetBranchesThatExistInRemote(Arg.Any<string[]>()).Returns(["branch-1"]);

var stacks = new List<Config.Stack>(
[
new("Stack1", remoteUri, "branch-1", ["branch-3"]),
new("Stack2", remoteUri, "branch-2", [])
]);

stackConfig.Load().Returns(stacks);
stackConfig
.WhenForAnyArgs(s => s.Save(Arg.Any<List<Config.Stack>>()))
.Do(ci => stacks = ci.ArgAt<List<Config.Stack>>(0));

inputProvider.Select(Questions.SelectStack, Arg.Any<string[]>()).Returns("Stack1");
inputProvider.Confirm(Questions.ConfirmDeleteStack).Returns(true);
inputProvider.Confirm(Questions.ConfirmDeleteBranches).Returns(true);

// Act
var response = await handler.Handle(DeleteStackCommandInputs.Empty);

// Assert
response.Should().Be(new DeleteStackCommandResponse("Stack1"));
stacks.Should().BeEquivalentTo(new List<Config.Stack>
{
new("Stack2", remoteUri, "branch-2", [])
});
gitOperations.Received().DeleteLocalBranch("branch-3");
}
}
11 changes: 11 additions & 0 deletions src/Stack/Commands/Helpers/Questions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using Spectre.Console;
using Stack.Config;

namespace Stack.Commands.Helpers;

public static class Questions
{
public const string SelectStack = "Select stack:";
public const string ConfirmDeleteStack = "Are you sure you want to delete this stack?";
public const string ConfirmDeleteBranches = "Are you sure you want to delete these local branches?";
}
Loading

0 comments on commit 6336d29

Please sign in to comment.