blob: 7b5db511d6f4a92ecb3651bb21e4ad53fe66afc5 [file]
// Copyright (C) 2026 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.owners;
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.Patch;
import com.google.gerrit.entities.PatchSet;
import com.google.gerrit.entities.Project;
import com.google.gerrit.server.patch.DiffNotAvailableException;
import com.google.gerrit.server.patch.DiffOperations;
import com.google.gerrit.server.patch.DiffOptions;
import com.google.gerrit.server.patch.filediff.FileDiffOutput;
import com.googlesource.gerrit.owners.common.InvalidOwnersFileException;
import com.googlesource.gerrit.owners.restapi.GetFilesOwners;
import java.io.IOException;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public final class AutoOwnersApprovalFunctions {
private static final DiffOptions DO_NOT_IGNORE_REBASE =
DiffOptions.builder().skipFilesWithAllEditsDueToRebase(false).build();
public static Map<String, FileDiffOutput> modifiedFilesBetweenPatchSets(
DiffOperations diffOperations,
Project.NameKey project,
PatchSet sourcePatchSet,
PatchSet targetPatchSet)
throws DiffNotAvailableException {
return diffOperations
.listModifiedFiles(
project, sourcePatchSet.commitId(), targetPatchSet.commitId(), DO_NOT_IGNORE_REBASE)
.entrySet()
.stream()
// COMMIT_MSG has never an owner, we don't ever want to consider it, even if it
// was modified as part of this patch-set.
.filter(entry -> !Patch.COMMIT_MSG.equals(entry.getKey()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
public static Set<String> touchedPaths(Map<String, FileDiffOutput> priorVsCurrent) {
return priorVsCurrent.values().stream()
.flatMap(v -> Stream.of(v.newPath(), v.oldPath()))
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toSet());
}
public static boolean allowsAutoApprovalOnPatch(
Account.Id approver,
Account.Id changeOwner,
Account.Id uploader,
Set<String> filesOwnedByApprover,
Set<String> allTouchedFiles,
GetFilesOwners getFilesOwners,
Project.NameKey project,
String branch)
throws IOException, InvalidOwnersFileException {
return approver.equals(changeOwner)
&& approver.equals(uploader)
&& !filesOwnedByApprover.isEmpty()
&& filesOwnedByApprover.size() == allTouchedFiles.size()
&& getFilesOwners.allOwnedFilesAllowAutoApproval(filesOwnedByApprover, project, branch);
}
}