Merge "superproject subscriptions: Separate checks and execution"
This commit is contained in:
@@ -262,16 +262,15 @@ public class SubmoduleSubscriptionsIT extends AbstractSubmoduleSubscription {
|
||||
"subscribed-to-project", "refs/heads/master");
|
||||
|
||||
pushChangeTo(subRepo, "master");
|
||||
pushChangeTo(superRepo, "master");
|
||||
createSubmoduleSubscription(superRepo, "master", "subscribed-to-project", "master");
|
||||
createSubmoduleSubscription(subRepo, "master", "super-project", "master");
|
||||
|
||||
ObjectId subHEAD = pushChangeTo(subRepo, "master");
|
||||
pushChangeTo(subRepo, "master");
|
||||
pushChangeTo(superRepo, "master");
|
||||
|
||||
expectToHaveSubmoduleState(superRepo, "master",
|
||||
"subscribed-to-project", subHEAD);
|
||||
|
||||
assertThat(hasSubmodule(subRepo, "master", "super-project")).isFalse();
|
||||
assertThat(hasSubmodule(superRepo, "master", "subscribed-to-project")).isFalse();
|
||||
}
|
||||
|
||||
|
||||
|
@@ -92,6 +92,71 @@ public class SubmoduleSubscriptionsWholeTopicMergeIT
|
||||
"subscribed-to-project", subRepoId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubscriptionUpdateIncludingChangeInSuperproject() throws Exception {
|
||||
TestRepository<?> superRepo = createProjectWithPush("super-project");
|
||||
TestRepository<?> subRepo = createProjectWithPush("subscribed-to-project");
|
||||
allowSubmoduleSubscription("subscribed-to-project", "refs/heads/master",
|
||||
"super-project", "refs/heads/master");
|
||||
|
||||
createSubmoduleSubscription(superRepo, "master", "subscribed-to-project", "master");
|
||||
|
||||
ObjectId subHEAD = subRepo.branch("HEAD").commit().insertChangeId()
|
||||
.message("some change")
|
||||
.add("a.txt", "a contents ")
|
||||
.create();
|
||||
subRepo.git().push().setRemote("origin").setRefSpecs(
|
||||
new RefSpec("HEAD:refs/heads/master")).call();
|
||||
|
||||
RevCommit c = subRepo.getRevWalk().parseCommit(subHEAD);
|
||||
|
||||
RevCommit c1 = subRepo.branch("HEAD").commit().insertChangeId()
|
||||
.message("first change")
|
||||
.add("asdf", "asdf\n")
|
||||
.create();
|
||||
subRepo.git().push().setRemote("origin")
|
||||
.setRefSpecs(new RefSpec("HEAD:refs/for/master/" + name("topic-foo")))
|
||||
.call();
|
||||
|
||||
subRepo.reset(c.getId());
|
||||
RevCommit c2 = subRepo.branch("HEAD").commit().insertChangeId()
|
||||
.message("qwerty")
|
||||
.add("qwerty", "qwerty")
|
||||
.create();
|
||||
|
||||
RevCommit c3 = subRepo.branch("HEAD").commit().insertChangeId()
|
||||
.message("qwerty followup")
|
||||
.add("qwerty", "qwerty\nqwerty\n")
|
||||
.create();
|
||||
subRepo.git().push().setRemote("origin")
|
||||
.setRefSpecs(new RefSpec("HEAD:refs/for/master/" + name("topic-foo")))
|
||||
.call();
|
||||
|
||||
RevCommit c4 = superRepo.branch("HEAD").commit().insertChangeId()
|
||||
.message("new change on superproject")
|
||||
.add("foo", "bar")
|
||||
.create();
|
||||
superRepo.git().push().setRemote("origin")
|
||||
.setRefSpecs(new RefSpec("HEAD:refs/for/master/" + name("topic-foo")))
|
||||
.call();
|
||||
|
||||
String id1 = getChangeId(subRepo, c1).get();
|
||||
String id2 = getChangeId(subRepo, c2).get();
|
||||
String id3 = getChangeId(subRepo, c3).get();
|
||||
String id4 = getChangeId(superRepo, c4).get();
|
||||
gApi.changes().id(id1).current().review(ReviewInput.approve());
|
||||
gApi.changes().id(id2).current().review(ReviewInput.approve());
|
||||
gApi.changes().id(id3).current().review(ReviewInput.approve());
|
||||
gApi.changes().id(id4).current().review(ReviewInput.approve());
|
||||
|
||||
gApi.changes().id(id1).current().submit();
|
||||
ObjectId subRepoId = subRepo.git().fetch().setRemote("origin").call()
|
||||
.getAdvertisedRef("refs/heads/master").getObjectId();
|
||||
|
||||
expectToHaveSubmoduleState(superRepo, "master",
|
||||
"subscribed-to-project", subRepoId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateManySubmodules() throws Exception {
|
||||
TestRepository<?> superRepo = createProjectWithPush("super-project");
|
||||
|
@@ -32,6 +32,9 @@ import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
|
||||
import com.google.gerrit.server.git.MergeOpRepoManager.OpenRepo;
|
||||
import com.google.gerrit.server.project.NoSuchProjectException;
|
||||
import com.google.gerrit.server.project.ProjectCache;
|
||||
import com.google.gerrit.server.util.SubmoduleSectionParser;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
import com.google.gwtorm.server.ResultSet;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import org.eclipse.jgit.dircache.DirCache;
|
||||
@@ -71,7 +74,6 @@ public class SubmoduleOp {
|
||||
private final PersonIdent myIdent;
|
||||
private final GitReferenceUpdated gitRefUpdated;
|
||||
private final ProjectCache projectCache;
|
||||
private final Set<Branch.NameKey> updatedSubscribers;
|
||||
private final Account account;
|
||||
private final ChangeHooks changeHooks;
|
||||
private final boolean verboseSuperProject;
|
||||
@@ -97,7 +99,6 @@ public class SubmoduleOp {
|
||||
"verboseSuperprojectUpdate", true);
|
||||
this.enableSuperProjectSubscriptions = cfg.getBoolean("submodule",
|
||||
"enableSuperProjectSubscriptions", true);
|
||||
updatedSubscribers = new HashSet<>();
|
||||
}
|
||||
|
||||
public Collection<Branch.NameKey> getDestinationBranches(Branch.NameKey src,
|
||||
@@ -165,32 +166,50 @@ public class SubmoduleOp {
|
||||
}
|
||||
this.updateId = updateId;
|
||||
logDebug("Updating superprojects");
|
||||
// These (repo/branch) will be updated later with all the given
|
||||
// individual submodule subscriptions
|
||||
|
||||
Multimap<Branch.NameKey, SubmoduleSubscription> targets =
|
||||
HashMultimap.create();
|
||||
|
||||
try {
|
||||
for (Branch.NameKey updatedBranch : updatedBranches) {
|
||||
for (SubmoduleSubscription sub :
|
||||
superProjectSubscriptionsForSubmoduleBranch(updatedBranch, orm)) {
|
||||
targets.put(sub.getSuperProject(), sub);
|
||||
for (Branch.NameKey updatedBranch : updatedBranches) {
|
||||
logDebug("Now processing " + updatedBranch);
|
||||
Set<Branch.NameKey> checkedTargets = new HashSet<>();
|
||||
Set<Branch.NameKey> targetsToProcess = new HashSet<>();
|
||||
targetsToProcess.add(updatedBranch);
|
||||
|
||||
while (!targetsToProcess.isEmpty()) {
|
||||
Set<Branch.NameKey> newTargets = new HashSet<>();
|
||||
for (Branch.NameKey b : targetsToProcess) {
|
||||
try {
|
||||
Collection<SubmoduleSubscription> subs =
|
||||
superProjectSubscriptionsForSubmoduleBranch(b, orm);
|
||||
for (SubmoduleSubscription sub : subs) {
|
||||
Branch.NameKey dst = sub.getSuperProject();
|
||||
targets.put(dst, sub);
|
||||
newTargets.add(dst);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new SubmoduleException("Cannot find superprojects for " + b, e);
|
||||
}
|
||||
}
|
||||
logDebug("adding to done " + targetsToProcess);
|
||||
checkedTargets.addAll(targetsToProcess);
|
||||
logDebug("completely done with " + checkedTargets);
|
||||
|
||||
Set<Branch.NameKey> intersection = new HashSet<>(checkedTargets);
|
||||
intersection.retainAll(newTargets);
|
||||
if (!intersection.isEmpty()) {
|
||||
throw new SubmoduleException("Possible circular subscription involving " + updatedBranch);
|
||||
}
|
||||
|
||||
targetsToProcess = newTargets;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new SubmoduleException("Could not calculate all superprojects");
|
||||
}
|
||||
updatedSubscribers.addAll(updatedBranches);
|
||||
// Update subscribers.
|
||||
for (Branch.NameKey dest : targets.keySet()) {
|
||||
|
||||
for (Branch.NameKey dst : targets.keySet()) {
|
||||
try {
|
||||
if (!updatedSubscribers.add(dest)) {
|
||||
log.error("Possible circular subscription involving " + dest);
|
||||
} else {
|
||||
updateGitlinks(db, dest, targets.get(dest), orm);
|
||||
}
|
||||
updateGitlinks(dst, targets.get(dst), orm);
|
||||
} catch (SubmoduleException e) {
|
||||
log.warn("Cannot update gitlinks for " + dest, e);
|
||||
throw new SubmoduleException("Cannot update gitlinks for " + dst, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -202,7 +221,7 @@ public class SubmoduleOp {
|
||||
* @param updates submodule updates which should be updated to.
|
||||
* @throws SubmoduleException
|
||||
*/
|
||||
private void updateGitlinks(ReviewDb db, Branch.NameKey subscriber,
|
||||
private void updateGitlinks(Branch.NameKey subscriber,
|
||||
Collection<SubmoduleSubscription> updates, MergeOpRepoManager orm)
|
||||
throws SubmoduleException {
|
||||
PersonIdent author = null;
|
||||
@@ -340,8 +359,6 @@ public class SubmoduleOp {
|
||||
default:
|
||||
throw new IOException(rfu.getResult().name());
|
||||
}
|
||||
// Recursive call: update subscribers of the subscriber
|
||||
updateSuperProjects(db, Sets.newHashSet(subscriber), updateId, orm);
|
||||
} catch (IOException e) {
|
||||
throw new SubmoduleException("Cannot update gitlinks for "
|
||||
+ subscriber.get(), e);
|
||||
|
Reference in New Issue
Block a user