import com.google.common.collect.ImmutableList;
import java.util.Date;
-import java.util.List;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.rules.RuleType;
import org.sonar.api.server.ServerSide;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.qualityprofile.QProfileDto;
import org.sonar.server.rule.index.RuleQuery;
-import org.sonar.server.ws.WsUtils;
+import static com.google.common.base.Preconditions.checkArgument;
import static java.lang.String.format;
import static org.sonar.server.util.EnumUtils.toEnums;
+import static org.sonar.server.ws.WsUtils.checkFound;
+import static org.sonar.server.ws.WsUtils.checkFoundWithOptional;
import static org.sonarqube.ws.client.rule.RulesWsParameters.PARAM_ACTIVATION;
import static org.sonarqube.ws.client.rule.RulesWsParameters.PARAM_ACTIVE_SEVERITIES;
import static org.sonarqube.ws.client.rule.RulesWsParameters.PARAM_AVAILABLE_SINCE;
+import static org.sonarqube.ws.client.rule.RulesWsParameters.PARAM_COMPARE_TO_PROFILE;
import static org.sonarqube.ws.client.rule.RulesWsParameters.PARAM_INHERITANCE;
import static org.sonarqube.ws.client.rule.RulesWsParameters.PARAM_IS_TEMPLATE;
import static org.sonarqube.ws.client.rule.RulesWsParameters.PARAM_LANGUAGES;
Boolean activation = request.paramAsBoolean(PARAM_ACTIVATION);
query.setActivation(activation);
- String profileUuid = request.param(PARAM_QPROFILE);
- String organizationKey = request.param(PARAM_ORGANIZATION);
- OrganizationDto organization;
- List<String> languages;
- if (profileUuid == null) {
- organization = wsSupport.getOrganizationByKey(dbSession, organizationKey);
- languages = request.paramAsStrings(PARAM_LANGUAGES);
- } else {
- QProfileDto profileOptional = dbClient.qualityProfileDao().selectByUuid(dbSession, profileUuid);
- QProfileDto profile = WsUtils.checkFound(profileOptional, "The specified qualityProfile '%s' does not exist", profileUuid);
- query.setQProfile(profile);
- languages = ImmutableList.of(profile.getLanguage());
- organization = WsUtils.checkFoundWithOptional(dbClient.organizationDao().selectByUuid(dbSession, profile.getOrganizationUuid()), "No organization with UUID ",
- profile.getOrganizationUuid());
- if (organizationKey != null) {
- OrganizationDto inputOrganization = WsUtils.checkFoundWithOptional(dbClient.organizationDao().selectByKey(dbSession, organizationKey), "No organization with key '%s'",
- organizationKey);
- if (!organization.getUuid().equals(inputOrganization.getUuid())) {
- throw new IllegalArgumentException(format("The specified quality profile '%s' is not part of the specified organization '%s'", profileUuid, organizationKey));
- }
- }
- }
- query.setOrganization(organization);
- query.setLanguages(languages);
+ // Order is important : 1. Load profile, 2. Load organization either from parameter or from profile, 3. Load compare to profile
+ setProfile(dbSession, query, request);
+ setOrganization(dbSession, query, request);
+ setCompareToProfile(dbSession, query, request);
+ QProfileDto profile = query.getQProfile();
+ query.setLanguages(profile == null ? request.paramAsStrings(PARAM_LANGUAGES) : ImmutableList.of(profile.getLanguage()));
query.setTags(request.paramAsStrings(PARAM_TAGS));
query.setInheritance(request.paramAsStrings(PARAM_INHERITANCE));
}
return query;
}
+
+ private void setProfile(DbSession dbSession, RuleQuery query, Request request) {
+ String profileUuid = request.param(PARAM_QPROFILE);
+ if (profileUuid == null) {
+ return;
+ }
+ QProfileDto profileOptional = dbClient.qualityProfileDao().selectByUuid(dbSession, profileUuid);
+ QProfileDto profile = checkFound(profileOptional, "The specified qualityProfile '%s' does not exist", profileUuid);
+ query.setQProfile(profile);
+ }
+
+ private void setOrganization(DbSession dbSession, RuleQuery query, Request request) {
+ String organizationKey = request.param(PARAM_ORGANIZATION);
+ QProfileDto profile = query.getQProfile();
+ if (profile == null) {
+ query.setOrganization(wsSupport.getOrganizationByKey(dbSession, organizationKey));
+ return;
+ }
+ OrganizationDto organization = checkFoundWithOptional(dbClient.organizationDao().selectByUuid(dbSession, profile.getOrganizationUuid()), "No organization with UUID ",
+ profile.getOrganizationUuid());
+ if (organizationKey != null) {
+ OrganizationDto inputOrganization = checkFoundWithOptional(dbClient.organizationDao().selectByKey(dbSession, organizationKey), "No organization with key '%s'",
+ organizationKey);
+ checkArgument(organization.getUuid().equals(inputOrganization.getUuid()),
+ format("The specified quality profile '%s' is not part of the specified organization '%s'", profile.getKee(), organizationKey));
+ }
+ query.setOrganization(organization);
+ }
+
+ private void setCompareToProfile(DbSession dbSession, RuleQuery query, Request request) {
+ String compareToProfileUuid = request.param(PARAM_COMPARE_TO_PROFILE);
+ if (compareToProfileUuid == null) {
+ return;
+ }
+ QProfileDto profileOptional = dbClient.qualityProfileDao().selectByUuid(dbSession, compareToProfileUuid);
+ QProfileDto profile = checkFound(profileOptional, "The specified qualityProfile '%s' does not exist", compareToProfileUuid);
+
+ checkArgument(query.getOrganization().getUuid().equals(profile.getOrganizationUuid()),
+ format("The specified quality profile '%s' is not part of the specified organization '%s'", profile.getKee(), query.getOrganization().getKey()));
+
+ query.setCompareToQProfile(profile);
+ }
}
import com.google.common.collect.Maps;
import com.google.common.collect.Ordering;
import com.google.common.collect.Sets;
-import com.google.common.io.Resources;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import static org.sonar.api.server.ws.WebService.Param.PAGE_SIZE;
import static org.sonar.api.server.ws.WebService.Param.SORT;
import static org.sonar.api.server.ws.WebService.Param.TEXT_QUERY;
+import static org.sonar.core.util.Uuids.UUID_EXAMPLE_01;
+import static org.sonar.core.util.Uuids.UUID_EXAMPLE_02;
import static org.sonar.server.es.SearchOptions.MAX_LIMIT;
import static org.sonar.server.rule.index.RuleIndex.ALL_STATUSES_EXCEPT_REMOVED;
import static org.sonar.server.rule.index.RuleIndex.FACET_ACTIVE_SEVERITIES;
import static org.sonarqube.ws.client.rule.RulesWsParameters.PARAM_ACTIVATION;
import static org.sonarqube.ws.client.rule.RulesWsParameters.PARAM_ACTIVE_SEVERITIES;
import static org.sonarqube.ws.client.rule.RulesWsParameters.PARAM_AVAILABLE_SINCE;
+import static org.sonarqube.ws.client.rule.RulesWsParameters.PARAM_COMPARE_TO_PROFILE;
import static org.sonarqube.ws.client.rule.RulesWsParameters.PARAM_INHERITANCE;
import static org.sonarqube.ws.client.rule.RulesWsParameters.PARAM_IS_TEMPLATE;
import static org.sonarqube.ws.client.rule.RulesWsParameters.PARAM_LANGUAGES;
.setPossibleValues(Ordering.natural().sortedCopy(OPTIONAL_FIELDS));
Iterator<String> it = OPTIONAL_FIELDS.iterator();
paramFields.setExampleValue(format("%s,%s", it.next(), it.next()));
-
doDefinition(action);
}
"<li>\"defaultDebtRemFnOffset\" becomes \"defaultRemFnBaseEffort\"</li>" +
"<li>\"debtOverloaded\" becomes \"remFnOverloaded\"</li>" +
"</ul>")
- .setResponseExample(Resources.getResource(getClass(), "example-search.json"))
+ .setResponseExample(getClass().getResource("search-example.json"))
.setSince("4.4")
.setHandler(this);
action
.createParam(PARAM_QPROFILE)
- .setDescription("Key of Quality profile to filter on. Used only if the parameter '" +
+ .setDescription("Quality profile key to filter on. Used only if the parameter '" +
PARAM_ACTIVATION + "' is set.")
- .setExampleValue("sonar-way-cs-12345");
+ .setExampleValue(UUID_EXAMPLE_01);
+
+ action.createParam(PARAM_COMPARE_TO_PROFILE)
+ .setDescription("Quality profile key to filter rules that are activated. Meant to compare easily to profile set in '%s'", PARAM_QPROFILE)
+ .setInternal(true)
+ .setSince("6.5")
+ .setExampleValue(UUID_EXAMPLE_02);
action
.createParam(PARAM_INHERITANCE)
+++ /dev/null
-{
- "total": 4,
- "p": 1,
- "ps": 3,
- "rules": [
- {
- "key": "squid:S1067",
- "repo": "squid",
- "name": "Expressions should not be too complex",
- "createdAt": "2013-03-27T08:52:40+0100",
- "htmlDesc": "<p>\nThe complexity of an expression is defined by the number of <code>&&</code>, <code>||</code> and <code>condition ? ifTrue : ifFalse</code> operators it contains.\nA single expression's complexity should not become too high to keep the code readable.\n</p>\n\n<p>The following code, with a maximum complexity of 3:</p>\n\n<pre>\nif (condition1 && condition2 && condition3 && condition4) { /* ... */ } // Non-Compliant\n</pre>\n\n<p>could be refactored into something like:</p>\n\n<pre>\nif (relevantMethodName1() && relevantMethodName2()) { /* ... */ } // Compliant\n\n/* ... */\n\nprivate boolean relevantMethodName1() {\n return condition1 && condition2;\n}\n\nprivate boolean relevantMethodName2() {\n return condition3 && condition4;\n}\n</pre>",
- "severity": "MAJOR",
- "status": "READY",
- "internalKey": "S1067",
- "isTemplate": false,
- "tags": [],
- "sysTags": ["brain-overload"],
- "lang": "java",
- "langName": "Java",
- "type": "CODE_SMELL",
- "params": [
- {
- "key": "max",
- "desc": "Maximum number of allowed conditional operators in an expression",
- "defaultValue": "3"
- }
- ]
- },
- {
- "key": "squid:ClassCyclomaticComplexity",
- "repo": "squid",
- "name": "Avoid too complex class",
- "createdAt": "2013-03-27T08:52:40+0100",
- "htmlDesc": "<p>The Cyclomatic Complexity is measured by the number of (&&, ||)\n\toperators and (if, while, do, for, ?:, catch, switch, case, return,\n\tthrow) statements in the body of a class plus one for each constructor,\n\tmethod (but not getter/setter), static initializer, or instance\n\tinitializer in the class. The last return stament in method, if exists,\n\tis not taken into account.</p>\n<p>\n\tEven when the Cyclomatic Complexity of a class is very high, this\n\tcomplexity might be well distributed among all methods. Nevertheless,\n\tmost of the time, a very complex class is a class which breaks the <a\n\t\thref='http://en.wikipedia.org/wiki/Single_responsibility_principle'>Single\n\t\tResponsibility Principle</a> and which should be re-factored to be split\n\tin several classes.\n</p>",
- "severity": "MAJOR",
- "status": "READY",
- "internalKey": "ClassCyclomaticComplexity",
- "isTemplate": false,
- "tags": [],
- "sysTags": ["brain-overload"],
- "lang": "java",
- "langName": "Java",
- "type": "BUG",
- "params": [
- {
- "key": "max",
- "desc": "Maximum complexity allowed.",
- "defaultValue": "200"
- }
- ]
- },
- {
- "key": "squid:MethodCyclomaticComplexity",
- "repo": "squid",
- "name": "Methods should not be too complex",
- "createdAt": "2013-03-27T08:52:40+0100",
- "htmlDesc": "<p>The Cyclomatic Complexity is measured by the number of\n\t(&&, ||) operators and (if, while, do, for, ?:, catch, switch,\n\tcase, return, throw) statements in the body of a class plus one for\n\teach constructor, method (but not getter/setter), static initializer,\n\tor instance initializer in the class. The last return stament in\n\tmethod, if exists, is not taken into account.</p>\n<p>\n\tEven when the Cyclomatic Complexity of a class is very high, this\n\tcomplexity might be well distributed among all methods. Nevertheless,\n\tmost of the time, a very complex class is a class which breaks the <a\n\t\thref=\"http://en.wikipedia.org/wiki/Single_responsibility_principle\">Single\n\t\tResponsibility Principle</a> and which should be re-factored to be split\n\tin several classes.\n</p>",
- "severity": "MAJOR",
- "status": "READY",
- "internalKey": "MethodCyclomaticComplexity",
- "isTemplate": false,
- "tags": [],
- "sysTags": ["brain-overload"],
- "lang": "java",
- "langName": "Java",
- "type": "VULNERABILITY",
- "params": [
- {
- "key": "max",
- "desc": "Maximum complexity allowed.",
- "defaultValue": "10"
- }
- ]
- },
- {
- "key": "squid:XPath",
- "repo": "squid",
- "name": "XPath rule",
- "createdAt": "2013-03-27T08:52:40+0100",
- "htmlDesc": "<p>\nThis rule allows to define some homemade Java rules with help of an XPath expression.\n</p>\n\n<p>\nIssues are created depending on the return value of the XPath expression. If the XPath expression returns:\n</p>\n<ul>\n <li>a single or list of AST nodes, then a line issue with the given message is created for each node</li>\n <li>a boolean, then a file issue with the given message is created only if the boolean is true</li>\n <li>anything else, no issue is created</li>\n</ul>\n\n<p>\nHere is an example of an XPath expression to log an issue on each if statement : //ifStatement\n</p>",
- "severity": "MAJOR",
- "status": "READY",
- "internalKey": "XPath",
- "isTemplate": true,
- "tags": [ ],
- "sysTags": [ ],
- "mdNote": "<p>\nThe tree produced by the <code>firstOf()</code> matcher is hard to work with from checks when alternatives are not named.\n</p>\n\n<p>\nConsider the following rule:\n</p>\n\n<pre>\nb.rule(COMPILATION_UNIT).is(\n b.firstOf( /* Non-Compliant */\n \"FOO\",\n \"BAR\"));\n</pre>\n\n<p>\nIf, from a check, one wants to forbid the usage of the \"BAR\" alternative,\nthe easiest option will be to verify that the value of the first token is \"BAR\",\ni.e. <code>\"BAR\".equals(compilationUnitNode.getTokenValue())</code>.\n</p>\n\n<p>\nThis is not maintainable, for at least two reasons:\n</p>\n\n<ul>\n <li>The grammar might evolve to also accept \"bar\" in lowercase, which will break <code>\"BAR\".equals(...)</code></li>\n <li>The grammar might evolve to optionally accept \"hello\" before the <code>firstOf()</code>, which will break <code>compilationUnitNode.getTokenValue()</code></li>\n</ul>\n\n<p>\nInstead, it is much better to rewrite the grammar as:\n</p>\n\n<pre>\nb.rule(COMPILATION_UNIT).is(\n firstOf( /* Compliant */\n FOO,\n BAR));\nb.rule(FOO).is(\"FOO\");\nb.rule(BAR).is(\"BAR\");\n</pre>\n\n<p>\nThe same check which forbids \"BAR\" would be written as: <code>compilationUnitNode.hasDirectChildren(BAR)</code>.\nThis allows both of the previous grammar evolutions to be made without impacting the check at all.\n</p>",
- "htmlNote": "<p><br/>The tree produced by the <code>firstOf()</code> matcher is hard to work with from checks when alternatives are not named.<br/></p><br/><br/><p><br/>Consider the following rule:<br/></p><br/><br/><pre><br/>b.rule(COMPILATION_UNIT).is(<br/> b.firstOf( /* Non-Compliant */<br/> "FOO",<br/> "BAR"));<br/></pre><br/><br/><p><br/>If, from a check, one wants to forbid the usage of the "BAR" alternative,<br/>the easiest option will be to verify that the value of the first token is "BAR",<br/>i.e. <code>"BAR".equals(compilationUnitNode.getTokenValue())</code>.<br/></p><br/><br/><p><br/>This is not maintainable, for at least two reasons:<br/></p><br/><br/><ul><br/> <li>The grammar might evolve to also accept "bar" in lowercase, which will break <code>"BAR".equals(...)</code></li><br/> <li>The grammar might evolve to optionally accept "hello" before the <code>firstOf()</code>, which will break <code>compilationUnitNode.getTokenValue()</code></li><br/></ul><br/><br/><p><br/>Instead, it is much better to rewrite the grammar as:<br/></p><br/><br/><pre><br/>b.rule(COMPILATION_UNIT).is(<br/> firstOf( /* Compliant */<br/> FOO,<br/> BAR));<br/>b.rule(FOO).is("FOO");<br/>b.rule(BAR).is("BAR");<br/></pre><br/><br/><p><br/>The same check which forbids "BAR" would be written as: <code>compilationUnitNode.hasDirectChildren(BAR)</code>.<br/>This allows both of the previous grammar evolutions to be made without impacting the check at all.<br/></p>",
- "noteLogin": "eric.hartmann",
- "lang": "java",
- "langName": "Java",
- "type": "CODE_SMELL",
- "params": [
- {
- "key": "xpathQuery",
- "desc": "The XPath query",
- "defaultValue": ""
- },
- {
- "key": "message",
- "desc": "The violation message",
- "defaultValue": "The XPath expression matches this piece of code"
- }
- ]
- },
- {
- "key": "squid:XPath_1369910135",
- "repo": "squid",
- "name": "firstOf() alternatives should be rules or token types",
- "createdAt": "2013-05-30T10:35:35+0200",
- "htmlDesc": "<p>\r\nThe tree produced by the <code>firstOf()</code> matcher is hard to work with from checks when alternatives are not named.\r\n</p>\r\n\r\n<p>\r\nConsider the following rule:\r\n</p>\r\n\r\n<pre>\r\nb.rule(COMPILATION_UNIT).is(\r\n b.firstOf( /* Non-Compliant */\r\n \"FOO\",\r\n \"BAR\"));\r\n</pre>\r\n\r\n<p>\r\nIf, from a check, one wants to forbid the usage of the \"BAR\" alternative,\r\nthe easiest option will be to verify that the value of the first token is \"BAR\",\r\ni.e. <code>\"BAR\".equals(compilationUnitNode.getTokenValue())</code>.\r\n</p>\r\n\r\n<p>\r\nThis is not maintainable, for at least two reasons:\r\n</p>\r\n\r\n<ul>\r\n <li>The grammar might evolve to also accept \"bar\" in lowercase, which will break <code>\"BAR\".equals(...)</code></li>\r\n <li>The grammar might evolve to optionally accept \"hello\" before the <code>firstOf()</code>, which will break <code>compilationUnitNode.getTokenValue()</code></li>\r\n</ul>\r\n\r\n<p>\r\nInstead, it is much better to rewrite the grammar as:\r\n</p>\r\n\r\n<pre>\r\nb.rule(COMPILATION_UNIT).is(\r\n firstOf( /* Compliant */\r\n FOO,\r\n BAR));\r\nb.rule(FOO).is(\"FOO\");\r\nb.rule(BAR).is(\"BAR\");\r\n</pre>\r\n\r\n<p>\r\nThe same check which forbids \"BAR\" would be written as: <code>compilationUnitNode.hasDirectChildren(BAR)</code>.\r\nThis allows both of the previous grammar evolutions to be made without impacting the check at all.\r\n</p>",
- "severity": "MAJOR",
- "status": "READY",
- "internalKey": "XPath",
- "isTemplate": false,
- "templateKey": "squid:XPath",
- "tags": [ ],
- "sysTags": [ ],
- "lang": "java",
- "langName": "Java",
- "type": "CODE_SMELL",
- "params": [
- {
- "key": "xpathQuery",
- "desc": "The XPath query",
- "defaultValue": "//expression[primary/qualifiedIdentifier[count(IDENTIFIER) = 2]/IDENTIFIER[2]/@tokenValue = 'firstOf' and primary/identifierSuffix/arguments/expression[not(primary) or primary[not(qualifiedIdentifier) or identifierSuffix]]]"
- },
- {
- "key": "message",
- "desc": "The violation message",
- "defaultValue": "Refactor this firstOf() to only use a rule or token type for each alternative."
- }
- ]
- }
- ],
- "actives": {
- "squid:MethodCyclomaticComplexity": [
- {
- "qProfile": "Sonar way with Findbugs:java",
- "inherit": "NONE",
- "severity": "MAJOR",
- "params": [
- {
- "key": "max",
- "value": "10"
- }
- ]
- },
- {
- "qProfile": "Sonar way:java",
- "inherit": "NONE",
- "severity": "MAJOR",
- "params": [
- {
- "key": "max",
- "value": "10"
- }
- ]
- }
- ],
- "squid:S1067": [
- {
- "qProfile": "Sonar way with Findbugs:java",
- "inherit": "NONE",
- "severity": "MAJOR",
- "params": [
- {
- "key": "max",
- "value": "3"
- }
- ]
- },
- {
- "qProfile": "Sonar way:java",
- "inherit": "NONE",
- "severity": "MAJOR",
- "params": [
- {
- "key": "max",
- "value": "3"
- }
- ]
- }
- ],
- "squid:ClassCyclomaticComplexity": [
- {
- "qProfile": "Sonar way with Findbugs:java",
- "inherit": "NONE",
- "severity": "MAJOR",
- "params": [
- {
- "key": "max",
- "value": "200"
- }
- ]
- },
- {
- "qProfile": "Sonar way:java",
- "inherit": "NONE",
- "severity": "MAJOR",
- "params": [
- {
- "key": "max",
- "value": "200"
- }
- ]
- }
- ]
- },
- "facets": [
- {
- "name": "tags",
- "values": [
- {
- "val": "complexity",
- "count": 141
- },
- {
- "val": "java8",
- "count": 42
- },
- {
- "val": "javadoc",
- "count": 13
- }
- ]
- },
- {
- "name": "languages",
- "values": [
- {
- "val": "java",
- "count": 563
- }
- ]
- },
- {
- "name": "repositories",
- "values": [
- {
- "val": "findbugs",
- "count": 419
- },
- {
- "val": "squid",
- "count": 138
- },
- {
- "val": "common-java",
- "count": 6
- }
- ]
- }
-
- ]
-}
--- /dev/null
+{
+ "total": 4,
+ "p": 1,
+ "ps": 3,
+ "rules": [
+ {
+ "key": "squid:S1067",
+ "repo": "squid",
+ "name": "Expressions should not be too complex",
+ "createdAt": "2013-03-27T08:52:40+0100",
+ "htmlDesc": "<p>\nThe complexity of an expression is defined by the number of <code>&&</code>, <code>||</code> and <code>condition ? ifTrue : ifFalse</code> operators it contains.\nA single expression's complexity should not become too high to keep the code readable.\n</p>\n\n<p>The following code, with a maximum complexity of 3:</p>\n\n<pre>\nif (condition1 && condition2 && condition3 && condition4) { /* ... */ } // Non-Compliant\n</pre>\n\n<p>could be refactored into something like:</p>\n\n<pre>\nif (relevantMethodName1() && relevantMethodName2()) { /* ... */ } // Compliant\n\n/* ... */\n\nprivate boolean relevantMethodName1() {\n return condition1 && condition2;\n}\n\nprivate boolean relevantMethodName2() {\n return condition3 && condition4;\n}\n</pre>",
+ "severity": "MAJOR",
+ "status": "READY",
+ "internalKey": "S1067",
+ "isTemplate": false,
+ "tags": [],
+ "sysTags": ["brain-overload"],
+ "lang": "java",
+ "langName": "Java",
+ "type": "CODE_SMELL",
+ "params": [
+ {
+ "key": "max",
+ "desc": "Maximum number of allowed conditional operators in an expression",
+ "defaultValue": "3"
+ }
+ ]
+ },
+ {
+ "key": "squid:ClassCyclomaticComplexity",
+ "repo": "squid",
+ "name": "Avoid too complex class",
+ "createdAt": "2013-03-27T08:52:40+0100",
+ "htmlDesc": "<p>The Cyclomatic Complexity is measured by the number of (&&, ||)\n\toperators and (if, while, do, for, ?:, catch, switch, case, return,\n\tthrow) statements in the body of a class plus one for each constructor,\n\tmethod (but not getter/setter), static initializer, or instance\n\tinitializer in the class. The last return stament in method, if exists,\n\tis not taken into account.</p>\n<p>\n\tEven when the Cyclomatic Complexity of a class is very high, this\n\tcomplexity might be well distributed among all methods. Nevertheless,\n\tmost of the time, a very complex class is a class which breaks the <a\n\t\thref='http://en.wikipedia.org/wiki/Single_responsibility_principle'>Single\n\t\tResponsibility Principle</a> and which should be re-factored to be split\n\tin several classes.\n</p>",
+ "severity": "MAJOR",
+ "status": "READY",
+ "internalKey": "ClassCyclomaticComplexity",
+ "isTemplate": false,
+ "tags": [],
+ "sysTags": ["brain-overload"],
+ "lang": "java",
+ "langName": "Java",
+ "type": "BUG",
+ "params": [
+ {
+ "key": "max",
+ "desc": "Maximum complexity allowed.",
+ "defaultValue": "200"
+ }
+ ]
+ },
+ {
+ "key": "squid:MethodCyclomaticComplexity",
+ "repo": "squid",
+ "name": "Methods should not be too complex",
+ "createdAt": "2013-03-27T08:52:40+0100",
+ "htmlDesc": "<p>The Cyclomatic Complexity is measured by the number of\n\t(&&, ||) operators and (if, while, do, for, ?:, catch, switch,\n\tcase, return, throw) statements in the body of a class plus one for\n\teach constructor, method (but not getter/setter), static initializer,\n\tor instance initializer in the class. The last return stament in\n\tmethod, if exists, is not taken into account.</p>\n<p>\n\tEven when the Cyclomatic Complexity of a class is very high, this\n\tcomplexity might be well distributed among all methods. Nevertheless,\n\tmost of the time, a very complex class is a class which breaks the <a\n\t\thref=\"http://en.wikipedia.org/wiki/Single_responsibility_principle\">Single\n\t\tResponsibility Principle</a> and which should be re-factored to be split\n\tin several classes.\n</p>",
+ "severity": "MAJOR",
+ "status": "READY",
+ "internalKey": "MethodCyclomaticComplexity",
+ "isTemplate": false,
+ "tags": [],
+ "sysTags": ["brain-overload"],
+ "lang": "java",
+ "langName": "Java",
+ "type": "VULNERABILITY",
+ "params": [
+ {
+ "key": "max",
+ "desc": "Maximum complexity allowed.",
+ "defaultValue": "10"
+ }
+ ]
+ },
+ {
+ "key": "squid:XPath",
+ "repo": "squid",
+ "name": "XPath rule",
+ "createdAt": "2013-03-27T08:52:40+0100",
+ "htmlDesc": "<p>\nThis rule allows to define some homemade Java rules with help of an XPath expression.\n</p>\n\n<p>\nIssues are created depending on the return value of the XPath expression. If the XPath expression returns:\n</p>\n<ul>\n <li>a single or list of AST nodes, then a line issue with the given message is created for each node</li>\n <li>a boolean, then a file issue with the given message is created only if the boolean is true</li>\n <li>anything else, no issue is created</li>\n</ul>\n\n<p>\nHere is an example of an XPath expression to log an issue on each if statement : //ifStatement\n</p>",
+ "severity": "MAJOR",
+ "status": "READY",
+ "internalKey": "XPath",
+ "isTemplate": true,
+ "tags": [ ],
+ "sysTags": [ ],
+ "mdNote": "<p>\nThe tree produced by the <code>firstOf()</code> matcher is hard to work with from checks when alternatives are not named.\n</p>\n\n<p>\nConsider the following rule:\n</p>\n\n<pre>\nb.rule(COMPILATION_UNIT).is(\n b.firstOf( /* Non-Compliant */\n \"FOO\",\n \"BAR\"));\n</pre>\n\n<p>\nIf, from a check, one wants to forbid the usage of the \"BAR\" alternative,\nthe easiest option will be to verify that the value of the first token is \"BAR\",\ni.e. <code>\"BAR\".equals(compilationUnitNode.getTokenValue())</code>.\n</p>\n\n<p>\nThis is not maintainable, for at least two reasons:\n</p>\n\n<ul>\n <li>The grammar might evolve to also accept \"bar\" in lowercase, which will break <code>\"BAR\".equals(...)</code></li>\n <li>The grammar might evolve to optionally accept \"hello\" before the <code>firstOf()</code>, which will break <code>compilationUnitNode.getTokenValue()</code></li>\n</ul>\n\n<p>\nInstead, it is much better to rewrite the grammar as:\n</p>\n\n<pre>\nb.rule(COMPILATION_UNIT).is(\n firstOf( /* Compliant */\n FOO,\n BAR));\nb.rule(FOO).is(\"FOO\");\nb.rule(BAR).is(\"BAR\");\n</pre>\n\n<p>\nThe same check which forbids \"BAR\" would be written as: <code>compilationUnitNode.hasDirectChildren(BAR)</code>.\nThis allows both of the previous grammar evolutions to be made without impacting the check at all.\n</p>",
+ "htmlNote": "<p><br/>The tree produced by the <code>firstOf()</code> matcher is hard to work with from checks when alternatives are not named.<br/></p><br/><br/><p><br/>Consider the following rule:<br/></p><br/><br/><pre><br/>b.rule(COMPILATION_UNIT).is(<br/> b.firstOf( /* Non-Compliant */<br/> "FOO",<br/> "BAR"));<br/></pre><br/><br/><p><br/>If, from a check, one wants to forbid the usage of the "BAR" alternative,<br/>the easiest option will be to verify that the value of the first token is "BAR",<br/>i.e. <code>"BAR".equals(compilationUnitNode.getTokenValue())</code>.<br/></p><br/><br/><p><br/>This is not maintainable, for at least two reasons:<br/></p><br/><br/><ul><br/> <li>The grammar might evolve to also accept "bar" in lowercase, which will break <code>"BAR".equals(...)</code></li><br/> <li>The grammar might evolve to optionally accept "hello" before the <code>firstOf()</code>, which will break <code>compilationUnitNode.getTokenValue()</code></li><br/></ul><br/><br/><p><br/>Instead, it is much better to rewrite the grammar as:<br/></p><br/><br/><pre><br/>b.rule(COMPILATION_UNIT).is(<br/> firstOf( /* Compliant */<br/> FOO,<br/> BAR));<br/>b.rule(FOO).is("FOO");<br/>b.rule(BAR).is("BAR");<br/></pre><br/><br/><p><br/>The same check which forbids "BAR" would be written as: <code>compilationUnitNode.hasDirectChildren(BAR)</code>.<br/>This allows both of the previous grammar evolutions to be made without impacting the check at all.<br/></p>",
+ "noteLogin": "eric.hartmann",
+ "lang": "java",
+ "langName": "Java",
+ "type": "CODE_SMELL",
+ "params": [
+ {
+ "key": "xpathQuery",
+ "desc": "The XPath query",
+ "defaultValue": ""
+ },
+ {
+ "key": "message",
+ "desc": "The violation message",
+ "defaultValue": "The XPath expression matches this piece of code"
+ }
+ ]
+ },
+ {
+ "key": "squid:XPath_1369910135",
+ "repo": "squid",
+ "name": "firstOf() alternatives should be rules or token types",
+ "createdAt": "2013-05-30T10:35:35+0200",
+ "htmlDesc": "<p>\r\nThe tree produced by the <code>firstOf()</code> matcher is hard to work with from checks when alternatives are not named.\r\n</p>\r\n\r\n<p>\r\nConsider the following rule:\r\n</p>\r\n\r\n<pre>\r\nb.rule(COMPILATION_UNIT).is(\r\n b.firstOf( /* Non-Compliant */\r\n \"FOO\",\r\n \"BAR\"));\r\n</pre>\r\n\r\n<p>\r\nIf, from a check, one wants to forbid the usage of the \"BAR\" alternative,\r\nthe easiest option will be to verify that the value of the first token is \"BAR\",\r\ni.e. <code>\"BAR\".equals(compilationUnitNode.getTokenValue())</code>.\r\n</p>\r\n\r\n<p>\r\nThis is not maintainable, for at least two reasons:\r\n</p>\r\n\r\n<ul>\r\n <li>The grammar might evolve to also accept \"bar\" in lowercase, which will break <code>\"BAR\".equals(...)</code></li>\r\n <li>The grammar might evolve to optionally accept \"hello\" before the <code>firstOf()</code>, which will break <code>compilationUnitNode.getTokenValue()</code></li>\r\n</ul>\r\n\r\n<p>\r\nInstead, it is much better to rewrite the grammar as:\r\n</p>\r\n\r\n<pre>\r\nb.rule(COMPILATION_UNIT).is(\r\n firstOf( /* Compliant */\r\n FOO,\r\n BAR));\r\nb.rule(FOO).is(\"FOO\");\r\nb.rule(BAR).is(\"BAR\");\r\n</pre>\r\n\r\n<p>\r\nThe same check which forbids \"BAR\" would be written as: <code>compilationUnitNode.hasDirectChildren(BAR)</code>.\r\nThis allows both of the previous grammar evolutions to be made without impacting the check at all.\r\n</p>",
+ "severity": "MAJOR",
+ "status": "READY",
+ "internalKey": "XPath",
+ "isTemplate": false,
+ "templateKey": "squid:XPath",
+ "tags": [ ],
+ "sysTags": [ ],
+ "lang": "java",
+ "langName": "Java",
+ "type": "CODE_SMELL",
+ "params": [
+ {
+ "key": "xpathQuery",
+ "desc": "The XPath query",
+ "defaultValue": "//expression[primary/qualifiedIdentifier[count(IDENTIFIER) = 2]/IDENTIFIER[2]/@tokenValue = 'firstOf' and primary/identifierSuffix/arguments/expression[not(primary) or primary[not(qualifiedIdentifier) or identifierSuffix]]]"
+ },
+ {
+ "key": "message",
+ "desc": "The violation message",
+ "defaultValue": "Refactor this firstOf() to only use a rule or token type for each alternative."
+ }
+ ]
+ }
+ ],
+ "actives": {
+ "squid:MethodCyclomaticComplexity": [
+ {
+ "qProfile": "Sonar way with Findbugs:java",
+ "inherit": "NONE",
+ "severity": "MAJOR",
+ "params": [
+ {
+ "key": "max",
+ "value": "10"
+ }
+ ]
+ },
+ {
+ "qProfile": "Sonar way:java",
+ "inherit": "NONE",
+ "severity": "MAJOR",
+ "params": [
+ {
+ "key": "max",
+ "value": "10"
+ }
+ ]
+ }
+ ],
+ "squid:S1067": [
+ {
+ "qProfile": "Sonar way with Findbugs:java",
+ "inherit": "NONE",
+ "severity": "MAJOR",
+ "params": [
+ {
+ "key": "max",
+ "value": "3"
+ }
+ ]
+ },
+ {
+ "qProfile": "Sonar way:java",
+ "inherit": "NONE",
+ "severity": "MAJOR",
+ "params": [
+ {
+ "key": "max",
+ "value": "3"
+ }
+ ]
+ }
+ ],
+ "squid:ClassCyclomaticComplexity": [
+ {
+ "qProfile": "Sonar way with Findbugs:java",
+ "inherit": "NONE",
+ "severity": "MAJOR",
+ "params": [
+ {
+ "key": "max",
+ "value": "200"
+ }
+ ]
+ },
+ {
+ "qProfile": "Sonar way:java",
+ "inherit": "NONE",
+ "severity": "MAJOR",
+ "params": [
+ {
+ "key": "max",
+ "value": "200"
+ }
+ ]
+ }
+ ]
+ },
+ "facets": [
+ {
+ "name": "tags",
+ "values": [
+ {
+ "val": "complexity",
+ "count": 141
+ },
+ {
+ "val": "java8",
+ "count": 42
+ },
+ {
+ "val": "javadoc",
+ "count": 13
+ }
+ ]
+ },
+ {
+ "name": "languages",
+ "values": [
+ {
+ "val": "java",
+ "count": 563
+ }
+ ]
+ },
+ {
+ "name": "repositories",
+ "values": [
+ {
+ "val": "findbugs",
+ "count": 419
+ },
+ {
+ "val": "squid",
+ "count": 138
+ },
+ {
+ "val": "common-java",
+ "count": 6
+ }
+ ]
+ }
+
+ ]
+}
"is_template",
"inheritance",
"qprofile",
+ "compareToProfile",
"targetSeverity",
"tags",
"asc",
import org.sonar.db.DbTester;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.permission.OrganizationPermission;
-import org.sonar.server.exceptions.BadRequestException;
import org.sonar.db.qualityprofile.QProfileDto;
+import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.UnauthorizedException;
import org.sonar.server.organization.TestDefaultOrganizationProvider;
"is_template",
"inheritance",
"qprofile",
+ "compareToProfile",
"tags",
"asc",
"q",
import org.sonar.db.DbTester;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.qualityprofile.QProfileDto;
+import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.organization.TestDefaultOrganizationProvider;
import org.sonar.server.rule.index.RuleQuery;
import org.sonar.server.ws.TestRequest;
import static org.sonarqube.ws.client.rule.RulesWsParameters.PARAM_ACTIVATION;
import static org.sonarqube.ws.client.rule.RulesWsParameters.PARAM_ACTIVE_SEVERITIES;
import static org.sonarqube.ws.client.rule.RulesWsParameters.PARAM_AVAILABLE_SINCE;
+import static org.sonarqube.ws.client.rule.RulesWsParameters.PARAM_COMPARE_TO_PROFILE;
import static org.sonarqube.ws.client.rule.RulesWsParameters.PARAM_INHERITANCE;
import static org.sonarqube.ws.client.rule.RulesWsParameters.PARAM_IS_TEMPLATE;
import static org.sonarqube.ws.client.rule.RulesWsParameters.PARAM_LANGUAGES;
@Rule
public DbTester dbTester = DbTester.create(System2.INSTANCE);
@Rule
- public ExpectedException thrown = ExpectedException.none();
+ public ExpectedException expectedException = ExpectedException.none();
private DbClient dbClient = dbTester.getDbClient();
assertThat(result.getTags()).isNull();
assertThat(result.templateKey()).isNull();
assertThat(result.getTypes()).isEmpty();
-
assertThat(result.getSortField()).isNull();
+ assertThat(result.getCompareToQProfile()).isNull();
}
@Test
public void create_query() throws Exception {
QProfileDto qualityProfile = dbTester.qualityProfiles().insert(organization);
+ QProfileDto compareToQualityProfile = dbTester.qualityProfiles().insert(organization);
RuleQuery result = execute(
PARAM_RULE_KEY, "ruleKey",
PARAM_IS_TEMPLATE, "true",
PARAM_LANGUAGES, "java,js",
TEXT_QUERY, "S001",
- PARAM_QPROFILE, qualityProfile.getKee(),
PARAM_ORGANIZATION, organization.getKey(),
+ PARAM_QPROFILE, qualityProfile.getKee(),
+ PARAM_COMPARE_TO_PROFILE, compareToQualityProfile.getKee(),
PARAM_REPOSITORIES, "pmd,checkstyle",
PARAM_SEVERITIES, "MINOR,CRITICAL",
PARAM_STATUSES, "DEPRECATED,READY",
assertThat(result.getLanguages()).containsOnly(qualityProfile.getLanguage());
assertThat(result.getQueryText()).isEqualTo("S001");
assertThat(result.getQProfile().getKee()).isEqualTo(qualityProfile.getKee());
+ assertThat(result.getCompareToQProfile().getKee()).isEqualTo(compareToQualityProfile.getKee());
assertThat(result.getOrganization().getUuid()).isEqualTo(organization.getUuid());
assertThat(result.getRepositories()).containsOnly("pmd", "checkstyle");
assertThat(result.getRuleKey()).isNull();
assertThat(result.getOrganization().getUuid()).isEqualTo(organization.getUuid());
}
+ @Test
+ public void filter_on_compare_to() {
+ QProfileDto compareToProfile = dbTester.qualityProfiles().insert(organization);
+
+ RuleQuery result = execute(
+ PARAM_ORGANIZATION, organization.getKey(),
+ PARAM_COMPARE_TO_PROFILE, compareToProfile.getKee());
+
+ assertThat(result.getCompareToQProfile().getKee()).isEqualTo(compareToProfile.getKee());
+ }
+
@Test
public void fail_if_organization_and_quality_profile_are_contradictory() throws Exception {
OrganizationDto organization1 = dbTester.organizations().insert();
String qualityProfileKey = qualityProfile.getKee();
String organization2Key = organization2.getKey();
- thrown.expect(IllegalArgumentException.class);
- thrown.expectMessage("The specified quality profile '" + qualityProfileKey + "' is not part of the specified organization '" + organization2Key + "'");
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("The specified quality profile '" + qualityProfileKey + "' is not part of the specified organization '" + organization2Key + "'");
execute(PARAM_QPROFILE, qualityProfileKey,
PARAM_ORGANIZATION, organization2Key);
}
+ @Test
+ public void fail_if_organization_and_compare_to_quality_profile_are_contradictory() throws Exception {
+ OrganizationDto organization = dbTester.organizations().insert();
+ QProfileDto qualityProfile = dbTester.qualityProfiles().insert(organization);
+
+ OrganizationDto otherOrganization = dbTester.organizations().insert();
+ QProfileDto compareToQualityProfile = dbTester.qualityProfiles().insert(otherOrganization);
+
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("The specified quality profile '" + compareToQualityProfile.getKee() + "' is not part of the specified organization '" + organization.getKey() + "'");
+
+ execute(PARAM_QPROFILE, qualityProfile.getKee(),
+ PARAM_COMPARE_TO_PROFILE, compareToQualityProfile.getKee(),
+ PARAM_ORGANIZATION, organization.getKey());
+ }
+
+ @Test
+ public void fail_when_organization_does_not_exist() {
+ QProfileDto qualityProfile = dbTester.qualityProfiles().insert(organization);
+ String qualityProfileKey = qualityProfile.getKee();
+
+ expectedException.expect(NotFoundException.class);
+ expectedException.expectMessage("No organization with key 'unknown'");
+
+ execute(PARAM_QPROFILE, qualityProfileKey,
+ PARAM_ORGANIZATION, "unknown");
+ }
+
+ @Test
+ public void fail_when_profile_does_not_exist() {
+ expectedException.expect(NotFoundException.class);
+ expectedException.expectMessage("The specified qualityProfile 'unknown' does not exist");
+
+ execute(PARAM_QPROFILE, "unknown");
+ }
+
+ @Test
+ public void fail_when_compare_to_profile_does_not_exist() {
+ QProfileDto qualityProfile = dbTester.qualityProfiles().insert(organization);
+
+ expectedException.expect(NotFoundException.class);
+ expectedException.expectMessage("The specified qualityProfile 'unknown' does not exist");
+
+ execute(PARAM_QPROFILE, qualityProfile.getKee(),
+ PARAM_COMPARE_TO_PROFILE, "unknown");
+ }
+
private RuleQuery execute(String... paramsKeyAndValue) {
WsActionTester ws = new WsActionTester(fakeAction);
TestRequest request = ws.newRequest();
import static org.sonar.api.rule.Severity.BLOCKER;
import static org.sonar.db.rule.RuleTesting.setSystemTags;
import static org.sonar.db.rule.RuleTesting.setTags;
+import static org.sonarqube.ws.client.rule.RulesWsParameters.PARAM_ACTIVATION;
+import static org.sonarqube.ws.client.rule.RulesWsParameters.PARAM_COMPARE_TO_PROFILE;
+import static org.sonarqube.ws.client.rule.RulesWsParameters.PARAM_ORGANIZATION;
+import static org.sonarqube.ws.client.rule.RulesWsParameters.PARAM_QPROFILE;
import static org.sonarqube.ws.client.rule.RulesWsParameters.PARAM_RULE_KEY;
public class SearchActionTest {
+ private static final String JAVA = "java";
+
@org.junit.Rule
public UserSessionRule userSession = UserSessionRule.standalone();
@org.junit.Rule
- public ExpectedException thrown = ExpectedException.none();
+ public ExpectedException expectedException = ExpectedException.none();
private System2 system2 = new AlwaysIncreasingSystem2();
@org.junit.Rule
- public DbTester dbTester = DbTester.create(system2);
+ public DbTester db = DbTester.create(system2);
@org.junit.Rule
public EsTester es = new EsTester(new RuleIndexDefinition(new MapSettings()));
- private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(dbTester);
+ private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db);
private RuleIndex ruleIndex = new RuleIndex(es.client());
- private RuleIndexer ruleIndexer = new RuleIndexer(es.client(), dbTester.getDbClient());
- private ActiveRuleIndexer activeRuleIndexer = new ActiveRuleIndexer(dbTester.getDbClient(), es.client(), new ActiveRuleIteratorFactory(dbTester.getDbClient()));
- private Languages languages = LanguageTesting.newLanguages("java", "js");
- private ActiveRuleCompleter activeRuleCompleter = new ActiveRuleCompleter(dbTester.getDbClient(), languages);
- private RuleWsSupport wsSupport = new RuleWsSupport(dbTester.getDbClient(), userSession, defaultOrganizationProvider);
- private RuleQueryFactory ruleQueryFactory = new RuleQueryFactory(dbTester.getDbClient(), wsSupport);
+ private RuleIndexer ruleIndexer = new RuleIndexer(es.client(), db.getDbClient());
+ private ActiveRuleIndexer activeRuleIndexer = new ActiveRuleIndexer(db.getDbClient(), es.client(), new ActiveRuleIteratorFactory(db.getDbClient()));
+ private Languages languages = LanguageTesting.newLanguages(JAVA, "js");
+ private ActiveRuleCompleter activeRuleCompleter = new ActiveRuleCompleter(db.getDbClient(), languages);
+ private RuleWsSupport wsSupport = new RuleWsSupport(db.getDbClient(), userSession, defaultOrganizationProvider);
+ private RuleQueryFactory ruleQueryFactory = new RuleQueryFactory(db.getDbClient(), wsSupport);
private MacroInterpreter macroInterpreter = mock(MacroInterpreter.class);
private RuleMapper ruleMapper = new RuleMapper(languages, macroInterpreter);
- private SearchAction underTest = new SearchAction(ruleIndex, activeRuleCompleter, ruleQueryFactory, dbTester.getDbClient(), ruleMapper);
+ private SearchAction underTest = new SearchAction(ruleIndex, activeRuleCompleter, ruleQueryFactory, db.getDbClient(), ruleMapper);
- private RuleActivatorContextFactory contextFactory = new RuleActivatorContextFactory(dbTester.getDbClient());
+ private RuleActivatorContextFactory contextFactory = new RuleActivatorContextFactory(db.getDbClient());
private TypeValidations typeValidations = new TypeValidations(asList(new StringTypeValidation(), new IntegerTypeValidation()));
- private RuleActivator ruleActivator = new RuleActivator(system2, dbTester.getDbClient(), ruleIndex, contextFactory, typeValidations, activeRuleIndexer,
+ private RuleActivator ruleActivator = new RuleActivator(system2, db.getDbClient(), ruleIndex, contextFactory, typeValidations, activeRuleIndexer,
userSession);
private WsActionTester ws = new WsActionTester(underTest);
@Test
public void test_definition() {
- assertThat(ws.getDef().isPost()).isFalse();
- assertThat(ws.getDef().since()).isEqualTo("4.4");
- assertThat(ws.getDef().isInternal()).isFalse();
- assertThat(ws.getDef().params()).hasSize(22);
+ WebService.Action def = ws.getDef();
+
+ assertThat(def.isPost()).isFalse();
+ assertThat(def.since()).isEqualTo("4.4");
+ assertThat(def.isInternal()).isFalse();
+ assertThat(def.responseExampleAsString()).isNotEmpty();
+ assertThat(def.params()).hasSize(23);
+
+ WebService.Param compareToProfile = def.param("compareToProfile");
+ assertThat(compareToProfile.since()).isEqualTo("6.5");
+ assertThat(compareToProfile.isRequired()).isFalse();
+ assertThat(compareToProfile.isInternal()).isTrue();
+ assertThat(compareToProfile.description()).isEqualTo("Quality profile key to filter rules that are activated. Meant to compare easily to profile set in 'qprofile'");
}
@Test
@Test
public void should_filter_on_organization_specific_tags() throws IOException {
- OrganizationDto organization = dbTester.organizations().insert();
+ OrganizationDto organization = db.organizations().insert();
RuleDefinitionDto rule1 = createJavaRule();
RuleMetadataDto metadata1 = insertMetadata(organization, rule1, setTags("tag1", "tag2"));
RuleDefinitionDto rule2 = createJavaRule();
@Test
public void should_list_tags_in_tags_facet() throws IOException {
- OrganizationDto organization = dbTester.organizations().insert();
- RuleDefinitionDto rule = dbTester.rules().insert(setSystemTags("tag1", "tag3", "tag5", "tag7", "tag9", "x"));
+ OrganizationDto organization = db.organizations().insert();
+ RuleDefinitionDto rule = db.rules().insert(setSystemTags("tag1", "tag3", "tag5", "tag7", "tag9", "x"));
RuleMetadataDto metadata = insertMetadata(organization, rule, setTags("tag2", "tag4", "tag6", "tag8", "tagA"));
indexRules();
@Test
public void should_include_selected_matching_tag_in_facet() throws IOException {
- RuleDefinitionDto rule = dbTester.rules().insert(setSystemTags("tag1", "tag2", "tag3", "tag4", "tag5", "tag6", "tag7", "tag8", "tag9", "tagA", "x"));
+ RuleDefinitionDto rule = db.rules().insert(setSystemTags("tag1", "tag2", "tag3", "tag4", "tag5", "tag6", "tag7", "tag8", "tag9", "tagA", "x"));
indexRules();
SearchResponse result = ws.newRequest()
@Test
public void should_included_selected_non_matching_tag_in_facet() throws IOException {
- RuleDefinitionDto rule = dbTester.rules().insert(setSystemTags("tag1", "tag2", "tag3", "tag4", "tag5", "tag6", "tag7", "tag8", "tag9", "tagA"));
+ RuleDefinitionDto rule = db.rules().insert(setSystemTags("tag1", "tag2", "tag3", "tag4", "tag5", "tag6", "tag7", "tag8", "tag9", "tagA"));
indexRules();
SearchResponse result = ws.newRequest()
@Test
public void should_return_organization_specific_tags() throws IOException {
- OrganizationDto organization = dbTester.organizations().insert();
+ OrganizationDto organization = db.organizations().insert();
RuleDefinitionDto rule = createJavaRule();
RuleMetadataDto metadata = insertMetadata(organization, rule, setTags("tag1", "tag2"));
indexRules();
@Test
public void return_lang_key_field_when_language_name_is_not_available() throws Exception {
- OrganizationDto organization = dbTester.organizations().insert();
+ OrganizationDto organization = db.organizations().insert();
String unknownLanguage = "unknown_" + randomAlphanumeric(5);
- RuleDefinitionDto rule = dbTester.rules().insert(r -> r.setLanguage(unknownLanguage));
+ RuleDefinitionDto rule = db.rules().insert(r -> r.setLanguage(unknownLanguage));
indexRules();
@Test
public void search_debt_rules_with_default_and_overridden_debt_values() throws Exception {
- RuleDefinitionDto rule = dbTester.rules().insert(r ->
+ RuleDefinitionDto rule = db.rules().insert(r ->
r.setLanguage("java")
.setDefRemediationFunction(DebtRemediationFunction.Type.LINEAR_OFFSET.name())
.setDefRemediationGapMultiplier("1h")
.setDefRemediationBaseEffort("15min"));
- RuleMetadataDto metadata = insertMetadata(dbTester.getDefaultOrganization(), rule,
+ RuleMetadataDto metadata = insertMetadata(db.getDefaultOrganization(), rule,
r -> r.setRemediationFunction(DebtRemediationFunction.Type.LINEAR_OFFSET.name())
.setRemediationGapMultiplier("2h")
.setRemediationBaseEffort("25min"));
@Test
public void search_debt_rules_with_default_linear_offset_and_overridden_constant_debt() throws Exception {
- RuleDefinitionDto rule = dbTester.rules().insert(r ->
+ RuleDefinitionDto rule = db.rules().insert(r ->
r.setLanguage("java")
.setDefRemediationFunction(DebtRemediationFunction.Type.LINEAR_OFFSET.name())
.setDefRemediationGapMultiplier("1h")
.setDefRemediationBaseEffort("15min"));
- RuleMetadataDto metadata = insertMetadata(dbTester.getDefaultOrganization(), rule,
+ RuleMetadataDto metadata = insertMetadata(db.getDefaultOrganization(), rule,
r -> r.setRemediationFunction(DebtRemediationFunction.Type.CONSTANT_ISSUE.name())
.setRemediationGapMultiplier(null)
.setRemediationBaseEffort("5min"));
@Test
public void search_debt_rules_with_default_linear_offset_and_overridden_linear_debt() throws Exception {
- RuleDefinitionDto rule = dbTester.rules().insert(r ->
+ RuleDefinitionDto rule = db.rules().insert(r ->
r.setLanguage("java")
.setDefRemediationFunction(DebtRemediationFunction.Type.LINEAR_OFFSET.name())
.setDefRemediationGapMultiplier("1h")
.setDefRemediationBaseEffort("15min"));
- RuleMetadataDto metadata = insertMetadata(dbTester.getDefaultOrganization(), rule,
+ RuleMetadataDto metadata = insertMetadata(db.getDefaultOrganization(), rule,
r -> r.setRemediationFunction(DebtRemediationFunction.Type.LINEAR.name())
.setRemediationGapMultiplier("1h")
.setRemediationBaseEffort(null));
@Test
public void search_template_rules() throws Exception {
- RuleDefinitionDto templateRule = dbTester.rules().insert(r ->
+ RuleDefinitionDto templateRule = db.rules().insert(r ->
r.setLanguage("java")
.setIsTemplate(true));
- RuleDefinitionDto rule = dbTester.rules().insert(r ->
+ RuleDefinitionDto rule = db.rules().insert(r ->
r.setLanguage("java")
.setTemplateId(templateRule.getId()));
@Test
public void search_custom_rules_from_template_key() throws Exception {
- RuleDefinitionDto templateRule = dbTester.rules().insert(r ->
+ RuleDefinitionDto templateRule = db.rules().insert(r ->
r.setLanguage("java")
.setIsTemplate(true));
- RuleDefinitionDto rule = dbTester.rules().insert(r ->
+ RuleDefinitionDto rule = db.rules().insert(r ->
r.setLanguage("java")
.setTemplateId(templateRule.getId()));
@Test
public void search_all_active_rules() throws Exception {
- OrganizationDto organization = dbTester.organizations().insert();
- QProfileDto profile = dbTester.qualityProfiles().insert(organization, p -> p.setLanguage("java"));
+ OrganizationDto organization = db.organizations().insert();
+ QProfileDto profile = db.qualityProfiles().insert(organization, p -> p.setLanguage("java"));
RuleDefinitionDto rule = createJavaRule();
RuleActivation activation = RuleActivation.create(rule.getKey(), BLOCKER, null);
- ruleActivator.activate(dbTester.getSession(), activation, profile);
+ ruleActivator.activate(db.getSession(), activation, profile);
indexRules();
@Test
public void search_profile_active_rules() throws Exception {
- OrganizationDto organization = dbTester.organizations().insert();
- QProfileDto profile = dbTester.qualityProfiles().insert(organization, p -> p.setLanguage("java"));
- QProfileDto waterproofProfile = dbTester.qualityProfiles().insert(organization, p -> p.setLanguage("java"));
+ OrganizationDto organization = db.organizations().insert();
+ QProfileDto profile = db.qualityProfiles().insert(organization, p -> p.setLanguage("java"));
+ QProfileDto waterproofProfile = db.qualityProfiles().insert(organization, p -> p.setLanguage("java"));
RuleDefinitionDto rule = createJavaRule();
- RuleParamDto ruleParam1 = dbTester.rules().insertRuleParam(rule, p ->
+ RuleParamDto ruleParam1 = db.rules().insertRuleParam(rule, p ->
p.setDefaultValue("some value")
.setType("STRING")
.setDescription("My small description")
.setName("my_var"));
- RuleParamDto ruleParam2 = dbTester.rules().insertRuleParam(rule, p ->
+ RuleParamDto ruleParam2 = db.rules().insertRuleParam(rule, p ->
p.setDefaultValue("1")
.setType("INTEGER")
.setDescription("My small description")
.setName("the_var"));
// SONAR-7083
- RuleParamDto ruleParam3 = dbTester.rules().insertRuleParam(rule, p ->
+ RuleParamDto ruleParam3 = db.rules().insertRuleParam(rule, p ->
p.setDefaultValue(null)
.setType("STRING")
.setDescription("Empty Param")
.setName("empty_var"));
RuleActivation activation = RuleActivation.create(rule.getKey());
- List<ActiveRuleChange> activeRuleChanges1 = ruleActivator.activate(dbTester.getSession(), activation, profile);
- ruleActivator.activate(dbTester.getSession(), activation, waterproofProfile);
+ List<ActiveRuleChange> activeRuleChanges1 = ruleActivator.activate(db.getSession(), activation, profile);
+ ruleActivator.activate(db.getSession(), activation, waterproofProfile);
assertThat(activeRuleChanges1).hasSize(1);
- dbTester.commit();
+ db.commit();
indexRules();
indexActiveRules();
);
String unknownProfile = "unknown_profile" + randomAlphanumeric(5);
- thrown.expect(NotFoundException.class);
- thrown.expectMessage("The specified qualityProfile '" + unknownProfile + "' does not exist");
+ expectedException.expect(NotFoundException.class);
+ expectedException.expectMessage("The specified qualityProfile '" + unknownProfile + "' does not exist");
ws.newRequest()
.setParam("activation", "true")
}
@Test
- public void test_SONAR7083() {
- OrganizationDto organization = dbTester.organizations().insert();
- QProfileDto profile = dbTester.qualityProfiles().insert(organization, p -> p.setLanguage("java"));
+ public void search_for_active_rules_when_parameter_value_is_null() {
+ OrganizationDto organization = db.organizations().insert();
+ QProfileDto profile = db.qualityProfiles().insert(organization, p -> p.setLanguage("java"));
RuleDefinitionDto rule = createJavaRule();
- RuleParamDto ruleParam = dbTester.rules().insertRuleParam(rule, p ->
+ RuleParamDto ruleParam = db.rules().insertRuleParam(rule, p ->
p.setDefaultValue("some value")
.setType("STRING")
.setDescription("My small description")
.setName("my_var"));
RuleActivation activation = RuleActivation.create(rule.getKey());
- List<ActiveRuleChange> activeRuleChanges = ruleActivator.activate(dbTester.getSession(), activation, profile);
+ List<ActiveRuleChange> activeRuleChanges = ruleActivator.activate(db.getSession(), activation, profile);
// Insert directly in database a rule parameter with a null value
ActiveRuleParamDto activeRuleParam = ActiveRuleParamDto.createFor(ruleParam).setValue(null);
- dbTester.getDbClient().activeRuleDao().insertParam(dbTester.getSession(), activeRuleChanges.get(0).getActiveRule(), activeRuleParam);
+ db.getDbClient().activeRuleDao().insertParam(db.getSession(), activeRuleChanges.get(0).getActiveRule(), activeRuleParam);
- dbTester.commit();
+ db.commit();
indexRules();
indexActiveRules();
@Test
public void statuses_facet_should_be_sticky() throws Exception {
- RuleDefinitionDto rule1 = dbTester.rules().insert(r -> r.setLanguage("java"));
- RuleDefinitionDto rule2 = dbTester.rules().insert(r -> r.setLanguage("java").setStatus(RuleStatus.BETA));
- RuleDefinitionDto rule3 = dbTester.rules().insert(r -> r.setLanguage("java").setStatus(RuleStatus.DEPRECATED));
+ RuleDefinitionDto rule1 = db.rules().insert(r -> r.setLanguage("java"));
+ RuleDefinitionDto rule2 = db.rules().insert(r -> r.setLanguage("java").setStatus(RuleStatus.BETA));
+ RuleDefinitionDto rule3 = db.rules().insert(r -> r.setLanguage("java").setStatus(RuleStatus.DEPRECATED));
indexRules();
);
}
+ @Test
+ public void compare_to_another_profile() throws Exception {
+ OrganizationDto organization = db.organizations().insert();
+ QProfileDto profile = db.qualityProfiles().insert(organization, p -> p.setLanguage(JAVA));
+ QProfileDto anotherProfile = db.qualityProfiles().insert(organization, p -> p.setLanguage(JAVA));
+ RuleDefinitionDto commonRule = db.rules().insertRule(r -> r.setLanguage(JAVA)).getDefinition();
+ RuleDefinitionDto profileRule1 = db.rules().insertRule(r -> r.setLanguage(JAVA)).getDefinition();
+ RuleDefinitionDto profileRule2 = db.rules().insertRule(r -> r.setLanguage(JAVA)).getDefinition();
+ RuleDefinitionDto profileRule3 = db.rules().insertRule(r -> r.setLanguage(JAVA)).getDefinition();
+ RuleDefinitionDto anotherProfileRule1 = db.rules().insertRule(r -> r.setLanguage(JAVA)).getDefinition();
+ RuleDefinitionDto anotherProfileRule2 = db.rules().insertRule(r -> r.setLanguage(JAVA)).getDefinition();
+ db.qualityProfiles().activateRule(profile, commonRule);
+ db.qualityProfiles().activateRule(profile, profileRule1);
+ db.qualityProfiles().activateRule(profile, profileRule2);
+ db.qualityProfiles().activateRule(profile, profileRule3);
+ db.qualityProfiles().activateRule(anotherProfile, commonRule);
+ db.qualityProfiles().activateRule(anotherProfile, anotherProfileRule1);
+ db.qualityProfiles().activateRule(anotherProfile, anotherProfileRule2);
+ indexRules();
+ indexActiveRules();
+
+ SearchResponse result = ws.newRequest()
+ .setParam(PARAM_ORGANIZATION, organization.getKey())
+ .setParam(PARAM_QPROFILE, profile.getKee())
+ .setParam(PARAM_ACTIVATION, "false")
+ .setParam(PARAM_COMPARE_TO_PROFILE, anotherProfile.getKee())
+ .executeProtobuf(SearchResponse.class);
+
+ assertThat(result.getRulesList())
+ .extracting(Rule::getKey)
+ .containsExactlyInAnyOrder(anotherProfileRule1.getKey().toString(), anotherProfileRule2.getKey().toString());
+ }
+
@SafeVarargs
private final <T> void checkField(RuleDefinitionDto rule, String fieldName, Extractor<Rule, T> responseExtractor, T... expected) throws IOException {
SearchResponse result = ws.newRequest()
@SafeVarargs
private final RuleMetadataDto insertMetadata(OrganizationDto organization, RuleDefinitionDto rule, Consumer<RuleMetadataDto>... populaters) {
- RuleMetadataDto metadata = dbTester.rules().insertOrUpdateMetadata(rule, organization, populaters);
+ RuleMetadataDto metadata = db.rules().insertOrUpdateMetadata(rule, organization, populaters);
ruleIndexer.indexRuleExtension(organization, rule.getKey());
return metadata;
}
}
private RuleDefinitionDto createJavaRule() {
- return dbTester.rules().insert(r -> r.setLanguage("java"));
+ return db.rules().insert(r -> r.setLanguage("java"));
}
}
public static final String PARAM_IS_TEMPLATE = "is_template";
public static final String PARAM_TEMPLATE_KEY = "template_key";
public static final String PARAM_ORGANIZATION = "organization";
+ public static final String PARAM_COMPARE_TO_PROFILE = "compare_to_profile";
public static final String FIELD_REPO = "repo";
public static final String FIELD_NAME = "name";