Merge changes from topic 'addUpdateChange'

* changes:
  Add new REST api for creating a merge patch set for change
  Refactor ReplaceOp for updating change rest api
This commit is contained in:
Dave Borowitz
2016-10-17 19:40:35 +00:00
committed by Gerrit Code Review
9 changed files with 453 additions and 10 deletions

View File

@@ -517,6 +517,61 @@ describes the change.
} }
---- ----
[[create-merge-patch-set-for-change]]
=== Create Merge Patch Set For Change
--
'POST /changes/link:#change-id[\{change-id\}]/merge'
--
Update an existing change by using a
link:#merge-patch-set-input[MergePatchSetInput] entity.
Gerrit will create a merge commit based on the information of
MergePatchSetInput and add a new patch set to the change corresponding
to the new merge commit.
.Request
----
POST /changes/test~master~Ic5466d107c5294414710935a8ef3b0180fb848dc/merge HTTP/1.0
Content-Type: application/json; charset=UTF-8
{
"source": "refs/12/1234/1"
}
----
As response a link:#change-info[ChangeInfo] entity with current revision is
returned that describes the resulting change.
.Response
----
HTTP/1.1 200 OK
Content-Disposition: attachment
Content-Type: application/json; charset=UTF-8
)]}'
{
"id": "test~master~Ic5466d107c5294414710935a8ef3b0180fb848dc",
"project": "test",
"branch": "master",
"hashtags": [],
"change_id": "Ic5466d107c5294414710935a8ef3b0180fb848dc",
"subject": "Merge dev_branch into master",
"status": "NEW",
"created": "2016-09-23 18:08:53.238000000",
"updated": "2016-09-23 18:09:25.934000000",
"submit_type": "MERGE_IF_NECESSARY",
"mergeable": true,
"insertions": 5,
"deletions": 0,
"_number": 72,
"owner": {
"_account_id": 1000000
},
"current_revision": "27cc4558b5a3d3387dd11ee2df7a117e7e581822"
}
----
[[get-change-detail]] [[get-change-detail]]
=== Get Change Detail === Get Change Detail
-- --
@@ -5367,6 +5422,25 @@ The strategy of the merge, can be `recursive`, `resolve`,
`simple-two-way-in-core`, `ours` or `theirs`, default will use project settings. `simple-two-way-in-core`, `ours` or `theirs`, default will use project settings.
|============================ |============================
[[merge-patch-set-input]]
=== MergePatchSetInput
The `MergePatchSetInput` entity contains information about updating a new
change by creating a new merge commit.
[options="header",cols="1,^1,5"]
|==================================
|Field Name ||Description
|`subject` |optional|
The new subject for the change, if not specified, will reuse the current patch
set's subject
|`inheritParent` |optional, default to `false`|
Use the current patch set's first parent as the merge tip when set to `true`.
Otherwise, use the current branch tip of the destination branch.
|`merge` ||
The detail of the source commit for merge as a link:#merge-input[MergeInput]
entity.
|==================================
[[move-input]] [[move-input]]
=== MoveInput === MoveInput
The `MoveInput` entity contains information for moving a change to a new branch. The `MoveInput` entity contains information for moving a change to a new branch.

View File

@@ -61,9 +61,11 @@ import com.google.gerrit.extensions.common.ApprovalInfo;
import com.google.gerrit.extensions.common.ChangeInfo; import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.common.ChangeInput; import com.google.gerrit.extensions.common.ChangeInput;
import com.google.gerrit.extensions.common.ChangeMessageInfo; import com.google.gerrit.extensions.common.ChangeMessageInfo;
import com.google.gerrit.extensions.common.MergePatchSetInput;
import com.google.gerrit.extensions.common.CommitInfo; import com.google.gerrit.extensions.common.CommitInfo;
import com.google.gerrit.extensions.common.GitPerson; import com.google.gerrit.extensions.common.GitPerson;
import com.google.gerrit.extensions.common.LabelInfo; import com.google.gerrit.extensions.common.LabelInfo;
import com.google.gerrit.extensions.common.MergeInput;
import com.google.gerrit.extensions.common.RevisionInfo; import com.google.gerrit.extensions.common.RevisionInfo;
import com.google.gerrit.extensions.restapi.AuthException; import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.ResourceConflictException; import com.google.gerrit.extensions.restapi.ResourceConflictException;
@@ -71,6 +73,7 @@ import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.UnprocessableEntityException; import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
import com.google.gerrit.reviewdb.client.Account; import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup; import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.Branch;
import com.google.gerrit.reviewdb.client.Change; import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.LabelId; import com.google.gerrit.reviewdb.client.LabelId;
import com.google.gerrit.reviewdb.client.PatchSet; import com.google.gerrit.reviewdb.client.PatchSet;
@@ -1921,6 +1924,86 @@ public class ChangeIT extends AbstractDaemonTest {
+ r1.getChange().getId().id + "."); + r1.getChange().getId().id + ".");
} }
@Test
public void testCreateMergePatchSet() throws Exception {
PushOneCommit.Result start = pushTo("refs/heads/master");
start.assertOkStatus();
// create a change for master
PushOneCommit.Result r = createChange();
r.assertOkStatus();
String changeId = r.getChangeId();
testRepo.reset(start.getCommit());
PushOneCommit.Result currentMaster = pushTo("refs/heads/master");
currentMaster.assertOkStatus();
String parent = currentMaster.getCommit().getName();
// push a commit into dev branch
createBranch(new Branch.NameKey(project, "dev"));
PushOneCommit.Result changeA = pushFactory
.create(db, user.getIdent(), testRepo, "change A", "A.txt", "A content")
.to("refs/heads/dev");
changeA.assertOkStatus();
MergeInput mergeInput = new MergeInput();
mergeInput.source = "dev";
MergePatchSetInput in = new MergePatchSetInput();
in.merge = mergeInput;
in.subject = "update change by merge ps2";
gApi.changes().id(changeId).createMergePatchSet(in);
ChangeInfo changeInfo = gApi.changes().id(changeId)
.get(EnumSet.of(ListChangesOption.ALL_REVISIONS,
ListChangesOption.CURRENT_COMMIT,
ListChangesOption.CURRENT_REVISION));
assertThat(changeInfo.revisions.size()).isEqualTo(2);
assertThat(changeInfo.subject).isEqualTo(in.subject);
assertThat(
changeInfo.revisions.get(changeInfo.currentRevision).commit.parents
.get(0).commit).isEqualTo(parent);
}
@Test
public void testCreateMergePatchSetInheritParent() throws Exception {
PushOneCommit.Result start = pushTo("refs/heads/master");
start.assertOkStatus();
// create a change for master
PushOneCommit.Result r = createChange();
r.assertOkStatus();
String changeId = r.getChangeId();
String parent = r.getCommit().getParent(0).getName();
// advance master branch
testRepo.reset(start.getCommit());
PushOneCommit.Result currentMaster = pushTo("refs/heads/master");
currentMaster.assertOkStatus();
// push a commit into dev branch
createBranch(new Branch.NameKey(project, "dev"));
PushOneCommit.Result changeA = pushFactory
.create(db, user.getIdent(), testRepo, "change A", "A.txt", "A content")
.to("refs/heads/dev");
changeA.assertOkStatus();
MergeInput mergeInput = new MergeInput();
mergeInput.source = "dev";
MergePatchSetInput in = new MergePatchSetInput();
in.merge = mergeInput;
in.subject = "update change by merge ps2 inherit parent of ps1";
in.inheritParent = true;
gApi.changes().id(changeId).createMergePatchSet(in);
ChangeInfo changeInfo = gApi.changes().id(changeId)
.get(EnumSet.of(ListChangesOption.ALL_REVISIONS,
ListChangesOption.CURRENT_COMMIT,
ListChangesOption.CURRENT_REVISION));
assertThat(changeInfo.revisions.size()).isEqualTo(2);
assertThat(changeInfo.subject).isEqualTo(in.subject);
assertThat(
changeInfo.revisions.get(changeInfo.currentRevision).commit.parents
.get(0).commit).isEqualTo(parent);
assertThat(
changeInfo.revisions.get(changeInfo.currentRevision).commit.parents
.get(0).commit).isNotEqualTo(currentMaster.getCommit().getName());
}
private static Iterable<Account.Id> getReviewers( private static Iterable<Account.Id> getReviewers(
Collection<AccountInfo> r) { Collection<AccountInfo> r) {
return Iterables.transform(r, a -> new Account.Id(a._accountId)); return Iterables.transform(r, a -> new Account.Id(a._accountId));

View File

@@ -17,6 +17,7 @@ package com.google.gerrit.extensions.api.changes;
import com.google.gerrit.extensions.client.ListChangesOption; import com.google.gerrit.extensions.client.ListChangesOption;
import com.google.gerrit.extensions.common.AccountInfo; import com.google.gerrit.extensions.common.AccountInfo;
import com.google.gerrit.extensions.common.ChangeInfo; import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.common.MergePatchSetInput;
import com.google.gerrit.extensions.common.CommentInfo; import com.google.gerrit.extensions.common.CommentInfo;
import com.google.gerrit.extensions.common.EditInfo; import com.google.gerrit.extensions.common.EditInfo;
import com.google.gerrit.extensions.common.SuggestedReviewerInfo; import com.google.gerrit.extensions.common.SuggestedReviewerInfo;
@@ -95,6 +96,9 @@ public interface ChangeApi {
*/ */
ChangeApi revert(RevertInput in) throws RestApiException; ChangeApi revert(RevertInput in) throws RestApiException;
/** Create a merge patch set for the change. */
ChangeInfo createMergePatchSet(MergePatchSetInput in) throws RestApiException;
List<ChangeInfo> submittedTogether() throws RestApiException; List<ChangeInfo> submittedTogether() throws RestApiException;
SubmittedTogetherInfo submittedTogether( SubmittedTogetherInfo submittedTogether(
EnumSet<SubmittedTogetherOption> options) throws RestApiException; EnumSet<SubmittedTogetherOption> options) throws RestApiException;
@@ -412,5 +416,11 @@ public interface ChangeApi {
EnumSet<SubmittedTogetherOption> b) throws RestApiException { EnumSet<SubmittedTogetherOption> b) throws RestApiException {
throw new NotImplementedException(); throw new NotImplementedException();
} }
@Override
public ChangeInfo createMergePatchSet(MergePatchSetInput in)
throws RestApiException {
throw new NotImplementedException();
}
} }
} }

View File

@@ -0,0 +1,21 @@
// Copyright (C) 2016 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gerrit.extensions.common;
public class MergePatchSetInput {
public String subject;
public boolean inheritParent;
public MergeInput merge;
}

View File

@@ -31,6 +31,7 @@ import com.google.gerrit.extensions.api.changes.SubmittedTogetherOption;
import com.google.gerrit.extensions.client.ListChangesOption; import com.google.gerrit.extensions.client.ListChangesOption;
import com.google.gerrit.extensions.common.AccountInfo; import com.google.gerrit.extensions.common.AccountInfo;
import com.google.gerrit.extensions.common.ChangeInfo; import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.common.MergePatchSetInput;
import com.google.gerrit.extensions.common.CommentInfo; import com.google.gerrit.extensions.common.CommentInfo;
import com.google.gerrit.extensions.common.EditInfo; import com.google.gerrit.extensions.common.EditInfo;
import com.google.gerrit.extensions.common.SuggestedReviewerInfo; import com.google.gerrit.extensions.common.SuggestedReviewerInfo;
@@ -63,7 +64,9 @@ import com.google.gerrit.server.change.Reviewers;
import com.google.gerrit.server.change.Revisions; import com.google.gerrit.server.change.Revisions;
import com.google.gerrit.server.change.SubmittedTogether; import com.google.gerrit.server.change.SubmittedTogether;
import com.google.gerrit.server.change.SuggestChangeReviewers; import com.google.gerrit.server.change.SuggestChangeReviewers;
import com.google.gerrit.server.change.CreateMergePatchSet;
import com.google.gerrit.server.git.UpdateException; import com.google.gerrit.server.git.UpdateException;
import com.google.gerrit.server.project.InvalidChangeOperationException;
import com.google.gerrit.server.project.NoSuchChangeException; import com.google.gerrit.server.project.NoSuchChangeException;
import com.google.gwtorm.server.OrmException; import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject; import com.google.inject.Inject;
@@ -91,6 +94,7 @@ class ChangeApiImpl implements ChangeApi {
private final Abandon abandon; private final Abandon abandon;
private final Revert revert; private final Revert revert;
private final Restore restore; private final Restore restore;
private final CreateMergePatchSet updateByMerge;
private final Provider<SubmittedTogether> submittedTogether; private final Provider<SubmittedTogether> submittedTogether;
private final PublishDraftPatchSet.CurrentRevision private final PublishDraftPatchSet.CurrentRevision
publishDraftChange; publishDraftChange;
@@ -122,6 +126,7 @@ class ChangeApiImpl implements ChangeApi {
Abandon abandon, Abandon abandon,
Revert revert, Revert revert,
Restore restore, Restore restore,
CreateMergePatchSet updateByMerge,
Provider<SubmittedTogether> submittedTogether, Provider<SubmittedTogether> submittedTogether,
PublishDraftPatchSet.CurrentRevision publishDraftChange, PublishDraftPatchSet.CurrentRevision publishDraftChange,
DeleteDraftChange deleteDraftChange, DeleteDraftChange deleteDraftChange,
@@ -151,6 +156,7 @@ class ChangeApiImpl implements ChangeApi {
this.suggestReviewers = suggestReviewers; this.suggestReviewers = suggestReviewers;
this.abandon = abandon; this.abandon = abandon;
this.restore = restore; this.restore = restore;
this.updateByMerge = updateByMerge;
this.submittedTogether = submittedTogether; this.submittedTogether = submittedTogether;
this.publishDraftChange = publishDraftChange; this.publishDraftChange = publishDraftChange;
this.deleteDraftChange = deleteDraftChange; this.deleteDraftChange = deleteDraftChange;
@@ -267,6 +273,17 @@ class ChangeApiImpl implements ChangeApi {
} }
} }
@Override
public ChangeInfo createMergePatchSet(MergePatchSetInput in)
throws RestApiException {
try {
return updateByMerge.apply(change, in).value();
} catch (IOException | UpdateException | InvalidChangeOperationException
| NoSuchChangeException | OrmException e) {
throw new RestApiException("Cannot update change by merge", e);
}
}
@Override @Override
public List<ChangeInfo> submittedTogether() throws RestApiException { public List<ChangeInfo> submittedTogether() throws RestApiException {
SubmittedTogetherInfo info = submittedTogether( SubmittedTogetherInfo info = submittedTogether(

View File

@@ -0,0 +1,212 @@
// Copyright (C) 2016 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gerrit.server.change;
import com.google.common.base.MoreObjects;
import com.google.common.base.Strings;
import com.google.gerrit.common.TimeUtil;
import com.google.gerrit.extensions.api.changes.NotifyHandling;
import com.google.gerrit.extensions.client.ListChangesOption;
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.common.MergePatchSetInput;
import com.google.gerrit.extensions.common.MergeInput;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.MergeConflictException;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.extensions.restapi.RestModifyView;
import com.google.gerrit.reviewdb.client.Branch;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.ChangeUtil;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.PatchSetUtil;
import com.google.gerrit.server.git.BatchUpdate;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.MergeIdenticalTreeException;
import com.google.gerrit.server.git.MergeUtil;
import com.google.gerrit.server.git.UpdateException;
import com.google.gerrit.server.project.ChangeControl;
import com.google.gerrit.server.project.InvalidChangeOperationException;
import com.google.gerrit.server.project.NoSuchChangeException;
import com.google.gerrit.server.project.ProjectControl;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.util.ChangeIdUtil;
import java.io.IOException;
import java.sql.Timestamp;
import java.util.EnumSet;
import java.util.TimeZone;
@Singleton
public class CreateMergePatchSet implements
RestModifyView<ChangeResource, MergePatchSetInput> {
private final Provider<ReviewDb> db;
private final GitRepositoryManager gitManager;
private final TimeZone serverTimeZone;
private final Provider<CurrentUser> user;
private final ChangeJson.Factory jsonFactory;
private final PatchSetUtil psUtil;
private final MergeUtil.Factory mergeUtilFactory;
private final BatchUpdate.Factory batchUpdateFactory;
private final PatchSetInserter.Factory patchSetInserterFactory;
@Inject
CreateMergePatchSet(Provider<ReviewDb> db,
GitRepositoryManager gitManager,
@GerritPersonIdent PersonIdent myIdent,
Provider<CurrentUser> user,
ChangeJson.Factory json,
PatchSetUtil psUtil,
MergeUtil.Factory mergeUtilFactory,
BatchUpdate.Factory batchUpdateFactory,
PatchSetInserter.Factory patchSetInserterFactory) {
this.db = db;
this.gitManager = gitManager;
this.serverTimeZone = myIdent.getTimeZone();
this.user = user;
this.jsonFactory = json;
this.psUtil = psUtil;
this.mergeUtilFactory = mergeUtilFactory;
this.batchUpdateFactory = batchUpdateFactory;
this.patchSetInserterFactory = patchSetInserterFactory;
}
@Override
public Response<ChangeInfo> apply(ChangeResource req, MergePatchSetInput in)
throws NoSuchChangeException, OrmException, IOException,
InvalidChangeOperationException, RestApiException, UpdateException {
if (in.merge == null) {
throw new BadRequestException("merge field is required");
}
MergeInput merge = in.merge;
if (Strings.isNullOrEmpty(merge.source)) {
throw new BadRequestException("merge.source must be non-empty");
}
ChangeControl ctl = req.getControl();
if (!ctl.isVisible(db.get())) {
throw new InvalidChangeOperationException(
"Base change not found: " + req.getId());
}
PatchSet ps = psUtil.current(db.get(), ctl.getNotes());
if (!ctl.canAddPatchSet(db.get())) {
throw new AuthException("cannot add patch set");
}
ProjectControl projectControl = ctl.getProjectControl();
Change change = ctl.getChange();
Project.NameKey project = change.getProject();
Branch.NameKey dest = change.getDest();
try (Repository git = gitManager.openRepository(project);
ObjectInserter oi = git.newObjectInserter();
RevWalk rw = new RevWalk(oi.newReader())) {
RevCommit sourceCommit =
MergeUtil.resolveCommit(git, rw, merge.source);
if (!projectControl.canReadCommit(db.get(), git, sourceCommit)) {
throw new ResourceNotFoundException(
"cannot find source commit: " + merge.source + " to merge.");
}
RevCommit currentPsCommit =
rw.parseCommit(ObjectId.fromString(ps.getRevision().get()));
Timestamp now = TimeUtil.nowTs();
IdentifiedUser me = user.get().asIdentifiedUser();
PersonIdent author = me.newCommitterIdent(now, serverTimeZone);
RevCommit newCommit =
createMergeCommit(in, projectControl, dest, git, oi, rw,
currentPsCommit, sourceCommit, author,
ObjectId.fromString(change.getKey().get().substring(1)));
PatchSet.Id nextPsId = ChangeUtil.nextPatchSetId(ps.getId());
PatchSetInserter psInserter =
patchSetInserterFactory.create(ctl, nextPsId, newCommit);
try (BatchUpdate bu = batchUpdateFactory
.create(db.get(), project, me, now)) {
bu.setRepository(git, rw, oi);
bu.addOp(ctl.getId(), psInserter
.setMessage("Uploaded patch set " + nextPsId.get() + ".")
.setDraft(ps.isDraft())
.setNotify(NotifyHandling.NONE));
bu.execute();
}
ChangeJson json =
jsonFactory.create(EnumSet.of(ListChangesOption.CURRENT_REVISION));
return Response.ok(json.format(psInserter.getChange()));
}
}
private RevCommit createMergeCommit(MergePatchSetInput in,
ProjectControl projectControl, Branch.NameKey dest, Repository git,
ObjectInserter oi, RevWalk rw, RevCommit currentPsCommit,
RevCommit sourceCommit, PersonIdent author, ObjectId changeId)
throws ResourceNotFoundException, MergeIdenticalTreeException,
MergeConflictException, IOException {
ObjectId parentCommit;
if (in.inheritParent) {
// inherit first parent from previous patch set
parentCommit = currentPsCommit.getParent(0);
} else {
// get the current branch tip of destination branch
Ref destRef = git.getRefDatabase().exactRef(dest.get());
if (destRef != null) {
parentCommit = destRef.getObjectId();
} else {
throw new ResourceNotFoundException("cannot find destination branch");
}
}
RevCommit mergeTip = rw.parseCommit(parentCommit);
String commitMsg;
if (Strings.emptyToNull(in.subject) != null) {
commitMsg = ChangeIdUtil.insertId(in.subject, changeId);
} else {
// reuse previous patch set commit message
commitMsg = currentPsCommit.getFullMessage();
}
String mergeStrategy = MoreObjects.firstNonNull(
Strings.emptyToNull(in.merge.strategy),
mergeUtilFactory.create(projectControl.getProjectState())
.mergeStrategyName());
return MergeUtil.createMergeCommit(git, oi, mergeTip, sourceCommit,
mergeStrategy, author, commitMsg, rw);
}
}

View File

@@ -53,6 +53,7 @@ public class Module extends RestApiModule {
DynamicMap.mapOf(binder(), VOTE_KIND); DynamicMap.mapOf(binder(), VOTE_KIND);
get(CHANGE_KIND).to(GetChange.class); get(CHANGE_KIND).to(GetChange.class);
post(CHANGE_KIND, "merge").to(CreateMergePatchSet.class);
get(CHANGE_KIND, "detail").to(GetDetail.class); get(CHANGE_KIND, "detail").to(GetDetail.class);
get(CHANGE_KIND, "topic").to(GetTopic.class); get(CHANGE_KIND, "topic").to(GetTopic.class);
get(CHANGE_KIND, "in").to(IncludedIn.class); get(CHANGE_KIND, "in").to(IncludedIn.class);

View File

@@ -2433,10 +2433,12 @@ public class ReceiveCommits {
rw.parseBody(newCommit); rw.parseBody(newCommit);
RevCommit priorCommit = revisions.inverse().get(priorPatchSet); RevCommit priorCommit = revisions.inverse().get(priorPatchSet);
replaceOp = replaceOpFactory.create(requestScopePropagator, replaceOp = replaceOpFactory
projectControl, notes.getChange().getDest(), checkMergedInto, .create(projectControl, notes.getChange().getDest(), checkMergedInto,
priorPatchSet, priorCommit, psId, newCommit, info, groups, priorPatchSet, priorCommit, psId, newCommit, info, groups,
magicBranch, rp.getPushCertificate()); magicBranch, rp.getPushCertificate())
.setRequestScopePropagator(requestScopePropagator)
.setUpdateRef(false);
bu.addOp(notes.getChangeId(), replaceOp); bu.addOp(notes.getChangeId(), replaceOp);
if (progress != null) { if (progress != null) {
bu.addOp(notes.getChangeId(), new ChangeProgressOp(progress)); bu.addOp(notes.getChangeId(), new ChangeProgressOp(progress));

View File

@@ -64,6 +64,7 @@ import org.eclipse.jgit.lib.RefDatabase;
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.transport.PushCertificate; import org.eclipse.jgit.transport.PushCertificate;
import org.eclipse.jgit.transport.ReceiveCommand;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -78,7 +79,6 @@ import java.util.concurrent.ExecutorService;
public class ReplaceOp extends BatchUpdate.Op { public class ReplaceOp extends BatchUpdate.Op {
public interface Factory { public interface Factory {
ReplaceOp create( ReplaceOp create(
RequestScopePropagator requestScopePropagator,
ProjectControl projectControl, ProjectControl projectControl,
Branch.NameKey dest, Branch.NameKey dest,
boolean checkMergedInto, boolean checkMergedInto,
@@ -112,7 +112,6 @@ public class ReplaceOp extends BatchUpdate.Op {
private final PatchSetUtil psUtil; private final PatchSetUtil psUtil;
private final ReplacePatchSetSender.Factory replacePatchSetFactory; private final ReplacePatchSetSender.Factory replacePatchSetFactory;
private final RequestScopePropagator requestScopePropagator;
private final ProjectControl projectControl; private final ProjectControl projectControl;
private final Branch.NameKey dest; private final Branch.NameKey dest;
private final boolean checkMergedInto; private final boolean checkMergedInto;
@@ -133,6 +132,8 @@ public class ReplaceOp extends BatchUpdate.Op {
private ChangeMessage msg; private ChangeMessage msg;
private String rejectMessage; private String rejectMessage;
private MergedByPushOp mergedByPushOp; private MergedByPushOp mergedByPushOp;
private RequestScopePropagator requestScopePropagator;
private boolean updateRef;
@AssistedInject @AssistedInject
ReplaceOp(AccountResolver accountResolver, ReplaceOp(AccountResolver accountResolver,
@@ -149,7 +150,6 @@ public class ReplaceOp extends BatchUpdate.Op {
PatchSetUtil psUtil, PatchSetUtil psUtil,
ReplacePatchSetSender.Factory replacePatchSetFactory, ReplacePatchSetSender.Factory replacePatchSetFactory,
@SendEmailExecutor ExecutorService sendEmailExecutor, @SendEmailExecutor ExecutorService sendEmailExecutor,
@Assisted RequestScopePropagator requestScopePropagator,
@Assisted ProjectControl projectControl, @Assisted ProjectControl projectControl,
@Assisted Branch.NameKey dest, @Assisted Branch.NameKey dest,
@Assisted boolean checkMergedInto, @Assisted boolean checkMergedInto,
@@ -176,7 +176,6 @@ public class ReplaceOp extends BatchUpdate.Op {
this.replacePatchSetFactory = replacePatchSetFactory; this.replacePatchSetFactory = replacePatchSetFactory;
this.sendEmailExecutor = sendEmailExecutor; this.sendEmailExecutor = sendEmailExecutor;
this.requestScopePropagator = requestScopePropagator;
this.projectControl = projectControl; this.projectControl = projectControl;
this.dest = dest; this.dest = dest;
this.checkMergedInto = checkMergedInto; this.checkMergedInto = checkMergedInto;
@@ -188,6 +187,7 @@ public class ReplaceOp extends BatchUpdate.Op {
this.groups = groups; this.groups = groups;
this.magicBranch = magicBranch; this.magicBranch = magicBranch;
this.pushCertificate = pushCertificate; this.pushCertificate = pushCertificate;
this.updateRef = true;
} }
@Override @Override
@@ -203,6 +203,12 @@ public class ReplaceOp extends BatchUpdate.Op {
requestScopePropagator, patchSetId, mergedInto.getName()); requestScopePropagator, patchSetId, mergedInto.getName());
} }
} }
if (updateRef) {
ctx.addRefUpdate(
new ReceiveCommand(ObjectId.zeroId(), commit,
patchSetId.toRefName()));
}
} }
@Override @Override
@@ -366,8 +372,10 @@ public class ReplaceOp extends BatchUpdate.Op {
// BatchUpdate's perspective there is no ref update. Thus we have to fire it // BatchUpdate's perspective there is no ref update. Thus we have to fire it
// manually. // manually.
final Account account = ctx.getAccount(); final Account account = ctx.getAccount();
gitRefUpdated.fire(ctx.getProject(), newPatchSet.getRefName(), if (!updateRef) {
ObjectId.zeroId(), commit, account); gitRefUpdated.fire(ctx.getProject(), newPatchSet.getRefName(),
ObjectId.zeroId(), commit, account);
}
if (changeKind != ChangeKind.TRIVIAL_REBASE) { if (changeKind != ChangeKind.TRIVIAL_REBASE) {
Runnable sender = new Runnable() { Runnable sender = new Runnable() {
@@ -454,10 +462,25 @@ public class ReplaceOp extends BatchUpdate.Op {
return newPatchSet; return newPatchSet;
} }
public Change getChange() {
return change;
}
public String getRejectMessage() { public String getRejectMessage() {
return rejectMessage; return rejectMessage;
} }
public ReplaceOp setUpdateRef(boolean updateRef) {
this.updateRef = updateRef;
return this;
}
public ReplaceOp setRequestScopePropagator(
RequestScopePropagator requestScopePropagator) {
this.requestScopePropagator = requestScopePropagator;
return this;
}
private Ref findMergedInto(Context ctx, String first, RevCommit commit) { private Ref findMergedInto(Context ctx, String first, RevCommit commit) {
try { try {
RefDatabase refDatabase = ctx.getRepository().getRefDatabase(); RefDatabase refDatabase = ctx.getRepository().getRefDatabase();