Add merge validation interface
Add a new MergeValidationListener interface which can be used to provide additional validation of commits before they are merged to the git repository. Add a MergeValidators class to invoke the merge validator listeners, and call it from MergeOp before the commit is merged. Add a listener to invoke validation provided by plugins. Change-Id: I325d923f5cc0245b60e86a035329b640c1682d48
This commit is contained in:
@@ -4,6 +4,11 @@ Gerrit Code Review - Commit Validation
|
||||
Gerrit supports link:dev-plugins.html[plugin-based] validation of
|
||||
commits.
|
||||
|
||||
[[new-commit-validation]]
|
||||
New commit validation
|
||||
---------------------
|
||||
|
||||
|
||||
Plugins implementing the `CommitValidationListener` interface can
|
||||
perform additional validation checks against new commits.
|
||||
|
||||
@@ -18,6 +23,18 @@ and cherry-pick buttons.
|
||||
Out of the box, Gerrit includes a plugin that checks the length of the
|
||||
subject and body lines of commit messages on uploaded commits.
|
||||
|
||||
[[pre-merge-validation]]
|
||||
Pre-merge validation
|
||||
--------------------
|
||||
|
||||
|
||||
Plugins implementing the `MergeValidationListener` interface can
|
||||
perform additional validation checks against commits before they
|
||||
are merged to the git repository.
|
||||
|
||||
If the commit fails the validation, the plugin can throw an exception
|
||||
which will cause the merge to fail.
|
||||
|
||||
|
||||
GERRIT
|
||||
------
|
||||
|
@@ -80,6 +80,8 @@ import com.google.gerrit.server.git.TagCache;
|
||||
import com.google.gerrit.server.git.TransferConfig;
|
||||
import com.google.gerrit.server.git.validators.CommitValidationListener;
|
||||
import com.google.gerrit.server.git.validators.CommitValidators;
|
||||
import com.google.gerrit.server.git.validators.MergeValidationListener;
|
||||
import com.google.gerrit.server.git.validators.MergeValidators;
|
||||
import com.google.gerrit.server.mail.AddReviewerSender;
|
||||
import com.google.gerrit.server.mail.CommitMessageEditedSender;
|
||||
import com.google.gerrit.server.mail.CreateChangeSender;
|
||||
@@ -251,11 +253,13 @@ public class GerritGlobalModule extends FactoryModule {
|
||||
DynamicSet.bind(binder(), GitReferenceUpdatedListener.class).to(ChangeCache.class);
|
||||
DynamicSet.setOf(binder(), ChangeListener.class);
|
||||
DynamicSet.setOf(binder(), CommitValidationListener.class);
|
||||
DynamicSet.setOf(binder(), MergeValidationListener.class);
|
||||
DynamicItem.itemOf(binder(), AvatarProvider.class);
|
||||
|
||||
bind(AnonymousUser.class);
|
||||
|
||||
factory(CommitValidators.Factory.class);
|
||||
factory(MergeValidators.Factory.class);
|
||||
factory(NotesBranchUtil.Factory.class);
|
||||
|
||||
bind(AccountManager.class);
|
||||
|
@@ -43,6 +43,8 @@ import com.google.gerrit.server.IdentifiedUser;
|
||||
import com.google.gerrit.server.account.AccountCache;
|
||||
import com.google.gerrit.server.config.AllProjectsName;
|
||||
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
|
||||
import com.google.gerrit.server.git.validators.MergeValidationException;
|
||||
import com.google.gerrit.server.git.validators.MergeValidators;
|
||||
import com.google.gerrit.server.index.ChangeIndexer;
|
||||
import com.google.gerrit.server.mail.MergeFailSender;
|
||||
import com.google.gerrit.server.mail.MergedSender;
|
||||
@@ -130,6 +132,7 @@ public class MergeOp {
|
||||
private final IdentifiedUser.GenericFactory identifiedUserFactory;
|
||||
private final ChangeControl.GenericFactory changeControlFactory;
|
||||
private final MergeQueue mergeQueue;
|
||||
private final MergeValidators.Factory mergeValidatorsFactory;
|
||||
|
||||
private final Branch.NameKey destBranch;
|
||||
private ProjectState destProject;
|
||||
@@ -170,7 +173,8 @@ public class MergeOp {
|
||||
final WorkQueue workQueue,
|
||||
final RequestScopePropagator requestScopePropagator,
|
||||
final AllProjectsName allProjectsName,
|
||||
final ChangeIndexer indexer) {
|
||||
final ChangeIndexer indexer,
|
||||
final MergeValidators.Factory mergeValidatorsFactory) {
|
||||
repoManager = grm;
|
||||
schemaFactory = sf;
|
||||
labelNormalizer = fs;
|
||||
@@ -191,6 +195,7 @@ public class MergeOp {
|
||||
this.requestScopePropagator = requestScopePropagator;
|
||||
this.allProjectsName = allProjectsName;
|
||||
this.indexer = indexer;
|
||||
this.mergeValidatorsFactory = mergeValidatorsFactory;
|
||||
destBranch = branch;
|
||||
toMerge = ArrayListMultimap.create();
|
||||
potentiallyStillSubmittable = new ArrayList<CodeReviewCommit>();
|
||||
@@ -487,6 +492,14 @@ public class MergeOp {
|
||||
continue;
|
||||
}
|
||||
|
||||
MergeValidators mergeValidators = mergeValidatorsFactory.create();
|
||||
try {
|
||||
mergeValidators.validatePreMerge(repo, commit, destProject, destBranch, ps.getId());
|
||||
} catch (MergeValidationException mve) {
|
||||
commits.put(changeId, CodeReviewCommit.error(mve.getStatus()));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (GitRepositoryManager.REF_CONFIG.equals(destBranch.get())) {
|
||||
final Project.NameKey newParent;
|
||||
try {
|
||||
|
@@ -0,0 +1,31 @@
|
||||
// Copyright (C) 2013 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.server.git.CommitMergeStatus;
|
||||
|
||||
public class MergeValidationException extends Exception {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final CommitMergeStatus status;
|
||||
|
||||
public MergeValidationException(CommitMergeStatus status) {
|
||||
super(status.toString());
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public CommitMergeStatus getStatus() {
|
||||
return status;
|
||||
}
|
||||
}
|
@@ -0,0 +1,48 @@
|
||||
// Copyright (C) 2013 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.Branch;
|
||||
import com.google.gerrit.reviewdb.client.PatchSet;
|
||||
import com.google.gerrit.server.git.CodeReviewCommit;
|
||||
import com.google.gerrit.server.project.ProjectState;
|
||||
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
|
||||
/**
|
||||
* Listener to provide validation of commits before merging.
|
||||
*
|
||||
* Invoked by Gerrit before a commit is merged.
|
||||
*/
|
||||
@ExtensionPoint
|
||||
public interface MergeValidationListener {
|
||||
/**
|
||||
* Validate a commit before it is merged.
|
||||
*
|
||||
* @param repo the repository
|
||||
* @param commit commit details
|
||||
* @param destProject the destination project
|
||||
* @param destBranch the destination branch
|
||||
* @param patchSetId the patch set ID
|
||||
* @throws MergeValidationException if the commit fails to validate
|
||||
*/
|
||||
public void onPreMerge(Repository repo,
|
||||
CodeReviewCommit commit,
|
||||
ProjectState destProject,
|
||||
Branch.NameKey destBranch,
|
||||
PatchSet.Id patchSetId)
|
||||
throws MergeValidationException;
|
||||
}
|
@@ -0,0 +1,78 @@
|
||||
// Copyright (C) 2013 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.common.collect.Lists;
|
||||
import com.google.gerrit.extensions.registration.DynamicSet;
|
||||
import com.google.gerrit.reviewdb.client.Branch;
|
||||
import com.google.gerrit.reviewdb.client.PatchSet;
|
||||
import com.google.gerrit.server.git.CodeReviewCommit;
|
||||
import com.google.gerrit.server.project.ProjectState;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class MergeValidators {
|
||||
private final DynamicSet<MergeValidationListener> mergeValidationListeners;
|
||||
|
||||
public interface Factory {
|
||||
MergeValidators create();
|
||||
}
|
||||
|
||||
@Inject
|
||||
MergeValidators(DynamicSet<MergeValidationListener> mergeValidationListeners) {
|
||||
this.mergeValidationListeners = mergeValidationListeners;
|
||||
}
|
||||
|
||||
public void validatePreMerge(Repository repo,
|
||||
CodeReviewCommit commit,
|
||||
ProjectState destProject,
|
||||
Branch.NameKey destBranch,
|
||||
PatchSet.Id patchSetId)
|
||||
throws MergeValidationException {
|
||||
List<MergeValidationListener> validators = Lists.newLinkedList();
|
||||
|
||||
validators.add(new PluginMergeValidationListener(mergeValidationListeners));
|
||||
|
||||
for (MergeValidationListener validator : validators) {
|
||||
validator.onPreMerge(repo, commit, destProject, destBranch, patchSetId);
|
||||
}
|
||||
}
|
||||
|
||||
/** Execute merge validation plug-ins */
|
||||
public static class PluginMergeValidationListener implements
|
||||
MergeValidationListener {
|
||||
private final DynamicSet<MergeValidationListener> mergeValidationListeners;
|
||||
|
||||
public PluginMergeValidationListener(
|
||||
DynamicSet<MergeValidationListener> mergeValidationListeners) {
|
||||
this.mergeValidationListeners = mergeValidationListeners;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPreMerge(Repository repo,
|
||||
CodeReviewCommit commit,
|
||||
ProjectState destProject,
|
||||
Branch.NameKey destBranch,
|
||||
PatchSet.Id patchSetId)
|
||||
throws MergeValidationException {
|
||||
for (MergeValidationListener validator : mergeValidationListeners) {
|
||||
validator.onPreMerge(repo, commit, destProject, destBranch, patchSetId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user