Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBlaine Lewis2015-09-19 00:31:28 +0000
committerSam Davis2015-12-10 18:03:20 +0000
commit03a47c7ebc66e39a2526e453b541b7f5daba5790 (patch)
treee0abc5e117cd980f22b1dc05c7d991edf0b99d74
parent625b620692d84e60d6645dcc2a1c2efb709cec66 (diff)
downloadorg.eclipse.mylyn.reviews-03a47c7ebc66e39a2526e453b541b7f5daba5790.tar.gz
org.eclipse.mylyn.reviews-03a47c7ebc66e39a2526e453b541b7f5daba5790.tar.xz
org.eclipse.mylyn.reviews-03a47c7ebc66e39a2526e453b541b7f5daba5790.zip
477635: Implemented functionality to capture a mapping between tasks and
any related reviews using the task-id in the summary of a field. Change-Id: If76a2db1304c5f4925981227ee80b602a370097c Task-Url: https://bugs.eclipse.org/bugs/show_bug.cgi?id=477635 Signed-off-by: Ratstache <landonbutterworth@gmail.com> Signed-off-by: Blaine Lewis <Blaine1@ualberta.ca>
-rw-r--r--org.eclipse.mylyn.gerrit.core/src/org/eclipse/mylyn/internal/gerrit/core/GerritConnector.java19
-rw-r--r--org.eclipse.mylyn.gerrit.core/src/org/eclipse/mylyn/internal/gerrit/core/GerritTaskDataHandler.java9
-rw-r--r--org.eclipse.mylyn.reviews.core.tests/META-INF/MANIFEST.MF3
-rw-r--r--org.eclipse.mylyn.reviews.core.tests/src/org/eclipse/mylyn/reviews/core/internal/TaskReviewMappingStoreTest.java238
-rw-r--r--org.eclipse.mylyn.reviews.core/src/org/eclipse/mylyn/reviews/internal/core/ReviewsCoreConstants.java4
-rw-r--r--org.eclipse.mylyn.reviews.core/src/org/eclipse/mylyn/reviews/internal/core/TaskReviewsMappingsStore.java176
-rw-r--r--org.eclipse.mylyn.reviews.ui/plugin.xml1
-rw-r--r--org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/ReviewsUiPlugin.java28
8 files changed, 467 insertions, 11 deletions
diff --git a/org.eclipse.mylyn.gerrit.core/src/org/eclipse/mylyn/internal/gerrit/core/GerritConnector.java b/org.eclipse.mylyn.gerrit.core/src/org/eclipse/mylyn/internal/gerrit/core/GerritConnector.java
index 38074ec24..dcd264093 100644
--- a/org.eclipse.mylyn.gerrit.core/src/org/eclipse/mylyn/internal/gerrit/core/GerritConnector.java
+++ b/org.eclipse.mylyn.gerrit.core/src/org/eclipse/mylyn/internal/gerrit/core/GerritConnector.java
@@ -50,6 +50,7 @@ import org.eclipse.mylyn.internal.gerrit.core.client.JSonSupport;
import org.eclipse.mylyn.internal.gerrit.core.client.data.GerritQueryResult;
import org.eclipse.mylyn.reviews.core.model.ReviewStatus;
import org.eclipse.mylyn.reviews.core.spi.ReviewsConnector;
+import org.eclipse.mylyn.reviews.internal.core.ReviewsCoreConstants;
import org.eclipse.mylyn.tasks.core.IRepositoryQuery;
import org.eclipse.mylyn.tasks.core.ITask;
import org.eclipse.mylyn.tasks.core.ITaskMapping;
@@ -68,7 +69,7 @@ import com.google.gwtorm.server.StandardKeyEncoder;
/**
* The Gerrit connector core.
- *
+ *
* @author Mikael Kober
* @author Thomas Westling
* @author Sascha Scholz
@@ -301,7 +302,8 @@ public class GerritConnector extends ReviewsConnector {
}
@Override
- public void updateRepositoryConfiguration(TaskRepository repository, IProgressMonitor monitor) throws CoreException {
+ public void updateRepositoryConfiguration(TaskRepository repository, IProgressMonitor monitor)
+ throws CoreException {
try {
getClient(repository).refreshConfig(monitor);
} catch (GerritException e) {
@@ -309,6 +311,7 @@ public class GerritConnector extends ReviewsConnector {
}
}
+ @SuppressWarnings("restriction")
@Override
public void updateTaskFromTaskData(TaskRepository taskRepository, ITask task, TaskData taskData) {
Date oldModificationDate = task.getModificationDate();
@@ -325,6 +328,11 @@ public class GerritConnector extends ReviewsConnector {
if (taskData.isPartial()) {
task.setModificationDate(oldModificationDate);
}
+
+ task.setAttribute(ReviewsCoreConstants.CODE_REVIEW,
+ taskData.getRoot().getAttribute(GerritTaskSchema.getDefault().REVIEW_STATE.getKey()).getValue());
+ task.setAttribute(ReviewsCoreConstants.VERIFIED,
+ taskData.getRoot().getAttribute(GerritTaskSchema.getDefault().VERIFY_STATE.getKey()).getValue());
}
public GerritSystemInfo validate(TaskRepository repository, IProgressMonitor monitor) throws CoreException {
@@ -437,8 +445,8 @@ public class GerritConnector extends ReviewsConnector {
JSonSupport support = new JSonSupport();
return support.toJson(config);
} catch (Exception e) {
- StatusHandler.log(new Status(IStatus.ERROR, GerritCorePlugin.PLUGIN_ID,
- "Failed to serialize configuration", e)); //$NON-NLS-1$
+ StatusHandler
+ .log(new Status(IStatus.ERROR, GerritCorePlugin.PLUGIN_ID, "Failed to serialize configuration", e)); //$NON-NLS-1$
return null;
}
}
@@ -474,7 +482,8 @@ public class GerritConnector extends ReviewsConnector {
return toStatus(repository, qualifier, (Exception) cause);
}
} else if (e instanceof GerritException && e.getMessage() != null) {
- return createErrorStatus(repository, NLS.bind("{0}Gerrit connection issue: {1}", qualifier, e.getMessage())); //$NON-NLS-1$
+ return createErrorStatus(repository,
+ NLS.bind("{0}Gerrit connection issue: {1}", qualifier, e.getMessage())); //$NON-NLS-1$
}
String message = NLS.bind("{0}Unexpected error while connecting to Gerrit: {1}", qualifier, e.getMessage()); //$NON-NLS-1$
if (repository != null) {
diff --git a/org.eclipse.mylyn.gerrit.core/src/org/eclipse/mylyn/internal/gerrit/core/GerritTaskDataHandler.java b/org.eclipse.mylyn.gerrit.core/src/org/eclipse/mylyn/internal/gerrit/core/GerritTaskDataHandler.java
index 1323cbd1a..f2d25bb5c 100644
--- a/org.eclipse.mylyn.gerrit.core/src/org/eclipse/mylyn/internal/gerrit/core/GerritTaskDataHandler.java
+++ b/org.eclipse.mylyn.gerrit.core/src/org/eclipse/mylyn/internal/gerrit/core/GerritTaskDataHandler.java
@@ -151,6 +151,7 @@ public class GerritTaskDataHandler extends AbstractTaskDataHandler {
if (!monitor.isCanceled()) {
updateTaskData(repository, taskData, gerritChange, !anonymous, id);
}
+
return taskData;
} catch (GerritException e) {
throw connector.toCoreException(repository, NLS.bind("Problem retrieving task data for task: {0}", taskId), //$NON-NLS-1$
@@ -162,11 +163,11 @@ public class GerritTaskDataHandler extends AbstractTaskDataHandler {
private RemoteEmfConsumer<IRepository, IReview, String, GerritChange, String, Date> updateModelData(
TaskRepository repository, TaskData taskData, ReviewObserver reviewObserver, IProgressMonitor monitor)
- throws CoreException {
+ throws CoreException {
GerritClient client = connector.getClient(repository);
GerritRemoteFactoryProvider factoryProvider = (GerritRemoteFactoryProvider) client.getFactoryProvider();
- RemoteEmfConsumer<IRepository, IReview, String, GerritChange, String, Date> consumer = factoryProvider.getReviewFactory()
- .getConsumerForLocalKey(factoryProvider.getRoot(), taskData.getTaskId());
+ RemoteEmfConsumer<IRepository, IReview, String, GerritChange, String, Date> consumer = factoryProvider
+ .getReviewFactory().getConsumerForLocalKey(factoryProvider.getRoot(), taskData.getTaskId());
consumer.addObserver(reviewObserver);
if (!consumer.isRetrieving()) {
@@ -212,7 +213,7 @@ public class GerritTaskDataHandler extends AbstractTaskDataHandler {
/**
* Get account id for repository
- *
+ *
* @param client
* @param repository
* @param monitor
diff --git a/org.eclipse.mylyn.reviews.core.tests/META-INF/MANIFEST.MF b/org.eclipse.mylyn.reviews.core.tests/META-INF/MANIFEST.MF
index fbf85ebf5..3cee7e52c 100644
--- a/org.eclipse.mylyn.reviews.core.tests/META-INF/MANIFEST.MF
+++ b/org.eclipse.mylyn.reviews.core.tests/META-INF/MANIFEST.MF
@@ -14,7 +14,8 @@ Require-Bundle: org.junit;bundle-version="4.5.0",
org.eclipse.mylyn.commons.net,
org.apache.commons.logging,
org.apache.commons.io,
- org.eclipse.core.net
+ org.eclipse.core.net,
+ com.google.guava
Export-Package:
org.eclipse.mylyn.reviews.core.model;x-internal:=true,
org.eclipse.mylyn.reviews.core.spi.remote;x-internal:=true,
diff --git a/org.eclipse.mylyn.reviews.core.tests/src/org/eclipse/mylyn/reviews/core/internal/TaskReviewMappingStoreTest.java b/org.eclipse.mylyn.reviews.core.tests/src/org/eclipse/mylyn/reviews/core/internal/TaskReviewMappingStoreTest.java
new file mode 100644
index 000000000..0bfecb08e
--- /dev/null
+++ b/org.eclipse.mylyn.reviews.core.tests/src/org/eclipse/mylyn/reviews/core/internal/TaskReviewMappingStoreTest.java
@@ -0,0 +1,238 @@
+/*******************************************************************************
+ * Copyright (c) 2015 Blaine Lewis
+ * 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:
+ * Blaine Lewis
+ *******************************************************************************/
+
+package org.eclipse.mylyn.reviews.core.internal;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Collection;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.mylyn.internal.tasks.core.TaskContainerDelta;
+import org.eclipse.mylyn.internal.tasks.core.TaskContainerDelta.Kind;
+import org.eclipse.mylyn.internal.tasks.core.TaskRepositoryManager;
+import org.eclipse.mylyn.internal.tasks.core.data.TaskDataManager;
+import org.eclipse.mylyn.reviews.core.spi.ReviewsConnector;
+import org.eclipse.mylyn.reviews.internal.core.TaskReviewsMappingsStore;
+import org.eclipse.mylyn.tasks.core.ITask;
+import org.eclipse.mylyn.tasks.core.TaskRepository;
+import org.eclipse.mylyn.tasks.core.data.TaskAttribute;
+import org.eclipse.mylyn.tasks.core.data.TaskAttributeMapper;
+import org.eclipse.mylyn.tasks.core.data.TaskData;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Matchers;
+
+import com.google.common.collect.ImmutableSet;
+
+@SuppressWarnings("restriction")
+public class TaskReviewMappingStoreTest {
+
+ final String taskUrl1 = "https://bugs.eclipse.org/bugs/show_bug.cgi?id=477635";
+
+ final String taskUrl2 = "https://bugs.eclipse.org/bugs/show_bug.cgi?id=345343";
+
+ final String notATaskUrl = "www.hello.com";
+
+ final ITask task1 = mock(ITask.class);
+
+ final ITask task2 = mock(ITask.class);
+
+ final String reviewUrl1 = "https://git.eclipse.org/r/#/c/56269/";
+
+ final String reviewUrl2 = "https://git.eclipse.org/r/#/c/43534/";
+
+ final String reviewUrlNoTask = "https://git.eclipse.org/r/#/c/12333/";
+
+ final String descriptionWithTaskUrl1 = "477635: [UCOSP] contribute reviews section to task editor showing"
+ + " associated reviews Change-Id: I3a38d375688aad7be36bfd58c3311d692eb51ed Task-Url: " + taskUrl1
+ + " Signed-off-by: Blaine Lewis <Blaine1@ualberta.ca>";
+
+ final String descriptionWithTaskUrl2 = "477635: [UCOSP] contribute reviews section to task editor showing"
+ + " associated reviews Change-Id: I3a38d375688aad7be36bfd58c3311d692eb51ed Task-Url: " + taskUrl2
+ + " Signed-off-by: Blaine Lewis <Blaine1@ualberta.ca>";
+
+ final String descriptionWithNoTaskUrl = "477635: [UCOSP] contribute reviews section to task editor showing"
+ + " associated reviews Change-Id: I3a38d375688aad7be36bfd58c3311d692eb51ed "
+ + " Signed-off-by: Blaine Lewis <Blaine1@ualberta.ca>";
+
+ final String descriptionWithNotATaskUrl = "477635: [UCOSP] contribute reviews section to task editor showing"
+ + " associated reviews Change-Id: I3a38d375688aad7be36bfd58c3311d692eb51ed " + notATaskUrl
+ + " Signed-off-by: Blaine Lewis <Blaine1@ualberta.ca>";
+
+ final ITask review1 = mock(ITask.class);
+
+ final ITask review2 = mock(ITask.class);
+
+ final ITask reviewNoTask = mock(ITask.class);
+
+ private TaskDataManager taskDataManager;
+
+ @Before
+ public void setup() {
+
+ when(review1.getUrl()).thenReturn(reviewUrl1);
+ when(review2.getUrl()).thenReturn(reviewUrl2);
+ when(reviewNoTask.getUrl()).thenReturn(reviewUrlNoTask);
+ when(task1.getUrl()).thenReturn(taskUrl1);
+ when(task2.getUrl()).thenReturn(taskUrl2);
+ when(task1.getTaskId()).thenReturn("1");
+ when(task1.getTaskId()).thenReturn("2");
+ when(review1.getTaskId()).thenReturn("3");
+ when(review2.getTaskId()).thenReturn("4");
+ when(reviewNoTask.getTaskId()).thenReturn("5");
+
+ }
+
+ public TaskReviewsMappingsStore getEmptyTaskReviewStore() {
+ TaskRepositoryManager repositoryManager = mock(TaskRepositoryManager.class);
+ ReviewsConnector connector = mock(ReviewsConnector.class);
+
+ taskDataManager = mock(TaskDataManager.class);
+
+ when(repositoryManager.getConnectorForRepositoryTaskUrl(Matchers.anyString())).thenReturn(connector);
+ when(repositoryManager.getRepositoryConnector(Matchers.anyString())).thenReturn(connector);
+
+ TaskReviewsMappingsStore taskReviewsMappingStore = new TaskReviewsMappingsStore(taskDataManager,
+ repositoryManager);
+ return taskReviewsMappingStore;
+ }
+
+ public void addReviewData(ITask review, String description) throws CoreException {
+ TaskData reviewData = new TaskData(new TaskAttributeMapper(new TaskRepository("", "")), "", review.getUrl(),
+ review.getTaskId());
+
+ reviewData.getRoot().createMappedAttribute(TaskAttribute.DESCRIPTION).setValue(description);
+
+ when(taskDataManager.getTaskData(review)).thenReturn(reviewData);
+ }
+
+ @Test
+ public void testAdd() throws CoreException {
+ TaskReviewsMappingsStore taskReviewsMappingStore = getEmptyTaskReviewStore();
+ addReviewData(review1, descriptionWithTaskUrl1);
+
+ TaskContainerDelta delta = new TaskContainerDelta(review1, Kind.ADDED);
+ taskReviewsMappingStore.containersChanged(ImmutableSet.of(delta));
+
+ assertTrue(taskReviewsMappingStore.getReviewUrls(taskUrl1).contains(reviewUrl1));
+ assertTrue(taskReviewsMappingStore.getTaskUrl(reviewUrl1).equals(taskUrl1));
+ }
+
+ @Test
+ public void testAddTwice() throws CoreException {
+ TaskReviewsMappingsStore taskReviewsMappingStore = getEmptyTaskReviewStore();
+ addReviewData(review1, descriptionWithTaskUrl1);
+
+ TaskContainerDelta delta = new TaskContainerDelta(review1, Kind.ADDED);
+ taskReviewsMappingStore.containersChanged(ImmutableSet.of(delta));
+ taskReviewsMappingStore.containersChanged(ImmutableSet.of(delta));
+
+ Collection<String> reviewUrls = taskReviewsMappingStore.getReviewUrls(taskUrl1);
+
+ assertTrue(reviewUrls.contains(reviewUrl1));
+ assertTrue(reviewUrls.size() == 1);
+ assertTrue(taskReviewsMappingStore.getTaskUrl(reviewUrl1).equals(taskUrl1));
+ }
+
+ @Test
+ public void testAddMultiple() throws CoreException {
+ TaskReviewsMappingsStore taskReviewsMappingStore = getEmptyTaskReviewStore();
+ addReviewData(review1, descriptionWithTaskUrl1);
+ addReviewData(review2, descriptionWithTaskUrl2);
+
+ TaskContainerDelta delta1 = new TaskContainerDelta(review1, Kind.ADDED);
+ TaskContainerDelta delta2 = new TaskContainerDelta(review2, Kind.ADDED);
+
+ taskReviewsMappingStore.containersChanged(ImmutableSet.of(delta1, delta2));
+
+ assertTrue(taskReviewsMappingStore.getReviewUrls(taskUrl1).contains(reviewUrl1));
+ assertTrue(taskReviewsMappingStore.getTaskUrl(reviewUrl1).equals(taskUrl1));
+
+ assertTrue(taskReviewsMappingStore.getReviewUrls(taskUrl2).contains(reviewUrl2));
+ assertTrue(taskReviewsMappingStore.getTaskUrl(reviewUrl2).equals(taskUrl2));
+ }
+
+ @Test
+ public void testRemove() throws CoreException {
+
+ TaskReviewsMappingsStore taskReviewsMappingStore = getEmptyTaskReviewStore();
+ addReviewData(review1, descriptionWithTaskUrl1);
+
+ TaskContainerDelta delta = new TaskContainerDelta(review1, Kind.ADDED);
+ taskReviewsMappingStore.containersChanged(ImmutableSet.of(delta));
+ assertTrue(taskReviewsMappingStore.getReviewUrls(taskUrl1).contains(reviewUrl1));
+
+ delta = new TaskContainerDelta(review1, Kind.DELETED);
+
+ taskReviewsMappingStore.containersChanged(ImmutableSet.of(delta));
+ assertFalse(taskReviewsMappingStore.getReviewUrls(taskUrl1).contains(reviewUrl1));
+ assertTrue(taskReviewsMappingStore.getTaskUrl(reviewUrl1) == null);
+ }
+
+ @Test
+ public void testUpdate() throws CoreException {
+ TaskReviewsMappingsStore taskReviewsMappingStore = getEmptyTaskReviewStore();
+ addReviewData(review1, descriptionWithTaskUrl1);
+
+ TaskContainerDelta delta = new TaskContainerDelta(review1, Kind.ADDED);
+ taskReviewsMappingStore.containersChanged(ImmutableSet.of(delta));
+ assertTrue(taskReviewsMappingStore.getReviewUrls(taskUrl1).contains(reviewUrl1));
+
+ addReviewData(review1, descriptionWithTaskUrl2);
+
+ delta = new TaskContainerDelta(review1, Kind.CONTENT);
+ taskReviewsMappingStore.containersChanged(ImmutableSet.of(delta));
+ assertFalse(taskReviewsMappingStore.getReviewUrls(taskUrl1).contains(reviewUrl1));
+ assertTrue(taskReviewsMappingStore.getReviewUrls(taskUrl2).contains(reviewUrl1));
+
+ }
+
+ @Test
+ public void testUpdateNoTask() throws CoreException {
+ TaskReviewsMappingsStore taskReviewsMappingStore = getEmptyTaskReviewStore();
+ addReviewData(review1, descriptionWithTaskUrl1);
+
+ TaskContainerDelta delta = new TaskContainerDelta(review1, Kind.ADDED);
+ taskReviewsMappingStore.containersChanged(ImmutableSet.of(delta));
+ assertTrue(taskReviewsMappingStore.getReviewUrls(taskUrl1).contains(reviewUrl1));
+
+ addReviewData(review1, descriptionWithNoTaskUrl);
+
+ delta = new TaskContainerDelta(review1, Kind.CONTENT);
+ taskReviewsMappingStore.containersChanged(ImmutableSet.of(delta));
+ assertFalse(taskReviewsMappingStore.getReviewUrls(taskUrl1).contains(reviewUrl1));
+ }
+
+ @Test
+ public void testAddNoTask() throws CoreException {
+ TaskReviewsMappingsStore taskReviewsMappingStore = getEmptyTaskReviewStore();
+ addReviewData(review1, descriptionWithNoTaskUrl);
+
+ TaskContainerDelta delta = new TaskContainerDelta(review1, Kind.ADDED);
+ taskReviewsMappingStore.containersChanged(ImmutableSet.of(delta));
+ assertTrue(taskReviewsMappingStore.getTaskUrl(reviewUrl1) == null);
+ }
+
+ @Test
+ public void testAddANonTaskUrl() throws CoreException {
+ TaskReviewsMappingsStore taskReviewsMappingStore = getEmptyTaskReviewStore();
+ addReviewData(review1, descriptionWithNotATaskUrl);
+
+ TaskContainerDelta delta = new TaskContainerDelta(review1, Kind.ADDED);
+ taskReviewsMappingStore.containersChanged(ImmutableSet.of(delta));
+ assertTrue(taskReviewsMappingStore.getTaskUrl(reviewUrl1) == null);
+ }
+
+}
diff --git a/org.eclipse.mylyn.reviews.core/src/org/eclipse/mylyn/reviews/internal/core/ReviewsCoreConstants.java b/org.eclipse.mylyn.reviews.core/src/org/eclipse/mylyn/reviews/internal/core/ReviewsCoreConstants.java
index f88a836c4..6f4466695 100644
--- a/org.eclipse.mylyn.reviews.core/src/org/eclipse/mylyn/reviews/internal/core/ReviewsCoreConstants.java
+++ b/org.eclipse.mylyn.reviews.core/src/org/eclipse/mylyn/reviews/internal/core/ReviewsCoreConstants.java
@@ -14,4 +14,8 @@ package org.eclipse.mylyn.reviews.internal.core;
public interface ReviewsCoreConstants {
public static final String PLUGIN_ID = "org.eclipse.mylyn.reviews.core"; //$NON-NLS-1$
+
+ public static final String CODE_REVIEW = "CODE_REVIEW"; //$NON-NLS-1$
+
+ public static final String VERIFIED = "VERIFIED"; //$NON-NLS-1$
}
diff --git a/org.eclipse.mylyn.reviews.core/src/org/eclipse/mylyn/reviews/internal/core/TaskReviewsMappingsStore.java b/org.eclipse.mylyn.reviews.core/src/org/eclipse/mylyn/reviews/internal/core/TaskReviewsMappingsStore.java
new file mode 100644
index 000000000..24d01be70
--- /dev/null
+++ b/org.eclipse.mylyn.reviews.core/src/org/eclipse/mylyn/reviews/internal/core/TaskReviewsMappingsStore.java
@@ -0,0 +1,176 @@
+package org.eclipse.mylyn.reviews.internal.core;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Collection;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.mylyn.commons.core.StatusHandler;
+import org.eclipse.mylyn.internal.tasks.core.ITaskListChangeListener;
+import org.eclipse.mylyn.internal.tasks.core.TaskContainerDelta;
+import org.eclipse.mylyn.internal.tasks.core.TaskRepositoryManager;
+import org.eclipse.mylyn.internal.tasks.core.data.TaskDataManager;
+import org.eclipse.mylyn.reviews.core.spi.ReviewsConnector;
+import org.eclipse.mylyn.tasks.core.AbstractRepositoryConnector;
+import org.eclipse.mylyn.tasks.core.IRepositoryElement;
+import org.eclipse.mylyn.tasks.core.ITask;
+import org.eclipse.mylyn.tasks.core.data.TaskAttribute;
+import org.eclipse.mylyn.tasks.core.data.TaskData;
+
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Multimaps;
+import com.google.common.collect.SetMultimap;
+
+/**
+ * This class is used by review connectors to provide a mapping from tasks to reviews. These mappings are used by
+ * TaskEditorReviewPart to give a table of the reviews pertaining to a task. The class is limited as it maps one task to
+ * many reviews. It is however possible (albeit strange) to have multiple tasks for one review. This is a limitation by
+ * design.
+ *
+ * @author Blaine Lewis
+ */
+
+@SuppressWarnings("restriction")
+public class TaskReviewsMappingsStore implements ITaskListChangeListener {
+
+ private final SetMultimap<String, String> taskReviewsMap;
+
+ private final TaskRepositoryManager repositoryManager;
+
+ private final TaskDataManager taskDataManager;
+
+ public TaskReviewsMappingsStore(TaskDataManager taskDataManager, TaskRepositoryManager repositoryManager) {
+ //BUG: This class is actually really volatile at the moment we have no
+ // collision rules for if we serialize and deserialize at the same time.
+
+ this.repositoryManager = repositoryManager;
+ this.taskDataManager = taskDataManager;
+ taskReviewsMap = Multimaps.synchronizedSetMultimap(LinkedHashMultimap.<String, String> create());
+ }
+
+ /*
+ * Updates or adds a mapping given a reviewUrl and a taskDescription. If no URL is found in the description we do nothing.
+ */
+ private void updateMapping(String reviewUrl, String reviewDescription) {
+ String oldTaskUrl = getTaskUrl(reviewUrl);
+ String newTaskUrl = this.extractTaskUrl(reviewDescription);
+
+ if (newTaskUrl == null && oldTaskUrl != null) {
+ taskReviewsMap.remove(oldTaskUrl, reviewUrl);
+ } else if (newTaskUrl != null) {
+ if (oldTaskUrl != null && !oldTaskUrl.equals(newTaskUrl)) {
+ taskReviewsMap.remove(oldTaskUrl, reviewUrl);
+ }
+ if (newTaskUrl != null) {
+ taskReviewsMap.put(newTaskUrl, reviewUrl);
+ }
+ }
+ }
+
+ public Collection<String> getReviewUrls(String taskUrl) {
+ return taskReviewsMap.get(taskUrl);
+ }
+
+ /*
+ * This method of extracting URLs is deficient because if we have "(www.helloworld.com)" it will be
+ * a valid URL. This is difficult to format though so we won't handle that case.
+ */
+ private String extractTaskUrl(String description) {
+
+ for (String token : description.split("\\s+")) { //$NON-NLS-1$
+ if (token.contains("://")) { //$NON-NLS-1$
+
+ try {
+ @SuppressWarnings("unused")
+ URL url = new URL(token);
+
+ AbstractRepositoryConnector connector = repositoryManager.getConnectorForRepositoryTaskUrl(token);
+
+ if (connector != null) {
+ return token;
+ }
+ } catch (MalformedURLException e) {
+ //Do nothing, this is expected behavior when there is no URL
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public String getTaskUrl(String reviewUrlToFind) {
+ for (Entry<String, String> mapping : taskReviewsMap.entries()) {
+ int index = mapping.getValue().indexOf(reviewUrlToFind);
+
+ if (index != -1) {
+ return mapping.getKey();
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public void containersChanged(Set<TaskContainerDelta> containers) {
+
+ for (TaskContainerDelta delta : containers) {
+ IRepositoryElement reviewRepoElement = delta.getElement();
+
+ if (!(reviewRepoElement instanceof ITask)) {
+ return;
+ }
+
+ ITask review = (ITask) reviewRepoElement;
+
+ AbstractRepositoryConnector connector = repositoryManager.getRepositoryConnector(review.getConnectorKind());
+
+ if (review != null && connector instanceof ReviewsConnector) {
+
+ try {
+ String reviewUrl = review.getUrl();
+
+ switch (delta.getKind()) {
+ case DELETED:
+ deleteMappingsTo(reviewUrl);
+ break;
+ case ADDED:
+ case CONTENT:
+ TaskData taskData = taskDataManager.getTaskData(review);
+
+ if (taskData == null) {
+ continue;
+ }
+
+ TaskAttribute attr = taskData.getRoot().getMappedAttribute(TaskAttribute.DESCRIPTION);
+
+ if (attr == null) {
+ continue;
+ }
+ String reviewDescription = attr.getValue();
+
+ updateMapping(reviewUrl, reviewDescription);
+ break;
+ }
+ } catch (CoreException e) {
+ StatusHandler.log(
+ new Status(IStatus.ERROR, ReviewsCoreConstants.PLUGIN_ID, "Error getting taskData.", e)); //$NON-NLS-1$
+
+ }
+ }
+ }
+ }
+
+ private void deleteMappingsTo(String reviewUrl) {
+ String taskUrl = getTaskUrl(reviewUrl);
+ if (taskUrl != null) {
+ Set<String> reviews = taskReviewsMap.get(taskUrl);
+ if (reviews != null) {
+ reviews.remove(reviewUrl);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.mylyn.reviews.ui/plugin.xml b/org.eclipse.mylyn.reviews.ui/plugin.xml
index e1fb64e68..72b7828ce 100644
--- a/org.eclipse.mylyn.reviews.ui/plugin.xml
+++ b/org.eclipse.mylyn.reviews.ui/plugin.xml
@@ -147,7 +147,6 @@
visibleInUI="true">
</commonFilter>
</extension>
-
<!--
<extension point="org.eclipse.ui.workbench.texteditor.rulerColumns">
<column id="org.eclipse.mylyn.reviews.ui.editor.AnnotationRuler" name="Review Comments"
diff --git a/org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/ReviewsUiPlugin.java b/org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/ReviewsUiPlugin.java
index 226a80d16..663854f57 100644
--- a/org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/ReviewsUiPlugin.java
+++ b/org.eclipse.mylyn.reviews.ui/src/org/eclipse/mylyn/internal/reviews/ui/ReviewsUiPlugin.java
@@ -10,12 +10,19 @@
*********************************************************************/
package org.eclipse.mylyn.internal.reviews.ui;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin;
+import org.eclipse.mylyn.reviews.internal.core.TaskReviewsMappingsStore;
import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.eclipse.ui.progress.UIJob;
import org.osgi.framework.BundleContext;
/**
* @author Steffen Pingel
*/
+@SuppressWarnings("restriction")
public class ReviewsUiPlugin extends AbstractUIPlugin {
public static final String PLUGIN_ID = "org.eclipse.mylyn.reviews.ui"; //$NON-NLS-1$
@@ -24,6 +31,10 @@ public class ReviewsUiPlugin extends AbstractUIPlugin {
private ActiveReviewManager reviewManager;
+ private TaskReviewsMappingsStore taskReviewsMappingStore;
+
+ private final String INITIALIZE_TASK_REVIEW_MAPPING_STORE_JOB = "initialize task review mapping store job"; //$NON-NLS-1$
+
public ReviewsUiPlugin() {
}
@@ -32,6 +43,19 @@ public class ReviewsUiPlugin extends AbstractUIPlugin {
super.start(context);
plugin = this;
reviewManager = new ActiveReviewManager();
+
+ //We need to schedule initialization otherwise TasksUiPlugin hasn't finished initialization.
+ UIJob job = new UIJob(INITIALIZE_TASK_REVIEW_MAPPING_STORE_JOB) {
+ @Override
+ public IStatus runInUIThread(IProgressMonitor monitor) {
+ taskReviewsMappingStore = new TaskReviewsMappingsStore(TasksUiPlugin.getTaskDataManager(),
+ TasksUiPlugin.getRepositoryManager());
+
+ TasksUiPlugin.getTaskList().addChangeListener(taskReviewsMappingStore);
+ return Status.OK_STATUS;
+ }
+ };
+ job.schedule();
}
@Override
@@ -47,4 +71,8 @@ public class ReviewsUiPlugin extends AbstractUIPlugin {
public ActiveReviewManager getReviewManager() {
return reviewManager;
}
+
+ public TaskReviewsMappingsStore getTaskReviewsMappingStore() {
+ return taskReviewsMappingStore;
+ }
}

Back to the top