From 59cdd227a94e66fe60470d708708482bfbef127b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C5=A1a=20=C5=BDivkov?= Date: Wed, 11 Nov 2015 14:50:46 -0800 Subject: [PATCH] New event listeners and new event types This is a first step towards moving ChangeHooks into a plugin. The listeners[1] are now invoked from all places where corresponding hooks are invoked. Invocation of hooks is not removed in this change. This will happen when we make sure that they are invoked from a new event listener. [1] All listeners under: gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/ Change-Id: I6e5356edb2c326d2d7a0133b84509ad6071140d0 --- .../events/CommentAddedListener.java | 1 + .../rpc/account/AccountSecurityImpl.java | 7 +- .../google/gerrit/server/change/Abandon.java | 7 +- .../gerrit/server/change/ChangeInserter.java | 12 ++ .../gerrit/server/change/ChangeJson.java | 17 ++- .../server/change/PatchSetInserter.java | 5 + .../gerrit/server/change/PostReview.java | 9 +- .../gerrit/server/change/PostReviewers.java | 7 +- .../server/change/PublishDraftPatchSet.java | 7 +- .../google/gerrit/server/change/PutTopic.java | 9 +- .../google/gerrit/server/change/Restore.java | 9 +- .../gerrit/server/change/SetHashtagsOp.java | 6 + .../server/config/GerritGlobalModule.java | 22 ++++ .../events/AbstractChangeEvent.java | 31 +++++ .../events/AbstractRevisionEvent.java | 35 +++++ .../extensions/events/AgreementSignup.java | 64 +++++++++ .../extensions/events/ChangeAbandoned.java | 97 ++++++++++++++ .../extensions/events/ChangeMerged.java | 98 ++++++++++++++ .../extensions/events/ChangeRestored.java | 98 ++++++++++++++ .../extensions/events/CommentAdded.java | 122 ++++++++++++++++++ .../extensions/events/DraftPublished.java | 85 ++++++++++++ .../server/extensions/events/EventUtil.java | 60 ++++++++- .../events/GitReferenceUpdated.java | 6 + .../extensions/events/HashtagsEdited.java | 110 ++++++++++++++++ .../server/extensions/events/PluginEvent.java | 65 ++++++++++ .../extensions/events/ReviewerAdded.java | 88 +++++++++++++ .../extensions/events/RevisionCreated.java | 88 +++++++++++++ .../server/extensions/events/TopicEdited.java | 87 +++++++++++++ .../gerrit/server/git/MergedByPushOp.java | 9 +- 29 files changed, 1251 insertions(+), 10 deletions(-) create mode 100644 gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/AbstractChangeEvent.java create mode 100644 gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/AbstractRevisionEvent.java create mode 100644 gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/AgreementSignup.java create mode 100644 gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/ChangeAbandoned.java create mode 100644 gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/ChangeMerged.java create mode 100644 gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/ChangeRestored.java create mode 100644 gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/CommentAdded.java create mode 100644 gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/DraftPublished.java create mode 100644 gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/HashtagsEdited.java create mode 100644 gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/PluginEvent.java create mode 100644 gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/ReviewerAdded.java create mode 100644 gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/RevisionCreated.java create mode 100644 gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/TopicEdited.java diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/CommentAddedListener.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/CommentAddedListener.java index 302ccb5b20..3e6a9c7e70 100644 --- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/CommentAddedListener.java +++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/CommentAddedListener.java @@ -27,6 +27,7 @@ public interface CommentAddedListener { AccountInfo getAuthor(); String getComment(); Map getApprovals(); + Map getOldApprovals(); } void onCommentAdded(Event event); diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/AccountSecurityImpl.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/AccountSecurityImpl.java index 3c1c12d2f0..ad0e409dde 100644 --- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/AccountSecurityImpl.java +++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/AccountSecurityImpl.java @@ -33,6 +33,7 @@ import com.google.gerrit.server.account.AccountByEmailCache; import com.google.gerrit.server.account.AccountCache; import com.google.gerrit.server.account.GroupCache; import com.google.gerrit.server.account.Realm; +import com.google.gerrit.server.extensions.events.AgreementSignup; import com.google.gerrit.server.project.ProjectCache; import com.google.gwtjsonrpc.common.AsyncCallback; import com.google.gwtjsonrpc.common.VoidResult; @@ -58,6 +59,7 @@ class AccountSecurityImpl extends BaseServiceImplementation implements private final ChangeHooks hooks; private final GroupCache groupCache; private final AuditService auditService; + private final AgreementSignup agreementSignup; @Inject AccountSecurityImpl(final Provider schema, @@ -68,7 +70,8 @@ class AccountSecurityImpl extends BaseServiceImplementation implements final DeleteExternalIds.Factory deleteExternalIdsFactory, final ExternalIdDetailFactory.Factory externalIdDetailFactory, final ChangeHooks hooks, final GroupCache groupCache, - final AuditService auditService) { + final AuditService auditService, + AgreementSignup agreementSignup) { super(schema, currentUser); realm = r; user = u; @@ -80,6 +83,7 @@ class AccountSecurityImpl extends BaseServiceImplementation implements this.externalIdDetailFactory = externalIdDetailFactory; this.hooks = hooks; this.groupCache = groupCache; + this.agreementSignup = agreementSignup; } @Override @@ -153,6 +157,7 @@ class AccountSecurityImpl extends BaseServiceImplementation implements } Account account = user.get().getAccount(); + agreementSignup.fire(account, ca.getName()); hooks.doClaSignupHook(account, ca.getName()); final AccountGroupMember.Key key = diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Abandon.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Abandon.java index 288dd83d71..a9fb61d734 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Abandon.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Abandon.java @@ -33,6 +33,7 @@ import com.google.gerrit.server.ChangeMessagesUtil; import com.google.gerrit.server.ChangeUtil; import com.google.gerrit.server.CurrentUser; import com.google.gerrit.server.PatchSetUtil; +import com.google.gerrit.server.extensions.events.ChangeAbandoned; import com.google.gerrit.server.git.BatchUpdate; import com.google.gerrit.server.git.BatchUpdate.ChangeContext; import com.google.gerrit.server.git.BatchUpdate.Context; @@ -61,6 +62,7 @@ public class Abandon implements RestModifyView, private final ChangeMessagesUtil cmUtil; private final PatchSetUtil psUtil; private final BatchUpdate.Factory batchUpdateFactory; + private final ChangeAbandoned changeAbandoned; @Inject Abandon(ChangeHooks hooks, @@ -69,7 +71,8 @@ public class Abandon implements RestModifyView, ChangeJson.Factory json, ChangeMessagesUtil cmUtil, PatchSetUtil psUtil, - BatchUpdate.Factory batchUpdateFactory) { + BatchUpdate.Factory batchUpdateFactory, + ChangeAbandoned changeAbandoned) { this.hooks = hooks; this.abandonedSenderFactory = abandonedSenderFactory; this.dbProvider = dbProvider; @@ -77,6 +80,7 @@ public class Abandon implements RestModifyView, this.cmUtil = cmUtil; this.psUtil = psUtil; this.batchUpdateFactory = batchUpdateFactory; + this.changeAbandoned = changeAbandoned; } @Override @@ -171,6 +175,7 @@ public class Abandon implements RestModifyView, } catch (Exception e) { log.error("Cannot email update for change " + change.getId(), e); } + changeAbandoned.fire(change, patchSet, account, msgTxt); hooks.doChangeAbandonedHook(change, account, patchSet, diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeInserter.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeInserter.java index 44e55c8d5a..41af4eb073 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeInserter.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeInserter.java @@ -37,6 +37,8 @@ import com.google.gerrit.server.ChangeMessagesUtil; import com.google.gerrit.server.ChangeUtil; import com.google.gerrit.server.PatchSetUtil; import com.google.gerrit.server.events.CommitReceivedEvent; +import com.google.gerrit.server.extensions.events.CommentAdded; +import com.google.gerrit.server.extensions.events.RevisionCreated; import com.google.gerrit.server.git.BanCommit; import com.google.gerrit.server.git.BatchUpdate; import com.google.gerrit.server.git.BatchUpdate.ChangeContext; @@ -94,6 +96,8 @@ public class ChangeInserter extends BatchUpdate.InsertChangeOp { private final CreateChangeSender.Factory createChangeSenderFactory; private final ExecutorService sendEmailExecutor; private final CommitValidators.Factory commitValidatorsFactory; + private final RevisionCreated revisionCreated; + private final CommentAdded commentAdded; private final Change.Id changeId; private final PatchSet.Id psId; @@ -134,6 +138,8 @@ public class ChangeInserter extends BatchUpdate.InsertChangeOp { CreateChangeSender.Factory createChangeSenderFactory, @SendEmailExecutor ExecutorService sendEmailExecutor, CommitValidators.Factory commitValidatorsFactory, + CommentAdded commentAdded, + RevisionCreated revisionCreated, @Assisted Change.Id changeId, @Assisted RevCommit commit, @Assisted String refName) { @@ -147,6 +153,8 @@ public class ChangeInserter extends BatchUpdate.InsertChangeOp { this.createChangeSenderFactory = createChangeSenderFactory; this.sendEmailExecutor = sendEmailExecutor; this.commitValidatorsFactory = commitValidatorsFactory; + this.revisionCreated = revisionCreated; + this.commentAdded = commentAdded; this.changeId = changeId; this.psId = new PatchSet.Id(changeId, INITIAL_PATCH_SET_ID); @@ -397,6 +405,7 @@ public class ChangeInserter extends BatchUpdate.InsertChangeOp { * show a transition from an oldValue of 0 to the new value. */ if (runHooks) { + revisionCreated.fire(change, patchSet, ctx.getUser().getAccountId()); ReviewDb db = ctx.getDb(); hooks.doPatchsetCreatedHook(change, patchSet, db); if (approvals != null && !approvals.isEmpty()) { @@ -415,6 +424,9 @@ public class ChangeInserter extends BatchUpdate.InsertChangeOp { oldApprovals.put(entry.getKey(), (short) 0); } } + commentAdded.fire(change, patchSet, + ctx.getUser().asIdentifiedUser().getAccount(), null, + allApprovals, oldApprovals, ctx.getWhen()); hooks.doCommentAddedHook(change, ctx.getUser().asIdentifiedUser().getAccount(), patchSet, null, allApprovals, oldApprovals, db); diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java index c9a0d11465..5665615fc3 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java @@ -754,11 +754,17 @@ public class ChangeJson { private ApprovalInfo approvalInfo(Account.Id id, Integer value, String tag, Timestamp date) { + ApprovalInfo ai = getApprovalInfo(id, value, tag, date); + accountLoader.put(ai); + return ai; + } + + public static ApprovalInfo getApprovalInfo( + Account.Id id, Integer value, String tag, Timestamp date) { ApprovalInfo ai = new ApprovalInfo(id.get()); ai.value = value; ai.date = date; ai.tag = tag; - accountLoader.put(ai); return ai; } @@ -923,6 +929,15 @@ public class ChangeJson { return map; } + public RevisionInfo getRevisionInfo(ChangeControl ctl, PatchSet in) + throws PatchListNotAvailableException, GpgException, OrmException, + IOException { + accountLoader = accountLoaderFactory.create(has(DETAILED_ACCOUNTS)); + RevisionInfo rev = toRevisionInfo(ctl, in); + accountLoader.fill(); + return rev; + } + private RevisionInfo toRevisionInfo(ChangeControl ctl, PatchSet in) throws PatchListNotAvailableException, GpgException, OrmException, IOException { diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/PatchSetInserter.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/PatchSetInserter.java index c0c9da30ab..cea07f4116 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/change/PatchSetInserter.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/PatchSetInserter.java @@ -33,6 +33,7 @@ import com.google.gerrit.server.ChangeUtil; import com.google.gerrit.server.PatchSetUtil; import com.google.gerrit.server.ReviewerSet; import com.google.gerrit.server.events.CommitReceivedEvent; +import com.google.gerrit.server.extensions.events.RevisionCreated; import com.google.gerrit.server.git.BanCommit; import com.google.gerrit.server.git.BatchUpdate; import com.google.gerrit.server.git.BatchUpdate.ChangeContext; @@ -76,6 +77,7 @@ public class PatchSetInserter extends BatchUpdate.Op { private final ReviewDb db; private final CommitValidators.Factory commitValidatorsFactory; private final ReplacePatchSetSender.Factory replacePatchSetFactory; + private final RevisionCreated revisionCreated; private final ApprovalsUtil approvalsUtil; private final ApprovalCopier approvalCopier; private final ChangeMessagesUtil cmUtil; @@ -118,6 +120,7 @@ public class PatchSetInserter extends BatchUpdate.Op { CommitValidators.Factory commitValidatorsFactory, ReplacePatchSetSender.Factory replacePatchSetFactory, PatchSetUtil psUtil, + RevisionCreated revisionCreated, @Assisted ChangeControl ctl, @Assisted PatchSet.Id psId, @Assisted RevCommit commit) { @@ -130,6 +133,7 @@ public class PatchSetInserter extends BatchUpdate.Op { this.commitValidatorsFactory = commitValidatorsFactory; this.replacePatchSetFactory = replacePatchSetFactory; this.psUtil = psUtil; + this.revisionCreated = revisionCreated; this.origCtl = ctl; this.psId = psId; @@ -274,6 +278,7 @@ public class PatchSetInserter extends BatchUpdate.Op { } if (runHooks) { + revisionCreated.fire(change, patchSet, ctx.getUser().getAccountId()); hooks.doPatchsetCreatedHook(change, patchSet, ctx.getDb()); } } diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReview.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReview.java index 23e366bad6..224d9d07d5 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReview.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReview.java @@ -61,6 +61,7 @@ import com.google.gerrit.server.IdentifiedUser; import com.google.gerrit.server.PatchLineCommentsUtil; import com.google.gerrit.server.PatchSetUtil; import com.google.gerrit.server.account.AccountsCollection; +import com.google.gerrit.server.extensions.events.CommentAdded; import com.google.gerrit.server.git.BatchUpdate; import com.google.gerrit.server.git.BatchUpdate.ChangeContext; import com.google.gerrit.server.git.BatchUpdate.Context; @@ -110,6 +111,7 @@ public class PostReview implements RestModifyView private final AccountsCollection accounts; private final EmailReviewComments.Factory email; private final ChangeHooks hooks; + private final CommentAdded commentAdded; @Inject PostReview(Provider db, @@ -123,7 +125,8 @@ public class PostReview implements RestModifyView PatchListCache patchListCache, AccountsCollection accounts, EmailReviewComments.Factory email, - ChangeHooks hooks) { + ChangeHooks hooks, + CommentAdded commentAdded) { this.db = db; this.batchUpdateFactory = batchUpdateFactory; this.changes = changes; @@ -136,6 +139,7 @@ public class PostReview implements RestModifyView this.accounts = accounts; this.email = email; this.hooks = hooks; + this.commentAdded = commentAdded; } @Override @@ -384,6 +388,9 @@ public class PostReview implements RestModifyView comments).sendAsync(); } try { + commentAdded.fire( + notes.getChange(), ps, user.getAccount(), message.getMessage(), + approvals, oldApprovals, ctx.getWhen()); hooks.doCommentAddedHook(notes.getChange(), user.getAccount(), ps, message.getMessage(), approvals, oldApprovals, ctx.getDb()); } catch (OrmException e) { diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReviewers.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReviewers.java index 7cb410e759..ad6b01451d 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReviewers.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReviewers.java @@ -46,6 +46,7 @@ import com.google.gerrit.server.git.BatchUpdate; import com.google.gerrit.server.git.BatchUpdate.ChangeContext; import com.google.gerrit.server.git.BatchUpdate.Context; import com.google.gerrit.server.git.UpdateException; +import com.google.gerrit.server.extensions.events.ReviewerAdded; import com.google.gerrit.server.group.GroupsCollection; import com.google.gerrit.server.group.SystemGroupBackend; import com.google.gerrit.server.mail.AddReviewerSender; @@ -91,6 +92,7 @@ public class PostReviewers implements RestModifyView dbProvider; private final ReplacePatchSetSender.Factory replacePatchSetFactory; + private final DraftPublished draftPublished; @Inject public PublishDraftPatchSet( @@ -93,7 +95,8 @@ public class PublishDraftPatchSet implements RestModifyView dbProvider, - ReplacePatchSetSender.Factory replacePatchSetFactory) { + ReplacePatchSetSender.Factory replacePatchSetFactory, + DraftPublished draftPublished) { this.accountResolver = accountResolver; this.approvalsUtil = approvalsUtil; this.updateFactory = updateFactory; @@ -103,6 +106,7 @@ public class PublishDraftPatchSet implements RestModifyView, private final ChangeHooks hooks; private final ChangeMessagesUtil cmUtil; private final BatchUpdate.Factory batchUpdateFactory; + private final TopicEdited topicEdited; public static class Input { @DefaultInput @@ -57,11 +59,13 @@ public class PutTopic implements RestModifyView, PutTopic(Provider dbProvider, ChangeHooks hooks, ChangeMessagesUtil cmUtil, - BatchUpdate.Factory batchUpdateFactory) { + BatchUpdate.Factory batchUpdateFactory, + TopicEdited topicEdited) { this.dbProvider = dbProvider; this.hooks = hooks; this.cmUtil = cmUtil; this.batchUpdateFactory = batchUpdateFactory; + this.topicEdited = topicEdited; } @Override @@ -129,6 +133,9 @@ public class PutTopic implements RestModifyView, @Override public void postUpdate(Context ctx) throws OrmException { if (change != null) { + topicEdited.fire(change, + ctx.getUser().asIdentifiedUser().getAccount(), + oldTopicName); hooks.doTopicChangedHook( change, ctx.getUser().asIdentifiedUser().getAccount(), diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Restore.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Restore.java index b03194eab6..b944ac4ccc 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Restore.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Restore.java @@ -32,6 +32,7 @@ import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.server.ChangeMessagesUtil; import com.google.gerrit.server.ChangeUtil; import com.google.gerrit.server.PatchSetUtil; +import com.google.gerrit.server.extensions.events.ChangeRestored; import com.google.gerrit.server.git.BatchUpdate; import com.google.gerrit.server.git.BatchUpdate.ChangeContext; import com.google.gerrit.server.git.BatchUpdate.Context; @@ -60,6 +61,7 @@ public class Restore implements RestModifyView, private final ChangeMessagesUtil cmUtil; private final PatchSetUtil psUtil; private final BatchUpdate.Factory batchUpdateFactory; + private final ChangeRestored changeRestored; @Inject Restore(ChangeHooks hooks, @@ -68,7 +70,8 @@ public class Restore implements RestModifyView, ChangeJson.Factory json, ChangeMessagesUtil cmUtil, PatchSetUtil psUtil, - BatchUpdate.Factory batchUpdateFactory) { + BatchUpdate.Factory batchUpdateFactory, + ChangeRestored changeRestored) { this.hooks = hooks; this.restoredSenderFactory = restoredSenderFactory; this.dbProvider = dbProvider; @@ -76,6 +79,7 @@ public class Restore implements RestModifyView, this.cmUtil = cmUtil; this.psUtil = psUtil; this.batchUpdateFactory = batchUpdateFactory; + this.changeRestored = changeRestored; } @Override @@ -154,6 +158,9 @@ public class Restore implements RestModifyView, } catch (Exception e) { log.error("Cannot email update for change " + change.getId(), e); } + changeRestored.fire(change, patchSet, + ctx.getUser().asIdentifiedUser().getAccount(), + Strings.emptyToNull(input.message)); hooks.doChangeRestoredHook(change, ctx.getUser().asIdentifiedUser().getAccount(), patchSet, diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/SetHashtagsOp.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/SetHashtagsOp.java index 4e6bd2d87e..dd14213e60 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/change/SetHashtagsOp.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/SetHashtagsOp.java @@ -30,6 +30,7 @@ import com.google.gerrit.reviewdb.client.Change; import com.google.gerrit.reviewdb.client.ChangeMessage; import com.google.gerrit.server.ChangeMessagesUtil; import com.google.gerrit.server.ChangeUtil; +import com.google.gerrit.server.extensions.events.HashtagsEdited; import com.google.gerrit.server.git.BatchUpdate; import com.google.gerrit.server.git.BatchUpdate.ChangeContext; import com.google.gerrit.server.git.BatchUpdate.Context; @@ -56,6 +57,7 @@ public class SetHashtagsOp extends BatchUpdate.Op { private final ChangeMessagesUtil cmUtil; private final ChangeHooks hooks; private final DynamicSet validationListeners; + private final HashtagsEdited hashtagsEdited; private final HashtagsInput input; private boolean runHooks = true; @@ -71,11 +73,13 @@ public class SetHashtagsOp extends BatchUpdate.Op { ChangeMessagesUtil cmUtil, ChangeHooks hooks, DynamicSet validationListeners, + HashtagsEdited hashtagsEdited, @Assisted @Nullable HashtagsInput input) { this.notesMigration = notesMigration; this.cmUtil = cmUtil; this.hooks = hooks; this.validationListeners = validationListeners; + this.hashtagsEdited = hashtagsEdited; this.input = input; } @@ -166,6 +170,8 @@ public class SetHashtagsOp extends BatchUpdate.Op { @Override public void postUpdate(Context ctx) throws OrmException { if (updated() && runHooks) { + hashtagsEdited.fire(change, ctx.getUser().getAccountId(), updatedHashtags, + toAdd, toRemove); hooks.doHashtagsChangedHook( change, ctx.getUser().asIdentifiedUser().getAccount(), toAdd, toRemove, updatedHashtags, diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java index e22e61dfb8..a9104021af 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java @@ -29,12 +29,23 @@ import com.google.gerrit.extensions.config.DownloadCommand; import com.google.gerrit.extensions.config.DownloadScheme; import com.google.gerrit.extensions.config.ExternalIncludedIn; import com.google.gerrit.extensions.config.FactoryModule; +import com.google.gerrit.extensions.events.AgreementSignupListener; +import com.google.gerrit.extensions.events.ChangeAbandonedListener; +import com.google.gerrit.extensions.events.ChangeMergedListener; +import com.google.gerrit.extensions.events.ChangeRestoredListener; +import com.google.gerrit.extensions.events.CommentAddedListener; +import com.google.gerrit.extensions.events.DraftPublishedListener; import com.google.gerrit.extensions.events.GarbageCollectorListener; import com.google.gerrit.extensions.events.GitReferenceUpdatedListener; +import com.google.gerrit.extensions.events.HashtagsEditedListener; import com.google.gerrit.extensions.events.HeadUpdatedListener; import com.google.gerrit.extensions.events.LifecycleListener; import com.google.gerrit.extensions.events.NewProjectCreatedListener; +import com.google.gerrit.extensions.events.PluginEventListener; import com.google.gerrit.extensions.events.ProjectDeletedListener; +import com.google.gerrit.extensions.events.ReviewerAddedListener; +import com.google.gerrit.extensions.events.RevisionCreatedListener; +import com.google.gerrit.extensions.events.TopicEditedListener; import com.google.gerrit.extensions.events.UsageDataPublishedListener; import com.google.gerrit.extensions.registration.DynamicItem; import com.google.gerrit.extensions.registration.DynamicMap; @@ -283,6 +294,17 @@ public class GerritGlobalModule extends FactoryModule { DynamicSet.setOf(binder(), CacheRemovalListener.class); DynamicMap.mapOf(binder(), CapabilityDefinition.class); DynamicSet.setOf(binder(), GitReferenceUpdatedListener.class); + DynamicSet.setOf(binder(), ChangeAbandonedListener.class); + DynamicSet.setOf(binder(), CommentAddedListener.class); + DynamicSet.setOf(binder(), DraftPublishedListener.class); + DynamicSet.setOf(binder(), HashtagsEditedListener.class); + DynamicSet.setOf(binder(), ChangeMergedListener.class); + DynamicSet.setOf(binder(), ChangeRestoredListener.class); + DynamicSet.setOf(binder(), ReviewerAddedListener.class); + DynamicSet.setOf(binder(), RevisionCreatedListener.class); + DynamicSet.setOf(binder(), TopicEditedListener.class); + DynamicSet.setOf(binder(), AgreementSignupListener.class); + DynamicSet.setOf(binder(), PluginEventListener.class); DynamicSet.setOf(binder(), ReceivePackInitializer.class); DynamicSet.setOf(binder(), PostReceiveHook.class); DynamicSet.setOf(binder(), PreUploadHook.class); diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/AbstractChangeEvent.java b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/AbstractChangeEvent.java new file mode 100644 index 0000000000..d25046f3f9 --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/AbstractChangeEvent.java @@ -0,0 +1,31 @@ +// Copyright (C) 2015 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.extensions.events; + +import com.google.gerrit.extensions.common.ChangeInfo; +import com.google.gerrit.extensions.events.ChangeEvent; + +public abstract class AbstractChangeEvent implements ChangeEvent { + private final ChangeInfo changeInfo; + + protected AbstractChangeEvent(ChangeInfo change) { + this.changeInfo = change; + } + + @Override + public ChangeInfo getChange() { + return changeInfo; + } +} diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/AbstractRevisionEvent.java b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/AbstractRevisionEvent.java new file mode 100644 index 0000000000..35ce9b4a4b --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/AbstractRevisionEvent.java @@ -0,0 +1,35 @@ +// Copyright (C) 2015 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.extensions.events; + +import com.google.gerrit.extensions.common.ChangeInfo; +import com.google.gerrit.extensions.common.RevisionInfo; +import com.google.gerrit.extensions.events.RevisionEvent; + +public abstract class AbstractRevisionEvent extends AbstractChangeEvent + implements RevisionEvent { + + private final RevisionInfo revisionInfo; + + protected AbstractRevisionEvent(ChangeInfo change, RevisionInfo revision) { + super(change); + revisionInfo = revision; + } + + @Override + public RevisionInfo getRevision() { + return revisionInfo; + } +} diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/AgreementSignup.java b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/AgreementSignup.java new file mode 100644 index 0000000000..5a0db21920 --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/AgreementSignup.java @@ -0,0 +1,64 @@ +// Copyright (C) 2015 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.extensions.events; + +import com.google.gerrit.extensions.common.AccountInfo; +import com.google.gerrit.extensions.events.AgreementSignupListener; +import com.google.gerrit.extensions.registration.DynamicSet; +import com.google.gerrit.reviewdb.client.Account; +import com.google.inject.Inject; + +public class AgreementSignup { + + private final DynamicSet listeners; + private final EventUtil util; + + @Inject + AgreementSignup(DynamicSet listeners, + EventUtil util) { + this.listeners = listeners; + this.util = util; + } + + public void fire(Account account, String agreementName) { + if (!listeners.iterator().hasNext()) { + return; + } + Event e = new Event(util.accountInfo(account), agreementName); + for (AgreementSignupListener l : listeners) { + l.onAgreementSignup(e); + } + } + + private static class Event implements AgreementSignupListener.Event { + private final AccountInfo account; + private final String agreementName; + + Event(AccountInfo account, String agreementName) { + this.account = account; + this.agreementName = agreementName; + } + + @Override + public AccountInfo getAccount() { + return account; + } + + @Override + public String getAgreementName() { + return agreementName; + } + } +} diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/ChangeAbandoned.java b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/ChangeAbandoned.java new file mode 100644 index 0000000000..7ab8eb00b8 --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/ChangeAbandoned.java @@ -0,0 +1,97 @@ +// Copyright (C) 2015 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.extensions.events; + +import com.google.gerrit.extensions.common.AccountInfo; +import com.google.gerrit.extensions.common.ChangeInfo; +import com.google.gerrit.extensions.common.RevisionInfo; +import com.google.gerrit.extensions.events.ChangeAbandonedListener; +import com.google.gerrit.extensions.registration.DynamicSet; +import com.google.gerrit.reviewdb.client.Account; +import com.google.gerrit.reviewdb.client.Change; +import com.google.gerrit.reviewdb.client.PatchSet; +import com.google.gerrit.server.GpgException; +import com.google.gerrit.server.patch.PatchListNotAvailableException; +import com.google.gwtorm.server.OrmException; +import com.google.inject.Inject; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; + +public class ChangeAbandoned { + private static final Logger log = + LoggerFactory.getLogger(ChangeAbandoned.class); + + private final DynamicSet listeners; + private final EventUtil util; + + @Inject + ChangeAbandoned(DynamicSet listeners, + EventUtil util) { + this.listeners = listeners; + this.util = util; + } + + public void fire(ChangeInfo change, RevisionInfo revision, + AccountInfo abandoner, String reason) { + if (!listeners.iterator().hasNext()) { + return; + } + Event e = new Event(change, revision, abandoner, reason); + for (ChangeAbandonedListener l : listeners) { + l.onChangeAbandoned(e); + } + } + + public void fire(Change change, PatchSet ps, Account abandoner, String reason) { + if (!listeners.iterator().hasNext()) { + return; + } + try { + fire(util.changeInfo(change), + util.revisionInfo(change.getProject(), ps), + util.accountInfo(abandoner), + reason); + } catch (PatchListNotAvailableException | GpgException | IOException + | OrmException e) { + log.error("Couldn't fire event", e); + } + } + + private static class Event extends AbstractRevisionEvent + implements ChangeAbandonedListener.Event { + private final AccountInfo abandoner; + private final String reason; + + Event(ChangeInfo change, RevisionInfo revision, AccountInfo abandoner, + String reason) { + super(change, revision); + this.abandoner = abandoner; + this.reason = reason; + } + + @Override + public AccountInfo getAbandoner() { + return abandoner; + } + + @Override + public String getReason() { + return reason; + } + } +} diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/ChangeMerged.java b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/ChangeMerged.java new file mode 100644 index 0000000000..1677166928 --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/ChangeMerged.java @@ -0,0 +1,98 @@ +// Copyright (C) 2015 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.extensions.events; + +import com.google.gerrit.extensions.common.AccountInfo; +import com.google.gerrit.extensions.common.ChangeInfo; +import com.google.gerrit.extensions.common.RevisionInfo; +import com.google.gerrit.extensions.events.ChangeMergedListener; +import com.google.gerrit.extensions.registration.DynamicSet; +import com.google.gerrit.reviewdb.client.Account; +import com.google.gerrit.reviewdb.client.Change; +import com.google.gerrit.reviewdb.client.PatchSet; +import com.google.gerrit.server.GpgException; +import com.google.gerrit.server.patch.PatchListNotAvailableException; +import com.google.gwtorm.server.OrmException; +import com.google.inject.Inject; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; + +public class ChangeMerged { + private static final Logger log = + LoggerFactory.getLogger(ChangeAbandoned.class); + + private final DynamicSet listeners; + private final EventUtil util; + + @Inject + ChangeMerged(DynamicSet listeners, + EventUtil util) { + this.listeners = listeners; + this.util = util; + } + + public void fire(ChangeInfo change, RevisionInfo revision, + AccountInfo merger, String newRevisionId) { + if (!listeners.iterator().hasNext()) { + return; + } + Event e = new Event(change, revision, merger, newRevisionId); + for (ChangeMergedListener l : listeners) { + l.onChangeMerged(e); + } + } + + public void fire(Change change, PatchSet ps, Account merger, + String newRevisionId) { + if (!listeners.iterator().hasNext()) { + return; + } + try { + fire(util.changeInfo(change), + util.revisionInfo(change.getProject(), ps), + util.accountInfo(merger), + newRevisionId); + } catch (PatchListNotAvailableException | GpgException | IOException + | OrmException e) { + log.error("Couldn't fire event", e); + } + } + + private static class Event extends AbstractRevisionEvent + implements ChangeMergedListener.Event { + private final AccountInfo merger; + private final String newRevisionId; + + Event(ChangeInfo change, RevisionInfo revision, AccountInfo merger, + String newRevisionId) { + super(change, revision); + this.merger = merger; + this.newRevisionId = newRevisionId; + } + + @Override + public AccountInfo getMerger() { + return merger; + } + + @Override + public String getNewRevisionId() { + return newRevisionId; + } + } +} diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/ChangeRestored.java b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/ChangeRestored.java new file mode 100644 index 0000000000..f62c42f72d --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/ChangeRestored.java @@ -0,0 +1,98 @@ +// Copyright (C) 2015 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.extensions.events; + +import com.google.gerrit.extensions.common.AccountInfo; +import com.google.gerrit.extensions.common.ChangeInfo; +import com.google.gerrit.extensions.common.RevisionInfo; +import com.google.gerrit.extensions.events.ChangeRestoredListener; +import com.google.gerrit.extensions.registration.DynamicSet; +import com.google.gerrit.reviewdb.client.Account; +import com.google.gerrit.reviewdb.client.Change; +import com.google.gerrit.reviewdb.client.PatchSet; +import com.google.gerrit.server.GpgException; +import com.google.gerrit.server.patch.PatchListNotAvailableException; +import com.google.gwtorm.server.OrmException; +import com.google.inject.Inject; + +import java.io.IOException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ChangeRestored { + private static final Logger log = + LoggerFactory.getLogger(ChangeRestored.class); + + private final DynamicSet listeners; + private final EventUtil util; + + @Inject + ChangeRestored(DynamicSet listeners, + EventUtil util) { + this.listeners = listeners; + this.util = util; + } + + public void fire(ChangeInfo change, RevisionInfo revision, + AccountInfo restorer, String reason) { + Event e = new Event(change, revision, restorer, reason); + if (!listeners.iterator().hasNext()) { + return; + } + for (ChangeRestoredListener l : listeners) { + l.onChangeRestored(e); + } + } + + public void fire(Change change, PatchSet ps, Account restorer, String reason) { + if (!listeners.iterator().hasNext()) { + return; + } + try { + fire(util.changeInfo(change), + util.revisionInfo(change.getProject(), ps), + util.accountInfo(restorer), + reason); + } catch (PatchListNotAvailableException | GpgException | IOException + | OrmException e) { + log.error("Couldn't fire event", e); + } + } + + private static class Event extends AbstractRevisionEvent + implements ChangeRestoredListener.Event { + + private AccountInfo restorer; + private String reason; + + Event(ChangeInfo change, RevisionInfo revision, AccountInfo restorer, + String reason) { + super(change, revision); + this.restorer = restorer; + this.reason = reason; + } + + @Override + public AccountInfo getRestorer() { + return restorer; + } + + @Override + public String getReason() { + return reason; + } + } +} diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/CommentAdded.java b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/CommentAdded.java new file mode 100644 index 0000000000..aa17517f91 --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/CommentAdded.java @@ -0,0 +1,122 @@ +// Copyright (C) 2015 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.extensions.events; + +import com.google.gerrit.extensions.common.AccountInfo; +import com.google.gerrit.extensions.common.ApprovalInfo; +import com.google.gerrit.extensions.common.ChangeInfo; +import com.google.gerrit.extensions.common.RevisionInfo; +import com.google.gerrit.extensions.events.CommentAddedListener; +import com.google.gerrit.extensions.registration.DynamicSet; +import com.google.gerrit.reviewdb.client.Account; +import com.google.gerrit.reviewdb.client.Change; +import com.google.gerrit.reviewdb.client.PatchSet; +import com.google.gerrit.server.GpgException; +import com.google.gerrit.server.patch.PatchListNotAvailableException; +import com.google.gwtorm.server.OrmException; +import com.google.inject.Inject; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.sql.Timestamp; +import java.util.Map; + +public class CommentAdded { + private static final Logger log = + LoggerFactory.getLogger(CommentAdded.class); + + private final DynamicSet listeners; + private final EventUtil util; + + @Inject + CommentAdded(DynamicSet listeners, + EventUtil util) { + this.listeners = listeners; + this.util = util; + } + + public void fire(ChangeInfo change, RevisionInfo revision, AccountInfo author, + String comment, Map approvals, + Map oldApprovals) { + if (!listeners.iterator().hasNext()) { + return; + } + Event e = new Event( + change, revision, author, comment, approvals, oldApprovals); + for (CommentAddedListener l : listeners) { + l.onCommentAdded(e); + } + } + + public void fire(Change change, PatchSet ps, Account author, + String comment, Map approvals, + Map oldApprovals, Timestamp ts) { + if (!listeners.iterator().hasNext()) { + return; + } + try { + fire(util.changeInfo(change), + util.revisionInfo(change.getProject(), ps), + util.accountInfo(author), + comment, + util.approvals(author, approvals, ts), + util.approvals(author, oldApprovals, ts)); + } catch (PatchListNotAvailableException | GpgException | IOException + | OrmException e) { + log.error("Couldn't fire event", e); + } + } + + private static class Event extends AbstractRevisionEvent + implements CommentAddedListener.Event { + + private final AccountInfo author; + private final String comment; + private final Map approvals; + private final Map oldApprovals; + + Event(ChangeInfo change, RevisionInfo revision, AccountInfo author, + String comment, Map approvals, + Map oldApprovals) { + super(change, revision); + this.author = author; + this.comment = comment; + this.approvals = approvals; + this.oldApprovals = oldApprovals; + } + + @Override + public AccountInfo getAuthor() { + return author; + } + + @Override + public String getComment() { + return comment; + } + + @Override + public Map getApprovals() { + return approvals; + } + + @Override + public Map getOldApprovals() { + return oldApprovals; + } + } +} diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/DraftPublished.java b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/DraftPublished.java new file mode 100644 index 0000000000..bc1772d111 --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/DraftPublished.java @@ -0,0 +1,85 @@ +// Copyright (C) 2015 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.extensions.events; + +import com.google.gerrit.extensions.common.AccountInfo; +import com.google.gerrit.extensions.common.ChangeInfo; +import com.google.gerrit.extensions.common.RevisionInfo; +import com.google.gerrit.extensions.events.DraftPublishedListener; +import com.google.gerrit.extensions.registration.DynamicSet; +import com.google.gerrit.reviewdb.client.Account; +import com.google.gerrit.reviewdb.client.Change; +import com.google.gerrit.reviewdb.client.PatchSet; +import com.google.gerrit.server.GpgException; +import com.google.gerrit.server.patch.PatchListNotAvailableException; +import com.google.gwtorm.server.OrmException; +import com.google.inject.Inject; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; + +public class DraftPublished { + private static final Logger log = + LoggerFactory.getLogger(DraftPublished.class); + + private final DynamicSet listeners; + private final EventUtil util; + + @Inject + public DraftPublished(DynamicSet listeners, + EventUtil util) { + this.listeners = listeners; + this.util = util; + } + + public void fire(ChangeInfo change, RevisionInfo revision, + AccountInfo publisher) { + if (!listeners.iterator().hasNext()) { + return; + } + Event e = new Event(change, revision, publisher); + for (DraftPublishedListener l : listeners) { + l.onDraftPublished(e); + } + } + + public void fire(Change change, PatchSet patchSet, Account.Id accountId) { + try { + fire(util.changeInfo(change), + util.revisionInfo(change.getProject(), patchSet), + util.accountInfo(accountId)); + } catch (PatchListNotAvailableException | GpgException | IOException + | OrmException e) { + log.error("Couldn't fire event", e); + } + } + + private static class Event extends AbstractRevisionEvent + implements DraftPublishedListener.Event { + private final AccountInfo publisher; + + Event(ChangeInfo change, RevisionInfo revision, AccountInfo publisher) { + super(change, revision); + this.publisher = publisher; + } + + @Override + public AccountInfo getPublisher() { + return publisher; + } + } +} diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/EventUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/EventUtil.java index cb30eea6cb..43f03cec5e 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/EventUtil.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/EventUtil.java @@ -15,19 +15,66 @@ package com.google.gerrit.server.extensions.events; import com.google.gerrit.extensions.common.AccountInfo; +import com.google.gerrit.extensions.common.ApprovalInfo; +import com.google.gerrit.extensions.common.ChangeInfo; +import com.google.gerrit.extensions.common.RevisionInfo; import com.google.gerrit.reviewdb.client.Account; +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.reviewdb.client.Change; +import com.google.gerrit.server.GpgException; import com.google.gerrit.server.account.AccountCache; +import com.google.gerrit.server.change.ChangeJson; +import com.google.gerrit.server.patch.PatchListNotAvailableException; +import com.google.gerrit.server.project.ChangeControl; +import com.google.gerrit.server.query.change.ChangeData; +import com.google.gwtorm.server.OrmException; import com.google.inject.Inject; +import com.google.inject.Provider; + +import java.io.IOException; +import java.sql.Timestamp; +import java.util.HashMap; +import java.util.Map; public class EventUtil { + private final ChangeData.Factory changeDataFactory; + private final Provider db; + private final ChangeJson changeJson; private final AccountCache accountCache; @Inject - EventUtil(AccountCache accountCache) { + EventUtil(ChangeJson.Factory changeJsonFactory, + ChangeData.Factory changeDataFactory, + Provider db, + AccountCache accountCache) { + this.changeDataFactory = changeDataFactory; + this.db = db; + this.changeJson = changeJsonFactory.create(ChangeJson.NO_OPTIONS); this.accountCache = accountCache; } + public ChangeInfo changeInfo(Change change) throws OrmException { + return changeJson.format(change); + } + + public RevisionInfo revisionInfo(Project project, PatchSet ps) + throws OrmException, PatchListNotAvailableException, GpgException, + IOException { + return revisionInfo(project.getNameKey(), ps); + } + + public RevisionInfo revisionInfo(Project.NameKey project, PatchSet ps) + throws OrmException, PatchListNotAvailableException, GpgException, + IOException { + ChangeData cd = changeDataFactory.create(db.get(), + project, ps.getId().getParentKey()); + ChangeControl ctl = cd.changeControl(); + return changeJson.getRevisionInfo(ctl, ps); + } + public AccountInfo accountInfo(Account a) { if (a == null || a.getId() == null) { return null; @@ -42,4 +89,15 @@ public class EventUtil { public AccountInfo accountInfo(Account.Id accountId) { return accountInfo(accountCache.get(accountId).getAccount()); } + + public Map approvals(Account a, + Map approvals, Timestamp ts) { + Map result = new HashMap<>(); + for (Map.Entry e : approvals.entrySet()) { + Integer value = e.getValue() != null ? new Integer(e.getValue()) : null; + result.put(e.getKey(), + ChangeJson.getApprovalInfo(a.getId(), value, null, ts)); + } + return result; + } } diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/GitReferenceUpdated.java b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/GitReferenceUpdated.java index 6eac07c5f5..29a47aa8f4 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/GitReferenceUpdated.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/GitReferenceUpdated.java @@ -115,6 +115,9 @@ public class GitReferenceUpdated { public void fire(Project.NameKey project, BatchRefUpdate batchRefUpdate, Account.Id updater) { + if (!listeners.iterator().hasNext()) { + return; + } for (ReceiveCommand cmd : batchRefUpdate.getCommands()) { if (cmd.getResult() == ReceiveCommand.Result.OK) { fire(project, cmd, util.accountInfo(updater)); @@ -130,6 +133,9 @@ public class GitReferenceUpdated { private void fire(Project.NameKey project, String ref, ObjectId oldObjectId, ObjectId newObjectId, ReceiveCommand.Type type, AccountInfo updater) { + if (!listeners.iterator().hasNext()) { + return; + } ObjectId o = oldObjectId != null ? oldObjectId : ObjectId.zeroId(); ObjectId n = newObjectId != null ? newObjectId : ObjectId.zeroId(); Event event = new Event(project, ref, o.name(), n.name(), type, updater); diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/HashtagsEdited.java b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/HashtagsEdited.java new file mode 100644 index 0000000000..de679e66cd --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/HashtagsEdited.java @@ -0,0 +1,110 @@ +// Copyright (C) 2015 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.extensions.events; + +import com.google.common.collect.ImmutableSortedSet; +import com.google.gerrit.extensions.common.AccountInfo; +import com.google.gerrit.extensions.common.ChangeInfo; +import com.google.gerrit.extensions.events.HashtagsEditedListener; +import com.google.gerrit.extensions.registration.DynamicSet; +import com.google.gerrit.reviewdb.client.Account.Id; +import com.google.gerrit.reviewdb.client.Change; +import com.google.gwtorm.server.OrmException; +import com.google.inject.Inject; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collection; +import java.util.Set; + +public class HashtagsEdited { + private static final Logger log = + LoggerFactory.getLogger(HashtagsEdited.class); + + private final DynamicSet listeners; + private final EventUtil util; + + @Inject + public HashtagsEdited(DynamicSet listeners, + EventUtil util) { + this.listeners = listeners; + this.util = util; + } + + public void fire(ChangeInfo change, AccountInfo editor, Collection hashtags, + Collection added, Collection removed) { + Event e = new Event(change, editor, hashtags, added, removed); + if (!listeners.iterator().hasNext()) { + return; + } + for (HashtagsEditedListener l : listeners) { + l.onHashtagsEdited(e); + } + } + + public void fire(Change change, Id accountId, + ImmutableSortedSet updatedHashtags, Set toAdd, + Set toRemove) { + if (!listeners.iterator().hasNext()) { + return; + } + try { + fire(util.changeInfo(change), + util.accountInfo(accountId), + updatedHashtags, toAdd, toRemove); + } catch (OrmException e) { + log.error("Couldn't fire event", e); + } + } + + private static class Event extends AbstractChangeEvent + implements HashtagsEditedListener.Event { + + private AccountInfo editor; + private Collection updatedHashtags; + private Collection addedHashtags; + private Collection removedHashtags; + + Event(ChangeInfo change, AccountInfo editor, Collection updated, + Collection added, Collection removed) { + super(change); + this.editor = editor; + this.updatedHashtags = updated; + this.addedHashtags = added; + this.removedHashtags = removed; + } + + @Override + public AccountInfo getEditor() { + return editor; + } + + @Override + public Collection getHashtags() { + return updatedHashtags; + } + + @Override + public Collection getAddedHashtags() { + return addedHashtags; + } + + @Override + public Collection getRemovedHashtags() { + return removedHashtags; + } + } +} diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/PluginEvent.java b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/PluginEvent.java new file mode 100644 index 0000000000..eadb6b9f71 --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/PluginEvent.java @@ -0,0 +1,65 @@ +// Copyright (C) 2015 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.extensions.events; + +import com.google.gerrit.extensions.events.PluginEventListener; +import com.google.gerrit.extensions.registration.DynamicSet; +import com.google.inject.Inject; + +public class PluginEvent { + private final DynamicSet listeners; + + @Inject + PluginEvent(DynamicSet listeners) { + this.listeners = listeners; + } + + public void fire(String pluginName, String type, String data) { + if (!listeners.iterator().hasNext()) { + return; + } + Event e = new Event(pluginName, type, data); + for (PluginEventListener l : listeners) { + l.onPluginEvent(e); + } + } + + private static class Event implements PluginEventListener.Event { + private final String pluginName; + private final String type; + private final String data; + + Event(String pluginName, String type, String data) { + this.pluginName = pluginName; + this.type = type; + this.data = data; + } + + @Override + public String pluginName() { + return pluginName; + } + + @Override + public String getType() { + return type; + } + + @Override + public String getData() { + return data; + } + } +} diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/ReviewerAdded.java b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/ReviewerAdded.java new file mode 100644 index 0000000000..4cd9be2aad --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/ReviewerAdded.java @@ -0,0 +1,88 @@ +// Copyright (C) 2015 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.extensions.events; + +import com.google.gerrit.extensions.common.AccountInfo; +import com.google.gerrit.extensions.common.ChangeInfo; +import com.google.gerrit.extensions.common.RevisionInfo; +import com.google.gerrit.extensions.events.ReviewerAddedListener; +import com.google.gerrit.extensions.registration.DynamicSet; +import com.google.gerrit.reviewdb.client.Account; +import com.google.gerrit.reviewdb.client.Change; +import com.google.gerrit.reviewdb.client.PatchSet; +import com.google.gerrit.server.GpgException; +import com.google.gerrit.server.patch.PatchListNotAvailableException; +import com.google.gwtorm.server.OrmException; +import com.google.inject.Inject; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; + +public class ReviewerAdded { + private static final Logger log = + LoggerFactory.getLogger(ReviewerAdded.class); + + private final DynamicSet listeners; + private final EventUtil util; + + @Inject + ReviewerAdded(DynamicSet listeners, + EventUtil util) { + this.listeners = listeners; + this.util = util; + } + + public void fire(ChangeInfo change, RevisionInfo revision, + AccountInfo reviewer) { + if (!listeners.iterator().hasNext()) { + return; + } + Event e = new Event(change, revision, reviewer); + for (ReviewerAddedListener l : listeners) { + l.onReviewerAdded(e); + } + } + + public void fire(Change change, PatchSet patchSet, Account account) { + if (!listeners.iterator().hasNext()) { + return; + } + try { + fire(util.changeInfo(change), + util.revisionInfo(change.getProject(), patchSet), + util.accountInfo(account)); + } catch (PatchListNotAvailableException | GpgException | IOException + | OrmException e) { + log.error("Couldn't fire event", e); + } + } + + private static class Event extends AbstractRevisionEvent + implements ReviewerAddedListener.Event { + private final AccountInfo reviewer; + + Event(ChangeInfo change, RevisionInfo revision, AccountInfo reviewer) { + super(change, revision); + this.reviewer = reviewer; + } + + @Override + public AccountInfo getReviewer() { + return reviewer; + } + } +} diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/RevisionCreated.java b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/RevisionCreated.java new file mode 100644 index 0000000000..7f03e78e20 --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/RevisionCreated.java @@ -0,0 +1,88 @@ +// Copyright (C) 2015 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.extensions.events; + +import com.google.gerrit.extensions.common.AccountInfo; +import com.google.gerrit.extensions.common.ChangeInfo; +import com.google.gerrit.extensions.common.RevisionInfo; +import com.google.gerrit.extensions.events.RevisionCreatedListener; +import com.google.gerrit.extensions.registration.DynamicSet; +import com.google.gerrit.reviewdb.client.Account; +import com.google.gerrit.reviewdb.client.Change; +import com.google.gerrit.reviewdb.client.PatchSet; +import com.google.gerrit.server.GpgException; +import com.google.gerrit.server.patch.PatchListNotAvailableException; +import com.google.gwtorm.server.OrmException; +import com.google.inject.Inject; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; + +public class RevisionCreated { + private static final Logger log = + LoggerFactory.getLogger(RevisionCreated.class); + + private final DynamicSet listeners; + private final EventUtil util; + + @Inject + RevisionCreated(DynamicSet listeners, + EventUtil util) { + this.listeners = listeners; + this.util = util; + } + + public void fire(ChangeInfo change, RevisionInfo revision, + AccountInfo uploader) { + if (!listeners.iterator().hasNext()) { + return; + } + Event e = new Event(change, revision, uploader); + for (RevisionCreatedListener l : listeners) { + l.onRevisionCreated(e); + } + } + + public void fire(Change change, PatchSet patchSet, Account.Id uploader) { + if (!listeners.iterator().hasNext()) { + return; + } + try { + fire(util.changeInfo(change), + util.revisionInfo(change.getProject(), patchSet), + util.accountInfo(uploader)); + } catch ( PatchListNotAvailableException | GpgException | IOException + | OrmException e) { + log.error("Couldn't fire event", e); + } + } + + private static class Event extends AbstractRevisionEvent + implements RevisionCreatedListener.Event { + private final AccountInfo uploader; + + Event(ChangeInfo change, RevisionInfo revision, AccountInfo uploader) { + super(change, revision); + this.uploader = uploader; + } + + @Override + public AccountInfo getUploader() { + return uploader; + } + } +} diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/TopicEdited.java b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/TopicEdited.java new file mode 100644 index 0000000000..7b1386dde2 --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/TopicEdited.java @@ -0,0 +1,87 @@ +// Copyright (C) 2015 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.extensions.events; + +import com.google.gerrit.extensions.common.AccountInfo; +import com.google.gerrit.extensions.common.ChangeInfo; +import com.google.gerrit.extensions.events.TopicEditedListener; +import com.google.gerrit.extensions.registration.DynamicSet; +import com.google.gerrit.reviewdb.client.Account; +import com.google.gerrit.reviewdb.client.Change; +import com.google.gwtorm.server.OrmException; +import com.google.inject.Inject; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TopicEdited { + private static final Logger log = + LoggerFactory.getLogger(TopicEdited.class); + + private final DynamicSet listeners; + private final EventUtil util; + + @Inject + TopicEdited(DynamicSet listeners, + EventUtil util) { + this.listeners = listeners; + this.util = util; + } + + public void fire(ChangeInfo change, AccountInfo editor, String oldTopic) { + if (!listeners.iterator().hasNext()) { + return; + } + Event e = new Event(change, editor, oldTopic); + for (TopicEditedListener l : listeners) { + l.onTopicEdited(e); + } + } + + public void fire(Change change, Account account, String oldTopicName) { + if (!listeners.iterator().hasNext()) { + return; + } + try { + fire(util.changeInfo(change), + util.accountInfo(account), + oldTopicName); + } catch (OrmException e) { + log.error("Couldn't fire event", e); + } + } + + private static class Event extends AbstractChangeEvent + implements TopicEditedListener.Event { + private final AccountInfo editor; + private final String oldTopic; + + Event(ChangeInfo change, AccountInfo editor, String oldTopic) { + super(change); + this.editor = editor; + this.oldTopic = oldTopic; + } + + @Override + public AccountInfo getEditor() { + return editor; + } + + @Override + public String getOldTopic() { + return oldTopic; + } + } +} diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergedByPushOp.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergedByPushOp.java index 755fe9a26f..51a67989de 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergedByPushOp.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergedByPushOp.java @@ -17,6 +17,7 @@ package com.google.gerrit.server.git; import static com.google.common.base.Preconditions.checkNotNull; import com.google.gerrit.common.ChangeHooks; +import com.google.gerrit.reviewdb.client.Account; import com.google.gerrit.reviewdb.client.Change; import com.google.gerrit.reviewdb.client.ChangeMessage; import com.google.gerrit.reviewdb.client.LabelId; @@ -26,6 +27,7 @@ import com.google.gerrit.reviewdb.client.PatchSetInfo; import com.google.gerrit.server.ChangeMessagesUtil; import com.google.gerrit.server.ChangeUtil; import com.google.gerrit.server.PatchSetUtil; +import com.google.gerrit.server.extensions.events.ChangeMerged; import com.google.gerrit.server.git.BatchUpdate.ChangeContext; import com.google.gerrit.server.git.BatchUpdate.Context; import com.google.gerrit.server.mail.MergedSender; @@ -65,6 +67,7 @@ public class MergedByPushOp extends BatchUpdate.Op { private final MergedSender.Factory mergedSenderFactory; private final PatchSetUtil psUtil; private final ExecutorService sendEmailExecutor; + private final ChangeMerged changeMerged; private final PatchSet.Id psId; private final String refName; @@ -83,6 +86,7 @@ public class MergedByPushOp extends BatchUpdate.Op { MergedSender.Factory mergedSenderFactory, PatchSetUtil psUtil, @SendEmailExecutor ExecutorService sendEmailExecutor, + ChangeMerged changeMerged, @Assisted RequestScopePropagator requestScopePropagator, @Assisted PatchSet.Id psId, @Assisted String refName) { @@ -92,6 +96,7 @@ public class MergedByPushOp extends BatchUpdate.Op { this.mergedSenderFactory = mergedSenderFactory; this.psUtil = psUtil; this.sendEmailExecutor = sendEmailExecutor; + this.changeMerged = changeMerged; this.requestScopePropagator = requestScopePropagator; this.psId = psId; this.refName = refName; @@ -194,9 +199,11 @@ public class MergedByPushOp extends BatchUpdate.Op { } })); + Account account = ctx.getUser().asIdentifiedUser().getAccount(); hooks.doChangeMergedHook( - change, ctx.getUser().asIdentifiedUser().getAccount(), patchSet, + change, account, patchSet, ctx.getDb(), patchSet.getRevision().get()); + changeMerged.fire(change, patchSet, account, patchSet.getRevision().get()); } private PatchSetInfo getPatchSetInfo(ChangeContext ctx) throws IOException {