blob: 5fde1ab3bb59edf1a62e0786e04fe5563e91fb7d [file] [log] [blame]
// Copyright (C) 2013 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.its.base.util;
import com.google.gerrit.extensions.annotations.PluginName;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.server.data.ApprovalAttribute;
import com.google.gerrit.server.data.ChangeAttribute;
import com.google.gerrit.server.data.PatchSetAttribute;
import com.google.gerrit.server.data.RefUpdateAttribute;
import com.google.gerrit.server.events.ChangeAbandonedEvent;
import com.google.gerrit.server.events.ChangeEvent;
import com.google.gerrit.server.events.ChangeMergedEvent;
import com.google.gerrit.server.events.ChangeRestoredEvent;
import com.google.gerrit.server.events.CommentAddedEvent;
import com.google.gerrit.server.events.PatchSetCreatedEvent;
import com.google.gerrit.server.events.PatchSetEvent;
import com.google.gerrit.server.events.RefEvent;
import com.google.gerrit.server.events.RefUpdatedEvent;
import com.google.inject.Inject;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.eclipse.jgit.lib.ObjectId;
/** Extractor to translate an {@link ChangeEvent} to a map of properties}. */
public class PropertyExtractor {
private IssueExtractor issueExtractor;
private PropertyAttributeExtractor propertyAttributeExtractor;
private final String pluginName;
@Inject
PropertyExtractor(
IssueExtractor issueExtractor,
PropertyAttributeExtractor propertyAttributeExtractor,
@PluginName String pluginName) {
this.issueExtractor = issueExtractor;
this.propertyAttributeExtractor = propertyAttributeExtractor;
this.pluginName = pluginName;
}
/**
* creates a patch id for change id string and patchset id string.
*
* @param changeId String representation of the patch sets {@code Change.Id@}
* @param patchId String representation of the patch sets {@code Patchset.Id@}
* @return PatchSet.Id for the specified patch set. If the String to int conversion fails for any
* of the parameters, null is returned.
*/
private PatchSet.Id newPatchSetId(String changeId, String patchId) {
try {
return new PatchSet.Id(new Change.Id(Integer.parseInt(changeId)), Integer.parseInt(patchId));
} catch (NumberFormatException e) {
return null;
}
}
private Map<String, Set<String>> extractMapFrom(PatchSetEvent event, Map<String, String> common) {
ChangeAttribute change = event.change.get();
PatchSetAttribute patchSet = event.patchSet.get();
common.putAll(propertyAttributeExtractor.extractFrom(change));
common.putAll(propertyAttributeExtractor.extractFrom(patchSet));
PatchSet.Id patchSetId =
newPatchSetId(Integer.toString(change.number), Integer.toString(patchSet.number));
return issueExtractor.getIssueIds(change.project, patchSet.revision, patchSetId);
}
private Map<String, Set<String>> extractFrom(
ChangeAbandonedEvent event, Map<String, String> common) {
common.putAll(propertyAttributeExtractor.extractFrom(event.abandoner.get(), "abandoner"));
common.put("reason", event.reason);
return extractMapFrom(event, common);
}
private Map<String, Set<String>> extractFrom(
ChangeMergedEvent event, Map<String, String> common) {
common.putAll(propertyAttributeExtractor.extractFrom(event.submitter.get(), "submitter"));
return extractMapFrom(event, common);
}
private Map<String, Set<String>> extractFrom(
ChangeRestoredEvent event, Map<String, String> common) {
common.putAll(propertyAttributeExtractor.extractFrom(event.restorer.get(), "restorer"));
return extractMapFrom(event, common);
}
private Map<String, Set<String>> extractFrom(RefUpdatedEvent event, Map<String, String> common) {
common.putAll(propertyAttributeExtractor.extractFrom(event.submitter.get(), "submitter"));
common.putAll(propertyAttributeExtractor.extractFrom(event.refUpdate.get()));
RefUpdateAttribute refUpdated = event.refUpdate.get();
if (ObjectId.zeroId().name().equals(refUpdated.newRev)) {
return Collections.emptyMap();
}
return issueExtractor.getIssueIds(event.getProjectNameKey().get(), refUpdated.newRev);
}
private Map<String, Set<String>> extractFrom(
PatchSetCreatedEvent event, Map<String, String> common) {
common.putAll(propertyAttributeExtractor.extractFrom(event.uploader.get(), "uploader"));
return extractMapFrom(event, common);
}
private Map<String, Set<String>> extractFrom(
CommentAddedEvent event, Map<String, String> common) {
common.putAll(propertyAttributeExtractor.extractFrom(event.author.get(), "commenter"));
common.put("comment", event.comment);
if (event.approvals != null) {
for (ApprovalAttribute approvalAttribute : event.approvals.get()) {
common.putAll(propertyAttributeExtractor.extractFrom(approvalAttribute));
}
}
return extractMapFrom(event, common);
}
/**
* A set of properties extracted from an event.
*
* <p>As events may relate to more that a single issue and a group of properties should be tied to
* a single issue, we need to return {@code Set<Map>} of properties. As properties we understand a
* map of event attributes. Using this approach, a PatchSetCreatedEvent for a patch set with
* commit message:
*
* <pre>
* (bug 4711) Fix treatment of special characters in title
*
* This commit mitigates the effects of bug 42, but does not fix them.
*
* Change-Id: I1234567891123456789212345678931234567894
* </pre>
*
* may return both
*
* <pre>
* issue: 4711
* association: subject
* event: patchset-created
* </pre>
*
* and
*
* <pre>
* issue: 42
* association: body
* event: patchset-created
* </pre>
*
* Thereby, sites can choose to cause different actions for different issues associated to the
* same event. So in the above example, a comment "mentioned in change 123" may be added for issue
* 42, and a comment "fixed by change 123” may be added for issue 4711.
*
* @param event The event to extract property maps from.
* @return set of property maps extracted from the event.
*/
public Set<Map<String, String>> extractFrom(RefEvent event) {
Map<String, Set<String>> associations = null;
Map<String, String> common = new HashMap<>();
common.put("event", event.getClass().getName());
common.put("event-type", event.type);
common.put("project", event.getProjectNameKey().get());
common.put("ref", event.getRefName());
common.put("itsName", pluginName);
if (event instanceof ChangeAbandonedEvent) {
associations = extractFrom((ChangeAbandonedEvent) event, common);
} else if (event instanceof ChangeMergedEvent) {
associations = extractFrom((ChangeMergedEvent) event, common);
} else if (event instanceof ChangeRestoredEvent) {
associations = extractFrom((ChangeRestoredEvent) event, common);
} else if (event instanceof CommentAddedEvent) {
associations = extractFrom((CommentAddedEvent) event, common);
} else if (event instanceof PatchSetCreatedEvent) {
associations = extractFrom((PatchSetCreatedEvent) event, common);
} else if (event instanceof RefUpdatedEvent) {
associations = extractFrom((RefUpdatedEvent) event, common);
}
Set<Map<String, String>> ret = new HashSet<>();
if (associations != null) {
for (Entry<String, Set<String>> assoc : associations.entrySet()) {
Map<String, String> properties = new HashMap<>();
properties.put("issue", assoc.getKey());
properties.put("association", String.join(" ", assoc.getValue()));
properties.putAll(common);
ret.add(properties);
}
}
return ret;
}
}