From fabdbaaf9242909c1528607a1aa97ebfda85a5f6 Mon Sep 17 00:00:00 2001 From: Viktor Nagy Date: Fri, 28 Jun 2024 17:24:08 +0200 Subject: [PATCH] Introduce visibility flag for bootstrap gitlab Signed-off-by: Viktor Nagy --- cmd/flux/bootstrap_gitlab.go | 29 ++++++++--- internal/flags/gitlab_visibility.go | 66 ++++++++++++++++++++++++ internal/flags/gitlab_visibility_test.go | 47 +++++++++++++++++ pkg/bootstrap/bootstrap_provider.go | 6 +++ 4 files changed, 140 insertions(+), 8 deletions(-) create mode 100644 internal/flags/gitlab_visibility.go create mode 100644 internal/flags/gitlab_visibility_test.go diff --git a/cmd/flux/bootstrap_gitlab.go b/cmd/flux/bootstrap_gitlab.go index 15716623dc..11919e2d3e 100644 --- a/cmd/flux/bootstrap_gitlab.go +++ b/cmd/flux/bootstrap_gitlab.go @@ -24,6 +24,7 @@ import ( "strings" "time" + "github.com/fluxcd/go-git-providers/gitprovider" "github.com/fluxcd/pkg/git" "github.com/fluxcd/pkg/git/gogit" "github.com/spf13/cobra" @@ -58,14 +59,14 @@ the bootstrap command will perform an upgrade if needed.`, # Run bootstrap for a repository path flux bootstrap gitlab --owner= --repository= --path=dev-cluster - # Run bootstrap for a public repository on a personal account - flux bootstrap gitlab --owner= --repository= --private=false --personal --token-auth + # Run bootstrap for a public repository + flux bootstrap gitlab --owner= --repository= --visibility=public --token-auth # Run bootstrap for a private repository hosted on a GitLab server - flux bootstrap gitlab --owner= --repository= --hostname= --token-auth + flux bootstrap gitlab --owner= --repository= --hostname= --token-auth # Run bootstrap for an existing repository with a branch named main - flux bootstrap gitlab --owner= --repository= --branch=main --token-auth + flux bootstrap gitlab --owner= --repository= --branch=main --token-auth # Run bootstrap for a private repository using Deploy Token authentication flux bootstrap gitlab --owner= --repository= --deploy-token-auth @@ -85,6 +86,7 @@ type gitlabFlags struct { repository string interval time.Duration personal bool + visibility flags.GitLabVisibility private bool hostname string path flags.SafeRelativePath @@ -94,7 +96,13 @@ type gitlabFlags struct { deployTokenAuth bool } -var gitlabArgs gitlabFlags +func NewGitlabFlags() gitlabFlags { + return gitlabFlags{ + visibility: flags.GitLabVisibility(gitprovider.RepositoryVisibilityPrivate), + } +} + +var gitlabArgs = NewGitlabFlags() func init() { bootstrapGitLabCmd.Flags().StringVar(&gitlabArgs.owner, "owner", "", "GitLab user or group name") @@ -102,6 +110,8 @@ func init() { bootstrapGitLabCmd.Flags().StringSliceVar(&gitlabArgs.teams, "team", []string{}, "GitLab teams to be given maintainer access (also accepts comma-separated values)") bootstrapGitLabCmd.Flags().BoolVar(&gitlabArgs.personal, "personal", false, "if true, the owner is assumed to be a GitLab user; otherwise a group") bootstrapGitLabCmd.Flags().BoolVar(&gitlabArgs.private, "private", true, "if true, the repository is setup or configured as private") + bootstrapGitLabCmd.Flags().MarkDeprecated("private", "use --visibility instead") + bootstrapGitLabCmd.Flags().Var(&gitlabArgs.visibility, "visibility", gitlabArgs.visibility.Description()) bootstrapGitLabCmd.Flags().DurationVar(&gitlabArgs.interval, "interval", time.Minute, "sync interval") bootstrapGitLabCmd.Flags().StringVar(&gitlabArgs.hostname, "hostname", glDefaultDomain, "GitLab hostname") bootstrapGitLabCmd.Flags().Var(&gitlabArgs.path, "path", "path relative to the repository root, when specified the cluster sync will be scoped to this path") @@ -133,6 +143,11 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error { return fmt.Errorf("--token-auth and --deploy-token-auth cannot be set both.") } + if !gitlabArgs.private { + gitlabArgs.visibility.Set(string(gitprovider.RepositoryVisibilityPublic)) + cmd.Println("Using visibility public as --private=false") + } + if err := bootstrapValidate(); err != nil { return err } @@ -282,6 +297,7 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error { // Bootstrap config bootstrapOpts := []bootstrap.GitProviderOption{ bootstrap.WithProviderRepository(gitlabArgs.owner, gitlabArgs.repository, gitlabArgs.personal), + bootstrap.WithProviderVisibility(gitlabArgs.visibility.String()), bootstrap.WithBranch(bootstrapArgs.branch), bootstrap.WithBootstrapTransportType("https"), bootstrap.WithSignature(bootstrapArgs.authorName, bootstrapArgs.authorEmail), @@ -301,9 +317,6 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error { if gitlabArgs.deployTokenAuth { bootstrapOpts = append(bootstrapOpts, bootstrap.WithDeployTokenAuth()) } - if !gitlabArgs.private { - bootstrapOpts = append(bootstrapOpts, bootstrap.WithProviderRepositoryConfig("", "", "public")) - } if gitlabArgs.reconcile { bootstrapOpts = append(bootstrapOpts, bootstrap.WithReconcile()) } diff --git a/internal/flags/gitlab_visibility.go b/internal/flags/gitlab_visibility.go new file mode 100644 index 0000000000..924dd898d1 --- /dev/null +++ b/internal/flags/gitlab_visibility.go @@ -0,0 +1,66 @@ +/* +Copyright 2024 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package flags + +import ( + "fmt" + "strings" + + "github.com/fluxcd/go-git-providers/gitprovider" + "github.com/fluxcd/go-git-providers/validation" +) + +var supportedGitLabVisibilities = map[gitprovider.RepositoryVisibility]struct{}{ + gitprovider.RepositoryVisibilityPublic: {}, + gitprovider.RepositoryVisibilityInternal: {}, + gitprovider.RepositoryVisibilityPrivate: {}, +} + +// ValidateRepositoryVisibility validates a given RepositoryVisibility. +func ValidateRepositoryVisibility(r gitprovider.RepositoryVisibility) error { + _, ok := supportedGitLabVisibilities[r] + if !ok { + return validation.ErrFieldEnumInvalid + } + return nil +} + +type GitLabVisibility gitprovider.RepositoryVisibility + +func (d *GitLabVisibility) String() string { + return string(*d) +} + +func (d *GitLabVisibility) Set(str string) error { + if strings.TrimSpace(str) == "" { + str = string(gitprovider.RepositoryVisibilityPrivate) + } + var visibility = gitprovider.RepositoryVisibility(str) + if ValidateRepositoryVisibility(visibility) != nil { + return fmt.Errorf("unsupported visibility '%s'", str) + } + *d = GitLabVisibility(visibility) + return nil +} + +func (d *GitLabVisibility) Type() string { + return "gitLabVisibility" +} + +func (d *GitLabVisibility) Description() string { + return fmt.Sprintf("specifies the visibility of the repository. Valid values are public, private, internal") +} diff --git a/internal/flags/gitlab_visibility_test.go b/internal/flags/gitlab_visibility_test.go new file mode 100644 index 0000000000..bf360f6747 --- /dev/null +++ b/internal/flags/gitlab_visibility_test.go @@ -0,0 +1,47 @@ +/* +Copyright 2024 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package flags + +import ( + "testing" +) + +func TestGitLabVisibility_Set(t *testing.T) { + tests := []struct { + name string + str string + expect string + expectErr bool + }{ + {"private", "private", "private", false}, + {"internal", "internal", "internal", false}, + {"public", "public", "public", false}, + {"unsupported", "unsupported", "", true}, + {"default", "", "private", false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var p GitLabVisibility + if err := p.Set(tt.str); (err != nil) != tt.expectErr { + t.Errorf("Set() error = %v, expectErr %v", err, tt.expectErr) + } + if str := p.String(); str != tt.expect { + t.Errorf("Set() = %v, expect %v", str, tt.expect) + } + }) + } +} diff --git a/pkg/bootstrap/bootstrap_provider.go b/pkg/bootstrap/bootstrap_provider.go index 265ab0c1be..d0bf592e1c 100644 --- a/pkg/bootstrap/bootstrap_provider.go +++ b/pkg/bootstrap/bootstrap_provider.go @@ -94,6 +94,12 @@ func WithProviderRepository(owner, repositoryName string, personal bool) GitProv } } +func WithProviderVisibility(visibility string) GitProviderOption { + return providerRepositoryConfigOption{ + visibility: visibility, + } +} + type providerRepositoryOption struct { owner string repositoryName string