001 /*
002 * SonarQube, open source software quality management tool.
003 * Copyright (C) 2008-2014 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 */
020 package org.sonar.maven;
021
022 import org.apache.maven.artifact.factory.ArtifactFactory;
023 import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
024 import org.apache.maven.artifact.repository.ArtifactRepository;
025 import org.apache.maven.artifact.resolver.ArtifactCollector;
026 import org.apache.maven.artifact.versioning.ArtifactVersion;
027 import org.apache.maven.execution.MavenSession;
028 import org.apache.maven.execution.RuntimeInformation;
029 import org.apache.maven.lifecycle.LifecycleExecutor;
030 import org.apache.maven.plugin.AbstractMojo;
031 import org.apache.maven.plugin.MojoExecutionException;
032 import org.apache.maven.project.MavenProject;
033 import org.apache.maven.project.MavenProjectBuilder;
034 import org.apache.maven.shared.dependency.tree.DependencyTreeBuilder;
035 import org.sonar.runner.api.EmbeddedRunner;
036 import org.sonar.runner.api.RunnerProperties;
037 import org.sonar.runner.api.ScanProperties;
038
039 import java.io.File;
040 import java.io.IOException;
041
042 /**
043 * @goal sonar
044 * @aggregator
045 * @requiresDependencyResolution test
046 */
047 public final class SonarMojo extends AbstractMojo {
048
049 /**
050 * @parameter property="session"
051 * @required
052 * @readonly
053 */
054 private MavenSession session;
055
056 /**
057 * @parameter property="project"
058 * @required
059 * @readonly
060 */
061 private MavenProject project;
062
063 /**
064 * @component
065 * @required
066 */
067 private LifecycleExecutor lifecycleExecutor;
068
069 /**
070 * The artifact factory to use.
071 *
072 * @component
073 * @required
074 * @readonly
075 */
076 private ArtifactFactory artifactFactory;
077
078 /**
079 * The artifact repository to use.
080 *
081 * @parameter property="localRepository"
082 * @required
083 * @readonly
084 */
085 private ArtifactRepository localRepository;
086
087 /**
088 * The artifact metadata source to use.
089 *
090 * @component
091 * @required
092 * @readonly
093 */
094 private ArtifactMetadataSource artifactMetadataSource;
095
096 /**
097 * The artifact collector to use.
098 *
099 * @component
100 * @required
101 * @readonly
102 */
103 private ArtifactCollector artifactCollector;
104
105 /**
106 * The dependency tree builder to use.
107 *
108 * @component
109 * @required
110 * @readonly
111 */
112 private DependencyTreeBuilder dependencyTreeBuilder;
113
114 /**
115 * @component
116 * @required
117 * @readonly
118 */
119 private MavenProjectBuilder projectBuilder;
120
121 /**
122 * @component
123 * @required
124 * @readonly
125 * @VisibleForTesting
126 */
127 RuntimeInformation runtimeInformation;
128
129 @Override
130 public void execute() throws MojoExecutionException {
131 ArtifactVersion mavenVersion = getMavenVersion();
132 if (mavenVersion.getMajorVersion() == 2 && mavenVersion.getMinorVersion() < 2) {
133 ExceptionHandling.handle("Please use at least Maven 2.2.x to perform SonarQube analysis (current version is " + mavenVersion.toString() + ")", getLog());
134 }
135
136 try {
137 EmbeddedRunner runner = EmbeddedRunner.create()
138 .setApp("Maven", mavenVersion.toString())
139 .addProperties(session.getExecutionProperties())
140 .addProperties(project.getModel().getProperties())
141 // Add user properties (ie command line arguments -Dsonar.xxx=yyyy) in last position to override all other
142 .addProperties(session.getUserProperties());
143 String encoding = getSourceEncoding(project);
144 if (encoding != null) {
145 runner.setProperty(ScanProperties.PROJECT_SOURCE_ENCODING, encoding);
146 }
147 runner
148 .setProperty(ScanProperties.PROJECT_KEY, getSonarKey(project))
149 .setProperty(RunnerProperties.WORK_DIR, getSonarWorkDir(project).getAbsolutePath())
150 .setProperty(ScanProperties.PROJECT_BASEDIR, project.getBasedir().getAbsolutePath())
151 .setProperty(ScanProperties.PROJECT_VERSION, toString(project.getVersion()))
152 .setProperty(ScanProperties.PROJECT_NAME, toString(project.getName()))
153 .setProperty(ScanProperties.PROJECT_DESCRIPTION, toString(project.getDescription()))
154 .setProperty(ScanProperties.PROJECT_SOURCE_DIRS, ".");
155 // Exclude log implementation to not conflict with Maven 3.1 logging impl
156 runner.mask("org.slf4j.LoggerFactory")
157 // Include slf4j Logger that is exposed by some Sonar components
158 .unmask("org.slf4j.Logger")
159 .unmask("org.slf4j.ILoggerFactory")
160 // Exclude other slf4j classes
161 // .unmask("org.slf4j.impl.")
162 .mask("org.slf4j.")
163 // Exclude logback
164 .mask("ch.qos.logback.")
165 .mask("org.sonar.")
166 // Include everything else
167 .unmask("");
168 runner.addExtensions(session, getLog(), lifecycleExecutor, artifactFactory, localRepository, artifactMetadataSource, artifactCollector,
169 dependencyTreeBuilder, projectBuilder);
170 if (getLog().isDebugEnabled()) {
171 runner.setProperty("sonar.verbose", "true");
172 }
173 runner.execute();
174 } catch (Exception e) {
175 throw ExceptionHandling.handle(e, getLog());
176 }
177 }
178
179 private ArtifactVersion getMavenVersion() {
180 return runtimeInformation.getApplicationVersion();
181 }
182
183 public static String toString(Object obj) {
184 return obj == null ? "" : obj.toString();
185 }
186
187 public static String getSourceEncoding(MavenProject pom) {
188 return pom.getProperties().getProperty("project.build.sourceEncoding");
189 }
190
191 public static String getSonarKey(MavenProject pom) {
192 return new StringBuilder().append(pom.getGroupId()).append(":").append(pom.getArtifactId()).toString();
193 }
194
195 public static File getSonarWorkDir(MavenProject pom) {
196 return new File(getBuildDir(pom), "sonar");
197 }
198
199 private static File getBuildDir(MavenProject pom) {
200 return resolvePath(pom.getBuild().getDirectory(), pom.getBasedir());
201 }
202
203 static File resolvePath(String path, File basedir) {
204 if (path != null) {
205 File file = new File(path);
206 if (!file.isAbsolute()) {
207 try {
208 file = new File(basedir, path).getCanonicalFile();
209 } catch (IOException e) {
210 throw new IllegalStateException("Unable to resolve path '" + path + "'", e);
211 }
212 }
213 return file;
214 }
215 return null;
216 }
217
218 }