blob: e7dc004cc202548018056df07c132274959ee4c6 [file] [log] [blame]
// Copyright (C) 2014 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.reviewers;
import com.google.common.base.Objects;
import com.google.gerrit.common.ChangeHooks;
import com.google.gerrit.extensions.annotations.PluginName;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.extensions.restapi.RestModifyView;
import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Branch;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.RefNames;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.account.AccountResolver;
import com.google.gerrit.server.git.MetaDataUpdate;
import com.google.gerrit.server.group.GroupsCollection;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectResource;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import com.googlesource.gerrit.plugins.reviewers.PutReviewers.Input;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.lib.ObjectId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.List;
@Singleton
class PutReviewers implements RestModifyView<ProjectResource, Input> {
private static final Logger log = LoggerFactory
.getLogger(PutReviewers.class);
public static class Input {
public Action action;
public String filter;
public String reviewer;
}
private final String pluginName;
private final ReviewersConfig.Factory configFactory;
private final Provider<MetaDataUpdate.User> metaDataUpdateFactory;
private final ProjectCache projectCache;
private final Provider<CurrentUser> currentUser;
private final ChangeHooks hooks;
private final AccountResolver accountResolver;
private final Provider<GroupsCollection> groupsCollection;
@Inject
PutReviewers(@PluginName String pluginName,
ReviewersConfig.Factory configFactory,
Provider<MetaDataUpdate.User> metaDataUpdateFactory,
ProjectCache projectCache,
ChangeHooks hooks,
Provider<CurrentUser> currentUser,
AccountResolver accountResolver,
Provider<GroupsCollection> groupsCollection) {
this.pluginName = pluginName;
this.configFactory = configFactory;
this.metaDataUpdateFactory = metaDataUpdateFactory;
this.projectCache = projectCache;
this.hooks = hooks;
this.currentUser = currentUser;
this.accountResolver = accountResolver;
this.groupsCollection = groupsCollection;
}
@Override
public List<ReviewerFilterSection> apply(ProjectResource rsrc, Input input)
throws RestApiException {
Project.NameKey projectName = rsrc.getNameKey();
ReviewersConfig cfg = configFactory.create(projectName);
if (!rsrc.getControl().isOwner() || cfg == null) {
throw new ResourceNotFoundException(
"Project" + projectName.get() + " not found");
}
MetaDataUpdate md;
try {
md = metaDataUpdateFactory.get().create(projectName);
} catch (RepositoryNotFoundException notFound) {
throw new ResourceNotFoundException(
"Project" + projectName.get() + " not found");
} catch (IOException e) {
throw new ResourceNotFoundException(
"Project" + projectName.get() + " not found", e);
}
if (input.action == Action.ADD) {
validateReviewer(input.reviewer);
}
try {
StringBuilder message = new StringBuilder(pluginName)
.append(" plugin: ");
cfg.load(md);
if (input.action == Action.ADD) {
message.append("Add reviewer ")
.append(input.reviewer)
.append(" to filter ")
.append(input.filter);
cfg.addReviewer(input.filter, input.reviewer);
} else {
message.append("Remove reviewer ")
.append(input.reviewer)
.append(" from filter ")
.append(input.filter);
cfg.removeReviewer(input.filter, input.reviewer);
}
message.append("\n");
md.setMessage(message.toString());
try {
ObjectId baseRev = cfg.getRevision();
ObjectId commitRev = cfg.commit(md);
// Only fire hook if project was actually changed.
if (!Objects.equal(baseRev, commitRev)) {
IdentifiedUser user = (IdentifiedUser) currentUser.get();
hooks.doRefUpdatedHook(
new Branch.NameKey(projectName, RefNames.REFS_CONFIG),
baseRev, commitRev, user.getAccount());
}
projectCache.evict(projectName);
} catch (IOException e) {
if (e.getCause() instanceof ConfigInvalidException) {
throw new ResourceConflictException("Cannot update " + projectName
+ ": " + e.getCause().getMessage());
} else {
throw new ResourceConflictException("Cannot update " + projectName);
}
}
} catch (ConfigInvalidException err) {
throw new ResourceConflictException("Cannot read " + pluginName
+ " configurations for project " + projectName, err);
} catch (IOException err) {
throw new ResourceConflictException("Cannot update " + pluginName
+ " configurations for project " + projectName, err);
} finally {
md.close();
}
return cfg.getReviewerFilterSections();
}
private void validateReviewer(String reviewer) throws RestApiException {
try {
Account account = accountResolver.find(reviewer);
if (account == null) {
try {
groupsCollection.get().parse(reviewer);
} catch (UnprocessableEntityException e) {
throw new ResourceNotFoundException(
"Account or group " + reviewer + " not found");
}
}
} catch (OrmException e) {
log.error("Failed to resolve account " + reviewer);
}
}
}