Skip to content

feat(config): rename default config to .oasdiff.*; add --config flag and OASDIFF_CONFIG env var#899

Merged
reuvenharrison merged 3 commits into
mainfrom
feat/dot-oasdiff-config-lookup
May 8, 2026
Merged

feat(config): rename default config to .oasdiff.*; add --config flag and OASDIFF_CONFIG env var#899
reuvenharrison merged 3 commits into
mainfrom
feat/dot-oasdiff-config-lookup

Conversation

@reuvenharrison
Copy link
Copy Markdown
Collaborator

@reuvenharrison reuvenharrison commented May 8, 2026

Summary

Adds .oasdiff.{json,yaml,yml,toml,hcl} as the preferred default config-file location, keeps the existing oasdiff.{json,yaml,yml,toml,hcl} lookup as a back-compat fallback, and adds two override mechanisms: a --config <path> persistent flag on the root command and an OASDIFF_CONFIG environment variable.

Why add .oasdiff.*

The dotfile convention is the overwhelming pattern for CI/lint tools — .eslintrc, .prettierrc, .golangci.yml, .yamllint, .flake8, .markdownlint.json, etc. The original oasdiff.{yaml,...} at the repo root reads as a project-defining file (Cargo.toml, package.json, pyproject.toml), which oasdiff isn't — it's a tool that operates on a project, not part of one. .oasdiff.* aligns with community muscle memory and makes the file's role obvious at a glance.

Why keep oasdiff.* as a fallback

The legacy lookup has been live in the CLI for a long time. We don't know how many users have oasdiff.yaml committed to their working directories. Silently breaking them for the sake of strict convention isn't worth it when the cost of keeping both is one extra SetConfigName call. Existing users don't have to do anything; .oasdiff.* is recommended for new setups.

Lookup order

In cwd, first hit wins:

  1. .oasdiff.{json,yaml,yml,toml,hcl} — preferred (dotfile)
  2. oasdiff.{json,yaml,yml,toml,hcl} — legacy fallback

Plus two explicit overrides that bypass the cwd lookup entirely:

  • --config <path> (persistent flag on root, inherited by all subcommands)
  • OASDIFF_CONFIG environment variable

Override precedence: --config <path> > OASDIFF_CONFIG > default cwd lookup.

When either override is set, the file MUST exist — missing or malformed file is an explicit error. The default cwd lookup retains its silent-skip semantics.

Why the env var (not just the flag)

The env var earns its place specifically for CI workflows: a customer with multiple oasdiff invocations in one workflow sets OASDIFF_CONFIG once at the workflow's env: block instead of duplicating --config per step. This matches industry convention (KUBECONFIG, AWS_CONFIG_FILE, DOCKER_CONFIG, NPM_CONFIG_USERCONFIG).

What's in the diff

  • internal/viper.goreadConfFile checks the override sources in order, falls back to a two-candidate cwd lookup (.oasdiff then oasdiff). New EnvConfigPath constant for the env var name. IViper interface gains SetConfigFile (already on viper.Viper, so no mock changes needed).
  • internal/run.go--config added as a persistent flag on the root command.
  • internal/viper_test.go — 8 new tests covering: .oasdiff.yaml loaded; legacy oasdiff.yaml still works; .oasdiff.yaml preferred when both exist; no-config not-an-error; --config explicit path; --config missing-file error; --config overrides default; OASDIFF_CONFIG env var; --config wins over env. All run in t.Chdir(t.TempDir()) for isolation.
  • docs/CONFIG-FILES.md — new "Default lookup" + "Explicit override" sections, documents both default filenames, the precedence, and the two override mechanisms with runnable examples.
  • examples/oasdiff.yamlexamples/.oasdiff.yaml — renamed to recommend the dotfile; the comment mentions the override mechanisms.

Backward compatibility

Strict — no existing setup breaks:

  • Users with oasdiff.yaml in cwd: still works, no change needed.
  • Users with no config file: still works, still no error.
  • Users with the new .oasdiff.yaml: works, takes precedence over a co-existing oasdiff.yaml.

Test plan

  • go test ./... — all packages green
  • go test ./internal/ -run TestViper -count=1 -v — 20 tests pass (12 existing + 8 new)
  • Manually verify oasdiff diff --config /tmp/x.yaml ... reads x.yaml
  • Manually verify OASDIFF_CONFIG=/tmp/x.yaml oasdiff diff ... reads x.yaml
  • Manually verify oasdiff diff ... with .oasdiff.yaml in cwd reads it
  • Manually verify oasdiff diff ... with oasdiff.yaml (and no .oasdiff.yaml) in cwd reads it
  • Manually verify oasdiff diff ... with both files prefers .oasdiff.yaml

…and OASDIFF_CONFIG env var

Switch the default config-file lookup from oasdiff.{json,yaml,yml,toml,hcl}
to .oasdiff.{json,yaml,yml,toml,hcl}. The dotfile convention matches the
overwhelming pattern for CI/lint tools (.eslintrc, .prettierrc,
.golangci.yml, .yamllint, .flake8, .markdownlint.json) — putting
oasdiff.yaml at the root reads as a project-defining file, which oasdiff
isn't.

For backward compatibility with existing CLI users who relied on the old
filename, two new override mechanisms:

- --config <path> persistent flag on the root command
- OASDIFF_CONFIG environment variable

Precedence: --config > OASDIFF_CONFIG > default .oasdiff.* lookup. When
either override is set, the file MUST exist (missing or malformed file is
an error, unlike the silent-skip semantics of the default lookup).

The env var earns its place specifically for CI workflows: a customer
with multiple oasdiff invocations in one workflow sets OASDIFF_CONFIG
once at the workflow's env: block instead of duplicating --config per
step. This matches industry convention (KUBECONFIG, AWS_CONFIG_FILE,
DOCKER_CONFIG, NPM_CONFIG_USERCONFIG).

Migration for existing oasdiff.yaml users: rename to .oasdiff.yaml,
OR pass --config oasdiff.yaml (or set OASDIFF_CONFIG=oasdiff.yaml).

Tests: 7 new cases in internal/viper_test.go cover the default lookup,
legacy-filename ignored, missing-config-not-an-error, --config explicit
path, --config missing file is an error, --config overrides default,
OASDIFF_CONFIG env var, and --config wins over OASDIFF_CONFIG.
@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented May 8, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.66%. Comparing base (2ae1a46) to head (bbf9277).
⚠️ Report is 3 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #899   +/-   ##
=======================================
  Coverage   90.65%   90.66%           
=======================================
  Files         264      264           
  Lines       15830    15845   +15     
=======================================
+ Hits        14351    14366   +15     
  Misses        948      948           
  Partials      531      531           
Flag Coverage Δ
unittests 90.66% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

The previous commit dropped the legacy oasdiff.{yaml,...} cwd lookup
entirely. That's a real backward-compatibility break: the lookup has
been live for a long time, and we don't know how many CLI users have
oasdiff.yaml committed to their working directories. Silently breaking
those users for the sake of strict convention isn't worth it when the
fix costs nothing.

Lookup order now (in cwd, first hit wins):

1. .oasdiff.{json,yaml,yml,toml,hcl} — preferred (dotfile convention)
2. oasdiff.{json,yaml,yml,toml,hcl}  — legacy fallback, no warning,
   no plan to remove

Existing oasdiff.* users don't have to do anything; .oasdiff.* is
recommended for new setups.

Tests: TestViper_DefaultLookup_LegacyOasdiffYamlIsIgnored renamed and
inverted to TestViper_DefaultLookup_LegacyOasdiffYamlStillWorks. New
TestViper_DefaultLookup_DotPreferredOverLegacy asserts the precedence
order when both files coexist.

CONFIG-FILES.md documents both filenames and the precedence.
…sdiff.yaml

The example .oasdiff.yaml referenced ignore-err-example.txt with a
relative path, but the file existed only at data/ — a test fixture
keyed to specific test specs. Anyone reading examples/ to learn the
config schema had to hunt for the file across the repo, and running
the example directly didn't work because the test fixture's regex
patterns are tied to the test specs in data/, not arbitrary user
specs.

Decouples the two concerns:

- data/ignore-{err,warn}-example.txt — unchanged. Test fixtures used
  by checker/example_test.go, checker/ignore_test.go, internal/run_test.go,
  and load/spec_info_test.go.
- examples/ignore-{err,warn}-example.txt — new. Comment-heavy templates
  that teach the format (regex per line, # comments, empty-by-default)
  rather than copies of test fixtures.

Also enables the warn-ignore line in examples/.oasdiff.yaml so both
flags are demonstrated symmetrically.
@reuvenharrison reuvenharrison merged commit 3dab475 into main May 8, 2026
13 checks passed
@reuvenharrison reuvenharrison deleted the feat/dot-oasdiff-config-lookup branch May 8, 2026 21:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants