PageRenderTime 26ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

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

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