From 662f90e979123c2935b0aca739db8ab75068c7f4 Mon Sep 17 00:00:00 2001 From: Norwin Date: Sat, 25 Sep 2021 12:33:17 +0200 Subject: [PATCH 01/10] add tea repo clone --- cmd/repos.go | 1 + cmd/repos/clone.go | 74 +++++++++++++++++++++++++++++++++++++++++++++ modules/git/repo.go | 15 +++++++++ 3 files changed, 90 insertions(+) create mode 100644 cmd/repos/clone.go diff --git a/cmd/repos.go b/cmd/repos.go index 3962706..71d0011 100644 --- a/cmd/repos.go +++ b/cmd/repos.go @@ -27,6 +27,7 @@ var CmdRepos = cli.Command{ &repos.CmdReposList, &repos.CmdReposSearch, &repos.CmdRepoCreate, + &repos.CmdRepoClone, }, Flags: repos.CmdReposListFlags, } diff --git a/cmd/repos/clone.go b/cmd/repos/clone.go new file mode 100644 index 0000000..f03be75 --- /dev/null +++ b/cmd/repos/clone.go @@ -0,0 +1,74 @@ +// Copyright 2020 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package repos + +import ( + "net/url" + + "code.gitea.io/tea/cmd/flags" + "code.gitea.io/tea/modules/context" + "code.gitea.io/tea/modules/git" + "code.gitea.io/tea/modules/interact" + + "github.com/urfave/cli/v2" +) + +// CmdRepoClone represents a sub command of repos to create a local copy +var CmdRepoClone = cli.Command{ + Name: "clone", + Aliases: []string{"C"}, + Usage: "Clone a repository locally", + Description: "Clone a repository locally, without a local git installation required (defaults to PWD)", + Action: runRepoClone, + ArgsUsage: "[target dir]", + Flags: append([]cli.Flag{ + &cli.IntFlag{ + Name: "depth", + Aliases: []string{"d"}, + Usage: "num commits to fetch, defaults to all", + }, + }, flags.LoginRepoFlags...), +} + +func runRepoClone(cmd *cli.Context) error { + ctx := context.InitCommand(cmd) + ctx.Ensure(context.CtxRequirement{RemoteRepo: true}) + + // get clone URLs robustly + repo, _, err := ctx.Login.Client().GetRepo(ctx.Owner, ctx.Repo) + if err != nil { + return err + } + var url *url.URL + urlStr := repo.CloneURL + if ctx.Login.SSHKey != "" { + urlStr = repo.SSHURL + } + url, err = git.ParseURL(urlStr) + if err != nil { + return err + } + + auth, err := git.GetAuthForURL(url, ctx.Login.Token, ctx.Login.SSHKey, interact.PromptPassword) + if err != nil { + return err + } + + // default path behaviour as native git + localPath := ctx.Args().First() + if localPath == "" { + localPath = ctx.Repo + } + + _, err = git.CloneIntoPath( + url.String(), + localPath, + auth, + ctx.Int("depth"), + ctx.Login.Insecure, + ) + + return err +} diff --git a/modules/git/repo.go b/modules/git/repo.go index cc5d01e..779f7ba 100644 --- a/modules/git/repo.go +++ b/modules/git/repo.go @@ -6,6 +6,7 @@ package git import ( "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/plumbing/transport" ) // TeaRepo is a go-git Repository, with an extended high level interface. @@ -33,3 +34,17 @@ func RepoFromPath(path string) (*TeaRepo, error) { return &TeaRepo{repo}, nil } + +// CloneIntoPath emulates a git clone --depth ... +func CloneIntoPath(url, path string, auth transport.AuthMethod, depth int, insecure bool) (*TeaRepo, error) { + repo, err := git.PlainClone(path, false, &git.CloneOptions{ + URL: url, + Auth: auth, + Depth: depth, + InsecureSkipTLS: insecure, + }) + if err != nil { + return nil, err + } + return &TeaRepo{repo}, nil +} -- 2.40.1 From 89aae7a87e84d5d6cd7fc2af12d521e1e8957b73 Mon Sep 17 00:00:00 2001 From: Norwin Date: Tue, 28 Sep 2021 11:50:05 +0200 Subject: [PATCH 02/10] 2021... --- cmd/repos/clone.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/repos/clone.go b/cmd/repos/clone.go index f03be75..d7b186e 100644 --- a/cmd/repos/clone.go +++ b/cmd/repos/clone.go @@ -1,4 +1,4 @@ -// Copyright 2020 The Gitea Authors. All rights reserved. +// Copyright 2021 The Gitea Authors. All rights reserved. // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -- 2.40.1 From b1efcc7a09be8538063ad8a0447b8ff0e6da8395 Mon Sep 17 00:00:00 2001 From: Norwin Date: Tue, 28 Sep 2021 12:06:54 +0200 Subject: [PATCH 03/10] set up upstream remote for forks --- cmd/repos/clone.go | 58 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 14 deletions(-) diff --git a/cmd/repos/clone.go b/cmd/repos/clone.go index d7b186e..aa35eaa 100644 --- a/cmd/repos/clone.go +++ b/cmd/repos/clone.go @@ -5,13 +5,18 @@ package repos import ( + "fmt" "net/url" + "code.gitea.io/sdk/gitea" "code.gitea.io/tea/cmd/flags" + "code.gitea.io/tea/modules/config" "code.gitea.io/tea/modules/context" "code.gitea.io/tea/modules/git" "code.gitea.io/tea/modules/interact" + git_config "github.com/go-git/go-git/v5/config" + "github.com/go-git/go-git/v5/plumbing" "github.com/urfave/cli/v2" ) @@ -36,22 +41,17 @@ func runRepoClone(cmd *cli.Context) error { ctx := context.InitCommand(cmd) ctx.Ensure(context.CtxRequirement{RemoteRepo: true}) - // get clone URLs robustly - repo, _, err := ctx.Login.Client().GetRepo(ctx.Owner, ctx.Repo) - if err != nil { - return err - } - var url *url.URL - urlStr := repo.CloneURL - if ctx.Login.SSHKey != "" { - urlStr = repo.SSHURL - } - url, err = git.ParseURL(urlStr) + repoMeta, _, err := ctx.Login.Client().GetRepo(ctx.Owner, ctx.Repo) if err != nil { return err } - auth, err := git.GetAuthForURL(url, ctx.Login.Token, ctx.Login.SSHKey, interact.PromptPassword) + originURL, err := cloneURL(repoMeta, ctx.Login) + if err != nil { + return err + } + + auth, err := git.GetAuthForURL(originURL, ctx.Login.Token, ctx.Login.SSHKey, interact.PromptPassword) if err != nil { return err } @@ -62,13 +62,43 @@ func runRepoClone(cmd *cli.Context) error { localPath = ctx.Repo } - _, err = git.CloneIntoPath( - url.String(), + repo, err := git.CloneIntoPath( + originURL.String(), localPath, auth, ctx.Int("depth"), ctx.Login.Insecure, ) + // set up upstream remote for forks + if repoMeta.Fork && repoMeta.Parent != nil { + upstreamURL, err := cloneURL(repoMeta.Parent, ctx.Login) + if err != nil { + return err + } + upstreamBranch := repoMeta.Parent.DefaultBranch + repo.CreateRemote(&git_config.RemoteConfig{ + Name: "upstream", + URLs: []string{upstreamURL.String()}, + }) + repoConf, err := repo.Config() + if err != nil { + return err + } + if b, ok := repoConf.Branches[upstreamBranch]; ok { + b.Remote = "upstream" + b.Merge = plumbing.ReferenceName(fmt.Sprintf("refs/heads/%s", upstreamBranch)) + } + return repo.SetConfig(repoConf) + } + return err } + +func cloneURL(repo *gitea.Repository, login *config.Login) (*url.URL, error) { + urlStr := repo.CloneURL + if login.SSHKey != "" { + urlStr = repo.SSHURL + } + return git.ParseURL(urlStr) +} -- 2.40.1 From 344bd6ce74c0e5de6a14948920f61dfc869e5555 Mon Sep 17 00:00:00 2001 From: Norwin Date: Tue, 28 Sep 2021 12:28:06 +0200 Subject: [PATCH 04/10] move clone logic into task.RepoClone() --- cmd/repos/clone.go | 71 +++-------------------------- modules/git/repo.go | 15 ------ modules/task/repo_clone.go | 93 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+), 79 deletions(-) create mode 100644 modules/task/repo_clone.go diff --git a/cmd/repos/clone.go b/cmd/repos/clone.go index aa35eaa..c966efe 100644 --- a/cmd/repos/clone.go +++ b/cmd/repos/clone.go @@ -5,18 +5,11 @@ package repos import ( - "fmt" - "net/url" - - "code.gitea.io/sdk/gitea" "code.gitea.io/tea/cmd/flags" - "code.gitea.io/tea/modules/config" "code.gitea.io/tea/modules/context" - "code.gitea.io/tea/modules/git" "code.gitea.io/tea/modules/interact" + "code.gitea.io/tea/modules/task" - git_config "github.com/go-git/go-git/v5/config" - "github.com/go-git/go-git/v5/plumbing" "github.com/urfave/cli/v2" ) @@ -41,64 +34,14 @@ func runRepoClone(cmd *cli.Context) error { ctx := context.InitCommand(cmd) ctx.Ensure(context.CtxRequirement{RemoteRepo: true}) - repoMeta, _, err := ctx.Login.Client().GetRepo(ctx.Owner, ctx.Repo) - if err != nil { - return err - } - - originURL, err := cloneURL(repoMeta, ctx.Login) - if err != nil { - return err - } - - auth, err := git.GetAuthForURL(originURL, ctx.Login.Token, ctx.Login.SSHKey, interact.PromptPassword) - if err != nil { - return err - } - - // default path behaviour as native git - localPath := ctx.Args().First() - if localPath == "" { - localPath = ctx.Repo - } - - repo, err := git.CloneIntoPath( - originURL.String(), - localPath, - auth, + _, err := task.RepoClone( + ctx.Args().First(), + ctx.Login, + ctx.Owner, + ctx.Repo, + interact.PromptPassword, ctx.Int("depth"), - ctx.Login.Insecure, ) - // set up upstream remote for forks - if repoMeta.Fork && repoMeta.Parent != nil { - upstreamURL, err := cloneURL(repoMeta.Parent, ctx.Login) - if err != nil { - return err - } - upstreamBranch := repoMeta.Parent.DefaultBranch - repo.CreateRemote(&git_config.RemoteConfig{ - Name: "upstream", - URLs: []string{upstreamURL.String()}, - }) - repoConf, err := repo.Config() - if err != nil { - return err - } - if b, ok := repoConf.Branches[upstreamBranch]; ok { - b.Remote = "upstream" - b.Merge = plumbing.ReferenceName(fmt.Sprintf("refs/heads/%s", upstreamBranch)) - } - return repo.SetConfig(repoConf) - } - return err } - -func cloneURL(repo *gitea.Repository, login *config.Login) (*url.URL, error) { - urlStr := repo.CloneURL - if login.SSHKey != "" { - urlStr = repo.SSHURL - } - return git.ParseURL(urlStr) -} diff --git a/modules/git/repo.go b/modules/git/repo.go index 779f7ba..cc5d01e 100644 --- a/modules/git/repo.go +++ b/modules/git/repo.go @@ -6,7 +6,6 @@ package git import ( "github.com/go-git/go-git/v5" - "github.com/go-git/go-git/v5/plumbing/transport" ) // TeaRepo is a go-git Repository, with an extended high level interface. @@ -34,17 +33,3 @@ func RepoFromPath(path string) (*TeaRepo, error) { return &TeaRepo{repo}, nil } - -// CloneIntoPath emulates a git clone --depth ... -func CloneIntoPath(url, path string, auth transport.AuthMethod, depth int, insecure bool) (*TeaRepo, error) { - repo, err := git.PlainClone(path, false, &git.CloneOptions{ - URL: url, - Auth: auth, - Depth: depth, - InsecureSkipTLS: insecure, - }) - if err != nil { - return nil, err - } - return &TeaRepo{repo}, nil -} diff --git a/modules/task/repo_clone.go b/modules/task/repo_clone.go new file mode 100644 index 0000000..bc164fc --- /dev/null +++ b/modules/task/repo_clone.go @@ -0,0 +1,93 @@ +// Copyright 2021 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package task + +import ( + "fmt" + "net/url" + + "code.gitea.io/sdk/gitea" + "code.gitea.io/tea/modules/config" + local_git "code.gitea.io/tea/modules/git" + + "github.com/go-git/go-git/v5" + git_config "github.com/go-git/go-git/v5/config" + "github.com/go-git/go-git/v5/plumbing" +) + +// RepoClone creates a local git clone in the given path, and sets up upstream remote +// for fork repos, for good usability with tea. +func RepoClone( + path string, + login *config.Login, + repoOwner, repoName string, + callback func(string) (string, error), + depth int, +) (*local_git.TeaRepo, error) { + + repoMeta, _, err := login.Client().GetRepo(repoOwner, repoName) + if err != nil { + return nil, err + } + + originURL, err := cloneURL(repoMeta, login) + if err != nil { + return nil, err + } + + auth, err := local_git.GetAuthForURL(originURL, login.Token, login.SSHKey, callback) + if err != nil { + return nil, err + } + + // default path behaviour as native git + if path == "" { + path = repoName + } + + repo, err := git.PlainClone(path, false, &git.CloneOptions{ + URL: originURL.String(), + Auth: auth, + Depth: depth, + InsecureSkipTLS: login.Insecure, + }) + if err != nil { + return nil, err + } + + // set up upstream remote for forks + if repoMeta.Fork && repoMeta.Parent != nil { + upstreamURL, err := cloneURL(repoMeta.Parent, login) + if err != nil { + return nil, err + } + upstreamBranch := repoMeta.Parent.DefaultBranch + repo.CreateRemote(&git_config.RemoteConfig{ + Name: "upstream", + URLs: []string{upstreamURL.String()}, + }) + repoConf, err := repo.Config() + if err != nil { + return nil, err + } + if b, ok := repoConf.Branches[upstreamBranch]; ok { + b.Remote = "upstream" + b.Merge = plumbing.ReferenceName(fmt.Sprintf("refs/heads/%s", upstreamBranch)) + } + if err = repo.SetConfig(repoConf); err != nil { + return nil, err + } + } + + return &local_git.TeaRepo{Repository: repo}, nil +} + +func cloneURL(repo *gitea.Repository, login *config.Login) (*url.URL, error) { + urlStr := repo.CloneURL + if login.SSHKey != "" { + urlStr = repo.SSHURL + } + return local_git.ParseURL(urlStr) +} -- 2.40.1 From 4077ea7102e55a0328e05d59921bb64230d83071 Mon Sep 17 00:00:00 2001 From: Norwin Date: Mon, 18 Oct 2021 10:21:50 +0200 Subject: [PATCH 05/10] move out of repo namespace --- cmd/{repos => }/clone.go | 5 +++-- cmd/repos.go | 1 - main.go | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) rename cmd/{repos => }/clone.go (94%) diff --git a/cmd/repos/clone.go b/cmd/clone.go similarity index 94% rename from cmd/repos/clone.go rename to cmd/clone.go index c966efe..8459f5b 100644 --- a/cmd/repos/clone.go +++ b/cmd/clone.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package repos +package cmd import ( "code.gitea.io/tea/cmd/flags" @@ -18,7 +18,8 @@ var CmdRepoClone = cli.Command{ Name: "clone", Aliases: []string{"C"}, Usage: "Clone a repository locally", - Description: "Clone a repository locally, without a local git installation required (defaults to PWD)", + Description: "Clone a repository locally, without a local git installation required", + Category: catHelpers, Action: runRepoClone, ArgsUsage: "[target dir]", Flags: append([]cli.Flag{ diff --git a/cmd/repos.go b/cmd/repos.go index a738637..3667995 100644 --- a/cmd/repos.go +++ b/cmd/repos.go @@ -28,7 +28,6 @@ var CmdRepos = cli.Command{ &repos.CmdReposSearch, &repos.CmdRepoCreate, &repos.CmdRepoFork, - &repos.CmdRepoClone, }, Flags: repos.CmdReposListFlags, } diff --git a/main.go b/main.go index 52735cf..580cb38 100644 --- a/main.go +++ b/main.go @@ -49,6 +49,7 @@ func main() { &cmd.CmdOpen, &cmd.CmdNotifications, + &cmd.CmdRepoClone, } app.EnableBashCompletion = true err := app.Run(os.Args) -- 2.40.1 From b7ab1cf95ec17f2dbeb884c230a35a8fde035899 Mon Sep 17 00:00:00 2001 From: Norwin Date: Mon, 18 Oct 2021 11:33:18 +0200 Subject: [PATCH 06/10] refactor URL handling + test git.ParseURL in preparation to handle more cases for `tea clone ` --- modules/git/url.go | 19 ++++++++----- modules/git/url_test.go | 56 +++++++++++++++++++++++++++++++++++++ modules/task/pull_create.go | 2 +- modules/utils/parse.go | 2 +- 4 files changed, 70 insertions(+), 9 deletions(-) create mode 100644 modules/git/url_test.go diff --git a/modules/git/url.go b/modules/git/url.go index 5b5a9a5..f76a666 100644 --- a/modules/git/url.go +++ b/modules/git/url.go @@ -22,13 +22,18 @@ type URLParser struct { func (p *URLParser) Parse(rawURL string) (u *url.URL, err error) { rawURL = strings.TrimSpace(rawURL) - // convert the weird git ssh url format to a canonical url: - // git@gitea.com:gitea/tea -> ssh://git@gitea.com/gitea/tea - if !protocolRe.MatchString(rawURL) && - strings.Contains(rawURL, ":") && - // not a Windows path - !strings.Contains(rawURL, "\\") { - rawURL = "ssh://" + strings.Replace(rawURL, ":", "/", 1) + if !protocolRe.MatchString(rawURL) { + // convert the weird git ssh url format to a canonical url: + // git@gitea.com:gitea/tea -> ssh://git@gitea.com/gitea/tea + if strings.Contains(rawURL, ":") && + // not a Windows path + !strings.Contains(rawURL, "\\") { + rawURL = "ssh://" + strings.Replace(rawURL, ":", "/", 1) + } else if !strings.Contains(rawURL, "@") && + strings.Count(rawURL, "/") == 2 { + // match cases like gitea.com/gitea/tea + rawURL = "https://" + rawURL + } } u, err = url.Parse(rawURL) diff --git a/modules/git/url_test.go b/modules/git/url_test.go new file mode 100644 index 0000000..f342525 --- /dev/null +++ b/modules/git/url_test.go @@ -0,0 +1,56 @@ +// Copyright 2019 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package git + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestParseUrl(t *testing.T) { + u, err := ParseURL("ssh://git@gitea.com:3000/gitea/tea") + assert.NoError(t, err) + assert.Equal(t, "gitea.com:3000", u.Host) + assert.Equal(t, "ssh", u.Scheme) + assert.Equal(t, "/gitea/tea", u.Path) + + u, err = ParseURL("https://gitea.com/gitea/tea") + assert.NoError(t, err) + assert.Equal(t, "gitea.com", u.Host) + assert.Equal(t, "https", u.Scheme) + assert.Equal(t, "/gitea/tea", u.Path) + + u, err = ParseURL("git@gitea.com:gitea/tea") + assert.NoError(t, err) + assert.Equal(t, "gitea.com", u.Host) + assert.Equal(t, "ssh", u.Scheme) + assert.Equal(t, "/gitea/tea", u.Path) + + u, err = ParseURL("gitea.com/gitea/tea") + assert.NoError(t, err) + assert.Equal(t, "gitea.com", u.Host) + assert.Equal(t, "https", u.Scheme) + assert.Equal(t, "/gitea/tea", u.Path) + + u, err = ParseURL("foo/bar") + assert.NoError(t, err) + assert.Equal(t, "", u.Host) + assert.Equal(t, "", u.Scheme) + assert.Equal(t, "foo/bar", u.Path) + + u, err = ParseURL("/foo/bar") + assert.NoError(t, err) + assert.Equal(t, "", u.Host) + assert.Equal(t, "https", u.Scheme) + assert.Equal(t, "/foo/bar", u.Path) + + // this case is unintuitive, but to ambiguous to be handled differently + u, err = ParseURL("gitea.com") + assert.NoError(t, err) + assert.Equal(t, "", u.Host) + assert.Equal(t, "", u.Scheme) + assert.Equal(t, "gitea.com", u.Path) +} diff --git a/modules/task/pull_create.go b/modules/task/pull_create.go index b7505b5..8ed6ec9 100644 --- a/modules/task/pull_create.go +++ b/modules/task/pull_create.go @@ -108,7 +108,7 @@ func GetDefaultPRHead(localRepo *local_git.TeaRepo) (owner, branch string, err e if err != nil { return } - owner, _ = utils.GetOwnerAndRepo(strings.TrimLeft(url.Path, "/"), "") + owner, _ = utils.GetOwnerAndRepo(url.Path, "") return } diff --git a/modules/utils/parse.go b/modules/utils/parse.go index 41e88ae..63fd19e 100644 --- a/modules/utils/parse.go +++ b/modules/utils/parse.go @@ -33,7 +33,7 @@ func GetOwnerAndRepo(repoPath, user string) (string, string) { if len(repoPath) == 0 { return "", "" } - p := strings.Split(repoPath, "/") + p := strings.Split(strings.TrimLeft(repoPath, "/"), "/") if len(p) >= 2 { return p[0], p[1] } -- 2.40.1 From b8cec7336f9656555ad1932b60c6c652c7849324 Mon Sep 17 00:00:00 2001 From: Norwin Date: Mon, 18 Oct 2021 11:34:14 +0200 Subject: [PATCH 07/10] accept repo slug as first arg instead of `--repo` and accept various formats (tea, gitea/tea, gitea.com/gitea/tea, ...) --- cmd/clone.go | 54 +++++++++++++++++++++++++++++++++++------ modules/config/login.go | 19 +++++++++++++++ 2 files changed, 65 insertions(+), 8 deletions(-) diff --git a/cmd/clone.go b/cmd/clone.go index 8459f5b..8d3bd58 100644 --- a/cmd/clone.go +++ b/cmd/clone.go @@ -5,10 +5,15 @@ package cmd import ( + "fmt" + "code.gitea.io/tea/cmd/flags" + "code.gitea.io/tea/modules/config" "code.gitea.io/tea/modules/context" + "code.gitea.io/tea/modules/git" "code.gitea.io/tea/modules/interact" "code.gitea.io/tea/modules/task" + "code.gitea.io/tea/modules/utils" "github.com/urfave/cli/v2" ) @@ -22,24 +27,57 @@ var CmdRepoClone = cli.Command{ Category: catHelpers, Action: runRepoClone, ArgsUsage: "[target dir]", - Flags: append([]cli.Flag{ + Flags: []cli.Flag{ &cli.IntFlag{ Name: "depth", Aliases: []string{"d"}, Usage: "num commits to fetch, defaults to all", }, - }, flags.LoginRepoFlags...), + &flags.LoginFlag, + }, } func runRepoClone(cmd *cli.Context) error { ctx := context.InitCommand(cmd) - ctx.Ensure(context.CtxRequirement{RemoteRepo: true}) - _, err := task.RepoClone( - ctx.Args().First(), - ctx.Login, - ctx.Owner, - ctx.Repo, + args := ctx.Args() + if args.Len() < 1 { + return cli.ShowCommandHelp(cmd, "clone") + } + dir := args.Get(1) + + var ( + login *config.Login = ctx.Login + owner string = ctx.Login.User + repo string + ) + + // parse first arg as repo specifier. can be one of + // tea (default login + user of that login) + // gitea/tea (default login) + // gitea.com/gitea/tea (finds matching login) + // https://gitea.com/gitea/tea + // ssh://git@gitea.com/gitea/tea + // git@gitea.com:gitea/tea + repoSlug := args.Get(0) + url, err := git.ParseURL(repoSlug) + if err != nil { + return err + } + + owner, repo = utils.GetOwnerAndRepo(url.Path, login.User) + if url.Host != "" { + login = config.GetLoginByHost(url.Host) + if login == nil { + return fmt.Errorf("No login configured matching host '%s', run `tea login add` first.", url.Host) + } + } + + _, err = task.RepoClone( + dir, + login, + owner, + repo, interact.PromptPassword, ctx.Int("depth"), ) diff --git a/modules/config/login.go b/modules/config/login.go index 47f944c..ddecd2f 100644 --- a/modules/config/login.go +++ b/modules/config/login.go @@ -111,6 +111,25 @@ func GetLoginByToken(token string) *Login { return nil } +// GetLoginByHost finds a login by it's server URL +func GetLoginByHost(host string) *Login { + err := loadConfig() + if err != nil { + log.Fatal(err) + } + + for _, l := range config.Logins { + loginURL, err := url.Parse(l.URL) + if err != nil { + log.Fatal(err) + } + if loginURL.Host == host { + return &l + } + } + return nil +} + // DeleteLogin delete a login by name from config func DeleteLogin(name string) error { var idx = -1 -- 2.40.1 From 0674a1c6f43ddb3f7bd1966f124a4042527094c0 Mon Sep 17 00:00:00 2001 From: Norwin Date: Mon, 18 Oct 2021 11:50:47 +0200 Subject: [PATCH 08/10] fix docs --- cmd/clone.go | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/cmd/clone.go b/cmd/clone.go index 8d3bd58..367e2a0 100644 --- a/cmd/clone.go +++ b/cmd/clone.go @@ -20,13 +20,22 @@ import ( // CmdRepoClone represents a sub command of repos to create a local copy var CmdRepoClone = cli.Command{ - Name: "clone", - Aliases: []string{"C"}, - Usage: "Clone a repository locally", - Description: "Clone a repository locally, without a local git installation required", - Category: catHelpers, - Action: runRepoClone, - ArgsUsage: "[target dir]", + Name: "clone", + Aliases: []string{"C"}, + Usage: "Clone a repository locally", + Description: `Clone a repository locally, without a local git installation required. + The repo slug can hold different formats: + gitea/tea + tea + gitea.com/gitea/tea + git@gitea.com:gitea/tea + https://gitea.com/gitea/tea + ssh://gitea.com:22/gitea/tea + When a host is specified in the repo-slug, it will override the login specified with --login. + `, + Category: catHelpers, + Action: runRepoClone, + ArgsUsage: " [target dir]", Flags: []cli.Flag{ &cli.IntFlag{ Name: "depth", @@ -52,13 +61,7 @@ func runRepoClone(cmd *cli.Context) error { repo string ) - // parse first arg as repo specifier. can be one of - // tea (default login + user of that login) - // gitea/tea (default login) - // gitea.com/gitea/tea (finds matching login) - // https://gitea.com/gitea/tea - // ssh://git@gitea.com/gitea/tea - // git@gitea.com:gitea/tea + // parse first arg as repo specifier repoSlug := args.Get(0) url, err := git.ParseURL(repoSlug) if err != nil { -- 2.40.1 From 0bdd95adbca1bc62d13b3e05701b4f4cb5a6cc19 Mon Sep 17 00:00:00 2001 From: Norwin Date: Mon, 18 Oct 2021 11:52:40 +0200 Subject: [PATCH 09/10] lint --- cmd/clone.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/clone.go b/cmd/clone.go index 367e2a0..d021181 100644 --- a/cmd/clone.go +++ b/cmd/clone.go @@ -72,7 +72,7 @@ func runRepoClone(cmd *cli.Context) error { if url.Host != "" { login = config.GetLoginByHost(url.Host) if login == nil { - return fmt.Errorf("No login configured matching host '%s', run `tea login add` first.", url.Host) + return fmt.Errorf("No login configured matching host '%s', run `tea login add` first", url.Host) } } -- 2.40.1 From b4e302c2f9bc2fb81c31ddcaf3ba5f91c8801622 Mon Sep 17 00:00:00 2001 From: Norwin Date: Mon, 18 Oct 2021 11:59:58 +0200 Subject: [PATCH 10/10] improve help layout --- cmd/clone.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/cmd/clone.go b/cmd/clone.go index d021181..e7e4e42 100644 --- a/cmd/clone.go +++ b/cmd/clone.go @@ -24,14 +24,14 @@ var CmdRepoClone = cli.Command{ Aliases: []string{"C"}, Usage: "Clone a repository locally", Description: `Clone a repository locally, without a local git installation required. - The repo slug can hold different formats: - gitea/tea - tea - gitea.com/gitea/tea - git@gitea.com:gitea/tea - https://gitea.com/gitea/tea - ssh://gitea.com:22/gitea/tea - When a host is specified in the repo-slug, it will override the login specified with --login. +The repo slug can be specified in different formats: + gitea/tea + tea + gitea.com/gitea/tea + git@gitea.com:gitea/tea + https://gitea.com/gitea/tea + ssh://gitea.com:22/gitea/tea +When a host is specified in the repo-slug, it will override the login specified with --login. `, Category: catHelpers, Action: runRepoClone, -- 2.40.1