Documentation
¶
Overview ¶
Package config handles loading, parsing, and validating husky.yaml.
Overview ¶
The primary entry point is Load, which:
- Reads and unmarshals the YAML file
- Runs JSON Schema structural validation
- Runs semantic validation (enum values, time format, field co-dependencies)
- Applies Defaults to every job that does not override a field
- Interpolates ${env:HOST_VAR} references in all env maps
All validation errors are collected and returned together as a ParseError so that every problem surfaces in a single pass.
Index ¶
- Constants
- func EffectiveDefaultRunTime(v string) string
- func EffectiveJobTime(job *Job, defaults Defaults) string
- func FrequencyAcceptedValues() string
- func FrequencyAllowsDefaultRunTime(freq string) bool
- func FrequencyIgnoresTime(freq string) bool
- func FrequencyUsesTimeField(freq string) bool
- func IsValidFrequency(freq string) bool
- func LoadDotEnv(dir string) error
- func ParseEveryIntervalFrequency(freq string) (time.Duration, bool)
- func ParseOnDaysFrequency(freq string) ([]time.Weekday, bool)
- func ScheduledWeekdays(freq string) ([]time.Weekday, bool)
- type Config
- type Defaults
- type Healthcheck
- type Integration
- type Job
- type Notify
- type NotifyEvent
- type ParseError
- type ValidationError
Constants ¶
const BuiltinDefaultRunTime = "0300"
Variables ¶
This section is empty.
Functions ¶
func EffectiveDefaultRunTime ¶
EffectiveDefaultRunTime returns the configured default run time, or Husky's built-in fallback when the defaults block leaves it empty.
func EffectiveJobTime ¶
EffectiveJobTime returns the concrete HHMM time that should be used for a job after applying default_run_time semantics.
func FrequencyAcceptedValues ¶
func FrequencyAcceptedValues() string
FrequencyAcceptedValues returns a human-readable description of the accepted frequency syntax.
func FrequencyAllowsDefaultRunTime ¶
FrequencyAllowsDefaultRunTime reports whether omitted Time values should fall back to defaults.default_run_time / BuiltinDefaultRunTime.
func FrequencyIgnoresTime ¶
FrequencyIgnoresTime reports whether the time field has no effect.
func FrequencyUsesTimeField ¶
FrequencyUsesTimeField reports whether the frequency participates in wall-clock scheduling via the Time field.
func IsValidFrequency ¶
IsValidFrequency returns true if freq is one of the accepted values.
func LoadDotEnv ¶
LoadDotEnv reads a .env file from dir (if one exists) and sets any key that is not already present in the process environment. Variables already set in the environment always take precedence over the .env file.
The file format follows the Docker Compose convention:
- Lines starting with # are comments and are ignored.
- Blank lines are ignored.
- KEY=VALUE pairs set the variable. Surrounding whitespace is trimmed.
- Values may be bare or wrapped in single/double quotes (quotes are stripped).
Returns nil if the .env file does not exist.
func ParseEveryIntervalFrequency ¶
ParseEveryIntervalFrequency parses the every:<interval> frequency form. Intervals must be positive and less than 24 hours.
func ParseOnDaysFrequency ¶
ParseOnDaysFrequency parses the on:[day[,day...]] frequency form.
Types ¶
type Config ¶
type Config struct {
// Version is the husky file format version. Currently only "1" is valid.
Version string `yaml:"version"`
// Defaults contains values applied to every job unless overridden.
Defaults Defaults `yaml:"defaults"`
// Integrations maps integration names to provider configurations.
// Keys are either known provider names ("slack", "pagerduty", "discord",
// "smtp", "webhook") or arbitrary names when Provider is set explicitly.
Integrations map[string]*Integration `yaml:"integrations"`
// Jobs is the set of all job definitions, keyed by job name.
Jobs map[string]*Job `yaml:"jobs"`
}
Config is the top-level in-memory representation of husky.yaml.
func Load ¶
Load reads path, validates it, applies defaults, and interpolates env vars. It returns a fully-resolved *Config ready for use by the scheduler, or a *ParseError describing every validation failure found.
Before reading path, Load attempts to source a .env file from the same directory. Variables already present in the process environment take precedence over .env values (non-destructive loading).
type Defaults ¶
type Defaults struct {
Timeout string `yaml:"timeout"`
Retries *int `yaml:"retries"`
RetryDelay string `yaml:"retry_delay"`
NotifyOnFailure bool `yaml:"notify_on_failure"`
OnFailure string `yaml:"on_failure"`
DefaultRunTime string `yaml:"default_run_time"`
// Timezone is the IANA timezone identifier used for all jobs that do not
// specify their own timezone. Falls back to the system timezone when empty.
Timezone string `yaml:"timezone"`
}
Defaults holds configuration applied to every job unless the individual job overrides the field. It maps directly to the `defaults:` block in husky.yaml.
type Healthcheck ¶
type Healthcheck struct {
// Command is the shell command to run. Exit 0 = healthy; non-zero = unhealthy.
Command string `yaml:"command"`
// Timeout is the maximum runtime for the healthcheck command. Default: "30s".
Timeout string `yaml:"timeout"`
// OnFail controls what happens when the healthcheck exits non-zero.
// Accepted values: "mark_failed" (default) — fail the run and trigger retries;
// "warn_only" — mark SUCCESS with hc_status=warn and fire a warning notification.
OnFail string `yaml:"on_fail"`
}
Healthcheck defines an optional secondary command that runs after the main command exits with code 0 to verify the job actually produced correct results.
type Integration ¶
type Integration struct {
// Provider explicitly names the notification backend when the map key
// does not match a known provider name. Accepted values: "slack",
// "pagerduty", "discord", "smtp", "webhook".
Provider string `yaml:"provider"`
// WebhookURL is the incoming webhook URL.
// Required for slack and discord providers.
WebhookURL string `yaml:"webhook_url"`
// RoutingKey is the PagerDuty Events API v2 integration routing key.
// Required for pagerduty providers.
RoutingKey string `yaml:"routing_key"`
// Host is the SMTP server hostname. Required for smtp providers.
Host string `yaml:"host"`
// Port is the SMTP server port. Defaults to 587 when zero.
Port int `yaml:"port"`
// Username is the SMTP authentication username.
Username string `yaml:"username"`
// Password is the SMTP authentication password.
// Should always reference ${env:VAR}.
Password string `yaml:"password"`
// From is the sender address for outbound emails. Required for smtp.
From string `yaml:"from"`
// Name is populated from the map key in husky.yaml.
Name string `yaml:"-"`
// EffectiveProvider is the resolved provider after inference.
// Set by validateConfig; equals Provider when explicit, otherwise the key.
EffectiveProvider string `yaml:"-"`
}
Integration holds the configuration and credentials for a single notification provider. Credentials must always be referenced via ${env:VAR} tokens so that the husky.yaml file can be safely committed without secrets.
The provider is inferred from the map key in husky.yaml when the key matches a known provider name (slack, pagerduty, discord, smtp, webhook). For multiple integrations that share the same provider, use an arbitrary key and set Provider explicitly:
integrations:
slack_ops:
provider: slack
webhook_url: "${env:SLACK_OPS_WEBHOOK}"
slack_data:
provider: slack
webhook_url: "${env:SLACK_DATA_WEBHOOK}"
type Job ¶
type Job struct {
// Description is a human-readable explanation of what the job does.
Description string `yaml:"description"`
// Frequency is the recurrence pattern. Accepted values: hourly, daily,
// weekly, monthly, weekdays, weekends, manual, after:<job_name>,
// every:<interval>, on:[day[,day...]].
Frequency string `yaml:"frequency"`
// Command is the shell command to execute, run via /bin/sh -c by default.
Command string `yaml:"command"`
// Time is a 4-character military-time string (e.g. "0200" = 2:00 AM).
// Required when Frequency is daily or monthly. Optional when Frequency is
// weekly, weekdays, weekends, or on:[...], where it falls back to
// defaults.default_run_time (default: "0300"). Ignored when Frequency is
// hourly, every:<interval>, manual, or after:<job>.
Time string `yaml:"time"`
// WorkingDir is the working directory for the command. Defaults to the
// directory of husky.yaml if not set.
WorkingDir string `yaml:"working_dir"`
// DependsOn is a list of job names that must succeed before this job runs.
DependsOn []string `yaml:"depends_on"`
// Timeout is the maximum runtime before SIGTERM + SIGKILL.
// Parsed as a duration string, e.g. "30m", "1h", "90s".
Timeout string `yaml:"timeout"`
// Retries is the number of retry attempts on failure. 0 = no retries.
// A pointer is used to distinguish "not set" (nil) from "set to 0".
Retries *int `yaml:"retries"`
// RetryDelay is the delay strategy between retry attempts.
// Accepted values: "exponential" or "fixed:<duration>" e.g. "fixed:30s".
RetryDelay string `yaml:"retry_delay"`
// Concurrency controls behaviour when a previous run is still executing.
// Accepted values: "allow" (default), "forbid", "replace".
Concurrency string `yaml:"concurrency"`
// OnFailure controls what happens when all retries are exhausted.
// Accepted values: "alert", "skip", "stop", "ignore".
OnFailure string `yaml:"on_failure"`
// Env is a map of environment variables passed to the command.
// Values may use ${env:HOST_VAR} to interpolate host environment variables.
Env map[string]string `yaml:"env"`
// Notify holds notification targets for each lifecycle event.
Notify *Notify `yaml:"notify"`
// Catchup controls whether missed runs are triggered after daemon restart.
// Default: false.
Catchup bool `yaml:"catchup"`
// SLA is the expected maximum duration for this job. When the job is still
// in RUNNING state after this duration, an on_sla_breach notification is fired.
// Must be less than Timeout when both are set. No SLA monitoring when empty.
SLA string `yaml:"sla"`
// Tags is a list of arbitrary labels used to group jobs for filtered status
// views and bulk CLI operations. Tags are lowercase alphanumeric with hyphens,
// max 10 tags per job, max 32 characters per tag.
Tags []string `yaml:"tags"`
// Timezone is the IANA timezone identifier used to resolve the Time field.
// Inherits from Defaults.Timezone when empty. Falls back to system timezone.
Timezone string `yaml:"timezone"`
// Healthcheck defines an optional secondary command that runs after the main
// command exits 0 to verify the job's output is correct.
Healthcheck *Healthcheck `yaml:"healthcheck"`
// Output declares variables captured from the job's stdout, keyed by
// variable name. The value is the capture mode string:
// "last_line", "first_line", "json_field:<key>", "regex:<pattern>", "exit_code".
Output map[string]string `yaml:"output"`
// Name is populated from the map key in husky.yaml. It is not part of the
// YAML structure itself.
Name string `yaml:"-"`
}
Job is the in-memory representation of a single job definition. Required fields are Description, Frequency, and Command. The Time field is conditionally required depending on the selected frequency syntax.
type Notify ¶
type Notify struct {
// OnFailure fires when all retry attempts are exhausted.
OnFailure *NotifyEvent `yaml:"on_failure"`
// OnSuccess fires when a job completes successfully.
OnSuccess *NotifyEvent `yaml:"on_success"`
// OnSLABreach fires when a running job exceeds its sla duration.
// Falls back to OnFailure when not set.
OnSLABreach *NotifyEvent `yaml:"on_sla_breach"`
// OnRetry fires at the start of each retry attempt.
OnRetry *NotifyEvent `yaml:"on_retry"`
}
Notify holds notification targets for each job lifecycle event.
Each field accepts both the v1.0 shorthand string form and the new full object form, preserving full backward compatibility.
type NotifyEvent ¶
type NotifyEvent struct {
// Channel is the destination in "<provider>:<target>" format.
// e.g. "slack:#data-alerts", "pagerduty:p1", "webhook:https://…"
Channel string `yaml:"channel"`
// Message is an optional Go template string rendered at dispatch time.
// Template variables: {{ job.name }}, {{ run.duration }}, etc.
Message string `yaml:"message"`
// AttachLogs controls whether log lines are included in the notification.
// Accepted values: "" / "none" (default), "last_N_lines" (e.g. "last_30_lines"), "all".
AttachLogs string `yaml:"attach_logs"`
// OnlyAfterFailure, when true, suppresses the notification unless the
// previous completed run of this job had a FAILED status. Only meaningful
// on on_success events.
OnlyAfterFailure bool `yaml:"only_after_failure"`
}
NotifyEvent is a single notification target for one lifecycle event. It accepts both a shorthand string form ("slack:#channel") and a full object form with channel, message, attach_logs, and only_after_failure. The custom YAML unmarshaler handles both representations transparently.
func (*NotifyEvent) UnmarshalYAML ¶
func (n *NotifyEvent) UnmarshalYAML(value *yaml.Node) error
UnmarshalYAML implements yaml.Unmarshaler so that NotifyEvent accepts both a bare string (the v1.0 shorthand) and the full object form. A bare string is treated as the Channel field.
type ParseError ¶
type ParseError struct {
Errors []*ValidationError
}
ParseError is returned by Load when one or more validation failures are found. It collects all errors so that the caller can report them all at once rather than surfacing a single failure per parse attempt.
func (*ParseError) Error ¶
func (p *ParseError) Error() string
type ValidationError ¶
type ValidationError struct {
// Job is the name of the job in which the error occurred.
// Empty when the error is at the top level (e.g. a missing version field).
Job string
// Field is the YAML field path where the error occurred (e.g. "frequency",
// "notify.on_failure").
Field string
// Msg is a human-readable description of the error.
Msg string
}
ValidationError describes a single validation failure within a husky.yaml file.
func (*ValidationError) Error ¶
func (e *ValidationError) Error() string