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

com.processpuzzle.fitnesse.launcher.maven.plugin.fitnesse.mojo.AbstractFitNesseMojo Maven / Gradle / Ivy

The newest version!
package com.processpuzzle.fitnesse.launcher.maven.plugin.fitnesse.mojo;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.ArtifactUtils;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
import org.apache.maven.artifact.resolver.ArtifactResolver;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.Plugin;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.descriptor.PluginDescriptor;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.classworlds.realm.ClassRealm;

import com.processpuzzle.fitnesse.launcher.maven.plugin.artifact.resolver.OptionalArtifactFilter;
import com.processpuzzle.fitnesse.launcher.maven.plugin.fitnesse.util.FitNesseHelper;
import com.processpuzzle.fitnesse.launcher.maven.plugin.fitnesse.util.Utils;

public abstract class AbstractFitNesseMojo extends org.apache.maven.plugin.AbstractMojo {
   public static final String MAVEN_CLASSPATH = "maven.classpath";

   private static final String LOG_LINE = "------------------------------------------------------------------------";

   /**
    * Used to look up Artifacts in the remote repository.
    * 
    * @component role="org.apache.maven.artifact.resolver.ArtifactResolver"
    * @readonly
    * @required
    */
   protected ArtifactResolver resolver;

   /**
    * Location of the local repository.
    *
    * @parameter property="localRepository"
    * @readonly
    * @required
    */
   protected ArtifactRepository localRepository;

   /**
    * List of Remote Repositories used by the resolver
    *
    * @parameter property="project.remoteArtifactRepositories"
    * @readonly
    * @required
    */
   protected List remoteArtifactRepositories;

   /**
    * Maven project, to be injected by Maven itself.
    * 
    * @parameter property="project"
    * @readonly
    * @required
    */
   protected MavenProject project;

   /**
    * The Maven Session Object
    * 
    * @parameter property="session"
    * @readonly
    * @required
    */
   protected MavenSession session;

   /**
    * @parameter property="plugin"
    * @readonly
    * @required
    */
   protected PluginDescriptor pluginDescriptor;

   /**
    * @parameter property="fitnesse.port" default-value="9123"
    */
   protected Integer port;

   /**
    * @parameter property="fitnesse.test.resource.directory" default-value="src/test/fitnesse"
    */
   protected String testResourceDirectory;

   /**
    * @parameter property="fitnesse.working" default-value="${project.build.directory}/fitnesse"
    */
   protected String workingDir;

   /**
    * @parameter property="fitnesse.root" default-value="FitNesseRoot"
    */
   protected String root;

   /**
    * @parameter property="fitnesse.logDir"
    */
   protected String logDir;

   /**
    * fitnesse-launcher-maven-plugin unpacks a fresh copy of FitNesse under /target; Only your project specific FitNesse tests need go under src/test/fitnesse.
    * By setting 'createSymLink' to 'true', fitnesse-launcher-maven-plugin will create a FitNesse SymLink directly to your test suite under src/test/fitnesse.
    * This is most useful when developing tests in 'wiki' mode, as then you can directly scm commit your changes. If you prefer to copy-resources from
    * src/test/fitnesse into /target/fitnesse, let 'createSymLink' be 'false'.
    * 
    * @see What are Symbolic Links
    * @parameter property="fitnesse.createSymLink" default-value="true"
    */
   protected boolean createSymLink;

   /**
    * This is where test results go.
    * 
    * @parameter property="fitnesse.results" default-value="${project.build.directory}/fitnesse/results"
    * @required
    */
   protected File resultsDir;

   /**
    * This is where reports go.
    * 
    * @parameter property="fitnesse.reports" default-value="${project.build.directory}/fitnesse/reports"
    * @required
    */
   protected File reportsDir;

   /**
    * The summary file to write integration test results to.
    * 
    * @parameter property="fitnesse.summary.file" default-value="${project.build.directory}/fitnesse/results/failsafe-summary.xml"
    * @required
    */
   protected File summaryFile;

   /**
    * @parameter property="fitnesse.launches"
    */
   protected Launch[] launches;

   /**
    * @parameter property="fitnesse.suite"
    */
   protected String suite;

   /**
    * @parameter property="fitnesse.test"
    */
   protected String test;

   /**
    * @see Suite Tags
    * @parameter property="fitnesse.suiteFilter"
    */
   protected String suiteFilter;

   /**
    * @see Suite Tags
    * @parameter property="fitnesse.excludeSuiteFilter"
    */
   protected String excludeSuiteFilter;

   /**
    * @see Suite Tags
    * @parameter property="fitnesse.runTestsMatchingAllTags"
    */
   protected String runTestsMatchingAllTags;

   /**
    * @parameter property="fitnesse.useProjectDependencies"
    */
   protected Set useProjectDependencies;

   /**
    * @parameter property="fitnesse.failIfNoTests" default-value=true
    */
   protected Boolean failIfNoTests;

   /**
    * Should fitnesse-launcher-maven-plugin exclude optional transitive dependencies, when configured using <useProjectDependencies> ? 
* Note: This may result in duplicates or conflicts for transitive dependencies.
* See Issue #27.
* Defaults to true.
* @Deprecated * * @parameter property="fitnesse.excludeOptionalDependencies" default-value="true" */ @Deprecated protected boolean excludeOptionalDependencies = true; protected String fitNesseClasspath; protected FitNesseHelper fitNesseHelper; protected abstract void executeInternal( Launch... executeLaunches ) throws MojoExecutionException, MojoFailureException; @Override public void execute() throws MojoExecutionException, MojoFailureException { this.fitNesseHelper = new FitNesseHelper( getLog() ); exportProperties(); executeInternal( launches() ); } /** * Pre-1.4.0 config is senior, as this allows easy override from command line using -D */ protected Launch[] launches() { if( this.suite == null && this.test == null ){ // if this.launches.length == 0, it won't throw exception, just nothing to run return this.launches; }else{ return new Launch[] { new Launch( this.suite, this.test, this.suiteFilter, this.excludeSuiteFilter, this.runTestsMatchingAllTags ) }; } } protected final void exportProperties() { final Properties projectProperties = this.project.getProperties(); getLog().info( LOG_LINE ); final String mavenClasspath = calcWikiFormatClasspath(); setSystemProperty( MAVEN_CLASSPATH, mavenClasspath ); // If a System property already exists, it has priority; // That way we can override with a -D on the command line for( String key : projectProperties.stringPropertyNames() ){ final String value = this.session.getSystemProperties().getProperty( key, projectProperties.getProperty( key ) ); setSystemProperty( key, value ); } setSystemProperty( "artifact", this.project.getArtifactId() ); setSystemProperty( "version", this.project.getVersion() ); try{ final String basedir = this.project.getBasedir().getCanonicalPath(); setSystemProperty( "basedir", basedir ); }catch( Exception e ){ getLog().error( e ); } getLog().info( LOG_LINE ); } protected final void setSystemProperty( final String key, final String value ) { if( !Utils.isBlank( key ) && !Utils.isBlank( value ) ){ getLog().info( String.format( "Setting FitNesse variable [%s] to [%s]", key, value ) ); System.setProperty( key, value ); } } protected final String calcWikiFormatClasspath() { final Set artifacts = buildArtifactSet(); return addArtifactsToClasspath( artifacts ); } private Set buildArtifactSet() { final Set artifacts = new LinkedHashSet(); addPluginArtifacts( artifacts ); addProjectArtifacts( artifacts ); return artifacts; } private void addPluginArtifacts( final Set artifacts ) { final Map dependencyArtifactMap = this.pluginDescriptor.getArtifactMap(); // We should always have FitNesse itself on the FitNesse classpath! artifacts.addAll( resolveDependencyKey( FitNesseMavenCoordinate.artifactKey, dependencyArtifactMap ) ); // We check plugin for null to allow use in standalone mode final Plugin fitnessePlugin = this.project.getPlugin( this.pluginDescriptor.getPluginLookupKey() ); if( fitnessePlugin == null ){ getLog().info( "Running standalone - launching vanilla FitNesse" ); }else{ final List dependecies = fitnessePlugin.getDependencies(); if( dependecies != null && !dependecies.isEmpty() ){ getLog().info( "Using dependencies specified in plugin config" ); for( Dependency dependency : dependecies ){ final String key = dependency.getGroupId() + ":" + dependency.getArtifactId(); artifacts.addAll( resolveDependencyKey( key, dependencyArtifactMap ) ); } } } } /** * From {@link org.apache.maven.project.MavenProject#getArtifacts()}: All dependencies that this project has, including transitive ones. Contents are lazily * populated, so depending on what phases have run dependencies in some scopes won't be included. eg. if only compile phase has run, dependencies with scope * test won't be included. * * @see org.apache.maven.project.MavenProject#getArtifacts() See * requiresDependencyResolution */ private void addProjectArtifacts( final Set artifacts ) { if( !this.useProjectDependencies.isEmpty() ){ getLog().info( "Using dependencies in the following scopes: " + this.useProjectDependencies ); if( !this.excludeOptionalDependencies ){ getLog().info( "Including transitive dependencies which are optional" ); resolveProjectDependencies( artifacts ); }else{ for( Artifact artifact : this.project.getArtifacts() ){ if( this.useProjectDependencies.contains( artifact.getScope() ) ){ artifacts.add( artifact ); } } } } } private String addArtifactsToClasspath( final Set artifacts ) { final StringBuilder wikiFormatClasspath = new StringBuilder( "\n" ); final ClassRealm realm = this.pluginDescriptor.getClassRealm(); this.fitNesseClasspath = "\""; setupLocalTestClasspath( realm, wikiFormatClasspath ); for( Artifact artifact : artifacts ){ final File artifactFile = artifact.getFile(); if( artifactFile != null ){ getLog().debug( String.format( "Adding artifact to FitNesse classpath [%s]", artifact ) ); this.fitNesseHelper.formatAndAppendClasspathArtifact( wikiFormatClasspath, artifact ); this.fitNesseClasspath += ( artifact.getFile().getPath() != null ) ? artifact.getFile().getPath() + ";" : ""; addToRealm( realm, artifactFile ); }else{ getLog().warn( String.format( "File for artifact [%s] is not found", artifact ) ); } } this.fitNesseClasspath += "\""; return wikiFormatClasspath.toString(); } /** * See Issue #27. This method may result in duplicates or conflicts for transitive dependencies. Better to use correct @requiresDependencyResolution for * mojo, in combination with project.getArtifacts(). See * requiresDependencyResolution */ @Deprecated private void resolveProjectDependencies( final Set artifacts ) { final Map dependencyArtifactMap = ArtifactUtils.artifactMapByVersionlessId( this.project.getDependencyArtifacts() ); final List dependecies = this.project.getDependencies(); for( Dependency dependency : dependecies ){ final String key = dependency.getGroupId() + ":" + dependency.getArtifactId(); if( this.useProjectDependencies.contains( dependency.getScope() ) ){ artifacts.addAll( resolveDependencyKey( key, dependencyArtifactMap ) ); } } } private void setupLocalTestClasspath( final ClassRealm realm, final StringBuilder wikiFormatClasspath ) { setupLocalTestClasspath( realm, wikiFormatClasspath, handleWhitespace( this.project.getBuild().getTestOutputDirectory() ) ); setupLocalTestClasspath( realm, wikiFormatClasspath, handleWhitespace( this.project.getBuild().getOutputDirectory() ) ); } private String handleWhitespace( final String directory ) { if( Utils.whitespaceSituation( directory ) ){ try{ final String relativePath = Utils.getRelativePath( new File( "." ), new File( directory ) ); if( !Utils.whitespaceSituation( relativePath ) ){ getLog().warn( Utils.whitespaceWarning( directory, "Attempting relative path workaround" ) ); return relativePath; } }catch( final IOException e ){ getLog().error( e ); } } return directory; } private void setupLocalTestClasspath( final ClassRealm realm, final StringBuilder wikiFormatClasspath, final String testClasspathElement ) { getLog().debug( String.format( "Adding element to FitNesse classpath [%s]", testClasspathElement ) ); this.fitNesseHelper.formatAndAppendClasspath( wikiFormatClasspath, testClasspathElement ); addToRealm( realm, new File( testClasspathElement ) ); } private void addToRealm( final ClassRealm realm, final File file ) { try{ final URL url = file.toURI().toURL(); getLog().debug( String.format( "Adding URL to ClassRealm [%s]", url ) ); realm.addURL( url ); }catch( final MalformedURLException e ){ getLog().error( e ); } } private Set resolveDependencyKey( final String key, final Map artifactMap ) { final Artifact artifact = artifactMap.get( key ); if( artifact == null ){ getLog().error( String.format( "Lookup for artifact [%s] failed", key ) ); return Collections.emptySet(); } return resolveArtifactTransitively( artifact ); } private Set resolveArtifactTransitively( final Artifact artifact ) { final ArtifactResolutionRequest request = new ArtifactResolutionRequest().setArtifact( artifact ).setResolveRoot( true ).setResolveTransitively( true ) .setRemoteRepositories( this.remoteArtifactRepositories ).setLocalRepository( this.localRepository ); if( this.excludeOptionalDependencies ){ request.setCollectionFilter( OptionalArtifactFilter.INSTANCE ); } final ArtifactResolutionResult result = this.resolver.resolve( request ); if( !result.isSuccess() ){ for( Artifact missing : result.getMissingArtifacts() ){ getLog().error( String.format( "Could not resolve artifact: [%s]", missing ) ); } if( result.hasExceptions() && getLog().isDebugEnabled() ){ for( Exception exception : result.getExceptions() ){ getLog().debug( exception ); } } } final Set dependencies = result.getArtifacts(); return dependencies; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy