// Copyright (C) 2016 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.server.account; import static com.google.common.base.MoreObjects.firstNonNull; import static java.util.Objects.requireNonNull; import com.google.auto.value.AutoValue; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Enums; import com.google.common.base.Joiner; import com.google.common.base.Splitter; import com.google.common.base.Strings; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ListMultimap; import com.google.common.collect.Multimap; import com.google.common.collect.MultimapBuilder; import com.google.common.collect.Sets; import com.google.gerrit.common.Nullable; import com.google.gerrit.reviewdb.client.Account; import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.server.git.ValidationError; import java.util.ArrayList; import java.util.Collection; import java.util.EnumSet; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.jgit.lib.Config; /** * Parses/writes project watches from/to a {@link Config} file. * *
This is a low-level API. Read/write of project watches in a user branch should be done through * {@link AccountsUpdate} or {@link AccountConfig}. * *
The config file has one 'project' section for all project watches of a project. * *
The project name is used as subsection name and the filters with the notify types that decide
* for which events email notifications should be sent are represented as 'notify' values in the
* subsection. A 'notify' value is formatted as {@code If two notify values in the same subsection have the same filter they are merged on the next
* save, taking the union of the notify types.
*
* For watch configurations that notify on no event the list of notify types is empty:
*
* Unknown notify types are ignored and removed on save.
*
* The project watches are lazily parsed.
*/
public class ProjectWatches {
@AutoValue
public abstract static class ProjectWatchKey {
public static ProjectWatchKey create(Project.NameKey project, @Nullable String filter) {
return new AutoValue_ProjectWatches_ProjectWatchKey(project, Strings.emptyToNull(filter));
}
public abstract Project.NameKey project();
public abstract @Nullable String filter();
}
public enum NotifyType {
// sort by name, except 'ALL' which should stay last
ABANDONED_CHANGES,
ALL_COMMENTS,
NEW_CHANGES,
NEW_PATCHSETS,
SUBMITTED_CHANGES,
ALL
}
public static final String FILTER_ALL = "*";
public static final String WATCH_CONFIG = "watch.config";
public static final String PROJECT = "project";
public static final String KEY_NOTIFY = "notify";
private final Account.Id accountId;
private final Config cfg;
private final ValidationError.Sink validationErrorSink;
private ImmutableMap A project watch is defined on a project and has a filter to match changes for which the
* project watch should be applied. The project and the filter form the map key. The map value is
* a set of notify types that decide for which events email notifications should be sent.
*
* A project watch on the {@code All-Projects} project applies for all projects unless the
* project has a matching project watch.
*
* A project watch can have an empty set of notify types. An empty set of notify types means
* that no notification for matching changes should be set. This is different from no project
* watch as it overwrites matching project watches from the {@code All-Projects} project.
*
* Since we must be able to differentiate a project watch with an empty set of notify types
* from no project watch we can't use a {@link Multimap} as return type.
*
* @param accountId the ID of the account for which the project watches should be parsed
* @param cfg the config file from which the project watches should be parsed
* @param validationErrorSink validation error sink
* @return the parsed project watches
*/
@VisibleForTesting
public static ImmutableMap
* [project "foo"]
* notify = * [ALL_COMMENTS]
* notify = branch:master [ALL_COMMENTS, NEW_PATCHSETS]
* notify = branch:master owner:self [SUBMITTED_CHANGES]
*
*
*
* [project "foo"]
* notify = branch:master []
*
*
*