PageRenderTime 46ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/jgit-flow-core/src/main/java/com/atlassian/jgitflow/core/command/HotfixFinishCommand.java

https://bitbucket.org/atlassian/jgit-flow
Java | 242 lines | 131 code | 39 blank | 72 comment | 8 complexity | 06d9a8aaddd3bb8b5208d094877dd270 MD5 | raw file
Possible License(s): Apache-2.0
  1. package com.atlassian.jgitflow.core.command;
  2. import java.util.List;
  3. import com.atlassian.jgitflow.core.GitFlowConfiguration;
  4. import com.atlassian.jgitflow.core.JGitFlowConstants;
  5. import com.atlassian.jgitflow.core.ReleaseMergeResult;
  6. import com.atlassian.jgitflow.core.exception.*;
  7. import com.atlassian.jgitflow.core.extension.HotfixFinishExtension;
  8. import com.atlassian.jgitflow.core.extension.impl.EmptyHotfixFinishExtension;
  9. import com.atlassian.jgitflow.core.extension.impl.MergeProcessExtensionWrapper;
  10. import com.atlassian.jgitflow.core.util.GitHelper;
  11. import com.atlassian.jgitflow.core.util.RequirementHelper;
  12. import org.eclipse.jgit.api.Git;
  13. import org.eclipse.jgit.api.MergeResult;
  14. import org.eclipse.jgit.api.errors.GitAPIException;
  15. import org.eclipse.jgit.lib.Ref;
  16. import org.eclipse.jgit.util.StringUtils;
  17. import static com.atlassian.jgitflow.core.util.Preconditions.checkState;
  18. /**
  19. * Finish a hotfix.
  20. * <p>
  21. * This will merge the hotfix into both master and develop and create a tag for the hotfix
  22. * </p>
  23. * <p></p>
  24. * Examples ({@code flow} is a {@link com.atlassian.jgitflow.core.JGitFlow} instance):
  25. * <p></p>
  26. * Finish a hotfix:
  27. * <p></p>
  28. * <pre>
  29. * flow.hotfixFinish(&quot;1.0&quot;).call();
  30. * </pre>
  31. * <p></p>
  32. * Don't delete the local hotfix branch
  33. * <p></p>
  34. * <pre>
  35. * flow.hotfixFinish(&quot;1.0&quot;).setKeepBranch(true).call();
  36. * </pre>
  37. * <p></p>
  38. * Squash all commits on the hotfix branch into one before merging
  39. * <p></p>
  40. * <pre>
  41. * flow.hotfixFinish(&quot;1.0&quot;).setSquash(true).call();
  42. * </pre>
  43. * <p></p>
  44. * Push changes to the remote origin
  45. * <p></p>
  46. * <pre>
  47. * flow.hotfixFinish(&quot;1.0&quot;).setPush(true).call();
  48. * </pre>
  49. * <p></p>
  50. * Don't create a tag for the hotfix
  51. * <p></p>
  52. * <pre>
  53. * flow.hotfixFinish(&quot;1.0&quot;).setNoTag(true).call();
  54. * </pre>
  55. */
  56. public class HotfixFinishCommand extends AbstractBranchMergingCommand<HotfixFinishCommand, ReleaseMergeResult>
  57. {
  58. private static final String SHORT_NAME = "hotfix-finish";
  59. private String message;
  60. private boolean noTag;
  61. private HotfixFinishExtension extension;
  62. /**
  63. * Create a new hotfix finish command instance.
  64. * <p></p>
  65. * An instance of this class is usually obtained by calling {@link com.atlassian.jgitflow.core.JGitFlow#hotfixFinish(String)}
  66. *
  67. * @param hotfixName The name/version of the hotfix
  68. * @param git The git instance to use
  69. * @param gfConfig The GitFlowConfiguration to use
  70. */
  71. public HotfixFinishCommand(String hotfixName, Git git, GitFlowConfiguration gfConfig)
  72. {
  73. super(hotfixName, git, gfConfig);
  74. checkState(!StringUtils.isEmptyOrNull(hotfixName));
  75. this.message = "tagging hotfix " + hotfixName;
  76. this.noTag = false;
  77. this.extension = new EmptyHotfixFinishExtension();
  78. }
  79. /**
  80. * @return nothing
  81. * @throws com.atlassian.jgitflow.core.exception.JGitFlowGitAPIException
  82. * @throws com.atlassian.jgitflow.core.exception.LocalBranchMissingException
  83. * @throws com.atlassian.jgitflow.core.exception.DirtyWorkingTreeException
  84. * @throws com.atlassian.jgitflow.core.exception.JGitFlowIOException
  85. * @throws com.atlassian.jgitflow.core.exception.BranchOutOfDateException
  86. */
  87. @Override
  88. public ReleaseMergeResult call() throws JGitFlowGitAPIException, LocalBranchMissingException, DirtyWorkingTreeException, JGitFlowIOException, BranchOutOfDateException, JGitFlowExtensionException, NotInitializedException
  89. {
  90. String prefixedBranchName = runBeforeAndGetPrefixedBranchName(extension.before(), JGitFlowConstants.PREFIXES.HOTFIX);
  91. enforcer().requireGitFlowInitialized();
  92. enforcer().requireLocalBranchExists(prefixedBranchName);
  93. enforcer().requireCleanWorkingTree(isAllowUntracked());
  94. MergeResult developResult = createEmptyMergeResult();
  95. MergeResult masterResult = createEmptyMergeResult();
  96. MergeResult releaseResult = createEmptyMergeResult();
  97. try
  98. {
  99. doFetchIfNeeded(extension);
  100. ensureLocalBranchesNotBehindRemotes(prefixedBranchName, gfConfig.getMaster(), gfConfig.getDevelop());
  101. //checkout the branch to merge just so we can run any extensions that need to be on this branch
  102. checkoutTopicBranch(prefixedBranchName, extension);
  103. //first merge master
  104. MergeProcessExtensionWrapper masterExtension = new MergeProcessExtensionWrapper(extension.beforeMasterCheckout(), extension.afterMasterCheckout(), extension.beforeMasterMerge(), extension.afterMasterMerge());
  105. masterResult = doMerge(prefixedBranchName, gfConfig.getMaster(), masterExtension);
  106. //now, tag master
  107. if (!noTag && masterResult.getMergeStatus().isSuccessful())
  108. {
  109. doTag(gfConfig.getMaster(), message, masterResult, extension);
  110. }
  111. //IMPORTANT: we need to back-merge master into develop so that git describe works properly
  112. MergeProcessExtensionWrapper developExtension = new MergeProcessExtensionWrapper(extension.beforeDevelopCheckout(), extension.afterDevelopCheckout(), extension.beforeDevelopMerge(), extension.afterDevelopMerge());
  113. developResult = doMerge(gfConfig.getMaster(), gfConfig.getDevelop(), developExtension);
  114. boolean mergeSuccess = checkMergeResults(masterResult, developResult);
  115. if (mergeSuccess)
  116. {
  117. doPushIfNeeded(extension, !noTag, gfConfig.getDevelop(), gfConfig.getMaster(), prefixedBranchName);
  118. }
  119. //Backmerge to release branch if needed
  120. if (releaseBranchExists())
  121. {
  122. String releaseBranchName = getReleaseBranchName();
  123. requirementHelper.requireLocalBranchExists(releaseBranchName);
  124. MergeProcessExtensionWrapper releaseExtension = new MergeProcessExtensionWrapper(extension.beforeReleaseCheckout(), extension.afterReleaseCheckout(), extension.beforeReleaseMerge(), extension.afterReleaseMerge());
  125. releaseResult = doMerge(gfConfig.getMaster(), releaseBranchName, releaseExtension);
  126. boolean releaseMergeSuccess = checkMergeResults(releaseResult);
  127. if (releaseMergeSuccess)
  128. {
  129. doPushIfNeeded(extension, !noTag, releaseBranchName);
  130. }
  131. }
  132. if (mergeSuccess)
  133. {
  134. cleanupBranchesIfNeeded(gfConfig.getDevelop(), prefixedBranchName);
  135. }
  136. reporter.infoText(getCommandName(), "checking out '" + gfConfig.getDevelop() + "'");
  137. git.checkout().setName(gfConfig.getDevelop()).call();
  138. runExtensionCommands(extension.after());
  139. return new ReleaseMergeResult(masterResult, developResult);
  140. }
  141. catch (GitAPIException e)
  142. {
  143. throw new JGitFlowGitAPIException(e);
  144. }
  145. finally
  146. {
  147. reporter.endCommand();
  148. reporter.flush();
  149. }
  150. }
  151. private boolean releaseBranchExists() throws JGitFlowGitAPIException
  152. {
  153. boolean exists = false;
  154. List<Ref> branches = GitHelper.listBranchesWithPrefix(git, gfConfig.getPrefixValue(JGitFlowConstants.PREFIXES.RELEASE.configKey()));
  155. if (!branches.isEmpty())
  156. {
  157. exists = true;
  158. }
  159. return exists;
  160. }
  161. private String getReleaseBranchName() throws JGitFlowGitAPIException
  162. {
  163. String branchName = "";
  164. List<Ref> branches = GitHelper.listBranchesWithPrefix(git, gfConfig.getPrefixValue(JGitFlowConstants.PREFIXES.RELEASE.configKey()));
  165. if (!branches.isEmpty())
  166. {
  167. branchName = branches.get(0).getName();
  168. }
  169. return branchName.substring(branchName.indexOf(gfConfig.getPrefixValue(JGitFlowConstants.PREFIXES.RELEASE.configKey())));
  170. }
  171. /**
  172. * Set the commit message for the tag creation
  173. *
  174. * @param message
  175. * @return {@code this}
  176. */
  177. public HotfixFinishCommand setMessage(String message)
  178. {
  179. this.message = message;
  180. return this;
  181. }
  182. /**
  183. * Set whether to turn off tagging
  184. *
  185. * @param noTag {@code true} to turn off tagging, {@code false}(default) otherwise
  186. * @return {@code this}
  187. */
  188. public HotfixFinishCommand setNoTag(boolean noTag)
  189. {
  190. this.noTag = noTag;
  191. return this;
  192. }
  193. public HotfixFinishCommand setExtension(HotfixFinishExtension extension)
  194. {
  195. this.extension = extension;
  196. return this;
  197. }
  198. @Override
  199. protected String getCommandName()
  200. {
  201. return SHORT_NAME;
  202. }
  203. }