summaryrefslogtreecommitdiffstats
path: root/it
diff options
context:
space:
mode:
authorJulien Lancelot <julien.lancelot@sonarsource.com>2015-10-07 14:12:10 +0200
committerJulien Lancelot <julien.lancelot@sonarsource.com>2015-10-09 16:48:24 +0200
commitf59052c8e1daed111d931893b2a08f9f5fa2a74a (patch)
tree247e34ce3bb90f2652a3fc0c4602990c66c76369 /it
parent74af3d8161ca9a767d9b6a7a2bdc3f5d29bd5003 (diff)
downloadsonarqube-f59052c8e1daed111d931893b2a08f9f5fa2a74a.tar.gz
sonarqube-f59052c8e1daed111d931893b2a08f9f5fa2a74a.zip
SONAR-6717 Restore issues actions API
Diffstat (limited to 'it')
-rw-r--r--it/it-plugins/issue-action-plugin/pom.xml40
-rw-r--r--it/it-plugins/issue-action-plugin/src/main/java/ActionDefinition.java46
-rw-r--r--it/it-plugins/issue-action-plugin/src/main/java/IssueActionPlugin.java34
-rw-r--r--it/it-plugins/issue-action-plugin/src/main/resources/org/sonar/l10n/issueaction.properties21
-rw-r--r--it/it-plugins/pom.xml1
-rw-r--r--it/it-tests/src/test/java/issue/suite/IssueActionTest.java257
-rw-r--r--it/it-tests/src/test/java/issue/suite/IssueTestSuite.java26
-rw-r--r--it/it-tests/src/test/java/util/ItUtils.java20
-rw-r--r--it/it-tests/src/test/resources/issue/suite/IssueActionTest/xoo-one-issue-per-line-profile.xml12
9 files changed, 449 insertions, 8 deletions
diff --git a/it/it-plugins/issue-action-plugin/pom.xml b/it/it-plugins/issue-action-plugin/pom.xml
new file mode 100644
index 00000000000..6b176b8e5bd
--- /dev/null
+++ b/it/it-plugins/issue-action-plugin/pom.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.sonarsource.it</groupId>
+ <artifactId>it-plugins</artifactId>
+ <version>5.2-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>issue-action-plugin</artifactId>
+ <packaging>sonar-plugin</packaging>
+ <name>Plugins :: Issue Action</name>
+ <version>1.0-SNAPSHOT</version>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.codehaus.sonar</groupId>
+ <artifactId>sonar-plugin-api</artifactId>
+ <version>${apiVersion}</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.sonar</groupId>
+ <artifactId>sonar-packaging-maven-plugin</artifactId>
+ <version>1.1</version>
+ <extensions>true</extensions>
+ <configuration>
+ <pluginClass>IssueActionPlugin</pluginClass>
+ <pluginKey>issueaction</pluginKey>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/it/it-plugins/issue-action-plugin/src/main/java/ActionDefinition.java b/it/it-plugins/issue-action-plugin/src/main/java/ActionDefinition.java
new file mode 100644
index 00000000000..84f5e6c5a6a
--- /dev/null
+++ b/it/it-plugins/issue-action-plugin/src/main/java/ActionDefinition.java
@@ -0,0 +1,46 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.
+ */
+
+import org.sonar.api.ServerExtension;
+import org.sonar.api.issue.Issue;
+import org.sonar.api.issue.action.Actions;
+import org.sonar.api.issue.action.Function;
+import org.sonar.api.issue.condition.HasResolution;
+
+public class ActionDefinition implements ServerExtension {
+
+ private final Actions actions;
+
+ public ActionDefinition(Actions actions) {
+ this.actions = actions;
+ }
+
+ public void start() {
+ actions.add("fake")
+ .setConditions(new HasResolution(Issue.RESOLUTION_FIXED))
+ .setFunctions(new Function() {
+ @Override
+ public void execute(Context context) {
+ context.setAttribute("fake", "fake action");
+ context.addComment("New Comment from fake action");
+ }
+ });
+ }
+}
diff --git a/it/it-plugins/issue-action-plugin/src/main/java/IssueActionPlugin.java b/it/it-plugins/issue-action-plugin/src/main/java/IssueActionPlugin.java
new file mode 100644
index 00000000000..d322d9f4d90
--- /dev/null
+++ b/it/it-plugins/issue-action-plugin/src/main/java/IssueActionPlugin.java
@@ -0,0 +1,34 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.
+ */
+
+import org.sonar.api.SonarPlugin;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class IssueActionPlugin extends SonarPlugin {
+
+ public List getExtensions() {
+ return Arrays.asList(
+ ActionDefinition.class
+ );
+ }
+
+}
diff --git a/it/it-plugins/issue-action-plugin/src/main/resources/org/sonar/l10n/issueaction.properties b/it/it-plugins/issue-action-plugin/src/main/resources/org/sonar/l10n/issueaction.properties
new file mode 100644
index 00000000000..f507ceed575
--- /dev/null
+++ b/it/it-plugins/issue-action-plugin/src/main/resources/org/sonar/l10n/issueaction.properties
@@ -0,0 +1,21 @@
+#
+# SonarQube, open source software quality management tool.
+# Copyright (C) 2008-2014 SonarSource
+# mailto:contact AT sonarsource DOT com
+#
+# SonarQube 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.
+#
+# SonarQube 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.
+#
+
+issue.action.fake.formlink=Fake
diff --git a/it/it-plugins/pom.xml b/it/it-plugins/pom.xml
index b0d7c374cef..984e022859d 100644
--- a/it/it-plugins/pom.xml
+++ b/it/it-plugins/pom.xml
@@ -35,6 +35,7 @@
<module>batch-plugin</module>
<module>extension-lifecycle-plugin</module>
<module>global-property-change-plugin</module>
+ <module>issue-action-plugin</module>
<module>l10n-fr-pack</module>
<module>license-plugin</module>
<module>project-builder-plugin</module>
diff --git a/it/it-tests/src/test/java/issue/suite/IssueActionTest.java b/it/it-tests/src/test/java/issue/suite/IssueActionTest.java
new file mode 100644
index 00000000000..ab23ce589fe
--- /dev/null
+++ b/it/it-tests/src/test/java/issue/suite/IssueActionTest.java
@@ -0,0 +1,257 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 issue.suite;
+
+import com.sonar.orchestrator.Orchestrator;
+import com.sonar.orchestrator.build.SonarRunner;
+import com.sonar.orchestrator.locator.FileLocation;
+import java.util.List;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.sonar.wsclient.base.HttpException;
+import org.sonar.wsclient.issue.ActionPlan;
+import org.sonar.wsclient.issue.ActionPlanClient;
+import org.sonar.wsclient.issue.Issue;
+import org.sonar.wsclient.issue.IssueComment;
+import org.sonar.wsclient.issue.IssueQuery;
+import org.sonar.wsclient.issue.Issues;
+import org.sonar.wsclient.issue.NewActionPlan;
+
+import static issue.suite.IssueTestSuite.ORCHESTRATOR;
+import static issue.suite.IssueTestSuite.adminIssueClient;
+import static issue.suite.IssueTestSuite.issueClient;
+import static issue.suite.IssueTestSuite.search;
+import static issue.suite.IssueTestSuite.searchIssueByKey;
+import static issue.suite.IssueTestSuite.searchIssues;
+import static issue.suite.IssueTestSuite.searchRandomIssue;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.fail;
+import static util.ItUtils.projectDir;
+import static util.ItUtils.toDate;
+import static util.ItUtils.verifyHttpException;
+
+public class IssueActionTest {
+
+ @ClassRule
+ public static Orchestrator orchestrator = ORCHESTRATOR;
+
+ Issue issue;
+ SonarRunner scan;
+
+ private static List<Issue> searchIssuesBySeverities(String componentKey, String... severities) {
+ return searchIssues(IssueQuery.create().componentRoots(componentKey).severities(severities));
+ }
+
+ private static ActionPlanClient adminActionPlanClient() {
+ return orchestrator.getServer().adminWsClient().actionPlanClient();
+ }
+
+ @Before
+ public void resetData() {
+ orchestrator.resetData();
+ orchestrator.getServer().restoreProfile(FileLocation.ofClasspath("/issue/suite/IssueActionTest/xoo-one-issue-per-line-profile.xml"));
+ orchestrator.getServer().provisionProject("sample", "Sample");
+ orchestrator.getServer().associateProjectToQualityProfile("sample", "xoo", "xoo-one-issue-per-line-profile");
+
+ scan = SonarRunner.create(projectDir("shared/xoo-sample"));
+ orchestrator.executeBuild(scan);
+ issue = searchRandomIssue();
+ }
+
+ @Test
+ public void no_comments_by_default() throws Exception {
+ assertThat(issue.comments()).isEmpty();
+ }
+
+ @Test
+ public void add_comment() throws Exception {
+ IssueComment comment = adminIssueClient().addComment(issue.key(), "this is my *comment*");
+ assertThat(comment.key()).isNotNull();
+ assertThat(comment.htmlText()).isEqualTo("this is my <em>comment</em>");
+ assertThat(comment.login()).isEqualTo("admin");
+ assertThat(comment.createdAt()).isNotNull();
+
+ // reload issue
+ Issue reloaded = searchIssueByKey(issue.key());
+
+ assertThat(reloaded.comments()).hasSize(1);
+ assertThat(reloaded.comments().get(0).key()).isEqualTo(comment.key());
+ assertThat(reloaded.comments().get(0).htmlText()).isEqualTo("this is my <em>comment</em>");
+ assertThat(reloaded.updateDate().before(issue.creationDate())).isFalse();
+ }
+
+ /**
+ * SONAR-4450
+ */
+ @Test
+ public void should_reject_blank_comment() throws Exception {
+ try {
+ adminIssueClient().addComment(issue.key(), " ");
+ fail();
+ } catch (HttpException ex) {
+ assertThat(ex.status()).isEqualTo(400);
+ }
+
+ Issue reloaded = searchIssueByKey(issue.key());
+ assertThat(reloaded.comments()).hasSize(0);
+ }
+
+ /**
+ * SONAR-4352
+ */
+ @Test
+ public void change_severity() {
+ String componentKey = "sample";
+
+ // there are no blocker issues
+ assertThat(searchIssuesBySeverities(componentKey, "BLOCKER")).isEmpty();
+
+ // increase the severity of an issue
+ adminIssueClient().setSeverity(issue.key(), "BLOCKER");
+
+ assertThat(searchIssuesBySeverities(componentKey, "BLOCKER")).hasSize(1);
+
+ orchestrator.executeBuild(scan);
+ Issue reloaded = searchIssueByKey(issue.key());
+ assertThat(reloaded.severity()).isEqualTo("BLOCKER");
+ assertThat(reloaded.status()).isEqualTo("OPEN");
+ assertThat(reloaded.resolution()).isNull();
+ assertThat(reloaded.creationDate()).isEqualTo(issue.creationDate());
+ assertThat(reloaded.creationDate().before(reloaded.updateDate())).isTrue();
+ }
+
+ /**
+ * SONAR-4287
+ */
+ @Test
+ public void assign() {
+ assertThat(issue.assignee()).isNull();
+ Issues issues = search(IssueQuery.create().issues(issue.key()));
+ assertThat(issues.users()).isEmpty();
+
+ adminIssueClient().assign(issue.key(), "admin");
+ assertThat(search(IssueQuery.create().assignees("admin")).list()).hasSize(1);
+
+ orchestrator.executeBuild(scan);
+ Issue reloaded = searchIssueByKey(issue.key());
+ assertThat(reloaded.assignee()).isEqualTo("admin");
+ assertThat(reloaded.creationDate()).isEqualTo(issue.creationDate());
+
+ issues = search(IssueQuery.create().issues(issue.key()));
+ assertThat(issues.user("admin")).isNotNull();
+ assertThat(issues.user("admin").name()).isEqualTo("Administrator");
+
+ // unassign
+ adminIssueClient().assign(issue.key(), null);
+ reloaded = searchIssueByKey(issue.key());
+ assertThat(reloaded.assignee()).isNull();
+ assertThat(issueClient().find(IssueQuery.create().assignees("admin")).list()).isEmpty();
+ }
+
+ /**
+ * SONAR-4287
+ */
+ @Test
+ public void fail_assign_if_assignee_does_not_exist() {
+ assertThat(issue.assignee()).isNull();
+ try {
+ adminIssueClient().assign(issue.key(), "unknown");
+ fail();
+ } catch (Exception e) {
+ verifyHttpException(e, 400);
+ }
+ }
+
+ /**
+ * SONAR-4290
+ */
+ @Test
+ public void plan() {
+ assertThat(issue.actionPlan()).isNull();
+
+ // Set action plan to issue
+ ActionPlan newActionPlan = adminActionPlanClient().create(NewActionPlan.create().name("Short term").project("sample")
+ .description("Short term issues").deadLine(toDate("2113-01-31")));
+ assertThat(newActionPlan.key()).isNotNull();
+ adminIssueClient().plan(issue.key(), newActionPlan.key());
+ assertThat(search(IssueQuery.create().actionPlans(newActionPlan.key())).list()).hasSize(1);
+
+ orchestrator.executeBuild(scan);
+ Issue reloaded = searchIssueByKey(issue.key());
+ assertThat(reloaded.actionPlan()).isEqualTo(newActionPlan.key());
+ assertThat(reloaded.creationDate()).isEqualTo(issue.creationDate());
+ ActionPlan actionPlan = search(IssueQuery.create().actionPlans(newActionPlan.key())).actionPlans(reloaded);
+ assertThat(actionPlan.name()).isEqualTo(newActionPlan.name());
+ assertThat(actionPlan.deadLine()).isEqualTo(newActionPlan.deadLine());
+ }
+
+ @Test
+ public void fail_plan_if_action_plan_does_not_exist() {
+ assertThat(issue.actionPlan()).isNull();
+ try {
+ adminIssueClient().plan(issue.key(), "unknown");
+ fail();
+ } catch (Exception e) {
+ verifyHttpException(e, 400);
+ }
+ }
+
+ @Test
+ public void unplan() {
+ assertThat(issue.actionPlan()).isNull();
+
+ // Set action plan to issue
+ ActionPlan newActionPlan = adminActionPlanClient().create(NewActionPlan.create().name("Short term").project("sample")
+ .description("Short term issues").deadLine(toDate("2113-01-31")));
+ assertThat(newActionPlan.key()).isNotNull();
+ adminIssueClient().plan(issue.key(), newActionPlan.key());
+ assertThat(search(IssueQuery.create().actionPlans(newActionPlan.key())).list()).hasSize(1);
+
+ // Unplan
+ adminIssueClient().plan(issue.key(), null);
+ assertThat(search(IssueQuery.create().actionPlans(newActionPlan.key())).list()).hasSize(0);
+
+ orchestrator.executeBuild(scan);
+ Issue reloaded = searchIssueByKey(issue.key());
+ assertThat(reloaded.actionPlan()).isNull();
+ assertThat(reloaded.creationDate()).isEqualTo(issue.creationDate());
+ }
+
+ /**
+ * SONAR-4315
+ */
+ @Test
+ public void apply_action_from_plugin() {
+ // The condition on the action defined by the plugin is that the status must be resolved
+ adminIssueClient().doTransition(issue.key(), "resolve");
+ assertThat(adminIssueClient().actions(issue.key())).contains("fake");
+
+ adminIssueClient().doAction(issue.key(), "fake");
+
+ // reload issue
+ Issue reloaded = searchIssueByKey(issue.key());
+
+ assertThat(reloaded.comments()).hasSize(1);
+ assertThat(reloaded.comments().get(0).htmlText()).isEqualTo("New Comment from fake action");
+ }
+
+}
diff --git a/it/it-tests/src/test/java/issue/suite/IssueTestSuite.java b/it/it-tests/src/test/java/issue/suite/IssueTestSuite.java
index 6757552276e..3e6a1e4ce02 100644
--- a/it/it-tests/src/test/java/issue/suite/IssueTestSuite.java
+++ b/it/it-tests/src/test/java/issue/suite/IssueTestSuite.java
@@ -13,42 +13,52 @@ import org.junit.runners.Suite;
import org.sonar.wsclient.issue.Issue;
import org.sonar.wsclient.issue.IssueClient;
import org.sonar.wsclient.issue.IssueQuery;
-import util.ItUtils;
+import org.sonar.wsclient.issue.Issues;
import static org.assertj.core.api.Assertions.assertThat;
+import static util.ItUtils.pluginArtifact;
+import static util.ItUtils.xooPlugin;
@RunWith(Suite.class)
@Suite.SuiteClasses({
- CommonRulesTest.class, IssueWorkflowTest.class, ManualRulesTest.class, CustomRulesTest.class
+ CommonRulesTest.class, IssueWorkflowTest.class, ManualRulesTest.class, CustomRulesTest.class, IssueActionTest.class
})
public class IssueTestSuite {
@ClassRule
public static final Orchestrator ORCHESTRATOR = Orchestrator.builderEnv()
.setSonarVersion("DEV")
- .addPlugin(ItUtils.xooPlugin())
+ .addPlugin(xooPlugin())
+ .addPlugin(pluginArtifact("issue-action-plugin"))
.build();
static IssueClient adminIssueClient() {
return ORCHESTRATOR.getServer().adminWsClient().issueClient();
}
+ static IssueClient issueClient() {
+ return ORCHESTRATOR.getServer().wsClient().issueClient();
+ }
+
static Issue searchRandomIssue() {
List<Issue> issues = searchIssues(IssueQuery.create());
assertThat(issues).isNotEmpty();
return issues.get(0);
}
- static List<Issue> searchIssues(IssueQuery issueQuery) {
+ static Issues search(IssueQuery issueQuery) {
issueQuery.urlParams().put("additionalFields", "_all");
- return adminIssueClient().find(issueQuery).list();
+ return issueClient().find(issueQuery);
+ }
+
+ static List<Issue> searchIssues(IssueQuery issueQuery) {
+ return search(issueQuery).list();
}
static Issue searchIssueByKey(String issueKey) {
- IssueQuery query = IssueQuery.create().issues(issueKey);
- query.urlParams().put("additionalFields", "_all");
- List<Issue> issues = searchIssues(query);
+ List<Issue> issues = searchIssues(IssueQuery.create().issues(issueKey));
assertThat(issues).hasSize(1);
return issues.get(0);
}
+
}
diff --git a/it/it-tests/src/test/java/util/ItUtils.java b/it/it-tests/src/test/java/util/ItUtils.java
index 1d8e3406ea8..4cb4df2c045 100644
--- a/it/it-tests/src/test/java/util/ItUtils.java
+++ b/it/it-tests/src/test/java/util/ItUtils.java
@@ -9,6 +9,9 @@ import com.google.common.collect.Iterables;
import com.sonar.orchestrator.Orchestrator;
import com.sonar.orchestrator.build.BuildResult;
import com.sonar.orchestrator.build.SonarRunner;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
@@ -27,6 +30,7 @@ import static org.assertj.core.api.Assertions.fail;
import static org.assertj.core.api.Assertions.assertThat;
import org.apache.commons.io.FileUtils;
+import org.sonar.wsclient.base.HttpException;
public class ItUtils {
@@ -157,4 +161,20 @@ public class ItUtils {
}
return from(Iterables.concat(asList(properties), asList(str))).toArray(String.class);
}
+
+ public static void verifyHttpException(Exception e, int expectedCode) {
+ assertThat(e).isInstanceOf(HttpException.class);
+ HttpException exception = (HttpException) e;
+ assertThat(exception.status()).isEqualTo(expectedCode);
+ }
+
+ public static Date toDate(String sDate) {
+ try {
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+ return sdf.parse(sDate);
+ } catch (ParseException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
}
diff --git a/it/it-tests/src/test/resources/issue/suite/IssueActionTest/xoo-one-issue-per-line-profile.xml b/it/it-tests/src/test/resources/issue/suite/IssueActionTest/xoo-one-issue-per-line-profile.xml
new file mode 100644
index 00000000000..608f80cae96
--- /dev/null
+++ b/it/it-tests/src/test/resources/issue/suite/IssueActionTest/xoo-one-issue-per-line-profile.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0"?><!-- Generated by Sonar -->
+<profile>
+ <name>xoo-one-issue-per-line-profile</name>
+ <language>xoo</language>
+ <rules>
+ <rule>
+ <repositoryKey>xoo</repositoryKey>
+ <key>OneIssuePerLine</key>
+ <priority>CRITICAL</priority>
+ </rule>
+ </rules>
+</profile>