Author: dfabulich Date: Fri Nov 5 19:15:58 2010 New Revision: 1031727 URL: http://svn.apache.org/viewvc?rev=1031727&view=rev Log: scm-changes-maven-extension
Added: maven/sandbox/trunk/shared/scm-changes-maven-extension/README.txt maven/sandbox/trunk/shared/scm-changes-maven-extension/pom.xml maven/sandbox/trunk/shared/scm-changes-maven-extension/src/ maven/sandbox/trunk/shared/scm-changes-maven-extension/src/main/ maven/sandbox/trunk/shared/scm-changes-maven-extension/src/main/java/ maven/sandbox/trunk/shared/scm-changes-maven-extension/src/main/java/org/ maven/sandbox/trunk/shared/scm-changes-maven-extension/src/main/java/org/apache/ maven/sandbox/trunk/shared/scm-changes-maven-extension/src/main/java/org/apache/maven/ maven/sandbox/trunk/shared/scm-changes-maven-extension/src/main/java/org/apache/maven/shared/ maven/sandbox/trunk/shared/scm-changes-maven-extension/src/main/java/org/apache/maven/shared/scmchanges/ maven/sandbox/trunk/shared/scm-changes-maven-extension/src/main/java/org/apache/maven/shared/scmchanges/MakeScmChanges.java Added: maven/sandbox/trunk/shared/scm-changes-maven-extension/README.txt URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/shared/scm-changes-maven-extension/README.txt?rev=1031727&view=auto ============================================================================== --- maven/sandbox/trunk/shared/scm-changes-maven-extension/README.txt (added) +++ maven/sandbox/trunk/shared/scm-changes-maven-extension/README.txt Fri Nov 5 19:15:58 2010 @@ -0,0 +1,37 @@ +SCM Changes Maven Extension +--------------------------- + +Build only projects containing files that that you personally have changed (according to SCM), and projects that +depend on those projects (downstream). + +To use, add this to your parent POM: + +<build> + <extensions> + <extension> + <groupId>org.apache.maven.examples</groupId> + <artifactId>retro-maven-extension</artifactId> + <version>1.0-SNAPSHOT</version> + </extension> + </extensions> +</build> + +Be sure to also specify an SCM connection: + +<scm> + <connection>scm:svn:http://svn.apache.org/repos/asf/maven/plugins/trunk/maven-reactor-plugin/</connection> + <developerConnection>scm:svn:https://svn.apache.org/repos/asf/maven/plugins/trunk/maven-reactor-plugin/</developerConnection> + <url>http://svn.apache.org/viewvc/maven/plugins/trunk/maven-reactor-plugin/</url> +</scm> + +Then run your build like this: + + mvn install -Dmake.scmChanges + +That will build only those projects that you changed, and projects that depend on those projects (downstream). + +IF IT DOESN'T APPEAR TO BE WORKING: Try running mvn with -X to get debug logs. + +Note that if you modify the root POM (to add this extension) without checking it in, then EVERYTHING is downstream of +the root POM, so -Dmake.scmChanges will cause a full rebuild; it will appear as if it's not working. You can use +-Dmake.ignoreRootPom to ignore changes in the root POM while testing this extension. \ No newline at end of file Added: maven/sandbox/trunk/shared/scm-changes-maven-extension/pom.xml URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/shared/scm-changes-maven-extension/pom.xml?rev=1031727&view=auto ============================================================================== --- maven/sandbox/trunk/shared/scm-changes-maven-extension/pom.xml (added) +++ maven/sandbox/trunk/shared/scm-changes-maven-extension/pom.xml Fri Nov 5 19:15:58 2010 @@ -0,0 +1,48 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <groupId>org.apache.maven.shared</groupId> + <artifactId>scm-changes-maven-extension</artifactId> + <version>1.0-SNAPSHOT</version> + <name>SCM Changes Extension</name> + <dependencies> + <dependency> + <groupId>org.apache.maven</groupId> + <artifactId>maven-compat</artifactId> + <version>3.0</version> + </dependency> + <dependency> + <groupId>org.apache.maven</groupId> + <artifactId>maven-core</artifactId> + <version>3.0</version> + </dependency> + <dependency> + <groupId>org.apache.maven.scm</groupId> + <artifactId>maven-scm-providers-standard</artifactId> + <version>1.4</version> + <type>pom</type> + </dependency> + <dependency> + <groupId>org.apache.maven.scm</groupId> + <artifactId>maven-scm-manager-plexus</artifactId> + <version>1.4</version> + </dependency> + </dependencies> + <build> + <plugins> + <plugin> + <groupId>org.codehaus.plexus</groupId> + <artifactId>plexus-component-metadata</artifactId> + <version>1.5.5</version> + <executions> + <execution> + <goals> + <goal>generate-metadata</goal> + <goal>generate-test-metadata</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project> Added: maven/sandbox/trunk/shared/scm-changes-maven-extension/src/main/java/org/apache/maven/shared/scmchanges/MakeScmChanges.java URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/shared/scm-changes-maven-extension/src/main/java/org/apache/maven/shared/scmchanges/MakeScmChanges.java?rev=1031727&view=auto ============================================================================== --- maven/sandbox/trunk/shared/scm-changes-maven-extension/src/main/java/org/apache/maven/shared/scmchanges/MakeScmChanges.java (added) +++ maven/sandbox/trunk/shared/scm-changes-maven-extension/src/main/java/org/apache/maven/shared/scmchanges/MakeScmChanges.java Fri Nov 5 19:15:58 2010 @@ -0,0 +1,171 @@ +package org.apache.maven.shared.scmchanges; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +import org.apache.maven.AbstractMavenLifecycleParticipant; +import org.apache.maven.MavenExecutionException; +import org.apache.maven.execution.MavenExecutionRequest; +import org.apache.maven.execution.MavenSession; +import org.apache.maven.execution.RuntimeInformation; +import org.apache.maven.project.MavenProject; +import org.apache.maven.scm.ScmFile; +import org.apache.maven.scm.ScmFileSet; +import org.apache.maven.scm.ScmFileStatus; +import org.apache.maven.scm.command.status.StatusScmResult; +import org.apache.maven.scm.manager.ScmManager; +import org.apache.maven.scm.repository.ScmRepository; +import org.codehaus.plexus.component.annotations.Component; +import org.codehaus.plexus.component.annotations.Requirement; +import org.codehaus.plexus.logging.Logger; + +/** + * Build only projects containing files that that you personally have changed (according to SCM) + * + * @author <a href="mailto:dfabul...@apache.org">Dan Fabulich</a> + */ +...@component( role = AbstractMavenLifecycleParticipant.class, hint = "scm-changes" ) +public class MakeScmChanges + extends AbstractMavenLifecycleParticipant +{ + @Requirement + private Logger logger; + + @Requirement + ScmManager scmManager; + + /** SCM connection from root project */ + String scmConnection; + + /** make.ignoreUnknown: Ignore files in the "unknown" status (created but not added to source control) */ + boolean ignoreUnknown = true; + + /** make.ignoreRootPom: Ignore changes in the root POM file, which would normally cause a full rebuild */ + boolean ignoreRootPom = false; + + /** Disabled by default; activate via -Dmake.scmChanges=true */ + boolean enabled = false; + + public void afterProjectsRead( MavenSession session ) + throws MavenExecutionException + { + readParameters( session ); + + if ( !enabled ) + { + logger.debug( "make.scmChanges = false, not modifying project list" ); + return; + } + + + List<ScmFile> changedFiles = getChangedFilesFromScm( session.getTopLevelProject().getBasedir() ); + + List<String> includedProjects = new ArrayList<String>(); + + for ( ScmFile changedScmFile : changedFiles ) + { + logger.debug( changedScmFile.toString() ); + ScmFileStatus status = changedScmFile.getStatus(); + if ( !status.isStatus() ) // isStatus means "isUnknown or isDiff" + { + logger.debug( "Not a diff: " + status ); + continue; + } + if ( ignoreUnknown && ScmFileStatus.UNKNOWN.equals( status ) ) + { + logger.debug( "Ignoring unknown" ); + continue; + } + + File changedFile = new File( changedScmFile.getPath() ); + + if ( ignoreRootPom && session.getTopLevelProject().getFile().getAbsoluteFile().equals( changedFile.getAbsoluteFile() ) ) + { + continue; + } + + boolean found = false; + // TODO There's a cleverer/faster way to code this, right? This is O(n^2) + for ( MavenProject project : session.getProjects() ) + { + File projectDirectory = project.getFile().getParentFile(); + if ( changedFile.getAbsolutePath().startsWith( projectDirectory.getAbsolutePath() + File.separator ) ) + { + if ( !includedProjects.contains( project ) ) + { + logger.debug( "Including " + project ); + } + includedProjects.add( project.getGroupId() + ":" + project.getArtifactId() ); + found = true; + break; + } + } + if ( !found ) + { + logger.debug( "Couldn't find file in any project root: " + changedFile.getAbsolutePath() ); + } + } + + if ( includedProjects.isEmpty() ) + throw new MavenExecutionException( "No SCM changes detected; nothing to do!", + session.getTopLevelProject().getFile() ); + + MavenExecutionRequest request = session.getRequest(); + String makeBehavior = request.getMakeBehavior(); + if ( makeBehavior == null ) + { + request.setMakeBehavior( MavenExecutionRequest.REACTOR_MAKE_DOWNSTREAM ); + } + if ( MavenExecutionRequest.REACTOR_MAKE_UPSTREAM.equals( makeBehavior ) ) + { + request.setMakeBehavior( MavenExecutionRequest.REACTOR_MAKE_BOTH ); + } + + request.setSelectedProjects( includedProjects ); + + } + + private void readParameters( MavenSession session ) + throws MavenExecutionException + { + Properties sessionProps = session.getUserProperties(); + scmConnection = sessionProps.getProperty( "make.scmConnection" ); + if ( scmConnection == null ) + { + try + { + scmConnection = session.getTopLevelProject().getScm().getConnection(); + } + catch ( NullPointerException e ) + { + String message = + "No SCM connection specified. You must specify an SCM " + + "connection by adding a <connection> element to your <scm> element in your POM"; + throw new MavenExecutionException( message, e ); + } + } + enabled = Boolean.parseBoolean( sessionProps.getProperty( "make.scmChanges", "false" ) ); + ignoreUnknown = Boolean.parseBoolean( sessionProps.getProperty( "make.ignoreUnknown", "true" ) ); + ignoreRootPom = Boolean.parseBoolean( sessionProps.getProperty( "make.ignoreRootPom", "false" ) ); + } + + @SuppressWarnings( "unchecked" ) + private List<ScmFile> getChangedFilesFromScm( File baseDir ) + throws MavenExecutionException + { + StatusScmResult result = null; + try + { + ScmRepository repository = scmManager.makeScmRepository( scmConnection ); + result = scmManager.status( repository, new ScmFileSet( baseDir ) ); + } + catch ( Exception e ) + { + throw new MavenExecutionException( "Couldn't configure SCM repository: " + e.getLocalizedMessage(), e ); + } + + return (List<ScmFile>) result.getChangedFiles(); + } +}