Add release edit command (#5422)
Co-authored-by: Mislav Marohnić <mislav@github.com>
This commit is contained in:
parent
5f4152fbfa
commit
186e5ccfb2
6 changed files with 629 additions and 1 deletions
|
|
@ -158,7 +158,7 @@ func NewCmdCreate(f *cmdutil.Factory, runF func(*CreateOptions) error) *cobra.Co
|
|||
cmd.Flags().StringVarP(&opts.Name, "title", "t", "", "Release title")
|
||||
cmd.Flags().StringVarP(&opts.Body, "notes", "n", "", "Release notes")
|
||||
cmd.Flags().StringVarP(¬esFile, "notes-file", "F", "", "Read release notes from `file` (use \"-\" to read from standard input)")
|
||||
cmd.Flags().StringVarP(&opts.DiscussionCategory, "discussion-category", "", "", "Start a discussion of the specified category")
|
||||
cmd.Flags().StringVarP(&opts.DiscussionCategory, "discussion-category", "", "", "Start a discussion in the specified category")
|
||||
cmd.Flags().BoolVarP(&opts.GenerateNotes, "generate-notes", "", false, "Automatically generate title and notes for the release")
|
||||
|
||||
return cmd
|
||||
|
|
|
|||
150
pkg/cmd/release/edit/edit.go
Normal file
150
pkg/cmd/release/edit/edit.go
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
package edit
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/MakeNowJust/heredoc"
|
||||
"github.com/cli/cli/v2/internal/ghrepo"
|
||||
"github.com/cli/cli/v2/pkg/cmd/release/shared"
|
||||
"github.com/cli/cli/v2/pkg/cmdutil"
|
||||
"github.com/cli/cli/v2/pkg/iostreams"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type EditOptions struct {
|
||||
IO *iostreams.IOStreams
|
||||
HttpClient func() (*http.Client, error)
|
||||
BaseRepo func() (ghrepo.Interface, error)
|
||||
|
||||
TagName string
|
||||
Target string
|
||||
Name *string
|
||||
Body *string
|
||||
DiscussionCategory *string
|
||||
Draft *bool
|
||||
Prerelease *bool
|
||||
}
|
||||
|
||||
func NewCmdEdit(f *cmdutil.Factory, runF func(*EditOptions) error) *cobra.Command {
|
||||
opts := &EditOptions{
|
||||
IO: f.IOStreams,
|
||||
HttpClient: f.HttpClient,
|
||||
}
|
||||
|
||||
var notesFile string
|
||||
|
||||
cmd := &cobra.Command{
|
||||
DisableFlagsInUseLine: true,
|
||||
|
||||
Use: "edit <tag>",
|
||||
Short: "Edit a release",
|
||||
Example: heredoc.Doc(`
|
||||
Publish a release that was previously a draft
|
||||
$ gh release edit v1.0 --draft=false
|
||||
|
||||
Update the release notes from the content of a file
|
||||
$ gh release edit v1.0 --notes-file /path/to/release_notes.md
|
||||
`),
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
opts.BaseRepo = f.BaseRepo
|
||||
|
||||
if cmd.Flags().NFlag() == 0 {
|
||||
return cmdutil.FlagErrorf("use flags to specify properties to edit")
|
||||
}
|
||||
|
||||
if notesFile != "" {
|
||||
b, err := cmdutil.ReadFile(notesFile, opts.IO.In)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
body := string(b)
|
||||
opts.Body = &body
|
||||
}
|
||||
|
||||
if runF != nil {
|
||||
return runF(opts)
|
||||
}
|
||||
return editRun(args[0], opts)
|
||||
},
|
||||
}
|
||||
|
||||
cmdutil.NilBoolFlag(cmd, &opts.Draft, "draft", "", "Save the release as a draft instead of publishing it")
|
||||
cmdutil.NilBoolFlag(cmd, &opts.Prerelease, "prerelease", "", "Mark the release as a prerelease")
|
||||
cmdutil.NilStringFlag(cmd, &opts.Body, "notes", "n", "Release notes")
|
||||
cmdutil.NilStringFlag(cmd, &opts.Name, "title", "t", "Release title")
|
||||
cmdutil.NilStringFlag(cmd, &opts.DiscussionCategory, "discussion-category", "", "Start a discussion in the specified category when publishing a draft")
|
||||
cmd.Flags().StringVar(&opts.Target, "target", "", "Target `branch` or full commit SHA (default: main branch)")
|
||||
cmd.Flags().StringVar(&opts.TagName, "tag", "", "The name of the tag")
|
||||
cmd.Flags().StringVarP(¬esFile, "notes-file", "F", "", "Read release notes from `file` (use \"-\" to read from standard input)")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func editRun(tag string, opts *EditOptions) error {
|
||||
httpClient, err := opts.HttpClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
baseRepo, err := opts.BaseRepo()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
release, err := shared.FetchRelease(httpClient, baseRepo, tag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
params := getParams(opts)
|
||||
|
||||
// If we don't provide any tag name, the API will remove the current tag from the release
|
||||
if _, ok := params["tag_name"]; !ok {
|
||||
params["tag_name"] = release.TagName
|
||||
}
|
||||
|
||||
editedRelease, err := editRelease(httpClient, baseRepo, release.DatabaseID, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Fprintf(opts.IO.Out, "%s\n", editedRelease.URL)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getParams(opts *EditOptions) map[string]interface{} {
|
||||
params := map[string]interface{}{}
|
||||
|
||||
if opts.Body != nil {
|
||||
params["body"] = opts.Body
|
||||
}
|
||||
|
||||
if opts.DiscussionCategory != nil {
|
||||
params["discussion_category_name"] = *opts.DiscussionCategory
|
||||
}
|
||||
|
||||
if opts.Draft != nil {
|
||||
params["draft"] = *opts.Draft
|
||||
}
|
||||
|
||||
if opts.Name != nil {
|
||||
params["name"] = opts.Name
|
||||
}
|
||||
|
||||
if opts.Prerelease != nil {
|
||||
params["prerelease"] = *opts.Prerelease
|
||||
}
|
||||
|
||||
if opts.TagName != "" {
|
||||
params["tag_name"] = opts.TagName
|
||||
}
|
||||
|
||||
if opts.Target != "" {
|
||||
params["target_commitish"] = opts.Target
|
||||
}
|
||||
|
||||
return params
|
||||
}
|
||||
426
pkg/cmd/release/edit/edit_test.go
Normal file
426
pkg/cmd/release/edit/edit_test.go
Normal file
|
|
@ -0,0 +1,426 @@
|
|||
package edit
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/cli/cli/v2/internal/ghrepo"
|
||||
"github.com/cli/cli/v2/pkg/cmdutil"
|
||||
"github.com/cli/cli/v2/pkg/httpmock"
|
||||
"github.com/cli/cli/v2/pkg/iostreams"
|
||||
"github.com/google/shlex"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func Test_NewCmdEdit(t *testing.T) {
|
||||
tempDir := t.TempDir()
|
||||
tf, err := ioutil.TempFile(tempDir, "release-create")
|
||||
require.NoError(t, err)
|
||||
fmt.Fprint(tf, "MY NOTES")
|
||||
tf.Close()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args string
|
||||
isTTY bool
|
||||
stdin string
|
||||
want EditOptions
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "no arguments notty",
|
||||
args: "",
|
||||
isTTY: false,
|
||||
wantErr: "accepts 1 arg(s), received 0",
|
||||
},
|
||||
{
|
||||
name: "provide title and notes",
|
||||
args: "v1.2.3 --title 'Some Title' --notes 'Some Notes'",
|
||||
isTTY: false,
|
||||
want: EditOptions{
|
||||
TagName: "",
|
||||
Name: stringPtr("Some Title"),
|
||||
Body: stringPtr("Some Notes"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "provide discussion category",
|
||||
args: "v1.2.3 --discussion-category some-category",
|
||||
isTTY: false,
|
||||
want: EditOptions{
|
||||
TagName: "",
|
||||
DiscussionCategory: stringPtr("some-category"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "provide tag and target commitish",
|
||||
args: "v1.2.3 --tag v9.8.7 --target 97ea5e77b4d61d5d80ed08f7512847dee3ec9af5",
|
||||
isTTY: false,
|
||||
want: EditOptions{
|
||||
TagName: "v9.8.7",
|
||||
Target: "97ea5e77b4d61d5d80ed08f7512847dee3ec9af5",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "provide prerelease",
|
||||
args: "v1.2.3 --prerelease",
|
||||
isTTY: false,
|
||||
want: EditOptions{
|
||||
TagName: "",
|
||||
Prerelease: boolPtr(true),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "provide prerelease=false",
|
||||
args: "v1.2.3 --prerelease=false",
|
||||
isTTY: false,
|
||||
want: EditOptions{
|
||||
TagName: "",
|
||||
Prerelease: boolPtr(false),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "provide draft",
|
||||
args: "v1.2.3 --draft",
|
||||
isTTY: false,
|
||||
want: EditOptions{
|
||||
TagName: "",
|
||||
Draft: boolPtr(true),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "provide draft=false",
|
||||
args: "v1.2.3 --draft=false",
|
||||
isTTY: false,
|
||||
want: EditOptions{
|
||||
TagName: "",
|
||||
Draft: boolPtr(false),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "provide notes from file",
|
||||
args: fmt.Sprintf(`v1.2.3 -F '%s'`, tf.Name()),
|
||||
isTTY: false,
|
||||
want: EditOptions{
|
||||
TagName: "",
|
||||
Body: stringPtr("MY NOTES"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "provide notes from stdin",
|
||||
args: "v1.2.3 -F -",
|
||||
isTTY: false,
|
||||
stdin: "MY NOTES",
|
||||
want: EditOptions{
|
||||
TagName: "",
|
||||
Body: stringPtr("MY NOTES"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
io, stdin, _, _ := iostreams.Test()
|
||||
if tt.stdin == "" {
|
||||
io.SetStdinTTY(tt.isTTY)
|
||||
} else {
|
||||
io.SetStdinTTY(false)
|
||||
fmt.Fprint(stdin, tt.stdin)
|
||||
}
|
||||
io.SetStdoutTTY(tt.isTTY)
|
||||
io.SetStderrTTY(tt.isTTY)
|
||||
|
||||
f := &cmdutil.Factory{
|
||||
IOStreams: io,
|
||||
}
|
||||
|
||||
var opts *EditOptions
|
||||
cmd := NewCmdEdit(f, func(o *EditOptions) error {
|
||||
opts = o
|
||||
return nil
|
||||
})
|
||||
cmd.PersistentFlags().StringP("repo", "R", "", "")
|
||||
|
||||
argv, err := shlex.Split(tt.args)
|
||||
require.NoError(t, err)
|
||||
cmd.SetArgs(argv)
|
||||
|
||||
cmd.SetIn(&bytes.Buffer{})
|
||||
cmd.SetOut(ioutil.Discard)
|
||||
cmd.SetErr(ioutil.Discard)
|
||||
|
||||
_, err = cmd.ExecuteC()
|
||||
if tt.wantErr != "" {
|
||||
require.EqualError(t, err, tt.wantErr)
|
||||
return
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
assert.Equal(t, tt.want.TagName, opts.TagName)
|
||||
assert.Equal(t, tt.want.Target, opts.Target)
|
||||
assert.Equal(t, tt.want.Name, opts.Name)
|
||||
assert.Equal(t, tt.want.Body, opts.Body)
|
||||
assert.Equal(t, tt.want.DiscussionCategory, opts.DiscussionCategory)
|
||||
assert.Equal(t, tt.want.Draft, opts.Draft)
|
||||
assert.Equal(t, tt.want.Prerelease, opts.Prerelease)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_editRun(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
isTTY bool
|
||||
opts EditOptions
|
||||
httpStubs func(t *testing.T, reg *httpmock.Registry)
|
||||
wantErr string
|
||||
wantStdout string
|
||||
wantStderr string
|
||||
}{
|
||||
{
|
||||
name: "edit the tag name",
|
||||
isTTY: true,
|
||||
opts: EditOptions{
|
||||
TagName: "v1.2.4",
|
||||
},
|
||||
httpStubs: func(t *testing.T, reg *httpmock.Registry) {
|
||||
mockSuccessfulEditResponse(reg, func(params map[string]interface{}) {
|
||||
assert.Equal(t, map[string]interface{}{
|
||||
"tag_name": "v1.2.4",
|
||||
}, params)
|
||||
})
|
||||
},
|
||||
wantStdout: "https://github.com/OWNER/REPO/releases/tag/v1.2.3\n",
|
||||
wantStderr: "",
|
||||
},
|
||||
{
|
||||
name: "edit the target",
|
||||
isTTY: true,
|
||||
opts: EditOptions{
|
||||
Target: "c0ff33",
|
||||
},
|
||||
httpStubs: func(t *testing.T, reg *httpmock.Registry) {
|
||||
mockSuccessfulEditResponse(reg, func(params map[string]interface{}) {
|
||||
assert.Equal(t, map[string]interface{}{
|
||||
"tag_name": "v1.2.3",
|
||||
"target_commitish": "c0ff33",
|
||||
}, params)
|
||||
})
|
||||
},
|
||||
wantStdout: "https://github.com/OWNER/REPO/releases/tag/v1.2.3\n",
|
||||
wantStderr: "",
|
||||
},
|
||||
{
|
||||
name: "edit the release name",
|
||||
isTTY: true,
|
||||
opts: EditOptions{
|
||||
Name: stringPtr("Hot Release #1"),
|
||||
},
|
||||
httpStubs: func(t *testing.T, reg *httpmock.Registry) {
|
||||
mockSuccessfulEditResponse(reg, func(params map[string]interface{}) {
|
||||
assert.Equal(t, map[string]interface{}{
|
||||
"tag_name": "v1.2.3",
|
||||
"name": "Hot Release #1",
|
||||
}, params)
|
||||
})
|
||||
},
|
||||
wantStdout: "https://github.com/OWNER/REPO/releases/tag/v1.2.3\n",
|
||||
wantStderr: "",
|
||||
},
|
||||
{
|
||||
name: "edit the discussion category",
|
||||
isTTY: true,
|
||||
opts: EditOptions{
|
||||
DiscussionCategory: stringPtr("some-category"),
|
||||
},
|
||||
httpStubs: func(t *testing.T, reg *httpmock.Registry) {
|
||||
mockSuccessfulEditResponse(reg, func(params map[string]interface{}) {
|
||||
assert.Equal(t, map[string]interface{}{
|
||||
"tag_name": "v1.2.3",
|
||||
"discussion_category_name": "some-category",
|
||||
}, params)
|
||||
})
|
||||
},
|
||||
wantStdout: "https://github.com/OWNER/REPO/releases/tag/v1.2.3\n",
|
||||
wantStderr: "",
|
||||
},
|
||||
{
|
||||
name: "edit the release name (empty)",
|
||||
isTTY: true,
|
||||
opts: EditOptions{
|
||||
Name: stringPtr(""),
|
||||
},
|
||||
httpStubs: func(t *testing.T, reg *httpmock.Registry) {
|
||||
mockSuccessfulEditResponse(reg, func(params map[string]interface{}) {
|
||||
assert.Equal(t, map[string]interface{}{
|
||||
"tag_name": "v1.2.3",
|
||||
"name": "",
|
||||
}, params)
|
||||
})
|
||||
},
|
||||
wantStdout: "https://github.com/OWNER/REPO/releases/tag/v1.2.3\n",
|
||||
wantStderr: "",
|
||||
},
|
||||
{
|
||||
name: "edit the release notes",
|
||||
isTTY: true,
|
||||
opts: EditOptions{
|
||||
Body: stringPtr("Release Notes:\n- Fix Bug #1\n- Fix Bug #2"),
|
||||
},
|
||||
httpStubs: func(t *testing.T, reg *httpmock.Registry) {
|
||||
mockSuccessfulEditResponse(reg, func(params map[string]interface{}) {
|
||||
assert.Equal(t, map[string]interface{}{
|
||||
"tag_name": "v1.2.3",
|
||||
"body": "Release Notes:\n- Fix Bug #1\n- Fix Bug #2",
|
||||
}, params)
|
||||
})
|
||||
},
|
||||
wantStdout: "https://github.com/OWNER/REPO/releases/tag/v1.2.3\n",
|
||||
wantStderr: "",
|
||||
},
|
||||
{
|
||||
name: "edit the release notes (empty)",
|
||||
isTTY: true,
|
||||
opts: EditOptions{
|
||||
Body: stringPtr(""),
|
||||
},
|
||||
httpStubs: func(t *testing.T, reg *httpmock.Registry) {
|
||||
mockSuccessfulEditResponse(reg, func(params map[string]interface{}) {
|
||||
assert.Equal(t, map[string]interface{}{
|
||||
"tag_name": "v1.2.3",
|
||||
"body": "",
|
||||
}, params)
|
||||
})
|
||||
},
|
||||
wantStdout: "https://github.com/OWNER/REPO/releases/tag/v1.2.3\n",
|
||||
wantStderr: "",
|
||||
},
|
||||
{
|
||||
name: "edit draft (true)",
|
||||
isTTY: true,
|
||||
opts: EditOptions{
|
||||
Draft: boolPtr(true),
|
||||
},
|
||||
httpStubs: func(t *testing.T, reg *httpmock.Registry) {
|
||||
mockSuccessfulEditResponse(reg, func(params map[string]interface{}) {
|
||||
assert.Equal(t, map[string]interface{}{
|
||||
"tag_name": "v1.2.3",
|
||||
"draft": true,
|
||||
}, params)
|
||||
})
|
||||
},
|
||||
wantStdout: "https://github.com/OWNER/REPO/releases/tag/v1.2.3\n",
|
||||
wantStderr: "",
|
||||
},
|
||||
{
|
||||
name: "edit draft (false)",
|
||||
isTTY: true,
|
||||
opts: EditOptions{
|
||||
Draft: boolPtr(false),
|
||||
},
|
||||
httpStubs: func(t *testing.T, reg *httpmock.Registry) {
|
||||
mockSuccessfulEditResponse(reg, func(params map[string]interface{}) {
|
||||
assert.Equal(t, map[string]interface{}{
|
||||
"tag_name": "v1.2.3",
|
||||
"draft": false,
|
||||
}, params)
|
||||
})
|
||||
},
|
||||
wantStdout: "https://github.com/OWNER/REPO/releases/tag/v1.2.3\n",
|
||||
wantStderr: "",
|
||||
},
|
||||
{
|
||||
name: "edit prerelease (true)",
|
||||
isTTY: true,
|
||||
opts: EditOptions{
|
||||
Prerelease: boolPtr(true),
|
||||
},
|
||||
httpStubs: func(t *testing.T, reg *httpmock.Registry) {
|
||||
mockSuccessfulEditResponse(reg, func(params map[string]interface{}) {
|
||||
assert.Equal(t, map[string]interface{}{
|
||||
"tag_name": "v1.2.3",
|
||||
"prerelease": true,
|
||||
}, params)
|
||||
})
|
||||
},
|
||||
wantStdout: "https://github.com/OWNER/REPO/releases/tag/v1.2.3\n",
|
||||
wantStderr: "",
|
||||
},
|
||||
{
|
||||
name: "edit prerelease (false)",
|
||||
isTTY: true,
|
||||
opts: EditOptions{
|
||||
Prerelease: boolPtr(false),
|
||||
},
|
||||
httpStubs: func(t *testing.T, reg *httpmock.Registry) {
|
||||
mockSuccessfulEditResponse(reg, func(params map[string]interface{}) {
|
||||
assert.Equal(t, map[string]interface{}{
|
||||
"tag_name": "v1.2.3",
|
||||
"prerelease": false,
|
||||
}, params)
|
||||
})
|
||||
},
|
||||
wantStdout: "https://github.com/OWNER/REPO/releases/tag/v1.2.3\n",
|
||||
wantStderr: "",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
io, _, stdout, stderr := iostreams.Test()
|
||||
io.SetStdoutTTY(tt.isTTY)
|
||||
io.SetStdinTTY(tt.isTTY)
|
||||
io.SetStderrTTY(tt.isTTY)
|
||||
|
||||
fakeHTTP := &httpmock.Registry{}
|
||||
fakeHTTP.Register(httpmock.REST("GET", "repos/OWNER/REPO/releases/tags/v1.2.3"), httpmock.JSONResponse(map[string]interface{}{
|
||||
"id": 12345,
|
||||
"tag_name": "v1.2.3",
|
||||
}))
|
||||
if tt.httpStubs != nil {
|
||||
tt.httpStubs(t, fakeHTTP)
|
||||
}
|
||||
defer fakeHTTP.Verify(t)
|
||||
|
||||
tt.opts.IO = io
|
||||
tt.opts.HttpClient = func() (*http.Client, error) {
|
||||
return &http.Client{Transport: fakeHTTP}, nil
|
||||
}
|
||||
tt.opts.BaseRepo = func() (ghrepo.Interface, error) {
|
||||
return ghrepo.FromFullName("OWNER/REPO")
|
||||
}
|
||||
|
||||
err := editRun("v1.2.3", &tt.opts)
|
||||
if tt.wantErr != "" {
|
||||
require.EqualError(t, err, tt.wantErr)
|
||||
return
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
assert.Equal(t, tt.wantStdout, stdout.String())
|
||||
assert.Equal(t, tt.wantStderr, stderr.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func mockSuccessfulEditResponse(reg *httpmock.Registry, cb func(params map[string]interface{})) {
|
||||
matcher := httpmock.REST("PATCH", "repos/OWNER/REPO/releases/12345")
|
||||
responder := httpmock.RESTPayload(201, `{
|
||||
"html_url": "https://github.com/OWNER/REPO/releases/tag/v1.2.3"
|
||||
}`, cb)
|
||||
reg.Register(matcher, responder)
|
||||
}
|
||||
|
||||
func boolPtr(b bool) *bool {
|
||||
return &b
|
||||
}
|
||||
|
||||
func stringPtr(s string) *string {
|
||||
return &s
|
||||
}
|
||||
49
pkg/cmd/release/edit/http.go
Normal file
49
pkg/cmd/release/edit/http.go
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
package edit
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/cli/cli/v2/api"
|
||||
"github.com/cli/cli/v2/internal/ghinstance"
|
||||
"github.com/cli/cli/v2/internal/ghrepo"
|
||||
"github.com/cli/cli/v2/pkg/cmd/release/shared"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func editRelease(httpClient *http.Client, repo ghrepo.Interface, releaseID int64, params map[string]interface{}) (*shared.Release, error) {
|
||||
bodyBytes, err := json.Marshal(params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
path := fmt.Sprintf("repos/%s/%s/releases/%d", repo.RepoOwner(), repo.RepoName(), releaseID)
|
||||
url := ghinstance.RESTPrefix(repo.RepoHost()) + path
|
||||
req, err := http.NewRequest("PATCH", url, bytes.NewBuffer(bodyBytes))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "application/json; charset=utf-8")
|
||||
|
||||
resp, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
success := resp.StatusCode >= 200 && resp.StatusCode < 300
|
||||
if !success {
|
||||
return nil, api.HandleHTTPError(resp)
|
||||
}
|
||||
|
||||
b, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var newRelease shared.Release
|
||||
err = json.Unmarshal(b, &newRelease)
|
||||
return &newRelease, err
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import (
|
|||
cmdDelete "github.com/cli/cli/v2/pkg/cmd/release/delete"
|
||||
cmdDeleteAsset "github.com/cli/cli/v2/pkg/cmd/release/delete-asset"
|
||||
cmdDownload "github.com/cli/cli/v2/pkg/cmd/release/download"
|
||||
cmdUpdate "github.com/cli/cli/v2/pkg/cmd/release/edit"
|
||||
cmdList "github.com/cli/cli/v2/pkg/cmd/release/list"
|
||||
cmdUpload "github.com/cli/cli/v2/pkg/cmd/release/upload"
|
||||
cmdView "github.com/cli/cli/v2/pkg/cmd/release/view"
|
||||
|
|
@ -28,6 +29,7 @@ func NewCmdRelease(f *cmdutil.Factory) *cobra.Command {
|
|||
cmd.AddCommand(cmdDeleteAsset.NewCmdDeleteAsset(f, nil))
|
||||
cmd.AddCommand(cmdDownload.NewCmdDownload(f, nil))
|
||||
cmd.AddCommand(cmdList.NewCmdList(f, nil))
|
||||
cmd.AddCommand(cmdUpdate.NewCmdEdit(f, nil))
|
||||
cmd.AddCommand(cmdView.NewCmdView(f, nil))
|
||||
cmd.AddCommand(cmdUpload.NewCmdUpload(f, nil))
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ var ReleaseFields = []string{
|
|||
}
|
||||
|
||||
type Release struct {
|
||||
DatabaseID int64 `json:"id"`
|
||||
ID string `json:"node_id"`
|
||||
TagName string `json:"tag_name"`
|
||||
Name string `json:"name"`
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue