Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.2.1-beta-2] - 2026-05-28

### Added

- Add OpenAPI language support without YAML and JSON conflicts.

## [1.2.1-beta-1] - 2024-05-22

### Security
Expand Down
2 changes: 1 addition & 1 deletion its/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>org.apiaddicts.apitools.dosonarapi</groupId>
<artifactId>dosonarapi</artifactId>
<version>1.2.1-beta-1</version>
<version>1.2.1-beta-2</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
Expand Down
2 changes: 1 addition & 1 deletion openapi-checks/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>org.apiaddicts.apitools.dosonarapi</groupId>
<artifactId>dosonarapi</artifactId>
<version>1.2.1-beta-1</version>
<version>1.2.1-beta-2</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@
public final class CheckList {
public static final String YAML_REPOSITORY_KEY = "openapi-yaml";
public static final String JSON_REPOSITORY_KEY = "openapi-json";
public static final String OPENAPI_REPOSITORY_KEY = "openapi";
public static final String YAML_LANGUAGE = "yaml";
public static final String JSON_LANGUAGE = "json";
public static final String OPENAPI_LANGUAGE = "openapi";

private CheckList() {
}
Expand Down
2 changes: 1 addition & 1 deletion openapi-front-end/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>org.apiaddicts.apitools.dosonarapi</groupId>
<artifactId>dosonarapi</artifactId>
<version>1.2.1-beta-1</version>
<version>1.2.1-beta-2</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
2 changes: 1 addition & 1 deletion openapi-test-tools/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>org.apiaddicts.apitools.dosonarapi</groupId>
<artifactId>dosonarapi</artifactId>
<version>1.2.1-beta-1</version>
<version>1.2.1-beta-2</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

<groupId>org.apiaddicts.apitools.dosonarapi</groupId>
<artifactId>dosonarapi</artifactId>
<version>1.2.1-beta-1</version>
<version>1.2.1-beta-2</version>
<packaging>pom</packaging>

<name>SonarOpenAPI</name>
Expand Down
2 changes: 1 addition & 1 deletion sonar-openapi-plugin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>org.apiaddicts.apitools.dosonarapi</groupId>
<artifactId>dosonarapi</artifactId>
<version>1.2.1-beta-1</version>
<version>1.2.1-beta-2</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,19 @@
*/
package org.apiaddicts.apitools.dosonarapi.plugin;

public final class OpenApi {
import org.sonar.api.resources.AbstractLanguage;

public class OpenApi extends AbstractLanguage {

public static final String KEY = "openapi";
private static final String NAME = "OpenAPI";

private OpenApi() {}
public OpenApi() {
super(KEY, NAME);
}

@Override
public String[] getFileSuffixes() {
return new String[0];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,15 @@ public OpenApiChecks addChecks(String repositoryKey, Iterable<Class<?>> checkCla

public OpenApiChecks addCustomChecks(@Nullable OpenApiCustomRuleRepository[] customRuleRepositories) {
if (customRuleRepositories != null) {

for (OpenApiCustomRuleRepository ruleRepository : customRuleRepositories) {
if (!ruleRepository.repositoryKey().equals(CheckList.YAML_REPOSITORY_KEY) &&
!ruleRepository.repositoryKey().equals(CheckList.JSON_REPOSITORY_KEY)) {
addChecks(ruleRepository.repositoryKey(), new ArrayList<>(ruleRepository.checkClasses()));
String key = ruleRepository.repositoryKey();
if (!key.equals(CheckList.YAML_REPOSITORY_KEY) &&
!key.equals(CheckList.JSON_REPOSITORY_KEY) &&
!key.equals(CheckList.OPENAPI_REPOSITORY_KEY)) {
addChecks(key, new ArrayList<>(ruleRepository.checkClasses()));
}
}
}

return this;
}

Expand All @@ -75,7 +75,8 @@ public OpenApiChecks addCustomYamlChecks(@Nullable OpenApiCustomRuleRepository[]
String key = ruleRepository.repositoryKey();
if (!key.equals(CheckList.YAML_REPOSITORY_KEY) &&
!key.equals(CheckList.JSON_REPOSITORY_KEY) &&
!key.endsWith("-json")) {
!key.equals(CheckList.OPENAPI_REPOSITORY_KEY) &&
key.endsWith("-yaml")) {
addChecks(key, new ArrayList<>(ruleRepository.checkClasses()));
}
}
Expand All @@ -89,6 +90,7 @@ public OpenApiChecks addCustomJsonChecks(@Nullable OpenApiCustomRuleRepository[]
String key = ruleRepository.repositoryKey();
if (!key.equals(CheckList.YAML_REPOSITORY_KEY) &&
!key.equals(CheckList.JSON_REPOSITORY_KEY) &&
!key.equals(CheckList.OPENAPI_REPOSITORY_KEY) &&
key.endsWith("-json")) {
addChecks(key, new ArrayList<>(ruleRepository.checkClasses()));
}
Expand All @@ -97,6 +99,22 @@ public OpenApiChecks addCustomJsonChecks(@Nullable OpenApiCustomRuleRepository[]
return this;
}

public OpenApiChecks addCustomOpenApiChecks(@Nullable OpenApiCustomRuleRepository[] customRuleRepositories) {
if (customRuleRepositories != null) {
for (OpenApiCustomRuleRepository ruleRepository : customRuleRepositories) {
String key = ruleRepository.repositoryKey();
if (!key.equals(CheckList.YAML_REPOSITORY_KEY) &&
!key.equals(CheckList.JSON_REPOSITORY_KEY) &&
!key.equals(CheckList.OPENAPI_REPOSITORY_KEY) &&
!key.endsWith("-yaml") &&
!key.endsWith("-json")) {
addChecks(key, new ArrayList<>(ruleRepository.checkClasses()));
}
}
}
return this;
}

public List<OpenApiCheck> all() {
List<OpenApiCheck> allVisitors = new ArrayList<>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ public class OpenApiPlugin implements Plugin {
@Override
public void define(Context context) {
context.addExtensions(
OpenApi.class,
OpenApiProfileDefinition.class,
OpenApiScannerSensor.class,
OpenApiRulesDefinition.class,
OpenApiMetrics.class);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* doSonarAPI: SonarQube OpenAPI Plugin
* Copyright (C) 2021-2022 Apiaddicts
* contacta AT apiaddicts DOT org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.apiaddicts.apitools.dosonarapi.plugin;

import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition;
import org.sonar.api.utils.AnnotationUtils;
import org.sonar.check.Rule;
import org.apiaddicts.apitools.dosonarapi.checks.CheckList;

public class OpenApiProfileDefinition implements BuiltInQualityProfilesDefinition {

public static final String SONAR_WAY_PROFILE = "Sonar way";

@Override
public void define(Context context) {
NewBuiltInQualityProfile profile = context.createBuiltInQualityProfile(SONAR_WAY_PROFILE, CheckList.OPENAPI_LANGUAGE);
for (Class<?> check : CheckList.getChecks()) {
Rule annotation = AnnotationUtils.getAnnotation(check, Rule.class);
profile.activateRule(CheckList.OPENAPI_REPOSITORY_KEY, annotation.key());
}
profile.done();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ private static RuleMetadataLoader getRuleMetadataLoader() {
public void define(Context context) {
createRepository(context, repositoryKey(), CheckList.YAML_LANGUAGE);
createRepository(context, CheckList.JSON_REPOSITORY_KEY, CheckList.JSON_LANGUAGE);
createRepository(context, CheckList.OPENAPI_REPOSITORY_KEY, CheckList.OPENAPI_LANGUAGE);
}

private void createRepository(Context context, String key, String language) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public class OpenApiScannerSensor implements Sensor {
private static final Logger LOGGER = Loggers.get(OpenApiScannerSensor.class);
private final OpenApiChecks yamlChecks;
private final OpenApiChecks jsonChecks;
private final OpenApiChecks openapiChecks;
private FileLinesContextFactory fileLinesContextFactory;
private final NoSonarFilter noSonarFilter;

Expand All @@ -54,6 +55,9 @@ public OpenApiScannerSensor(CheckFactory checkFactory, FileLinesContextFactory f
this.jsonChecks = OpenApiChecks.createOpenApiCheck(checkFactory)
.addChecks(CheckList.JSON_REPOSITORY_KEY, CheckList.getChecks())
.addCustomJsonChecks(customRuleRepositories);
this.openapiChecks = OpenApiChecks.createOpenApiCheck(checkFactory)
.addChecks(CheckList.OPENAPI_REPOSITORY_KEY, CheckList.getChecks())
.addCustomOpenApiChecks(customRuleRepositories);
this.fileLinesContextFactory = fileLinesContextFactory;
this.noSonarFilter = noSonarFilter;
}
Expand All @@ -62,7 +66,7 @@ public OpenApiScannerSensor(CheckFactory checkFactory, FileLinesContextFactory f
public void describe(SensorDescriptor descriptor) {
descriptor.name("OpenAPI Scanner Sensor")
.onlyOnFileType(InputFile.Type.MAIN)
.onlyOnLanguages(CheckList.YAML_LANGUAGE, CheckList.JSON_LANGUAGE);
.onlyOnLanguages(CheckList.YAML_LANGUAGE, CheckList.JSON_LANGUAGE, CheckList.OPENAPI_LANGUAGE);
}

@Override
Expand All @@ -82,6 +86,11 @@ public void scanFiles(SensorContext context, FilePredicates p) {
p.and(p.hasType(InputFile.Type.MAIN), p.hasLanguage(CheckList.JSON_LANGUAGE))
).forEach(jsonFiles::add);

List<InputFile> openapiFiles = new ArrayList<>();
context.fileSystem().inputFiles(
p.and(p.hasType(InputFile.Type.MAIN), p.hasLanguage(CheckList.OPENAPI_LANGUAGE))
).forEach(openapiFiles::add);

if (!yamlFiles.isEmpty()) {
LOGGER.info("OpenAPI Scanner called for yaml files: {}.", yamlFiles);
new OpenApiAnalyzer(context, yamlChecks, fileLinesContextFactory, noSonarFilter, Collections.unmodifiableList(yamlFiles)).scanFiles();
Expand All @@ -90,5 +99,9 @@ public void scanFiles(SensorContext context, FilePredicates p) {
LOGGER.info("OpenAPI Scanner called for json files: {}.", jsonFiles);
new OpenApiAnalyzer(context, jsonChecks, fileLinesContextFactory, noSonarFilter, Collections.unmodifiableList(jsonFiles)).scanFiles();
}
if (!openapiFiles.isEmpty()) {
LOGGER.info("OpenAPI Scanner called for openapi files: {}.", openapiFiles);
new OpenApiAnalyzer(context, openapiChecks, fileLinesContextFactory, noSonarFilter, Collections.unmodifiableList(openapiFiles)).scanFiles();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -144,4 +144,53 @@ public void ruleKeyFor_returns_null_when_not_found() {
OpenApiChecks checks = OpenApiChecks.createOpenApiCheck(factory);
assertThat(checks.ruleKeyFor(new org.apiaddicts.apitools.dosonarapi.checks.PathMaskeradingCheck())).isNull();
}

@Test
public void addCustomOpenApiChecks_adds_repo_without_suffix() {
CheckFactory factory = factoryWithRule("my-custom", "PathMaskerading");
OpenApiChecks checks = OpenApiChecks.createOpenApiCheck(factory)
.addCustomOpenApiChecks(new OpenApiCustomRuleRepository[]{repoWithKey("my-custom")});
assertThat(checks.all()).isNotEmpty();
}

@Test
public void addCustomOpenApiChecks_skips_yaml_repo() {
CheckFactory factory = factoryWithRule("my-custom-yaml", "PathMaskerading");
OpenApiChecks checks = OpenApiChecks.createOpenApiCheck(factory)
.addCustomOpenApiChecks(new OpenApiCustomRuleRepository[]{repoWithKey("my-custom-yaml")});
assertThat(checks.all()).isEmpty();
}

@Test
public void addCustomOpenApiChecks_skips_json_repo() {
CheckFactory factory = factoryWithRule("my-custom-json", "PathMaskerading");
OpenApiChecks checks = OpenApiChecks.createOpenApiCheck(factory)
.addCustomOpenApiChecks(new OpenApiCustomRuleRepository[]{repoWithKey("my-custom-json")});
assertThat(checks.all()).isEmpty();
}

@Test
public void addCustomOpenApiChecks_skips_base_openapi_repo() {
CheckFactory factory = factoryWithRule(CheckList.OPENAPI_REPOSITORY_KEY, "PathMaskerading");
OpenApiChecks checks = OpenApiChecks.createOpenApiCheck(factory)
.addCustomOpenApiChecks(new OpenApiCustomRuleRepository[]{repoWithKey(CheckList.OPENAPI_REPOSITORY_KEY)});
assertThat(checks.all()).isEmpty();
}

@Test
public void addCustomOpenApiChecks_handles_null() {
ActiveRules rules = new ActiveRulesBuilder().build();
CheckFactory factory = new CheckFactory(rules);
OpenApiChecks checks = OpenApiChecks.createOpenApiCheck(factory)
.addCustomOpenApiChecks(null);
assertThat(checks.all()).isEmpty();
}

@Test
public void addCustomYamlChecks_requires_yaml_suffix() {
CheckFactory factory = factoryWithRule("my-custom", "PathMaskerading");
OpenApiChecks checks = OpenApiChecks.createOpenApiCheck(factory)
.addCustomYamlChecks(new OpenApiCustomRuleRepository[]{repoWithKey("my-custom")});
assertThat(checks.all()).isEmpty();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ public void defines_expected_extensions() {
new OpenApiPlugin().define(context);

assertThat(context.getExtensions())
.contains(OpenApiScannerSensor.class, OpenApiRulesDefinition.class, OpenApiMetrics.class);
.contains(
OpenApi.class,
OpenApiProfileDefinition.class,
OpenApiScannerSensor.class,
OpenApiRulesDefinition.class,
OpenApiMetrics.class);
}
}
Loading
Loading