import org.sonar.core.permission.GlobalPermissions;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.preview.PreviewCache;
-import org.sonar.core.qualityprofile.db.ActiveRuleDto;
-import org.sonar.core.qualityprofile.db.ActiveRuleKey;
-import org.sonar.core.qualityprofile.db.ActiveRuleParamDto;
-import org.sonar.core.qualityprofile.db.QualityProfileDto;
-import org.sonar.core.qualityprofile.db.QualityProfileKey;
+import org.sonar.core.qualityprofile.db.*;
import org.sonar.core.rule.RuleParamDto;
import org.sonar.server.db.DbClient;
import org.sonar.server.qualityprofile.db.ActiveRuleDao;
import org.sonar.server.rule.Rule;
import org.sonar.server.rule.index.RuleIndex;
+import org.sonar.server.rule.index.RuleNormalizer;
import org.sonar.server.rule.index.RuleQuery;
import org.sonar.server.rule.index.RuleResult;
import org.sonar.server.search.IndexClient;
import org.sonar.server.util.TypeValidations;
import javax.annotation.Nullable;
+
import java.util.List;
import java.util.Map;
RuleResult result = ruleIndex.search(ruleQuery,
QueryOptions.DEFAULT.setOffset(0)
.setLimit(Integer.MAX_VALUE)
- .setFieldsToReturn(ImmutableSet.of("template", "severity"))
+ .setFieldsToReturn(ImmutableSet.of(RuleNormalizer.RuleField.IS_TEMPLATE.field(), RuleNormalizer.RuleField.SEVERITY.field()))
);
for (Rule rule : result.getHits()) {
- if (!rule.template()) {
+ if (!rule.isTemplate()) {
ActiveRuleKey key = ActiveRuleKey.of(profile, rule.key());
RuleActivation activation = new RuleActivation(key);
activation.setSeverity(rule.severity());
QueryOptions.DEFAULT.setOffset(0)
// TODO pb because limited to QueryOptions.MAX_LIMIT
.setLimit(Integer.MAX_VALUE)
- .setFieldsToReturn(ImmutableSet.of("template", "severity"))
+ .setFieldsToReturn(ImmutableSet.of(RuleNormalizer.RuleField.IS_TEMPLATE.field(), RuleNormalizer.RuleField.SEVERITY.field()))
);
for (Rule rule : result.getHits()) {
*/
RuleStatus status();
- boolean template();
+ boolean isTemplate();
@CheckForNull
RuleKey templateKey();
}
@Override
- public boolean template() {
- return (Boolean) getField(RuleNormalizer.RuleField.TEMPLATE.field());
+ public boolean isTemplate() {
+ return (Boolean) getField(RuleNormalizer.RuleField.IS_TEMPLATE.field());
}
@Override
Boolean isTemplate = query.isTemplate();
if (isTemplate != null) {
- this.addTermFilter(fb, RuleNormalizer.RuleField.TEMPLATE.field(), Boolean.toString(isTemplate));
+ this.addTermFilter(fb, RuleNormalizer.RuleField.IS_TEMPLATE.field(), Boolean.toString(isTemplate));
}
- String template = query.template();
+ String template = query.templateKey();
if (template != null) {
this.addTermFilter(fb, RuleNormalizer.RuleField.TEMPLATE_KEY.field(), template);
}
public static IndexField TAGS = add(IndexField.Type.STRING, "tags");
public static IndexField SYSTEM_TAGS = add(IndexField.Type.STRING, "sysTags");
public static IndexField INTERNAL_KEY = add(IndexField.Type.STRING, "internalKey");
- public static IndexField TEMPLATE = add(IndexField.Type.BOOLEAN, "template");
+ public static IndexField IS_TEMPLATE = add(IndexField.Type.BOOLEAN, "isTemplate");
+ public static IndexField TEMPLATE_KEY = add(IndexField.Type.STRING, "templateKey");
public static IndexField DEBT_FUNCTION_TYPE = add(IndexField.Type.STRING, "debtRemFnType");
public static IndexField DEBT_FUNCTION_COEFFICIENT = add(IndexField.Type.STRING, "debtRemFnCoefficient");
public static IndexField DEBT_FUNCTION_OFFSET = add(IndexField.Type.STRING, "debtRemFnOffset");
public static IndexField SUB_CHARACTERISTIC = add(IndexField.Type.STRING, "debtSubChar");
public static IndexField CHARACTERISTIC = add(IndexField.Type.STRING, "debtChar");
- public static IndexField TEMPLATE_KEY = add(IndexField.Type.STRING, "templateKey");
public static IndexField NOTE = add(IndexField.Type.TEXT, "markdownNote");
public static IndexField NOTE_LOGIN = add(IndexField.Type.STRING, "noteLogin");
public static IndexField NOTE_CREATED_AT = add(IndexField.Type.DATE, "noteCreatedAt");
update.put(RuleField.STATUS.field(), rule.getStatus().name());
update.put(RuleField.LANGUAGE.field(), rule.getLanguage());
update.put(RuleField.INTERNAL_KEY.field(), rule.getConfigKey());
- update.put(RuleField.TEMPLATE.field(), rule.getCardinality() == Cardinality.MULTIPLE);
+ update.put(RuleField.IS_TEMPLATE.field(), rule.getCardinality() == Cardinality.MULTIPLE);
update.put(RuleField.NOTE.field(), rule.getNoteData());
update.put(RuleField.NOTE_LOGIN.field(), rule.getNoteUserLogin());
private Boolean activation;
private String qProfileKey;
private Collection<String> inheritance;
- private String template;
+ private String templateKey;
private Boolean isTemplate;
private Date availableSince;
private IndexField sortField;
}
@CheckForNull
- public String template() {
- return template;
+ public String templateKey() {
+ return templateKey;
}
- public RuleQuery setTemplate(@Nullable String template) {
- this.template = template;
+ public RuleQuery setTemplateKey(@Nullable String templateKey) {
+ this.templateKey = templateKey;
return this;
}
addIndexStringField("severity", RuleNormalizer.RuleField.SEVERITY.field());
addIndexStringField("status", RuleNormalizer.RuleField.STATUS.field());
addIndexStringField("internalKey", RuleNormalizer.RuleField.INTERNAL_KEY.field());
- addIndexBooleanField("template", RuleNormalizer.RuleField.TEMPLATE.field());
+ addIndexBooleanField("isTemplate", RuleNormalizer.RuleField.IS_TEMPLATE.field());
addIndexStringField("templateKey", RuleNormalizer.RuleField.TEMPLATE_KEY.field());
addIndexArrayField("tags", RuleNormalizer.RuleField.TAGS.field());
addIndexArrayField("sysTags", RuleNormalizer.RuleField.SYSTEM_TAGS.field());
public static final String PARAM_ALL_OF_TAGS = "all_of_tags";
public static final String PARAM_INHERITANCE = "inheritance";
public static final String PARAM_IS_TEMPLATE = "is_template";
- public static final String PARAM_TEMPLATE = "template";
+ public static final String PARAM_TEMPLATE_KEY = "template_key";
public static final String PARAM_FACETS = "facets";
public static final String SEARCH_ACTION = "search";
.setBooleanPossibleValues();
action
- .createParam(PARAM_TEMPLATE)
+ .createParam(PARAM_TEMPLATE_KEY)
.setDescription("Key of template rule to filter on. Available since 4.4")
.setExampleValue("java:S001");
query.setAllOfTags(request.paramAsStrings(PARAM_ALL_OF_TAGS));
query.setInheritance(request.paramAsStrings(PARAM_INHERITANCE));
query.setIsTemplate(request.paramAsBoolean(PARAM_IS_TEMPLATE));
- query.setTemplate(request.param(PARAM_TEMPLATE));
+ query.setTemplateKey(request.param(PARAM_TEMPLATE_KEY));
return query;
}
"severity": "MAJOR",
"status": "READY",
"internalKey": "S1067",
- "template": false,
+ "isTemplate": false,
"tags": [],
"sysTags": ["brain-overload"],
"lang": "java",
"severity": "MAJOR",
"status": "READY",
"internalKey": "ClassCyclomaticComplexity",
- "template": false,
+ "isTemplate": false,
"tags": [],
"sysTags": ["brain-overload"],
"lang": "java",
"severity": "MAJOR",
"status": "READY",
"internalKey": "MethodCyclomaticComplexity",
- "template": false,
+ "isTemplate": false,
"tags": [],
"sysTags": ["brain-overload"],
"lang": "java",
"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",
+ "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",
+ "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": {
{
"val": "javadoc",
"count": 13
- }]
+ }
+ ]
},
{
"name": "languages",
assertThat(hit.updatedAt()).isNotNull();
assertThat(hit.internalKey()).isEqualTo("InternalKeyS001");
assertThat(hit.severity()).isEqualTo("INFO");
- assertThat(hit.template()).isFalse();
+ assertThat(hit.isTemplate()).isFalse();
assertThat(hit.tags()).containsOnly("tag1", "tag2");
assertThat(hit.systemTags()).containsOnly("systag1", "systag2");
}
results = index.search(query, new QueryOptions());
assertThat(results.getHits()).hasSize(1);
assertThat(Iterables.getFirst(results.getHits(), null).key().rule()).isEqualTo("S002");
- assertThat(Iterables.getFirst(results.getHits(), null).template()).isTrue();
+ assertThat(Iterables.getFirst(results.getHits(), null).isTemplate()).isTrue();
// Only not template
query = new RuleQuery().setIsTemplate(false);
results = index.search(query, new QueryOptions());
assertThat(results.getHits()).hasSize(1);
- assertThat(Iterables.getFirst(results.getHits(), null).template()).isFalse();
+ assertThat(Iterables.getFirst(results.getHits(), null).isTemplate()).isFalse();
assertThat(Iterables.getFirst(results.getHits(), null).key().rule()).isEqualTo("S001");
// null => no filter
assertThat(results.getHits()).hasSize(2);
// Only custom rule
- query = new RuleQuery().setTemplate("java:S001");
+ query = new RuleQuery().setTemplateKey("java:S001");
results = index.search(query, new QueryOptions());
assertThat(results.getHits()).hasSize(1);
assertThat(Iterables.getFirst(results.getHits(), null).key().rule()).isEqualTo("S001_MY_CUSTOM");
assertThat(Iterables.getFirst(results.getHits(), null).templateKey()).isEqualTo(RuleKey.of("java", "S001"));
// null => no filter
- query = new RuleQuery().setTemplate(null);
+ query = new RuleQuery().setTemplateKey(null);
assertThat(index.search(query, new QueryOptions()).getHits()).hasSize(2);
}
MockUserSession.set();
WsTester.TestRequest request = tester.wsTester().newGetRequest(API_ENDPOINT, API_SEARCH_METHOD);
- request.setParam(SearchOptions.PARAM_FIELDS, "template");
+ request.setParam(SearchOptions.PARAM_FIELDS, "isTemplate");
request.setParam(SearchAction.PARAM_IS_TEMPLATE, "true");
WsTester.Result result = request.execute();
result.assertJson(this.getClass(), "search_template_rules.json");
MockUserSession.set();
WsTester.TestRequest request = tester.wsTester().newGetRequest(API_ENDPOINT, API_SEARCH_METHOD);
request.setParam(SearchOptions.PARAM_FIELDS, "templateKey");
- request.setParam(SearchAction.PARAM_TEMPLATE, "java:S001");
+ request.setParam(SearchAction.PARAM_TEMPLATE_KEY, "java:S001");
WsTester.Result result = request.execute();
result.assertJson(this.getClass(), "search_rules_from_template_key.json");
}
"htmlDesc": "Description S002",
"status": "READY",
"severity": "INFO",
- "template": false,
+ "isTemplate": false,
"internalKey": "InternalKeyS002",
"tags": [],
"sysTags": [],
"htmlDesc": "Description S001",
"status": "READY",
"severity": "INFO",
- "template": false,
+ "isTemplate": false,
"internalKey": "InternalKeyS001",
"tags": [],
"sysTags": [],
{"total": 1, "p": 1, "ps": 10, "rules": [
{
"key": "java:S001",
- "template": true
+ "isTemplate": true
}
]}
"status": "READY",
"sysTags": [],
"tags": [],
- "template": false
+ "isTemplate": false
}
}
"status": "READY",
"sysTags": [],
"tags": [],
- "template": false
+ "isTemplate": false
}
}