Disable submit button if merge will fail
This feature aims to test the mergeability of each change tagging it according to the result (true or false). When the change page is load, the test is triggered and the sha1 of the dest branch (tested against) is stored within the change table. The submit button will be enabled or disabled according to the result. The test is triggered only if it’s outdated. As the branch evolves the sha1 stored at the moment of the test becomes different from the last one merged into the branch, meaning the test is outdated. Bug: issue 381 Change-Id: I8bdb26db6fc35067b8c14b987984cfd80745f3d3
This commit is contained in:

committed by
Ulrik Sjölin

parent
3f41a0ad0a
commit
14246de3c0
@@ -563,6 +563,22 @@ link:cmd-flush-caches.html[gerrit flush-caches].
|
|||||||
Default is 5 minutes.
|
Default is 5 minutes.
|
||||||
|
|
||||||
|
|
||||||
|
[[changeMerge]]Section changeMerge
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Controls whether or not the mergeability test of changes is
|
||||||
|
enabled. If enabled, when the change page is loaded, the test is
|
||||||
|
triggered. The submit button will be enabled or disabled according to
|
||||||
|
the result.
|
||||||
|
|
||||||
|
----
|
||||||
|
[changeMerge]
|
||||||
|
test = true
|
||||||
|
----
|
||||||
|
|
||||||
|
+
|
||||||
|
By default this is false (test is not enabled).
|
||||||
|
|
||||||
[[commentlink]]Section commentlink
|
[[commentlink]]Section commentlink
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
Comment links are find/replace strings applied to change descriptions,
|
Comment links are find/replace strings applied to change descriptions,
|
||||||
|
@@ -41,6 +41,7 @@ public class GerritConfig implements Cloneable {
|
|||||||
protected Set<Account.FieldName> editableAccountFields;
|
protected Set<Account.FieldName> editableAccountFields;
|
||||||
protected List<RegexFindReplace> commentLinks;
|
protected List<RegexFindReplace> commentLinks;
|
||||||
protected boolean documentationAvailable;
|
protected boolean documentationAvailable;
|
||||||
|
protected boolean testChangeMerge;
|
||||||
|
|
||||||
public String getRegisterUrl() {
|
public String getRegisterUrl() {
|
||||||
return registerUrl;
|
return registerUrl;
|
||||||
@@ -160,4 +161,12 @@ public class GerritConfig implements Cloneable {
|
|||||||
public void setDocumentationAvailable(final boolean available) {
|
public void setDocumentationAvailable(final boolean available) {
|
||||||
documentationAvailable = available;
|
documentationAvailable = available;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean testChangeMerge() {
|
||||||
|
return testChangeMerge;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTestChangeMerge(final boolean test) {
|
||||||
|
testChangeMerge = test;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -245,6 +245,15 @@ public class ApprovalTable extends Composite {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addReviewer.setVisible(Gerrit.isSignedIn());
|
addReviewer.setVisible(Gerrit.isSignedIn());
|
||||||
|
|
||||||
|
if (Gerrit.getConfig().testChangeMerge()
|
||||||
|
&& !detail.getChange().isMergeable()) {
|
||||||
|
Element li = DOM.createElement("li");
|
||||||
|
li.setClassName(Gerrit.RESOURCES.css().missingApproval());
|
||||||
|
DOM.setInnerText(li, Util.C.messageNeedsRebaseOrHasDependency());
|
||||||
|
DOM.appendChild(missingList, li);
|
||||||
|
missing.setVisible(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doAddReviewer() {
|
private void doAddReviewer() {
|
||||||
|
@@ -91,6 +91,9 @@ public interface ChangeConstants extends Constants {
|
|||||||
String changeInfoBlockUpdated();
|
String changeInfoBlockUpdated();
|
||||||
String changeInfoBlockStatus();
|
String changeInfoBlockStatus();
|
||||||
String changePermalink();
|
String changePermalink();
|
||||||
|
String changeInfoBlockCanMerge();
|
||||||
|
String changeInfoBlockCanMergeYes();
|
||||||
|
String changeInfoBlockCanMergeNo();
|
||||||
|
|
||||||
String includedInTableBranch();
|
String includedInTableBranch();
|
||||||
String includedInTableTag();
|
String includedInTableTag();
|
||||||
@@ -99,6 +102,7 @@ public interface ChangeConstants extends Constants {
|
|||||||
String messageExpandRecent();
|
String messageExpandRecent();
|
||||||
String messageExpandAll();
|
String messageExpandAll();
|
||||||
String messageCollapseAll();
|
String messageCollapseAll();
|
||||||
|
String messageNeedsRebaseOrHasDependency();
|
||||||
|
|
||||||
String patchSetInfoAuthor();
|
String patchSetInfoAuthor();
|
||||||
String patchSetInfoCommitter();
|
String patchSetInfoCommitter();
|
||||||
@@ -142,4 +146,4 @@ public interface ChangeConstants extends Constants {
|
|||||||
|
|
||||||
String buttonDiffAllSideBySide();
|
String buttonDiffAllSideBySide();
|
||||||
String buttonDiffAllUnified();
|
String buttonDiffAllUnified();
|
||||||
}
|
}
|
@@ -68,6 +68,9 @@ changeInfoBlockUploaded = Uploaded
|
|||||||
changeInfoBlockUpdated = Updated
|
changeInfoBlockUpdated = Updated
|
||||||
changeInfoBlockStatus = Status
|
changeInfoBlockStatus = Status
|
||||||
changePermalink = Permalink
|
changePermalink = Permalink
|
||||||
|
changeInfoBlockCanMerge = Can Merge
|
||||||
|
changeInfoBlockCanMergeYes = Yes
|
||||||
|
changeInfoBlockCanMergeNo = No
|
||||||
|
|
||||||
includedInTableBranch = Branch Name
|
includedInTableBranch = Branch Name
|
||||||
includedInTableTag = Tag Name
|
includedInTableTag = Tag Name
|
||||||
@@ -76,6 +79,7 @@ messageNoAuthor = Gerrit Code Review
|
|||||||
messageExpandRecent = Expand Recent
|
messageExpandRecent = Expand Recent
|
||||||
messageExpandAll = Expand All
|
messageExpandAll = Expand All
|
||||||
messageCollapseAll = Collapse All
|
messageCollapseAll = Collapse All
|
||||||
|
messageNeedsRebaseOrHasDependency = Need Rebase or Has Dependency
|
||||||
|
|
||||||
patchSetInfoAuthor = Author
|
patchSetInfoAuthor = Author
|
||||||
patchSetInfoCommitter = Committer
|
patchSetInfoCommitter = Committer
|
||||||
@@ -122,4 +126,4 @@ submitFailed = Submit Failed
|
|||||||
buttonClose = Close
|
buttonClose = Close
|
||||||
|
|
||||||
buttonDiffAllSideBySide = Diff All Side-by-Side
|
buttonDiffAllSideBySide = Diff All Side-by-Side
|
||||||
buttonDiffAllUnified = Diff All Unified
|
buttonDiffAllUnified = Diff All Unified
|
@@ -39,13 +39,20 @@ public class ChangeInfoBlock extends Composite {
|
|||||||
private static final int R_UPLOADED = 5;
|
private static final int R_UPLOADED = 5;
|
||||||
private static final int R_UPDATED = 6;
|
private static final int R_UPDATED = 6;
|
||||||
private static final int R_STATUS = 7;
|
private static final int R_STATUS = 7;
|
||||||
private static final int R_PERMALINK = 8;
|
private static final int R_MERGE_TEST = 8;
|
||||||
private static final int R_CNT = 9;
|
private final int R_PERMALINK;
|
||||||
|
private static final int R_CNT = 10;
|
||||||
|
|
||||||
private final Grid table;
|
private final Grid table;
|
||||||
|
|
||||||
public ChangeInfoBlock() {
|
public ChangeInfoBlock() {
|
||||||
table = new Grid(R_CNT, 2);
|
if (Gerrit.getConfig().testChangeMerge()) {
|
||||||
|
table = new Grid(R_CNT, 2);
|
||||||
|
R_PERMALINK = 9;
|
||||||
|
} else {
|
||||||
|
table = new Grid(R_CNT - 1, 2);
|
||||||
|
R_PERMALINK = 8;
|
||||||
|
}
|
||||||
table.setStyleName(Gerrit.RESOURCES.css().infoBlock());
|
table.setStyleName(Gerrit.RESOURCES.css().infoBlock());
|
||||||
table.addStyleName(Gerrit.RESOURCES.css().changeInfoBlock());
|
table.addStyleName(Gerrit.RESOURCES.css().changeInfoBlock());
|
||||||
|
|
||||||
@@ -57,6 +64,9 @@ public class ChangeInfoBlock extends Composite {
|
|||||||
initRow(R_UPLOADED, Util.C.changeInfoBlockUploaded());
|
initRow(R_UPLOADED, Util.C.changeInfoBlockUploaded());
|
||||||
initRow(R_UPDATED, Util.C.changeInfoBlockUpdated());
|
initRow(R_UPDATED, Util.C.changeInfoBlockUpdated());
|
||||||
initRow(R_STATUS, Util.C.changeInfoBlockStatus());
|
initRow(R_STATUS, Util.C.changeInfoBlockStatus());
|
||||||
|
if (Gerrit.getConfig().testChangeMerge()) {
|
||||||
|
initRow(R_MERGE_TEST, Util.C.changeInfoBlockCanMerge());
|
||||||
|
}
|
||||||
|
|
||||||
final CellFormatter fmt = table.getCellFormatter();
|
final CellFormatter fmt = table.getCellFormatter();
|
||||||
fmt.addStyleName(0, 0, Gerrit.RESOURCES.css().topmost());
|
fmt.addStyleName(0, 0, Gerrit.RESOURCES.css().topmost());
|
||||||
@@ -91,6 +101,10 @@ public class ChangeInfoBlock extends Composite {
|
|||||||
table.setText(R_UPLOADED, 1, mediumFormat(chg.getCreatedOn()));
|
table.setText(R_UPLOADED, 1, mediumFormat(chg.getCreatedOn()));
|
||||||
table.setText(R_UPDATED, 1, mediumFormat(chg.getLastUpdatedOn()));
|
table.setText(R_UPDATED, 1, mediumFormat(chg.getLastUpdatedOn()));
|
||||||
table.setText(R_STATUS, 1, Util.toLongString(chg.getStatus()));
|
table.setText(R_STATUS, 1, Util.toLongString(chg.getStatus()));
|
||||||
|
if (Gerrit.getConfig().testChangeMerge()) {
|
||||||
|
table.setText(R_MERGE_TEST, 1, chg.isMergeable() ? Util.C
|
||||||
|
.changeInfoBlockCanMergeYes() : Util.C.changeInfoBlockCanMergeNo());
|
||||||
|
}
|
||||||
|
|
||||||
if (chg.getStatus().isClosed()) {
|
if (chg.getStatus().isClosed()) {
|
||||||
table.getCellFormatter().addStyleName(R_STATUS, 1, Gerrit.RESOURCES.css().closedstate());
|
table.getCellFormatter().addStyleName(R_STATUS, 1, Gerrit.RESOURCES.css().closedstate());
|
||||||
|
@@ -405,6 +405,10 @@ class PatchSetComplexDisclosurePanel extends ComplexDisclosurePanel implements O
|
|||||||
final Button b =
|
final Button b =
|
||||||
new Button(Util.M
|
new Button(Util.M
|
||||||
.submitPatchSet(detail.getPatchSet().getPatchSetId()));
|
.submitPatchSet(detail.getPatchSet().getPatchSetId()));
|
||||||
|
if (Gerrit.getConfig().testChangeMerge()) {
|
||||||
|
b.setEnabled(changeDetail.getChange().isMergeable());
|
||||||
|
}
|
||||||
|
|
||||||
b.addClickHandler(new ClickHandler() {
|
b.addClickHandler(new ClickHandler() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(final ClickEvent event) {
|
public void onClick(final ClickEvent event) {
|
||||||
@@ -640,4 +644,4 @@ class PatchSetComplexDisclosurePanel extends ComplexDisclosurePanel implements O
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -41,11 +41,11 @@ import com.google.gwt.event.dom.client.ClickHandler;
|
|||||||
import com.google.gwt.user.client.ui.Button;
|
import com.google.gwt.user.client.ui.Button;
|
||||||
import com.google.gwt.user.client.ui.FlowPanel;
|
import com.google.gwt.user.client.ui.FlowPanel;
|
||||||
import com.google.gwt.user.client.ui.FormPanel;
|
import com.google.gwt.user.client.ui.FormPanel;
|
||||||
import com.google.gwt.user.client.ui.FormPanel.SubmitEvent;
|
|
||||||
import com.google.gwt.user.client.ui.Panel;
|
import com.google.gwt.user.client.ui.Panel;
|
||||||
import com.google.gwt.user.client.ui.RadioButton;
|
import com.google.gwt.user.client.ui.RadioButton;
|
||||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||||
import com.google.gwt.user.client.ui.Widget;
|
import com.google.gwt.user.client.ui.Widget;
|
||||||
|
import com.google.gwt.user.client.ui.FormPanel.SubmitEvent;
|
||||||
import com.google.gwtexpui.globalkey.client.NpTextArea;
|
import com.google.gwtexpui.globalkey.client.NpTextArea;
|
||||||
import com.google.gwtjsonrpc.client.VoidResult;
|
import com.google.gwtjsonrpc.client.VoidResult;
|
||||||
|
|
||||||
@@ -311,6 +311,9 @@ public class PublishCommentScreen extends AccountScreen implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
submit.setVisible(r.canSubmit());
|
submit.setVisible(r.canSubmit());
|
||||||
|
if (Gerrit.getConfig().testChangeMerge()) {
|
||||||
|
submit.setEnabled(r.getChange().isMergeable());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onSend(final boolean submit) {
|
private void onSend(final boolean submit) {
|
||||||
|
@@ -102,6 +102,8 @@ class GerritConfigProvider implements Provider<GerritConfig> {
|
|||||||
config.setApprovalTypes(approvalTypes);
|
config.setApprovalTypes(approvalTypes);
|
||||||
config.setDocumentationAvailable(servletContext
|
config.setDocumentationAvailable(servletContext
|
||||||
.getResource("/Documentation/index.html") != null);
|
.getResource("/Documentation/index.html") != null);
|
||||||
|
config.setTestChangeMerge(cfg.getBoolean("changeMerge",
|
||||||
|
"test", false));
|
||||||
|
|
||||||
final Set<Account.FieldName> fields = new HashSet<Account.FieldName>();
|
final Set<Account.FieldName> fields = new HashSet<Account.FieldName>();
|
||||||
for (final Account.FieldName n : Account.FieldName.values()) {
|
for (final Account.FieldName n : Account.FieldName.values()) {
|
||||||
|
@@ -31,8 +31,11 @@ import com.google.gerrit.reviewdb.PatchSetApproval;
|
|||||||
import com.google.gerrit.reviewdb.RevId;
|
import com.google.gerrit.reviewdb.RevId;
|
||||||
import com.google.gerrit.reviewdb.ReviewDb;
|
import com.google.gerrit.reviewdb.ReviewDb;
|
||||||
import com.google.gerrit.server.AnonymousUser;
|
import com.google.gerrit.server.AnonymousUser;
|
||||||
|
import com.google.gerrit.server.ChangeUtil;
|
||||||
import com.google.gerrit.server.IdentifiedUser;
|
import com.google.gerrit.server.IdentifiedUser;
|
||||||
import com.google.gerrit.server.account.AccountInfoCacheFactory;
|
import com.google.gerrit.server.account.AccountInfoCacheFactory;
|
||||||
|
import com.google.gerrit.server.config.GerritServerConfig;
|
||||||
|
import com.google.gerrit.server.git.MergeOp;
|
||||||
import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
|
import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
|
||||||
import com.google.gerrit.server.project.ChangeControl;
|
import com.google.gerrit.server.project.ChangeControl;
|
||||||
import com.google.gerrit.server.project.NoSuchChangeException;
|
import com.google.gerrit.server.project.NoSuchChangeException;
|
||||||
@@ -42,6 +45,8 @@ import com.google.gwtorm.client.OrmException;
|
|||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.assistedinject.Assisted;
|
import com.google.inject.assistedinject.Assisted;
|
||||||
|
|
||||||
|
import org.eclipse.jgit.lib.Config;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
@@ -70,6 +75,9 @@ public class ChangeDetailFactory extends Handler<ChangeDetail> {
|
|||||||
private ChangeDetail detail;
|
private ChangeDetail detail;
|
||||||
private ChangeControl control;
|
private ChangeControl control;
|
||||||
|
|
||||||
|
private final MergeOp.Factory opFactory;
|
||||||
|
private boolean testMerge;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
ChangeDetailFactory(final ApprovalTypes approvalTypes,
|
ChangeDetailFactory(final ApprovalTypes approvalTypes,
|
||||||
final FunctionState.Factory functionState,
|
final FunctionState.Factory functionState,
|
||||||
@@ -77,6 +85,8 @@ public class ChangeDetailFactory extends Handler<ChangeDetail> {
|
|||||||
final ChangeControl.Factory changeControlFactory,
|
final ChangeControl.Factory changeControlFactory,
|
||||||
final AccountInfoCacheFactory.Factory accountInfoCacheFactory,
|
final AccountInfoCacheFactory.Factory accountInfoCacheFactory,
|
||||||
final AnonymousUser anonymousUser,
|
final AnonymousUser anonymousUser,
|
||||||
|
final MergeOp.Factory opFactory,
|
||||||
|
@GerritServerConfig final Config cfg,
|
||||||
@Assisted final Change.Id id) {
|
@Assisted final Change.Id id) {
|
||||||
this.approvalTypes = approvalTypes;
|
this.approvalTypes = approvalTypes;
|
||||||
this.functionState = functionState;
|
this.functionState = functionState;
|
||||||
@@ -86,6 +96,9 @@ public class ChangeDetailFactory extends Handler<ChangeDetail> {
|
|||||||
this.anonymousUser = anonymousUser;
|
this.anonymousUser = anonymousUser;
|
||||||
this.aic = accountInfoCacheFactory.create();
|
this.aic = accountInfoCacheFactory.create();
|
||||||
|
|
||||||
|
this.opFactory = opFactory;
|
||||||
|
this.testMerge = cfg.getBoolean("changeMerge", "test", false);
|
||||||
|
|
||||||
this.changeId = id;
|
this.changeId = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,7 +161,11 @@ public class ChangeDetailFactory extends Handler<ChangeDetail> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void load() throws OrmException {
|
private void load() throws OrmException, NoSuchChangeException {
|
||||||
|
if (detail.getChange().getStatus().equals(Change.Status.NEW) && testMerge) {
|
||||||
|
ChangeUtil.testMerge(opFactory, detail.getChange());
|
||||||
|
}
|
||||||
|
|
||||||
final PatchSet.Id psId = detail.getChange().currentPatchSetId();
|
final PatchSet.Id psId = detail.getChange().currentPatchSetId();
|
||||||
final List<PatchSetApproval> allApprovals =
|
final List<PatchSetApproval> allApprovals =
|
||||||
db.patchSetApprovals().byChange(changeId).toList();
|
db.patchSetApprovals().byChange(changeId).toList();
|
||||||
|
@@ -18,7 +18,9 @@ import com.google.gerrit.common.ChangeHookRunner;
|
|||||||
import com.google.gerrit.common.data.ChangeDetail;
|
import com.google.gerrit.common.data.ChangeDetail;
|
||||||
import com.google.gerrit.common.errors.NoSuchEntityException;
|
import com.google.gerrit.common.errors.NoSuchEntityException;
|
||||||
import com.google.gerrit.httpd.rpc.Handler;
|
import com.google.gerrit.httpd.rpc.Handler;
|
||||||
import com.google.gerrit.reviewdb.*;
|
import com.google.gerrit.reviewdb.Change;
|
||||||
|
import com.google.gerrit.reviewdb.PatchSet;
|
||||||
|
import com.google.gerrit.reviewdb.ReviewDb;
|
||||||
import com.google.gerrit.server.ChangeUtil;
|
import com.google.gerrit.server.ChangeUtil;
|
||||||
import com.google.gerrit.server.IdentifiedUser;
|
import com.google.gerrit.server.IdentifiedUser;
|
||||||
import com.google.gerrit.server.mail.EmailException;
|
import com.google.gerrit.server.mail.EmailException;
|
||||||
|
@@ -355,6 +355,17 @@ public final class Change {
|
|||||||
@Column(id = 14, notNull = false)
|
@Column(id = 14, notNull = false)
|
||||||
protected String topic;
|
protected String topic;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Null if the change has never been tested.
|
||||||
|
* Empty if it has been tested but against a branch that does
|
||||||
|
* not exist.
|
||||||
|
*/
|
||||||
|
@Column(id = 15, notNull = false)
|
||||||
|
protected RevId lastSha1MergeTested;
|
||||||
|
|
||||||
|
@Column(id = 16)
|
||||||
|
protected boolean mergeable;
|
||||||
|
|
||||||
protected Change() {
|
protected Change() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,6 +378,7 @@ public final class Change {
|
|||||||
owner = ownedBy;
|
owner = ownedBy;
|
||||||
dest = forBranch;
|
dest = forBranch;
|
||||||
setStatus(Status.NEW);
|
setStatus(Status.NEW);
|
||||||
|
setLastSha1MergeTested(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Legacy 32 bit integer identity for a change. */
|
/** Legacy 32 bit integer identity for a change. */
|
||||||
@@ -466,4 +478,20 @@ public final class Change {
|
|||||||
public void setTopic(String topic) {
|
public void setTopic(String topic) {
|
||||||
this.topic = topic;
|
this.topic = topic;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public RevId getLastSha1MergeTested() {
|
||||||
|
return lastSha1MergeTested;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastSha1MergeTested(RevId lastSha1MergeTested) {
|
||||||
|
this.lastSha1MergeTested = lastSha1MergeTested;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMergeable() {
|
||||||
|
return mergeable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMergeable(boolean mergeable) {
|
||||||
|
this.mergeable = mergeable;
|
||||||
|
}
|
||||||
|
}
|
@@ -25,27 +25,25 @@ import com.google.gerrit.reviewdb.PatchSetInfo;
|
|||||||
import com.google.gerrit.reviewdb.RevId;
|
import com.google.gerrit.reviewdb.RevId;
|
||||||
import com.google.gerrit.reviewdb.ReviewDb;
|
import com.google.gerrit.reviewdb.ReviewDb;
|
||||||
import com.google.gerrit.reviewdb.TrackingId;
|
import com.google.gerrit.reviewdb.TrackingId;
|
||||||
import com.google.gerrit.server.IdentifiedUser;
|
|
||||||
import com.google.gerrit.server.config.TrackingFooter;
|
import com.google.gerrit.server.config.TrackingFooter;
|
||||||
import com.google.gerrit.server.config.TrackingFooters;
|
import com.google.gerrit.server.config.TrackingFooters;
|
||||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||||
import com.google.gerrit.server.git.MergeOp;
|
import com.google.gerrit.server.git.MergeOp;
|
||||||
import com.google.gerrit.server.git.MergeQueue;
|
import com.google.gerrit.server.git.MergeQueue;
|
||||||
import com.google.gerrit.server.git.ReplicationQueue;
|
import com.google.gerrit.server.git.ReplicationQueue;
|
||||||
import com.google.gerrit.server.patch.PatchSetInfoFactory;
|
|
||||||
import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
|
|
||||||
import com.google.gerrit.server.project.InvalidChangeOperationException;
|
|
||||||
import com.google.gerrit.server.project.NoSuchChangeException;
|
|
||||||
import com.google.gerrit.server.mail.AbandonedSender;
|
import com.google.gerrit.server.mail.AbandonedSender;
|
||||||
import com.google.gerrit.server.mail.EmailException;
|
import com.google.gerrit.server.mail.EmailException;
|
||||||
import com.google.gerrit.server.mail.ReplyToChangeSender;
|
import com.google.gerrit.server.mail.ReplyToChangeSender;
|
||||||
import com.google.gerrit.server.mail.RestoredSender;
|
import com.google.gerrit.server.mail.RestoredSender;
|
||||||
import com.google.gerrit.server.mail.RevertedSender;
|
import com.google.gerrit.server.mail.RevertedSender;
|
||||||
|
import com.google.gerrit.server.patch.PatchSetInfoFactory;
|
||||||
|
import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
|
||||||
|
import com.google.gerrit.server.project.InvalidChangeOperationException;
|
||||||
|
import com.google.gerrit.server.project.NoSuchChangeException;
|
||||||
import com.google.gwtorm.client.AtomicUpdate;
|
import com.google.gwtorm.client.AtomicUpdate;
|
||||||
import com.google.gwtorm.client.OrmConcurrencyException;
|
import com.google.gwtorm.client.OrmConcurrencyException;
|
||||||
import com.google.gwtorm.client.OrmException;
|
import com.google.gwtorm.client.OrmException;
|
||||||
|
|
||||||
|
|
||||||
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
|
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
|
||||||
import org.eclipse.jgit.errors.MissingObjectException;
|
import org.eclipse.jgit.errors.MissingObjectException;
|
||||||
import org.eclipse.jgit.errors.RepositoryNotFoundException;
|
import org.eclipse.jgit.errors.RepositoryNotFoundException;
|
||||||
@@ -165,6 +163,10 @@ public class ChangeUtil {
|
|||||||
db.trackingIds().delete(toDelete);
|
db.trackingIds().delete(toDelete);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void testMerge(MergeOp.Factory opFactory, Change change) {
|
||||||
|
opFactory.create(change.getDest()).verifyMergeability(change);
|
||||||
|
}
|
||||||
|
|
||||||
public static void submit(final PatchSet.Id patchSetId,
|
public static void submit(final PatchSet.Id patchSetId,
|
||||||
final IdentifiedUser user, final ReviewDb db,
|
final IdentifiedUser user, final ReviewDb db,
|
||||||
final MergeOp.Factory opFactory, final MergeQueue merger)
|
final MergeOp.Factory opFactory, final MergeQueue merger)
|
||||||
|
@@ -16,32 +16,50 @@ package com.google.gerrit.server.git;
|
|||||||
|
|
||||||
enum CommitMergeStatus {
|
enum CommitMergeStatus {
|
||||||
/** */
|
/** */
|
||||||
CLEAN_MERGE,
|
CLEAN_MERGE("Change has been successfully merged into the git repository."),
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
CLEAN_PICK,
|
CLEAN_PICK("Change has been successfully cherry-picked"),
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
ALREADY_MERGED,
|
ALREADY_MERGED(""),
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
PATH_CONFLICT,
|
PATH_CONFLICT("Your change could not be merged due to a path conflict.\n"
|
||||||
|
+ "\n"
|
||||||
|
+ "Please merge (or rebase) the change locally and upload the resolution for review."),
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
MISSING_DEPENDENCY,
|
MISSING_DEPENDENCY(""),
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
NO_PATCH_SET,
|
NO_PATCH_SET(""),
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
REVISION_GONE,
|
REVISION_GONE(""),
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
CRISS_CROSS_MERGE,
|
CRISS_CROSS_MERGE("Your change requires a recursive merge to resolve.\n"
|
||||||
|
+ "\n"
|
||||||
|
+ "Please merge (or rebase) the change locally and upload the resolution for review."),
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
CANNOT_CHERRY_PICK_ROOT,
|
CANNOT_CHERRY_PICK_ROOT("Cannot cherry-pick an initial commit onto an existing branch.\n"
|
||||||
|
+ "\n"
|
||||||
|
+ "Please merge the change locally and upload the merge commit for review."),
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
NOT_FAST_FORWARD;
|
NOT_FAST_FORWARD("Project policy requires all submissions to be a fast-forward.\n"
|
||||||
}
|
+ "\n"
|
||||||
|
+ "Please rebase the change locally and upload again for review.");
|
||||||
|
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
CommitMergeStatus(String message){
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage(){
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
}
|
@@ -20,6 +20,7 @@ import static java.util.concurrent.TimeUnit.MINUTES;
|
|||||||
import com.google.gerrit.common.ChangeHookRunner;
|
import com.google.gerrit.common.ChangeHookRunner;
|
||||||
import com.google.gerrit.common.data.ApprovalType;
|
import com.google.gerrit.common.data.ApprovalType;
|
||||||
import com.google.gerrit.common.data.ApprovalTypes;
|
import com.google.gerrit.common.data.ApprovalTypes;
|
||||||
|
import com.google.gerrit.common.data.Capable;
|
||||||
import com.google.gerrit.reviewdb.Account;
|
import com.google.gerrit.reviewdb.Account;
|
||||||
import com.google.gerrit.reviewdb.ApprovalCategory;
|
import com.google.gerrit.reviewdb.ApprovalCategory;
|
||||||
import com.google.gerrit.reviewdb.Branch;
|
import com.google.gerrit.reviewdb.Branch;
|
||||||
@@ -174,8 +175,7 @@ public class MergeOp {
|
|||||||
@GerritPersonIdent final PersonIdent myIdent,
|
@GerritPersonIdent final PersonIdent myIdent,
|
||||||
final MergeQueue mergeQueue, @Assisted final Branch.NameKey branch,
|
final MergeQueue mergeQueue, @Assisted final Branch.NameKey branch,
|
||||||
final ChangeHookRunner hooks, final AccountCache accountCache,
|
final ChangeHookRunner hooks, final AccountCache accountCache,
|
||||||
final TagCache tagCache,
|
final TagCache tagCache, final CreateCodeReviewNotes.Factory crnf) {
|
||||||
final CreateCodeReviewNotes.Factory crnf) {
|
|
||||||
repoManager = grm;
|
repoManager = grm;
|
||||||
schemaFactory = sf;
|
schemaFactory = sf;
|
||||||
functionState = fs;
|
functionState = fs;
|
||||||
@@ -200,20 +200,76 @@ public class MergeOp {
|
|||||||
commits = new HashMap<Change.Id, CodeReviewCommit>();
|
commits = new HashMap<Change.Id, CodeReviewCommit>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void merge() throws MergeException {
|
public void verifyMergeability(Change change) {
|
||||||
|
try {
|
||||||
|
setDestProject();
|
||||||
|
openRepository();
|
||||||
|
final Ref destBranchRef = db.getRef(destBranch.get());
|
||||||
|
submitted = new ArrayList<Change>();
|
||||||
|
submitted.add(change);
|
||||||
|
|
||||||
|
// Test mergeability of the change if the last merged sha1
|
||||||
|
// in the branch is different from the last sha1
|
||||||
|
// the change was tested against.
|
||||||
|
if ((destBranchRef == null && change.getLastSha1MergeTested() == null)
|
||||||
|
|| change.getLastSha1MergeTested() == null
|
||||||
|
|| (destBranchRef != null && !destBranchRef.getObjectId().getName()
|
||||||
|
.equals(change.getLastSha1MergeTested().get()))) {
|
||||||
|
openSchema();
|
||||||
|
preMerge();
|
||||||
|
|
||||||
|
// update sha1 tested merge.
|
||||||
|
if (destBranchRef != null) {
|
||||||
|
change.setLastSha1MergeTested(new RevId(destBranchRef
|
||||||
|
.getObjectId().getName()));
|
||||||
|
} else {
|
||||||
|
change.setLastSha1MergeTested(new RevId(""));
|
||||||
|
}
|
||||||
|
change.setMergeable(isMergeable(change));
|
||||||
|
schema.changes().update(Collections.singleton(change));
|
||||||
|
}
|
||||||
|
} catch (MergeException e) {
|
||||||
|
log.error("Test merge attempt for change: " + change.getId()
|
||||||
|
+ " failed", e);
|
||||||
|
} catch (OrmException e) {
|
||||||
|
log.error("Test merge attempt for change: " + change.getId()
|
||||||
|
+ " failed: Not able to query the database", e);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Test merge attempt for change: " + change.getId()
|
||||||
|
+ " failed", e);
|
||||||
|
} finally {
|
||||||
|
if (schema != null) {
|
||||||
|
schema.close();
|
||||||
|
}
|
||||||
|
schema = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setDestProject() throws MergeException {
|
||||||
final ProjectState pe = projectCache.get(destBranch.getParentKey());
|
final ProjectState pe = projectCache.get(destBranch.getParentKey());
|
||||||
if (pe == null) {
|
if (pe == null) {
|
||||||
throw new MergeException("No such project: " + destBranch.getParentKey());
|
throw new MergeException("No such project: " + destBranch.getParentKey());
|
||||||
}
|
}
|
||||||
destProject = pe.getProject();
|
destProject = pe.getProject();
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
private void openSchema() throws OrmException {
|
||||||
|
if (schema == null) {
|
||||||
schema = schemaFactory.open();
|
schema = schemaFactory.open();
|
||||||
} catch (OrmException e) {
|
|
||||||
throw new MergeException("Cannot open database", e);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void merge() throws MergeException {
|
||||||
|
setDestProject();
|
||||||
try {
|
try {
|
||||||
mergeImpl();
|
openSchema();
|
||||||
|
openRepository();
|
||||||
|
submitted = schema.changes().submitted(destBranch).toList();
|
||||||
|
preMerge();
|
||||||
|
updateBranch();
|
||||||
|
updateChangeStatus();
|
||||||
|
} catch (OrmException e) {
|
||||||
|
throw new MergeException("Cannot query the database", e);
|
||||||
} finally {
|
} finally {
|
||||||
if (rw != null) {
|
if (rw != null) {
|
||||||
rw.release();
|
rw.release();
|
||||||
@@ -226,10 +282,8 @@ public class MergeOp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void mergeImpl() throws MergeException {
|
private void preMerge() throws MergeException {
|
||||||
openRepository();
|
|
||||||
openBranch();
|
openBranch();
|
||||||
listPendingSubmits();
|
|
||||||
validateChangeList();
|
validateChangeList();
|
||||||
mergeTip = branchTip;
|
mergeTip = branchTip;
|
||||||
switch (destProject.getSubmitType()) {
|
switch (destProject.getSubmitType()) {
|
||||||
@@ -246,8 +300,6 @@ public class MergeOp {
|
|||||||
markCleanMerges();
|
markCleanMerges();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
updateBranch();
|
|
||||||
updateChangeStatus();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void openRepository() throws MergeException {
|
private void openRepository() throws MergeException {
|
||||||
@@ -298,14 +350,6 @@ public class MergeOp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void listPendingSubmits() throws MergeException {
|
|
||||||
try {
|
|
||||||
submitted = schema.changes().submitted(destBranch).toList();
|
|
||||||
} catch (OrmException e) {
|
|
||||||
throw new MergeException("Cannot query the database", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void validateChangeList() throws MergeException {
|
private void validateChangeList() throws MergeException {
|
||||||
final Set<ObjectId> tips = new HashSet<ObjectId>();
|
final Set<ObjectId> tips = new HashSet<ObjectId>();
|
||||||
for (final Ref r : db.getAllRefs().values()) {
|
for (final Ref r : db.getAllRefs().values()) {
|
||||||
@@ -942,6 +986,20 @@ public class MergeOp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isMergeable(Change c) throws OrmException {
|
||||||
|
final CodeReviewCommit commit = commits.get(c.getId());
|
||||||
|
final CommitMergeStatus s = commit != null ? commit.statusCode : null;
|
||||||
|
boolean isMergeable = false;
|
||||||
|
if (s != null
|
||||||
|
&& (s.equals(CommitMergeStatus.CLEAN_MERGE)
|
||||||
|
|| s.equals(CommitMergeStatus.CLEAN_PICK) || s
|
||||||
|
.equals(CommitMergeStatus.ALREADY_MERGED))) {
|
||||||
|
isMergeable = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isMergeable;
|
||||||
|
}
|
||||||
|
|
||||||
private void updateChangeStatus() throws MergeException {
|
private void updateChangeStatus() throws MergeException {
|
||||||
List<CodeReviewCommit> merged = new ArrayList<CodeReviewCommit>();
|
List<CodeReviewCommit> merged = new ArrayList<CodeReviewCommit>();
|
||||||
|
|
||||||
@@ -955,19 +1013,16 @@ public class MergeOp {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final String txt = s.getMessage();
|
||||||
|
|
||||||
switch (s) {
|
switch (s) {
|
||||||
case CLEAN_MERGE: {
|
case CLEAN_MERGE: {
|
||||||
final String txt =
|
|
||||||
"Change has been successfully merged into the git repository.";
|
|
||||||
setMerged(c, message(c, txt));
|
setMerged(c, message(c, txt));
|
||||||
merged.add(commit);
|
merged.add(commit);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case CLEAN_PICK: {
|
case CLEAN_PICK: {
|
||||||
final String txt =
|
|
||||||
"Change has been successfully cherry-picked as " + commit.name()
|
|
||||||
+ ".";
|
|
||||||
setMerged(c, message(c, txt));
|
setMerged(c, message(c, txt));
|
||||||
merged.add(commit);
|
merged.add(commit);
|
||||||
break;
|
break;
|
||||||
@@ -978,44 +1033,19 @@ public class MergeOp {
|
|||||||
merged.add(commit);
|
merged.add(commit);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PATH_CONFLICT: {
|
case PATH_CONFLICT:
|
||||||
final String txt =
|
case CRISS_CROSS_MERGE:
|
||||||
"Your change could not be merged due to a path conflict.\n"
|
case CANNOT_CHERRY_PICK_ROOT:
|
||||||
+ "\n"
|
|
||||||
+ "Please merge (or rebase) the change locally and upload the resolution for review.";
|
|
||||||
setNew(c, message(c, txt));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case CRISS_CROSS_MERGE: {
|
|
||||||
final String txt =
|
|
||||||
"Your change requires a recursive merge to resolve.\n"
|
|
||||||
+ "\n"
|
|
||||||
+ "Please merge (or rebase) the change locally and upload the resolution for review.";
|
|
||||||
setNew(c, message(c, txt));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case CANNOT_CHERRY_PICK_ROOT: {
|
|
||||||
final String txt =
|
|
||||||
"Cannot cherry-pick an initial commit onto an existing branch.\n"
|
|
||||||
+ "\n"
|
|
||||||
+ "Please merge the change locally and upload the merge commit for review.";
|
|
||||||
setNew(c, message(c, txt));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case NOT_FAST_FORWARD: {
|
case NOT_FAST_FORWARD: {
|
||||||
final String txt =
|
|
||||||
"Project policy requires all submissions to be a fast-forward.\n"
|
|
||||||
+ "\n"
|
|
||||||
+ "Please rebase the change locally and upload again for review.";
|
|
||||||
setNew(c, message(c, txt));
|
setNew(c, message(c, txt));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case MISSING_DEPENDENCY: {
|
case MISSING_DEPENDENCY: {
|
||||||
dependencyError(commit);
|
final Capable capable = isSubmitStillPossible(commit);
|
||||||
|
if (capable != Capable.OK) {
|
||||||
|
sendMergeFail(c, message(c, capable.getMessage()), false);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1036,7 +1066,8 @@ public class MergeOp {
|
|||||||
GitRepositoryManager.REFS_NOTES_REVIEW);
|
GitRepositoryManager.REFS_NOTES_REVIEW);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void dependencyError(final CodeReviewCommit commit) {
|
private Capable isSubmitStillPossible(final CodeReviewCommit commit) {
|
||||||
|
final Capable capable;
|
||||||
final Change c = commit.change;
|
final Change c = commit.change;
|
||||||
if (commit.missing == null) {
|
if (commit.missing == null) {
|
||||||
commit.missing = new ArrayList<CodeReviewCommit>();
|
commit.missing = new ArrayList<CodeReviewCommit>();
|
||||||
@@ -1071,7 +1102,7 @@ public class MergeOp {
|
|||||||
// this change submitted. Reschedule an attempt in a bit.
|
// this change submitted. Reschedule an attempt in a bit.
|
||||||
//
|
//
|
||||||
mergeQueue.recheckAfter(destBranch, waitUntil - now, MILLISECONDS);
|
mergeQueue.recheckAfter(destBranch, waitUntil - now, MILLISECONDS);
|
||||||
|
capable = Capable.OK;
|
||||||
} else if (submitStillPossible) {
|
} else if (submitStillPossible) {
|
||||||
// It would be possible to submit the change if the missing
|
// It would be possible to submit the change if the missing
|
||||||
// dependencies are also submitted. Perhaps the user just
|
// dependencies are also submitted. Perhaps the user just
|
||||||
@@ -1095,9 +1126,7 @@ public class MergeOp {
|
|||||||
}
|
}
|
||||||
txt = m.toString();
|
txt = m.toString();
|
||||||
}
|
}
|
||||||
|
capable = new Capable(txt);
|
||||||
sendMergeFail(c, message(c, txt), false);
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// It is impossible to submit this change as-is. The author
|
// It is impossible to submit this change as-is. The author
|
||||||
// needs to rebase it in order to work around the missing
|
// needs to rebase it in order to work around the missing
|
||||||
@@ -1127,9 +1156,10 @@ public class MergeOp {
|
|||||||
}
|
}
|
||||||
m.append("\n");
|
m.append("\n");
|
||||||
m.append("Please rebase the change and upload a replacement commit.");
|
m.append("Please rebase the change and upload a replacement commit.");
|
||||||
|
capable = new Capable(m.toString());
|
||||||
setNew(c, message(c, m.toString()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return capable;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadChangeInfo(final CodeReviewCommit commit) {
|
private void loadChangeInfo(final CodeReviewCommit commit) {
|
||||||
@@ -1215,6 +1245,10 @@ public class MergeOp {
|
|||||||
@Override
|
@Override
|
||||||
public Change update(Change c) {
|
public Change update(Change c) {
|
||||||
c.setStatus(Change.Status.MERGED);
|
c.setStatus(Change.Status.MERGED);
|
||||||
|
// It could be possible that the change being merged
|
||||||
|
// has never had its mergeability tested. So we insure
|
||||||
|
// merged changes has mergeable field true.
|
||||||
|
c.setMergeable(true);
|
||||||
if (!merged.equals(c.currentPatchSetId())) {
|
if (!merged.equals(c.currentPatchSetId())) {
|
||||||
// Uncool; the patch set changed after we merged it.
|
// Uncool; the patch set changed after we merged it.
|
||||||
// Go back to the patch set that was actually merged.
|
// Go back to the patch set that was actually merged.
|
||||||
|
@@ -1169,6 +1169,7 @@ public class ReceiveCommits implements PreReceiveHook, PostReceiveHook {
|
|||||||
public Change update(Change change) {
|
public Change update(Change change) {
|
||||||
if (change.getStatus().isOpen()) {
|
if (change.getStatus().isOpen()) {
|
||||||
change.nextPatchSetId();
|
change.nextPatchSetId();
|
||||||
|
change.setLastSha1MergeTested(null);
|
||||||
return change;
|
return change;
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
|
@@ -32,7 +32,7 @@ import java.util.List;
|
|||||||
/** A version of the database schema. */
|
/** A version of the database schema. */
|
||||||
public abstract class SchemaVersion {
|
public abstract class SchemaVersion {
|
||||||
/** The current schema version. */
|
/** The current schema version. */
|
||||||
private static final Class<? extends SchemaVersion> C = Schema_58.class;
|
private static final Class<? extends SchemaVersion> C = Schema_59.class;
|
||||||
|
|
||||||
public static class Module extends AbstractModule {
|
public static class Module extends AbstractModule {
|
||||||
@Override
|
@Override
|
||||||
|
@@ -0,0 +1,42 @@
|
|||||||
|
// Copyright (C) 2011 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.schema;
|
||||||
|
|
||||||
|
import com.google.gerrit.reviewdb.Change;
|
||||||
|
import com.google.gerrit.reviewdb.ReviewDb;
|
||||||
|
import com.google.gwtorm.client.OrmException;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.Provider;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Schema_59 extends SchemaVersion {
|
||||||
|
@Inject
|
||||||
|
Schema_59(Provider<Schema_58> prior) {
|
||||||
|
super(prior);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void migrateData(ReviewDb db, UpdateUI ui) throws OrmException,
|
||||||
|
SQLException {
|
||||||
|
List<Change> allChanges = db.changes().all().toList();
|
||||||
|
for (Change change : allChanges) {
|
||||||
|
change.setMergeable(true);
|
||||||
|
change.setLastSha1MergeTested(null);
|
||||||
|
}
|
||||||
|
db.changes().update(allChanges);
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user