labelsync

package
v0.1.0-rc.2 Latest Latest
Warning

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

Go to latest
Published: Aug 19, 2026 License: MIT Imports: 3 Imported by: 0

Documentation

Overview

Package labelsync holds the values every other labelsync package depends on: the sentinel errors that describe how a run can fail, and the XDG paths and file names that describe where its files live. It has no behaviour of its own and imports nothing from the rest of the tree, so any package may import it.

Wrapping rule

Sentinels are never returned bare from a call site that has context to add. Always wrap with %w so the caller keeps both a readable message and a machine-comparable identity:

return fmt.Errorf("%w: %s", labelsync.ErrInvalidColor, raw)

Callers match with errors.Is; the JSON output layer calls KindOf to render the stable error_kind field. Returning a sentinel through %v or a freshly constructed error breaks both.

Index

Constants

View Source
const (
	// AppName is the binary name, and the directory name used under both the XDG
	// config and cache homes.
	AppName = "labelsync"

	// Config file names. Both spellings are accepted; having both present in one
	// directory is ErrAmbiguousConfigFile.
	ConfigYMLFile  = "labels.yml"
	ConfigYAMLFile = "labels.yaml"
)

Variables

View Source
var (
	// ErrConfigNotFound is returned when no config file is found at the --config
	// path, in the working directory, or under the XDG config directory.
	ErrConfigNotFound = errors.New("no config file found")

	// ErrAmbiguousConfigFile is returned when both labels.yml and labels.yaml
	// exist in the same directory. Only one is allowed.
	ErrAmbiguousConfigFile = errors.New("ambiguous config file: both labels.yml and labels.yaml exist — remove one")

	// ErrConfigExists is returned when `labelsync init` is asked to scaffold a
	// config file over one that is already there. Overwriting a hand-edited
	// catalogue is not a thing to do by accident, so it takes --force.
	ErrConfigExists = errors.New("config file already exists")

	// ErrUnsupportedConfigVersion is returned when the config's version field is
	// missing, or names a schema version this binary does not understand.
	ErrUnsupportedConfigVersion = errors.New("unsupported config version")

	// ErrEmptyConfig is returned when the config parses but declares no labels,
	// leaving nothing to reconcile.
	ErrEmptyConfig = errors.New("config declares no labels")

	// ErrDuplicateLabelName is returned when two label entries share a name.
	// Comparison is case-insensitive, because GitHub treats label names that way.
	ErrDuplicateLabelName = errors.New("duplicate label name")

	// ErrDuplicateLabelColor is returned when two label entries share a colour.
	// Distinct labels need distinct colours for the diff to stay readable.
	ErrDuplicateLabelColor = errors.New("duplicate label colour")

	// ErrInvalidColor is returned when a colour is not a 6-digit hex value, with
	// or without a leading #.
	ErrInvalidColor = errors.New("invalid colour: want a 6-digit hex value")

	// ErrInvalidLabelName is returned when a label name is empty, consists only
	// of emoji, or is longer than the 50 code points GitHub accepts.
	ErrInvalidLabelName = errors.New("invalid label name")

	// ErrDescriptionTooLong is returned when a label description exceeds the 100
	// code points GitHub accepts.
	ErrDescriptionTooLong = errors.New("label description is too long")

	// ErrUnknownGroup is returned when a label, or defaults.groups, references a
	// group name that the groups section does not define.
	ErrUnknownGroup = errors.New("unknown group")

	// ErrAmbiguousGroupSource is returned when a group mixes sources. Exactly one
	// of org, user, repos, or include_groups must be set.
	ErrAmbiguousGroupSource = errors.New("ambiguous group source: set exactly one of org, user, repos, or include_groups")

	// ErrCyclicGroup is returned when include_groups forms a cycle, so the group
	// cannot be resolved to a repository set.
	ErrCyclicGroup = errors.New("cyclic group composition")

	// ErrInvalidRepoRef is returned when a repository reference is not in
	// owner/repo form.
	ErrInvalidRepoRef = errors.New("invalid repository reference: want owner/repo")

	// ErrInvalidRename is returned when a rename entry is malformed: an empty
	// from or to, a rename to a name no label declares, or two renames targeting
	// the same name.
	ErrInvalidRename = errors.New("invalid rename")

	// ErrNoToken is returned when the token resolution chain finds no GitHub
	// credential to authenticate with.
	ErrNoToken = errors.New("no GitHub token found")

	// ErrInteractiveRequired is returned when an operation needs a prompt but
	// stdin is not a TTY — prune without --prune=all in CI, for example.
	ErrInteractiveRequired = errors.New("operation requires an interactive terminal")

	// ErrRepoInaccessible is returned when a repository cannot be reached with
	// the current token: missing, archived, or outside the token's scopes. It is
	// reported per repository and does not abort the run.
	ErrRepoInaccessible = errors.New("repository is inaccessible")

	// ErrUnsafeCacheDir is returned when a cache command is pointed at a
	// directory outside the XDG cache home. The path comes from the
	// environment and the command then deletes what is in it, so the bound is
	// explicit rather than assumed.
	ErrUnsafeCacheDir = errors.New("refusing to touch a cache directory outside the cache home")

	// ErrMaxWaitExceeded is returned when a rate-limit backoff would sleep for
	// longer than the --max-wait ceiling allows.
	ErrMaxWaitExceeded = errors.New("rate limit wait exceeds --max-wait")

	// ErrBudgetExhausted is returned when an apply is refused before its first
	// write because the plan needs more requests than the primary rate-limit
	// budget has left. Refusing beats stopping halfway: the reading that predicts
	// it is free, and a half-applied run leaves repositories in a state nobody
	// asked for.
	ErrBudgetExhausted = errors.New("not enough GitHub rate-limit budget to apply this plan")
)

Sentinel errors for every way a labelsync run can fail. Each one maps to a stable kind string in KindOf — see the error table in docs/design.md.

View Source
var ConfigFileNames = []string{ConfigYMLFile, ConfigYAMLFile}

ConfigFileNames lists the accepted config file names, in the order a directory is searched. A directory containing more than one of them is ambiguous.

Functions

func CacheDir

func CacheDir() string

CacheDir returns the directory holding the label/ETag cache. Defaults to $XDG_CACHE_HOME/labelsync (~/.cache/labelsync).

func CacheRoot

func CacheRoot() string

CacheRoot returns the XDG cache home that CacheDir sits inside.

It exists for the one command that deletes things: `labelsync cache clear` takes a path that ultimately comes from the environment, so the bound it is checked against has to be a value rather than an assumption. See github.OpenStore.

func ConfigDir

func ConfigDir() string

ConfigDir returns the labelsync configuration directory. Defaults to $XDG_CONFIG_HOME/labelsync (~/.config/labelsync).

func KindOf

func KindOf(err error) string

KindOf returns a stable, machine-readable string identifier for the sentinel wrapped in err, or "" when err wraps no known sentinel. The returned strings are a public contract: they are embedded in JSON output as the error_kind field, so they may be added to but never renamed.

Types

This section is empty.

Jump to

Keyboard shortcuts

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