Added cla-signed hook
The cla-signed hook is fired every time a user accepts a contributor
license agreement.
Change-Id: Ia907b879e84517fe16ed898e6eaf6cff1d80bbdf
diff --git a/Documentation/config-hooks.txt b/Documentation/config-hooks.txt
index fd2ae82..963b628 100644
--- a/Documentation/config-hooks.txt
+++ b/Documentation/config-hooks.txt
@@ -75,6 +75,15 @@
ref-updated --oldrev <old rev> --newrev <new rev> --refname <ref name> --project <project name> --submitter <submitter>
====
+cla-signed
+~~~~~~~~~~~
+
+Called whenever a user signs a contributor license agreement
+
+====
+ cla-signed --submitter <submitter> --user-id <user_id> --cla-id <cla_id>
+====
+
Configuration Settings
----------------------
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 173ca60..f69a0d6 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
@@ -14,6 +14,7 @@
package com.google.gerrit.httpd.rpc.account;
+import com.google.gerrit.common.ChangeHookRunner;
import com.google.gerrit.common.data.AccountSecurity;
import com.google.gerrit.common.data.GroupDetail;
import com.google.gerrit.common.errors.ContactInformationStoreException;
@@ -32,6 +33,7 @@
import com.google.gerrit.reviewdb.ContactInformation;
import com.google.gerrit.reviewdb.ContributorAgreement;
import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.Project;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.account.AccountByEmailCache;
@@ -89,6 +91,8 @@
private final MyGroupsFactory.Factory myGroupsFactory;
private final GroupDetailFactory.Factory groupDetailFactory;
+ private final ChangeHookRunner hooks;
+
@Inject
AccountSecurityImpl(final Provider<ReviewDb> schema,
final Provider<CurrentUser> currentUser, final ContactStore cs,
@@ -102,7 +106,8 @@
final DeleteExternalIds.Factory deleteExternalIdsFactory,
final ExternalIdDetailFactory.Factory externalIdDetailFactory,
final MyGroupsFactory.Factory myGroupsFactory,
- final GroupDetailFactory.Factory groupDetailFactory) {
+ final GroupDetailFactory.Factory groupDetailFactory,
+ final ChangeHookRunner hooks) {
super(schema, currentUser);
contactStore = cs;
authConfig = ac;
@@ -123,6 +128,7 @@
this.externalIdDetailFactory = externalIdDetailFactory;
this.myGroupsFactory = myGroupsFactory;
this.groupDetailFactory = groupDetailFactory;
+ this.hooks = hooks;
}
public void mySshKeys(final AsyncCallback<List<AccountSshKey>> callback) {
@@ -279,6 +285,8 @@
.getAccountId(), id));
if (cla.isAutoVerify()) {
a.review(AccountAgreement.Status.VERIFIED, null);
+
+ hooks.doClaSignupHook(user.get().getAccount(), cla);
}
db.accountAgreements().insert(Collections.singleton(a));
return VoidResult.INSTANCE;
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 8205946..0a7337a 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
@@ -21,6 +21,7 @@
import com.google.gerrit.reviewdb.ApprovalCategoryValue;
import com.google.gerrit.reviewdb.Branch;
import com.google.gerrit.reviewdb.Change;
+import com.google.gerrit.reviewdb.ContributorAgreement;
import com.google.gerrit.reviewdb.PatchSet;
import com.google.gerrit.reviewdb.Project;
import com.google.gerrit.server.IdentifiedUser;
@@ -103,6 +104,9 @@
/** Filename of the ref updated hook. */
private final File refUpdatedHook;
+ /** Filename of the cla signed hook. */
+ private final File claSignedHook;
+
/** Repository Manager. */
private final GitRepositoryManager repoManager;
@@ -149,6 +153,7 @@
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());
+ claSignedHook = sitePath.resolve(new File(hooksPath, getValue(config, "hooks", "claSignedHook", "cla-signed")).getPath());
}
public void addChangeListener(ChangeListener listener, IdentifiedUser user) {
@@ -390,6 +395,17 @@
runHook(openRepository(refName.getParentKey()), refUpdatedHook, args);
}
+ public void doClaSignupHook(Account account, ContributorAgreement cla) {
+ if (account != null) {
+ final List<String> args = new ArrayList<String>();
+ addArg(args, "--submitter", getDisplayName(account));
+ addArg(args, "--user-id", account.getId().toString());
+ addArg(args, "--cla-id", cla.getId().toString());
+
+ runHook(claSignedHook, args);
+ }
+ }
+
private void fireEvent(final Change change, final ChangeEvent event) {
for (ChangeListenerHolder holder : listeners.values()) {
if (isVisibleTo(change, holder.user)) {
@@ -477,6 +493,12 @@
}
}
+ private synchronized void runHook(File hook, List<String> args) {
+ if (hook.exists()) {
+ hookQueue.execute(new HookTask(null, hook, args));
+ }
+ }
+
private final class HookTask implements Runnable {
private final Repository repo;
private final File hook;
@@ -497,10 +519,12 @@
final ProcessBuilder pb = new ProcessBuilder(argv);
pb.redirectErrorStream(true);
- pb.directory(repo.getDirectory());
+ if (repo != null) {
+ pb.directory(repo.getDirectory());
- final Map<String, String> env = pb.environment();
- env.put("GIT_DIR", repo.getDirectory().getAbsolutePath());
+ final Map<String, String> env = pb.environment();
+ env.put("GIT_DIR", repo.getDirectory().getAbsolutePath());
+ }
Process ps = pb.start();
ps.getOutputStream().close();
@@ -522,7 +546,9 @@
} catch (Throwable err) {
log.error("Error running hook " + hook.getAbsolutePath(), err);
} finally {
- repo.close();
+ if (repo != null) {
+ repo.close();
+ }
}
}