Merge "New extension to validate branch updates by submit strategies."
This commit is contained in:
@@ -128,6 +128,8 @@ import com.google.gerrit.server.git.validators.MergeValidators;
|
||||
import com.google.gerrit.server.git.validators.MergeValidators.ProjectConfigValidator;
|
||||
import com.google.gerrit.server.git.validators.RefOperationValidationListener;
|
||||
import com.google.gerrit.server.git.validators.RefOperationValidators;
|
||||
import com.google.gerrit.server.git.validators.OnSubmitValidationListener;
|
||||
import com.google.gerrit.server.git.validators.OnSubmitValidators;
|
||||
import com.google.gerrit.server.git.validators.UploadValidationListener;
|
||||
import com.google.gerrit.server.git.validators.UploadValidators;
|
||||
import com.google.gerrit.server.group.GroupInfoCache;
|
||||
@@ -350,6 +352,7 @@ public class GerritGlobalModule extends FactoryModule {
|
||||
DynamicSet.setOf(binder(), CommitValidationListener.class);
|
||||
DynamicSet.setOf(binder(), ChangeMessageModifier.class);
|
||||
DynamicSet.setOf(binder(), RefOperationValidationListener.class);
|
||||
DynamicSet.setOf(binder(), OnSubmitValidationListener.class);
|
||||
DynamicSet.setOf(binder(), MergeValidationListener.class);
|
||||
DynamicSet.setOf(binder(), ProjectCreationValidationListener.class);
|
||||
DynamicSet.setOf(binder(), GroupCreationValidationListener.class);
|
||||
@@ -391,6 +394,7 @@ public class GerritGlobalModule extends FactoryModule {
|
||||
|
||||
factory(AbandonOp.Factory.class);
|
||||
factory(RefOperationValidators.Factory.class);
|
||||
factory(OnSubmitValidators.Factory.class);
|
||||
factory(MergeValidators.Factory.class);
|
||||
factory(ProjectConfigValidator.Factory.class);
|
||||
factory(NotesBranchUtil.Factory.class);
|
||||
|
||||
@@ -51,6 +51,7 @@ import com.google.gerrit.server.IdentifiedUser;
|
||||
import com.google.gerrit.server.config.AllUsersName;
|
||||
import com.google.gerrit.server.config.GerritServerConfig;
|
||||
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
|
||||
import com.google.gerrit.server.git.validators.OnSubmitValidators;
|
||||
import com.google.gerrit.server.index.change.ChangeIndexer;
|
||||
import com.google.gerrit.server.notedb.ChangeNotes;
|
||||
import com.google.gerrit.server.notedb.ChangeUpdate;
|
||||
@@ -532,6 +533,7 @@ public class BatchUpdate implements AutoCloseable {
|
||||
private BatchRefUpdate batchRefUpdate;
|
||||
private boolean closeRepo;
|
||||
private Order order;
|
||||
private OnSubmitValidators onSubmitValidators;
|
||||
private boolean updateChangesInParallel;
|
||||
private RequestId requestId;
|
||||
|
||||
@@ -606,6 +608,15 @@ public class BatchUpdate implements AutoCloseable {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a validation step for intended ref operations, which will be performed
|
||||
* at the end of {@link RepoOnlyOp#updateRepo(RepoContext)} step.
|
||||
*/
|
||||
BatchUpdate setOnSubmitValidators(OnSubmitValidators onSubmitValidators) {
|
||||
this.onSubmitValidators = onSubmitValidators;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute {@link Op#updateChange(ChangeContext)} in parallel for each change.
|
||||
*/
|
||||
@@ -692,6 +703,18 @@ public class BatchUpdate implements AutoCloseable {
|
||||
op.updateRepo(ctx);
|
||||
}
|
||||
|
||||
if (onSubmitValidators != null && commands != null
|
||||
&& !commands.isEmpty()) {
|
||||
// Validation of refs has to take place here and not at the beginning
|
||||
// executeRefUpdates. Otherwise failing validation in a second
|
||||
// BatchUpdate object will happen *after* first object's
|
||||
// executeRefUpdates has finished, hence after first repo's refs have
|
||||
// been updated, which is too late.
|
||||
onSubmitValidators.validate(project,
|
||||
new ReadOnlyRepository(getRepository()),
|
||||
ctx.getInserter().newReader(), commands.getCommands());
|
||||
}
|
||||
|
||||
if (inserter != null) {
|
||||
logDebug("Flushing inserter");
|
||||
inserter.flush();
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gerrit.reviewdb.server.ReviewDb;
|
||||
import com.google.gerrit.server.IdentifiedUser;
|
||||
import com.google.gerrit.server.git.CodeReviewCommit.CodeReviewRevWalk;
|
||||
import com.google.gerrit.server.git.validators.OnSubmitValidators;
|
||||
import com.google.gerrit.server.project.NoSuchProjectException;
|
||||
import com.google.gerrit.server.project.ProjectCache;
|
||||
import com.google.gerrit.server.project.ProjectState;
|
||||
@@ -107,7 +108,8 @@ public class MergeOpRepoManager implements AutoCloseable {
|
||||
if (update == null) {
|
||||
update = batchUpdateFactory.create(db, getProjectName(), caller, ts)
|
||||
.setRepository(repo, rw, ins)
|
||||
.setRequestId(submissionId);
|
||||
.setRequestId(submissionId)
|
||||
.setOnSubmitValidators(onSubmitValidatorsFactory.create());
|
||||
}
|
||||
return update;
|
||||
}
|
||||
@@ -157,6 +159,7 @@ public class MergeOpRepoManager implements AutoCloseable {
|
||||
|
||||
private final Map<Project.NameKey, OpenRepo> openRepos;
|
||||
private final BatchUpdate.Factory batchUpdateFactory;
|
||||
private final OnSubmitValidators.Factory onSubmitValidatorsFactory;
|
||||
private final GitRepositoryManager repoManager;
|
||||
private final ProjectCache projectCache;
|
||||
|
||||
@@ -169,10 +172,12 @@ public class MergeOpRepoManager implements AutoCloseable {
|
||||
MergeOpRepoManager(
|
||||
GitRepositoryManager repoManager,
|
||||
ProjectCache projectCache,
|
||||
BatchUpdate.Factory batchUpdateFactory) {
|
||||
BatchUpdate.Factory batchUpdateFactory,
|
||||
OnSubmitValidators.Factory onSubmitValidatorsFactory) {
|
||||
this.repoManager = repoManager;
|
||||
this.projectCache = projectCache;
|
||||
this.batchUpdateFactory = batchUpdateFactory;
|
||||
this.onSubmitValidatorsFactory = onSubmitValidatorsFactory;
|
||||
|
||||
openRepos = new HashMap<>();
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ import com.google.gerrit.server.git.MergeTip;
|
||||
import com.google.gerrit.server.git.MergeUtil;
|
||||
import com.google.gerrit.server.git.SubmoduleOp;
|
||||
import com.google.gerrit.server.git.TagCache;
|
||||
import com.google.gerrit.server.git.validators.OnSubmitValidators;
|
||||
import com.google.gerrit.server.patch.PatchSetInfoFactory;
|
||||
import com.google.gerrit.server.project.ChangeControl;
|
||||
import com.google.gerrit.server.project.ProjectCache;
|
||||
@@ -118,6 +119,7 @@ public abstract class SubmitStrategy {
|
||||
final ProjectCache projectCache;
|
||||
final PersonIdent serverIdent;
|
||||
final RebaseChangeOp.Factory rebaseFactory;
|
||||
final OnSubmitValidators.Factory onSubmitValidatorsFactory;
|
||||
final TagCache tagCache;
|
||||
|
||||
final Branch.NameKey destBranch;
|
||||
@@ -158,6 +160,7 @@ public abstract class SubmitStrategy {
|
||||
@GerritPersonIdent PersonIdent serverIdent,
|
||||
ProjectCache projectCache,
|
||||
RebaseChangeOp.Factory rebaseFactory,
|
||||
OnSubmitValidators.Factory onSubmitValidatorsFactory,
|
||||
TagCache tagCache,
|
||||
@Assisted Branch.NameKey destBranch,
|
||||
@Assisted CommitStatus commits,
|
||||
@@ -212,6 +215,7 @@ public abstract class SubmitStrategy {
|
||||
"project not found: %s", destBranch.getParentKey());
|
||||
this.mergeSorter = new MergeSorter(rw, alreadyAccepted, canMergeFlag);
|
||||
this.mergeUtil = mergeUtilFactory.create(project);
|
||||
this.onSubmitValidatorsFactory = onSubmitValidatorsFactory;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
// Copyright (C) 2017 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.git.validators;
|
||||
|
||||
import com.google.gerrit.extensions.annotations.ExtensionPoint;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gerrit.reviewdb.client.Project.NameKey;
|
||||
import com.google.gerrit.server.validators.ValidationException;
|
||||
|
||||
import org.eclipse.jgit.lib.ObjectReader;
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
import org.eclipse.jgit.revwalk.RevWalk;
|
||||
import org.eclipse.jgit.transport.ReceiveCommand;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Listener to validate ref updates performed during submit operation.
|
||||
*
|
||||
* As submit strategies may generate new commits (e.g. Cherry Pick), this
|
||||
* listener allows validation of resulting new commit before destination branch
|
||||
* is updated and new patchset ref is created.
|
||||
*
|
||||
* If you only care about validating the change being submitted and not the
|
||||
* resulting new commit, consider using {@link MergeValidationListener} instead.
|
||||
*/
|
||||
@ExtensionPoint
|
||||
public interface OnSubmitValidationListener {
|
||||
public class Arguments {
|
||||
private Project.NameKey project;
|
||||
private Repository repository;
|
||||
private ObjectReader objectReader;
|
||||
private Map<String, ReceiveCommand> commands;
|
||||
|
||||
public Arguments(NameKey project, Repository repository,
|
||||
ObjectReader objectReader, Map<String, ReceiveCommand> commands) {
|
||||
this.project = project;
|
||||
this.repository = repository;
|
||||
this.objectReader = objectReader;
|
||||
this.commands = commands;
|
||||
}
|
||||
|
||||
public Project.NameKey getProject() {
|
||||
return project;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a read only repository
|
||||
*/
|
||||
public Repository getRepository() {
|
||||
return repository;
|
||||
}
|
||||
|
||||
public RevWalk newRevWalk() {
|
||||
return new RevWalk(objectReader);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a map from ref to op on it covering all ref ops to be performed
|
||||
* on this repository as part of ongoing submit operation.
|
||||
*/
|
||||
public Map<String, ReceiveCommand> getCommands(){
|
||||
return commands;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called right before branch is updated with new commit or commits as a
|
||||
* result of submit.
|
||||
*
|
||||
* If ValidationException is thrown, submitting is aborted.
|
||||
*/
|
||||
void preBranchUpdate(Arguments args) throws ValidationException;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
// Copyright (C) 2017 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.git.validators;
|
||||
|
||||
import com.google.gerrit.extensions.registration.DynamicSet;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gerrit.server.git.IntegrationException;
|
||||
import com.google.gerrit.server.git.validators.OnSubmitValidationListener.Arguments;
|
||||
import com.google.gerrit.server.validators.ValidationException;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import org.eclipse.jgit.lib.ObjectReader;
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
import org.eclipse.jgit.transport.ReceiveCommand;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class OnSubmitValidators {
|
||||
public interface Factory {
|
||||
OnSubmitValidators create();
|
||||
}
|
||||
|
||||
private final DynamicSet<OnSubmitValidationListener> listeners;
|
||||
|
||||
@Inject
|
||||
OnSubmitValidators(DynamicSet<OnSubmitValidationListener> listeners) {
|
||||
this.listeners = listeners;
|
||||
}
|
||||
|
||||
public void validate(Project.NameKey project, Repository repo,
|
||||
ObjectReader objectReader, Map<String, ReceiveCommand> commands)
|
||||
throws IntegrationException {
|
||||
try {
|
||||
for (OnSubmitValidationListener listener : this.listeners) {
|
||||
listener.preBranchUpdate(
|
||||
new Arguments(project, repo, objectReader, commands));
|
||||
}
|
||||
} catch (ValidationException e) {
|
||||
throw new IntegrationException(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user