ExQuality.Config (ExQuality v0.13.0)
View SourceLoads and merges configuration from multiple sources.
Configuration is resolved in the following order (later wins):
- Defaults
- Auto-detected tool availability
- Project config file (.quality.exs, read from the project root)
- The selected profile, if
--profilenamed one - CLI arguments
Example .quality.exs
[
# Global options
quick: false,
# Override auto-detection: force disable dialyzer
dialyzer: [enabled: false],
# Credo options (enabled: :auto by default)
credo: [
strict: true,
all: false
],
# Doctor options
doctor: [
summary_only: true
],
# Named bundles, selected with `mix quality --profile loop`
profiles: [
loop: [stages: [:format, :compile, :credo], test: [scope: :changed]],
gate: []
]
]Configuration Options
Global Options
quick- Quick mode: skip dialyzer and coverage enforcement (default: false)profiles- Named option bundles, see "Profiles" below (default:[])
Stage Options
Each stage supports:
enabled- :auto (use auto-detection) | true (force enable) | false (force disable)
Stage-specific options:
compile.warnings_as_errors- Treat warnings as errors (default: true)compile.force- Recompile from scratch (default: false)credo.strict- Use strict mode (default: true)credo.all- Check all files (default: false)credo.configs- Names of the.credo.exsconfigs to run, in order (default:nil, meaning one run with no--config-name)dependencies.check_unused- Check for unused dependencies (default: true)dependencies.audit- Run security audit if available (default: :auto)doctor.summary_only- Show only summary (default: false)gettext.source_locale- The locale the source is written in, whose.pofiles are not checked (default:"en")gettext.exclude- Basenames to skip (default:["errors.po"])gettext.extract- Runmix gettext.extract --mergefirst, which writes to the repository and recompiles the project (default: false)sobelow.exit- Confidence level that blocks, when.sobelow-confsets noexit:of its own (default: "medium")sobelow.show_informational- Render findings below that level as well as counting them (default: false)test.coverage- :auto (measure when the project's config asks for it) | true (always measure) | false (never measure) (default: :auto)test.scope- :all (the whole suite):changed (only the test files covering changed code) a glob string (default: :all) test.base_ref- Whatscope: :changedis measured against (default: the repository's default branch)
Profiles
A profile is a named bundle of the options above, so the fast path a project wants its agents to use has a name its docs can point at:
profiles: [
loop: [stages: [:format, :compile, :credo], test: [scope: :changed]],
gate: []
]mix quality --profile loop merges the profile over the config file and under
the CLI, so a switch still wins over the profile that a run selected.
stages: is the allow-list of stage keys for the profile. Every other stage,
built-in or custom, is reported as skipped naming the profile. A profile with
no stages: key narrows nothing and only carries options, which is what an
empty gate: [] is for.
An invocation with no --profile behaves exactly as it does without any
profiles configured. An unknown profile name fails the run: falling back to
"run everything" would turn a typo into a slow green, and falling back to the
profile's intent would turn one into a fast green over nothing.
Summary
Functions
Merges the named profile into a config, or returns it unchanged for nil.
Returns the path of the .quality.exs that applies here, or nil.
Returns the .quality.exs under project_root, or under umbrella_root
when the project has none of its own, or nil when neither has one.
Loads configuration with auto-detection and overrides.
Returns the name of the profile a loaded config was resolved with, or nil.
Returns why a stage will not run, or nil when it will.
Determines if a stage should run based on config.
Functions
Merges the named profile into a config, or returns it unchanged for nil.
Called by load/1 between the config file and the CLI. name is a string
because it comes from a switch, and the profile keys it is matched against are
atoms because they come from a config file.
iex> ExQuality.Config.apply_profile([credo: [strict: true]], nil)
[credo: [strict: true]]
iex> config = [profiles: [loop: [test: [scope: :changed]]]]
iex> config |> ExQuality.Config.apply_profile("loop") |> Keyword.take([:profile, :test])
[profile: :loop, test: [scope: :changed]]
@spec config_path() :: String.t() | nil
Returns the path of the .quality.exs that applies here, or nil.
The file belongs to the project, not to wherever the shell happened to be
when mix quality was run. An umbrella child with no file of its own falls
back to the umbrella root's, because the settings describe the tree.
Finding the umbrella root needs Mix.Project.parent_umbrella_project_file/0,
which arrived in Elixir 1.15. On 1.14 only the current project's root is
looked at.
Returns the .quality.exs under project_root, or under umbrella_root
when the project has none of its own, or nil when neither has one.
Either root may be nil, meaning there is no such directory to look in.
Loads configuration with auto-detection and overrides.
Resolution order (later wins):
- Defaults
- Auto-detected tool availability
- .quality.exs file
- The profile named by
--profile, if any - CLI arguments
Examples
# Load with CLI options
config = ExQuality.Config.load(quick: true, skip_dialyzer: true)
# Load with defaults only
config = ExQuality.Config.load()
Returns the name of the profile a loaded config was resolved with, or nil.
iex> ExQuality.Config.profile(ExQuality.Config.load())
nil
Returns why a stage will not run, or nil when it will.
The reason is meant to be shown to the reader, because a stage that is silently omitted reads as a stage that passed.
Examples
config = ExQuality.Config.load(skip_credo: true)
ExQuality.Config.skip_reason(config, :credo)
#=> "--skip-credo"
config = ExQuality.Config.load()
ExQuality.Config.skip_reason(config, :doctor)
#=> ":doctor not installed"
Determines if a stage should run based on config.
enabled: :auto→ use detected availabilityenabled: true→ force enable (will error if tool missing)enabled: false→ force disable
Examples
config = ExQuality.Config.load()
ExQuality.Config.stage_enabled?(config, :credo)
#=> true (if credo is installed)
config = ExQuality.Config.load(skip_credo: true)
ExQuality.Config.stage_enabled?(config, :credo)
#=> false