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  }