configstore: implement projectgroup delete
This commit is contained in:
parent
5c15eb4db7
commit
d551dcb820
|
@ -291,7 +291,7 @@ func (h *ActionHandler) DeleteProject(ctx context.Context, projectRef string) er
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(sgotti) delete project secrets/variables
|
// TODO(sgotti) implement childs garbage collection
|
||||||
actions := []*datamanager.Action{
|
actions := []*datamanager.Action{
|
||||||
{
|
{
|
||||||
ActionType: datamanager.ActionTypeDelete,
|
ActionType: datamanager.ActionTypeDelete,
|
||||||
|
|
|
@ -147,3 +147,47 @@ func (h *ActionHandler) CreateProjectGroup(ctx context.Context, projectGroup *ty
|
||||||
_, err = h.dm.WriteWal(ctx, actions, cgt)
|
_, err = h.dm.WriteWal(ctx, actions, cgt)
|
||||||
return projectGroup, err
|
return projectGroup, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *ActionHandler) DeleteProjectGroup(ctx context.Context, projectGroupRef string) error {
|
||||||
|
var projectGroup *types.ProjectGroup
|
||||||
|
|
||||||
|
var cgt *datamanager.ChangeGroupsUpdateToken
|
||||||
|
|
||||||
|
// must do all the checks in a single transaction to avoid concurrent changes
|
||||||
|
err := h.readDB.Do(func(tx *db.Tx) error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// check project group existance
|
||||||
|
projectGroup, err = h.readDB.GetProjectGroup(tx, projectGroupRef)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if projectGroup == nil {
|
||||||
|
return util.NewErrBadRequest(errors.Errorf("project group %q doesn't exist", projectGroupRef))
|
||||||
|
}
|
||||||
|
|
||||||
|
// changegroup is the project group id.
|
||||||
|
cgNames := []string{util.EncodeSha256Hex(projectGroup.ID)}
|
||||||
|
cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(sgotti) implement childs garbage collection
|
||||||
|
actions := []*datamanager.Action{
|
||||||
|
{
|
||||||
|
ActionType: datamanager.ActionTypeDelete,
|
||||||
|
DataType: string(types.ConfigTypeProjectGroup),
|
||||||
|
ID: projectGroup.ID,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = h.dm.WriteWal(ctx, actions, cgt)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
|
@ -135,6 +135,10 @@ func (c *Client) CreateProjectGroup(ctx context.Context, projectGroup *types.Pro
|
||||||
return resProjectGroup, resp, err
|
return resProjectGroup, resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) DeleteProjectGroup(ctx context.Context, projectGroupRef string) (*http.Response, error) {
|
||||||
|
return c.getResponse(ctx, "DELETE", fmt.Sprintf("/projectgroups/%s", url.PathEscape(projectGroupRef)), nil, jsonContent, nil)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Client) GetProject(ctx context.Context, projectRef string) (*Project, *http.Response, error) {
|
func (c *Client) GetProject(ctx context.Context, projectRef string) (*Project, *http.Response, error) {
|
||||||
project := new(Project)
|
project := new(Project)
|
||||||
resp, err := c.getParsedResponse(ctx, "GET", fmt.Sprintf("/projects/%s", url.PathEscape(projectRef)), nil, jsonContent, nil, project)
|
resp, err := c.getParsedResponse(ctx, "GET", fmt.Sprintf("/projects/%s", url.PathEscape(projectRef)), nil, jsonContent, nil, project)
|
||||||
|
|
|
@ -243,3 +243,31 @@ func (h *CreateProjectGroupHandler) ServeHTTP(w http.ResponseWriter, r *http.Req
|
||||||
h.log.Errorf("err: %+v", err)
|
h.log.Errorf("err: %+v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DeleteProjectGroupHandler struct {
|
||||||
|
log *zap.SugaredLogger
|
||||||
|
ah *action.ActionHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDeleteProjectGroupHandler(logger *zap.Logger, ah *action.ActionHandler) *DeleteProjectGroupHandler {
|
||||||
|
return &DeleteProjectGroupHandler{log: logger.Sugar(), ah: ah}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *DeleteProjectGroupHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ctx := r.Context()
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
projectGroupRef, err := url.PathUnescape(vars["projectgroupref"])
|
||||||
|
if err != nil {
|
||||||
|
httpError(w, util.NewErrBadRequest(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = h.ah.DeleteProjectGroup(ctx, projectGroupRef)
|
||||||
|
if httpError(w, err) {
|
||||||
|
h.log.Errorf("err: %+v", err)
|
||||||
|
}
|
||||||
|
if err := httpResponse(w, http.StatusNoContent, nil); err != nil {
|
||||||
|
h.log.Errorf("err: %+v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -129,6 +129,7 @@ func (s *Configstore) Run(ctx context.Context) error {
|
||||||
projectGroupSubgroupsHandler := api.NewProjectGroupSubgroupsHandler(logger, s.ah, s.readDB)
|
projectGroupSubgroupsHandler := api.NewProjectGroupSubgroupsHandler(logger, s.ah, s.readDB)
|
||||||
projectGroupProjectsHandler := api.NewProjectGroupProjectsHandler(logger, s.ah, s.readDB)
|
projectGroupProjectsHandler := api.NewProjectGroupProjectsHandler(logger, s.ah, s.readDB)
|
||||||
createProjectGroupHandler := api.NewCreateProjectGroupHandler(logger, s.ah, s.readDB)
|
createProjectGroupHandler := api.NewCreateProjectGroupHandler(logger, s.ah, s.readDB)
|
||||||
|
deleteProjectGroupHandler := api.NewDeleteProjectGroupHandler(logger, s.ah)
|
||||||
|
|
||||||
projectHandler := api.NewProjectHandler(logger, s.readDB)
|
projectHandler := api.NewProjectHandler(logger, s.readDB)
|
||||||
createProjectHandler := api.NewCreateProjectHandler(logger, s.ah, s.readDB)
|
createProjectHandler := api.NewCreateProjectHandler(logger, s.ah, s.readDB)
|
||||||
|
@ -178,6 +179,7 @@ func (s *Configstore) Run(ctx context.Context) error {
|
||||||
apirouter.Handle("/projectgroups/{projectgroupref}/subgroups", projectGroupSubgroupsHandler).Methods("GET")
|
apirouter.Handle("/projectgroups/{projectgroupref}/subgroups", projectGroupSubgroupsHandler).Methods("GET")
|
||||||
apirouter.Handle("/projectgroups/{projectgroupref}/projects", projectGroupProjectsHandler).Methods("GET")
|
apirouter.Handle("/projectgroups/{projectgroupref}/projects", projectGroupProjectsHandler).Methods("GET")
|
||||||
apirouter.Handle("/projectgroups", createProjectGroupHandler).Methods("POST")
|
apirouter.Handle("/projectgroups", createProjectGroupHandler).Methods("POST")
|
||||||
|
apirouter.Handle("/projectgroups/{projectgroupref}", deleteProjectGroupHandler).Methods("DELETE")
|
||||||
|
|
||||||
apirouter.Handle("/projects/{projectref}", projectHandler).Methods("GET")
|
apirouter.Handle("/projects/{projectref}", projectHandler).Methods("GET")
|
||||||
apirouter.Handle("/projects", createProjectHandler).Methods("POST")
|
apirouter.Handle("/projects", createProjectHandler).Methods("POST")
|
||||||
|
|
|
@ -507,6 +507,147 @@ func TestProjectGroupsAndProjects(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestProjectGroupDelete(t *testing.T) {
|
||||||
|
dir, err := ioutil.TempDir("", "agola")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected err: %v", err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
cs, tetcd := setupConfigstore(t, ctx, dir)
|
||||||
|
defer shutdownEtcd(tetcd)
|
||||||
|
|
||||||
|
t.Logf("starting cs")
|
||||||
|
go func() {
|
||||||
|
if err := cs.Run(ctx); err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// TODO(sgotti) change the sleep with a real check that all is ready
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
|
||||||
|
//user, err := cs.ah.CreateUser(ctx, &action.CreateUserRequest{UserName: "user01"})
|
||||||
|
//if err != nil {
|
||||||
|
// t.Fatalf("unexpected err: %v", err)
|
||||||
|
//}
|
||||||
|
org, err := cs.ah.CreateOrg(ctx, &types.Organization{Name: "org01"})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected err: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(sgotti) change the sleep with a real check that user is in readdb
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
|
||||||
|
// create a projectgroup in org root project group
|
||||||
|
pg01, err := cs.ah.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)
|
||||||
|
}
|
||||||
|
|
||||||
|
//create a child projectgroup in org root project group
|
||||||
|
spg01, err := cs.ah.CreateProjectGroup(ctx, &types.ProjectGroup{Name: "subprojectgroup01", Parent: types.Parent{Type: types.ConfigTypeProjectGroup, ID: pg01.ID}, Visibility: types.VisibilityPublic})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected err: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a project inside child projectgroup
|
||||||
|
project, err := cs.ah.CreateProject(ctx, &types.Project{Name: "project01", Parent: types.Parent{Type: types.ConfigTypeProjectGroup, ID: spg01.ID}, Visibility: types.VisibilityPublic, RemoteRepositoryConfigType: types.RemoteRepositoryConfigTypeManual})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected err: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// create project secret
|
||||||
|
_, err = cs.ah.CreateSecret(ctx, &types.Secret{Name: "secret01", Parent: types.Parent{Type: types.ConfigTypeProject, ID: project.ID}, Type: types.SecretTypeInternal, Data: map[string]string{"secret01": "secretvar01"}})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected err: %v", err)
|
||||||
|
}
|
||||||
|
// create project variable
|
||||||
|
_, err = cs.ah.CreateVariable(ctx, &types.Variable{Name: "variable01", Parent: types.Parent{Type: types.ConfigTypeProject, ID: project.ID}, Values: []types.VariableValue{{SecretName: "secret01", SecretVar: "secretvar01"}}})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected err: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete root projectgroup
|
||||||
|
if err = cs.ah.DeleteProjectGroup(ctx, pg01.ID); err != nil {
|
||||||
|
t.Fatalf("unexpected err: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// recreate the same hierarchj using the paths
|
||||||
|
pg01, err = cs.ah.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)
|
||||||
|
}
|
||||||
|
spg01, err = cs.ah.CreateProjectGroup(ctx, &types.ProjectGroup{Name: "subprojectgroup01", Parent: types.Parent{Type: types.ConfigTypeProjectGroup, ID: path.Join("org", org.Name, pg01.Name)}, Visibility: types.VisibilityPublic})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected err: %v", err)
|
||||||
|
}
|
||||||
|
project, err = cs.ah.CreateProject(ctx, &types.Project{Name: "project01", Parent: types.Parent{Type: types.ConfigTypeProjectGroup, ID: path.Join("org", org.Name, pg01.Name, spg01.Name)}, Visibility: types.VisibilityPublic, RemoteRepositoryConfigType: types.RemoteRepositoryConfigTypeManual})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected err: %v", err)
|
||||||
|
}
|
||||||
|
secret, err := cs.ah.CreateSecret(ctx, &types.Secret{Name: "secret01", Parent: types.Parent{Type: types.ConfigTypeProject, ID: path.Join("org", org.Name, pg01.Name, spg01.Name, project.Name)}, Type: types.SecretTypeInternal, Data: map[string]string{"secret01": "secretvar01"}})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected err: %v", err)
|
||||||
|
}
|
||||||
|
variable, err := cs.ah.CreateVariable(ctx, &types.Variable{Name: "variable01", Parent: types.Parent{Type: types.ConfigTypeProject, ID: path.Join("org", org.Name, pg01.Name, spg01.Name, project.Name)}, Values: []types.VariableValue{{SecretName: "secret01", SecretVar: "secretvar01"}}})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected err: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get by projectgroup id
|
||||||
|
projects, err := cs.ah.GetProjectGroupProjects(ctx, spg01.ID)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected err: %v", err)
|
||||||
|
}
|
||||||
|
if diff := cmp.Diff(projects, []*types.Project{project}); diff != "" {
|
||||||
|
t.Error(diff)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get by projectgroup path
|
||||||
|
projects, err = cs.ah.GetProjectGroupProjects(ctx, path.Join("org", org.Name, pg01.Name, spg01.Name))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected err: %v", err)
|
||||||
|
}
|
||||||
|
if diff := cmp.Diff(projects, []*types.Project{project}); diff != "" {
|
||||||
|
t.Error(diff)
|
||||||
|
}
|
||||||
|
|
||||||
|
secrets, err := cs.ah.GetSecrets(ctx, types.ConfigTypeProject, project.ID, false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected err: %v", err)
|
||||||
|
}
|
||||||
|
if diff := cmp.Diff(secrets, []*types.Secret{secret}); diff != "" {
|
||||||
|
t.Error(diff)
|
||||||
|
}
|
||||||
|
|
||||||
|
secrets, err = cs.ah.GetSecrets(ctx, types.ConfigTypeProject, path.Join("org", org.Name, pg01.Name, spg01.Name, project.Name), false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected err: %v", err)
|
||||||
|
}
|
||||||
|
if diff := cmp.Diff(secrets, []*types.Secret{secret}); diff != "" {
|
||||||
|
t.Error(diff)
|
||||||
|
}
|
||||||
|
|
||||||
|
variables, err := cs.ah.GetVariables(ctx, types.ConfigTypeProject, project.ID, false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected err: %v", err)
|
||||||
|
}
|
||||||
|
if diff := cmp.Diff(variables, []*types.Variable{variable}); diff != "" {
|
||||||
|
t.Error(diff)
|
||||||
|
}
|
||||||
|
|
||||||
|
variables, err = cs.ah.GetVariables(ctx, types.ConfigTypeProject, path.Join("org", org.Name, pg01.Name, spg01.Name, project.Name), false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected err: %v", err)
|
||||||
|
}
|
||||||
|
if diff := cmp.Diff(variables, []*types.Variable{variable}); diff != "" {
|
||||||
|
t.Error(diff)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestOrgMembers(t *testing.T) {
|
func TestOrgMembers(t *testing.T) {
|
||||||
dir, err := ioutil.TempDir("", "agola")
|
dir, err := ioutil.TempDir("", "agola")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
Loading…
Reference in New Issue