Skip to content

Commit 09abb9d

Browse files
feat: Add support for 3.2.0 openapi spec (#54)
Co-authored-by: Tristan Cartledge <tristan@speakeasyapi.dev> Co-authored-by: Tristan Cartledge <108070248+TristanSpeakEasy@users.noreply.github.com>
1 parent 526f2c7 commit 09abb9d

File tree

105 files changed

+5399
-592
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

105 files changed

+5399
-592
lines changed

.github/workflows/ci.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ jobs:
1717

1818
- name: Install mise
1919
uses: jdx/mise-action@v3
20+
with:
21+
experimental: true
2022

2123
- name: Setup Go with caching
2224
uses: actions/setup-go@v6

.mise.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
[tools]
22
go = "1.24.3"
3-
golangci-lint = "2.1.1"
43
gotestsum = "latest"
54

65
[tasks.setup-vscode-symlinks]
76
description = "Create VSCode symlinks for tools not automatically handled by mise-vscode"
87
run = [
98
"mkdir -p .vscode/mise-tools",
10-
"ln -sf $(mise exec -- which golangci-lint-v2) $(dirname $(mise exec -- which golangci-lint-v2))/golangci-lint || true",
11-
"ln -sf $(mise exec -- which golangci-lint) .vscode/mise-tools/golangci-lint",
9+
"ln -sf $(mise exec golangci-lint@2.7.2 -- which golangci-lint) .vscode/mise-tools/golangci-lint",
1210
]
1311

1412
[hooks]
1513
postinstall = [
1614
"ln -sf ./AGENTS.md ./CLAUDE.md",
15+
"git submodule update --init --recursive",
16+
"mise exec go@1.24.3 -- go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.7.2",
1717
"mise run setup-vscode-symlinks",
1818
"go install go.uber.org/nilaway/cmd/nilaway@8ad05f0",
1919
]

AGENTS.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,54 @@ mise test -count=1 ./...
5858
- **Race Detection**: Automatically enables race detection to catch concurrency issues
5959
- **Submodule Awareness**: Checks for and warns about uninitialized test submodules
6060

61+
## Git Commit Conventions
62+
63+
**Always use single-line conventional commits.** Do not create multi-line commit messages.
64+
65+
### Commit Message Format
66+
67+
```
68+
<type>: <description>
69+
```
70+
71+
### Common Types
72+
73+
- `feat:` - New feature
74+
- `fix:` - Bug fix
75+
- `docs:` - Documentation changes
76+
- `refactor:` - Code refactoring
77+
- `test:` - Adding or updating tests
78+
- `chore:` - Maintenance tasks
79+
- `perf:` - Performance improvements
80+
81+
### Examples
82+
83+
#### ✅ Good: Single-line conventional commits
84+
85+
```bash
86+
git commit -m "feat: add prefixEncoding and itemEncoding support for OpenAPI 3.2 multipart media types"
87+
git commit -m "fix: correct validation logic for encoding field mutual exclusivity"
88+
git commit -m "test: add comprehensive tests for multipart encoding validation"
89+
git commit -m "refactor: simplify media type context passing in validation"
90+
```
91+
92+
#### ❌ Bad: Multi-line commits
93+
94+
```bash
95+
git commit -m "feat: implement prefixEncoding and itemEncoding for OpenAPI 3.2
96+
97+
- Add PrefixEncoding and ItemEncoding fields to MediaType
98+
- Implement validation for mutual exclusivity
99+
- Add comprehensive tests"
100+
```
101+
102+
### Why Single-Line Commits?
103+
104+
1. **Simplicity**: Easy to read in git log and GitHub UI
105+
2. **Consistency**: All commits follow the same pattern
106+
3. **Searchability**: Easier to search and filter commits
107+
4. **Tool Compatibility**: Works better with automated tools and scripts
108+
61109
## Testing
62110

63111
Follow these testing conventions when writing Go tests in this project. Run newly added or modified test immediately after changes to make sure they work as expected before continuing with more work.

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
<!-- OpenAPI Hub Badge -->
2828
<a href="https://www.speakeasy.com/openapi"><img alt="OpenAPI Hub" src="https://www.speakeasy.com/assets/badges/openapi-hub.svg" /></a>
2929
<!-- OpenAPI Support Badge -->
30-
<a href="https://www.speakeasy.com/openapi"><img alt="OpenAPI Support" src="https://img.shields.io/badge/OpenAPI-3.0%20%7C%203.1-85EA2D.svg?style=for-the-badge&logo=openapiinitiative"></a>
30+
<a href="https://www.speakeasy.com/openapi"><img alt="OpenAPI Support" src="https://img.shields.io/badge/OpenAPI-3.0%20%7C%203.1%20%7C%203.2-85EA2D.svg?style=for-the-badge&logo=openapiinitiative"></a>
3131
<!-- Arazzo Support Badge -->
3232
<img alt="Arazzo Support" src="https://img.shields.io/badge/Arazzo-1.0-purple.svg?style=for-the-badge">
3333
<a href="https://pkg.go.dev/github.com/speakeasy-api/openapi?tab=doc"><img alt="Go Doc" src="https://img.shields.io/badge/godoc-reference-blue.svg?style=for-the-badge"></a>
@@ -68,7 +68,7 @@ The `arazzo` package provides an API for working with Arazzo documents including
6868

6969
### [openapi](./openapi)
7070

71-
The `openapi` package provides an API for working with OpenAPI documents including reading, creating, mutating, walking, validating and upgrading them. Supports both OpenAPI 3.0.x and 3.1.x specifications.
71+
The `openapi` package provides an API for working with OpenAPI documents including reading, creating, mutating, walking, validating and upgrading them. Supports OpenAPI 3.0.x, 3.1.x, and 3.2.x specifications.
7272

7373
### [swagger](./swagger)
7474

arazzo/arazzo.go

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111
"github.com/speakeasy-api/openapi/arazzo/core"
1212
"github.com/speakeasy-api/openapi/extensions"
1313
"github.com/speakeasy-api/openapi/internal/interfaces"
14-
"github.com/speakeasy-api/openapi/internal/utils"
14+
"github.com/speakeasy-api/openapi/internal/version"
1515
"github.com/speakeasy-api/openapi/jsonschema/oas3"
1616
"github.com/speakeasy-api/openapi/marshaller"
1717
"github.com/speakeasy-api/openapi/pointer"
@@ -20,10 +20,12 @@ import (
2020

2121
// Version is the version of the Arazzo Specification that this package conforms to.
2222
const (
23-
Version = "1.0.1"
24-
VersionMajor = 1
25-
VersionMinor = 0
26-
VersionPatch = 1
23+
Version = "1.0.1"
24+
)
25+
26+
var (
27+
MinimumSupportedVersion = version.MustParse("1.0.0")
28+
MaximumSupportedVersion = version.MustParse(Version)
2729
)
2830

2931
// Arazzo is the root object for an Arazzo document.
@@ -105,13 +107,14 @@ func (a *Arazzo) Validate(ctx context.Context, opts ...validation.Option) []erro
105107
core := a.GetCore()
106108
errs := []error{}
107109

108-
arazzoMajor, arazzoMinor, arazzoPatch, err := utils.ParseVersion(a.Arazzo)
110+
arazzoVersion, err := version.Parse(a.Arazzo)
109111
if err != nil {
110112
errs = append(errs, validation.NewValueError(validation.NewValueValidationError("arazzo.version is invalid %s: %s", a.Arazzo, err.Error()), core, core.Arazzo))
111113
}
112-
113-
if arazzoMajor != VersionMajor || arazzoMinor != VersionMinor || arazzoPatch > VersionPatch {
114-
errs = append(errs, validation.NewValueError(validation.NewValueValidationError("arazzo.version only %s and below is supported", Version), core, core.Arazzo))
114+
if arazzoVersion != nil {
115+
if arazzoVersion.GreaterThan(*MaximumSupportedVersion) {
116+
errs = append(errs, validation.NewValueError(validation.NewValueValidationError("arazzo.version only Arazzo versions between %s and %s are supported", MinimumSupportedVersion, MaximumSupportedVersion), core, core.Arazzo))
117+
}
115118
}
116119

117120
errs = append(errs, a.Info.Validate(ctx, opts...)...)

arazzo/arazzo_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ sourceDescriptions:
301301
underlyingError error
302302
}{
303303
{line: 1, column: 1, underlyingError: validation.NewMissingFieldError("arazzo.workflows is missing")},
304-
{line: 1, column: 9, underlyingError: validation.NewValueValidationError("arazzo.version only 1.0.1 and below is supported")},
304+
{line: 1, column: 9, underlyingError: validation.NewValueValidationError("arazzo.version only Arazzo versions between 1.0.0 and 1.0.1 are supported")},
305305
{line: 4, column: 3, underlyingError: validation.NewMissingFieldError("info.version is missing")},
306306
{line: 6, column: 5, underlyingError: validation.NewMissingFieldError("sourceDescription.url is missing")},
307307
{line: 7, column: 11, underlyingError: validation.NewValueValidationError("sourceDescription.type must be one of [openapi, arazzo]")},

cmd/openapi/commands/openapi/README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ This command checks for:
5050

5151
### `upgrade`
5252

53-
Upgrade an OpenAPI specification to the latest supported version (3.1.1).
53+
Upgrade an OpenAPI specification to the latest supported version (3.2.0).
5454

5555
```bash
5656
# Upgrade to stdout
@@ -64,11 +64,12 @@ openapi spec upgrade -w ./spec.yaml
6464

6565
# Upgrade with specific target version
6666
openapi spec upgrade --version 3.1.0 ./spec.yaml
67+
openapi spec upgrade --version 3.2.0 ./spec.yaml
6768
```
6869

6970
Features:
7071

71-
- Converts OpenAPI 3.0.x specifications to 3.1.x
72+
- Converts OpenAPI 3.0.x and 3.1.x specifications to 3.2.0
7273
- Maintains backward compatibility where possible
7374
- Updates schema formats and structures
7475
- Preserves all custom extensions and vendor-specific content
@@ -937,7 +938,7 @@ All commands work with both YAML and JSON input files and preserve the original
937938
openapi spec validate ./spec.yaml
938939
939940
# Upgrade if needed
940-
openapi spec upgrade ./spec.yaml ./spec-v3.1.yaml
941+
openapi spec upgrade ./spec.yaml ./spec-v3.2.yaml
941942
942943
# Bundle external references
943944
openapi spec bundle ./spec-v3.1.yaml ./spec-bundled.yaml

cmd/openapi/commands/openapi/upgrade.go

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,17 @@ import (
1313
var upgradeCmd = &cobra.Command{
1414
Use: "upgrade <input-file> [output-file]",
1515
Short: "Upgrade an OpenAPI specification to the latest supported version",
16-
Long: `Upgrade an OpenAPI specification document to the latest supported version (3.1.1).
16+
Long: `Upgrade an OpenAPI specification document to the latest supported version (3.2.0).
1717
18-
This command will upgrade OpenAPI documents from:
19-
- OpenAPI 3.0.x versions to 3.1.1 (always)
20-
- OpenAPI 3.1.x versions to 3.1.1 (by default)
21-
- Use --minor-only to only upgrade minor versions (3.0.x to 3.1.1, but skip 3.1.x versions)
18+
By default, upgrades all versions including patch-level upgrades:
19+
- 3.0.x → 3.2.0
20+
- 3.1.x → 3.2.0
21+
- 3.2.x (e.g., 3.2.0) → 3.2.0 (patch upgrade if newer patch exists)
22+
23+
With --minor-only, only performs cross-minor version upgrades:
24+
- 3.0.x → 3.2.0 (cross-minor upgrade)
25+
- 3.1.x → 3.2.0 (cross-minor upgrade)
26+
- 3.2.x → no change (same minor version, skip patch upgrades)
2227
2328
The upgrade process includes:
2429
- Updating the OpenAPI version field
@@ -40,7 +45,7 @@ var (
4045
)
4146

4247
func init() {
43-
upgradeCmd.Flags().BoolVar(&minorOnly, "minor-only", false, "only upgrade minor versions (3.0.x to 3.1.1, skip 3.1.x versions)")
48+
upgradeCmd.Flags().BoolVar(&minorOnly, "minor-only", false, "only upgrade across minor versions, skip patch-level upgrades within same minor")
4449
upgradeCmd.Flags().BoolVarP(&writeInPlace, "write", "w", false, "write result in-place to input file")
4550
}
4651

@@ -59,13 +64,13 @@ func runUpgrade(cmd *cobra.Command, args []string) {
5964
os.Exit(1)
6065
}
6166

62-
if err := upgradeOpenAPI(ctx, processor, minorOnly); err != nil {
67+
if err := upgradeOpenAPI(ctx, processor, !minorOnly); err != nil {
6368
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
6469
os.Exit(1)
6570
}
6671
}
6772

68-
func upgradeOpenAPI(ctx context.Context, processor *OpenAPIProcessor, minorOnly bool) error {
73+
func upgradeOpenAPI(ctx context.Context, processor *OpenAPIProcessor, upgradeSameMinorVersion bool) error {
6974
// Load the OpenAPI document
7075
doc, validationErrors, err := processor.LoadDocument(ctx)
7176
if err != nil {
@@ -80,12 +85,12 @@ func upgradeOpenAPI(ctx context.Context, processor *OpenAPIProcessor, minorOnly
8085

8186
// Prepare upgrade options
8287
var opts []openapi.Option[openapi.UpgradeOptions]
83-
if !minorOnly {
84-
// By default, upgrade all versions including patch versions (3.1.x to 3.1.1)
85-
opts = append(opts, openapi.WithUpgradeSamePatchVersion())
88+
if upgradeSameMinorVersion {
89+
// By default, upgrade all versions including patch upgrades (e.g., 3.2.0 → 3.2.1)
90+
opts = append(opts, openapi.WithUpgradeSameMinorVersion())
8691
}
87-
// When minorOnly is true, only 3.0.x versions will be upgraded to 3.1.1
88-
// 3.1.x versions will be skipped unless they need minor version upgrade
92+
// When minorOnly is true, only cross-minor upgrades are performed
93+
// Patch upgrades within the same minor version (e.g., 3.2.0 → 3.2.1) are skipped
8994

9095
// Perform the upgrade
9196
originalVersion := doc.OpenAPI

cmd/openapi/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ This CLI provides tools for:
6767
6868
OpenAPI Specifications:
6969
- Validate OpenAPI specification documents for compliance
70-
- Upgrade OpenAPI specs to the latest supported version (3.1.1)
70+
- Upgrade OpenAPI specs to the latest supported version (3.2.0)
7171
- Inline all references to create self-contained documents
7272
- Bundle external references into components section while preserving structure
7373

internal/utils/versions.go

Lines changed: 0 additions & 40 deletions
This file was deleted.

0 commit comments

Comments
 (0)