Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions pkg/handlers/delete_project.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,14 @@ func (h DeleteProjectHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
return
}

result := <-h.Manager.DeleteProject(r.Context(), projectID)

if result.IsFailure() {
if err := h.Manager.DeleteProject(r.Context(), projectID); err != nil {
var projectNotFoundError *project.ProjectNotFoundError
if errors.As(result.Error, &projectNotFoundError) {
if errors.As(err, &projectNotFoundError) {
http.Error(w, projectNotFoundError.Error(), http.StatusNotFound)
return
}

http.Error(w, fmt.Sprintf("Failed to delete project: %s", result.Error), http.StatusInternalServerError)
http.Error(w, fmt.Sprintf("Failed to delete project: %s", err), http.StatusInternalServerError)
return
}

Expand Down
21 changes: 7 additions & 14 deletions pkg/handlers/delete_project_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,47 +10,40 @@ import (
"github.com/hide-org/hide/pkg/handlers"
"github.com/hide-org/hide/pkg/project"
"github.com/hide-org/hide/pkg/project/mocks"
"github.com/hide-org/hide/pkg/result"
"github.com/stretchr/testify/assert"
)

func TestDeleteProjectHandler_ServeHTTP(t *testing.T) {
tests := []struct {
name string
target string
mockDeleteProjectFunc func(ctx context.Context, projectId string) <-chan result.Empty
mockDeleteProjectFunc func(ctx context.Context, projectId string) error
wantStatusCode int
wantBody string
}{
{
name: "successful deletion",
target: "/projects/123",
mockDeleteProjectFunc: func(ctx context.Context, projectId string) <-chan result.Empty {
ch := make(chan result.Empty, 1)
ch <- result.EmptySuccess()
return ch
mockDeleteProjectFunc: func(ctx context.Context, projectId string) error {
return nil
},
wantStatusCode: http.StatusNoContent,
wantBody: "",
},
{
name: "project not found",
target: "/projects/123",
mockDeleteProjectFunc: func(ctx context.Context, projectId string) <-chan result.Empty {
ch := make(chan result.Empty, 1)
ch <- result.EmptyFailure(project.NewProjectNotFoundError(projectId))
return ch
mockDeleteProjectFunc: func(ctx context.Context, projectId string) error {
return project.NewProjectNotFoundError(projectId)
},
wantStatusCode: http.StatusNotFound,
wantBody: "project 123 not found\n",
},
{
name: "internal server error",
target: "/projects/123",
mockDeleteProjectFunc: func(ctx context.Context, projectId string) <-chan result.Empty {
ch := make(chan result.Empty, 1)
ch <- result.EmptyFailure(errors.New("internal error"))
return ch
mockDeleteProjectFunc: func(ctx context.Context, projectId string) error {
return errors.New("internal error")
},
wantStatusCode: http.StatusInternalServerError,
wantBody: "Failed to delete project: internal error\n",
Expand Down
66 changes: 25 additions & 41 deletions pkg/project/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ type Manager interface {
CreateProject(ctx context.Context, request CreateProjectRequest) <-chan result.Result[model.Project]
CreateTask(ctx context.Context, projectId model.ProjectId, command string) (TaskResult, error)
DeleteFile(ctx context.Context, projectId, path string) error
DeleteProject(ctx context.Context, projectId model.ProjectId) <-chan result.Empty
DeleteProject(ctx context.Context, projectId model.ProjectId) error
GetProject(ctx context.Context, projectId model.ProjectId) (model.Project, error)
GetProjects(ctx context.Context) ([]*model.Project, error)
ListFiles(ctx context.Context, projectId string, opts ...files.ListFileOption) ([]*model.File, error)
Expand Down Expand Up @@ -193,37 +193,33 @@ func (pm ManagerImpl) GetProjects(ctx context.Context) ([]*model.Project, error)
return projects, nil
}

func (pm ManagerImpl) DeleteProject(ctx context.Context, projectId string) <-chan result.Empty {
c := make(chan result.Empty)

go func() {
log.Debug().Msgf("Deleting project %s", projectId)
func (pm ManagerImpl) DeleteProject(ctx context.Context, projectId string) error {
log.Debug().Msgf("Deleting project %s", projectId)

project, err := pm.GetProject(ctx, projectId)
if err != nil {
log.Error().Err(err).Msgf("Failed to get project with id %s", projectId)
c <- result.EmptyFailure(fmt.Errorf("Failed to get project with id %s: %w", projectId, err))
return
}
project, err := pm.GetProject(ctx, projectId)
if err != nil {
log.Error().Err(err).Msgf("Failed to get project with id %s", projectId)
return fmt.Errorf("Failed to get project with id %s: %w", projectId, err)
}

if err := pm.devContainerRunner.Stop(ctx, project.ContainerId); err != nil {
log.Error().Err(err).Msgf("Failed to stop container %s", project.ContainerId)
c <- result.EmptyFailure(fmt.Errorf("Failed to stop container: %w", err))
return
}
if err := pm.devContainerRunner.Stop(ctx, project.ContainerId); err != nil {
log.Error().Err(err).Msgf("Failed to stop container %s", project.ContainerId)
return fmt.Errorf("Failed to stop container: %w", err)
}

if err := pm.store.DeleteProject(projectId); err != nil {
log.Error().Err(err).Msgf("Failed to delete project %s", projectId)
c <- result.EmptyFailure(fmt.Errorf("Failed to delete project: %w", err))
return
}
if err := pm.lspService.CleanupProject(ctx, projectId); err != nil {
log.Error().Err(err).Str("projectId", projectId).Msg("Failed to stop LSP server(s)")
return fmt.Errorf("Failed to stop LSP server(s): %w", err)
}

log.Debug().Msgf("Deleted project %s", projectId)
if err := pm.store.DeleteProject(projectId); err != nil {
log.Error().Err(err).Msgf("Failed to delete project %s", projectId)
return fmt.Errorf("Failed to delete project: %w", err)
}

c <- result.EmptySuccess()
}()
log.Debug().Msgf("Deleted project %s", projectId)

return c
return nil
}

func (pm ManagerImpl) ResolveTaskAlias(ctx context.Context, projectId string, alias string) (devcontainer.Task, error) {
Expand Down Expand Up @@ -282,22 +278,10 @@ func (pm ManagerImpl) Cleanup(ctx context.Context) error {
wg.Add(1)
go func(p *model.Project) {
defer wg.Done()
log.Debug().Msgf("Cleaning up project %s", p.Id)

if err := pm.devContainerRunner.Stop(ctx, p.ContainerId); err != nil {
errChan <- fmt.Errorf("Failed to stop container for project %s: %w", p.Id, err)
return
}

if err := pm.lspService.CleanupProject(ctx, p.Id); err != nil {
errChan <- fmt.Errorf("Failed to cleanup LSP for project %s: %w", p.Id, err)
return
}

if err := pm.store.DeleteProject(p.Id); err != nil {
errChan <- fmt.Errorf("Failed to delete project %s: %w", p.Id, err)
return
if err := pm.DeleteProject(ctx, p.Id); err != nil {
errChan <- err
}
return
}(project)
}

Expand Down
4 changes: 2 additions & 2 deletions pkg/project/mocks/mock_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ type MockProjectManager struct {
CreateProjectFunc func(ctx context.Context, request project.CreateProjectRequest) <-chan result.Result[model.Project]
CreateTaskFunc func(ctx context.Context, projectId string, command string) (project.TaskResult, error)
DeleteFileFunc func(ctx context.Context, projectId, path string) error
DeleteProjectFunc func(ctx context.Context, projectId string) <-chan result.Empty
DeleteProjectFunc func(ctx context.Context, projectId string) error
GetProjectFunc func(ctx context.Context, projectId string) (model.Project, error)
GetProjectsFunc func(ctx context.Context) ([]*model.Project, error)
ListFilesFunc func(ctx context.Context, projectId string, opts ...files.ListFileOption) ([]*model.File, error)
Expand All @@ -42,7 +42,7 @@ func (m *MockProjectManager) GetProjects(ctx context.Context) ([]*model.Project,
return m.GetProjectsFunc(ctx)
}

func (m *MockProjectManager) DeleteProject(ctx context.Context, projectId string) <-chan result.Empty {
func (m *MockProjectManager) DeleteProject(ctx context.Context, projectId string) error {
return m.DeleteProjectFunc(ctx, projectId)
}

Expand Down