Skip to content

Commit

Permalink
(snippets) formalize picking remote by allows user to pass it as firs…
Browse files Browse the repository at this point in the history
…t argument
  • Loading branch information
zaquestion committed Dec 4, 2017
1 parent 46f4479 commit af4ea1d
Show file tree
Hide file tree
Showing 7 changed files with 155 additions and 82 deletions.
43 changes: 41 additions & 2 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import (
"log"
"os"
"os/exec"
"strconv"
"strings"
"syscall"
"text/template"
"unicode"

"github.com/pkg/errors"
"github.com/spf13/cobra"
gitconfig "github.com/tcnksm/go-gitconfig"
"github.com/zaquestion/lab/internal/git"
Expand Down Expand Up @@ -66,6 +68,39 @@ func labUsage(c *cobra.Command) string {
return buf.String()
}

// parseArgsRemote returns the remote and a number if parsed. Many commands
// accept a remote to operate on and number such as a page id
func parseArgsRemote(args []string) (string, int64, error) {
if len(args) == 2 {
n, err := strconv.ParseInt(args[1], 0, 64)
if err != nil {
return "", 0, err
}
ok, err := git.IsRemote(args[0])
if err != nil {
return "", 0, err
} else if !ok {
return "", 0, errors.New(fmt.Sprintf("%s is not a valid remote", args[0]))
}
return args[0], n, nil
}
if len(args) == 1 {
ok, err := git.IsRemote(args[0])
if err != nil {
return "", 0, err
}
if ok {
return args[0], 0, nil
}
n, err := strconv.ParseInt(args[0], 0, 64)
if err == nil {
return "", n, nil
}
return "", 0, errors.New(fmt.Sprintf("%s is not a valid remote or number", args[0]))
}
return "", 0, nil
}

var (
// Will be updated to upstream in init() if "upstream" remote exists
forkedFromRemote = "origin"
Expand All @@ -82,10 +117,14 @@ func Execute() {
}

if forkedFromRemote == "origin" {
forkRemote = lab.User()
// Check if the user fork exists
_, err = gitconfig.Local("remote." + lab.User() + ".url")
if err == nil {
forkRemote = lab.User()
}
}
if cmd, _, err := RootCmd.Find(os.Args[1:]); err != nil || cmd.Use == "clone" {
// Determine if any undefined flags were passed to "clone
// Determine if any undefined flags were passed to "clone"
if cmd.Use == "clone" && len(os.Args) > 2 {
// ParseFlags will err in these cases
err = cmd.ParseFlags(os.Args[1:])
Expand Down
7 changes: 6 additions & 1 deletion cmd/snippet.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,12 @@ var snippetCmd = &cobra.Command{
},
}

var (
global bool
)

func init() {
// flags added in snippetCreate.go
snippetCmd.PersistentFlags().BoolVarP(&global, "global", "g", false, "Create as a personal snippet")
// Create flags added in snippetCreate.go
RootCmd.AddCommand(snippetCmd)
}
69 changes: 34 additions & 35 deletions cmd/snippetCreate.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"strings"
"text/template"

"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/xanzy/go-gitlab"
"github.com/zaquestion/lab/internal/git"
Expand All @@ -34,8 +35,21 @@ var snippetCreateCmd = &cobra.Command{
Source snippets from stdin, file, or in editor from scratch
Write title & description in editor, or using -m`,
Run: func(cmd *cobra.Command, args []string) {
remote := forkedFromRemote
ok, err := git.IsRemote(args[0])
if err != nil {
log.Fatal(err)
}
if ok {
remote = args[0]
}
if len(args) > 0 {
file = args[0]
if !ok {
file = args[0]
}
if ok && len(args) > 1 {
file = args[1]
}
}
code, err := determineCode(file)
if err != nil {
Expand All @@ -56,54 +70,39 @@ Write title & description in editor, or using -m`,
case public:
visibility = gitlab.PublicVisibility
}

if rn, _ := git.PathWithNameSpace(forkRemote); rn != "" {
// Looking up the fork ensures there is only 1 api call
// because it returns the forked from Project
project, err := lab.FindProject(rn)
if err != nil {
log.Fatal(err)
}
psOpts := gitlab.CreateProjectSnippetOptions{
// See if we're in a git repo or if global is set to determine
// if this should be a personal snippet
rn, _ := git.PathWithNameSpace(remote)
if global || rn == "" {
opts := gitlab.CreateSnippetOptions{
Title: gitlab.String(title),
Description: gitlab.String(body),
Code: gitlab.String(code),
Content: gitlab.String(code),
FileName: gitlab.String(name),
Visibility: &visibility,
}
// Assuming that if you have permissions to create
// snippets on forkedFromRepo thats what you want
snip, err := lab.ProjectSnippetCreate(project.ForkedFromProject.ID, &psOpts)
if err == nil && snip != nil {
fmt.Println(snip.WebURL)
return
}

// Try creating on user fork if failed to create on
// forkedFromRepo. Seemingly the next best bet
snip, err := lab.SnippetCreate(&opts)
if err != nil || snip == nil {
snip, err = lab.ProjectSnippetCreate(project.ID, &psOpts)
if err == nil && snip != nil {
fmt.Println(snip.WebURL)
return
}
log.Fatal(errors.Wrap(err, "failed to create snippet"))
}
fmt.Println(snip.WebURL)
return
}

sOpts := gitlab.CreateSnippetOptions{
project, err := lab.FindProject(rn)
if err != nil {
log.Fatal(err)
}
opts := gitlab.CreateProjectSnippetOptions{
Title: gitlab.String(title),
Description: gitlab.String(body),
Content: gitlab.String(code),
Code: gitlab.String(code),
FileName: gitlab.String(name),
Visibility: &visibility,
}
snip, err := lab.SnippetCreate(&sOpts)
if err != nil {
log.Fatal(err)

}
if snip == nil {
log.Fatal("failed to create snippet")
snip, err := lab.ProjectSnippetCreate(project.ID, &opts)
if err != nil || snip == nil {
log.Fatal(errors.Wrap(err, "failed to create snippet"))
}
fmt.Println(snip.WebURL)
},
Expand Down
26 changes: 21 additions & 5 deletions cmd/snippetDelete.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ package cmd
import (
"fmt"
"log"
"strconv"

"github.com/spf13/cobra"
"github.com/zaquestion/lab/internal/git"
lab "github.com/zaquestion/lab/internal/gitlab"
)

Expand All @@ -14,17 +14,33 @@ var snippetDeleteCmd = &cobra.Command{
Use: "delete",
Short: "Delete a personal snippet by ID",
Long: ``,
Args: cobra.ExactArgs(1),
Args: cobra.MinimumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
id, err := strconv.ParseInt(args[0], 0, 64)
remote, id, err := parseArgsRemote(args)
if err != nil {
log.Fatal(err)
}
err = lab.SnippetDelete(int(id))
if remote == "" {
remote = forkedFromRemote
}
rn, _ := git.PathWithNameSpace(remote)
if global || rn == "" {
err = lab.SnippetDelete(int(id))
if err != nil {
log.Fatal(err)
}
fmt.Printf("Snippet #%d deleted\n", id)
return
}

project, err := lab.FindProject(rn)
if err != nil {
log.Fatal(err)
}
err = lab.ProjectSnippetDelete(project.ID, int(id))
if err != nil {
log.Fatal(err)
}
fmt.Printf("Snippet #%d deleted\n", id)
},
}

Expand Down
71 changes: 32 additions & 39 deletions cmd/snippetList.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package cmd
import (
"fmt"
"log"
"strconv"

"github.com/spf13/cobra"
"github.com/xanzy/go-gitlab"
Expand All @@ -17,51 +16,45 @@ var snippetListCmd = &cobra.Command{
Short: "List personal or project snippets",
Long: ``,
Run: func(cmd *cobra.Command, args []string) {
page := 0
if len(args) == 1 {
var err error
page, err = strconv.Atoi(args[0])
if err != nil {
log.Fatal(err)
}
remote, page, err := parseArgsRemote(args)
if err != nil {
log.Fatal(err)
}
var snips []*gitlab.Snippet
if rn, _ := git.PathWithNameSpace(forkRemote); rn != "" {
project, err := lab.FindProject(rn)
if err != nil {
log.Fatal(err)
}
opts := gitlab.ListProjectSnippetsOptions{
ListOptions: gitlab.ListOptions{
Page: page,
PerPage: 10,
},
}
snips, err = lab.ProjectSnippetList(project.ForkedFromProject.ID, &opts)
if err != nil {
log.Fatal(err)
}
// Try user fork if failed to create on forkedFromRepo.
// Seemingly the next best bet
if len(snips) == 0 {
snips, err = lab.ProjectSnippetList(project.ID, &opts)
if err != nil {
log.Fatal(err)
}
}
if remote == "" {
remote = forkedFromRemote
}
listOpts := gitlab.ListOptions{
Page: int(page),
PerPage: 10,
}
if len(snips) == 0 {

// See if we're in a git repo or if global is set to determine
// if this should be a personal snippet
rn, _ := git.PathWithNameSpace(remote)
if global || rn == "" {
opts := gitlab.ListSnippetsOptions{
ListOptions: gitlab.ListOptions{
Page: page,
PerPage: 10,
},
ListOptions: listOpts,
}
var err error
snips, err = lab.SnippetList(&opts)
snips, err := lab.SnippetList(&opts)
if err != nil {
log.Fatal(err)
}
for _, snip := range snips {
fmt.Printf("#%d %s\n", snip.ID, snip.Title)
}
return
}

project, err := lab.FindProject(rn)
if err != nil {
log.Fatal(err)
}
opts := gitlab.ListProjectSnippetsOptions{
ListOptions: listOpts,
}
snips, err := lab.ProjectSnippetList(project.ID, &opts)
if err != nil {
log.Fatal(err)
}
for _, snip := range snips {
fmt.Printf("#%d %s\n", snip.ID, snip.Title)
Expand Down
13 changes: 13 additions & 0 deletions internal/git/git.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package git

import (
"bytes"
"fmt"
"log"
"os"
Expand Down Expand Up @@ -167,3 +168,15 @@ func RemoteAdd(name, url string) error {
fmt.Println("new remote:", name)
return nil
}

// IsRemote returns true when passed a valid remote in the git repo
func IsRemote(remote string) (bool, error) {
cmd := New("remote")
cmd.Stdout = nil
remotes, err := cmd.Output()
if err != nil {
return false, err
}

return bytes.Contains(remotes, []byte(remote+"\n")), nil
}
8 changes: 8 additions & 0 deletions internal/git/git_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,11 @@ func TestRepoName(t *testing.T) {
expectedRepo := "test"
require.Equal(t, expectedRepo, repo)
}

func TestIsRemote(t *testing.T) {
res, err := IsRemote("origin")
if err != nil {
t.Fatal(err)
}
require.True(t, res)
}

0 comments on commit af4ea1d

Please sign in to comment.