]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-7458 new component org.sonar.api.SonarQubeVersion
authorSimon Brandhof <simon.brandhof@sonarsource.com>
Tue, 15 Mar 2016 09:14:45 +0000 (10:14 +0100)
committerSimon Brandhof <simon.brandhof@sonarsource.com>
Wed, 16 Mar 2016 18:42:59 +0000 (19:42 +0100)
server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel1.java
sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchComponents.java
sonar-core/src/main/java/org/sonar/core/platform/SonarQubeVersionProvider.java [new file with mode: 0644]
sonar-core/src/test/java/org/sonar/core/platform/SonarQubeVersionProviderTest.java [new file with mode: 0644]
sonar-plugin-api/src/main/java/org/sonar/api/SonarQubeVersion.java [new file with mode: 0644]
sonar-plugin-api/src/main/java/org/sonar/api/utils/Version.java
sonar-plugin-api/src/test/java/org/sonar/api/SonarQubeVersionTest.java [new file with mode: 0644]
sonar-plugin-api/src/test/java/org/sonar/api/utils/VersionTest.java

index 39491d3e6b04a571bf16bbd615962fe5231cb0ba..361e35c3558b6449028eb1ab4d4cae062109877a 100644 (file)
@@ -24,6 +24,7 @@ import javax.annotation.Nullable;
 import org.sonar.api.utils.System2;
 import org.sonar.api.utils.internal.TempFolderCleaner;
 import org.sonar.core.config.CorePropertyDefinitions;
+import org.sonar.core.platform.SonarQubeVersionProvider;
 import org.sonar.core.util.UuidFactoryImpl;
 import org.sonar.db.DaoModule;
 import org.sonar.db.DatabaseChecker;
@@ -66,6 +67,7 @@ public class PlatformLevel1 extends PlatformLevel {
     add(platform, properties);
     addExtraRootComponents();
     add(
+      new SonarQubeVersionProvider(),
       ServerSettings.class,
       ServerImpl.class,
       UuidFactoryImpl.INSTANCE,
index aa107887ea44aff67c55f79e92b105b12b23a22d..0a2ec661d7395db5851e01e21aed4ff13dea3970 100644 (file)
@@ -43,6 +43,7 @@ import org.sonar.batch.task.Tasks;
 import org.sonar.core.component.DefaultResourceTypes;
 import org.sonar.core.config.CorePropertyDefinitions;
 import org.sonar.core.issue.tracking.Tracker;
+import org.sonar.core.platform.SonarQubeVersionProvider;
 
 public class BatchComponents {
   private BatchComponents() {
@@ -51,6 +52,7 @@ public class BatchComponents {
 
   public static Collection<Object> all(AnalysisMode analysisMode) {
     List<Object> components = Lists.newArrayList(
+      new SonarQubeVersionProvider(),
       DefaultResourceTypes.get(),
 
       // Tasks
diff --git a/sonar-core/src/main/java/org/sonar/core/platform/SonarQubeVersionProvider.java b/sonar-core/src/main/java/org/sonar/core/platform/SonarQubeVersionProvider.java
new file mode 100644 (file)
index 0000000..a0f54de
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.core.platform;
+
+import com.google.common.io.Resources;
+import java.io.IOException;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import org.picocontainer.injectors.ProviderAdapter;
+import org.sonar.api.SonarQubeVersion;
+import org.sonar.api.utils.System2;
+import org.sonar.api.utils.Version;
+
+public class SonarQubeVersionProvider extends ProviderAdapter {
+
+  private static final String FILE_PATH = "/sq-version.txt";
+
+  private SonarQubeVersion version = null;
+
+  public SonarQubeVersion provide(System2 system) {
+    if (version == null) {
+      try {
+        URL url = system.getResource(FILE_PATH);
+        String versionInFile = Resources.toString(url, StandardCharsets.UTF_8);
+        version = new SonarQubeVersion(Version.parse(versionInFile));
+      } catch (IOException e) {
+        throw new IllegalStateException("Can not load " + FILE_PATH + " from classpath", e);
+      }
+    }
+    return version;
+  }
+}
diff --git a/sonar-core/src/test/java/org/sonar/core/platform/SonarQubeVersionProviderTest.java b/sonar-core/src/test/java/org/sonar/core/platform/SonarQubeVersionProviderTest.java
new file mode 100644 (file)
index 0000000..79d9bad
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.core.platform;
+
+import java.io.File;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.SonarQubeVersion;
+import org.sonar.api.utils.System2;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class SonarQubeVersionProviderTest {
+
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+
+  SonarQubeVersionProvider underTest = new SonarQubeVersionProvider();
+
+  @Test
+  public void create() {
+    SonarQubeVersion version = underTest.provide(System2.INSTANCE);
+    assertThat(version).isNotNull();
+    assertThat(version.get().major()).isGreaterThanOrEqualTo(5);
+  }
+
+  @Test
+  public void cache_version() {
+    SonarQubeVersion version1 = underTest.provide(System2.INSTANCE);
+    SonarQubeVersion version2 = underTest.provide(System2.INSTANCE);
+    assertThat(version1).isSameAs(version2);
+  }
+
+  @Test
+  public void throw_ISE_if_fail_to_load_version() throws Exception {
+    expectedException.expect(IllegalStateException.class);
+    expectedException.expectMessage("Can not load /sq-version.txt from classpath");
+
+    System2 system = mock(System2.class);
+    when(system.getResource(anyString())).thenReturn(new File("target/unknown").toURL());
+    underTest.provide(system);
+  }
+}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/SonarQubeVersion.java b/sonar-plugin-api/src/main/java/org/sonar/api/SonarQubeVersion.java
new file mode 100644 (file)
index 0000000..5d76568
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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;
+
+import javax.annotation.concurrent.Immutable;
+import org.sonar.api.batch.BatchSide;
+import org.sonar.api.server.ServerSide;
+import org.sonar.api.utils.Version;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * Version of SonarQube at runtime. This component can be injected as a dependency
+ * of plugin extensions. The main usage for a plugin is to benefit from new APIs
+ * while keeping backward-compatibility with previous versions of SonarQube.
+
+ * Example: a plugin needs to use an API introduced in version 5.6 ({@code AnApi} in the following
+ * snippet) and still requires to support version 5.5 at runtime.
+ * <p></p>
+ * <pre>
+ * // Component provided by sonar-plugin-api
+ * // @since 5.5
+ * public interface AnApi {
+ *   // implicitly since 5.5
+ *   public void foo();
+ *
+ *   // @since 5.6
+ *   public void bar();
+ * }
+ *
+ * // Component provided by plugin
+ * public class MyExtension {
+ *   private final SonarQubeVersion sonarQubeVersion;
+ *   private final AnApi api;
+ *
+ *   public MyExtension(SonarQubeVersion sonarQubeVersion, AnApi api) {
+ *     this.sonarQubeVersion = sonarQubeVersion;
+ *     this.api = api;
+ *   }
+ *
+ *   public void doSomething() {
+ *     // assume that runtime is 5.5+
+ *     api.foo();
+ *
+ *     if (sonarQubeVersion.isGreaterThanOrEqual(SonarQubeVersion.V5_6)) {
+ *       api.bar();
+ *     }
+ *   }
+ * }
+ * </pre>
+ * <p></p>
+ * The minimal supported version of SonarQube is verified at runtime. As plugin is built
+ * with sonar-plugin-api 5.6, we assume that the plugin requires v5.6 or greater at runtime.
+ * For this reason the plugin must default which is the minimal supported version
+ * in the configuration of sonar-packaging-maven-plugin 1.16+:
+ * <p></p>
+ * <pre>
+ * &lt;packaging&gt;sonar-plugin&lt;/packaging&gt;
+ *
+ * &lt;dependencies&gt;
+ *   &lt;dependency&gt;
+ *     &lt;groupId&gt;org.sonarsource.sonarqube&lt;/groupId&gt;
+ *     &lt;artifactId&gt;sonar-plugin-api&lt;/artifactId&gt;
+ *     &lt;version&gt;5.6&lt;/version&gt;
+ *     &lt;scope&gt;provided&lt;/scope&gt;
+ *   &lt;/dependency&gt;
+ * &lt;/dependencies&gt;
+ *
+ * &lt;build&gt;
+ *  &lt;plugins&gt;
+ *    &lt;plugin&gt;
+ *      &lt;groupId&gt;org.sonarsource.sonar-packaging-maven-plugin&lt;/groupId&gt;
+ *      &lt;artifactId&gt;sonar-packaging-maven-plugin&lt;/artifactId&gt;
+ *      &lt;version&gt;1.16&lt;/version&gt;
+ *      &lt;extensions&gt;true&lt;/extensions&gt;
+ *      &lt;configuration&gt;
+ *        &lt;!-- Override the default value 5.6 which is guessed from sonar-plugin-api dependency --&gt;
+ *        &lt;sonarQubeMinVersion&gt;5.5&lt;/sonarQubeMinVersion&gt;
+ *      &lt;/configuration&gt;
+ *    &lt;/plugin&gt;
+ *  &lt;/plugins&gt;
+ * &lt;/build&gt;
+ * </pre>
+ *
+ *
+ * @since 5.5
+ */
+@BatchSide
+@ServerSide
+@Immutable
+public class SonarQubeVersion {
+
+  /**
+   * Constant for version 5.5
+   */
+  public static final Version V5_5 = Version.create(5, 5);
+
+  /**
+   * Constant for version 5.6
+   */
+  public static final Version V5_6 = Version.create(5, 6);
+
+  private final Version version;
+
+  public SonarQubeVersion(Version version) {
+    requireNonNull(version);
+    this.version = version;
+  }
+
+  public Version get() {
+    return this.version;
+  }
+
+  public boolean isGreaterThanOrEqual(Version than) {
+    return this.version.compareTo(than) >= 0;
+  }
+}
index d1dc9b5dbebb7bc8cd24a05de4671e8292b40dc1..f009dc61756ce78c807f3b1e7d589381df98571a 100644 (file)
@@ -24,12 +24,25 @@ import java.util.List;
 import javax.annotation.concurrent.Immutable;
 
 import static java.lang.Integer.parseInt;
+import static java.util.Objects.requireNonNull;
 import static org.apache.commons.lang.StringUtils.substringAfter;
 import static org.apache.commons.lang.StringUtils.substringBefore;
 import static org.apache.commons.lang.StringUtils.trimToEmpty;
 
 /**
- * TODO document equals/comparison without qualifier
+ * Version composed of 3 integer-sequences (major, minor and patch fields) and optionally a qualifier.
+ * <p></p>
+ * Examples: 1.0, 1.0.0, 1.2.3, 1.2-beta1, 1.2.1-beta-1
+ * <p></p>
+ * <h3>IMPORTANT NOTE</h3>
+ * Qualifier is ignored when comparing objects (methods {@link #equals(Object)}, {@link #hashCode()}
+ * and {@link #compareTo(Version)}).
+ * <p></p>
+ * <pre>
+ *   assertThat(Version.parse("1.2")).isEqualTo(Version.parse("1.2-beta1"));
+ *   assertThat(Version.parse("1.2").compareTo(Version.parse("1.2-beta1"))).isZero();
+ * </pre>
+ *
  * @since 5.5
  */
 @Immutable
@@ -45,6 +58,7 @@ public class Version implements Comparable<Version> {
   private final String qualifier;
 
   private Version(int major, int minor, int patch, String qualifier) {
+    requireNonNull(qualifier, "Version qualifier must not be null");
     this.major = major;
     this.minor = minor;
     this.patch = patch;
@@ -64,12 +78,27 @@ public class Version implements Comparable<Version> {
   }
 
   /**
-   * @return non-null suffix
+   * @return non-null suffix. Empty if absent, else the suffix without the first character "-"
    */
   public String qualifier() {
     return qualifier;
   }
 
+  /**
+   * Convert a {@link String} to a Version. Supported formats:
+   * <ul>
+   *   <li>1</li>
+   *   <li>1.2</li>
+   *   <li>1.2.3</li>
+   *   <li>1-beta-1</li>
+   *   <li>1.2-beta-1</li>
+   *   <li>1.2.3-beta-1</li>
+   * </ul>
+   * Note that the optional qualifier is the part after the first "-".
+   *
+   * @throws IllegalArgumentException if parameter is badly formatted, for example
+   * if it defines 4 integer-sequences.
+   */
   public static Version parse(String text) {
     String s = trimToEmpty(text);
     String qualifier = substringAfter(s, QUALIFIER_SEPARATOR);
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/SonarQubeVersionTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/SonarQubeVersionTest.java
new file mode 100644 (file)
index 0000000..0cc786c
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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;
+
+import org.junit.Test;
+import org.sonar.api.utils.Version;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class SonarQubeVersionTest {
+
+  @Test
+  public void isGte() {
+    Version version = Version.parse("1.2.3");
+    SonarQubeVersion qubeVersion = new SonarQubeVersion(version);
+    assertThat(qubeVersion.get()).isEqualTo(version);
+    assertThat(qubeVersion.isGreaterThanOrEqual(version)).isTrue();
+    assertThat(qubeVersion.isGreaterThanOrEqual(Version.parse("1.1"))).isTrue();
+    assertThat(qubeVersion.isGreaterThanOrEqual(Version.parse("1.3"))).isFalse();
+  }
+}
index ed765062c20e970aeb560b794b851fcc64367a74..a702c852fd51d4f981c4cf8a06de8fd52c98e8d5 100644 (file)
@@ -57,6 +57,7 @@ public class VersionTest {
     assertThat(one).isEqualTo(parse("1.0"));
     assertThat(one).isEqualTo(parse("1.0.0"));
     assertThat(one).isNotEqualTo(parse("1.2.3"));
+    assertThat(one).isNotEqualTo("1");
 
     assertThat(parse("1.2.3")).isEqualTo(parse("1.2.3"));
     assertThat(parse("1.2.3")).isNotEqualTo(parse("1.2.4"));
@@ -98,8 +99,18 @@ public class VersionTest {
     assertThat(parse("1.2.3-b1").toString()).isEqualTo("1.2.3-b1");
   }
 
+  @Test
+  public void test_create() {
+    assertVersion(Version.create(1, 2), 1, 2, 0, "");
+    assertVersion(Version.create(1, 2, 3), 1, 2, 3, "");
+    assertVersion(Version.create(1, 2, 0, ""), 1, 2, 0, "");
+    assertVersion(Version.create(1, 2, 3, "build1"), 1, 2, 3, "build1");
+    assertThat(Version.create(1, 2, 3, "build1").toString()).isEqualTo("1.2.3-build1");
+
+  }
+
   private static void assertVersion(Version version,
-    int expectedMajor, int expectedMinor, int expectedPatch, String expectedQualifier) {
+                                    int expectedMajor, int expectedMinor, int expectedPatch, String expectedQualifier) {
     assertThat(version.major()).isEqualTo(expectedMajor);
     assertThat(version.minor()).isEqualTo(expectedMinor);
     assertThat(version.patch()).isEqualTo(expectedPatch);