diff --git a/server/repository/repository_test.go b/server/repository/repository_test.go index f4d80c3c434d8..91c2e016ab3d4 100644 --- a/server/repository/repository_test.go +++ b/server/repository/repository_test.go @@ -21,6 +21,7 @@ import ( "github.com/argoproj/argo-cd/v2/common" "github.com/argoproj/argo-cd/v2/pkg/apiclient/repository" + repositorypkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/repository" appsv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" fakeapps "github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned/fake" appinformer "github.com/argoproj/argo-cd/v2/pkg/client/informers/externalversions" @@ -1119,3 +1120,35 @@ func TestGetRepository(t *testing.T) { }) } } + +func TestDeleteRepository(t *testing.T) { + repositories := map[string]string{ + "valid": "https://bitbucket.org/workspace/repo.git", + // Check a wrongly formatter repo as well, see https://github.com/argoproj/argo-cd/issues/20921 + "invalid": "git clone https://bitbucket.org/workspace/repo.git", + } + + kubeclientset := fake.NewSimpleClientset(&argocdCM, &argocdSecret) + settingsMgr := settings.NewSettingsManager(context.Background(), kubeclientset, testNamespace) + + for name, repo := range repositories { + t.Run(name, func(t *testing.T) { + repoServerClient := mocks.RepoServerServiceClient{} + repoServerClient.On("TestRepository", mock.Anything, mock.Anything).Return(&apiclient.TestRepositoryResponse{}, nil) + + repoServerClientset := mocks.Clientset{RepoServerServiceClient: &repoServerClient} + enforcer := newEnforcer(kubeclientset) + + db := &dbmocks.ArgoDB{} + db.On("DeleteRepository", context.TODO(), repo, "default").Return(nil) + db.On("ListRepositories", context.TODO()).Return([]*appsv1.Repository{{Repo: repo, Project: "default"}}, nil) + db.On("GetRepository", context.TODO(), repo, "default").Return(&appsv1.Repository{Repo: repo, Project: "default"}, nil) + appLister, projLister := newAppAndProjLister(defaultProj) + + s := NewServer(&repoServerClientset, db, enforcer, newFixtures().Cache, appLister, projLister, testNamespace, settingsMgr) + resp, err := s.DeleteRepository(context.TODO(), &repository.RepoQuery{Repo: repo, AppProject: "default"}) + require.NoError(t, err) + assert.Equal(t, repositorypkg.RepoResponse{}, *resp) + }) + } +} diff --git a/util/git/git.go b/util/git/git.go index 3a087aeb00096..6ef47fecfb172 100644 --- a/util/git/git.go +++ b/util/git/git.go @@ -35,8 +35,8 @@ func IsTruncatedCommitSHA(sha string) bool { // SameURL returns whether or not the two repository URLs are equivalent in location func SameURL(leftRepo, rightRepo string) bool { - normalLeft := NormalizeGitURL(leftRepo) - normalRight := NormalizeGitURL(rightRepo) + normalLeft := NormalizeGitURLAllowInvalid(leftRepo) + normalRight := NormalizeGitURLAllowInvalid(rightRepo) return normalLeft != "" && normalRight != "" && normalLeft == normalRight } @@ -45,6 +45,16 @@ func SameURL(leftRepo, rightRepo string) bool { // Prefer using SameURL() over this function when possible. This algorithm may change over time // and should not be considered stable from release to release func NormalizeGitURL(repo string) string { + return normalizeGitURL(repo, false) +} + +// Similar to NormalizeGitURL, except returning a not fully normalized string when the url is invalid. +// Needed to allow a deletion of repos with invalid urls. See https://github.com/argoproj/argo-cd/issues/20921. +func NormalizeGitURLAllowInvalid(repo string) string { + return normalizeGitURL(repo, true) +} + +func normalizeGitURL(repo string, allowInvalid bool) string { repo = strings.ToLower(strings.TrimSpace(repo)) if yes, _ := IsSSHURL(repo); yes { if !strings.HasPrefix(repo, "ssh://") { @@ -57,7 +67,11 @@ func NormalizeGitURL(repo string) string { repo = strings.TrimSuffix(repo, ".git") repoURL, err := url.Parse(repo) if err != nil { - return "" + if allowInvalid { + return repo + } else { + return "" + } } normalized := repoURL.String() return strings.TrimPrefix(normalized, "ssh://")