package org.sonar.server.qualityprofile;
import com.google.common.collect.ImmutableList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
+import java.util.stream.Collectors;
import javax.annotation.Nullable;
import org.sonar.api.profiles.RulesProfile;
+import org.sonar.api.resources.Language;
import org.sonar.api.resources.Languages;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition;
}
Map<String, Map<String, BuiltInQualityProfile>> rulesProfilesByLanguage = validateAndClean(context);
this.qProfiles = toFlatList(rulesProfilesByLanguage);
+ ensureAllLanguagesHaveAtLeastOneBuiltInQP();
profiler.stopDebug();
}
return qProfiles;
}
+ private void ensureAllLanguagesHaveAtLeastOneBuiltInQP() {
+ Set<String> languagesWithBuiltInQProfiles = qProfiles.stream().map(BuiltInQProfile::getLanguage).collect(Collectors.toSet());
+ Set<String> languagesWithoutBuiltInQProfiles = Arrays.stream(languages.all())
+ .map(Language::getKey)
+ .filter(key -> !languagesWithBuiltInQProfiles.contains(key))
+ .collect(Collectors.toSet());
+
+ checkState(languagesWithoutBuiltInQProfiles.isEmpty(), "The following languages have no built-in quality profiles: %s",
+ languagesWithoutBuiltInQProfiles.stream().collect(Collectors.joining()));
+ }
+
private Map<String, Map<String, BuiltInQualityProfile>> validateAndClean(BuiltInQualityProfilesDefinition.Context context) {
Map<String, Map<String, BuiltInQualityProfile>> profilesByLanguageAndName = context.profilesByLanguageAndName();
profilesByLanguageAndName.entrySet()
.removeIf(entry -> {
String language = entry.getKey();
if (languages.get(language) == null) {
- LOGGER.info("Language {} is not installed, related Quality profiles are ignored", language);
- return true;
- }
- Collection<BuiltInQualityProfile> profiles = entry.getValue().values();
- if (profiles.isEmpty()) {
- LOGGER.warn("No Quality profiles defined for language: {}", language);
+ LOGGER.info("Language {} is not installed, related quality profiles are ignored", language);
return true;
}
return false;
});
+
return profilesByLanguageAndName;
}
}
@Test
- public void initialize_creates_no_BuiltInQProfile_when_there_is_no_definition() {
+ public void initialize_throws_ISE_if_language_has_no_builtin_qp() {
BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(mock(DbClient.class), new Languages(FOO_LANGUAGE));
+ expectedException.expect(IllegalStateException.class);
+ expectedException.expectMessage("The following languages have no built-in quality profiles: foo");
+
underTest.initialize();
-
- assertThat(underTest.get()).isEmpty();
}
@Test
include 'tests:plugins:foo-plugin-v1'
include 'tests:plugins:foo-plugin-v2'
include 'tests:plugins:foo-plugin-v3'
+include 'tests:plugins:foo-plugin-without-qprofile'
include 'tests:plugins:global-property-change-plugin'
include 'tests:plugins:issue-filter-plugin'
include 'tests:plugins:l10n-fr-pack'
':tests:plugins:foo-plugin-v1',
':tests:plugins:foo-plugin-v2',
':tests:plugins:foo-plugin-v3',
+ ':tests:plugins:foo-plugin-without-qprofile',
':tests:plugins:global-property-change-plugin',
':tests:plugins:issue-filter-plugin',
':tests:plugins:l10n-fr-pack',
--- /dev/null
+sonarqube {
+ skipProject = true
+}
+
+dependencies {
+ compile 'com.google.guava:guava'
+ compile 'commons-io:commons-io'
+ compile 'commons-lang:commons-lang'
+ compileOnly 'com.google.code.findbugs:jsr305'
+ compileOnly project(path: ':sonar-plugin-api', configuration: 'shadow')
+}
+
+jar {
+ manifest {
+ attributes(
+ 'Plugin-Key': 'foo',
+ 'Plugin-Version': version,
+ 'Plugin-Class': 'org.sonar.foo.FooPlugin',
+ 'Plugin-ChildFirstClassLoader': 'false',
+ 'Sonar-Version': version,
+ 'SonarLint-Supported': 'false',
+ 'Plugin-Name': 'Foo',
+ 'Plugin-License': 'GNU LGPL 3'
+ )
+ }
+ into('META-INF/lib') {
+ from configurations.compile
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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];
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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;
+
+/**
+ * Plugin entry-point, as declared in pom.xml.
+ */
+public class FooPlugin implements Plugin {
+
+ @Override
+ public void define(Context context) {
+ context.addExtension(
+ Foo.class);
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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;
import org.sonarqube.tests.marketplace.UpdateCenterTest;
import org.sonarqube.tests.qualityProfile.ActiveRuleEsResilienceTest;
import org.sonarqube.tests.qualityProfile.BuiltInQualityProfilesNotificationTest;
+import org.sonarqube.tests.qualityProfile.PluginWithoutBuiltinQualityProfile;
import org.sonarqube.tests.rule.RuleEsResilienceTest;
import org.sonarqube.tests.serverSystem.BlueGreenTest;
import org.sonarqube.tests.serverSystem.RestartTest;
HttpHeadersAuthenticationTest.class,
OnboardingTest.class,
BuiltInQualityProfilesNotificationTest.class,
+ PluginWithoutBuiltinQualityProfile.class,
ActiveRuleEsResilienceTest.class,
AnalysisEsResilienceTest.class,
RuleEsResilienceTest.class,
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.sonarqube.tests.qualityProfile;
+
+import com.sonar.orchestrator.Orchestrator;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import org.apache.commons.io.FileUtils;
+import org.junit.After;
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.fail;
+import static util.ItUtils.newOrchestratorBuilder;
+import static util.ItUtils.pluginArtifact;
+
+public class PluginWithoutBuiltinQualityProfile {
+ private static Orchestrator orchestrator;
+
+ @Test
+ public void should_fail_if_plugin_defines_language_and_no_builtin_qprofile() throws IOException {
+ orchestrator = newOrchestratorBuilder()
+ .addPlugin(pluginArtifact("foo-plugin-without-qprofile"))
+ .build();
+
+ try {
+ orchestrator.start();
+ fail("Expected to fail to start");
+ } catch (IllegalStateException e) {
+ String logs = FileUtils.readFileToString(orchestrator.getServer().getWebLogs(), StandardCharsets.UTF_8);
+ assertThat(logs).contains("java.lang.IllegalStateException: The following languages have no built-in quality profiles: foo");
+ }
+ }
+
+ @After
+ public void after() {
+ if (orchestrator != null) {
+ orchestrator.stop();
+ }
+ }
+}