Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
JENKINS-26568: New accumulated commit message:
The accumulated commit strategy is now using a commit message that is
almost identical to the squash commit message. It includes the commit
message of every included commit.

Implementation change details:

- Fixed the callback method, by limiting JGit tree walk to only work on
  branch and ignore master. That is, master commits are not collected
  and the tree walk stops.

- Minor helper method implemented in TestUtilsFactory that can count
  commits on a branch.

- All tests are moved to its own class, and there are tests written for
  a series of common cases. Each test case verifies selected text
  strings are in the new commit message.
  • Loading branch information
Bue Petersen committed Mar 5, 2015
1 parent 1657040 commit 6050417
Show file tree
Hide file tree
Showing 5 changed files with 1,591 additions and 96 deletions.
Expand Up @@ -87,9 +87,13 @@ public void integrate(AbstractBuild<?,?> build, Launcher launcher, BuildListener

listener.getLogger().println( String.format( "Preparing to merge changes in commit %s to integration branch %s", commit, gitbridge.getBranch() ) );
try {
String commits = client.withRepository(new GetAllCommitsFromBranchCallback(listener, gitDataBranch.getSHA1()));

exitCode = gitbridge.git(build, launcher, listener, out, "merge","-m", String.format("%s\n[%s]", commits, gitDataBranch.getName()), commit, "--no-ff");
// FIXME I don't like this call back design, where we collect data for commit message based on a series of commits
// which aren't really ensure to match what the 'git merge' command ends up merging.
// The method that get all commits from a branch walk the git tree using JGit, so it is complete independent from the following
// merge operation. Worst case is that the merge commit message is based on other commits than the actual merge commit consist of.
String commits = client.withRepository(new GetAllCommitsFromBranchCallback(listener, gitDataBranch.getSHA1(), gitbridge.getBranch()));
String headerLine = String.format("Accumulated commit of the following from branch '%s':\n", gitDataBranch.getName());
exitCode = gitbridge.git(build, launcher, listener, out, "merge","-m", String.format("%s\n%s", headerLine, commits), commit, "--no-ff");

} catch (Exception ex) {
logger.exiting("AccumulatedCommitStrategy ", "integrate-mergeFailure");// Generated code DONT TOUCH! Bookmark: 26b6ce59c6edbad7afa29f96febc6fd7
Expand Down
Expand Up @@ -8,12 +8,14 @@
import hudson.model.TaskListener;
import hudson.remoting.VirtualChannel;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.regex.Pattern;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.revwalk.RevWalk;

/**
Expand All @@ -22,31 +24,67 @@
*/
public class GetAllCommitsFromBranchCallback extends RepositoryListenerAwareCallback<String> {
public final ObjectId id;
public final String branch;

public GetAllCommitsFromBranchCallback(TaskListener listener, final ObjectId id) {
public GetAllCommitsFromBranchCallback(TaskListener listener, final ObjectId id, final String branch ) {
super(listener);
this.id = id;
this.id = id;
this.branch = branch;
}

@Override
public String invoke(Repository repo, VirtualChannel channel) throws IOException, InterruptedException {
StringBuilder sb = new StringBuilder();
RevWalk walk = new RevWalk(repo);

// commit on our branch, resolved from the jGit object id
RevCommit commit = walk.parseCommit(id);

Ref head = repo.getRef(Constants.HEAD);

// walk tree starting from the integration commit
walk.markStart(commit);

// limit the tree walk to keep away from master commits
// Reference for this idea is: https://wiki.eclipse.org/JGit/User_Guide#Restrict_the_walked_revision_graph
ObjectId to = repo.resolve("master");
walk.markUninteresting(walk.parseCommit(to));

// build the complete commit message, to look like squash commit msg
// iterating over the commits that will be integrated
for (RevCommit rev : walk) {
if (rev.getId().equals(head.getObjectId()))
break;

sb.append(rev.getName());
sb.append("\n");
sb.append(rev.getFullMessage());
sb.append("\n");
sb.append("\n");


// Using spaces in git commit message formatting, to avoid inconsistent
// results based on tab with, and to mimic normal recommendations
// on writing commit message (indented bullet lists with space)
// following (same) examples:
// http://chris.beams.io/posts/git-commit/
// http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
// 4 spaces are used, as this is how the squashed commit message looks like
sb.append(String.format("commit %s",rev.getName()));
sb.append(String.format("%n"));
// In the commit message overview, the author is right one to give credit (author wrote the code)
sb.append(String.format("Author: %s <%s>",rev.getAuthorIdent().getName(), rev.getAuthorIdent().getEmailAddress()));
sb.append(String.format("%n"));

Integer secondsSinceUnixEpoch = rev.getCommitTime();
SimpleDateFormat formatter = new SimpleDateFormat("EEE MMM dd hh:mm:ss yyyy ZZZZ"); //yyyy-MM-dd'T'hh:mm:ssZZZZ");
Date commitTime = new Date(secondsSinceUnixEpoch * 1000L);
String asString = formatter.format(commitTime);
sb.append(String.format("Date: %s", asString ));
sb.append(String.format("%n"));
sb.append(String.format("%n"));

String newlinechar = System.getProperty("line.separator");
String indentation = String.format("%" + 4 + "s", "");

String fullMessage = rev.getFullMessage();
Pattern myregexp = Pattern.compile(newlinechar, Pattern.MULTILINE);

String newstring = myregexp.matcher(fullMessage).replaceAll(newlinechar + indentation);

sb.append(String.format(indentation + "%s", newstring));
sb.append(String.format("%n"));
sb.append(String.format("%n"));
}

walk.dispose();
Expand Down

0 comments on commit 6050417

Please sign in to comment.