Skip to content

Commit

Permalink
feat: added --ssh-auth option (#215)
Browse files Browse the repository at this point in the history
  • Loading branch information
lindell committed Dec 16, 2021
1 parent 8e30ba9 commit f5767a8
Show file tree
Hide file tree
Showing 10 changed files with 110 additions and 78 deletions.
12 changes: 9 additions & 3 deletions cmd/platform.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ func configurePlatform(cmd *cobra.Command) {
flags.StringSliceP("repo", "R", nil, "The name, including owner of a GitHub repository in the format \"ownerName/repoName\".")
flags.StringSliceP("project", "P", nil, "The name, including owner of a GitLab project in the format \"ownerName/repoName\".")
flags.BoolP("include-subgroups", "", false, "Include GitLab subgroups when using the --group flag.")
flags.BoolP("ssh-auth", "", false, `Use SSH cloning URL instead of HTTPS + token. This requires that a setup with ssh keys that have access to all repos and that the server is already in known_hosts.`)

flags.StringP("platform", "p", "github", "The platform that is used. Available values: github, gitlab, gitea, bitbucket_server.")
_ = cmd.RegisterFlagCompletionFunc("platform", func(cmd *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) {
Expand Down Expand Up @@ -120,6 +121,7 @@ func createGithubClient(flag *flag.FlagSet, verifyFlags bool) (multigitter.Versi
repos, _ := flag.GetStringSlice("repo")
forkMode, _ := flag.GetBool("fork")
forkOwner, _ := flag.GetString("fork-owner")
sshAuth, _ := flag.GetBool("ssh-auth")

if verifyFlags && len(orgs) == 0 && len(users) == 0 && len(repos) == 0 {
return nil, errors.New("no organization, user or repo set")
Expand Down Expand Up @@ -147,7 +149,7 @@ func createGithubClient(flag *flag.FlagSet, verifyFlags bool) (multigitter.Versi
Organizations: orgs,
Users: users,
Repositories: repoRefs,
}, mergeTypes, forkMode, forkOwner)
}, mergeTypes, forkMode, forkOwner, sshAuth)
if err != nil {
return nil, err
}
Expand All @@ -161,6 +163,7 @@ func createGitlabClient(flag *flag.FlagSet, verifyFlags bool) (multigitter.Versi
users, _ := flag.GetStringSlice("user")
projects, _ := flag.GetStringSlice("project")
includeSubgroups, _ := flag.GetBool("include-subgroups")
sshAuth, _ := flag.GetBool("ssh-auth")

if verifyFlags && len(groups) == 0 && len(users) == 0 && len(projects) == 0 {
return nil, errors.New("no group user or project set")
Expand All @@ -185,6 +188,7 @@ func createGitlabClient(flag *flag.FlagSet, verifyFlags bool) (multigitter.Versi
Projects: projRefs,
}, gitlab.Config{
IncludeSubgroups: includeSubgroups,
SSHAuth: sshAuth,
})
if err != nil {
return nil, err
Expand All @@ -198,6 +202,7 @@ func createGiteaClient(flag *flag.FlagSet, verifyFlags bool) (multigitter.Versio
orgs, _ := flag.GetStringSlice("org")
users, _ := flag.GetStringSlice("user")
repos, _ := flag.GetStringSlice("repo")
sshAuth, _ := flag.GetBool("ssh-auth")

if verifyFlags && len(orgs) == 0 && len(users) == 0 && len(repos) == 0 {
return nil, errors.New("no organization, user or repository set")
Expand Down Expand Up @@ -229,7 +234,7 @@ func createGiteaClient(flag *flag.FlagSet, verifyFlags bool) (multigitter.Versio
Organizations: orgs,
Users: users,
Repositories: repoRefs,
}, mergeTypes)
}, mergeTypes, sshAuth)
if err != nil {
return nil, err
}
Expand All @@ -244,6 +249,7 @@ func createBitbucketServerClient(flag *flag.FlagSet, verifyFlags bool) (multigit
repos, _ := flag.GetStringSlice("repo")
username, _ := flag.GetString("username")
insecure, _ := flag.GetBool("insecure")
sshAuth, _ := flag.GetBool("ssh-auth")

if verifyFlags && len(projects) == 0 && len(users) == 0 && len(repos) == 0 {
return nil, errors.New("no organization, user or repository set")
Expand All @@ -270,7 +276,7 @@ func createBitbucketServerClient(flag *flag.FlagSet, verifyFlags bool) (multigit
}
}

vc, err := bitbucketserver.New(username, token, bitbucketServerBaseURL, insecure, http.NewLoggingRoundTripper, bitbucketserver.RepositoryListing{
vc, err := bitbucketserver.New(username, token, bitbucketServerBaseURL, insecure, sshAuth, http.NewLoggingRoundTripper, bitbucketserver.RepositoryListing{
Projects: projects,
Users: users,
Repositories: repoRefs,
Expand Down
9 changes: 6 additions & 3 deletions internal/scm/bitbucketserver/bitbucket_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,14 @@ import (
)

const (
cloneType = "http"
cloneHTTPType = "http"
cloneSSHType = "ssh"
stateMerged = "MERGED"
stateDeclined = "DECLINED"
)

// New create a new BitbucketServer client
func New(username, token, baseURL string, insecure bool, transportMiddleware func(http.RoundTripper) http.RoundTripper, repoListing RepositoryListing) (*BitbucketServer, error) {
func New(username, token, baseURL string, insecure bool, sshAuth bool, transportMiddleware func(http.RoundTripper) http.RoundTripper, repoListing RepositoryListing) (*BitbucketServer, error) {
if strings.TrimSpace(token) == "" {
return nil, errors.New("token is empty")
}
Expand All @@ -49,6 +50,7 @@ func New(username, token, baseURL string, insecure bool, transportMiddleware fun
bitbucketServer.baseURL = bitbucketBaseURL
bitbucketServer.username = username
bitbucketServer.token = token
bitbucketServer.sshAuth = sshAuth
bitbucketServer.httpClient = &http.Client{
Transport: transportMiddleware(&http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: insecure}, // nolint: gosec
Expand Down Expand Up @@ -78,6 +80,7 @@ type BitbucketServer struct {
RepositoryListing
baseURL *url.URL
username, token string
sshAuth bool
config *bitbucketv1.Configuration
httpClient *http.Client
}
Expand Down Expand Up @@ -136,7 +139,7 @@ func (b *BitbucketServer) GetRepositories(ctx context.Context) ([]scm.Repository
return nil, err
}

repo, repoErr := convertRepository(bitbucketRepository, defaultBranch, b.username, b.token)
repo, repoErr := b.convertRepository(bitbucketRepository, defaultBranch)
if repoErr != nil {
return nil, repoErr
}
Expand Down
54 changes: 29 additions & 25 deletions internal/scm/bitbucketserver/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,54 +8,58 @@ import (
"github.com/pkg/errors"
)

func convertRepository(bitbucketRepository *bitbucketv1.Repository, defaultBranch bitbucketv1.Branch, username, token string) (*repository, error) {
var cloneURL *url.URL
var err error
for _, clone := range bitbucketRepository.Links.Clone {
if strings.EqualFold(clone.Name, cloneType) {
cloneURL, err = url.Parse(clone.Href)
if err != nil {
return nil, err
}
func (b *BitbucketServer) convertRepository(bitbucketRepository *bitbucketv1.Repository, defaultBranch bitbucketv1.Branch) (*repository, error) {
var cloneURL string

break
if b.sshAuth {
cloneURL = findLinkType(bitbucketRepository.Links.Clone, cloneSSHType)
if cloneURL == "" {
return nil, errors.Errorf("unable to find clone url for repository %s using clone type %s", bitbucketRepository.Name, cloneSSHType)
}
} else {
httpURL := findLinkType(bitbucketRepository.Links.Clone, cloneHTTPType)
if httpURL == "" {
return nil, errors.Errorf("unable to find clone url for repository %s using clone type %s", bitbucketRepository.Name, cloneHTTPType)
}
parsedURL, err := url.Parse(httpURL)
if err != nil {
return nil, err
}
}

if cloneURL == nil {
return nil, errors.Errorf("unable to find clone url for repostory %s using clone type %s", bitbucketRepository.Name, cloneType)
parsedURL.User = url.UserPassword(b.username, b.token)
cloneURL = parsedURL.String()
}

repo := repository{
name: bitbucketRepository.Slug,
project: bitbucketRepository.Project.Key,
defaultBranch: defaultBranch.DisplayID,
username: username,
token: token,
cloneURL: cloneURL,
}

return &repo, nil
}

func findLinkType(links []bitbucketv1.CloneLink, cloneType string) string {
for _, clone := range links {
if strings.EqualFold(clone.Name, cloneType) {
return clone.Href
}
}

return ""
}

// repository contains information about a bitbucket repository
type repository struct {
name string
project string
defaultBranch string
username string
token string
cloneURL *url.URL
cloneURL string
}

func (r repository) CloneURL() string {
cloneURL := r.cloneURL

if r.username != "" && r.token != "" {
cloneURL.User = url.UserPassword(r.username, r.token)
}

return cloneURL.String()
return r.cloneURL
}

func (r repository) DefaultBranch() string {
Expand Down
10 changes: 6 additions & 4 deletions internal/scm/gitea/gitea.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,15 @@ import (
)

// New create a new Gitea client
func New(token, baseURL string, repoListing RepositoryListing, mergeTypes []scm.MergeType) (*Gitea, error) {
func New(token, baseURL string, repoListing RepositoryListing, mergeTypes []scm.MergeType, sshAuth bool) (*Gitea, error) {
gitea := &Gitea{
RepositoryListing: repoListing,

baseURL: baseURL,
token: token,

MergeTypes: mergeTypes,
SSHAuth: sshAuth,
}

// Initialize the gitea client to ensure no error will occur when running a function
Expand Down Expand Up @@ -58,6 +59,7 @@ type Gitea struct {
currentUser *gitea.User

MergeTypes []scm.MergeType
SSHAuth bool
}

// RepositoryListing contains information about which repositories that should be fetched
Expand Down Expand Up @@ -94,7 +96,7 @@ func (g *Gitea) GetRepositories(ctx context.Context) ([]scm.Repository, error) {

repos := make([]scm.Repository, 0, len(allRepos))
for _, repo := range allRepos {
convertedRepo, err := convertRepository(repo, g.token)
convertedRepo, err := g.convertRepository(repo)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -424,7 +426,7 @@ func (g *Gitea) ForkRepository(ctx context.Context, repo scm.Repository, newOwne

existingRepo, _, err := g.giteaClient(ctx).GetRepo(forkTo, r.name)
if err == nil { // NB!
return convertRepository(existingRepo, g.token)
return g.convertRepository(existingRepo)
}

forkOptions := gitea.CreateForkOption{}
Expand All @@ -437,7 +439,7 @@ func (g *Gitea) ForkRepository(ctx context.Context, repo scm.Repository, newOwne
return nil, err
}

return convertRepository(createdRepo, g.token)
return g.convertRepository(createdRepo)
}

func (g *Gitea) getUser(ctx context.Context) (*gitea.User, error) {
Expand Down
26 changes: 15 additions & 11 deletions internal/scm/gitea/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,33 +7,37 @@ import (
"code.gitea.io/sdk/gitea"
)

func convertRepository(repo *gitea.Repository, token string) (repository, error) {
u, err := url.Parse(repo.CloneURL)
if err != nil {
return repository{}, err
func (g *Gitea) convertRepository(repo *gitea.Repository) (repository, error) {
var repoURL string
if g.SSHAuth {
repoURL = repo.SSHURL
} else {
u, err := url.Parse(repo.CloneURL)
if err != nil {
return repository{}, err
}
// Set the token as https://oauth2:TOKEN@url
u.User = url.UserPassword("oauth2", g.token)
repoURL = u.String()
}

return repository{
url: *u,
url: repoURL,
name: repo.Name,
ownerName: repo.Owner.UserName,
defaultBranch: repo.DefaultBranch,
token: token,
}, nil
}

type repository struct {
url url.URL
url string
name string
ownerName string
defaultBranch string
token string
}

func (r repository) CloneURL() string {
// Set the token as https://oauth2:TOKEN@url
r.url.User = url.UserPassword("oauth2", r.token)
return r.url.String()
return r.url
}

func (r repository) DefaultBranch() string {
Expand Down
11 changes: 8 additions & 3 deletions internal/scm/github/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ func New(
mergeTypes []scm.MergeType,
forkMode bool,
forkOwner string,
sshAuth bool,
) (*Github, error) {
ctx := context.Background()
ts := oauth2.StaticTokenSource(
Expand All @@ -50,6 +51,7 @@ func New(
token: token,
Fork: forkMode,
ForkOwner: forkOwner,
SSHAuth: sshAuth,
ghClient: client,
}, nil
}
Expand All @@ -67,6 +69,9 @@ type Github struct {
// If set, the fork will happen to the ForkOwner value, and not the logged in user
ForkOwner string

// If set, use the SSH clone url instead of http(s)
SSHAuth bool

ghClient *github.Client

// Caching of the logged in user
Expand Down Expand Up @@ -127,7 +132,7 @@ func (g *Github) GetRepositories(ctx context.Context) ([]scm.Repository, error)
continue
}

newRepo, err := convertRepo(r, g.token)
newRepo, err := g.convertRepo(r)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -482,13 +487,13 @@ func (g *Github) ForkRepository(ctx context.Context, repo scm.Repository, newOwn
continue
}
// The fork does now exist
return convertRepo(repo, g.token)
return g.convertRepo(repo)
}

return nil, errors.New("time waiting for fork to complete was exceeded")
}

return convertRepo(createdRepo, g.token)
return g.convertRepo(createdRepo)
}

// GetAutocompleteOrganizations gets organizations for autocompletion
Expand Down
8 changes: 4 additions & 4 deletions internal/scm/github/github_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ func Test_GetRepositories(t *testing.T) {
{
gh, err := github.New("", "", transport.Wrapper, github.RepositoryListing{
Organizations: []string{"test-org"},
}, []scm.MergeType{scm.MergeTypeMerge}, false, "")
}, []scm.MergeType{scm.MergeTypeMerge}, false, "", false)
require.NoError(t, err)

repos, err := gh.GetRepositories(context.Background())
Expand All @@ -137,7 +137,7 @@ func Test_GetRepositories(t *testing.T) {
Name: "test1",
},
},
}, []scm.MergeType{scm.MergeTypeMerge}, false, "")
}, []scm.MergeType{scm.MergeTypeMerge}, false, "", false)
require.NoError(t, err)

repos, err := gh.GetRepositories(context.Background())
Expand All @@ -152,7 +152,7 @@ func Test_GetRepositories(t *testing.T) {
{
gh, err := github.New("", "", transport.Wrapper, github.RepositoryListing{
Users: []string{"test-user"},
}, []scm.MergeType{scm.MergeTypeMerge}, false, "")
}, []scm.MergeType{scm.MergeTypeMerge}, false, "", false)
require.NoError(t, err)

repos, err := gh.GetRepositories(context.Background())
Expand All @@ -174,7 +174,7 @@ func Test_GetRepositories(t *testing.T) {
Name: "test1",
},
},
}, []scm.MergeType{scm.MergeTypeMerge}, false, "")
}, []scm.MergeType{scm.MergeTypeMerge}, false, "", false)
require.NoError(t, err)

repos, err := gh.GetRepositories(context.Background())
Expand Down

0 comments on commit f5767a8

Please sign in to comment.