Skip to content

Commit

Permalink
Merge pull request #8 from noahstreller/feature/checkout
Browse files Browse the repository at this point in the history
  • Loading branch information
noahstreller authored Aug 28, 2024
2 parents 09eb9ca + d882a94 commit 442e622
Show file tree
Hide file tree
Showing 4 changed files with 226 additions and 28 deletions.
89 changes: 89 additions & 0 deletions internal/operations/git/branch.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package git

import (
"fmt"
"os/exec"
"strings"
"time"

"github.com/briandowns/spinner"
"github.com/fatih/color"
"github.com/noahstreller/igitt/internal/utilities"
"github.com/noahstreller/igitt/internal/utilities/logger"
)

type BranchResult struct {
Branches []string
CheckedOutBranch string
}

func GetBranches() BranchResult {
var branches []string

progressIndicator := spinner.New(spinner.CharSets[11], 100*time.Millisecond)
progressIndicator.Start()
byteOut, errOut := exec.Command("git", "branch", "-l").CombinedOutput()
progressIndicator.Stop()

branchesAsString := string(byteOut)
branchesAsString = utilities.RemoveLastEmptyLine(branchesAsString)

branches = strings.Split(branchesAsString, "\n")

checkedOutBranch := GetCheckedOutBranch(branches)

branchesTrimmed := trimBranchPrefixes(branches)

if errOut != nil {
logger.ErrorLogger.Println("Error:", errOut, string(byteOut))
utilities.PrintError(string(byteOut))
return BranchResult{}
}

logger.InfoLogger.Println("Branch:", errOut, string(byteOut))

return BranchResult{
Branches: branchesTrimmed,
CheckedOutBranch: checkedOutBranch,
}
}

func GetCheckedOutBranch(branches []string) string {
for _, branch := range branches {
if strings.HasPrefix(branch, "*") {
return strings.TrimSpace(strings.TrimPrefix(branch, "*"))
}
}

return ""
}

func trimBranchPrefix(branch string) string {
return strings.TrimSpace(strings.TrimPrefix(branch, "*"))
}

func trimBranchPrefixes(branches []string) []string {
var trimmedBranches []string

for _, branch := range branches {
trimmedBranches = append(trimmedBranches, trimBranchPrefix(branch))
}

return trimmedBranches
}

func CheckoutBranch(branch string) {
fmt.Println("Checking out branch:", color.HiGreenString(branch))
progressIndicator := spinner.New(spinner.CharSets[11], 100*time.Millisecond)
progressIndicator.Start()
byteOut, errOut := exec.Command("git", "checkout", branch).CombinedOutput()
progressIndicator.Stop()

if errOut != nil {
logger.ErrorLogger.Println("Error checking out:", errOut, string(byteOut))
utilities.PrintError(string(byteOut))
return
}

logger.InfoLogger.Println("Checkout:", errOut, string(byteOut))
}
99 changes: 93 additions & 6 deletions internal/operations/interactive/interactive.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/charmbracelet/huh"
"github.com/charmbracelet/lipgloss"
"github.com/fatih/color"
"github.com/noahstreller/igitt/internal/operations/git"
"github.com/noahstreller/igitt/internal/utilities/logger"
"github.com/rivo/uniseg"
Expand Down Expand Up @@ -46,18 +47,24 @@ type CommandFlowResult struct {
RepoUrlInput string
GitAddArguments string
CommitMessage string
SelectedBranch string
BranchAction string
}

const iconWidth = 4
const iconWidth = 3
const shortcutsEnabled = false
const iconVariant = NerdFont

func bold(s string) string {
return color.New(color.Bold).Sprint(s)
}

func getTitle(command Command) string {
if iconVariant == Emoji {
return command.IconEmoji + strings.Repeat(" ", iconWidth-uniseg.StringWidth(command.IconEmoji)) + command.Name
return command.IconEmoji + strings.Repeat(" ", iconWidth-uniseg.StringWidth(command.IconEmoji)) + bold(command.Name)
}
if iconVariant == NerdFont {
return command.IconNerdFont + strings.Repeat(" ", iconWidth-uniseg.StringWidth(command.IconNerdFont)) + command.Name
return command.IconNerdFont + strings.Repeat(" ", iconWidth-uniseg.StringWidth(command.IconNerdFont)) + bold(command.Name)
}
return command.Icon + strings.Repeat(" ", iconWidth-uniseg.StringWidth(command.Icon)) + command.Name
}
Expand Down Expand Up @@ -102,6 +109,34 @@ func getCommitIcon(variant IconType) string {
return "✎ "
}

func getBranchOptions() []huh.Option[string] {
branchResult := git.GetBranches()
branches := branchResult.Branches

branchOptions := make([]huh.Option[string], len(branches))

for i, b := range branches {
if b == branchResult.CheckedOutBranch {
b = fmt.Sprintf("%s*", b)
}
branchOptions[i] = huh.NewOption(b, b)
}

return branchOptions
}

func getBranchActionOptions() []huh.Option[string] {
branchActions := []string{"Check out", "Delete (wip)", "Rename (wip)"}

branchActionOptions := make([]huh.Option[string], len(branchActions))

for i, b := range branchActions {
branchActionOptions[i] = huh.NewOption(b, b)
}

return branchActionOptions
}

func StartInteractive() {
var commands []Command

Expand Down Expand Up @@ -136,9 +171,22 @@ func StartInteractive() {
Filtering(true).
DescriptionFunc(func() string {
if commandFlowResult.SelectedCommand.NextStep != "none" {
return "\n" + getTitle(commandFlowResult.SelectedCommand) + ": " + commandFlowResult.SelectedCommand.Description + "\n\n" + " " + getNextStepIcon(iconVariant) + " " + "Next step: " + commandFlowResult.SelectedCommand.NextStepTitle + "\n\n"
return fmt.Sprintf(
"\n%s: %s\n\n %s %s\n\n",
getTitle(commandFlowResult.SelectedCommand),
commandFlowResult.SelectedCommand.Description,
getNextStepIcon(iconVariant),
bold("Next step: "+commandFlowResult.SelectedCommand.NextStepTitle),
)
}
return "\n" + getTitle(commandFlowResult.SelectedCommand) + ": " + commandFlowResult.SelectedCommand.Description + "\n\n" + " " + getNoNextStepIcon(iconVariant) + " " + "No next steps" + "\n\n"

return fmt.Sprintf(
"\n%s: %s\n\n %s %s next steps\n\n",
getTitle(commandFlowResult.SelectedCommand),
commandFlowResult.SelectedCommand.Description,
getNoNextStepIcon(iconVariant),
bold("No"),
)
}, &commandFlowResult.SelectedCommand).
Options(commandOptions...).
Value(&commandFlowResult.SelectedCommand),
Expand Down Expand Up @@ -191,7 +239,27 @@ func StartInteractive() {
).WithHideFunc(func() bool {
return commandFlowResult.SelectedCommand.NextStep != "ns-enter-commit-message"
}),
).WithTheme(theme).WithHeight(20).Run()

huh.NewGroup(
huh.NewSelect[string]().
Title("Branch selection").
Description(bold("\n Select a branch\n")).
Options(getBranchOptions()...).
Value(&commandFlowResult.SelectedBranch),
).WithHideFunc(func() bool {
return commandFlowResult.SelectedCommand.NextStep != "ns-choose-branch"
}),

huh.NewGroup(
huh.NewSelect[string]().
Title("Branch action selection").
Description(fmt.Sprintf("\n Select an action for the branch %s\n", commandFlowResult.SelectedBranch)).
Options(getBranchActionOptions()...).
Value(&commandFlowResult.BranchAction),
).WithHideFunc(func() bool {
return commandFlowResult.SelectedCommand.NextStep != "ns-choose-branch" || !(commandFlowResult.SelectedBranch != "")
}),
).WithTheme(theme).WithHeight(len(commands) + 9).Run()

if err != nil {
logger.ErrorLogger.Fatal(err)
Expand All @@ -206,12 +274,31 @@ func runResultingCommand(commandFlow CommandFlowResult) {
git.CloneRepository(commandFlow.RepoUrlInput)
return
}

if commandFlow.SelectedCommand.Id == "op-commit" && commandFlow.CommitMessage != "" {
logger.InfoLogger.Println("commit command selected, sending to operations")
git.CommitChanges(commandFlow.CommitMessage)
return
}

if commandFlow.SelectedCommand.Id == "op-branches" && commandFlow.SelectedBranch != "" && commandFlow.BranchAction != "" {
isCheckedOutAlready := strings.Contains(commandFlow.SelectedBranch, "*")
checkedOutBranchWithoutStar := strings.TrimPrefix(commandFlow.SelectedBranch, "*")

logger.InfoLogger.Printf("branch command selected, sending to action block, isCheckedOutAlready: %v, checkedOutBranchWithoutStar: %s\n", isCheckedOutAlready, checkedOutBranchWithoutStar)

if commandFlow.BranchAction == "Check out" && !isCheckedOutAlready {
logger.InfoLogger.Println("checkout command selected, sending to operations")
git.CheckoutBranch(commandFlow.SelectedBranch)
return
}
if commandFlow.BranchAction == "Check out" && isCheckedOutAlready {
logger.InfoLogger.Println("checkout command selected, not sending to operations, branch already checked out")
fmt.Println("Branch already checked out")
return
}
}

if commandFlow.SelectedCommand.Id == "op-init" {
logger.InfoLogger.Println("init command selected, sending to operations")
git.InitRepository()
Expand Down
55 changes: 33 additions & 22 deletions internal/operations/interactive/operations.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,6 @@
"nextStep": "none",
"nextStepTitle": "None"
},
{
"id": "op-clone",
"name": "Clone",
"shortcut": "cln",
"description": "Clones a remote repository to your local device",
"icon": "",
"icon_emoji": "📂",
"icon_nerdfont": "",
"nextStep": "ns-enter-repo-url",
"nextStepTitle": "Enter remote repository URL"
},
{
"id": "op-init",
"name": "Init",
"shortcut": "none",
"description": "Initialize an empty Git repository in the current folder",
"icon": "",
"icon_emoji": "",
"icon_nerdfont": "",
"nextStep": "none",
"nextStepTitle": "None"
},
{
"id": "op-commit",
"name": "Commit",
Expand Down Expand Up @@ -76,6 +54,39 @@
"nextStep": "none",
"nextStepTitle": "None"
},
{
"id": "op-branches",
"name": "Branches",
"shortcut": "none",
"description": "Manage and check out branches",
"icon": "",
"icon_emoji": "🌿",
"icon_nerdfont": "",
"nextStep": "ns-choose-branch",
"nextStepTitle": "Choose a branch"
},
{
"id": "op-clone",
"name": "Clone",
"shortcut": "cln",
"description": "Clones a remote repository to your local device",
"icon": "",
"icon_emoji": "📂",
"icon_nerdfont": "",
"nextStep": "ns-enter-repo-url",
"nextStepTitle": "Enter remote repository URL"
},
{
"id": "op-init",
"name": "Init",
"shortcut": "none",
"description": "Initialize an empty Git repository in the current folder",
"icon": "",
"icon_emoji": "",
"icon_nerdfont": "",
"nextStep": "none",
"nextStepTitle": "None"
},
{
"id": "exit",
"name": "Exit",
Expand Down
11 changes: 11 additions & 0 deletions internal/utilities/initialize/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,16 @@ func InitializeIgitt() {
},
}

var checkoutCmd = &cobra.Command{
Use: "checkout",
Short: "(cout) Change to a different branch",
Args: cobra.MinimumNArgs(1),
Aliases: []string{"cout"},
Run: func(cmd *cobra.Command, args []string) {
git.CheckoutBranch(args[0])
},
}

var interactiveCmd = &cobra.Command{
Use: "interactive",
Short: "(i) Enter interactive mode",
Expand Down Expand Up @@ -118,6 +128,7 @@ func InitializeIgitt() {
pullCmd,
pushCmd,
statusCmd,
checkoutCmd,
commitCmd,
createAliasScripts,
)
Expand Down

0 comments on commit 442e622

Please sign in to comment.