Merge "Allow replication of refs that point to non-commit objects" into stable-3.3
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/PullReplicationApiModule.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/PullReplicationApiModule.java
index 8dc0f0f..e7b3a7f 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/PullReplicationApiModule.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/PullReplicationApiModule.java
@@ -28,9 +28,11 @@
     bind(FetchAction.class).in(Scopes.SINGLETON);
     bind(ApplyObjectAction.class).in(Scopes.SINGLETON);
     bind(ProjectDeletionAction.class).in(Scopes.SINGLETON);
+    bind(UpdateHeadAction.class).in(Scopes.SINGLETON);
     post(PROJECT_KIND, "fetch").to(FetchAction.class);
     post(PROJECT_KIND, "apply-object").to(ApplyObjectAction.class);
     delete(PROJECT_KIND, "delete-project").to(ProjectDeletionAction.class);
+    put(PROJECT_KIND, "HEAD").to(UpdateHeadAction.class);
 
     bind(FetchPreconditions.class).in(Scopes.SINGLETON);
     bind(CapabilityDefinition.class)
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/UpdateHeadAction.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/UpdateHeadAction.java
index 4195435..ae9c072 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/UpdateHeadAction.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/UpdateHeadAction.java
@@ -14,66 +14,28 @@
 
 package com.googlesource.gerrit.plugins.replication.pull.api;
 
-import com.google.common.base.Strings;
-import com.google.gerrit.entities.RefNames;
 import com.google.gerrit.extensions.api.projects.HeadInput;
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.BadRequestException;
 import com.google.gerrit.extensions.restapi.ResourceConflictException;
-import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
 import com.google.gerrit.extensions.restapi.Response;
 import com.google.gerrit.extensions.restapi.RestModifyView;
-import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
-import com.google.gerrit.server.permissions.PermissionBackend;
-import com.google.gerrit.server.permissions.RefPermission;
 import com.google.gerrit.server.project.ProjectResource;
+import com.google.gerrit.server.restapi.project.SetHead;
 import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import com.googlesource.gerrit.plugins.replication.LocalFS;
-import com.googlesource.gerrit.plugins.replication.pull.GerritConfigOps;
-import java.util.Optional;
-import org.eclipse.jgit.transport.URIish;
 
-@Singleton
 public class UpdateHeadAction implements RestModifyView<ProjectResource, HeadInput> {
-  private final GerritConfigOps gerritConfigOps;
-  private final PermissionBackend permissionBackend;
+
+  private final SetHead setHead;
 
   @Inject
-  UpdateHeadAction(GerritConfigOps gerritConfigOps, PermissionBackend permissionBackend) {
-    this.gerritConfigOps = gerritConfigOps;
-    this.permissionBackend = permissionBackend;
+  public UpdateHeadAction(SetHead setHead) {
+    this.setHead = setHead;
   }
 
   @Override
-  public Response<?> apply(ProjectResource projectResource, HeadInput input)
+  public Response<?> apply(ProjectResource resource, HeadInput input)
       throws AuthException, BadRequestException, ResourceConflictException, Exception {
-    if (input == null || Strings.isNullOrEmpty(input.ref)) {
-      throw new BadRequestException("ref required");
-    }
-    String ref = RefNames.fullName(input.ref);
-
-    permissionBackend
-        .user(projectResource.getUser())
-        .project(projectResource.getNameKey())
-        .ref(ref)
-        .check(RefPermission.SET_HEAD);
-
-    // TODO: the .git suffix should not be added here, but rather it should be
-    //  dealt with by the caller, honouring the naming style from the
-    //  replication.config (Issue 15221)
-    Optional<URIish> maybeRepo =
-        gerritConfigOps.getGitRepositoryURI(String.format("%s.git", projectResource.getName()));
-
-    if (maybeRepo.isPresent()) {
-      if (new LocalFS(maybeRepo.get()).updateHead(projectResource.getNameKey(), ref)) {
-        return Response.ok(ref);
-      }
-      throw new UnprocessableEntityException(
-          String.format(
-              "Could not update HEAD of repo %s to ref %s", projectResource.getName(), ref));
-    }
-    throw new ResourceNotFoundException(
-        String.format("Could not compute URL for repo: %s", projectResource.getName()));
+    return setHead.apply(resource, input);
   }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/client/FetchRestApiClient.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/client/FetchRestApiClient.java
index a7e71af..a916a7c 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/client/FetchRestApiClient.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/client/FetchRestApiClient.java
@@ -194,6 +194,6 @@
   }
 
   String getProjectUpdateHeadUrl(String projectName) {
-    return String.format("a/projects/%s/HEAD", Url.encode(projectName));
+    return String.format("a/projects/%s/%s~HEAD", Url.encode(projectName), pluginName);
   }
 }
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/client/FetchRestApiClientTest.java b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/client/FetchRestApiClientTest.java
index 17df2df..a778049 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/client/FetchRestApiClientTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/client/FetchRestApiClientTest.java
@@ -395,7 +395,7 @@
 
     assertThat(httpPut.getURI().getHost()).isEqualTo("gerrit-host");
     assertThat(httpPut.getURI().getPath())
-        .isEqualTo(String.format("/a/projects/%s/HEAD", projectName));
+        .isEqualTo(String.format("/a/projects/%s/pull-replication~HEAD", projectName));
     assertThat(payload).isEqualTo(String.format("{\"ref\": \"%s\"}", newHead));
   }