Merge changes Ie5d1b547,Ib623ce65,Ie1ab3bfa,I66ed2bd8,Ib320b0ed, ...

* changes:
  MergeOp: Use factories of the subscription components
  MergeOp: Pass the specific objects, instead of submoduleOp
  SubmoduleOp: Move subscription graph instantiation to its own factory
  UpdateOrderCalculator: Move update order calculation out of submoduleOp
  SubmoduleCommits: Define its own guice factory
  GitlinkOp: Move it to its own class and factory
This commit is contained in:
Alice Kober-Sotzek
2020-09-22 07:51:17 +00:00
committed by Gerrit Code Review
9 changed files with 306 additions and 138 deletions

View File

@@ -187,9 +187,11 @@ import com.google.gerrit.server.rules.PrologModule;
import com.google.gerrit.server.rules.RulesCache; import com.google.gerrit.server.rules.RulesCache;
import com.google.gerrit.server.rules.SubmitRule; import com.google.gerrit.server.rules.SubmitRule;
import com.google.gerrit.server.ssh.SshAddressesModule; import com.google.gerrit.server.ssh.SshAddressesModule;
import com.google.gerrit.server.submit.ConfiguredSubscriptionGraphFactory;
import com.google.gerrit.server.submit.GitModules; import com.google.gerrit.server.submit.GitModules;
import com.google.gerrit.server.submit.MergeSuperSetComputation; import com.google.gerrit.server.submit.MergeSuperSetComputation;
import com.google.gerrit.server.submit.SubmitStrategy; import com.google.gerrit.server.submit.SubmitStrategy;
import com.google.gerrit.server.submit.SubscriptionGraph;
import com.google.gerrit.server.tools.ToolsCatalog; import com.google.gerrit.server.tools.ToolsCatalog;
import com.google.gerrit.server.update.BatchUpdate; import com.google.gerrit.server.update.BatchUpdate;
import com.google.gerrit.server.util.IdGenerator; import com.google.gerrit.server.util.IdGenerator;
@@ -453,6 +455,7 @@ public class GerritGlobalModule extends FactoryModule {
factory(VersionedAuthorizedKeys.Factory.class); factory(VersionedAuthorizedKeys.Factory.class);
bind(AccountManager.class); bind(AccountManager.class);
bind(SubscriptionGraph.Factory.class).to(ConfiguredSubscriptionGraphFactory.class);
bind(new TypeLiteral<List<CommentLinkInfo>>() {}).toProvider(CommentLinkProvider.class); bind(new TypeLiteral<List<CommentLinkInfo>>() {}).toProvider(CommentLinkProvider.class);
DynamicSet.bind(binder(), GerritConfigListener.class).to(CommentLinkProvider.class); DynamicSet.bind(binder(), GerritConfigListener.class).to(CommentLinkProvider.class);

View File

@@ -0,0 +1,54 @@
// Copyright (C) 2020 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gerrit.server.submit;
import com.google.common.collect.ImmutableSet;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.entities.BranchNameKey;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.inject.Inject;
import java.util.Set;
import org.eclipse.jgit.lib.Config;
/**
* Wrap a (@link {@link SubscriptionGraph.Factory} to honor the gerrit configuration.
*
* <p>If superproject subscriptions are disabled in the conf, return an empty graph.
*/
public class ConfiguredSubscriptionGraphFactory implements SubscriptionGraph.Factory {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private final SubscriptionGraph.Factory subscriptionGraphFactory;
private final Config cfg;
@Inject
ConfiguredSubscriptionGraphFactory(
@VanillaSubscriptionGraph SubscriptionGraph.Factory subscriptionGraphFactory,
@GerritServerConfig Config cfg) {
this.subscriptionGraphFactory = subscriptionGraphFactory;
this.cfg = cfg;
}
@Override
public SubscriptionGraph compute(Set<BranchNameKey> updatedBranches, MergeOpRepoManager orm)
throws SubmoduleConflictException {
if (cfg.getBoolean("submodule", "enableSuperProjectSubscriptions", true)) {
return subscriptionGraphFactory.compute(updatedBranches, orm);
} else {
logger.atFine().log("Updating superprojects disabled");
return SubscriptionGraph.createEmptyGraph(ImmutableSet.copyOf(updatedBranches));
}
}
}

View File

@@ -0,0 +1,64 @@
// Copyright (C) 2020 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gerrit.server.submit;
import com.google.gerrit.entities.BranchNameKey;
import com.google.gerrit.entities.SubmoduleSubscription;
import com.google.gerrit.server.git.CodeReviewCommit;
import com.google.gerrit.server.update.RepoContext;
import com.google.gerrit.server.update.RepoOnlyOp;
import java.util.Collection;
import java.util.Optional;
/** Only used for branches without code review changes */
public class GitlinkOp implements RepoOnlyOp {
static class Factory {
private SubmoduleCommits submoduleCommits;
private SubscriptionGraph subscriptionGraph;
Factory(SubmoduleCommits submoduleCommits, SubscriptionGraph subscriptionGraph) {
this.submoduleCommits = submoduleCommits;
this.subscriptionGraph = subscriptionGraph;
}
GitlinkOp create(BranchNameKey branch) {
return new GitlinkOp(branch, submoduleCommits, subscriptionGraph.getSubscriptions(branch));
}
}
private final BranchNameKey branch;
private final SubmoduleCommits commitHelper;
private final Collection<SubmoduleSubscription> branchTargets;
GitlinkOp(
BranchNameKey branch,
SubmoduleCommits commitHelper,
Collection<SubmoduleSubscription> branchTargets) {
this.branch = branch;
this.commitHelper = commitHelper;
this.branchTargets = branchTargets;
}
@Override
public void updateRepo(RepoContext ctx) throws Exception {
Optional<CodeReviewCommit> commit = commitHelper.composeGitlinksCommit(branch, branchTargets);
if (commit.isPresent()) {
CodeReviewCommit c = commit.get();
ctx.addRefUpdate(c.getParent(0), c, branch.branch());
commitHelper.addBranchTip(branch, c);
}
}
}

View File

@@ -226,7 +226,9 @@ public class MergeOp implements AutoCloseable {
private final MergeValidators.Factory mergeValidatorsFactory; private final MergeValidators.Factory mergeValidatorsFactory;
private final Provider<InternalChangeQuery> queryProvider; private final Provider<InternalChangeQuery> queryProvider;
private final SubmitStrategyFactory submitStrategyFactory; private final SubmitStrategyFactory submitStrategyFactory;
private final SubscriptionGraph.Factory subscriptionGraphFactory;
private final SubmoduleOp.Factory subOpFactory; private final SubmoduleOp.Factory subOpFactory;
private final SubmoduleCommits.Factory submoduleCommitsFactory;
private final Provider<MergeOpRepoManager> ormProvider; private final Provider<MergeOpRepoManager> ormProvider;
private final NotifyResolver notifyResolver; private final NotifyResolver notifyResolver;
private final RetryHelper retryHelper; private final RetryHelper retryHelper;
@@ -256,6 +258,8 @@ public class MergeOp implements AutoCloseable {
MergeValidators.Factory mergeValidatorsFactory, MergeValidators.Factory mergeValidatorsFactory,
Provider<InternalChangeQuery> queryProvider, Provider<InternalChangeQuery> queryProvider,
SubmitStrategyFactory submitStrategyFactory, SubmitStrategyFactory submitStrategyFactory,
SubmoduleCommits.Factory submoduleCommitsFactory,
SubscriptionGraph.Factory subscriptionGraphFactory,
SubmoduleOp.Factory subOpFactory, SubmoduleOp.Factory subOpFactory,
Provider<MergeOpRepoManager> ormProvider, Provider<MergeOpRepoManager> ormProvider,
NotifyResolver notifyResolver, NotifyResolver notifyResolver,
@@ -269,6 +273,8 @@ public class MergeOp implements AutoCloseable {
this.mergeValidatorsFactory = mergeValidatorsFactory; this.mergeValidatorsFactory = mergeValidatorsFactory;
this.queryProvider = queryProvider; this.queryProvider = queryProvider;
this.submitStrategyFactory = submitStrategyFactory; this.submitStrategyFactory = submitStrategyFactory;
this.submoduleCommitsFactory = submoduleCommitsFactory;
this.subscriptionGraphFactory = subscriptionGraphFactory;
this.subOpFactory = subOpFactory; this.subOpFactory = subOpFactory;
this.ormProvider = ormProvider; this.ormProvider = ormProvider;
this.notifyResolver = notifyResolver; this.notifyResolver = notifyResolver;
@@ -605,9 +611,13 @@ public class MergeOp implements AutoCloseable {
commitStatus.maybeFailVerbose(); commitStatus.maybeFailVerbose();
try { try {
SubmoduleOp submoduleOp = subOpFactory.create(branches, orm); SubscriptionGraph subscriptionGraph = subscriptionGraphFactory.compute(branches, orm);
List<SubmitStrategy> strategies = getSubmitStrategies(toSubmit, submoduleOp, dryrun); SubmoduleCommits submoduleCommits = submoduleCommitsFactory.create(orm);
this.allProjects = submoduleOp.getProjectsInOrder(); UpdateOrderCalculator updateOrderCalculator = new UpdateOrderCalculator(subscriptionGraph);
List<SubmitStrategy> strategies =
getSubmitStrategies(
toSubmit, updateOrderCalculator, submoduleCommits, subscriptionGraph, dryrun);
this.allProjects = updateOrderCalculator.getProjectsInOrder();
try { try {
BatchUpdate.execute( BatchUpdate.execute(
orm.batchUpdates(allProjects), orm.batchUpdates(allProjects),
@@ -658,12 +668,19 @@ public class MergeOp implements AutoCloseable {
} }
private List<SubmitStrategy> getSubmitStrategies( private List<SubmitStrategy> getSubmitStrategies(
Map<BranchNameKey, BranchBatch> toSubmit, SubmoduleOp submoduleOp, boolean dryrun) Map<BranchNameKey, BranchBatch> toSubmit,
UpdateOrderCalculator updateOrderCalculator,
SubmoduleCommits submoduleCommits,
SubscriptionGraph subscriptionGraph,
boolean dryrun)
throws IntegrationConflictException, NoSuchProjectException, IOException { throws IntegrationConflictException, NoSuchProjectException, IOException {
List<SubmitStrategy> strategies = new ArrayList<>(); List<SubmitStrategy> strategies = new ArrayList<>();
Set<BranchNameKey> allBranches = submoduleOp.getBranchesInOrder(); Set<BranchNameKey> allBranches = updateOrderCalculator.getBranchesInOrder();
Set<CodeReviewCommit> allCommits = Set<CodeReviewCommit> allCommits =
toSubmit.values().stream().map(BranchBatch::commits).flatMap(Set::stream).collect(toSet()); toSubmit.values().stream().map(BranchBatch::commits).flatMap(Set::stream).collect(toSet());
GitlinkOp.Factory gitlinkOpFactory = new GitlinkOp.Factory(submoduleCommits, subscriptionGraph);
for (BranchNameKey branch : allBranches) { for (BranchNameKey branch : allBranches) {
OpenRepo or = orm.getRepo(branch.project()); OpenRepo or = orm.getRepo(branch.project());
if (toSubmit.containsKey(branch)) { if (toSubmit.containsKey(branch)) {
@@ -688,19 +705,19 @@ public class MergeOp implements AutoCloseable {
commitStatus, commitStatus,
submissionId, submissionId,
submitInput, submitInput,
submoduleOp.getSubmoduleCommits(), submoduleCommits,
submoduleOp.getSubscriptionGraph(), subscriptionGraph,
dryrun); dryrun);
strategies.add(strategy); strategies.add(strategy);
strategy.addOps(or.getUpdate(), commitsToSubmit); strategy.addOps(or.getUpdate(), commitsToSubmit);
if (submitting.submitType().equals(SubmitType.FAST_FORWARD_ONLY) if (submitting.submitType().equals(SubmitType.FAST_FORWARD_ONLY)
&& submoduleOp.getSubscriptionGraph().hasSubscription(branch)) { && subscriptionGraph.hasSubscription(branch)) {
submoduleOp.addOp(or.getUpdate(), branch); or.getUpdate().addRepoOnlyOp(gitlinkOpFactory.create(branch));
} }
} else { } else {
// no open change for this branch // no open change for this branch
// add submodule triggered op into BatchUpdate // add submodule triggered op into BatchUpdate
submoduleOp.addOp(or.getUpdate(), branch); or.getUpdate().addRepoOnlyOp(gitlinkOpFactory.create(branch));
} }
} }
return strategies; return strategies;

View File

@@ -21,10 +21,15 @@ import com.google.common.flogger.FluentLogger;
import com.google.gerrit.entities.BranchNameKey; import com.google.gerrit.entities.BranchNameKey;
import com.google.gerrit.entities.SubmoduleSubscription; import com.google.gerrit.entities.SubmoduleSubscription;
import com.google.gerrit.exceptions.StorageException; import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.VerboseSuperprojectUpdate; import com.google.gerrit.server.config.VerboseSuperprojectUpdate;
import com.google.gerrit.server.git.CodeReviewCommit; import com.google.gerrit.server.git.CodeReviewCommit;
import com.google.gerrit.server.project.NoSuchProjectException; import com.google.gerrit.server.project.NoSuchProjectException;
import com.google.gerrit.server.submit.MergeOpRepoManager.OpenRepo; import com.google.gerrit.server.submit.MergeOpRepoManager.OpenRepo;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import java.io.IOException; import java.io.IOException;
import java.util.Collection; import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
@@ -58,6 +63,22 @@ class SubmoduleCommits {
private final long maxCommitMessages; private final long maxCommitMessages;
private final BranchTips branchTips = new BranchTips(); private final BranchTips branchTips = new BranchTips();
@Singleton
public static class Factory {
private final Provider<PersonIdent> serverIdent;
private final Config cfg;
@Inject
Factory(@GerritPersonIdent Provider<PersonIdent> serverIdent, @GerritServerConfig Config cfg) {
this.serverIdent = serverIdent;
this.cfg = cfg;
}
public SubmoduleCommits create(MergeOpRepoManager orm) {
return new SubmoduleCommits(orm, serverIdent.get(), cfg);
}
}
SubmoduleCommits(MergeOpRepoManager orm, PersonIdent myIdent, Config cfg) { SubmoduleCommits(MergeOpRepoManager orm, PersonIdent myIdent, Config cfg) {
this.orm = orm; this.orm = orm;
this.myIdent = myIdent; this.myIdent = myIdent;

View File

@@ -15,116 +15,59 @@
package com.google.gerrit.server.submit; package com.google.gerrit.server.submit;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.UsedAt; import com.google.gerrit.common.UsedAt;
import com.google.gerrit.entities.BranchNameKey; import com.google.gerrit.entities.BranchNameKey;
import com.google.gerrit.entities.Project; import com.google.gerrit.entities.Project;
import com.google.gerrit.entities.SubmoduleSubscription;
import com.google.gerrit.exceptions.StorageException; import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.extensions.restapi.RestApiException; import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.git.CodeReviewCommit;
import com.google.gerrit.server.project.NoSuchProjectException; import com.google.gerrit.server.project.NoSuchProjectException;
import com.google.gerrit.server.submit.MergeOpRepoManager.OpenRepo; import com.google.gerrit.server.submit.MergeOpRepoManager.OpenRepo;
import com.google.gerrit.server.update.BatchUpdate; import com.google.gerrit.server.update.BatchUpdate;
import com.google.gerrit.server.update.BatchUpdateListener; import com.google.gerrit.server.update.BatchUpdateListener;
import com.google.gerrit.server.update.RepoContext;
import com.google.gerrit.server.update.RepoOnlyOp;
import com.google.gerrit.server.update.UpdateException; import com.google.gerrit.server.update.UpdateException;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton; import com.google.inject.Singleton;
import java.io.IOException; import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.Optional;
import java.util.Set; import java.util.Set;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.PersonIdent;
public class SubmoduleOp { public class SubmoduleOp {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
/** Only used for branches without code review changes */
public static class GitlinkOp implements RepoOnlyOp {
private final BranchNameKey branch;
private final SubmoduleCommits commitHelper;
private final Collection<SubmoduleSubscription> branchTargets;
GitlinkOp(
BranchNameKey branch,
SubmoduleCommits commitHelper,
Collection<SubmoduleSubscription> branchTargets) {
this.branch = branch;
this.commitHelper = commitHelper;
this.branchTargets = branchTargets;
}
@Override
public void updateRepo(RepoContext ctx) throws Exception {
Optional<CodeReviewCommit> commit = commitHelper.composeGitlinksCommit(branch, branchTargets);
if (commit.isPresent()) {
CodeReviewCommit c = commit.get();
ctx.addRefUpdate(c.getParent(0), c, branch.branch());
commitHelper.addBranchTip(branch, c);
}
}
}
@Singleton @Singleton
public static class Factory { public static class Factory {
private final SubscriptionGraph.Factory subscriptionGraphFactory; private final SubscriptionGraph.Factory subscriptionGraphFactory;
private final Provider<PersonIdent> serverIdent; private final SubmoduleCommits.Factory submoduleCommitsFactory;
private final Config cfg;
@Inject @Inject
Factory( Factory(
SubscriptionGraph.Factory subscriptionGraphFactory, SubscriptionGraph.Factory subscriptionGraphFactory,
@GerritPersonIdent Provider<PersonIdent> serverIdent, SubmoduleCommits.Factory submoduleCommitsFactory) {
@GerritServerConfig Config cfg) {
this.subscriptionGraphFactory = subscriptionGraphFactory; this.subscriptionGraphFactory = subscriptionGraphFactory;
this.serverIdent = serverIdent; this.submoduleCommitsFactory = submoduleCommitsFactory;
this.cfg = cfg;
} }
public SubmoduleOp create(Set<BranchNameKey> updatedBranches, MergeOpRepoManager orm) public SubmoduleOp create(Set<BranchNameKey> updatedBranches, MergeOpRepoManager orm)
throws SubmoduleConflictException { throws SubmoduleConflictException {
SubscriptionGraph subscriptionGraph; return new SubmoduleOp(
if (cfg.getBoolean("submodule", "enableSuperProjectSubscriptions", true)) { orm,
subscriptionGraph = subscriptionGraphFactory.compute(updatedBranches, orm); subscriptionGraphFactory.compute(updatedBranches, orm),
} else { submoduleCommitsFactory.create(orm));
logger.atFine().log("Updating superprojects disabled");
subscriptionGraph =
SubscriptionGraph.createEmptyGraph(ImmutableSet.copyOf(updatedBranches));
}
return new SubmoduleOp(serverIdent.get(), cfg, orm, subscriptionGraph);
} }
} }
private final MergeOpRepoManager orm; private final MergeOpRepoManager orm;
private final SubscriptionGraph subscriptionGraph; private final SubscriptionGraph subscriptionGraph;
private final SubmoduleCommits submoduleCommits; private final SubmoduleCommits submoduleCommits;
private final UpdateOrderCalculator updateOrderCalculator;
private SubmoduleOp( private SubmoduleOp(
PersonIdent myIdent,
Config cfg,
MergeOpRepoManager orm, MergeOpRepoManager orm,
SubscriptionGraph subscriptionGraph) { SubscriptionGraph subscriptionGraph,
SubmoduleCommits submoduleCommits) {
this.orm = orm; this.orm = orm;
this.subscriptionGraph = subscriptionGraph; this.subscriptionGraph = subscriptionGraph;
this.submoduleCommits = new SubmoduleCommits(orm, myIdent, cfg); this.submoduleCommits = submoduleCommits;
} this.updateOrderCalculator = new UpdateOrderCalculator(subscriptionGraph);
// TODO(ifrade): subscription graph should be instantiated somewhere else and passed to
// SubmoduleOp
SubscriptionGraph getSubscriptionGraph() {
return subscriptionGraph;
}
SubmoduleCommits getSubmoduleCommits() {
return submoduleCommits;
} }
@UsedAt(UsedAt.Project.PLUGIN_DELETE_PROJECT) @UsedAt(UsedAt.Project.PLUGIN_DELETE_PROJECT)
@@ -133,13 +76,15 @@ public class SubmoduleOp {
} }
public void updateSuperProjects() throws RestApiException { public void updateSuperProjects() throws RestApiException {
ImmutableSet<Project.NameKey> projects = getProjectsInOrder(); ImmutableSet<Project.NameKey> projects = updateOrderCalculator.getProjectsInOrder();
if (projects == null) { if (projects == null) {
return; return;
} }
LinkedHashSet<Project.NameKey> superProjects = new LinkedHashSet<>(); LinkedHashSet<Project.NameKey> superProjects = new LinkedHashSet<>();
try { try {
GitlinkOp.Factory gitlinkOpFactory =
new GitlinkOp.Factory(submoduleCommits, subscriptionGraph);
for (Project.NameKey project : projects) { for (Project.NameKey project : projects) {
// only need superprojects // only need superprojects
if (subscriptionGraph.isAffectedSuperProject(project)) { if (subscriptionGraph.isAffectedSuperProject(project)) {
@@ -147,7 +92,7 @@ public class SubmoduleOp {
// get a new BatchUpdate for the super project // get a new BatchUpdate for the super project
OpenRepo or = orm.getRepo(project); OpenRepo or = orm.getRepo(project);
for (BranchNameKey branch : subscriptionGraph.getAffectedSuperBranches(project)) { for (BranchNameKey branch : subscriptionGraph.getAffectedSuperBranches(project)) {
addOp(or.getUpdate(), branch); or.getUpdate().addRepoOnlyOp(gitlinkOpFactory.create(branch));
} }
} }
} }
@@ -156,60 +101,4 @@ public class SubmoduleOp {
throw new StorageException("Cannot update gitlinks", e); throw new StorageException("Cannot update gitlinks", e);
} }
} }
ImmutableSet<Project.NameKey> getProjectsInOrder() throws SubmoduleConflictException {
LinkedHashSet<Project.NameKey> projects = new LinkedHashSet<>();
for (Project.NameKey project : subscriptionGraph.getAffectedSuperProjects()) {
addAllSubmoduleProjects(project, new LinkedHashSet<>(), projects);
}
for (BranchNameKey branch : subscriptionGraph.getUpdatedBranches()) {
projects.add(branch.project());
}
return ImmutableSet.copyOf(projects);
}
private void addAllSubmoduleProjects(
Project.NameKey project,
LinkedHashSet<Project.NameKey> current,
LinkedHashSet<Project.NameKey> projects)
throws SubmoduleConflictException {
if (current.contains(project)) {
throw new SubmoduleConflictException(
"Project level circular subscriptions detected: "
+ CircularPathFinder.printCircularPath(current, project));
}
if (projects.contains(project)) {
return;
}
current.add(project);
Set<Project.NameKey> subprojects = new HashSet<>();
for (BranchNameKey branch : subscriptionGraph.getAffectedSuperBranches(project)) {
Collection<SubmoduleSubscription> subscriptions = subscriptionGraph.getSubscriptions(branch);
for (SubmoduleSubscription s : subscriptions) {
subprojects.add(s.getSubmodule().project());
}
}
for (Project.NameKey p : subprojects) {
addAllSubmoduleProjects(p, current, projects);
}
current.remove(project);
projects.add(project);
}
ImmutableSet<BranchNameKey> getBranchesInOrder() {
LinkedHashSet<BranchNameKey> branches = new LinkedHashSet<>();
branches.addAll(subscriptionGraph.getSortedSuperprojectAndSubmoduleBranches());
branches.addAll(subscriptionGraph.getUpdatedBranches());
return ImmutableSet.copyOf(branches);
}
void addOp(BatchUpdate bu, BranchNameKey branch) {
bu.addRepoOnlyOp(
new GitlinkOp(branch, submoduleCommits, subscriptionGraph.getSubscriptions(branch)));
}
} }

View File

@@ -159,7 +159,7 @@ public class SubscriptionGraph {
public static class Module extends AbstractModule { public static class Module extends AbstractModule {
@Override @Override
protected void configure() { protected void configure() {
bind(Factory.class).to(DefaultFactory.class); bind(Factory.class).annotatedWith(VanillaSubscriptionGraph.class).to(DefaultFactory.class);
} }
} }

View File

@@ -0,0 +1,91 @@
// Copyright (C) 2020 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gerrit.server.submit;
import com.google.common.collect.ImmutableSet;
import com.google.gerrit.entities.BranchNameKey;
import com.google.gerrit.entities.Project;
import com.google.gerrit.entities.SubmoduleSubscription;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
/**
* Sorts the projects or branches affected by the update.
*
* <p>The subscription graph contains all branches (and projects) affected by the update, but the
* updates must be executed in the right order, so no superproject reference is updated before its
* target.
*/
class UpdateOrderCalculator {
private final SubscriptionGraph subscriptionGraph;
UpdateOrderCalculator(SubscriptionGraph subscriptionGraph) {
this.subscriptionGraph = subscriptionGraph;
}
ImmutableSet<Project.NameKey> getProjectsInOrder() throws SubmoduleConflictException {
LinkedHashSet<Project.NameKey> projects = new LinkedHashSet<>();
for (Project.NameKey project : subscriptionGraph.getAffectedSuperProjects()) {
addAllSubmoduleProjects(project, new LinkedHashSet<>(), projects);
}
for (BranchNameKey branch : subscriptionGraph.getUpdatedBranches()) {
projects.add(branch.project());
}
return ImmutableSet.copyOf(projects);
}
private void addAllSubmoduleProjects(
Project.NameKey project,
LinkedHashSet<Project.NameKey> current,
LinkedHashSet<Project.NameKey> projects)
throws SubmoduleConflictException {
if (current.contains(project)) {
throw new SubmoduleConflictException(
"Project level circular subscriptions detected: "
+ CircularPathFinder.printCircularPath(current, project));
}
if (projects.contains(project)) {
return;
}
current.add(project);
Set<Project.NameKey> subprojects = new HashSet<>();
for (BranchNameKey branch : subscriptionGraph.getAffectedSuperBranches(project)) {
Collection<SubmoduleSubscription> subscriptions = subscriptionGraph.getSubscriptions(branch);
for (SubmoduleSubscription s : subscriptions) {
subprojects.add(s.getSubmodule().project());
}
}
for (Project.NameKey p : subprojects) {
addAllSubmoduleProjects(p, current, projects);
}
current.remove(project);
projects.add(project);
}
ImmutableSet<BranchNameKey> getBranchesInOrder() {
LinkedHashSet<BranchNameKey> branches = new LinkedHashSet<>();
branches.addAll(subscriptionGraph.getSortedSuperprojectAndSubmoduleBranches());
branches.addAll(subscriptionGraph.getUpdatedBranches());
return ImmutableSet.copyOf(branches);
}
}

View File

@@ -0,0 +1,29 @@
// Copyright (C) 2020 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gerrit.server.submit;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import com.google.inject.BindingAnnotation;
import java.lang.annotation.Retention;
/**
* Marker on a {@link SubscriptionGraph.Factory} without gerrit configuration.
*
* <p>See {@link ConfiguredSubscriptionGraphFactory}.
*/
@Retention(RUNTIME)
@BindingAnnotation
public @interface VanillaSubscriptionGraph {}