Skip to content

Commit

Permalink
PLUGINAPI-56 PLUGINAPI-57 Add Clean Code Attribute to plugin-api
Browse files Browse the repository at this point in the history
  • Loading branch information
1 parent 4baf8f9 commit 1fdce7a
Show file tree
Hide file tree
Showing 14 changed files with 204 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

* Remove @Beta Code Characteristics `org.sonar.api.code.CodeCharacteristic`
* Introduce `org.sonar.api.issue.impact.SoftwareQuality` and `org.sonar.api.issue.impact.Severity` to define impacts of rules and issues
* Introduce `org.sonar.api.rules.CleanCodeAttribute` to define clean code attribute on rules.

## 10.0

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import javax.annotation.CheckForNull;
import org.sonar.api.batch.rule.Severity;
import org.sonar.api.batch.sensor.Sensor;
import org.sonar.api.rules.CleanCodeAttribute;
import org.sonar.api.issue.impact.SoftwareQuality;
import org.sonar.api.rules.RuleType;

Expand Down Expand Up @@ -61,4 +62,11 @@ public interface ExternalIssue extends IIssue {
*/
Map<SoftwareQuality, org.sonar.api.issue.impact.Severity> impacts();

/**
* Clean Code Attribute of the issue.
* @since 10.1
*/
@CheckForNull
CleanCodeAttribute cleanCodeAttribute();

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.sonar.api.batch.sensor.Sensor;
import org.sonar.api.issue.impact.SoftwareQuality;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rules.CleanCodeAttribute;
import org.sonar.api.rules.RuleType;

/**
Expand Down Expand Up @@ -57,6 +58,13 @@ public interface NewExternalIssue {
*/
NewExternalIssue type(RuleType type);

/**
* Attribute of the issue according to Clean Code Taxonomy.
* Providing it is optional for now but will become mandatory in the future.
* @since 10.1
*/
NewExternalIssue cleanCodeAttribute(CleanCodeAttribute attribute);

/**
* Effort to fix the issue, in minutes.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.sonar.api.batch.sensor.Sensor;
import org.sonar.api.issue.impact.SoftwareQuality;
import org.sonar.api.rules.RuleType;
import org.sonar.api.rules.CleanCodeAttribute;

/**
* Represents a rule imported from an external rule engine by a {@link Sensor}.
Expand Down Expand Up @@ -70,8 +71,7 @@ public interface AdHocRule {
Map<SoftwareQuality, org.sonar.api.issue.impact.Severity> defaultImpacts();

/**
* Clean Code Attribute of the rule according to Clean Code Taxonomy.
*
* Clean Code Attribute of the rule.
* @since 10.1
*/
@CheckForNull
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.sonar.api.batch.rule.Severity;
import org.sonar.api.batch.sensor.Sensor;
import org.sonar.api.issue.impact.SoftwareQuality;
import org.sonar.api.rules.CleanCodeAttribute;
import org.sonar.api.rules.RuleType;

/**
Expand Down Expand Up @@ -59,6 +60,13 @@ public interface NewAdHocRule {
*/
NewAdHocRule type(RuleType type);

/**
* Clean Code Attribute of the rule.
* Providing it is optional for now but will become mandatory in the future.
* @since 10.1
*/
NewAdHocRule cleanCodeAttribute(CleanCodeAttribute attribute);

/**
* Set the severity of the rule.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Sonar Plugin API
* Copyright (C) 2009-2023 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* 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.sonar.api.rules;

import static org.sonar.api.rules.CleanCodeAttributeCategory.ADAPTABLE;
import static org.sonar.api.rules.CleanCodeAttributeCategory.CONSISTENT;
import static org.sonar.api.rules.CleanCodeAttributeCategory.INTENTIONAL;
import static org.sonar.api.rules.CleanCodeAttributeCategory.RESPONSIBLE;

public enum CleanCodeAttribute {
CONVENTIONAL(CONSISTENT),
FORMATTED(CONSISTENT),
IDENTIFIABLE(CONSISTENT),

CLEAR(INTENTIONAL),
COMPLETE(INTENTIONAL),
EFFICIENT(INTENTIONAL),
LOGICAL(INTENTIONAL),

DISTINCT(ADAPTABLE),
FOCUSED(ADAPTABLE),
MODULAR(ADAPTABLE),
TESTED(ADAPTABLE),

LAWFUL(RESPONSIBLE),
RESPECTFUL(RESPONSIBLE),
TRUSTWORTHY(RESPONSIBLE);

private final CleanCodeAttributeCategory attributeCategory;

CleanCodeAttribute(CleanCodeAttributeCategory attributeCategory) {

this.attributeCategory = attributeCategory;
}

public CleanCodeAttributeCategory getAttributeCategory() {
return attributeCategory;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Sonar Plugin API
* Copyright (C) 2009-2023 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* 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.sonar.api.rules;

public enum CleanCodeAttributeCategory {
ADAPTABLE,
CONSISTENT,
INTENTIONAL,
RESPONSIBLE;
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.RuleScope;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.rules.CleanCodeAttribute;
import org.sonar.api.rules.RuleType;
import org.sonar.api.server.ServerSide;
import org.sonar.api.server.debt.DebtRemediationFunction;
Expand Down Expand Up @@ -435,6 +436,13 @@ abstract class NewRule {
*/
public abstract NewRule setType(RuleType t);

/**
* The Clean Code Attribute of the rule.
* Providing it is optional for now, but will become mandatory in the future.
* @since 10.1
*/
public abstract NewRule setCleanCodeAttribute(CleanCodeAttribute attribute);

/**
* Add a rule description section. The sections must be added in the right order.
* For backward compatibility, one of the old method {@link #setHtmlDescription(String)} or {@link #setHtmlDescription(URL)} still
Expand Down Expand Up @@ -603,6 +611,13 @@ abstract class Rule {
*/
public abstract RuleType type();

/**
* @see NewRule#setCleanCodeAttribute(CleanCodeAttribute)
* @since 10.1
*/
@CheckForNull
public abstract CleanCodeAttribute cleanCodeAttribute();

public abstract String severity();

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import org.sonar.api.rule.RuleScope;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.rule.Severity;
import org.sonar.api.rules.CleanCodeAttribute;
import org.sonar.api.rules.RuleType;
import org.sonar.api.server.debt.DebtRemediationFunction;
import org.sonar.api.server.rule.Context;
Expand Down Expand Up @@ -79,6 +80,7 @@ class DefaultNewRule extends RulesDefinition.NewRule {
private final String repoKey;
private final String key;
private RuleType type;
private CleanCodeAttribute attribute;
private String name;
private String htmlDescription;
private String markdownDescription;
Expand Down Expand Up @@ -161,6 +163,12 @@ public RulesDefinition.NewRule addDefaultImpact(SoftwareQuality softwareQuality,
return this;
}

@Override
public RulesDefinition.NewRule setCleanCodeAttribute(CleanCodeAttribute attribute) {
this.attribute = attribute;
return this;
}

@Override
public RulesDefinition.NewRule addDescriptionSection(RuleDescriptionSection ruleDescriptionSection) {
assertRuleDescriptionSectionIsValid(ruleDescriptionSection);
Expand Down Expand Up @@ -420,6 +428,10 @@ RuleType type() {
return type;
}

CleanCodeAttribute cleanCodeAttribute() {
return attribute;
}

String name() {
return name;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.RuleScope;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.rules.CleanCodeAttribute;
import org.sonar.api.rules.RuleType;
import org.sonar.api.server.debt.DebtRemediationFunction;
import org.sonar.api.server.rule.RuleDescriptionSection;
Expand All @@ -50,6 +51,7 @@ public class DefaultRule extends RulesDefinition.Rule {
private final String key;
private final String name;
private final RuleType type;
private final CleanCodeAttribute cleanCodeAttribute;
private final String htmlDescription;
private final String markdownDescription;
private final String internalKey;
Expand Down Expand Up @@ -85,6 +87,7 @@ public class DefaultRule extends RulesDefinition.Rule {
this.gapDescription = newRule.gapDescription();
this.scope = newRule.scope() == null ? RuleScope.MAIN : newRule.scope();
this.type = newRule.type() == null ? RuleTagsToTypeConverter.convert(newRule.tags()) : newRule.type();
this.cleanCodeAttribute = newRule.cleanCodeAttribute();
Set<String> tagsBuilder = new TreeSet<>(newRule.tags());
tagsBuilder.removeAll(RuleTagsToTypeConverter.RESERVED_TAGS);
this.tags = Collections.unmodifiableSet(tagsBuilder);
Expand Down Expand Up @@ -131,6 +134,12 @@ public RuleType type() {
return type;
}

@CheckForNull
@Override
public CleanCodeAttribute cleanCodeAttribute() {
return cleanCodeAttribute;
}

@Override
public String severity() {
return severity;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Sonar Plugin API
* Copyright (C) 2009-2023 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* 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.sonar.api.rules;

import org.junit.Test;

import static org.assertj.core.api.Assertions.assertThat;
public class CleanCodeAttributeTest {

@Test
public void values_shouldNotBeEmpty() {
CleanCodeAttribute[] values = CleanCodeAttribute.values();

assertThat(values).isNotEmpty();
}

@Test
public void getAttributeCategory_shouldReturnExpectedCategory() {
assertThat(CleanCodeAttribute.COMPLETE.getAttributeCategory()).isEqualTo(CleanCodeAttributeCategory.INTENTIONAL);
assertThat(CleanCodeAttribute.CONVENTIONAL.getAttributeCategory()).isEqualTo(CleanCodeAttributeCategory.CONSISTENT);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import org.sonar.api.rule.RuleScope;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.rule.Severity;
import org.sonar.api.rules.CleanCodeAttribute;
import org.sonar.api.rules.RuleType;
import org.sonar.api.server.debt.DebtRemediationFunction;
import org.sonar.api.server.rule.RuleDescriptionSection;
Expand Down Expand Up @@ -587,6 +588,17 @@ public void type_is_defined() {
// tag "bug" is reserved and removed.
assertThat(rule.tags()).containsOnly("misra");
}
@Test

public void cleanCodeAttribute_is_defined() {
RulesDefinition.NewRepository newRepository = context.createRepository("findbugs", "java");
newRepository.createRule("NPE").setName("NPE").setHtmlDescription("desc")
.setType(RuleType.VULNERABILITY).setCleanCodeAttribute(CleanCodeAttribute.EFFICIENT);
newRepository.done();

RulesDefinition.Rule rule = context.repository("findbugs").rule("NPE");
assertThat(rule.cleanCodeAttribute()).isEqualTo(CleanCodeAttribute.EFFICIENT);
}

@Test
public void guess_type_from_tags_if_type_is_missing() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.RuleScope;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.rules.CleanCodeAttribute;
import org.sonar.api.rules.RuleType;
import org.sonar.api.server.debt.DebtRemediationFunction;
import org.sonar.api.server.rule.Context;
Expand All @@ -39,6 +40,7 @@
import org.sonar.api.server.rule.RulesDefinition.PciDssVersion;

import static java.lang.String.format;
import static org.assertj.core.api.Assertions.as;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.mock;
Expand Down Expand Up @@ -131,6 +133,9 @@ public void testSimpleSetGet() {
rule.setType(RuleType.SECURITY_HOTSPOT);
assertThat(rule.type()).isEqualTo(RuleType.SECURITY_HOTSPOT);

rule.setCleanCodeAttribute(CleanCodeAttribute.FOCUSED);
assertThat(rule.cleanCodeAttribute()).isEqualTo(CleanCodeAttribute.FOCUSED);

DebtRemediationFunction f = mock(DebtRemediationFunction.class);
rule.setDebtRemediationFunction(f);
assertThat(rule.debtRemediationFunction()).isEqualTo(f);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ public void getters() {
rule.addCwe(10);
rule.setType(RuleType.SECURITY_HOTSPOT);
rule.addDefaultImpact(SoftwareQuality.MAINTAINABILITY, Severity.HIGH);
rule.setCleanCodeAttribute(CleanCodeAttribute.COMPLETE);
DebtRemediationFunction f = mock(DebtRemediationFunction.class);
rule.setDebtRemediationFunction(f);
rule.setSeverity("MAJOR");
Expand Down

0 comments on commit 1fdce7a

Please sign in to comment.