gh gist edit
This commit is contained in:
parent
39b6ec8aec
commit
0d3056d9a7
5 changed files with 217 additions and 8 deletions
203
pkg/cmd/gist/edit/edit.go
Normal file
203
pkg/cmd/gist/edit/edit.go
Normal 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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue