scan

package
v0.10.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 9, 2026 License: Apache-2.0 Imports: 9 Imported by: 0

Documentation

Overview

Package scan finds the user facing errors of the code base and the places, where one should be used, but is not.

The domain-errors command turns that into the report of the places, which do not follow the conventions of doc/development/error-handling.md.

Index

Constants

View Source
const (
	// DomainPkg holds the error kinds and the constructor of a user facing error.
	DomainPkg = "github.com/FuturFusion/operations-center/internal/domain"

	// APIPkg declares the reasons, which are reported to a client.
	APIPkg = "github.com/FuturFusion/operations-center/shared/api"

	// ResponsePkg turns an error into an HTTP response.
	ResponsePkg = "github.com/FuturFusion/operations-center/internal/util/response"

	// SmartError is the response helper, which derives the status code from the
	// kind of the error. An error without a kind becomes an internal server
	// error there, which is what makes an unclassified error visible.
	SmartError = "SmartError"

	// IgnoreDirective exempts the call on the following line from the checks.
	// It carries the reason, so an exemption, which is no longer warranted, can
	// be told from one, which is.
	IgnoreDirective = "//domain-errors:ignore "

	// InternalDirective declares the error on the following line to be internal
	// by design, e.g. a violated invariant, which the user can do nothing
	// about. Such an error stays unclassified and is reported as an internal
	// server error.
	//
	// It is a directive of its own rather than an IgnoreDirective, because it
	// states the intent and makes every such place greppable.
	InternalDirective = "//domain-errors:internal "
)

LoadMode is what the scan needs from the packages it inspects. The types of the whole program are needed, because a kind is recognised by the object it resolves to, not by the way it is spelled at the call site.

Variables

This section is empty.

Functions

func Load

func Load(patterns ...string) ([]*packages.Package, error)

Load loads the given patterns, including their test files, so an error reported only by a test is covered as well.

Types

type BareKind

type BareKind struct {
	Pos token.Position

	// Kind is the name of the kind, e.g. "ErrNotFound".
	Kind string

	// Ignored is set, if the call carries an ignore directive.
	Ignored bool
}

BareKind is a kind returned as the error itself, without a message.

type BoundaryError

type BoundaryError struct {
	Pos token.Position

	// Responder is the response helper the error is handed to, e.g.
	// "response.BadRequest".
	Responder string

	// Callee is the function creating the error, e.g. "errors.New".
	Callee string

	// Ignored is set, if the call carries an ignore directive.
	Ignored bool
}

BoundaryError is an error created at the HTTP boundary without a kind.

type DomainError

type DomainError struct {
	Pos token.Position

	// Kind is the name of the kind, e.g. "ErrNotFound". It is empty for an
	// error constructed with a nil kind, which carries a message for the user
	// without classifying it.
	Kind string

	// Reason is the name of the api.ErrorReason constant, e.g.
	// "ErrorReasonServerIsClusterMember", or empty, if the empty string was
	// passed. ReasonValue is the value of the constant.
	Reason      string
	ReasonValue string

	// ReasonUnresolved is set, if the reason is neither the empty string, nor a
	// constant declared in shared/api, nor an api.ErrorReason resolved
	// elsewhere.
	ReasonUnresolved bool

	// Message is the format string of the message for the user. Format is
	// false, if it is not a constant, in which case the message can not be
	// reported in the catalog.
	Message      string
	MessageConst bool

	// Hint is the format string of the hint, if WithHintf is called on the
	// error. HintConst is false, if it is not a constant.
	Hint      string
	HintConst bool
	HasHint   bool

	// DetailKeys are the keys passed to WithDetail, in the order they are
	// added. A key, which is not a constant, is reported as the empty string.
	DetailKeys []string

	// CauseIsKind is set, if the error passed to WithCause is a domain error
	// kind itself, which reclassifies the error.
	CauseIsKind bool
	CauseKind   string

	// Ignored is set, if the call carries an ignore directive.
	Ignored bool
}

DomainError is a domain.NewErrorf call together with the chain of methods called on its result.

type KindWrap

type KindWrap struct {
	Pos token.Position

	// Callee is the function the kind is handed to, e.g. "fmt.Errorf".
	Callee string

	// Kind is the name of the kind, e.g. "ErrNotFound".
	Kind string

	// Ignored is set, if the call carries an ignore directive.
	Ignored bool
}

KindWrap is a call, which hands a domain error kind to something other than domain.NewErrorf, e.g. fmt.Errorf("...: %w", domain.ErrNotFound).

type Reason

type Reason struct {
	Pos   token.Position
	Name  string
	Value string
}

Reason is an api.ErrorReason constant declared in shared/api.

type Result

type Result struct {
	// Errors are the domain.NewErrorf calls, in the order they were found.
	Errors []DomainError

	// KindWraps are the calls, which classify an error by handing a domain
	// error kind to something other than domain.NewErrorf.
	KindWraps []KindWrap

	// BoundaryErrors are the errors, which are created at the HTTP boundary
	// without a kind, so they reach the user as an internal server error.
	BoundaryErrors []BoundaryError

	// BareKinds are the places, which return a kind without a message of its
	// own, outside the layer, where a kind is a sentinel for the caller.
	BareKinds []BareKind

	// UnkindedErrors are the errors, which originate in the business logic
	// without a kind, so nothing says, whether they are meant for the user.
	UnkindedErrors []UnkindedError

	// UnknownConstructs are the constructors and the builder methods of the
	// domain package, which the scan does not know about, so the errors they
	// build would be checked by nothing.
	UnknownConstructs []UnknownConstruct

	// DeclaredReasons are the api.ErrorReason constants of shared/api.
	DeclaredReasons []Reason

	// UsedReasons are the reason constants referenced anywhere in the module,
	// keyed by the constant name.
	UsedReasons map[string]bool
}

Result is everything the scan found in the inspected packages.

func Scan

func Scan(pkgs []*packages.Package) (*Result, error)

Scan inspects the given packages. Generated files are inspected as well, because a generated error reaches the user just like a hand written one.

type UnkindedError

type UnkindedError struct {
	Pos token.Position

	// Callee is the function creating the error, e.g. "fmt.Errorf".
	Callee string

	// Message is the constant format string of the error.
	Message string

	// Internal is set, if the error is declared internal by design.
	Internal bool

	// Ignored is set, if the call carries an ignore directive.
	Ignored bool
}

UnkindedError is an error, which originates where it is built, i.e. it wraps nothing, and carries no kind.

type UnknownConstruct

type UnknownConstruct struct {
	Pos token.Position

	// Name is the name of the function or the method, e.g. "NewSomethingErr".
	Name string

	// What says, what the name is, so the report can tell the reader, where to
	// teach the scan about it.
	What string
}

UnknownConstruct is a way of building a user facing error, which the scan does not understand.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL