Merge changes I9a7060e3,I8d80186c

* changes:
  Refactor CommitValidators to reduce repetition
  Add test for pushing initial review in empty repo
This commit is contained in:
Edwin Kempin
2016-09-13 08:55:52 +00:00
committed by Gerrit Code Review
7 changed files with 126 additions and 129 deletions

View File

@@ -33,6 +33,7 @@ import com.google.gerrit.acceptance.GerritConfig;
import com.google.gerrit.acceptance.GitUtil; import com.google.gerrit.acceptance.GitUtil;
import com.google.gerrit.acceptance.PushOneCommit; import com.google.gerrit.acceptance.PushOneCommit;
import com.google.gerrit.acceptance.TestAccount; import com.google.gerrit.acceptance.TestAccount;
import com.google.gerrit.acceptance.TestProjectInput;
import com.google.gerrit.common.data.LabelType; import com.google.gerrit.common.data.LabelType;
import com.google.gerrit.common.data.Permission; import com.google.gerrit.common.data.Permission;
import com.google.gerrit.extensions.api.changes.NotifyHandling; import com.google.gerrit.extensions.api.changes.NotifyHandling;
@@ -128,6 +129,27 @@ public abstract class AbstractPushForReview extends AbstractDaemonTest {
r.assertChange(Change.Status.NEW, null); r.assertChange(Change.Status.NEW, null);
} }
@Test
@TestProjectInput(createEmptyCommit = false)
public void pushInitialCommitForMasterBranch() throws Exception {
RevCommit c =
testRepo.commit().message("Initial commit").insertChangeId().create();
String id = GitUtil.getChangeId(testRepo, c).get();
testRepo.reset(c);
String r = "refs/for/master";
PushResult pr = pushHead(testRepo, r, false);
assertPushOk(pr, r);
ChangeInfo change = gApi.changes().id(id).info();
assertThat(change.branch).isEqualTo("master");
assertThat(change.status).isEqualTo(ChangeStatus.NEW);
try (Repository repo = repoManager.openRepository(project)) {
assertThat(repo.resolve("master")).isNull();
}
}
@Test @Test
public void output() throws Exception { public void output() throws Exception {
String url = canonicalWebUrl.get(); String url = canonicalWebUrl.get();

View File

@@ -19,7 +19,6 @@ import com.google.gerrit.extensions.events.GitReferenceUpdatedListener;
import com.google.gerrit.extensions.registration.DynamicSet; import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.server.git.GitModule; import com.google.gerrit.server.git.GitModule;
import com.google.gerrit.server.git.validators.CommitValidationListener; import com.google.gerrit.server.git.validators.CommitValidationListener;
import com.google.gerrit.server.git.validators.CommitValidators;
/** Module for batch programs that need git access. */ /** Module for batch programs that need git access. */
public class BatchGitModule extends FactoryModule { public class BatchGitModule extends FactoryModule {
@@ -27,7 +26,6 @@ public class BatchGitModule extends FactoryModule {
protected void configure() { protected void configure() {
DynamicSet.setOf(binder(), GitReferenceUpdatedListener.class); DynamicSet.setOf(binder(), GitReferenceUpdatedListener.class);
DynamicSet.setOf(binder(), CommitValidationListener.class); DynamicSet.setOf(binder(), CommitValidationListener.class);
factory(CommitValidators.Factory.class);
install(new GitModule()); install(new GitModule());
} }
} }

View File

@@ -41,7 +41,6 @@ import com.google.gerrit.server.PatchSetUtil;
import com.google.gerrit.server.events.CommitReceivedEvent; import com.google.gerrit.server.events.CommitReceivedEvent;
import com.google.gerrit.server.extensions.events.CommentAdded; import com.google.gerrit.server.extensions.events.CommentAdded;
import com.google.gerrit.server.extensions.events.RevisionCreated; import com.google.gerrit.server.extensions.events.RevisionCreated;
import com.google.gerrit.server.git.BanCommit;
import com.google.gerrit.server.git.BatchUpdate; import com.google.gerrit.server.git.BatchUpdate;
import com.google.gerrit.server.git.BatchUpdate.ChangeContext; import com.google.gerrit.server.git.BatchUpdate.ChangeContext;
import com.google.gerrit.server.git.BatchUpdate.Context; import com.google.gerrit.server.git.BatchUpdate.Context;
@@ -66,7 +65,6 @@ import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted; import com.google.inject.assistedinject.Assisted;
import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.notes.NoteMap;
import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.transport.ReceiveCommand; import org.eclipse.jgit.transport.ReceiveCommand;
import org.eclipse.jgit.util.ChangeIdUtil; import org.eclipse.jgit.util.ChangeIdUtil;
@@ -468,9 +466,6 @@ public class ChangeInserter extends BatchUpdate.InsertChangeOp {
try { try {
RefControl refControl = projectControlFactory RefControl refControl = projectControlFactory
.controlFor(ctx.getProject(), ctx.getUser()).controlForRef(refName); .controlFor(ctx.getProject(), ctx.getUser()).controlForRef(refName);
CommitValidators cv = commitValidatorsFactory.create(
refControl, new NoSshInfo(), ctx.getRepository());
String refName = psId.toRefName(); String refName = psId.toRefName();
CommitReceivedEvent event = new CommitReceivedEvent( CommitReceivedEvent event = new CommitReceivedEvent(
new ReceiveCommand( new ReceiveCommand(
@@ -481,19 +476,10 @@ public class ChangeInserter extends BatchUpdate.InsertChangeOp {
change.getDest().get(), change.getDest().get(),
commit, commit,
ctx.getIdentifiedUser()); ctx.getIdentifiedUser());
commitValidatorsFactory
switch (validatePolicy) { .create(
case RECEIVE_COMMITS: validatePolicy, refControl, new NoSshInfo(), ctx.getRepository())
NoteMap rejectCommits = BanCommit.loadRejectCommitsMap( .validate(event);
ctx.getRepository(), ctx.getRevWalk());
cv.validateForReceiveCommits(event, rejectCommits);
break;
case GERRIT:
cv.validateForGerritCommits(event);
break;
case NONE:
break;
}
} catch (CommitValidationException e) { } catch (CommitValidationException e) {
throw new ResourceConflictException(e.getFullMessage()); throw new ResourceConflictException(e.getFullMessage());
} catch (NoSuchProjectException e) { } catch (NoSuchProjectException e) {

View File

@@ -35,7 +35,6 @@ import com.google.gerrit.server.PatchSetUtil;
import com.google.gerrit.server.ReviewerSet; import com.google.gerrit.server.ReviewerSet;
import com.google.gerrit.server.events.CommitReceivedEvent; import com.google.gerrit.server.events.CommitReceivedEvent;
import com.google.gerrit.server.extensions.events.RevisionCreated; import com.google.gerrit.server.extensions.events.RevisionCreated;
import com.google.gerrit.server.git.BanCommit;
import com.google.gerrit.server.git.BatchUpdate; import com.google.gerrit.server.git.BatchUpdate;
import com.google.gerrit.server.git.BatchUpdate.ChangeContext; import com.google.gerrit.server.git.BatchUpdate.ChangeContext;
import com.google.gerrit.server.git.BatchUpdate.Context; import com.google.gerrit.server.git.BatchUpdate.Context;
@@ -52,7 +51,6 @@ import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject; import com.google.inject.assistedinject.AssistedInject;
import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.notes.NoteMap;
import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.transport.ReceiveCommand; import org.eclipse.jgit.transport.ReceiveCommand;
import org.slf4j.Logger; import org.slf4j.Logger;
@@ -275,12 +273,12 @@ public class PatchSetInserter extends BatchUpdate.Op {
private void validate(RepoContext ctx) private void validate(RepoContext ctx)
throws AuthException, ResourceConflictException, IOException, throws AuthException, ResourceConflictException, IOException,
OrmException { OrmException {
CommitValidators cv = commitValidatorsFactory.create(
origCtl.getRefControl(), new NoSshInfo(), ctx.getRepository());
if (!origCtl.canAddPatchSet(ctx.getDb())) { if (!origCtl.canAddPatchSet(ctx.getDb())) {
throw new AuthException("cannot add patch set"); throw new AuthException("cannot add patch set");
} }
if (validatePolicy == CommitValidators.Policy.NONE) {
return;
}
String refName = getPatchSetId().toRefName(); String refName = getPatchSetId().toRefName();
CommitReceivedEvent event = new CommitReceivedEvent( CommitReceivedEvent event = new CommitReceivedEvent(
@@ -293,18 +291,11 @@ public class PatchSetInserter extends BatchUpdate.Op {
commit, ctx.getIdentifiedUser()); commit, ctx.getIdentifiedUser());
try { try {
switch (validatePolicy) { commitValidatorsFactory
case RECEIVE_COMMITS: .create(
NoteMap rejectCommits = BanCommit.loadRejectCommitsMap( validatePolicy, origCtl.getRefControl(), new NoSshInfo(),
ctx.getRepository(), ctx.getRevWalk()); ctx.getRepository())
cv.validateForReceiveCommits(event, rejectCommits); .validate(event);
break;
case GERRIT:
cv.validateForGerritCommits(event);
break;
case NONE:
break;
}
} catch (CommitValidationException e) { } catch (CommitValidationException e) {
throw new ResourceConflictException(e.getFullMessage()); throw new ResourceConflictException(e.getFullMessage());
} }

View File

@@ -116,7 +116,6 @@ import com.google.gerrit.server.git.TagCache;
import com.google.gerrit.server.git.TransferConfig; import com.google.gerrit.server.git.TransferConfig;
import com.google.gerrit.server.git.strategy.SubmitStrategy; import com.google.gerrit.server.git.strategy.SubmitStrategy;
import com.google.gerrit.server.git.validators.CommitValidationListener; 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.MergeValidationListener;
import com.google.gerrit.server.git.validators.MergeValidators; import com.google.gerrit.server.git.validators.MergeValidators;
import com.google.gerrit.server.git.validators.MergeValidators.ProjectConfigValidator; import com.google.gerrit.server.git.validators.MergeValidators.ProjectConfigValidator;
@@ -372,7 +371,6 @@ public class GerritGlobalModule extends FactoryModule {
bind(AnonymousUser.class); bind(AnonymousUser.class);
factory(CommitValidators.Factory.class);
factory(RefOperationValidators.Factory.class); factory(RefOperationValidators.Factory.class);
factory(MergeValidators.Factory.class); factory(MergeValidators.Factory.class);
factory(ProjectConfigValidator.Factory.class); factory(ProjectConfigValidator.Factory.class);

View File

@@ -2588,12 +2588,11 @@ public class ReceiveCommits {
rw.parseBody(c); rw.parseBody(c);
CommitReceivedEvent receiveEvent = CommitReceivedEvent receiveEvent =
new CommitReceivedEvent(cmd, project, ctl.getRefName(), c, user); new CommitReceivedEvent(cmd, project, ctl.getRefName(), c, user);
CommitValidators commitValidators = CommitValidators commitValidators = commitValidatorsFactory.create(
commitValidatorsFactory.create(ctl, sshInfo, repo); CommitValidators.Policy.RECEIVE_COMMITS, ctl, sshInfo, repo);
try { try {
messages.addAll(commitValidators.validateForReceiveCommits( messages.addAll(commitValidators.validate(receiveEvent));
receiveEvent, rejectCommits));
} catch (CommitValidationException e) { } catch (CommitValidationException e) {
logDebug("Commit validation failed on {}", c.name()); logDebug("Commit validation failed on {}", c.name());
messages.addAll(e.getMessages()); messages.addAll(e.getMessages());

View File

@@ -16,8 +16,10 @@ package com.google.gerrit.server.git.validators;
import static com.google.gerrit.reviewdb.client.Change.CHANGE_ID_PATTERN; import static com.google.gerrit.reviewdb.client.Change.CHANGE_ID_PATTERN;
import static com.google.gerrit.reviewdb.client.RefNames.REFS_CONFIG; import static com.google.gerrit.reviewdb.client.RefNames.REFS_CONFIG;
import static com.google.gerrit.server.git.ReceiveCommits.NEW_PATCHSET;
import com.google.common.base.CharMatcher; import com.google.common.base.CharMatcher;
import com.google.common.collect.ImmutableList;
import com.google.gerrit.common.FooterConstants; import com.google.gerrit.common.FooterConstants;
import com.google.gerrit.common.Nullable; import com.google.gerrit.common.Nullable;
import com.google.gerrit.common.PageLinks; import com.google.gerrit.common.PageLinks;
@@ -31,15 +33,15 @@ import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.config.CanonicalWebUrl; import com.google.gerrit.server.config.CanonicalWebUrl;
import com.google.gerrit.server.config.GerritServerConfig; import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.events.CommitReceivedEvent; import com.google.gerrit.server.events.CommitReceivedEvent;
import com.google.gerrit.server.git.BanCommit;
import com.google.gerrit.server.git.ProjectConfig; import com.google.gerrit.server.git.ProjectConfig;
import com.google.gerrit.server.git.ReceiveCommits;
import com.google.gerrit.server.git.ValidationError; import com.google.gerrit.server.git.ValidationError;
import com.google.gerrit.server.project.ProjectControl; import com.google.gerrit.server.project.ProjectControl;
import com.google.gerrit.server.project.RefControl; import com.google.gerrit.server.project.RefControl;
import com.google.gerrit.server.ssh.SshInfo; import com.google.gerrit.server.ssh.SshInfo;
import com.google.gerrit.server.util.MagicBranch; import com.google.gerrit.server.util.MagicBranch;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted; import com.google.inject.Singleton;
import com.jcraft.jsch.HostKey; import com.jcraft.jsch.HostKey;
@@ -51,6 +53,7 @@ import org.eclipse.jgit.notes.NoteMap;
import org.eclipse.jgit.revwalk.FooterKey; import org.eclipse.jgit.revwalk.FooterKey;
import org.eclipse.jgit.revwalk.FooterLine; import org.eclipse.jgit.revwalk.FooterLine;
import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.util.SystemReader; import org.eclipse.jgit.util.SystemReader;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -68,107 +71,99 @@ public class CommitValidators {
.getLogger(CommitValidators.class); .getLogger(CommitValidators.class);
public enum Policy { public enum Policy {
/** Use {@link #validateForGerritCommits}. */ /** Use {@link Factory#forGerritCommits}. */
GERRIT, GERRIT,
/** Use {@link #validateForReceiveCommits}. */ /** Use {@link Factory#forReceiveCommits}. */
RECEIVE_COMMITS, RECEIVE_COMMITS,
/** Do not validate commits. */ /** Do not validate commits. */
NONE NONE
} }
public interface Factory { @Singleton
CommitValidators create(RefControl refControl, SshInfo sshInfo, public static class Factory {
Repository repo); private final PersonIdent gerritIdent;
} private final String canonicalWebUrl;
private final DynamicSet<CommitValidationListener> pluginValidators;
private final AllUsersName allUsers;
private final String installCommitMsgHookCommand;
private final PersonIdent gerritIdent; @Inject
private final RefControl refControl; Factory(@GerritPersonIdent PersonIdent gerritIdent,
private final String canonicalWebUrl; @CanonicalWebUrl @Nullable String canonicalWebUrl,
private final String installCommitMsgHookCommand; @GerritServerConfig Config cfg,
private final SshInfo sshInfo; DynamicSet<CommitValidationListener> pluginValidators,
private final Repository repo; AllUsersName allUsers) {
private final DynamicSet<CommitValidationListener> commitValidationListeners; this.gerritIdent = gerritIdent;
private final AllUsersName allUsers; this.canonicalWebUrl = canonicalWebUrl;
this.pluginValidators = pluginValidators;
@Inject this.allUsers = allUsers;
CommitValidators(@GerritPersonIdent PersonIdent gerritIdent, this.installCommitMsgHookCommand = cfg != null
@CanonicalWebUrl @Nullable String canonicalWebUrl, ? cfg.getString("gerrit", null, "installCommitMsgHookCommand") : null;
@GerritServerConfig Config config,
DynamicSet<CommitValidationListener> commitValidationListeners,
AllUsersName allUsers,
@Assisted SshInfo sshInfo,
@Assisted Repository repo,
@Assisted RefControl refControl) {
this.gerritIdent = gerritIdent;
this.canonicalWebUrl = canonicalWebUrl;
this.installCommitMsgHookCommand =
config.getString("gerrit", null, "installCommitMsgHookCommand");
this.commitValidationListeners = commitValidationListeners;
this.allUsers = allUsers;
this.sshInfo = sshInfo;
this.repo = repo;
this.refControl = refControl;
}
public List<CommitValidationMessage> validateForReceiveCommits(
CommitReceivedEvent receiveEvent, NoteMap rejectCommits)
throws CommitValidationException {
List<CommitValidationListener> validators = new LinkedList<>();
validators.add(new UploadMergesPermissionValidator(refControl));
validators.add(new AmendedGerritMergeCommitValidationListener(
refControl, gerritIdent));
validators.add(new AuthorUploaderValidator(refControl, canonicalWebUrl));
validators.add(new CommitterUploaderValidator(refControl, canonicalWebUrl));
validators.add(new SignedOffByValidator(refControl));
if (MagicBranch.isMagicBranch(receiveEvent.command.getRefName())
|| ReceiveCommits.NEW_PATCHSET.matcher(
receiveEvent.command.getRefName()).matches()) {
validators.add(new ChangeIdValidator(refControl, canonicalWebUrl,
installCommitMsgHookCommand, sshInfo));
} }
validators.add(new ConfigValidator(refControl, repo, allUsers));
validators.add(new BannedCommitsValidator(rejectCommits));
validators.add(new PluginCommitValidationListener(commitValidationListeners));
List<CommitValidationMessage> messages = new LinkedList<>(); public CommitValidators create(Policy policy, RefControl refControl,
SshInfo sshInfo, Repository repo) throws IOException {
try { switch (policy) {
for (CommitValidationListener commitValidator : validators) { case RECEIVE_COMMITS:
messages.addAll(commitValidator.onCommitReceived(receiveEvent)); return forReceiveCommits(refControl, sshInfo, repo);
case GERRIT:
return forGerritCommits(refControl, sshInfo, repo);
case NONE:
return none();
default:
throw new IllegalArgumentException("unspported policy: " + policy);
} }
} catch (CommitValidationException e) {
// Keep the old messages (and their order) in case of an exception
messages.addAll(e.getMessages());
throw new CommitValidationException(e.getMessage(), messages);
} }
return messages;
private CommitValidators forReceiveCommits(RefControl refControl,
SshInfo sshInfo, Repository repo) throws IOException {
try (RevWalk rw = new RevWalk(repo)) {
NoteMap rejectCommits = BanCommit.loadRejectCommitsMap(repo, rw);
return new CommitValidators(ImmutableList.of(
new UploadMergesPermissionValidator(refControl),
new AmendedGerritMergeCommitValidationListener(
refControl, gerritIdent),
new AuthorUploaderValidator(refControl, canonicalWebUrl),
new CommitterUploaderValidator(refControl, canonicalWebUrl),
new SignedOffByValidator(refControl),
new ChangeIdValidator(refControl, canonicalWebUrl,
installCommitMsgHookCommand, sshInfo),
new ConfigValidator(refControl, repo, allUsers),
new BannedCommitsValidator(rejectCommits),
new PluginCommitValidationListener(pluginValidators)));
}
}
private CommitValidators forGerritCommits(RefControl refControl,
SshInfo sshInfo, Repository repo) {
return new CommitValidators(ImmutableList.of(
new UploadMergesPermissionValidator(refControl),
new AmendedGerritMergeCommitValidationListener(
refControl, gerritIdent),
new AuthorUploaderValidator(refControl, canonicalWebUrl),
new SignedOffByValidator(refControl),
new ChangeIdValidator(refControl, canonicalWebUrl,
installCommitMsgHookCommand, sshInfo),
new ConfigValidator(refControl, repo, allUsers),
new PluginCommitValidationListener(pluginValidators)));
}
private CommitValidators none() {
return new CommitValidators(ImmutableList.<CommitValidationListener>of());
}
} }
public List<CommitValidationMessage> validateForGerritCommits( private final List<CommitValidationListener> validators;
CommitValidators(List<CommitValidationListener> validators) {
this.validators = validators;
}
public List<CommitValidationMessage> validate(
CommitReceivedEvent receiveEvent) throws CommitValidationException { CommitReceivedEvent receiveEvent) throws CommitValidationException {
List<CommitValidationListener> validators = new LinkedList<>();
validators.add(new UploadMergesPermissionValidator(refControl));
validators.add(new AmendedGerritMergeCommitValidationListener(
refControl, gerritIdent));
validators.add(new AuthorUploaderValidator(refControl, canonicalWebUrl));
validators.add(new SignedOffByValidator(refControl));
if (MagicBranch.isMagicBranch(receiveEvent.command.getRefName())
|| ReceiveCommits.NEW_PATCHSET.matcher(
receiveEvent.command.getRefName()).matches()) {
validators.add(new ChangeIdValidator(refControl, canonicalWebUrl,
installCommitMsgHookCommand, sshInfo));
}
validators.add(new ConfigValidator(refControl, repo, allUsers));
validators.add(new PluginCommitValidationListener(commitValidationListeners));
List<CommitValidationMessage> messages = new LinkedList<>(); List<CommitValidationMessage> messages = new LinkedList<>();
try { try {
for (CommitValidationListener commitValidator : validators) { for (CommitValidationListener commitValidator : validators) {
messages.addAll(commitValidator.onCommitReceived(receiveEvent)); messages.addAll(commitValidator.onCommitReceived(receiveEvent));
@@ -221,6 +216,9 @@ public class CommitValidators {
@Override @Override
public List<CommitValidationMessage> onCommitReceived( public List<CommitValidationMessage> onCommitReceived(
CommitReceivedEvent receiveEvent) throws CommitValidationException { CommitReceivedEvent receiveEvent) throws CommitValidationException {
if (!shouldValidateChangeId(receiveEvent)) {
return Collections.emptyList();
}
RevCommit commit = receiveEvent.commit; RevCommit commit = receiveEvent.commit;
List<CommitValidationMessage> messages = new LinkedList<>(); List<CommitValidationMessage> messages = new LinkedList<>();
List<String> idList = commit.getFooterLines(FooterConstants.CHANGE_ID); List<String> idList = commit.getFooterLines(FooterConstants.CHANGE_ID);
@@ -255,6 +253,11 @@ public class CommitValidators {
return Collections.emptyList(); return Collections.emptyList();
} }
private static boolean shouldValidateChangeId(CommitReceivedEvent event) {
return MagicBranch.isMagicBranch(event.command.getRefName())
|| NEW_PATCHSET.matcher(event.command.getRefName()).matches();
}
private CommitValidationMessage getMissingChangeIdErrorMsg( private CommitValidationMessage getMissingChangeIdErrorMsg(
final String errMsg, final RevCommit c) { final String errMsg, final RevCommit c) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();