]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6300 WS to select the default quality profile for a language
authorJean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com>
Mon, 30 Mar 2015 16:40:05 +0000 (18:40 +0200)
committerJean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com>
Wed, 1 Apr 2015 08:44:20 +0000 (10:44 +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/QProfileSetDefaultAction.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfileSetDefaultActionTest.java [new file with mode: 0644]

index 3742afb756799a1c0a2e806a64af64413f9affbe..eef1ee231407db4b3d85b5159a78150471350cef 100644 (file)
@@ -380,6 +380,7 @@ class ServerComponents {
     pico.addSingleton(BuiltInProfiles.class);
     pico.addSingleton(QProfileRestoreBuiltInAction.class);
     pico.addSingleton(QProfileSearchAction.class);
+    pico.addSingleton(QProfileSetDefaultAction.class);
     pico.addSingleton(QProfilesWs.class);
     pico.addSingleton(ProfilesWs.class);
     pico.addSingleton(RuleActivationActions.class);
index ccc8f8f2d52c18ecbd0472fb3a5ba15f3fa12db0..c6d99c1eb4241f7900f543c0be0829b90772f6ed 100644 (file)
@@ -138,7 +138,7 @@ public class QProfileFactory implements ServerComponent {
     return db.qualityProfileDao().getDefaultProfile(language, session);
   }
 
-  void setDefault(String profileKey) {
+  public void setDefault(String profileKey) {
     DbSession dbSession = db.openSession(false);
     try {
       setDefault(dbSession, profileKey);
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfileSetDefaultAction.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfileSetDefaultAction.java
new file mode 100644 (file)
index 0000000..ec88a6c
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * 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.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Collections2;
+import org.sonar.api.resources.Language;
+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;
+import org.sonar.api.server.ws.WebService.NewAction;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.qualityprofile.QProfile;
+import org.sonar.server.qualityprofile.QProfileFactory;
+import org.sonar.server.qualityprofile.QProfileLookup;
+import org.sonar.server.user.UserSession;
+
+import java.util.Arrays;
+
+import static org.apache.commons.lang.StringUtils.isEmpty;
+
+public class QProfileSetDefaultAction implements BaseQProfileWsAction {
+
+  private static final String PARAM_LANGUAGE = "language";
+  private static final String PARAM_PROFILE_NAME = "profileName";
+  private static final String PARAM_PROFILE_KEY = "profileKey";
+
+  private final Languages languages;
+
+  private final QProfileLookup profileLookup;
+
+  private final QProfileFactory profileFactory;
+
+  public QProfileSetDefaultAction(Languages languages, QProfileLookup profileLookup, QProfileFactory profileFactory) {
+    this.languages = languages;
+    this.profileLookup = profileLookup;
+    this.profileFactory = profileFactory;
+  }
+
+  @Override
+  public void handle(Request request, Response response) throws Exception {
+    UserSession.get().checkLoggedIn().checkGlobalPermission(GlobalPermissions.QUALITY_PROFILE_ADMIN);
+
+    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.setDefault(profileKey);
+
+    response.noContent();
+  }
+
+  private String getProfileKeyFromLanguageAndName(String language, String profileName) {
+    QProfile profile = profileLookup.profile(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.key();
+  }
+
+  @Override
+  public void define(WebService.NewController controller) {
+    NewAction setDefault = controller.createAction("set_default")
+      .setSince("5.2")
+      .setDescription("Select the default profile for a given language.")
+      .setHandler(this)
+      .setResponseExample(getClass().getResource("example-search.json"));
+
+    setDefault.createParam(PARAM_LANGUAGE)
+      .setDescription("The key of a language supported by the platform. If specified, profileName must be set to select the default profile for the selected language.")
+      .setExampleValue("js")
+      .setPossibleValues(Collections2.transform(Arrays.asList(languages.all()), new Function<Language, String>() {
+        @Override
+        public String apply(Language input) {
+          return input.getKey();
+        }
+      }));
+
+    setDefault.createParam(PARAM_PROFILE_NAME)
+      .setDescription("The name of a quality profile. If specified, language must be set. The matching profile will be used as default for the selected language.")
+      .setExampleValue("sonar-way-js-12345");
+
+    setDefault.createParam(PARAM_PROFILE_KEY)
+      .setDescription("The key of a quality profile. If specified, language and profileName must not be set. The matching profile will be used as default for its language.")
+      .setExampleValue("sonar-way-js-12345");
+  }
+
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfileSetDefaultActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfileSetDefaultActionTest.java
new file mode 100644 (file)
index 0000000..8dac750
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * 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.server.exceptions.ForbiddenException;
+
+import org.apache.commons.lang.StringUtils;
+import org.assertj.core.api.Fail;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.sonar.api.resources.AbstractLanguage;
+import org.sonar.api.resources.Language;
+import org.sonar.api.resources.Languages;
+import org.sonar.api.utils.System2;
+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.db.DbClient;
+import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.qualityprofile.QProfileFactory;
+import org.sonar.server.qualityprofile.QProfileLookup;
+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 QProfileSetDefaultActionTest {
+
+  @ClassRule
+  public static DbTester dbTester = new DbTester();
+
+  private DbClient dbClient;
+
+  private QualityProfileDao qualityProfileDao;
+
+  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));
+    dbClient = new DbClient(dbTester.database(), dbTester.myBatis(), qualityProfileDao);
+    session = dbClient.openSession(false);
+
+    xoo1 = createLanguage("xoo1");
+    xoo2 = createLanguage("xoo2");
+    createProfiles();
+
+    tester = new WsTester(new QProfilesWs(
+      mock(RuleActivationActions.class),
+      mock(BulkRuleActivationActions.class),
+      mock(ProjectAssociationActions.class),
+      new QProfileSetDefaultAction(new Languages(xoo1, xoo2), new QProfileLookup(dbClient), new QProfileFactory(dbClient))));
+  }
+
+  @After
+  public void tearDown() {
+    session.close();
+  }
+
+  @Test
+  public void set_default_profile_using_key() throws Exception {
+    MockUserSession.set().setLogin("obiwan").setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN);
+
+
+    checkDefaultProfile("xoo1", "sonar-way-xoo1-12345");
+    checkDefaultProfile("xoo2", "my-sonar-way-xoo2-34567");
+
+    tester.newPostRequest("api/qualityprofiles", "set_default").setParam("profileKey", "sonar-way-xoo2-23456").execute().assertNoContent();
+
+    checkDefaultProfile("xoo1", "sonar-way-xoo1-12345");
+    checkDefaultProfile("xoo2", "sonar-way-xoo2-23456");
+    assertThat(dbClient.qualityProfileDao().getByKey(session, "sonar-way-xoo2-23456").isDefault()).isTrue();
+    assertThat(dbClient.qualityProfileDao().getByKey(session, "my-sonar-way-xoo2-34567").isDefault()).isFalse();
+
+    // One more time!
+    tester.newPostRequest("api/qualityprofiles", "set_default").setParam("profileKey", "sonar-way-xoo2-23456").execute().assertNoContent();
+    checkDefaultProfile("xoo1", "sonar-way-xoo1-12345");
+    checkDefaultProfile("xoo2", "sonar-way-xoo2-23456");
+  }
+
+  @Test
+  public void set_default_profile_using_language_and_name() throws Exception {
+    MockUserSession.set().setLogin("obiwan").setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN);
+
+    tester.newPostRequest("api/qualityprofiles", "set_default").setParam("language", "xoo2").setParam("profileName", "Sonar way").execute().assertNoContent();
+
+    checkDefaultProfile("xoo1", "sonar-way-xoo1-12345");
+    checkDefaultProfile("xoo2", "sonar-way-xoo2-23456");
+  }
+
+  @Test
+  public void fail_to_set_default_profile_using_key() throws Exception {
+    MockUserSession.set().setLogin("obiwan").setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN);
+
+    try {
+      tester.newPostRequest("api/qualityprofiles", "set_default").setParam("profileKey", "unknown-profile-666").execute();
+      Fail.failBecauseExceptionWasNotThrown(IllegalArgumentException.class);
+    } catch(IllegalArgumentException nfe) {
+      assertThat(nfe).hasMessage("Quality profile not found: unknown-profile-666");
+      checkDefaultProfile("xoo1", "sonar-way-xoo1-12345");
+      checkDefaultProfile("xoo2", "my-sonar-way-xoo2-34567");
+    }
+  }
+
+
+  @Test
+  public void fail_to_set_default_profile_using_language_and_name() throws Exception {
+    MockUserSession.set().setLogin("obiwan").setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN);
+
+    try {
+      tester.newPostRequest("api/qualityprofiles", "set_default").setParam("language", "xoo2").setParam("profileName", "Unknown").execute();
+      Fail.failBecauseExceptionWasNotThrown(NotFoundException.class);
+    } catch(NotFoundException nfe) {
+      assertThat(nfe).hasMessage("Unable to find a profile for language 'xoo2' with name 'Unknown'");
+      checkDefaultProfile("xoo1", "sonar-way-xoo1-12345");
+      checkDefaultProfile("xoo2", "my-sonar-way-xoo2-34567");
+    }
+  }
+
+  @Test
+  public void fail_on_missing_permission() throws Exception {
+    MockUserSession.set().setLogin("obiwan");
+
+    try {
+      tester.newPostRequest("api/qualityprofiles", "set_default").setParam("profileKey", "sonar-way-xoo2-23456").execute().assertNoContent();
+      Fail.failBecauseExceptionWasNotThrown(ForbiddenException.class);
+    } catch(ForbiddenException forbidden) {
+      checkDefaultProfile("xoo1", "sonar-way-xoo1-12345");
+      checkDefaultProfile("xoo2", "my-sonar-way-xoo2-34567");
+    }
+  }
+
+  private void createProfiles() {
+    qualityProfileDao.insert(session,
+      QualityProfileDto.createFor("sonar-way-xoo1-12345").setLanguage(xoo1.getKey()).setName("Sonar way").setDefault(true),
+      QualityProfileDto.createFor("sonar-way-xoo2-23456").setLanguage(xoo2.getKey()).setName("Sonar way"),
+      QualityProfileDto.createFor("my-sonar-way-xoo2-34567").setLanguage(xoo2.getKey()).setName("My Sonar way").setParentKee("sonar-way-xoo2-23456").setDefault(true)
+      );
+    session.commit();
+  }
+
+  private void checkDefaultProfile(String language, String key) throws Exception {
+    assertThat(dbClient.qualityProfileDao().getDefaultProfile(language).getKey()).isEqualTo(key);
+  }
+
+  private Language createLanguage(final String key) {
+    return new AbstractLanguage(key, StringUtils.capitalize(key)) {
+      @Override
+      public String[] getFileSuffixes() {
+        return new String[] {key};
+      }
+    };
+  }
+}