chore(repo): reinitialize repository
This commit is contained in:
@@ -0,0 +1,152 @@
|
||||
package workspaceprovision
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"inbox/internal/app/workspaceruntime"
|
||||
"inbox/internal/base/slug"
|
||||
"inbox/internal/domain/workspace"
|
||||
)
|
||||
|
||||
type store interface {
|
||||
GetProject(context.Context, string) (workspace.Project, error)
|
||||
GetProjectByRootPath(context.Context, string) (workspace.Project, error)
|
||||
GetProjectBySlug(context.Context, string) (workspace.Project, error)
|
||||
CreateProject(context.Context, workspace.Project) (workspace.Project, error)
|
||||
UpdateProjectDefaultBranch(context.Context, string, string) error
|
||||
GetWorkspace(context.Context, string) (workspace.Workspace, error)
|
||||
GetWorkspaceByProjectAndSlug(context.Context, string, string) (workspace.Workspace, error)
|
||||
CreateWorkspace(context.Context, workspace.Workspace) (workspace.Workspace, error)
|
||||
UpdateWorkspace(context.Context, workspace.Workspace) error
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
store store
|
||||
workspacesDir string
|
||||
runtime runtimeManager
|
||||
}
|
||||
|
||||
type ProvisionRequest struct {
|
||||
ProjectDir string
|
||||
Name string
|
||||
}
|
||||
|
||||
type runtimeManager interface {
|
||||
EnsureRepository(ctx context.Context, projectDir string) (string, error)
|
||||
Ensure(ctx context.Context, workspaceID string) (workspace.Workspace, workspaceruntime.Runtime, error)
|
||||
}
|
||||
|
||||
func NewService(store store, workspacesDir string, runtime runtimeManager) *Service {
|
||||
return &Service{
|
||||
store: store,
|
||||
workspacesDir: strings.TrimSpace(workspacesDir),
|
||||
runtime: runtime,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) Provision(ctx context.Context, req ProvisionRequest) (workspace.Workspace, workspaceruntime.Runtime, error) {
|
||||
if s.runtime == nil {
|
||||
return workspace.Workspace{}, workspaceruntime.Runtime{}, fmt.Errorf("workspace runtime is not configured")
|
||||
}
|
||||
projectDir, err := filepath.Abs(strings.TrimSpace(req.ProjectDir))
|
||||
if err != nil {
|
||||
return workspace.Workspace{}, workspaceruntime.Runtime{}, fmt.Errorf("resolve project dir: %w", err)
|
||||
}
|
||||
info, err := os.Stat(projectDir)
|
||||
if err != nil {
|
||||
return workspace.Workspace{}, workspaceruntime.Runtime{}, fmt.Errorf("stat project dir: %w", err)
|
||||
}
|
||||
if !info.IsDir() {
|
||||
return workspace.Workspace{}, workspaceruntime.Runtime{}, fmt.Errorf("project dir is not a directory: %s", projectDir)
|
||||
}
|
||||
|
||||
projectName := filepath.Base(projectDir)
|
||||
projectSlug := slug.Normalize(projectName)
|
||||
if projectSlug == "" {
|
||||
projectSlug = "project"
|
||||
}
|
||||
workspaceSlug := slug.Normalize(firstNonEmpty(req.Name, projectName))
|
||||
if workspaceSlug == "" {
|
||||
workspaceSlug = projectSlug
|
||||
}
|
||||
|
||||
baseBranch, err := s.runtime.EnsureRepository(ctx, projectDir)
|
||||
if err != nil {
|
||||
return workspace.Workspace{}, workspaceruntime.Runtime{}, err
|
||||
}
|
||||
|
||||
project, err := s.ensureProject(ctx, projectDir, projectName, projectSlug, baseBranch)
|
||||
if err != nil {
|
||||
return workspace.Workspace{}, workspaceruntime.Runtime{}, err
|
||||
}
|
||||
|
||||
ws, err := s.store.GetWorkspaceByProjectAndSlug(ctx, project.ID, workspaceSlug)
|
||||
if err != nil {
|
||||
if !errors.Is(err, sql.ErrNoRows) {
|
||||
return workspace.Workspace{}, workspaceruntime.Runtime{}, err
|
||||
}
|
||||
ws = workspace.NormalizeWorkspaceForCreate(workspace.Workspace{
|
||||
ProjectID: project.ID,
|
||||
Slug: workspaceSlug,
|
||||
Name: workspaceSlug,
|
||||
RootPath: filepath.Join(s.workspacesDir, workspaceSlug),
|
||||
BaseBranch: baseBranch,
|
||||
})
|
||||
ws, err = s.store.CreateWorkspace(ctx, ws)
|
||||
if err != nil {
|
||||
return workspace.Workspace{}, workspaceruntime.Runtime{}, err
|
||||
}
|
||||
}
|
||||
|
||||
ws = workspace.ApplyManagedRuntimeConfig(ws, s.workspacesDir, baseBranch)
|
||||
if err := s.store.UpdateWorkspace(ctx, ws); err != nil {
|
||||
return workspace.Workspace{}, workspaceruntime.Runtime{}, err
|
||||
}
|
||||
return s.runtime.Ensure(ctx, ws.ID)
|
||||
}
|
||||
|
||||
func (s *Service) ensureProject(ctx context.Context, projectDir, projectName, projectSlug, baseBranch string) (workspace.Project, error) {
|
||||
project, err := s.store.GetProjectByRootPath(ctx, projectDir)
|
||||
if err != nil {
|
||||
if !errors.Is(err, sql.ErrNoRows) {
|
||||
return workspace.Project{}, err
|
||||
}
|
||||
project = workspace.NormalizeProjectForCreate(workspace.Project{
|
||||
Slug: projectSlug,
|
||||
Name: projectName,
|
||||
RootPath: projectDir,
|
||||
DefaultBranch: baseBranch,
|
||||
})
|
||||
created, createErr := s.store.CreateProject(ctx, project)
|
||||
if createErr == nil {
|
||||
return created, nil
|
||||
}
|
||||
if existing, lookupErr := s.store.GetProjectBySlug(ctx, projectSlug); lookupErr == nil && existing.RootPath == projectDir {
|
||||
project = existing
|
||||
} else {
|
||||
return workspace.Project{}, createErr
|
||||
}
|
||||
}
|
||||
if project.DefaultBranch != baseBranch {
|
||||
if err := s.store.UpdateProjectDefaultBranch(ctx, project.ID, baseBranch); err != nil {
|
||||
return workspace.Project{}, err
|
||||
}
|
||||
project.DefaultBranch = baseBranch
|
||||
}
|
||||
return project, nil
|
||||
}
|
||||
|
||||
func firstNonEmpty(values ...string) string {
|
||||
for _, value := range values {
|
||||
if strings.TrimSpace(value) != "" {
|
||||
return value
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
Reference in New Issue
Block a user