forked from profclems/glab
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(snippet): Add command for creating snippets
This adds a simple snippet creation command. This currently just allows for creating snippets from STDIN like so: `echo "this is a script" | glab snippet create --title "snippet" --filename "example.py"` There are few things that are missing from this, like ability to add more then one file to the snippet, but that is not supported by the "github.com/xanzy/go-gitlab" yet. Issue is opened for that xanzy/go-gitlab#1372 Issue profclems#872
- Loading branch information
Showing
4 changed files
with
193 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
package create | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"io" | ||
|
||
"github.com/MakeNowJust/heredoc" | ||
"github.com/profclems/glab/api" | ||
"github.com/profclems/glab/commands/cmdutils" | ||
"github.com/profclems/glab/internal/glrepo" | ||
"github.com/profclems/glab/pkg/iostreams" | ||
"github.com/spf13/cobra" | ||
"github.com/xanzy/go-gitlab" | ||
) | ||
|
||
type CreateOpts struct { | ||
Title string | ||
Description string | ||
Filename string | ||
Visibility string | ||
|
||
ForUser bool | ||
|
||
IO *iostreams.IOStreams | ||
Lab func() (*gitlab.Client, error) | ||
BaseRepo func() (glrepo.Interface, error) | ||
} | ||
|
||
func NewCmdCreate(f *cmdutils.Factory) *cobra.Command { | ||
opts := &CreateOpts{} | ||
var snippetCreateCmd = &cobra.Command{ | ||
Use: "create", | ||
Short: `Create new snippet`, | ||
Long: ``, | ||
Aliases: []string{"new"}, | ||
Example: heredoc.Doc(` | ||
$ glab snippet new --title "Title of the snippet" --filename "main.go" | ||
$ glab snippet create --title "Title of the snippet" --filename "main.go" | ||
$ glab snippet create -t Title -f "main.go" -d Description | ||
`), | ||
Args: cobra.ExactArgs(0), | ||
PreRunE: func(cmd *cobra.Command, args []string) error { | ||
opts.IO = f.IO | ||
opts.BaseRepo = f.BaseRepo | ||
opts.Lab = f.HttpClient | ||
if opts.Title == "" { | ||
return &cmdutils.FlagError{ | ||
Err: errors.New("--title required for snipets"), | ||
} | ||
} | ||
if opts.Filename == "" { | ||
return &cmdutils.FlagError{ | ||
Err: errors.New("--filename required for snipets"), | ||
} | ||
} | ||
return nil | ||
}, | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
client, err := opts.Lab() | ||
if err != nil { | ||
return err | ||
} | ||
repo, err := opts.BaseRepo() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return runCreate(client, repo, opts) | ||
}, | ||
} | ||
|
||
snippetCreateCmd.Flags().StringVarP(&opts.Title, "title", "t", "", "Title of the snippet") | ||
snippetCreateCmd.Flags().StringVarP(&opts.Filename, "filename", "f", "", "Filename of the snippet") | ||
snippetCreateCmd.Flags().StringVarP(&opts.Description, "description", "d", "", "Description of the snippet") | ||
snippetCreateCmd.Flags().StringVarP(&opts.Visibility, "visibility", "v", "private", "Limit by visibility {public, internal, or private}") | ||
|
||
return snippetCreateCmd | ||
} | ||
|
||
func runCreate(client *gitlab.Client, repo glrepo.Interface, opts *CreateOpts) error { | ||
content, err := readSnippetsContent(opts) | ||
if err != nil { | ||
return err | ||
} | ||
fmt.Fprintln(opts.IO.StdErr, "- Creating snippet in", repo.FullName()) | ||
snippet, err := api.CreateProjectSnippet(client, repo.FullName(), &gitlab.CreateProjectSnippetOptions{ | ||
Title: &opts.Title, | ||
Description: &opts.Description, | ||
Content: gitlab.String(string(content)), | ||
FileName: &opts.Filename, | ||
Visibility: gitlab.Visibility(gitlab.VisibilityValue(opts.Visibility)), | ||
}) | ||
if err != nil { | ||
return fmt.Errorf("failed to create snippet. %w", err) | ||
} | ||
snippetID := opts.IO.Color().Green(fmt.Sprintf("$%d", snippet.ID)) | ||
if opts.IO.IsaTTY { | ||
fmt.Fprintf(opts.IO.StdOut, "%s %s (%s)\n %s\n", snippetID, snippet.Title, snippet.FileName, snippet.WebURL) | ||
} else { | ||
fmt.Fprintln(opts.IO.StdOut, snippet.WebURL) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// FIXME: Add a flag that would allow reading the snippets from a file instead of just STDIN. | ||
// Adding more then one file can't be done right now because the GitLab API library | ||
// Doesn't support it yet. | ||
// | ||
// See for the API reference: https://docs.gitlab.com/ee/api/snippets.html#create-new-snippet | ||
// See for the library docs : https://pkg.go.dev/github.com/xanzy/go-gitlab#CreateSnippetOptions | ||
// See for GitHub issue : https://github.com/xanzy/go-gitlab/issues/1372 | ||
func readSnippetsContent(opts *CreateOpts) (string, error) { | ||
content, err := io.ReadAll(opts.IO.In) | ||
if err != nil { | ||
return "", fmt.Errorf("Failed to read snippet from STDIN. %w", err) | ||
} | ||
return string(content), nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package snippet | ||
|
||
import ( | ||
"github.com/MakeNowJust/heredoc" | ||
"github.com/profclems/glab/commands/cmdutils" | ||
"github.com/profclems/glab/commands/snippet/create" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
func NewCmdSnippet(f *cmdutils.Factory) *cobra.Command { | ||
var snippetCmd = &cobra.Command{ | ||
Use: "snippet <command> [flags]", | ||
Short: `Create, view and manage snippets`, | ||
Long: ``, | ||
Example: heredoc.Doc(` | ||
$ glab snippet create --title "Title of the snippet" --filename "main.go" | ||
`), | ||
Annotations: map[string]string{ | ||
"help:arguments": heredoc.Doc(` | ||
A snippet can be supplied as argument in the following format: | ||
- by number, e.g. "123" | ||
`), | ||
}, | ||
} | ||
|
||
cmdutils.EnableRepoOverride(snippetCmd, f) | ||
|
||
snippetCmd.AddCommand(create.NewCmdCreate(f)) | ||
return snippetCmd | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package snippet | ||
|
||
import ( | ||
"bytes" | ||
"io" | ||
"os" | ||
"testing" | ||
|
||
"github.com/alecthomas/assert" | ||
"github.com/profclems/glab/commands/cmdtest" | ||
"github.com/profclems/glab/commands/cmdutils" | ||
) | ||
|
||
func TestMain(m *testing.M) { | ||
cmdtest.InitTest(m, "mr_cmd_test") | ||
cmdtest.InitTest(m, "mr_cmd_autofill") | ||
} | ||
|
||
func TestCmdSnippet_noARgs(t *testing.T) { | ||
old := os.Stdout // keep backup of the real stdout | ||
r, w, _ := os.Pipe() | ||
os.Stdout = w | ||
|
||
assert.Nil(t, NewCmdSnippet(&cmdutils.Factory{}).Execute()) | ||
|
||
outC := make(chan string) | ||
// copy the output in a separate goroutine so printing can't block indefinitely | ||
go func() { | ||
var buf bytes.Buffer | ||
_, _ = io.Copy(&buf, r) | ||
outC <- buf.String() | ||
}() | ||
|
||
// back to normal state | ||
w.Close() | ||
os.Stdout = old // restoring the real stdout | ||
out := <-outC | ||
|
||
assert.Contains(t, out, "Use \"snippet [command] --help\" for more information about a command.\n") | ||
|
||
} |