blob: 86765b9ea4b5847fb195e0fa7f99050d92214643 [file] [log] [blame]
// Copyright (C) 2019 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.plugins.checks.api;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableSortedSet;
import com.google.gerrit.entities.Project;
import com.google.gerrit.exceptions.DuplicateKeyException;
import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.extensions.restapi.RestCollectionModifyView;
import com.google.gerrit.extensions.restapi.TopLevelResource;
import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
import com.google.gerrit.plugins.checks.AdministrateCheckersPermission;
import com.google.gerrit.plugins.checks.Checker;
import com.google.gerrit.plugins.checks.CheckerCreation;
import com.google.gerrit.plugins.checks.CheckerJson;
import com.google.gerrit.plugins.checks.CheckerName;
import com.google.gerrit.plugins.checks.CheckerQuery;
import com.google.gerrit.plugins.checks.CheckerUpdate;
import com.google.gerrit.plugins.checks.CheckerUuid;
import com.google.gerrit.plugins.checks.CheckersUpdate;
import com.google.gerrit.plugins.checks.UrlValidator;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.UserInitiated;
import com.google.gerrit.server.permissions.PermissionBackend;
import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectState;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import java.io.IOException;
import org.eclipse.jgit.errors.ConfigInvalidException;
@Singleton
public class CreateChecker
implements RestCollectionModifyView<TopLevelResource, CheckerResource, CheckerInput> {
private final Provider<CurrentUser> self;
private final PermissionBackend permissionBackend;
private final Provider<CheckerQuery> checkerQueryProvider;
private final Provider<CheckersUpdate> checkersUpdate;
private final CheckerJson checkerJson;
private final AdministrateCheckersPermission permission;
private final ProjectCache projectCache;
@Inject
public CreateChecker(
Provider<CurrentUser> self,
PermissionBackend permissionBackend,
Provider<CheckerQuery> checkerQueryProvider,
@UserInitiated Provider<CheckersUpdate> checkersUpdate,
CheckerJson checkerJson,
AdministrateCheckersPermission permission,
ProjectCache projectCache) {
this.self = self;
this.permissionBackend = permissionBackend;
this.checkerQueryProvider = checkerQueryProvider;
this.checkersUpdate = checkersUpdate;
this.checkerJson = checkerJson;
this.permission = permission;
this.projectCache = projectCache;
}
@Override
public Response<CheckerInfo> apply(TopLevelResource parentResource, CheckerInput input)
throws RestApiException, PermissionBackendException, IOException, ConfigInvalidException,
StorageException {
if (!self.get().isIdentifiedUser()) {
throw new AuthException("Authentication required");
}
permissionBackend.currentUser().check(permission);
if (input == null) {
input = new CheckerInput();
}
if (Strings.isNullOrEmpty(input.uuid)) {
throw new BadRequestException("uuid is required");
}
String uuidStr = input.uuid;
CheckerUuid checkerUuid =
CheckerUuid.tryParse(input.uuid)
.orElseThrow(() -> new BadRequestException("invalid uuid: " + uuidStr));
String name = CheckerName.clean(input.name);
if (name.isEmpty()) {
throw new BadRequestException("name is required");
}
Project.NameKey repository = resolveRepository(input.repository);
CheckerCreation.Builder checkerCreationBuilder =
CheckerCreation.builder()
.setCheckerUuid(checkerUuid)
.setName(name)
.setRepository(repository);
CheckerUpdate.Builder checkerUpdateBuilder = CheckerUpdate.builder();
if (input.description != null && !input.description.trim().isEmpty()) {
checkerUpdateBuilder.setDescription(input.description.trim());
}
if (input.url != null) {
checkerUpdateBuilder.setUrl(UrlValidator.clean(input.url));
}
if (input.status != null) {
checkerUpdateBuilder.setStatus(input.status);
}
if (input.blocking != null) {
checkerUpdateBuilder.setBlockingConditions(ImmutableSortedSet.copyOf(input.blocking));
}
if (input.query != null) {
checkerUpdateBuilder.setQuery(validateQuery(checkerUuid, repository, input.query));
}
try {
Checker checker =
checkersUpdate
.get()
.createChecker(checkerCreationBuilder.build(), checkerUpdateBuilder.build());
return Response.created(checkerJson.format(checker));
} catch (DuplicateKeyException e) {
throw new ResourceConflictException(e.getMessage());
}
}
private Project.NameKey resolveRepository(String repository)
throws BadRequestException, UnprocessableEntityException, IOException {
if (repository == null || repository.trim().isEmpty()) {
throw new BadRequestException("repository is required");
}
ProjectState projectState = projectCache.checkedGet(Project.nameKey(repository.trim()));
if (projectState == null) {
throw new UnprocessableEntityException(String.format("repository %s not found", repository));
}
return projectState.getNameKey();
}
private String validateQuery(CheckerUuid checkerUuid, Project.NameKey repository, String query)
throws BadRequestException, StorageException {
try {
return checkerQueryProvider.get().validate(checkerUuid, repository, query);
} catch (ConfigInvalidException e) {
throw new BadRequestException(e.getMessage(), e);
}
}
}