Files
gitea-tea/internal/clierr/errors.go
T
bircni 2c5e005bcf fix(pr): report checks like gh, exit 8 while they are pending
tea pr checks printed relative links, "Error: pull request checks have
not all succeeded" with exit 1 for checks that were only pending, and
nothing at all without checks. It now heads the table with a colored
verdict and "0 failing, 1 successful, and 2 pending checks", prints a
status icon and absolute links, and exits 8 while checks are pending
and 1 when one failed, without an Error line (D21). clierr.Quiet
carries such an exit code past main without a message. Without checks
it says "no checks reported for pull request alice/x#8".

--watch redraws the summary in place on a terminal, and an expired
--timeout reads "timed out after 3s waiting for 2 pending checks". The
pull request argument is optional, and --web opens the pull request.

Signed-off-by: bircni <bircni@icloud.com>
2026-10-11 23:54:47 +02:00

70 lines
1.6 KiB
Go

// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package clierr
import (
"context"
"errors"
)
// Public exit codes for errors returned by commands.
const (
Failure = 1
Usage = 2
Canceled = 3
Authentication = 4
// Pending reports checks that have not finished, like gh pr checks.
Pending = 8
Interrupted = 130
)
// errReported is the message of Quiet errors.
var errReported = errors.New("the command reported the outcome")
// Quiet exits with code without an error message, for an outcome the command already reported,
// such as failing checks.
func Quiet(code int) error {
return &Error{Code: code, Err: errReported}
}
// IsQuiet reports whether err is a Quiet exit code.
func IsQuiet(err error) bool {
return errors.Is(err, errReported)
}
// Error associates an operation error with a public CLI exit code.
type Error struct {
Code int
Err error
}
func (e *Error) Error() string { return e.Err.Error() }
func (e *Error) Unwrap() error { return e.Err }
// Wrap preserves the underlying error while assigning an exit code.
func Wrap(code int, err error) error {
if err == nil {
return nil
}
return &Error{Code: code, Err: err}
}
// ExitCode translates returned errors into the executable exit contract.
func ExitCode(err error) int {
if err == nil {
return 0
}
typed, ok := errors.AsType[*Error](err)
if ok && typed.Code == Interrupted {
return Interrupted
}
if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
return Canceled
}
if ok {
return typed.Code
}
return Failure
}