From e8dfa9e72893b004e49d96cf45c12caf2acce2df Mon Sep 17 00:00:00 2001 From: Spenser Black Date: Wed, 12 Jan 2022 09:21:41 -0500 Subject: [PATCH 1/3] Fix tag message option hidden This fixes the option in `gh release create` to generate release notes from the tag message being hidden whenever generated notes are available. This changes the behavior from hiding "generate from tag" and "generate from commit log" being hidden to *only* the "generate from commit log" option being hidden. Fixes #5027 --- pkg/cmd/release/create/create.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/pkg/cmd/release/create/create.go b/pkg/cmd/release/create/create.go index 1b834373f..96f7245c1 100644 --- a/pkg/cmd/release/create/create.go +++ b/pkg/cmd/release/create/create.go @@ -234,7 +234,7 @@ func createRun(opts *CreateOptions) error { return err } - if opts.RepoOverride == "" && generatedNotes == nil { + if opts.RepoOverride == "" { headRef := opts.TagName tagDescription, _ = gitTagInfo(opts.TagName) if tagDescription == "" { @@ -245,9 +245,11 @@ func createRun(opts *CreateOptions) error { headRef = "HEAD" } } - if prevTag, err := detectPreviousTag(headRef); err == nil { - commits, _ := changelogForRange(fmt.Sprintf("%s..%s", prevTag, headRef)) - generatedChangelog = generateChangelog(commits) + if generatedNotes == nil { + if prevTag, err := detectPreviousTag(headRef); err == nil { + commits, _ := changelogForRange(fmt.Sprintf("%s..%s", prevTag, headRef)) + generatedChangelog = generateChangelog(commits) + } } } From 709092271388b5e5f8457a581cdd782dc5992394 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mislav=20Marohni=C4=87?= Date: Mon, 17 Jan 2022 14:05:01 +0100 Subject: [PATCH 2/3] :nail_care: `release create` tests --- pkg/cmd/release/create/create_test.go | 70 ++++++++++++++------------- 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/pkg/cmd/release/create/create_test.go b/pkg/cmd/release/create/create_test.go index a6f6a2d7a..ed07e1ad2 100644 --- a/pkg/cmd/release/create/create_test.go +++ b/pkg/cmd/release/create/create_test.go @@ -528,18 +528,18 @@ func Test_createRun_interactive(t *testing.T) { }, httpStubs: func(reg *httpmock.Registry) { reg.Register(httpmock.REST("GET", "repos/OWNER/REPO/tags"), httpmock.StatusStringResponse(200, `[ - { "name": "v1.2.3" }, { "name": "v1.2.2" }, { "name": "v1.0.0" }, { "name": "v0.1.2" } - ]`)) + { "name": "v1.2.3" }, { "name": "v1.2.2" }, { "name": "v1.0.0" }, { "name": "v0.1.2" } + ]`)) reg.Register(httpmock.REST("POST", "repos/OWNER/REPO/releases/generate-notes"), httpmock.StatusStringResponse(200, `{ - "name": "generated name", - "body": "generated body" - }`)) + "name": "generated name", + "body": "generated body" + }`)) reg.Register(httpmock.REST("POST", "repos/OWNER/REPO/releases"), httpmock.StatusStringResponse(201, `{ - "url": "https://api.github.com/releases/123", - "upload_url": "https://api.github.com/assets/upload", - "html_url": "https://github.com/OWNER/REPO/releases/tag/v1.2.3" - }`)) + "url": "https://api.github.com/releases/123", + "upload_url": "https://api.github.com/assets/upload", + "html_url": "https://github.com/OWNER/REPO/releases/tag/v1.2.3" + }`)) }, wantOut: "https://github.com/OWNER/REPO/releases/tag/v1.2.3\n", }, @@ -550,24 +550,26 @@ func Test_createRun_interactive(t *testing.T) { as.StubPrompt("Choose a tag").AnswerWith("Create a new tag") as.StubPrompt("Tag name").AnswerWith("v1.2.3") as.StubPrompt("Title (optional)").AnswerWith("") - as.StubPrompt("Release notes").AnswerWith("Leave blank") + as.StubPrompt("Release notes"). + AssertOptions([]string{"Write my own", "Write using generated notes as template", "Leave blank"}). + AnswerWith("Leave blank") as.StubPrompt("Is this a prerelease?").AnswerWith(false) as.StubPrompt("Submit?").AnswerWith("Publish release") }, httpStubs: func(reg *httpmock.Registry) { reg.Register(httpmock.REST("GET", "repos/OWNER/REPO/tags"), httpmock.StatusStringResponse(200, `[ - { "name": "v1.2.2" }, { "name": "v1.0.0" }, { "name": "v0.1.2" } - ]`)) + { "name": "v1.2.2" }, { "name": "v1.0.0" }, { "name": "v0.1.2" } + ]`)) reg.Register(httpmock.REST("POST", "repos/OWNER/REPO/releases/generate-notes"), httpmock.StatusStringResponse(200, `{ - "name": "generated name", - "body": "generated body" - }`)) + "name": "generated name", + "body": "generated body" + }`)) reg.Register(httpmock.REST("POST", "repos/OWNER/REPO/releases"), httpmock.StatusStringResponse(201, `{ - "url": "https://api.github.com/releases/123", - "upload_url": "https://api.github.com/assets/upload", - "html_url": "https://github.com/OWNER/REPO/releases/tag/v1.2.3" - }`)) + "url": "https://api.github.com/releases/123", + "upload_url": "https://api.github.com/assets/upload", + "html_url": "https://github.com/OWNER/REPO/releases/tag/v1.2.3" + }`)) }, wantOut: "https://github.com/OWNER/REPO/releases/tag/v1.2.3\n", }, @@ -578,22 +580,24 @@ func Test_createRun_interactive(t *testing.T) { }, askStubs: func(as *prompt.AskStubber) { as.StubPrompt("Title (optional)").AnswerDefault() - as.StubPrompt("Release notes").AnswerWith("Write using generated notes as template") + as.StubPrompt("Release notes"). + AssertOptions([]string{"Write my own", "Write using generated notes as template", "Leave blank"}). + AnswerWith("Write using generated notes as template") as.StubPrompt("Is this a prerelease?").AnswerWith(false) as.StubPrompt("Submit?").AnswerWith("Publish release") }, httpStubs: func(reg *httpmock.Registry) { reg.Register(httpmock.REST("POST", "repos/OWNER/REPO/releases/generate-notes"), httpmock.StatusStringResponse(200, `{ - "name": "generated name", - "body": "generated body" - }`)) + "name": "generated name", + "body": "generated body" + }`)) reg.Register(httpmock.REST("POST", "repos/OWNER/REPO/releases"), httpmock.StatusStringResponse(201, `{ - "url": "https://api.github.com/releases/123", - "upload_url": "https://api.github.com/assets/upload", - "html_url": "https://github.com/OWNER/REPO/releases/tag/v1.2.3" - }`)) + "url": "https://api.github.com/releases/123", + "upload_url": "https://api.github.com/assets/upload", + "html_url": "https://github.com/OWNER/REPO/releases/tag/v1.2.3" + }`)) }, wantParams: map[string]interface{}{ "body": "generated body", @@ -631,14 +635,12 @@ func Test_createRun_interactive(t *testing.T) { return val, nil } - //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber - as, teardown := prompt.InitAskStubber() - defer teardown() - if tt.askStubs != nil { - tt.askStubs(as) - } - t.Run(tt.name, func(t *testing.T) { + as := prompt.NewAskStubber(t) + if tt.askStubs != nil { + tt.askStubs(as) + } + err := createRun(tt.opts) if tt.wantErr != "" { From df2102513384009dbafa28caa80de8768417e05a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mislav=20Marohni=C4=87?= Date: Mon, 17 Jan 2022 14:23:05 +0100 Subject: [PATCH 3/3] Add tests for `release create` from commit log, annotated tag --- pkg/cmd/release/create/create_test.go | 88 +++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/pkg/cmd/release/create/create_test.go b/pkg/cmd/release/create/create_test.go index ed07e1ad2..ea9c2aa44 100644 --- a/pkg/cmd/release/create/create_test.go +++ b/pkg/cmd/release/create/create_test.go @@ -13,6 +13,7 @@ import ( "github.com/cli/cli/v2/internal/config" "github.com/cli/cli/v2/internal/ghrepo" + "github.com/cli/cli/v2/internal/run" "github.com/cli/cli/v2/pkg/cmd/release/shared" "github.com/cli/cli/v2/pkg/cmdutil" "github.com/cli/cli/v2/pkg/httpmock" @@ -506,6 +507,7 @@ func Test_createRun_interactive(t *testing.T) { name string httpStubs func(*httpmock.Registry) askStubs func(*prompt.AskStubber) + runStubs func(*run.CommandStubber) opts *CreateOptions wantParams map[string]interface{} wantOut string @@ -526,6 +528,9 @@ func Test_createRun_interactive(t *testing.T) { as.StubPrompt("Submit?"). AssertOptions([]string{"Publish release", "Save as draft", "Cancel"}).AnswerWith("Publish release") }, + runStubs: func(rs *run.CommandStubber) { + rs.Register(`git tag --list`, 1, "") + }, httpStubs: func(reg *httpmock.Registry) { reg.Register(httpmock.REST("GET", "repos/OWNER/REPO/tags"), httpmock.StatusStringResponse(200, `[ { "name": "v1.2.3" }, { "name": "v1.2.2" }, { "name": "v1.0.0" }, { "name": "v0.1.2" } @@ -556,6 +561,9 @@ func Test_createRun_interactive(t *testing.T) { as.StubPrompt("Is this a prerelease?").AnswerWith(false) as.StubPrompt("Submit?").AnswerWith("Publish release") }, + runStubs: func(rs *run.CommandStubber) { + rs.Register(`git tag --list`, 1, "") + }, httpStubs: func(reg *httpmock.Registry) { reg.Register(httpmock.REST("GET", "repos/OWNER/REPO/tags"), httpmock.StatusStringResponse(200, `[ { "name": "v1.2.2" }, { "name": "v1.0.0" }, { "name": "v0.1.2" } @@ -586,6 +594,9 @@ func Test_createRun_interactive(t *testing.T) { as.StubPrompt("Is this a prerelease?").AnswerWith(false) as.StubPrompt("Submit?").AnswerWith("Publish release") }, + runStubs: func(rs *run.CommandStubber) { + rs.Register(`git tag --list`, 1, "") + }, httpStubs: func(reg *httpmock.Registry) { reg.Register(httpmock.REST("POST", "repos/OWNER/REPO/releases/generate-notes"), httpmock.StatusStringResponse(200, `{ @@ -608,6 +619,77 @@ func Test_createRun_interactive(t *testing.T) { }, wantOut: "https://github.com/OWNER/REPO/releases/tag/v1.2.3\n", }, + { + name: "create a release using commit log as notes", + opts: &CreateOptions{ + TagName: "v1.2.3", + }, + askStubs: func(as *prompt.AskStubber) { + as.StubPrompt("Title (optional)").AnswerDefault() + as.StubPrompt("Release notes"). + AssertOptions([]string{"Write my own", "Write using commit log as template", "Leave blank"}). + AnswerWith("Write using commit log as template") + as.StubPrompt("Is this a prerelease?").AnswerWith(false) + as.StubPrompt("Submit?").AnswerWith("Publish release") + }, + runStubs: func(rs *run.CommandStubber) { + rs.Register(`git tag --list`, 1, "") + rs.Register(`git describe --tags --abbrev=0 HEAD\^`, 0, "v1.2.2\n") + rs.Register(`git .+log .+v1\.2\.2\.\.HEAD$`, 0, "commit subject\n\ncommit body\n") + }, + httpStubs: func(reg *httpmock.Registry) { + reg.Register(httpmock.REST("POST", "repos/OWNER/REPO/releases/generate-notes"), + httpmock.StatusStringResponse(404, `{}`)) + reg.Register(httpmock.REST("POST", "repos/OWNER/REPO/releases"), + httpmock.StatusStringResponse(201, `{ + "url": "https://api.github.com/releases/123", + "upload_url": "https://api.github.com/assets/upload", + "html_url": "https://github.com/OWNER/REPO/releases/tag/v1.2.3" + }`)) + }, + wantParams: map[string]interface{}{ + "body": "* commit subject\n\n commit body\n ", + "draft": false, + "prerelease": false, + "tag_name": "v1.2.3", + }, + wantOut: "https://github.com/OWNER/REPO/releases/tag/v1.2.3\n", + }, + { + name: "create using annotated tag as notes", + opts: &CreateOptions{ + TagName: "v1.2.3", + }, + askStubs: func(as *prompt.AskStubber) { + as.StubPrompt("Title (optional)").AnswerDefault() + as.StubPrompt("Release notes"). + AssertOptions([]string{"Write my own", "Write using git tag message as template", "Leave blank"}). + AnswerWith("Write using git tag message as template") + as.StubPrompt("Is this a prerelease?").AnswerWith(false) + as.StubPrompt("Submit?").AnswerWith("Publish release") + }, + runStubs: func(rs *run.CommandStubber) { + rs.Register(`git tag --list`, 0, "hello from annotated tag") + rs.Register(`git describe --tags --abbrev=0 v1\.2\.3\^`, 1, "") + }, + httpStubs: func(reg *httpmock.Registry) { + reg.Register(httpmock.REST("POST", "repos/OWNER/REPO/releases/generate-notes"), + httpmock.StatusStringResponse(404, `{}`)) + reg.Register(httpmock.REST("POST", "repos/OWNER/REPO/releases"), + httpmock.StatusStringResponse(201, `{ + "url": "https://api.github.com/releases/123", + "upload_url": "https://api.github.com/assets/upload", + "html_url": "https://github.com/OWNER/REPO/releases/tag/v1.2.3" + }`)) + }, + wantParams: map[string]interface{}{ + "body": "hello from annotated tag", + "draft": false, + "prerelease": false, + "tag_name": "v1.2.3", + }, + wantOut: "https://github.com/OWNER/REPO/releases/tag/v1.2.3\n", + }, } for _, tt := range tests { ios, _, stdout, stderr := iostreams.Test() @@ -641,6 +723,12 @@ func Test_createRun_interactive(t *testing.T) { tt.askStubs(as) } + rs, teardown := run.Stub() + defer teardown(t) + if tt.runStubs != nil { + tt.runStubs(rs) + } + err := createRun(tt.opts) if tt.wantErr != "" {