feat: extract build/, release/, sdk/ from go-devops
Build system (8 builders, signing, archiving), release pipeline
(7 publishers, versioning, changelog), and SDK generation
(OpenAPI diff, code gen). 18K LOC, all tests pass except Go
builder workspace isolation (pre-existing).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-09 12:37:36 +00:00
|
|
|
package sdk
|
|
|
|
|
|
|
|
|
|
import (
|
2026-03-26 14:58:13 +00:00
|
|
|
"dappco.re/go/core"
|
2026-03-22 01:34:37 +00:00
|
|
|
coreerr "dappco.re/go/core/log"
|
2026-03-17 02:28:07 +00:00
|
|
|
"github.com/oasdiff/kin-openapi/openapi3"
|
feat: extract build/, release/, sdk/ from go-devops
Build system (8 builders, signing, archiving), release pipeline
(7 publishers, versioning, changelog), and SDK generation
(OpenAPI diff, code gen). 18K LOC, all tests pass except Go
builder workspace isolation (pre-existing).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-09 12:37:36 +00:00
|
|
|
"github.com/oasdiff/oasdiff/checker"
|
|
|
|
|
"github.com/oasdiff/oasdiff/diff"
|
|
|
|
|
"github.com/oasdiff/oasdiff/load"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// DiffResult holds the result of comparing two OpenAPI specs.
|
2026-03-31 18:33:36 +01:00
|
|
|
//
|
|
|
|
|
// result, err := sdk.Diff("docs/openapi.v1.yaml", "docs/openapi.yaml")
|
feat: extract build/, release/, sdk/ from go-devops
Build system (8 builders, signing, archiving), release pipeline
(7 publishers, versioning, changelog), and SDK generation
(OpenAPI diff, code gen). 18K LOC, all tests pass except Go
builder workspace isolation (pre-existing).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-09 12:37:36 +00:00
|
|
|
type DiffResult struct {
|
|
|
|
|
// Breaking is true if breaking changes were detected.
|
|
|
|
|
Breaking bool
|
|
|
|
|
// Changes is the list of breaking changes.
|
|
|
|
|
Changes []string
|
|
|
|
|
// Summary is a human-readable summary.
|
|
|
|
|
Summary string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Diff compares two OpenAPI specs and detects breaking changes.
|
2026-03-31 18:33:36 +01:00
|
|
|
//
|
|
|
|
|
// result, err := sdk.Diff("docs/openapi.v1.yaml", "docs/openapi.yaml")
|
feat: extract build/, release/, sdk/ from go-devops
Build system (8 builders, signing, archiving), release pipeline
(7 publishers, versioning, changelog), and SDK generation
(OpenAPI diff, code gen). 18K LOC, all tests pass except Go
builder workspace isolation (pre-existing).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-09 12:37:36 +00:00
|
|
|
func Diff(basePath, revisionPath string) (*DiffResult, error) {
|
|
|
|
|
loader := openapi3.NewLoader()
|
|
|
|
|
loader.IsExternalRefsAllowed = true
|
|
|
|
|
|
|
|
|
|
// Load specs
|
|
|
|
|
baseSpec, err := load.NewSpecInfo(loader, load.NewSource(basePath))
|
|
|
|
|
if err != nil {
|
2026-03-16 21:03:21 +00:00
|
|
|
return nil, coreerr.E("sdk.Diff", "failed to load base spec", err)
|
feat: extract build/, release/, sdk/ from go-devops
Build system (8 builders, signing, archiving), release pipeline
(7 publishers, versioning, changelog), and SDK generation
(OpenAPI diff, code gen). 18K LOC, all tests pass except Go
builder workspace isolation (pre-existing).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-09 12:37:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
revSpec, err := load.NewSpecInfo(loader, load.NewSource(revisionPath))
|
|
|
|
|
if err != nil {
|
2026-03-16 21:03:21 +00:00
|
|
|
return nil, coreerr.E("sdk.Diff", "failed to load revision spec", err)
|
feat: extract build/, release/, sdk/ from go-devops
Build system (8 builders, signing, archiving), release pipeline
(7 publishers, versioning, changelog), and SDK generation
(OpenAPI diff, code gen). 18K LOC, all tests pass except Go
builder workspace isolation (pre-existing).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-09 12:37:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Compute diff with operations sources map for better error reporting
|
|
|
|
|
diffResult, operationsSources, err := diff.GetWithOperationsSourcesMap(diff.NewConfig(), baseSpec, revSpec)
|
|
|
|
|
if err != nil {
|
2026-03-16 21:03:21 +00:00
|
|
|
return nil, coreerr.E("sdk.Diff", "failed to compute diff", err)
|
feat: extract build/, release/, sdk/ from go-devops
Build system (8 builders, signing, archiving), release pipeline
(7 publishers, versioning, changelog), and SDK generation
(OpenAPI diff, code gen). 18K LOC, all tests pass except Go
builder workspace isolation (pre-existing).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-09 12:37:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check for breaking changes
|
|
|
|
|
config := checker.NewConfig(checker.GetAllChecks())
|
|
|
|
|
breaks := checker.CheckBackwardCompatibilityUntilLevel(
|
|
|
|
|
config,
|
|
|
|
|
diffResult,
|
|
|
|
|
operationsSources,
|
|
|
|
|
checker.ERR, // Only errors (breaking changes)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// Build result
|
|
|
|
|
result := &DiffResult{
|
|
|
|
|
Breaking: len(breaks) > 0,
|
|
|
|
|
Changes: make([]string, 0, len(breaks)),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
localizer := checker.NewDefaultLocalizer()
|
|
|
|
|
for _, b := range breaks {
|
2026-03-15 17:38:31 +00:00
|
|
|
// GetUncolorizedText uses US spelling — upstream oasdiff API.
|
feat: extract build/, release/, sdk/ from go-devops
Build system (8 builders, signing, archiving), release pipeline
(7 publishers, versioning, changelog), and SDK generation
(OpenAPI diff, code gen). 18K LOC, all tests pass except Go
builder workspace isolation (pre-existing).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-09 12:37:36 +00:00
|
|
|
result.Changes = append(result.Changes, b.GetUncolorizedText(localizer))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if result.Breaking {
|
2026-03-26 14:58:13 +00:00
|
|
|
result.Summary = core.Sprintf("%d breaking change(s) detected", len(breaks))
|
feat: extract build/, release/, sdk/ from go-devops
Build system (8 builders, signing, archiving), release pipeline
(7 publishers, versioning, changelog), and SDK generation
(OpenAPI diff, code gen). 18K LOC, all tests pass except Go
builder workspace isolation (pre-existing).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-09 12:37:36 +00:00
|
|
|
} else {
|
|
|
|
|
result.Summary = "No breaking changes"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DiffExitCode returns the exit code for CI integration.
|
2026-03-31 18:33:36 +01:00
|
|
|
// 0 = no breaking changes, 1 = breaking changes, 2 = error.
|
|
|
|
|
//
|
|
|
|
|
// os.Exit(sdk.DiffExitCode(sdk.Diff("old.yaml", "new.yaml")))
|
feat: extract build/, release/, sdk/ from go-devops
Build system (8 builders, signing, archiving), release pipeline
(7 publishers, versioning, changelog), and SDK generation
(OpenAPI diff, code gen). 18K LOC, all tests pass except Go
builder workspace isolation (pre-existing).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-09 12:37:36 +00:00
|
|
|
func DiffExitCode(result *DiffResult, err error) int {
|
|
|
|
|
if err != nil {
|
|
|
|
|
return 2
|
|
|
|
|
}
|
|
|
|
|
if result.Breaking {
|
|
|
|
|
return 1
|
|
|
|
|
}
|
|
|
|
|
return 0
|
|
|
|
|
}
|