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

com.atlassian.maven.plugins.jgitflow.manager.DefaultFlowHotfixManager Maven / Gradle / Ivy

There is a newer version: 1.0-alpha27
Show newest version
package com.atlassian.maven.plugins.jgitflow.manager;

import java.io.IOException;
import java.util.List;
import java.util.Map;

import com.atlassian.jgitflow.core.JGitFlow;
import com.atlassian.jgitflow.core.ReleaseMergeResult;
import com.atlassian.jgitflow.core.exception.HotfixBranchExistsException;
import com.atlassian.jgitflow.core.exception.JGitFlowException;
import com.atlassian.jgitflow.core.exception.JGitFlowGitAPIException;
import com.atlassian.jgitflow.core.util.GitHelper;
import com.atlassian.maven.plugins.jgitflow.MavenJGitFlowConfiguration;
import com.atlassian.maven.plugins.jgitflow.ReleaseContext;
import com.atlassian.maven.plugins.jgitflow.exception.JGitFlowReleaseException;
import com.atlassian.maven.plugins.jgitflow.exception.ReactorReloadException;
import com.atlassian.maven.plugins.jgitflow.exception.UnresolvedSnapshotsException;

import com.google.common.base.Joiner;

import org.apache.maven.execution.MavenSession;
import org.apache.maven.project.MavenProject;
import org.apache.maven.shared.release.ReleaseExecutionException;
import org.apache.maven.shared.release.exec.MavenExecutorException;
import org.apache.maven.shared.release.util.ReleaseUtil;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.InvalidRemoteException;
import org.eclipse.jgit.api.errors.TransportException;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.transport.RefSpec;

/**
 * @since version
 */
public class DefaultFlowHotfixManager extends AbstractFlowReleaseManager
{
    @Override
    public void start(ReleaseContext ctx, List originalProjects, MavenSession session) throws JGitFlowReleaseException
    {
        JGitFlow flow = null;
        MavenJGitFlowConfiguration config = null;
        try
        {
            flow = JGitFlow.forceInit(ctx.getBaseDir(), ctx.getFlowInitContext());

            writeReportHeader(ctx,flow.getReporter());
            setupSshCredentialProviders(ctx,flow.getReporter());
            
            config = configManager.getConfiguration(flow.git());

            String hotfixLabel = startHotfix(flow, config, ctx, originalProjects, session);
            updateHotfixPomsWithSnapshot(hotfixLabel, flow, ctx, config, originalProjects, session);

            if(ctx.isPushHotfixes())
            {
                final String prefixedBranchName = flow.getReleaseBranchPrefix() + hotfixLabel;
                RefSpec branchSpec = new RefSpec(prefixedBranchName);
                flow.git().push().setRemote("origin").setRefSpecs(branchSpec).call();
            }
        }
        catch (JGitFlowException e)
        {
            throw new JGitFlowReleaseException("Error starting hotfix: " + e.getMessage(), e);
        }
        catch (IOException e)
        {
            throw new JGitFlowReleaseException("Error starting hotfix: " + e.getMessage(), e);
        }
        catch (GitAPIException e)
        {
            throw new JGitFlowReleaseException("Error starting hotfix: " + e.getMessage(), e);
        }
        finally
        {
            if(null != flow)
            {
                flow.getReporter().flush();
            }
        }

        //do this separately since we just warn
        try
        {
            savePreHotfixDevelopVersions(flow, originalProjects, session, config);
        }
        catch (Exception e)
        {
            //TODO: warn that the develop versions will be foobarred after hotfix finish
        }
    }

    @Override
    public void finish(ReleaseContext ctx, List originalProjects, MavenSession session) throws JGitFlowReleaseException
    {
        JGitFlow flow = null;
        MavenJGitFlowConfiguration config = null;

        try
        {
            flow = JGitFlow.forceInit(ctx.getBaseDir(), ctx.getFlowInitContext());

            writeReportHeader(ctx,flow.getReporter());
            setupSshCredentialProviders(ctx,flow.getReporter());
            
            config = configManager.getConfiguration(flow.git());
            finishHotfix(flow, config, ctx, originalProjects, session);
        }
        catch (JGitFlowException e)
        {
            throw new JGitFlowReleaseException("Error finishing hotfix: " + e.getMessage(), e);
        }
        catch (IOException e)
        {
            throw new JGitFlowReleaseException("Error finishing hotfix: " + e.getMessage(), e);
        }
        finally
        {
            if(null != flow)
            {
                flow.getReporter().flush();
            }
        }
    }

    private String startHotfix(JGitFlow flow, MavenJGitFlowConfiguration config, ReleaseContext ctx, List originalProjects, MavenSession session) throws JGitFlowReleaseException
    {
        String hotfixLabel = "";
        try
        {
            //make sure we're on master
            flow.git().checkout().setName(flow.getMasterBranchName()).call();

            //reload the reactor projects for master
            MavenSession masterSession = getSessionForBranch(flow, flow.getMasterBranchName(), originalProjects, session);
            List masterProjects = masterSession.getSortedProjects();

            checkPomForRelease(masterProjects);

            if (!ctx.isAllowSnapshots())
            {
                List snapshots = projectHelper.checkForNonReactorSnapshots("master", masterProjects);
                if (!snapshots.isEmpty())
                {
                    String details = Joiner.on(ls).join(snapshots);
                    throw new UnresolvedSnapshotsException("Cannot start a hotfix due to snapshot dependencies:" + ls + details);
                }
            }

            if (ctx.isPushHotfixes() || !ctx.isNoTag())
            {
                projectHelper.ensureOrigin(ctx.getDefaultOriginUrl(), flow);
            }


            hotfixLabel = getHotfixLabel("hotfixlabel", ctx, masterProjects, config);
            flow.hotfixStart(hotfixLabel)
                .setAllowUntracked(ctx.isAllowUntracked())
                .setPush(ctx.isPushHotfixes())
                .setStartCommit(ctx.getStartCommit())
                .call();
        }
        catch (GitAPIException e)
        {
            throw new JGitFlowReleaseException("Error starting hotfix: " + e.getMessage(), e);
        }
        catch (HotfixBranchExistsException e)
        {
            throw new JGitFlowReleaseException("Error starting hotfix: " + e.getMessage(), e);
        }
        catch (JGitFlowException e)
        {
            throw new JGitFlowReleaseException("Error starting hotfix: " + e.getMessage(), e);
        }
        catch (IOException e)
        {
            throw new JGitFlowReleaseException("Error starting hotfix: " + e.getMessage(), e);
        }
        catch (ReactorReloadException e)
        {
            throw new JGitFlowReleaseException("Error starting hotfix: " + e.getMessage(), e);
        }

        return hotfixLabel;
    }

    private void finishHotfix(JGitFlow flow, MavenJGitFlowConfiguration config, ReleaseContext ctx, List originalProjects, MavenSession session) throws JGitFlowReleaseException
    {
        String hotfixLabel = "";

        try
        {
            //get the hotfix branch
            List hotfixBranches = GitHelper.listBranchesWithPrefix(flow.git(), flow.getHotfixBranchPrefix());

            if (hotfixBranches.isEmpty())
            {
                throw new JGitFlowReleaseException("Could not find hotfix branch!");
            }

            //there can be only one
            String rheadPrefix = Constants.R_HEADS + flow.getHotfixBranchPrefix();
            Ref hotfixBranch = hotfixBranches.get(0);
            hotfixLabel = hotfixBranch.getName().substring(hotfixBranch.getName().indexOf(rheadPrefix) + rheadPrefix.length());


            //make sure we're on the hotfix branch
            flow.git().checkout().setName(flow.getHotfixBranchPrefix() + hotfixLabel).call();

            //get the reactor projects for hotfix
            MavenSession hotfixSession = getSessionForBranch(flow, flow.getHotfixBranchPrefix() + hotfixLabel, originalProjects, session);
            List hotfixProjects = hotfixSession.getSortedProjects();

            updateHotfixPomsWithRelease(hotfixLabel,flow,ctx,config,originalProjects,session);
            projectHelper.commitAllPoms(flow.git(), originalProjects, "updating poms for " + hotfixLabel + " hotfix");

            //reload the reactor projects for hotfix
            hotfixSession = getSessionForBranch(flow, flow.getHotfixBranchPrefix() + hotfixLabel, originalProjects, session);
            hotfixProjects = hotfixSession.getSortedProjects();
            
            checkPomForRelease(hotfixProjects);

            if (!ctx.isAllowSnapshots())
            {
                List snapshots = projectHelper.checkForNonReactorSnapshots("hotfix", hotfixProjects);
                if (!snapshots.isEmpty())
                {
                    String details = Joiner.on(ls).join(snapshots);
                    throw new UnresolvedSnapshotsException("Cannot finish a hotfix due to snapshot dependencies:" + ls + details);
                }
            }

            MavenProject rootProject = ReleaseUtil.getRootProject(hotfixProjects);

            if (!ctx.isNoBuild())
            {
                try
                {
                    mavenExecutionHelper.execute(rootProject, ctx, hotfixSession);
                }
                catch (MavenExecutorException e)
                {
                    throw new JGitFlowReleaseException("Error building: " + e.getMessage(), e);
                }
            }


            Map originalVersions = projectHelper.getOriginalVersions("hotfix", hotfixProjects);

            //We need to commit the hotfix versioned poms to develop to avoid a merge conflict

            //reload the reactor projects for develop
            MavenSession developSession = getSessionForBranch(flow, flow.getDevelopBranchName(), originalProjects, session);
            List developProjects = developSession.getSortedProjects();

            savePreHotfixDevelopVersions(flow, developProjects, config);

            flow.git().checkout().setName(flow.getDevelopBranchName()).call();
            updatePomsWithVersionCopy(ctx, developProjects, hotfixProjects);
            flow.git().add().addFilepattern(".").call();
            flow.git().commit().setMessage("updating develop with hotfix versions to avoid merge conflicts").call();

            flow.git().checkout().setName(flow.getHotfixBranchPrefix() + hotfixLabel);

            if (ctx.isPushHotfixes() || !ctx.isNoTag())
            {
                projectHelper.ensureOrigin(ctx.getDefaultOriginUrl(), flow);
            }

            getLogger().info("running jgitflow hotfix finish...");
            
            ReleaseMergeResult mergeResult = flow.hotfixFinish(hotfixLabel)
                .setPush(ctx.isPushHotfixes())
                .setKeepBranch(ctx.isKeepBranch())
                .setNoTag(ctx.isNoTag())
                .setMessage(ReleaseUtil.interpolate(ctx.getTagMessage(), rootProject.getModel()))
                .setAllowUntracked(ctx.isAllowUntracked())
                .call();

            if(!mergeResult.wasSuccessful())
            {
                if(mergeResult.masterHasProblems())
                {
                    getLogger().error("Error merging into " + flow.getMasterBranchName() + ":");
                    getLogger().error(mergeResult.getMasterResult().toString());
                    getLogger().error("see .git/jgitflow.log for more info");
                }

                if(mergeResult.developHasProblems())
                {
                    getLogger().error("Error merging into " + flow.getDevelopBranchName() + ":");
                    getLogger().error(mergeResult.getDevelopResult().toString());
                    getLogger().error("see .git/jgitflow.log for more info");
                }

                throw new JGitFlowReleaseException("Error while merging hotfix!");
            }

            //make sure we're on develop
            flow.git().checkout().setName(flow.getDevelopBranchName()).call();

            //reload the reactor projects for develop
            developSession = getSessionForBranch(flow, flow.getDevelopBranchName(), originalProjects, session);
            developProjects = developSession.getSortedProjects();
            updatePomsWithPreviousVersions("develop", ctx, developProjects, config);

            projectHelper.commitAllPoms(flow.git(), developProjects, "updating poms for development");

            config.setLastReleaseVersions(originalVersions);
            configManager.saveConfiguration(config, flow.git());
        }
        catch (JGitFlowException e)
        {
            throw new JGitFlowReleaseException("Error releasing: " + e.getMessage(), e);
        }
        catch (GitAPIException e)
        {
            throw new JGitFlowReleaseException("Error releasing: " + e.getMessage(), e);
        }
        catch (ReleaseExecutionException e)
        {
            throw new JGitFlowReleaseException("Error releasing: " + e.getMessage(), e);
        }
        catch (IOException e)
        {
            throw new JGitFlowReleaseException("Error releasing: " + e.getMessage(), e);
        }
        catch (ReactorReloadException e)
        {
            throw new JGitFlowReleaseException("Error releasing: " + e.getMessage(), e);
        }
    }

    private void updateHotfixPoms(String hotfixLabel, JGitFlow flow, ReleaseContext ctx, MavenJGitFlowConfiguration config, List originalProjects, MavenSession session) throws JGitFlowReleaseException
    {
        try
        {
            //reload the reactor projects for hotfix
            MavenSession hotfixSession = getSessionForBranch(flow, flow.getHotfixBranchPrefix() + hotfixLabel, originalProjects, session);
            List hotfixProjects = hotfixSession.getSortedProjects();
            updatePomsWithHotfixVersion("hotfixlabel", ctx, hotfixProjects, config);

            projectHelper.commitAllPoms(flow.git(), hotfixProjects, "updating poms for " + hotfixLabel + " hotfix");
        }
        catch (GitAPIException e)
        {
            throw new JGitFlowReleaseException("Error starting hotfix: " + e.getMessage(), e);
        }
        catch (ReactorReloadException e)
        {
            throw new JGitFlowReleaseException("Error starting hotfix: " + e.getMessage(), e);
        }
        catch (IOException e)
        {
            throw new JGitFlowReleaseException("Error starting hotfix: " + e.getMessage(), e);
        }
    }

    private void updateHotfixPomsWithRelease(String hotfixLabel, JGitFlow flow, ReleaseContext ctx, MavenJGitFlowConfiguration config, List originalProjects, MavenSession session) throws JGitFlowReleaseException
    {
        try
        {
            //reload the reactor projects for hotfix
            MavenSession hotfixSession = getSessionForBranch(flow, flow.getHotfixBranchPrefix() + hotfixLabel, originalProjects, session);
            List hotfixProjects = hotfixSession.getSortedProjects();
            updatePomsWithHotfixVersion("hotfixlabel", hotfixLabel, ctx, hotfixProjects, config);

            projectHelper.commitAllPoms(flow.git(), hotfixProjects, "updating poms for " + hotfixLabel + " hotfix");
        }
        catch (GitAPIException e)
        {
            throw new JGitFlowReleaseException("Error starting hotfix: " + e.getMessage(), e);
        }
        catch (ReactorReloadException e)
        {
            throw new JGitFlowReleaseException("Error starting hotfix: " + e.getMessage(), e);
        }
        catch (IOException e)
        {
            throw new JGitFlowReleaseException("Error starting hotfix: " + e.getMessage(), e);
        }
    }

    private void updateHotfixPomsWithSnapshot(String hotfixLabel, JGitFlow flow, ReleaseContext ctx, MavenJGitFlowConfiguration config, List originalProjects, MavenSession session) throws JGitFlowReleaseException
    {
        try
        {
            //reload the reactor projects for hotfix
            MavenSession hotfixSession = getSessionForBranch(flow, flow.getHotfixBranchPrefix() + hotfixLabel, originalProjects, session);
            List hotfixProjects = hotfixSession.getSortedProjects();
            updatePomsWithHotfixSnapshotVersion("hotfixlabel", hotfixLabel, ctx, hotfixProjects, config);

            projectHelper.commitAllPoms(flow.git(), hotfixProjects, "updating poms for " + hotfixLabel + " hotfix");
        }
        catch (GitAPIException e)
        {
            throw new JGitFlowReleaseException("Error starting hotfix: " + e.getMessage(), e);
        }
        catch (ReactorReloadException e)
        {
            throw new JGitFlowReleaseException("Error starting hotfix: " + e.getMessage(), e);
        }
        catch (IOException e)
        {
            throw new JGitFlowReleaseException("Error starting hotfix: " + e.getMessage(), e);
        }
    }

    private void savePreHotfixDevelopVersions(JGitFlow flow, List originalProjects, MavenSession session, MavenJGitFlowConfiguration config) throws IOException, ReactorReloadException, GitAPIException
    {
        //reload the reactor projects for develop
        MavenSession developSession = getSessionForBranch(flow, flow.getDevelopBranchName(), originalProjects, session);
        List developProjects = developSession.getSortedProjects();

        Map originalDevelopVersions = projectHelper.getOriginalVersions("develop", developProjects);

        config.setPreHotfixVersions(originalDevelopVersions);
        configManager.saveConfiguration(config, flow.git());
    }

    private void savePreHotfixDevelopVersions(JGitFlow flow, List developProjects, MavenJGitFlowConfiguration config) throws IOException, GitAPIException
    {
        Map originalDevelopVersions = projectHelper.getOriginalVersions("develop", developProjects);

        config.setPreHotfixVersions(originalDevelopVersions);
        configManager.saveConfiguration(config, flow.git());
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy