Skip to content

Commit 60e8856

Browse files
committed
resolve merge conflicts and clean issues
2 parents d920e68 + d509c87 commit 60e8856

File tree

8 files changed

+163
-112
lines changed

8 files changed

+163
-112
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [1.2.3] - 2025-11-17
9+
10+
### Fixed
11+
- OAR031 - ExamplesCheck
12+
813
## [1.2.2] - 2025-11-04
914

1015
### Fixed

pom.xml

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<modelVersion>4.0.0</modelVersion>
44
<groupId>org.apiaddicts.apitools.dosonarapi</groupId>
55
<artifactId>sonaropenapi-rules-community</artifactId>
6-
<version>1.2.2</version>
6+
<version>1.2.3</version>
77
<packaging>sonar-plugin</packaging>
88

99
<name>SonarQube OpenAPI Community Rules</name>
@@ -148,17 +148,18 @@
148148
</dependencies>
149149
</plugin>
150150

151-
<plugin>
152-
<groupId>org.sonatype.plugins</groupId>
153-
<artifactId>nexus-staging-maven-plugin</artifactId>
154-
<version>1.6.13</version>
155-
<extensions>true</extensions>
156-
<configuration>
157-
<serverId>ossrh</serverId>
158-
<nexusUrl>https://s01.oss.sonatype.org/</nexusUrl>
159-
<autoReleaseAfterClose>true</autoReleaseAfterClose>
160-
</configuration>
161-
</plugin>
151+
<!-- To release to Maven central -->
152+
<plugin>
153+
<groupId>org.sonatype.central</groupId>
154+
<artifactId>central-publishing-maven-plugin</artifactId>
155+
<version>0.8.0</version>
156+
<extensions>true</extensions>
157+
<configuration>
158+
<publishingServerId>ossrh</publishingServerId>
159+
<autoPublish>true</autoPublish>
160+
<waitUntil>published</waitUntil>
161+
</configuration>
162+
</plugin>
162163

163164
<plugin>
164165
<groupId>org.apache.maven.plugins</groupId>

src/main/java/apiaddicts/sonar/openapi/checks/examples/OAR031ExamplesCheck.java

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,23 @@
11
package apiaddicts.sonar.openapi.checks.examples;
22

3+
import apiaddicts.sonar.openapi.checks.BaseCheck;
4+
import static apiaddicts.sonar.openapi.utils.JsonNodeUtils.getType;
5+
import static apiaddicts.sonar.openapi.utils.JsonNodeUtils.isArrayType;
6+
import static apiaddicts.sonar.openapi.utils.JsonNodeUtils.isExternalRef;
7+
import static apiaddicts.sonar.openapi.utils.JsonNodeUtils.isObjectType;
8+
import static apiaddicts.sonar.openapi.utils.JsonNodeUtils.isOperation;
9+
import static apiaddicts.sonar.openapi.utils.JsonNodeUtils.resolve;
310
import com.google.common.collect.ImmutableSet;
411
import com.sonar.sslr.api.AstNodeType;
5-
import org.sonar.check.Rule;
6-
import org.apiaddicts.apitools.dosonarapi.api.v2.OpenApi2Grammar;
7-
import org.apiaddicts.apitools.dosonarapi.api.v3.OpenApi3Grammar;
8-
import org.apiaddicts.apitools.dosonarapi.api.v31.OpenApi31Grammar;
9-
import apiaddicts.sonar.openapi.checks.BaseCheck;
10-
import org.apiaddicts.apitools.dosonarapi.sslr.yaml.grammar.JsonNode;
11-
1212
import java.util.List;
1313
import java.util.Map;
1414
import java.util.Set;
1515
import java.util.stream.Collectors;
16-
17-
import static apiaddicts.sonar.openapi.utils.JsonNodeUtils.*;
16+
import org.apiaddicts.apitools.dosonarapi.api.v2.OpenApi2Grammar;
17+
import org.apiaddicts.apitools.dosonarapi.api.v3.OpenApi3Grammar;
18+
import org.apiaddicts.apitools.dosonarapi.api.v31.OpenApi31Grammar;
19+
import org.apiaddicts.apitools.dosonarapi.sslr.yaml.grammar.JsonNode;
20+
import org.sonar.check.Rule;
1821

1922
@Rule(key = OAR031ExamplesCheck.KEY)
2023
public class OAR031ExamplesCheck extends BaseCheck {
@@ -52,7 +55,9 @@ private void visitV2Node(JsonNode node) {
5255
}
5356
responseNode = resolve(responseNode);
5457
visitResponseV2Node(responseNode);
55-
if (externalRefManagement) externalRefNode = null;
58+
if (externalRefManagement) {
59+
externalRefNode = null;
60+
}
5661
}
5762
}
5863
}
@@ -80,8 +85,10 @@ private void visitV3Node(JsonNode node) {
8085
}
8186
responseNode = resolve(responseNode);
8287
visitRequestBodyOrResponseV3Node(responseNode);
83-
if (externalRefManagement) externalRefNode = null;
84-
}
88+
if (externalRefManagement) {
89+
externalRefNode = null;
90+
}
91+
}
8592
}
8693
} else if (type.equals(OpenApi3Grammar.SCHEMA)) {
8794
visitSchemaNode(node);
@@ -92,7 +99,9 @@ private void visitV3Node(JsonNode node) {
9299

93100
private void visitRequestBodyOrResponseV3Node(JsonNode node) {
94101
JsonNode content = node.at("/content");
95-
if (content.isMissing()) return;
102+
if (content.isMissing()) {
103+
return;
104+
}
96105
for (JsonNode mediaTypeNode : content.propertyMap().values()) {
97106
AstNodeType type = node.getType();
98107
JsonNode schemaNode = mediaTypeNode.get("schema");
@@ -117,8 +126,13 @@ private void visitSchemaNode(JsonNode node) {
117126
if (node.get("example").isMissing() && parentNode.get("example").isMissing() && parentNode.get("examples").isMissing()) {
118127
addIssue(KEY, translate("OAR031.error-parameter"), parentNode);
119128
}
120-
} else if (parentNode.getType().equals(OpenApi3Grammar.SCHEMA_PROPERTIES) ||
121-
parentNode.getType().toString().equals("BLOCK_MAPPING") || parentNode.getType().toString().equals("FLOW_MAPPING")) {
129+
} else if (parentNode.getType().equals(OpenApi3Grammar.SCHEMA_PROPERTIES)
130+
|| parentNode.getType().toString().equals("BLOCK_MAPPING") || parentNode.getType().toString().equals("FLOW_MAPPING")) {
131+
JsonNode schemaParent = (JsonNode) parentNode.getParent().getParent();
132+
if (schemaParent != null && !schemaParent.get("allOf").isMissing()) {
133+
return;
134+
}
135+
122136
JsonNode type = getType(node);
123137
if (!isObjectType(type) && !type.isMissing() && !isArrayType(type)) {
124138
if (node.get("example").isMissing()) {
@@ -129,7 +143,7 @@ private void visitSchemaNode(JsonNode node) {
129143
}
130144

131145
private void visitPathNode(JsonNode node) {
132-
List<JsonNode> allResponses = node.properties().stream().filter(propertyNode -> isOperation(propertyNode))
146+
List<JsonNode> allResponses = node.properties().stream().filter(propertyNode -> isOperation(propertyNode))
133147
.map(JsonNode::value)
134148
.flatMap(n -> n.properties().stream())
135149
.map(JsonNode::value)
@@ -148,15 +162,21 @@ private void visitPathNode(JsonNode node) {
148162
} else if (responseNode.getType().equals(OpenApi3Grammar.RESPONSE)) {
149163
JsonNode content = responseNode.at("/content");
150164
if (content.isMissing()) {
151-
if (externalRefManagement) externalRefNode = null;
165+
if (externalRefManagement) {
166+
externalRefNode = null;
167+
}
152168
continue;
153169
}
154170
content.propertyMap().forEach((mediaType, mediaTypeNode) -> { // estudiar función lambda
155-
if (!mediaType.toLowerCase().contains("json")) return;
156-
visitSchemaNode2(mediaTypeNode);
171+
if (!mediaType.toLowerCase().contains("json")) {
172+
return;
173+
}
174+
visitSchemaNode(mediaTypeNode);
157175
});
158176
}
159-
if (externalRefManagement) externalRefNode = null;
177+
if (externalRefManagement) {
178+
externalRefNode = null;
179+
}
160180
}
161181
}
162182

src/main/java/apiaddicts/sonar/openapi/checks/format/AbstractDefaultMediaTypeCheck.java

Lines changed: 43 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package apiaddicts.sonar.openapi.checks.format;
22

33
import apiaddicts.sonar.openapi.checks.BaseCheck;
4-
import static apiaddicts.sonar.openapi.utils.JsonNodeUtils.isExternalRef;
5-
import static apiaddicts.sonar.openapi.utils.JsonNodeUtils.resolve;
4+
import apiaddicts.sonar.openapi.utils.MediaTypeUtils;
5+
66
import com.google.common.collect.ImmutableSet;
77
import com.sonar.sslr.api.AstNode;
88
import com.sonar.sslr.api.AstNodeType;
@@ -73,63 +73,58 @@ public void visitNode(JsonNode node) {
7373
}
7474

7575
private void visitV2Node(JsonNode node) {
76-
if(node.getType() == OpenApi2Grammar.OPERATION){
77-
String operation = node.key().getTokenValue().toLowerCase();
78-
if (operation.equals("post") || operation.equals("put") || operation.equals("patch")){
79-
JsonNode sectionNode = node.get(section);
80-
boolean definesMimeTypes = !sectionNode.isMissing();
81-
82-
if (definesMimeTypes) {
83-
if (!supportsDefaultMimeTypeV2(node)) {
84-
addIssue(key, message, sectionNode.key());
85-
}
86-
} else {
87-
if (!globalSupportsDefaultMimeType) {
88-
addIssue(key, message, node.key());
89-
}
90-
}
91-
}
92-
}
76+
if (node.getType() != OpenApi2Grammar.OPERATION) return;
77+
78+
String operation = node.key().getTokenValue().toLowerCase();
79+
if (!(operation.equals("post") || operation.equals("put") || operation.equals("patch"))) return;
80+
81+
JsonNode sectionNode = node.get(section);
82+
boolean definesMimeTypes = !sectionNode.isMissing();
83+
84+
if (definesMimeTypes) {
85+
if (!supportsDefaultMimeTypeV2(node)) {
86+
addIssue(key, message, sectionNode.key());
87+
}
88+
return;
89+
}
90+
91+
if (!globalSupportsDefaultMimeType) {
92+
addIssue(key, message, node.key());
93+
}
9394
}
9495

9596
private void visitV3Node(JsonNode node) {
97+
9698
if (node.getType() == OpenApi3Grammar.OPERATION && section.equals("consumes")) {
97-
String operation = node.key().getTokenValue().toLowerCase();
98-
if (operation.equals("post") || operation.equals("put") || operation.equals("patch")) {
99-
visitContentNode(node);
100-
} else {
101-
JsonNode requestBodyNode = node.at("/requestBody");
102-
if (!requestBodyNode.isMissing()) {
103-
addIssue(key, translate("OAR010.error-request-body-not-allowed", operation.toUpperCase()), node.key());
104-
}
105-
}
99+
handleConsumesOperation(node);
100+
return;
106101
}
107102

108103
if (node.getType() == OpenApi3Grammar.RESPONSES && section.equals("produces")) {
109-
List<JsonNode> responseCodes = node.properties().stream().collect(Collectors.toList());
110-
for (JsonNode jsonNode : responseCodes) {
111-
if (!jsonNode.key().getTokenValue().equals("204")) {
112-
boolean externalRefManagement = false;
113-
if (isExternalRef(jsonNode) && externalRefNode == null) {
114-
externalRefNode = jsonNode;
115-
externalRefManagement = true;
116-
}
117-
jsonNode = resolve(jsonNode);
118-
visitContentNode(jsonNode);
119-
if (externalRefManagement) externalRefNode = null;
120-
}
121-
}
104+
MediaTypeUtils.handleProducesResponses(node, externalRefNode, this::visitContentNode);
122105
}
123106
}
124107

125-
private void visitContentNode(JsonNode node) {
126-
JsonNode contentNode;
127-
if (section.equals("consumes")) {
128-
JsonNode requestBodyNode = node.at("/requestBody");
129-
contentNode = resolve(requestBodyNode).at("/content");
130-
} else {
131-
contentNode = node.at("/content");
108+
private void handleConsumesOperation(JsonNode node) {
109+
String operation = node.key().getTokenValue().toLowerCase();
110+
boolean allowsBody = operation.equals("post") || operation.equals("put") || operation.equals("patch");
111+
112+
if (allowsBody) {
113+
visitContentNode(node);
114+
return;
132115
}
116+
117+
JsonNode requestBodyNode = node.at("/requestBody");
118+
if (!requestBodyNode.isMissing()) {
119+
addIssue(key,
120+
translate("OAR010.error-request-body-not-allowed", operation.toUpperCase()),
121+
node.key());
122+
}
123+
}
124+
125+
private void visitContentNode(JsonNode node) {
126+
JsonNode contentNode = MediaTypeUtils.getContentNode(node, section);
127+
133128
boolean definesMimeTypes = !contentNode.isMissing();
134129
if (definesMimeTypes) {
135130
if (!supportsDefaultMimeTypeV3(contentNode)) {

src/main/java/apiaddicts/sonar/openapi/checks/format/AbstractUndefinedMediaTypeCheck.java

Lines changed: 25 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
package apiaddicts.sonar.openapi.checks.format;
22

33
import apiaddicts.sonar.openapi.checks.BaseCheck;
4-
import static apiaddicts.sonar.openapi.utils.JsonNodeUtils.isExternalRef;
5-
import static apiaddicts.sonar.openapi.utils.JsonNodeUtils.resolve;
4+
import apiaddicts.sonar.openapi.utils.MediaTypeUtils;
5+
66
import com.google.common.collect.ImmutableSet;
77
import com.sonar.sslr.api.AstNodeType;
8-
import java.util.List;
98
import java.util.Map;
109
import java.util.Set;
11-
import java.util.stream.Collectors;
1210
import org.apiaddicts.apitools.dosonarapi.api.v2.OpenApi2Grammar;
1311
import org.apiaddicts.apitools.dosonarapi.api.v3.OpenApi3Grammar;
1412
import org.apiaddicts.apitools.dosonarapi.api.v31.OpenApi31Grammar;
@@ -48,52 +46,49 @@ public void visitNode(JsonNode node) {
4846
}
4947

5048
private void visitV2Node(JsonNode node) {
51-
if(node.getType() == OpenApi2Grammar.OPERATION){
52-
String operation = node.key().getTokenValue().toLowerCase();
53-
if (operation.equals("post") || operation.equals("put") || operation.equals("patch")){
54-
if (!globalDefinesMediaTypes && !definesMimeTypesV2(node)) {
55-
addIssue(key, translate(MESSAGE, section), node.key());
56-
}
57-
}
49+
if (node.getType() == OpenApi2Grammar.OPERATION) {
50+
String operation = node.key().getTokenValue().toLowerCase();
51+
52+
if ((operation.equals("post") || operation.equals("put") || operation.equals("patch"))
53+
&& !globalDefinesMediaTypes
54+
&& !definesMimeTypesV2(node)) {
55+
56+
addIssue(key, translate(MESSAGE, section), node.key());
57+
}
5858
}
5959
}
6060

6161
private void visitV3Node(JsonNode node) {
6262
if (node.getType() == OpenApi3Grammar.OPERATION && section.equals("consumes")) {
63-
String operation = node.key().getTokenValue().toLowerCase();
64-
if (operation.equals("post") || operation.equals("put") || operation.equals("patch")) {
65-
visitContentNode(node);
66-
}
63+
handleConsumesOperation(node);
64+
return;
6765
}
6866

6967
if (node.getType() == OpenApi3Grammar.RESPONSES && section.equals("produces")) {
70-
List<JsonNode> responseCodes = node.properties().stream().collect(Collectors.toList());
71-
for (JsonNode jsonNode : responseCodes) {
72-
if (!jsonNode.key().getTokenValue().equals("204")) {
73-
boolean externalRefManagement = false;
74-
if (isExternalRef(jsonNode) && externalRefNode == null) {
75-
externalRefNode = jsonNode;
76-
externalRefManagement = true;
77-
}
78-
jsonNode = resolve(jsonNode);
79-
visitContentNode(jsonNode);
80-
if (externalRefManagement) externalRefNode = null;
81-
}
82-
}
68+
MediaTypeUtils.handleProducesResponses(node, externalRefNode, this::visitContentNode);
69+
}
70+
}
71+
72+
private void handleConsumesOperation(JsonNode node) {
73+
String operation = node.key().getTokenValue().toLowerCase();
74+
75+
if (operation.equals("post") || operation.equals("put") || operation.equals("patch")) {
76+
visitContentNode(node);
8377
}
8478
}
8579

8680
private void visitContentNode(JsonNode node) {
8781
JsonNode contentNode;
82+
8883
if (section.equals("consumes")) {
8984
JsonNode requestBodyNode = node.at("/requestBody");
9085
if (requestBodyNode.isMissing() || requestBodyNode.isNull()) {
9186
addIssue(key, translate(MESSAGE, "requestBody"), node.key());
9287
return;
9388
}
94-
contentNode = resolve(requestBodyNode).at("/content");
89+
contentNode = MediaTypeUtils.getContentNode(node, section);
9590
} else {
96-
contentNode = node.at("/content");
91+
contentNode = MediaTypeUtils.getContentNode(node, section);
9792
}
9893

9994
if (!globalDefinesMediaTypes && !definesMimeTypesV3(contentNode)) {

0 commit comments

Comments
 (0)