Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

391: Abort merge if source branch merge isn't fast-forward #622

wants to merge 1 commit into from
Changes from all commits
File filter
Filter file types
Failed to load comments.
Jump to
Jump to file
Failed to load files.


Just for now

@@ -478,6 +478,9 @@ public void run(Path scratchPath) {
new IllegalStateException("Could not get remote branch name for " +
repo.merge(remoteBranch); // should always be a fast-forward merge
if (!repo.isClean()) {
throw new RuntimeException("Local repository isn't clean after fast-forward merge - has the fork diverged unexpectedly?");
}"Trying to merge " + + ":" + + " to " +;"Fetching " + + ":" +;
@@ -22,23 +22,19 @@
package org.openjdk.skara.bots.merge;

import org.junit.jupiter.api.*;
import org.openjdk.skara.issuetracker.Issue;
import org.openjdk.skara.test.*;
import org.openjdk.skara.vcs.*;
import org.openjdk.skara.issuetracker.Issue;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;

import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.time.*;
import java.util.*;
import java.time.DayOfWeek;
import java.time.Month;
import java.time.ZonedDateTime;
import java.time.ZoneId;

import static org.junit.jupiter.api.Assertions.*;

@@ -1289,4 +1285,78 @@ void testMergeYearly(TestInfo testInfo) throws IOException {
assertEquals(6, toCommits.size());

void mergeAfterDivergedStorage(TestInfo testInfo) throws IOException {
try (var temp = new TemporaryDirectory()) {
var host = TestHost.createNew(List.of(new HostUser(0, "duke", "J. Duke")));

var fromDir = temp.path().resolve("from.git");
var fromLocalRepo = Repository.init(fromDir, VCS.GIT);
var fromHostedRepo = new TestHostedRepository(host, "test", fromLocalRepo);

var toDir = temp.path().resolve("to.git");
var toLocalRepo = Repository.init(toDir, VCS.GIT);
var toGitConfig = toDir.resolve(".git").resolve("config");
Files.write(toGitConfig, List.of("[receive]", "denyCurrentBranch = ignore"),
var toHostedRepo = new TestHostedRepository(host, "test-mirror", toLocalRepo);

var forkDir = temp.path().resolve("fork.git");
var forkLocalRepo = Repository.init(forkDir, VCS.GIT);
var forkGitConfig = forkDir.resolve(".git").resolve("config");
Files.write(forkGitConfig, List.of("[receive]", "denyCurrentBranch = ignore"),
var toFork = new TestHostedRepository(host, "test-mirror-fork", forkLocalRepo);

var now =;
var fromFileA = fromDir.resolve("a.txt");
Files.writeString(fromFileA, "Hello A\n");
var fromHashA = fromLocalRepo.commit("Adding a.txt", "duke", "", now);
var fromCommits = fromLocalRepo.commits().asList();
assertEquals(1, fromCommits.size());
assertEquals(fromHashA, fromCommits.get(0).hash());

var toFileA = toDir.resolve("a.txt");
Files.writeString(toFileA, "Hello A\n");
var toHashA = toLocalRepo.commit("Adding a.txt", "duke", "", now);
var toCommits = toLocalRepo.commits().asList();
assertEquals(1, toCommits.size());
assertEquals(toHashA, toCommits.get(0).hash());
assertEquals(fromHashA, toHashA);

var storage = temp.path().resolve("storage");
var master = new Branch("master");
var specs = List.of(new MergeBot.Spec(fromHostedRepo, master, master));
var bot = new MergeBot(storage, toHostedRepo, toFork, specs);

// Add something new to the source
var fromFileB = fromDir.resolve("b.txt");
Files.writeString(fromFileB, "Hello B\n");
var fromHashB = fromLocalRepo.commit("Adding a.txt", "duke", "", now);
fromLocalRepo.push(fromHashB, fromHostedRepo.url(), "master");

// Diverge the target with something non-conflicting
var toFileC = toDir.resolve("c.txt");
Files.writeString(toFileC, "Hello C\n");
var toHashC = toLocalRepo.commit("Adding c.txt", "duke", "");
toLocalRepo.push(toHashC, toHostedRepo.url(), "master");

// But push something out of place to the local storage as well
var sanitizedForkUrl = URLEncoder.encode(toFork.webUrl().toString(), StandardCharsets.UTF_8);
var storageRepo = Repository.init(storage.resolve(sanitizedForkUrl), VCS.GIT);
var divergedForkFile = storageRepo.root().resolve("d.txt");
Files.writeString(divergedForkFile, "Hello D\n");
var divergedForkHash = storageRepo.commit("Adding d.txt", "duke", "");

// This will need manual intervention
assertThrows(RuntimeException.class, () -> TestBotRunner.runPeriodicItems(bot));