From 6dfae58b47e5ee0335c013d1f2b4638497c413a6 Mon Sep 17 00:00:00 2001 From: Federico Guerinoni Date: Tue, 5 Dec 2023 22:54:52 +0100 Subject: [PATCH 1/3] git: Return body from list of commits This allow to use body of every commits between two ref. --- git/client.go | 18 +++++++++++++----- git/client_test.go | 6 +++--- git/objects.go | 1 + 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/git/client.go b/git/client.go index 3ac6a475451..ca004cdcec3 100644 --- a/git/client.go +++ b/git/client.go @@ -228,7 +228,7 @@ func (c *Client) UncommittedChangeCount(ctx context.Context) (int, error) { } 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 @@ -240,15 +240,23 @@ func (c *Client) Commits(ctx context.Context, baseRef, headRef string) ([]*Commi commits := []*Commit{} sha := 0 title := 1 + body := 2 for _, line := range outputLines(out) { - split := strings.SplitN(line, ",", 2) - if len(split) != 2 { + split := strings.Split(line, ",") + if len(split) < 2 { continue } - commits = append(commits, &Commit{ + + c := &Commit{ Sha: split[sha], Title: split[title], - }) + } + + if len(split) > 2 { + c.Body = split[body] + } + + commits = append(commits, c) } if len(commits) == 0 { return nil, fmt.Errorf("could not find any commits between %s and %s", baseRef, headRef) diff --git a/git/client_test.go b/git/client_test.go index 841a496da9a..f11e4909821 100644 --- a/git/client_test.go +++ b/git/client_test.go @@ -471,7 +471,7 @@ 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", @@ -479,14 +479,14 @@ func TestClientCommits(t *testing.T) { }, { 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", }, } diff --git a/git/objects.go b/git/objects.go index 952b6c335a6..c33d92b7cb2 100644 --- a/git/objects.go +++ b/git/objects.go @@ -67,6 +67,7 @@ func (r TrackingRef) String() string { type Commit struct { Sha string Title string + Body string } type BranchConfig struct { From 42613172bd1a83a555dcd4f3d688c502277c5cd4 Mon Sep 17 00:00:00 2001 From: Federico Guerinoni Date: Tue, 5 Dec 2023 22:55:48 +0100 Subject: [PATCH 2/3] pr: Add flag fillverbose This is used to fill the body of PR with all commits msg + body of every commits because there can be lot of useful information. Signed-off-by: Federico Guerinoni --- git/client.go | 46 ++++-- git/client_test.go | 10 ++ pkg/cmd/pr/create/create.go | 49 ++++-- pkg/cmd/pr/create/create_test.go | 276 +++++++++++++++++-------------- 4 files changed, 229 insertions(+), 152 deletions(-) diff --git a/git/client.go b/git/client.go index ca004cdcec3..21adc8bb12b 100644 --- a/git/client.go +++ b/git/client.go @@ -227,6 +227,12 @@ 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,%b", "--cherry", fmt.Sprintf("%s...%s", baseRef, headRef)} cmd, err := c.Command(ctx, args...) @@ -241,22 +247,38 @@ func (c *Client) Commits(ctx context.Context, baseRef, headRef string) ([]*Commi sha := 0 title := 1 body := 2 - for _, line := range outputLines(out) { - split := strings.Split(line, ",") - if len(split) < 2 { - continue - } + 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], + } - c := &Commit{ - Sha: split[sha], - Title: split[title], - } + if len(split) == 2 { + commits = append(commits, c) + continue + } - if len(split) > 2 { 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 + } - commits = append(commits, c) + 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) + } } if len(commits) == 0 { return nil, fmt.Errorf("could not find any commits between %s and %s", baseRef, headRef) diff --git a/git/client_test.go b/git/client_test.go index f11e4909821..a1183b08d26 100644 --- a/git/client_test.go +++ b/git/client_test.go @@ -477,6 +477,16 @@ func TestClientCommits(t *testing.T) { 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,%b --cherry SHA1...SHA2`, diff --git a/pkg/cmd/pr/create/create.go b/pkg/cmd/pr/create/create.go index a8907aa3f30..809c83128b9 100644 --- a/pkg/cmd/pr/create/create.go +++ b/pkg/cmd/pr/create/create.go @@ -45,6 +45,7 @@ type CreateOptions struct { RepoOverride string Autofill bool + FillVerbose bool FillFirst bool WebMode bool RecoverFile string @@ -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) @@ -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 { @@ -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`") @@ -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 @@ -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 @@ -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) + 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() } @@ -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) } } @@ -659,7 +676,6 @@ func NewCreateContext(opts *CreateOptions) (*CreateContext, error) { Client: client, GitClient: gitClient, }, nil - } func getRemotes(opts *CreateOptions) (ghContext.Remotes, error) { @@ -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 { diff --git a/pkg/cmd/pr/create/create_test.go b/pkg/cmd/pr/create/create_test.go index 2c71ab39408..c088e4169d4 100644 --- a/pkg/cmd/pr/create/create_test.go +++ b/pkg/cmd/pr/create/create_test.go @@ -279,9 +279,9 @@ func Test_createRun(t *testing.T) { reg.Register( httpmock.GraphQL(`mutation PullRequestCreate\b`), httpmock.GraphQLMutation(` - { "data": { "createPullRequest": { "pullRequest": { - "URL": "https://github.com/OWNER/REPO/pull/12" - } } } }`, + { "data": { "createPullRequest": { "pullRequest": { + "URL": "https://github.com/OWNER/REPO/pull/12" + } } } }`, func(input map[string]interface{}) { assert.Equal(t, "REPOID", input["repositoryId"]) assert.Equal(t, "my title", input["title"]) @@ -318,9 +318,9 @@ func Test_createRun(t *testing.T) { reg.Register( httpmock.GraphQL(`mutation PullRequestCreate\b`), httpmock.GraphQLMutation(` - { "data": { "createPullRequest": { "pullRequest": { - "URL": "https://github.com/OWNER/REPO/pull/12" - } } } }`, func(input map[string]interface{}) { + { "data": { "createPullRequest": { "pullRequest": { + "URL": "https://github.com/OWNER/REPO/pull/12" + } } } }`, func(input map[string]interface{}) { assert.Equal(t, "REPOID", input["repositoryId"].(string)) assert.Equal(t, "my title", input["title"].(string)) assert.Equal(t, "my body", input["body"].(string)) @@ -366,11 +366,11 @@ func Test_createRun(t *testing.T) { reg.Register( httpmock.GraphQL(`mutation PullRequestCreate\b`), httpmock.GraphQLMutation(` - { "data": { "createPullRequest": { "pullRequest": { - "id": "PullRequest#1", - "URL": "https://github.com/OWNER/REPO/pull/12" - } } } } - `, func(input map[string]interface{}) { + { "data": { "createPullRequest": { "pullRequest": { + "id": "PullRequest#1", + "URL": "https://github.com/OWNER/REPO/pull/12" + } } } } + `, func(input map[string]interface{}) { assert.Equal(t, "REPOID", input["repositoryId"].(string)) assert.Equal(t, "my title", input["title"].(string)) assert.Equal(t, "my body", input["body"].(string)) @@ -381,10 +381,10 @@ func Test_createRun(t *testing.T) { reg.Register( httpmock.GraphQL(`mutation UpdateProjectV2Items\b`), httpmock.GraphQLQuery(` - { "data": { "add_000": { "item": { - "id": "1" - } } } } - `, func(mutations string, inputs map[string]interface{}) { + { "data": { "add_000": { "item": { + "id": "1" + } } } } + `, func(mutations string, inputs map[string]interface{}) { variables, err := json.Marshal(inputs) assert.NoError(t, err) expectedMutations := "mutation UpdateProjectV2Items($input_000: AddProjectV2ItemByIdInput!) {add_000: addProjectV2ItemById(input: $input_000) { item { id } }}" @@ -428,10 +428,10 @@ func Test_createRun(t *testing.T) { reg.Register( httpmock.GraphQL(`mutation PullRequestCreate\b`), httpmock.GraphQLMutation(` - { "data": { "createPullRequest": { "pullRequest": { - "URL": "https://github.com/OWNER/REPO/pull/12" - } } } } - `, func(input map[string]interface{}) { + { "data": { "createPullRequest": { "pullRequest": { + "URL": "https://github.com/OWNER/REPO/pull/12" + } } } } + `, func(input map[string]interface{}) { assert.Equal(t, false, input["maintainerCanModify"].(bool)) assert.Equal(t, "REPOID", input["repositoryId"].(string)) assert.Equal(t, "my title", input["title"].(string)) @@ -475,16 +475,16 @@ func Test_createRun(t *testing.T) { reg.Register( httpmock.REST("POST", "repos/OWNER/REPO/forks"), httpmock.StatusStringResponse(201, ` - { "node_id": "NODEID", - "name": "REPO", - "owner": {"login": "monalisa"} - }`)) + { "node_id": "NODEID", + "name": "REPO", + "owner": {"login": "monalisa"} + }`)) reg.Register( httpmock.GraphQL(`mutation PullRequestCreate\b`), httpmock.GraphQLMutation(` - { "data": { "createPullRequest": { "pullRequest": { - "URL": "https://github.com/OWNER/REPO/pull/12" - }}}}`, func(input map[string]interface{}) { + { "data": { "createPullRequest": { "pullRequest": { + "URL": "https://github.com/OWNER/REPO/pull/12" + }}}}`, func(input map[string]interface{}) { assert.Equal(t, "REPOID", input["repositoryId"].(string)) assert.Equal(t, "master", input["baseRefName"].(string)) assert.Equal(t, "monalisa:feature", input["headRefName"].(string)) @@ -541,9 +541,9 @@ func Test_createRun(t *testing.T) { reg.Register( httpmock.GraphQL(`mutation PullRequestCreate\b`), httpmock.GraphQLMutation(` - { "data": { "createPullRequest": { "pullRequest": { - "URL": "https://github.com/OWNER/REPO/pull/12" - } } } }`, func(input map[string]interface{}) { + { "data": { "createPullRequest": { "pullRequest": { + "URL": "https://github.com/OWNER/REPO/pull/12" + } } } }`, func(input map[string]interface{}) { assert.Equal(t, "REPOID", input["repositoryId"].(string)) assert.Equal(t, "master", input["baseRefName"].(string)) assert.Equal(t, "monalisa:feature", input["headRefName"].(string)) @@ -552,9 +552,9 @@ func Test_createRun(t *testing.T) { cmdStubs: func(cs *run.CommandStubber) { cs.Register(`git config --get-regexp \^branch\\\.feature\\\.`, 1, "") // determineTrackingBranch cs.Register("git show-ref --verify", 0, heredoc.Doc(` - deadbeef HEAD - deadb00f refs/remotes/upstream/feature - deadbeef refs/remotes/origin/feature`)) // determineTrackingBranch + deadbeef HEAD + deadb00f refs/remotes/upstream/feature + deadbeef refs/remotes/origin/feature`)) // determineTrackingBranch }, expectedOut: "https://github.com/OWNER/REPO/pull/12\n", expectedErrOut: "\nCreating pull request for monalisa:feature into master in OWNER/REPO\n\n", @@ -573,10 +573,10 @@ func Test_createRun(t *testing.T) { reg.Register( httpmock.GraphQL(`mutation PullRequestCreate\b`), httpmock.GraphQLMutation(` - { "data": { "createPullRequest": { "pullRequest": { - "URL": "https://github.com/OWNER/REPO/pull/12" - } } } } - `, func(input map[string]interface{}) { + { "data": { "createPullRequest": { "pullRequest": { + "URL": "https://github.com/OWNER/REPO/pull/12" + } } } } + `, func(input map[string]interface{}) { assert.Equal(t, "REPOID", input["repositoryId"].(string)) assert.Equal(t, "master", input["baseRefName"].(string)) assert.Equal(t, "my-feat2", input["headRefName"].(string)) @@ -584,13 +584,13 @@ func Test_createRun(t *testing.T) { }, cmdStubs: func(cs *run.CommandStubber) { cs.Register(`git config --get-regexp \^branch\\\.feature\\\.`, 0, heredoc.Doc(` - branch.feature.remote origin - branch.feature.merge refs/heads/my-feat2 - `)) // determineTrackingBranch + branch.feature.remote origin + branch.feature.merge refs/heads/my-feat2 + `)) // determineTrackingBranch cs.Register("git show-ref --verify", 0, heredoc.Doc(` - deadbeef HEAD - deadbeef refs/remotes/origin/my-feat2 - `)) // determineTrackingBranch + deadbeef HEAD + deadbeef refs/remotes/origin/my-feat2 + `)) // determineTrackingBranch }, expectedOut: "https://github.com/OWNER/REPO/pull/12\n", expectedErrOut: "\nCreating pull request for my-feat2 into master in OWNER/REPO\n\n", @@ -609,25 +609,25 @@ func Test_createRun(t *testing.T) { reg.Register( httpmock.GraphQL(`query PullRequestTemplates\b`), httpmock.StringResponse(` - { "data": { "repository": { "pullRequestTemplates": [ - { "filename": "template1", - "body": "this is a bug" }, - { "filename": "template2", - "body": "this is a enhancement" } - ] } } }`)) + { "data": { "repository": { "pullRequestTemplates": [ + { "filename": "template1", + "body": "this is a bug" }, + { "filename": "template2", + "body": "this is a enhancement" } + ] } } }`)) reg.Register( httpmock.GraphQL(`mutation PullRequestCreate\b`), httpmock.GraphQLMutation(` - { "data": { "createPullRequest": { "pullRequest": { - "URL": "https://github.com/OWNER/REPO/pull/12" - } } } } - `, func(input map[string]interface{}) { + { "data": { "createPullRequest": { "pullRequest": { + "URL": "https://github.com/OWNER/REPO/pull/12" + } } } } + `, func(input map[string]interface{}) { assert.Equal(t, "my title", input["title"].(string)) assert.Equal(t, "- commit 1\n- commit 0\n\nthis is a bug", input["body"].(string)) })) }, cmdStubs: func(cs *run.CommandStubber) { - cs.Register(`git( .+)? log( .+)? origin/master\.\.\.feature`, 0, "1234567890,commit 0\n2345678901,commit 1") + cs.Register(`git( .+)? log( .+)? origin/master\.\.\.feature`, 0, "d3476a1,commit 0\n7a6ea13,commit 1") }, promptStubs: func(pm *prompter.PrompterMock) { pm.MarkdownEditorFunc = func(p, d string, ba bool) (string, error) { @@ -671,39 +671,39 @@ func Test_createRun(t *testing.T) { reg.Register( httpmock.GraphQL(`query RepositoryResolveMetadataIDs\b`), httpmock.StringResponse(` - { "data": { - "u000": { "login": "MonaLisa", "id": "MONAID" }, - "u001": { "login": "hubot", "id": "HUBOTID" }, - "repository": { - "l000": { "name": "bug", "id": "BUGID" }, - "l001": { "name": "TODO", "id": "TODOID" } - }, - "organization": { - "t000": { "slug": "core", "id": "COREID" }, - "t001": { "slug": "robots", "id": "ROBOTID" } - } - } } - `)) + { "data": { + "u000": { "login": "MonaLisa", "id": "MONAID" }, + "u001": { "login": "hubot", "id": "HUBOTID" }, + "repository": { + "l000": { "name": "bug", "id": "BUGID" }, + "l001": { "name": "TODO", "id": "TODOID" } + }, + "organization": { + "t000": { "slug": "core", "id": "COREID" }, + "t001": { "slug": "robots", "id": "ROBOTID" } + } + } } + `)) reg.Register( httpmock.GraphQL(`query RepositoryMilestoneList\b`), httpmock.StringResponse(` - { "data": { "repository": { "milestones": { - "nodes": [ - { "title": "GA", "id": "GAID" }, - { "title": "Big One.oh", "id": "BIGONEID" } - ], - "pageInfo": { "hasNextPage": false } - } } } } - `)) + { "data": { "repository": { "milestones": { + "nodes": [ + { "title": "GA", "id": "GAID" }, + { "title": "Big One.oh", "id": "BIGONEID" } + ], + "pageInfo": { "hasNextPage": false } + } } } } + `)) mockRetrieveProjects(t, reg) reg.Register( httpmock.GraphQL(`mutation PullRequestCreate\b`), httpmock.GraphQLMutation(` - { "data": { "createPullRequest": { "pullRequest": { - "id": "NEWPULLID", - "URL": "https://github.com/OWNER/REPO/pull/12" - } } } } - `, func(inputs map[string]interface{}) { + { "data": { "createPullRequest": { "pullRequest": { + "id": "NEWPULLID", + "URL": "https://github.com/OWNER/REPO/pull/12" + } } } } + `, func(inputs map[string]interface{}) { assert.Equal(t, "TITLE", inputs["title"]) assert.Equal(t, "BODY", inputs["body"]) if v, ok := inputs["assigneeIds"]; ok { @@ -716,10 +716,10 @@ func Test_createRun(t *testing.T) { reg.Register( httpmock.GraphQL(`mutation PullRequestCreateMetadata\b`), httpmock.GraphQLMutation(` - { "data": { "updatePullRequest": { - "clientMutationId": "" - } } } - `, func(inputs map[string]interface{}) { + { "data": { "updatePullRequest": { + "clientMutationId": "" + } } } + `, func(inputs map[string]interface{}) { assert.Equal(t, "NEWPULLID", inputs["pullRequestId"]) assert.Equal(t, []interface{}{"MONAID"}, inputs["assigneeIds"]) assert.Equal(t, []interface{}{"BUGID", "TODOID"}, inputs["labelIds"]) @@ -729,10 +729,10 @@ func Test_createRun(t *testing.T) { reg.Register( httpmock.GraphQL(`mutation PullRequestCreateRequestReviews\b`), httpmock.GraphQLMutation(` - { "data": { "requestReviews": { - "clientMutationId": "" - } } } - `, func(inputs map[string]interface{}) { + { "data": { "requestReviews": { + "clientMutationId": "" + } } } + `, func(inputs map[string]interface{}) { assert.Equal(t, "NEWPULLID", inputs["pullRequestId"]) assert.Equal(t, []interface{}{"HUBOTID", "MONAID"}, inputs["userIds"]) assert.Equal(t, []interface{}{"COREID", "ROBOTID"}, inputs["teamIds"]) @@ -807,7 +807,6 @@ func Test_createRun(t *testing.T) { cs.Register(`git show-ref --verify -- HEAD refs/remotes/origin/feature`, 0, "") cs.Register(`git( .+)? log( .+)? origin/master\.\.\.feature`, 0, "") cs.Register(`git push --set-upstream origin HEAD:refs/heads/feature`, 0, "") - }, promptStubs: func(pm *prompter.PrompterMock) { pm.SelectFunc = func(p, _ string, opts []string) (int, error) { @@ -834,25 +833,25 @@ func Test_createRun(t *testing.T) { reg.Register( httpmock.GraphQL(`query PullRequestTemplates\b`), httpmock.StringResponse(` - { "data": { "repository": { "pullRequestTemplates": [ - { "filename": "template1", - "body": "this is a bug" }, - { "filename": "template2", - "body": "this is a enhancement" } - ] } } }`), + { "data": { "repository": { "pullRequestTemplates": [ + { "filename": "template1", + "body": "this is a bug" }, + { "filename": "template2", + "body": "this is a enhancement" } + ] } } }`), ) reg.Register( httpmock.GraphQL(`mutation PullRequestCreate\b`), httpmock.GraphQLMutation(` - { "data": { "createPullRequest": { "pullRequest": { - "URL": "https://github.com/OWNER/REPO/pull/12" - } } } } - `, func(input map[string]interface{}) { + { "data": { "createPullRequest": { "pullRequest": { + "URL": "https://github.com/OWNER/REPO/pull/12" + } } } } + `, func(input map[string]interface{}) { assert.Equal(t, true, input["draft"].(bool)) })) }, cmdStubs: func(cs *run.CommandStubber) { - cs.Register(`git -c log.ShowSignature=false log --pretty=format:%H,%s --cherry origin/master...feature`, 0, "") + cs.Register(`git -c log.ShowSignature=false log --pretty=format:%H,%s,%b --cherry origin/master...feature`, 0, "") cs.Register(`git rev-parse --show-toplevel`, 0, "") }, promptStubs: func(pm *prompter.PrompterMock) { @@ -884,28 +883,28 @@ func Test_createRun(t *testing.T) { reg.Register( httpmock.GraphQL(`query RepositoryResolveMetadataIDs\b`), httpmock.StringResponse(` - { "data": { - "u000": { "login": "jillValentine", "id": "JILLID" }, - "repository": {}, - "organization": {} - } } - `)) + { "data": { + "u000": { "login": "jillValentine", "id": "JILLID" }, + "repository": {}, + "organization": {} + } } + `)) reg.Register( httpmock.GraphQL(`mutation PullRequestCreateRequestReviews\b`), httpmock.GraphQLMutation(` - { "data": { "requestReviews": { - "clientMutationId": "" - } } } - `, func(inputs map[string]interface{}) { + { "data": { "requestReviews": { + "clientMutationId": "" + } } } + `, func(inputs map[string]interface{}) { assert.Equal(t, []interface{}{"JILLID"}, inputs["userIds"]) })) reg.Register( httpmock.GraphQL(`mutation PullRequestCreate\b`), httpmock.GraphQLMutation(` - { "data": { "createPullRequest": { "pullRequest": { - "URL": "https://github.com/OWNER/REPO/pull/12" - } } } } - `, func(input map[string]interface{}) { + { "data": { "createPullRequest": { "pullRequest": { + "URL": "https://github.com/OWNER/REPO/pull/12" + } } } } + `, func(input map[string]interface{}) { assert.Equal(t, "recovered title", input["title"].(string)) assert.Equal(t, "recovered body", input["body"].(string)) })) @@ -989,10 +988,10 @@ func Test_createRun(t *testing.T) { reg.Register( httpmock.GraphQL(`mutation PullRequestCreate\b`), httpmock.StringResponse(` - { "data": { "createPullRequest": { "pullRequest": { - "URL": "https://github.com/OWNER/REPO/pull/12" - } } } } - `)) + { "data": { "createPullRequest": { "pullRequest": { + "URL": "https://github.com/OWNER/REPO/pull/12" + } } } } + `)) }, expectedOut: "https://github.com/OWNER/REPO/pull/12\n", }, @@ -1006,15 +1005,46 @@ func Test_createRun(t *testing.T) { }, cmdStubs: func(cs *run.CommandStubber) { cs.Register( - "git -c log.ShowSignature=false log --pretty=format:%H,%s --cherry origin/master...feature", + "git -c log.ShowSignature=false log --pretty=format:%H,%s,%b --cherry origin/master...feature", 0, "56b6f8bb7c9e3a30093cd17e48934ce354148e80,second commit of pr\n"+ - "343jdfe47c9e3a30093cd17e48934ce354148e80,first commit of pr", + "3a9b48085046d156c5acce8f3b3a0532cd706a4a,first commit of pr,first commit description\n", + ) + }, + httpStubs: func(reg *httpmock.Registry, t *testing.T) { + reg.Register( + httpmock.GraphQL(`mutation PullRequestCreate\b`), + httpmock.GraphQLMutation(` + { + "data": { "createPullRequest": { "pullRequest": { + "URL": "https://github.com/OWNER/REPO/pull/12" + } } } + } + `, + func(input map[string]interface{}) { + assert.Equal(t, "first commit of pr", input["title"], "pr title should be first commit message") + assert.Equal(t, "first commit description", input["body"], "pr body should be first commit description") + }, + ), ) + }, + expectedOut: "https://github.com/OWNER/REPO/pull/12\n", + expectedErrOut: "\nCreating pull request for feature into master in OWNER/REPO\n\n", + }, + { + name: "fillverbose flag provided", + tty: true, + setup: func(opts *CreateOptions, t *testing.T) func() { + opts.FillVerbose = true + opts.HeadBranch = "feature" + return func() {} + }, + cmdStubs: func(cs *run.CommandStubber) { cs.Register( - "git -c log.ShowSignature=false show -s --pretty=format:%b 343jdfe47c9e3a30093cd17e48934ce354148e80", + "git -c log.ShowSignature=false log --pretty=format:%H,%s,%b --cherry origin/master...feature", 0, - "first commit description", + "56b6f8bb7c9e3a30093cd17e48934ce354148e80,second commit of pr,second commit description\n"+ + "3a9b48085046d156c5acce8f3b3a0532cd706a4a,first commit of pr,first commit with super long description, with super long description, with super long description, with super long description.\n", ) }, httpStubs: func(reg *httpmock.Registry, t *testing.T) { @@ -1028,8 +1058,8 @@ func Test_createRun(t *testing.T) { } `, func(input map[string]interface{}) { - assert.Equal(t, "first commit of pr", input["title"], "pr title should be first commit message") - assert.Equal(t, "first commit description", input["body"], "pr body should be first commit description") + assert.Equal(t, "feature", input["title"], "pr title should be branch name") + assert.Equal(t, "- **first commit of pr**\n first commit with super long description, with super long description, with super long description, with super long description.\n\n- **second commit of pr**\n second commit description", input["body"], "pr body should be commits msg+body") }, ), ) From 3409d068d4f85a7e1d613d97151071758a27b005 Mon Sep 17 00:00:00 2001 From: Federico Guerinoni Date: Thu, 11 Jan 2024 11:34:08 +0100 Subject: [PATCH 3/3] Make commit title in bold --- pkg/cmd/pr/create/create.go | 2 +- pkg/cmd/pr/create/create_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/cmd/pr/create/create.go b/pkg/cmd/pr/create/create.go index 809c83128b9..4b37001bbe0 100644 --- a/pkg/cmd/pr/create/create.go +++ b/pkg/cmd/pr/create/create.go @@ -432,7 +432,7 @@ func initDefaultTitleBody(ctx CreateContext, state *shared.IssueMetadataState, u 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) diff --git a/pkg/cmd/pr/create/create_test.go b/pkg/cmd/pr/create/create_test.go index c088e4169d4..bd878a8c434 100644 --- a/pkg/cmd/pr/create/create_test.go +++ b/pkg/cmd/pr/create/create_test.go @@ -623,7 +623,7 @@ func Test_createRun(t *testing.T) { } } } } `, func(input map[string]interface{}) { assert.Equal(t, "my title", input["title"].(string)) - assert.Equal(t, "- commit 1\n- commit 0\n\nthis is a bug", input["body"].(string)) + assert.Equal(t, "- **commit 1**\n- **commit 0**\n\nthis is a bug", input["body"].(string)) })) }, cmdStubs: func(cs *run.CommandStubber) {