blob: ce47bdb6d0feeb16e695251840c91bbbb7f93cd5 [file] [log] [blame]
// 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.googlesource.gerrit.plugins.hooks.validation;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.transport.ReceiveCommand;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.events.CommitReceivedEvent;
import com.google.gerrit.server.git.validators.CommitValidationException;
import com.google.gerrit.server.git.validators.CommitValidationListener;
import com.google.gerrit.server.git.validators.CommitValidationMessage;
import com.google.inject.Inject;
import com.googlesource.gerrit.plugins.hooks.its.ItsFacade;
import com.googlesource.gerrit.plugins.hooks.its.ItsName;
import com.googlesource.gerrit.plugins.hooks.util.IssueExtractor;
public class ItsValidateComment implements CommitValidationListener {
private static final Logger log = LoggerFactory
.getLogger(ItsValidateComment.class);
@Inject
private ItsFacade client;
@Inject
@GerritServerConfig
private Config gerritConfig;
@Inject @ItsName
private String itsName;
@Inject
private IssueExtractor issueExtractor;
public List<CommitValidationMessage> validCommit(ReceiveCommand cmd, RevCommit commit) throws CommitValidationException {
Pattern pattern = issueExtractor.getPattern();
if (pattern == null) {
return Collections.emptyList();
}
String message = commit.getFullMessage();
log.debug("Searching comment " + message.trim() + " for pattern "
+ pattern.pattern());
String issueId = null;
ItsAssociationPolicy associationPolicy = ItsAssociationPolicy.OPTIONAL;
Matcher matcher = pattern.matcher(message);
associationPolicy = getItsAssociationPolicy();
if (matcher.find()) {
issueId = issueExtractor.extractMatchedWorkItems(matcher);
log.debug("Pattern matched on comment '{}' with issue id '{}'",
message.trim(), issueId);
}
String validationMessage = null;
if (pattern != null && issueId == null) {
validationMessage =
"Missing issue-id in commit message\n"
+ "Commit "
+ commit.getId().getName()
+ " not associated to any issue\n"
+ "\n"
+ "Hint: insert one or more issue-id anywhere in the commit message.\n"
+ " Issue-ids are strings matching " + pattern.pattern() + "\n"
+ " and are pointing to existing tickets on "
+ client.name() + " Issue-Tracker";
} else if (pattern != null && !isWorkitemPresent(issueId, message)) {
validationMessage =
"Issue " + issueId + " not found or visible in " + client.name()
+ " Issue-Tracker";
} else {
return Collections.emptyList();
}
switch (associationPolicy) {
case MANDATORY:
throw new CommitValidationException(validationMessage.split("\n")[0],
Collections.singletonList(new CommitValidationMessage("\n"
+ validationMessage + "\n", false)));
case SUGGESTED:
return Collections.singletonList(new CommitValidationMessage("\n"
+ validationMessage + "\n", false));
default:
return Collections.emptyList();
}
}
private boolean isWorkitemPresent(String issueId, String comment) {
boolean exist = false;
if (issueId != null) {
try {
if (!client.exists(issueId)) {
log.warn("Workitem " + issueId + " declared in the comment "
+ comment + " but not found on ITS");
} else {
exist = true;
log.debug("Workitem " + issueId + " found");
}
} catch (IOException ex) {
log.warn("Unexpected error accessint ITS", ex);
}
} else {
log.debug("Rejecting commit: no pattern matched on comment " + comment);
}
return exist;
}
private ItsAssociationPolicy getItsAssociationPolicy() {
return gerritConfig.getEnum("commentLink", itsName, "association",
ItsAssociationPolicy.OPTIONAL);
}
@Override
public List<CommitValidationMessage> onCommitReceived(
CommitReceivedEvent receiveEvent) throws CommitValidationException {
return validCommit(receiveEvent.command, receiveEvent.commit);
}
}