diff --git a/cli/pom.xml b/cli/pom.xml
index afbc6b7a..cdc684fe 100644
--- a/cli/pom.xml
+++ b/cli/pom.xml
@@ -4,7 +4,7 @@
org.openapitools.openapidiff
openapi-diff-parent
- 2.1.4
+ 2.1.5
openapi-diff-cli
diff --git a/core/pom.xml b/core/pom.xml
index 4b79a2d6..3856a5fe 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -4,7 +4,7 @@
org.openapitools.openapidiff
openapi-diff-parent
- 2.1.4
+ 2.1.5
openapi-diff-core
diff --git a/core/src/main/java/org/openapitools/openapidiff/core/model/BackwardIncompatibleProp.java b/core/src/main/java/org/openapitools/openapidiff/core/model/BackwardIncompatibleProp.java
index 0772eace..f2180b34 100644
--- a/core/src/main/java/org/openapitools/openapidiff/core/model/BackwardIncompatibleProp.java
+++ b/core/src/main/java/org/openapitools/openapidiff/core/model/BackwardIncompatibleProp.java
@@ -52,8 +52,10 @@ public enum BackwardIncompatibleProp {
SECURITY_SCHEME_SCHEME_CHANGED("incompatible.security.scheme.scheme.changed", true),
SECURITY_SCHEME_SCOPES_INCREASED("incompatible.security.scheme.scopes.increased", true),
SCHEMA_DISCRIMINATOR_CHANGED("incompatible.schema.discriminator.changed", true),
- SCHEMA_TYPE_CHANGED("incompatible.schema.type.changed", true),
SCHEMA_PATTERN_CHANGED("incompatible.schema.pattern.changed", true),
+ SCHEMA_MIN_PROPERTIES_CHANGED("incompatible.schema.min-properties.changed", true),
+ SCHEMA_MAX_PROPERTIES_CHANGED("incompatible.schema.max-properties.changed", true),
+ SCHEMA_TYPE_CHANGED("incompatible.schema.type.changed", true),
;
private final String propertyName;
diff --git a/core/src/main/java/org/openapitools/openapidiff/core/model/schema/ChangedMaxProperties.java b/core/src/main/java/org/openapitools/openapidiff/core/model/schema/ChangedMaxProperties.java
index c4c56af3..8c5dce25 100644
--- a/core/src/main/java/org/openapitools/openapidiff/core/model/schema/ChangedMaxProperties.java
+++ b/core/src/main/java/org/openapitools/openapidiff/core/model/schema/ChangedMaxProperties.java
@@ -1,5 +1,7 @@
package org.openapitools.openapidiff.core.model.schema;
+import static org.openapitools.openapidiff.core.model.BackwardIncompatibleProp.SCHEMA_MAX_PROPERTIES_CHANGED;
+
import org.openapitools.openapidiff.core.model.Changed;
import org.openapitools.openapidiff.core.model.DiffContext;
import org.openapitools.openapidiff.core.model.DiffResult;
@@ -30,7 +32,11 @@ public DiffResult isChanged() {
}
if (oldValue == null) {
- return DiffResult.INCOMPATIBLE;
+ if (SCHEMA_MAX_PROPERTIES_CHANGED.enabled(context)) {
+ return DiffResult.INCOMPATIBLE;
+ } else {
+ return DiffResult.COMPATIBLE;
+ }
}
if (newValue == null) {
@@ -38,7 +44,11 @@ public DiffResult isChanged() {
}
if (!oldValue.equals(newValue)) {
- return oldValue > newValue ? DiffResult.INCOMPATIBLE : DiffResult.COMPATIBLE;
+ if (SCHEMA_MAX_PROPERTIES_CHANGED.enabled(context) && oldValue > newValue) {
+ return DiffResult.INCOMPATIBLE;
+ } else {
+ return DiffResult.COMPATIBLE;
+ }
}
return DiffResult.NO_CHANGES;
diff --git a/core/src/main/java/org/openapitools/openapidiff/core/model/schema/ChangedMinProperties.java b/core/src/main/java/org/openapitools/openapidiff/core/model/schema/ChangedMinProperties.java
index f574b5c8..16059593 100644
--- a/core/src/main/java/org/openapitools/openapidiff/core/model/schema/ChangedMinProperties.java
+++ b/core/src/main/java/org/openapitools/openapidiff/core/model/schema/ChangedMinProperties.java
@@ -1,5 +1,7 @@
package org.openapitools.openapidiff.core.model.schema;
+import static org.openapitools.openapidiff.core.model.BackwardIncompatibleProp.SCHEMA_MIN_PROPERTIES_CHANGED;
+
import org.openapitools.openapidiff.core.model.Changed;
import org.openapitools.openapidiff.core.model.DiffContext;
import org.openapitools.openapidiff.core.model.DiffResult;
@@ -30,7 +32,11 @@ public DiffResult isChanged() {
}
if (oldValue == null) {
- return DiffResult.INCOMPATIBLE;
+ if (SCHEMA_MIN_PROPERTIES_CHANGED.enabled(context)) {
+ return DiffResult.INCOMPATIBLE;
+ } else {
+ return DiffResult.COMPATIBLE;
+ }
}
if (newValue == null) {
@@ -38,7 +44,11 @@ public DiffResult isChanged() {
}
if (!oldValue.equals(newValue)) {
- return newValue > oldValue ? DiffResult.INCOMPATIBLE : DiffResult.COMPATIBLE;
+ if (SCHEMA_MIN_PROPERTIES_CHANGED.enabled(context) && newValue > oldValue) {
+ return DiffResult.INCOMPATIBLE;
+ } else {
+ return DiffResult.COMPATIBLE;
+ }
}
return DiffResult.NO_CHANGES;
diff --git a/core/src/test/java/org/openapitools/openapidiff/core/backcompat/SchemaBCTest.java b/core/src/test/java/org/openapitools/openapidiff/core/backcompat/SchemaBCTest.java
index 28d6d398..f4d624b6 100644
--- a/core/src/test/java/org/openapitools/openapidiff/core/backcompat/SchemaBCTest.java
+++ b/core/src/test/java/org/openapitools/openapidiff/core/backcompat/SchemaBCTest.java
@@ -4,10 +4,7 @@
import static org.openapitools.openapidiff.core.TestUtils.assertSpecChangedButCompatible;
import static org.openapitools.openapidiff.core.TestUtils.assertSpecIncompatible;
import static org.openapitools.openapidiff.core.TestUtils.assertSpecUnchanged;
-import static org.openapitools.openapidiff.core.model.BackwardIncompatibleProp.RESPONSE_REQUIRED_DECREASED;
-import static org.openapitools.openapidiff.core.model.BackwardIncompatibleProp.SCHEMA_DISCRIMINATOR_CHANGED;
-import static org.openapitools.openapidiff.core.model.BackwardIncompatibleProp.SCHEMA_PATTERN_CHANGED;
-import static org.openapitools.openapidiff.core.model.BackwardIncompatibleProp.SCHEMA_TYPE_CHANGED;
+import static org.openapitools.openapidiff.core.model.BackwardIncompatibleProp.*;
import org.junit.jupiter.api.Test;
import org.openapitools.openapidiff.core.model.BackwardIncompatibleProp;
@@ -76,4 +73,28 @@ public void patternChanged() {
BackwardIncompatibleProp prop = SCHEMA_PATTERN_CHANGED;
assertSpecIncompatible(BASE, "bc_schema_pattern_changed.yaml", prop);
}
+
+ @Test
+ public void minPropertiesIncreased() {
+ BackwardIncompatibleProp prop = SCHEMA_MIN_PROPERTIES_CHANGED;
+ assertSpecIncompatible(BASE, "bc_schema_min_properties_increased.yaml", prop);
+ }
+
+ @Test
+ public void minPropertiesAdded() {
+ BackwardIncompatibleProp prop = SCHEMA_MIN_PROPERTIES_CHANGED;
+ assertSpecIncompatible(BASE, "bc_schema_min_properties_added.yaml", prop);
+ }
+
+ @Test
+ public void maxPropertiesDecreased() {
+ BackwardIncompatibleProp prop = SCHEMA_MAX_PROPERTIES_CHANGED;
+ assertSpecIncompatible(BASE, "bc_schema_max_properties_decreased.yaml", prop);
+ }
+
+ @Test
+ public void maxPropertiesAdded() {
+ BackwardIncompatibleProp prop = SCHEMA_MAX_PROPERTIES_CHANGED;
+ assertSpecIncompatible(BASE, "bc_schema_max_properties_added.yaml", prop);
+ }
}
diff --git a/core/src/test/resources/bc_schema_base.yaml b/core/src/test/resources/bc_schema_base.yaml
index 28d8800d..79c9aa69 100644
--- a/core/src/test/resources/bc_schema_base.yaml
+++ b/core/src/test/resources/bc_schema_base.yaml
@@ -86,6 +86,16 @@ components:
type: integer
format: int32
deprecated: true
+ stuffUnbounded:
+ type: object
+ additionalProperties:
+ type: string
+ stuffBounded:
+ type: object
+ minProperties: 1
+ maxProperties: 10
+ additionalProperties:
+ type: string
required:
- '@type'
- prop1
diff --git a/core/src/test/resources/bc_schema_max_properties_added.yaml b/core/src/test/resources/bc_schema_max_properties_added.yaml
new file mode 100644
index 00000000..670f5afe
--- /dev/null
+++ b/core/src/test/resources/bc_schema_max_properties_added.yaml
@@ -0,0 +1,126 @@
+openapi: 3.0.0
+info:
+ description: myDesc
+ title: myTitle
+ version: 1.0.0
+paths:
+ /widgets:
+ post:
+ operationId: widgetCreate
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/WidgetCreateRequest'
+ responses:
+ '200':
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/WidgetCreateResponse'
+ put:
+ operationId: widgetUpdate
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ put_prop1:
+ type: string
+ put_prop2:
+ type: string
+ responses:
+ '200':
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ type: string
+components:
+ schemas:
+ WidgetCreateRequest:
+ type: object
+ properties:
+ to_create:
+ $ref: '#/components/schemas/Widget_Polymorphic'
+ request_prop1:
+ type: integer
+ format: int32
+ request_prop2:
+ type: integer
+ format: int64
+ required:
+ - to_create
+ - request_prop1
+ WidgetCreateResponse:
+ type: object
+ properties:
+ created:
+ $ref: '#/components/schemas/Widget_Polymorphic'
+ response_prop1:
+ type: integer
+ format: int32
+ response_prop2:
+ type: integer
+ format: int64
+ required:
+ - created
+ - response_prop1
+ Widget_Polymorphic:
+ type: object
+ oneOf:
+ - $ref: '#/components/schemas/Doodad'
+ - $ref: '#/components/schemas/Gadget'
+ discriminator:
+ propertyName: '@type'
+ Widget:
+ type: object
+ properties:
+ '@type':
+ type: string
+ prop1:
+ type: string
+ prop2:
+ type: integer
+ format: int32
+ deprecated: true
+ stuffUnbounded:
+ type: object
+ maxProperties: 5
+ additionalProperties:
+ type: string
+ stuffBounded:
+ type: object
+ minProperties: 1
+ maxProperties: 10
+ additionalProperties:
+ type: string
+ required:
+ - '@type'
+ - prop1
+ Doodad:
+ type: object
+ allOf:
+ - $ref: '#/components/schemas/Widget'
+ - type: object
+ properties:
+ doodad_prop1:
+ type: string
+ Gadget:
+ type: object
+ allOf:
+ - $ref: '#/components/schemas/Widget'
+ - type: object
+ properties:
+ gadget_prop1:
+ type: string
+ Gizmo:
+ type: object
+ allOf:
+ - $ref: '#/components/schemas/Widget'
+ - type: object
+ properties:
+ gizmo_prop1:
+ type: string
diff --git a/core/src/test/resources/bc_schema_max_properties_decreased.yaml b/core/src/test/resources/bc_schema_max_properties_decreased.yaml
new file mode 100644
index 00000000..a4b86071
--- /dev/null
+++ b/core/src/test/resources/bc_schema_max_properties_decreased.yaml
@@ -0,0 +1,125 @@
+openapi: 3.0.0
+info:
+ description: myDesc
+ title: myTitle
+ version: 1.0.0
+paths:
+ /widgets:
+ post:
+ operationId: widgetCreate
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/WidgetCreateRequest'
+ responses:
+ '200':
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/WidgetCreateResponse'
+ put:
+ operationId: widgetUpdate
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ put_prop1:
+ type: string
+ put_prop2:
+ type: string
+ responses:
+ '200':
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ type: string
+components:
+ schemas:
+ WidgetCreateRequest:
+ type: object
+ properties:
+ to_create:
+ $ref: '#/components/schemas/Widget_Polymorphic'
+ request_prop1:
+ type: integer
+ format: int32
+ request_prop2:
+ type: integer
+ format: int64
+ required:
+ - to_create
+ - request_prop1
+ WidgetCreateResponse:
+ type: object
+ properties:
+ created:
+ $ref: '#/components/schemas/Widget_Polymorphic'
+ response_prop1:
+ type: integer
+ format: int32
+ response_prop2:
+ type: integer
+ format: int64
+ required:
+ - created
+ - response_prop1
+ Widget_Polymorphic:
+ type: object
+ oneOf:
+ - $ref: '#/components/schemas/Doodad'
+ - $ref: '#/components/schemas/Gadget'
+ discriminator:
+ propertyName: '@type'
+ Widget:
+ type: object
+ properties:
+ '@type':
+ type: string
+ prop1:
+ type: string
+ prop2:
+ type: integer
+ format: int32
+ deprecated: true
+ stuffUnbounded:
+ type: object
+ additionalProperties:
+ type: string
+ stuffBounded:
+ type: object
+ minProperties: 1
+ maxProperties: 5
+ additionalProperties:
+ type: string
+ required:
+ - '@type'
+ - prop1
+ Doodad:
+ type: object
+ allOf:
+ - $ref: '#/components/schemas/Widget'
+ - type: object
+ properties:
+ doodad_prop1:
+ type: string
+ Gadget:
+ type: object
+ allOf:
+ - $ref: '#/components/schemas/Widget'
+ - type: object
+ properties:
+ gadget_prop1:
+ type: string
+ Gizmo:
+ type: object
+ allOf:
+ - $ref: '#/components/schemas/Widget'
+ - type: object
+ properties:
+ gizmo_prop1:
+ type: string
diff --git a/core/src/test/resources/bc_schema_min_properties_added.yaml b/core/src/test/resources/bc_schema_min_properties_added.yaml
new file mode 100644
index 00000000..5398280c
--- /dev/null
+++ b/core/src/test/resources/bc_schema_min_properties_added.yaml
@@ -0,0 +1,126 @@
+openapi: 3.0.0
+info:
+ description: myDesc
+ title: myTitle
+ version: 1.0.0
+paths:
+ /widgets:
+ post:
+ operationId: widgetCreate
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/WidgetCreateRequest'
+ responses:
+ '200':
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/WidgetCreateResponse'
+ put:
+ operationId: widgetUpdate
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ put_prop1:
+ type: string
+ put_prop2:
+ type: string
+ responses:
+ '200':
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ type: string
+components:
+ schemas:
+ WidgetCreateRequest:
+ type: object
+ properties:
+ to_create:
+ $ref: '#/components/schemas/Widget_Polymorphic'
+ request_prop1:
+ type: integer
+ format: int32
+ request_prop2:
+ type: integer
+ format: int64
+ required:
+ - to_create
+ - request_prop1
+ WidgetCreateResponse:
+ type: object
+ properties:
+ created:
+ $ref: '#/components/schemas/Widget_Polymorphic'
+ response_prop1:
+ type: integer
+ format: int32
+ response_prop2:
+ type: integer
+ format: int64
+ required:
+ - created
+ - response_prop1
+ Widget_Polymorphic:
+ type: object
+ oneOf:
+ - $ref: '#/components/schemas/Doodad'
+ - $ref: '#/components/schemas/Gadget'
+ discriminator:
+ propertyName: '@type'
+ Widget:
+ type: object
+ properties:
+ '@type':
+ type: string
+ prop1:
+ type: string
+ prop2:
+ type: integer
+ format: int32
+ deprecated: true
+ stuffUnbounded:
+ type: object
+ minProperties: 5
+ additionalProperties:
+ type: string
+ stuffBounded:
+ type: object
+ minProperties: 1
+ maxProperties: 10
+ additionalProperties:
+ type: string
+ required:
+ - '@type'
+ - prop1
+ Doodad:
+ type: object
+ allOf:
+ - $ref: '#/components/schemas/Widget'
+ - type: object
+ properties:
+ doodad_prop1:
+ type: string
+ Gadget:
+ type: object
+ allOf:
+ - $ref: '#/components/schemas/Widget'
+ - type: object
+ properties:
+ gadget_prop1:
+ type: string
+ Gizmo:
+ type: object
+ allOf:
+ - $ref: '#/components/schemas/Widget'
+ - type: object
+ properties:
+ gizmo_prop1:
+ type: string
diff --git a/core/src/test/resources/bc_schema_min_properties_increased.yaml b/core/src/test/resources/bc_schema_min_properties_increased.yaml
new file mode 100644
index 00000000..0236a1b1
--- /dev/null
+++ b/core/src/test/resources/bc_schema_min_properties_increased.yaml
@@ -0,0 +1,125 @@
+openapi: 3.0.0
+info:
+ description: myDesc
+ title: myTitle
+ version: 1.0.0
+paths:
+ /widgets:
+ post:
+ operationId: widgetCreate
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/WidgetCreateRequest'
+ responses:
+ '200':
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/WidgetCreateResponse'
+ put:
+ operationId: widgetUpdate
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ put_prop1:
+ type: string
+ put_prop2:
+ type: string
+ responses:
+ '200':
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ type: string
+components:
+ schemas:
+ WidgetCreateRequest:
+ type: object
+ properties:
+ to_create:
+ $ref: '#/components/schemas/Widget_Polymorphic'
+ request_prop1:
+ type: integer
+ format: int32
+ request_prop2:
+ type: integer
+ format: int64
+ required:
+ - to_create
+ - request_prop1
+ WidgetCreateResponse:
+ type: object
+ properties:
+ created:
+ $ref: '#/components/schemas/Widget_Polymorphic'
+ response_prop1:
+ type: integer
+ format: int32
+ response_prop2:
+ type: integer
+ format: int64
+ required:
+ - created
+ - response_prop1
+ Widget_Polymorphic:
+ type: object
+ oneOf:
+ - $ref: '#/components/schemas/Doodad'
+ - $ref: '#/components/schemas/Gadget'
+ discriminator:
+ propertyName: '@type'
+ Widget:
+ type: object
+ properties:
+ '@type':
+ type: string
+ prop1:
+ type: string
+ prop2:
+ type: integer
+ format: int32
+ deprecated: true
+ stuffUnbounded:
+ type: object
+ additionalProperties:
+ type: string
+ stuffBounded:
+ type: object
+ minProperties: 5
+ maxProperties: 10
+ additionalProperties:
+ type: string
+ required:
+ - '@type'
+ - prop1
+ Doodad:
+ type: object
+ allOf:
+ - $ref: '#/components/schemas/Widget'
+ - type: object
+ properties:
+ doodad_prop1:
+ type: string
+ Gadget:
+ type: object
+ allOf:
+ - $ref: '#/components/schemas/Widget'
+ - type: object
+ properties:
+ gadget_prop1:
+ type: string
+ Gizmo:
+ type: object
+ allOf:
+ - $ref: '#/components/schemas/Widget'
+ - type: object
+ properties:
+ gizmo_prop1:
+ type: string
diff --git a/maven-example/pom.xml b/maven-example/pom.xml
index 064c4056..b6938325 100644
--- a/maven-example/pom.xml
+++ b/maven-example/pom.xml
@@ -3,7 +3,7 @@
openapi-diff-parent
org.openapitools.openapidiff
- 2.1.4
+ 2.1.5
4.0.0
@@ -23,7 +23,7 @@
org.openapitools.openapidiff
openapi-diff-maven
- 2.1.4
+ 2.1.5
diff --git a/maven/pom.xml b/maven/pom.xml
index 4c398bc1..79a072c4 100644
--- a/maven/pom.xml
+++ b/maven/pom.xml
@@ -5,7 +5,7 @@
org.openapitools.openapidiff
openapi-diff-parent
- 2.1.4
+ 2.1.5
openapi-diff-maven
diff --git a/pom.xml b/pom.xml
index 5989b9bc..6187f0f0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -9,7 +9,7 @@
org.openapitools.openapidiff
openapi-diff-parent
- 2.1.4
+ 2.1.5
pom
openapi-diff-parent
@@ -82,7 +82,7 @@
1.8
UTF-8
UTF-8
- 2025-10-14T20:47:24Z
+ 2025-11-03T08:59:15Z
github
openapitools
@@ -99,7 +99,7 @@
org.openapitools.openapidiff
openapi-diff-core
- 2.1.4
+ 2.1.5
org.junit
@@ -349,7 +349,7 @@
org.jacoco
jacoco-maven-plugin
- 0.8.13
+ 0.8.14
org.sonarsource.scanner.maven