Skip to content

Commit

Permalink
Merge pull request #126 from fluxcd/add-provider-url-methods
Browse files Browse the repository at this point in the history
[Stash] Add methods to generate a clone url for a specific provider.
  • Loading branch information
souleb authored Nov 12, 2021
2 parents bbf0f49 + 2cc05ef commit 18218b6
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 16 deletions.
28 changes: 20 additions & 8 deletions gitprovider/repositoryref.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,8 +279,8 @@ func (r UserRepositoryRef) GetRepository() string {
return r.RepositoryName
}

// GetSlug returns the unique slug for this object.
func (r UserRepositoryRef) GetSlug() string {
// Slug returns the unique slug for this object.
func (r UserRepositoryRef) Slug() string {
return r.slug
}

Expand Down Expand Up @@ -309,18 +309,30 @@ func (r UserRepositoryRef) GetCloneURL(transport TransportType) string {
func GetCloneURL(rs RepositoryRef, transport TransportType) string {
switch transport {
case TransportTypeHTTPS:
return fmt.Sprintf("%s.git", rs.String())
return ParseTypeHTTPS(rs.String())
case TransportTypeGit:
return fmt.Sprintf("git@%s:%s/%s.git", rs.GetDomain(), rs.GetIdentity(), rs.GetRepository())
return ParseTypeGit(rs.GetDomain(), rs.GetIdentity(), rs.GetRepository())
case TransportTypeSSH:
trimmedDomain := rs.GetDomain()
trimmedDomain = strings.Replace(trimmedDomain, "https://", "", -1)
trimmedDomain = strings.Replace(trimmedDomain, "http://", "", -1)
return fmt.Sprintf("ssh://git@%s/%s/%s", trimmedDomain, rs.GetIdentity(), rs.GetRepository())
return ParseTypeSSH(rs.GetDomain(), rs.GetIdentity(), rs.GetRepository())
}
return ""
}

func ParseTypeHTTPS(url string) string {
return fmt.Sprintf("%s.git", url)
}

func ParseTypeGit(domain, identity, repository string) string {
return fmt.Sprintf("git@%s:%s/%s.git", domain, identity, repository)
}

func ParseTypeSSH(domain, identity, repository string) string {
trimmedDomain := domain
trimmedDomain = strings.Replace(trimmedDomain, "https://", "", -1)
trimmedDomain = strings.Replace(trimmedDomain, "http://", "", -1)
return fmt.Sprintf("ssh://git@%s/%s/%s", trimmedDomain, identity, repository)
}

// ParseOrganizationURL parses an URL to an organization into a OrganizationRef object.
func ParseOrganizationURL(o string) (*OrganizationRef, error) {
u, parts, err := parseURL(o)
Expand Down
5 changes: 5 additions & 0 deletions gitprovider/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ type OrgRepository interface {
TeamAccess() TeamAccessClient
}

// CloneableURL returns the HTTPS URL to clone the repository.
type CloneableURL interface {
GetCloneURL(prefix string, transport TransportType) string
}

// DeployKey represents a short-lived credential (e.g. an SSH public key) used to access a repository.
type DeployKey interface {
// DeployKey implements the Object interface,
Expand Down
6 changes: 3 additions & 3 deletions stash/client_repositories_user.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func (c *UserRepositoriesClient) Get(ctx context.Context, ref gitprovider.UserRe
return nil, err
}

slug := ref.GetSlug()
slug := ref.Slug()
if slug == "" {
// try with name
slug = ref.GetRepository()
Expand Down Expand Up @@ -182,9 +182,9 @@ func (c *UserRepositoriesClient) reconcileRepository(ctx context.Context, actual
ref := actual.Repository().(gitprovider.UserRepositoryRef)
// Apply the desired state by running Update
if *req.DefaultBranch != "" && repo.DefaultBranch != *req.DefaultBranch {
_, err = update(ctx, c.client, addTilde(ref.UserLogin), ref.GetSlug(), repo, *req.DefaultBranch)
_, err = update(ctx, c.client, addTilde(ref.UserLogin), ref.Slug(), repo, *req.DefaultBranch)
} else {
_, err = update(ctx, c.client, addTilde(ref.UserLogin), ref.GetSlug(), repo, "")
_, err = update(ctx, c.client, addTilde(ref.UserLogin), ref.Slug(), repo, "")
}

if err != nil {
Expand Down
16 changes: 13 additions & 3 deletions stash/integration_repositories_org_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ var _ = Describe("Stash Provider", func() {
testOrgRepoName = fmt.Sprintf("test-org-repo-%03d", rand.Intn(1000))
}

fmt.Print("Creating repository ", testOrgRepoName, "...")
// We know that a repo with this name doesn't exist in the organization, let's verify we get an
// ErrNotFound
repoRef := newOrgRepoRef(testOrg.Organization(), testOrgRepoName)
Expand All @@ -92,10 +93,19 @@ var _ = Describe("Stash Provider", func() {

validateOrgRepo(repo, getRepoRef.Repository())

getRepo, err := client.OrgRepositories().Get(ctx, repoRef)
Expect(err).ToNot(HaveOccurred())
// Verify that we can get clone url for the repo
if cloner, ok := getRepoRef.(gitprovider.CloneableURL); ok {
url := cloner.GetCloneURL("scm", gitprovider.TransportTypeHTTPS)
Expect(url).ToNot(BeEmpty())
fmt.Println("Clone URL: ", url)

sshURL := cloner.GetCloneURL("scm", gitprovider.TransportTypeSSH)
Expect(url).ToNot(BeEmpty())
fmt.Println("Clone ssh URL: ", sshURL)
}

// Expect the two responses (one from POST and one from GET to have equal "spec")
getSpec := repositoryFromAPI(getRepo.APIObject().(*Repository))
getSpec := repositoryFromAPI(getRepoRef.APIObject().(*Repository))
postSpec := repositoryFromAPI(repo.APIObject().(*Repository))
Expect(getSpec.Equals(postSpec)).To(BeTrue())
})
Expand Down
11 changes: 11 additions & 0 deletions stash/integration_repositories_user_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,17 @@ var _ = Describe("Stash Provider", func() {
getRepoRef, err := client.UserRepositories().Get(ctx, repoRef)
Expect(err).ToNot(HaveOccurred())

// Verify that we can get clone url for the repo
if cloner, ok := getRepoRef.(gitprovider.CloneableURL); ok {
url := cloner.GetCloneURL("scm", gitprovider.TransportTypeHTTPS)
Expect(url).ToNot(BeEmpty())
fmt.Println("Clone URL: ", url)

sshURL := cloner.GetCloneURL("scm", gitprovider.TransportTypeSSH)
Expect(url).ToNot(BeEmpty())
fmt.Println("Clone ssh URL: ", sshURL)
}

validateUserRepo(repo, getRepoRef.Repository())

getRepo, err := client.UserRepositories().Get(ctx, repoRef)
Expand Down
45 changes: 43 additions & 2 deletions stash/resource_repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,13 @@ package stash

import (
"context"
"fmt"

"github.com/fluxcd/go-git-providers/gitprovider"
)

const defaultClonePrefix = "scm"

func newUserRepository(ctx *clientContext, apiObj *Repository, ref gitprovider.RepositoryRef) *userRepository {
return &userRepository{
c: &UserRepositoriesClient{
Expand Down Expand Up @@ -100,7 +103,7 @@ func (r *userRepository) DeployKeys() gitprovider.DeployKeyClient {
func (r *userRepository) Update(ctx context.Context) error {
// update by calling client
ref := r.ref.(gitprovider.UserRepositoryRef)
apiObj, err := update(ctx, r.c.client, addTilde(ref.UserLogin), ref.GetSlug(), &r.repository, "")
apiObj, err := update(ctx, r.c.client, addTilde(ref.UserLogin), ref.Slug(), &r.repository, "")
if err != nil {
// Log the error and return it
r.c.log.V(1).Error(err, "Error updating repository",
Expand Down Expand Up @@ -141,7 +144,26 @@ func (r *userRepository) Reconcile(ctx context.Context) (bool, error) {
// ErrNotFound is returned if the resource doesn't exist anymore.
func (r *userRepository) Delete(ctx context.Context) error {
ref := r.ref.(gitprovider.UserRepositoryRef)
return delete(ctx, r.c.client, addTilde(ref.UserLogin), ref.GetSlug())
return delete(ctx, r.c.client, addTilde(ref.UserLogin), ref.Slug())
}

// GetCloneURL returns a formatted string that can be used for cloning
// from a remote Git provider.
func (r *userRepository) GetCloneURL(prefix string, transport gitprovider.TransportType) string {
if prefix == "" {
prefix = defaultClonePrefix
}
ref := r.ref.(gitprovider.UserRepositoryRef)
switch transport {
case gitprovider.TransportTypeHTTPS:
return gitprovider.ParseTypeHTTPS(fmt.Sprintf("%s/%s/%s/%s", gitprovider.GetDomainURL(ref.GetDomain()), prefix, addTilde(ref.UserLogin), ref.Slug()))
case gitprovider.TransportTypeGit:
return gitprovider.ParseTypeGit(ref.GetDomain(), addTilde(ref.UserLogin), ref.Slug())
case gitprovider.TransportTypeSSH:
return gitprovider.ParseTypeSSH(ref.GetDomain(), addTilde(ref.UserLogin), ref.Slug())
default:
return ""
}
}

func newOrgRepository(ctx *clientContext, apiObj *Repository, ref gitprovider.RepositoryRef) *orgRepository {
Expand Down Expand Up @@ -252,3 +274,22 @@ func repositoryInfoToAPIObj(repo *gitprovider.RepositoryInfo, apiObj *Repository
apiObj.DefaultBranch = *gitprovider.StringVar(*repo.DefaultBranch)
}
}

// GetCloneURL returns a formatted string that can be used for cloning
// from a remote Git provider.
func (r *orgRepository) GetCloneURL(prefix string, transport gitprovider.TransportType) string {
if prefix == "" {
prefix = defaultClonePrefix
}
ref := r.ref.(gitprovider.OrgRepositoryRef)
switch transport {
case gitprovider.TransportTypeHTTPS:
return gitprovider.ParseTypeHTTPS(fmt.Sprintf("%s/%s/%s/%s", gitprovider.GetDomainURL(ref.GetDomain()), prefix, ref.Key(), ref.Slug()))
case gitprovider.TransportTypeGit:
return gitprovider.ParseTypeGit(ref.GetDomain(), ref.Key(), ref.Slug())
case gitprovider.TransportTypeSSH:
return gitprovider.ParseTypeSSH(ref.GetDomain(), ref.Key(), ref.Slug())
default:
return ""
}
}

0 comments on commit 18218b6

Please sign in to comment.