gh gist edit

This commit is contained in:
vilmibm 2020-09-11 17:41:24 -05:00 committed by vilmibm
parent 39b6ec8aec
commit 0d3056d9a7
5 changed files with 217 additions and 8 deletions

203
pkg/cmd/gist/edit/edit.go Normal file
View file

@ -0,0 +1,203 @@
package edit
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"net/http"
"net/url"
"os"
"sort"
"strings"
"github.com/AlecAivazis/survey/v2"
"github.com/cli/cli/api"
"github.com/cli/cli/internal/config"
"github.com/cli/cli/internal/ghinstance"
"github.com/cli/cli/pkg/cmd/gist/shared"
"github.com/cli/cli/pkg/cmdutil"
"github.com/cli/cli/pkg/iostreams"
"github.com/cli/cli/pkg/prompt"
"github.com/cli/cli/pkg/surveyext"
"github.com/spf13/cobra"
)
type EditOptions struct {
IO *iostreams.IOStreams
HttpClient func() (*http.Client, error)
Config func() (config.Config, error)
Selector string
Filename string
}
func NewCmdEdit(f *cmdutil.Factory, runF func(*EditOptions) error) *cobra.Command {
opts := EditOptions{
IO: f.IOStreams,
HttpClient: f.HttpClient,
Config: f.Config,
}
cmd := &cobra.Command{
Use: "edit {<gist ID> | <gist URL>}",
Short: "Edit one of your gists",
Args: cobra.ExactArgs(1),
RunE: func(c *cobra.Command, args []string) error {
opts.Selector = args[0]
if runF != nil {
return runF(&opts)
}
return editRun(&opts)
},
}
cmd.Flags().StringVarP(&opts.Filename, "filename", "f", "", "a specific file to edit")
return cmd
}
func editRun(opts *EditOptions) error {
gistID := opts.Selector
u, err := url.Parse(opts.Selector)
if err == nil {
if strings.HasPrefix(u.Path, "/") {
gistID = u.Path[1:]
}
}
client, err := opts.HttpClient()
if err != nil {
return err
}
gist, err := shared.GetGist(client, ghinstance.OverridableDefault(), gistID)
if err != nil {
return err
}
filesToUpdate := map[string]string{}
for true {
filename := opts.Filename
candidates := []string{}
for filename, _ := range gist.Files {
candidates = append(candidates, filename)
}
sort.Strings(candidates)
if filename == "" {
if len(candidates) == 1 {
filename = candidates[0]
} else {
if !opts.IO.CanPrompt() {
return errors.New("unsure what file to edit; either specify --filename or run interactively")
}
err = prompt.SurveyAskOne(&survey.Select{
Message: "Edit which file?",
Options: candidates,
}, &filename)
}
}
if _, ok := gist.Files[filename]; !ok {
return fmt.Errorf("gist has no file %q", filename)
}
editorCommand, err := cmdutil.DetermineEditor(opts.Config)
if err != nil {
return err
}
text, err := surveyext.Edit(
editorCommand,
"*."+filename,
gist.Files[filename].Content,
// TODO: consider using iostreams here
os.Stdin, os.Stdout, os.Stderr, nil)
if err != nil {
return err
}
if text != gist.Files[filename].Content {
gistFile := gist.Files[filename]
gistFile.Content = text // so it appears if they re-edit
filesToUpdate[filename] = text
}
if !opts.IO.CanPrompt() {
break
}
if len(candidates) == 1 {
break
}
choice := ""
err = prompt.SurveyAskOne(&survey.Select{
Message: "What next?",
Options: []string{
"Edit another file",
"Submit",
"Cancel",
},
}, &choice)
if err != nil {
return err
}
stop := false
switch choice {
case "Edit another file":
continue
case "Submit":
stop = true
case "Cancel":
return cmdutil.SilentError
}
if stop {
break
}
}
err = updateGist(client, ghinstance.OverridableDefault(), gist)
if err != nil {
return err
}
return nil
}
func updateGist(client *http.Client, hostname string, gist *shared.Gist) error {
body := shared.Gist{
Description: gist.Description,
Files: gist.Files,
}
path := "gists/" + gist.ID
requestByte, err := json.Marshal(body)
if err != nil {
return err
}
requestBody := bytes.NewReader(requestByte)
result := shared.Gist{}
apiClient := api.NewClientFromHTTP(client)
err = apiClient.REST(hostname, "POST", path, requestBody, &result)
if err != nil {
return err
}
return nil
}

View file

@ -2,6 +2,7 @@ package gist
import (
gistCreateCmd "github.com/cli/cli/pkg/cmd/gist/create"
gistEditCmd "github.com/cli/cli/pkg/cmd/gist/edit"
gistListCmd "github.com/cli/cli/pkg/cmd/gist/list"
gistViewCmd "github.com/cli/cli/pkg/cmd/gist/view"
"github.com/cli/cli/pkg/cmdutil"
@ -18,6 +19,7 @@ func NewCmdGist(f *cmdutil.Factory) *cobra.Command {
cmd.AddCommand(gistCreateCmd.NewCmdCreate(f, nil))
cmd.AddCommand(gistListCmd.NewCmdList(f, nil))
cmd.AddCommand(gistViewCmd.NewCmdView(f, nil))
cmd.AddCommand(gistEditCmd.NewCmdEdit(f, nil))
return cmd
}

View file

@ -11,7 +11,7 @@ import (
)
type Gist struct {
Description string `json:"description"`
Description string
HTMLURL string `json:"html_url"`
UpdatedAt time.Time `json:"updated_at"`
Public bool

View file

@ -7,16 +7,19 @@ import (
"github.com/cli/cli/api"
)
// TODO make gist create use this file
type GistFile struct {
Filename string
Type string
Language string
Content string
Filename string `json:"filename"`
Type string `json:"type,omitempty"`
Language string `json:"language,omitempty"`
Content string `json:"content"`
}
type Gist struct {
Description string
Files map[string]GistFile
ID string `json:"id,omitempty"`
Description string `json:"description"`
Files map[string]*GistFile `json:"files"`
}
func GetGist(client *http.Client, hostname, gistID string) (*Gist, error) {

View file

@ -7,6 +7,7 @@ import (
"strings"
"github.com/cli/cli/internal/ghinstance"
"github.com/cli/cli/pkg/cmd/gist/shared"
"github.com/cli/cli/pkg/cmdutil"
"github.com/cli/cli/pkg/iostreams"
"github.com/cli/cli/utils"
@ -65,7 +66,7 @@ func viewRun(opts *ViewOptions) error {
return err
}
gist, err := getGist(client, ghinstance.OverridableDefault(), gistID)
gist, err := shared.GetGist(client, ghinstance.OverridableDefault(), gistID)
if err != nil {
return err
}