blob: 7d6fcdbb5ae9b1caec520f6593422edbccc52409 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011 Tasktop Technologies and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Tasktop Technologies - initial API and implementation
* Sascha Scholz (SAP) - improvements
*******************************************************************************/
package org.eclipse.mylyn.internal.gerrit.core;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import org.eclipse.core.runtime.Assert;
import org.eclipse.mylyn.internal.gerrit.core.client.GerritChange;
import org.eclipse.mylyn.internal.gerrit.core.client.GerritConfiguration;
import org.eclipse.mylyn.internal.gerrit.core.client.GerritException;
import org.eclipse.mylyn.internal.gerrit.core.client.GerritPatchSetContent;
import org.eclipse.mylyn.internal.gerrit.core.client.JSonSupport;
import org.eclipse.mylyn.internal.gerrit.core.client.compat.ProjectDetailX;
import org.eclipse.mylyn.reviews.core.model.IComment;
import org.eclipse.mylyn.reviews.core.model.IFileItem;
import org.eclipse.mylyn.reviews.core.model.IFileRevision;
import org.eclipse.mylyn.reviews.core.model.ILineLocation;
import org.eclipse.mylyn.reviews.core.model.ILineRange;
import org.eclipse.mylyn.reviews.core.model.IReview;
import org.eclipse.mylyn.reviews.core.model.IReviewItem;
import org.eclipse.mylyn.reviews.core.model.IReviewItemSet;
import org.eclipse.mylyn.reviews.core.model.ITopic;
import org.eclipse.mylyn.reviews.core.model.IUser;
import org.eclipse.mylyn.reviews.internal.core.model.ReviewsFactory;
import org.eclipse.mylyn.tasks.core.TaskRepository;
import org.eclipse.mylyn.tasks.core.data.TaskAttribute;
import org.eclipse.mylyn.tasks.core.data.TaskData;
import org.eclipse.osgi.util.NLS;
import com.google.gerrit.common.data.AccountInfo;
import com.google.gerrit.common.data.AccountInfoCache;
import com.google.gerrit.common.data.ChangeDetail;
import com.google.gerrit.common.data.CommentDetail;
import com.google.gerrit.common.data.GerritConfig;
import com.google.gerrit.common.data.PatchScript;
import com.google.gerrit.prettify.common.SparseFileContent;
import com.google.gerrit.reviewdb.Account;
import com.google.gerrit.reviewdb.Account.Id;
import com.google.gerrit.reviewdb.AccountGeneralPreferences.DownloadScheme;
import com.google.gerrit.reviewdb.Change.Status;
import com.google.gerrit.reviewdb.Patch;
import com.google.gerrit.reviewdb.PatchLineComment;
import com.google.gerrit.reviewdb.PatchSet;
import com.google.gerrit.reviewdb.Project;
import com.google.gerrit.reviewdb.UserIdentity;
/**
* @author Steffen Pingel
* @author Sascha Scholz
*/
public class GerritUtil {
private static final ReviewsFactory FACTORY = ReviewsFactory.eINSTANCE;
public static GerritChange getChange(TaskData taskData) {
JSonSupport json = new JSonSupport();
TaskAttribute attribute = taskData.getRoot().getAttribute(GerritTaskSchema.getDefault().OBJ_REVIEW.getKey());
if (attribute != null) {
return json.getGson().fromJson(attribute.getValue(), GerritChange.class);
}
return null;
}
public static IReview toReview(ChangeDetail detail) throws GerritException {
IReview review = FACTORY.createReview();
review.setId(detail.getChange().getId().get() + "");
List<PatchSet> patchSets = detail.getPatchSets();
for (PatchSet patchSet : patchSets) {
IReviewItemSet itemSet = toReviewItemSet(detail, null, patchSet);
itemSet.setReview(review);
review.getItems().add(itemSet);
}
return review;
}
public static IReviewItemSet toReviewItemSet(ChangeDetail detail, PatchSet base, PatchSet patchSet) {
IReviewItemSet itemSet = FACTORY.createReviewItemSet();
if (base == null) {
itemSet.setName(NLS.bind("Patch Set {0}", patchSet.getPatchSetId()));
} else {
itemSet.setName(NLS.bind("Compare Patch Set {0} and {1}", patchSet.getPatchSetId(), base.getPatchSetId()));
}
itemSet.setId(patchSet.getPatchSetId() + "");
itemSet.setAddedBy(createUser(patchSet.getUploader(), detail.getAccounts()));
itemSet.setRevision(patchSet.getRevision().get());
return itemSet;
}
public static List<IReviewItem> toReviewItems(GerritPatchSetContent content, ReviewItemCache cache) {
List<IReviewItem> items = new ArrayList<IReviewItem>();
for (Patch patch : content.getTarget().getPatches()) {
String targetId = patch.getKey().toString();
String sourceFileName = (patch.getSourceFileName() != null)
? patch.getSourceFileName()
: patch.getFileName();
String baseId = (content.getBase() != null)
? new Patch.Key(content.getBase().getId(), sourceFileName).toString()
: "base-" + targetId;
String id = baseId + ":" + targetId; //$NON-NLS-1$
IFileItem item = (IFileItem) cache.getItem(id);
if (item == null) {
item = FACTORY.createFileItem();
item.setId(id);
item.setName(patch.getFileName());
cache.put(item);
}
items.add(item);
if (content.getPatchScriptByPatchKey() != null) {
PatchScript patchScript = content.getPatchScriptByPatchKey().get(patch.getKey());
if (patchScript != null) {
CommentDetail commentDetail = patchScript.getCommentDetail();
IFileRevision revisionA = (IFileRevision) cache.getItem(baseId);
if (revisionA == null) {
revisionA = FACTORY.createFileRevision();
revisionA.setId(baseId);
revisionA.setContent(patchScript.getA().asString());
revisionA.setPath(patchScript.getA().getPath());
revisionA.setRevision((content.getBase() != null) ? NLS.bind("Patch Set {0}", content.getBase()
.getPatchSetId()) : "Base");
addComments(revisionA, commentDetail.getCommentsA(), commentDetail.getAccounts());
cache.put(revisionA);
}
item.setBase(revisionA);
IFileRevision revisionB = (IFileRevision) cache.getItem(targetId);
if (revisionB == null) {
revisionB = FACTORY.createFileRevision();
revisionB.setId(targetId);
SparseFileContent target = patchScript.getB().apply(patchScript.getA(), patchScript.getEdits());
revisionB.setContent(target.asString());
revisionB.setPath(patchScript.getB().getPath());
revisionB.setRevision(NLS.bind("Patch Set {0}", content.getTarget()
.getPatchSet()
.getPatchSetId()));
addComments(revisionB, commentDetail.getCommentsB(), commentDetail.getAccounts());
cache.put(revisionB);
}
item.setTarget(revisionB);
}
}
}
return items;
}
private static void addComments(IFileRevision revision, List<PatchLineComment> comments,
AccountInfoCache accountInfoCache) {
if (comments == null || comments.isEmpty()) {
return;
}
for (PatchLineComment comment : comments) {
ILineRange line = FACTORY.createLineRange();
line.setStart(comment.getLine());
line.setEnd(comment.getLine());
ILineLocation location = FACTORY.createLineLocation();
location.getRanges().add(line);
IUser author = GerritUtil.createUser(comment.getAuthor(), accountInfoCache);
IComment topicComment = FACTORY.createComment();
topicComment.setAuthor(author);
topicComment.setCreationDate(comment.getWrittenOn());
topicComment.setDescription(comment.getMessage());
ITopic topic = FACTORY.createTopic();
topic.setId(comment.getKey().get());
topic.setAuthor(author);
topic.setCreationDate(comment.getWrittenOn());
topic.setLocation(location);
topic.setItem(revision);
topic.setDraft(PatchLineComment.Status.DRAFT == comment.getStatus());
topic.setDescription(comment.getMessage());
topic.setTitle(shortenText(comment.getMessage(), 10, 20));
topic.getComments().add(topicComment);
revision.getTopics().add(topic);
}
}
public static IUser createUser(Id id, AccountInfoCache accountInfoCache) {
AccountInfo info = accountInfoCache.get(id);
IUser user = FACTORY.createUser();
user.setDisplayName(getUserLabel(info));
user.setId(Integer.toString(id.get()));
return user;
}
public static String getUserLabel(AccountInfo user) {
if (user == null) {
return "Anonymous";
}
if (user.getFullName() != null) {
return user.getFullName();
}
if (user.getPreferredEmail() != null) {
String email = user.getPreferredEmail();
int i = email.indexOf("@");
return (i > 0) ? email.substring(0, i) : email;
}
return "<Unknown>";
}
public static String getUserLabel(UserIdentity user) {
StringBuilder sb = new StringBuilder();
sb.append(user.getName());
if (user.getEmail() != null) {
sb.append(" <");
sb.append(user.getEmail());
sb.append(">");
}
return sb.toString();
}
public static boolean isPermissionOnlyProject(ProjectDetailX projectDetail, GerritConfig config) {
if (projectDetail.isPermissionOnly) {
return true;
} else if (projectDetail.project.getName().equals(config.getWildProject().get())) {
return true;
} else {
return false;
}
}
public static String shortenText(String t, int minChars, int maxChars) {
Assert.isTrue(minChars >= 0);
Assert.isTrue(maxChars >= 0);
Assert.isTrue(minChars <= maxChars);
if (t.length() < maxChars) {
return t;
}
for (int i = maxChars - 1; i >= minChars; i--) {
if (Character.isWhitespace(t.charAt(i))) {
return NLS.bind("{0}...", t.substring(0, i));
}
}
return NLS.bind("{0}...", t.substring(0, minChars));
}
public static IReviewItemSet createInput(ChangeDetail changeDetail, GerritPatchSetContent content,
ReviewItemCache cache) {
IReviewItemSet itemSet = GerritUtil.toReviewItemSet(changeDetail, content.getBase(), content.getTarget()
.getPatchSet());
List<IReviewItem> items = GerritUtil.toReviewItems(content, cache);
itemSet.getItems().addAll(items);
return itemSet;
}
public static String getSshCloneUri(TaskRepository repository, GerritConfiguration config, Project project)
throws URISyntaxException {
Set<DownloadScheme> supportedDownloadSchemes = config.getGerritConfig().getDownloadSchemes();
if (supportedDownloadSchemes.contains(DownloadScheme.SSH)
|| supportedDownloadSchemes.contains(DownloadScheme.DEFAULT_DOWNLOADS)) {
String sshAddress = config.getGerritConfig().getSshdAddress();
Account account = config.getAccount();
final StringBuilder sb = new StringBuilder();
sb.append("ssh://"); //$NON-NLS-1$
if (account != null) {
String user = account.getUserName();
if (user != null && !user.equals("")) { //$NON-NLS-1$
sb.append(user);
sb.append("@"); //$NON-NLS-1$
}
}
if (sshAddress.startsWith("*:") || "".equals(sshAddress)) { //$NON-NLS-1$ //$NON-NLS-2$
sb.append(new URI(repository.getRepositoryUrl()).getHost());
}
if (sshAddress.startsWith("*:")) { //$NON-NLS-1$
sb.append(sshAddress.substring(1));
} else {
sb.append(sshAddress);
}
sb.append("/"); //$NON-NLS-1$
sb.append(project.getName());
return sb.toString();
} else {
return null;
}
}
public static String getHttpCloneUri(TaskRepository repository, GerritConfiguration config, Project project) {
Set<DownloadScheme> supportedDownloadSchemes = config.getGerritConfig().getDownloadSchemes();
if (supportedDownloadSchemes.contains(DownloadScheme.HTTP)
|| supportedDownloadSchemes.contains(DownloadScheme.DEFAULT_DOWNLOADS)) {
Account account = config.getAccount();
final StringBuilder sb = new StringBuilder();
String httpAddress;
if (config.getGerritConfig().getGitHttpUrl() != null) {
httpAddress = config.getGerritConfig().getGitHttpUrl();
} else {
httpAddress = repository.getUrl();
}
int schemeEndIndex = httpAddress.indexOf("://") + 3; //$NON-NLS-1$
sb.append(httpAddress.substring(0, schemeEndIndex));
if (!httpAddress.contains("@") && account != null) { //$NON-NLS-1$
String user = account.getUserName();
if (user != null && !user.equals("")) { //$NON-NLS-1$
sb.append(user);
sb.append('@');
}
}
sb.append(httpAddress.substring(schemeEndIndex));
if (!httpAddress.substring(schemeEndIndex).endsWith("/")) { //$NON-NLS-1$
sb.append("/"); //$NON-NLS-1$
}
sb.append("p/"); //$NON-NLS-1$
sb.append(project.getName());
return sb.toString();
} else {
return null;
}
}
public static String getAnonHttpCloneUri(TaskRepository repository, GerritConfiguration config, Project project) {
Set<DownloadScheme> supportedDownloadSchemes = config.getGerritConfig().getDownloadSchemes();
if (supportedDownloadSchemes.contains(DownloadScheme.ANON_HTTP)
|| supportedDownloadSchemes.contains(DownloadScheme.DEFAULT_DOWNLOADS)) {
final StringBuilder sb = new StringBuilder();
String httpAddress;
if (config.getGerritConfig().getGitHttpUrl() != null) {
httpAddress = config.getGerritConfig().getGitHttpUrl();
} else {
httpAddress = repository.getUrl();
}
sb.append(httpAddress);
if (!httpAddress.endsWith("/")) { //$NON-NLS-1$
sb.append("/"); //$NON-NLS-1$
}
sb.append("p/"); //$NON-NLS-1$
sb.append(project.getName());
return sb.toString();
} else {
return null;
}
}
public static String getAnonGitCloneUri(TaskRepository repository, GerritConfiguration config, Project project) {
Set<DownloadScheme> supportedDownloadSchemes = config.getGerritConfig().getDownloadSchemes();
String gitAddress = config.getGerritConfig().getGitDaemonUrl();
if (gitAddress != null
&& (supportedDownloadSchemes.contains(DownloadScheme.ANON_GIT) || supportedDownloadSchemes.contains(DownloadScheme.DEFAULT_DOWNLOADS))) {
final StringBuilder sb = new StringBuilder();
sb.append(gitAddress);
if (!gitAddress.endsWith("/")) { //$NON-NLS-1$
sb.append("/"); //$NON-NLS-1$
}
sb.append(project.getName());
return sb.toString();
} else {
return null;
}
}
public static HashMap<DownloadScheme, String> getCloneUris(GerritConfiguration config, TaskRepository repository,
Project project) throws URISyntaxException {
boolean isAuthenticated = config.getAccount() != null;
HashMap<DownloadScheme, String> uriMap = new HashMap<DownloadScheme, String>();
if (isAuthenticated) {
uriMap.put(DownloadScheme.SSH, getSshCloneUri(repository, config, project));
uriMap.put(DownloadScheme.HTTP, getHttpCloneUri(repository, config, project));
}
uriMap.put(DownloadScheme.ANON_HTTP, getAnonHttpCloneUri(repository, config, project));
uriMap.put(DownloadScheme.ANON_GIT, getAnonGitCloneUri(repository, config, project));
return uriMap;
}
public static boolean isDraft(Status status) {
// DRAFT is not correctly parsed for ChangeInfo since Change.Status does not define the corresponding enum field
return status == null;
}
}