Merge branch 'stable-2.12'

* stable-2.12:
  Build with API version 2.12

Change-Id: Ia5e685a9723dba4460a73972ca0a513f7836f3d6
diff --git a/lib/gerrit/BUCK b/lib/gerrit/BUCK
index 88ee169..f0e73e7 100644
--- a/lib/gerrit/BUCK
+++ b/lib/gerrit/BUCK
@@ -1,12 +1,12 @@
 include_defs('//bucklets/maven_jar.bucklet')
 
-VER = '2.12'
+VER = '2.13.1'
 REPO = MAVEN_CENTRAL
 
 maven_jar(
   name = 'plugin-api',
   id = 'com.google.gerrit:gerrit-plugin-api:' + VER,
-  sha1 = '8ce1f6e65078bbcf03a1758f96b3ebca19b7fe3c',
+  sha1 = '8e12346dbb677d70987afdbec5352ff6e889a181',
   attach_source = False,
   repository = REPO,
   license = 'Apache2.0',
diff --git a/src/main/java/com/googlesource/gerrit/plugins/reviewersbyblame/ChangeUpdatedListener.java b/src/main/java/com/googlesource/gerrit/plugins/reviewersbyblame/ChangeUpdatedListener.java
index bfe88e7..e5c1179 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/reviewersbyblame/ChangeUpdatedListener.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/reviewersbyblame/ChangeUpdatedListener.java
@@ -84,13 +84,25 @@
       return;
     }
     PatchSetCreatedEvent e = (PatchSetCreatedEvent) event;
-    Project.NameKey projectName = new Project.NameKey(e.change.project);
+    Project.NameKey projectName = e.getProjectNameKey();
 
     int maxReviewers;
+    boolean ignoreDrafts;
+    String ignoreSubjectRegEx;
+    String ignoreFileRegEx;
     try {
       maxReviewers =
           cfg.getFromProjectConfigWithInheritance(projectName, pluginName)
              .getInt("maxReviewers", 3);
+      ignoreDrafts =
+          cfg.getFromProjectConfigWithInheritance(projectName, pluginName)
+              .getBoolean("ignoreDrafts", false);
+      ignoreSubjectRegEx =
+          cfg.getFromProjectConfigWithInheritance(projectName, pluginName)
+              .getString("ignoreSubjectRegEx", "");
+      ignoreFileRegEx =
+          cfg.getFromProjectConfigWithInheritance(projectName, pluginName)
+              .getString("ignoreFileRegEx", "");
     } catch (NoSuchProjectException x) {
       log.error(x.getMessage(), x);
       return;
@@ -99,72 +111,77 @@
       return;
     }
 
-    try (final Repository git = repoManager.openRepository(projectName)) {
-      try (final RevWalk rw = new RevWalk(git)) {
-        final ReviewDb reviewDb = schemaFactory.open();
-        try {
-          Change.Id changeId = new Change.Id(Integer.parseInt(e.change.number));
-          PatchSet.Id psId = new PatchSet.Id(changeId, Integer.parseInt(e.patchSet.number));
-          PatchSet ps = reviewDb.patchSets().get(psId);
-          if (ps == null) {
-            log.warn("Patch set " + psId.get() + " not found.");
-            return;
-          }
+    try (Repository git = repoManager.openRepository(projectName);
+        RevWalk rw = new RevWalk(git);
+        ReviewDb reviewDb = schemaFactory.open()) {
+      Change.Id changeId = new Change.Id(Integer.parseInt(e.change.get().number));
+      PatchSet.Id psId = new PatchSet.Id(changeId, Integer.parseInt(e.patchSet.get().number));
+      PatchSet ps = reviewDb.patchSets().get(psId);
+      if (ps == null) {
+        log.warn("Patch set " + psId.get() + " not found.");
+        return;
+      }
 
-          final Change change = reviewDb.changes().get(psId.getParentKey());
-          if (change == null) {
-            log.warn("Change " + changeId.get() + " not found.");
-            return;
-          }
+      if (ignoreDrafts && ps.isDraft()) {
+        return;
+      }
 
-          final RevCommit commit =
-              rw.parseCommit(ObjectId.fromString(e.patchSet.revision));
+      final Change change = reviewDb.changes().get(psId.getParentKey());
+      if (change == null) {
+        log.warn("Change " + changeId.get() + " not found.");
+        return;
+      }
 
-          final Runnable task =
-              reviewersByBlameFactory.create(commit, change, ps, maxReviewers, git);
+      final RevCommit commit =
+          rw.parseCommit(ObjectId.fromString(e.patchSet.get().revision));
 
-          workQueue.getDefaultQueue().submit(new Runnable() {
+      if (!ignoreSubjectRegEx.isEmpty()
+          && commit.getShortMessage().matches(ignoreSubjectRegEx)) {
+        return;
+      }
+
+      final Runnable task =
+          reviewersByBlameFactory.create(commit, change, ps, maxReviewers,
+              git, ignoreFileRegEx);
+
+      workQueue.getDefaultQueue().submit(new Runnable() {
+        @Override
+        public void run() {
+          RequestContext old = tl.setContext(new RequestContext() {
+
             @Override
-            public void run() {
-              RequestContext old = tl.setContext(new RequestContext() {
+            public CurrentUser getUser() {
+              return identifiedUserFactory.create(change.getOwner());
+            }
 
+            @Override
+            public Provider<ReviewDb> getReviewDbProvider() {
+              return new Provider<ReviewDb>() {
                 @Override
-                public CurrentUser getUser() {
-                  return identifiedUserFactory.create(change.getOwner());
-                }
-
-                @Override
-                public Provider<ReviewDb> getReviewDbProvider() {
-                  return new Provider<ReviewDb>() {
-                    @Override
-                    public ReviewDb get() {
-                      if (db == null) {
-                        try {
-                          db = schemaFactory.open();
-                        } catch (OrmException e) {
-                          throw new ProvisionException("Cannot open ReviewDb", e);
-                        }
-                      }
-                      return db;
+                public ReviewDb get() {
+                  if (db == null) {
+                    try {
+                      db = schemaFactory.open();
+                    } catch (OrmException e) {
+                      throw new ProvisionException("Cannot open ReviewDb", e);
                     }
-                  };
+                  }
+                  return db;
                 }
-              });
-              try {
-                task.run();
-              } finally {
-                tl.setContext(old);
-                if (db != null) {
-                  db.close();
-                  db = null;
-                }
-              }
+              };
             }
           });
-        } finally {
-          reviewDb.close();
+          try {
+            task.run();
+          } finally {
+            tl.setContext(old);
+            if (db != null) {
+              db.close();
+              db = null;
+            }
+          }
         }
-      }
+      });
     } catch (OrmException|IOException x) {
       log.error(x.getMessage(), x);
     }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/reviewersbyblame/ReviewersByBlame.java b/src/main/java/com/googlesource/gerrit/plugins/reviewersbyblame/ReviewersByBlame.java
index bc14c9d..5f8ebef 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/reviewersbyblame/ReviewersByBlame.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/reviewersbyblame/ReviewersByBlame.java
@@ -62,6 +62,7 @@
   private final PatchSet ps;
   private final Repository repo;
   private final int maxReviewers;
+  private final String ignoreFileRegEx;
 
   private final AccountByEmailCache byEmailCache;
   private final AccountCache accountCache;
@@ -71,7 +72,7 @@
 
   public interface Factory {
     ReviewersByBlame create(RevCommit commit, Change change, PatchSet ps,
-        int maxReviewers, Repository repo);
+        int maxReviewers, Repository repo, String ignoreFileRegEx);
   }
 
   @Inject
@@ -82,7 +83,8 @@
       final PatchListCache patchListCache,
       @Assisted final RevCommit commit, @Assisted final Change change,
       @Assisted final PatchSet ps, @Assisted final int maxReviewers,
-      @Assisted final Repository repo) {
+      @Assisted final Repository repo,
+      @Assisted final String ignoreFileRegEx) {
     this.byEmailCache = byEmailCache;
     this.accountCache = accountCache;
     this.changes = changes;
@@ -93,6 +95,7 @@
     this.ps = ps;
     this.maxReviewers = maxReviewers;
     this.repo = repo;
+    this.ignoreFileRegEx = ignoreFileRegEx;
   }
 
   @Override
@@ -113,6 +116,8 @@
       BlameResult blameResult;
       if ((entry.getChangeType() == ChangeType.MODIFIED ||
           entry.getChangeType() == ChangeType.DELETED)
+          && (ignoreFileRegEx.isEmpty() ||
+              !entry.getNewName().matches(ignoreFileRegEx))
           && (blameResult = computeBlame(entry, commit.getParent(0))) != null) {
         List<Edit> edits = entry.getEdits();
         reviewers.putAll(getReviewersForPatch(edits, blameResult));
@@ -203,7 +208,7 @@
    * that edited this specific part of the code.
    *
    * @param entry {@link PatchListEntry}
-   * @param commit Parent {@link RevCommit}
+   * @param parent Parent {@link RevCommit}
    * @return Result of blame computation, null if the computation fails
    */
   private BlameResult computeBlame(final PatchListEntry entry,
diff --git a/src/main/java/com/googlesource/gerrit/plugins/reviewersbyblame/ReviewersByBlameModule.java b/src/main/java/com/googlesource/gerrit/plugins/reviewersbyblame/ReviewersByBlameModule.java
index 89218c9..4d61984 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/reviewersbyblame/ReviewersByBlameModule.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/reviewersbyblame/ReviewersByBlameModule.java
@@ -31,5 +31,22 @@
         .toInstance(new ProjectConfigEntry("Max Reviewers", 3, true,
             "The maximum number of reviewers that should be automatically added"
             + " to a change based on the git blame computation on the changed files."));
+    bind(ProjectConfigEntry.class).annotatedWith(Exports.named("ignoreDrafts"))
+        .toInstance(
+            new ProjectConfigEntry("Ignore Drafts", false,
+                "Ignore draft commits when adding reviewers"));
+    bind(ProjectConfigEntry.class)
+        .annotatedWith(Exports.named("ignoreSubjectRegEx"))
+        .toInstance(
+            new ProjectConfigEntry("Ignore Regex", "", true,
+                "Ignore commits where the subject matches the given regular expression"));
+    bind(ProjectConfigEntry.class)
+        .annotatedWith(Exports.named("ignoreFileRegEx"))
+        .toInstance(
+            new ProjectConfigEntry(
+                "Ignore file Regex",
+                "",
+                true,
+                "Ignore files that match the given regular expression when looking for reviewers"));
   }
 }
diff --git a/src/main/resources/Documentation/about.md b/src/main/resources/Documentation/about.md
index 62863ee..9816f36 100644
--- a/src/main/resources/Documentation/about.md
+++ b/src/main/resources/Documentation/about.md
@@ -6,5 +6,6 @@
 authored most of the lines touched by the change, since these users should be
 familiar with the code and can mostly review the change.
 
-The maximum number of reviewers that are added by this plugin can be
-[configured per project](config.html).
+The maximum number of reviewers that are added as well as exceptions when no
+reviewers should be added by this plugin can be
+[configured per project](config.md).
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md
index 434bd45..a0ceb1d 100644
--- a/src/main/resources/Documentation/config.md
+++ b/src/main/resources/Documentation/config.md
@@ -11,6 +11,8 @@
 ```
   [plugin "reviewers-by-blame"]
     maxReviewers = 2
+    ignoreDrafts = true
+    ignoreSubjectRegEx = WIP(.*)
 ```
 
 plugin.reviewers-by-blame.maxReviewers
@@ -18,3 +20,21 @@
 	this plugin.
 
 	By default 3.
+
+
+plugin.reviewers-by-blame.ignoreDrafts
+:	Ignore draft commits when adding reviewers.
+
+	By default false.
+
+plugin.reviewers-by-blame.ignoreFileRegEx
+:	Ignore files where the filename matches the given regular expression when
+	computing the reviewers. If empty or not set, no files are ignored.
+
+	By default not set.
+
+plugin.reviewers-by-blame.ignoreSubjectRegEx
+:	Ignore commits where the subject of the commit messages matches
+	the given regular expression. If empty or not set, no commits are ignored.
+
+	By default not set.
\ No newline at end of file