From a624a9cc04c37176e311c39cf250f5ff19e6cf42 Mon Sep 17 00:00:00 2001 From: Julien Lancelot Date: Wed, 21 Jun 2017 11:18:26 +0200 Subject: [PATCH] SONAR-9442 Add details of added/updated/disabled rules in notification --- it/it-plugins/foo-plugin-v1/pom.xml | 75 ------------- .../src/main/java/org/sonar/foo/Foo.java | 43 ------- .../main/java/org/sonar/foo/FooPlugin.java | 39 ------- .../main/java/org/sonar/foo/package-info.java | 23 ---- .../org/sonar/foo/rule/FooBasicProfile.java | 41 ------- .../sonar/foo/rule/FooRulesDefinition.java | 46 -------- .../java/org/sonar/foo/rule/package-info.java | 23 ---- it/it-plugins/foo-plugin-v2/pom.xml | 75 ------------- .../src/main/java/org/sonar/foo/Foo.java | 43 ------- .../main/java/org/sonar/foo/FooPlugin.java | 39 ------- .../main/java/org/sonar/foo/package-info.java | 23 ---- .../org/sonar/foo/rule/FooBasicProfile.java | 42 ------- .../sonar/foo/rule/FooRulesDefinition.java | 46 -------- .../java/org/sonar/foo/rule/package-info.java | 23 ---- .../BuiltInQualityProfilesNotification.java | 91 +++++++++++++-- ...ltInQualityProfilesNotificationSender.java | 21 +++- ...InQualityProfilesNotificationTemplate.java | 18 ++- .../RegisterQualityProfiles.java | 9 +- ...QualityProfilesNotificationSenderTest.java | 97 +++++++++++++--- ...alityProfilesNotificationTemplateTest.java | 106 +++++++++++++++++- ...uiltInQualityProfilesNotificationTest.java | 16 ++- ...gisterQualityProfilesNotificationTest.java | 61 +++++++--- .../org/sonar/foo/rule/FooBasicProfile.java | 26 ++++- .../sonar/foo/rule/FooRulesDefinition.java | 7 +- .../org/sonar/foo/rule/FooBasicProfile.java | 27 ++++- .../sonar/foo/rule/FooRulesDefinition.java | 6 + ...uiltInQualityProfilesNotificationTest.java | 17 +-- 27 files changed, 430 insertions(+), 653 deletions(-) delete mode 100644 it/it-plugins/foo-plugin-v1/pom.xml delete mode 100644 it/it-plugins/foo-plugin-v1/src/main/java/org/sonar/foo/Foo.java delete mode 100644 it/it-plugins/foo-plugin-v1/src/main/java/org/sonar/foo/FooPlugin.java delete mode 100644 it/it-plugins/foo-plugin-v1/src/main/java/org/sonar/foo/package-info.java delete mode 100644 it/it-plugins/foo-plugin-v1/src/main/java/org/sonar/foo/rule/FooBasicProfile.java delete mode 100644 it/it-plugins/foo-plugin-v1/src/main/java/org/sonar/foo/rule/FooRulesDefinition.java delete mode 100644 it/it-plugins/foo-plugin-v1/src/main/java/org/sonar/foo/rule/package-info.java delete mode 100644 it/it-plugins/foo-plugin-v2/pom.xml delete mode 100644 it/it-plugins/foo-plugin-v2/src/main/java/org/sonar/foo/Foo.java delete mode 100644 it/it-plugins/foo-plugin-v2/src/main/java/org/sonar/foo/FooPlugin.java delete mode 100644 it/it-plugins/foo-plugin-v2/src/main/java/org/sonar/foo/package-info.java delete mode 100644 it/it-plugins/foo-plugin-v2/src/main/java/org/sonar/foo/rule/FooBasicProfile.java delete mode 100644 it/it-plugins/foo-plugin-v2/src/main/java/org/sonar/foo/rule/FooRulesDefinition.java delete mode 100644 it/it-plugins/foo-plugin-v2/src/main/java/org/sonar/foo/rule/package-info.java diff --git a/it/it-plugins/foo-plugin-v1/pom.xml b/it/it-plugins/foo-plugin-v1/pom.xml deleted file mode 100644 index e34322baece..00000000000 --- a/it/it-plugins/foo-plugin-v1/pom.xml +++ /dev/null @@ -1,75 +0,0 @@ - - - 4.0.0 - - org.sonarsource.sonarqube - sonarqube - 6.5-SNAPSHOT - ../.. - - foo-plugin-v1 - SonarQube :: Plugins :: Foo (V1) - sonar-plugin - Sample of plugin to document and test available APIs - - - true - - - - - com.google.guava - guava - - - commons-io - commons-io - - - commons-lang - commons-lang - - - com.google.code.findbugs - jsr305 - provided - - - org.sonarsource.sonarqube - sonar-plugin-api - provided - - - - - junit - junit - test - - - org.assertj - assertj-core - test - - - org.mockito - mockito-core - test - - - - - - - org.sonarsource.sonar-packaging-maven-plugin - sonar-packaging-maven-plugin - - foo - Foo - org.sonar.foo.FooPlugin - - - - - diff --git a/it/it-plugins/foo-plugin-v1/src/main/java/org/sonar/foo/Foo.java b/it/it-plugins/foo-plugin-v1/src/main/java/org/sonar/foo/Foo.java deleted file mode 100644 index a2b2d237b01..00000000000 --- a/it/it-plugins/foo-plugin-v1/src/main/java/org/sonar/foo/Foo.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.foo; - -import org.sonar.api.resources.Language; - -public class Foo implements Language { - - public static final String KEY = "foo"; - public static final String NAME = "Foo"; - - @Override - public String getKey() { - return KEY; - } - - @Override - public String getName() { - return NAME; - } - - @Override - public String[] getFileSuffixes() { - return new String[0]; - } -} diff --git a/it/it-plugins/foo-plugin-v1/src/main/java/org/sonar/foo/FooPlugin.java b/it/it-plugins/foo-plugin-v1/src/main/java/org/sonar/foo/FooPlugin.java deleted file mode 100644 index 17677e0acb2..00000000000 --- a/it/it-plugins/foo-plugin-v1/src/main/java/org/sonar/foo/FooPlugin.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.foo; - -import org.sonar.api.Plugin; -import org.sonar.foo.rule.FooBasicProfile; -import org.sonar.foo.rule.FooRulesDefinition; - -/** - * Plugin entry-point, as declared in pom.xml. - */ -public class FooPlugin implements Plugin { - - @Override - public void define(Context context) { - context.addExtensions( - Foo.class, - FooRulesDefinition.class, - FooBasicProfile.class); - } - -} diff --git a/it/it-plugins/foo-plugin-v1/src/main/java/org/sonar/foo/package-info.java b/it/it-plugins/foo-plugin-v1/src/main/java/org/sonar/foo/package-info.java deleted file mode 100644 index 24613bbdaf7..00000000000 --- a/it/it-plugins/foo-plugin-v1/src/main/java/org/sonar/foo/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -@ParametersAreNonnullByDefault -package org.sonar.foo; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/it/it-plugins/foo-plugin-v1/src/main/java/org/sonar/foo/rule/FooBasicProfile.java b/it/it-plugins/foo-plugin-v1/src/main/java/org/sonar/foo/rule/FooBasicProfile.java deleted file mode 100644 index 3a53e9293ff..00000000000 --- a/it/it-plugins/foo-plugin-v1/src/main/java/org/sonar/foo/rule/FooBasicProfile.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.foo.rule; - -import org.sonar.api.profiles.ProfileDefinition; -import org.sonar.api.profiles.RulesProfile; -import org.sonar.api.rules.Rule; -import org.sonar.api.utils.ValidationMessages; - -import static org.sonar.api.rules.RulePriority.MAJOR; -import static org.sonar.foo.Foo.KEY; -import static org.sonar.foo.rule.FooRulesDefinition.FOO_REPOSITORY; - -public class FooBasicProfile extends ProfileDefinition { - - @Override - public RulesProfile createProfile(ValidationMessages validation) { - final RulesProfile profile = RulesProfile.create("Basic", KEY); - profile.activateRule(Rule.create(FOO_REPOSITORY, "UnchangedRule"), MAJOR); - profile.activateRule(Rule.create(FOO_REPOSITORY, "ChangedRule"), MAJOR); - profile.activateRule(Rule.create(FOO_REPOSITORY, "RemovedRule"), MAJOR); - return profile; - } -} diff --git a/it/it-plugins/foo-plugin-v1/src/main/java/org/sonar/foo/rule/FooRulesDefinition.java b/it/it-plugins/foo-plugin-v1/src/main/java/org/sonar/foo/rule/FooRulesDefinition.java deleted file mode 100644 index 7257dd72681..00000000000 --- a/it/it-plugins/foo-plugin-v1/src/main/java/org/sonar/foo/rule/FooRulesDefinition.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.foo.rule; - -import org.sonar.api.server.rule.RulesDefinition; -import org.sonar.foo.Foo; - -public class FooRulesDefinition implements RulesDefinition { - - public static final String FOO_REPOSITORY = "foo"; - - @Override - public void define(Context context) { - defineRulesXoo(context); - } - - private static void defineRulesXoo(Context context) { - NewRepository repo = context.createRepository(FOO_REPOSITORY, Foo.KEY).setName("Foo"); - createRule(repo, "UnchangedRule"); - createRule(repo, "ChangedRule"); - createRule(repo, "RemovedRule"); - repo.done(); - } - - private static NewRule createRule(NewRepository repo, String key) { - return repo.createRule(key).setName(key).setHtmlDescription(key); - } - -} diff --git a/it/it-plugins/foo-plugin-v1/src/main/java/org/sonar/foo/rule/package-info.java b/it/it-plugins/foo-plugin-v1/src/main/java/org/sonar/foo/rule/package-info.java deleted file mode 100644 index b3209c8ac96..00000000000 --- a/it/it-plugins/foo-plugin-v1/src/main/java/org/sonar/foo/rule/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -@ParametersAreNonnullByDefault -package org.sonar.foo.rule; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/it/it-plugins/foo-plugin-v2/pom.xml b/it/it-plugins/foo-plugin-v2/pom.xml deleted file mode 100644 index db2fc2c5916..00000000000 --- a/it/it-plugins/foo-plugin-v2/pom.xml +++ /dev/null @@ -1,75 +0,0 @@ - - - 4.0.0 - - org.sonarsource.sonarqube - sonarqube - 6.5-SNAPSHOT - ../.. - - foo-plugin-v2 - SonarQube :: Plugins :: Foo (V2) - sonar-plugin - Sample of plugin to document and test available APIs - - - true - - - - - com.google.guava - guava - - - commons-io - commons-io - - - commons-lang - commons-lang - - - com.google.code.findbugs - jsr305 - provided - - - org.sonarsource.sonarqube - sonar-plugin-api - provided - - - - - junit - junit - test - - - org.assertj - assertj-core - test - - - org.mockito - mockito-core - test - - - - - - - org.sonarsource.sonar-packaging-maven-plugin - sonar-packaging-maven-plugin - - foo - Foo - org.sonar.foo.FooPlugin - - - - - diff --git a/it/it-plugins/foo-plugin-v2/src/main/java/org/sonar/foo/Foo.java b/it/it-plugins/foo-plugin-v2/src/main/java/org/sonar/foo/Foo.java deleted file mode 100644 index a2b2d237b01..00000000000 --- a/it/it-plugins/foo-plugin-v2/src/main/java/org/sonar/foo/Foo.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.foo; - -import org.sonar.api.resources.Language; - -public class Foo implements Language { - - public static final String KEY = "foo"; - public static final String NAME = "Foo"; - - @Override - public String getKey() { - return KEY; - } - - @Override - public String getName() { - return NAME; - } - - @Override - public String[] getFileSuffixes() { - return new String[0]; - } -} diff --git a/it/it-plugins/foo-plugin-v2/src/main/java/org/sonar/foo/FooPlugin.java b/it/it-plugins/foo-plugin-v2/src/main/java/org/sonar/foo/FooPlugin.java deleted file mode 100644 index 17677e0acb2..00000000000 --- a/it/it-plugins/foo-plugin-v2/src/main/java/org/sonar/foo/FooPlugin.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.foo; - -import org.sonar.api.Plugin; -import org.sonar.foo.rule.FooBasicProfile; -import org.sonar.foo.rule.FooRulesDefinition; - -/** - * Plugin entry-point, as declared in pom.xml. - */ -public class FooPlugin implements Plugin { - - @Override - public void define(Context context) { - context.addExtensions( - Foo.class, - FooRulesDefinition.class, - FooBasicProfile.class); - } - -} diff --git a/it/it-plugins/foo-plugin-v2/src/main/java/org/sonar/foo/package-info.java b/it/it-plugins/foo-plugin-v2/src/main/java/org/sonar/foo/package-info.java deleted file mode 100644 index 24613bbdaf7..00000000000 --- a/it/it-plugins/foo-plugin-v2/src/main/java/org/sonar/foo/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -@ParametersAreNonnullByDefault -package org.sonar.foo; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/it/it-plugins/foo-plugin-v2/src/main/java/org/sonar/foo/rule/FooBasicProfile.java b/it/it-plugins/foo-plugin-v2/src/main/java/org/sonar/foo/rule/FooBasicProfile.java deleted file mode 100644 index 1c2d051f7cf..00000000000 --- a/it/it-plugins/foo-plugin-v2/src/main/java/org/sonar/foo/rule/FooBasicProfile.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.foo.rule; - -import org.sonar.api.profiles.ProfileDefinition; -import org.sonar.api.profiles.RulesProfile; -import org.sonar.api.rules.Rule; -import org.sonar.api.utils.ValidationMessages; - -import static org.sonar.api.rules.RulePriority.MAJOR; -import static org.sonar.api.rules.RulePriority.MINOR; -import static org.sonar.foo.Foo.KEY; -import static org.sonar.foo.rule.FooRulesDefinition.FOO_REPOSITORY; - -public class FooBasicProfile extends ProfileDefinition { - - @Override - public RulesProfile createProfile(ValidationMessages validation) { - final RulesProfile profile = RulesProfile.create("Basic", KEY); - profile.activateRule(Rule.create(FOO_REPOSITORY, "UnchangedRule"), MAJOR); - profile.activateRule(Rule.create(FOO_REPOSITORY, "ChangedRule"), MINOR); - profile.activateRule(Rule.create(FOO_REPOSITORY, "NewRule"), MAJOR); - return profile; - } -} diff --git a/it/it-plugins/foo-plugin-v2/src/main/java/org/sonar/foo/rule/FooRulesDefinition.java b/it/it-plugins/foo-plugin-v2/src/main/java/org/sonar/foo/rule/FooRulesDefinition.java deleted file mode 100644 index aacc2335262..00000000000 --- a/it/it-plugins/foo-plugin-v2/src/main/java/org/sonar/foo/rule/FooRulesDefinition.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.foo.rule; - -import org.sonar.api.server.rule.RulesDefinition; -import org.sonar.foo.Foo; - -public class FooRulesDefinition implements RulesDefinition { - - public static final String FOO_REPOSITORY = "foo"; - - @Override - public void define(Context context) { - defineRulesXoo(context); - } - - private static void defineRulesXoo(Context context) { - NewRepository repo = context.createRepository(FOO_REPOSITORY, Foo.KEY).setName("Foo"); - createRule(repo, "UnchangedRule"); - createRule(repo, "ChangedRule"); - createRule(repo, "NewRule"); - repo.done(); - } - - private static NewRule createRule(NewRepository repo, String key) { - return repo.createRule(key).setName(key).setHtmlDescription(key); - } - -} diff --git a/it/it-plugins/foo-plugin-v2/src/main/java/org/sonar/foo/rule/package-info.java b/it/it-plugins/foo-plugin-v2/src/main/java/org/sonar/foo/rule/package-info.java deleted file mode 100644 index b3209c8ac96..00000000000 --- a/it/it-plugins/foo-plugin-v2/src/main/java/org/sonar/foo/rule/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -@ParametersAreNonnullByDefault -package org.sonar.foo.rule; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotification.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotification.java index 9c2a906147c..6609ae3d829 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotification.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotification.java @@ -27,6 +27,8 @@ import java.util.stream.IntStream; import org.sonar.api.notifications.Notification; import static com.google.common.base.Preconditions.checkState; +import static java.lang.Integer.parseInt; +import static java.lang.String.format; import static java.util.Objects.requireNonNull; import static org.sonar.server.qualityprofile.BuiltInQualityProfilesNotificationSender.BUILT_IN_QUALITY_PROFILES; @@ -35,6 +37,10 @@ public class BuiltInQualityProfilesNotification { private static final String NUMBER_OF_PROFILES = "numberOfProfiles"; private static final String PROFILE_NAME = ".profileName"; private static final String LANGUAGE = ".language"; + private static final String NEW_RULES = ".newRules"; + private static final String UPDATED_RULES = ".updatedRules"; + private static final String REMOVED_RULES = ".removedRules"; + private final List profiles = new ArrayList<>(); public BuiltInQualityProfilesNotification addProfile(Profile profile) { @@ -48,8 +54,11 @@ public class BuiltInQualityProfilesNotification { AtomicInteger count = new AtomicInteger(); profiles.forEach(profile -> { int index = count.getAndIncrement(); - notification.setFieldValue(index + ".profileName", profile.getProfileName()); - notification.setFieldValue(index + ".language", profile.getLanguage()); + notification.setFieldValue(index + PROFILE_NAME, profile.getProfileName()); + notification.setFieldValue(index + LANGUAGE, profile.getLanguage()); + notification.setFieldValue(index + NEW_RULES, String.valueOf(profile.getNewRules())); + notification.setFieldValue(index + UPDATED_RULES, String.valueOf(profile.getUpdatedRules())); + notification.setFieldValue(index + REMOVED_RULES, String.valueOf(profile.getRemovedRules())); }); return notification; } @@ -62,13 +71,22 @@ public class BuiltInQualityProfilesNotification { checkState(numberOfProfilesText != null, "Could not read the built-in quality profile notification"); Integer numberOfProfiles = Integer.valueOf(numberOfProfilesText); IntStream.rangeClosed(0, numberOfProfiles - 1) - .mapToObj(index -> new Profile( - requireNonNull(notification.getFieldValue(index + PROFILE_NAME)), - requireNonNull(notification.getFieldValue(index + LANGUAGE)))) + .mapToObj(index -> Profile.newBuilder( + getNonNullFieldValue(notification, index + PROFILE_NAME), + getNonNullFieldValue(notification, index + LANGUAGE)) + .setNewRules(parseInt(getNonNullFieldValue(notification, index + NEW_RULES))) + .setUpdatedRules(parseInt(getNonNullFieldValue(notification, index + UPDATED_RULES))) + .setRemovedRules(parseInt(getNonNullFieldValue(notification, index + REMOVED_RULES))) + .build()) .forEach(notif::addProfile); return notif; } + private static String getNonNullFieldValue(Notification notification, String key) { + String value = notification.getFieldValue(key); + return requireNonNull(value, format("Notification field '%s' is null", key)); + } + public List getProfiles() { return profiles; } @@ -76,10 +94,16 @@ public class BuiltInQualityProfilesNotification { public static class Profile { private final String profileName; private final String language; + private final int newRules; + private final int updatedRules; + private final int removedRules; - public Profile(String profileName, String language) { - this.profileName = profileName; - this.language = language; + public Profile(Builder builder) { + this.profileName = builder.profileName; + this.language = builder.language; + this.newRules = builder.newRules; + this.updatedRules = builder.updatedRules; + this.removedRules = builder.removedRules; } public String getProfileName() { @@ -89,5 +113,56 @@ public class BuiltInQualityProfilesNotification { public String getLanguage() { return language; } + + public int getNewRules() { + return newRules; + } + + public int getUpdatedRules() { + return updatedRules; + } + + public int getRemovedRules() { + return removedRules; + } + + public static Builder newBuilder(String profileName, String language) { + return new Builder(profileName, language); + } + + public static class Builder { + private final String profileName; + private final String language; + private int newRules; + private int updatedRules; + private int removedRules; + + private Builder(String profileName, String language) { + this.profileName = requireNonNull(profileName, "profileName should not be null"); + this.language = requireNonNull(language, "language should not be null"); + } + + public Builder setNewRules(int newRules) { + checkState(newRules >= 0, "newRules should not be negative"); + this.newRules = newRules; + return this; + } + + public Builder setUpdatedRules(int updatedRules) { + checkState(updatedRules >= 0, "updatedRules should not be negative"); + this.updatedRules = updatedRules; + return this; + } + + public Builder setRemovedRules(int removedRules) { + checkState(removedRules >= 0, "removedRules should not be negative"); + this.removedRules = removedRules; + return this; + } + + public Profile build() { + return new Profile(this); + } + } } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotificationSender.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotificationSender.java index 329ad9da3cc..fee337a9832 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotificationSender.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotificationSender.java @@ -20,11 +20,16 @@ package org.sonar.server.qualityprofile; -import java.util.List; +import com.google.common.collect.Multimap; +import java.util.Collection; import org.sonar.api.resources.Languages; import org.sonar.server.notification.NotificationManager; import org.sonar.server.qualityprofile.BuiltInQualityProfilesNotification.Profile; +import static org.sonar.server.qualityprofile.ActiveRuleChange.Type.ACTIVATED; +import static org.sonar.server.qualityprofile.ActiveRuleChange.Type.DEACTIVATED; +import static org.sonar.server.qualityprofile.ActiveRuleChange.Type.UPDATED; + public class BuiltInQualityProfilesNotificationSender { static final String BUILT_IN_QUALITY_PROFILES = "built-in-quality-profiles"; @@ -37,13 +42,21 @@ public class BuiltInQualityProfilesNotificationSender { this.languages = languages; } - void send(List changedProfiles) { + void send(Multimap changedProfiles) { BuiltInQualityProfilesNotification notification = new BuiltInQualityProfilesNotification(); - changedProfiles.stream() + changedProfiles.keySet().stream() .map(changedProfile -> { String profileName = changedProfile.getName(); String languageName = languages.get(changedProfile.getLanguage()).getName(); - return new Profile(profileName, languageName); + Collection activeRuleChanges = changedProfiles.get(changedProfile); + int newRules = (int) activeRuleChanges.stream().map(ActiveRuleChange::getType).filter(ACTIVATED::equals).count(); + int updatedRules = (int) activeRuleChanges.stream().map(ActiveRuleChange::getType).filter(UPDATED::equals).count(); + int removedRules = (int) activeRuleChanges.stream().map(ActiveRuleChange::getType).filter(DEACTIVATED::equals).count(); + return Profile.newBuilder(profileName, languageName) + .setNewRules(newRules) + .setUpdatedRules(updatedRules) + .setRemovedRules(removedRules) + .build(); }) .forEach(notification::addProfile); notificationManager.scheduleForSending(notification.serialize()); diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotificationTemplate.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotificationTemplate.java index 222525acfac..82db0ca0b9e 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotificationTemplate.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotificationTemplate.java @@ -40,7 +40,23 @@ public class BuiltInQualityProfilesNotificationTemplate extends EmailTemplate { StringBuilder message = new StringBuilder("Built-in quality profiles have been updated:\n"); profilesNotification.getProfiles().stream() .sorted(Comparator.comparing(Profile::getLanguage).thenComparing(Profile::getProfileName)) - .forEach(profile -> message.append("\"").append(profile.getProfileName()).append("\" - ").append(profile.getLanguage()).append("\n")); + .forEach(profile -> { + message.append("\"") + .append(profile.getProfileName()).append("\" - ") + .append(profile.getLanguage()).append("\n"); + int newRules = profile.getNewRules(); + if (newRules > 0) { + message.append(" ").append(newRules).append(" new rules\n"); + } + int updatedRules = profile.getUpdatedRules(); + if (updatedRules > 0) { + message.append(" ").append(updatedRules).append(" rules have been updated\n"); + } + int removedRules = profile.getRemovedRules(); + if (removedRules > 0) { + message.append(" ").append(removedRules).append(" rules removed\n"); + } + }); message.append( "This is a good time to review your quality profiles and update them to benefit from the latest evolutions."); diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RegisterQualityProfiles.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RegisterQualityProfiles.java index d343bbf526f..50490dc11b6 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RegisterQualityProfiles.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RegisterQualityProfiles.java @@ -19,7 +19,8 @@ */ package org.sonar.server.qualityprofile; -import java.util.ArrayList; +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Multimap; import java.util.Collection; import java.util.List; import java.util.Map; @@ -70,16 +71,14 @@ public class RegisterQualityProfiles { Map persistedRuleProfiles = loadPersistedProfiles(dbSession); - List changedProfiles = new ArrayList<>(); + Multimap changedProfiles = ArrayListMultimap.create(); builtInQProfiles.forEach(builtIn -> { RulesProfileDto ruleProfile = persistedRuleProfiles.get(builtIn.getQProfileName()); if (ruleProfile == null) { register(dbSession, batchDbSession, builtIn); } else { List changes = update(dbSession, builtIn, ruleProfile); - if (!changes.isEmpty()) { - changedProfiles.add(builtIn.getQProfileName()); - } + changedProfiles.putAll(builtIn.getQProfileName(), changes); } }); if (!changedProfiles.isEmpty()) { diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotificationSenderTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotificationSenderTest.java index 819412888d5..9bd803d14bc 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotificationSenderTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotificationSenderTest.java @@ -19,47 +19,118 @@ */ package org.sonar.server.qualityprofile; -import java.util.List; +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Multimap; +import java.util.Random; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import org.assertj.core.groups.Tuple; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.sonar.api.notifications.Notification; +import org.sonar.api.resources.Language; import org.sonar.api.resources.Languages; -import org.sonar.server.language.LanguageTesting; +import org.sonar.db.qualityprofile.ActiveRuleKey; import org.sonar.server.notification.NotificationManager; import org.sonar.server.qualityprofile.BuiltInQualityProfilesNotification.Profile; -import static java.util.Collections.singletonList; import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; import static org.assertj.core.api.Java6Assertions.assertThat; import static org.assertj.core.api.Java6Assertions.tuple; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.sonar.server.language.LanguageTesting.newLanguage; +import static org.sonar.server.qualityprofile.ActiveRuleChange.Type.ACTIVATED; +import static org.sonar.server.qualityprofile.ActiveRuleChange.Type.DEACTIVATED; +import static org.sonar.server.qualityprofile.ActiveRuleChange.Type.UPDATED; public class BuiltInQualityProfilesNotificationSenderTest { + private static final Random RANDOM = new Random(); private NotificationManager notificationManager = mock(NotificationManager.class); @Test - public void add_profile_to_notification() throws Exception { - String profileName = randomLowerCaseText(); - String languageKey = randomLowerCaseText(); - String languageName = randomLowerCaseText(); - List profileNames = singletonList(new QProfileName(languageKey, profileName)); - Languages languages = new Languages(LanguageTesting.newLanguage(languageKey, languageName)); + public void add_profile_to_notification_for_added_rules() throws Exception { + Multimap profiles = ArrayListMultimap.create(); + Languages languages = new Languages(); + Tuple expectedTuple = addProfile(profiles, languages, ACTIVATED); + + BuiltInQualityProfilesNotificationSender underTest = new BuiltInQualityProfilesNotificationSender(notificationManager, languages); + underTest.send(profiles); + + ArgumentCaptor notificationArgumentCaptor = ArgumentCaptor.forClass(Notification.class); + verify(notificationManager).scheduleForSending(notificationArgumentCaptor.capture()); + verifyNoMoreInteractions(notificationManager); + assertThat(BuiltInQualityProfilesNotification.parse(notificationArgumentCaptor.getValue()).getProfiles()) + .extracting(Profile::getProfileName, Profile::getLanguage, Profile::getNewRules) + .containsExactlyInAnyOrder(expectedTuple); + } + + @Test + public void add_profile_to_notification_for_updated_rules() throws Exception { + Multimap profiles = ArrayListMultimap.create(); + Languages languages = new Languages(); + Tuple expectedTuple = addProfile(profiles, languages, UPDATED); + + BuiltInQualityProfilesNotificationSender underTest = new BuiltInQualityProfilesNotificationSender(notificationManager, languages); + underTest.send(profiles); + + ArgumentCaptor notificationArgumentCaptor = ArgumentCaptor.forClass(Notification.class); + verify(notificationManager).scheduleForSending(notificationArgumentCaptor.capture()); + verifyNoMoreInteractions(notificationManager); + assertThat(BuiltInQualityProfilesNotification.parse(notificationArgumentCaptor.getValue()).getProfiles()) + .extracting(Profile::getProfileName, Profile::getLanguage, Profile::getUpdatedRules) + .containsExactlyInAnyOrder(expectedTuple); + } + + @Test + public void add_profile_to_notification_for_removed_rules() throws Exception { + Multimap profiles = ArrayListMultimap.create(); + Languages languages = new Languages(); + Tuple expectedTuple = addProfile(profiles, languages, DEACTIVATED); BuiltInQualityProfilesNotificationSender underTest = new BuiltInQualityProfilesNotificationSender(notificationManager, languages); - underTest.send(profileNames); + underTest.send(profiles); ArgumentCaptor notificationArgumentCaptor = ArgumentCaptor.forClass(Notification.class); verify(notificationManager).scheduleForSending(notificationArgumentCaptor.capture()); verifyNoMoreInteractions(notificationManager); assertThat(BuiltInQualityProfilesNotification.parse(notificationArgumentCaptor.getValue()).getProfiles()) - .extracting(Profile::getProfileName, Profile::getLanguage) - .containsExactlyInAnyOrder(tuple(profileName, languageName)); + .extracting(Profile::getProfileName, Profile::getLanguage, Profile::getRemovedRules) + .containsExactlyInAnyOrder(expectedTuple); + } + + @Test + public void add_multiple_profiles_to_notification() throws Exception { + Multimap profiles = ArrayListMultimap.create(); + Languages languages = new Languages(); + Tuple expectedTuple1 = addProfile(profiles, languages, ACTIVATED); + Tuple expectedTuple2 = addProfile(profiles, languages, ACTIVATED); + + BuiltInQualityProfilesNotificationSender underTest = new BuiltInQualityProfilesNotificationSender(notificationManager, languages); + underTest.send(profiles); + + ArgumentCaptor notificationArgumentCaptor = ArgumentCaptor.forClass(Notification.class); + verify(notificationManager).scheduleForSending(notificationArgumentCaptor.capture()); + verifyNoMoreInteractions(notificationManager); + assertThat(BuiltInQualityProfilesNotification.parse(notificationArgumentCaptor.getValue()).getProfiles()) + .extracting(Profile::getProfileName, Profile::getLanguage, Profile::getNewRules) + .containsExactlyInAnyOrder(expectedTuple1, expectedTuple2); + } + + private Tuple addProfile(Multimap profiles, Languages languages, ActiveRuleChange.Type type) { + String profileName = randomLowerCaseText(); + Language language = newLanguage(randomLowerCaseText(), randomLowerCaseText()); + languages.add(language); + int numberOfChanges = RANDOM.nextInt(1000); + profiles.putAll( + new QProfileName(language.getKey(), profileName), + IntStream.range(0, numberOfChanges).mapToObj(i -> new ActiveRuleChange(type, ActiveRuleKey.parse("qp:repo:rule" + i))).collect(Collectors.toSet())); + return tuple(profileName, language.getName(), numberOfChanges); } private static String randomLowerCaseText() { return randomAlphanumeric(20).toLowerCase(); } -} \ No newline at end of file +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotificationTemplateTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotificationTemplateTest.java index 27a65edfb2b..1bd78367688 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotificationTemplateTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotificationTemplateTest.java @@ -32,16 +32,118 @@ public class BuiltInQualityProfilesNotificationTemplateTest { private BuiltInQualityProfilesNotificationTemplate underTest = new BuiltInQualityProfilesNotificationTemplate(); @Test - public void notification_contains_list_of_quality_profiles() { + public void notification_contains_list_of_new_rules() { String profileName = randomAlphanumeric(20); String language = randomAlphanumeric(20); BuiltInQualityProfilesNotification notification = new BuiltInQualityProfilesNotification() - .addProfile(new Profile(profileName, language)); + .addProfile(Profile.newBuilder(profileName, language) + .setNewRules(2) + .build()); EmailMessage emailMessage = underTest.format(notification.serialize()); assertThat(emailMessage.getMessage()).isEqualTo("Built-in quality profiles have been updated:\n" + "\"" + profileName + "\" - " + language + "\n" + + " 2 new rules\n" + "This is a good time to review your quality profiles and update them to benefit from the latest evolutions."); } + + @Test + public void notification_contains_list_of_updated_rules() { + String profileName = randomAlphanumeric(20); + String language = randomAlphanumeric(20); + BuiltInQualityProfilesNotification notification = new BuiltInQualityProfilesNotification() + .addProfile(Profile.newBuilder(profileName, language) + .setUpdatedRules(2) + .build()); + + EmailMessage emailMessage = underTest.format(notification.serialize()); + + assertThat(emailMessage.getMessage()).isEqualTo("Built-in quality profiles have been updated:\n" + + "\"" + profileName + "\" - " + language + "\n" + + " 2 rules have been updated\n" + + "This is a good time to review your quality profiles and update them to benefit from the latest evolutions."); + } + + @Test + public void notification_contains_list_of_removed_rules() { + String profileName = randomAlphanumeric(20); + String language = randomAlphanumeric(20); + BuiltInQualityProfilesNotification notification = new BuiltInQualityProfilesNotification() + .addProfile(Profile.newBuilder(profileName, language) + .setRemovedRules(2) + .build()); + + EmailMessage emailMessage = underTest.format(notification.serialize()); + + assertThat(emailMessage.getMessage()).isEqualTo("Built-in quality profiles have been updated:\n" + + "\"" + profileName + "\" - " + language + "\n" + + " 2 rules removed\n" + + "This is a good time to review your quality profiles and update them to benefit from the latest evolutions."); + } + + @Test + public void notification_contains_list_of_new_updated_and_removed_rules() { + String profileName = randomAlphanumeric(20); + String language = randomAlphanumeric(20); + BuiltInQualityProfilesNotification notification = new BuiltInQualityProfilesNotification() + .addProfile(Profile.newBuilder(profileName, language) + .setNewRules(2) + .setUpdatedRules(3) + .setRemovedRules(4) + .build()); + + EmailMessage emailMessage = underTest.format(notification.serialize()); + + assertThat(emailMessage.getMessage()).isEqualTo("Built-in quality profiles have been updated:\n" + + "\"" + profileName + "\" - " + language + "\n" + + " 2 new rules\n" + + " 3 rules have been updated\n" + + " 4 rules removed\n" + + "This is a good time to review your quality profiles and update them to benefit from the latest evolutions."); + } + + @Test + public void notification_contains_many_profiles() { + String profileName1 = "profile1_" + randomAlphanumeric(20); + String language1 = "lang1_" + randomAlphanumeric(20); + String profileName2 = "profile1_" + randomAlphanumeric(20); + String language2 = "lang2_" + randomAlphanumeric(20); + BuiltInQualityProfilesNotification notification = new BuiltInQualityProfilesNotification() + .addProfile(Profile.newBuilder(profileName1, language1) + .setNewRules(2) + .build()) + .addProfile(Profile.newBuilder(profileName2, language2) + .setNewRules(13) + .build()); + + EmailMessage emailMessage = underTest.format(notification.serialize()); + + assertThat(emailMessage.getMessage()).isEqualTo("Built-in quality profiles have been updated:\n" + + "\"" + profileName1 + "\" - " + language1 + "\n" + + " 2 new rules\n" + + "\"" + profileName2 + "\" - " + language2 + "\n" + + " 13 new rules\n" + + "This is a good time to review your quality profiles and update them to benefit from the latest evolutions."); + } + + @Test + public void notification_contains_profiles_sorted_by_language_then_by_profile_name() { + String language1 = "lang1_" + randomAlphanumeric(20); + String language2 = "lang2_" + randomAlphanumeric(20); + String profileName1 = "profile1_" + randomAlphanumeric(20); + String profileName2 = "profile2_" + randomAlphanumeric(20); + String profileName3 = "profile3_" + randomAlphanumeric(20); + BuiltInQualityProfilesNotification notification = new BuiltInQualityProfilesNotification() + .addProfile(Profile.newBuilder(profileName3, language2).build()) + .addProfile(Profile.newBuilder(profileName2, language1).build()) + .addProfile(Profile.newBuilder(profileName1, language2).build()); + + EmailMessage emailMessage = underTest.format(notification.serialize()); + + assertThat(emailMessage.getMessage()).containsSequence( + "\"" + profileName2 + "\" - " + language1, + "\"" + profileName1 + "\" - " + language2, + "\"" + profileName3 + "\" - " + language2); + } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotificationTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotificationTest.java index 7ea0b93b029..9180e904311 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotificationTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesNotificationTest.java @@ -50,11 +50,17 @@ public class BuiltInQualityProfilesNotificationTest { String profileName = randomAlphanumeric(20); String language = randomAlphanumeric(20); - Notification notification = new BuiltInQualityProfilesNotification().addProfile(new Profile(profileName, language)).serialize(); + Notification notification = new BuiltInQualityProfilesNotification() + .addProfile(Profile.newBuilder(profileName, language) + .setNewRules(3) + .setUpdatedRules(5) + .setRemovedRules(7) + .build()) + .serialize(); BuiltInQualityProfilesNotification result = BuiltInQualityProfilesNotification.parse(notification); - assertThat(result.getProfiles()).extracting(Profile::getProfileName, Profile::getLanguage) - .containsExactlyInAnyOrder(tuple(profileName, language)); + assertThat(result.getProfiles()).extracting(Profile::getProfileName, Profile::getLanguage, Profile::getNewRules, Profile::getUpdatedRules, Profile::getRemovedRules) + .containsExactlyInAnyOrder(tuple(profileName, language, 3, 5, 7)); } @Test @@ -65,8 +71,8 @@ public class BuiltInQualityProfilesNotificationTest { String language2 = randomAlphanumeric(20); Notification notification = new BuiltInQualityProfilesNotification() - .addProfile(new Profile(profileName1, language1)) - .addProfile(new Profile(profileName2, language2)) + .addProfile(Profile.newBuilder(profileName1, language1).build()) + .addProfile(Profile.newBuilder(profileName2, language2).build()) .serialize(); BuiltInQualityProfilesNotification result = BuiltInQualityProfilesNotification.parse(notification); diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RegisterQualityProfilesNotificationTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RegisterQualityProfilesNotificationTest.java index 362486e0fec..e11f76806f9 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RegisterQualityProfilesNotificationTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RegisterQualityProfilesNotificationTest.java @@ -19,8 +19,8 @@ */ package org.sonar.server.qualityprofile; +import com.google.common.collect.Multimap; import java.util.Arrays; -import java.util.List; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -53,6 +53,8 @@ import static org.sonar.api.rules.Rule.create; import static org.sonar.api.rules.RulePriority.MAJOR; import static org.sonar.db.qualityprofile.QualityProfileTesting.newRuleProfileDto; import static org.sonar.server.language.LanguageTesting.newLanguage; +import static org.sonar.server.qualityprofile.ActiveRuleChange.Type.ACTIVATED; +import static org.sonar.server.qualityprofile.ActiveRuleChange.Type.DEACTIVATED; public class RegisterQualityProfilesNotificationTest { @@ -116,40 +118,73 @@ public class RegisterQualityProfilesNotificationTest { underTest.start(); - ArgumentCaptor captor = ArgumentCaptor.forClass(List.class); + ArgumentCaptor captor = ArgumentCaptor.forClass(Multimap.class); verify(builtInQualityProfilesNotification).send(captor.capture()); - List updatedProfiles = captor.>getValue(); - assertThat(updatedProfiles) + Multimap updatedProfiles = captor.>getValue(); + assertThat(updatedProfiles.keySet()) .extracting(QProfileName::getName, QProfileName::getLanguage) .containsExactlyInAnyOrder(tuple(dbProfile.getName(), dbProfile.getLanguage())); + assertThat(updatedProfiles.values()) + .extracting(value -> value.getActiveRule().getRuleId(), ActiveRuleChange::getType) + .containsExactlyInAnyOrder(tuple(newRule.getId(), ACTIVATED)); } @Test - public void only_send_one_notification_when_several_built_in_profiles_contain_new_rules() { + public void send_notification_when_built_in_profile_contains_deactivated_rule() { String language = newLanguageKey(); RuleDefinitionDto existingRule = db.rules().insert(r -> r.setLanguage(language)); - RuleDefinitionDto newRule = db.rules().insert(r -> r.setLanguage(language)); + RulesProfileDto dbProfile = insertBuiltInProfile(language); + activateRuleInDb(dbProfile, existingRule, MAJOR); + addPluginProfile(dbProfile); + builtInQProfileRepositoryRule.initialize(); + + underTest.start(); + + ArgumentCaptor captor = ArgumentCaptor.forClass(Multimap.class); + verify(builtInQualityProfilesNotification).send(captor.capture()); + Multimap updatedProfiles = captor.>getValue(); + assertThat(updatedProfiles.keySet()) + .extracting(QProfileName::getName, QProfileName::getLanguage) + .containsExactlyInAnyOrder(tuple(dbProfile.getName(), dbProfile.getLanguage())); + assertThat(updatedProfiles.values()) + .extracting(value -> value.getActiveRule().getRuleId(), ActiveRuleChange::getType) + .containsExactlyInAnyOrder(tuple(existingRule.getId(), DEACTIVATED)); + } + @Test + public void only_send_one_notification_when_several_built_in_profiles_contain_new_rules() { + String language = newLanguageKey(); + + RuleDefinitionDto existingRule1 = db.rules().insert(r -> r.setLanguage(language)); + RuleDefinitionDto newRule1 = db.rules().insert(r -> r.setLanguage(language)); RulesProfileDto dbProfile1 = insertBuiltInProfile(language); - activateRuleInDb(dbProfile1, existingRule, MAJOR); - addPluginProfile(dbProfile1, existingRule, newRule); + activateRuleInDb(dbProfile1, existingRule1, MAJOR); + addPluginProfile(dbProfile1, existingRule1, newRule1); + RuleDefinitionDto existingRule2 = db.rules().insert(r -> r.setLanguage(language)); + RuleDefinitionDto newRule2 = db.rules().insert(r -> r.setLanguage(language)); RulesProfileDto dbProfile2 = insertBuiltInProfile(language); - activateRuleInDb(dbProfile2, existingRule, MAJOR); - addPluginProfile(dbProfile2, existingRule, newRule); + activateRuleInDb(dbProfile2, existingRule2, MAJOR); + addPluginProfile(dbProfile2, existingRule2, newRule2); builtInQProfileRepositoryRule.initialize(); underTest.start(); - ArgumentCaptor captor = ArgumentCaptor.forClass(List.class); + ArgumentCaptor captor = ArgumentCaptor.forClass(Multimap.class); verify(builtInQualityProfilesNotification).send(captor.capture()); - List updatedProfiles = captor.>getValue(); - assertThat(updatedProfiles) + Multimap updatedProfiles = captor.>getValue(); + assertThat(updatedProfiles.keySet()) .extracting(QProfileName::getName, QProfileName::getLanguage) .containsExactlyInAnyOrder( tuple(dbProfile1.getName(), dbProfile1.getLanguage()), tuple(dbProfile2.getName(), dbProfile2.getLanguage()) ); + assertThat(updatedProfiles.values()) + .extracting(value -> value.getActiveRule().getRuleId(), ActiveRuleChange::getType) + .containsExactlyInAnyOrder( + tuple(newRule1.getId(), ACTIVATED), + tuple(newRule2.getId(), ACTIVATED) + ); } private void addPluginProfile(RulesProfileDto dbProfile, RuleDefinitionDto... dbRules) { diff --git a/tests/plugins/foo-plugin-v1/src/main/java/org/sonar/foo/rule/FooBasicProfile.java b/tests/plugins/foo-plugin-v1/src/main/java/org/sonar/foo/rule/FooBasicProfile.java index 3a53e9293ff..73f54dc30f4 100644 --- a/tests/plugins/foo-plugin-v1/src/main/java/org/sonar/foo/rule/FooBasicProfile.java +++ b/tests/plugins/foo-plugin-v1/src/main/java/org/sonar/foo/rule/FooBasicProfile.java @@ -21,7 +21,9 @@ package org.sonar.foo.rule; import org.sonar.api.profiles.ProfileDefinition; import org.sonar.api.profiles.RulesProfile; -import org.sonar.api.rules.Rule; +import org.sonar.api.rules.ActiveRule; +import org.sonar.api.rules.RuleFinder; +import org.sonar.api.rules.RulePriority; import org.sonar.api.utils.ValidationMessages; import static org.sonar.api.rules.RulePriority.MAJOR; @@ -30,12 +32,28 @@ import static org.sonar.foo.rule.FooRulesDefinition.FOO_REPOSITORY; public class FooBasicProfile extends ProfileDefinition { + private final RuleFinder ruleFinder; + + public FooBasicProfile(RuleFinder ruleFinder) { + this.ruleFinder = ruleFinder; + } + @Override public RulesProfile createProfile(ValidationMessages validation) { final RulesProfile profile = RulesProfile.create("Basic", KEY); - profile.activateRule(Rule.create(FOO_REPOSITORY, "UnchangedRule"), MAJOR); - profile.activateRule(Rule.create(FOO_REPOSITORY, "ChangedRule"), MAJOR); - profile.activateRule(Rule.create(FOO_REPOSITORY, "RemovedRule"), MAJOR); + activateRule(profile, FOO_REPOSITORY, "UnchangedRule", MAJOR); + activateRule(profile, FOO_REPOSITORY, "ChangedRule", MAJOR); + activateRule(profile, FOO_REPOSITORY, "ToBeDeactivatedRule", MAJOR); + activateRule(profile, FOO_REPOSITORY, "ToBeRemovedRule", MAJOR); + activateRule(profile, FOO_REPOSITORY, "RuleWithUnchangedParameter", MAJOR); + activateRule(profile, FOO_REPOSITORY, "RuleWithChangedParameter", MAJOR); + activateRule(profile, FOO_REPOSITORY, "RuleWithRemovedParameter", MAJOR); + activateRule(profile, FOO_REPOSITORY, "RuleWithAddedParameter", MAJOR); return profile; } + + private ActiveRule activateRule(RulesProfile profile, String repo, String key, RulePriority severity) { + return profile.activateRule(ruleFinder.findByKey(repo, key), severity); + } + } diff --git a/tests/plugins/foo-plugin-v1/src/main/java/org/sonar/foo/rule/FooRulesDefinition.java b/tests/plugins/foo-plugin-v1/src/main/java/org/sonar/foo/rule/FooRulesDefinition.java index 7257dd72681..039cea9fd2b 100644 --- a/tests/plugins/foo-plugin-v1/src/main/java/org/sonar/foo/rule/FooRulesDefinition.java +++ b/tests/plugins/foo-plugin-v1/src/main/java/org/sonar/foo/rule/FooRulesDefinition.java @@ -35,7 +35,12 @@ public class FooRulesDefinition implements RulesDefinition { NewRepository repo = context.createRepository(FOO_REPOSITORY, Foo.KEY).setName("Foo"); createRule(repo, "UnchangedRule"); createRule(repo, "ChangedRule"); - createRule(repo, "RemovedRule"); + createRule(repo, "ToBeDeactivatedRule"); + createRule(repo, "ToBeRemovedRule"); + createRule(repo, "RuleWithUnchangedParameter").createParam("unchanged").setDefaultValue("10"); + createRule(repo, "RuleWithChangedParameter").createParam("toBeChanged").setDefaultValue("10"); + createRule(repo, "RuleWithRemovedParameter").createParam("toBeRemoved").setDefaultValue("10"); + createRule(repo, "RuleWithAddedParameter").createParam("added"); repo.done(); } diff --git a/tests/plugins/foo-plugin-v2/src/main/java/org/sonar/foo/rule/FooBasicProfile.java b/tests/plugins/foo-plugin-v2/src/main/java/org/sonar/foo/rule/FooBasicProfile.java index 1c2d051f7cf..aceb76331e2 100644 --- a/tests/plugins/foo-plugin-v2/src/main/java/org/sonar/foo/rule/FooBasicProfile.java +++ b/tests/plugins/foo-plugin-v2/src/main/java/org/sonar/foo/rule/FooBasicProfile.java @@ -21,7 +21,9 @@ package org.sonar.foo.rule; import org.sonar.api.profiles.ProfileDefinition; import org.sonar.api.profiles.RulesProfile; -import org.sonar.api.rules.Rule; +import org.sonar.api.rules.ActiveRule; +import org.sonar.api.rules.RuleFinder; +import org.sonar.api.rules.RulePriority; import org.sonar.api.utils.ValidationMessages; import static org.sonar.api.rules.RulePriority.MAJOR; @@ -31,12 +33,29 @@ import static org.sonar.foo.rule.FooRulesDefinition.FOO_REPOSITORY; public class FooBasicProfile extends ProfileDefinition { + private final RuleFinder ruleFinder; + + public FooBasicProfile(RuleFinder ruleFinder) { + this.ruleFinder = ruleFinder; + } + @Override public RulesProfile createProfile(ValidationMessages validation) { final RulesProfile profile = RulesProfile.create("Basic", KEY); - profile.activateRule(Rule.create(FOO_REPOSITORY, "UnchangedRule"), MAJOR); - profile.activateRule(Rule.create(FOO_REPOSITORY, "ChangedRule"), MINOR); - profile.activateRule(Rule.create(FOO_REPOSITORY, "NewRule"), MAJOR); + activateRule(profile, FOO_REPOSITORY, "UnchangedRule", MAJOR); + activateRule(profile, FOO_REPOSITORY, "ChangedRule", MINOR); + activateRule(profile, FOO_REPOSITORY, "NewRule", MAJOR); + activateRule(profile, FOO_REPOSITORY, "RuleWithUnchangedParameter", MAJOR); + // Update of the default value of a parameter is not taken into account in quality profile as long as it's not also explicitly set in the quality profile + // TODO Remove the parameter value when SONAR_9475 will be fixed + activateRule(profile, FOO_REPOSITORY, "RuleWithChangedParameter", MAJOR).setParameter("toBeChanged", "20"); + activateRule(profile, FOO_REPOSITORY, "RuleWithRemovedParameter", MAJOR); + activateRule(profile, FOO_REPOSITORY, "RuleWithAddedParameter", MAJOR); return profile; } + + private ActiveRule activateRule(RulesProfile profile, String repo, String key, RulePriority severity) { + return profile.activateRule(ruleFinder.findByKey(repo, key), severity); + } + } diff --git a/tests/plugins/foo-plugin-v2/src/main/java/org/sonar/foo/rule/FooRulesDefinition.java b/tests/plugins/foo-plugin-v2/src/main/java/org/sonar/foo/rule/FooRulesDefinition.java index aacc2335262..a0ef0ccbdf7 100644 --- a/tests/plugins/foo-plugin-v2/src/main/java/org/sonar/foo/rule/FooRulesDefinition.java +++ b/tests/plugins/foo-plugin-v2/src/main/java/org/sonar/foo/rule/FooRulesDefinition.java @@ -36,6 +36,12 @@ public class FooRulesDefinition implements RulesDefinition { createRule(repo, "UnchangedRule"); createRule(repo, "ChangedRule"); createRule(repo, "NewRule"); + createRule(repo, "ToBeDeactivatedRule"); + createRule(repo, "RuleWithUnchangedParameter").createParam("unchanged").setDefaultValue("10"); + // Update of the default value of a parameter is not taken into account in quality profile as long as it's not also explicitly set in the quality profile + createRule(repo, "RuleWithChangedParameter").createParam("toBeChanged").setDefaultValue("20"); + createRule(repo, "RuleWithRemovedParameter"); + createRule(repo, "RuleWithAddedParameter").createParam("added").setDefaultValue("10"); repo.done(); } diff --git a/tests/src/test/java/org/sonarqube/tests/qualityProfile/BuiltInQualityProfilesNotificationTest.java b/tests/src/test/java/org/sonarqube/tests/qualityProfile/BuiltInQualityProfilesNotificationTest.java index 4f287380171..7845f3ced14 100644 --- a/tests/src/test/java/org/sonarqube/tests/qualityProfile/BuiltInQualityProfilesNotificationTest.java +++ b/tests/src/test/java/org/sonarqube/tests/qualityProfile/BuiltInQualityProfilesNotificationTest.java @@ -70,8 +70,7 @@ public class BuiltInQualityProfilesNotificationTest { .addPlugin(pluginArtifact("foo-plugin-v1")) .setServerProperty("email.smtp_host.secured", "localhost") .setServerProperty("email.smtp_port.secured", Integer.toString(smtpServer.getServer().getPort())) - // .setServerProperty("sonar.web.javaAdditionalOpts", "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005")// FIXME - // remove web debugging + //.setServerProperty("sonar.web.javaAdditionalOpts", "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005")// FIXME remove web debugging .build(); orchestrator.start(); @@ -101,8 +100,7 @@ public class BuiltInQualityProfilesNotificationTest { .addPlugin(pluginArtifact("foo-plugin-v1")) .setServerProperty("email.smtp_host.secured", "localhost") .setServerProperty("email.smtp_port.secured", Integer.toString(smtpServer.getServer().getPort())) - // .setServerProperty("sonar.web.javaAdditionalOpts", "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005")// FIXME - // remove web debugging + //.setServerProperty("sonar.web.javaAdditionalOpts", "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005")// FIXME remove web debugging .build(); orchestrator.start(); @@ -139,6 +137,9 @@ public class BuiltInQualityProfilesNotificationTest { .containsSequence( "Built-in quality profiles have been updated:", "\"Basic\" - Foo", + " 1 new rules", + " 3 rules have been updated", + " 1 rules removed", "This is a good time to review your quality profiles and update them to benefit from the latest evolutions.") .isEqualTo(messages.get(1).getMimeMessage().getContent().toString()); } @@ -151,14 +152,6 @@ public class BuiltInQualityProfilesNotificationTest { } } - private String getContent(MimeMessage mimeMessage1) { - try { - return mimeMessage1.getContent().toString(); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - private String getAllRecipients(MimeMessage mimeMessage) { try { return mimeMessage.getHeader("To", null); -- 2.39.5