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
|
||||
}
|
||||
|
||||
// TODO(sgotti) delete project secrets/variables
|
||||
// TODO(sgotti) implement childs garbage collection
|
||||
actions := []*datamanager.Action{
|
||||
{
|
||||
ActionType: datamanager.ActionTypeDelete,
|
||||
|
|
|
@ -147,3 +147,47 @@ func (h *ActionHandler) CreateProjectGroup(ctx context.Context, projectGroup *ty
|
|||
_, err = h.dm.WriteWal(ctx, actions, cgt)
|
||||
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
|
||||
}
|
||||
|
||||
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) {
|
||||
project := new(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)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
projectGroupProjectsHandler := api.NewProjectGroupProjectsHandler(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)
|
||||
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}/projects", projectGroupProjectsHandler).Methods("GET")
|
||||
apirouter.Handle("/projectgroups", createProjectGroupHandler).Methods("POST")
|
||||
apirouter.Handle("/projectgroups/{projectgroupref}", deleteProjectGroupHandler).Methods("DELETE")
|
||||
|
||||
apirouter.Handle("/projects/{projectref}", projectHandler).Methods("GET")
|
||||
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) {
|
||||
dir, err := ioutil.TempDir("", "agola")
|
||||
if err != nil {
|
||||
|
|
Loading…
Reference in New Issue