Merge branch 'stable-2.12'

* stable-2.12:
  Supply parent before validating project creation

Change-Id: Ia51fa323d767ebe173441c2b0cd7c54433e949e4
diff --git a/BUCK b/BUCK
index 28e335b..e08dc76 100644
--- a/BUCK
+++ b/BUCK
@@ -2,10 +2,9 @@
 
 MODULE = 'com.googlesource.gerrit.plugins.importer.Importer'
 
-if STANDALONE_MODE:
-  HTTP_LIB = '//lib/http:http_lib'
-else:
-  HTTP_LIB = '//plugins/importer/lib/http:http_lib'
+PROVIDED_DEPS = [
+  '//lib:gson',
+]
 
 gerrit_plugin(
   name = 'importer',
@@ -20,13 +19,7 @@
     'Gerrit-SshModule: com.googlesource.gerrit.plugins.importer.SshModule',
     'Gerrit-HttpModule: com.googlesource.gerrit.plugins.importer.HttpModule',
   ],
-  deps = [
-    HTTP_LIB,
-  ],
-  provided_deps = [
-    '//lib:gson',
-    '//lib/log:log4j',
-  ],
+  provided_deps = PROVIDED_DEPS + GERRIT_TESTS,
 )
 
 # this is required for bucklets/tools/eclipse/project.py to work
@@ -37,4 +30,3 @@
     '//lib/gwt:user',
   ],
 )
-
diff --git a/lib/commons/BUCK b/lib/commons/BUCK
deleted file mode 100644
index ba42a1f..0000000
--- a/lib/commons/BUCK
+++ /dev/null
@@ -1,41 +0,0 @@
-include_defs('//bucklets/maven_jar.bucklet')
-
-java_library(
-  name = 'commons_lib',
-  deps = [
-    ':codec',
-    ':io',
-    ':lang',
-  ],
-  visibility = ['PUBLIC'],
-)
-
-EXCLUDE = [
-  'META-INF/LICENSE.txt',
-  'META-INF/NOTICE.txt'
-]
-
-maven_jar(
-  name = 'codec',
-  id = 'commons-codec:commons-codec:1.4',
-  sha1 = '4216af16d38465bbab0f3dff8efa14204f7a399a',
-  license = 'Apache2.0',
-  exclude = EXCLUDE,
-)
-
-maven_jar(
-  name = 'io',
-  id = 'commons-io:commons-io:1.4',
-  sha1 = 'a8762d07e76cfde2395257a5da47ba7c1dbd3dce',
-  license = 'Apache2.0',
-  exclude = EXCLUDE,
-)
-
-maven_jar(
-  name = 'lang',
-  id = 'commons-lang:commons-lang:2.5',
-  sha1 = 'b0236b252e86419eef20c31a44579d2aee2f0a69',
-  license = 'Apache2.0',
-  exclude = EXCLUDE,
-)
-
diff --git a/lib/gerrit/BUCK b/lib/gerrit/BUCK
index f1ab768..d897745 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',
@@ -15,8 +15,17 @@
 maven_jar(
   name = 'gwtui-api',
   id = 'com.google.gerrit:gerrit-plugin-gwtui:' + VER,
-  sha1 = 'a7e7d82746b847678022242ec9eb44d1f16e8639',
+  sha1 = '0890414f42fc1fd0fef0400a479836f558727234',
   attach_source = False,
   repository = REPO,
   license = 'Apache2.0',
 )
+
+maven_jar(
+  name = 'acceptance-framework',
+  id = 'com.google.gerrit:gerrit-acceptance-framework:' + VER,
+  sha1 = 'e6565b206653d741c48348ce90116a6b22555015',
+  license = 'Apache2.0',
+  attach_source = False,
+  repository = REPO,
+)
diff --git a/lib/http/BUCK b/lib/http/BUCK
deleted file mode 100644
index 4de1df9..0000000
--- a/lib/http/BUCK
+++ /dev/null
@@ -1,40 +0,0 @@
-include_defs('//bucklets/gerrit_plugin.bucklet')
-include_defs('//bucklets/maven_jar.bucklet')
-
-if STANDALONE_MODE:
-  COMMONS = '//lib/commons:commons_lib'
-  LOG = '//lib/log:jcl-over-slf4j'
-else:
-  COMMONS = '//plugins/importer/lib/commons:commons_lib'
-  LOG = '//plugins/importer/lib/log:jcl-over-slf4j'
-
-java_library(
-  name = 'http_lib',
-  exported_deps = [
-    ':httpclient',
-    ':httpcore',
-  ],
-  visibility = ['PUBLIC'],
-)
-
-maven_jar(
-  name = 'httpclient',
-  id = 'org.apache.httpcomponents:httpclient:4.3.4',
-  bin_sha1 = 'a9a1fef2faefed639ee0d0fba5b3b8e4eb2ff2d8',
-  src_sha1 = '7a14aafed8c5e2c4e360a2c1abd1602efa768b1f',
-  license = 'Apache2.0',
-  deps = [
-    COMMONS,
-    ':httpcore',
-    LOG,
-  ],
-)
-
-maven_jar(
-  name = 'httpcore',
-  id = 'org.apache.httpcomponents:httpcore:4.3.2',
-  bin_sha1 = '31fbbff1ddbf98f3aa7377c94d33b0447c646b6e',
-  src_sha1 = '4809f38359edeea9487f747e09aa58ec8d3a54c5',
-  license = 'Apache2.0',
-)
-
diff --git a/lib/log/BUCK b/lib/log/BUCK
deleted file mode 100644
index 17e606b..0000000
--- a/lib/log/BUCK
+++ /dev/null
@@ -1,16 +0,0 @@
-include_defs('//bucklets/maven_jar.bucklet')
-
-maven_jar(
-  name = 'jcl-over-slf4j',
-  id = 'org.slf4j:jcl-over-slf4j:1.7.7',
-  sha1 = '56003dcd0a31deea6391b9e2ef2f2dc90b205a92',
-  license = 'slf4j',
-)
-
-maven_jar(
-  name = 'log4j',
-  id = 'log4j:log4j:1.2.17',
-  sha1 = '5af35056b4d257e4b64b9e8069c0746e8b08629f',
-  license = 'Apache2.0',
-  exclude = ['META-INF/LICENSE', 'META-INF/NOTICE'],
-)
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/AccountUtil.java b/src/main/java/com/googlesource/gerrit/plugins/importer/AccountUtil.java
index 90147a0..1b91675 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/importer/AccountUtil.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/AccountUtil.java
@@ -14,36 +14,35 @@
 
 package com.googlesource.gerrit.plugins.importer;
 
+import com.google.gerrit.common.errors.InvalidSshKeyException;
 import com.google.gerrit.common.errors.NoSuchAccountException;
+import com.google.gerrit.extensions.api.accounts.AccountInput;
 import com.google.gerrit.extensions.api.groups.GroupApi;
 import com.google.gerrit.extensions.common.AccountInfo;
+import com.google.gerrit.extensions.common.SshKeyInfo;
 import com.google.gerrit.extensions.restapi.BadRequestException;
 import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
 import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.extensions.restapi.TopLevelResource;
 import com.google.gerrit.reviewdb.client.Account;
-import com.google.gerrit.reviewdb.client.AccountSshKey;
 import com.google.gerrit.reviewdb.client.AuthType;
-import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.account.AccountCache;
 import com.google.gerrit.server.account.AccountException;
 import com.google.gerrit.server.account.AccountManager;
 import com.google.gerrit.server.account.AccountState;
 import com.google.gerrit.server.account.AuthRequest;
 import com.google.gerrit.server.account.CreateAccount;
-import com.google.gerrit.server.account.GetSshKeys.SshKeyInfo;
+import com.google.gerrit.server.account.VersionedAuthorizedKeys;
 import com.google.gerrit.server.config.AuthConfig;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
-import com.google.inject.Provider;
 import com.google.inject.Singleton;
 
+import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
-import java.util.Collection;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Objects;
 
@@ -57,10 +56,8 @@
   private final AccountManager accountManager;
   private final AuthType authType;
   private final com.google.gerrit.extensions.api.GerritApi gApi;
-  private final Provider<ReviewDb> db;
-
-  @Inject
-  private CreateAccount.Factory createAccountFactory;
+  private final VersionedAuthorizedKeys.Accessor authorizedKeys;
+  private final CreateAccount.Factory createAccountFactory;
 
   @Inject
   public AccountUtil(
@@ -68,17 +65,19 @@
       AccountManager accountManager,
       AuthConfig authConfig,
       com.google.gerrit.extensions.api.GerritApi gApi,
-      Provider<ReviewDb> db) {
+      VersionedAuthorizedKeys.Accessor authorizedKeys,
+      CreateAccount.Factory createAccountFactory) {
     this.accountCache = accountCache;
     this.accountManager = accountManager;
     this.authType = authConfig.getAuthType();
-    this.db = db;
     this.gApi = gApi;
+    this.authorizedKeys = authorizedKeys;
+    this.createAccountFactory = createAccountFactory;
   }
 
   Account.Id resolveUser(GerritApi api, AccountInfo acc)
       throws NoSuchAccountException, IOException, OrmException,
-      RestApiException {
+      RestApiException, ConfigInvalidException {
     if (acc.username == null) {
       throw new NoSuchAccountException(String.format(
           "User %s <%s> (%s) doesn't have a username and cannot be looked up.",
@@ -92,6 +91,13 @@
         case CLIENT_SSL_CERT_LDAP:
         case LDAP:
           return createAccountByLdapAndAddSshKeys(api, acc);
+        case CUSTOM_EXTENSION:
+        case DEVELOPMENT_BECOME_ANY_ACCOUNT:
+        case HTTP:
+        case LDAP_BIND:
+        case OAUTH:
+        case OPENID:
+        case OPENID_SSO:
         default:
           return createLocalUser(acc);
       }
@@ -105,8 +111,8 @@
   }
 
   private Account.Id createAccountByLdapAndAddSshKeys(GerritApi api,
-      AccountInfo acc) throws NoSuchAccountException, IOException,
-      OrmException, RestApiException {
+      AccountInfo acc) throws NoSuchAccountException, IOException, OrmException,
+          RestApiException, ConfigInvalidException {
     if (!acc.username.matches(Account.USER_NAME_PATTERN)) {
       throw new NoSuchAccountException(String.format("User %s not found",
           acc.username));
@@ -124,27 +130,22 @@
   }
 
   private void addSshKeys(GerritApi api, AccountInfo acc)
-      throws BadRequestException, IOException, OrmException {
+      throws BadRequestException, IOException, OrmException,
+      ConfigInvalidException {
     List<SshKeyInfo> sshKeys = api.getSshKeys(acc.username);
     AccountState a = accountCache.getByUsername(acc.username);
-    db.get().accountSshKeys().upsert(toAccountSshKey(a, sshKeys));
-  }
-
-  private static Collection<AccountSshKey> toAccountSshKey(AccountState a,
-      List<SshKeyInfo> sshKeys) {
-    Collection<AccountSshKey> result = new HashSet<>();
-    int index = 1;
     for (SshKeyInfo sshKeyInfo : sshKeys) {
-      result.add(new AccountSshKey(
-          new AccountSshKey.Id(a.getAccount().getId(), index++),
-          sshKeyInfo.sshPublicKey));
+      try {
+        authorizedKeys.addKey(a.getAccount().getId(), sshKeyInfo.sshPublicKey);
+      } catch (InvalidSshKeyException e) {
+        log.warn(String.format("Invalid SSH key for user %s", acc.username));
+      }
     }
-    return result;
   }
 
   private Account.Id createLocalUser(AccountInfo acc)
-      throws OrmException, RestApiException {
-    CreateAccount.Input input = new CreateAccount.Input();
+      throws OrmException, RestApiException, IOException, ConfigInvalidException {
+    AccountInput input = new AccountInput();
     log.info(String.format("User '%s' not found", acc.username));
     String username = acc.username;
     input.username = username;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/AddApprovalsStep.java b/src/main/java/com/googlesource/gerrit/plugins/importer/AddApprovalsStep.java
index 4477031..b541966 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/importer/AddApprovalsStep.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/AddApprovalsStep.java
@@ -35,6 +35,7 @@
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
+import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -80,8 +81,9 @@
     this.resume = resume;
   }
 
-  void add(GerritApi api) throws OrmException, NoSuchChangeException, IOException,
-      NoSuchAccountException, RestApiException{
+  void add(GerritApi api) throws OrmException, NoSuchChangeException,
+      IOException, NoSuchAccountException, RestApiException,
+      ConfigInvalidException {
     if (resume) {
       db.patchSetApprovals().delete(
           db.patchSetApprovals().byChange(change.getId()));
@@ -130,7 +132,11 @@
 
   private ChangeControl control(Change change, Account.Id id)
       throws NoSuchChangeException {
-    return changeControlFactory.controlFor(change,
-        genericUserFactory.create(id));
+    try {
+      return changeControlFactory.controlFor(db, change,
+          genericUserFactory.create(id));
+    } catch (OrmException e) {
+      throw new NoSuchChangeException(change.getId());
+    }
   }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/AddHashtagsStep.java b/src/main/java/com/googlesource/gerrit/plugins/importer/AddHashtagsStep.java
index a8de4a2..3e8de69 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/importer/AddHashtagsStep.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/AddHashtagsStep.java
@@ -77,7 +77,8 @@
 
   void add() throws IllegalArgumentException, OrmException,
       NoSuchChangeException, UpdateException, RestApiException {
-    ChangeControl ctrl = changeControlFactory.controlFor(change, currentUser);
+    ChangeControl ctrl =
+        changeControlFactory.controlFor(db.get(), change, currentUser);
 
     try {
       if (resume) {
@@ -108,4 +109,4 @@
           ChangeTriplet.format(change), currentUser.getUserName()));
     }
   }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/CompleteProjectImport.java b/src/main/java/com/googlesource/gerrit/plugins/importer/CompleteProjectImport.java
index c108e08..2a6438d 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/importer/CompleteProjectImport.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/CompleteProjectImport.java
@@ -38,7 +38,6 @@
 import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.RefUpdate;
 import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.util.FS;
 
 import java.io.File;
 import java.io.IOException;
@@ -77,7 +76,7 @@
   private LockFile lockForDelete(Project.NameKey project)
       throws ResourceConflictException {
     File importStatus = projects.FS_LAYOUT.getImportStatusFile(project.get());
-    LockFile lockFile = new LockFile(importStatus, FS.DETECTED);
+    LockFile lockFile = new LockFile(importStatus);
     try {
       if (lockFile.lock()) {
         return lockFile;
@@ -105,6 +104,12 @@
           case FAST_FORWARD:
           case FORCED:
             break;
+          case IO_FAILURE:
+          case LOCK_FAILURE:
+          case NOT_ATTEMPTED:
+          case REJECTED:
+          case REJECTED_CURRENT_BRANCH:
+          case RENAMED:
           default:
             throw new IOException(String.format(
                 "Failed to delete %s, RefUpdate.Result = %s", ref, result));
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/ConfigureRepositoryStep.java b/src/main/java/com/googlesource/gerrit/plugins/importer/ConfigureRepositoryStep.java
index f15a3ec..aca47c3 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/importer/ConfigureRepositoryStep.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/ConfigureRepositoryStep.java
@@ -27,10 +27,8 @@
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.lib.StoredConfig;
 
-import java.nio.file.Files;
-import java.nio.file.Path;
-
 import java.io.IOException;
+import java.nio.file.Path;
 
 @Singleton
 class ConfigureRepositoryStep {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/CopyProject.java b/src/main/java/com/googlesource/gerrit/plugins/importer/CopyProject.java
index 6598f30..0992551 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/importer/CopyProject.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/CopyProject.java
@@ -38,6 +38,7 @@
 import com.googlesource.gerrit.plugins.importer.CopyProject.Input;
 
 import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.errors.ConfigInvalidException;
 
 import java.io.IOException;
 import java.io.PrintWriter;
@@ -71,7 +72,7 @@
   public ImportStatistic apply(ProjectResource rsrc, Input input)
       throws RestApiException, OrmException, IOException, ValidationException,
       GitAPIException, NoSuchChangeException, NoSuchAccountException,
-      UpdateException {
+      UpdateException, ConfigInvalidException {
     if (Strings.isNullOrEmpty(input.name)) {
       throw new BadRequestException("name is required");
     }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/GerritApi.java b/src/main/java/com/googlesource/gerrit/plugins/importer/GerritApi.java
index 7d47c79..40b321b 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/importer/GerritApi.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/GerritApi.java
@@ -19,11 +19,13 @@
 import com.google.gerrit.extensions.common.CommentInfo;
 import com.google.gerrit.extensions.common.GroupInfo;
 import com.google.gerrit.extensions.common.ProjectInfo;
+import com.google.gerrit.extensions.common.SshKeyInfo;
 import com.google.gerrit.extensions.restapi.BadRequestException;
-import com.google.gerrit.server.account.GetSshKeys.SshKeyInfo;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 
+import org.eclipse.jgit.errors.ConfigInvalidException;
+
 import java.io.IOException;
 import java.util.List;
 import java.util.regex.Matcher;
@@ -72,7 +74,7 @@
       throws BadRequestException, IOException, OrmException;
 
   public List<SshKeyInfo> getSshKeys(String userId) throws BadRequestException,
-      IOException, OrmException;
+      IOException, OrmException, ConfigInvalidException;
 
   public Version getVersion() throws BadRequestException, IOException;
 
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/GitFetchStep.java b/src/main/java/com/googlesource/gerrit/plugins/importer/GitFetchStep.java
index 2fc0f59..132a36c 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/importer/GitFetchStep.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/GitFetchStep.java
@@ -77,6 +77,12 @@
         case FORCED:
         case NO_CHANGE:
           break;
+        case IO_FAILURE:
+        case LOCK_FAILURE:
+        case NOT_ATTEMPTED:
+        case REJECTED:
+        case REJECTED_CURRENT_BRANCH:
+        case RENAMED:
         default:
           throw new IOException(String.format(
               "Failed to update %s, RefUpdate.Result = %s", targetRef, result));
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/GroupCommand.java b/src/main/java/com/googlesource/gerrit/plugins/importer/GroupCommand.java
index b78913e..5b4c758 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/importer/GroupCommand.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/GroupCommand.java
@@ -27,6 +27,7 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 
+import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.kohsuke.args4j.Argument;
 import org.kohsuke.args4j.Option;
 
@@ -66,7 +67,7 @@
 
   @Override
   protected void run() throws UnloggedFailure, OrmException, IOException,
-      NoSuchAccountException {
+      NoSuchAccountException, ConfigInvalidException {
     ImportGroup.Input input = new ImportGroup.Input();
     input.from = url;
     input.user = user;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/HttpResponse.java b/src/main/java/com/googlesource/gerrit/plugins/importer/HttpResponse.java
index 34786d3..4966c3c 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/importer/HttpResponse.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/HttpResponse.java
@@ -46,7 +46,9 @@
     try {
       Reader reader = getReader();
       if (reader != null) {
-        while (reader.read() != -1);
+        while (reader.read() != -1) {
+          // Empty
+        }
       }
     } finally {
       response.close();
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/HttpSession.java b/src/main/java/com/googlesource/gerrit/plugins/importer/HttpSession.java
index 9fb8e27..531d176 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/importer/HttpSession.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/HttpSession.java
@@ -20,7 +20,6 @@
 import org.apache.http.auth.UsernamePasswordCredentials;
 import org.apache.http.client.methods.HttpGet;
 import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
-import org.apache.http.conn.ssl.X509HostnameVerifier;
 import org.apache.http.impl.client.BasicCredentialsProvider;
 import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.impl.client.HttpClients;
@@ -31,10 +30,9 @@
 import java.security.NoSuchAlgorithmException;
 import java.security.cert.X509Certificate;
 
+import javax.net.ssl.HostnameVerifier;
 import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLException;
 import javax.net.ssl.SSLSession;
-import javax.net.ssl.SSLSocket;
 import javax.net.ssl.TrustManager;
 import javax.net.ssl.X509TrustManager;
 
@@ -106,28 +104,12 @@
     }
   }
 
-  private static class DummyHostnameVerifier implements X509HostnameVerifier {
+  private static class DummyHostnameVerifier implements HostnameVerifier {
     @Override
     public boolean verify(String hostname, SSLSession session) {
       // always accept
       return true;
     }
-
-    @Override
-    public void verify(String host, SSLSocket ssl) throws IOException {
-      // no check
-    }
-
-    @Override
-    public void verify(String host, X509Certificate cert) throws SSLException {
-      // no check
-    }
-
-    @Override
-    public void verify(String host, String[] cns, String[] subjectAlts)
-        throws SSLException {
-      // no check
-    }
   }
 
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/ImportGroup.java b/src/main/java/com/googlesource/gerrit/plugins/importer/ImportGroup.java
index 7825d97..e2eec41 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/importer/ImportGroup.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/ImportGroup.java
@@ -49,6 +49,7 @@
 
 import com.googlesource.gerrit.plugins.importer.ImportGroup.Input;
 
+import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.lib.Config;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -115,7 +116,7 @@
   @Override
   public Response<String> apply(ConfigResource rsrc, Input input)
       throws NoSuchAccountException, OrmException, IOException,
-      RestApiException {
+      RestApiException, ConfigInvalidException {
     GroupInfo groupInfo;
     this.api = apiFactory.create(input.from, input.user, input.pass);
     groupInfo = api.getGroup(group.get());
@@ -127,7 +128,7 @@
 
   private void validate(Input input, GroupInfo groupInfo)
       throws IOException, OrmException, NoSuchAccountException,
-      RestApiException {
+      RestApiException, ConfigInvalidException {
     if (!isInternalGroup(new AccountGroup.UUID(groupInfo.id))) {
       throw new MethodNotAllowedException(String.format(
           "Group with name %s is not an internal group and cannot be imported",
@@ -182,7 +183,8 @@
   }
 
   private CreateGroupArgs toCreateGroupArgs(GroupInfo groupInfo)
-      throws IOException, OrmException, NoSuchAccountException, RestApiException {
+      throws IOException, OrmException, NoSuchAccountException,
+      RestApiException, ConfigInvalidException {
     CreateGroupArgs args = new CreateGroupArgs();
     args.setGroupName(groupInfo.name);
     args.groupDescription = groupInfo.description;
@@ -198,8 +200,9 @@
     return args;
   }
 
-  private AccountGroup createGroup(Input input, GroupInfo info) throws OrmException,
-      NoSuchAccountException, IOException, RestApiException {
+  private AccountGroup createGroup(Input input, GroupInfo info)
+      throws OrmException, NoSuchAccountException, IOException,
+      RestApiException, ConfigInvalidException {
     String uniqueName = getUniqueGroupName(info.name);
     if (!info.name.equals(uniqueName)) {
       log.warn(String.format("Group %s with UUID %s is imported with name %s",
@@ -277,7 +280,8 @@
   }
 
   private void addMembers(AccountGroup.Id groupId, List<AccountInfo> members)
-      throws OrmException, NoSuchAccountException, IOException, RestApiException {
+      throws OrmException, NoSuchAccountException, IOException,
+      RestApiException, ConfigInvalidException {
     List<AccountGroupMember> memberships = new ArrayList<>();
     for (AccountInfo member : members) {
       Account.Id userId = accountUtil.resolveUser(api, member);
@@ -292,10 +296,10 @@
     }
   }
 
-  private void addGroups(Input input, AccountGroup.Id groupId,
-      String groupName, List<GroupInfo> includedGroups)
-      throws NoSuchAccountException, OrmException,
-      IOException, RestApiException {
+  private void addGroups(Input input, AccountGroup.Id groupId, String groupName,
+      List<GroupInfo> includedGroups)
+          throws NoSuchAccountException, OrmException, IOException,
+          RestApiException, ConfigInvalidException {
     List<AccountGroupById> includeList = new ArrayList<>();
     for (GroupInfo includedGroup : includedGroups) {
       if (isInternalGroup(new AccountGroup.UUID(includedGroup.id))) {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/ImportGroupsStep.java b/src/main/java/com/googlesource/gerrit/plugins/importer/ImportGroupsStep.java
index bae0813..e8b0288 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/importer/ImportGroupsStep.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/ImportGroupsStep.java
@@ -30,6 +30,7 @@
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
+import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.lib.ProgressMonitor;
 
 import java.io.IOException;
@@ -76,7 +77,7 @@
   }
 
   void importGroups() throws NoSuchAccountException, OrmException, IOException,
-      RestApiException {
+      RestApiException, ConfigInvalidException {
     ProjectConfig projectConfig = projectCache.get(project).getConfig();
     Set<AccountGroup.UUID> groupUUIDs = projectConfig.getAllGroupUUIDs();
     pm.beginTask("Import Groups", groupUUIDs.size());
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/ImportLog.java b/src/main/java/com/googlesource/gerrit/plugins/importer/ImportLog.java
index 38e0f8b..8c6f27e 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/importer/ImportLog.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/ImportLog.java
@@ -14,6 +14,7 @@
 
 package com.googlesource.gerrit.plugins.importer;
 
+import com.google.common.base.Throwables;
 import com.google.common.collect.HashMultimap;
 import com.google.common.collect.Multimap;
 import com.google.gerrit.audit.AuditEvent;
@@ -96,7 +97,7 @@
     event.setProperty(TARGET_PROJECT_NAME, targetProject.get());
 
     if (ex != null) {
-      event.setProperty(ERROR, ex.toString());
+      event.setProperty(ERROR, Throwables.getStackTraceAsString(ex));
     }
 
     log.callAppenders(event);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/ImportMenu.java b/src/main/java/com/googlesource/gerrit/plugins/importer/ImportMenu.java
index ad9c37c..f0b0976 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/importer/ImportMenu.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/ImportMenu.java
@@ -16,6 +16,7 @@
 
 import com.google.common.collect.Lists;
 import com.google.gerrit.extensions.annotations.PluginName;
+import com.google.gerrit.extensions.client.MenuItem;
 import com.google.gerrit.extensions.webui.TopMenu;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.account.CapabilityControl;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/ImportProject.java b/src/main/java/com/googlesource/gerrit/plugins/importer/ImportProject.java
index 82c75d0..83c9cb9 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/importer/ImportProject.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/ImportProject.java
@@ -42,12 +42,12 @@
 import com.googlesource.gerrit.plugins.importer.ImportProject.Input;
 
 import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.internal.storage.file.LockFile;
 import org.eclipse.jgit.lib.NullProgressMonitor;
 import org.eclipse.jgit.lib.ProgressMonitor;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.lib.TextProgressMonitor;
-import org.eclipse.jgit.util.FS;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -166,7 +166,7 @@
   public ImportStatistic apply(ConfigResource rsrc, Input input)
       throws RestApiException, OrmException, IOException, ValidationException,
       GitAPIException, NoSuchChangeException, NoSuchAccountException,
-      UpdateException {
+      UpdateException, ConfigInvalidException {
     if (input == null) {
       input = new Input();
     }
@@ -182,7 +182,7 @@
   public ResumeImportStatistic resume(String user, String pass, boolean force,
       File importStatus) throws RestApiException, OrmException, IOException,
       GitAPIException, NoSuchChangeException, NoSuchAccountException,
-      UpdateException {
+      UpdateException, ConfigInvalidException {
     LockFile lockFile = lockForImport();
     try {
       ImportProjectInfo info = ImportJson.parse(importStatus);
@@ -205,7 +205,7 @@
   private ResumeImportStatistic apply(LockFile lockFile, Input input,
       ImportProjectInfo info) throws RestApiException, OrmException,
       IOException, GitAPIException, NoSuchChangeException,
-      NoSuchAccountException, UpdateException {
+      NoSuchAccountException, UpdateException, ConfigInvalidException {
     boolean resume = info != null;
     api = apiFactory.create(input.from, input.user, input.pass);
 
@@ -303,7 +303,7 @@
 
   private LockFile lockForImport() throws ResourceConflictException {
     File importStatus = projects.FS_LAYOUT.getImportStatusFile(targetProject.get());
-    LockFile lockFile = new LockFile(importStatus, FS.DETECTED);
+    LockFile lockFile = new LockFile(importStatus);
     try {
       if (lockFile.lock()) {
         return lockFile;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/InsertLinkToOriginalChangeStep.java b/src/main/java/com/googlesource/gerrit/plugins/importer/InsertLinkToOriginalChangeStep.java
index 6bee56c..27ead51 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/importer/InsertLinkToOriginalChangeStep.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/InsertLinkToOriginalChangeStep.java
@@ -111,8 +111,12 @@
 
   private ChangeControl control(Change change, Account.Id id)
       throws NoSuchChangeException {
-    return changeControlFactory.controlFor(change,
-        genericUserFactory.create(id));
+    try {
+      return changeControlFactory.controlFor(db, change,
+          genericUserFactory.create(id));
+    } catch (OrmException e) {
+      throw new NoSuchChangeException(change.getId());
+    }
   }
 
   private static String ensureSlash(String in) {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/LocalApi.java b/src/main/java/com/googlesource/gerrit/plugins/importer/LocalApi.java
index c9ec59f..a5dd841 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/importer/LocalApi.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/LocalApi.java
@@ -21,6 +21,7 @@
 import com.google.gerrit.extensions.common.CommentInfo;
 import com.google.gerrit.extensions.common.GroupInfo;
 import com.google.gerrit.extensions.common.ProjectInfo;
+import com.google.gerrit.extensions.common.SshKeyInfo;
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.BadRequestException;
 import com.google.gerrit.extensions.restapi.IdString;
@@ -30,10 +31,11 @@
 import com.google.gerrit.server.account.AccountResource;
 import com.google.gerrit.server.account.AccountsCollection;
 import com.google.gerrit.server.account.GetSshKeys;
-import com.google.gerrit.server.account.GetSshKeys.SshKeyInfo;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 
+import org.eclipse.jgit.errors.ConfigInvalidException;
+
 import java.io.IOException;
 import java.util.List;
 import java.util.Map;
@@ -120,7 +122,7 @@
 
   @Override
   public List<SshKeyInfo> getSshKeys(String userId) throws BadRequestException,
-      IOException, OrmException {
+      IOException, OrmException, ConfigInvalidException {
     try {
       AccountResource rsrc =
           accounts.parse(TopLevelResource.INSTANCE,
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/Module.java b/src/main/java/com/googlesource/gerrit/plugins/importer/Module.java
index 1cad41f..7c2c2d4 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/importer/Module.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/Module.java
@@ -16,8 +16,8 @@
 
 import static com.google.gerrit.server.config.ConfigResource.CONFIG_KIND;
 import static com.google.gerrit.server.project.ProjectResource.PROJECT_KIND;
-import static com.googlesource.gerrit.plugins.importer.ImportProjectResource.IMPORT_PROJECT_KIND;
 import static com.googlesource.gerrit.plugins.importer.ImportGroupResource.IMPORT_GROUP_KIND;
+import static com.googlesource.gerrit.plugins.importer.ImportProjectResource.IMPORT_PROJECT_KIND;
 
 import com.google.gerrit.extensions.annotations.Exports;
 import com.google.gerrit.extensions.config.CapabilityDefinition;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/ProjectCommand.java b/src/main/java/com/googlesource/gerrit/plugins/importer/ProjectCommand.java
index f31e160..e449d36 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/importer/ProjectCommand.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/ProjectCommand.java
@@ -29,6 +29,7 @@
 import com.google.inject.Inject;
 
 import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.kohsuke.args4j.Argument;
 import org.kohsuke.args4j.Option;
 
@@ -69,9 +70,10 @@
   private ImportProject.Factory importProjectFactory;
 
   @Override
-  protected void run() throws OrmException, IOException, UnloggedFailure,
-      ValidationException, GitAPIException, NoSuchChangeException,
-      NoSuchAccountException, UpdateException {
+  protected void run()
+      throws OrmException, IOException, UnloggedFailure, ValidationException,
+      GitAPIException, NoSuchChangeException, NoSuchAccountException,
+      UpdateException, ConfigInvalidException {
     ImportProject.Input input = new ImportProject.Input();
     input.from = url;
     input.name = name;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/RemoteApi.java b/src/main/java/com/googlesource/gerrit/plugins/importer/RemoteApi.java
index 5ee6f06..b83a142 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/importer/RemoteApi.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/RemoteApi.java
@@ -23,9 +23,9 @@
 import com.google.gerrit.extensions.common.GroupInfo;
 import com.google.gerrit.extensions.common.ProjectInfo;
 import com.google.gerrit.extensions.common.RevisionInfo;
+import com.google.gerrit.extensions.common.SshKeyInfo;
 import com.google.gerrit.extensions.restapi.BadRequestException;
 import com.google.gerrit.server.OutputFormat;
-import com.google.gerrit.server.account.GetSshKeys.SshKeyInfo;
 import com.google.gson.Gson;
 import com.google.gson.reflect.TypeToken;
 
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/ReplayChangesStep.java b/src/main/java/com/googlesource/gerrit/plugins/importer/ReplayChangesStep.java
index 3322dfc..2ada0e5 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/importer/ReplayChangesStep.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/ReplayChangesStep.java
@@ -26,8 +26,10 @@
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.Sequences;
 import com.google.gerrit.server.git.UpdateException;
-import com.google.gerrit.server.index.ChangeIndexer;
+import com.google.gerrit.server.index.change.ChangeIndexer;
+import com.google.gerrit.server.notedb.NotesMigration;
 import com.google.gerrit.server.project.NoSuchChangeException;
 import com.google.gerrit.server.query.change.ChangeData;
 import com.google.gerrit.server.query.change.InternalChangeQuery;
@@ -36,6 +38,7 @@
 import com.google.inject.Provider;
 import com.google.inject.assistedinject.Assisted;
 
+import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.ProgressMonitor;
 import org.eclipse.jgit.lib.Repository;
@@ -74,6 +77,7 @@
   private final ReviewDb db;
   private final ChangeIndexer indexer;
   private final Provider<InternalChangeQuery> queryProvider;
+  private final Sequences sequences;
   private final String fromGerrit;
   private final GerritApi api;
   private final Repository repo;
@@ -83,6 +87,7 @@
   private final boolean resume;
   private final ResumeImportStatistic importStatistic;
   private final ProgressMonitor pm;
+  private final boolean isNoteDbEnabled;
 
   @Inject
   ReplayChangesStep(
@@ -96,6 +101,8 @@
       ReviewDb db,
       ChangeIndexer indexer,
       Provider<InternalChangeQuery> queryProvider,
+      Sequences sequences,
+      NotesMigration migration,
       @Assisted @Nullable String fromGerrit,
       @Assisted GerritApi api,
       @Assisted Repository repo,
@@ -115,6 +122,7 @@
     this.db = db;
     this.indexer = indexer;
     this.queryProvider = queryProvider;
+    this.sequences = sequences;
     this.fromGerrit = fromGerrit;
     this.api = api;
     this.repo = repo;
@@ -124,11 +132,12 @@
     this.resume = resume;
     this.importStatistic = importStatistic;
     this.pm = pm;
+    this.isNoteDbEnabled = migration.enabled();
   }
 
   void replay() throws IOException, OrmException,
       NoSuchAccountException, NoSuchChangeException, RestApiException,
-      UpdateException {
+      UpdateException, ConfigInvalidException {
     int start = 0;
     int limit = GlobalCapability.DEFAULT_MAX_QUERY_LIMIT;
     pm.beginTask("Replay Changes", ProgressMonitor.UNKNOWN);
@@ -162,7 +171,8 @@
 
   private void replayChange(RevWalk rw, ChangeInfo c)
       throws IOException, OrmException, NoSuchAccountException,
-      NoSuchChangeException, RestApiException, IllegalArgumentException, UpdateException {
+      NoSuchChangeException, RestApiException, IllegalArgumentException,
+      UpdateException, ConfigInvalidException {
     if (c.status == ChangeStatus.DRAFT) {
       // no import of draft changes
       return;
@@ -192,7 +202,9 @@
     replayInlineCommentsFactory.create(change, c, api, resumeChange).replay();
     replayMessagesFactory.create(change, c, resumeChange).replay(api);
     addApprovalsFactory.create(change, c, resume).add(api);
-    addHashtagsFactory.create(change, c, resumeChange).add();
+    if (isNoteDbEnabled) {
+      addHashtagsFactory.create(change, c, resumeChange).add();
+    }
 
     insertLinkToOriginalFactory.create(fromGerrit, change, c, resumeChange).insert();
 
@@ -212,15 +224,15 @@
             new Change.Key(c.changeId)));
     if (changes.isEmpty()) {
       return null;
-    } else {
-      return db.changes().get(
-          Iterators.getOnlyElement(changes.iterator()).getId());
     }
+    return db.changes().get(
+        Iterators.getOnlyElement(changes.iterator()).getId());
   }
 
-  private Change createChange(ChangeInfo c) throws OrmException,
-      NoSuchAccountException, IOException, RestApiException {
-    Change.Id changeId = new Change.Id(db.nextChangeId());
+  private Change createChange(ChangeInfo c)
+      throws OrmException, NoSuchAccountException, IOException,
+      RestApiException, ConfigInvalidException {
+    Change.Id changeId = new Change.Id(sequences.nextChangeId());
 
     Change change =
         new Change(new Change.Key(c.changeId), changeId, accountUtil.resolveUser(api, c.owner),
@@ -244,8 +256,7 @@
   private static String fullName(String branch) {
     if (branch.startsWith(Constants.R_HEADS)) {
       return branch;
-    } else {
-      return Constants.R_HEADS + branch;
     }
+    return Constants.R_HEADS + branch;
   }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/ReplayInlineCommentsStep.java b/src/main/java/com/googlesource/gerrit/plugins/importer/ReplayInlineCommentsStep.java
index 0df6a89..be71dd7 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/importer/ReplayInlineCommentsStep.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/ReplayInlineCommentsStep.java
@@ -34,8 +34,10 @@
 import com.google.gerrit.reviewdb.client.PatchLineComment;
 import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.ChangeUtil;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.PatchLineCommentsUtil;
+import com.google.gerrit.server.PatchSetUtil;
 import com.google.gerrit.server.notedb.ChangeUpdate;
 import com.google.gerrit.server.patch.PatchListCache;
 import com.google.gerrit.server.project.ChangeControl;
@@ -44,6 +46,7 @@
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
+import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -72,6 +75,7 @@
   private final ChangeUpdate.Factory updateFactory;
   private final PatchLineCommentsUtil plcUtil;
   private final PatchListCache patchListCache;
+  private final PatchSetUtil psUtil;
   private final Change change;
   private final ChangeInfo changeInfo;
   private final GerritApi api;
@@ -85,6 +89,7 @@
       ChangeUpdate.Factory updateFactory,
       PatchLineCommentsUtil plcUtil,
       PatchListCache patchListCache,
+      PatchSetUtil psUtil,
       @Assisted Change change,
       @Assisted ChangeInfo changeInfo,
       @Assisted GerritApi api,
@@ -96,15 +101,19 @@
     this.updateFactory = updateFactory;
     this.plcUtil = plcUtil;
     this.patchListCache = patchListCache;
+    this.psUtil = psUtil;
     this.change = change;
     this.changeInfo = changeInfo;
     this.api = api;
     this.resume = resume;
   }
 
-  void replay() throws RestApiException, OrmException, IOException,
-      NoSuchChangeException, NoSuchAccountException {
-    for (PatchSet ps : db.patchSets().byChange(change.getId())) {
+  void replay()
+      throws RestApiException, OrmException, IOException, NoSuchChangeException,
+      NoSuchAccountException, ConfigInvalidException {
+    ChangeControl ctrl =  control(change, change.getOwner());
+    for (PatchSet ps : ChangeUtil.PS_ID_ORDER
+        .sortedCopy(psUtil.byChange(db, ctrl.getNotes()))) {
       Iterable<CommentInfo> comments = api.getComments(
           changeInfo._number, ps.getRevision().get());
       if (resume) {
@@ -203,7 +212,7 @@
     ChangeUpdate update = updateFactory.create(ctrl, TimeUtil.nowTs());
     update.setPatchSetId(ps.getId());
     plcUtil.deleteComments(db, update, del);
-    plcUtil.upsertComments(db, update, ups);
+    plcUtil.putComments(db, update, ups);
     update.commit();
   }
 
@@ -220,7 +229,11 @@
 
   private ChangeControl control(Change change, Account.Id id)
       throws NoSuchChangeException {
-    return changeControlFactory.controlFor(change,
-        genericUserFactory.create(id));
+    try {
+      return changeControlFactory.controlFor(db, change,
+          genericUserFactory.create(id));
+    } catch (OrmException e) {
+       throw new NoSuchChangeException(change.getId());
+     }
   }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/ReplayMessagesStep.java b/src/main/java/com/googlesource/gerrit/plugins/importer/ReplayMessagesStep.java
index c5ee3c5..dde14ee 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/importer/ReplayMessagesStep.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/ReplayMessagesStep.java
@@ -32,6 +32,8 @@
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
+import org.eclipse.jgit.errors.ConfigInvalidException;
+
 import java.io.IOException;
 import java.sql.Timestamp;
 import java.util.Collections;
@@ -74,8 +76,9 @@
     this.resume = resume;
   }
 
-  void replay(GerritApi api) throws NoSuchAccountException, NoSuchChangeException,
-      OrmException, IOException, RestApiException {
+  void replay(GerritApi api) throws NoSuchAccountException,
+      NoSuchChangeException, OrmException, IOException, RestApiException,
+      ConfigInvalidException {
     for (ChangeMessageInfo msg : changeInfo.messages) {
       ChangeMessage.Key msgKey = new ChangeMessage.Key(change.getId(), msg.id);
       if (resume && db.changeMessages().get(msgKey) != null) {
@@ -84,12 +87,12 @@
       }
 
       Timestamp ts = msg.date;
+      PatchSet.Id psId = msg._revisionNumber != null
+          ? new PatchSet.Id(change.getId(),  msg._revisionNumber)
+          : null;
       if (msg.author != null) {
         Account.Id userId = accountUtil.resolveUser(api, msg.author);
         ChangeUpdate update = updateFactory.create(control(change, userId), ts);
-        PatchSet.Id psId = msg._revisionNumber != null
-            ? new PatchSet.Id(change.getId(),  msg._revisionNumber)
-            : null;
         ChangeMessage cmsg = new ChangeMessage(msgKey, userId, ts, psId);
         cmsg.setMessage(msg.message);
         cmUtil.addChangeMessage(db, update, cmsg);
@@ -98,7 +101,7 @@
         // Message create by the GerritPersonIdent user
         ChangeMessage cmsg =
             new ChangeMessage(new ChangeMessage.Key(change.getId(), msg.id),
-                null, ts, new PatchSet.Id(change.getId(), msg._revisionNumber));
+                null, ts, psId);
         cmsg.setMessage(msg.message);
         db.changeMessages().insert(Collections.singleton(cmsg));
       }
@@ -107,7 +110,11 @@
 
   private ChangeControl control(Change change, Account.Id id)
       throws NoSuchChangeException {
-    return changeControlFactory.controlFor(change,
+    try {
+      return changeControlFactory.controlFor(db, change,
         genericUserFactory.create(id));
+    } catch (OrmException e) {
+      throw new NoSuchChangeException(change.getId());
+    }
   }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/ReplayRevisionsStep.java b/src/main/java/com/googlesource/gerrit/plugins/importer/ReplayRevisionsStep.java
index 5adf74f..50efc97 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/importer/ReplayRevisionsStep.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/ReplayRevisionsStep.java
@@ -23,12 +23,12 @@
 import com.google.gerrit.reviewdb.client.PatchSetInfo;
 import com.google.gerrit.reviewdb.client.RevId;
 import com.google.gerrit.reviewdb.server.ReviewDb;
-import com.google.gerrit.server.ChangeUtil;
 import com.google.gerrit.server.patch.PatchSetInfoFactory;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
+import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.RefUpdate;
@@ -79,8 +79,9 @@
     this.changeInfo = changeInfo;
   }
 
-  void replay(GerritApi api) throws IOException, OrmException,
-      NoSuchAccountException, RestApiException {
+  void replay(GerritApi api)
+      throws IOException, OrmException, NoSuchAccountException,
+      RestApiException, ConfigInvalidException {
     List<RevisionInfo> revisions = new ArrayList<>(changeInfo.revisions.values());
     sortRevisionInfoByNumber(revisions);
     List<PatchSet> patchSets = new ArrayList<>();
@@ -181,6 +182,13 @@
       case FORCED:
       case FAST_FORWARD:
         return;
+      case IO_FAILURE:
+      case LOCK_FAILURE:
+      case NOT_ATTEMPTED:
+      case NO_CHANGE:
+      case REJECTED:
+      case REJECTED_CURRENT_BRANCH:
+      case RENAMED:
       default:
         throw new IOException(String.format(
             "Failed to create ref %s, RefUpdate.Result = %s", ref, result));
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/ResumeCopyProject.java b/src/main/java/com/googlesource/gerrit/plugins/importer/ResumeCopyProject.java
index e040133..731e077 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/importer/ResumeCopyProject.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/ResumeCopyProject.java
@@ -38,6 +38,7 @@
 import com.googlesource.gerrit.plugins.importer.ResumeCopyProject.Input;
 
 import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.errors.ConfigInvalidException;
 
 import java.io.IOException;
 import java.io.Writer;
@@ -80,7 +81,7 @@
   public ResumeImportStatistic apply(ProjectResource rsrc, Input input)
       throws RestApiException, IOException, OrmException, ValidationException,
       GitAPIException, NoSuchChangeException, NoSuchAccountException,
-      UpdateException {
+      UpdateException, ConfigInvalidException {
     ImportProjectResource projectResource =
         projectsCollection.parse(new ConfigResource(),
             IdString.fromDecoded(rsrc.getName()));
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/ResumeProjectImport.java b/src/main/java/com/googlesource/gerrit/plugins/importer/ResumeProjectImport.java
index b5793b5..a27ef44 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/importer/ResumeProjectImport.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/ResumeProjectImport.java
@@ -38,6 +38,7 @@
 import com.googlesource.gerrit.plugins.importer.ResumeProjectImport.Input;
 
 import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.errors.ConfigInvalidException;
 
 import java.io.IOException;
 import java.io.Writer;
@@ -94,7 +95,7 @@
   public ResumeImportStatistic apply(ImportProjectResource rsrc, Input input)
       throws RestApiException, IOException, OrmException, ValidationException,
       GitAPIException, NoSuchChangeException, NoSuchAccountException,
-      UpdateException {
+      UpdateException, ConfigInvalidException {
     if (copy) {
       input.validateResumeCopy();
     } else {
@@ -129,9 +130,9 @@
 
     @Override
     public ResumeImportStatistic apply(ProjectResource rsrc, Input input)
-        throws RestApiException, IOException, OrmException,
-        ValidationException, GitAPIException, NoSuchChangeException,
-        NoSuchAccountException, UpdateException {
+        throws RestApiException, IOException, OrmException, ValidationException,
+        GitAPIException, NoSuchChangeException, NoSuchAccountException,
+        UpdateException, ConfigInvalidException {
       ImportProjectResource projectResource =
           projectsCollection.parse(new ConfigResource(),
               IdString.fromDecoded(rsrc.getName()));
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/client/ResumeImportDialog.java b/src/main/java/com/googlesource/gerrit/plugins/importer/client/ResumeImportDialog.java
index c75b5eb..5b25ec4 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/importer/client/ResumeImportDialog.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/client/ResumeImportDialog.java
@@ -14,8 +14,8 @@
 
 package com.googlesource.gerrit.plugins.importer.client;
 
-import static com.googlesource.gerrit.plugins.importer.client.InputUtil.addPasswordTextBox;
 import static com.googlesource.gerrit.plugins.importer.client.InputUtil.addCheckBox;
+import static com.googlesource.gerrit.plugins.importer.client.InputUtil.addPasswordTextBox;
 import static com.googlesource.gerrit.plugins.importer.client.InputUtil.addTextBox;
 import static com.googlesource.gerrit.plugins.importer.client.InputUtil.getValue;
 
@@ -87,6 +87,7 @@
                 p.add(new Label("Updated Changes: " + result.numChangesUpdated()));
                 Button okButton = new Button("OK");
                 okButton.addClickHandler(new ClickHandler() {
+                  @Override
                   public void onClick(ClickEvent event) {
                     successDialog.hide();
                   }
diff --git a/src/main/resources/Documentation/about.md b/src/main/resources/Documentation/about.md
index 7a7526b..b7b867e 100644
--- a/src/main/resources/Documentation/about.md
+++ b/src/main/resources/Documentation/about.md
@@ -111,21 +111,21 @@
 
 Importing a project can be done via
 
-* [REST](rest-api-config.html#import-project)
-* [SSH](cmd-project.html) and
+* [REST](rest-api-config.md#import-project)
+* [SSH](cmd-project.md) and
 * UI from menu 'Projects' > 'Import Project'
 
 Resuming a project import can be done via
 
-* [REST](rest-api-config.html#resume-project-import)
-* [SSH](cmd-resume-project.html)
+* [REST](rest-api-config.md#resume-project-import)
+* [SSH](cmd-resume-project.md)
 * UI from the list imports screen (menu 'Projects' > 'List Imports') and
 * UI from the project info screen ('Resume Import...' action)
 
 Completing the import can be done via
 
-* [REST](rest-api-config.html#complete-project-import)
-* [SSH](cmd-complete-project.html)
+* [REST](rest-api-config.md#complete-project-import)
+* [SSH](cmd-complete-project.md)
 * UI from the list imports screen (menu 'Projects' > 'List Imports') and
 * UI from the project info screen ('Complete Import' action)
 
@@ -171,7 +171,7 @@
 import file
 'review\_site/data/@PLUGIN@/\<target-project-name\>.$importstatus' and
 locks this file. In the import file an
-[ImportProjectInfo](rest-api-config.html#import-project-info) entity is
+[ImportProjectInfo](rest-api-config.md#import-project-info) entity is
 persisted that stores the input parameters and records the past
 imports. The import file is kept after the import is done so that the
 input parameters do not need to be specified again when the import is
@@ -231,21 +231,21 @@
 
 Copying a project can be done via
 
-* [REST](rest-api-projects.html#copy-project)
-* [SSH](cmd-copy-project.html) and
+* [REST](rest-api-projects.md#copy-project)
+* [SSH](cmd-copy-project.md) and
 * UI from the project info screen ('Copy...' action)
 
 Resuming a project copy can be done via
 
-* [REST](rest-api-projects.html#resume-copy-import)
-* [SSH](cmd-resume-project.html)
+* [REST](rest-api-projects.md#resume-copy-import)
+* [SSH](cmd-resume-project.md)
 * UI from the list imports screen (menu 'Projects' > 'List Imports') and
 * UI from the project info screen ('Resume Copy...' action)
 
 Completing the copy can be done via
 
-* [REST](rest-api-config.html#complete-project-import)
-* [SSH](cmd-complete-project.html)
+* [REST](rest-api-config.md#complete-project-import)
+* [SSH](cmd-complete-project.md)
 * UI from the list imports screen (menu 'Projects' > 'List Imports') and
 * UI from the project info screen ('Complete Copy' action)
 
@@ -309,6 +309,6 @@
 
 Importing a group can be done via
 
-* [REST](rest-api-config.html#import-group)
-* [SSH](cmd-group.html) and
+* [REST](rest-api-config.md#import-group)
+* [SSH](cmd-group.md) and
 * UI from menu 'People' > 'Import Group'
diff --git a/src/main/resources/Documentation/rest-api-config.md b/src/main/resources/Documentation/rest-api-config.md
index 7173c6b..3af29b0 100644
--- a/src/main/resources/Documentation/rest-api-config.md
+++ b/src/main/resources/Documentation/rest-api-config.md
@@ -163,7 +163,7 @@
 ```
 
 ### <a id="resume-project-import"> Resume Project Import
-_GET /config/server/@PLUGIN@~projects/[\{project-name\}](../../../Documentation/rest-api-projects.html#project-name)/resume_
+_PUT /config/server/@PLUGIN@~projects/[\{project-name\}](../../../Documentation/rest-api-projects.html#project-name)/resume_
 
 Resumes a project import.
 
diff --git a/src/main/resources/Documentation/rest-api-projects.md b/src/main/resources/Documentation/rest-api-projects.md
index 2b8db28..6ac7a3c 100644
--- a/src/main/resources/Documentation/rest-api-projects.md
+++ b/src/main/resources/Documentation/rest-api-projects.md
@@ -33,7 +33,7 @@
   }
 ```
 
-As result a [ImportStatisticInfo](rest-api-config.html#import-statistic-info)
+As result a [ImportStatisticInfo](rest-api-config.md#import-statistic-info)
 entity is returned.
 
 #### Response
@@ -67,7 +67,7 @@
   PUT /projects/myProjectCopy/@PLUGIN@~copy.resume HTTP/1.0
 ```
 
-As result a [ResumeImportStatisticInfo](rest-api-config.html#resume-import-statistic-info)
+As result a [ResumeImportStatisticInfo](rest-api-config.md#resume-import-statistic-info)
 entity is returned.
 
 #### Response
@@ -90,7 +90,7 @@
 Resumes importing to a project from the original copy source.
 
 Information about the import resume must be provided in the request
-body as a [ImportResumeInput](rest-api-config.html#import-resume-input)
+body as a [ImportResumeInput](rest-api-config.md#import-resume-input)
 entity.
 
 Caller must be a member of a group that is granted the 'ImportProject'
@@ -109,7 +109,7 @@
   }
 ```
 
-As result a [ResumeImportStatisticInfo](rest-api-config.html#resume-import-statistic-info)
+As result a [ResumeImportStatisticInfo](rest-api-config.md#resume-import-statistic-info)
 entity is returned.
 
 #### Response