All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.sonar.maven.SonarMojo Maven / Gradle / Ivy

/*
 * Sonar, open source software quality management tool.
 * Copyright (C) 2009 SonarSource SA
 * mailto:contact AT sonarsource DOT com
 *
 * Sonar 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.
 *
 * Sonar 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 Sonar; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
 */
package org.sonar.maven;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate;
import org.apache.commons.lang.StringUtils;
import org.apache.maven.cli.ConsoleDownloadMonitor;
import org.apache.maven.embedder.MavenEmbedderException;
import org.apache.maven.embedder.PlexusLoggerAdapter;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.monitor.event.DefaultEventMonitor;
import org.apache.maven.monitor.event.EventMonitor;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.project.MavenProject;
import org.apache.maven.settings.Settings;
import org.sonar.commons.ServerHttpClient;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.*;

/**
 * Main sonar bootstrap plugin
 *
 * @goal sonar
 * @aggregator
 */
public class SonarMojo extends AbstractMojo {

  public final static String ADDITIONAL_GOALS_PROPERTY = "sonar.bootstrap.additional.goals";

  /**
   * The plugin version
   *
   * @parameter expression="${plugin.version}"
   * @readonly
   */
  private String pluginVersion;

  /**
   * The current maven session
   *
   * @parameter expression="${session}"
   * @readonly
   */
  private MavenSession session;

  /**
   * The projects in the reactor.
   *
   * @parameter expression="${reactorProjects}"
   * @readonly
   */
  private List reactorProjects;

  /**
   * The maven settings this project is using
   *
   * @parameter expression="${settings}"
   * @required
   * @readonly
   */
  private Settings settings;

  /**
   * Sonar host URL
   *
   * @parameter expression="${sonar.host.url}" default-value="http://localhost:9000" alias="sonar.host.url"
   */
  private String sonarHostURL;


  /**
   * Modules from the project to skip
   *
   * @parameter expression="${sonar.skippedModules}" alias="sonar.skippedModules"
   */
  private String skippedModules;

  /**
   * For internal use only. Used for benchmarks.
   *
   * @parameter expression="${sonar.collectOnly}" default-value="false" alias="sonar.collectOnly"
   */
  private Boolean collectOnly = Boolean.FALSE;

  public void execute() throws MojoExecutionException {
    ServerHttpClient server = new ServerHttpClient(sonarHostURL);
    server.checkUp();

    String sonarServerVersion = getServerVersion(server);

    reactorProjects = getReactorProjects(reactorProjects);
    fixProjectsReportingDir(reactorProjects);
    executeGoals(sonarServerVersion);
  }

  protected List getReactorProjects(List projects) throws MojoExecutionException {
    if (StringUtils.isEmpty(skippedModules)) {
      return new ArrayList(projects);
    }
    getLog().info("Filtering projects: " + skippedModules);
    final List skippedNames = new ArrayList(Arrays.asList(StringUtils.split(skippedModules, ',')));
    Collection skipped = (Collection) CollectionUtils.select(projects, new Predicate() {
      public boolean evaluate(Object o) {
        MavenProject p = (MavenProject) o;
        boolean match = skippedNames.contains(p.getArtifactId());
        if (match) {
          skippedNames.remove(p.getArtifactId());
        }
        return match;
      }
    });
    if (!skippedNames.isEmpty()) {
      getLog().warn("Unable to filter the following projects: " + skippedNames);
    }

    List filteredProjects = new ArrayList(projects);
    MavenProjectHierarchy root = MavenProjectHierarchy.getProjectHierarchy(projects);
    for (MavenProject toSkip : skipped) {
      MavenProjectHierarchy toSkipHierarchy = root.getModule(toSkip);
      Collection childrens = toSkipHierarchy.getChildrensProjects();
      filteredProjects.remove(toSkip);
      filteredProjects.removeAll(childrens);
    }
    getLog().info("Filtered reactor build order:");
    for (MavenProject filteredProject : filteredProjects) {
      getLog().info("\t" + filteredProject.getName());
    }
    return filteredProjects;
  }

  private String getServerVersion(ServerHttpClient srv)
      throws MojoExecutionException {
    String sonarServerVersion = null;
    try {
      sonarServerVersion = srv.getVersion();
    } catch (IOException e) {
      throw new MojoExecutionException("Unable to retreive sonar server version");
    }

    if (!sonarServerVersion.equals(pluginVersion)) {
      String error = "Sonar plugin (" + pluginVersion + ") and server (" + sonarServerVersion + ") version do not matchExclusionPattern.\n";
      error += "Either update your server to the " + pluginVersion + " plugin version or launch\n";
      error += "the mvn org.codehaus.sonar:sonar-maven-plugin:" + sonarServerVersion + ":sonar plugin command.";
      throw new MojoExecutionException(error);
    }

    return sonarServerVersion;
  }

  protected List getBoostrapGoals(String sonarServerVersion) {
    List goals = new ArrayList();
    Properties sonarProperties = new Properties(System.getProperties());
    sonarProperties.put("sonar.server.version", sonarServerVersion);

    if (!collectOnly) {
      BootstrapGoal dependencies = new BootstrapGoal();
      dependencies.setGoal("org.codehaus.sonar:sonar-core-maven-plugin:" + sonarServerVersion + ":dependencies");
      goals.add(dependencies);

      BootstrapGoal prepare = new BootstrapGoal();
      prepare.setGoal("org.codehaus.sonar:sonar-core-maven-plugin:" + sonarServerVersion + ":prepare");
      goals.add(prepare);
    }
    BootstrapGoal collect = new BootstrapGoal();
    collect.setGoal("org.codehaus.sonar:sonar-core-maven-plugin:" + sonarServerVersion + ":collect");
    goals.add(collect);

    BootstrapGoal batch = new BootstrapGoal();
    batch.setGoal("org.codehaus.sonar:sonar-core-maven-plugin:" + sonarServerVersion + ":batch");
    goals.add(batch);

    for (BootstrapGoal bootstrapGoal : goals) {
      bootstrapGoal.setGoalProps(new Properties(sonarProperties));
    }
    return goals;
  }

  private SonarMavenEmbedder getNewMavenEmbedder() throws MojoExecutionException {
    SonarMavenEmbedder maven = null;
    try {
      maven = new SonarMavenEmbedder(settings, session.getContainer().getContainerRealm().getWorld());
      maven.setLogger(new SonarMavenEmbedderLogger(getLog()));
      maven.start();
    } catch (Exception e) {
      throw new MojoExecutionException("Cannot start the maven embedder", e);
    }
    return maven;
  }

  private MavenProject saveSonarPom(SonarMavenEmbedder maven, MavenProject project) throws MojoExecutionException {
    File targetDir = new File(project.getBuild().getDirectory() + "/sonar");
    if (!targetDir.exists() && !targetDir.mkdirs()) {
      throw new MojoExecutionException("Unable to created directory " + targetDir.getPath());
    }
    File targetPom = new File(targetDir, "sonar-pom.xml");
    try {
      project.writeModel(new FileWriter(targetPom, false));
    } catch (Exception e) {
      throw new MojoExecutionException("Cannot save sonar-pom.xml to " + targetDir, e);
    }
    try {
      boolean executionRoot = project.isExecutionRoot();
      project = maven.readProjectWithDependencies(targetPom);
      // copy the isExecutionRoot flag to avoid problems with aggregator style mojos
      project.setExecutionRoot(executionRoot);
    } catch (Exception e) {
      throw new MojoExecutionException("Cannot read the sonar-pom.xml", e);
    }
    return project;
  }

  private void fixProjectsReportingDir(List executedProjects) {
    for (MavenProject executedProject : executedProjects) {
      // force the report dir with a complete path to avoid issues with some reporting tools
      String reportDir = executedProject.getBuild().getDirectory() + "/site";
      executedProject.getReporting().setOutputDirectory(reportDir);
    }
  }

  private void saveExecutedProjects(SonarMavenEmbedder maven, List executedProjects) throws MojoExecutionException {
    for (int i = 0; i < executedProjects.size(); i++) {
      MavenProject executedProject = executedProjects.get(i);
      File baseDir = executedProject.getBasedir();
      executedProject = saveSonarPom(maven, executedProject);
      executedProject.setFile(new File(baseDir, "pom.xml"));
      executedProjects.set(i, executedProject);

    }
  }

  private void executeGoals(String sonarServerVersion) throws MojoExecutionException {
    List goals = getBoostrapGoals(sonarServerVersion);
    for (BootstrapGoal goal : goals) {
      executeMaven(reactorProjects, goal);
    }
  }

  private void executeMaven(List executedProjects, BootstrapGoal goal) throws MojoExecutionException {
    SonarMavenEmbedder maven = getNewMavenEmbedder();
    EventMonitor eventMonitor = new DefaultEventMonitor(new PlexusLoggerAdapter(maven.getLogger()));
    // very important clone the project objects to avoid problems with maven embedder
    List executedProjectsClone = new ArrayList();
    for (MavenProject mavenProject : executedProjects) {
      executedProjectsClone.add(cloneMavenProject(mavenProject));
    }
    saveExecutedProjects(maven, executedProjects);

    try {
      maven.execute(Collections.unmodifiableList(executedProjectsClone), Arrays.asList(goal.getGoal()), eventMonitor,
          new ConsoleDownloadMonitor(), goal.goalProps, new File("."));
    } catch (Throwable e) {
      getLog().error("Cannot execute the command " + goal.getGoal(), e);
      throw new MojoExecutionException("Cannot execute the command " + goal.getGoal(), e);
    }
    // put back the cloned objects in the original array
    int i = 0;
    for (MavenProject executedProjectClone : executedProjectsClone) {
      executedProjects.set(i++, executedProjectClone);
    }
    saveExecutedProjects(maven, executedProjects);

    // required to correcly load plugin dependencies potentially done during the previous phase
    maven = getNewMavenEmbedder();
    // now call the additional goals potentially created by the called previous goal
    for (MavenProject executedProject : executedProjects) {
      List additionalGoals = getBootstrapAdditionalGoals(executedProject, goal);
      for (BootstrapGoal bootstrapAdditionalGoal : additionalGoals) {
        try {
          maven.execute(executedProject, Arrays.asList(bootstrapAdditionalGoal.getGoal()), eventMonitor,
              new ConsoleDownloadMonitor(), bootstrapAdditionalGoal.getGoalProps(), executedProject.getBasedir());
        } catch (Throwable e) {
          throw new MojoExecutionException("Cannot execute the command " + bootstrapAdditionalGoal.getGoal(), e);
        }
      }
    }
    saveExecutedProjects(maven, executedProjects);
    finalizeMavenEmbedder(maven);
  }

  protected MavenProject cloneMavenProject(MavenProject mavenProject) {
    MavenProject clone = new MavenProject(mavenProject);
    clone.getProperties().putAll(mavenProject.getProperties());
    clone.getProperties().putAll(System.getProperties());
    return clone;
  }

  protected List getBootstrapAdditionalGoals(MavenProject executedProject, BootstrapGoal currentGoal) {
    List additionalGoals = new ArrayList();

    String prepareGoalsToExecute = executedProject.getProperties().getProperty(ADDITIONAL_GOALS_PROPERTY);
    if (prepareGoalsToExecute != null) {
      String[] goals = prepareGoalsToExecute.split(",");
      for (String goal : goals) {

        BootstrapGoal additionalGoal = new BootstrapGoal();
        additionalGoal.setGoal(goal);
        additionalGoal.setGoalProps(new Properties(currentGoal.goalProps));
        additionalGoals.add(additionalGoal);
      }
      executedProject.getProperties().remove(ADDITIONAL_GOALS_PROPERTY);
    }
    return additionalGoals;
  }

  private void finalizeMavenEmbedder(SonarMavenEmbedder maven) {
    try {
      maven.stop();
    } catch (MavenEmbedderException e) {
      getLog().warn("Cannot stop the maven embedder", e);
    }
  }

  protected static class BootstrapGoal {
    private String goal;
    private Properties goalProps;

    public String getGoal() {
      return goal;
    }

    public void setGoal(String goal) {
      this.goal = goal;
    }

    public Properties getGoalProps() {
      return goalProps;
    }

    public void setGoalProps(Properties goalProps) {
      this.goalProps = goalProps;
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy