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(
 | 
			
		||||
  srcs = ['ChangeEditIT.java'],
 | 
			
		||||
  labels = ['edit'],
 | 
			
		||||
  deps = ['//lib/joda:joda-time'],
 | 
			
		||||
)
 | 
			
		||||
 
 | 
			
		||||
@@ -15,6 +15,8 @@
 | 
			
		||||
package com.google.gerrit.acceptance.edit;
 | 
			
		||||
 | 
			
		||||
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.assertEquals;
 | 
			
		||||
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.lib.PersonIdent;
 | 
			
		||||
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.Before;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
 | 
			
		||||
import java.io.ByteArrayOutputStream;
 | 
			
		||||
import java.util.Date;
 | 
			
		||||
import java.util.concurrent.atomic.AtomicLong;
 | 
			
		||||
 | 
			
		||||
@NoHttpd
 | 
			
		||||
public class ChangeEditIT extends AbstractDaemonTest {
 | 
			
		||||
@@ -84,6 +91,7 @@ public class ChangeEditIT extends AbstractDaemonTest {
 | 
			
		||||
 | 
			
		||||
  private ReviewDb db;
 | 
			
		||||
  private Change change;
 | 
			
		||||
  private String changeId;
 | 
			
		||||
  private Change change2;
 | 
			
		||||
  private PatchSet ps;
 | 
			
		||||
  private PatchSet ps2;
 | 
			
		||||
@@ -92,22 +100,33 @@ public class ChangeEditIT extends AbstractDaemonTest {
 | 
			
		||||
  @Before
 | 
			
		||||
  public void setUp() throws Exception {
 | 
			
		||||
    db = reviewDbProvider.open();
 | 
			
		||||
    String changeId = newChange(git, admin.getIdent());
 | 
			
		||||
    change = getChange(changeId);
 | 
			
		||||
    changeId = newChange(git, admin.getIdent());
 | 
			
		||||
    ps = getCurrentPatchSet(changeId);
 | 
			
		||||
    amendChange(git, admin.getIdent(), changeId);
 | 
			
		||||
    change = getChange(changeId);
 | 
			
		||||
    assertNotNull(ps);
 | 
			
		||||
    changeId = newChange2(git, admin.getIdent());
 | 
			
		||||
    change2 = getChange(changeId);
 | 
			
		||||
    String changeId2 = newChange2(git, admin.getIdent());
 | 
			
		||||
    change2 = getChange(changeId2);
 | 
			
		||||
    assertNotNull(change2);
 | 
			
		||||
    ps2 = getCurrentPatchSet(changeId);
 | 
			
		||||
    ps2 = getCurrentPatchSet(changeId2);
 | 
			
		||||
    assertNotNull(ps2);
 | 
			
		||||
    session = new RestSession(server, admin);
 | 
			
		||||
    atrScope.set(atrScope.newContext(reviewDbProvider, sshSession,
 | 
			
		||||
        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
 | 
			
		||||
  public void cleanup() {
 | 
			
		||||
    DateTimeUtils.setCurrentMillisSystem();
 | 
			
		||||
    db.close();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -128,6 +147,21 @@ public class ChangeEditIT extends AbstractDaemonTest {
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  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,
 | 
			
		||||
        modifier.createEdit(
 | 
			
		||||
            change,
 | 
			
		||||
@@ -137,8 +171,23 @@ public class ChangeEditIT extends AbstractDaemonTest {
 | 
			
		||||
            editUtil.byChange(change).get(),
 | 
			
		||||
            FILE_NAME,
 | 
			
		||||
            CONTENT_NEW));
 | 
			
		||||
    editUtil.publish(editUtil.byChange(change).get());
 | 
			
		||||
    assertFalse(editUtil.byChange(change).isPresent());
 | 
			
		||||
    ChangeEdit edit = editUtil.byChange(change).get();
 | 
			
		||||
    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
 | 
			
		||||
@@ -332,6 +381,13 @@ public class ChangeEditIT extends AbstractDaemonTest {
 | 
			
		||||
    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 {
 | 
			
		||||
    PushOneCommit push =
 | 
			
		||||
        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.RefUpdate;
 | 
			
		||||
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.RevWalk;
 | 
			
		||||
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.
 | 
			
		||||
   *
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user