001/* 002 * SonarQube, open source software quality management tool. 003 * Copyright (C) 2008-2013 SonarSource 004 * mailto:contact AT sonarsource DOT com 005 * 006 * SonarQube is free software; you can redistribute it and/or 007 * modify it under the terms of the GNU Lesser General Public 008 * License as published by the Free Software Foundation; either 009 * version 3 of the License, or (at your option) any later version. 010 * 011 * SonarQube is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 * Lesser General Public License for more details. 015 * 016 * You should have received a copy of the GNU Lesser General Public License 017 * along with this program; if not, write to the Free Software Foundation, 018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 019 */ 020package org.sonar.maven; 021 022import org.apache.maven.artifact.factory.ArtifactFactory; 023import org.apache.maven.artifact.metadata.ArtifactMetadataSource; 024import org.apache.maven.artifact.repository.ArtifactRepository; 025import org.apache.maven.artifact.resolver.ArtifactCollector; 026import org.apache.maven.artifact.versioning.ArtifactVersion; 027import org.apache.maven.execution.MavenSession; 028import org.apache.maven.execution.RuntimeInformation; 029import org.apache.maven.lifecycle.LifecycleExecutor; 030import org.apache.maven.plugin.AbstractMojo; 031import org.apache.maven.plugin.MojoExecutionException; 032import org.apache.maven.plugin.MojoFailureException; 033import org.apache.maven.project.MavenProject; 034import org.apache.maven.project.MavenProjectBuilder; 035import org.apache.maven.shared.dependency.tree.DependencyTreeBuilder; 036import org.sonar.runner.api.EmbeddedRunner; 037import org.sonar.runner.api.RunnerProperties; 038import org.sonar.runner.api.ScanProperties; 039 040import java.io.File; 041import java.io.IOException; 042 043/** 044 * @goal sonar 045 * @aggregator 046 * @requiresDependencyResolution test 047 */ 048public final class SonarMojo extends AbstractMojo { 049 050 /** 051 * @parameter expression="${session}" 052 * @required 053 * @readonly 054 */ 055 private MavenSession session; 056 057 /** 058 * @parameter expression="${project}" 059 * @required 060 * @readonly 061 */ 062 private MavenProject project; 063 064 /** 065 * @component 066 * @required 067 */ 068 private LifecycleExecutor lifecycleExecutor; 069 070 /** 071 * The artifact factory to use. 072 * 073 * @component 074 * @required 075 * @readonly 076 */ 077 private ArtifactFactory artifactFactory; 078 079 /** 080 * The artifact repository to use. 081 * 082 * @parameter expression="${localRepository}" 083 * @required 084 * @readonly 085 */ 086 private ArtifactRepository localRepository; 087 088 /** 089 * The artifact metadata source to use. 090 * 091 * @component 092 * @required 093 * @readonly 094 */ 095 private ArtifactMetadataSource artifactMetadataSource; 096 097 /** 098 * The artifact collector to use. 099 * 100 * @component 101 * @required 102 * @readonly 103 */ 104 private ArtifactCollector artifactCollector; 105 106 /** 107 * The dependency tree builder to use. 108 * 109 * @component 110 * @required 111 * @readonly 112 */ 113 private DependencyTreeBuilder dependencyTreeBuilder; 114 115 /** 116 * @component 117 * @required 118 * @readonly 119 */ 120 private MavenProjectBuilder projectBuilder; 121 122 /** 123 * @component 124 * @required 125 * @readonly 126 * @VisibleForTesting 127 */ 128 RuntimeInformation runtimeInformation; 129 130 public void execute() throws MojoExecutionException, MojoFailureException { 131 ArtifactVersion mavenVersion = getMavenVersion(); 132 if (mavenVersion.getMajorVersion() == 2 && mavenVersion.getMinorVersion() < 2) { 133 throw new MojoExecutionException("Please use at least Maven 2.2.x to perform SonarQube analysis (current version is " + mavenVersion.toString() + ")"); 134 } 135 136 EmbeddedRunner runner = EmbeddedRunner.create() 137 .setApp("Maven", mavenVersion.toString()) 138 .addProperties(session.getExecutionProperties()) 139 .addProperties(project.getModel().getProperties()) 140 // Add user properties (ie command line arguments -Dsonar.xxx=yyyy) in last position to override all other 141 .addProperties(session.getUserProperties()); 142 String encoding = getSourceEncoding(project); 143 if (encoding != null) { 144 runner.setProperty(ScanProperties.PROJECT_SOURCE_ENCODING, encoding); 145 } 146 runner 147 .setProperty(ScanProperties.PROJECT_KEY, getSonarKey(project)) 148 .setProperty(RunnerProperties.WORK_DIR, getSonarWorkDir(project).getAbsolutePath()) 149 .setProperty(ScanProperties.PROJECT_BASEDIR, project.getBasedir().getAbsolutePath()) 150 .setProperty(ScanProperties.PROJECT_VERSION, toString(project.getVersion())) 151 .setProperty(ScanProperties.PROJECT_NAME, toString(project.getName())) 152 .setProperty(ScanProperties.PROJECT_DESCRIPTION, toString(project.getDescription())) 153 .setProperty(ScanProperties.PROJECT_SOURCE_DIRS, "."); 154 // Exclude log implementation to not conflict with Maven 3.1 logging impl 155 runner.mask("org.slf4j.LoggerFactory") 156 // Include slf4j Logger that is exposed by some Sonar components 157 .unmask("org.slf4j.Logger") 158 .unmask("org.slf4j.ILoggerFactory") 159 // Exclude other slf4j classes 160 // .unmask("org.slf4j.impl.") 161 .mask("org.slf4j.") 162 // Exclude logback 163 .mask("ch.qos.logback.") 164 .mask("org.sonar.") 165 // Include everything else 166 .unmask(""); 167 runner.addExtensions(session, getLog(), lifecycleExecutor, artifactFactory, localRepository, artifactMetadataSource, artifactCollector, 168 dependencyTreeBuilder, projectBuilder); 169 if (getLog().isDebugEnabled()) { 170 runner.setProperty("sonar.verbose", "true"); 171 } 172 runner.execute(); 173 } 174 175 private ArtifactVersion getMavenVersion() { 176 return runtimeInformation.getApplicationVersion(); 177 } 178 179 public static String toString(Object obj) { 180 return obj == null ? "" : obj.toString(); 181 } 182 183 public static String getSourceEncoding(MavenProject pom) { 184 return pom.getProperties().getProperty("project.build.sourceEncoding"); 185 } 186 187 public static String getSonarKey(MavenProject pom) { 188 return new StringBuilder().append(pom.getGroupId()).append(":").append(pom.getArtifactId()).toString(); 189 } 190 191 public static File getSonarWorkDir(MavenProject pom) { 192 return new File(getBuildDir(pom), "sonar"); 193 } 194 195 private static File getBuildDir(MavenProject pom) { 196 return resolvePath(pom.getBuild().getDirectory(), pom.getBasedir()); 197 } 198 199 static File resolvePath(String path, File basedir) { 200 if (path != null) { 201 File file = new File(path); 202 if (!file.isAbsolute()) { 203 try { 204 file = new File(basedir, path).getCanonicalFile(); 205 } catch (IOException e) { 206 throw new IllegalStateException("Unable to resolve path '" + path + "'", e); 207 } 208 } 209 return file; 210 } 211 return null; 212 } 213}