Commit 74b460eb authored by Jonathan Doklovic's avatar Jonathan Doklovic

Merge branch 'release/1.0-alpha27'

parents b14aa361 c54a30e2
......@@ -2,6 +2,8 @@
**Current Version: 1.0-alpha21.1**
**The Issue Tracker Has Moved To: [https://ecosystem.atlassian.net/browse/MJF](https://ecosystem.atlassian.net/browse/MJF)**
The Maven JGit-Flow Plugin is based on and a replacement for the maven-release-plugin to enable git-flow release workflows.
This plugin also provides support for other git-flow tasks like managing features and hotfixes.
......@@ -10,6 +12,6 @@ For more information and usage guide, [see the wiki](https://bitbucket.org/atlas
For discussion about the plugin, [see the google group](https://groups.google.com/forum/#!forum/maven-jgitflow-users)
To log an issue or feature request, [use the issue tracker](https://bitbucket.org/atlassian/maven-jgitflow-plugin/issues)
To log an issue or feature request, [use the issue tracker](https://ecosystem.atlassian.net/browse/MJF)
Got something to say? [@sysbliss](https://twitter.com/sysbliss) #MavenJGitFlow
\ No newline at end of file
......@@ -6,13 +6,13 @@
<artifactId>oss-parent</artifactId>
<version>7</version>
</parent>
<groupId>com.atlassian.maven.plugins</groupId>
<artifactId>maven-jgitflow-plugin</artifactId>
<version>1.0-alpha26</version>
<version>1.0-alpha27</version>
<packaging>maven-plugin</packaging>
<name>Maven JGitFlow Plugin</name>
<description>A plugin to support doing git-flow releases</description>
<url>https://bitbucket.org/atlassian/maven-jgitflow-plugin</url>
......@@ -42,14 +42,14 @@
<prerequisites>
<maven>2.2.1</maven>
</prerequisites>
<scm>
<connection>scm:git:ssh://git@bitbucket.org/atlassian/maven-jgitflow-plugin.git</connection>
<developerConnection>scm:git:ssh://git@bitbucket.org/atlassian/maven-jgitflow-plugin.git</developerConnection>
<url>https://bitbucket.org/atlassian/maven-jgitflow-plugin</url>
<tag>HEAD</tag>
</scm>
<dependencies>
<dependency>
<groupId>com.atlassian.jgitflow</groupId>
......@@ -93,14 +93,14 @@
<version>${mavenVersion}</version>
</dependency>
<!--<dependency>-->
<!--<groupId>org.apache.maven</groupId>-->
<!--<artifactId>maven-compat</artifactId>-->
<!--<version>${mavenVersion}</version>-->
<!--<groupId>org.apache.maven</groupId>-->
<!--<artifactId>maven-compat</artifactId>-->
<!--<version>${mavenVersion}</version>-->
<!--</dependency>-->
<!--<dependency>-->
<!--<groupId>org.apache.maven</groupId>-->
<!--<artifactId>maven-project</artifactId>-->
<!--<version>${mavenVersion}</version>-->
<!--<groupId>org.apache.maven</groupId>-->
<!--<artifactId>maven-project</artifactId>-->
<!--<version>${mavenVersion}</version>-->
<!--</dependency>-->
<dependency>
<groupId>org.apache.maven</groupId>
......@@ -141,14 +141,14 @@
<artifactId>plexus-utils</artifactId>
<version>1.5.15</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
......@@ -160,7 +160,7 @@
<artifactId>maven-artifact</artifactId>
<version>2.2.1</version>
</dependency>
<!-- jsch agent stuff -->
<dependency>
<groupId>com.jcraft</groupId>
......@@ -178,7 +178,7 @@
<version>${jschAgentVersion}</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
......@@ -232,12 +232,12 @@
<skipErrorNoDescriptorsFound>true</skipErrorNoDescriptorsFound>
</configuration>
<executions>
<execution>
<id>mojo-descriptor</id>
<goals>
<goal>descriptor</goal>
</goals>
</execution>
<execution>
<id>mojo-descriptor</id>
<goals>
<goal>descriptor</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
......@@ -290,7 +290,7 @@
</plugins>
</build>
</profile>
<profile>
<id>it-tests</id>
<build>
......@@ -329,6 +329,58 @@
</profile>
</profiles>
<repositories>
<repository>
<id>atlas-central</id>
<url>https://maven.atlassian.com/content/repositories/central</url>
<releases>
<checksumPolicy>fail</checksumPolicy>
<enabled>true</enabled>
</releases>
<snapshots>
<checksumPolicy>fail</checksumPolicy>
<updatePolicy>never</updatePolicy>
</snapshots>
</repository>
<repository>
<id>the-real-central</id>
<url>http://repo1.maven.org/maven2</url>
<releases>
<checksumPolicy>fail</checksumPolicy>
<enabled>true</enabled>
</releases>
<snapshots>
<checksumPolicy>fail</checksumPolicy>
<updatePolicy>never</updatePolicy>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>atlas-central</id>
<url>https://maven.atlassian.com/content/repositories/central</url>
<releases>
<checksumPolicy>fail</checksumPolicy>
<enabled>true</enabled>
</releases>
<snapshots>
<checksumPolicy>fail</checksumPolicy>
<updatePolicy>never</updatePolicy>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>the-real-central</id>
<url>http://repo1.maven.org/maven2</url>
<releases>
<checksumPolicy>fail</checksumPolicy>
<enabled>true</enabled>
</releases>
<snapshots>
<checksumPolicy>fail</checksumPolicy>
<updatePolicy>never</updatePolicy>
</snapshots>
</pluginRepository>
</pluginRepositories>
<properties>
<mavenVersion>2.2.1</mavenVersion>
<!--<mavenVersion>3.0.5</mavenVersion>-->
......
package com.atlassian.maven.plugins.jgitflow;
import java.io.Console;
import java.io.IOException;
import java.io.*;
import org.codehaus.plexus.components.interactivity.AbstractInputHandler;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.Disposable;
......@@ -9,29 +8,67 @@ import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
import org.eclipse.jgit.console.ConsoleText;
import jline.ConsoleReader;
import jline.UnixTerminal;
/**
* @since version
*/
public class ConsoleInputHandler extends AbstractInputHandler implements Initializable, Disposable
{
private final Console console = System.console();
private ConsoleReader jline;
@Override
public void dispose()
public ConsoleInputHandler()
{
if(null == console)
{
return;
try
{
this.jline = new ConsoleReader();
}
catch (IOException e)
{
this.jline = null;
}
}
}
public void setCygwinTerminal()
{
try
{
console.reader().close();
this.jline = new ConsoleReader(new FileInputStream(FileDescriptor.in)
,new PrintWriter(
new OutputStreamWriter(System.out,
System.getProperty("jline.WindowsTerminal.output.encoding", System.getProperty("file.encoding"))))
,null
,new UnixTerminal());
}
catch (IOException e)
{
getLogger().error( "Error closing input stream must be ignored", e );
this.jline = null;
}
}
@Override
public void dispose()
{
if(noConsole())
{
return;
}
if(null != console)
{
try
{
console.reader().close();
}
catch (IOException e)
{
getLogger().error( "Error closing input stream must be ignored", e );
}
}
}
......@@ -44,22 +81,37 @@ public class ConsoleInputHandler extends AbstractInputHandler implements Initial
@Override
public String readLine() throws IOException
{
if(null == console)
if(null != console)
{
return "";
return console.readLine();
}
return console.readLine();
if(null != jline)
{
return jline.readLine();
}
return "";
}
@Override
public String readPassword() throws IOException
{
if(null == console)
if(null != console)
{
return "";
return new String(console.readPassword());
}
return new String(console.readPassword());
if(null != jline)
{
return jline.readLine(new Character('*'));
}
return "";
}
private boolean noConsole()
{
return (null == console && null == jline);
}
}
......@@ -43,6 +43,12 @@ public class FeatureFinishMojo extends AbstractJGitFlowMojo
@Parameter( defaultValue = "false", property = "noFeatureBuild" )
private boolean noFeatureBuild = false;
@Parameter( defaultValue = "false", property = "pullMaster" )
private boolean pullMaster = false;
@Parameter( defaultValue = "false", property = "pullDevelop" )
private boolean pullDevelop = false;
@Component(hint = "feature")
FlowReleaseManager releaseManager;
......@@ -66,6 +72,8 @@ public class FeatureFinishMojo extends AbstractJGitFlowMojo
.setNoBuild(noFeatureBuild)
.setDefaultOriginUrl(defaultOriginUrl)
.setScmCommentPrefix(scmCommentPrefix)
.setPullMaster(pullMaster)
.setPullDevelop(pullDevelop)
.setFlowInitContext(getFlowInitContext().getJGitFlowContext());
try
......
......@@ -64,6 +64,12 @@ public class HotfixFinishMojo extends AbstractJGitFlowMojo
@Parameter( property = "tagMessage" )
private String tagMessage;
@Parameter( defaultValue = "false", property = "pullMaster" )
private boolean pullMaster = false;
@Parameter( defaultValue = "false", property = "pullDevelop" )
private boolean pullDevelop = false;
@Component(hint = "hotfix")
FlowReleaseManager releaseManager;
......@@ -89,6 +95,8 @@ public class HotfixFinishMojo extends AbstractJGitFlowMojo
.setNoBuild(noHotfixBuild)
.setDefaultOriginUrl(defaultOriginUrl)
.setScmCommentPrefix(scmCommentPrefix)
.setPullMaster(pullMaster)
.setPullDevelop(pullDevelop)
.setFlowInitContext(getFlowInitContext().getJGitFlowContext());
try
......
......@@ -60,6 +60,11 @@ public class PrettyPrompter implements Prompter
useAnsiColor = false;
}
}
public void setCygwinTerminal()
{
((ConsoleInputHandler) inputHandler).setCygwinTerminal();
}
public String promptNotBlank(String message) throws PrompterException
{
......
......@@ -52,6 +52,7 @@ import org.eclipse.jgit.api.AddCommand;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.Status;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.*;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.JschConfigSessionFactory;
......@@ -69,6 +70,8 @@ public class DefaultProjectHelper extends AbstractLogEnabled implements ProjectH
private static final String ls = System.getProperty("line.separator");
private static String OS = System.getProperty("os.name").toLowerCase();
private static boolean isWindows = (OS.indexOf("win") >= 0);
private static boolean isCygwin = (isWindows && !Strings.isNullOrEmpty(System.getenv("TERM")));
private PrettyPrompter prompter;
private ArtifactFactory artifactFactory;
......@@ -85,6 +88,35 @@ public class DefaultProjectHelper extends AbstractLogEnabled implements ProjectH
this.hotfixVersions = new HashMap<String, Map<String, String>>();
}
@Override
public void fixCygwinIfNeeded(JGitFlow flow) throws JGitFlowReleaseException
{
if(isCygwin)
{
getLogger().info("detected cygwin:");
try
{
getLogger().info(" - turning off filemode...");
StoredConfig config = flow.git().getRepository().getConfig();
config.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null, ConfigConstants.CONFIG_KEY_FILEMODE, false);
config.save();
config.load();
}
catch (IOException e)
{
throw new JGitFlowReleaseException("error configuring filemode for cygwin", e);
}
catch (ConfigInvalidException e)
{
throw new JGitFlowReleaseException("error configuring filemode for cygwin", e);
}
getLogger().info(" - fixing maven prompter...");
prompter.setCygwinTerminal();
}
}
@Override
public String getReleaseVersion(ReleaseContext ctx, MavenProject rootProject) throws JGitFlowReleaseException
{
......
......@@ -24,6 +24,8 @@ public interface ProjectHelper
public static final String AT_REPORT = "report";
public static final String AT_EXTENSIONS = "extensions";
void fixCygwinIfNeeded(JGitFlow flow) throws JGitFlowReleaseException;
String getReleaseVersion(ReleaseContext ctx, MavenProject rootProject) throws JGitFlowReleaseException;
String getHotfixVersion(ReleaseContext ctx, MavenProject rootProject, String lastRelease) throws JGitFlowReleaseException;
......
......@@ -45,7 +45,9 @@ public class DefaultFlowFeatureManager extends AbstractFlowReleaseManager
try
{
flow = JGitFlow.forceInit(ctx.getBaseDir(), ctx.getFlowInitContext(), ctx.getDefaultOriginUrl());
projectHelper.fixCygwinIfNeeded(flow);
writeReportHeader(ctx, flow.getReporter());
setupCredentialProviders(ctx, flow.getReporter());
......@@ -93,11 +95,38 @@ public class DefaultFlowFeatureManager extends AbstractFlowReleaseManager
{
flow = JGitFlow.forceInit(ctx.getBaseDir(), ctx.getFlowInitContext(), ctx.getDefaultOriginUrl());
projectHelper.fixCygwinIfNeeded(flow);
JGitFlowReporter reporter = flow.getReporter();
writeReportHeader(ctx, reporter);
setupCredentialProviders(ctx, reporter);
if (ctx.isPushFeatures() || ctx.isPullDevelop())
{
projectHelper.ensureOrigin(ctx.getDefaultOriginUrl(), flow);
}
//do a pull if needed
if(GitHelper.remoteBranchExists(flow.git(), flow.getDevelopBranchName(), flow.getReporter()))
{
if(ctx.isPullDevelop())
{
reporter.debugText("finishFeature", "pulling develop before remote behind check");
reporter.flush();
flow.git().checkout().setName(flow.getDevelopBranchName()).call();
flow.git().pull().call();
}
if(GitHelper.localBranchBehindRemote(flow.git(),flow.getDevelopBranchName(),flow.getReporter()))
{
reporter.errorText("feature-finish","local branch '" + flow.getDevelopBranchName() + "' is behind the remote branch");
reporter.flush();
throw new BranchOutOfDateException("local branch '" + flow.getDevelopBranchName() + "' is behind the remote branch");
}
}
String featureLabel = getFeatureFinishName(ctx, flow);
String prefixedBranchName = flow.getFeatureBranchPrefix() + featureLabel;
......@@ -116,16 +145,6 @@ public class DefaultFlowFeatureManager extends AbstractFlowReleaseManager
}
}
if(GitHelper.remoteBranchExists(flow.git(), flow.getDevelopBranchName(), flow.getReporter()))
{
if(GitHelper.localBranchBehindRemote(flow.git(),flow.getDevelopBranchName(),flow.getReporter()))
{
reporter.errorText("feature-finish","local branch '" + flow.getDevelopBranchName() + "' is behind the remote branch");
reporter.flush();
throw new BranchOutOfDateException("local branch '" + flow.getDevelopBranchName() + "' is behind the remote branch");
}
}
if (ctx.isEnableFeatureVersions())
{
updateFeaturePomsWithNonFeatureVersion(featureLabel, flow, ctx, reactorProjects, session);
......@@ -138,10 +157,6 @@ public class DefaultFlowFeatureManager extends AbstractFlowReleaseManager
rootProject = ReleaseUtil.getRootProject(featureProjects);
}
if (ctx.isPushFeatures())
{
projectHelper.ensureOrigin(ctx.getDefaultOriginUrl(), flow);
}
if (!ctx.isNoBuild())
{
......@@ -206,6 +221,7 @@ public class DefaultFlowFeatureManager extends AbstractFlowReleaseManager
try
{
flow = JGitFlow.forceInit(ctx.getBaseDir(), ctx.getFlowInitContext(), ctx.getDefaultOriginUrl());
projectHelper.fixCygwinIfNeeded(flow);
projectHelper.ensureOrigin(ctx.getDefaultOriginUrl(), flow);
writeReportHeader(ctx, flow.getReporter());
......
......@@ -46,6 +46,8 @@ public class DefaultFlowHotfixManager extends AbstractFlowReleaseManager
{
flow = JGitFlow.forceInit(ctx.getBaseDir(), ctx.getFlowInitContext(), ctx.getDefaultOriginUrl());
projectHelper.fixCygwinIfNeeded(flow);
writeReportHeader(ctx,flow.getReporter());
setupCredentialProviders(ctx,flow.getReporter());
......@@ -102,6 +104,8 @@ public class DefaultFlowHotfixManager extends AbstractFlowReleaseManager
{
flow = JGitFlow.forceInit(ctx.getBaseDir(), ctx.getFlowInitContext(), ctx.getDefaultOriginUrl());
projectHelper.fixCygwinIfNeeded(flow);
writeReportHeader(ctx,flow.getReporter());
setupCredentialProviders(ctx,flow.getReporter());
......@@ -194,6 +198,26 @@ public class DefaultFlowHotfixManager extends AbstractFlowReleaseManager
try
{
JGitFlowReporter reporter = flow.getReporter();
//do a pull if needed
if(GitHelper.remoteBranchExists(flow.git(), flow.getDevelopBranchName(), flow.getReporter()))
{
if(ctx.isPullDevelop())
{
reporter.debugText("finishRelease", "pulling develop before remote behind check");
reporter.flush();
flow.git().checkout().setName(flow.getDevelopBranchName()).call();
flow.git().pull().call();
}
if(GitHelper.localBranchBehindRemote(flow.git(),flow.getDevelopBranchName(),flow.getReporter()))
{
reporter.errorText("hotfix-finish","local branch '" + flow.getDevelopBranchName() + "' is behind the remote branch");
reporter.flush();
throw new BranchOutOfDateException("local branch '" + flow.getDevelopBranchName() + "' is behind the remote branch");
}
}
//get the hotfix branch
List<Ref> hotfixBranches = GitHelper.listBranchesWithPrefix(flow.git(), flow.getHotfixBranchPrefix());
......@@ -224,18 +248,18 @@ public class DefaultFlowHotfixManager extends AbstractFlowReleaseManager
}
}
if(GitHelper.remoteBranchExists(flow.git(), flow.getDevelopBranchName(), flow.getReporter()))
if(GitHelper.remoteBranchExists(flow.git(), flow.getMasterBranchName(), flow.getReporter()))
{
if(GitHelper.localBranchBehindRemote(flow.git(),flow.getDevelopBranchName(),flow.getReporter()))
if(ctx.isPullMaster())
{
reporter.errorText("hotfix-finish","local branch '" + flow.getDevelopBranchName() + "' is behind the remote branch");
reporter.debugText("finishHotfix", "pulling master before remote behind check");
reporter.flush();
throw new BranchOutOfDateException("local branch '" + flow.getDevelopBranchName() + "' is behind the remote branch");
flow.git().checkout().setName(flow.getMasterBranchName()).call();
flow.git().pull().call();
flow.git().checkout().setName(prefixedBranchName).call();
}
}
if(GitHelper.remoteBranchExists(flow.git(), flow.getMasterBranchName(), flow.getReporter()))
{
if(GitHelper.localBranchBehindRemote(flow.git(),flow.getMasterBranchName(),flow.getReporter()))
{
reporter.errorText("hotfix-finish","local branch '" + flow.getMasterBranchName() + "' is behind the remote branch");
......
......@@ -40,6 +40,8 @@ public class DefaultFlowReleaseManager extends AbstractFlowReleaseManager
{
flow = JGitFlow.forceInit(ctx.getBaseDir(), ctx.getFlowInitContext(), ctx.getDefaultOriginUrl());
projectHelper.fixCygwinIfNeeded(flow);
writeReportHeader(ctx,flow.getReporter());
setupCredentialProviders(ctx,flow.getReporter());
......@@ -81,6 +83,8 @@ public class DefaultFlowReleaseManager extends AbstractFlowReleaseManager
{
flow = JGitFlow.forceInit(ctx.getBaseDir(), ctx.getFlowInitContext(), ctx.getDefaultOriginUrl());
projectHelper.fixCygwinIfNeeded(flow);
writeReportHeader(ctx,flow.getReporter());
setupCredentialProviders(ctx,flow.getReporter());
......@@ -180,6 +184,27 @@ public class DefaultFlowReleaseManager extends AbstractFlowReleaseManager
try
{
JGitFlowReporter reporter = flow.getReporter();
//do a pull if needed
if(GitHelper.remoteBranchExists(flow.git(), flow.getDevelopBranchName(), flow.getReporter()))
{
if(ctx.isPullDevelop())
{
reporter.debugText("finishRelease", "pulling develop before remote behind check");
reporter.flush();
flow.git().checkout().setName(flow.getDevelopBranchName()).call();
flow.git().pull().call();
}
if(GitHelper.localBranchBehindRemote(flow.git(),flow.getDevelopBranchName(),flow.getReporter()))
{
reporter.errorText("release-finish","local branch '" + flow.getDevelopBranchName() + "' is behind the remote branch");
reporter.flush();
throw new BranchOutOfDateException("local branch '" + flow.getDevelopBranchName() + "' is behind the remote branch");
}
}
//get the release branch
List<Ref> releaseBranches = GitHelper.listBranchesWithPrefix(flow.git(), flow.getReleaseBranchPrefix());
......@@ -214,26 +239,6 @@ public class DefaultFlowReleaseManager extends AbstractFlowReleaseManager
}
}
if(GitHelper.remoteBranchExists(flow.git(), flow.getDevelopBranchName(), flow.getReporter()))
{
if(ctx.isPullDevelop())
{
reporter.debugText("finishRelease", "pulling develop before remote behind check");
reporter.flush();
flow.git().checkout().setName(flow.getDevelopBranchName()).call();
flow.git().pull().call();
flow.git().checkout().setName(prefixedBranchName).call();
}
if(GitHelper.localBranchBehindRemote(flow.git(),flow.getDevelopBranchName(),flow.getReporter()))
{
reporter.errorText("release-finish","local branch '" + flow.getDevelopBranchName() + "' is behind the remote branch");
reporter.flush();
throw new BranchOutOfDateException("local branch '" + flow.getDevelopBranchName() + "' is behind the remote branch");
}
}
if(GitHelper.remoteBranchExists(flow.git(), flow.getMasterBranchName(), flow.getReporter()))
{
if(ctx.isPullMaster())
......
......@@ -5,11 +5,12 @@ import java.util.ArrayList;
import java.util.List;
import org.codehaus.plexus.components.interactivity.InputHandler;
import com.atlassian.maven.plugins.jgitflow.ConsoleInputHandler;
/**
* @since version
*/
public class TestInputHandler implements InputHandler
public class TestInputHandler extends ConsoleInputHandler implements InputHandler
{
private final StringBuilder sb;
......
......@@ -79,4 +79,20 @@ public class ReleaseManagerFinishReleaseTest extends AbstractFlowManagerTest
}
@Test
public void releaseFinishWithComplexVersionAndSuffix() throws Exception
{
String commentPrefix = "woot!";
String projectName = "complex-version-and-suffix";
List<MavenProject> projects = createReactorProjects("rewrite-for-release", projectName);
File projectRoot = projects.get(0).getBasedir();
ReleaseContext ctx = new ReleaseContext(projectRoot);
ctx.setInteractive(false).setNoTag(true).setAllowSnapshots(true).setReleaseBranchVersionSuffix("RC");