Consider the headName value when creating a new repository
The creation of a new repository is notified through the
ProjectCreatedEvent but the headName was ignored, causing the new
project to be always created with a default head.
Use the headName in the ProjectCreatedEvent and use it for creating the
new empty repository.
Also consider the 'headName' parameter when the creation happens via
REST-API, even though the client-side of the replication via HTTP isn't
implemented yet in this change and will be expanded in a follow-up
change.
Bug: Issue 430486435
Change-Id: I2a37b01e55c1acbc5e51bde365dd84c9943c9b31
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/ReplicationQueue.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/ReplicationQueue.java
index b94189e..e21aaf3 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/ReplicationQueue.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/ReplicationQueue.java
@@ -750,10 +750,10 @@
private Optional<HttpResult> initProject(
Project.NameKey project, URIish uri, FetchApiClient fetchClient, Optional<HttpResult> result)
- throws IOException {
+ throws IOException, URISyntaxException {
+ RevisionReader revisionReader = revReaderProvider.get();
RevisionData refsMetaConfigRevisionData =
- revReaderProvider
- .get()
+ revisionReader
.read(project, null, RefNames.REFS_CONFIG, 0)
.orElseThrow(
() ->
@@ -764,7 +764,12 @@
List<RevisionData> refsMetaConfigDataList =
fetchWholeMetaHistory(project, RefNames.REFS_CONFIG, refsMetaConfigRevisionData);
HttpResult initProjectResult =
- fetchClient.initProject(project, uri, System.currentTimeMillis(), refsMetaConfigDataList);
+ fetchClient.initProject(
+ project,
+ revisionReader.getHeadName(project),
+ uri,
+ System.currentTimeMillis(),
+ refsMetaConfigDataList);
if (initProjectResult.isSuccessful()) {
result = Optional.of(fetchClient.callFetch(project, FetchOne.ALL_REFS, uri));
} else {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/RevisionReader.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/RevisionReader.java
index 9458083..68fa98a 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/RevisionReader.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/RevisionReader.java
@@ -19,6 +19,7 @@
import com.google.common.collect.Lists;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.Project;
+import com.google.gerrit.entities.RefNames;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.inject.Inject;
import com.googlesource.gerrit.plugins.replication.api.ReplicationConfig;
@@ -319,4 +320,15 @@
return "type:" + type;
}
}
+
+ @Nullable
+ public String getHeadName(Project.NameKey project) throws IOException {
+ try (Repository repo = gitRepositoryManager.openRepository(project)) {
+ Ref ref = repo.exactRef(RefNames.HEAD);
+ if (ref == null) {
+ return null;
+ }
+ return ref.getTarget().getName();
+ }
+ }
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/ProjectInitializationAction.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/ProjectInitializationAction.java
index 3214787..c7e8a8c 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/ProjectInitializationAction.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/ProjectInitializationAction.java
@@ -22,6 +22,7 @@
import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
+import com.google.common.base.MoreObjects;
import com.google.common.base.Strings;
import com.google.common.flogger.FluentLogger;
import com.google.common.net.MediaType;
@@ -103,15 +104,17 @@
}
String gitRepositoryName = getGitRepositoryName(httpServletRequest);
+ String headName = getGitRepositoryHeadName(httpServletRequest);
try {
boolean initProjectStatus;
String contentType = httpServletRequest.getContentType();
if (checkContentType(contentType, MediaType.JSON_UTF_8)) {
// init project request includes project configuration in JSON format.
- initProjectStatus = initProjectWithConfiguration(httpServletRequest, gitRepositoryName);
+ initProjectStatus =
+ initProjectWithConfiguration(httpServletRequest, gitRepositoryName, headName);
} else if (checkContentType(contentType, MediaType.PLAIN_TEXT_UTF_8)) {
// init project request does not include project configuration.
- initProjectStatus = initProject(gitRepositoryName);
+ initProjectStatus = initProject(gitRepositoryName, RefNames.HEAD);
} else {
setResponse(
httpServletResponse,
@@ -146,17 +149,17 @@
}
}
- public boolean initProject(String gitRepositoryName)
+ public boolean initProject(String gitRepositoryName, String headName)
throws AuthException, PermissionBackendException, IOException {
- if (initProject(gitRepositoryName, true)) {
- repLog.info("Init project API from {}", gitRepositoryName);
+ if (initProject(gitRepositoryName, headName, true)) {
+ repLog.info("Init project {} with head {}", gitRepositoryName, headName);
return true;
}
return false;
}
private boolean initProjectWithConfiguration(
- HttpServletRequest httpServletRequest, String gitRepositoryName)
+ HttpServletRequest httpServletRequest, String gitRepositoryName, String headName)
throws AuthException,
PermissionBackendException,
IOException,
@@ -167,7 +170,7 @@
RevisionsInput input = PayloadSerDes.parseRevisionsInput(httpServletRequest);
validateInput(input);
- if (!initProject(gitRepositoryName, false)) {
+ if (!initProject(gitRepositoryName, headName, false)) {
return false;
}
@@ -206,7 +209,8 @@
return true;
}
- private boolean initProject(String gitRepositoryName, boolean needsProjectReindexing)
+ private boolean initProject(
+ String gitRepositoryName, String headName, boolean needsProjectReindexing)
throws AuthException, PermissionBackendException, IOException {
// When triggered internally(for example by consuming stream events) user is not provided
// and internal user is returned. Project creation should be always allowed for internal user.
@@ -220,7 +224,7 @@
}
LocalFS localFS = new LocalFS(maybeUri.get());
Project.NameKey projectNameKey = Project.NameKey.parse(gitRepositoryName);
- if (localFS.createProject(projectNameKey, RefNames.HEAD)) {
+ if (localFS.createProject(projectNameKey, headName)) {
if (needsProjectReindexing) {
projectCache.onCreateProject(projectNameKey);
}
@@ -247,6 +251,11 @@
return Url.decode(path.substring(path.lastIndexOf('/') + 1));
}
+ private String getGitRepositoryHeadName(HttpServletRequest httpServletRequest) {
+ String headName = httpServletRequest.getParameter("headName");
+ return MoreObjects.firstNonNull(headName, RefNames.HEAD);
+ }
+
private void logExceptionAndUpdateResponse(
HttpServletResponse httpServletResponse,
Exception e,
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/client/FetchApiClient.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/client/FetchApiClient.java
index b908435..67651ff 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/client/FetchApiClient.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/client/FetchApiClient.java
@@ -16,6 +16,7 @@
import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.Project;
import com.google.gerrit.entities.Project.NameKey;
import com.googlesource.gerrit.plugins.replication.pull.Source;
@@ -23,6 +24,7 @@
import com.googlesource.gerrit.plugins.replication.pull.api.data.BatchApplyObjectData;
import com.googlesource.gerrit.plugins.replication.pull.api.data.RevisionData;
import java.io.IOException;
+import java.net.URISyntaxException;
import java.util.List;
import org.eclipse.jgit.transport.URIish;
@@ -68,10 +70,11 @@
*/
HttpResult initProject(
Project.NameKey project,
+ @Nullable String headName,
URIish uri,
long eventCreatedOn,
List<RevisionData> refsMetaConfigRevisionData)
- throws IOException;
+ throws IOException, URISyntaxException;
HttpResult deleteProject(Project.NameKey project, URIish apiUri) throws IOException;
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 c3bb378..ec33a64 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
@@ -44,6 +44,8 @@
import com.googlesource.gerrit.plugins.replication.pull.api.data.RevisionsInput;
import com.googlesource.gerrit.plugins.replication.pull.filter.SyncRefsFilter;
import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Optional;
@@ -59,6 +61,7 @@
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;
+import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.message.BasicHeader;
@@ -190,11 +193,12 @@
@Override
public HttpResult initProject(
NameKey project,
+ @Nullable String headName,
URIish uri,
long eventCreatedOn,
List<RevisionData> refsMetaConfigRevisionData)
- throws IOException {
- String url = formatInitProjectUrl(uri.toString(), project);
+ throws IOException, URISyntaxException {
+ URI url = formatInitProjectUrl(uri.toString(), project, headName);
RevisionData[] inputData = new RevisionData[refsMetaConfigRevisionData.size()];
RevisionsInput input =
@@ -321,10 +325,18 @@
targetUri, urlAuthenticationPrefix, Url.encode(project.get()), pluginName, api);
}
- private String formatInitProjectUrl(String targetUri, Project.NameKey project) {
- return String.format(
- "%s/%splugins/%s/init-project/%s.git",
- targetUri, urlAuthenticationPrefix, pluginName, Url.encode(project.get()));
+ private URI formatInitProjectUrl(
+ String targetUri, Project.NameKey project, @Nullable String headName)
+ throws URISyntaxException {
+ String baseUrl =
+ String.format(
+ "%s/%splugins/%s/init-project/%s.git",
+ targetUri, urlAuthenticationPrefix, pluginName, Url.encode(project.get()));
+ URIBuilder baseUriBuilder = new URIBuilder(baseUrl);
+ if (headName != null) {
+ baseUriBuilder = baseUriBuilder.addParameter("headName", headName);
+ }
+ return baseUriBuilder.build();
}
private void requireNull(Object object, String string) {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/event/StreamEventListener.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/event/StreamEventListener.java
index eb2d7e0..d8cf100 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/event/StreamEventListener.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/event/StreamEventListener.java
@@ -164,7 +164,8 @@
} else if (event instanceof ProjectCreatedEvent) {
ProjectCreatedEvent projectCreatedEvent = (ProjectCreatedEvent) event;
try {
- projectInitializationAction.initProject(getProjectRepositoryName(projectCreatedEvent));
+ projectInitializationAction.initProject(
+ getProjectRepositoryName(projectCreatedEvent), projectCreatedEvent.headName);
fetchRefsAsync(
FetchOne.ALL_REFS,
projectCreatedEvent.instanceId,
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationITBase.java b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationITBase.java
index a6058d3..a73a97e 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationITBase.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationITBase.java
@@ -376,6 +376,7 @@
FetchApiClient client = getInstance(FetchApiClient.Factory.class).create(source);
client.initProject(
projectToCreate,
+ null,
new URIish(source.getApis().get(0)),
System.currentTimeMillis(),
Collections.emptyList());
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/ReplicationQueueTest.java b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/ReplicationQueueTest.java
index 7f4ca4e..88a7ba1 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/ReplicationQueueTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/ReplicationQueueTest.java
@@ -182,7 +182,7 @@
when(fetchRestApiClient.callFetch(any(), anyString(), any(), anyLong(), anyBoolean()))
.thenReturn(fetchHttpResult);
when(fetchRestApiClient.callBatchFetch(any(), any(), any())).thenReturn(batchFetchHttpResult);
- when(fetchRestApiClient.initProject(any(), any(), anyLong(), any()))
+ when(fetchRestApiClient.initProject(any(), any(), any(), anyLong(), any()))
.thenReturn(successfulHttpResult);
when(successfulHttpResult.isSuccessful()).thenReturn(true);
when(httpResult.isSuccessful()).thenReturn(true);
@@ -273,7 +273,7 @@
objectUnderTest.start();
objectUnderTest.onEvent(event);
- verify(fetchRestApiClient).initProject(any(), any(), anyLong(), any());
+ verify(fetchRestApiClient).initProject(any(), any(), any(), anyLong(), any());
}
@Test
@@ -299,7 +299,7 @@
objectUnderTest.start();
objectUnderTest.onEvent(event);
- verify(fetchRestApiClient, never()).initProject(any(), any(), anyLong(), any());
+ verify(fetchRestApiClient, never()).initProject(any(), any(), any(), anyLong(), any());
}
@Test
@@ -316,7 +316,7 @@
objectUnderTest.start();
objectUnderTest.onEvent(event);
- verify(fetchRestApiClient, never()).initProject(any(), any(), anyLong(), any());
+ verify(fetchRestApiClient, never()).initProject(any(), any(), any(), anyLong(), any());
}
@Test
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/client/FetchRestApiClientBase.java b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/client/FetchRestApiClientBase.java
index cfff177..4c756f6 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/client/FetchRestApiClientBase.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/client/FetchRestApiClientBase.java
@@ -557,8 +557,10 @@
@Test
public void shouldCallInitProjectEndpoint() throws Exception {
+ String headName = RefNames.REFS_HEADS + "main";
objectUnderTest.initProject(
Project.nameKey("test_repo"),
+ headName,
new URIish(api),
eventCreatedOn,
Collections.singletonList(createSampleRevisionData()));
@@ -576,6 +578,7 @@
String.format(
"%s/plugins/pull-replication/init-project/test_repo.git",
urlAuthenticationPrefix()));
+ assertThat(httpPut.getURI().getQuery()).isEqualTo("headName=" + headName);
assertThat(payload).isEqualTo(expectedInitProjectWithConfigPayload);
assertAuthentication(httpPut);
}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/event/StreamEventListenerTest.java b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/event/StreamEventListenerTest.java
index 980c509..dd6b110 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/event/StreamEventListenerTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/event/StreamEventListenerTest.java
@@ -25,6 +25,7 @@
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.Lists;
import com.google.gerrit.entities.Project;
+import com.google.gerrit.entities.RefNames;
import com.google.gerrit.server.data.RefUpdateAttribute;
import com.google.gerrit.server.events.Event;
import com.google.gerrit.server.events.ProjectCreatedEvent;
@@ -208,10 +209,12 @@
ProjectCreatedEvent event = new ProjectCreatedEvent();
event.instanceId = REMOTE_INSTANCE_ID;
event.projectName = TEST_PROJECT;
+ event.headName = RefNames.HEAD;
objectUnderTest.onEvent(event);
- verify(projectInitializationAction).initProject(String.format("%s.git", TEST_PROJECT));
+ verify(projectInitializationAction)
+ .initProject(String.format("%s.git", TEST_PROJECT), RefNames.HEAD);
}
@Test
@@ -221,10 +224,11 @@
ProjectCreatedEvent event = new ProjectCreatedEvent();
event.instanceId = REMOTE_INSTANCE_ID;
event.projectName = TEST_PROJECT;
+ event.headName = RefNames.HEAD;
objectUnderTest.onEvent(event);
- verify(projectInitializationAction, never()).initProject(any());
+ verify(projectInitializationAction, never()).initProject(any(), eq(RefNames.HEAD));
}
@Test
@@ -234,10 +238,11 @@
ProjectCreatedEvent event = new ProjectCreatedEvent();
event.instanceId = REMOTE_INSTANCE_ID;
event.projectName = TEST_PROJECT;
+ event.headName = RefNames.HEAD;
objectUnderTest.onEvent(event);
- verify(projectInitializationAction, never()).initProject(any());
+ verify(projectInitializationAction, never()).initProject(any(), eq(RefNames.HEAD));
}
@Test