diff --git a/Documentation/cmd-stream-events.txt b/Documentation/cmd-stream-events.txt index c754f35019..dcdbb0717a 100644 --- a/Documentation/cmd-stream-events.txt +++ b/Documentation/cmd-stream-events.txt @@ -153,6 +153,19 @@ hashtags:: List of hashtags on the change after tags were added or removed eventCreatedOn:: Time in seconds since the UNIX epoch when this event was created. +=== Project Created + +Sent when a new project has been created. + +type:: "project-created" + +projectName:: The created project name + +projectHead:: The created project head name + +eventCreatedOn:: Time in seconds since the UNIX epoch when this event was +created. + === Merge Failed Sent when a change has failed to be merged into the git repository. diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt index dab0f5e1cc..742d996790 100644 --- a/Documentation/config-gerrit.txt +++ b/Documentation/config-gerrit.txt @@ -1832,6 +1832,11 @@ Optional filename for the draft published hook, if not specified then Optional filename for the hashtags changed hook, if not specified then `hashtags-changed` will be used. +[[hooks.projectCreatedHook]]hooks.projectCreatedHook:: ++ +Optional filename for the project created hook, if not specified then +`project-created` will be used. + [[hooks.mergeFailedHook]]hooks.mergeFailedHook:: + Optional filename for the merge failed hook, if not specified then diff --git a/Documentation/config-hooks.txt b/Documentation/config-hooks.txt index 5666dffff3..d4f53bf5e5 100644 --- a/Documentation/config-hooks.txt +++ b/Documentation/config-hooks.txt @@ -110,6 +110,14 @@ Called whenever a ref has been updated. ref-updated --oldrev --newrev --refname --project --submitter ==== +=== project-created + +Called whenever a project has been created. + +==== + project-created --project --head +==== + === reviewer-added Called whenever a reviewer is added to a change. 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 3a58373f15..19c31456de 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 @@ -20,6 +20,7 @@ import com.google.gerrit.common.data.ContributorAgreement; import com.google.gerrit.common.data.LabelType; import com.google.gerrit.common.data.LabelTypes; import com.google.gerrit.extensions.events.LifecycleListener; +import com.google.gerrit.extensions.events.NewProjectCreatedListener; import com.google.gerrit.extensions.registration.DynamicSet; import com.google.gerrit.lifecycle.LifecycleModule; import com.google.gerrit.reviewdb.client.Account; @@ -40,11 +41,11 @@ import com.google.gerrit.server.events.ChangeMergedEvent; import com.google.gerrit.server.events.ChangeRestoredEvent; import com.google.gerrit.server.events.CommentAddedEvent; import com.google.gerrit.server.events.DraftPublishedEvent; -import com.google.gerrit.server.events.Event; import com.google.gerrit.server.events.EventFactory; import com.google.gerrit.server.events.HashtagsChangedEvent; import com.google.gerrit.server.events.MergeFailedEvent; import com.google.gerrit.server.events.PatchSetCreatedEvent; +import com.google.gerrit.server.events.ProjectCreatedEvent; import com.google.gerrit.server.events.RefUpdatedEvent; import com.google.gerrit.server.events.ReviewerAddedEvent; import com.google.gerrit.server.events.TopicChangedEvent; @@ -89,7 +90,7 @@ import java.util.concurrent.TimeoutException; /** Spawns local executables when a hook action occurs. */ @Singleton public class ChangeHookRunner implements ChangeHooks, EventDispatcher, - EventSource, LifecycleListener { + EventSource, LifecycleListener, NewProjectCreatedListener { /** A logger for this class. */ private static final Logger log = LoggerFactory.getLogger(ChangeHookRunner.class); @@ -100,6 +101,7 @@ public class ChangeHookRunner implements ChangeHooks, EventDispatcher, bind(ChangeHooks.class).to(ChangeHookRunner.class); bind(EventDispatcher.class).to(ChangeHookRunner.class); bind(EventSource.class).to(ChangeHookRunner.class); + DynamicSet.bind(binder(), NewProjectCreatedListener.class).to(ChangeHookRunner.class); listener().to(ChangeHookRunner.class); } } @@ -209,6 +211,9 @@ public class ChangeHookRunner implements ChangeHooks, EventDispatcher, /** Path of the hashtags changed hook */ private final Path hashtagsChangedHook; + /** Path of the project created hook. */ + private final Path projectCreatedHook; + private final String anonymousCowardName; /** Repository Manager. */ @@ -282,6 +287,7 @@ public class ChangeHookRunner implements ChangeHooks, EventDispatcher, claSignedHook = hook(config, hooksPath, "cla-signed"); refUpdateHook = hook(config, hooksPath, "ref-update"); hashtagsChangedHook = hook(config, hooksPath, "hashtags-changed"); + projectCreatedHook = hook(config, hooksPath, "project-created"); syncHookTimeout = config.getInt("hooks", "syncHookTimeout", 30); syncHookThreadPool = Executors.newCachedThreadPool( @@ -346,6 +352,20 @@ public class ChangeHookRunner implements ChangeHooks, EventDispatcher, return runSyncHook(project.getNameKey(), refUpdateHook, args); } + @Override + public void doProjectCreatedHook(Project.NameKey project, String headName) { + ProjectCreatedEvent event = new ProjectCreatedEvent(); + event.projectName = project.get(); + event.headName = headName; + fireEvent(project, event); + + List args = new ArrayList<>(); + addArg(args, "--project", project.get()); + addArg(args, "--head", headName); + + runHook(project, projectCreatedHook, args); + } + /** * Fire the Patchset Created Hook. * @@ -695,24 +715,24 @@ public class ChangeHookRunner implements ChangeHooks, EventDispatcher, } @Override - public void postEvent(Change change, Event event, ReviewDb db) - throws OrmException { + public void postEvent(Change change, com.google.gerrit.server.events.Event event, + ReviewDb db) throws OrmException { fireEvent(change, event, db); } @Override - public void postEvent(Branch.NameKey branchName, Event event) { + public void postEvent(Branch.NameKey branchName, com.google.gerrit.server.events.Event event) { fireEvent(branchName, event); } - private void fireEventForUnrestrictedListeners(Event event) { + private void fireEventForUnrestrictedListeners(com.google.gerrit.server.events.Event event) { for (EventListener listener : unrestrictedListeners) { listener.onEvent(event); } } - private void fireEvent(Change change, Event event, ReviewDb db) - throws OrmException { + private void fireEvent(Change change, com.google.gerrit.server.events.Event event, + ReviewDb db) throws OrmException { for (EventListenerHolder holder : listeners.values()) { if (isVisibleTo(change, holder.user, db)) { holder.listener.onEvent(event); @@ -722,7 +742,32 @@ public class ChangeHookRunner implements ChangeHooks, EventDispatcher, fireEventForUnrestrictedListeners( event ); } - private void fireEvent(Branch.NameKey branchName, Event event) { + private void fireEvent(Project.NameKey project, ProjectCreatedEvent event) { + for (EventListenerHolder holder : listeners.values()) { + if (isVisibleTo(project, event, holder.user)) { + holder.listener.onEvent(event); + } + } + + fireEventForUnrestrictedListeners(event); + } + + private void fireEventForUnrestrictedListeners(ProjectCreatedEvent event) { + for (EventListener listener : unrestrictedListeners) { + listener.onEvent(event); + } + } + + private boolean isVisibleTo(Project.NameKey project, ProjectCreatedEvent event, CurrentUser user) { + ProjectState pe = projectCache.get(project); + if (pe == null) { + return false; + } + ProjectControl pc = pe.controlFor(user); + return pc.controlForRef(event.getHeadName()).isVisible(); + } + + private void fireEvent(Branch.NameKey branchName, com.google.gerrit.server.events.Event event) { for (EventListenerHolder holder : listeners.values()) { if (isVisibleTo(branchName, holder.user)) { holder.listener.onEvent(event); @@ -995,4 +1040,10 @@ public class ChangeHookRunner implements ChangeHooks, EventDispatcher, super.runHook(); } } + + @Override + public void onNewProjectCreated(NewProjectCreatedListener.Event event) { + Project.NameKey project = new Project.NameKey(event.getProjectName()); + doProjectCreatedHook(project, event.getHeadName()); + } } 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 7f7e8b24a3..b16a8a5b3a 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 @@ -181,4 +181,12 @@ public interface ChangeHooks { public void doHashtagsChangedHook(Change change, Account account, Setadded, Set removed, Set hashtags, ReviewDb db) throws OrmException; + + /** + * Fire the project created hook + * + * @param project The project that was created + * @param headName The head name of the created project + */ + public void doProjectCreatedHook(Project.NameKey project, String headName); } 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 156672eb7b..bed77a7f7c 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 @@ -113,6 +113,10 @@ public final class DisabledChangeHooks implements ChangeHooks, EventDispatcher, return null; } + @Override + public void doProjectCreatedHook(Project.NameKey project, String headName) { + } + @Override public void postEvent(Change change, Event event, ReviewDb db) { } diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/events/EventTypes.java b/gerrit-server/src/main/java/com/google/gerrit/server/events/EventTypes.java index 908fd0a870..9b37c385c8 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/events/EventTypes.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/events/EventTypes.java @@ -35,6 +35,7 @@ public class EventTypes { registerClass(new ReviewerAddedEvent()); registerClass(new PatchSetCreatedEvent()); registerClass(new TopicChangedEvent()); + registerClass(new ProjectCreatedEvent()); } /** Register an event. diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/events/ProjectCreatedEvent.java b/gerrit-server/src/main/java/com/google/gerrit/server/events/ProjectCreatedEvent.java new file mode 100644 index 0000000000..c1534dff7e --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/events/ProjectCreatedEvent.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.events; + +import com.google.gerrit.reviewdb.client.Project; + +public class ProjectCreatedEvent extends ProjectEvent { + public String projectName; + public String headName; + + public ProjectCreatedEvent() { + super("project-created"); + } + + @Override + public Project.NameKey getProjectNameKey() { + return new Project.NameKey(projectName); + } + + public String getHeadName() { + return headName; + } +}