Skip to content

Commit

Permalink
fork: enable different target name, namespace and path
Browse files Browse the repository at this point in the history
Gitlab API allows the user to specify different destination name, namespace
(if usr has permission) and the path for the projects being forked, however,
`lab` isn't aware in the current status. This patch adds three different
flags to `lab fork` command, being that each represents a different property
in the destination location of the fork:

  -n, --name string        fork project with a different name
  -m, --namespace string   fork project in a different namespace
  -p, --path string        fork project with a different path

"name" is the new name; "namespace" is the new namespace, different from the
own user namespace; "path" is the last part of the git url, which may be
different from project's name (in case "name" isn't specified, "path" is
used as the name).

Signed-off-by: Bruno Meneguele <bmeneg@redhat.com>
  • Loading branch information
bmeneg committed Dec 17, 2020
1 parent b569d45 commit 1ab3a53
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 12 deletions.
37 changes: 30 additions & 7 deletions cmd/fork.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
)

var skipClone = false
var forkData lab.ForkStruct

// forkCmd represents the fork command
var forkCmd = &cobra.Command{
Expand All @@ -21,6 +22,10 @@ var forkCmd = &cobra.Command{
PersistentPreRun: LabPersistentPreRun,
Run: func(cmd *cobra.Command, args []string) {
skipClone, _ = cmd.Flags().GetBool("skip-clone")
forkData.TargetName, _ = cmd.Flags().GetString("name")
forkData.TargetNamespace, _ = cmd.Flags().GetString("namespace")
forkData.TargetPath, _ = cmd.Flags().GetString("path")

if len(args) == 1 {
forkToUpstream(cmd, args)
return
Expand Down Expand Up @@ -54,7 +59,8 @@ func forkFromOrigin(cmd *cobra.Command, args []string) {
if err != nil {
log.Fatal(err)
}
forkRemoteURL, err := lab.Fork(project, useHTTP)
forkData.SrcProject = project
forkRemoteURL, err := lab.Fork(forkData, useHTTP)
if err != nil {
log.Fatal(err)
}
Expand All @@ -66,18 +72,32 @@ func forkFromOrigin(cmd *cobra.Command, args []string) {
}
}
func forkToUpstream(cmd *cobra.Command, args []string) {
forkData.SrcProject = args[0]
// lab.Fork doesn't have access to the useHTTP var, so we need to pass
// this info to that, so the process works correctly.
_, err := lab.Fork(args[0], useHTTP)
_, err := lab.Fork(forkData, useHTTP)
if err != nil {
log.Fatal(err)
}

if !skipClone {
projectParts := strings.Split(args[0], "/")
// In case many subgroups are used, the project's name forked will be
// the last index
projectName := projectParts[len(projectParts)-1]
cloneCmd.Run(nil, []string{projectName})
// the clone may happen in a different name/path when compared to
// the original source project
namespace := ""
if forkData.TargetNamespace != "" {
namespace = forkData.TargetNamespace + "/"
}

name := forkData.SrcProject
if forkData.TargetPath != "" {
name = forkData.TargetPath
} else if forkData.TargetName != "" {
name = forkData.TargetName
} else {
nameParts := strings.Split(name, "/")
name = nameParts[len(nameParts)-1]
}
cloneCmd.Run(nil, []string{namespace + name})
}
}
func determineForkRemote(project string) string {
Expand All @@ -92,6 +112,9 @@ func determineForkRemote(project string) string {

func init() {
forkCmd.Flags().BoolP("skip-clone", "s", false, "skip clone after remote fork")
forkCmd.Flags().StringP("name", "n", "", "fork project with a different name")
forkCmd.Flags().StringP("namespace", "m", "", "fork project in a different namespace")
forkCmd.Flags().StringP("path", "p", "", "fork project with a different path")
// useHTTP is defined in "project_create.go"
forkCmd.Flags().BoolVar(&useHTTP, "http", false, "fork using HTTP protocol instead of SSH")
RootCmd.AddCommand(forkCmd)
Expand Down
31 changes: 26 additions & 5 deletions internal/gitlab/gitlab.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,12 +211,24 @@ func FindProject(project string) (*gitlab.Project, error) {
return target, nil
}

type ForkStruct struct {
SrcProject string
TargetName string
TargetNamespace string
TargetPath string
}

// isCustomTargetSet checks if at least one destination value is set
func (fs ForkStruct) isCustomTargetSet() bool {
return fs.TargetName != "" || fs.TargetNamespace != "" || fs.TargetPath != ""
}

// Fork creates a user fork of a GitLab project using the specified protocol
func Fork(project string, useHTTP bool) (string, error) {
if !strings.Contains(project, "/") {
func Fork(data ForkStruct, useHTTP bool) (string, error) {
if !strings.Contains(data.SrcProject, "/") {
return "", errors.New("remote must include namespace")
}
parts := strings.Split(project, "/")
parts := strings.Split(data.SrcProject, "/")

// See if a fork already exists
target, err := FindProject(parts[1])
Expand All @@ -230,15 +242,24 @@ func Fork(project string, useHTTP bool) (string, error) {
return "", err
}

target, err = FindProject(project)
target, err = FindProject(data.SrcProject)
if err != nil {
return "", err
}

fork, _, err := lab.Projects.ForkProject(target.ID, nil)
var forkOpts *gitlab.ForkProjectOptions = nil
if data.isCustomTargetSet() {
forkOpts = &gitlab.ForkProjectOptions{
Name: gitlab.String(data.TargetName),
Namespace: gitlab.String(data.TargetNamespace),
Path: gitlab.String(data.TargetPath),
}
}
fork, _, err := lab.Projects.ForkProject(target.ID, forkOpts)
if err != nil {
return "", err
}

urlToRepo := fork.SSHURLToRepo
if useHTTP {
urlToRepo = fork.HTTPURLToRepo
Expand Down

0 comments on commit 1ab3a53

Please sign in to comment.