Merge "Send event to stream and execute hook when merge fails"
diff --git a/Documentation/cmd-stream-events.txt b/Documentation/cmd-stream-events.txt
index 03aec40..ce23da6 100644
--- a/Documentation/cmd-stream-events.txt
+++ b/Documentation/cmd-stream-events.txt
@@ -44,7 +44,8 @@
*patchSet*, *account* involved, and other attributes as appropriate.
The currently supported message types are *patchset-created*,
*draft-published*, *change-abandoned*, *change-restored*,
-*change-merged*, *comment-added*, *ref-updated* and *reviewer-added*.
+*change-merged*, *merge-failed*, *comment-added*, *ref-updated* and
+*reviewer-added*.
Note that any field may be missing in the JSON messages, so consumers of
this JSON stream should deal with that appropriately.
@@ -105,6 +106,18 @@
submitter:: link:json.html#account[account attribute]
+Merge Failed
+^^^^^^^^^^^^
+type:: "merge-failed"
+
+change:: link:json.html#change[change attribute]
+
+patchSet:: link:json.html#patchSet[patchSet attribute]
+
+submitter:: link:json.html#account[account attribute]
+
+reason:: Reason that the merge failed.
+
Comment Added
^^^^^^^^^^^^^
type:: "comment-added"
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index d4259a9..12aa1a8 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -1275,6 +1275,11 @@
Optional filename for the change merged hook, if not specified then
`change-merged` will be used.
+[[hooks.mergeFailedHook]]hooks.mergeFailedHook::
++
+Optional filename for the merge failed hook, if not specified then
+`merge-failed` will be used.
+
[[hooks.changeAbandonedHook]]hooks.changeAbandonedHook::
+
Optional filename for the change abandoned hook, if not specified then
diff --git a/Documentation/config-hooks.txt b/Documentation/config-hooks.txt
index 0783696..dfac6d1 100644
--- a/Documentation/config-hooks.txt
+++ b/Documentation/config-hooks.txt
@@ -57,6 +57,15 @@
change-merged --change <change id> --change-url <change url> --project <project name> --branch <branch> --topic <topic> --submitter <submitter> --commit <sha1>
====
+merge-failed
+~~~~~~~~~~~~
+
+Called whenever a change has failed to merge.
+
+====
+ merge-failed --change <change id> --change-url <change url> --project <project name> --branch <branch> --topic <topic> --submitter <submitter> --commit <sha1> --reason <reason>
+====
+
change-abandoned
~~~~~~~~~~~~~~~~
diff --git a/gerrit-server/src/main/java/com/google/gerrit/common/ChangeHookRunner.java b/gerrit-server/src/main/java/com/google/gerrit/common/ChangeHookRunner.java
index 7299d07..177ec65 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/common/ChangeHookRunner.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/common/ChangeHookRunner.java
@@ -39,6 +39,7 @@
import com.google.gerrit.server.events.CommentAddedEvent;
import com.google.gerrit.server.events.DraftPublishedEvent;
import com.google.gerrit.server.events.EventFactory;
+import com.google.gerrit.server.events.MergeFailedEvent;
import com.google.gerrit.server.events.PatchSetCreatedEvent;
import com.google.gerrit.server.events.RefUpdatedEvent;
import com.google.gerrit.server.events.ReviewerAddedEvent;
@@ -109,6 +110,9 @@
/** Filename of the change merged hook. */
private final File changeMergedHook;
+ /** Filename of the merge failed hook. */
+ private final File mergeFailedHook;
+
/** Filename of the change abandoned hook. */
private final File changeAbandonedHook;
@@ -174,6 +178,7 @@
draftPublishedHook = sitePath.resolve(new File(hooksPath, getValue(config, "hooks", "draftPublishedHook", "draft-published")).getPath());
commentAddedHook = sitePath.resolve(new File(hooksPath, getValue(config, "hooks", "commentAddedHook", "comment-added")).getPath());
changeMergedHook = sitePath.resolve(new File(hooksPath, getValue(config, "hooks", "changeMergedHook", "change-merged")).getPath());
+ mergeFailedHook = sitePath.resolve(new File(hooksPath, getValue(config, "hooks", "mergeFailed", "merge-failed")).getPath());
changeAbandonedHook = sitePath.resolve(new File(hooksPath, getValue(config, "hooks", "changeAbandonedHook", "change-abandoned")).getPath());
changeRestoredHook = sitePath.resolve(new File(hooksPath, getValue(config, "hooks", "changeRestoredHook", "change-restored")).getPath());
refUpdatedHook = sitePath.resolve(new File(hooksPath, getValue(config, "hooks", "refUpdatedHook", "ref-updated")).getPath());
@@ -329,6 +334,30 @@
runHook(change.getProject(), changeMergedHook, args);
}
+ public void doMergeFailedHook(final Change change, final Account account,
+ final PatchSet patchSet, final String reason,
+ final ReviewDb db) throws OrmException {
+ final MergeFailedEvent event = new MergeFailedEvent();
+
+ event.change = eventFactory.asChangeAttribute(change);
+ event.submitter = eventFactory.asAccountAttribute(account);
+ event.patchSet = eventFactory.asPatchSetAttribute(patchSet);
+ event.reason = reason;
+ fireEvent(change, event, db);
+
+ final List<String> args = new ArrayList<String>();
+ addArg(args, "--change", event.change.id);
+ addArg(args, "--change-url", event.change.url);
+ addArg(args, "--project", event.change.project);
+ addArg(args, "--branch", event.change.branch);
+ addArg(args, "--topic", event.change.topic);
+ addArg(args, "--submitter", getDisplayName(account));
+ addArg(args, "--commit", event.patchSet.revision);
+ addArg(args, "--reason", reason == null ? "" : reason);
+
+ runHook(change.getProject(), mergeFailedHook, args);
+ }
+
public void doChangeAbandonedHook(final Change change, final Account account,
final String reason, final ReviewDb db) throws OrmException {
final ChangeAbandonedEvent event = new ChangeAbandonedEvent();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/common/ChangeHooks.java b/gerrit-server/src/main/java/com/google/gerrit/common/ChangeHooks.java
index 028afe9..0d8dfb8 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/common/ChangeHooks.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/common/ChangeHooks.java
@@ -83,6 +83,18 @@
PatchSet patchSet, ReviewDb db) throws OrmException;
/**
+ * Fire the Merge Failed Hook.
+ *
+ * @param change The change itself.
+ * @param account The gerrit user who attempted to submit the change.
+ * @param patchSet The patchset that failed to merge.
+ * @param reason The reason that the change failed to merge.
+ * @throws OrmException
+ */
+ public void doMergeFailedHook(Change change, Account account,
+ PatchSet patchSet, String reason, ReviewDb db) throws OrmException;
+
+ /**
* Fire the Change Abandoned Hook.
*
* @param change The change itself.
diff --git a/gerrit-server/src/main/java/com/google/gerrit/common/DisabledChangeHooks.java b/gerrit-server/src/main/java/com/google/gerrit/common/DisabledChangeHooks.java
index 8794901..57ccba7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/common/DisabledChangeHooks.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/common/DisabledChangeHooks.java
@@ -46,6 +46,11 @@
}
@Override
+ public void doMergeFailedHook(Change change, Account account,
+ PatchSet patchSet, String reason, ReviewDb db) {
+ }
+
+ @Override
public void doChangeRestoredHook(Change change, Account account,
String reason, ReviewDb db) {
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/events/MergeFailedEvent.java b/gerrit-server/src/main/java/com/google/gerrit/server/events/MergeFailedEvent.java
new file mode 100644
index 0000000..e6ff525
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/events/MergeFailedEvent.java
@@ -0,0 +1,23 @@
+// Copyright (C) 2012 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.events;
+
+public class MergeFailedEvent extends ChangeEvent {
+ public final String type = "merge-failed";
+ public ChangeAttribute change;
+ public PatchSetAttribute patchSet;
+ public AccountAttribute submitter;
+ public String reason;
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java
index c80b3e6..e7298b3 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java
@@ -1053,17 +1053,23 @@
}
}
+ PatchSetApproval submitter = null;
+ try {
+ submitter = getSubmitter(db, c.currentPatchSetId());
+ } catch (Exception e) {
+ log.error("Cannot get submitter", e);
+ }
+
+ final PatchSetApproval from = submitter;
workQueue.getDefaultQueue()
.submit(requestScopePropagator.wrap(new Runnable() {
@Override
public void run() {
PatchSet patchSet;
- PatchSetApproval submitter;
try {
ReviewDb reviewDb = schemaFactory.open();
try {
patchSet = reviewDb.patchSets().get(c.currentPatchSetId());
- submitter = getSubmitter(reviewDb, c.currentPatchSetId());
} finally {
reviewDb.close();
}
@@ -1074,8 +1080,8 @@
try {
final MergeFailSender cm = mergeFailSenderFactory.create(c);
- if (submitter != null) {
- cm.setFrom(submitter.getAccountId());
+ if (from != null) {
+ cm.setFrom(from.getAccountId());
}
cm.setPatchSet(patchSet);
cm.setChangeMessage(msg);
@@ -1090,5 +1096,15 @@
return "send-email merge-failed";
}
}));
+
+ if (submitter != null) {
+ try {
+ hooks.doMergeFailedHook(c,
+ accountCache.get(submitter.getAccountId()).getAccount(),
+ db.patchSets().get(c.currentPatchSetId()), msg.getMessage(), db);
+ } catch (OrmException ex) {
+ log.error("Cannot run hook for merge failed " + c.getId(), ex);
+ }
+ }
}
}