Skip to content

Commit

Permalink
Merge pull request cli#8423 from guerinoni/autofill-with-body
Browse files Browse the repository at this point in the history
autofill with body
  • Loading branch information
andyfeller committed Feb 1, 2024
2 parents 28c3a40 + 3409d06 commit 201842d
Show file tree
Hide file tree
Showing 5 changed files with 240 additions and 154 deletions.
48 changes: 39 additions & 9 deletions git/client.go
Expand Up @@ -227,8 +227,14 @@ func (c *Client) UncommittedChangeCount(ctx context.Context) (int, error) {
return count, nil
}

func isGitSha(s string) bool {
shaRegex := regexp.MustCompile(`^[0-9a-fA-F]{7,40}$`)
ret := shaRegex.MatchString(s)
return ret
}

func (c *Client) Commits(ctx context.Context, baseRef, headRef string) ([]*Commit, error) {
args := []string{"-c", "log.ShowSignature=false", "log", "--pretty=format:%H,%s", "--cherry", fmt.Sprintf("%s...%s", baseRef, headRef)}
args := []string{"-c", "log.ShowSignature=false", "log", "--pretty=format:%H,%s,%b", "--cherry", fmt.Sprintf("%s...%s", baseRef, headRef)}
cmd, err := c.Command(ctx, args...)
if err != nil {
return nil, err
Expand All @@ -240,15 +246,39 @@ func (c *Client) Commits(ctx context.Context, baseRef, headRef string) ([]*Commi
commits := []*Commit{}
sha := 0
title := 1
for _, line := range outputLines(out) {
split := strings.SplitN(line, ",", 2)
if len(split) != 2 {
continue
body := 2
lines := outputLines(out)
for i := 0; i < len(lines); i++ {
split := strings.SplitN(lines[i], ",", 3)
if isGitSha(split[sha]) {
c := &Commit{
Sha: split[sha],
Title: split[title],
}

if len(split) == 2 {
commits = append(commits, c)
continue
}

c.Body = split[body]
// This consumes all lines until the next commit and adds them to the body.
for {
i++
if i >= len(lines) {
break
}

possibleSplit := strings.SplitN(lines[i], ",", 3)
if len(possibleSplit) > 2 && isGitSha(possibleSplit[sha]) {
i--
break
}
c.Body += "\n"
c.Body += lines[i]
}
commits = append(commits, c)
}
commits = append(commits, &Commit{
Sha: split[sha],
Title: split[title],
})
}
if len(commits) == 0 {
return nil, fmt.Errorf("could not find any commits between %s and %s", baseRef, headRef)
Expand Down
16 changes: 13 additions & 3 deletions git/client_test.go
Expand Up @@ -471,22 +471,32 @@ func TestClientCommits(t *testing.T) {
{
name: "get commits",
cmdStdout: "6a6872b918c601a0e730710ad8473938a7516d30,testing testability test",
wantCmdArgs: `path/to/git -c log.ShowSignature=false log --pretty=format:%H,%s --cherry SHA1...SHA2`,
wantCmdArgs: `path/to/git -c log.ShowSignature=false log --pretty=format:%H,%s,%b --cherry SHA1...SHA2`,
wantCommits: []*Commit{{
Sha: "6a6872b918c601a0e730710ad8473938a7516d30",
Title: "testing testability test",
}},
},
{
name: "get commits with body",
cmdStdout: "6a6872b918c601a0e730710ad8473938a7516d30,testing testability test,This is the body",
wantCmdArgs: `path/to/git -c log.ShowSignature=false log --pretty=format:%H,%s,%b --cherry SHA1...SHA2`,
wantCommits: []*Commit{{
Sha: "6a6872b918c601a0e730710ad8473938a7516d30",
Title: "testing testability test",
Body: "This is the body",
}},
},
{
name: "no commits between SHAs",
wantCmdArgs: `path/to/git -c log.ShowSignature=false log --pretty=format:%H,%s --cherry SHA1...SHA2`,
wantCmdArgs: `path/to/git -c log.ShowSignature=false log --pretty=format:%H,%s,%b --cherry SHA1...SHA2`,
wantErrorMsg: "could not find any commits between SHA1 and SHA2",
},
{
name: "git error",
cmdExitStatus: 1,
cmdStderr: "git error message",
wantCmdArgs: `path/to/git -c log.ShowSignature=false log --pretty=format:%H,%s --cherry SHA1...SHA2`,
wantCmdArgs: `path/to/git -c log.ShowSignature=false log --pretty=format:%H,%s,%b --cherry SHA1...SHA2`,
wantErrorMsg: "failed to run git: git error message",
},
}
Expand Down
1 change: 1 addition & 0 deletions git/objects.go
Expand Up @@ -67,6 +67,7 @@ func (r TrackingRef) String() string {
type Commit struct {
Sha string
Title string
Body string
}

type BranchConfig struct {
Expand Down
51 changes: 33 additions & 18 deletions pkg/cmd/pr/create/create.go
Expand Up @@ -45,6 +45,7 @@ type CreateOptions struct {
RepoOverride string

Autofill bool
FillVerbose bool
FillFirst bool
WebMode bool
RecoverFile string
Expand Down Expand Up @@ -163,6 +164,14 @@ func NewCmdCreate(f *cmdutil.Factory, runF func(*CreateOptions) error) *cobra.Co
return cmdutil.FlagErrorf("`--fill` is not supported with `--fill-first`")
}

if opts.FillVerbose && opts.FillFirst {
return cmdutil.FlagErrorf("`--fill-verbose` is not supported with `--fill-first`")
}

if opts.FillVerbose && opts.Autofill {
return cmdutil.FlagErrorf("`--fill-verbose` is not supported with `--fill`")
}

opts.BodyProvided = cmd.Flags().Changed("body")
if bodyFile != "" {
b, err := cmdutil.ReadFile(bodyFile, opts.IO.In)
Expand All @@ -177,8 +186,8 @@ func NewCmdCreate(f *cmdutil.Factory, runF func(*CreateOptions) error) *cobra.Co
return cmdutil.FlagErrorf("`--template` is not supported when using `--body` or `--body-file`")
}

if !opts.IO.CanPrompt() && !opts.WebMode && !(opts.Autofill || opts.FillFirst) && (!opts.TitleProvided || !opts.BodyProvided) {
return cmdutil.FlagErrorf("must provide `--title` and `--body` (or `--fill` or `fill-first`) when not running interactively")
if !opts.IO.CanPrompt() && !opts.WebMode && !(opts.FillVerbose || opts.Autofill || opts.FillFirst) && (!opts.TitleProvided || !opts.BodyProvided) {
return cmdutil.FlagErrorf("must provide `--title` and `--body` (or `--fill` or `fill-first` or `--fillverbose`) when not running interactively")
}

if runF != nil {
Expand All @@ -196,6 +205,7 @@ func NewCmdCreate(f *cmdutil.Factory, runF func(*CreateOptions) error) *cobra.Co
fl.StringVarP(&opts.BaseBranch, "base", "B", "", "The `branch` into which you want your code merged")
fl.StringVarP(&opts.HeadBranch, "head", "H", "", "The `branch` that contains commits for your pull request (default: current branch)")
fl.BoolVarP(&opts.WebMode, "web", "w", false, "Open the web browser to create a pull request")
fl.BoolVarP(&opts.FillVerbose, "fill-verbose", "", false, "Use commits msg+body for description")
fl.BoolVarP(&opts.Autofill, "fill", "f", false, "Use commit info for title and body")
fl.BoolVar(&opts.FillFirst, "fill-first", false, "Use first commit info for title and body")
fl.StringSliceVarP(&opts.Reviewers, "reviewer", "r", nil, "Request reviews from people or teams by their `handle`")
Expand Down Expand Up @@ -292,7 +302,7 @@ func createRun(opts *CreateOptions) (err error) {
ghrepo.FullName(ctx.BaseRepo))
}

if opts.Autofill || opts.FillFirst || (opts.TitleProvided && opts.BodyProvided) {
if opts.FillVerbose || opts.Autofill || opts.FillFirst || (opts.TitleProvided && opts.BodyProvided) {
err = handlePush(*opts, *ctx)
if err != nil {
return
Expand Down Expand Up @@ -403,7 +413,9 @@ func createRun(opts *CreateOptions) (err error) {
return
}

func initDefaultTitleBody(ctx CreateContext, state *shared.IssueMetadataState, useFirstCommit bool) error {
var regexPattern = regexp.MustCompile(`(?m)^`)

func initDefaultTitleBody(ctx CreateContext, state *shared.IssueMetadataState, useFirstCommit bool, addBody bool) error {
baseRef := ctx.BaseTrackingBranch
headRef := ctx.HeadBranch
gitClient := ctx.GitClient
Expand All @@ -412,19 +424,24 @@ func initDefaultTitleBody(ctx CreateContext, state *shared.IssueMetadataState, u
if err != nil {
return err
}
if len(commits) == 1 || useFirstCommit {
commitIndex := len(commits) - 1
state.Title = commits[commitIndex].Title
body, err := gitClient.CommitBody(context.Background(), commits[commitIndex].Sha)
if err != nil {
return err
}
state.Body = body

if useFirstCommit {
state.Title = commits[len(commits)-1].Title
state.Body = commits[len(commits)-1].Body
} else {
state.Title = humanize(headRef)
var body strings.Builder
for i := len(commits) - 1; i >= 0; i-- {
fmt.Fprintf(&body, "- %s\n", commits[i].Title)
fmt.Fprintf(&body, "- **%s**\n", commits[i].Title)
if addBody {
x := regexPattern.ReplaceAllString(commits[i].Body, " ")
fmt.Fprintf(&body, "%s", x)

if i > 0 {
fmt.Fprintln(&body)
fmt.Fprintln(&body)
}
}
}
state.Body = body.String()
}
Expand Down Expand Up @@ -495,9 +512,9 @@ func NewIssueState(ctx CreateContext, opts CreateOptions) (*shared.IssueMetadata
Draft: opts.IsDraft,
}

if opts.Autofill || opts.FillFirst || !opts.TitleProvided || !opts.BodyProvided {
err := initDefaultTitleBody(ctx, state, opts.FillFirst)
if err != nil && (opts.Autofill || opts.FillFirst) {
if opts.FillVerbose || opts.Autofill || opts.FillFirst || !opts.TitleProvided || !opts.BodyProvided {
err := initDefaultTitleBody(ctx, state, opts.FillFirst, opts.FillVerbose)
if err != nil && (opts.FillVerbose || opts.Autofill || opts.FillFirst) {
return nil, fmt.Errorf("could not compute title or body defaults: %w", err)
}
}
Expand Down Expand Up @@ -659,7 +676,6 @@ func NewCreateContext(opts *CreateOptions) (*CreateContext, error) {
Client: client,
GitClient: gitClient,
}, nil

}

func getRemotes(opts *CreateOptions) (ghContext.Remotes, error) {
Expand Down Expand Up @@ -716,7 +732,6 @@ func previewPR(opts CreateOptions, openURL string) error {
fmt.Fprintf(opts.IO.ErrOut, "Opening %s in your browser.\n", text.DisplayURL(openURL))
}
return opts.Browser.Browse(openURL)

}

func handlePush(opts CreateOptions, ctx CreateContext) error {
Expand Down

0 comments on commit 201842d

Please sign in to comment.