Skip to content

feat: add --neat flag for K8s/Helm/ArgoCD/Flux noise filtering#131

Open
szhekpisov wants to merge 5 commits intomainfrom
worktree-neat-flag
Open

feat: add --neat flag for K8s/Helm/ArgoCD/Flux noise filtering#131
szhekpisov wants to merge 5 commits intomainfrom
worktree-neat-flag

Conversation

@szhekpisov
Copy link
Copy Markdown
Owner

What

Add --neat, a curated regex bundle that excludes noise paths injected by the Kubernetes API server, kubectl, Helm, ArgoCD, and Flux from diff output.

Why

When users pipe kubectl diff, helm diff upgrade, or ArgoCD-rendered manifests through diffyml, the output is dominated by server- and controller-injected noise: `metadata.managedFields`, `status`, `helm.sh/chart` (cause of phantom diffs on chart bumps — see helm-diff#392), `argocd.argoproj.io/tracking-id`, `kustomize.toolkit.fluxcd.io/*`, and similar paths.

Existing wrappers (`kubectl-neat-diff` over `kubectl-neat`) only address the K8s-server layer and leave Helm/Argo/Flux noise untouched. `--neat` makes diffyml the first YAML diff tool to handle all four layers natively in one flag.

How

Curated regex bundles in five profiles (k8s, status, helm, argocd, flux) live in `pkg/diffyml/neat.go`. CLI is a thin wiring layer; the implementation reuses the existing post-diff regex filter (`FilterDiffsWithRegexp`) — `--neat` is a regex bundle prepended to `ExcludeRegexp`, not new comparison logic.

Per-layer opt-outs (`--no-neat-{helm,argocd,flux,status}`), an audit mode (`--neat-explain`) that prints per-pattern hit counts to stderr, and `--neat-strip-path` to extend the bundle. Config-file support via a `neat:` block (positive truth-table inverted to opt-out flags on apply).

Deliberate non-strips (covered by tests + docs):

  • `spec.template.metadata.annotations[kubectl.kubernetes.io/restartedAt]` — intentional rollout marker (regression guard in fixture 120)
  • `spec.replicas`, `data`/`stringData`, user-defined labels/annotations outside canonical noise prefixes

Checklist

  • PR title follows convention (`feat:`, `bug:`, `fix:`, `doc:`, `chore:`, `test:`)
  • `make ci` passes locally
  • New/changed behavior covered by tests
  • Coverage thresholds met (parser 100%, ordered_map 100%, kubernetes 95%)
  • No new dependencies (or justified)

Notes for reviewers

  • `pkg/diffyml/filter.go` gains a `FilterDiffsWithRegexpReport` sibling (existing `FilterDiffsWithRegexp` delegates) so `--neat-explain` can attribute exclusions to specific patterns. First-match wins for hit attribution; path-based exclusions are not counted.
  • Bundle is documented as profile `v1` in `doc/neat.md` so future additions to the strip list have a clear stability story.
  • The `--neat` category had to be added to `doc/gen-cli-ref/main.go` `categoryOrder` — without it the generated docs reference would silently drop the section.
  • Three new fixtures (`118-neat-kubernetes`, `119-neat-no-helm`, `120-neat-keeps-restartedat`) exercise the golden path, an opt-out, and the restartedAt regression guard end-to-end.

Curated regex bundle that excludes noise paths injected by the K8s API
server, kubectl, Helm, ArgoCD, and Flux (managedFields, status,
helm.sh/chart, argocd.argoproj.io/*, kustomize.toolkit.fluxcd.io/*, ...).
Users can opt out per-layer (--no-neat-{helm,argocd,flux,status}), extend
the bundle (--neat-strip-path), and audit which patterns fired
(--neat-explain).

The implementation reuses the existing post-diff regex filter
(FilterDiffsWithRegexp); --neat is a curated bundle prepended to
ExcludeRegexp. spec.template.metadata.annotations[
kubectl.kubernetes.io/restartedAt] is deliberately preserved as it is
an intentional rollout marker.
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 30, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

- Rename CLIConfig.NeatOptions() to ToNeatOptions() to match the
  ToCompareOptions/ToFilterOptions/ToMaskOptions/ToFormatOptions sibling
  pattern.
- Replace 4 near-identical preallocation/append blocks in NeatPatterns
  with a table-driven loop.
- Delete matchesAnyRegexWithNested; route its single remaining caller
  through firstMatchingRegexWithNested (discarding the index).
- Document the positional-correspondence contract between
  NeatPatterns(opts) and BuildNeatExcludeRegexp(opts).
- Drop the masked-invariant min() guard in writeNeatExplain — iterate
  range patterns directly since report.ExcludeHits is built positionally
  in ToFilterOptions and is always at least len(patterns).
- Extract a small applyInverted local helper for the 4 polarity-flipped
  config blocks in applyFileConfig (config positive ⇒ CLI opt-out).
- Remove dead code after t.Fatalf and inline the single-use pathsOf
  helper in filter_test.go.
- Merge TestNeatRegexes_Compile and TestNeatRegexes_Anchored into a
  single per-pattern walker; fold TestBuildNeatExcludeRegexp_AllProfiles
  into the bundle-selection table.
- Trim narrative file/var doc comments that restate identifiers.
Restore a defensive length check for the positional invariant between
NeatPatterns(opts) and report.ExcludeHits. The previous /simplify pass
removed the min() bound on the grounds that the invariant was load-bearing,
but that left no guard against a future caller (e.g. a test stub) passing
a FilterReport not produced via ToFilterOptions. The new explicit early
return makes the contract visible and fails closed instead of panicking.
Address review feedback on PR #131:

- Replace the README example that piped kubectl output into --neat with
  process substitution, since LoadContent only handles file paths and
  HTTP(S) URLs (not stdin/-).
- Surface a stderr message instead of bare-returning when writeNeatExplain
  hits the FilterReport length-mismatch guard, so future regressions
  don't silently swallow --neat-explain output.
- Add CLI-level unit tests for the previously-uncovered surface:
  - ToNeatOptions polarity (NoNeat* fields invert per-bundle gates;
    K8s gate stays true unconditionally)
  - ToFilterOptions neat-merge ordering (neat ++ NeatStripPath ++ user)
  - ToFilterOptions no-neat path leaves user ExcludeRegexp untouched
  - --neat-strip-path requires --neat (Validate error)
  - --neat-strip-path regex compile error
- Add config-file polarity-inversion tests:
  - neat.{helm,argocd,flux,status}: false ⇒ NoNeat* set true
  - neat.{...}: true does not double-invert
  - CLI override beats config (existing notSet pattern)
  - StripPath and Explain pass-through
  - Missing neat block leaves all defaults intact
Mechanical rename across docs, Makefile, mutation workflow, and
nolint/test comments to match the upstream tool repository rename.
Both the `go install` target (github.com/szhekpisov/gomutants) and the
CLI invocation (`gomutants unleash …`) are updated.
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.

1 participant