From 824a1c63f89e7e611f15d007faf55f2e0d0a8558 Mon Sep 17 00:00:00 2001 From: Simon Brandhof Date: Tue, 15 Mar 2016 10:14:45 +0100 Subject: [PATCH] SONAR-7458 new component org.sonar.api.SonarQubeVersion --- .../platformlevel/PlatformLevel1.java | 2 + .../batch/bootstrap/BatchComponents.java | 2 + .../platform/SonarQubeVersionProvider.java | 49 +++++++ .../SonarQubeVersionProviderTest.java | 64 +++++++++ .../java/org/sonar/api/SonarQubeVersion.java | 134 ++++++++++++++++++ .../java/org/sonar/api/utils/Version.java | 33 ++++- .../org/sonar/api/SonarQubeVersionTest.java | 38 +++++ .../java/org/sonar/api/utils/VersionTest.java | 13 +- 8 files changed, 332 insertions(+), 3 deletions(-) create mode 100644 sonar-core/src/main/java/org/sonar/core/platform/SonarQubeVersionProvider.java create mode 100644 sonar-core/src/test/java/org/sonar/core/platform/SonarQubeVersionProviderTest.java create mode 100644 sonar-plugin-api/src/main/java/org/sonar/api/SonarQubeVersion.java create mode 100644 sonar-plugin-api/src/test/java/org/sonar/api/SonarQubeVersionTest.java diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel1.java b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel1.java index 39491d3e6b0..361e35c3558 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel1.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel1.java @@ -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, diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchComponents.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchComponents.java index aa107887ea4..0a2ec661d73 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchComponents.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchComponents.java @@ -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 all(AnalysisMode analysisMode) { List 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 index 00000000000..a0f54de7490 --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/platform/SonarQubeVersionProvider.java @@ -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 index 00000000000..79d9baddc27 --- /dev/null +++ b/sonar-core/src/test/java/org/sonar/core/platform/SonarQubeVersionProviderTest.java @@ -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 index 00000000000..5d76568ad17 --- /dev/null +++ b/sonar-plugin-api/src/main/java/org/sonar/api/SonarQubeVersion.java @@ -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. + *

+ *
+ * // 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();
+ *     }
+ *   }
+ * }
+ * 
+ *

+ * 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+: + *

+ *
+ * <packaging>sonar-plugin</packaging>
+ *
+ * <dependencies>
+ *   <dependency>
+ *     <groupId>org.sonarsource.sonarqube</groupId>
+ *     <artifactId>sonar-plugin-api</artifactId>
+ *     <version>5.6</version>
+ *     <scope>provided</scope>
+ *   </dependency>
+ * </dependencies>
+ *
+ * <build>
+ *  <plugins>
+ *    <plugin>
+ *      <groupId>org.sonarsource.sonar-packaging-maven-plugin</groupId>
+ *      <artifactId>sonar-packaging-maven-plugin</artifactId>
+ *      <version>1.16</version>
+ *      <extensions>true</extensions>
+ *      <configuration>
+ *        <!-- Override the default value 5.6 which is guessed from sonar-plugin-api dependency -->
+ *        <sonarQubeMinVersion>5.5</sonarQubeMinVersion>
+ *      </configuration>
+ *    </plugin>
+ *  </plugins>
+ * </build>
+ * 
+ * + * + * @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; + } +} diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/utils/Version.java b/sonar-plugin-api/src/main/java/org/sonar/api/utils/Version.java index d1dc9b5dbeb..f009dc61756 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/utils/Version.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/utils/Version.java @@ -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. + *

+ * Examples: 1.0, 1.0.0, 1.2.3, 1.2-beta1, 1.2.1-beta-1 + *

+ *

IMPORTANT NOTE

+ * Qualifier is ignored when comparing objects (methods {@link #equals(Object)}, {@link #hashCode()} + * and {@link #compareTo(Version)}). + *

+ *
+ *   assertThat(Version.parse("1.2")).isEqualTo(Version.parse("1.2-beta1"));
+ *   assertThat(Version.parse("1.2").compareTo(Version.parse("1.2-beta1"))).isZero();
+ * 
+ * * @since 5.5 */ @Immutable @@ -45,6 +58,7 @@ public class Version implements Comparable { 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 { } /** - * @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: + *
    + *
  • 1
  • + *
  • 1.2
  • + *
  • 1.2.3
  • + *
  • 1-beta-1
  • + *
  • 1.2-beta-1
  • + *
  • 1.2.3-beta-1
  • + *
+ * 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 index 00000000000..0cc786c3ba4 --- /dev/null +++ b/sonar-plugin-api/src/test/java/org/sonar/api/SonarQubeVersionTest.java @@ -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(); + } +} diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/utils/VersionTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/utils/VersionTest.java index ed765062c20..a702c852fd5 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/utils/VersionTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/utils/VersionTest.java @@ -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); -- 2.39.5