mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-10 07:25:44 +01:00
Fix initial mirror sync if empty (#1842)
Fixes an error, when the initial synchronization of a git mirror had no branches.
This commit is contained in:
2
gradle/changelog/initial_empty_mirror.yaml
Normal file
2
gradle/changelog/initial_empty_mirror.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
- type: fixed
|
||||
descripion: Initial mirror with no accepted branch ([#1842](https://github.com/scm-manager/scm-manager/pull/1842))
|
||||
@@ -198,12 +198,18 @@ public class GitMirrorCommand extends AbstractGitCommand implements MirrorComman
|
||||
if (fetchResult.getTrackingRefUpdates().isEmpty()) {
|
||||
LOG.trace("No updates found for mirror repository {}", repository);
|
||||
mirrorLog.add("No updates found");
|
||||
return new MirrorCommandResult(result, mirrorLog, stopwatch.stop().elapsed());
|
||||
} else {
|
||||
handleBranches();
|
||||
handleTags();
|
||||
}
|
||||
|
||||
defaultBranchSelector.newDefault().ifPresent(this::setNewDefaultBranch);
|
||||
if (!defaultBranchSelector.isChanged()) {
|
||||
mirrorLog.add("No effective changes detected");
|
||||
return new MirrorCommandResult(result, mirrorLog, stopwatch.stop().elapsed());
|
||||
}
|
||||
|
||||
defaultBranchSelector.newDefaultBranch().ifPresent(this::setNewDefaultBranch);
|
||||
|
||||
String[] pushRefSpecs = generatePushRefSpecs().toArray(new String[0]);
|
||||
push(pushRefSpecs);
|
||||
@@ -272,7 +278,7 @@ public class GitMirrorCommand extends AbstractGitCommand implements MirrorComman
|
||||
}
|
||||
|
||||
private void handleBranch(LoggerWithHeader logger, TrackingRefUpdate ref) {
|
||||
MirrorReferenceUpdateHandler refHandler = new MirrorReferenceUpdateHandler(logger, ref, "heads/", "branch");
|
||||
MirrorReferenceUpdateHandler refHandler = new MirrorReferenceUpdateHandler(logger, ref, RefType.BRANCH);
|
||||
refHandler.handleRef(ref1 -> refHandler.testFilterForBranch());
|
||||
}
|
||||
|
||||
@@ -282,28 +288,26 @@ public class GitMirrorCommand extends AbstractGitCommand implements MirrorComman
|
||||
}
|
||||
|
||||
private void handleTag(LoggerWithHeader logger, TrackingRefUpdate ref) {
|
||||
MirrorReferenceUpdateHandler refHandler = new MirrorReferenceUpdateHandler(logger, ref, "tags/", "tag");
|
||||
MirrorReferenceUpdateHandler refHandler = new MirrorReferenceUpdateHandler(logger, ref, RefType.TAG);
|
||||
refHandler.handleRef(ref1 -> refHandler.testFilterForTag());
|
||||
}
|
||||
|
||||
private class MirrorReferenceUpdateHandler {
|
||||
private final LoggerWithHeader logger;
|
||||
private final TrackingRefUpdate ref;
|
||||
private final String refType;
|
||||
private final String typeForLog;
|
||||
private final RefType refType;
|
||||
|
||||
public MirrorReferenceUpdateHandler(LoggerWithHeader logger, TrackingRefUpdate ref, String refType, String typeForLog) {
|
||||
public MirrorReferenceUpdateHandler(LoggerWithHeader logger, TrackingRefUpdate ref, RefType refType) {
|
||||
this.logger = logger;
|
||||
this.ref = ref;
|
||||
this.refType = refType;
|
||||
this.typeForLog = typeForLog;
|
||||
}
|
||||
|
||||
private void handleRef(Function<TrackingRefUpdate, Result> filter) {
|
||||
LOG.trace("Handling {}", ref.getLocalName());
|
||||
Result filterResult = filter.apply(ref);
|
||||
try {
|
||||
String referenceName = ref.getLocalName().substring("refs/".length() + refType.length());
|
||||
String referenceName = ref.getLocalName().substring("refs/".length() + refType.refPath.length());
|
||||
if (filterResult.isAccepted()) {
|
||||
LOG.trace("Accepted ref {}", ref.getLocalName());
|
||||
handleAcceptedReference(referenceName);
|
||||
@@ -332,7 +336,7 @@ public class GitMirrorCommand extends AbstractGitCommand implements MirrorComman
|
||||
|
||||
private void handleRejectedRef(String referenceName, Result filterResult) throws IOException {
|
||||
result = REJECTED_UPDATES;
|
||||
LOG.trace("{} ref rejected in {}: {}", typeForLog, GitMirrorCommand.this.repository, ref.getLocalName());
|
||||
LOG.trace("{} ref rejected in {}: {}", refType.typeForLog, GitMirrorCommand.this.repository, ref.getLocalName());
|
||||
if (ref.getResult() == NEW) {
|
||||
deleteReference(ref.getLocalName());
|
||||
} else {
|
||||
@@ -342,16 +346,16 @@ public class GitMirrorCommand extends AbstractGitCommand implements MirrorComman
|
||||
}
|
||||
|
||||
private void handleAcceptedReference(String referenceName) throws IOException {
|
||||
String targetRef = "refs/" + refType + referenceName;
|
||||
String targetRef = "refs/" + refType.refPath + referenceName;
|
||||
if (isDeletedReference(ref)) {
|
||||
LOG.trace("deleting {} ref in {}: {}", typeForLog, GitMirrorCommand.this.repository, targetRef);
|
||||
defaultBranchSelector.deleted(referenceName);
|
||||
LOG.trace("deleting {} ref in {}: {}", refType.typeForLog, GitMirrorCommand.this.repository, targetRef);
|
||||
defaultBranchSelector.deleted(refType, referenceName);
|
||||
logger.logChange(ref, referenceName, "deleted");
|
||||
deleteReference(targetRef);
|
||||
deletedRefs.add(targetRef);
|
||||
} else {
|
||||
LOG.trace("updating {} ref in {}: {}", typeForLog, GitMirrorCommand.this.repository, targetRef);
|
||||
defaultBranchSelector.accepted(referenceName);
|
||||
LOG.trace("updating {} ref in {}: {}", refType.typeForLog, GitMirrorCommand.this.repository, targetRef);
|
||||
defaultBranchSelector.accepted(refType, referenceName);
|
||||
logger.logChange(ref, referenceName, getUpdateType(ref));
|
||||
}
|
||||
}
|
||||
@@ -665,6 +669,8 @@ public class GitMirrorCommand extends AbstractGitCommand implements MirrorComman
|
||||
private final Set<String> remainingBranches;
|
||||
private final Set<String> newBranches = new HashSet<>();
|
||||
|
||||
private boolean changed = false;
|
||||
|
||||
DefaultBranchSelector(String initialDefaultBranch, Collection<String> initialBranches) {
|
||||
this.initialDefaultBranch = initialBranches.isEmpty() ? null : initialDefaultBranch;
|
||||
this.initialBranches = new HashSet<>(initialBranches);
|
||||
@@ -706,25 +712,50 @@ public class GitMirrorCommand extends AbstractGitCommand implements MirrorComman
|
||||
}
|
||||
}
|
||||
|
||||
public void accepted(String branch) {
|
||||
newBranches.add(branch);
|
||||
public void accepted(RefType refType, String ref) {
|
||||
changed = true;
|
||||
if (refType == RefType.BRANCH) {
|
||||
newBranches.add(ref);
|
||||
}
|
||||
}
|
||||
|
||||
public void deleted(String branch) {
|
||||
remainingBranches.remove(branch);
|
||||
public void deleted(RefType refType, String ref) {
|
||||
changed = true;
|
||||
if (refType == RefType.BRANCH) {
|
||||
remainingBranches.remove(ref);
|
||||
}
|
||||
}
|
||||
|
||||
public Optional<String> newDefault() {
|
||||
public boolean isChanged() {
|
||||
return changed;
|
||||
}
|
||||
|
||||
public Optional<String> newDefaultBranch() {
|
||||
if (initialDefaultBranch == null && newBranches.contains("master") || remainingBranches.contains(initialDefaultBranch)) {
|
||||
return empty();
|
||||
} else if (!newBranches.isEmpty() && initialBranches.isEmpty()) {
|
||||
return of(newBranches.iterator().next());
|
||||
} else if (initialDefaultBranch == null && newBranches.isEmpty()) {
|
||||
LOG.info("Could not mirror repository with tags only.");
|
||||
throw new IllegalStateException("No branch could be mirrored. Initial mirror without accepted branch is not supported. Make sure that at least one branch can be mirrored.");
|
||||
} else if (remainingBranches.isEmpty()) {
|
||||
LOG.warn("Could not compute new default branch.");
|
||||
LOG.info("Could not compute new default branch.");
|
||||
throw new IllegalStateException("Deleting all existing branches is not supported. Please restore branch '" + initialDefaultBranch + "' or recreate the mirror.");
|
||||
} else {
|
||||
return of(remainingBranches.iterator().next());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum RefType {
|
||||
BRANCH("heads/", "branch"), TAG("tags/", "tag");
|
||||
|
||||
private final String refPath;
|
||||
private final String typeForLog;
|
||||
|
||||
RefType(String refPath, String typeForLog) {
|
||||
this.refPath = refPath;
|
||||
this.typeForLog = typeForLog;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,6 +82,7 @@ import static org.mockito.Mockito.when;
|
||||
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;
|
||||
import static sonia.scm.repository.spi.GitMirrorCommand.RefType.BRANCH;
|
||||
|
||||
public class GitMirrorCommandTest extends AbstractGitCommandTestBase {
|
||||
|
||||
@@ -164,6 +165,58 @@ public class GitMirrorCommandTest extends AbstractGitCommandTestBase {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldAcceptEmptyInitialMirror() 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) {
|
||||
return Result.reject("nothing accepted");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result acceptTag(TagUpdate tag) {
|
||||
return Result.reject("nothing accepted");
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
assertThat(result.getResult()).isEqualTo(REJECTED_UPDATES);
|
||||
assertThat(result.getLog()).contains("Branches:")
|
||||
.contains("- 000000000..fcd0ef183 master (nothing accepted)")
|
||||
.contains("- 000000000..3f76a12f0 test-branch (nothing accepted)")
|
||||
.contains("Tags:")
|
||||
.contains("- 000000000..86a6645ec test-tag (nothing accepted)");
|
||||
|
||||
try (Git createdMirror = Git.open(clone)) {
|
||||
assertThat(createdMirror.branchList().call()).isEmpty();
|
||||
assertThat(createdMirror.tagList().call()).isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldAcceptOnlyTagInInitialMirror() {
|
||||
assertThrows(IllegalStateException.class, () ->
|
||||
callMirrorCommand(repositoryDirectory.getAbsolutePath(), c -> {
|
||||
c.setFilter(new MirrorFilter() {
|
||||
@Override
|
||||
public Filter getFilter(FilterContext context) {
|
||||
return new Filter() {
|
||||
@Override
|
||||
public Result acceptBranch(BranchUpdate branch) {
|
||||
return Result.reject("nothing accepted");
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFilterMasterBranchWhenFilteredOnInitialMirror() throws IOException, GitAPIException {
|
||||
MirrorCommandResult result = callMirrorCommand(repositoryDirectory.getAbsolutePath(), c -> {
|
||||
@@ -356,7 +409,8 @@ public class GitMirrorCommandTest extends AbstractGitCommandTestBase {
|
||||
assertThat(result.getResult()).isEqualTo(REJECTED_UPDATES);
|
||||
assertThat(result.getLog()).containsExactly(
|
||||
"Branches:",
|
||||
"- 000000000..fcd0ef183 added-branch (rejected due to filter)"
|
||||
"- 000000000..fcd0ef183 added-branch (rejected due to filter)",
|
||||
"No effective changes detected"
|
||||
);
|
||||
|
||||
try (Git updatedMirror = Git.open(clone)) {
|
||||
@@ -378,7 +432,8 @@ public class GitMirrorCommandTest extends AbstractGitCommandTestBase {
|
||||
assertThat(result.getResult()).isEqualTo(REJECTED_UPDATES);
|
||||
assertThat(result.getLog()).containsExactly(
|
||||
"Branches:",
|
||||
"- 3f76a12f0..9e93d8631 test-branch (rejected due to filter)"
|
||||
"- 3f76a12f0..9e93d8631 test-branch (rejected due to filter)",
|
||||
"No effective changes detected"
|
||||
);
|
||||
|
||||
try (Git updatedMirror = Git.open(clone)) {
|
||||
@@ -400,7 +455,8 @@ public class GitMirrorCommandTest extends AbstractGitCommandTestBase {
|
||||
assertThat(result.getResult()).isEqualTo(REJECTED_UPDATES);
|
||||
assertThat(result.getLog()).containsExactly(
|
||||
"Branches:",
|
||||
"- 3f76a12f0..000000000 test-branch (rejected due to filter)"
|
||||
"- 3f76a12f0..000000000 test-branch (rejected due to filter)",
|
||||
"No effective changes detected"
|
||||
);
|
||||
|
||||
try (Git updatedMirror = Git.open(clone)) {
|
||||
@@ -423,7 +479,8 @@ public class GitMirrorCommandTest extends AbstractGitCommandTestBase {
|
||||
assertThat(result.getResult()).isEqualTo(REJECTED_UPDATES);
|
||||
assertThat(result.getLog()).containsExactly(
|
||||
"Tags:",
|
||||
"- 000000000..9e93d8631 added-tag (rejected due to filter)"
|
||||
"- 000000000..9e93d8631 added-tag (rejected due to filter)",
|
||||
"No effective changes detected"
|
||||
);
|
||||
|
||||
try (Git updatedMirror = Git.open(clone)) {
|
||||
@@ -446,7 +503,8 @@ public class GitMirrorCommandTest extends AbstractGitCommandTestBase {
|
||||
assertThat(result.getResult()).isEqualTo(REJECTED_UPDATES);
|
||||
assertThat(result.getLog()).containsExactly(
|
||||
"Tags:",
|
||||
"- 86a6645ec..9e93d8631 test-tag (rejected due to filter)"
|
||||
"- 86a6645ec..9e93d8631 test-tag (rejected due to filter)",
|
||||
"No effective changes detected"
|
||||
);
|
||||
|
||||
try (Git updatedMirror = Git.open(clone)) {
|
||||
@@ -468,7 +526,8 @@ public class GitMirrorCommandTest extends AbstractGitCommandTestBase {
|
||||
assertThat(result.getResult()).isEqualTo(REJECTED_UPDATES);
|
||||
assertThat(result.getLog()).containsExactly(
|
||||
"Tags:",
|
||||
"- 86a6645ec..000000000 test-tag (rejected due to filter)"
|
||||
"- 86a6645ec..000000000 test-tag (rejected due to filter)",
|
||||
"No effective changes detected"
|
||||
);
|
||||
|
||||
try (Git updatedMirror = Git.open(clone)) {
|
||||
@@ -490,7 +549,8 @@ public class GitMirrorCommandTest extends AbstractGitCommandTestBase {
|
||||
assertThat(result.getResult()).isEqualTo(REJECTED_UPDATES);
|
||||
assertThat(result.getLog()).containsExactly(
|
||||
"Tags:",
|
||||
"- 86a6645ec..000000000 test-tag (thou shalt not pass)"
|
||||
"- 86a6645ec..000000000 test-tag (thou shalt not pass)",
|
||||
"No effective changes detected"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -508,7 +568,8 @@ public class GitMirrorCommandTest extends AbstractGitCommandTestBase {
|
||||
assertThat(result.getLog()).containsExactly(
|
||||
"! got error checking filter for update: this tag creates an exception",
|
||||
"Tags:",
|
||||
"- 86a6645ec..000000000 test-tag (exception in filter)"
|
||||
"- 86a6645ec..000000000 test-tag (exception in filter)",
|
||||
"No effective changes detected"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -777,10 +838,10 @@ public class GitMirrorCommandTest extends AbstractGitCommandTestBase {
|
||||
GitMirrorCommand.DefaultBranchSelector selector =
|
||||
new GitMirrorCommand.DefaultBranchSelector("master", emptyList());
|
||||
|
||||
selector.accepted("master");
|
||||
selector.accepted("something");
|
||||
selector.accepted(BRANCH, "master");
|
||||
selector.accepted(BRANCH, "something");
|
||||
|
||||
assertThat(selector.newDefault()).isEmpty();
|
||||
assertThat(selector.newDefaultBranch()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -788,10 +849,10 @@ public class GitMirrorCommandTest extends AbstractGitCommandTestBase {
|
||||
GitMirrorCommand.DefaultBranchSelector selector =
|
||||
new GitMirrorCommand.DefaultBranchSelector("master", BRANCHES);
|
||||
|
||||
selector.accepted("new");
|
||||
selector.deleted("two");
|
||||
selector.accepted(BRANCH, "new");
|
||||
selector.deleted(BRANCH, "two");
|
||||
|
||||
assertThat(selector.newDefault()).isEmpty();
|
||||
assertThat(selector.newDefaultBranch()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -799,9 +860,9 @@ public class GitMirrorCommandTest extends AbstractGitCommandTestBase {
|
||||
GitMirrorCommand.DefaultBranchSelector selector =
|
||||
new GitMirrorCommand.DefaultBranchSelector("master", BRANCHES);
|
||||
|
||||
selector.deleted("master");
|
||||
selector.deleted(BRANCH, "master");
|
||||
|
||||
assertThat(selector.newDefault()).get().isIn("one", "two", "three");
|
||||
assertThat(selector.newDefaultBranch()).get().isIn("one", "two", "three");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -809,11 +870,11 @@ public class GitMirrorCommandTest extends AbstractGitCommandTestBase {
|
||||
GitMirrorCommand.DefaultBranchSelector selector =
|
||||
new GitMirrorCommand.DefaultBranchSelector("master", BRANCHES);
|
||||
|
||||
selector.deleted("master");
|
||||
selector.deleted("one");
|
||||
selector.deleted("three");
|
||||
selector.deleted(BRANCH, "master");
|
||||
selector.deleted(BRANCH, "one");
|
||||
selector.deleted(BRANCH, "three");
|
||||
|
||||
assertThat(selector.newDefault()).get().isEqualTo("two");
|
||||
assertThat(selector.newDefaultBranch()).get().isEqualTo("two");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -821,11 +882,11 @@ public class GitMirrorCommandTest extends AbstractGitCommandTestBase {
|
||||
GitMirrorCommand.DefaultBranchSelector selector =
|
||||
new GitMirrorCommand.DefaultBranchSelector("master", BRANCHES);
|
||||
|
||||
selector.deleted("master");
|
||||
selector.deleted("one");
|
||||
selector.deleted("three");
|
||||
selector.deleted(BRANCH, "master");
|
||||
selector.deleted(BRANCH, "one");
|
||||
selector.deleted(BRANCH, "three");
|
||||
|
||||
assertThat(selector.newDefault()).get().isEqualTo("two");
|
||||
assertThat(selector.newDefaultBranch()).get().isEqualTo("two");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -833,13 +894,13 @@ public class GitMirrorCommandTest extends AbstractGitCommandTestBase {
|
||||
GitMirrorCommand.DefaultBranchSelector selector =
|
||||
new GitMirrorCommand.DefaultBranchSelector("master", BRANCHES);
|
||||
|
||||
selector.deleted("master");
|
||||
selector.deleted("one");
|
||||
selector.deleted("two");
|
||||
selector.accepted("new");
|
||||
selector.deleted("three");
|
||||
selector.deleted(BRANCH, "master");
|
||||
selector.deleted(BRANCH, "one");
|
||||
selector.deleted(BRANCH, "two");
|
||||
selector.accepted(BRANCH, "new");
|
||||
selector.deleted(BRANCH, "three");
|
||||
|
||||
assertThrows(IllegalStateException.class, selector::newDefault);
|
||||
assertThrows(IllegalStateException.class, selector::newDefaultBranch);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -847,10 +908,10 @@ public class GitMirrorCommandTest extends AbstractGitCommandTestBase {
|
||||
GitMirrorCommand.DefaultBranchSelector selector =
|
||||
new GitMirrorCommand.DefaultBranchSelector("master", emptyList());
|
||||
|
||||
selector.accepted("main");
|
||||
selector.deleted("master");
|
||||
selector.accepted(BRANCH, "main");
|
||||
selector.deleted(BRANCH, "master");
|
||||
|
||||
assertThat(selector.newDefault()).get().isEqualTo("main");
|
||||
assertThat(selector.newDefaultBranch()).get().isEqualTo("main");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -858,9 +919,9 @@ public class GitMirrorCommandTest extends AbstractGitCommandTestBase {
|
||||
GitMirrorCommand.DefaultBranchSelector selector =
|
||||
new GitMirrorCommand.DefaultBranchSelector("master", emptyList());
|
||||
|
||||
selector.accepted("main");
|
||||
selector.accepted(BRANCH, "main");
|
||||
|
||||
assertThat(selector.newDefault()).get().isEqualTo("main");
|
||||
assertThat(selector.newDefaultBranch()).get().isEqualTo("main");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user