configstore: add project/projectgroup visibility

This commit is contained in:
Simone Gotti 2019-04-30 17:09:26 +02:00
parent b1c9892378
commit 68e6bd5bdf
11 changed files with 149 additions and 48 deletions

View File

@ -19,6 +19,7 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sorintlab/agola/internal/services/gateway/api" "github.com/sorintlab/agola/internal/services/gateway/api"
"github.com/sorintlab/agola/internal/services/types"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -39,6 +40,7 @@ type projectCreateOptions struct {
repoPath string repoPath string
remoteSourceName string remoteSourceName string
skipSSHHostKeyCheck bool skipSSHHostKeyCheck bool
visibility string
} }
var projectCreateOpts projectCreateOptions var projectCreateOpts projectCreateOptions
@ -51,6 +53,7 @@ func init() {
flags.StringVar(&projectCreateOpts.remoteSourceName, "remote-source", "", "remote source name") 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.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.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("name")
cmdProjectCreate.MarkFlagRequired("parent") cmdProjectCreate.MarkFlagRequired("parent")
@ -63,9 +66,15 @@ func init() {
func projectCreate(cmd *cobra.Command, args []string) error { func projectCreate(cmd *cobra.Command, args []string) error {
gwclient := api.NewClient(gatewayURL, token) 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{ req := &api.CreateProjectRequest{
Name: projectCreateOpts.name, Name: projectCreateOpts.name,
ParentID: projectCreateOpts.parentPath, ParentID: projectCreateOpts.parentPath,
Visibility: types.Visibility(projectCreateOpts.visibility),
RepoPath: projectCreateOpts.repoPath, RepoPath: projectCreateOpts.repoPath,
RemoteSourceName: projectCreateOpts.remoteSourceName, RemoteSourceName: projectCreateOpts.remoteSourceName,
SkipSSHHostKeyCheck: projectCreateOpts.skipSSHHostKeyCheck, SkipSSHHostKeyCheck: projectCreateOpts.skipSSHHostKeyCheck,

View File

@ -19,6 +19,7 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sorintlab/agola/internal/services/gateway/api" "github.com/sorintlab/agola/internal/services/gateway/api"
"github.com/sorintlab/agola/internal/services/types"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -36,6 +37,7 @@ var cmdProjectGroupCreate = &cobra.Command{
type projectGroupCreateOptions struct { type projectGroupCreateOptions struct {
name string name string
parentPath string parentPath string
visibility string
} }
var projectGroupCreateOpts projectGroupCreateOptions var projectGroupCreateOpts projectGroupCreateOptions
@ -45,6 +47,7 @@ func init() {
flags.StringVarP(&projectGroupCreateOpts.name, "name", "n", "", "project group name") 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.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("name")
cmdProjectGroupCreate.MarkFlagRequired("parent") cmdProjectGroupCreate.MarkFlagRequired("parent")
@ -55,9 +58,15 @@ func init() {
func projectGroupCreate(cmd *cobra.Command, args []string) error { func projectGroupCreate(cmd *cobra.Command, args []string) error {
gwclient := api.NewClient(gatewayURL, token) 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{ req := &api.CreateProjectGroupRequest{
Name: projectGroupCreateOpts.name, Name: projectGroupCreateOpts.name,
ParentID: projectGroupCreateOpts.parentPath, ParentID: projectGroupCreateOpts.parentPath,
Visibility: types.Visibility(projectCreateOpts.visibility),
} }
log.Infof("creating project group") log.Infof("creating project group")

View File

@ -37,8 +37,9 @@ type Project struct {
*types.Project *types.Project
// dynamic data // dynamic data
Path string Path string
ParentPath string ParentPath string
GlobalVisibility types.Visibility
} }
func projectResponse(readDB *readdb.ReadDB, project *types.Project) (*Project, error) { 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 { if err != nil {
return err 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 // we calculate the path here from parent path since the db could not yet be
// updated on create // updated on create
resProjects[i] = &Project{ resProjects[i] = &Project{
Project: project, Project: project,
Path: path.Join(pp, project.Name), Path: path.Join(pp, project.Name),
ParentPath: pp, ParentPath: pp,
GlobalVisibility: visibility,
} }
} }
return nil return nil
}) })
return resProjects, err 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 { type ProjectHandler struct {
log *zap.SugaredLogger log *zap.SugaredLogger
readDB *readdb.ReadDB readDB *readdb.ReadDB

View File

@ -36,8 +36,9 @@ type ProjectGroup struct {
*types.ProjectGroup *types.ProjectGroup
// dynamic data // dynamic data
Path string Path string
ParentPath string ParentPath string
GlobalVisibility types.Visibility
} }
func projectGroupResponse(readDB *readdb.ReadDB, projectGroup *types.ProjectGroup) (*ProjectGroup, error) { 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 { if err != nil {
return err 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 // we calculate the path here from parent path since the db could not yet be
// updated on create // updated on create
resProjectGroups[i] = &ProjectGroup{ resProjectGroups[i] = &ProjectGroup{
ProjectGroup: projectGroup, ProjectGroup: projectGroup,
Path: path.Join(pp, projectGroup.Name), Path: path.Join(pp, projectGroup.Name),
ParentPath: pp, ParentPath: pp,
GlobalVisibility: visibility,
} }
} }
return nil return nil
}) })

View File

@ -52,6 +52,9 @@ func (s *CommandHandler) CreateProjectGroup(ctx context.Context, projectGroup *t
if projectGroup.Parent.ID == "" { if projectGroup.Parent.ID == "" {
return nil, util.NewErrBadRequest(errors.Errorf("project group parent id required")) 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 var cgt *datamanager.ChangeGroupsUpdateToken
@ -129,6 +132,9 @@ func (s *CommandHandler) CreateProject(ctx context.Context, project *types.Proje
if project.Parent.ID == "" { if project.Parent.ID == "" {
return nil, util.NewErrBadRequest(errors.Errorf("project parent id required")) 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 var cgt *datamanager.ChangeGroupsUpdateToken

View File

@ -394,37 +394,37 @@ func TestProjectGroupsAndProjects(t *testing.T) {
time.Sleep(2 * time.Second) time.Sleep(2 * time.Second)
t.Run("create a project in user root project group", func(t *testing.T) { 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 { if err != nil {
t.Fatalf("unexpected err: %v", err) t.Fatalf("unexpected err: %v", err)
} }
}) })
t.Run("create a project in org root project group", func(t *testing.T) { 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 { if err != nil {
t.Fatalf("unexpected err: %v", err) t.Fatalf("unexpected err: %v", err)
} }
}) })
t.Run("create a projectgroup in user root project group", func(t *testing.T) { 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 { if err != nil {
t.Fatalf("unexpected err: %v", err) t.Fatalf("unexpected err: %v", err)
} }
}) })
t.Run("create a projectgroup in org root project group", func(t *testing.T) { 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 { if err != nil {
t.Fatalf("unexpected err: %v", err) 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) { 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 { if err != nil {
t.Fatalf("unexpected err: %+#v", err) 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) { 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 { if err != nil {
t.Fatalf("unexpected err: %v", err) 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) { t.Run("create duplicated project in user root project group", func(t *testing.T) {
projectName := "project01" projectName := "project01"
expectedErr := fmt.Sprintf("project with name %q, path %q already exists", projectName, path.Join("user", user.Name, projectName)) 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 { if err.Error() != expectedErr {
t.Fatalf("expected err %v, got err: %v", expectedErr, err) 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) { t.Run("create duplicated project in org root project group", func(t *testing.T) {
projectName := "project01" projectName := "project01"
expectedErr := fmt.Sprintf("project with name %q, path %q already exists", projectName, path.Join("org", org.Name, projectName)) 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 { if err.Error() != expectedErr {
t.Fatalf("expected err %v, got err: %v", expectedErr, err) 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) { t.Run("create duplicated project in user non root project group", func(t *testing.T) {
projectName := "project01" projectName := "project01"
expectedErr := fmt.Sprintf("project with name %q, path %q already exists", projectName, path.Join("user", user.Name, "projectgroup01", projectName)) 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 { if err.Error() != expectedErr {
t.Fatalf("expected err %v, got err: %v", expectedErr, err) 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) { t.Run("create duplicated project in org non root project group", func(t *testing.T) {
projectName := "project01" projectName := "project01"
expectedErr := fmt.Sprintf("project with name %q, path %q already exists", projectName, path.Join("org", org.Name, "projectgroup01", projectName)) 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 { if err.Error() != expectedErr {
t.Fatalf("expected err %v, got err: %v", expectedErr, err) 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) { t.Run("create project in unexistent project group", func(t *testing.T) {
expectedErr := `project group with id "unexistentid" doesn't exist` 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 { if err.Error() != expectedErr {
t.Fatalf("expected err %v, got err: %v", expectedErr, err) t.Fatalf("expected err %v, got err: %v", expectedErr, err)
} }
}) })
t.Run("create project without parent id specified", func(t *testing.T) { t.Run("create project without parent id specified", func(t *testing.T) {
expectedErr := "project parent id required" 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 { if err.Error() != expectedErr {
t.Fatalf("expected err %v, got err: %v", expectedErr, err) t.Fatalf("expected err %v, got err: %v", expectedErr, err)
} }
@ -488,7 +488,7 @@ func TestProjectGroupsAndProjects(t *testing.T) {
wg := sync.WaitGroup{} wg := sync.WaitGroup{}
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
wg.Add(1) 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.Done()
} }
wg.Wait() wg.Wait()

View File

@ -22,6 +22,7 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
csapi "github.com/sorintlab/agola/internal/services/configstore/api" csapi "github.com/sorintlab/agola/internal/services/configstore/api"
"github.com/sorintlab/agola/internal/services/gateway/command" "github.com/sorintlab/agola/internal/services/gateway/command"
"github.com/sorintlab/agola/internal/services/types"
"github.com/sorintlab/agola/internal/util" "github.com/sorintlab/agola/internal/util"
"github.com/gorilla/mux" "github.com/gorilla/mux"
@ -29,11 +30,12 @@ import (
) )
type CreateProjectRequest struct { type CreateProjectRequest struct {
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
ParentID string `json:"parent_id,omitempty"` ParentID string `json:"parent_id,omitempty"`
RepoPath string `json:"repo_path,omitempty"` Visibility types.Visibility `json:"visibility,omitempty"`
RemoteSourceName string `json:"remote_source_name,omitempty"` RepoPath string `json:"repo_path,omitempty"`
SkipSSHHostKeyCheck bool `json:"skip_ssh_host_key_check,omitempty"` RemoteSourceName string `json:"remote_source_name,omitempty"`
SkipSSHHostKeyCheck bool `json:"skip_ssh_host_key_check,omitempty"`
} }
type CreateProjectHandler struct { type CreateProjectHandler struct {
@ -68,6 +70,7 @@ func (h *CreateProjectHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
creq := &command.CreateProjectRequest{ creq := &command.CreateProjectRequest{
Name: req.Name, Name: req.Name,
ParentID: req.ParentID, ParentID: req.ParentID,
Visibility: req.Visibility,
RepoPath: req.RepoPath, RepoPath: req.RepoPath,
RemoteSourceName: req.RemoteSourceName, RemoteSourceName: req.RemoteSourceName,
CurrentUserID: userID, CurrentUserID: userID,
@ -181,18 +184,20 @@ func (h *ProjectHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
} }
type ProjectResponse struct { type ProjectResponse struct {
ID string `json:"id,omitempty"` ID string `json:"id,omitempty"`
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
Path string `json:"path,omitempty"` Path string `json:"path,omitempty"`
ParentPath string `json:"parent_path,omitempty"` ParentPath string `json:"parent_path,omitempty"`
GlobalVisibility string `json:"global_visibility,omitempty"`
} }
func createProjectResponse(r *csapi.Project) *ProjectResponse { func createProjectResponse(r *csapi.Project) *ProjectResponse {
res := &ProjectResponse{ res := &ProjectResponse{
ID: r.ID, ID: r.ID,
Name: r.Name, Name: r.Name,
Path: r.Path, Path: r.Path,
ParentPath: r.ParentPath, ParentPath: r.ParentPath,
GlobalVisibility: string(r.GlobalVisibility),
} }
return res return res

View File

@ -22,6 +22,7 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
csapi "github.com/sorintlab/agola/internal/services/configstore/api" csapi "github.com/sorintlab/agola/internal/services/configstore/api"
"github.com/sorintlab/agola/internal/services/gateway/command" "github.com/sorintlab/agola/internal/services/gateway/command"
"github.com/sorintlab/agola/internal/services/types"
"github.com/sorintlab/agola/internal/util" "github.com/sorintlab/agola/internal/util"
"github.com/gorilla/mux" "github.com/gorilla/mux"
@ -29,8 +30,9 @@ import (
) )
type CreateProjectGroupRequest struct { type CreateProjectGroupRequest struct {
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
ParentID string `json:"parent_id,omitempty"` ParentID string `json:"parent_id,omitempty"`
Visibility types.Visibility `json:"visibility,omitempty"`
} }
type CreateProjectGroupHandler struct { type CreateProjectGroupHandler struct {
@ -65,6 +67,7 @@ func (h *CreateProjectGroupHandler) ServeHTTP(w http.ResponseWriter, r *http.Req
creq := &command.CreateProjectGroupRequest{ creq := &command.CreateProjectGroupRequest{
Name: req.Name, Name: req.Name,
ParentID: req.ParentID, ParentID: req.ParentID,
Visibility: req.Visibility,
CurrentUserID: userID, CurrentUserID: userID,
} }
@ -179,18 +182,20 @@ func (h *ProjectGroupSubgroupsHandler) ServeHTTP(w http.ResponseWriter, r *http.
} }
type ProjectGroupResponse struct { type ProjectGroupResponse struct {
ID string `json:"id,omitempty"` ID string `json:"id,omitempty"`
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
Path string `json:"path,omitempty"` Path string `json:"path,omitempty"`
ParentPath string `json:"parent_path,omitempty"` ParentPath string `json:"parent_path,omitempty"`
GlobalVisibility string `json:"global_visibility,omitempty"`
} }
func createProjectGroupResponse(r *csapi.ProjectGroup) *ProjectGroupResponse { func createProjectGroupResponse(r *csapi.ProjectGroup) *ProjectGroupResponse {
run := &ProjectGroupResponse{ run := &ProjectGroupResponse{
ID: r.ID, ID: r.ID,
Name: r.Name, Name: r.Name,
Path: r.Path, Path: r.Path,
ParentPath: r.ParentPath, ParentPath: r.ParentPath,
GlobalVisibility: string(r.GlobalVisibility),
} }
return run return run

View File

@ -31,6 +31,7 @@ type CreateProjectRequest struct {
CurrentUserID string CurrentUserID string
Name string Name string
ParentID string ParentID string
Visibility types.Visibility
RemoteSourceName string RemoteSourceName string
RepoPath string RepoPath string
SkipSSHHostKeyCheck bool SkipSSHHostKeyCheck bool
@ -92,6 +93,7 @@ func (c *CommandHandler) CreateProject(ctx context.Context, req *CreateProjectRe
Type: types.ConfigTypeProjectGroup, Type: types.ConfigTypeProjectGroup,
ID: parentID, ID: parentID,
}, },
Visibility: req.Visibility,
LinkedAccountID: la.ID, LinkedAccountID: la.ID,
RepositoryID: repo.ID, RepositoryID: repo.ID,
RepositoryPath: req.RepoPath, RepositoryPath: req.RepoPath,

View File

@ -29,6 +29,7 @@ type CreateProjectGroupRequest struct {
CurrentUserID string CurrentUserID string
Name string Name string
ParentID string ParentID string
Visibility types.Visibility
} }
func (c *CommandHandler) CreateProjectGroup(ctx context.Context, req *CreateProjectGroupRequest) (*csapi.ProjectGroup, error) { 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, Type: types.ConfigTypeProjectGroup,
ID: parentID, ID: parentID,
}, },
Visibility: req.Visibility,
} }
c.log.Infof("creating projectGroup") c.log.Infof("creating projectGroup")

View File

@ -33,6 +33,23 @@ const (
ConfigTypeVariable ConfigType = "variable" 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 Parent struct {
Type ConfigType `json:"type,omitempty"` Type ConfigType `json:"type,omitempty"`
ID string `json:"id,omitempty"` ID string `json:"id,omitempty"`
@ -73,6 +90,8 @@ type ProjectGroup struct {
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
Parent Parent `json:"parent,omitempty"` Parent Parent `json:"parent,omitempty"`
Visibility Visibility `json:"visibility,omitempty"`
} }
type RemoteSourceType string type RemoteSourceType string
@ -139,6 +158,8 @@ type Project struct {
Parent Parent `json:"parent,omitempty"` Parent Parent `json:"parent,omitempty"`
Visibility Visibility `json:"visibility,omitempty"`
// The remote repository id // The remote repository id
RepositoryID string `json:"repository_id,omitempty"` RepositoryID string `json:"repository_id,omitempty"`