Skip to content

Commit

Permalink
fork: allow user to fork a project from its numerid ID
Browse files Browse the repository at this point in the history
The `lab fork` command allows only the project name from user's input, but
it's not a huge change to allow the user to enter the project numeric ID
instead. This commit adds this ability to the fork command by changing the
way Fork() handles the project ID: receiving as interface{} and checking its
real value. With that, an additional change was necessary in the
FindProject(), which was accepting only project IDs as string.

As consiquence, this change allow other functions to pass either the project
ID comming from a go-gitlab module object (int) or the one comming from the
user input (string) to the FindProject() function.

Signed-off-by: Bruno Meneguele <[email protected]>
  • Loading branch information
bmeneg committed Feb 3, 2022
1 parent f0ca76d commit 9293471
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 13 deletions.
4 changes: 3 additions & 1 deletion cmd/fork.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,15 @@ var (

// forkCmd represents the fork command
var forkCmd = &cobra.Command{
Use: "fork [remote|repo]",
Use: "fork [remote],[project name or ID]",
Short: "Fork a remote repository on GitLab and add as remote",
Long: heredoc.Doc(`
Fork a remote repository on user's location of choice.
Both an already existent remote or a repository path can be specified.`),
Example: heredoc.Doc(`
lab fork origin
lab fork coolGroup/coolProject
lab fork 1234567
lab fork upstream --remote-name origin
lab fork origin --name new-awesome-project
lab fork origin -g TheCoolestGroup -n InitialProject
Expand Down
68 changes: 56 additions & 12 deletions internal/gitlab/gitlab.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"os"
"path/filepath"
"sort"
"strconv"
"strings"
"time"

Expand Down Expand Up @@ -182,33 +183,76 @@ func GetProject(projID interface{}) (*gitlab.Project, error) {

// FindProject looks up the Gitlab project. If the namespace is not provided in
// the project string it will search for projects in the users namespace
func FindProject(projID string) (*gitlab.Project, error) {
if target, ok := localProjects[projID]; ok {
return target, nil
func FindProject(projID interface{}) (*gitlab.Project, error) {
var (
id string
search string
)

switch v := projID.(type) {
case int:
// If the project number is used directly, don't "guess" anything
id = strconv.Itoa(v)
search = id
case string:
id = v
search = id
// If the project name is used, check if it already has the
// namespace (already have a slash '/' in the name) or try to guess
// it's on user's own namespace.
if !strings.Contains(id, "/") {
search = user + "/" + id
}
}

search := projID
// Assuming that a "/" in the project means its owned by an org
if !strings.Contains(projID, "/") {
search = user + "/" + projID
if target, ok := localProjects[id]; ok {
return target, nil
}

target, err := GetProject(search)
if err != nil {
return nil, err
}

// fwiw, I feel bad about this
localProjects[projID] = target
localProjects[id] = target

return target, nil
}

// Fork creates a user fork of a GitLab project using the specified protocol
func Fork(projID string, opts *gitlab.ForkProjectOptions, useHTTP bool, wait bool) (string, error) {
if !strings.Contains(projID, "/") {
return "", errors.New("remote must include namespace")
func Fork(projID interface{}, opts *gitlab.ForkProjectOptions, useHTTP bool, wait bool) (string, error) {
var id string

switch v := projID.(type) {
case int:
// If numeric ID, we need the complete name with namespace
p, err := FindProject(v)
if err != nil {
return "", err
}
id = p.NameWithNamespace
case string:
id = v
// Check if the ID passed already contains the namespace/path that
// we need.
if !strings.Contains(id, "/") {
// Is it a numeric ID passed as string?
if _, err := strconv.Atoi(id); err != nil {
return "", errors.New("remote must include namespace")
}

// Do the same as done in 'case int' for numeric ID passed as
// string
p, err := FindProject(id)
if err != nil {
return "", err
}
id = p.NameWithNamespace
}
}
parts := strings.Split(projID, "/")

parts := strings.Split(id, "/")

// See if a fork already exists in the destination
name := parts[len(parts)-1]
Expand Down

0 comments on commit 9293471

Please sign in to comment.