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