]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6299 WS to delete a quality profile
authorJean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com>
Thu, 2 Apr 2015 14:13:29 +0000 (16:13 +0200)
committerJean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com>
Fri, 3 Apr 2015 14:46:17 +0000 (16:46 +0200)
server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileFactory.java
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfileDeleteAction.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfileParamUtils.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfileDeleteActionTest.java [new file with mode: 0644]

index 38d5d1469fd06451dbe3d80b2474df18d0ed48dc..7762405242228dff0138e2985d37c9a7849c52ae 100644 (file)
@@ -382,6 +382,7 @@ class ServerComponents {
     pico.addSingleton(QProfileSearchAction.class);
     pico.addSingleton(QProfileSetDefaultAction.class);
     pico.addSingleton(QProfileProjectsAction.class);
+    pico.addSingleton(QProfileDeleteAction.class);
     pico.addSingleton(QProfilesWs.class);
     pico.addSingleton(ProfilesWs.class);
     pico.addSingleton(RuleActivationActions.class);
index c6d99c1eb4241f7900f543c0be0829b90772f6ed..411b1b8d4cc60a098e19e0fc898c7a6ece51c816 100644 (file)
@@ -100,7 +100,7 @@ public class QProfileFactory implements ServerComponent {
    * Session is NOT committed. Profiles marked as "default" for a language can't be deleted,
    * except if the parameter <code>force</code> is true.
    */
-  void delete(DbSession session, String key, boolean force) {
+  public void delete(DbSession session, String key, boolean force) {
     QualityProfileDto profile = db.qualityProfileDao().getNonNullByKey(session, key);
     List<QualityProfileDto> descendants = db.qualityProfileDao().findDescendants(session, key);
     if (!force) {
@@ -117,6 +117,7 @@ public class QProfileFactory implements ServerComponent {
   }
 
   private void doDelete(DbSession session, QualityProfileDto profile) {
+    db.qualityProfileDao().deleteAllProjectProfileAssociation(profile.getKey(), session);
     db.activeRuleDao().deleteByProfileKey(session, profile.getKey());
     db.qualityProfileDao().delete(session, profile);
   }
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfileDeleteAction.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfileDeleteAction.java
new file mode 100644 (file)
index 0000000..e86ff0b
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * 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 org.sonar.server.qualityprofile.ws;
+
+import org.sonar.api.resources.Languages;
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.server.ws.Response;
+import org.sonar.api.server.ws.WebService.NewAction;
+import org.sonar.api.server.ws.WebService.NewController;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.qualityprofile.QProfileFactory;
+import org.sonar.server.user.UserSession;
+
+public class QProfileDeleteAction implements BaseQProfileWsAction {
+
+  private final Languages languages;
+  private final QProfileFactory profileFactory;
+  private final DbClient dbClient;
+
+  public QProfileDeleteAction(Languages languages, QProfileFactory profileFactory, DbClient dbClient) {
+    this.languages = languages;
+    this.profileFactory = profileFactory;
+    this.dbClient = dbClient;
+  }
+
+  @Override
+  public void define(NewController controller) {
+    NewAction action = controller.createAction("delete")
+      .setDescription("Delete a quality profile and all its descendants. The default quality profile cannot be deleted.")
+      .setSince("5.2")
+      .setPost(true)
+      .setHandler(this);
+
+    QProfileParamUtils.defineProfileParams(action, languages);
+  }
+
+
+  @Override
+  public void handle(Request request, Response response) throws Exception {
+    UserSession.get().checkLoggedIn();
+    UserSession.get().checkGlobalPermission(GlobalPermissions.QUALITY_PROFILE_ADMIN);
+
+
+    DbSession session = dbClient.openSession(false);
+    try {
+      String profileKey = QProfileParamUtils.getProfileKey(request, profileFactory, session);
+      profileFactory.delete(session, profileKey, false);
+
+      session.commit();
+    } finally {
+      session.close();
+    }
+
+    response.noContent();
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfileParamUtils.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfileParamUtils.java
new file mode 100644 (file)
index 0000000..f4e11fd
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * 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 org.sonar.server.qualityprofile.ws;
+
+import com.google.common.base.Preconditions;
+import org.sonar.api.resources.Languages;
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.server.ws.WebService.NewAction;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.qualityprofile.db.QualityProfileDto;
+import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.qualityprofile.QProfileFactory;
+
+import static org.apache.commons.lang.StringUtils.isEmpty;
+
+public class QProfileParamUtils {
+
+  private static final String PARAM_LANGUAGE = "language";
+  private static final String PARAM_PROFILE_NAME = "profileName";
+  private static final String PARAM_PROFILE_KEY = "profileKey";
+
+  private QProfileParamUtils() {
+    // Utility class
+  }
+
+  public static void defineProfileParams(NewAction action, Languages languages) {
+    action.createParam(PARAM_PROFILE_KEY)
+      .setDescription("A quality profile key. Either this parameter, or a combination of profileName + language must be set.")
+      .setExampleValue("sonar-way-java-12345");
+    action.createParam(PARAM_PROFILE_NAME)
+      .setDescription("A quality profile name. If this parameter is set, profileKey must not be set and language must be set to disambiguate.")
+      .setExampleValue("Sonar way");
+    action.createParam(PARAM_LANGUAGE)
+      .setDescription("A quality profile language. If this parameter is set, profileKey must not be set and profileName must be set to disambiguate.")
+      .setPossibleValues(LanguageParamUtils.getLanguageKeys(languages))
+      .setExampleValue("js");
+  }
+
+  public static String getProfileKey(Request request, QProfileFactory profileFactory, DbSession session) {
+    String language = request.param(PARAM_LANGUAGE);
+    String profileName = request.param(PARAM_PROFILE_NAME);
+    String profileKey = request.param(PARAM_PROFILE_KEY);
+
+    Preconditions.checkArgument(
+      (!isEmpty(language) && !isEmpty(profileName)) ^ !isEmpty(profileKey), "Either profileKey or profileName + language must be set");
+
+    if (profileKey == null) {
+      profileKey = getProfileKeyFromLanguageAndName(language, profileName, profileFactory, session);
+    }
+    return profileKey;
+  }
+
+  private static String getProfileKeyFromLanguageAndName(String language, String profileName, QProfileFactory profileFactory, DbSession session) {
+    QualityProfileDto profile = profileFactory.getByNameAndLanguage(session, profileName, language);
+    if (profile == null) {
+      throw new NotFoundException(String.format("Unable to find a profile for language '%s' with name '%s'", language, profileName));
+    }
+    return profile.getKey();
+  }
+
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfileDeleteActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfileDeleteActionTest.java
new file mode 100644 (file)
index 0000000..3d31e67
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * 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 org.sonar.server.qualityprofile.ws;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.sonar.api.resources.Language;
+import org.sonar.api.resources.Languages;
+import org.sonar.api.utils.System2;
+import org.sonar.core.component.ComponentDto;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.DbTester;
+import org.sonar.core.qualityprofile.db.QualityProfileDao;
+import org.sonar.core.qualityprofile.db.QualityProfileDto;
+import org.sonar.server.component.ComponentTesting;
+import org.sonar.server.component.db.ComponentDao;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.language.LanguageTesting;
+import org.sonar.server.qualityprofile.QProfileFactory;
+import org.sonar.server.qualityprofile.db.ActiveRuleDao;
+import org.sonar.server.rule.db.RuleDao;
+import org.sonar.server.user.MockUserSession;
+import org.sonar.server.ws.WsTester;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+
+public class QProfileDeleteActionTest {
+
+  @ClassRule
+  public static DbTester dbTester = new DbTester();
+
+  private DbClient dbClient;
+
+  private QualityProfileDao qualityProfileDao;
+
+  private ComponentDao componentDao;
+
+  private Language xoo1, xoo2;
+
+  private WsTester tester;
+
+  private DbSession session;
+
+  @Before
+  public void setUp() throws Exception {
+    dbTester.truncateTables();
+    qualityProfileDao = new QualityProfileDao(dbTester.myBatis(), mock(System2.class));
+    componentDao = new ComponentDao();
+
+    dbClient = new DbClient(dbTester.database(), dbTester.myBatis(), qualityProfileDao, new ActiveRuleDao(qualityProfileDao, new RuleDao()));
+    session = dbClient.openSession(false);
+
+    xoo1 = LanguageTesting.newLanguage("xoo1");
+    xoo2 = LanguageTesting.newLanguage("xoo2");
+
+    tester = new WsTester(new QProfilesWs(
+      mock(RuleActivationActions.class),
+      mock(BulkRuleActivationActions.class),
+      mock(ProjectAssociationActions.class),
+      new QProfileDeleteAction(new Languages(xoo1, xoo2), new QProfileFactory(dbClient), dbClient)));
+  }
+
+  @After
+  public void teadDown() {
+    session.close();
+  }
+
+  @Test
+  public void delete_nominal_with_key() throws Exception {
+    String profileKey = "sonar-way-xoo1-12345";
+
+    ComponentDto project = ComponentTesting.newProjectDto("polop");
+    componentDao.insert(session, project);
+    qualityProfileDao.insert(session, QualityProfileDto.createFor(profileKey).setLanguage(xoo1.getKey()).setName("Sonar way"));
+    qualityProfileDao.insertProjectProfileAssociation(project.uuid(), profileKey, session);
+    session.commit();
+
+    MockUserSession.set().setLogin("obiwan").setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN);
+
+    tester.newPostRequest("api/qualityprofiles", "delete").setParam("profileKey", "sonar-way-xoo1-12345").execute().assertNoContent();
+
+    assertThat(qualityProfileDao.getByKey(session, "sonar-way-xoo1-12345")).isNull();
+    assertThat(qualityProfileDao.selectProjects("Sonar way", xoo1.getName())).isEmpty();
+  }
+
+  @Test
+  public void delete_nominal_with_language_and_name() throws Exception {
+    String profileKey = "sonar-way-xoo1-12345";
+
+    ComponentDto project = ComponentTesting.newProjectDto("polop");
+    componentDao.insert(session, project);
+    qualityProfileDao.insert(session, QualityProfileDto.createFor(profileKey).setLanguage(xoo1.getKey()).setName("Sonar way"));
+    qualityProfileDao.insertProjectProfileAssociation(project.uuid(), profileKey, session);
+    session.commit();
+
+    MockUserSession.set().setLogin("obiwan").setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN);
+
+    tester.newPostRequest("api/qualityprofiles", "delete").setParam("profileName", "Sonar way").setParam("language", xoo1.getKey()).execute().assertNoContent();
+
+    assertThat(qualityProfileDao.getByKey(session, "sonar-way-xoo1-12345")).isNull();
+    assertThat(qualityProfileDao.selectProjects("Sonar way", xoo1.getName())).isEmpty();
+  }
+
+  @Test(expected = ForbiddenException.class)
+  public void fail_on_missing_permission() throws Exception {
+    MockUserSession.set().setLogin("obiwan");
+    tester.newPostRequest("api/qualityprofiles", "delete").execute();
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void fail_on_missing_arguments() throws Exception {
+    MockUserSession.set().setLogin("obiwan").setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN);
+    tester.newPostRequest("api/qualityprofiles", "delete").execute();
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void fail_on_missing_language() throws Exception {
+    MockUserSession.set().setLogin("obiwan").setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN);
+    tester.newPostRequest("api/qualityprofiles", "delete").setParam("profileName", "Polop").execute();
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void fail_on_missing_name() throws Exception {
+    MockUserSession.set().setLogin("obiwan").setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN);
+    tester.newPostRequest("api/qualityprofiles", "delete").setParam("language", xoo1.getKey()).execute();
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void fail_on_too_many_arguments() throws Exception {
+    MockUserSession.set().setLogin("obiwan").setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN);
+    tester.newPostRequest("api/qualityprofiles", "delete").setParam("profileName", "Polop").setParam("language", xoo1.getKey()).setParam("profileKey", "polop").execute();
+  }
+
+  @Test(expected = NotFoundException.class)
+  public void fail_on_unexisting_profile() throws Exception {
+    MockUserSession.set().setLogin("obiwan").setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN);
+    tester.newPostRequest("api/qualityprofiles", "delete").setParam("profileName", "Polop").setParam("language", xoo1.getKey()).execute();
+  }
+}