Make commit message configurable

This commit is contained in:
René Pfeuffer
2018-11-08 14:59:00 +01:00
parent 97d158ab35
commit 6bddf9951f
4 changed files with 69 additions and 7 deletions

View File

@@ -10,8 +10,8 @@ import sonia.scm.repository.spi.MergeCommandRequest;
* the branches could be merged without conflicts ({@link #dryRun()}). To do so, you have to specify the name of * the branches could be merged without conflicts ({@link #dryRun()}). To do so, you have to specify the name of
* the target branch ({@link #setTargetBranch(String)}) and the name of the branch that should be merged * the target branch ({@link #setTargetBranch(String)}) and the name of the branch that should be merged
* ({@link #setBranchToMerge(String)}). Additionally you can specify an author that should be used for the commit * ({@link #setBranchToMerge(String)}). Additionally you can specify an author that should be used for the commit
* ({@link #setAuthor(Person)}) if you are not doing a dry run only. If no author is specified, the logged in user * ({@link #setAuthor(Person)}) and a message template ({@link #setMessageTemplate(String)}) if you are not doing a dry
* will be used instead. * run only. If no author is specified, the logged in user and a default message will be used instead.
* *
* To actually merge <code>feature_branch</code> into <code>integration_branch</code> do this: * To actually merge <code>feature_branch</code> into <code>integration_branch</code> do this:
* <pre><code> * <pre><code>
@@ -91,6 +91,25 @@ public class MergeCommandBuilder {
return this; return this;
} }
/**
* Use this to set a template for the commit message. If no message is set, a default message will be used.
*
* You can use the placeholder <code>{0}</code> for the branch to be merged and <code>{1}</code> for the target
* branch, eg.:
*
* <pre><code>
* ...setMessageTemplate("Merge of {0} into {1}")...
* </code></pre>
*
* This is optional and for {@link #executeMerge()} only.
*
* @return This builder instance.
*/
public MergeCommandBuilder setMessageTemplate(String messageTemplate) {
request.setMessageTemplate(messageTemplate);
return this;
}
/** /**
* Use this to reset the command. * Use this to reset the command.
* @return This builder instance. * @return This builder instance.

View File

@@ -16,6 +16,7 @@ public class MergeCommandRequest implements Validateable, Resetable, Serializabl
private String branchToMerge; private String branchToMerge;
private String targetBranch; private String targetBranch;
private Person author; private Person author;
private String messageTemplate;
public String getBranchToMerge() { public String getBranchToMerge() {
return branchToMerge; return branchToMerge;
@@ -41,6 +42,14 @@ public class MergeCommandRequest implements Validateable, Resetable, Serializabl
this.author = author; this.author = author;
} }
public String getMessageTemplate() {
return messageTemplate;
}
public void setMessageTemplate(String messageTemplate) {
this.messageTemplate = messageTemplate;
}
public boolean isValid() { public boolean isValid() {
return !Strings.isNullOrEmpty(getBranchToMerge()) return !Strings.isNullOrEmpty(getBranchToMerge())
&& !Strings.isNullOrEmpty(getTargetBranch()); && !Strings.isNullOrEmpty(getTargetBranch());

View File

@@ -1,5 +1,6 @@
package sonia.scm.repository.spi; package sonia.scm.repository.spi;
import com.google.common.base.Strings;
import org.apache.shiro.SecurityUtils; import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject; import org.apache.shiro.subject.Subject;
import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.Git;
@@ -19,15 +20,16 @@ import sonia.scm.repository.api.MergeDryRunCommandResult;
import sonia.scm.user.User; import sonia.scm.user.User;
import java.io.IOException; import java.io.IOException;
import java.text.MessageFormat;
public class GitMergeCommand extends AbstractGitCommand implements MergeCommand { public class GitMergeCommand extends AbstractGitCommand implements MergeCommand {
private static final Logger logger = LoggerFactory.getLogger(GitMergeCommand.class); private static final Logger logger = LoggerFactory.getLogger(GitMergeCommand.class);
private static final String MERGE_COMMIT_MESSAGE_TEMPLATE = private static final String MERGE_COMMIT_MESSAGE_TEMPLATE = String.join("\n",
"Merge of branch %s into %s\n" + "Merge of branch {0} into {1}",
"\n" + "",
"Automatic merge by SCM-Manager."; "Automatic merge by SCM-Manager.");
private final GitWorkdirFactory workdirFactory; private final GitWorkdirFactory workdirFactory;
@@ -64,11 +66,13 @@ public class GitMergeCommand extends AbstractGitCommand implements MergeCommand
private final String toMerge; private final String toMerge;
private final Person author; private final Person author;
private final Git clone; private final Git clone;
private final String messageTemplate;
private MergeWorker(Repository clone, MergeCommandRequest request) { private MergeWorker(Repository clone, MergeCommandRequest request) {
this.target = request.getTargetBranch(); this.target = request.getTargetBranch();
this.toMerge = request.getBranchToMerge(); this.toMerge = request.getBranchToMerge();
this.author = request.getAuthor(); this.author = request.getAuthor();
this.messageTemplate = request.getMessageTemplate();
this.clone = new Git(clone); this.clone = new Git(clone);
} }
@@ -111,13 +115,21 @@ public class GitMergeCommand extends AbstractGitCommand implements MergeCommand
try { try {
clone.commit() clone.commit()
.setAuthor(authorToUse.getName(), authorToUse.getMail()) .setAuthor(authorToUse.getName(), authorToUse.getMail())
.setMessage(String.format(MERGE_COMMIT_MESSAGE_TEMPLATE, toMerge, target)) .setMessage(MessageFormat.format(determineMessageTemplate(), toMerge, target))
.call(); .call();
} catch (GitAPIException e) { } catch (GitAPIException e) {
throw new InternalRepositoryException("could not commit merge between branch " + toMerge + " and " + target, e); throw new InternalRepositoryException("could not commit merge between branch " + toMerge + " and " + target, e);
} }
} }
private String determineMessageTemplate() {
if (Strings.isNullOrEmpty(messageTemplate)) {
return MERGE_COMMIT_MESSAGE_TEMPLATE;
} else {
return messageTemplate;
}
}
private Person determineAuthor() { private Person determineAuthor() {
if (author == null) { if (author == null) {
Subject subject = SecurityUtils.getSubject(); Subject subject = SecurityUtils.getSubject();

View File

@@ -67,14 +67,36 @@ public class GitMergeCommandTest extends AbstractGitCommandTestBase {
Iterable<RevCommit> commits = new Git(repository).log().add(repository.resolve("master")).setMaxCount(1).call(); Iterable<RevCommit> commits = new Git(repository).log().add(repository.resolve("master")).setMaxCount(1).call();
RevCommit mergeCommit = commits.iterator().next(); RevCommit mergeCommit = commits.iterator().next();
PersonIdent mergeAuthor = mergeCommit.getAuthorIdent(); PersonIdent mergeAuthor = mergeCommit.getAuthorIdent();
String message = mergeCommit.getFullMessage();
assertThat(mergeAuthor.getName()).isEqualTo("Dirk Gently"); assertThat(mergeAuthor.getName()).isEqualTo("Dirk Gently");
assertThat(mergeAuthor.getEmailAddress()).isEqualTo("dirk@holistic.det"); assertThat(mergeAuthor.getEmailAddress()).isEqualTo("dirk@holistic.det");
assertThat(message).contains("master", "mergeable");
// We expect the merge result of file b.txt here by looking up the sha hash of its content. // We expect the merge result of file b.txt here by looking up the sha hash of its content.
// If the file is missing (aka not merged correctly) this will throw a MissingObjectException: // If the file is missing (aka not merged correctly) this will throw a MissingObjectException:
byte[] contentOfFileB = repository.open(repository.resolve("9513e9c76e73f3e562fd8e4c909d0607113c77c6")).getBytes(); byte[] contentOfFileB = repository.open(repository.resolve("9513e9c76e73f3e562fd8e4c909d0607113c77c6")).getBytes();
assertThat(new String(contentOfFileB)).isEqualTo("b\ncontent from branch\n"); assertThat(new String(contentOfFileB)).isEqualTo("b\ncontent from branch\n");
} }
@Test
public void shouldUseConfiguredCommitMessageTemplate() throws IOException, GitAPIException {
GitMergeCommand command = createCommand();
MergeCommandRequest request = new MergeCommandRequest();
request.setTargetBranch("master");
request.setBranchToMerge("mergeable");
request.setAuthor(new Person("Dirk Gently", "dirk@holistic.det"));
request.setMessageTemplate("simple");
MergeCommandResult mergeCommandResult = command.merge(request);
assertThat(mergeCommandResult.isSuccess()).isTrue();
Repository repository = createContext().open();
Iterable<RevCommit> commits = new Git(repository).log().add(repository.resolve("master")).setMaxCount(1).call();
RevCommit mergeCommit = commits.iterator().next();
String message = mergeCommit.getFullMessage();
assertThat(message).isEqualTo("simple");
}
@Test @Test
public void shouldNotMergeConflictingBranches() { public void shouldNotMergeConflictingBranches() {
GitMergeCommand command = createCommand(); GitMergeCommand command = createCommand();