feat(appset): filtering repos by archived status #20736 (#21505)

Signed-off-by: Prune <prune@lecentre.net>
Signed-off-by: Alexandre Gaudreault <alexandre_gaudreault@intuit.com>
Co-authored-by: Alexandre Gaudreault <alexandre_gaudreault@intuit.com>
This commit is contained in:
Prune Sebastien THOMAS 2026-04-17 13:32:18 -04:00 committed by GitHub
parent 37e10dba75
commit 29fd8db39a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 2628 additions and 948 deletions

View file

@ -164,7 +164,7 @@ func (g *SCMProviderGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha
if err != nil {
return nil, fmt.Errorf("error fetching Gitlab token: %w", err)
}
provider, err = scm_provider.NewGitlabProvider(providerConfig.Group, token, providerConfig.API, providerConfig.AllBranches, providerConfig.IncludeSubgroups, providerConfig.WillIncludeSharedProjects(), providerConfig.Insecure, g.scmRootCAPath, providerConfig.Topic, caCerts)
provider, err = scm_provider.NewGitlabProvider(providerConfig.Group, token, providerConfig.API, providerConfig.AllBranches, providerConfig.IncludeSubgroups, providerConfig.WillIncludeSharedProjects(), providerConfig.IncludeArchivedRepos, providerConfig.Insecure, g.scmRootCAPath, providerConfig.Topic, caCerts)
if err != nil {
return nil, fmt.Errorf("error initializing Gitlab service: %w", err)
}
@ -173,7 +173,7 @@ func (g *SCMProviderGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha
if err != nil {
return nil, fmt.Errorf("error fetching Gitea token: %w", err)
}
provider, err = scm_provider.NewGiteaProvider(providerConfig.Gitea.Owner, token, providerConfig.Gitea.API, providerConfig.Gitea.AllBranches, providerConfig.Gitea.Insecure)
provider, err = scm_provider.NewGiteaProvider(providerConfig.Gitea.Owner, token, providerConfig.Gitea.API, providerConfig.Gitea.AllBranches, providerConfig.Gitea.Insecure, providerConfig.Gitea.ExcludeArchivedRepos)
if err != nil {
return nil, fmt.Errorf("error initializing Gitea service: %w", err)
}
@ -289,9 +289,9 @@ func (g *SCMProviderGenerator) githubProvider(ctx context.Context, github *argop
}
if g.enableGitHubAPIMetrics {
return scm_provider.NewGithubAppProviderFor(ctx, *auth, github.Organization, github.API, github.AllBranches, httpClient)
return scm_provider.NewGithubAppProviderFor(ctx, *auth, github.Organization, github.API, github.AllBranches, github.ExcludeArchivedRepos, httpClient)
}
return scm_provider.NewGithubAppProviderFor(ctx, *auth, github.Organization, github.API, github.AllBranches)
return scm_provider.NewGithubAppProviderFor(ctx, *auth, github.Organization, github.API, github.AllBranches, github.ExcludeArchivedRepos)
}
token, err := utils.GetSecretRef(ctx, g.client, github.TokenRef, applicationSetInfo.Namespace, g.tokenRefStrictMode)
@ -300,7 +300,7 @@ func (g *SCMProviderGenerator) githubProvider(ctx context.Context, github *argop
}
if g.enableGitHubAPIMetrics {
return scm_provider.NewGithubProvider(github.Organization, token, github.API, github.AllBranches, httpClient)
return scm_provider.NewGithubProvider(github.Organization, token, github.API, github.AllBranches, github.ExcludeArchivedRepos, httpClient)
}
return scm_provider.NewGithubProvider(github.Organization, token, github.API, github.AllBranches)
return scm_provider.NewGithubProvider(github.Organization, token, github.API, github.AllBranches, github.ExcludeArchivedRepos)
}

View file

@ -15,11 +15,12 @@ type GiteaProvider struct {
client *gitea.Client
owner string
allBranches bool
excludeArchivedRepos bool
}
var _ SCMProviderService = &GiteaProvider{}
func NewGiteaProvider(owner, token, url string, allBranches, insecure bool) (*GiteaProvider, error) {
func NewGiteaProvider(owner, token, url string, allBranches, insecure, excludeArchivedRepos bool) (*GiteaProvider, error) {
if token == "" {
token = os.Getenv("GITEA_TOKEN")
}
@ -43,6 +44,7 @@ func NewGiteaProvider(owner, token, url string, allBranches, insecure bool) (*Gi
client: client,
owner: owner,
allBranches: allBranches,
excludeArchivedRepos: excludeArchivedRepos,
}, nil
}
@ -114,6 +116,11 @@ func (g *GiteaProvider) ListRepos(_ context.Context, cloneProtocol string) ([]*R
for _, label := range giteaLabels {
labels = append(labels, label.Name)
}
if g.excludeArchivedRepos && repo.Archived {
continue
}
repos = append(repos, &Repository{
Organization: g.owner,
Repository: repo.Name,

View file

@ -100,17 +100,96 @@ func giteaMockHandler(t *testing.T) func(http.ResponseWriter, *http.Request) {
"mirror_interval": "",
"mirror_updated": "0001-01-01T00:00:00Z",
"repo_transfer": null
}]`)
},
{
"id": 21619,
"owner": {
"id": 31480,
"login": "test-argocd",
"full_name": "",
"email": "",
"avatar_url": "https://gitea.com/avatars/22d1b1d3f61abf95951c4a958731d848",
"language": "",
"is_admin": false,
"last_login": "0001-01-01T00:00:00Z",
"created": "2022-04-06T02:28:06+08:00",
"restricted": false,
"active": false,
"prohibit_login": false,
"location": "",
"website": "",
"description": "",
"visibility": "public",
"followers_count": 0,
"following_count": 0,
"starred_repos_count": 0,
"username": "test-argocd"
},
"name": "another-repo",
"full_name": "test-argocd/another-repo",
"description": "",
"empty": false,
"private": false,
"fork": false,
"template": false,
"parent": null,
"mirror": false,
"size": 28,
"language": "",
"languages_url": "https://gitea.com/api/v1/repos/test-argocd/another-repo/languages",
"html_url": "https://gitea.com/test-argocd/another-repo",
"ssh_url": "git@gitea.com:test-argocd/another-repo.git",
"clone_url": "https://gitea.com/test-argocd/another-repo.git",
"original_url": "",
"website": "",
"stars_count": 0,
"forks_count": 0,
"watchers_count": 1,
"open_issues_count": 0,
"open_pr_counter": 1,
"release_counter": 0,
"default_branch": "main",
"archived": true,
"created_at": "2022-04-06T02:32:09+08:00",
"updated_at": "2022-04-06T02:33:12+08:00",
"permissions": {
"admin": false,
"push": false,
"pull": true
},
"has_issues": true,
"internal_tracker": {
"enable_time_tracker": true,
"allow_only_contributors_to_track_time": true,
"enable_issue_dependencies": true
},
"has_wiki": true,
"has_pull_requests": true,
"has_projects": true,
"ignore_whitespace_conflicts": false,
"allow_merge_commits": true,
"allow_rebase": true,
"allow_rebase_explicit": true,
"allow_squash_merge": true,
"default_merge_style": "merge",
"avatar_url": "",
"internal": false,
"mirror_interval": "",
"mirror_updated": "0001-01-01T00:00:00Z",
"repo_transfer": null
}
]`)
if err != nil {
t.Fail()
}
case "/api/v1/repos/test-argocd/pr-test/branches/main":
case "/api/v1/repos/test-argocd/another-repo/branches/main":
_, err := io.WriteString(w, `{
"name": "main",
"commit": {
"id": "72687815ccba81ef014a96201cc2e846a68789d8",
"id": "1fa33898cf84e89836863e3a5e76eee45777b4b0",
"message": "initial commit\n",
"url": "https://gitea.com/test-argocd/pr-test/commit/72687815ccba81ef014a96201cc2e846a68789d8",
"url": "https://gitea.com/test-argocd/pr-test/commit/1fa33898cf84e89836863e3a5e76eee45777b4b0",
"author": {
"name": "Dan Molik",
"email": "dan@danmolik.com",
@ -144,13 +223,209 @@ func giteaMockHandler(t *testing.T) func(http.ResponseWriter, *http.Request) {
if err != nil {
t.Fail()
}
case "/api/v1/repos/test-argocd/pr-test/branches/test":
_, err := io.WriteString(w, `{
"name": "test",
"commit": {
"id": "28c3b329933f6fefd9b55225535123bbffec5a46",
"message": "initial commit\n",
"url": "https://gitea.com/test-argocd/pr-test/commit/28c3b329933f6fefd9b55225535123bbffec5a46",
"author": {
"name": "Dan Molik",
"email": "dan@danmolik.com",
"username": "graytshirt"
},
"committer": {
"name": "Dan Molik",
"email": "dan@danmolik.com",
"username": "graytshirt"
},
"verification": {
"verified": false,
"reason": "gpg.error.no_gpg_keys_found",
"signature": "-----BEGIN PGP SIGNATURE-----\n\niQEzBAABCAAdFiEEXYAkwEBRpXzXgHFWlgCr7m50zBMFAmJMiqUACgkQlgCr7m50\nzBPSmQgAiVVEIxC42tuks4iGFNURrtYvypZAEIc+hJgt2kBpmdCrAphYPeAj+Wtr\n9KT7dDscCZIba2wx39HEXO2S7wNCXESvAzrA8rdfbXjR4L2miZ1urfBkEoqK5i/F\noblWGuAyjurX4KPa2ARROd0H4AXxt6gNAXaFPgZO+xXCyNKZfad/lkEP1AiPRknD\nvTTMbEkIzFHK9iVwZ9DORGpfF1wnLzxWmMfhYatZnBgFNnoeJNtFhCJo05rHBgqc\nqVZWXt1iF7nysBoXSzyx1ZAsmBr/Qerkuj0nonh0aPVa6NKJsdmeJyPX4zXXoi6E\ne/jpxX2UQJkpFezg3IjUpvE5FvIiYg==\n=3Af2\n-----END PGP SIGNATURE-----\n",
"signer": null,
"payload": "tree 64d47c7fc6e31dcf00654223ec4ab749dd0a464e\nauthor Dan Molik \u003cdan@danmolik.com\u003e 1649183391 -0400\ncommitter Dan Molik \u003cdan@danmolik.com\u003e 1649183391 -0400\n\ninitial commit\n"
},
"timestamp": "2022-04-05T14:29:51-04:00",
"added": null,
"removed": null,
"modified": null
},
"protected": false,
"required_approvals": 0,
"enable_status_check": false,
"status_check_contexts": [],
"user_can_push": false,
"user_can_merge": false,
"effective_branch_protection_name": ""
}`)
if err != nil {
t.Fail()
}
case "/api/v1/repos/test-argocd/another-repo/branches/test":
_, err := io.WriteString(w, `{
"name": "test",
"commit": {
"id": "32cdcf613b259a9439ceabd4d1745d43f163ea70",
"message": "initial commit\n",
"url": "https://gitea.com/test-argocd/another-repo/commit/32cdcf613b259a9439ceabd4d1745d43f163ea70",
"author": {
"name": "Dan Molik",
"email": "dan@danmolik.com",
"username": "graytshirt"
},
"committer": {
"name": "Dan Molik",
"email": "dan@danmolik.com",
"username": "graytshirt"
},
"verification": {
"verified": false,
"reason": "gpg.error.no_gpg_keys_found",
"signature": "-----BEGIN PGP SIGNATURE-----\n\niQEzBAABCAAdFiEEXYAkwEBRpXzXgHFWlgCr7m50zBMFAmJMiqUACgkQlgCr7m50\nzBPSmQgAiVVEIxC42tuks4iGFNURrtYvypZAEIc+hJgt2kBpmdCrAphYPeAj+Wtr\n9KT7dDscCZIba2wx39HEXO2S7wNCXESvAzrA8rdfbXjR4L2miZ1urfBkEoqK5i/F\noblWGuAyjurX4KPa2ARROd0H4AXxt6gNAXaFPgZO+xXCyNKZfad/lkEP1AiPRknD\nvTTMbEkIzFHK9iVwZ9DORGpfF1wnLzxWmMfhYatZnBgFNnoeJNtFhCJo05rHBgqc\nqVZWXt1iF7nysBoXSzyx1ZAsmBr/Qerkuj0nonh0aPVa6NKJsdmeJyPX4zXXoi6E\ne/jpxX2UQJkpFezg3IjUpvE5FvIiYg==\n=3Af2\n-----END PGP SIGNATURE-----\n",
"signer": null,
"payload": "tree 64d47c7fc6e31dcf00654223ec4ab749dd0a464e\nauthor Dan Molik \u003cdan@danmolik.com\u003e 1649183391 -0400\ncommitter Dan Molik \u003cdan@danmolik.com\u003e 1649183391 -0400\n\ninitial commit\n"
},
"timestamp": "2022-04-05T14:29:51-04:00",
"added": null,
"removed": null,
"modified": null
},
"protected": false,
"required_approvals": 0,
"enable_status_check": false,
"status_check_contexts": [],
"user_can_push": false,
"user_can_merge": false,
"effective_branch_protection_name": ""
}`)
if err != nil {
t.Fail()
}
case "/api/v1/repos/test-argocd/pr-test/branches/main":
_, err := io.WriteString(w, `{
"name": "main",
"commit": {
"id": "75f6fceff80f6aaf12b65a2cf6a89190b866625b",
"message": "initial commit\n",
"url": "https://gitea.com/test-argocd/pr-test/commit/75f6fceff80f6aaf12b65a2cf6a89190b866625b",
"author": {
"name": "Dan Molik",
"email": "dan@danmolik.com",
"username": "graytshirt"
},
"committer": {
"name": "Dan Molik",
"email": "dan@danmolik.com",
"username": "graytshirt"
},
"verification": {
"verified": false,
"reason": "gpg.error.no_gpg_keys_found",
"signature": "-----BEGIN PGP SIGNATURE-----\n\niQEzBAABCAAdFiEEXYAkwEBRpXzXgHFWlgCr7m50zBMFAmJMiqUACgkQlgCr7m50\nzBPSmQgAiVVEIxC42tuks4iGFNURrtYvypZAEIc+hJgt2kBpmdCrAphYPeAj+Wtr\n9KT7dDscCZIba2wx39HEXO2S7wNCXESvAzrA8rdfbXjR4L2miZ1urfBkEoqK5i/F\noblWGuAyjurX4KPa2ARROd0H4AXxt6gNAXaFPgZO+xXCyNKZfad/lkEP1AiPRknD\nvTTMbEkIzFHK9iVwZ9DORGpfF1wnLzxWmMfhYatZnBgFNnoeJNtFhCJo05rHBgqc\nqVZWXt1iF7nysBoXSzyx1ZAsmBr/Qerkuj0nonh0aPVa6NKJsdmeJyPX4zXXoi6E\ne/jpxX2UQJkpFezg3IjUpvE5FvIiYg==\n=3Af2\n-----END PGP SIGNATURE-----\n",
"signer": null,
"payload": "tree 64d47c7fc6e31dcf00654223ec4ab749dd0a464e\nauthor Dan Molik \u003cdan@danmolik.com\u003e 1649183391 -0400\ncommitter Dan Molik \u003cdan@danmolik.com\u003e 1649183391 -0400\n\ninitial commit\n"
},
"timestamp": "2022-04-05T14:29:51-04:00",
"added": null,
"removed": null,
"modified": null
},
"protected": false,
"required_approvals": 0,
"enable_status_check": false,
"status_check_contexts": [],
"user_can_push": false,
"user_can_merge": false,
"effective_branch_protection_name": ""
}`)
if err != nil {
t.Fail()
}
case "/api/v1/repos/test-argocd/another-repo/branches?limit=0&page=1":
_, err := io.WriteString(w, `[{
"name": "main",
"commit": {
"id": "1fa33898cf84e89836863e3a5e76eee45777b4b0",
"message": "initial commit\n",
"url": "https://gitea.com/test-argocd/pr-test/commit/1fa33898cf84e89836863e3a5e76eee45777b4b0",
"author": {
"name": "Dan Molik",
"email": "dan@danmolik.com",
"username": "graytshirt"
},
"committer": {
"name": "Dan Molik",
"email": "dan@danmolik.com",
"username": "graytshirt"
},
"verification": {
"verified": false,
"reason": "gpg.error.no_gpg_keys_found",
"signature": "-----BEGIN PGP SIGNATURE-----\n\niQEzBAABCAAdFiEEXYAkwEBRpXzXgHFWlgCr7m50zBMFAmJMiqUACgkQlgCr7m50\nzBPSmQgAiVVEIxC42tuks4iGFNURrtYvypZAEIc+hJgt2kBpmdCrAphYPeAj+Wtr\n9KT7dDscCZIba2wx39HEXO2S7wNCXESvAzrA8rdfbXjR4L2miZ1urfBkEoqK5i/F\noblWGuAyjurX4KPa2ARROd0H4AXxt6gNAXaFPgZO+xXCyNKZfad/lkEP1AiPRknD\nvTTMbEkIzFHK9iVwZ9DORGpfF1wnLzxWmMfhYatZnBgFNnoeJNtFhCJo05rHBgqc\nqVZWXt1iF7nysBoXSzyx1ZAsmBr/Qerkuj0nonh0aPVa6NKJsdmeJyPX4zXXoi6E\ne/jpxX2UQJkpFezg3IjUpvE5FvIiYg==\n=3Af2\n-----END PGP SIGNATURE-----\n",
"signer": null,
"payload": "tree 64d47c7fc6e31dcf00654223ec4ab749dd0a464e\nauthor Dan Molik \u003cdan@danmolik.com\u003e 1649183391 -0400\ncommitter Dan Molik \u003cdan@danmolik.com\u003e 1649183391 -0400\n\ninitial commit\n"
},
"timestamp": "2022-04-05T14:29:51-04:00",
"added": null,
"removed": null,
"modified": null
},
"protected": false,
"required_approvals": 0,
"enable_status_check": false,
"status_check_contexts": [],
"user_can_push": false,
"user_can_merge": false,
"effective_branch_protection_name": ""
},
{
"name": "test",
"commit": {
"id": "32cdcf613b259a9439ceabd4d1745d43f163ea70",
"message": "add an empty file\n",
"url": "https://gitea.com/test-argocd/pr-test/commit/32cdcf613b259a9439ceabd4d1745d43f163ea70",
"author": {
"name": "Dan Molik",
"email": "dan@danmolik.com",
"username": "graytshirt"
},
"committer": {
"name": "Dan Molik",
"email": "dan@danmolik.com",
"username": "graytshirt"
},
"verification": {
"verified": false,
"reason": "gpg.error.no_gpg_keys_found",
"signature": "-----BEGIN PGP SIGNATURE-----\n\niQEzBAABCAAdFiEEXYAkwEBRpXzXgHFWlgCr7m50zBMFAmJMiugACgkQlgCr7m50\nzBN+7wgAkCHD3KfX3Ffkqv2qPwqgHNYM1bA6Hmffzhv0YeD9jWCI3tp0JulP4iFZ\ncQ7jqx9xP9tCQMSFCaijLRHaE6Js1xrVtf0OKRkbpdlvkyrIM3sQhqyQgAsISrDG\nLzSqeoQQjglzeWESYh2Tjn1CgqQNKjI6LLepSwvF1pIeV4pJpJobaEbIfTgStdzM\nWEk8o0I+EZaYqK0C0vU9N0LK/LR/jnlaHsb4OUjvk+S7lRjZwBkrsg7P/QsqtCVd\nw5nkxDiCx1J58zKMnQ7ZinJEK9A5WYdnMYc6aBn7ARgZrblXPPBkkKUhEv3ZSPeW\nKv9i4GQy838xkVSTFkHNj1+a5o6zEA==\n=JiFw\n-----END PGP SIGNATURE-----\n",
"signer": null,
"payload": "tree cdddf3e1d6a8a7e6899a044d0e1bc73bf798e2f5\nparent 72687815ccba81ef014a96201cc2e846a68789d8\nauthor Dan Molik \u003cdan@danmolik.com\u003e 1649183458 -0400\ncommitter Dan Molik \u003cdan@danmolik.com\u003e 1649183458 -0400\n\nadd an empty file\n"
},
"timestamp": "2022-04-05T14:30:58-04:00",
"added": null,
"removed": null,
"modified": null
},
"protected": false,
"required_approvals": 0,
"enable_status_check": false,
"status_check_contexts": [],
"user_can_push": false,
"user_can_merge": false,
"effective_branch_protection_name": ""
}]`)
if err != nil {
t.Fail()
}
case "/api/v1/repos/test-argocd/pr-test/branches?limit=0&page=1":
_, err := io.WriteString(w, `[{
"name": "main",
"commit": {
"id": "72687815ccba81ef014a96201cc2e846a68789d8",
"id": "75f6fceff80f6aaf12b65a2cf6a89190b866625b",
"message": "initial commit\n",
"url": "https://gitea.com/test-argocd/pr-test/commit/72687815ccba81ef014a96201cc2e846a68789d8",
"url": "https://gitea.com/test-argocd/pr-test/commit/75f6fceff80f6aaf12b65a2cf6a89190b866625b",
"author": {
"name": "Dan Molik",
"email": "dan@danmolik.com",
@ -183,9 +458,9 @@ func giteaMockHandler(t *testing.T) func(http.ResponseWriter, *http.Request) {
}, {
"name": "test",
"commit": {
"id": "7bbaf62d92ddfafd9cc8b340c619abaec32bc09f",
"id": "28c3b329933f6fefd9b55225535123bbffec5a46",
"message": "add an empty file\n",
"url": "https://gitea.com/test-argocd/pr-test/commit/7bbaf62d92ddfafd9cc8b340c619abaec32bc09f",
"url": "https://gitea.com/test-argocd/pr-test/commit/28c3b329933f6fefd9b55225535123bbffec5a46",
"author": {
"name": "Dan Molik",
"email": "dan@danmolik.com",
@ -261,40 +536,270 @@ func giteaMockHandler(t *testing.T) func(http.ResponseWriter, *http.Request) {
func TestGiteaListRepos(t *testing.T) {
cases := []struct {
name, proto, url string
name, proto string
hasError, allBranches, includeSubgroups bool
excludeArchivedRepos bool
branches []string
expectedRepos []*Repository
filters []v1alpha1.SCMProviderGeneratorFilter
}{
{
name: "blank protocol",
allBranches: false,
url: "git@gitea.com:test-argocd/pr-test.git",
excludeArchivedRepos: false,
filters: []v1alpha1.SCMProviderGeneratorFilter{},
branches: []string{"main"},
expectedRepos: []*Repository{
{
Organization: "test-argocd",
Repository: "pr-test",
Branch: "main",
URL: "git@gitea.com:test-argocd/pr-test.git",
SHA: "75f6fceff80f6aaf12b65a2cf6a89190b866625b",
RepositoryId: 21618,
Labels: []string{},
},
{
Organization: "test-argocd",
Repository: "another-repo",
Branch: "main",
URL: "git@gitea.com:test-argocd/another-repo.git",
SHA: "1fa33898cf84e89836863e3a5e76eee45777b4b0",
RepositoryId: 21619,
Labels: []string{},
},
},
},
{
name: "ssh protocol",
allBranches: false,
excludeArchivedRepos: false,
filters: []v1alpha1.SCMProviderGeneratorFilter{},
proto: "ssh",
url: "git@gitea.com:test-argocd/pr-test.git",
expectedRepos: []*Repository{
{
Organization: "test-argocd",
Repository: "pr-test",
Branch: "main",
URL: "git@gitea.com:test-argocd/pr-test.git",
SHA: "75f6fceff80f6aaf12b65a2cf6a89190b866625b",
RepositoryId: 21618,
Labels: []string{},
},
{
Organization: "test-argocd",
Repository: "another-repo",
Branch: "main",
URL: "git@gitea.com:test-argocd/another-repo.git",
SHA: "1fa33898cf84e89836863e3a5e76eee45777b4b0",
RepositoryId: 21619,
Labels: []string{},
},
},
},
{
name: "https protocol",
allBranches: false,
excludeArchivedRepos: false,
filters: []v1alpha1.SCMProviderGeneratorFilter{},
proto: "https",
url: "https://gitea.com/test-argocd/pr-test",
expectedRepos: []*Repository{
{
Organization: "test-argocd",
Repository: "pr-test",
Branch: "main",
URL: "https://gitea.com/test-argocd/pr-test",
SHA: "75f6fceff80f6aaf12b65a2cf6a89190b866625b",
RepositoryId: 21618,
Labels: []string{},
},
{
Organization: "test-argocd",
Repository: "another-repo",
Branch: "main",
URL: "https://gitea.com/test-argocd/another-repo",
SHA: "1fa33898cf84e89836863e3a5e76eee45777b4b0",
RepositoryId: 21619,
Labels: []string{},
},
},
},
{
name: "other protocol",
allBranches: false,
excludeArchivedRepos: false,
filters: []v1alpha1.SCMProviderGeneratorFilter{},
proto: "other",
hasError: true,
expectedRepos: []*Repository{},
},
{
name: "all branches including archived repos",
allBranches: true,
excludeArchivedRepos: false,
filters: []v1alpha1.SCMProviderGeneratorFilter{},
expectedRepos: []*Repository{
{
Organization: "test-argocd",
Repository: "pr-test",
Branch: "main",
URL: "git@gitea.com:test-argocd/pr-test.git",
SHA: "75f6fceff80f6aaf12b65a2cf6a89190b866625b",
Labels: []string{},
RepositoryId: 21618,
},
{
Organization: "test-argocd",
Repository: "another-repo",
Branch: "main",
URL: "git@gitea.com:test-argocd/another-repo.git",
SHA: "1fa33898cf84e89836863e3a5e76eee45777b4b0",
Labels: []string{},
RepositoryId: 21619,
},
{
Organization: "test-argocd",
Repository: "pr-test",
Branch: "test",
URL: "git@gitea.com:test-argocd/pr-test.git",
SHA: "28c3b329933f6fefd9b55225535123bbffec5a46",
Labels: []string{},
RepositoryId: 21618,
},
{
Organization: "test-argocd",
Repository: "another-repo",
Branch: "test",
URL: "git@gitea.com:test-argocd/another-repo.git",
SHA: "32cdcf613b259a9439ceabd4d1745d43f163ea70",
Labels: []string{},
RepositoryId: 21619,
},
},
},
{
name: "all branches",
allBranches: true,
url: "git@gitea.com:test-argocd/pr-test.git",
excludeArchivedRepos: false,
filters: []v1alpha1.SCMProviderGeneratorFilter{},
expectedRepos: []*Repository{
{
Organization: "test-argocd",
Repository: "pr-test",
Branch: "main",
URL: "git@gitea.com:test-argocd/pr-test.git",
SHA: "75f6fceff80f6aaf12b65a2cf6a89190b866625b",
Labels: []string{},
RepositoryId: 21618,
},
{
Organization: "test-argocd",
Repository: "another-repo",
Branch: "main",
URL: "git@gitea.com:test-argocd/another-repo.git",
SHA: "1fa33898cf84e89836863e3a5e76eee45777b4b0",
Labels: []string{},
RepositoryId: 21619,
},
{
Organization: "test-argocd",
Repository: "pr-test",
Branch: "test",
URL: "git@gitea.com:test-argocd/pr-test.git",
SHA: "28c3b329933f6fefd9b55225535123bbffec5a46",
Labels: []string{},
RepositoryId: 21618,
},
{
Organization: "test-argocd",
Repository: "another-repo",
Branch: "test",
URL: "git@gitea.com:test-argocd/another-repo.git",
SHA: "32cdcf613b259a9439ceabd4d1745d43f163ea70",
Labels: []string{},
RepositoryId: 21619,
},
},
},
{
name: "all branches",
allBranches: true,
excludeArchivedRepos: false,
filters: []v1alpha1.SCMProviderGeneratorFilter{},
branches: []string{"main"},
expectedRepos: []*Repository{
{
Organization: "test-argocd",
Repository: "pr-test",
Branch: "main",
URL: "git@gitea.com:test-argocd/pr-test.git",
SHA: "75f6fceff80f6aaf12b65a2cf6a89190b866625b",
Labels: []string{},
RepositoryId: 21618,
},
{
Organization: "test-argocd",
Repository: "another-repo",
Branch: "main",
URL: "git@gitea.com:test-argocd/another-repo.git",
SHA: "1fa33898cf84e89836863e3a5e76eee45777b4b0",
Labels: []string{},
RepositoryId: 21619,
},
{
Organization: "test-argocd",
Repository: "pr-test",
Branch: "test",
URL: "git@gitea.com:test-argocd/pr-test.git",
SHA: "28c3b329933f6fefd9b55225535123bbffec5a46",
Labels: []string{},
RepositoryId: 21618,
},
{
Organization: "test-argocd",
Repository: "another-repo",
Branch: "test",
URL: "git@gitea.com:test-argocd/another-repo.git",
SHA: "32cdcf613b259a9439ceabd4d1745d43f163ea70",
Labels: []string{},
RepositoryId: 21619,
},
},
},
{
name: "all branches with no archived repos",
allBranches: true,
excludeArchivedRepos: true,
filters: []v1alpha1.SCMProviderGeneratorFilter{},
branches: []string{"main"},
expectedRepos: []*Repository{
{
Organization: "test-argocd",
Repository: "pr-test",
Branch: "main",
URL: "git@gitea.com:test-argocd/pr-test.git",
SHA: "75f6fceff80f6aaf12b65a2cf6a89190b866625b",
Labels: []string{},
RepositoryId: 21618,
},
{
Organization: "test-argocd",
Repository: "pr-test",
Branch: "test",
URL: "git@gitea.com:test-argocd/pr-test.git",
SHA: "28c3b329933f6fefd9b55225535123bbffec5a46",
Labels: []string{},
RepositoryId: 21618,
},
},
},
}
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@ -303,26 +808,19 @@ func TestGiteaListRepos(t *testing.T) {
defer ts.Close()
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
provider, _ := NewGiteaProvider("test-argocd", "", ts.URL, c.allBranches, false)
provider, _ := NewGiteaProvider("test-argocd", "", ts.URL, c.allBranches, false, c.excludeArchivedRepos)
rawRepos, err := ListRepos(t.Context(), provider, c.filters, c.proto)
if c.hasError {
require.Error(t, err)
} else {
require.NoError(t, err)
// Just check that this one project shows up. Not a great test but better thing nothing?
repos := []*Repository{}
branches := []string{}
for _, r := range rawRepos {
if r.Repository == "pr-test" {
repos = append(repos, r)
branches = append(branches, r.Branch)
}
}
repos = append(rawRepos, repos...)
assert.NotEmpty(t, repos)
assert.Equal(t, c.url, repos[0].URL)
for _, b := range c.branches {
assert.Contains(t, branches, b)
}
assert.Len(t, repos, len(c.expectedRepos))
assert.ElementsMatch(t, c.expectedRepos, repos)
}
})
}
@ -333,7 +831,7 @@ func TestGiteaHasPath(t *testing.T) {
giteaMockHandler(t)(w, r)
}))
defer ts.Close()
host, _ := NewGiteaProvider("gitea", "", ts.URL, false, false)
host, _ := NewGiteaProvider("gitea", "", ts.URL, false, false, false)
repo := &Repository{
Organization: "gitea",
Repository: "go-sdk",

View file

@ -15,11 +15,12 @@ type GithubProvider struct {
client *github.Client
organization string
allBranches bool
excludeArchivedRepos bool
}
var _ SCMProviderService = &GithubProvider{}
func NewGithubProvider(organization string, token string, url string, allBranches bool, optionalHTTPClient ...*http.Client) (*GithubProvider, error) {
func NewGithubProvider(organization string, token string, url string, allBranches bool, excludeArchivedRepos bool, optionalHTTPClient ...*http.Client) (*GithubProvider, error) {
// Undocumented environment variable to set a default token, to be used in testing to dodge anonymous rate limits.
if token == "" {
token = os.Getenv("GITHUB_TOKEN")
@ -45,7 +46,7 @@ func NewGithubProvider(organization string, token string, url string, allBranche
return nil, err
}
}
return &GithubProvider{client: client, organization: organization, allBranches: allBranches}, nil
return &GithubProvider{client: client, organization: organization, allBranches: allBranches, excludeArchivedRepos: excludeArchivedRepos}, nil
}
func (g *GithubProvider) GetBranches(ctx context.Context, repo *Repository) ([]*Repository, error) {
@ -90,6 +91,11 @@ func (g *GithubProvider) ListRepos(ctx context.Context, cloneProtocol string) ([
default:
return nil, fmt.Errorf("unknown clone protocol for GitHub %v", cloneProtocol)
}
if g.excludeArchivedRepos && githubRepo.GetArchived() {
continue
}
repos = append(repos, &Repository{
Organization: githubRepo.Owner.GetLogin(),
Repository: githubRepo.GetName(),

View file

@ -9,11 +9,11 @@ import (
appsetutils "github.com/argoproj/argo-cd/v3/applicationset/utils"
)
func NewGithubAppProviderFor(ctx context.Context, g github_app_auth.Authentication, organization string, url string, allBranches bool, optionalHTTPClient ...*http.Client) (*GithubProvider, error) {
func NewGithubAppProviderFor(ctx context.Context, g github_app_auth.Authentication, organization string, url string, allBranches bool, excludeArchivedRepos bool, optionalHTTPClient ...*http.Client) (*GithubProvider, error) {
httpClient := appsetutils.GetOptionalHTTPClient(optionalHTTPClient...)
client, err := github_app.Client(ctx, g, url, organization, httpClient)
if err != nil {
return nil, err
}
return &GithubProvider{client: client, organization: organization, allBranches: allBranches}, nil
return &GithubProvider{client: client, organization: organization, allBranches: allBranches, excludeArchivedRepos: excludeArchivedRepos}, nil
}

View file

@ -122,6 +122,110 @@ func githubMockHandler(t *testing.T) func(http.ResponseWriter, *http.Request) {
"pull": true
},
"template_repository": null
},
{
"id": 1296270,
"node_id": "MDEwOlJlcGsddRvcnkxMjk2MjY5",
"name": "another-repo",
"full_name": "argoproj/another-repo",
"owner": {
"login": "argoproj",
"id": 1,
"node_id": "MDQ6VXNlcjE=",
"avatar_url": "https://github.com/images/error/argoproj_happy.gif",
"gravatar_id": "",
"url": "https://api.github.com/users/argoproj",
"html_url": "https://github.com/argoproj",
"followers_url": "https://api.github.com/users/argoproj/followers",
"following_url": "https://api.github.com/users/argoproj/following{/other_user}",
"gists_url": "https://api.github.com/users/argoproj/gists{/gist_id}",
"starred_url": "https://api.github.com/users/argoproj/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/argoproj/subscriptions",
"organizations_url": "https://api.github.com/users/argoproj/orgs",
"repos_url": "https://api.github.com/users/argoproj/repos",
"events_url": "https://api.github.com/users/argoproj/events{/privacy}",
"received_events_url": "https://api.github.com/users/argoproj/received_events",
"type": "User",
"site_admin": false
},
"private": false,
"html_url": "https://github.com/argoproj/another-repo",
"description": "This your first repo!",
"fork": false,
"url": "https://api.github.com/repos/argoproj/another-repo",
"archive_url": "https://api.github.com/repos/argoproj/another-repo/{archive_format}{/ref}",
"assignees_url": "https://api.github.com/repos/argoproj/another-repo/assignees{/user}",
"blobs_url": "https://api.github.com/repos/argoproj/another-repo/git/blobs{/sha}",
"branches_url": "https://api.github.com/repos/argoproj/another-repo/branches{/branch}",
"collaborators_url": "https://api.github.com/repos/argoproj/another-repo/collaborators{/collaborator}",
"comments_url": "https://api.github.com/repos/argoproj/another-repo/comments{/number}",
"commits_url": "https://api.github.com/repos/argoproj/another-repo/commits{/sha}",
"compare_url": "https://api.github.com/repos/argoproj/another-repo/compare/{base}...{head}",
"contents_url": "https://api.github.com/repos/argoproj/another-repo/contents/{path}",
"contributors_url": "https://api.github.com/repos/argoproj/another-repo/contributors",
"deployments_url": "https://api.github.com/repos/argoproj/another-repo/deployments",
"downloads_url": "https://api.github.com/repos/argoproj/another-repo/downloads",
"events_url": "https://api.github.com/repos/argoproj/another-repo/events",
"forks_url": "https://api.github.com/repos/argoproj/another-repo/forks",
"git_commits_url": "https://api.github.com/repos/argoproj/another-repo/git/commits{/sha}",
"git_refs_url": "https://api.github.com/repos/argoproj/another-repo/git/refs{/sha}",
"git_tags_url": "https://api.github.com/repos/argoproj/another-repo/git/tags{/sha}",
"git_url": "git:github.com/argoproj/another-repo.git",
"issue_comment_url": "https://api.github.com/repos/argoproj/another-repo/issues/comments{/number}",
"issue_events_url": "https://api.github.com/repos/argoproj/another-repo/issues/events{/number}",
"issues_url": "https://api.github.com/repos/argoproj/another-repo/issues{/number}",
"keys_url": "https://api.github.com/repos/argoproj/another-repo/keys{/key_id}",
"labels_url": "https://api.github.com/repos/argoproj/another-repo/labels{/name}",
"languages_url": "https://api.github.com/repos/argoproj/another-repo/languages",
"merges_url": "https://api.github.com/repos/argoproj/another-repo/merges",
"milestones_url": "https://api.github.com/repos/argoproj/another-repo/milestones{/number}",
"notifications_url": "https://api.github.com/repos/argoproj/another-repo/notifications{?since,all,participating}",
"pulls_url": "https://api.github.com/repos/argoproj/another-repo/pulls{/number}",
"releases_url": "https://api.github.com/repos/argoproj/another-repo/releases{/id}",
"ssh_url": "git@github.com:argoproj/another-repo.git",
"stargazers_url": "https://api.github.com/repos/argoproj/another-repo/stargazers",
"statuses_url": "https://api.github.com/repos/argoproj/another-repo/statuses/{sha}",
"subscribers_url": "https://api.github.com/repos/argoproj/another-repo/subscribers",
"subscription_url": "https://api.github.com/repos/argoproj/another-repo/subscription",
"tags_url": "https://api.github.com/repos/argoproj/another-repo/tags",
"teams_url": "https://api.github.com/repos/argoproj/another-repo/teams",
"trees_url": "https://api.github.com/repos/argoproj/another-repo/git/trees{/sha}",
"clone_url": "https://github.com/argoproj/another-repo.git",
"mirror_url": "git:git.example.com/argoproj/another-repo",
"hooks_url": "https://api.github.com/repos/argoproj/another-repo/hooks",
"svn_url": "https://svn.github.com/argoproj/another-repo",
"homepage": "https://github.com",
"language": null,
"forks_count": 9,
"stargazers_count": 80,
"watchers_count": 80,
"size": 108,
"default_branch": "master",
"open_issues_count": 0,
"is_template": false,
"topics": [
"argoproj",
"atom",
"electron",
"api"
],
"has_issues": true,
"has_projects": true,
"has_wiki": true,
"has_pages": false,
"has_downloads": true,
"archived": true,
"disabled": false,
"visibility": "public",
"pushed_at": "2011-01-26T19:06:43Z",
"created_at": "2011-01-26T19:01:12Z",
"updated_at": "2011-01-26T19:14:43Z",
"permissions": {
"admin": false,
"push": false,
"pull": true
},
"template_repository": null
}
]`)
if err != nil {
@ -145,6 +249,49 @@ func githubMockHandler(t *testing.T) func(http.ResponseWriter, *http.Request) {
]
}
},
"protection_url": "https://api.github.com/repos/argoproj/hello-world/branches/master/protection"
},
{
"name": "test",
"commit": {
"sha": "80a6e93f16e8093e24091b03c614362df3fb9b92",
"url": "https://api.github.com/repos/argoproj/argo-cd/commits/80a6e93f16e8093e24091b03c614362df3fb9b92"
},
"protected": true,
"protection": {
"required_status_checks": {
"enforcement_level": "non_admins",
"contexts": [
"ci-test",
"linter"
]
}
},
"protection_url": "https://api.github.com/repos/argoproj/hello-world/branches/master/protection"
}
]
`)
if err != nil {
t.Fail()
}
case "/api/v3/repos/argoproj/another-repo/branches?per_page=100":
_, err := io.WriteString(w, `[
{
"name": "main",
"commit": {
"sha": "19b016818bc0e0a44ddeaab345838a2a6c97fa67",
"url": "https://api.github.com/repos/argoproj/another-repo/commits/19b016818bc0e0a44ddeaab345838a2a6c97fa67"
},
"protected": true,
"protection": {
"required_status_checks": {
"enforcement_level": "non_admins",
"contexts": [
"ci-test",
"linter"
]
}
},
"protection_url": "https://api.github.com/repos/argoproj/hello-world/branches/master/protection"
}
]
@ -196,6 +343,50 @@ func githubMockHandler(t *testing.T) func(http.ResponseWriter, *http.Request) {
if err != nil {
t.Fail()
}
case "/api/v3/repos/argoproj/argo-cd/branches/test":
_, err := io.WriteString(w, `{
"name": "test",
"commit": {
"sha": "80a6e93f16e8093e24091b03c614362df3fb9b92",
"url": "https://api.github.com/repos/octocat/Hello-World/commits/80a6e93f16e8093e24091b03c614362df3fb9b92"
},
"protected": true,
"protection": {
"required_status_checks": {
"enforcement_level": "non_admins",
"contexts": [
"ci-test",
"linter"
]
}
},
"protection_url": "https://api.github.com/repos/octocat/hello-world/branches/test/protection"
}`)
if err != nil {
t.Fail()
}
case "/api/v3/repos/argoproj/another-repo/branches/main":
_, err := io.WriteString(w, `{
"name": "main",
"commit": {
"sha": "19b016818bc0e0a44ddeaab345838a2a6c97fa67",
"url": "https://api.github.com/repos/octocat/Hello-World/commits/c5b97d5ae6c19d5c5df71a34c7fbeeda2479ccbc"
},
"protected": true,
"protection": {
"required_status_checks": {
"enforcement_level": "non_admins",
"contexts": [
"ci-test",
"linter"
]
}
},
"protection_url": "https://api.github.com/repos/octocat/hello-world/branches/master/protection"
}`)
if err != nil {
t.Fail()
}
default:
w.WriteHeader(http.StatusNotFound)
}
@ -203,37 +394,276 @@ func githubMockHandler(t *testing.T) func(http.ResponseWriter, *http.Request) {
}
func TestGithubListRepos(t *testing.T) {
idptr := func(i int64) *int64 {
return &i
}
// Test cases for ListRepos
cases := []struct {
name, proto, url string
name, proto string
hasError, allBranches bool
branches []string
excludeArchivedRepos bool
expectedRepos []*Repository
filters []v1alpha1.SCMProviderGeneratorFilter
}{
{
name: "blank protocol",
url: "git@github.com:argoproj/argo-cd.git",
branches: []string{"master"},
allBranches: true,
excludeArchivedRepos: false,
expectedRepos: []*Repository{
{
Organization: "argoproj",
Repository: "argo-cd",
Branch: "master",
URL: "git@github.com:argoproj/argo-cd.git",
SHA: "c5b97d5ae6c19d5c5df71a34c7fbeeda2479ccbc",
Labels: []string{
"argoproj",
"atom",
"electron",
"api",
},
RepositoryId: idptr(1296269),
},
{
Organization: "argoproj",
Repository: "argo-cd",
Branch: "test",
URL: "git@github.com:argoproj/argo-cd.git",
SHA: "80a6e93f16e8093e24091b03c614362df3fb9b92",
Labels: []string{
"argoproj",
"atom",
"electron",
"api",
},
RepositoryId: idptr(1296269),
},
{
Organization: "argoproj",
Repository: "another-repo",
Branch: "main",
URL: "git@github.com:argoproj/another-repo.git",
SHA: "19b016818bc0e0a44ddeaab345838a2a6c97fa67",
Labels: []string{
"argoproj",
"atom",
"electron",
"api",
},
RepositoryId: idptr(1296270),
},
},
filters: []v1alpha1.SCMProviderGeneratorFilter{
{},
},
},
{
name: "ssh protocol",
proto: "ssh",
url: "git@github.com:argoproj/argo-cd.git",
allBranches: true,
excludeArchivedRepos: false,
expectedRepos: []*Repository{
{
Organization: "argoproj",
Repository: "argo-cd",
Branch: "master",
URL: "git@github.com:argoproj/argo-cd.git",
SHA: "c5b97d5ae6c19d5c5df71a34c7fbeeda2479ccbc",
Labels: []string{
"argoproj",
"atom",
"electron",
"api",
},
RepositoryId: idptr(1296269),
},
{
Organization: "argoproj",
Repository: "argo-cd",
Branch: "test",
URL: "git@github.com:argoproj/argo-cd.git",
SHA: "80a6e93f16e8093e24091b03c614362df3fb9b92",
Labels: []string{
"argoproj",
"atom",
"electron",
"api",
},
RepositoryId: idptr(1296269),
},
{
Organization: "argoproj",
Repository: "another-repo",
Branch: "main",
URL: "git@github.com:argoproj/another-repo.git",
SHA: "19b016818bc0e0a44ddeaab345838a2a6c97fa67",
Labels: []string{
"argoproj",
"atom",
"electron",
"api",
},
RepositoryId: idptr(1296270),
},
},
filters: []v1alpha1.SCMProviderGeneratorFilter{
{},
},
},
{
name: "https protocol",
proto: "https",
url: "https://github.com/argoproj/argo-cd.git",
allBranches: true,
excludeArchivedRepos: false,
expectedRepos: []*Repository{
{
Organization: "argoproj",
Repository: "argo-cd",
Branch: "master",
URL: "https://github.com/argoproj/argo-cd.git",
SHA: "c5b97d5ae6c19d5c5df71a34c7fbeeda2479ccbc",
Labels: []string{
"argoproj",
"atom",
"electron",
"api",
},
RepositoryId: idptr(1296269),
},
{
Organization: "argoproj",
Repository: "argo-cd",
Branch: "test",
URL: "https://github.com/argoproj/argo-cd.git",
SHA: "80a6e93f16e8093e24091b03c614362df3fb9b92",
Labels: []string{
"argoproj",
"atom",
"electron",
"api",
},
RepositoryId: idptr(1296269),
},
{
Organization: "argoproj",
Repository: "another-repo",
Branch: "main",
URL: "https://github.com/argoproj/another-repo.git",
SHA: "19b016818bc0e0a44ddeaab345838a2a6c97fa67",
Labels: []string{
"argoproj",
"atom",
"electron",
"api",
},
RepositoryId: idptr(1296270),
},
},
filters: []v1alpha1.SCMProviderGeneratorFilter{
{},
},
},
{
name: "other protocol",
proto: "other",
hasError: true,
excludeArchivedRepos: false,
expectedRepos: []*Repository{},
filters: []v1alpha1.SCMProviderGeneratorFilter{
{},
},
},
{
name: "all branches",
name: "all branches with archived repos",
allBranches: true,
url: "git@github.com:argoproj/argo-cd.git",
branches: []string{"master"},
proto: "ssh",
excludeArchivedRepos: false,
expectedRepos: []*Repository{
{
Organization: "argoproj",
Repository: "argo-cd",
Branch: "master",
URL: "git@github.com:argoproj/argo-cd.git",
SHA: "c5b97d5ae6c19d5c5df71a34c7fbeeda2479ccbc",
Labels: []string{
"argoproj",
"atom",
"electron",
"api",
},
RepositoryId: idptr(1296269),
},
{
Organization: "argoproj",
Repository: "argo-cd",
Branch: "test",
URL: "git@github.com:argoproj/argo-cd.git",
SHA: "80a6e93f16e8093e24091b03c614362df3fb9b92",
Labels: []string{
"argoproj",
"atom",
"electron",
"api",
},
RepositoryId: idptr(1296269),
},
{
Organization: "argoproj",
Repository: "another-repo",
Branch: "main",
URL: "git@github.com:argoproj/another-repo.git",
SHA: "19b016818bc0e0a44ddeaab345838a2a6c97fa67",
Labels: []string{
"argoproj",
"atom",
"electron",
"api",
},
RepositoryId: idptr(1296270),
},
},
filters: []v1alpha1.SCMProviderGeneratorFilter{
{},
},
},
{
name: "test repo all branches without archived repos",
allBranches: true,
excludeArchivedRepos: true,
proto: "https",
expectedRepos: []*Repository{
{
Organization: "argoproj",
Repository: "argo-cd",
Branch: "master",
URL: "https://github.com/argoproj/argo-cd.git",
SHA: "c5b97d5ae6c19d5c5df71a34c7fbeeda2479ccbc",
Labels: []string{
"argoproj",
"atom",
"electron",
"api",
},
RepositoryId: idptr(1296269),
},
{
Organization: "argoproj",
Repository: "argo-cd",
Branch: "test",
URL: "https://github.com/argoproj/argo-cd.git",
SHA: "80a6e93f16e8093e24091b03c614362df3fb9b92",
Labels: []string{
"argoproj",
"atom",
"electron",
"api",
},
RepositoryId: idptr(1296269),
},
},
filters: []v1alpha1.SCMProviderGeneratorFilter{
{},
},
},
}
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@ -242,26 +672,18 @@ func TestGithubListRepos(t *testing.T) {
defer ts.Close()
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
provider, _ := NewGithubProvider("argoproj", "", ts.URL, c.allBranches)
provider, _ := NewGithubProvider("argoproj", "", ts.URL, c.allBranches, c.excludeArchivedRepos)
rawRepos, err := ListRepos(t.Context(), provider, c.filters, c.proto)
if c.hasError {
require.Error(t, err)
} else {
require.NoError(t, err)
// Just check that this one project shows up. Not a great test but better thing nothing?
repos := []*Repository{}
branches := []string{}
for _, r := range rawRepos {
if r.Repository == "argo-cd" {
repos = append(repos, r)
branches = append(branches, r.Branch)
}
}
repos = append(rawRepos, repos...)
assert.NotEmpty(t, repos)
assert.Equal(t, c.url, repos[0].URL)
for _, b := range c.branches {
assert.Contains(t, branches, b)
}
assert.Len(t, repos, len(c.expectedRepos))
assert.ElementsMatch(t, c.expectedRepos, repos)
}
})
}
@ -280,7 +702,7 @@ func TestGithubHasPath(t *testing.T) {
githubMockHandler(t)(w, r)
}))
defer ts.Close()
host, _ := NewGithubProvider("argoproj", "", ts.URL, false)
host, _ := NewGithubProvider("argoproj", "", ts.URL, false, false)
repo := &Repository{
Organization: "argoproj",
Repository: "argo-cd",
@ -300,7 +722,7 @@ func TestGithubGetBranches(t *testing.T) {
githubMockHandler(t)(w, r)
}))
defer ts.Close()
host, _ := NewGithubProvider("argoproj", "", ts.URL, false)
host, _ := NewGithubProvider("argoproj", "", ts.URL, false, false)
repo := &Repository{
Organization: "argoproj",
Repository: "argo-cd",
@ -328,6 +750,6 @@ func TestGithubGetBranches(t *testing.T) {
require.NoError(t, err)
} else {
// considering master branch to exist.
assert.Len(t, repos, 1)
assert.Len(t, repos, 2)
}
}

View file

@ -19,12 +19,13 @@ type GitlabProvider struct {
allBranches bool
includeSubgroups bool
includeSharedProjects bool
includeArchivedRepos bool
topic string
}
var _ SCMProviderService = &GitlabProvider{}
func NewGitlabProvider(organization string, token string, url string, allBranches, includeSubgroups, includeSharedProjects, insecure bool, scmRootCAPath, topic string, caCerts []byte) (*GitlabProvider, error) {
func NewGitlabProvider(organization string, token string, url string, allBranches, includeSubgroups, includeSharedProjects, includeArchivedRepos, insecure bool, scmRootCAPath, topic string, caCerts []byte) (*GitlabProvider, error) {
// Undocumented environment variable to set a default token, to be used in testing to dodge anonymous rate limits.
if token == "" {
token = os.Getenv("GITLAB_TOKEN")
@ -51,7 +52,15 @@ func NewGitlabProvider(organization string, token string, url string, allBranche
}
}
return &GitlabProvider{client: client, organization: organization, allBranches: allBranches, includeSubgroups: includeSubgroups, includeSharedProjects: includeSharedProjects, topic: topic}, nil
return &GitlabProvider{
client: client,
organization: organization,
allBranches: allBranches,
includeSubgroups: includeSubgroups,
includeSharedProjects: includeSharedProjects,
includeArchivedRepos: includeArchivedRepos,
topic: topic,
}, nil
}
func (g *GitlabProvider) GetBranches(ctx context.Context, repo *Repository) ([]*Repository, error) {
@ -88,6 +97,11 @@ func (g *GitlabProvider) ListRepos(_ context.Context, cloneProtocol string) ([]*
Topic: &g.topic,
}
// gitlab does not include Archived repos by default
if g.includeArchivedRepos {
opt.Archived = gitlab.Ptr(true)
}
repos := []*Repository{}
for {
gitlabRepos, resp, err := g.client.Groups.ListGroupProjects(g.organization, opt)

View file

@ -3,7 +3,6 @@ package scm_provider
import (
"crypto/x509"
"encoding/pem"
"fmt"
"io"
"net/http"
"net/http/httptest"
@ -19,12 +18,9 @@ func gitlabMockHandler(t *testing.T) func(http.ResponseWriter, *http.Request) {
t.Helper()
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
fmt.Println(r.RequestURI)
switch r.RequestURI {
case "/api/v4":
fmt.Println("here1")
case "/api/v4/groups/test-argocd-proton/projects?include_subgroups=false&per_page=100", "/api/v4/groups/test-argocd-proton/projects?include_subgroups=false&per_page=100&topic=&with_shared=false":
fmt.Println("here")
case "/api/v4/groups/test-argocd-proton/projects?include_subgroups=false&per_page=100", "/api/v4/groups/test-argocd-proton/projects?include_subgroups=false&per_page=100&topic=&with_shared=false", "/api/v4/groups/test-argocd-proton/projects?archived=false&include_subgroups=false&per_page=100", "/api/v4/groups/test-argocd-proton/projects?archived=false&include_subgroups=false&per_page=100&topic=&with_shared=false":
_, err := io.WriteString(w, `[{
"id": 27084533,
"description": "",
@ -151,8 +147,253 @@ func gitlabMockHandler(t *testing.T) func(http.ResponseWriter, *http.Request) {
if err != nil {
t.Fail()
}
case "/api/v4/groups/test-argocd-proton/projects?archived=true&include_subgroups=false&per_page=100", "/api/v4/groups/test-argocd-proton/projects?archived=true&include_subgroups=false&per_page=100&topic=&with_shared=false":
_, err := io.WriteString(w, `[{
"id": 27084533,
"description": "",
"name": "argocd",
"name_with_namespace": "test argocd proton / argocd",
"path": "argocd",
"path_with_namespace": "test-argocd-proton/argocd",
"created_at": "2021-06-01T17:30:44.724Z",
"default_branch": "master",
"tag_list": [],
"topics": [],
"ssh_url_to_repo": "git@gitlab.com:test-argocd-proton/argocd.git",
"http_url_to_repo": "https://gitlab.com/test-argocd-proton/argocd.git",
"web_url": "https://gitlab.com/test-argocd-proton/argocd",
"readme_url": null,
"avatar_url": null,
"forks_count": 0,
"star_count": 0,
"last_activity_at": "2021-06-04T08:19:51.656Z",
"namespace": {
"id": 12258515,
"name": "test argocd proton",
"path": "test-argocd-proton",
"kind": "gro* Connection #0 to host gitlab.com left intact up ",
"full_path ": "test - argocd - proton ",
"parent_id ": null,
"avatar_url ": null,
"web_url ": "https: //gitlab.com/groups/test-argocd-proton"
},
"container_registry_image_prefix": "registry.gitlab.com/test-argocd-proton/argocd",
"_links": {
"self": "https://gitlab.com/api/v4/projects/27084533",
"issues": "https://gitlab.com/api/v4/projects/27084533/issues",
"merge_requests": "https://gitlab.com/api/v4/projects/27084533/merge_requests",
"repo_branches": "https://gitlab.com/api/v4/projects/27084533/repository/branches",
"labels": "https://gitlab.com/api/v4/projects/27084533/labels",
"events": "https://gitlab.com/api/v4/projects/27084533/events",
"members": "https://gitlab.com/api/v4/projects/27084533/members",
"cluster_agents": "https://gitlab.com/api/v4/projects/27084533/cluster_agents"
},
"packages_enabled": true,
"empty_repo": false,
"archived": false,
"visibility": "public",
"resolve_outdated_diff_discussions": false,
"container_expiration_policy": {
"cadence": "1d",
"enabled": false,
"keep_n": 10,
"older_than": "90d",
"name_regex": ".*",
"name_regex_keep": null,
"next_run_at": "2021-06-02T17:30:44.740Z"
},
"issues_enabled": true,
"merge_requests_enabled": true,
"wiki_enabled": true,
"jobs_enabled": true,
"snippets_enabled": true,
"container_registry_enabled": true,
"service_desk_enabled": true,
"can_create_merge_request_in": false,
"issues_access_level": "enabled",
"repository_access_level": "enabled",
"merge_requests_access_level": "enabled",
"forking_access_level": "enabled",
"wiki_access_level": "enabled",
"builds_access_level": "enabled",
"snippets_access_level": "enabled",
"pages_access_level": "enabled",
"operations_access_level": "enabled",
"analytics_access_level": "enabled",
"container_registry_access_level": "enabled",
"security_and_compliance_access_level": "private",
"emails_disabled": null,
"shared_runners_enabled": true,
"lfs_enabled": true,
"creator_id": 2378866,
"import_status": "none",
"open_issues_count": 0,
"ci_default_git_depth": 50,
"ci_forward_deployment_enabled": true,
"ci_job_token_scope_enabled": false,
"public_jobs": true,
"build_timeout": 3600,
"auto_cancel_pending_pipelines": "enabled",
"ci_config_path": "",
"shared_with_groups": [],
"only_allow_merge_if_pipeline_succeeds": false,
"allow_merge_on_skipped_pipeline": null,
"restrict_user_defined_variables": false,
"request_access_enabled": true,
"only_allow_merge_if_all_discussions_are_resolved": false,
"remove_source_branch_after_merge": true,
"printing_merge_request_link_enabled": true,
"merge_method": "merge",
"squash_option": "default_off",
"suggestion_commit_message": null,
"merge_commit_template": null,
"squash_commit_template": null,
"auto_devops_enabled": false,
"auto_devops_deploy_strategy": "continuous",
"autoclose_referenced_issues": true,
"keep_latest_artifact": true,
"runner_token_expiration_interval": null,
"approvals_before_merge": 0,
"mirror": false,
"external_authorization_classification_label": "",
"marked_for_deletion_at": null,
"marked_for_deletion_on": null,
"requirements_enabled": true,
"requirements_access_level": "enabled",
"security_and_compliance_enabled": false,
"compliance_frameworks": [],
"issues_template": null,
"merge_requests_template": null,
"merge_pipelines_enabled": false,
"merge_trains_enabled": false
},
{
"id": 56522142,
"description": "",
"name": "another-repo",
"name_with_namespace": "test argocd proton / another-repo",
"path": "another-repo",
"path_with_namespace": "test-argocd-proton/another-repo",
"created_at": "2022-09-13T12:10:14.722Z",
"default_branch": "master",
"tag_list": [
"test-topic"
],
"topics": [
"test-topic"
],
"ssh_url_to_repo": "git@gitlab.com:test-argocd-proton/another-repo.git",
"http_url_to_repo": "https://gitlab.com/test-argocd-proton/another-repo.git",
"web_url": "https://gitlab.com/test-argocd-proton/another-repo",
"readme_url": null,
"avatar_url": null,
"forks_count": 0,
"star_count": 0,
"last_activity_at": "2021-06-04T08:19:51.656Z",
"namespace": {
"id": 12258515,
"name": "test argocd proton",
"path": "test-argocd-proton",
"kind": "gro* Connection #0 to host gitlab.com left intact up ",
"full_path ": "test - argocd - proton ",
"parent_id ": null,
"avatar_url ": null,
"web_url ": "https: //gitlab.com/groups/test-argocd-proton"
},
"container_registry_image_prefix": "registry.gitlab.com/test-argocd-proton/another-repo",
"_links": {
"self": "https://gitlab.com/api/v4/projects/56522142",
"issues": "https://gitlab.com/api/v4/projects/56522142/issues",
"merge_requests": "https://gitlab.com/api/v4/projects/56522142/merge_requests",
"repo_branches": "https://gitlab.com/api/v4/projects/56522142/repository/branches",
"labels": "https://gitlab.com/api/v4/projects/56522142/labels",
"events": "https://gitlab.com/api/v4/projects/56522142/events",
"members": "https://gitlab.com/api/v4/projects/56522142/members",
"cluster_agents": "https://gitlab.com/api/v4/projects/56522142/cluster_agents"
},
"packages_enabled": true,
"empty_repo": false,
"archived": true,
"visibility": "public",
"resolve_outdated_diff_discussions": false,
"container_expiration_policy": {
"cadence": "1d",
"enabled": false,
"keep_n": 10,
"older_than": "90d",
"name_regex": ".*",
"name_regex_keep": null,
"next_run_at": "2021-06-02T17:30:44.740Z"
},
"issues_enabled": true,
"merge_requests_enabled": true,
"wiki_enabled": true,
"jobs_enabled": true,
"snippets_enabled": true,
"container_registry_enabled": true,
"service_desk_enabled": true,
"can_create_merge_request_in": false,
"issues_access_level": "enabled",
"repository_access_level": "enabled",
"merge_requests_access_level": "enabled",
"forking_access_level": "enabled",
"wiki_access_level": "enabled",
"builds_access_level": "enabled",
"snippets_access_level": "enabled",
"pages_access_level": "enabled",
"operations_access_level": "enabled",
"analytics_access_level": "enabled",
"container_registry_access_level": "enabled",
"security_and_compliance_access_level": "private",
"emails_disabled": null,
"shared_runners_enabled": true,
"lfs_enabled": true,
"creator_id": 2378866,
"import_status": "none",
"open_issues_count": 0,
"ci_default_git_depth": 50,
"ci_forward_deployment_enabled": true,
"ci_job_token_scope_enabled": false,
"public_jobs": true,
"build_timeout": 3600,
"auto_cancel_pending_pipelines": "enabled",
"ci_config_path": "",
"shared_with_groups": [],
"only_allow_merge_if_pipeline_succeeds": false,
"allow_merge_on_skipped_pipeline": null,
"restrict_user_defined_variables": false,
"request_access_enabled": true,
"only_allow_merge_if_all_discussions_are_resolved": false,
"remove_source_branch_after_merge": true,
"printing_merge_request_link_enabled": true,
"merge_method": "merge",
"squash_option": "default_off",
"suggestion_commit_message": null,
"merge_commit_template": null,
"squash_commit_template": null,
"auto_devops_enabled": false,
"auto_devops_deploy_strategy": "continuous",
"autoclose_referenced_issues": true,
"keep_latest_artifact": true,
"runner_token_expiration_interval": null,
"approvals_before_merge": 0,
"mirror": false,
"external_authorization_classification_label": "",
"marked_for_deletion_at": null,
"marked_for_deletion_on": null,
"requirements_enabled": true,
"requirements_access_level": "enabled",
"security_and_compliance_enabled": false,
"compliance_frameworks": [],
"issues_template": null,
"merge_requests_template": null,
"merge_pipelines_enabled": false,
"merge_trains_enabled": false
}]`)
if err != nil {
t.Fail()
}
case "/api/v4/groups/test-argocd-proton/projects?include_subgroups=true&per_page=100&topic=&with_shared=false":
fmt.Println("here")
_, err := io.WriteString(w, `[{
"id": 27084533,
"description": "",
@ -406,7 +647,6 @@ func gitlabMockHandler(t *testing.T) func(http.ResponseWriter, *http.Request) {
t.Fail()
}
case "/api/v4/groups/test-argocd-proton/projects?include_subgroups=false&per_page=100&topic=specific-topic&with_shared=false":
fmt.Println("here")
_, err := io.WriteString(w, `[{
"id": 27084533,
"description": "",
@ -537,7 +777,6 @@ func gitlabMockHandler(t *testing.T) func(http.ResponseWriter, *http.Request) {
t.Fail()
}
case "/api/v4/groups/test-argocd-proton/projects?include_subgroups=true&per_page=100&topic=&with_shared=true":
fmt.Println("here")
_, err := io.WriteString(w, `[{
"id": 27084533,
"description": "",
@ -796,7 +1035,6 @@ func gitlabMockHandler(t *testing.T) func(http.ResponseWriter, *http.Request) {
t.Fail()
}
case "/api/v4/projects/27084533/repository/branches/master":
fmt.Println("returning")
_, err := io.WriteString(w, `{
"name": "master",
"commit": {
@ -826,6 +1064,36 @@ func gitlabMockHandler(t *testing.T) func(http.ResponseWriter, *http.Request) {
if err != nil {
t.Fail()
}
case "/api/v4/projects/56522142/repository/branches/master":
_, err := io.WriteString(w, `{
"name": "master",
"commit": {
"id": "9998d7999fc99dd0fd578650b58b244fc63f6b53",
"short_id": "9998d799",
"created_at": "2023-08-04T08:14:14.000+00:00",
"parent_ids": ["5d9d50be1ef949ad28674e238c7e12a17b1e9706", "99482e001731640b4123cf177e51c696f08a3005"],
"title": "Merge branch 'pipeline-4547911429' into 'master'",
"message": "Merge branch 'pipeline-4547911429' into 'master'\n\n[testapp-ci] manifests/demo/test-app.yaml: release v1.2.0\n\nSee merge request test-argocd-proton/argocd!3",
"author_name": "Martin Vozník",
"author_email": "martin@voznik.cz",
"authored_date": "2023-08-04T08:14:14.000+00:00",
"committer_name": "Martin Vozník",
"committer_email": "martin@voznik.cz",
"committed_date": "2023-08-04T08:14:14.000+00:00",
"trailers": {},
"web_url": "https://gitlab.com/test-argocd-proton/argocd/-/commit/9998d7999fc99dd0fd578650b58b244fc63f6b53"
},
"merged": false,
"protected": true,
"developers_can_push": false,
"developers_can_merge": false,
"can_push": false,
"default": true,
"web_url": "https://gitlab.com/test-argocd-proton/argocd/-/tree/master"
}`)
if err != nil {
t.Fail()
}
case "/api/v4/projects/27084533/repository/branches?per_page=100":
_, err := io.WriteString(w, `[{
"name": "master",
@ -991,8 +1259,62 @@ func gitlabMockHandler(t *testing.T) func(http.ResponseWriter, *http.Request) {
if err != nil {
t.Fail()
}
case "/api/v4/projects/56522142/repository/branches?per_page=100":
_, err := io.WriteString(w, `[{
"name": "master",
"commit": {
"id": "8898d8889fc99dd0fd578650b58b244fc63f6b58",
"short_id": "8898d801",
"created_at": "2021-06-04T08:24:44.000+00:00",
"parent_ids": null,
"title": "Merge branch 'pipeline-1317911429' into 'master'",
"message": "Merge branch 'pipeline-1317911429' into 'master'",
"author_name": "Martin Vozník",
"author_email": "martin@voznik.cz",
"authored_date": "2021-06-04T08:24:44.000+00:00",
"committer_name": "Martin Vozník",
"committer_email": "martin@voznik.cz",
"committed_date": "2021-06-04T08:24:44.000+00:00",
"trailers": null,
"web_url": "https://gitlab.com/test-argocd-proton/subgroup/argocd-subgroup/-/commit/8898d7999fc99dd0fd578650b58b244fc63f6b53"
},
"merged": false,
"protected": true,
"developers_can_push": false,
"developers_can_merge": false,
"can_push": false,
"default": true,
"web_url": "https://gitlab.com/test-argocd-proton/subgroup/argocd-subgroup/-/tree/master"
}, {
"name": "pipeline-2310077506",
"commit": {
"id": "0f92540e5f396ba960adea4ed0aa905baf3f73d1",
"short_id": "0f92540e",
"created_at": "2021-06-01T18:39:59.000+00:00",
"parent_ids": null,
"title": "[testapp-ci] manifests/demo/test-app.yaml: release v1.0.1",
"message": "[testapp-ci] manifests/demo/test-app.yaml: release v1.0.1",
"author_name": "ci-test-app",
"author_email": "mvoznik+cicd@protonmail.com",
"authored_date": "2021-06-01T18:39:59.000+00:00",
"committer_name": "ci-test-app",
"committer_email": "mvoznik+cicd@protonmail.com",
"committed_date": "2021-06-01T18:39:59.000+00:00",
"trailers": null,
"web_url": "https://gitlab.com/test-argocd-proton/subgroup/argocd-subgroup/-/commit/0f92540e5f396ba960adea4ed0aa905baf3f73d1"
},
"merged": false,
"protected": false,
"developers_can_push": false,
"developers_can_merge": false,
"can_push": false,
"default": false,
"web_url": "https://gitlab.com/test-argocd-proton/subgroup/argocd-subgroup/-/tree/pipeline-1310077506"
}]`)
if err != nil {
t.Fail()
}
case "/api/v4/projects/test-argocd-proton%2Fargocd":
fmt.Println("auct")
_, err := io.WriteString(w, `{
"id": 27084533,
"description": "",
@ -1079,35 +1401,94 @@ func gitlabMockHandler(t *testing.T) func(http.ResponseWriter, *http.Request) {
func TestGitlabListRepos(t *testing.T) {
cases := []struct {
name, proto, url, topic string
hasError, allBranches, includeSubgroups, includeSharedProjects, insecure bool
name, proto, topic string
hasError, allBranches, includeSubgroups, includeSharedProjects, includeArchivedRepos, insecure bool
branches []string
expectedRepos []*Repository
filters []v1alpha1.SCMProviderGeneratorFilter
}{
{
name: "blank protocol",
url: "git@gitlab.com:test-argocd-proton/argocd.git",
allBranches: false,
includeArchivedRepos: false,
filters: []v1alpha1.SCMProviderGeneratorFilter{},
branches: []string{"master"},
expectedRepos: []*Repository{
{
Organization: "",
Repository: "argocd",
Branch: "master",
URL: "git@gitlab.com:test-argocd-proton/argocd.git",
SHA: "8898d7999fc99dd0fd578650b58b244fc63f6b53",
RepositoryId: int64(27084533),
Labels: []string{"test-topic"},
},
},
},
{
name: "ssh protocol",
proto: "ssh",
url: "git@gitlab.com:test-argocd-proton/argocd.git",
},
allBranches: false,
includeArchivedRepos: false,
filters: []v1alpha1.SCMProviderGeneratorFilter{},
branches: []string{"master"},
expectedRepos: []*Repository{
{
name: "labelmatch",
proto: "ssh",
url: "git@gitlab.com:test-argocd-proton/argocd.git",
filters: []v1alpha1.SCMProviderGeneratorFilter{
{
LabelMatch: new("test-topic"),
Organization: "",
Repository: "argocd",
Branch: "master",
URL: "git@gitlab.com:test-argocd-proton/argocd.git",
SHA: "8898d7999fc99dd0fd578650b58b244fc63f6b53",
RepositoryId: int64(27084533),
Labels: []string{"test-topic"},
},
},
},
{
name: "https protocol",
proto: "https",
url: "https://gitlab.com/test-argocd-proton/argocd.git",
allBranches: false,
includeArchivedRepos: false,
filters: []v1alpha1.SCMProviderGeneratorFilter{},
branches: []string{"master"},
expectedRepos: []*Repository{
{
Organization: "",
Repository: "argocd",
Branch: "master",
URL: "https://gitlab.com/test-argocd-proton/argocd.git",
SHA: "8898d7999fc99dd0fd578650b58b244fc63f6b53",
RepositoryId: int64(27084533),
Labels: []string{"test-topic"},
},
},
},
{
name: "labelmatch",
proto: "ssh",
allBranches: false,
includeArchivedRepos: false,
filters: []v1alpha1.SCMProviderGeneratorFilter{
{
LabelMatch: new("test-topic"),
},
},
branches: []string{"master"},
expectedRepos: []*Repository{
{
Organization: "",
Repository: "argocd",
Branch: "master",
URL: "git@gitlab.com:test-argocd-proton/argocd.git",
SHA: "8898d7999fc99dd0fd578650b58b244fc63f6b53",
RepositoryId: int64(27084533),
Labels: []string{"test-topic"},
},
},
},
{
name: "other protocol",
@ -1117,32 +1498,131 @@ func TestGitlabListRepos(t *testing.T) {
{
name: "all branches",
allBranches: true,
url: "git@gitlab.com:test-argocd-proton/argocd.git",
includeArchivedRepos: false,
filters: []v1alpha1.SCMProviderGeneratorFilter{},
branches: []string{"master"},
expectedRepos: []*Repository{
{
Organization: "",
Repository: "argocd",
Branch: "master",
URL: "git@gitlab.com:test-argocd-proton/argocd.git",
SHA: "8898d7999fc99dd0fd578650b58b244fc63f6b53",
RepositoryId: int64(27084533),
Labels: []string{"test-topic"},
},
},
},
{
name: "all subgroups",
allBranches: true,
url: "git@gitlab.com:test-argocd-proton/argocd.git",
branches: []string{"master"},
includeSharedProjects: false,
includeSubgroups: true,
includeArchivedRepos: false,
filters: []v1alpha1.SCMProviderGeneratorFilter{},
expectedRepos: []*Repository{
{
Organization: "",
Repository: "argocd",
Branch: "master",
URL: "git@gitlab.com:test-argocd-proton/argocd.git",
SHA: "8898d7999fc99dd0fd578650b58b244fc63f6b53",
RepositoryId: int64(27084533),
Labels: []string{"test-topic", "specific-topic"},
},
{
Organization: "",
Repository: "argocd-subgroup",
Branch: "master",
URL: "git@gitlab.com:test-argocd-proton/subgroup/argocd-subgroup.git",
SHA: "8898d7999fc99dd0fd578650b58b244fc63f6b58",
RepositoryId: int64(27084538),
Labels: []string{"test-topic"},
},
},
},
{
name: "all subgroups and shared projects",
allBranches: true,
url: "git@gitlab.com:test-argocd-proton/argocd.git",
branches: []string{"master"},
includeSharedProjects: true,
includeSubgroups: true,
includeArchivedRepos: false,
filters: []v1alpha1.SCMProviderGeneratorFilter{},
expectedRepos: []*Repository{
{
Organization: "",
Repository: "argocd",
Branch: "master",
URL: "git@gitlab.com:test-argocd-proton/argocd.git",
SHA: "8898d7999fc99dd0fd578650b58b244fc63f6b53",
RepositoryId: int64(27084533),
Labels: []string{"test-topic"},
},
{
Organization: "",
Repository: "shared-argocd",
Branch: "master",
URL: "git@gitlab.com:test-shared-argocd-proton/shared-argocd.git",
SHA: "8898d7999fc99dd0fd578650b58b244fc63f6b53",
RepositoryId: int64(27084534),
Labels: []string{"test-topic"},
},
},
},
{
name: "specific topic",
allBranches: true,
url: "git@gitlab.com:test-argocd-proton/argocd.git",
branches: []string{"master"},
includeSubgroups: false,
topic: "specific-topic",
includeArchivedRepos: false,
filters: []v1alpha1.SCMProviderGeneratorFilter{},
expectedRepos: []*Repository{
{
Organization: "",
Repository: "argocd",
Branch: "master",
URL: "git@gitlab.com:test-argocd-proton/argocd.git",
SHA: "8898d7999fc99dd0fd578650b58b244fc63f6b53",
RepositoryId: int64(27084533),
Labels: []string{"test-topic", "specific-topic"},
},
},
},
{
name: "all branches with archived repos",
allBranches: true,
branches: []string{"master"},
includeSubgroups: false,
includeArchivedRepos: true,
filters: []v1alpha1.SCMProviderGeneratorFilter{},
expectedRepos: []*Repository{
{
Organization: "",
Repository: "argocd",
Branch: "master",
URL: "git@gitlab.com:test-argocd-proton/argocd.git",
SHA: "8898d7999fc99dd0fd578650b58b244fc63f6b53",
RepositoryId: int64(27084533),
Labels: []string{},
},
{
Organization: "",
Repository: "another-repo",
Branch: "master",
URL: "git@gitlab.com:test-argocd-proton/another-repo.git",
SHA: "8898d8889fc99dd0fd578650b58b244fc63f6b58",
RepositoryId: int64(56522142),
Labels: []string{"test-topic"},
},
},
},
}
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@ -1150,28 +1630,24 @@ func TestGitlabListRepos(t *testing.T) {
}))
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
provider, _ := NewGitlabProvider("test-argocd-proton", "", ts.URL, c.allBranches, c.includeSubgroups, c.includeSharedProjects, c.insecure, "", c.topic, nil)
provider, _ := NewGitlabProvider("test-argocd-proton", "", ts.URL, c.allBranches, c.includeSubgroups, c.includeSharedProjects, c.includeArchivedRepos, c.insecure, "", c.topic, nil)
rawRepos, err := ListRepos(t.Context(), provider, c.filters, c.proto)
if c.hasError {
require.Error(t, err)
} else {
require.NoError(t, err)
// Just check that this one project shows up. Not a great test but better than nothing?
repos := []*Repository{}
uniqueRepos := map[string]int{}
branches := []string{}
for _, r := range rawRepos {
if r.Repository == "argocd" {
if _, ok := uniqueRepos[r.Repository]; !ok {
repos = append(repos, r)
branches = append(branches, r.Branch)
}
uniqueRepos[r.Repository]++
}
assert.NotEmpty(t, repos)
assert.Equal(t, c.url, repos[0].URL)
for _, b := range c.branches {
assert.Contains(t, branches, b)
}
// In case of listing subgroups, validate the number of returned projects
if c.includeSubgroups || c.includeSharedProjects {
assert.Len(t, uniqueRepos, 2)
@ -1180,6 +1656,8 @@ func TestGitlabListRepos(t *testing.T) {
if c.topic != "" {
assert.Len(t, uniqueRepos, 1)
}
assert.Len(t, repos, len(c.expectedRepos))
assert.ElementsMatch(t, c.expectedRepos, repos)
}
})
}
@ -1189,7 +1667,7 @@ func TestGitlabHasPath(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
gitlabMockHandler(t)(w, r)
}))
host, _ := NewGitlabProvider("test-argocd-proton", "", ts.URL, false, true, true, false, "", "", nil)
host, _ := NewGitlabProvider("test-argocd-proton", "", ts.URL, false, true, true, false, false, "", "", nil)
repo := &Repository{
Organization: "test-argocd-proton",
Repository: "argocd",
@ -1245,10 +1723,10 @@ func TestGitlabGetBranches(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
gitlabMockHandler(t)(w, r)
}))
host, _ := NewGitlabProvider("test-argocd-proton", "", ts.URL, false, true, true, false, "", "", nil)
host, _ := NewGitlabProvider("test-argocd-proton", "", ts.URL, false, true, true, false, false, "", "", nil)
repo := &Repository{
RepositoryId: 27084533,
RepositoryId: int64(27084533),
Branch: "master",
}
t.Run("branch exists", func(t *testing.T) {
@ -1258,7 +1736,7 @@ func TestGitlabGetBranches(t *testing.T) {
})
repo2 := &Repository{
RepositoryId: 27084533,
RepositoryId: int64(27084533),
Branch: "foo",
}
t.Run("unknown branch", func(t *testing.T) {
@ -1321,10 +1799,10 @@ func TestGetBranchesTLS(t *testing.T) {
}
}
host, err := NewGitlabProvider("test-argocd-proton", "", ts.URL, false, true, true, test.tlsInsecure, "", "", certs)
host, err := NewGitlabProvider("test-argocd-proton", "", ts.URL, false, true, true, false, test.tlsInsecure, "", "", certs)
require.NoError(t, err)
repo := &Repository{
RepositoryId: 27084533,
RepositoryId: int64(27084533),
Branch: "master",
}
_, err = host.GetBranches(t.Context(), repo)

12
assets/swagger.json generated
View file

@ -10498,6 +10498,10 @@
"description": "The Gitea URL to talk to. For example https://gitea.mydomain.com/.",
"type": "string"
},
"excludeArchivedRepos": {
"description": "Exclude repositories that are archived.",
"type": "boolean"
},
"insecure": {
"type": "boolean",
"title": "Allow self-signed TLS / Certificates; default: false"
@ -10527,6 +10531,10 @@
"description": "AppSecretName is a reference to a GitHub App repo-creds secret.",
"type": "string"
},
"excludeArchivedRepos": {
"description": "Exclude repositories that are archived.",
"type": "boolean"
},
"organization": {
"description": "GitHub org to scan. Required.",
"type": "string"
@ -10555,6 +10563,10 @@
"description": "Gitlab group to scan. Required. You can use either the project id (recommended) or the full namespaced path.",
"type": "string"
},
"includeArchivedRepos": {
"description": "Include repositories that are archived.",
"type": "boolean"
},
"includeSharedProjects": {
"type": "boolean",
"title": "When recursing through subgroups, also include shared Projects (true) or scan only the subgroups under same path (false). Defaults to \"true\""

View file

@ -44,6 +44,8 @@ spec:
api: https://git.example.com/
# If true, scan every branch of every repository. If false, scan only the default branch. Defaults to false.
allBranches: true
# Exclude repos that are archived
excludeArchivedRepos: true
# Reference to a Secret containing an access token. (optional)
tokenRef:
secretName: github-token
@ -59,6 +61,7 @@ spec:
* `allBranches`: By default (false) the template will only be evaluated for the default branch of each repo. If this is true, every branch of every repository will be passed to the filters. If using this flag, you likely want to use a `branchMatch` filter.
* `tokenRef`: A `Secret` name and key containing the GitHub access token to use for requests. If not specified, will make anonymous requests which have a lower rate limit and can only see public repositories.
* `appSecretName`: A `Secret` name containing a GitHub App secret in [repo-creds format][repo-creds].
* `excludeArchivedRepos`: exclude repositories that are archived. defaults to false
[repo-creds]: ../declarative-setup.md#repository-credentials
@ -90,6 +93,8 @@ spec:
# If true and includeSubgroups is also true, include Shared Projects, which is gitlab API default.
# If false only search Projects under the same path. Defaults to true.
includeSharedProjects: false
# Include repos that are archived
includeArchivedRepos: true
# filter projects by topic. A single topic is supported by Gitlab API. Defaults to "" (all topics).
topic: "my-topic"
# Reference to a Secret containing an access token. (optional)
@ -111,6 +116,7 @@ spec:
* `allBranches`: By default (false) the template will only be evaluated for the default branch of each repo. If this is true, every branch of every repository will be passed to the filters. If using this flag, you likely want to use a `branchMatch` filter.
* `includeSubgroups`: By default (false) the controller will only search for repos directly in the base group. If this is true, it will recurse through all the subgroups searching for repos to scan.
* `includeSharedProjects`: If true and includeSubgroups is also true, include Shared Projects, which is gitlab API default. If false only search Projects under the same path. In general most would want the behaviour when set to false. Defaults to true.
* `includeArchivedRepos`: include repositories that are archived. defaults to false
* `topic`: filter projects by topic. A single topic is supported by Gitlab API. Defaults to "" (all topics).
* `tokenRef`: A `Secret` name and key containing the GitLab access token to use for requests. If not specified, will make anonymous requests which have a lower rate limit and can only see public repositories.
* `insecure`: By default (false) - Skip checking the validity of the SCM's certificate - useful for self-signed TLS certificates.
@ -147,6 +153,8 @@ spec:
api: https://gitea.mydomain.com/
# If true, scan every branch of every repository. If false, scan only the default branch. Defaults to false.
allBranches: true
# Exclude repos that are archived
excludeArchivedRepos: true
# Reference to a Secret containing an access token. (optional)
tokenRef:
secretName: gitea-token
@ -160,6 +168,7 @@ spec:
* `allBranches`: By default (false) the template will only be evaluated for the default branch of each repo. If this is true, every branch of every repository will be passed to the filters. If using this flag, you likely want to use a `branchMatch` filter.
* `tokenRef`: A `Secret` name and key containing the Gitea access token to use for requests. If not specified, will make anonymous requests which have a lower rate limit and can only see public repositories.
* `insecure`: Allow for self-signed TLS certificates.
* `excludeArchivedRepos`: exclude repositories that are archived. defaults to false
This SCM provider does not yet support label filtering

View file

@ -16441,6 +16441,8 @@ spec:
type: boolean
api:
type: string
excludeArchivedRepos:
type: boolean
insecure:
type: boolean
owner:
@ -16467,6 +16469,8 @@ spec:
type: string
appSecretName:
type: string
excludeArchivedRepos:
type: boolean
organization:
type: string
tokenRef:
@ -16500,6 +16504,8 @@ spec:
type: object
group:
type: string
includeArchivedRepos:
type: boolean
includeSharedProjects:
type: boolean
includeSubgroups:
@ -24093,6 +24099,8 @@ spec:
type: boolean
api:
type: string
excludeArchivedRepos:
type: boolean
insecure:
type: boolean
owner:
@ -24119,6 +24127,8 @@ spec:
type: string
appSecretName:
type: string
excludeArchivedRepos:
type: boolean
organization:
type: string
tokenRef:
@ -24152,6 +24162,8 @@ spec:
type: object
group:
type: string
includeArchivedRepos:
type: boolean
includeSharedProjects:
type: boolean
includeSubgroups:
@ -28130,6 +28142,8 @@ spec:
type: boolean
api:
type: string
excludeArchivedRepos:
type: boolean
insecure:
type: boolean
owner:
@ -28156,6 +28170,8 @@ spec:
type: string
appSecretName:
type: string
excludeArchivedRepos:
type: boolean
organization:
type: string
tokenRef:
@ -28189,6 +28205,8 @@ spec:
type: object
group:
type: string
includeArchivedRepos:
type: boolean
includeSharedProjects:
type: boolean
includeSubgroups:

View file

@ -16441,6 +16441,8 @@ spec:
type: boolean
api:
type: string
excludeArchivedRepos:
type: boolean
insecure:
type: boolean
owner:
@ -16467,6 +16469,8 @@ spec:
type: string
appSecretName:
type: string
excludeArchivedRepos:
type: boolean
organization:
type: string
tokenRef:
@ -16500,6 +16504,8 @@ spec:
type: object
group:
type: string
includeArchivedRepos:
type: boolean
includeSharedProjects:
type: boolean
includeSubgroups:
@ -24093,6 +24099,8 @@ spec:
type: boolean
api:
type: string
excludeArchivedRepos:
type: boolean
insecure:
type: boolean
owner:
@ -24119,6 +24127,8 @@ spec:
type: string
appSecretName:
type: string
excludeArchivedRepos:
type: boolean
organization:
type: string
tokenRef:
@ -24152,6 +24162,8 @@ spec:
type: object
group:
type: string
includeArchivedRepos:
type: boolean
includeSharedProjects:
type: boolean
includeSubgroups:
@ -28130,6 +28142,8 @@ spec:
type: boolean
api:
type: string
excludeArchivedRepos:
type: boolean
insecure:
type: boolean
owner:
@ -28156,6 +28170,8 @@ spec:
type: string
appSecretName:
type: string
excludeArchivedRepos:
type: boolean
organization:
type: string
tokenRef:
@ -28189,6 +28205,8 @@ spec:
type: object
group:
type: string
includeArchivedRepos:
type: boolean
includeSharedProjects:
type: boolean
includeSubgroups:

View file

@ -9436,6 +9436,8 @@ spec:
type: boolean
api:
type: string
excludeArchivedRepos:
type: boolean
insecure:
type: boolean
owner:
@ -9462,6 +9464,8 @@ spec:
type: string
appSecretName:
type: string
excludeArchivedRepos:
type: boolean
organization:
type: string
tokenRef:
@ -9495,6 +9499,8 @@ spec:
type: object
group:
type: string
includeArchivedRepos:
type: boolean
includeSharedProjects:
type: boolean
includeSubgroups:
@ -17088,6 +17094,8 @@ spec:
type: boolean
api:
type: string
excludeArchivedRepos:
type: boolean
insecure:
type: boolean
owner:
@ -17114,6 +17122,8 @@ spec:
type: string
appSecretName:
type: string
excludeArchivedRepos:
type: boolean
organization:
type: string
tokenRef:
@ -17147,6 +17157,8 @@ spec:
type: object
group:
type: string
includeArchivedRepos:
type: boolean
includeSharedProjects:
type: boolean
includeSubgroups:
@ -21125,6 +21137,8 @@ spec:
type: boolean
api:
type: string
excludeArchivedRepos:
type: boolean
insecure:
type: boolean
owner:
@ -21151,6 +21165,8 @@ spec:
type: string
appSecretName:
type: string
excludeArchivedRepos:
type: boolean
organization:
type: string
tokenRef:
@ -21184,6 +21200,8 @@ spec:
type: object
group:
type: string
includeArchivedRepos:
type: boolean
includeSharedProjects:
type: boolean
includeSubgroups:

View file

@ -16441,6 +16441,8 @@ spec:
type: boolean
api:
type: string
excludeArchivedRepos:
type: boolean
insecure:
type: boolean
owner:
@ -16467,6 +16469,8 @@ spec:
type: string
appSecretName:
type: string
excludeArchivedRepos:
type: boolean
organization:
type: string
tokenRef:
@ -16500,6 +16504,8 @@ spec:
type: object
group:
type: string
includeArchivedRepos:
type: boolean
includeSharedProjects:
type: boolean
includeSubgroups:
@ -24093,6 +24099,8 @@ spec:
type: boolean
api:
type: string
excludeArchivedRepos:
type: boolean
insecure:
type: boolean
owner:
@ -24119,6 +24127,8 @@ spec:
type: string
appSecretName:
type: string
excludeArchivedRepos:
type: boolean
organization:
type: string
tokenRef:
@ -24152,6 +24162,8 @@ spec:
type: object
group:
type: string
includeArchivedRepos:
type: boolean
includeSharedProjects:
type: boolean
includeSubgroups:
@ -28130,6 +28142,8 @@ spec:
type: boolean
api:
type: string
excludeArchivedRepos:
type: boolean
insecure:
type: boolean
owner:
@ -28156,6 +28170,8 @@ spec:
type: string
appSecretName:
type: string
excludeArchivedRepos:
type: boolean
organization:
type: string
tokenRef:
@ -28189,6 +28205,8 @@ spec:
type: object
group:
type: string
includeArchivedRepos:
type: boolean
includeSharedProjects:
type: boolean
includeSubgroups:

View file

@ -16441,6 +16441,8 @@ spec:
type: boolean
api:
type: string
excludeArchivedRepos:
type: boolean
insecure:
type: boolean
owner:
@ -16467,6 +16469,8 @@ spec:
type: string
appSecretName:
type: string
excludeArchivedRepos:
type: boolean
organization:
type: string
tokenRef:
@ -16500,6 +16504,8 @@ spec:
type: object
group:
type: string
includeArchivedRepos:
type: boolean
includeSharedProjects:
type: boolean
includeSubgroups:
@ -24093,6 +24099,8 @@ spec:
type: boolean
api:
type: string
excludeArchivedRepos:
type: boolean
insecure:
type: boolean
owner:
@ -24119,6 +24127,8 @@ spec:
type: string
appSecretName:
type: string
excludeArchivedRepos:
type: boolean
organization:
type: string
tokenRef:
@ -24152,6 +24162,8 @@ spec:
type: object
group:
type: string
includeArchivedRepos:
type: boolean
includeSharedProjects:
type: boolean
includeSubgroups:
@ -28130,6 +28142,8 @@ spec:
type: boolean
api:
type: string
excludeArchivedRepos:
type: boolean
insecure:
type: boolean
owner:
@ -28156,6 +28170,8 @@ spec:
type: string
appSecretName:
type: string
excludeArchivedRepos:
type: boolean
organization:
type: string
tokenRef:
@ -28189,6 +28205,8 @@ spec:
type: object
group:
type: string
includeArchivedRepos:
type: boolean
includeSharedProjects:
type: boolean
includeSubgroups:

View file

@ -16441,6 +16441,8 @@ spec:
type: boolean
api:
type: string
excludeArchivedRepos:
type: boolean
insecure:
type: boolean
owner:
@ -16467,6 +16469,8 @@ spec:
type: string
appSecretName:
type: string
excludeArchivedRepos:
type: boolean
organization:
type: string
tokenRef:
@ -16500,6 +16504,8 @@ spec:
type: object
group:
type: string
includeArchivedRepos:
type: boolean
includeSharedProjects:
type: boolean
includeSubgroups:
@ -24093,6 +24099,8 @@ spec:
type: boolean
api:
type: string
excludeArchivedRepos:
type: boolean
insecure:
type: boolean
owner:
@ -24119,6 +24127,8 @@ spec:
type: string
appSecretName:
type: string
excludeArchivedRepos:
type: boolean
organization:
type: string
tokenRef:
@ -24152,6 +24162,8 @@ spec:
type: object
group:
type: string
includeArchivedRepos:
type: boolean
includeSharedProjects:
type: boolean
includeSubgroups:
@ -28130,6 +28142,8 @@ spec:
type: boolean
api:
type: string
excludeArchivedRepos:
type: boolean
insecure:
type: boolean
owner:
@ -28156,6 +28170,8 @@ spec:
type: string
appSecretName:
type: string
excludeArchivedRepos:
type: boolean
organization:
type: string
tokenRef:
@ -28189,6 +28205,8 @@ spec:
type: object
group:
type: string
includeArchivedRepos:
type: boolean
includeSharedProjects:
type: boolean
includeSubgroups:

18
manifests/install.yaml generated
View file

@ -16441,6 +16441,8 @@ spec:
type: boolean
api:
type: string
excludeArchivedRepos:
type: boolean
insecure:
type: boolean
owner:
@ -16467,6 +16469,8 @@ spec:
type: string
appSecretName:
type: string
excludeArchivedRepos:
type: boolean
organization:
type: string
tokenRef:
@ -16500,6 +16504,8 @@ spec:
type: object
group:
type: string
includeArchivedRepos:
type: boolean
includeSharedProjects:
type: boolean
includeSubgroups:
@ -24093,6 +24099,8 @@ spec:
type: boolean
api:
type: string
excludeArchivedRepos:
type: boolean
insecure:
type: boolean
owner:
@ -24119,6 +24127,8 @@ spec:
type: string
appSecretName:
type: string
excludeArchivedRepos:
type: boolean
organization:
type: string
tokenRef:
@ -24152,6 +24162,8 @@ spec:
type: object
group:
type: string
includeArchivedRepos:
type: boolean
includeSharedProjects:
type: boolean
includeSubgroups:
@ -28130,6 +28142,8 @@ spec:
type: boolean
api:
type: string
excludeArchivedRepos:
type: boolean
insecure:
type: boolean
owner:
@ -28156,6 +28170,8 @@ spec:
type: string
appSecretName:
type: string
excludeArchivedRepos:
type: boolean
organization:
type: string
tokenRef:
@ -28189,6 +28205,8 @@ spec:
type: object
group:
type: string
includeArchivedRepos:
type: boolean
includeSharedProjects:
type: boolean
includeSubgroups:

View file

@ -484,6 +484,8 @@ type SCMProviderGeneratorGitea struct {
AllBranches bool `json:"allBranches,omitempty" protobuf:"varint,4,opt,name=allBranches"`
// Allow self-signed TLS / Certificates; default: false
Insecure bool `json:"insecure,omitempty" protobuf:"varint,5,opt,name=insecure"`
// Exclude repositories that are archived.
ExcludeArchivedRepos bool `json:"excludeArchivedRepos,omitempty" protobuf:"varint,6,opt,name=excludeArchivedRepos"`
}
// SCMProviderGeneratorGithub defines connection info specific to GitHub.
@ -498,6 +500,8 @@ type SCMProviderGeneratorGithub struct {
AppSecretName string `json:"appSecretName,omitempty" protobuf:"bytes,4,opt,name=appSecretName"`
// Scan all branches instead of just the default branch.
AllBranches bool `json:"allBranches,omitempty" protobuf:"varint,5,opt,name=allBranches"`
// Exclude repositories that are archived.
ExcludeArchivedRepos bool `json:"excludeArchivedRepos,omitempty" protobuf:"varint,6,opt,name=excludeArchivedRepos"`
}
// SCMProviderGeneratorGitlab defines connection info specific to Gitlab.
@ -520,6 +524,8 @@ type SCMProviderGeneratorGitlab struct {
Topic string `json:"topic,omitempty" protobuf:"bytes,8,opt,name=topic"`
// ConfigMap key holding the trusted certificates
CARef *ConfigMapKeyRef `json:"caRef,omitempty" protobuf:"bytes,9,opt,name=caRef"`
// Include repositories that are archived.
IncludeArchivedRepos bool `json:"includeArchivedRepos,omitempty" protobuf:"varint,10,opt,name=includeArchivedRepos"`
}
func (s *SCMProviderGeneratorGitlab) WillIncludeSharedProjects() bool {

File diff suppressed because it is too large Load diff

View file

@ -2518,6 +2518,9 @@ message SCMProviderGeneratorGitea {
// Allow self-signed TLS / Certificates; default: false
optional bool insecure = 5;
// Exclude repositories that are archived.
optional bool excludeArchivedRepos = 6;
}
// SCMProviderGeneratorGithub defines connection info specific to GitHub.
@ -2536,6 +2539,9 @@ message SCMProviderGeneratorGithub {
// Scan all branches instead of just the default branch.
optional bool allBranches = 5;
// Exclude repositories that are archived.
optional bool excludeArchivedRepos = 6;
}
// SCMProviderGeneratorGitlab defines connection info specific to Gitlab.
@ -2566,6 +2572,9 @@ message SCMProviderGeneratorGitlab {
// ConfigMap key holding the trusted certificates
optional ConfigMapKeyRef caRef = 9;
// Include repositories that are archived.
optional bool includeArchivedRepos = 10;
}
// SecretRef struct for a reference to a secret key.