blob: 06cead44019b101abe73ceaac1317984072c49e7 [file] [log] [blame]
package org.apache.maven.plugins.invoker;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import static org.apache.maven.shared.utils.logging.MessageUtils.buffer;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.invoker.model.BuildJob;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.shared.utils.io.IOUtil;
/**
* Tracks a set of build jobs and their results.
*
* @author Benjamin Bentmann
*/
class InvokerSession
{
private static final String SEPARATOR = buffer().strong(
"-------------------------------------------------" ).toString();
private List<BuildJob> buildJobs;
private List<BuildJob> failedJobs;
private List<BuildJob> errorJobs;
private List<BuildJob> successfulJobs;
private List<BuildJob> skippedJobs;
/**
* Creates a new empty session.
*/
InvokerSession()
{
buildJobs = new ArrayList<>();
}
/**
* Creates a session that initially contains the specified build jobs.
*
* @param buildJobs The build jobs to set, must not be <code>null</code>.
*/
InvokerSession( List<BuildJob> buildJobs )
{
this.buildJobs = new ArrayList<>( buildJobs );
}
/**
* Adds the specified build job to this session.
*
* @param buildJob The build job to add, must not be <code>null</code>.
*/
public void addJob( BuildJob buildJob )
{
buildJobs.add( buildJob );
resetStats();
}
/**
* Sets the build jobs of this session.
*
* @param buildJobs The build jobs to set, must not be <code>null</code>.
*/
public void setJobs( List<? extends BuildJob> buildJobs )
{
this.buildJobs = new ArrayList<>( buildJobs );
resetStats();
}
/**
* Gets the build jobs in this session.
*
* @return The build jobs in this session, can be empty but never <code>null</code>.
*/
public List<BuildJob> getJobs()
{
return buildJobs;
}
/**
* Gets the successful build jobs in this session.
*
* @return The successful build jobs in this session, can be empty but never <code>null</code>.
*/
public List<BuildJob> getSuccessfulJobs()
{
updateStats();
return successfulJobs;
}
/**
* Gets the failed build jobs in this session.
*
* @return The failed build jobs in this session, can be empty but never <code>null</code>.
*/
public List<BuildJob> getFailedJobs()
{
updateStats();
return failedJobs;
}
/**
* Gets the build jobs which had errors for this session.
*
* @return The build jobs in error for this session, can be empty but never <code>null</code>.
*/
public List<BuildJob> getErrorJobs()
{
updateStats();
return errorJobs;
}
/**
* Gets the skipped build jobs in this session.
*
* @return The skipped build jobs in this session, can be empty but never <code>null</code>.
*/
public List<BuildJob> getSkippedJobs()
{
updateStats();
return skippedJobs;
}
private void resetStats()
{
successfulJobs = null;
failedJobs = null;
skippedJobs = null;
errorJobs = null;
}
private void updateStats()
{
if ( successfulJobs != null && skippedJobs != null && failedJobs != null && errorJobs != null )
{
return;
}
successfulJobs = new ArrayList<>();
failedJobs = new ArrayList<>();
skippedJobs = new ArrayList<>();
errorJobs = new ArrayList<>();
for ( BuildJob buildJob : buildJobs )
{
if ( BuildJob.Result.SUCCESS.equals( buildJob.getResult() ) )
{
successfulJobs.add( buildJob );
}
else if ( BuildJob.Result.SKIPPED.equals( buildJob.getResult() ) )
{
skippedJobs.add( buildJob );
}
else if ( BuildJob.Result.ERROR.equals( buildJob.getResult() ) )
{
errorJobs.add( buildJob );
}
else if ( buildJob.getResult() != null )
{
failedJobs.add( buildJob );
}
}
}
/**
* Prints a summary of this session to the specified logger.
*
* @param logger The mojo logger to output messages to, must not be <code>null</code>.
* @param ignoreFailures A flag whether failures should be ignored or whether a build failure should be signaled.
*/
public void logSummary( Log logger, boolean ignoreFailures )
{
updateStats();
logger.info( SEPARATOR );
logger.info( "Build Summary:" );
logger.info( " Passed: " + successfulJobs.size()
+ ", Failed: " + failedJobs.size()
+ ", Errors: " + errorJobs.size()
+ ", Skipped: " + skippedJobs.size() );
logger.info( SEPARATOR );
logBuildJobList( logger, ignoreFailures, "The following builds failed:", failedJobs );
logBuildJobList( logger, ignoreFailures, "The following builds finished with error:", errorJobs );
logBuildJobList( logger, true, "The following builds were skipped:", skippedJobs );
}
public void logFailedBuildLog( Log logger, boolean ignoreFailures )
throws MojoFailureException
{
List<BuildJob> jobToLogs = new ArrayList<>( failedJobs );
jobToLogs.addAll( errorJobs );
for ( BuildJob buildJob: jobToLogs )
{
File buildLogFile = buildJob.getBuildlog() != null ? new File( buildJob.getBuildlog() ) : null;
if ( buildLogFile != null && buildLogFile.exists() )
{
try
{
// prepare message with build.log in one string to omit begin [ERROR], [WARN]
// so whole log will be displayed without decoration
StringBuilder buildLogMessage = new StringBuilder( );
buildLogMessage.append( System.lineSeparator() );
buildLogMessage.append( System.lineSeparator() );
buildLogMessage.append( "*** begin build.log for: " + buildJob.getProject() + " ***" );
buildLogMessage.append( System.lineSeparator() );
buildLogMessage.append( IOUtil.toString( new FileReader( buildLogFile ) ) );
buildLogMessage.append( "*** end build.log for: " + buildJob.getProject() + " ***" );
buildLogMessage.append( System.lineSeparator() );
logWithLevel( logger, ignoreFailures, SEPARATOR );
logWithLevel( logger, ignoreFailures, buildLogMessage.toString() );
logWithLevel( logger, ignoreFailures, SEPARATOR );
logWithLevel( logger, ignoreFailures, "" );
}
catch ( IOException e )
{
throw new MojoFailureException( e.getMessage(), e );
}
}
}
}
/**
* Handles the build failures in this session.
*
* @param logger The mojo logger to output messages to, must not be <code>null</code>.
* @param ignoreFailures A flag whether failures should be ignored or whether a build failure should be signaled.
* @throws MojoFailureException If failures are present and not ignored.
*/
public void handleFailures( Log logger, boolean ignoreFailures )
throws MojoFailureException
{
updateStats();
if ( !failedJobs.isEmpty() )
{
String message = failedJobs.size() + " build" + ( failedJobs.size() == 1 ? "" : "s" ) + " failed.";
if ( ignoreFailures )
{
logger.warn( "Ignoring that " + message );
}
else
{
throw new MojoFailureException( message + " See console output above for details." );
}
}
if ( !errorJobs.isEmpty() )
{
String message = errorJobs.size() + " build" + ( errorJobs.size() == 1 ? "" : "s" ) + " in error.";
if ( ignoreFailures )
{
logger.warn( "Ignoring that " + message );
}
else
{
throw new MojoFailureException( message + " See console output above for details." );
}
}
}
/**
* Log list of jobs.
*
* @param logger logger to write
* @param warn flag indicate log level
* @param buildJobs jobs to list
*/
private void logBuildJobList( Log logger, boolean warn, String header, List<BuildJob> buildJobs )
{
if ( buildJobs.isEmpty() )
{
return;
}
logWithLevel( logger, warn, header );
for ( BuildJob buildJob : buildJobs )
{
logWithLevel( logger, warn, "* " + buildJob.getProject() );
}
logger.info( SEPARATOR );
}
/**
* Log message in correct level depends on flag.
*
* @param logger logger to write
* @param warn flag indicate log level
* @param message message to write
*/
private void logWithLevel( Log logger, boolean warn, String message )
{
if ( warn )
{
logger.warn( message );
}
else
{
logger.error( message );
}
}
}