feat: command timeouts (#2898)

This commit is contained in:
Valentin Maerten
2026-08-11 22:09:25 +02:00
committed by GitHub
parent 993508c782
commit 37898d9102
21 changed files with 830 additions and 50 deletions

View File

@@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"strings"
"time"
"mvdan.cc/sh/v3/interp"
)
@@ -51,6 +52,10 @@ func (err *TaskRunError) TaskExitCode() int {
if errors.As(err.Err, &exit) {
return int(exit)
}
var timeout *TaskTimeoutError
if errors.As(err.Err, &timeout) {
return TimeoutExitCode
}
return err.Code()
}
@@ -58,6 +63,25 @@ func (err *TaskRunError) Unwrap() error {
return err.Err
}
// TimeoutExitCode is what a killed command reports in place of the exit status
// it never got, following the convention of timeout(1).
const TimeoutExitCode = 124
// TaskTimeoutError is returned when a command exceeds the timeout it declared.
// It must not unwrap to context.DeadlineExceeded, which --watch swallows.
type TaskTimeoutError struct {
TaskName string
Timeout time.Duration
}
func (err *TaskTimeoutError) Error() string {
return fmt.Sprintf(`task: [%s] command timeout exceeded (%s)`, err.TaskName, err.Timeout)
}
func (err *TaskTimeoutError) Code() int {
return CodeTaskTimedOut
}
// TaskInternalError when the user attempts to invoke a task that is internal.
type TaskInternalError struct {
TaskName string