50 lines
1.5 KiB
Go
50 lines
1.5 KiB
Go
package service
|
|
|
|
import (
|
|
"errors"
|
|
|
|
"github.com/kandev/kandev/internal/worktree"
|
|
)
|
|
|
|
const TaskDeleteDirtyWorktreeErrorCode = "task_delete_dirty_worktree"
|
|
|
|
// TaskDeleteDirtyWorktreeError is returned before task deletion when one or
|
|
// more owned worktrees contain local changes and the caller did not grant
|
|
// discard consent.
|
|
type TaskDeleteDirtyWorktreeError struct {
|
|
DirtyWorktrees []worktree.DirtyWorktree
|
|
}
|
|
|
|
func (e *TaskDeleteDirtyWorktreeError) Error() string {
|
|
return "task worktree contains local changes"
|
|
}
|
|
|
|
func newTaskDeleteDirtyWorktreeError(dirty []worktree.DirtyWorktree) error {
|
|
if len(dirty) == 0 {
|
|
return nil
|
|
}
|
|
copyDirty := make([]worktree.DirtyWorktree, len(dirty))
|
|
copy(copyDirty, dirty)
|
|
for i := range copyDirty {
|
|
copyDirty[i].DirtyFiles = append([]string(nil), copyDirty[i].DirtyFiles...)
|
|
}
|
|
return &TaskDeleteDirtyWorktreeError{DirtyWorktrees: copyDirty}
|
|
}
|
|
|
|
func isDirtyWorktreeCleanupError(err error) bool {
|
|
// A dirty refusal is terminal only when it is the sole cleanup failure.
|
|
// Joined errors can also contain retryable environment or remote cleanup
|
|
// failures that must keep their retry schedule.
|
|
if err == nil {
|
|
return false
|
|
}
|
|
if joined, ok := err.(interface{ Unwrap() []error }); ok {
|
|
causes := joined.Unwrap()
|
|
return len(causes) == 1 && isDirtyWorktreeCleanupError(causes[0])
|
|
}
|
|
if wrapped, ok := err.(interface{ Unwrap() error }); ok {
|
|
return isDirtyWorktreeCleanupError(wrapped.Unwrap())
|
|
}
|
|
return errors.Is(err, worktree.ErrDirtyWorktreeCleanup)
|
|
}
|