mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-09 23:15:43 +01:00
Filter master branch correctly on initial mirror (#1747)
On the first synchronization, the clone has the implicit branch "master". This cannot be changed in JGit. When we fetch the refs from the repository that should be mirrored, the master branch of the clone will be updated to the revision of the remote repository (if it has a master branch). If now the master branch shall be filtered from mirroring (ie. if it is rejected), we normally would delete the ref in this clone. But because it is the current branch, it cannot be deleted. We detect this and later, after we have pushed the result, delete the master branch by pushing an empty ref to the central repository.
This commit is contained in:
2
gradle/changelog/master_on_initial_mirror.yaml
Normal file
2
gradle/changelog/master_on_initial_mirror.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
- type: fixed
|
||||
description: Handle rejected master branch on initial mirror synchronization correctly ([#1747](https://github.com/scm-manager/scm-manager/pull/1747))
|
||||
@@ -74,6 +74,7 @@ import static java.util.Collections.unmodifiableMap;
|
||||
import static java.util.Optional.empty;
|
||||
import static java.util.Optional.of;
|
||||
import static org.eclipse.jgit.lib.RefUpdate.Result.NEW;
|
||||
import static org.eclipse.jgit.lib.RefUpdate.Result.REJECTED_CURRENT_BRANCH;
|
||||
import static sonia.scm.repository.api.MirrorCommandResult.ResultType.FAILED;
|
||||
import static sonia.scm.repository.api.MirrorCommandResult.ResultType.OK;
|
||||
import static sonia.scm.repository.api.MirrorCommandResult.ResultType.REJECTED_UPDATES;
|
||||
@@ -135,6 +136,18 @@ public class GitMirrorCommand extends AbstractGitCommand implements MirrorComman
|
||||
|
||||
private ResultType result = OK;
|
||||
|
||||
/**
|
||||
* On the first synchronization, the clone has the implicit branch "master". This cannot be
|
||||
* changed in JGit. When we fetch the refs from the repository that should be mirrored, the
|
||||
* master branch of the clone will be updated to the revision of the remote repository (if
|
||||
* it has a master branch). If now the master branch shall be filtered from mirroring (ie.
|
||||
* if it is rejected), we normally would delete the ref in this clone. But because it is
|
||||
* the current branch, it cannot be deleted. We detect this, set this variable to
|
||||
* {@code true}, and later, after we have pushed the result, delete the master branch by
|
||||
* pushing an empty ref to the central repository.
|
||||
*/
|
||||
private boolean deleteMasterAfterInitialSync = false;
|
||||
|
||||
private Worker(GitContext context, MirrorCommandRequest mirrorCommandRequest, sonia.scm.repository.Repository repository, Git git) {
|
||||
super(git, context, repository);
|
||||
this.mirrorCommandRequest = mirrorCommandRequest;
|
||||
@@ -167,9 +180,16 @@ public class GitMirrorCommand extends AbstractGitCommand implements MirrorComman
|
||||
}
|
||||
|
||||
push(generatePushRefSpecs().toArray(new String[0]));
|
||||
cleanUpMasterIfNecessary();
|
||||
return new MirrorCommandResult(result, mirrorLog, stopwatch.stop().elapsed());
|
||||
}
|
||||
|
||||
private void cleanUpMasterIfNecessary() {
|
||||
if (deleteMasterAfterInitialSync) {
|
||||
push(":refs/heads/master");
|
||||
}
|
||||
}
|
||||
|
||||
private Collection<String> generatePushRefSpecs() {
|
||||
Collection<String> refSpecs = new ArrayList<>();
|
||||
refSpecs.add("refs/heads/*:refs/heads/*");
|
||||
@@ -302,7 +322,10 @@ public class GitMirrorCommand extends AbstractGitCommand implements MirrorComman
|
||||
private void deleteReference(String targetRef) throws IOException {
|
||||
RefUpdate deleteUpdate = git.getRepository().getRefDatabase().newUpdate(targetRef, true);
|
||||
deleteUpdate.setForceUpdate(true);
|
||||
deleteUpdate.delete();
|
||||
RefUpdate.Result deleteResult = deleteUpdate.delete();
|
||||
if (deleteResult == REJECTED_CURRENT_BRANCH) {
|
||||
deleteMasterAfterInitialSync = true;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isDeletedReference(TrackingRefUpdate ref) {
|
||||
|
||||
@@ -112,6 +112,36 @@ public class GitMirrorCommandTest extends AbstractGitCommandTestBase {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFilterMasterBranchWhenFilteredOnInitialMirror() throws IOException, GitAPIException {
|
||||
MirrorCommandResult result = callMirrorCommand(repositoryDirectory.getAbsolutePath(), c -> {
|
||||
c.setFilter(new MirrorFilter() {
|
||||
@Override
|
||||
public Filter getFilter(FilterContext context) {
|
||||
return new Filter() {
|
||||
@Override
|
||||
public Result acceptBranch(BranchUpdate branch) {
|
||||
if (branch.getBranchName().equals("master")) {
|
||||
return Result.reject("master not accepted");
|
||||
} else {
|
||||
return Result.accept();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
assertThat(result.getResult()).isEqualTo(REJECTED_UPDATES);
|
||||
assertThat(result.getLog())
|
||||
.contains("- 000000000..fcd0ef183 master (master not accepted)");
|
||||
|
||||
try (Git createdMirror = Git.open(clone)) {
|
||||
assertThat(createdMirror.branchList().call().stream().filter(r -> r.getName().contains("master")).findAny())
|
||||
.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCreateEmptyLogWhenNoChangesFound() {
|
||||
callMirrorCommand();
|
||||
|
||||
Reference in New Issue
Block a user