diff --git a/pkg/git/repository.go b/pkg/git/repository.go index 536376a0..b5a4c7ea 100644 --- a/pkg/git/repository.go +++ b/pkg/git/repository.go @@ -66,7 +66,6 @@ type ( url string revision string path string - provider Provider } PushOptions struct { @@ -78,9 +77,10 @@ type ( repo struct { gogit.Repository - auth Auth - progress io.Writer - provider Provider + auth Auth + progress io.Writer + providerType string + repoURL string } ) @@ -106,6 +106,29 @@ var ( return r.checkoutBranch(branch, upsertBranch) } + getProvider = func(providerType, repoURL string, auth *Auth) (Provider, error) { + if providerType == "" { + u, err := url.Parse(repoURL) + if err != nil { + return nil, err + } + + if strings.Contains(u.Hostname(), AzureHostName) { + providerType = Azure + } else { + providerType = strings.TrimSuffix(u.Hostname(), ".com") + } + + log.G().Warnf("--provider not specified, assuming provider from url: %s", providerType) + } + + return newProvider(&ProviderOptions{ + Type: providerType, + Auth: auth, + RepoURL: repoURL, + }) + } + ggClone = func(ctx context.Context, s storage.Storer, worktree billy.Filesystem, o *gg.CloneOptions) (gogit.Repository, error) { return gg.CloneContext(ctx, s, worktree, o) } @@ -187,7 +210,6 @@ func (o *CloneOptions) GetRepo(ctx context.Context) (Repository, fs.FS, error) { return nil, nil, ErrNoParse } - o.provider, err = getProvider(o.Provider, o.url, &o.Auth) if err != nil { log.G(ctx).Warn("failed initializing git provider: %s", err.Error()) } @@ -327,10 +349,13 @@ func (r *repo) getAuthor(ctx context.Context) (*object.Signature, error) { username := cfg.User.Name email := cfg.User.Email - if (username == "" || email == "") && r.provider != nil { - username, email, err = r.provider.GetAuthor(ctx) - if err != nil { - return nil, fmt.Errorf("failed to get author information: %w", err) + if username == "" || email == "" { + provider, _ := getProvider(r.providerType, r.repoURL, &r.auth) + if provider != nil { + username, email, err = provider.GetAuthor(ctx) + if err != nil { + return nil, fmt.Errorf("failed to get author information: %w", err) + } } } @@ -411,10 +436,11 @@ var clone = func(ctx context.Context, opts *CloneOptions) (*repo, error) { } repo := &repo{ - Repository: r, - auth: opts.Auth, - progress: progress, - provider: opts.provider, + Repository: r, + auth: opts.Auth, + progress: progress, + providerType: opts.Provider, + repoURL: opts.Repo, } if opts.revision != "" { @@ -440,35 +466,13 @@ var clone = func(ctx context.Context, opts *CloneOptions) (*repo, error) { } var createRepo = func(ctx context.Context, opts *CloneOptions) (string, error) { - if opts.provider == nil { + provider, _ := getProvider(opts.Provider, opts.Repo, &opts.Auth) + if provider == nil { return "", errors.New("failed creating repository - no git provider supplied") } _, orgRepo, _, _, _, _, _ := util.ParseGitUrl(opts.Repo) - return opts.provider.CreateRepository(ctx, orgRepo) -} - -func getProvider(providerType, repoUrl string, auth *Auth) (Provider, error) { - if providerType == "" { - u, err := url.Parse(repoUrl) - if err != nil { - return nil, err - } - - if strings.Contains(u.Hostname(), AzureHostName) { - providerType = Azure - } else { - providerType = strings.TrimSuffix(u.Hostname(), ".com") - } - - log.G().Warnf("--provider not specified, assuming provider from url: %s", providerType) - } - - return newProvider(&ProviderOptions{ - Type: providerType, - Auth: auth, - RepoURL: repoUrl, - }) + return provider.CreateRepository(ctx, orgRepo) } func getDefaultRepoOptions(orgRepo string) (*CreateRepoOptions, error) { @@ -498,10 +502,11 @@ var initRepo = func(ctx context.Context, opts *CloneOptions) (*repo, error) { } r := &repo{ - Repository: ggr, - auth: opts.Auth, - progress: progress, - provider: opts.provider, + Repository: ggr, + progress: progress, + providerType: opts.Provider, + repoURL: opts.Repo, + auth: opts.Auth, } if err = r.addRemote("origin", opts.url); err != nil { return nil, err @@ -528,7 +533,12 @@ var initRepo = func(ctx context.Context, opts *CloneOptions) (*repo, error) { func (r *repo) getDefaultBranch(ctx context.Context, repo string) (string, error) { _, orgRepo, _, _, _, _, _ := util.ParseGitUrl(repo) - defaultBranch, err := r.provider.GetDefaultBranch(ctx, orgRepo) + provider, err := getProvider(r.providerType, r.repoURL, &r.auth) + if err != nil { + return "", err + } + + defaultBranch, err := provider.GetDefaultBranch(ctx, orgRepo) if err != nil { return "", fmt.Errorf("failed to get default branch from provider. Error: %w", err) } diff --git a/pkg/git/repository_test.go b/pkg/git/repository_test.go index 2378e107..58fa5b77 100644 --- a/pkg/git/repository_test.go +++ b/pkg/git/repository_test.go @@ -310,7 +310,7 @@ func Test_initRepo(t *testing.T) { }, }, "Should fail when addRemote fails": { - repo: "https://github.com/owner/name", + repo: "https://github.com/owner/name", wantErr: "some error", beforeFn: func(r *mocks.MockRepository, _ *mocks.MockWorktree, _ *mockProvider) { r.EXPECT().CreateRemote(&config.RemoteConfig{ @@ -322,7 +322,7 @@ func Test_initRepo(t *testing.T) { }, }, "Should fail when initBranch fails": { - repo: "https://github.com/owner/name", + repo: "https://github.com/owner/name", wantErr: "failed to commit while trying to initialize the branch. Error: some error", beforeFn: func(r *mocks.MockRepository, wt *mocks.MockWorktree, p *mockProvider) { r.EXPECT().CreateRemote(&config.RemoteConfig{ @@ -343,9 +343,14 @@ func Test_initRepo(t *testing.T) { } orgInitRepo := ggInitRepo - defer func() { ggInitRepo = orgInitRepo }() + orgGetProvider := getProvider orgWorktree := worktree - defer func() { worktree = orgWorktree }() + defer func() { + ggInitRepo = orgInitRepo + worktree = orgWorktree + getProvider = orgGetProvider + }() + for tname, tt := range tests { t.Run(tname, func(t *testing.T) { ctrl := gomock.NewController(t) @@ -358,10 +363,10 @@ func Test_initRepo(t *testing.T) { ggInitRepo = func(s storage.Storer, worktree billy.Filesystem) (gogit.Repository, error) { return mockRepo, nil } worktree = func(r gogit.Repository) (gogit.Worktree, error) { return mockWt, nil } + getProvider = func(providerType, repoURL string, auth *Auth) (Provider, error) { return mockProvider, nil } opts := &CloneOptions{ - Repo: tt.repo, - provider: mockProvider, + Repo: tt.repo, } opts.Parse() got, err := initRepo(context.Background(), opts) @@ -538,7 +543,8 @@ func Test_clone(t *testing.T) { }, } - origCheckoutRef, origClone := checkoutRef, ggClone + origCheckoutRef := checkoutRef + origClone := ggClone defer func() { checkoutRef = origCheckoutRef ggClone = origClone @@ -704,6 +710,7 @@ func TestGetRepo(t *testing.T) { }, }, } + origClone, origCreateRepo, origInitRepo := clone, createRepo, initRepo defer func() { clone = origClone @@ -839,8 +846,12 @@ func Test_repo_Persist(t *testing.T) { }, } - worktreeOrg := worktree - defer func() { worktree = worktreeOrg }() + orgGetProvider := getProvider + orgWorktree := worktree + defer func() { + getProvider = orgGetProvider + worktree = orgWorktree + }() for tname, tt := range tests { t.Run(tname, func(t *testing.T) { @@ -850,10 +861,12 @@ func Test_repo_Persist(t *testing.T) { mockProvider := &mockProvider{} mockRepo.EXPECT().ConfigScoped(gomock.Any()).Return(gitConfig, nil).AnyTimes() + getProvider = func(providerType, repoURL string, auth *Auth) (Provider, error) { return mockProvider, nil } + worktree = func(r gogit.Repository) (gogit.Worktree, error) { return mockWt, nil } - r := &repo{Repository: mockRepo, progress: os.Stderr, provider: mockProvider} - worktree = func(r gogit.Repository) (gogit.Worktree, error) { - return mockWt, nil + r := &repo{ + Repository: mockRepo, + progress: os.Stderr, } tt.beforeFn(mockRepo, mockWt) @@ -1309,35 +1322,25 @@ func Test_createRepo(t *testing.T) { Username: "username", Password: "password", }, - provider: &mockProvider{func(orgRepo string) (string, error) { - assert.Equal(t, "owner/name", orgRepo) - return "https://github.com/owner/name.git", nil - }, nil, nil}, }, want: "https://github.com/owner/name.git", }, "Should infer correct provider type from repo url": { opts: &CloneOptions{ Repo: "https://github.com/owner/name.git", - provider: &mockProvider{func(orgRepo string) (string, error) { - return "https://github.com/owner/name.git", nil - }, nil, nil}, }, want: "https://github.com/owner/name.git", }, - "Should succesfully parse owner and name for long orgRepos": { - opts: &CloneOptions{ - Repo: "https://github.com/foo22/bar/fizz.git", - provider: &mockProvider{func(orgRepo string) (string, error) { - assert.Equal(t, "foo22/bar/fizz", orgRepo) - return "https://github.com/foo22/bar/fizz.git", nil - }, nil, nil}, - }, - want: "https://github.com/foo22/bar/fizz.git", - }, } + + orgGetProvider := getProvider + defer func() { getProvider = orgGetProvider }() for name, tt := range tests { t.Run(name, func(t *testing.T) { + mockProvider := &mockProvider{func(orgRepo string) (string, error) { + return "https://github.com/owner/name.git", nil + }, nil, nil} + getProvider = func(providerType, repoURL string, auth *Auth) (Provider, error) { return mockProvider, nil } got, err := createRepo(context.Background(), tt.opts) if err != nil || tt.wantErr != "" { assert.EqualError(t, err, tt.wantErr) @@ -1518,19 +1521,22 @@ func Test_repo_commit(t *testing.T) { }, } + orgGetProvider := getProvider orgWorktree := worktree - defer func() { worktree = orgWorktree }() + defer func() { + getProvider = orgGetProvider + worktree = orgWorktree + }() for tname, tt := range tests { t.Run(tname, func(t *testing.T) { ctrl := gomock.NewController(t) mockRepo := mocks.NewMockRepository(ctrl) mockWt := mocks.NewMockWorktree(ctrl) mockProvider := &mockProvider{} + getProvider = func(providerType, repoURL string, auth *Auth) (Provider, error) { return mockProvider, nil } + worktree = func(r gogit.Repository) (gogit.Worktree, error) { return mockWt, nil } - r := &repo{Repository: mockRepo, provider: mockProvider} - worktree = func(r gogit.Repository) (gogit.Worktree, error) { - return mockWt, nil - } + r := &repo{Repository: mockRepo} tt.beforeFn(mockRepo, mockWt, mockProvider)