@@ -29,6 +29,12 @@ With --minor-only, only performs cross-minor version upgrades:
2929- 3.1.x → 3.2.0 (cross-minor upgrade)
3030- 3.2.x → no change (same minor version, skip patch upgrades)
3131
32+ With --version, upgrades to a specific OpenAPI version instead of the latest:
33+ - openapi spec upgrade --version 3.1.0 spec.yaml
34+ (upgrades a 3.0.x spec to 3.1.0)
35+
36+ Note: --version and --minor-only are mutually exclusive.
37+
3238The upgrade process includes:
3339- Updating the OpenAPI version field
3440- Converting nullable properties to proper JSON Schema format
@@ -44,19 +50,26 @@ Output options:
4450}
4551
4652var (
47- minorOnly bool
48- writeInPlace bool
53+ minorOnly bool
54+ writeInPlace bool
55+ targetVersion string
4956)
5057
5158func init () {
5259 upgradeCmd .Flags ().BoolVar (& minorOnly , "minor-only" , false , "only upgrade across minor versions, skip patch-level upgrades within same minor" )
5360 upgradeCmd .Flags ().BoolVarP (& writeInPlace , "write" , "w" , false , "write result in-place to input file" )
61+ upgradeCmd .Flags ().StringVarP (& targetVersion , "version" , "V" , "" , "target OpenAPI version to upgrade to (default latest)" )
5462}
5563
5664func runUpgrade (cmd * cobra.Command , args []string ) {
5765 ctx := cmd .Context ()
5866 inputFile := inputFileFromArgs (args )
5967
68+ if targetVersion != "" && minorOnly {
69+ fmt .Fprintf (os .Stderr , "Error: --version and --minor-only are mutually exclusive\n " )
70+ os .Exit (1 )
71+ }
72+
6073 outputFile := outputFileFromArgs (args )
6174
6275 processor , err := NewOpenAPIProcessor (inputFile , outputFile , writeInPlace )
@@ -65,13 +78,27 @@ func runUpgrade(cmd *cobra.Command, args []string) {
6578 os .Exit (1 )
6679 }
6780
68- if err := upgradeOpenAPI (ctx , processor , ! minorOnly ); err != nil {
81+ var opts []openapi.Option [openapi.UpgradeOptions ]
82+ if targetVersion != "" {
83+ opts = append (opts , openapi .WithUpgradeTargetVersion (targetVersion ))
84+ // Enable same-minor upgrades so patch-level targets work as expected.
85+ // Without this, --version 3.1.2 on a 3.1.0 doc would be silently
86+ // skipped because they share the same minor version.
87+ opts = append (opts , openapi .WithUpgradeSameMinorVersion ())
88+ } else if ! minorOnly {
89+ // By default, upgrade all versions including patch upgrades (e.g., 3.2.0 → 3.2.1)
90+ opts = append (opts , openapi .WithUpgradeSameMinorVersion ())
91+ }
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
94+
95+ if err := upgradeOpenAPI (ctx , processor , opts ... ); err != nil {
6996 fmt .Fprintf (os .Stderr , "Error: %v\n " , err )
7097 os .Exit (1 )
7198 }
7299}
73100
74- func upgradeOpenAPI (ctx context.Context , processor * OpenAPIProcessor , upgradeSameMinorVersion bool ) error {
101+ func upgradeOpenAPI (ctx context.Context , processor * OpenAPIProcessor , opts ... openapi. Option [openapi. UpgradeOptions ] ) error {
75102 // Load the OpenAPI document
76103 doc , validationErrors , err := processor .LoadDocument (ctx )
77104 if err != nil {
@@ -84,15 +111,6 @@ func upgradeOpenAPI(ctx context.Context, processor *OpenAPIProcessor, upgradeSam
84111 // Report validation errors but continue with upgrade
85112 processor .ReportValidationErrors (validationErrors )
86113
87- // Prepare upgrade options
88- var opts []openapi.Option [openapi.UpgradeOptions ]
89- if upgradeSameMinorVersion {
90- // By default, upgrade all versions including patch upgrades (e.g., 3.2.0 → 3.2.1)
91- opts = append (opts , openapi .WithUpgradeSameMinorVersion ())
92- }
93- // When minorOnly is true, only cross-minor upgrades are performed
94- // Patch upgrades within the same minor version (e.g., 3.2.0 → 3.2.1) are skipped
95-
96114 // Perform the upgrade
97115 originalVersion := doc .OpenAPI
98116 upgraded , err := openapi .Upgrade (ctx , doc , opts ... )
0 commit comments