Merge pull request #121 from sgotti/configstore_project_move
configstore: implement project move
This commit is contained in:
commit
52fa406eea
|
@ -64,6 +64,24 @@ func (h *ActionHandler) ValidateProject(ctx context.Context, project *types.Proj
|
|||
return nil
|
||||
}
|
||||
|
||||
func (h *ActionHandler) GetProject(ctx context.Context, projectRef string) (*types.Project, error) {
|
||||
var project *types.Project
|
||||
err := h.readDB.Do(ctx, func(tx *db.Tx) error {
|
||||
var err error
|
||||
project, err = h.readDB.GetProject(tx, projectRef)
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if project == nil {
|
||||
return nil, util.NewErrNotFound(errors.Errorf("project %q doesn't exist", projectRef))
|
||||
}
|
||||
|
||||
return project, nil
|
||||
}
|
||||
|
||||
func (h *ActionHandler) CreateProject(ctx context.Context, project *types.Project) (*types.Project, error) {
|
||||
if err := h.ValidateProject(ctx, project); err != nil {
|
||||
return nil, err
|
||||
|
@ -190,12 +208,7 @@ func (h *ActionHandler) UpdateProject(ctx context.Context, req *UpdateProjectReq
|
|||
if group == nil {
|
||||
return util.NewErrBadRequest(errors.Errorf("project group with id %q doesn't exist", req.Project.Parent.ID))
|
||||
}
|
||||
|
||||
// currently we don't support changing parent
|
||||
// TODO(sgotti) handle project move (changed parent project group)
|
||||
if p.Parent.ID != req.Project.Parent.ID {
|
||||
return util.NewErrBadRequest(errors.Errorf("changing project parent isn't supported"))
|
||||
}
|
||||
req.Project.Parent.ID = group.ID
|
||||
|
||||
groupPath, err := h.readDB.GetProjectGroupPath(tx, group)
|
||||
if err != nil {
|
||||
|
@ -203,7 +216,7 @@ func (h *ActionHandler) UpdateProject(ctx context.Context, req *UpdateProjectReq
|
|||
}
|
||||
pp := path.Join(groupPath, req.Project.Name)
|
||||
|
||||
if p.Name != req.Project.Name {
|
||||
if p.Name != req.Project.Name || p.Parent.ID != req.Project.Parent.ID {
|
||||
// check duplicate project name
|
||||
ap, err := h.readDB.GetProjectByName(tx, req.Project.Parent.ID, req.Project.Name)
|
||||
if err != nil {
|
||||
|
@ -217,6 +230,26 @@ func (h *ActionHandler) UpdateProject(ctx context.Context, req *UpdateProjectReq
|
|||
// changegroup is the project path. Use "projectpath" prefix as it must
|
||||
// cover both projects and projectgroups
|
||||
cgNames := []string{util.EncodeSha256Hex("projectpath-" + pp)}
|
||||
|
||||
// add new projectpath
|
||||
if p.Parent.ID != req.Project.Parent.ID {
|
||||
// get old parent project group
|
||||
curGroup, err := h.readDB.GetProjectGroup(tx, p.Parent.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if curGroup == nil {
|
||||
return util.NewErrBadRequest(errors.Errorf("project group with id %q doesn't exist", p.Parent.ID))
|
||||
}
|
||||
curGroupPath, err := h.readDB.GetProjectGroupPath(tx, curGroup)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pp := path.Join(curGroupPath, req.Project.Name)
|
||||
|
||||
cgNames = append(cgNames, util.EncodeSha256Hex("projectpath-"+pp))
|
||||
}
|
||||
|
||||
cgt, err = h.readDB.GetChangeGroupsUpdateTokens(tx, cgNames)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -30,7 +30,6 @@ import (
|
|||
|
||||
"github.com/gorilla/mux"
|
||||
"go.uber.org/zap"
|
||||
errors "golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
func projectResponse(ctx context.Context, readDB *readdb.ReadDB, project *types.Project) (*csapitypes.Project, error) {
|
||||
|
@ -114,11 +113,12 @@ func getGlobalVisibility(readDB *readdb.ReadDB, tx *db.Tx, curVisibility types.V
|
|||
|
||||
type ProjectHandler struct {
|
||||
log *zap.SugaredLogger
|
||||
ah *action.ActionHandler
|
||||
readDB *readdb.ReadDB
|
||||
}
|
||||
|
||||
func NewProjectHandler(logger *zap.Logger, readDB *readdb.ReadDB) *ProjectHandler {
|
||||
return &ProjectHandler{log: logger.Sugar(), readDB: readDB}
|
||||
func NewProjectHandler(logger *zap.Logger, ah *action.ActionHandler, readDB *readdb.ReadDB) *ProjectHandler {
|
||||
return &ProjectHandler{log: logger.Sugar(), ah: ah, readDB: readDB}
|
||||
}
|
||||
|
||||
func (h *ProjectHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -130,20 +130,9 @@ func (h *ProjectHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
var project *types.Project
|
||||
err = h.readDB.Do(ctx, func(tx *db.Tx) error {
|
||||
var err error
|
||||
project, err = h.readDB.GetProject(tx, projectRef)
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
project, err := h.ah.GetProject(ctx, projectRef)
|
||||
if httpError(w, err) {
|
||||
h.log.Errorf("err: %+v", err)
|
||||
httpError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
if project == nil {
|
||||
httpError(w, util.NewErrNotFound(errors.Errorf("project %q doesn't exist", projectRef)))
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -184,7 +184,7 @@ func (s *Configstore) setupDefaultRouter() http.Handler {
|
|||
updateProjectGroupHandler := api.NewUpdateProjectGroupHandler(logger, s.ah, s.readDB)
|
||||
deleteProjectGroupHandler := api.NewDeleteProjectGroupHandler(logger, s.ah)
|
||||
|
||||
projectHandler := api.NewProjectHandler(logger, s.readDB)
|
||||
projectHandler := api.NewProjectHandler(logger, s.ah, s.readDB)
|
||||
createProjectHandler := api.NewCreateProjectHandler(logger, s.ah, s.readDB)
|
||||
updateProjectHandler := api.NewUpdateProjectHandler(logger, s.ah, s.readDB)
|
||||
deleteProjectHandler := api.NewDeleteProjectHandler(logger, s.ah)
|
||||
|
|
|
@ -57,7 +57,7 @@ func shutdownEtcd(tetcd *testutil.TestEmbeddedEtcd) {
|
|||
}
|
||||
}
|
||||
|
||||
func setupConfigstore(t *testing.T, ctx context.Context, dir string) (*Configstore, *testutil.TestEmbeddedEtcd) {
|
||||
func setupConfigstore(ctx context.Context, t *testing.T, dir string) (*Configstore, *testutil.TestEmbeddedEtcd) {
|
||||
etcdDir, err := ioutil.TempDir(dir, "etcd")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected err: %v", err)
|
||||
|
@ -550,7 +550,7 @@ func TestUser(t *testing.T) {
|
|||
|
||||
ctx := context.Background()
|
||||
|
||||
cs, tetcd := setupConfigstore(t, ctx, dir)
|
||||
cs, tetcd := setupConfigstore(ctx, t, dir)
|
||||
defer shutdownEtcd(tetcd)
|
||||
|
||||
t.Logf("starting cs")
|
||||
|
@ -608,7 +608,7 @@ func TestUser(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestProjectGroupsAndProjects(t *testing.T) {
|
||||
func TestProjectGroupsAndProjectsCreate(t *testing.T) {
|
||||
dir, err := ioutil.TempDir("", "agola")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected err: %v", err)
|
||||
|
@ -617,7 +617,7 @@ func TestProjectGroupsAndProjects(t *testing.T) {
|
|||
|
||||
ctx := context.Background()
|
||||
|
||||
cs, tetcd := setupConfigstore(t, ctx, dir)
|
||||
cs, tetcd := setupConfigstore(ctx,t, dir)
|
||||
defer shutdownEtcd(tetcd)
|
||||
|
||||
t.Logf("starting cs")
|
||||
|
@ -755,6 +755,82 @@ func TestProjectGroupsAndProjects(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestProjectUpdate(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(ctx,t, dir)
|
||||
defer shutdownEtcd(tetcd)
|
||||
|
||||
t.Logf("starting cs")
|
||||
go func() {
|
||||
_ = cs.Run(ctx)
|
||||
}()
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// TODO(sgotti) change the sleep with a real check that user is in readdb
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
_, err = cs.ah.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)
|
||||
}
|
||||
p01 := &types.Project{Name: "project01", Parent: types.Parent{Type: types.ConfigTypeProjectGroup, ID: path.Join("user", user.Name)}, Visibility: types.VisibilityPublic, RemoteRepositoryConfigType: types.RemoteRepositoryConfigTypeManual}
|
||||
_, err = cs.ah.CreateProject(ctx, p01)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected err: %v", err)
|
||||
}
|
||||
p02 := &types.Project{Name: "project01", Parent: types.Parent{Type: types.ConfigTypeProjectGroup, ID: path.Join("user", user.Name, "projectgroup01")}, Visibility: types.VisibilityPublic, RemoteRepositoryConfigType: types.RemoteRepositoryConfigTypeManual}
|
||||
_, err = cs.ah.CreateProject(ctx, p02)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected err: %v", err)
|
||||
}
|
||||
p03 := &types.Project{Name: "project02", Parent: types.Parent{Type: types.ConfigTypeProjectGroup, ID: path.Join("user", user.Name, "projectgroup01")}, Visibility: types.VisibilityPublic, RemoteRepositoryConfigType: types.RemoteRepositoryConfigTypeManual}
|
||||
_, err = cs.ah.CreateProject(ctx, p03)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected err: %v", err)
|
||||
}
|
||||
|
||||
t.Run("rename project keeping same parent", func(t *testing.T) {
|
||||
projectName := "project02"
|
||||
p03.Name = "newproject02"
|
||||
_, err := cs.ah.UpdateProject(ctx, &action.UpdateProjectRequest{ProjectRef: path.Join("user", user.Name, "projectgroup01", projectName), Project: p03})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected err: %v", err)
|
||||
}
|
||||
})
|
||||
t.Run("move project to project group having project with same name", func(t *testing.T) {
|
||||
projectName := "project01"
|
||||
expectedErr := fmt.Sprintf("project with name %q, path %q already exists", projectName, path.Join("user", user.Name, projectName))
|
||||
p02.Parent.ID = path.Join("user", user.Name)
|
||||
_, err := cs.ah.UpdateProject(ctx, &action.UpdateProjectRequest{ProjectRef: path.Join("user", user.Name, "projectgroup01", projectName), Project: p02})
|
||||
if err.Error() != expectedErr {
|
||||
t.Fatalf("expected err %v, got err: %v", expectedErr, err)
|
||||
}
|
||||
})
|
||||
t.Run("move project to project group changing name", func(t *testing.T) {
|
||||
projectName := "project01"
|
||||
p02.Name = "newproject01"
|
||||
p02.Parent.ID = path.Join("user", user.Name)
|
||||
_, err := cs.ah.UpdateProject(ctx, &action.UpdateProjectRequest{ProjectRef: path.Join("user", user.Name, "projectgroup01", projectName), Project: p02})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected err: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestProjectGroupDelete(t *testing.T) {
|
||||
dir, err := ioutil.TempDir("", "agola")
|
||||
if err != nil {
|
||||
|
@ -764,7 +840,7 @@ func TestProjectGroupDelete(t *testing.T) {
|
|||
|
||||
ctx := context.Background()
|
||||
|
||||
cs, tetcd := setupConfigstore(t, ctx, dir)
|
||||
cs, tetcd := setupConfigstore(ctx,t, dir)
|
||||
defer shutdownEtcd(tetcd)
|
||||
|
||||
t.Logf("starting cs")
|
||||
|
@ -903,7 +979,7 @@ func TestOrgMembers(t *testing.T) {
|
|||
|
||||
ctx := context.Background()
|
||||
|
||||
cs, tetcd := setupConfigstore(t, ctx, dir)
|
||||
cs, tetcd := setupConfigstore(ctx,t, dir)
|
||||
defer shutdownEtcd(tetcd)
|
||||
|
||||
t.Logf("starting cs")
|
||||
|
@ -1139,7 +1215,7 @@ func TestRemoteSource(t *testing.T) {
|
|||
}
|
||||
ctx := context.Background()
|
||||
|
||||
cs, tetcd := setupConfigstore(t, ctx, dir)
|
||||
cs, tetcd := setupConfigstore(ctx,t, dir)
|
||||
defer shutdownEtcd(tetcd)
|
||||
|
||||
t.Logf("starting cs")
|
||||
|
|
Loading…
Reference in New Issue