InlineEdit: Add method to rebase change edit
Change-Id: I09bbf692bc7812df5f608fc87455aa673b9f0cf9
This commit is contained in:
@@ -3,4 +3,5 @@ include_defs('//gerrit-acceptance-tests/tests.defs')
|
|||||||
acceptance_tests(
|
acceptance_tests(
|
||||||
srcs = ['ChangeEditIT.java'],
|
srcs = ['ChangeEditIT.java'],
|
||||||
labels = ['edit'],
|
labels = ['edit'],
|
||||||
|
deps = ['//lib/joda:joda-time'],
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -15,6 +15,8 @@
|
|||||||
package com.google.gerrit.acceptance.edit;
|
package com.google.gerrit.acceptance.edit;
|
||||||
|
|
||||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||||
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
|
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
@@ -46,11 +48,16 @@ import com.google.inject.util.Providers;
|
|||||||
import org.eclipse.jgit.api.Git;
|
import org.eclipse.jgit.api.Git;
|
||||||
import org.eclipse.jgit.lib.PersonIdent;
|
import org.eclipse.jgit.lib.PersonIdent;
|
||||||
import org.eclipse.jgit.lib.RefUpdate;
|
import org.eclipse.jgit.lib.RefUpdate;
|
||||||
|
import org.joda.time.DateTime;
|
||||||
|
import org.joda.time.DateTimeUtils;
|
||||||
|
import org.joda.time.DateTimeUtils.MillisProvider;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
@NoHttpd
|
@NoHttpd
|
||||||
public class ChangeEditIT extends AbstractDaemonTest {
|
public class ChangeEditIT extends AbstractDaemonTest {
|
||||||
@@ -84,6 +91,7 @@ public class ChangeEditIT extends AbstractDaemonTest {
|
|||||||
|
|
||||||
private ReviewDb db;
|
private ReviewDb db;
|
||||||
private Change change;
|
private Change change;
|
||||||
|
private String changeId;
|
||||||
private Change change2;
|
private Change change2;
|
||||||
private PatchSet ps;
|
private PatchSet ps;
|
||||||
private PatchSet ps2;
|
private PatchSet ps2;
|
||||||
@@ -92,22 +100,33 @@ public class ChangeEditIT extends AbstractDaemonTest {
|
|||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
db = reviewDbProvider.open();
|
db = reviewDbProvider.open();
|
||||||
String changeId = newChange(git, admin.getIdent());
|
changeId = newChange(git, admin.getIdent());
|
||||||
change = getChange(changeId);
|
|
||||||
ps = getCurrentPatchSet(changeId);
|
ps = getCurrentPatchSet(changeId);
|
||||||
|
amendChange(git, admin.getIdent(), changeId);
|
||||||
|
change = getChange(changeId);
|
||||||
assertNotNull(ps);
|
assertNotNull(ps);
|
||||||
changeId = newChange2(git, admin.getIdent());
|
String changeId2 = newChange2(git, admin.getIdent());
|
||||||
change2 = getChange(changeId);
|
change2 = getChange(changeId2);
|
||||||
assertNotNull(change2);
|
assertNotNull(change2);
|
||||||
ps2 = getCurrentPatchSet(changeId);
|
ps2 = getCurrentPatchSet(changeId2);
|
||||||
assertNotNull(ps2);
|
assertNotNull(ps2);
|
||||||
session = new RestSession(server, admin);
|
session = new RestSession(server, admin);
|
||||||
atrScope.set(atrScope.newContext(reviewDbProvider, sshSession,
|
atrScope.set(atrScope.newContext(reviewDbProvider, sshSession,
|
||||||
identifiedUserFactory.create(Providers.of(db), admin.getId())));
|
identifiedUserFactory.create(Providers.of(db), admin.getId())));
|
||||||
|
final long clockStepMs = MILLISECONDS.convert(1, SECONDS);
|
||||||
|
final AtomicLong clockMs = new AtomicLong(
|
||||||
|
new DateTime(2009, 9, 30, 17, 0, 0).getMillis());
|
||||||
|
DateTimeUtils.setCurrentMillisProvider(new MillisProvider() {
|
||||||
|
@Override
|
||||||
|
public long getMillis() {
|
||||||
|
return clockMs.getAndAdd(clockStepMs);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void cleanup() {
|
public void cleanup() {
|
||||||
|
DateTimeUtils.setCurrentMillisSystem();
|
||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,6 +147,21 @@ public class ChangeEditIT extends AbstractDaemonTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void publishEdit() throws Exception {
|
public void publishEdit() throws Exception {
|
||||||
|
assertEquals(RefUpdate.Result.NEW,
|
||||||
|
modifier.createEdit(
|
||||||
|
change,
|
||||||
|
getCurrentPatchSet(changeId)));
|
||||||
|
assertEquals(RefUpdate.Result.FORCED,
|
||||||
|
modifier.modifyFile(
|
||||||
|
editUtil.byChange(change).get(),
|
||||||
|
FILE_NAME,
|
||||||
|
CONTENT_NEW2));
|
||||||
|
editUtil.publish(editUtil.byChange(change).get());
|
||||||
|
assertFalse(editUtil.byChange(change).isPresent());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void rebaseEdit() throws Exception {
|
||||||
assertEquals(RefUpdate.Result.NEW,
|
assertEquals(RefUpdate.Result.NEW,
|
||||||
modifier.createEdit(
|
modifier.createEdit(
|
||||||
change,
|
change,
|
||||||
@@ -137,8 +171,23 @@ public class ChangeEditIT extends AbstractDaemonTest {
|
|||||||
editUtil.byChange(change).get(),
|
editUtil.byChange(change).get(),
|
||||||
FILE_NAME,
|
FILE_NAME,
|
||||||
CONTENT_NEW));
|
CONTENT_NEW));
|
||||||
editUtil.publish(editUtil.byChange(change).get());
|
ChangeEdit edit = editUtil.byChange(change).get();
|
||||||
assertFalse(editUtil.byChange(change).isPresent());
|
PatchSet current = getCurrentPatchSet(changeId);
|
||||||
|
assertEquals(current.getPatchSetId() - 1,
|
||||||
|
edit.getBasePatchSet().getPatchSetId());
|
||||||
|
Date beforeRebase = edit.getEditCommit().getCommitterIdent().getWhen();
|
||||||
|
modifier.rebaseEdit(edit, current);
|
||||||
|
edit = editUtil.byChange(change).get();
|
||||||
|
assertArrayEquals(CONTENT_NEW,
|
||||||
|
toBytes(fileUtil.getContent(edit.getChange().getProject(),
|
||||||
|
edit.getRevision().get(), FILE_NAME)));
|
||||||
|
assertArrayEquals(CONTENT_NEW2,
|
||||||
|
toBytes(fileUtil.getContent(edit.getChange().getProject(),
|
||||||
|
edit.getRevision().get(), FILE_NAME2)));
|
||||||
|
assertEquals(current.getPatchSetId(),
|
||||||
|
edit.getBasePatchSet().getPatchSetId());
|
||||||
|
Date afterRebase = edit.getEditCommit().getCommitterIdent().getWhen();
|
||||||
|
assertFalse(beforeRebase.equals(afterRebase));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -332,6 +381,13 @@ public class ChangeEditIT extends AbstractDaemonTest {
|
|||||||
return push.to(git, "refs/for/master").getChangeId();
|
return push.to(git, "refs/for/master").getChangeId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String amendChange(Git git, PersonIdent ident, String changeId) throws Exception {
|
||||||
|
PushOneCommit push =
|
||||||
|
pushFactory.create(db, ident, PushOneCommit.SUBJECT, FILE_NAME2,
|
||||||
|
new String(CONTENT_NEW2), changeId);
|
||||||
|
return push.to(git, "refs/for/master").getChangeId();
|
||||||
|
}
|
||||||
|
|
||||||
private String newChange2(Git git, PersonIdent ident) throws Exception {
|
private String newChange2(Git git, PersonIdent ident) throws Exception {
|
||||||
PushOneCommit push =
|
PushOneCommit push =
|
||||||
pushFactory.create(db, ident, PushOneCommit.SUBJECT, FILE_NAME,
|
pushFactory.create(db, ident, PushOneCommit.SUBJECT, FILE_NAME,
|
||||||
|
|||||||
@@ -46,6 +46,8 @@ import org.eclipse.jgit.lib.ObjectReader;
|
|||||||
import org.eclipse.jgit.lib.PersonIdent;
|
import org.eclipse.jgit.lib.PersonIdent;
|
||||||
import org.eclipse.jgit.lib.RefUpdate;
|
import org.eclipse.jgit.lib.RefUpdate;
|
||||||
import org.eclipse.jgit.lib.Repository;
|
import org.eclipse.jgit.lib.Repository;
|
||||||
|
import org.eclipse.jgit.merge.MergeStrategy;
|
||||||
|
import org.eclipse.jgit.merge.ThreeWayMerger;
|
||||||
import org.eclipse.jgit.revwalk.RevCommit;
|
import org.eclipse.jgit.revwalk.RevCommit;
|
||||||
import org.eclipse.jgit.revwalk.RevWalk;
|
import org.eclipse.jgit.revwalk.RevWalk;
|
||||||
import org.eclipse.jgit.treewalk.TreeWalk;
|
import org.eclipse.jgit.treewalk.TreeWalk;
|
||||||
@@ -126,6 +128,61 @@ public class ChangeEditModifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rebase change edit on latest patch set
|
||||||
|
*
|
||||||
|
* @param edit change edit that contains edit to rebase
|
||||||
|
* @param current patch set to rebase the edit on
|
||||||
|
* @throws AuthException
|
||||||
|
* @throws InvalidChangeOperationException
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public RefUpdate.Result rebaseEdit(ChangeEdit edit, PatchSet current)
|
||||||
|
throws AuthException, InvalidChangeOperationException, IOException {
|
||||||
|
if (!currentUser.get().isIdentifiedUser()) {
|
||||||
|
throw new AuthException("Authentication required");
|
||||||
|
}
|
||||||
|
|
||||||
|
Change change = edit.getChange();
|
||||||
|
IdentifiedUser me = (IdentifiedUser) currentUser.get();
|
||||||
|
String refName = editRefName(me.getAccountId(), change.getId());
|
||||||
|
Repository repo = gitManager.openRepository(change.getProject());
|
||||||
|
try {
|
||||||
|
RevWalk rw = new RevWalk(repo);
|
||||||
|
ObjectInserter inserter = repo.newObjectInserter();
|
||||||
|
try {
|
||||||
|
RevCommit editCommit = edit.getEditCommit();
|
||||||
|
RevCommit mergeTip = rw.parseCommit(ObjectId.fromString(
|
||||||
|
current.getRevision().get()));
|
||||||
|
ThreeWayMerger m = MergeStrategy.RESOLVE.newMerger(repo, true);
|
||||||
|
m.setObjectInserter(inserter);
|
||||||
|
m.setBase(editCommit.getParent(0));
|
||||||
|
if (m.merge(mergeTip, editCommit)) {
|
||||||
|
ObjectId tree = m.getResultTreeId();
|
||||||
|
|
||||||
|
CommitBuilder mergeCommit = new CommitBuilder();
|
||||||
|
mergeCommit.setTreeId(tree);
|
||||||
|
mergeCommit.setParentId(mergeTip);
|
||||||
|
mergeCommit.setAuthor(editCommit.getAuthorIdent());
|
||||||
|
mergeCommit.setCommitter(new PersonIdent(
|
||||||
|
editCommit.getCommitterIdent(), TimeUtil.nowTs()));
|
||||||
|
mergeCommit.setMessage(editCommit.getFullMessage());
|
||||||
|
ObjectId newEdit = inserter.insert(mergeCommit);
|
||||||
|
inserter.flush();
|
||||||
|
return update(repo, me, refName, rw, editCommit, newEdit);
|
||||||
|
} else {
|
||||||
|
// TODO(davido): Allow to resolve conflicts inline
|
||||||
|
throw new InvalidChangeOperationException("merge conflict");
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
rw.release();
|
||||||
|
inserter.release();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
repo.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Modify file in existing change edit from its base commit.
|
* Modify file in existing change edit from its base commit.
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user