]> source.dussan.org Git - sonarqube.git/commitdiff
Add Java API Plugin.Context#getBootConfiguration()
authorSimon Brandhof <simon.brandhof@sonarsource.com>
Mon, 5 Feb 2018 13:48:50 +0000 (14:48 +0100)
committerJanos Gyerik <janos.gyerik@sonarsource.com>
Tue, 6 Feb 2018 08:13:51 +0000 (09:13 +0100)
That allows plugins to check configuration when providing the list
of extensions.

plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/XooPluginTest.java
server/sonar-server/src/main/java/org/sonar/server/plugins/ServerExtensionInstaller.java
sonar-plugin-api/src/main/java/org/sonar/api/Plugin.java
sonar-plugin-api/src/main/java/org/sonar/api/internal/PluginContextImpl.java [new file with mode: 0644]
sonar-plugin-api/src/test/java/org/sonar/api/PluginTest.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ExtensionInstaller.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/ExtensionInstallerTest.java

index e9703dc34de055c15491aaaceff1c86195c6190a..fa1cb855b2bb601ea392ee0999a4383b28525456 100644 (file)
@@ -23,6 +23,7 @@ import org.junit.Test;
 import org.sonar.api.Plugin;
 import org.sonar.api.SonarQubeSide;
 import org.sonar.api.SonarRuntime;
+import org.sonar.api.internal.PluginContextImpl;
 import org.sonar.api.internal.SonarRuntimeImpl;
 import org.sonar.api.utils.Version;
 import org.sonar.xoo.lang.CpdTokenizerSensor;
@@ -34,7 +35,7 @@ public class XooPluginTest {
   @Test
   public void provide_extensions_for_5_4() {
     SonarRuntime runtime = SonarRuntimeImpl.forSonarLint(Version.parse("5.4"));
-    Plugin.Context context = new Plugin.Context(runtime);
+    Plugin.Context context = new PluginContextImpl.Builder().setSonarRuntime(runtime).build();
     new XooPlugin().define(context);
     assertThat(context.getExtensions()).hasSize(46).doesNotContain(CpdTokenizerSensor.class);
   }
@@ -42,7 +43,7 @@ public class XooPluginTest {
   @Test
   public void provide_extensions_for_5_5() {
     SonarRuntime runtime = SonarRuntimeImpl.forSonarQube(Version.parse("5.5"), SonarQubeSide.SCANNER);
-    Plugin.Context context = new Plugin.Context(runtime);
+    Plugin.Context context = new PluginContextImpl.Builder().setSonarRuntime(runtime).build();
     new XooPlugin().define(context);
     assertThat(context.getExtensions()).hasSize(49).contains(CpdTokenizerSensor.class);
   }
@@ -50,7 +51,7 @@ public class XooPluginTest {
   @Test
   public void provide_extensions_for_6_6() {
     SonarRuntime runtime = SonarRuntimeImpl.forSonarQube(Version.parse("6.6"), SonarQubeSide.SCANNER);
-    Plugin.Context context = new Plugin.Context(runtime);
+    Plugin.Context context = new PluginContextImpl.Builder().setSonarRuntime(runtime).build();
     new XooPlugin().define(context);
     assertThat(context.getExtensions()).hasSize(50).contains(CpdTokenizerSensor.class);
   }
index f584c2eb3b8d1bb66fd435897cc96abda67ed65c..f6fe4d1dadd2dd2092841ed9c1b3a47c27722b0b 100644 (file)
@@ -30,6 +30,8 @@ import javax.annotation.Nullable;
 import org.sonar.api.ExtensionProvider;
 import org.sonar.api.Plugin;
 import org.sonar.api.SonarRuntime;
+import org.sonar.api.config.Configuration;
+import org.sonar.api.internal.PluginContextImpl;
 import org.sonar.api.utils.AnnotationUtils;
 import org.sonar.core.platform.ComponentContainer;
 import org.sonar.core.platform.PluginInfo;
@@ -74,7 +76,10 @@ public abstract class ServerExtensionInstaller {
         Plugin plugin = pluginRepository.getPluginInstance(pluginKey);
         container.addExtension(pluginInfo, plugin);
 
-        Plugin.Context context = new Plugin.Context(sonarRuntime);
+        Plugin.Context context = new PluginContextImpl.Builder()
+          .setSonarRuntime(sonarRuntime)
+          .setBootConfiguration(container.getComponentByType(Configuration.class))
+          .build();
         plugin.define(context);
         for (Object extension : context.getExtensions()) {
           if (installExtension(container, pluginInfo, extension, true) != null) {
index 9dd31141f1ead4a83665f908826daeeff2d0301b..b52e628f66d1abfbed15607baae24d13da5a6e87 100644 (file)
@@ -22,6 +22,7 @@ package org.sonar.api;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
+import org.sonar.api.config.Configuration;
 import org.sonar.api.utils.Version;
 
 import static java.util.Arrays.asList;
@@ -67,18 +68,22 @@ import static java.util.Objects.requireNonNull;
  * &lt;/project&gt;
  * </pre>
  *
- * <p>Example of test
+ * <p>Example of Test
  * <pre>
  *{@literal @}Test
  * public void test_plugin_extensions_compatible_with_5_6() {
  *   SonarRuntime runtime = SonarRuntimeImpl.forSonarQube(Version.create(5, 6), SonarQubeSide.SCANNER);
- *   Plugin.Context context = new Plugin.Context(runtime);
- *   new MyPlugin().define(context);
+ *   Plugin.Context context = new PluginContextImpl.Builder().setSonarRuntime(runtime).build();
+ *   MyPlugin underTest = new MyPlugin();
+ *
+ *   underTest.define(context);
+ *
  *   assertThat(context.getExtensions()).hasSize(4);
  * }
  * </pre>
  *
  * @since 5.5
+ * @see org.sonar.api.internal.PluginContextImpl for unit tests
  */
 public interface Plugin {
 
@@ -86,8 +91,13 @@ public interface Plugin {
     private final SonarRuntime sonarRuntime;
     private final List extensions = new ArrayList();
 
+    /**
+     * For unit tests only. It's recommended to use {@link org.sonar.api.internal.PluginContextImpl.Builder}
+     * to create instances of {@link Plugin.Context}.
+     * The configuration returned by {@see #getBootConfiguration()} is empty.
+     */
     public Context(SonarRuntime sonarRuntime) {
-      this.sonarRuntime = sonarRuntime;
+      this.sonarRuntime = requireNonNull(sonarRuntime, "sonarRuntime is null");
     }
 
     /**
@@ -152,6 +162,18 @@ public interface Plugin {
       return extensions;
     }
 
+    /**
+     * The configuration that contains only the few properties required to bootstrap the process, for example:
+     * - conf/sonar.properties and persisted properties on web server and Compute Engine sides. The default values
+     *   defined by plugins are ignored.
+     * - command-line arguments on scanner side. Default values or properties persisted in server are ignored.
+     *
+     * @since 7.1
+     */
+    public Configuration getBootConfiguration() {
+      throw new UnsupportedOperationException("Unit tests should create Plugin.Context with org.sonar.api.internal.PluginContextImpl#Builder");
+    }
+
   }
 
   /**
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/internal/PluginContextImpl.java b/sonar-plugin-api/src/main/java/org/sonar/api/internal/PluginContextImpl.java
new file mode 100644 (file)
index 0000000..b82c4d8
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * 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.api.internal;
+
+import org.sonar.api.Plugin;
+import org.sonar.api.SonarRuntime;
+import org.sonar.api.config.Configuration;
+import org.sonar.api.config.internal.MapSettings;
+
+/**
+ * Implementation of {@link Plugin.Context} that plugins could use in their unit tests.
+ *
+ * Example:
+ *
+ * <pre>
+ *   import org.sonar.api.internal.SonarRuntimeImpl;
+ *   import org.sonar.api.config.internal.MapSettings;
+ *
+ *   ...
+ *
+ *   SonarRuntime runtime = SonarRuntimeImpl.forSonarQube(Version.create(7, 1), SonarQubeSide.SCANNER);
+ *   MapSettings settings = new MapSettings().setProperty("foo", "bar");
+ *   Plugin.Context context = new PluginContextImpl.Builder()
+ *     .setSonarRuntime(runtime)
+ *     .setBootConfiguration(settings.asConfig());
+ *     .build();
+ * </pre>
+ *
+ * @since 7.1
+ */
+public class PluginContextImpl extends Plugin.Context {
+
+  private final Configuration bootConfiguration;
+
+  private PluginContextImpl(Builder builder) {
+    super(builder.sonarRuntime);
+    this.bootConfiguration = builder.bootConfiguration != null ? builder.bootConfiguration : new MapSettings().asConfig();
+  }
+
+  @Override
+  public Configuration getBootConfiguration() {
+    return bootConfiguration;
+  }
+
+  public static class Builder {
+    private SonarRuntime sonarRuntime;
+    private Configuration bootConfiguration;
+
+    /**
+     * Required.
+     * @see SonarRuntimeImpl
+     * @return this
+     */
+    public Builder setSonarRuntime(SonarRuntime r) {
+      this.sonarRuntime = r;
+      return this;
+    }
+
+    /**
+     * If not set, then an empty configuration is used.
+     * @return this
+     */
+    public Builder setBootConfiguration(Configuration c) {
+      this.bootConfiguration = c;
+      return this;
+    }
+
+    public Plugin.Context build() {
+      return new PluginContextImpl(this);
+    }
+  }
+}
index 46bf7131b524fb81c8d76a4f124defbb4750b2ec..f8b280c40e204c8ef3116686db0d9ac9bec6a618 100644 (file)
@@ -21,6 +21,8 @@ package org.sonar.api;
 
 import java.util.Arrays;
 import org.junit.Test;
+import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.internal.PluginContextImpl;
 import org.sonar.api.internal.SonarRuntimeImpl;
 import org.sonar.api.utils.Version;
 
@@ -33,7 +35,11 @@ public class PluginTest {
   @Test
   public void test_context() {
     SonarRuntime runtime = SonarRuntimeImpl.forSonarQube(VERSION_5_6, SonarQubeSide.SERVER);
-    Plugin.Context context = new Plugin.Context(runtime);
+    MapSettings settings = new MapSettings().setProperty("foo", "bar");
+    Plugin.Context context = new PluginContextImpl.Builder()
+      .setSonarRuntime(runtime)
+      .setBootConfiguration(settings.asConfig())
+      .build();
 
     assertThat(context.getSonarQubeVersion()).isEqualTo(VERSION_5_6);
     assertThat(context.getExtensions()).isEmpty();
@@ -46,5 +52,7 @@ public class PluginTest {
 
     context.addExtensions("one", "two", "three", "four");
     assertThat(context.getExtensions()).containsOnly("foo", "bar", "baz", "one", "two", "three", "four");
+
+    assertThat(context.getBootConfiguration().get("foo")).hasValue("bar");
   }
 }
index 07abe2ffe3c7ee0c169276e611ea6324dee858c5..25ccc3bfeb0347d911d43307bb7d2221c58de327 100644 (file)
@@ -24,6 +24,8 @@ import javax.annotation.Nullable;
 import org.sonar.api.ExtensionProvider;
 import org.sonar.api.Plugin;
 import org.sonar.api.SonarRuntime;
+import org.sonar.api.config.Configuration;
+import org.sonar.api.internal.PluginContextImpl;
 import org.sonar.core.platform.ComponentContainer;
 import org.sonar.core.platform.PluginInfo;
 import org.sonar.core.platform.PluginRepository;
@@ -33,11 +35,14 @@ public class ExtensionInstaller {
   private final SonarRuntime sonarRuntime;
   private final PluginRepository pluginRepository;
   private final GlobalAnalysisMode analysisMode;
+  private final Configuration bootConfiguration;
 
-  public ExtensionInstaller(SonarRuntime sonarRuntime, PluginRepository pluginRepository, GlobalAnalysisMode analysisMode) {
+  public ExtensionInstaller(SonarRuntime sonarRuntime, PluginRepository pluginRepository, GlobalAnalysisMode analysisMode,
+    Configuration bootConfiguration) {
     this.sonarRuntime = sonarRuntime;
     this.pluginRepository = pluginRepository;
     this.analysisMode = analysisMode;
+    this.bootConfiguration = bootConfiguration;
   }
 
   public ExtensionInstaller install(ComponentContainer container, ExtensionMatcher matcher) {
@@ -50,7 +55,11 @@ public class ExtensionInstaller {
     // plugin extensions
     for (PluginInfo pluginInfo : pluginRepository.getPluginInfos()) {
       Plugin plugin = pluginRepository.getPluginInstance(pluginInfo.getKey());
-      Plugin.Context context = new Plugin.Context(sonarRuntime);
+      Plugin.Context context = new PluginContextImpl.Builder()
+        .setSonarRuntime(sonarRuntime)
+        .setBootConfiguration(bootConfiguration)
+        .build();
+
       plugin.define(context);
       for (Object extension : context.getExtensions()) {
         doInstall(container, matcher, pluginInfo, extension);
index 08baf0285ad534f813051566391f0c59b5afc857..09cfc454a41d3615f3f869c94aa700d902538787 100644 (file)
@@ -22,12 +22,12 @@ package org.sonar.scanner.bootstrap;
 import java.util.Arrays;
 import java.util.List;
 import org.apache.commons.lang.ClassUtils;
-import org.junit.Before;
 import org.junit.Test;
 import org.sonar.api.BatchExtension;
 import org.sonar.api.ExtensionProvider;
 import org.sonar.api.SonarPlugin;
 import org.sonar.api.SonarRuntime;
+import org.sonar.api.config.internal.MapSettings;
 import org.sonar.core.platform.ComponentContainer;
 import org.sonar.core.platform.PluginInfo;
 
@@ -37,8 +37,9 @@ import static org.mockito.Mockito.when;
 
 public class ExtensionInstallerTest {
 
-  GlobalAnalysisMode mode;
-  ScannerPluginRepository pluginRepository = mock(ScannerPluginRepository.class);
+  private MapSettings settings = new MapSettings();
+  private GlobalAnalysisMode mode = mock(GlobalAnalysisMode.class);
+  private ScannerPluginRepository pluginRepository = mock(ScannerPluginRepository.class);
 
   private static SonarPlugin newPluginInstance(final Object... extensions) {
     return new SonarPlugin() {
@@ -48,18 +49,13 @@ public class ExtensionInstallerTest {
     };
   }
 
-  @Before
-  public void setUp() {
-    mode = mock(GlobalAnalysisMode.class);
-  }
-
   @Test
   public void should_filter_extensions_to_install() {
     when(pluginRepository.getPluginInfos()).thenReturn(Arrays.asList(new PluginInfo("foo")));
     when(pluginRepository.getPluginInstance("foo")).thenReturn(newPluginInstance(Foo.class, Bar.class));
 
     ComponentContainer container = new ComponentContainer();
-    ExtensionInstaller installer = new ExtensionInstaller(mock(SonarRuntime.class), pluginRepository, mock(GlobalAnalysisMode.class));
+    ExtensionInstaller installer = new ExtensionInstaller(mock(SonarRuntime.class), pluginRepository, mode, settings.asConfig());
     installer.install(container, new FooMatcher());
 
     assertThat(container.getComponentByType(Foo.class)).isNotNull();
@@ -71,7 +67,7 @@ public class ExtensionInstallerTest {
     when(pluginRepository.getPluginInfos()).thenReturn(Arrays.asList(new PluginInfo("foo")));
     when(pluginRepository.getPluginInstance("foo")).thenReturn(newPluginInstance(new FooProvider(), new BarProvider()));
     ComponentContainer container = new ComponentContainer();
-    ExtensionInstaller installer = new ExtensionInstaller(mock(SonarRuntime.class), pluginRepository, mock(GlobalAnalysisMode.class));
+    ExtensionInstaller installer = new ExtensionInstaller(mock(SonarRuntime.class), pluginRepository, mode, settings.asConfig());
 
     installer.install(container, new FooMatcher());
 
@@ -84,7 +80,7 @@ public class ExtensionInstallerTest {
     when(pluginRepository.getPluginInfos()).thenReturn(Arrays.asList(new PluginInfo("foo")));
     when(pluginRepository.getPluginInstance("foo")).thenReturn(newPluginInstance(new FooBarProvider()));
     ComponentContainer container = new ComponentContainer();
-    ExtensionInstaller installer = new ExtensionInstaller(mock(SonarRuntime.class), pluginRepository, mock(GlobalAnalysisMode.class));
+    ExtensionInstaller installer = new ExtensionInstaller(mock(SonarRuntime.class), pluginRepository, mode, settings.asConfig());
 
     installer.install(container, new TrueMatcher());