From: Julien HENRY Date: Wed, 8 Oct 2014 15:10:38 +0000 (+0200) Subject: Merge remote-tracking branch 'origin/branch-4.5' X-Git-Tag: 5.0-RC1~761 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=a799ea39801e72ed68595599fd2d1b8a239c69d7;p=sonarqube.git Merge remote-tracking branch 'origin/branch-4.5' --- a799ea39801e72ed68595599fd2d1b8a239c69d7 diff --cc sonar-batch/src/main/java/org/sonar/batch/design/MavenDependenciesSensor.java index 0f2e7157b22,00000000000..67f92b40e55 mode 100644,000000..100644 --- a/sonar-batch/src/main/java/org/sonar/batch/design/MavenDependenciesSensor.java +++ b/sonar-batch/src/main/java/org/sonar/batch/design/MavenDependenciesSensor.java @@@ -1,265 -1,0 +1,265 @@@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube 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.batch.design; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.reflect.TypeToken; +import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.factory.ArtifactFactory; +import org.apache.maven.artifact.metadata.ArtifactMetadataSource; +import org.apache.maven.artifact.repository.ArtifactRepository; +import org.apache.maven.artifact.resolver.ArtifactCollector; +import org.apache.maven.shared.dependency.tree.DependencyNode; +import org.apache.maven.shared.dependency.tree.DependencyTreeBuilder; +import org.apache.maven.shared.dependency.tree.DependencyTreeBuilderException; +import org.apache.maven.shared.dependency.tree.filter.AncestorOrSelfDependencyNodeFilter; +import org.apache.maven.shared.dependency.tree.filter.DependencyNodeFilter; +import org.apache.maven.shared.dependency.tree.filter.StateDependencyNodeFilter; +import org.apache.maven.shared.dependency.tree.traversal.BuildingDependencyNodeVisitor; +import org.apache.maven.shared.dependency.tree.traversal.CollectingDependencyNodeVisitor; +import org.apache.maven.shared.dependency.tree.traversal.DependencyNodeVisitor; +import org.apache.maven.shared.dependency.tree.traversal.FilteringDependencyNodeVisitor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.sonar.api.batch.Sensor; +import org.sonar.api.batch.SensorContext; +import org.sonar.api.batch.SonarIndex; +import org.sonar.api.batch.SupportedEnvironment; +import org.sonar.api.config.Settings; +import org.sonar.api.design.Dependency; +import org.sonar.api.resources.Library; +import org.sonar.api.resources.Project; +import org.sonar.api.resources.Resource; +import org.sonar.api.utils.SonarException; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +@SupportedEnvironment("maven") +public class MavenDependenciesSensor implements Sensor { + + private static final String SONAR_MAVEN_PROJECT_DEPENDENCY = "sonar.maven.projectDependencies"; + + private static final Logger LOG = LoggerFactory.getLogger(MavenDependenciesSensor.class); + + private ArtifactRepository localRepository; + private ArtifactFactory artifactFactory; + private ArtifactMetadataSource artifactMetadataSource; + private ArtifactCollector artifactCollector; + private DependencyTreeBuilder treeBuilder; + private SonarIndex index; + private Settings settings; + + public MavenDependenciesSensor(Settings settings, ArtifactRepository localRepository, ArtifactFactory artifactFactory, ArtifactMetadataSource artifactMetadataSource, + ArtifactCollector artifactCollector, DependencyTreeBuilder treeBuilder, SonarIndex index) { + this.settings = settings; + this.localRepository = localRepository; + this.artifactFactory = artifactFactory; + this.artifactMetadataSource = artifactMetadataSource; + this.artifactCollector = artifactCollector; + this.index = index; + this.treeBuilder = treeBuilder; + } + + /** + * Used with SQ Maven plugin 2.5+ + */ + public MavenDependenciesSensor(Settings settings, SonarIndex index) { + this.settings = settings; + this.index = index; + } + + public boolean shouldExecuteOnProject(Project project) { + return true; + } + + private static class InputDependency { + + private final String key; + + private final String version; + + private String scope; + + List dependencies = new ArrayList(); + + public InputDependency(String key, String version) { + this.key = key; + this.version = version; + } + + public String key() { + return key; + } + + public String version() { + return version; + } + + public String scope() { + return scope; + } + + public InputDependency setScope(String scope) { + this.scope = scope; + return this; + } + + public List dependencies() { + return dependencies; + } + } + + private static class DependencyDeserializer implements JsonDeserializer { + + @Override + public InputDependency deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) { + + JsonObject dep = json.getAsJsonObject(); + String key = dep.get("k").getAsString(); + String version = dep.get("v").getAsString(); + InputDependency result = new InputDependency(key, version); + result.setScope(dep.get("s").getAsString()); + JsonElement subDeps = dep.get("d"); + if (subDeps != null) { + JsonArray arrayOfSubDeps = subDeps.getAsJsonArray(); + for (JsonElement e : arrayOfSubDeps) { + result.dependencies().add(deserialize(e, typeOfT, context)); + } + } + return result; + } + + } + + public void analyse(final Project project, final SensorContext context) { + if (settings.hasKey(SONAR_MAVEN_PROJECT_DEPENDENCY)) { + LOG.debug("Using dependency provided by property " + SONAR_MAVEN_PROJECT_DEPENDENCY); + String depsAsJson = settings.getString(SONAR_MAVEN_PROJECT_DEPENDENCY); + Collection deps; + try { + GsonBuilder gsonBuilder = new GsonBuilder(); + gsonBuilder.registerTypeAdapter(InputDependency.class, new DependencyDeserializer()); + Gson gson = gsonBuilder.create(); + + Type collectionType = new TypeToken>() { + }.getType(); + deps = gson.fromJson(depsAsJson, collectionType); + saveDependencies(project, deps, context); + } catch (Exception e) { + throw new IllegalStateException("Unable to deserialize dependency information: " + depsAsJson, e); + } + } else if (treeBuilder != null) { + computeDependencyTree(project, context); + } + } + + private void computeDependencyTree(final Project project, final SensorContext context) { + LOG.warn("Computation of Maven dependencies by SonarQube is deprecated. Please update the version of SonarQube Maven plugin to 2.5+"); + try { + DependencyNode root = treeBuilder.buildDependencyTree(project.getPom(), localRepository, artifactFactory, artifactMetadataSource, null, artifactCollector); + + DependencyNodeVisitor visitor = new BuildingDependencyNodeVisitor(new DependencyNodeVisitor() { + public boolean visit(DependencyNode node) { + return true; + } + + public boolean endVisit(DependencyNode node) { + if (node.getParent() != null && node.getParent() != node) { - saveDependency(node, context); ++ saveDependency(project, node, context); + } + return true; + } + }); + + // mode verbose OFF : do not show the same lib many times + DependencyNodeFilter filter = StateDependencyNodeFilter.INCLUDED; + + CollectingDependencyNodeVisitor collectingVisitor = new CollectingDependencyNodeVisitor(); + DependencyNodeVisitor firstPassVisitor = new FilteringDependencyNodeVisitor(collectingVisitor, filter); + root.accept(firstPassVisitor); + + DependencyNodeFilter secondPassFilter = new AncestorOrSelfDependencyNodeFilter(collectingVisitor.getNodes()); + visitor = new FilteringDependencyNodeVisitor(visitor, secondPassFilter); + + root.accept(visitor); + + } catch (DependencyTreeBuilderException e) { + throw new SonarException("Can not load the graph of dependencies of the project " + project.getKey(), e); + } + } + + private void saveDependencies(Resource from, Collection deps, SensorContext context) { + for (InputDependency inputDep : deps) { + Resource to = toResource(inputDep, context); + Dependency dependency = new Dependency(from, to); + dependency.setUsage(inputDep.scope()); + dependency.setWeight(1); + context.saveDependency(dependency); + if (!inputDep.dependencies().isEmpty()) { + saveDependencies(to, inputDep.dependencies(), context); + } + } + } + + private Resource toResource(InputDependency dependency, SensorContext context) { + Project project = new Project(dependency.key()); + Resource result = context.getResource(project); + if (result == null || !((Project) result).getAnalysisVersion().equals(dependency.version())) { + Library lib = new Library(project.getKey(), dependency.version()); + context.saveResource(lib); + result = context.getResource(lib); + } + return result; + } + - protected void saveDependency(DependencyNode node, SensorContext context) { - Resource from = (node.getParent().getParent() == null) ? index.getProject() : toResource(node.getParent().getArtifact(), context); - Resource to = toResource(node.getArtifact(), context); ++ protected void saveDependency(final Project project, DependencyNode node, SensorContext context) { ++ Resource from = (node.getParent().getParent() == null) ? index.getProject() : toResource(project, node.getParent().getArtifact(), context); ++ Resource to = toResource(project, node.getArtifact(), context); + Dependency dependency = new Dependency(from, to); + dependency.setUsage(node.getArtifact().getScope()); + dependency.setWeight(1); + context.saveDependency(dependency); + } + - protected static Resource toResource(Artifact artifact, SensorContext context) { - Project project = Project.createFromMavenIds(artifact.getGroupId(), artifact.getArtifactId()); - Resource result = context.getResource(project); ++ protected static Resource toResource(final Project project, Artifact artifact, SensorContext context) { ++ Project depWithBranch = Project.createFromMavenIds(artifact.getGroupId(), artifact.getArtifactId(), project.getBranch()); ++ Resource result = context.getResource(depWithBranch); + if (result == null || !((Project) result).getAnalysisVersion().equals(artifact.getBaseVersion())) { - Library lib = new Library(project.getKey(), artifact.getBaseVersion()); ++ Library lib = Library.createFromMavenIds(artifact.getGroupId(), artifact.getArtifactId(), artifact.getBaseVersion()); + context.saveResource(lib); + result = context.getResource(lib); + } + return result; + } + + @Override + public String toString() { + return "Maven dependencies"; + } +} diff --cc sonar-batch/src/main/java/org/sonar/batch/referential/DefaultProjectReferentialsLoader.java index eeb1853de77,8340c63a681..b86dd4e1cf7 --- a/sonar-batch/src/main/java/org/sonar/batch/referential/DefaultProjectReferentialsLoader.java +++ b/sonar-batch/src/main/java/org/sonar/batch/referential/DefaultProjectReferentialsLoader.java @@@ -19,17 -19,9 +19,19 @@@ */ package org.sonar.batch.referential; +import com.google.common.collect.Maps; + import org.slf4j.Logger; + import org.slf4j.LoggerFactory; +import org.sonar.api.batch.bootstrap.ProjectDefinition; import org.sonar.api.batch.bootstrap.ProjectReactor; +import org.sonar.api.database.DatabaseSession; +import org.sonar.api.database.model.MeasureModel; +import org.sonar.api.database.model.ResourceModel; +import org.sonar.api.database.model.Snapshot; +import org.sonar.api.measures.CoreMetrics; +import org.sonar.api.measures.Metric; +import org.sonar.api.resources.Qualifiers; +import org.sonar.api.utils.KeyValueFormat; import org.sonar.batch.bootstrap.AnalysisMode; import org.sonar.batch.bootstrap.ServerClient; import org.sonar.batch.bootstrap.TaskProperties; @@@ -68,9 -47,10 +72,11 @@@ public class DefaultProjectReferentials @Override public ProjectReferentials load(ProjectReactor reactor, TaskProperties taskProperties) { - String url = BATCH_PROJECT_URL + "?key=" + reactor.getRoot().getKeyWithBranch(); + String projectKey = reactor.getRoot().getKeyWithBranch(); + String url = BATCH_PROJECT_URL + "?key=" + projectKey; if (taskProperties.properties().containsKey(ModuleQProfiles.SONAR_PROFILE_PROP)) { + LOG.warn("Ability to set quality profile from command line using '" + ModuleQProfiles.SONAR_PROFILE_PROP + + "' is deprecated and will be dropped in a future SonarQube version. Please configure quality profile used by your project on SonarQube server."); try { url += "&profile=" + URLEncoder.encode(taskProperties.properties().get(ModuleQProfiles.SONAR_PROFILE_PROP), "UTF-8"); } catch (UnsupportedEncodingException e) { diff --cc sonar-plugin-api/src/main/java/org/sonar/api/resources/Project.java index 65f6dc39d45,64be7f80a54..bc866693f9b --- a/sonar-plugin-api/src/main/java/org/sonar/api/resources/Project.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/resources/Project.java @@@ -24,8 -27,9 +24,10 @@@ import org.apache.commons.lang.builder. import org.apache.maven.project.MavenProject; import org.sonar.api.CoreProperties; import org.sonar.api.component.Component; +import org.sonar.api.config.Settings; + import javax.annotation.Nullable; + import java.util.ArrayList; import java.util.Date; import java.util.List; @@@ -413,8 -457,37 +415,12 @@@ public class Project extends Resource i return pom; } - /** - * @return the project configuration - * @deprecated since 2.12. The component org.sonar.api.config.Settings must be used. - */ - @Deprecated - public Configuration getConfiguration() { - return configuration; - } - - /** - * For internal use only. - */ - public final Project setConfiguration(Configuration configuration) { - this.configuration = configuration; - return this; - } - - /** - * @deprecated since 3.6. Replaced by {@link org.sonar.api.config.Settings}. - */ - @Deprecated - public Object getProperty(String key) { - return configuration != null ? configuration.getProperty(key) : null; - } - public static Project createFromMavenIds(String groupId, String artifactId) { - return new Project(String.format(MAVEN_KEY_FORMAT, groupId, artifactId)); + return createFromMavenIds(groupId, artifactId, null); + } + + public static Project createFromMavenIds(String groupId, String artifactId, @Nullable String branch) { + return new Project(String.format(MAVEN_KEY_FORMAT, groupId, artifactId), branch, ""); } @Override