Skip to content

Commit

Permalink
Creating PR (#3)
Browse files Browse the repository at this point in the history
* introducing generated ql client

Signed-off-by: Vittorio Ballestra <[email protected]>

moved away

Fixed some stupidity

Fixed some stupidity

Minor improvements

removed other queries

removed other queries

minor optimization

showing pending review

creating a pending review

cancel a review

client in/from context

using existing review in reply

using inline editor

Merge pr

* Merge pr

* Merge pr

Co-authored-by: Vittorio Ballestra <[email protected]>
  • Loading branch information
dam0vm3nt and Vittorio Ballestra authored Jan 3, 2023
1 parent 93fd7ae commit 03b2b34
Show file tree
Hide file tree
Showing 24 changed files with 23,511 additions and 800 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ dist/

docs/.graphqlconfig
bazel-*
.ijwb
20 changes: 10 additions & 10 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -738,8 +738,8 @@ go_repository(
go_repository(
name = "com_github_microcosm_cc_bluemonday",
importpath = "github.com/microcosm-cc/bluemonday",
sum = "h1:Z1a//hgsQ4yjC+8zEkV8IWySkXnsxmdSY642CTFQb5Y=",
version = "v1.0.17",
sum = "h1:dNH3e4PSyE4vNX+KlRGHT5KrSvjeUkoNPwEORjffHJg=",
version = "v1.0.21",
)

go_repository(
Expand Down Expand Up @@ -1151,15 +1151,15 @@ go_repository(
go_repository(
name = "org_golang_x_mod",
importpath = "golang.org/x/mod",
sum = "h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=",
version = "v0.3.0",
sum = "h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o=",
version = "v0.6.0-dev.0.20220106191415-9b9b3d81d5e3",
)

go_repository(
name = "org_golang_x_net",
importpath = "golang.org/x/net",
sum = "h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=",
version = "v0.0.0-20220127200216-cd36cc0744dd",
sum = "h1:6e93nYa3hNqAvLr0pD4PN1fFS+gKzp2zAXqrnTCstqU=",
version = "v0.0.0-20221002022538-bcab6841153b",
)

go_repository(
Expand All @@ -1179,8 +1179,8 @@ go_repository(
go_repository(
name = "org_golang_x_sys",
importpath = "golang.org/x/sys",
sum = "h1:OH54vjqzRWmbJ62fjuhxy7AxFFgoHN0/DPc/UrL8cAs=",
version = "v0.0.0-20220319134239-a9b59b0215f8",
sum = "h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg=",
version = "v0.0.0-20220728004956-3c1f35247d10",
)

go_repository(
Expand All @@ -1207,8 +1207,8 @@ go_repository(
go_repository(
name = "org_golang_x_tools",
importpath = "golang.org/x/tools",
sum = "h1:W07d4xkoAUSNOkOzdzXCdFGxT7o2rW4q8M34tB2i//k=",
version = "v0.0.0-20200825202427-b303f430e36d",
sum = "h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20=",
version = "v0.1.10",
)

go_repository(
Expand Down
1 change: 1 addition & 0 deletions cmd/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ go_library(
"prShow.go",
"prStatus.go",
"root.go",
"prNew.go",
],
importpath = "github.com/vballestra/sv/cmd",
visibility = ["//visibility:public"],
Expand Down
64 changes: 64 additions & 0 deletions cmd/prNew.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
Copyright © 2022 NAME HERE <EMAIL ADDRESS>
*/
package cmd

import (
"github.com/pterm/pterm"
"github.com/spf13/cobra"
)

// prNewCmd represents the prNew command
var prNewCmd = &cobra.Command{
Use: "new",
Short: "Create a new PR",
Long: `Create a new PR`,
Run: func(cmd *cobra.Command, args []string) {
sv := GetSv()

if newPrDestBranch == "" {
if currentBranch, err := sv.GetCurrentBranch(); err != nil {
pterm.Fatal.Printfln("no head branch was provided or could be inferred: %v", err)
} else {
newPrDestBranch = currentBranch
}
}

var newPrDescriptionOpt *string
if newPrDescription == "" {
newPrDescriptionOpt = nil
} else {
newPrDescriptionOpt = &newPrDescription
}

if pr, err := sv.CreatePullRequest(newPrBaseBranch, newPrDestBranch, newPrTitle, newPrDescriptionOpt); err != nil {
pterm.Fatal.Printfln("couldn't create a new pr : %v", err)
} else {
pterm.Info.Printfln("New Pr created.\nId: %v\nStatus: %v", pr.GetId(), pr.GetStatus())
}
},
}

var newPrTitle = ""
var newPrDescription = ""

var newPrBaseBranch = ""

var newPrDestBranch = ""

func init() {
prCmd.AddCommand(prNewCmd)

// Here you will define your flags and configuration settings.

// Cobra supports Persistent Flags which will work for this command
// and all subcommands, e.g.:
// prStatusCmd.PersistentFlags().String("foo", "", "A help for foo")

// Cobra supports local flags which will only run when this command
// is called directly, e.g.:
prNewCmd.Flags().StringVarP(&newPrTitle, "title", "T", "", "The new PR title")
prNewCmd.Flags().StringVarP(&newPrDescription, "description", "d", "", "New PR optional description")
prNewCmd.Flags().StringVarP(&newPrBaseBranch, "base", "b", "", "The base branch (required)")
prNewCmd.Flags().StringVarP(&newPrDestBranch, "head", "h", "", "The (optional) head branch")
}
2 changes: 2 additions & 0 deletions cmd/ui/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ go_library(
importpath = "github.com/vballestra/sv/cmd/ui",
visibility = ["//visibility:public"],
deps = [
"//cmd/ui/simpleEditor",
"//sv",
"@com_github_bluekeyes_go_gitdiff//gitdiff",
"@com_github_charmbracelet_bubbles//viewport",
"@com_github_charmbracelet_bubbletea//:bubbletea",
"@com_github_charmbracelet_glamour//:glamour",
"@com_github_charmbracelet_lipgloss//:lipgloss",
"@com_github_erikgeiser_promptkit//confirmation",
"@com_github_itchyny_timefmt_go//:timefmt-go",
"@com_github_pterm_pterm//:pterm",
"@com_github_treilik_bubbleboxer//:bubbleboxer",
],
Expand Down
167 changes: 131 additions & 36 deletions cmd/ui/prViewer.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ import (
"github.com/charmbracelet/glamour"
"github.com/charmbracelet/lipgloss"
"github.com/erikgeiser/promptkit/confirmation"
"github.com/itchyny/timefmt-go"
"github.com/pterm/pterm"
boxer "github.com/treilik/bubbleboxer"
"github.com/vballestra/sv/cmd/ui/simpleEditor"
"github.com/vballestra/sv/sv"
"math"
"os"
Expand All @@ -30,12 +32,13 @@ type Heading struct {

type pullRequestData struct {
sv.PullRequest
checks []sv.Check
reviews []sv.Review
prComments []sv.Comment
commentMap map[string]map[int64][]sv.Comment
files []*gitdiff.File
lastCommitId string
checks []sv.Check
reviews []sv.Review
prComments []sv.Comment
commentMap map[string]map[int64][]sv.Comment
files []*gitdiff.File
lastCommitId string
pendingReview sv.Review
}

func (d *pullRequestData) addComment(path string, old int64, new int64, isNew bool, comment sv.Comment) {
Expand Down Expand Up @@ -64,6 +67,9 @@ func loadPullRequestData(pr sv.PullRequest) (*pullRequestData, error) {
} else if reviews, err := pr.GetReviews(); err != nil {
pterm.Warning.Println("Couldn't read the checks ", err)
return nil, err
} else if pending, err := pr.GetPendingReview(); err != nil {
pterm.Warning.Println("Couldn't read the pending review ", err)
return nil, err
} else if prComments, commentMap, err := pr.GetCommentsByLine(); err != nil {
return nil, err
} else if files, err := pr.GetDiff(); err != nil {
Expand All @@ -75,7 +81,8 @@ func loadPullRequestData(pr sv.PullRequest) (*pullRequestData, error) {
prComments,
commentMap,
files,
pr.GetLastCommitId()}, nil
pr.GetLastCommitId(),
pending}, nil
}
}

Expand Down Expand Up @@ -748,7 +755,10 @@ func (p PullRequestView) Update(m tea.Msg) (tea.Model, tea.Cmd) {
input := confirmation.New(fmt.Sprintf("Want to comment line %05d/%05d", msg.code.old, msg.code.new), confirmation.Yes)
if yes, err := input.RunPrompt(); yes && err == nil {
// Do nothing for now
if comment, err := launchEditor(""); err == nil && comment != "" {
if comment, err := launchEditor("",
simpleEditor.WithWidth{pterm.GetTerminalWidth()},
simpleEditor.WithTitle{"New Comment"},
simpleEditor.WithPlaceholder{"Edit comment"}); err == nil && comment != "" {
isNew := msg.code.code.New()
fn := getFileName(msg.code.file)
lineNum := int(msg.code.new)
Expand All @@ -768,10 +778,13 @@ func (p PullRequestView) Update(m tea.Msg) (tea.Model, tea.Cmd) {
case replyComment:
if _, data := bookmarkAt(&p, COMMENT_CATEGORY, msg.line); data != nil {
if comment, ok := data.(sv.Comment); ok {
input := confirmation.New(fmt.Sprintf("Whant to reply to comment by %s", comment.GetUser().GetDisplayName()), confirmation.Yes)
input := confirmation.New(fmt.Sprintf("Want to reply to comment by %s", comment.GetUser().GetDisplayName()), confirmation.Yes)
if yes, err := input.RunPrompt(); yes && err == nil {
// Do nothing for now
if replyText, err := launchEditor(""); err == nil {
if replyText, err := launchEditor("",
simpleEditor.WithWidth{pterm.GetTerminalWidth()},
simpleEditor.WithTitle{"Reply to Comment"},
simpleEditor.WithPlaceholder{"Edit comment"}); err == nil {
if _, err := p.pullRequest.ReplyToComment(comment, replyText); err != nil {
return p, showErrCmd(err)
} else {
Expand Down Expand Up @@ -821,6 +834,73 @@ func (p PullRequestView) Update(m tea.Msg) (tea.Model, tea.Cmd) {
return p, tea.Quit
case "esc":
return p, tea.Quit
case "R":
if rev := p.pullRequest.pendingReview; rev == nil {
if rev, err := p.pullRequest.StartReview(); err != nil {
return p, showErrCmd(err)
} else {
p.pullRequest.pendingReview = rev
return p, renderPrCmd
}
} else if yes, err := confirmation.New(fmt.Sprintf("Want to approve rev %s ?", rev.GetId()), confirmation.Yes).RunPrompt(); !yes || err != nil {
return p, nil
} else if text, err := launchEditor("",
simpleEditor.WithWidth{pterm.GetTerminalWidth()},
simpleEditor.WithTitle{"Request changes"},
simpleEditor.WithPlaceholder{"Edit review comment"}); err != nil {
return p, nil
} else if err := rev.RequestChanges(&text); err != nil {
return p, showErrCmd(err)
} else {
return p, p.reloadPullRequest()
}
case "C":
if rev := p.pullRequest.pendingReview; rev != nil {
if yes, err := confirmation.New(fmt.Sprintf("Want to cancel rev %s ?", rev.GetId()), confirmation.Yes).RunPrompt(); !yes || err != nil {
return p, nil
} else if err := rev.Cancel(); err != nil {
return p, showErrCmd(err)
} else {
p.pullRequest.pendingReview = nil
return p, renderPrCmd
}
}
case "S":
if rev := p.pullRequest.pendingReview; rev != nil {
if yes, err := confirmation.New(fmt.Sprintf("Want to submit rev %s ?", rev.GetId()), confirmation.Yes).RunPrompt(); !yes || err != nil {
return p, nil
} else if err := rev.Close(nil); err != nil {
return p, showErrCmd(err)
} else {
p.pullRequest.pendingReview = nil
return p, p.reloadPullRequest()
}
}
case "M":
if yes, err := confirmation.New(fmt.Sprintf("Want to merge rev %v ?", p.pullRequest.GetId()), confirmation.Yes).RunPrompt(); !yes || err != nil {
return p, nil
} else if err := p.pullRequest.Merge(); err != nil {
return p, showErrCmd(err)
} else {
return p, p.reloadPullRequest()
}

case "A":
if rev := p.pullRequest.pendingReview; rev != nil {
if text, err := launchEditor("",
simpleEditor.WithWidth{pterm.GetTerminalWidth()},
simpleEditor.WithTitle{"Request changes"},
simpleEditor.WithPlaceholder{"Edit review comment"}); err != nil {
return p, showErrCmd(err)
} else if yes, err := confirmation.New(fmt.Sprintf("Want to approve rev %v ?", rev.GetId()), confirmation.Yes).RunPrompt(); !yes || err != nil {
return p, nil
} else if err := rev.Approve(&text); err != nil {
return p, showErrCmd(err)
} else {
p.pullRequest.pendingReview = nil
return p, p.reloadPullRequest()
}
}
case "v":
newMode := p.layoutMode.withFileView(!p.layoutMode.showFileView)
if tree, err := layoutWidgets(&p.boxer, newMode); err == nil {
Expand Down Expand Up @@ -902,39 +982,47 @@ func (p PullRequestView) Update(m tea.Msg) (tea.Model, tea.Cmd) {
return p, tea.Batch(cmds...)
}

func launchEditor(initialText string) (string, error) {
if file, err := os.CreateTemp("", "comment-*.txt"); err == nil {
if _, err = file.WriteString(initialText); err != nil {
return "", err
}
file.Close()
defer os.Remove(file.Name())
var useEditor = false

// Run editor
var editorPath string
if editorPath = os.Getenv("EDITOR"); editorPath == "" {
editorPath = "vim"
}
func launchEditor(initialText string, opts ...simpleEditor.Opts) (string, error) {

cmd := exec.Command(editorPath, file.Name())
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
if err = cmd.Start(); err != nil {
return "", err
}
if err = cmd.Wait(); err != nil {
return "", err
}
if useEditor {
if file, err := os.CreateTemp("", "comment-*.txt"); err == nil {
if _, err = file.WriteString(initialText); err != nil {
return "", err
}
file.Close()
defer os.Remove(file.Name())

// Run editor
var editorPath string
if editorPath = os.Getenv("EDITOR"); editorPath == "" {
editorPath = "vim"
}

cmd := exec.Command(editorPath, file.Name())
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
if err = cmd.Start(); err != nil {
return "", err
}
if err = cmd.Wait(); err != nil {
return "", err
}

// Read back the file and write it
if content, err := os.ReadFile(file.Name()); err == nil {
return string(content[:]), nil
} else {
return "", err
}

// Read back the file and write it
if content, err := os.ReadFile(file.Name()); err == nil {
return string(content[:]), nil
} else {
return "", err
}

} else {
return "", err
opts = append(opts, simpleEditor.WithValue{initialText})
return simpleEditor.RunEditor(opts...)
}
}

Expand Down Expand Up @@ -1048,6 +1136,13 @@ func (prv *PullRequestView) renderPullRequest() {
}
}

pendingReviewStyle := lipgloss.NewStyle().Width(content.viewport.Width).Background(lipgloss.Color("#00e0e0")).ColorWhitespace(true).Foreground(lipgloss.Color("#000000"))
if perev := pr.pendingReview; perev != nil {
header.header.printf(pendingReviewStyle.Render(fmt.Sprintf("PENDING REVIEW %s SUBMITTED AT %s (C='CANCEL', S='SUBMIT', M='APPROVE', R='REQ. CHANGES')", perev.GetId(), timefmt.Format(perev.GetSubmitedAt(), "%02d/%02m/%Y %H:%M:%S"))))
} else {
header.header.printf("NO PENDING REVIEW (R='Create a new one')")
}

prv.PrintComments(content, header, prv.pullRequest.prComments, content.viewport.Width)

//fmt.Printf("Diff of %d files:\n\n", len(files))
Expand Down
2 changes: 1 addition & 1 deletion cmd/ui/pullRequestHeader.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ type pullRequestHeader struct {
}

func (p pullRequestHeader) measureHeight() int {
return min1(p.maxChecks, len(p.data.checks)) + min1(len(p.data.reviews), p.maxReviews) + 4
return min1(p.maxChecks, len(p.data.checks)) + min1(len(p.data.reviews), p.maxReviews) + 4 + 1
}

func (p pullRequestHeader) Init() tea.Cmd {
Expand Down
Loading

0 comments on commit 03b2b34

Please sign in to comment.