MergeOp: Record when submit rules were bypassed

We pass checkSubmitRules = false when pushing with %submit, meaning
submit should be forced regardless of the result of the submit rule.
Record this fact explicitly in the rules stamped into notedb.

Change-Id: If5609572e28393485d2e1a33f031f4505ccb526b
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/SubmitRecord.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/SubmitRecord.java
index f4fe963..5a32fcf 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/SubmitRecord.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/SubmitRecord.java
@@ -33,6 +33,9 @@
     /** The change has been closed. */
     CLOSED,
 
+    /** The change was submitted bypassing submit rules. */
+    FORCED,
+
     /**
      * An internal server error occurred preventing computation.
      * <p>
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java
index 3d72917..e198771c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java
@@ -377,11 +377,7 @@
       throw new ResourceConflictException(
           "missing current patch set for change " + cd.getId());
     }
-    List<SubmitRecord> results = cd.getSubmitRecords();
-    if (results == null) {
-      results = new SubmitRuleEvaluator(cd).evaluate();
-      cd.setSubmitRecords(results);
-    }
+    List<SubmitRecord> results = getSubmitRecords(cd);
     if (findOkRecord(results).isPresent()) {
       // Rules supplied a valid solution.
       return;
@@ -418,6 +414,16 @@
     throw new IllegalStateException();
   }
 
+  private static List<SubmitRecord> getSubmitRecords(ChangeData cd)
+      throws OrmException {
+    List<SubmitRecord> results = cd.getSubmitRecords();
+    if (results == null) {
+      results = new SubmitRuleEvaluator(cd).evaluate();
+      cd.setSubmitRecords(results);
+    }
+    return results;
+  }
+
   private static String describeLabels(ChangeData cd,
       List<SubmitRecord.Label> labels) throws OrmException {
     List<String> labelResults = new ArrayList<>();
@@ -470,6 +476,22 @@
     }
   }
 
+  private void bypassSubmitRules(ChangeSet cs) {
+    for (ChangeData cd : cs.changes()) {
+      List<SubmitRecord> records;
+      try {
+        records = new ArrayList<>(getSubmitRecords(cd));
+      } catch (OrmException e) {
+        log.warn("Error checking submit rules for change " + cd.getId(), e);
+        records = new ArrayList<>(1);
+      }
+      SubmitRecord forced = new SubmitRecord();
+      forced.status = SubmitRecord.Status.FORCED;
+      records.add(forced);
+      cd.setSubmitRecords(records);
+    }
+  }
+
   private void updateSubmissionId(Change change) {
     Hasher h = Hashing.sha1().newHasher();
     h.putLong(Thread.currentThread().getId())
@@ -493,6 +515,9 @@
         logDebug("Checking submit rules and state");
         checkSubmitRulesAndState(cs);
         failFast(cs); // Done checks that don't involve opening repo.
+      } else {
+        logDebug("Bypassing submit rules");
+        bypassSubmitRules(cs);
       }
       try {
         integrateIntoHistory(cs);
@@ -1146,6 +1171,8 @@
     Optional<SubmitRecord> okRecord = findOkRecord(cd.getSubmitRecords());
     if (okRecord.isPresent()) {
       update.merge(ImmutableList.of(okRecord.get()));
+    } else {
+      update.merge(cd.getSubmitRecords());
     }
     db.changes().beginTransaction(cd.change().getId());
     try {