feat(jobs/runners): worktree prune two-phase + workspace prune queries/repo methods

This commit is contained in:
2026-05-06 07:55:56 +08:00
parent 0111135e78
commit c50621eeca
8 changed files with 638 additions and 12 deletions
+74 -9
View File
@@ -50,6 +50,12 @@ type Repository interface {
GetWorktreeByID(ctx context.Context, id uuid.UUID) (*Worktree, error)
ListWorktreesByWorkspace(ctx context.Context, wsID uuid.UUID) ([]*Worktree, error)
DeleteWorktree(ctx context.Context, id uuid.UUID) error
ListWorktreesNeedingPruneWarning(ctx context.Context, lastUsedBefore time.Time) ([]*Worktree, error)
ListWorktreesNeedingPrune(ctx context.Context, lastUsedBefore time.Time) ([]*Worktree, error)
MarkPruneWarning(ctx context.Context, id uuid.UUID) error
TryStartPrune(ctx context.Context, id uuid.UUID) (*Worktree, error)
FinishPruneSuccess(ctx context.Context, id uuid.UUID) error
FinishPruneRollback(ctx context.Context, id uuid.UUID) error
// Credential
UpsertCredential(ctx context.Context, c *Credential) (*Credential, error)
@@ -240,15 +246,16 @@ func (r *pgRepo) ResetStuckSyncStatuses(ctx context.Context) error {
func rowToWorktree(r workspacesqlc.WorkspaceWorktree) *Worktree {
return &Worktree{
ID: fromPgUUID(r.ID),
WorkspaceID: fromPgUUID(r.WorkspaceID),
Branch: r.Branch,
Path: r.Path,
Status: WorktreeStatus(r.Status),
ActiveHolder: fromPtrString(r.ActiveHolder),
AcquiredAt: fromPgTimePtr(r.AcquiredAt),
LastUsedAt: r.LastUsedAt.Time,
CreatedAt: r.CreatedAt.Time,
ID: fromPgUUID(r.ID),
WorkspaceID: fromPgUUID(r.WorkspaceID),
Branch: r.Branch,
Path: r.Path,
Status: WorktreeStatus(r.Status),
ActiveHolder: fromPtrString(r.ActiveHolder),
AcquiredAt: fromPgTimePtr(r.AcquiredAt),
LastUsedAt: r.LastUsedAt.Time,
PruneWarningAt: fromPgTimePtr(r.PruneWarningAt),
CreatedAt: r.CreatedAt.Time,
}
}
@@ -283,6 +290,64 @@ func (r *pgRepo) DeleteWorktree(ctx context.Context, id uuid.UUID) error {
return nil
}
func (r *pgRepo) ListWorktreesNeedingPruneWarning(ctx context.Context, lastUsedBefore time.Time) ([]*Worktree, error) {
ts := pgtype.Timestamptz{Time: lastUsedBefore, Valid: true}
rows, err := r.q.ListWorktreesNeedingPruneWarning(ctx, ts)
if err != nil {
return nil, errs.Wrap(err, errs.CodeInternal, "list worktrees needing prune warning")
}
out := make([]*Worktree, 0, len(rows))
for _, row := range rows {
out = append(out, rowToWorktree(row))
}
return out, nil
}
func (r *pgRepo) ListWorktreesNeedingPrune(ctx context.Context, lastUsedBefore time.Time) ([]*Worktree, error) {
ts := pgtype.Timestamptz{Time: lastUsedBefore, Valid: true}
rows, err := r.q.ListWorktreesNeedingPrune(ctx, ts)
if err != nil {
return nil, errs.Wrap(err, errs.CodeInternal, "list worktrees needing prune")
}
out := make([]*Worktree, 0, len(rows))
for _, row := range rows {
out = append(out, rowToWorktree(row))
}
return out, nil
}
func (r *pgRepo) MarkPruneWarning(ctx context.Context, id uuid.UUID) error {
if err := r.q.MarkPruneWarning(ctx, toPgUUID(id)); err != nil {
return errs.Wrap(err, errs.CodeInternal, "mark prune warning")
}
return nil
}
func (r *pgRepo) TryStartPrune(ctx context.Context, id uuid.UUID) (*Worktree, error) {
row, err := r.q.TryStartPrune(ctx, toPgUUID(id))
if errors.Is(err, pgx.ErrNoRows) {
return nil, errs.New(errs.CodeWorktreeAlreadyActive, "worktree no longer idle")
}
if err != nil {
return nil, errs.Wrap(err, errs.CodeInternal, "try start prune")
}
return rowToWorktree(row), nil
}
func (r *pgRepo) FinishPruneSuccess(ctx context.Context, id uuid.UUID) error {
if err := r.q.FinishPruneSuccess(ctx, toPgUUID(id)); err != nil {
return errs.Wrap(err, errs.CodeInternal, "finish prune success")
}
return nil
}
func (r *pgRepo) FinishPruneRollback(ctx context.Context, id uuid.UUID) error {
if err := r.q.FinishPruneRollback(ctx, toPgUUID(id)); err != nil {
return errs.Wrap(err, errs.CodeInternal, "finish prune rollback")
}
return nil
}
// ===== Credential =====
func rowToCredential(r workspacesqlc.GitCredential) *Credential {