Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Will it work this time #20

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/Stack/Commands/Helpers/DryRunCommandSettingsBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,6 @@ internal class DryRunCommandSettingsBase : CommandSettingsBase
public bool DryRun { get; init; }

public override GitOperationSettings GetGitOperationSettings() => new(DryRun, Verbose);

public override GitHubOperationSettings GetGitHubOperationSettings() => new(DryRun, Verbose);
}
82 changes: 82 additions & 0 deletions src/Stack/Commands/PullRequests/CreatePullRequestsCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
using System.ComponentModel;
using Spectre.Console;
using Spectre.Console.Cli;
using Stack.Config;
using Stack.Git;

namespace Stack.Commands;

internal class CreatePullRequestsCommandSettings : DryRunCommandSettingsBase
{
[Description("The name of the stack to update.")]
[CommandOption("-n|--name")]
public string? Name { get; init; }
}

internal class CreatePullRequestsCommand(
IAnsiConsole console,
IGitOperations gitOperations,
IGitHubOperations gitHubOperations,
IStackConfig stackConfig) : AsyncCommand<CreatePullRequestsCommandSettings>
{
public override async Task<int> ExecuteAsync(CommandContext context, CreatePullRequestsCommandSettings settings)
{
await Task.CompletedTask;

var stacks = stackConfig.Load();

var remoteUri = gitOperations.GetRemoteUri(settings.GetGitOperationSettings());

var stacksForRemote = stacks.Where(s => s.RemoteUri.Equals(remoteUri, StringComparison.OrdinalIgnoreCase)).ToList();

if (stacksForRemote.Count == 0)
{
console.WriteLine("No stacks found for current repository.");
return 0;
}

var currentBranch = gitOperations.GetCurrentBranch(settings.GetGitOperationSettings());
var stackSelection = settings.Name ?? console.Prompt(Prompts.Stack(stacksForRemote, currentBranch));
var stack = stacksForRemote.First(s => s.Name.Equals(stackSelection, StringComparison.OrdinalIgnoreCase));

console.MarkupLine($"Stack: {stack.Name}");

if (console.Prompt(new ConfirmationPrompt("Are you sure you want to create pull requests for branches in this stack?")))
{
var sourceBranch = stack.SourceBranch;

foreach (var branch in stack.Branches)
{
var existingPullRequest = gitHubOperations.GetPullRequest(branch, settings.GetGitHubOperationSettings());

if (existingPullRequest is not null && existingPullRequest.State != GitHubPullRequestStates.Closed)
{
console.MarkupLine($"Pull request [{existingPullRequest.GetPullRequestColor()} link={existingPullRequest.Url}]#{existingPullRequest.Number}: {existingPullRequest.Title}[/] already exists for branch [blue]{branch}[/] to [blue]{sourceBranch}[/]. Skipping...");
}
else
{
if (gitOperations.DoesRemoteBranchExist(branch, settings.GetGitOperationSettings()))
{
var prTitle = console.Prompt(new TextPrompt<string>($"Pull request title for branch [blue]{branch}[/] to [blue]{sourceBranch}[/]:"));
console.MarkupLine($"Creating pull request for branch [blue]{branch}[/] to [blue]{sourceBranch}[/]");
var pullRequest = gitHubOperations.CreatePullRequest(branch, sourceBranch, prTitle, "test", settings.GetGitHubOperationSettings());

if (pullRequest is not null)
{
console.MarkupLine($"Pull request [{pullRequest.GetPullRequestColor()} link={pullRequest.Url}]#{pullRequest.Number}: {pullRequest.Title}[/] created for branch [blue]{branch}[/] to [blue]{sourceBranch}[/]");
}

sourceBranch = branch;
}
else
{
// Remote branch no longer exists, skip over
console.MarkupLine($"[red]Branch '{branch}' no longer exists on the remote repository. Skipping...[/]");
}
}
}
}

return 0;
}
}
11 changes: 1 addition & 10 deletions src/Stack/Commands/Stack/StackStatusCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -168,16 +168,7 @@ string BuildBranchName(string branch, string? parentBranch, bool isSourceBranchF

if (status.PullRequests.TryGetValue(branch, out var pr))
{
var prStatusColor = Color.Green;
if (pr.State == GitHubPullRequestStates.Merged)
{
prStatusColor = Color.Purple;
}
else if (pr.State == GitHubPullRequestStates.Closed)
{
prStatusColor = Color.Red;
}
branchNameBuilder.Append($" [{prStatusColor} link={pr.Url}]#{pr.Number}: {pr.Title}[/]");
branchNameBuilder.Append($" [{pr.GetPullRequestColor()} link={pr.Url}]#{pr.Number}: {pr.Title}[/]");
}

return branchNameBuilder.ToString();
Expand Down
33 changes: 30 additions & 3 deletions src/Stack/Git/GitHubOperations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,31 @@ internal record GitHubOperationSettings(bool DryRun, bool Verbose)

internal static class GitHubPullRequestStates
{
public static string Open = "OPEN";
public static string Closed = "CLOSED";
public static string Merged = "MERGED";
public const string Open = "OPEN";
public const string Closed = "CLOSED";
public const string Merged = "MERGED";
}

internal record GitHubPullRequest(int Number, string Title, string State, Uri Url);

internal static class GitHubPullRequestExtensionMethods
{
public static Color GetPullRequestColor(this GitHubPullRequest pullRequest)
{
return pullRequest.State switch
{
GitHubPullRequestStates.Open => Color.Green,
GitHubPullRequestStates.Closed => Color.Red,
GitHubPullRequestStates.Merged => Color.Purple,
_ => Color.Default
};
}
}

internal interface IGitHubOperations
{
GitHubPullRequest? GetPullRequest(string branch, GitHubOperationSettings settings);
GitHubPullRequest? CreatePullRequest(string headBranch, string baseBranch, string title, string body, GitHubOperationSettings settings);
}

internal class GitHubOperations(IAnsiConsole console) : IGitHubOperations
Expand All @@ -34,6 +49,18 @@ internal class GitHubOperations(IAnsiConsole console) : IGitHubOperations
return pullRequests.FirstOrDefault();
}

public GitHubPullRequest? CreatePullRequest(string headBranch, string baseBranch, string title, string body, GitHubOperationSettings settings)
{
ExecuteGitHubCommand($"pr create --title \"{title}\" --body \"{body}\" --base {baseBranch} --head {headBranch}", settings);

if (settings.DryRun)
{
return null;
}

return GetPullRequest(headBranch, settings);
}

private string ExecuteGitHubCommandAndReturnOutput(string command, GitHubOperationSettings settings)
{
if (settings.Verbose)
Expand Down
12 changes: 9 additions & 3 deletions src/Stack/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,6 @@
configure.AddCommand<DeleteStackCommand>("delete").WithDescription("Deletes a stack.");
configure.AddCommand<UpdateStackCommand>("update").WithDescription("Updates the branches in a stack.");

// Config commands
configure.AddCommand<OpenConfigCommand>("config").WithDescription("Opens the configuration file in the default editor.");

// Branch commands
configure.AddCommand<BranchCommand>("branch").WithDescription("Create or add a new branch to a stack.");
configure.AddBranch("branches", branch =>
Expand All @@ -41,6 +38,15 @@
branch.AddCommand<AddBranchCommand>("add").WithDescription("Adds an existing branch in a stack.");
});

// Pull request commands
configure.AddBranch("pr", pr =>
{
pr.SetDescription("Manages pull requests for a stack.");
pr.AddCommand<CreatePullRequestsCommand>("create").WithDescription("Creates pull requests for a stack.");
});

// Config commands
configure.AddCommand<OpenConfigCommand>("config").WithDescription("Opens the configuration file in the default editor.");
});

await app.RunAsync(args);
Expand Down
Loading