Skip to content

feat: add reusable OpenAPI diff package - #1424

Draft
andmatei wants to merge 2 commits into
mainfrom
feat/foas-diff-package
Draft

feat: add reusable OpenAPI diff package#1424
andmatei wants to merge 2 commits into
mainfrom
feat/foas-diff-package

Conversation

@andmatei

@andmatei andmatei commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds a reusable tools/foas/diff package that exposes FOAS compatibility comparison without leaking oasdiff types.

The changelog generator now consumes this package instead of owning the checker configuration and invoking oasdiff directly.

Why

Compatibility comparison was split across packages:

  • openapi.OasDiff produced the raw structural diff;
  • changelog privately owned checker severities and deprecation settings;
  • consumers outside changelog had to reproduce those rules or import oasdiff directly.

This made it difficult for OASIS and other Go consumers to use the same compatibility behavior as the FOAS CLI.

Public API

report, err := diff.Compare(
    ctx,
    diff.Document{Spec: base, Source: "base.yaml"},
    diff.Document{Spec: revision, Source: "revision.yaml"},
)

The returned report contains FOAS-owned types:

  • stable change IDs and fingerprints;
  • severity and breaking classification;
  • component and change-type classifications;
  • operation, path, component name, and source locations;
  • breaking/non-breaking summary counts;
  • ruleset and engine identifiers.

No oasdiff types are exposed.

Package responsibilities

diff

  • owns compatibility comparison;
  • owns the existing custom checker severity configuration;
  • owns the 365-day deprecation settings;
  • provides a validated custom-rule registry inspired by the custom-check POC in poc: FOASCLI breaking change command with custom check #1166;
  • deduplicates shared custom checker handlers;
  • keeps custom rule metadata and FOAS-owned message formatting together;
  • flattens allOf before comparison;
  • includes structural component additions omitted by compatibility checkers;
  • deduplicates checker and structural additions;
  • produces deterministic ordering and fingerprints.

changelog

  • consumes checker-origin findings from diff.Compare;
  • continues to apply changelog exemptions, hiding, squashing, version grouping, sunset entries, and manual entries;
  • preserves existing generated changelog output.

breakingchanges

  • continues to validate and convert exemption files;
  • does not compute a separate diff.

openapi.OasDiff

  • remains in place for merge conflict detection;
  • this is intentionally a raw structural comparison with merge-specific configuration, not a second compatibility ruleset.

Compatibility

The existing outputfilter.NewChangelogEntries(checker.Changes, ...) API remains available. Changelog uses the new NewChangelogEntriesFromDiff path.

No oasdiff dependency upgrade is included in this PR.

Adding custom rules

The custom-rule registry is intentionally internal so callers cannot redefine
the canonical FOAS ruleset at runtime.

An approved custom rule is added by:

  1. implementing its checker in a dedicated file;
  2. defining its ID, severity, description, direction, area, kind, action, and
    FOAS message formatter with newCustomRule;
  3. adding the definition to registeredCustomRules;
  4. adding checker and normalized-report tests;
  5. incrementing RulesetVersion when classification changes.

The registry rejects duplicate IDs, collisions with built-in oasdiff IDs,
unsupported severities, missing descriptions, nil handlers, and nil message
formatters. Multiple rule IDs may share a handler; that handler is executed
only once.

The x-xgen-operation-id-override rule from #1166 is not enabled by this PR
because #1166 is explicitly a POC and its rule behavior has not been approved.
The new registry is the library-level extension point where that rule can be
added once approved.

Testing

  • GOWORK=off go test ./...
  • GOWORK=off go test -race ./...
  • go vet ./...
  • golangci-lint v2.10.1: 0 issues
  • FOAS diff package coverage: 79.1%
  • CLI changelog E2E golden-output suite: pass
  • targeted post-review changelog golden-output E2E: pass

The new diff tests cover:

  • identical documents;
  • added endpoints and deduplication;
  • removed endpoints;
  • custom operation ID removal classification;
  • custom checker registration, message formatting, and execution;
  • duplicate and built-in rule ID rejection;
  • shared-handler deduplication;
  • warning-level non-breaking changes;
  • component additions;
  • stable fingerprints;
  • invalid input and context cancellation.

Follow-up

OASIS can replace its direct oasdiff integration with foas/diff.Compare after this API is released.

@andmatei andmatei changed the title feat(foas): add reusable OpenAPI diff package feat: add reusable OpenAPI diff package Aug 7, 2026
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