Skip to content

Commit

Permalink
Add git integration (#4)
Browse files Browse the repository at this point in the history
Add git integration with first command

- start work on work package
  - create branch and switch to it
  - convert type and subject to lower case
  - replace whitespace with -
  - drop every other character not being alphanumeric
  • Loading branch information
Kharonus authored Aug 6, 2024
1 parent cca1d5e commit b796b68
Show file tree
Hide file tree
Showing 6 changed files with 309 additions and 12 deletions.
18 changes: 18 additions & 0 deletions cmd/git/git.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package git

import (
"github.com/spf13/cobra"

"github.com/opf/openproject-cli/cmd/git/start"
)

var RootCmd = &cobra.Command{
Use: "git [command]",
Short: "Executes a git related command.",
Long: `This is a command prefix that enables a nested
set of executable commands, related to a git context.`,
}

func init() {
RootCmd.AddCommand(start.RootCmd)
}
13 changes: 13 additions & 0 deletions cmd/git/start/start.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package start

import "github.com/spf13/cobra"

var RootCmd = &cobra.Command{
Use: "start [resource]",
Short: "Starts the work on a resource",
Long: "Creates a branch based on the given resource and switches to it.",
}

func init() {
RootCmd.AddCommand(startWorkPackageCmd)
}
104 changes: 104 additions & 0 deletions cmd/git/start/work_package.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package start

import (
"fmt"
"os"
"regexp"
"strconv"
"strings"

"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
"github.com/spf13/cobra"

"github.com/opf/openproject-cli/components/printer"
"github.com/opf/openproject-cli/components/resources/work_packages"
)

var startWorkPackageCmd = &cobra.Command{
Use: "workpackage [id]",
Short: "Starts the work on a work package",
Long: "Creates a branch based on the workpackage id, subject and type. Switches to the branch after creation.",
Run: startWorkPackage,
}

func startWorkPackage(_ *cobra.Command, args []string) {
id := checkArgumentsForId(args)

repo, err := git.PlainOpen(".")
if err != nil {
printer.ErrorText("No git repository found in the current location.")
return
}

head, err := repo.Head()
handleGitError(err)

worktree, err := repo.Worktree()
handleGitError(err)

branchName, err := deriveBranchName(id)
if err != nil {
printer.Error(err)
return
}

err = worktree.Checkout(&git.CheckoutOptions{
Hash: head.Hash(),
Branch: plumbing.ReferenceName(fmt.Sprintf("refs/heads/%s", branchName)),
Create: true,
Keep: true,
})
handleGitError(err)

printer.Info(fmt.Sprintf("Switched to a new branch: %s", branchName))
}

func checkArgumentsForId(args []string) uint64 {
if len(args) != 1 {
printer.ErrorText(fmt.Sprintf("Expected 1 argument [id], but got %d", len(args)))
os.Exit(1)
}

id, err := strconv.ParseUint(args[0], 10, 64)
if err != nil {
printer.ErrorText(fmt.Sprintf("'%s' is an invalid work package id. Must be a number.", args[0]))
os.Exit(1)
}

return id
}

func handleGitError(err error) {
if err != nil {
printer.ErrorText(fmt.Sprintf("Fatal error on executing git commands: %s", err.Error()))
os.Exit(1)
}
}

func deriveBranchName(id uint64) (string, error) {
workPackage, err := work_packages.Lookup(id)
if err != nil {
return "", err
}

name := fmt.Sprintf(
"%s/%d-%s",
sanitizeString(workPackage.Type),
workPackage.Id,
sanitizeString(workPackage.Subject),
)

return name, nil
}

func sanitizeString(str string) string {
lower := strings.ToLower(str)
return regexp.MustCompile("[^a-zA-Z0-9-/_.]").ReplaceAllStringFunc(lower, func(s string) string {
if s == " " {
return "-"
}

return ""
})
}
2 changes: 2 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/spf13/cobra"

"github.com/opf/openproject-cli/cmd/create"
"github.com/opf/openproject-cli/cmd/git"
"github.com/opf/openproject-cli/cmd/inspect"
"github.com/opf/openproject-cli/cmd/list"
"github.com/opf/openproject-cli/cmd/search"
Expand Down Expand Up @@ -87,5 +88,6 @@ func init() {
inspect.RootCmd,
create.RootCmd,
search.RootCmd,
git.RootCmd,
)
}
29 changes: 25 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,37 @@ module github.com/opf/openproject-cli
go 1.22

require (
github.com/briandowns/spinner v1.23.0
github.com/spf13/cobra v1.8.0
github.com/briandowns/spinner v1.23.1
github.com/go-git/go-git/v5 v5.12.0
github.com/spf13/cobra v1.8.1
)

require (
dario.cat/mergo v1.0.0 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/ProtonMail/go-crypto v1.0.0 // indirect
github.com/cloudflare/circl v1.3.7 // indirect
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/fatih/color v1.7.0 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-git/go-billy/v5 v5.5.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/mattn/go-colorable v0.1.2 // indirect
github.com/mattn/go-isatty v0.0.8 // indirect
github.com/pjbgf/sha1cd v0.3.0 // indirect
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
github.com/skeema/knownhosts v1.2.2 // indirect
github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 // indirect
golang.org/x/term v0.1.0 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/mod v0.12.0 // indirect
golang.org/x/net v0.22.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/term v0.18.0 // indirect
golang.org/x/tools v0.13.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
)
Loading

0 comments on commit b796b68

Please sign in to comment.