Skip to content

Commit

Permalink
[MDEPLOY-193] Deploy At End feature (no extension) (#20)
Browse files Browse the repository at this point in the history
This PR makes deployAtEnd work as expected even
if maven-deploy-plugin is not used as extension.

How it works: it uses mojo Context to store "state markers" (and params):
* presence of marker means project was "processed"
* value of state marker tells what should be done
* if needed, other params are stored as well

UTs adjusted to provide plugin context (was null before).
  • Loading branch information
cstamas authored Jul 3, 2022
1 parent dd39f5d commit 89c28fb
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 46 deletions.
2 changes: 1 addition & 1 deletion src/it/deploy-at-end-fail/verify.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,5 @@ assert !( new File( basedir, "module1/target/repo/org/apache/maven/its/deploy/da

File buildLog = new File( basedir, 'build.log' )
assert buildLog.exists()
assert buildLog.text.contains( "[INFO] Deploying org.apache.maven.its.deploy.dae.fail:dae:1.0 at end" )
assert buildLog.text.contains( "[INFO] Deferring deploy for org.apache.maven.its.deploy.dae.fail:dae:1.0 at end" )

2 changes: 1 addition & 1 deletion src/it/deploy-at-end-pass/verify.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,5 @@ assert new File( basedir, "module1/target/repo/org/apache/maven/its/deploy/dae/p

File buildLog = new File( basedir, 'build.log' )
assert buildLog.exists()
assert buildLog.text.contains( "[INFO] Deploying org.apache.maven.its.deploy.dae.pass:dae:1.0 at end" )
assert buildLog.text.contains( "[INFO] Deferring deploy for org.apache.maven.its.deploy.dae.pass:dae:1.0 at end" )

147 changes: 107 additions & 40 deletions src/main/java/org/apache/maven/plugins/deploy/DeployMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,16 @@
* under the License.
*/

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.maven.artifact.ArtifactUtils;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.descriptor.PluginDescriptor;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
Expand All @@ -55,23 +54,15 @@ public class DeployMojo

private static final Pattern ALT_REPO_SYNTAX_PATTERN = Pattern.compile( "(.+?)::(.+)" );

/**
* When building with multiple threads, reaching the last project doesn't have to mean that all projects are ready
* to be deployed
*/
private static final AtomicInteger READYPROJECTSCOUNTER = new AtomicInteger();

private static final List<ProjectDeployerRequest> DEPLOYREQUESTS =
Collections.synchronizedList( new ArrayList<ProjectDeployerRequest>() );

/**
*/
@Parameter( defaultValue = "${project}", readonly = true, required = true )
private MavenProject project;

@Parameter( defaultValue = "${reactorProjects}", required = true, readonly = true )
private List<MavenProject> reactorProjects;

@Parameter( defaultValue = "${plugin}", required = true, readonly = true )
private PluginDescriptor pluginDescriptor;

/**
* Whether every project should be deployed during its own deploy-phase or at the end of the multimodule build. If
* set to {@code true} and the build fails, none of the reactor projects is deployed.
Expand Down Expand Up @@ -143,63 +134,139 @@ public class DeployMojo
@Component
private ProjectDeployer projectDeployer;

private enum State
{
SKIPPED, DEPLOYED, TO_BE_DEPLOYED
}

private static final String DEPLOY_PROCESSED_MARKER = DeployMojo.class.getName() + ".processed";

private static final String DEPLOY_ALT_RELEASE_DEPLOYMENT_REPOSITORY =
DeployMojo.class.getName() + ".altReleaseDeploymentRepository";

private static final String DEPLOY_ALT_SNAPSHOT_DEPLOYMENT_REPOSITORY =
DeployMojo.class.getName() + ".altSnapshotDeploymentRepository";

private static final String DEPLOY_ALT_DEPLOYMENT_REPOSITORY =
DeployMojo.class.getName() + ".altDeploymentRepository";

private void putState( State state )
{
getPluginContext().put( DEPLOY_PROCESSED_MARKER, state.name() );
}

private void putPluginContextValue( String key, String value )
{
if ( value != null )
{
getPluginContext().put( key, value );
}
}

private String getPluginContextValue( Map<String, Object> pluginContext, String key )
{
return (String) pluginContext.get( key );
}

private State getState( Map<String, Object> pluginContext )
{
return State.valueOf( getPluginContextValue( pluginContext, DEPLOY_PROCESSED_MARKER ) );
}

private boolean hasState( MavenProject project )
{
Map<String, Object> pluginContext = getSession().getPluginContext( pluginDescriptor, project );
return pluginContext.containsKey( DEPLOY_PROCESSED_MARKER );
}

public void execute()
throws MojoExecutionException, MojoFailureException
{
boolean addedDeployRequest = false;
if ( Boolean.parseBoolean( skip )
|| ( "releases".equals( skip ) && !ArtifactUtils.isSnapshot( project.getVersion() ) )
|| ( "snapshots".equals( skip ) && ArtifactUtils.isSnapshot( project.getVersion() ) )
)
{
getLog().info( "Skipping artifact deployment" );
putState( State.SKIPPED );
}
else
{
failIfOffline();

// CHECKSTYLE_OFF: LineLength
// @formatter:off
ProjectDeployerRequest pdr = new ProjectDeployerRequest()
.setProject( project )
.setRetryFailedDeploymentCount( getRetryFailedDeploymentCount() )
.setAltReleaseDeploymentRepository( altReleaseDeploymentRepository )
.setAltSnapshotDeploymentRepository( altSnapshotDeploymentRepository )
.setAltDeploymentRepository( altDeploymentRepository );
// @formatter:on
// CHECKSTYLE_ON: LineLength

ArtifactRepository repo = getDeploymentRepository( pdr );

if ( !deployAtEnd )
{
// CHECKSTYLE_OFF: LineLength
// @formatter:off
ProjectDeployerRequest pdr = new ProjectDeployerRequest()
.setProject( project )
.setRetryFailedDeploymentCount( getRetryFailedDeploymentCount() )
.setAltReleaseDeploymentRepository( altReleaseDeploymentRepository )
.setAltSnapshotDeploymentRepository( altSnapshotDeploymentRepository )
.setAltDeploymentRepository( altDeploymentRepository );
// @formatter:on
// CHECKSTYLE_ON: LineLength

ArtifactRepository repo = getDeploymentRepository( pdr );

deployProject( getSession().getProjectBuildingRequest(), pdr, repo );
putState( State.DEPLOYED );
}
else
{
DEPLOYREQUESTS.add( pdr );
addedDeployRequest = true;
putState( State.TO_BE_DEPLOYED );
putPluginContextValue( DEPLOY_ALT_RELEASE_DEPLOYMENT_REPOSITORY, altReleaseDeploymentRepository );
putPluginContextValue( DEPLOY_ALT_SNAPSHOT_DEPLOYMENT_REPOSITORY, altSnapshotDeploymentRepository );
putPluginContextValue( DEPLOY_ALT_DEPLOYMENT_REPOSITORY, altDeploymentRepository );
getLog().info( "Deferring deploy for " + getProjectReferenceId( project ) + " at end" );
}
}

boolean projectsReady = READYPROJECTSCOUNTER.incrementAndGet() == reactorProjects.size();
if ( projectsReady )
if ( allProjectsMarked() )
{
synchronized ( DEPLOYREQUESTS )
for ( MavenProject reactorProject : reactorProjects )
{
while ( !DEPLOYREQUESTS.isEmpty() )
Map<String, Object> pluginContext = getSession().getPluginContext( pluginDescriptor, reactorProject );
State state = getState( pluginContext );
if ( state == State.TO_BE_DEPLOYED )
{
ArtifactRepository repo = getDeploymentRepository( DEPLOYREQUESTS.get( 0 ) );

deployProject( getSession().getProjectBuildingRequest(), DEPLOYREQUESTS.remove( 0 ), repo );
String altReleaseDeploymentRepository =
getPluginContextValue( pluginContext, DEPLOY_ALT_RELEASE_DEPLOYMENT_REPOSITORY );
String altSnapshotDeploymentRepository =
getPluginContextValue( pluginContext, DEPLOY_ALT_SNAPSHOT_DEPLOYMENT_REPOSITORY );
String altDeploymentRepository =
getPluginContextValue( pluginContext, DEPLOY_ALT_DEPLOYMENT_REPOSITORY );

ProjectDeployerRequest pdr = new ProjectDeployerRequest()
.setProject( reactorProject )
.setRetryFailedDeploymentCount( getRetryFailedDeploymentCount() )
.setAltReleaseDeploymentRepository( altReleaseDeploymentRepository )
.setAltSnapshotDeploymentRepository( altSnapshotDeploymentRepository )
.setAltDeploymentRepository( altDeploymentRepository );

ArtifactRepository repo = getDeploymentRepository( pdr );

deployProject( getSession().getProjectBuildingRequest(), pdr, repo );
}
}
}
else if ( addedDeployRequest )
}

private String getProjectReferenceId( MavenProject mavenProject )
{
return mavenProject.getGroupId() + ":" + mavenProject.getArtifactId() + ":" + mavenProject.getVersion();
}

private boolean allProjectsMarked()
{
for ( MavenProject reactorProject : reactorProjects )
{
getLog().info( "Deploying " + project.getGroupId() + ":" + project.getArtifactId() + ":"
+ project.getVersion() + " at end" );
if ( !hasState( reactorProject ) )
{
return false;
}
}
return true;
}

private void deployProject( ProjectBuildingRequest pbr, ProjectDeployerRequest pir, ArtifactRepository repo )
Expand Down
22 changes: 18 additions & 4 deletions src/test/java/org/apache/maven/plugins/deploy/DeployMojoTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
* under the License.
*/

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
Expand All @@ -28,11 +29,13 @@
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.descriptor.PluginDescriptor;
import org.apache.maven.plugin.testing.AbstractMojoTestCase;
import org.apache.maven.plugin.testing.stubs.MavenProjectStub;
import org.apache.maven.plugins.deploy.stubs.ArtifactDeployerStub;
Expand Down Expand Up @@ -68,7 +71,6 @@ public class DeployMojoTest

MavenProjectStub project = new MavenProjectStub();

@Mock
private MavenSession session;

@InjectMocks
Expand All @@ -78,7 +80,11 @@ public void setUp()
throws Exception
{
super.setUp();


session = mock( MavenSession.class );
when( session.getPluginContext(any(PluginDescriptor.class), any(MavenProject.class)))
.thenReturn( new ConcurrentHashMap<String, Object>() );

remoteRepo = new File( REMOTE_REPO );

remoteRepo.mkdirs();
Expand Down Expand Up @@ -144,7 +150,8 @@ public void testBasicDeploy()
assertTrue( file.exists() );

MavenProject project = (MavenProject) getVariableValueFromObject( mojo, "project" );


setVariableValueToObject( mojo, "pluginContext", new ConcurrentHashMap<>() );
setVariableValueToObject( mojo, "reactorProjects", Collections.singletonList( project ) );

artifact = ( DeployArtifactStub ) project.getArtifact();
Expand Down Expand Up @@ -251,8 +258,11 @@ public void testSkippingDeploy()
assertTrue( file.exists() );

MavenProject project = (MavenProject) getVariableValueFromObject( mojo, "project" );


setVariableValueToObject( mojo, "pluginDescriptor", new PluginDescriptor() );
setVariableValueToObject( mojo, "pluginContext", new ConcurrentHashMap<>() );
setVariableValueToObject( mojo, "reactorProjects", Collections.singletonList( project ) );
setVariableValueToObject( mojo, "session", session );

artifact = (DeployArtifactStub) project.getArtifact();

Expand Down Expand Up @@ -316,6 +326,7 @@ public void testBasicDeployWithPackagingAsPom()

MavenProject project = (MavenProject) getVariableValueFromObject( mojo, "project" );

setVariableValueToObject( mojo, "pluginContext", new ConcurrentHashMap<>() );
setVariableValueToObject( mojo, "reactorProjects", Collections.singletonList( project ) );

artifact = (DeployArtifactStub) project.getArtifact();
Expand Down Expand Up @@ -381,6 +392,7 @@ public void testDeployIfArtifactFileIsNull()

MavenProject project = (MavenProject) getVariableValueFromObject( mojo, "project" );

setVariableValueToObject( mojo, "pluginContext", new ConcurrentHashMap<>() );
setVariableValueToObject( mojo, "reactorProjects", Collections.singletonList( project ) );

artifact = (DeployArtifactStub) project.getArtifact();
Expand Down Expand Up @@ -422,6 +434,7 @@ public void testDeployWithAttachedArtifacts()

MavenProject project = (MavenProject) getVariableValueFromObject( mojo, "project" );

setVariableValueToObject( mojo, "pluginContext", new ConcurrentHashMap<>() );
setVariableValueToObject( mojo, "reactorProjects", Collections.singletonList( project ) );

artifact = (DeployArtifactStub) project.getArtifact();
Expand Down Expand Up @@ -523,6 +536,7 @@ public void _testBasicDeployWithScpAsProtocol()

MavenProject project = (MavenProject) getVariableValueFromObject( mojo, "project" );

setVariableValueToObject( mojo, "pluginContext", new ConcurrentHashMap<>() );
setVariableValueToObject( mojo, "reactorProjects", Collections.singletonList( project ) );

artifact = (DeployArtifactStub) project.getArtifact();
Expand Down

0 comments on commit 89c28fb

Please sign in to comment.