Line data Source code
1 : // Copyright (C) 2015 The Android Open Source Project 2 : // 3 : // Licensed under the Apache License, Version 2.0 (the "License"); 4 : // you may not use this file except in compliance with the License. 5 : // You may obtain a copy of the License at 6 : // 7 : // http://www.apache.org/licenses/LICENSE-2.0 8 : // 9 : // Unless required by applicable law or agreed to in writing, software 10 : // distributed under the License is distributed on an "AS IS" BASIS, 11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 : // See the License for the specific language governing permissions and 13 : // limitations under the License. 14 : 15 : package com.google.gerrit.server.extensions.events; 16 : 17 : import com.google.common.collect.ImmutableSet; 18 : import com.google.common.collect.Sets; 19 : import com.google.common.flogger.FluentLogger; 20 : import com.google.gerrit.common.Nullable; 21 : import com.google.gerrit.entities.Account; 22 : import com.google.gerrit.entities.PatchSet; 23 : import com.google.gerrit.entities.Project; 24 : import com.google.gerrit.extensions.client.ListChangesOption; 25 : import com.google.gerrit.extensions.common.AccountInfo; 26 : import com.google.gerrit.extensions.common.ApprovalInfo; 27 : import com.google.gerrit.extensions.common.ChangeInfo; 28 : import com.google.gerrit.extensions.common.RevisionInfo; 29 : import com.google.gerrit.server.GpgException; 30 : import com.google.gerrit.server.account.AccountState; 31 : import com.google.gerrit.server.change.ChangeJson; 32 : import com.google.gerrit.server.change.RevisionJson; 33 : import com.google.gerrit.server.config.GerritServerConfig; 34 : import com.google.gerrit.server.patch.PatchListNotAvailableException; 35 : import com.google.gerrit.server.permissions.PermissionBackendException; 36 : import com.google.gerrit.server.query.change.ChangeData; 37 : import com.google.inject.Inject; 38 : import com.google.inject.Singleton; 39 : import java.io.IOException; 40 : import java.time.Instant; 41 : import java.util.EnumSet; 42 : import java.util.HashMap; 43 : import java.util.Map; 44 : import org.eclipse.jgit.lib.Config; 45 : 46 : /** 47 : * Formats change and revision info objects to serve as payload for Gerrit events. 48 : * 49 : * <p>Uses configurable options ({@code event.payload.listChangeOptions}) to decide which change 50 : * fields to populate. 51 : */ 52 : @Singleton 53 : public class EventUtil { 54 151 : private static final FluentLogger logger = FluentLogger.forEnclosingClass(); 55 : 56 : private static final ImmutableSet<ListChangesOption> DEFAULT_CHANGE_OPTIONS; 57 : 58 : static { 59 151 : EnumSet<ListChangesOption> opts = EnumSet.allOf(ListChangesOption.class); 60 : // Some options, like actions, are expensive to compute because they potentially have to walk 61 : // lots of history and inspect lots of other changes. 62 151 : opts.remove(ListChangesOption.CHANGE_ACTIONS); 63 151 : opts.remove(ListChangesOption.CURRENT_ACTIONS); 64 : // CHECK suppresses some exceptions on corrupt changes, which is not appropriate for passing 65 : // through the event system as we would rather let them propagate. 66 151 : opts.remove(ListChangesOption.CHECK); 67 151 : DEFAULT_CHANGE_OPTIONS = Sets.immutableEnumSet(opts); 68 151 : } 69 : 70 : private final ChangeData.Factory changeDataFactory; 71 : private final ChangeJson.Factory changeJsonFactory; 72 : private final RevisionJson.Factory revisionJsonFactory; 73 : private final ImmutableSet<ListChangesOption> changeOptions; 74 : 75 : @Inject 76 : EventUtil( 77 : ChangeJson.Factory changeJsonFactory, 78 : RevisionJson.Factory revisionJsonFactory, 79 : ChangeData.Factory changeDataFactory, 80 151 : @GerritServerConfig Config gerritConfig) { 81 151 : this.changeDataFactory = changeDataFactory; 82 151 : this.changeJsonFactory = changeJsonFactory; 83 151 : this.revisionJsonFactory = revisionJsonFactory; 84 151 : this.changeOptions = parseChangeListOptions(gerritConfig); 85 151 : } 86 : 87 : public ChangeInfo changeInfo(ChangeData changeData) { 88 100 : return changeJsonFactory.create(changeOptions).format(changeData); 89 : } 90 : 91 : public RevisionInfo revisionInfo(Project project, PatchSet ps) 92 : throws PatchListNotAvailableException, GpgException, IOException, PermissionBackendException { 93 0 : return revisionInfo(project.getNameKey(), ps); 94 : } 95 : 96 : public RevisionInfo revisionInfo(Project.NameKey project, PatchSet ps) 97 : throws PatchListNotAvailableException, GpgException, IOException, PermissionBackendException { 98 99 : ChangeData cd = changeDataFactory.create(project, ps.id().changeId()); 99 99 : return revisionJsonFactory.create(changeOptions).getRevisionInfo(cd, ps); 100 : } 101 : 102 : @Nullable 103 : public AccountInfo accountInfo(@Nullable AccountState accountState) { 104 151 : if (accountState == null || accountState.account().id() == null) { 105 151 : return null; 106 : } 107 151 : Account account = accountState.account(); 108 151 : AccountInfo accountInfo = new AccountInfo(account.id().get()); 109 151 : accountInfo.email = account.preferredEmail(); 110 151 : accountInfo.name = account.fullName(); 111 151 : accountInfo.username = accountState.userName().orElse(null); 112 151 : return accountInfo; 113 : } 114 : 115 : public Map<String, ApprovalInfo> approvals( 116 : AccountState accountState, Map<String, Short> approvals, Instant ts) { 117 61 : Map<String, ApprovalInfo> result = new HashMap<>(); 118 61 : for (Map.Entry<String, Short> e : approvals.entrySet()) { 119 61 : Integer value = e.getValue() != null ? Integer.valueOf(e.getValue()) : null; 120 61 : result.put( 121 61 : e.getKey(), new ApprovalInfo(accountState.account().id().get(), value, null, null, ts)); 122 61 : } 123 61 : return result; 124 : } 125 : 126 : private static ImmutableSet<ListChangesOption> parseChangeListOptions(Config gerritConfig) { 127 151 : String[] config = gerritConfig.getStringList("event", "payload", "listChangeOptions"); 128 151 : if (config.length == 0) { 129 151 : return DEFAULT_CHANGE_OPTIONS; 130 : } 131 : 132 1 : ImmutableSet.Builder<ListChangesOption> result = ImmutableSet.builder(); 133 1 : for (String c : config) { 134 : try { 135 1 : result.add(ListChangesOption.valueOf(c)); 136 0 : } catch (IllegalArgumentException e) { 137 0 : logger.atWarning().withCause(e).log("could not parse list change option %s", c); 138 1 : } 139 : } 140 1 : return result.build(); 141 : } 142 : }