github.com/zaquestion/lab@v0.25.1/cmd/snippet_create.go (about) 1 package cmd 2 3 import ( 4 "bytes" 5 "fmt" 6 "io/ioutil" 7 "os" 8 "runtime" 9 "strconv" 10 "strings" 11 "text/template" 12 13 "github.com/MakeNowJust/heredoc/v2" 14 "github.com/pkg/errors" 15 "github.com/rsteube/carapace" 16 "github.com/spf13/cobra" 17 gitlab "github.com/xanzy/go-gitlab" 18 "github.com/zaquestion/lab/internal/action" 19 "github.com/zaquestion/lab/internal/git" 20 lab "github.com/zaquestion/lab/internal/gitlab" 21 ) 22 23 var ( 24 name string 25 file string 26 ) 27 28 // mrCmd represents the mr command 29 var snippetCreateCmd = &cobra.Command{ 30 Use: "create [remote]", 31 Short: "Create a personal or project snippet", 32 Long: heredoc.Doc(` 33 Source snippets from stdin, file, or in editor from scratch.`), 34 Example: heredoc.Doc(` 35 lab snippet create 36 lab snippet create snippet_file.txt 37 lab snippet create -n "potato.go for GoLang" 38 lab snippet create -m "Snippet example" -M "Description message" 39 lab snippet create upstream --private 40 lab snippet create origin --public`), 41 PersistentPreRun: labPersistentPreRun, 42 Run: func(cmd *cobra.Command, args []string) { 43 msgs, err := cmd.Flags().GetStringArray("message") 44 if err != nil { 45 log.Fatal(err) 46 } 47 remote := defaultRemote 48 if len(args) > 0 { 49 ok, err := git.IsRemote(args[0]) 50 if err != nil { 51 log.Fatal(err) 52 } 53 if ok { 54 remote = args[0] 55 } else { 56 file = args[0] 57 } 58 if ok && len(args) > 1 { 59 file = args[1] 60 } 61 } 62 code, err := snipCode(file) 63 if err != nil { 64 log.Fatal(err) 65 } 66 if strings.TrimSpace(code) == "" { 67 log.Fatal("aborting snippet due to empty contents") 68 } 69 title, body := snipMsg(msgs) 70 if title == "" { 71 log.Fatal("aborting snippet due to empty msg") 72 } 73 74 visibility := gitlab.PrivateVisibility 75 switch { 76 case private: 77 visibility = gitlab.PrivateVisibility 78 case public: 79 visibility = gitlab.PublicVisibility 80 } 81 // See if we're in a git repo or if global is set to determine 82 // if this should be a personal snippet 83 rn, _ := git.PathWithNamespace(remote) 84 if global || rn == "" { 85 opts := gitlab.CreateSnippetOptions{ 86 Title: gitlab.String(title), 87 Description: gitlab.String(body), 88 Content: gitlab.String(code), 89 FileName: gitlab.String(name), 90 Visibility: &visibility, 91 } 92 snip, err := lab.SnippetCreate(&opts) 93 if err != nil || snip == nil { 94 log.Fatal(errors.Wrap(err, "failed to create snippet")) 95 } 96 fmt.Println(snip.WebURL) 97 return 98 } 99 100 opts := gitlab.CreateProjectSnippetOptions{ 101 Title: gitlab.String(title), 102 Description: gitlab.String(body), 103 Content: gitlab.String(code), 104 FileName: gitlab.String(name), 105 Visibility: &visibility, 106 } 107 snip, err := lab.ProjectSnippetCreate(rn, &opts) 108 if err != nil || snip == nil { 109 log.Fatal(errors.Wrap(err, "failed to create snippet")) 110 } 111 fmt.Println(snip.WebURL) 112 }, 113 } 114 115 func snipMsg(msgs []string) (string, string) { 116 return msgs[0], strings.Join(msgs[1:], "\n\n") 117 } 118 119 func snipCode(path string) (string, error) { 120 b, err := ioutil.ReadFile(path) 121 if !os.IsNotExist(err) && err != nil { 122 return "", err 123 } 124 if len(b) > 0 { 125 return string(b), nil 126 } 127 128 if stat, _ := os.Stdin.Stat(); (stat.Mode() & os.ModeCharDevice) == 0 { 129 b, err = ioutil.ReadAll(os.Stdin) 130 if err != nil { 131 return "", err 132 } 133 if len(b) > 0 { 134 return string(b), nil 135 } 136 } 137 138 tmpl := heredoc.Doc(` 139 {{.CommentChar}} In this mode you are writing a snippet from scratch 140 {{.CommentChar}} The first block is the title and the rest is the contents. 141 `) 142 143 text, err := snipText(tmpl) 144 if err != nil { 145 log.Fatal(err) 146 } 147 title, body, err := git.Edit("SNIPCODE", text) 148 if err != nil { 149 _, f, l, _ := runtime.Caller(0) 150 log.Fatal(f+":"+strconv.Itoa(l)+" ", err) 151 } 152 return fmt.Sprintf("%s\n\n%s", title, body), nil 153 } 154 155 func snipText(tmpl string) (string, error) { 156 t, err := template.New("tmpl").Parse(tmpl) 157 if err != nil { 158 return "", err 159 } 160 161 cc := git.CommentChar() 162 msg := &struct{ CommentChar string }{CommentChar: cc} 163 var b bytes.Buffer 164 err = t.Execute(&b, msg) 165 if err != nil { 166 return "", err 167 } 168 169 return b.String(), nil 170 } 171 172 func init() { 173 snippetCreateCmd.Flags().BoolVarP(&private, "private", "p", false, "make snippet private; visible only to project members (default: internal)") 174 snippetCreateCmd.Flags().BoolVar(&public, "public", false, "make snippet public; can be accessed without any authentication (default: internal)") 175 snippetCreateCmd.Flags().StringVarP(&name, "name", "n", "", "name snippet to add code highlighting") 176 snippetCreateCmd.Flags().StringArrayP("message", "m", []string{"-"}, "use the given <msg>; multiple -m are concatenated as separate paragraphs") 177 snippetCmd.Flags().AddFlagSet(snippetCreateCmd.Flags()) 178 179 snippetCmd.AddCommand(snippetCreateCmd) 180 carapace.Gen(snippetCreateCmd).PositionalCompletion( 181 action.Remotes(), 182 ) 183 }