Merge "Remove unnecessary dependency on commons-io"
diff --git a/Documentation/rest-api-changes.txt b/Documentation/rest-api-changes.txt
index 8421b0f..94f8ac9 100644
--- a/Documentation/rest-api-changes.txt
+++ b/Documentation/rest-api-changes.txt
@@ -2239,6 +2239,7 @@
 
   )]}'
   {
+    "commit": "674ac754f91e64a0efb8087e59a176484bd534d1",
     "parents": [
       {
         "commit": "1eee2c9d8f352483781e772f35dc586a69ff5646",
@@ -3951,7 +3952,10 @@
 [options="header",cols="1,^1,5"]
 |===========================
 |Field Name    ||Description
-|`commit`      ||The commit ID.
+|`commit`      |Optional|
+The commit ID. Not set if included in a link:#revision-info[
+RevisionInfo] entity that is contained in a map which has the commit ID
+as key.
 |`parents`     ||
 The parent commits of this commit as a list of
 link:#commit-info[CommitInfo] entities. In each parent
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
index a4cbe72..0f9ffc7 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
@@ -30,6 +30,7 @@
 import com.google.gerrit.extensions.api.changes.ReviewInput;
 import com.google.gerrit.extensions.api.changes.RevisionApi;
 import com.google.gerrit.extensions.api.projects.ProjectInput;
+import com.google.gerrit.extensions.client.InheritableBoolean;
 import com.google.gerrit.extensions.client.ListChangesOption;
 import com.google.gerrit.extensions.common.ActionInfo;
 import com.google.gerrit.extensions.common.ChangeInfo;
@@ -490,6 +491,15 @@
     saveProjectConfig(allProjects, cfg);
   }
 
+  protected void setUseContributorAgreements(InheritableBoolean value)
+      throws Exception {
+    MetaDataUpdate md = metaDataUpdateFactory.create(project);
+    ProjectConfig config = ProjectConfig.read(md);
+    config.getProject().setUseContributorAgreements(value);
+    config.commit(md);
+    projectCache.evict(config.getProject());
+  }
+
   protected void deny(String permission, AccountGroup.UUID id, String ref)
       throws Exception {
     ProjectConfig cfg = projectCache.checkedGet(project).getConfig();
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/PushOneCommit.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/PushOneCommit.java
index 85ba6de..77c38c8 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/PushOneCommit.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/PushOneCommit.java
@@ -47,6 +47,23 @@
   public static final String SUBJECT = "test commit";
   public static final String FILE_NAME = "a.txt";
   public static final String FILE_CONTENT = "some content";
+  public static final String PATCH =
+      "From %s Mon Sep 17 00:00:00 2001\n" +
+      "From: Administrator <admin@example.com>\n" +
+      "Date: %s\n" +
+      "Subject: [PATCH] test commit\n" +
+      "\n" +
+      "Change-Id: %s\n" +
+      "---\n" +
+      "\n" +
+      "diff --git a/a.txt b/a.txt\n" +
+      "new file mode 100644\n" +
+      "index 0000000..f0eec86\n" +
+      "--- /dev/null\n" +
+      "+++ b/a.txt\n" +
+      "@@ -0,0 +1 @@\n" +
+      "+some content\n" +
+      "\\ No newline at end of file\n";
 
   public interface Factory {
     PushOneCommit create(
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java
index f7f7192..967575a 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java
@@ -244,6 +244,8 @@
     assertThat(info.project).isEqualTo(in.project);
     assertThat(info.branch).isEqualTo(in.branch);
     assertThat(info.subject).isEqualTo(in.subject);
+    assertThat(Iterables.getOnlyElement(info.messages).message)
+        .isEqualTo("Uploaded patch set 1.");
   }
 
   @Test
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/RevisionIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/RevisionIT.java
index 23e3685..5429b95 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/RevisionIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/RevisionIT.java
@@ -17,6 +17,7 @@
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.gerrit.acceptance.PushOneCommit.FILE_CONTENT;
 import static com.google.gerrit.acceptance.PushOneCommit.FILE_NAME;
+import static com.google.gerrit.acceptance.PushOneCommit.PATCH;
 import static org.eclipse.jgit.lib.Constants.HEAD;
 
 import com.google.common.base.Predicate;
@@ -40,6 +41,7 @@
 import com.google.gerrit.extensions.common.CommentInfo;
 import com.google.gerrit.extensions.common.DiffInfo;
 import com.google.gerrit.extensions.common.MergeableInfo;
+import com.google.gerrit.extensions.common.RevisionInfo;
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.BinaryResult;
 import com.google.gerrit.extensions.restapi.ResourceConflictException;
@@ -52,6 +54,8 @@
 
 import java.io.ByteArrayOutputStream;
 import java.nio.charset.StandardCharsets;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -540,6 +544,25 @@
       .isEqualTo(in.message);
   }
 
+  @Test
+  public void patch() throws Exception {
+    PushOneCommit.Result r = createChange();
+    ChangeApi changeApi = gApi.changes()
+        .id(r.getChangeId());
+    BinaryResult bin = changeApi
+        .revision(r.getCommit().name())
+        .patch();
+    ByteArrayOutputStream os = new ByteArrayOutputStream();
+    bin.writeTo(os);
+    String res = new String(os.toByteArray(), StandardCharsets.UTF_8);
+    DateFormat dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z");
+    ChangeInfo change = changeApi.get();
+    RevisionInfo rev = change.revisions.get(change.currentRevision);
+    String date = dateFormat.format(rev.commit.author.date);
+    assertThat(res).isEqualTo(
+        String.format(PATCH, r.getCommitId().name(), date, r.getChangeId()));
+  }
+
   private void merge(PushOneCommit.Result r) throws Exception {
     revision(r).review(ReviewInput.approve());
     revision(r).submit();
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/edit/ChangeEditIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/edit/ChangeEditIT.java
index 1624da2..9fcd931 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/edit/ChangeEditIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/edit/ChangeEditIT.java
@@ -19,6 +19,7 @@
 import static java.nio.charset.StandardCharsets.UTF_8;
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
 import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.apache.http.HttpStatus.SC_FORBIDDEN;
 import static org.apache.http.HttpStatus.SC_CONFLICT;
 import static org.apache.http.HttpStatus.SC_NOT_FOUND;
 import static org.apache.http.HttpStatus.SC_NO_CONTENT;
@@ -35,6 +36,7 @@
 import com.google.gerrit.acceptance.TestProjectInput;
 import com.google.gerrit.common.data.LabelType;
 import com.google.gerrit.extensions.api.changes.ReviewInput;
+import com.google.gerrit.extensions.client.InheritableBoolean;
 import com.google.gerrit.extensions.client.ListChangesOption;
 import com.google.gerrit.extensions.common.ApprovalInfo;
 import com.google.gerrit.extensions.common.ChangeInfo;
@@ -210,6 +212,22 @@
   }
 
   @Test
+  public void publishEditRestWithoutCLA() throws Exception {
+    setUseContributorAgreements(InheritableBoolean.TRUE);
+    PatchSet oldCurrentPatchSet = getCurrentPatchSet(changeId);
+    assertThat(modifier.createEdit(change, oldCurrentPatchSet)).isEqualTo(
+        RefUpdate.Result.NEW);
+    assertThat(
+        modifier.modifyFile(editUtil.byChange(change).get(), FILE_NAME,
+            RestSession.newRawInput(CONTENT_NEW))).isEqualTo(RefUpdate.Result.FORCED);
+    RestResponse r = adminSession.post(urlPublish());
+    assertThat(r.getStatusCode()).isEqualTo(SC_FORBIDDEN);
+    setUseContributorAgreements(InheritableBoolean.FALSE);
+    r = adminSession.post(urlPublish());
+    assertThat(r.getStatusCode()).isEqualTo(SC_NO_CONTENT);
+  }
+
+  @Test
   public void rebaseEdit() throws Exception {
     assertThat(modifier.createEdit(change, ps)).isEqualTo(RefUpdate.Result.NEW);
     assertThat(
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/RevisionApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/RevisionApi.java
index cb0d5f3..44c2ba4 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/RevisionApi.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/RevisionApi.java
@@ -18,6 +18,7 @@
 import com.google.gerrit.extensions.common.CommentInfo;
 import com.google.gerrit.extensions.common.FileInfo;
 import com.google.gerrit.extensions.common.MergeableInfo;
+import com.google.gerrit.extensions.restapi.BinaryResult;
 import com.google.gerrit.extensions.restapi.NotImplementedException;
 import com.google.gerrit.extensions.restapi.RestApiException;
 
@@ -57,6 +58,11 @@
 
   CommentApi comment(String id) throws RestApiException;
 
+  /**
+   * Returns patch of revision.
+   */
+  BinaryResult patch() throws RestApiException;
+
   Map<String, ActionInfo> actions() throws RestApiException;
 
   /**
@@ -180,6 +186,11 @@
     }
 
     @Override
+    public BinaryResult patch() throws RestApiException {
+      throw new NotImplementedException();
+    }
+
+    @Override
     public Map<String, ActionInfo> actions() throws RestApiException {
       throw new NotImplementedException();
     }
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/ChangeInfo.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/ChangeInfo.java
index 13baf6b..cdfe0c6 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/ChangeInfo.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/ChangeInfo.java
@@ -35,6 +35,7 @@
   public Boolean starred;
   public Boolean reviewed;
   public Boolean mergeable;
+  public Boolean submittable;
   public Integer insertions;
   public Integer deletions;
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfo.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfo.java
index 9a5a4f2..5b7e304 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfo.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfo.java
@@ -107,7 +107,6 @@
   public final native LabelInfo label(String n) /*-{ return this.labels[n]; }-*/;
   public final native String currentRevision() /*-{ return this.current_revision; }-*/;
   public final native void setCurrentRevision(String r) /*-{ this.current_revision = r; }-*/;
-  private final native void setSubmittable(boolean x) /*-{ this.submittable = x; }-*/;
   public final native NativeMap<RevisionInfo> revisions() /*-{ return this.revisions; }-*/;
   public final native RevisionInfo revision(String n) /*-{ return this.revisions[n]; }-*/;
   public final native JsArray<MessageInfo> messages() /*-{ return this.messages; }-*/;
@@ -135,7 +134,6 @@
 
   public final boolean submittable() {
     init();
-    getMissingLabelIndex();
     return _submittable();
   }
 
@@ -143,8 +141,6 @@
   /*-{ return this.submittable ? true : false; }-*/;
 
   /**
-   * As a side effect this.submittable is evaluated and set accordingly.
-   *
    * @return the index of the missing label or -1
    *         if no label is missing, or if more than one label is missing.
    */
@@ -168,7 +164,6 @@
           if (ret != -1) {
             // more than one label is missing, so it's unclear which to quick
             // approve, return -1
-            setSubmittable(false);
             return -1;
           } else {
             ret = i;
@@ -181,11 +176,9 @@
 
         case REJECT: // Submit cannot happen, do not quick approve.
         case IMPOSSIBLE:
-          setSubmittable(false);
           return -1;
       }
     }
-    setSubmittable(ret == -1);
     return ret;
   }
 
diff --git a/gerrit-server/BUCK b/gerrit-server/BUCK
index bea53ec..c7bd8c9 100644
--- a/gerrit-server/BUCK
+++ b/gerrit-server/BUCK
@@ -211,6 +211,7 @@
     '//gerrit-server/src/main/prolog:common',
     '//lib:args4j',
     '//lib:grappa',
+    '//lib:guava',
     '//lib:gwtorm',
     '//lib:truth',
     '//lib/bouncycastle:bcprov',
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountManager.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountManager.java
index 5c175ad..f3528e0 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountManager.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountManager.java
@@ -125,13 +125,13 @@
         }
 
       }
-    } catch (OrmException e) {
+    } catch (OrmException | NameAlreadyUsedException | InvalidUserNameException e) {
       throw new AccountException("Authentication error", e);
     }
   }
 
   private void update(ReviewDb db, AuthRequest who, AccountExternalId extId)
-      throws OrmException {
+      throws OrmException, NameAlreadyUsedException, InvalidUserNameException {
     IdentifiedUser user = userFactory.create(extId.getAccountId());
     Account toUpdate = null;
 
@@ -159,7 +159,7 @@
 
     if (!realm.allowsEdit(Account.FieldName.USER_NAME)
         && !eq(user.getUserName(), who.getUserName())) {
-      changeUserNameFactory.create(db, user, who.getUserName());
+      changeUserNameFactory.create(db, user, who.getUserName()).call();
     }
 
     if (toUpdate != null) {
@@ -327,7 +327,11 @@
         if (!extId.getAccountId().equals(to)) {
           throw new AccountException("Identity in use by another account");
         }
-        update(db, who, extId);
+        try {
+          update(db, who, extId);
+        } catch(NameAlreadyUsedException | InvalidUserNameException e) {
+          throw new AccountException("Account update failed", e);
+        }
 
       } else {
         extId = createId(to, who);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/RevisionApiImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/RevisionApiImpl.java
index 1f8aa0c..0569e5f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/RevisionApiImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/RevisionApiImpl.java
@@ -31,6 +31,7 @@
 import com.google.gerrit.extensions.common.CommentInfo;
 import com.google.gerrit.extensions.common.FileInfo;
 import com.google.gerrit.extensions.common.MergeableInfo;
+import com.google.gerrit.extensions.restapi.BinaryResult;
 import com.google.gerrit.extensions.restapi.IdString;
 import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.extensions.restapi.RestModifyView;
@@ -41,6 +42,7 @@
 import com.google.gerrit.server.change.DraftComments;
 import com.google.gerrit.server.change.FileResource;
 import com.google.gerrit.server.change.Files;
+import com.google.gerrit.server.change.GetPatch;
 import com.google.gerrit.server.change.GetRevisionActions;
 import com.google.gerrit.server.change.ListRevisionComments;
 import com.google.gerrit.server.change.ListRevisionDrafts;
@@ -79,6 +81,7 @@
   private final RevisionResource revision;
   private final Provider<Files> files;
   private final Provider<Files.ListFiles> listFiles;
+  private final Provider<GetPatch> getPatch;
   private final Provider<PostReview> review;
   private final Provider<Mergeable> mergeable;
   private final FileApiImpl.Factory fileApi;
@@ -103,6 +106,7 @@
       Reviewed.DeleteReviewed deleteReviewed,
       Provider<Files> files,
       Provider<Files.ListFiles> listFiles,
+      Provider<GetPatch> getPatch,
       Provider<PostReview> review,
       Provider<Mergeable> mergeable,
       FileApiImpl.Factory fileApi,
@@ -127,6 +131,7 @@
     this.putReviewed = putReviewed;
     this.deleteReviewed = deleteReviewed;
     this.listFiles = listFiles;
+    this.getPatch = getPatch;
     this.mergeable = mergeable;
     this.fileApi = fileApi;
     this.listComments = listComments;
@@ -357,6 +362,15 @@
   }
 
   @Override
+  public BinaryResult patch() throws RestApiException {
+    try {
+      return getPatch.get().apply(revision);
+    } catch (IOException e) {
+      throw new RestApiException("Cannot get patch", e);
+    }
+  }
+
+  @Override
   public Map<String, ActionInfo> actions() throws RestApiException {
     return revisionActions.apply(revision).value();
   }
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 dc7f1b3..acdf004 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
@@ -137,6 +137,7 @@
   private final GitRepositoryManager repoManager;
   private final ProjectCache projectCache;
   private final MergeUtil.Factory mergeUtilFactory;
+  private final Submit submit;
   private final IdentifiedUser.GenericFactory userFactory;
   private final ChangeData.Factory changeDataFactory;
   private final FileInfoJson fileInfoJson;
@@ -161,6 +162,7 @@
       GitRepositoryManager repoManager,
       ProjectCache projectCache,
       MergeUtil.Factory mergeUtilFactory,
+      Submit submit,
       IdentifiedUser.GenericFactory uf,
       ChangeData.Factory cdf,
       FileInfoJson fileInfoJson,
@@ -180,6 +182,7 @@
     this.repoManager = repoManager;
     this.userFactory = uf;
     this.projectCache = projectCache;
+    this.submit = submit;
     this.mergeUtilFactory = mergeUtilFactory;
     this.fileInfoJson = fileInfoJson;
     this.accountLoaderFactory = ailf;
@@ -383,6 +386,7 @@
     // the response and avoid making a request to /submit_type from the UI.
     out.mergeable = in.getStatus() == Change.Status.MERGED
         ? null : cd.isMergeable();
+    out.submittable = submit.submittable(cd);
     ChangedLines changedLines = cd.changedLines();
     if (changedLines != null) {
       out.insertions = changedLines.insertions;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/CreateChange.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/CreateChange.java
index 3ec18f3..6c0ee3b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/CreateChange.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/CreateChange.java
@@ -32,6 +32,7 @@
 import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
 import com.google.gerrit.reviewdb.client.Branch;
 import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.ChangeMessage;
 import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.reviewdb.client.RefNames;
@@ -207,6 +208,15 @@
           changeInserterFactory.create(refControl.getProjectControl(),
               change, c);
 
+      ChangeMessage msg = new ChangeMessage(new ChangeMessage.Key(change.getId(),
+          ChangeUtil.messageUUID(db.get())),
+          me.getAccountId(),
+          ins.getPatchSet().getCreatedOn(),
+          ins.getPatchSet().getId());
+      msg.setMessage(String.format("Uploaded patch set %s.",
+          ins.getPatchSet().getPatchSetId()));
+
+      ins.setMessage(msg);
       validateCommit(git, refControl, c, me, ins);
       updateRef(git, rw, c, change, ins.getPatchSet());
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetCommit.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetCommit.java
index a7f8dea..72f8c35 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetCommit.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetCommit.java
@@ -54,6 +54,7 @@
       rw.parseBody(commit);
       CommitInfo info = json.create(ChangeJson.NO_OPTIONS)
           .toCommit(rsrc.getControl(), rw, commit, addLinks);
+      info.commit = commit.name();
       Response<CommitInfo> r = Response.ok(info);
       if (rsrc.isCacheable()) {
         r.caching(CacheControl.PRIVATE(7, TimeUnit.DAYS));
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/PublishChangeEdit.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/PublishChangeEdit.java
index 5db46ae..b88931e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/PublishChangeEdit.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/PublishChangeEdit.java
@@ -15,6 +15,7 @@
 package com.google.gerrit.server.change;
 
 import com.google.common.base.Optional;
+import com.google.gerrit.common.data.Capable;
 import com.google.gerrit.extensions.registration.DynamicMap;
 import com.google.gerrit.extensions.restapi.AcceptsPost;
 import com.google.gerrit.extensions.restapi.AuthException;
@@ -84,6 +85,12 @@
     public Response<?> apply(ChangeResource rsrc, Publish.Input in)
         throws AuthException, ResourceConflictException, NoSuchChangeException,
         IOException, OrmException {
+      Capable r =
+          rsrc.getControl().getProjectControl().canPushToAtLeastOneRef();
+      if (r != Capable.OK) {
+        throw new AuthException(r.getMessage());
+      }
+
       Optional<ChangeEdit> edit = editUtil.byChange(rsrc.getChange());
       if (!edit.isPresent()) {
         throw new ResourceConflictException(String.format(
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Submit.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Submit.java
index 2b8e3bc..6bba656 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Submit.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Submit.java
@@ -212,13 +212,13 @@
   private String problemsForSubmittingChangeset(
       ChangeSet cs, IdentifiedUser identifiedUser) {
     try {
+      ReviewDb db = dbProvider.get();
       for (PatchSet.Id psId : cs.patchIds()) {
-        ReviewDb db = dbProvider.get();
         ChangeControl changeControl = changeControlFactory
             .controlFor(psId.getParentKey(), identifiedUser);
         ChangeData c = changeDataFactory.create(db, changeControl);
 
-        if (!changeControl.isVisible(dbProvider.get())) {
+        if (!changeControl.isVisible(db)) {
           return BLOCKED_HIDDEN_SUBMIT_TOOLTIP;
         }
         if (!changeControl.canSubmit()) {
@@ -248,6 +248,22 @@
     return null;
   }
 
+  /**
+   * Check if there are any problems with the given change. It doesn't take
+   * any problems of related changes into account.
+   * <p>
+   * @param cd the change to check for submittability
+   * @return if the change has any problems for submission
+   */
+  public boolean submittable(ChangeData cd) {
+    try {
+      MergeOp.checkSubmitRule(cd);
+      return true;
+    } catch (ResourceConflictException | OrmException e) {
+      return false;
+    }
+  }
+
   @Override
   public UiAction.Description getDescription(RevisionResource resource) {
     PatchSet.Id current = resource.getChange().currentPatchSetId();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/SubmittedTogether.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/SubmittedTogether.java
index 71e25a5..1f6dfe4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/SubmittedTogether.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/SubmittedTogether.java
@@ -64,9 +64,7 @@
       if (cs.ids().size() > 1) {
         return json.create(EnumSet.of(
             ListChangesOption.CURRENT_REVISION,
-            ListChangesOption.CURRENT_COMMIT,
-            ListChangesOption.DETAILED_LABELS,
-            ListChangesOption.LABELS))
+            ListChangesOption.CURRENT_COMMIT))
           .format(cs.ids());
       } else {
         return Collections.emptyList();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/util/SubmoduleSectionParser.java b/gerrit-server/src/main/java/com/google/gerrit/server/util/SubmoduleSectionParser.java
index 195a3e0..ad2ab90 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/util/SubmoduleSectionParser.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/util/SubmoduleSectionParser.java
@@ -84,6 +84,7 @@
     final String url = bbc.getString("submodule", id, "url");
     final String path = bbc.getString("submodule", id, "path");
     String branch = bbc.getString("submodule", id, "branch");
+    SubmoduleSubscription ss = null;
 
     try {
       if (url != null && url.length() > 0 && path != null && path.length() > 0
@@ -116,8 +117,10 @@
             }
             Project.NameKey projectKey = new Project.NameKey(projectName);
             if (projectCache.get(projectKey) != null) {
-              return new SubmoduleSubscription(superProjectBranch,
-                  new Branch.NameKey(projectKey, branch), path);
+              ss = new SubmoduleSubscription(
+                  superProjectBranch,
+                  new Branch.NameKey(new Project.NameKey(projectName), branch),
+                  path);
             }
           }
         }
@@ -126,6 +129,6 @@
       // Error in url syntax (in fact it is uri syntax)
     }
 
-    return null;
+    return ss;
   }
 }
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/util/SubmoduleSectionParserTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/util/SubmoduleSectionParserTest.java
index bd672f3..3945da7 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/util/SubmoduleSectionParserTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/util/SubmoduleSectionParserTest.java
@@ -190,6 +190,28 @@
         expectedSubscriptions);
   }
 
+  @Test
+  public void testSubmodulesParseWithSubProjectFound() throws Exception {
+    Map<String, SubmoduleSection> sectionsToReturn = new TreeMap<>();
+    sectionsToReturn.put("a/b", new SubmoduleSection(
+        "ssh://localhost/a/b", "a/b", "."));
+
+    Map<String, String> reposToBeFound = new HashMap<>();
+    reposToBeFound.put("a/b", "a/b");
+    reposToBeFound.put("b", "b");
+
+    Branch.NameKey superBranchNameKey =
+        new Branch.NameKey(new Project.NameKey("super-project"),
+            "refs/heads/master");
+
+    Set<SubmoduleSubscription> expectedSubscriptions = Sets.newHashSet();
+    expectedSubscriptions
+        .add(new SubmoduleSubscription(superBranchNameKey, new Branch.NameKey(
+            new Project.NameKey("a/b"), "refs/heads/master"), "a/b"));
+    execute(superBranchNameKey, sectionsToReturn, reposToBeFound,
+        expectedSubscriptions);
+  }
+
   private void execute(final Branch.NameKey superProjectBranch,
       final Map<String, SubmoduleSection> sectionsToReturn,
       final Map<String, String> reposToBeFound,
@@ -217,10 +239,9 @@
             projectNameCandidate = projectNameCandidate.substring(0, //
                 projectNameCandidate.length() - Constants.DOT_GIT_EXT.length());
           }
-          if (projectNameCandidate.equals(reposToBeFound.get(id))) {
+          if (reposToBeFound.containsValue(projectNameCandidate)) {
             expect(projectCache.get(new Project.NameKey(projectNameCandidate)))
                 .andReturn(createNiceMock(ProjectState.class));
-            break;
           } else {
             expect(projectCache.get(new Project.NameKey(projectNameCandidate)))
                 .andReturn(null);
diff --git a/lib/asciidoctor/BUCK b/lib/asciidoctor/BUCK
index 66a12c1..f8feb63 100644
--- a/lib/asciidoctor/BUCK
+++ b/lib/asciidoctor/BUCK
@@ -43,8 +43,8 @@
 
 maven_jar(
   name = 'asciidoctor',
-  id = 'org.asciidoctor:asciidoctorj:1.5.0',
-  sha1 = '192df5660f72a0fb76966dcc64193b94fba65f99',
+  id = 'org.asciidoctor:asciidoctorj:1.5.2',
+  sha1 = '39d33f739ec1c46f6e908a725264eb74b23c9f99',
   license = 'Apache2.0',
   visibility = [],
   attach_source = False,
@@ -52,8 +52,8 @@
 
 maven_jar(
   name = 'jruby',
-  id = 'org.jruby:jruby-complete:1.7.4',
-  sha1 = '74984d84846523bd7da49064679ed1ccf199e1db',
+  id = 'org.jruby:jruby-complete:1.7.18',
+  sha1 = 'a1be3e1790aace5c99614a87785454d875eb21c2',
   license = 'DO_NOT_DISTRIBUTE',
   visibility = [],
   attach_source = False,
diff --git a/lib/jetty/BUCK b/lib/jetty/BUCK
index 2e65abc..d02916f 100644
--- a/lib/jetty/BUCK
+++ b/lib/jetty/BUCK
@@ -1,12 +1,12 @@
 include_defs('//lib/maven.defs')
 
-VERSION = '9.2.10.v20150310'
+VERSION = '9.2.12.v20150709'
 EXCLUDE = ['about.html']
 
 maven_jar(
   name = 'servlet',
   id = 'org.eclipse.jetty:jetty-servlet:' + VERSION,
-  sha1 = '9e923adf1671af7da09dba778e132ab0a9c62415',
+  sha1 = '50116cac18ad893c9628f0a1984390464b133921',
   license = 'Apache2.0',
   deps = [':security'],
   exclude = EXCLUDE,
@@ -15,7 +15,7 @@
 maven_jar(
   name = 'security',
   id = 'org.eclipse.jetty:jetty-security:' + VERSION,
-  sha1 = 'b56228088355023117ba9a9de0da00d652a7e655',
+  sha1 = '9ace95998fbaae8425b2621c90230a229a554784',
   license = 'Apache2.0',
   deps = [':server'],
   exclude = EXCLUDE,
@@ -25,7 +25,7 @@
 maven_jar(
   name = 'servlets',
   id = 'org.eclipse.jetty:jetty-servlets:' + VERSION,
-  sha1 = 'b48a9bb30e9d5e73dcedf8039f96abdb04a3892c',
+  sha1 = 'a1f9e7874e1db2f664213f524463d12bd5ab5db4',
   license = 'Apache2.0',
   exclude = EXCLUDE,
   visibility = [
@@ -37,7 +37,7 @@
 maven_jar(
   name = 'server',
   id = 'org.eclipse.jetty:jetty-server:' + VERSION,
-  sha1 = '0e6b8bff28b3e9ca6254415d2aa49603a5887fe8',
+  sha1 = '8c90ceffb6954385b024899d334192947d0e4077',
   license = 'Apache2.0',
   exported_deps = [
     ':continuation',
@@ -49,7 +49,7 @@
 maven_jar(
   name = 'jmx',
   id = 'org.eclipse.jetty:jetty-jmx:' + VERSION,
-  sha1 = 'fa94eb39f1dd63c40efe44471664f8f70bc7ca2e',
+  sha1 = '8bc0288abba26dbbf4e9225d6fe6fa6348f8da05',
   license = 'Apache2.0',
   exported_deps = [
     ':continuation',
@@ -61,7 +61,7 @@
 maven_jar(
   name = 'continuation',
   id = 'org.eclipse.jetty:jetty-continuation:' + VERSION,
-  sha1 = '1c9bc80037e9898974ada7318f11c984363d4707',
+  sha1 = '0578cb87b78b71eeda91f5dfa3e8bfbafb55cced',
   license = 'Apache2.0',
   exclude = EXCLUDE,
 )
@@ -69,7 +69,7 @@
 maven_jar(
   name = 'http',
   id = 'org.eclipse.jetty:jetty-http:' + VERSION,
-  sha1 = '886b628f62cd518bbb04b37bd1b308fa19340a53',
+  sha1 = '9a6c83f52c70c28e2272d83866b4111cd15ddbc5',
   license = 'Apache2.0',
   exported_deps = [':io'],
   exclude = EXCLUDE,
@@ -78,7 +78,7 @@
 maven_jar(
   name = 'io',
   id = 'org.eclipse.jetty:jetty-io:' + VERSION,
-  sha1 = '29bc6a5e2049d9858bfa811f2728a7a8efcdc1c0',
+  sha1 = 'c02e9e303d231a589e0c8866c1ee89bcdeb40a55',
   license = 'Apache2.0',
   exported_deps = [':util'],
   exclude = EXCLUDE,
@@ -88,7 +88,7 @@
 maven_jar(
   name = 'util',
   id = 'org.eclipse.jetty:jetty-util:' + VERSION,
-  sha1 = '90cc75668dc9a9885108733d4d46420907cf863c',
+  sha1 = 'd99d38adfdb5ec677643f04fa862554b0bb8b42e',
   license = 'Apache2.0',
   exclude = EXCLUDE,
   visibility = [],