From da85ca73ff8cf79da3f13542a93794a1929a8f44 Mon Sep 17 00:00:00 2001 From: Dave Borowitz Date: Wed, 11 Mar 2015 12:04:10 -0700 Subject: [PATCH] TestRepository: Add methods to amend commits or refs Change-Id: I47082416f6e281262b160ba15272258f9109abd1 --- .../eclipse/jgit/junit/TestRepository.java | 99 ++++++++++++++-- .../jgit/junit/TestRepositoryTest.java | 106 +++++++++++++++++- 2 files changed, 192 insertions(+), 13 deletions(-) diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java index 479ac7e5c..6abd34d6f 100644 --- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java +++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java @@ -435,6 +435,72 @@ public class TestRepository { return update(ref, to.create()); } + /** + * Amend an existing ref. + * + * @param ref + * the name of the reference to amend, which must already exist. + * If {@code ref} does not start with {@code refs/} and is not the + * magic names {@code HEAD} {@code FETCH_HEAD} or {@code + * MERGE_HEAD}, then {@code refs/heads/} will be prefixed in front + * of the given name, thereby assuming it is a branch. + * @return commit builder that amends the branch on commit. + * @throws Exception + */ + public CommitBuilder amendRef(String ref) throws Exception { + String name = normalizeRef(ref); + Ref r = db.getRef(name); + if (r == null) + throw new IOException("Not a ref: " + ref); + return amend(pool.parseCommit(r.getObjectId()), branch(name).commit()); + } + + /** + * Amend an existing commit. + * + * @param id + * the id of the commit to amend. + * @return commit builder. + * @throws Exception + */ + public CommitBuilder amend(AnyObjectId id) throws Exception { + return amend(pool.parseCommit(id), commit()); + } + + private CommitBuilder amend(RevCommit old, CommitBuilder b) throws Exception { + pool.parseBody(old); + b.author(old.getAuthorIdent()); + b.committer(old.getCommitterIdent()); + b.message(old.getFullMessage()); + // Use the committer name from the old commit, but update it after ticking + // the clock in CommitBuilder#create(). + b.updateCommitterTime = true; + + // Reset parents to original parents. + b.noParents(); + for (int i = 0; i < old.getParentCount(); i++) + b.parent(old.getParent(i)); + + // Reset tree to original tree; resetting parents reset tree contents to the + // first parent. + b.tree.clear(); + try (TreeWalk tw = new TreeWalk(db)) { + tw.reset(old.getTree()); + tw.setRecursive(true); + while (tw.next()) { + b.edit(new PathEdit(tw.getPathString()) { + @Override + public void apply(DirCacheEntry ent) { + ent.setFileMode(tw.getFileMode(0)); + ent.setObjectId(tw.getObjectId(0)); + } + }); + } + } + + return b; + } + /** * Update a reference to point to an object. * @@ -452,17 +518,7 @@ public class TestRepository { * @throws Exception */ public T update(String ref, T obj) throws Exception { - if (Constants.HEAD.equals(ref)) { - // nothing - } else if ("FETCH_HEAD".equals(ref)) { - // nothing - } else if ("MERGE_HEAD".equals(ref)) { - // nothing - } else if (ref.startsWith(Constants.R_REFS)) { - // nothing - } else - ref = Constants.R_HEADS + ref; - + ref = normalizeRef(ref); RefUpdate u = db.updateRef(ref); u.setNewObjectId(obj); switch (u.forceUpdate()) { @@ -478,6 +534,20 @@ public class TestRepository { } } + private static String normalizeRef(String ref) { + if (Constants.HEAD.equals(ref)) { + // nothing + } else if ("FETCH_HEAD".equals(ref)) { + // nothing + } else if ("MERGE_HEAD".equals(ref)) { + // nothing + } else if (ref.startsWith(Constants.R_REFS)) { + // nothing + } else + ref = Constants.R_HEADS + ref; + return ref; + } + /** * Soft-reset HEAD to a detached state. *

@@ -807,6 +877,8 @@ public class TestRepository { private boolean insertChangeId; + private boolean updateCommitterTime; + CommitBuilder() { branch = null; } @@ -930,8 +1002,11 @@ public class TestRepository { setAuthorAndCommitter(c); if (author != null) c.setAuthor(author); - if (committer != null) + if (committer != null) { + if (updateCommitterTime) + committer = new PersonIdent(committer, new Date(now)); c.setCommitter(committer); + } ObjectId commitId; try (ObjectInserter ins = inserter) { diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/junit/TestRepositoryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/junit/TestRepositoryTest.java index c14b32e6c..cc8ed504d 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/junit/TestRepositoryTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/junit/TestRepositoryTest.java @@ -43,19 +43,29 @@ package org.eclipse.jgit.junit; +import static java.nio.charset.StandardCharsets.UTF_8; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; +import java.util.Date; import java.util.regex.Pattern; import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription; import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository; import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.AnyObjectId; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.ObjectLoader; +import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.revwalk.RevBlob; import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevObject; import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.treewalk.TreeWalk; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -76,7 +86,7 @@ public class TestRepositoryTest { @After public void tearDown() { rw.close(); - tr.getRepository().close(); + repo.close(); } @Test @@ -168,4 +178,98 @@ public class TestRepositoryTest { assertEquals(detached, head.getObjectId()); assertFalse(head.isSymbolic()); } + + @Test + public void amendRef() throws Exception { + RevCommit root = tr.commit() + .add("todelete", "to be deleted") + .create(); + RevCommit orig = tr.commit().parent(root) + .rm("todelete") + .add("foo", "foo contents") + .add("bar", "bar contents") + .add("dir/baz", "baz contents") + .create(); + rw.parseBody(orig); + tr.branch("master").update(orig); + assertEquals("foo contents", blobAsString(orig, "foo")); + assertEquals("bar contents", blobAsString(orig, "bar")); + assertEquals("baz contents", blobAsString(orig, "dir/baz")); + + RevCommit amended = tr.amendRef("master") + .tick(3) + .add("bar", "fixed bar contents") + .create(); + assertEquals(amended, repo.getRef("refs/heads/master").getObjectId()); + rw.parseBody(amended); + + assertEquals(1, amended.getParentCount()); + assertEquals(root, amended.getParent(0)); + assertEquals(orig.getFullMessage(), amended.getFullMessage()); + assertEquals(orig.getAuthorIdent(), amended.getAuthorIdent()); + + // Committer name/email is the same, but time was incremented. + assertEquals(new PersonIdent(orig.getCommitterIdent(), new Date(0)), + new PersonIdent(amended.getCommitterIdent(), new Date(0))); + assertTrue(orig.getCommitTime() < amended.getCommitTime()); + + assertEquals("foo contents", blobAsString(amended, "foo")); + assertEquals("fixed bar contents", blobAsString(amended, "bar")); + assertEquals("baz contents", blobAsString(amended, "dir/baz")); + assertNull(TreeWalk.forPath(repo, "todelete", amended.getTree())); + } + + @Test + public void amendHead() throws Exception { + repo.updateRef("HEAD").link("refs/heads/master"); + RevCommit root = tr.commit() + .add("foo", "foo contents") + .create(); + RevCommit orig = tr.commit().parent(root) + .message("original message") + .add("bar", "bar contents") + .create(); + tr.branch("master").update(orig); + + RevCommit amended = tr.amendRef("HEAD") + .add("foo", "fixed foo contents") + .create(); + + Ref head = repo.getRef(Constants.HEAD); + assertEquals(amended, head.getObjectId()); + assertTrue(head.isSymbolic()); + assertEquals("refs/heads/master", head.getTarget().getName()); + + rw.parseBody(amended); + assertEquals("original message", amended.getFullMessage()); + assertEquals("fixed foo contents", blobAsString(amended, "foo")); + assertEquals("bar contents", blobAsString(amended, "bar")); + } + + @Test + public void amendCommit() throws Exception { + RevCommit root = tr.commit() + .add("foo", "foo contents") + .create(); + RevCommit orig = tr.commit().parent(root) + .message("original message") + .add("bar", "bar contents") + .create(); + RevCommit amended = tr.amend(orig.copy()) + .add("foo", "fixed foo contents") + .create(); + + rw.parseBody(amended); + assertEquals("original message", amended.getFullMessage()); + assertEquals("fixed foo contents", blobAsString(amended, "foo")); + assertEquals("bar contents", blobAsString(amended, "bar")); + } + + private String blobAsString(AnyObjectId treeish, String path) + throws Exception { + RevObject obj = tr.get(rw.parseTree(treeish), path); + assertSame(RevBlob.class, obj.getClass()); + ObjectLoader loader = rw.getObjectReader().open(obj); + return new String(loader.getCachedBytes(), UTF_8); + } }