From 68e6bd5bdfd9b69df27d9cc9b5a4dc0b835830b9 Mon Sep 17 00:00:00 2001 From: Simone Gotti Date: Tue, 30 Apr 2019 17:09:26 +0200 Subject: [PATCH] configstore: add project/projectgroup visibility --- cmd/agola/cmd/projectcreate.go | 9 ++++ cmd/agola/cmd/projectgroupcreate.go | 13 +++++- internal/services/configstore/api/project.go | 42 ++++++++++++++++--- .../services/configstore/api/projectgroup.go | 20 ++++++--- .../services/configstore/command/command.go | 6 +++ .../services/configstore/configstore_test.go | 26 ++++++------ internal/services/gateway/api/project.go | 31 ++++++++------ internal/services/gateway/api/projectgroup.go | 25 ++++++----- internal/services/gateway/command/project.go | 2 + .../services/gateway/command/projectgroup.go | 2 + internal/services/types/types.go | 21 ++++++++++ 11 files changed, 149 insertions(+), 48 deletions(-) diff --git a/cmd/agola/cmd/projectcreate.go b/cmd/agola/cmd/projectcreate.go index 70d8f1b..4012c2d 100644 --- a/cmd/agola/cmd/projectcreate.go +++ b/cmd/agola/cmd/projectcreate.go @@ -19,6 +19,7 @@ import ( "github.com/pkg/errors" "github.com/sorintlab/agola/internal/services/gateway/api" + "github.com/sorintlab/agola/internal/services/types" "github.com/spf13/cobra" ) @@ -39,6 +40,7 @@ type projectCreateOptions struct { repoPath string remoteSourceName string skipSSHHostKeyCheck bool + visibility string } var projectCreateOpts projectCreateOptions @@ -51,6 +53,7 @@ func init() { flags.StringVar(&projectCreateOpts.remoteSourceName, "remote-source", "", "remote source name") flags.BoolVarP(&projectCreateOpts.skipSSHHostKeyCheck, "skip-ssh-host-key-check", "s", false, "skip ssh host key check") flags.StringVar(&projectCreateOpts.parentPath, "parent", "", `parent project group path (i.e "org/org01" for root project group in org01, "user/user01/group01/subgroub01") or project group id where the project should be created`) + flags.StringVar(&projectCreateOpts.visibility, "visibility", "public", `project visibility (public or private)`) cmdProjectCreate.MarkFlagRequired("name") cmdProjectCreate.MarkFlagRequired("parent") @@ -63,9 +66,15 @@ func init() { func projectCreate(cmd *cobra.Command, args []string) error { gwclient := api.NewClient(gatewayURL, token) + // TODO(sgotti) make this a custom pflag Value? + if !types.IsValidVisibility(types.Visibility(projectCreateOpts.visibility)) { + return errors.Errorf("invalid visibility %q", projectCreateOpts.visibility) + } + req := &api.CreateProjectRequest{ Name: projectCreateOpts.name, ParentID: projectCreateOpts.parentPath, + Visibility: types.Visibility(projectCreateOpts.visibility), RepoPath: projectCreateOpts.repoPath, RemoteSourceName: projectCreateOpts.remoteSourceName, SkipSSHHostKeyCheck: projectCreateOpts.skipSSHHostKeyCheck, diff --git a/cmd/agola/cmd/projectgroupcreate.go b/cmd/agola/cmd/projectgroupcreate.go index 27ad939..2e5cc1d 100644 --- a/cmd/agola/cmd/projectgroupcreate.go +++ b/cmd/agola/cmd/projectgroupcreate.go @@ -19,6 +19,7 @@ import ( "github.com/pkg/errors" "github.com/sorintlab/agola/internal/services/gateway/api" + "github.com/sorintlab/agola/internal/services/types" "github.com/spf13/cobra" ) @@ -36,6 +37,7 @@ var cmdProjectGroupCreate = &cobra.Command{ type projectGroupCreateOptions struct { name string parentPath string + visibility string } var projectGroupCreateOpts projectGroupCreateOptions @@ -45,6 +47,7 @@ func init() { flags.StringVarP(&projectGroupCreateOpts.name, "name", "n", "", "project group name") flags.StringVar(&projectGroupCreateOpts.parentPath, "parent", "", `parent project group path (i.e "org/org01" for root project group in org01, "user/user01/group01/subgroub01") or project group id where the project group should be created`) + flags.StringVar(&projectGroupCreateOpts.visibility, "visibility", "public", `project group visibility (public or private)`) cmdProjectGroupCreate.MarkFlagRequired("name") cmdProjectGroupCreate.MarkFlagRequired("parent") @@ -55,9 +58,15 @@ func init() { func projectGroupCreate(cmd *cobra.Command, args []string) error { gwclient := api.NewClient(gatewayURL, token) + // TODO(sgotti) make this a custom pflag Value? + if !types.IsValidVisibility(types.Visibility(projectCreateOpts.visibility)) { + return errors.Errorf("invalid visibility %q", projectCreateOpts.visibility) + } + req := &api.CreateProjectGroupRequest{ - Name: projectGroupCreateOpts.name, - ParentID: projectGroupCreateOpts.parentPath, + Name: projectGroupCreateOpts.name, + ParentID: projectGroupCreateOpts.parentPath, + Visibility: types.Visibility(projectCreateOpts.visibility), } log.Infof("creating project group") diff --git a/internal/services/configstore/api/project.go b/internal/services/configstore/api/project.go index 3a4a42c..7646a18 100644 --- a/internal/services/configstore/api/project.go +++ b/internal/services/configstore/api/project.go @@ -37,8 +37,9 @@ type Project struct { *types.Project // dynamic data - Path string - ParentPath string + Path string + ParentPath string + GlobalVisibility types.Visibility } func projectResponse(readDB *readdb.ReadDB, project *types.Project) (*Project, error) { @@ -58,20 +59,51 @@ func projectsResponse(readDB *readdb.ReadDB, projects []*types.Project) ([]*Proj if err != nil { return err } + + // calculate global visibility + visibility, err := getGlobalVisibility(readDB, tx, project.Visibility, &project.Parent) + if err != nil { + return err + } + // we calculate the path here from parent path since the db could not yet be // updated on create resProjects[i] = &Project{ - Project: project, - Path: path.Join(pp, project.Name), - ParentPath: pp, + Project: project, + Path: path.Join(pp, project.Name), + ParentPath: pp, + GlobalVisibility: visibility, } } + return nil }) return resProjects, err } +func getGlobalVisibility(readDB *readdb.ReadDB, tx *db.Tx, curVisibility types.Visibility, parent *types.Parent) (types.Visibility, error) { + curParent := parent + if curVisibility == types.VisibilityPrivate { + return curVisibility, nil + } + + for curParent.Type == types.ConfigTypeProjectGroup { + projectGroup, err := readDB.GetProjectGroupByID(tx, curParent.ID) + if err != nil { + return "", err + } + if projectGroup.Visibility == types.VisibilityPrivate { + curVisibility = types.VisibilityPrivate + continue + } + + curParent = &projectGroup.Parent + } + + return curVisibility, nil +} + type ProjectHandler struct { log *zap.SugaredLogger readDB *readdb.ReadDB diff --git a/internal/services/configstore/api/projectgroup.go b/internal/services/configstore/api/projectgroup.go index 124e976..a6a45e5 100644 --- a/internal/services/configstore/api/projectgroup.go +++ b/internal/services/configstore/api/projectgroup.go @@ -36,8 +36,9 @@ type ProjectGroup struct { *types.ProjectGroup // dynamic data - Path string - ParentPath string + Path string + ParentPath string + GlobalVisibility types.Visibility } func projectGroupResponse(readDB *readdb.ReadDB, projectGroup *types.ProjectGroup) (*ProjectGroup, error) { @@ -57,13 +58,22 @@ func projectGroupsResponse(readDB *readdb.ReadDB, projectGroups []*types.Project if err != nil { return err } + + // calculate global visibility + visibility, err := getGlobalVisibility(readDB, tx, projectGroup.Visibility, &projectGroup.Parent) + if err != nil { + return err + } + // we calculate the path here from parent path since the db could not yet be // updated on create resProjectGroups[i] = &ProjectGroup{ - ProjectGroup: projectGroup, - Path: path.Join(pp, projectGroup.Name), - ParentPath: pp, + ProjectGroup: projectGroup, + Path: path.Join(pp, projectGroup.Name), + ParentPath: pp, + GlobalVisibility: visibility, } + } return nil }) diff --git a/internal/services/configstore/command/command.go b/internal/services/configstore/command/command.go index 286864e..2b92db9 100644 --- a/internal/services/configstore/command/command.go +++ b/internal/services/configstore/command/command.go @@ -52,6 +52,9 @@ func (s *CommandHandler) CreateProjectGroup(ctx context.Context, projectGroup *t if projectGroup.Parent.ID == "" { return nil, util.NewErrBadRequest(errors.Errorf("project group parent id required")) } + if !types.IsValidVisibility(projectGroup.Visibility) { + return nil, util.NewErrBadRequest(errors.Errorf("invalid project group visibility")) + } var cgt *datamanager.ChangeGroupsUpdateToken @@ -129,6 +132,9 @@ func (s *CommandHandler) CreateProject(ctx context.Context, project *types.Proje if project.Parent.ID == "" { return nil, util.NewErrBadRequest(errors.Errorf("project parent id required")) } + if !types.IsValidVisibility(project.Visibility) { + return nil, util.NewErrBadRequest(errors.Errorf("invalid project visibility")) + } var cgt *datamanager.ChangeGroupsUpdateToken diff --git a/internal/services/configstore/configstore_test.go b/internal/services/configstore/configstore_test.go index 88d9caa..ae11c92 100644 --- a/internal/services/configstore/configstore_test.go +++ b/internal/services/configstore/configstore_test.go @@ -394,37 +394,37 @@ func TestProjectGroupsAndProjects(t *testing.T) { time.Sleep(2 * time.Second) t.Run("create a project in user root project group", func(t *testing.T) { - _, err := cs.ch.CreateProject(ctx, &types.Project{Name: "project01", Parent: types.Parent{Type: types.ConfigTypeProjectGroup, ID: path.Join("user", user.Name)}}) + _, err := cs.ch.CreateProject(ctx, &types.Project{Name: "project01", Parent: types.Parent{Type: types.ConfigTypeProjectGroup, ID: path.Join("user", user.Name)}, Visibility: types.VisibilityPublic}) if err != nil { t.Fatalf("unexpected err: %v", err) } }) t.Run("create a project in org root project group", func(t *testing.T) { - _, err := cs.ch.CreateProject(ctx, &types.Project{Name: "project01", Parent: types.Parent{Type: types.ConfigTypeProjectGroup, ID: path.Join("org", org.Name)}}) + _, err := cs.ch.CreateProject(ctx, &types.Project{Name: "project01", Parent: types.Parent{Type: types.ConfigTypeProjectGroup, ID: path.Join("org", org.Name)}, Visibility: types.VisibilityPublic}) if err != nil { t.Fatalf("unexpected err: %v", err) } }) t.Run("create a projectgroup in user root project group", func(t *testing.T) { - _, err := cs.ch.CreateProjectGroup(ctx, &types.ProjectGroup{Name: "projectgroup01", Parent: types.Parent{Type: types.ConfigTypeProjectGroup, ID: path.Join("user", user.Name)}}) + _, err := cs.ch.CreateProjectGroup(ctx, &types.ProjectGroup{Name: "projectgroup01", Parent: types.Parent{Type: types.ConfigTypeProjectGroup, ID: path.Join("user", user.Name)}, Visibility: types.VisibilityPublic}) if err != nil { t.Fatalf("unexpected err: %v", err) } }) t.Run("create a projectgroup in org root project group", func(t *testing.T) { - _, err := cs.ch.CreateProjectGroup(ctx, &types.ProjectGroup{Name: "projectgroup01", Parent: types.Parent{Type: types.ConfigTypeProjectGroup, ID: path.Join("org", org.Name)}}) + _, err := cs.ch.CreateProjectGroup(ctx, &types.ProjectGroup{Name: "projectgroup01", Parent: types.Parent{Type: types.ConfigTypeProjectGroup, ID: path.Join("org", org.Name)}, Visibility: types.VisibilityPublic}) if err != nil { t.Fatalf("unexpected err: %v", err) } }) t.Run("create a project in user non root project group with same name as a root project", func(t *testing.T) { - _, err := cs.ch.CreateProject(ctx, &types.Project{Name: "project01", Parent: types.Parent{Type: types.ConfigTypeProjectGroup, ID: path.Join("user", user.Name, "projectgroup01")}}) + _, err := cs.ch.CreateProject(ctx, &types.Project{Name: "project01", Parent: types.Parent{Type: types.ConfigTypeProjectGroup, ID: path.Join("user", user.Name, "projectgroup01")}, Visibility: types.VisibilityPublic}) if err != nil { t.Fatalf("unexpected err: %+#v", err) } }) t.Run("create a project in org non root project group with same name as a root project", func(t *testing.T) { - _, err := cs.ch.CreateProject(ctx, &types.Project{Name: "project01", Parent: types.Parent{Type: types.ConfigTypeProjectGroup, ID: path.Join("org", org.Name, "projectgroup01")}}) + _, err := cs.ch.CreateProject(ctx, &types.Project{Name: "project01", Parent: types.Parent{Type: types.ConfigTypeProjectGroup, ID: path.Join("org", org.Name, "projectgroup01")}, Visibility: types.VisibilityPublic}) if err != nil { t.Fatalf("unexpected err: %v", err) } @@ -433,7 +433,7 @@ func TestProjectGroupsAndProjects(t *testing.T) { t.Run("create duplicated project in user root project group", func(t *testing.T) { projectName := "project01" expectedErr := fmt.Sprintf("project with name %q, path %q already exists", projectName, path.Join("user", user.Name, projectName)) - _, err := cs.ch.CreateProject(ctx, &types.Project{Name: projectName, Parent: types.Parent{Type: types.ConfigTypeProjectGroup, ID: path.Join("user", user.Name)}}) + _, err := cs.ch.CreateProject(ctx, &types.Project{Name: projectName, Parent: types.Parent{Type: types.ConfigTypeProjectGroup, ID: path.Join("user", user.Name)}, Visibility: types.VisibilityPublic}) if err.Error() != expectedErr { t.Fatalf("expected err %v, got err: %v", expectedErr, err) } @@ -441,7 +441,7 @@ func TestProjectGroupsAndProjects(t *testing.T) { t.Run("create duplicated project in org root project group", func(t *testing.T) { projectName := "project01" expectedErr := fmt.Sprintf("project with name %q, path %q already exists", projectName, path.Join("org", org.Name, projectName)) - _, err := cs.ch.CreateProject(ctx, &types.Project{Name: projectName, Parent: types.Parent{Type: types.ConfigTypeProjectGroup, ID: path.Join("org", org.Name)}}) + _, err := cs.ch.CreateProject(ctx, &types.Project{Name: projectName, Parent: types.Parent{Type: types.ConfigTypeProjectGroup, ID: path.Join("org", org.Name)}, Visibility: types.VisibilityPublic}) if err.Error() != expectedErr { t.Fatalf("expected err %v, got err: %v", expectedErr, err) } @@ -450,7 +450,7 @@ func TestProjectGroupsAndProjects(t *testing.T) { t.Run("create duplicated project in user non root project group", func(t *testing.T) { projectName := "project01" expectedErr := fmt.Sprintf("project with name %q, path %q already exists", projectName, path.Join("user", user.Name, "projectgroup01", projectName)) - _, err := cs.ch.CreateProject(ctx, &types.Project{Name: projectName, Parent: types.Parent{Type: types.ConfigTypeProjectGroup, ID: path.Join("user", user.Name, "projectgroup01")}}) + _, err := cs.ch.CreateProject(ctx, &types.Project{Name: projectName, Parent: types.Parent{Type: types.ConfigTypeProjectGroup, ID: path.Join("user", user.Name, "projectgroup01")}, Visibility: types.VisibilityPublic}) if err.Error() != expectedErr { t.Fatalf("expected err %v, got err: %v", expectedErr, err) } @@ -458,7 +458,7 @@ func TestProjectGroupsAndProjects(t *testing.T) { t.Run("create duplicated project in org non root project group", func(t *testing.T) { projectName := "project01" expectedErr := fmt.Sprintf("project with name %q, path %q already exists", projectName, path.Join("org", org.Name, "projectgroup01", projectName)) - _, err := cs.ch.CreateProject(ctx, &types.Project{Name: projectName, Parent: types.Parent{Type: types.ConfigTypeProjectGroup, ID: path.Join("org", org.Name, "projectgroup01")}}) + _, err := cs.ch.CreateProject(ctx, &types.Project{Name: projectName, Parent: types.Parent{Type: types.ConfigTypeProjectGroup, ID: path.Join("org", org.Name, "projectgroup01")}, Visibility: types.VisibilityPublic}) if err.Error() != expectedErr { t.Fatalf("expected err %v, got err: %v", expectedErr, err) } @@ -466,14 +466,14 @@ func TestProjectGroupsAndProjects(t *testing.T) { t.Run("create project in unexistent project group", func(t *testing.T) { expectedErr := `project group with id "unexistentid" doesn't exist` - _, err := cs.ch.CreateProject(ctx, &types.Project{Name: "project01", Parent: types.Parent{Type: types.ConfigTypeProjectGroup, ID: "unexistentid"}}) + _, err := cs.ch.CreateProject(ctx, &types.Project{Name: "project01", Parent: types.Parent{Type: types.ConfigTypeProjectGroup, ID: "unexistentid"}, Visibility: types.VisibilityPublic}) if err.Error() != expectedErr { t.Fatalf("expected err %v, got err: %v", expectedErr, err) } }) t.Run("create project without parent id specified", func(t *testing.T) { expectedErr := "project parent id required" - _, err := cs.ch.CreateProject(ctx, &types.Project{Name: "project01"}) + _, err := cs.ch.CreateProject(ctx, &types.Project{Name: "project01", Visibility: types.VisibilityPublic}) if err.Error() != expectedErr { t.Fatalf("expected err %v, got err: %v", expectedErr, err) } @@ -488,7 +488,7 @@ func TestProjectGroupsAndProjects(t *testing.T) { wg := sync.WaitGroup{} for i := 0; i < 10; i++ { wg.Add(1) - go cs.ch.CreateProject(ctx, &types.Project{Name: "project02", Parent: types.Parent{Type: types.ConfigTypeProjectGroup, ID: path.Join("user", user.Name)}}) + go cs.ch.CreateProject(ctx, &types.Project{Name: "project02", Parent: types.Parent{Type: types.ConfigTypeProjectGroup, ID: path.Join("user", user.Name)}, Visibility: types.VisibilityPublic}) wg.Done() } wg.Wait() diff --git a/internal/services/gateway/api/project.go b/internal/services/gateway/api/project.go index d3a9fd9..992246a 100644 --- a/internal/services/gateway/api/project.go +++ b/internal/services/gateway/api/project.go @@ -22,6 +22,7 @@ import ( "github.com/pkg/errors" csapi "github.com/sorintlab/agola/internal/services/configstore/api" "github.com/sorintlab/agola/internal/services/gateway/command" + "github.com/sorintlab/agola/internal/services/types" "github.com/sorintlab/agola/internal/util" "github.com/gorilla/mux" @@ -29,11 +30,12 @@ import ( ) type CreateProjectRequest struct { - Name string `json:"name,omitempty"` - ParentID string `json:"parent_id,omitempty"` - RepoPath string `json:"repo_path,omitempty"` - RemoteSourceName string `json:"remote_source_name,omitempty"` - SkipSSHHostKeyCheck bool `json:"skip_ssh_host_key_check,omitempty"` + Name string `json:"name,omitempty"` + ParentID string `json:"parent_id,omitempty"` + Visibility types.Visibility `json:"visibility,omitempty"` + RepoPath string `json:"repo_path,omitempty"` + RemoteSourceName string `json:"remote_source_name,omitempty"` + SkipSSHHostKeyCheck bool `json:"skip_ssh_host_key_check,omitempty"` } type CreateProjectHandler struct { @@ -68,6 +70,7 @@ func (h *CreateProjectHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) creq := &command.CreateProjectRequest{ Name: req.Name, ParentID: req.ParentID, + Visibility: req.Visibility, RepoPath: req.RepoPath, RemoteSourceName: req.RemoteSourceName, CurrentUserID: userID, @@ -181,18 +184,20 @@ func (h *ProjectHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } type ProjectResponse struct { - ID string `json:"id,omitempty"` - Name string `json:"name,omitempty"` - Path string `json:"path,omitempty"` - ParentPath string `json:"parent_path,omitempty"` + ID string `json:"id,omitempty"` + Name string `json:"name,omitempty"` + Path string `json:"path,omitempty"` + ParentPath string `json:"parent_path,omitempty"` + GlobalVisibility string `json:"global_visibility,omitempty"` } func createProjectResponse(r *csapi.Project) *ProjectResponse { res := &ProjectResponse{ - ID: r.ID, - Name: r.Name, - Path: r.Path, - ParentPath: r.ParentPath, + ID: r.ID, + Name: r.Name, + Path: r.Path, + ParentPath: r.ParentPath, + GlobalVisibility: string(r.GlobalVisibility), } return res diff --git a/internal/services/gateway/api/projectgroup.go b/internal/services/gateway/api/projectgroup.go index 63ea46c..1a63fea 100644 --- a/internal/services/gateway/api/projectgroup.go +++ b/internal/services/gateway/api/projectgroup.go @@ -22,6 +22,7 @@ import ( "github.com/pkg/errors" csapi "github.com/sorintlab/agola/internal/services/configstore/api" "github.com/sorintlab/agola/internal/services/gateway/command" + "github.com/sorintlab/agola/internal/services/types" "github.com/sorintlab/agola/internal/util" "github.com/gorilla/mux" @@ -29,8 +30,9 @@ import ( ) type CreateProjectGroupRequest struct { - Name string `json:"name,omitempty"` - ParentID string `json:"parent_id,omitempty"` + Name string `json:"name,omitempty"` + ParentID string `json:"parent_id,omitempty"` + Visibility types.Visibility `json:"visibility,omitempty"` } type CreateProjectGroupHandler struct { @@ -65,6 +67,7 @@ func (h *CreateProjectGroupHandler) ServeHTTP(w http.ResponseWriter, r *http.Req creq := &command.CreateProjectGroupRequest{ Name: req.Name, ParentID: req.ParentID, + Visibility: req.Visibility, CurrentUserID: userID, } @@ -179,18 +182,20 @@ func (h *ProjectGroupSubgroupsHandler) ServeHTTP(w http.ResponseWriter, r *http. } type ProjectGroupResponse struct { - ID string `json:"id,omitempty"` - Name string `json:"name,omitempty"` - Path string `json:"path,omitempty"` - ParentPath string `json:"parent_path,omitempty"` + ID string `json:"id,omitempty"` + Name string `json:"name,omitempty"` + Path string `json:"path,omitempty"` + ParentPath string `json:"parent_path,omitempty"` + GlobalVisibility string `json:"global_visibility,omitempty"` } func createProjectGroupResponse(r *csapi.ProjectGroup) *ProjectGroupResponse { run := &ProjectGroupResponse{ - ID: r.ID, - Name: r.Name, - Path: r.Path, - ParentPath: r.ParentPath, + ID: r.ID, + Name: r.Name, + Path: r.Path, + ParentPath: r.ParentPath, + GlobalVisibility: string(r.GlobalVisibility), } return run diff --git a/internal/services/gateway/command/project.go b/internal/services/gateway/command/project.go index 468a909..19d6b44 100644 --- a/internal/services/gateway/command/project.go +++ b/internal/services/gateway/command/project.go @@ -31,6 +31,7 @@ type CreateProjectRequest struct { CurrentUserID string Name string ParentID string + Visibility types.Visibility RemoteSourceName string RepoPath string SkipSSHHostKeyCheck bool @@ -92,6 +93,7 @@ func (c *CommandHandler) CreateProject(ctx context.Context, req *CreateProjectRe Type: types.ConfigTypeProjectGroup, ID: parentID, }, + Visibility: req.Visibility, LinkedAccountID: la.ID, RepositoryID: repo.ID, RepositoryPath: req.RepoPath, diff --git a/internal/services/gateway/command/projectgroup.go b/internal/services/gateway/command/projectgroup.go index 654c418..3875252 100644 --- a/internal/services/gateway/command/projectgroup.go +++ b/internal/services/gateway/command/projectgroup.go @@ -29,6 +29,7 @@ type CreateProjectGroupRequest struct { CurrentUserID string Name string ParentID string + Visibility types.Visibility } func (c *CommandHandler) CreateProjectGroup(ctx context.Context, req *CreateProjectGroupRequest) (*csapi.ProjectGroup, error) { @@ -53,6 +54,7 @@ func (c *CommandHandler) CreateProjectGroup(ctx context.Context, req *CreateProj Type: types.ConfigTypeProjectGroup, ID: parentID, }, + Visibility: req.Visibility, } c.log.Infof("creating projectGroup") diff --git a/internal/services/types/types.go b/internal/services/types/types.go index b86f7f7..47980a9 100644 --- a/internal/services/types/types.go +++ b/internal/services/types/types.go @@ -33,6 +33,23 @@ const ( ConfigTypeVariable ConfigType = "variable" ) +type Visibility string + +const ( + VisibilityPublic Visibility = "public" + VisibilityPrivate Visibility = "private" +) + +func IsValidVisibility(v Visibility) bool { + switch v { + case VisibilityPublic: + case VisibilityPrivate: + default: + return false + } + return true +} + type Parent struct { Type ConfigType `json:"type,omitempty"` ID string `json:"id,omitempty"` @@ -73,6 +90,8 @@ type ProjectGroup struct { Name string `json:"name,omitempty"` Parent Parent `json:"parent,omitempty"` + + Visibility Visibility `json:"visibility,omitempty"` } type RemoteSourceType string @@ -139,6 +158,8 @@ type Project struct { Parent Parent `json:"parent,omitempty"` + Visibility Visibility `json:"visibility,omitempty"` + // The remote repository id RepositoryID string `json:"repository_id,omitempty"`