Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin Sawicki2011-05-16 19:44:31 +0000
committerKevin Sawicki2011-05-16 19:44:31 +0000
commitf196bf7bc2f5e6f61f86a0f41a4ee9ce061b8b31 (patch)
tree461bf222097a2764f21ac7fc91cc1e69e89b57bb /org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core
parent48fe56ce3a3bb048d1103afb4c5ceb168f79a961 (diff)
downloadegit-github-f196bf7bc2f5e6f61f86a0f41a4ee9ce061b8b31.tar.gz
egit-github-f196bf7bc2f5e6f61f86a0f41a4ee9ce061b8b31.tar.xz
egit-github-f196bf7bc2f5e6f61f86a0f41a4ee9ce061b8b31.zip
Refactor package and class names for issue connector.
Change-Id: Icfaf402936f0ebd2527ac9ba2fbbeb135a58e5c4 Signed-off-by: Kevin Sawicki <kevin@github.com>
Diffstat (limited to 'org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core')
-rw-r--r--org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/GitHub.java163
-rw-r--r--org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/GitHubException.java74
-rw-r--r--org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/Messages.java41
-rw-r--r--org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/QueryUtils.java78
-rw-r--r--org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/gist/GistAttachmentHandler.java2
-rw-r--r--org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/gist/GistConnector.java2
-rw-r--r--org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/gist/GistTaskDataHandler.java6
-rw-r--r--org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/issue/IssueAttribute.java190
-rw-r--r--org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/issue/IssueAttributeMapper.java57
-rw-r--r--org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/issue/IssueConnector.java413
-rw-r--r--org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/issue/IssueOperation.java76
-rw-r--r--org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/issue/IssueTaskDataHandler.java449
-rw-r--r--org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/issue/Messages.java86
-rw-r--r--org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/issue/messages.properties19
-rw-r--r--org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/messages.properties4
15 files changed, 1655 insertions, 5 deletions
diff --git a/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/GitHub.java b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/GitHub.java
new file mode 100644
index 00000000..6206ad0f
--- /dev/null
+++ b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/GitHub.java
@@ -0,0 +1,163 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Red Hat 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:
+ * David Green <david.green@tasktop.com> - initial contribution
+ * Christian Trutz <christian.trutz@gmail.com> - initial contribution
+ * Chris Aniszczyk <caniszczyk@gmail.com> - initial contribution
+ *******************************************************************************/
+package org.eclipse.mylyn.internal.github.core;
+
+import java.util.regex.Pattern;
+
+import org.eclipse.core.runtime.ILog;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.egit.github.core.Repository;
+
+/**
+ * GitHub class
+ */
+public class GitHub {
+
+ /** BUNDLE_ID */
+ public static final String BUNDLE_ID = "org.eclipse.mylyn.github.core";
+
+ /** CONNECTOR_KIND */
+ public static final String CONNECTOR_KIND = "github";
+
+ /** HTTP_WWW_GITHUB_ORG */
+ public static final String HTTP_WWW_GITHUB_ORG = "http://www.github.org";
+
+ /** HTTP_GITHUB_COM */
+ public static final String HTTP_GITHUB_COM = "http://github.com";
+
+ /** URL_PATTERN */
+ public static final Pattern URL_PATTERN = Pattern.compile("(?:"
+ + Pattern.quote(HTTP_WWW_GITHUB_ORG) + "|"
+ + Pattern.quote(HTTP_GITHUB_COM) + ")/([^/]+)/([^/]+)");
+
+ /**
+ * Create status of severity with message
+ *
+ * @param severity
+ * @param message
+ * @return status
+ */
+ public static IStatus createStatus(int severity, String message) {
+ return new Status(severity, BUNDLE_ID, message);
+ }
+
+ /**
+ * Create status of severity with message and throwable
+ *
+ * @param severity
+ * @param message
+ * @param e
+ * @return status
+ */
+ public static IStatus createStatus(int severity, String message, Throwable e) {
+ return new Status(severity, BUNDLE_ID, message, e);
+ }
+
+ /**
+ * Create error status from message
+ *
+ * @param message
+ * @return status
+ */
+ public static IStatus createErrorStatus(String message) {
+ return createStatus(IStatus.ERROR, message);
+ }
+
+ /**
+ * Create error status from message and throwable
+ *
+ * @param message
+ * @param t
+ * @return status
+ */
+ public static IStatus createErrorStatus(String message, Throwable t) {
+ return createStatus(IStatus.ERROR, message, t);
+ }
+
+ /**
+ * Create error status from throwable
+ *
+ * @param e
+ * @return status
+ */
+ public static IStatus createErrorStatus(Throwable e) {
+ return createStatus(IStatus.ERROR,
+ "Unexpected error: " + e.getLocalizedMessage(), e);
+ }
+
+ /**
+ * Get log
+ *
+ * @return log
+ */
+ public static ILog getLog() {
+ return Platform.getLog(Platform.getBundle(BUNDLE_ID));
+ }
+
+ /**
+ * Log message and throwable as error status
+ *
+ * @param message
+ * @param t
+ */
+ public static void logError(String message, Throwable t) {
+ getLog().log(createErrorStatus(message, t));
+ }
+
+ /**
+ * Log throwable as error status
+ *
+ * @param t
+ */
+ public static void logError(Throwable t) {
+ getLog().log(createErrorStatus(t.getMessage(), t));
+ }
+
+ /**
+ * Get repository for url
+ *
+ * @param repositoryUrl
+ * @return repository or null if not present in url
+ */
+ public static Repository getRepository(String repositoryUrl) {
+ return Repository.createFromUrl(repositoryUrl);
+ }
+
+ /**
+ * Create url with github.com host
+ *
+ * @param user
+ * @param project
+ * @return url
+ *
+ * @see #createGitHubUrlAlternate(String, String)
+ */
+ public static String createGitHubUrl(String user, String project) {
+ return HTTP_GITHUB_COM + '/' + user + '/' + project;
+ }
+
+ /**
+ * Create url with github.org host
+ *
+ * @param user
+ * @param project
+ * @return url
+ *
+ * @see #createGitHubUrl(String, String)
+ */
+ public static String createGitHubUrlAlternate(String user, String project) {
+ return HTTP_WWW_GITHUB_ORG + '/' + user + '/' + project;
+ }
+}
diff --git a/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/GitHubException.java b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/GitHubException.java
new file mode 100644
index 00000000..a0a58cf7
--- /dev/null
+++ b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/GitHubException.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2011 GitHub Inc.
+ * 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:
+ * Kevin Sawicki (GitHub Inc.) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.mylyn.internal.github.core;
+
+import java.io.IOException;
+import java.text.MessageFormat;
+import java.util.List;
+
+import org.eclipse.egit.github.core.FieldError;
+import org.eclipse.egit.github.core.RequestError;
+import org.eclipse.egit.github.core.client.RequestException;
+
+/**
+ * GitHub exception that wraps and formats a {@link RequestException}
+ */
+public class GitHubException extends IOException {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -1456910662911777231L;
+
+ /**
+ * Create GitHub exception from {@link RequestException}
+ *
+ * @param cause
+ */
+ public GitHubException(RequestException cause) {
+ super(cause);
+ }
+
+ public String getMessage() {
+ RequestError error = ((RequestException) getCause()).getError();
+ StringBuilder message = new StringBuilder(error.getMessage());
+ List<FieldError> errors = error.getErrors();
+ if (errors != null && errors.size() > 0) {
+ message.append(':');
+ for (FieldError fieldError : errors)
+ message.append(' ').append(format(fieldError)).append(',');
+ message.deleteCharAt(message.length() - 1);
+ }
+ return message.toString();
+ }
+
+ private String format(FieldError error) {
+ String code = error.getCode();
+ String value = error.getValue();
+ String field = error.getField();
+ String resource = error.getResource();
+ if (FieldError.CODE_INVALID.equals(code))
+ if (value != null)
+ return MessageFormat
+ .format(Messages.FieldError_InvalidFieldWithValue,
+ value, field);
+ else
+ return MessageFormat.format(Messages.FieldError_InvalidField,
+ field, value);
+ else if (FieldError.CODE_MISSING_FIELD.equals(code))
+ return MessageFormat
+ .format(Messages.FieldError_MissingField, field);
+ else
+ return MessageFormat.format(Messages.FieldError_ResourceError,
+ field, resource);
+ }
+
+}
diff --git a/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/Messages.java b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/Messages.java
new file mode 100644
index 00000000..0c8858bf
--- /dev/null
+++ b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/Messages.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2011 GitHub Inc.
+ * 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:
+ * Kevin Sawicki (GitHub Inc.) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.mylyn.internal.github.core;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * NLS for Mylyn GitHub Core
+ */
+public class Messages extends NLS {
+
+ private static final String BUNDLE_NAME = "org.eclipse.mylyn.internal.github.core.messages"; //$NON-NLS-1$
+
+ /** */
+ public static String FieldError_InvalidField;
+
+ /** */
+ public static String FieldError_InvalidFieldWithValue;
+
+ /** */
+ public static String FieldError_MissingField;
+
+ /** */
+ public static String FieldError_ResourceError;
+
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
diff --git a/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/QueryUtils.java b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/QueryUtils.java
new file mode 100644
index 00000000..85728004
--- /dev/null
+++ b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/QueryUtils.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Copyright (c) 2011 GitHub Inc.
+ * 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:
+ * Kevin Sawicki (GitHub Inc.) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.mylyn.internal.github.core;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.eclipse.mylyn.tasks.core.IRepositoryQuery;
+
+/**
+ * Utilities for working with {@link IRepositoryQuery} objects.
+ *
+ * @author Kevin Sawicki (kevin@github.com)
+ */
+public abstract class QueryUtils {
+
+ /**
+ * DELIMITER
+ */
+ public static final String DELIMITER = "::"; //$NON-NLS-1$
+
+ /**
+ * Set attribute
+ *
+ * @param key
+ * @param values
+ * @param query
+ */
+ public static void setAttribute(String key, Collection<String> values,
+ IRepositoryQuery query) {
+ if (key == null || query == null)
+ return;
+
+ if (values != null && !values.isEmpty()) {
+ StringBuilder value = new StringBuilder();
+ for (String entry : values)
+ value.append(entry).append(DELIMITER);
+ query.setAttribute(key, value.toString());
+ } else
+ query.setAttribute(key, null);
+
+ }
+
+ /**
+ * Get attribute
+ *
+ * @param key
+ * @param query
+ * @return non-null but possibly empty list
+ */
+ public static List<String> getAttributes(String key, IRepositoryQuery query) {
+ if (key == null || query == null)
+ return Collections.emptyList();
+
+ String attribute = query.getAttribute(key);
+ if (attribute == null || attribute.length() == 0)
+ return Collections.emptyList();
+
+ List<String> attrs = new LinkedList<String>();
+ String[] values = attribute.split(DELIMITER);
+ for (String value : values)
+ if (value.length() > 0)
+ attrs.add(value);
+
+ return attrs;
+ }
+
+}
diff --git a/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/gist/GistAttachmentHandler.java b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/gist/GistAttachmentHandler.java
index 172c9332..09609f7e 100644
--- a/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/gist/GistAttachmentHandler.java
+++ b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/gist/GistAttachmentHandler.java
@@ -24,7 +24,7 @@ import org.eclipse.egit.github.core.client.GitHubRequest;
import org.eclipse.egit.github.core.service.GistService;
import org.eclipse.mylyn.commons.net.AuthenticationCredentials;
import org.eclipse.mylyn.commons.net.AuthenticationType;
-import org.eclipse.mylyn.github.internal.GitHub;
+import org.eclipse.mylyn.internal.github.core.GitHub;
import org.eclipse.mylyn.tasks.core.ITask;
import org.eclipse.mylyn.tasks.core.TaskRepository;
import org.eclipse.mylyn.tasks.core.data.AbstractTaskAttachmentHandler;
diff --git a/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/gist/GistConnector.java b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/gist/GistConnector.java
index fe3760bc..f92c6d1a 100644
--- a/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/gist/GistConnector.java
+++ b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/gist/GistConnector.java
@@ -22,7 +22,7 @@ import org.eclipse.egit.github.core.client.GitHubClient;
import org.eclipse.egit.github.core.service.GistService;
import org.eclipse.mylyn.commons.net.AuthenticationCredentials;
import org.eclipse.mylyn.commons.net.AuthenticationType;
-import org.eclipse.mylyn.github.internal.GitHub;
+import org.eclipse.mylyn.internal.github.core.GitHub;
import org.eclipse.mylyn.tasks.core.AbstractRepositoryConnector;
import org.eclipse.mylyn.tasks.core.IRepositoryQuery;
import org.eclipse.mylyn.tasks.core.ITask;
diff --git a/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/gist/GistTaskDataHandler.java b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/gist/GistTaskDataHandler.java
index a09539e9..e68a2900 100644
--- a/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/gist/GistTaskDataHandler.java
+++ b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/gist/GistTaskDataHandler.java
@@ -27,8 +27,8 @@ import org.eclipse.egit.github.core.client.GitHubClient;
import org.eclipse.egit.github.core.service.GistService;
import org.eclipse.mylyn.commons.net.AuthenticationCredentials;
import org.eclipse.mylyn.commons.net.AuthenticationType;
-import org.eclipse.mylyn.github.internal.GitHub;
-import org.eclipse.mylyn.github.internal.GitHubTaskAttributeMapper;
+import org.eclipse.mylyn.internal.github.core.GitHub;
+import org.eclipse.mylyn.internal.github.core.issue.IssueAttributeMapper;
import org.eclipse.mylyn.tasks.core.IRepositoryPerson;
import org.eclipse.mylyn.tasks.core.ITaskMapping;
import org.eclipse.mylyn.tasks.core.RepositoryResponse;
@@ -274,7 +274,7 @@ public class GistTaskDataHandler extends AbstractTaskDataHandler {
* @see org.eclipse.mylyn.tasks.core.data.AbstractTaskDataHandler#getAttributeMapper(org.eclipse.mylyn.tasks.core.TaskRepository)
*/
public TaskAttributeMapper getAttributeMapper(TaskRepository taskRepository) {
- return new GitHubTaskAttributeMapper(taskRepository);
+ return new IssueAttributeMapper(taskRepository);
}
}
diff --git a/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/issue/IssueAttribute.java b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/issue/IssueAttribute.java
new file mode 100644
index 00000000..8c97c965
--- /dev/null
+++ b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/issue/IssueAttribute.java
@@ -0,0 +1,190 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Red Hat 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:
+ * David Green <david.green@tasktop.com> - initial contribution
+ * Christian Trutz <christian.trutz@gmail.com> - initial contribution
+ * Chris Aniszczyk <caniszczyk@gmail.com> - initial contribution
+ *******************************************************************************/
+package org.eclipse.mylyn.internal.github.core.issue;
+
+import org.eclipse.mylyn.tasks.core.data.TaskAttribute;
+
+/**
+ * GitHub issue task attributes
+ */
+public enum IssueAttribute {
+
+ /**
+ * Issue key
+ */
+ KEY(Messages.IssueAttribute_LabelKey, TaskAttribute.TASK_KEY,
+ TaskAttribute.TYPE_SHORT_TEXT, true, true),
+
+ /**
+ * Issue title
+ */
+ TITLE(Messages.IssueAttribute_LabekSummary, TaskAttribute.SUMMARY,
+ TaskAttribute.TYPE_SHORT_RICH_TEXT, false, true),
+
+ /**
+ * Issue description
+ */
+ BODY(Messages.IssueAttribute_LabelDescription,
+ TaskAttribute.DESCRIPTION, TaskAttribute.TYPE_LONG_RICH_TEXT,
+ false, true),
+
+ /**
+ * Issue creation date
+ */
+ CREATION_DATE(Messages.IssueAttribute_LabelCreated,
+ TaskAttribute.DATE_CREATION, TaskAttribute.TYPE_DATETIME, true,
+ false),
+
+ /**
+ * Issue modification date
+ */
+ MODIFICATION_DATE(Messages.IssueAttribute_LabelModified,
+ TaskAttribute.DATE_MODIFICATION, TaskAttribute.TYPE_DATETIME, true,
+ false),
+
+ /**
+ * Issue closed date
+ */
+ CLOSED_DATE(Messages.IssueAttribute_LabelClosed,
+ TaskAttribute.DATE_COMPLETION, TaskAttribute.TYPE_DATETIME, true,
+ false),
+
+ /**
+ * Issue status
+ */
+ STATUS(Messages.IssueAttribute_LabelStatus, TaskAttribute.STATUS,
+ TaskAttribute.TYPE_SHORT_TEXT, false, true),
+
+ /**
+ * Issue reporter
+ */
+ REPORTER(Messages.IssueAttribute_LabelReporter,
+ TaskAttribute.USER_REPORTER, TaskAttribute.TYPE_PERSON, true, false),
+
+ /**
+ * Comment being added to issue
+ */
+ COMMENT_NEW(Messages.IssueAttribute_LabelComment,
+ TaskAttribute.COMMENT_NEW, TaskAttribute.TYPE_LONG_RICH_TEXT,
+ false, false),
+
+ /**
+ * Labels applied to issue
+ */
+ LABELS(Messages.IssueAttribute_LabelLabels, "github.issue.labels", //$NON-NLS-1$
+ TaskAttribute.TYPE_MULTI_SELECT, true, false),
+
+ /**
+ * Issue assignee
+ */
+ ASSIGNEE(Messages.IssueAttribute_LabelAssignee,
+ TaskAttribute.USER_ASSIGNED, TaskAttribute.TYPE_PERSON, false, true),
+
+ /**
+ * Issue milestone
+ */
+ MILESTONE(Messages.IssueAttribute_LabelMilestone,
+ "github.issue.milestone", TaskAttribute.TYPE_SINGLE_SELECT, //$NON-NLS-1$
+ false, true),
+
+ /**
+ * Issue assignee gravatar
+ */
+ ASSIGNEE_GRAVATAR(Messages.IssueAttribute_LabelAssigneeGravatar,
+ "github.issue.assignee.gravatar", TaskAttribute.TYPE_URL, null, //$NON-NLS-1$
+ true, false),
+
+ /**
+ * Issue reporter gravatar
+ */
+ REPORTER_GRAVATAR(Messages.IssueAttribute_LabelReporterGravatar,
+ "github.issue.reporter.gravatar", TaskAttribute.TYPE_URL, null, //$NON-NLS-1$
+ true, false);
+
+ private final String id;
+ private final String label;
+ private final String kind;
+ private final boolean readOnly;
+ private final boolean initTask;
+ private final String type;
+
+ private IssueAttribute(String label, String id, String type,
+ boolean readOnly, boolean initTask) {
+ this(label, id, type, TaskAttribute.KIND_DEFAULT, readOnly, initTask);
+ }
+
+ private IssueAttribute(String label, String id, String type,
+ String kind, boolean readOnly, boolean initTask) {
+ this.label = label;
+ this.id = id;
+ this.kind = kind;
+ this.type = type;
+ this.readOnly = readOnly;
+ this.initTask = initTask;
+ }
+
+ /**
+ * Get attribute label
+ *
+ * @return label
+ */
+ public String getLabel() {
+ return label;
+ }
+
+ /**
+ * Get attribute id
+ *
+ * @return id
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Get attribute type
+ *
+ * @return type
+ */
+ public String getType() {
+ return type;
+ }
+
+ /**
+ * Is attribute read only?
+ *
+ * @return true if read only, false otherwise
+ */
+ public boolean isReadOnly() {
+ return readOnly;
+ }
+
+ /**
+ * Get attribute kind
+ *
+ * @return kind
+ */
+ public String getKind() {
+ return this.kind;
+ }
+
+ /**
+ * Is this attribute created for new tasks?
+ *
+ * @return true if needed for new tasks, false otherwise
+ */
+ public boolean isInitTask() {
+ return initTask;
+ }
+
+}
diff --git a/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/issue/IssueAttributeMapper.java b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/issue/IssueAttributeMapper.java
new file mode 100644
index 00000000..e4038af7
--- /dev/null
+++ b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/issue/IssueAttributeMapper.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Red Hat 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:
+ * David Green <david.green@tasktop.com> - initial contribution
+ * Christian Trutz <christian.trutz@gmail.com> - initial contribution
+ * Chris Aniszczyk <caniszczyk@gmail.com> - initial contribution
+ *******************************************************************************/
+package org.eclipse.mylyn.internal.github.core.issue;
+
+import java.text.DateFormat;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+import org.eclipse.mylyn.tasks.core.TaskRepository;
+import org.eclipse.mylyn.tasks.core.data.TaskAttribute;
+import org.eclipse.mylyn.tasks.core.data.TaskAttributeMapper;
+
+/**
+ * GitHub task attribute mapper class.
+ */
+public class IssueAttributeMapper extends TaskAttributeMapper {
+
+ private DateFormat format = DateFormat.getDateTimeInstance(
+ DateFormat.MEDIUM, DateFormat.SHORT);
+
+ /**
+ * @param taskRepository
+ */
+ public IssueAttributeMapper(TaskRepository taskRepository) {
+ super(taskRepository);
+ }
+
+ /**
+ * @see org.eclipse.mylyn.tasks.core.data.TaskAttributeMapper#getValueLabels(org.eclipse.mylyn.tasks.core.data.TaskAttribute)
+ */
+ public List<String> getValueLabels(TaskAttribute taskAttribute) {
+ String type = taskAttribute.getMetaData().getType();
+ if (TaskAttribute.TYPE_DATE.equals(type)
+ || TaskAttribute.TYPE_DATETIME.equals(type)) {
+ String value = taskAttribute.getValue();
+ if (value.length() > 0) {
+ Date date = new Date(Long.parseLong(value));
+ synchronized (this.format) {
+ value = this.format.format(date);
+ }
+ return Collections.singletonList(value);
+ }
+ }
+ return super.getValueLabels(taskAttribute);
+ }
+}
diff --git a/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/issue/IssueConnector.java b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/issue/IssueConnector.java
new file mode 100644
index 00000000..274c4bcc
--- /dev/null
+++ b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/issue/IssueConnector.java
@@ -0,0 +1,413 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Red Hat 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:
+ * David Green <david.green@tasktop.com> - initial contribution
+ * Christian Trutz <christian.trutz@gmail.com> - initial contribution
+ * Chris Aniszczyk <caniszczyk@gmail.com> - initial contribution
+ *******************************************************************************/
+package org.eclipse.mylyn.internal.github.core.issue;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.egit.github.core.Comment;
+import org.eclipse.egit.github.core.Issue;
+import org.eclipse.egit.github.core.Label;
+import org.eclipse.egit.github.core.Milestone;
+import org.eclipse.egit.github.core.Repository;
+import org.eclipse.egit.github.core.client.GitHubClient;
+import org.eclipse.egit.github.core.client.RequestException;
+import org.eclipse.egit.github.core.service.IssueService;
+import org.eclipse.egit.github.core.service.LabelService;
+import org.eclipse.egit.github.core.service.MilestoneService;
+import org.eclipse.egit.github.core.util.LabelComparator;
+import org.eclipse.mylyn.commons.net.AuthenticationCredentials;
+import org.eclipse.mylyn.commons.net.AuthenticationType;
+import org.eclipse.mylyn.commons.net.Policy;
+import org.eclipse.mylyn.internal.github.core.GitHub;
+import org.eclipse.mylyn.internal.github.core.GitHubException;
+import org.eclipse.mylyn.internal.github.core.QueryUtils;
+import org.eclipse.mylyn.tasks.core.AbstractRepositoryConnector;
+import org.eclipse.mylyn.tasks.core.IRepositoryQuery;
+import org.eclipse.mylyn.tasks.core.ITask;
+import org.eclipse.mylyn.tasks.core.TaskRepository;
+import org.eclipse.mylyn.tasks.core.data.AbstractTaskDataHandler;
+import org.eclipse.mylyn.tasks.core.data.TaskAttribute;
+import org.eclipse.mylyn.tasks.core.data.TaskData;
+import org.eclipse.mylyn.tasks.core.data.TaskDataCollector;
+import org.eclipse.mylyn.tasks.core.data.TaskMapper;
+import org.eclipse.mylyn.tasks.core.sync.ISynchronizationSession;
+
+/**
+ * GitHub connector.
+ */
+public class IssueConnector extends AbstractRepositoryConnector {
+
+ /**
+ * GitHub kind.
+ */
+ public static final String KIND = GitHub.CONNECTOR_KIND;
+
+ /**
+ * Create client for repository
+ *
+ * @param repository
+ * @return client
+ */
+ public static GitHubClient createClient(TaskRepository repository) {
+ GitHubClient client = new GitHubClient();
+ AuthenticationCredentials credentials = repository
+ .getCredentials(AuthenticationType.REPOSITORY);
+ if (credentials != null)
+ client.setCredentials(credentials.getUserName(),
+ credentials.getPassword());
+ return client;
+ }
+
+ /**
+ * GitHub specific {@link AbstractTaskDataHandler}.
+ */
+ private final IssueTaskDataHandler taskDataHandler;
+
+ private final Map<TaskRepository, List<Label>> repositoryLabels = Collections
+ .synchronizedMap(new HashMap<TaskRepository, List<Label>>());
+
+ private final Map<TaskRepository, List<Milestone>> repositoryMilestones = Collections
+ .synchronizedMap(new HashMap<TaskRepository, List<Milestone>>());
+
+ /**
+ * Create GitHub issue repository connector
+ */
+ public IssueConnector() {
+ taskDataHandler = new IssueTaskDataHandler(this);
+ }
+
+ /**
+ * Refresh labels for repository
+ *
+ * @param repository
+ * @return labels
+ * @throws CoreException
+ */
+ public List<Label> refreshLabels(TaskRepository repository)
+ throws CoreException {
+ Assert.isNotNull(repository, "Repository cannot be null"); //$NON-NLS-1$
+ Repository repo = GitHub.getRepository(repository.getRepositoryUrl());
+ GitHubClient client = createClient(repository);
+ LabelService service = new LabelService(client);
+ try {
+ List<Label> labels = service.getLabels(repo.getOwner(),
+ repo.getName());
+ Collections.sort(labels, new LabelComparator());
+ this.repositoryLabels.put(repository, labels);
+ return labels;
+ } catch (IOException e) {
+ throw new CoreException(GitHub.createErrorStatus(e));
+ }
+ }
+
+ /**
+ * Get labels for task repository.
+ *
+ * @param repository
+ * @return non-null but possibly empty list of labels
+ */
+ public List<Label> getLabels(TaskRepository repository) {
+ Assert.isNotNull(repository, "Repository cannot be null"); //$NON-NLS-1$
+ List<Label> labels = new LinkedList<Label>();
+ List<Label> cached = this.repositoryLabels.get(repository);
+ if (cached != null) {
+ labels.addAll(cached);
+ }
+ return labels;
+ }
+
+ /**
+ * Are there cached labels for the specified task repository?
+ *
+ * @param repository
+ * @return true if contains labels, false otherwise
+ */
+ public boolean hasCachedLabels(TaskRepository repository) {
+ return this.repositoryLabels.containsKey(repository);
+ }
+
+ /**
+ * Refresh milestones for repository
+ *
+ * @param repository
+ * @return milestones
+ * @throws CoreException
+ */
+ public List<Milestone> refreshMilestones(TaskRepository repository)
+ throws CoreException {
+ Assert.isNotNull(repository, "Repository cannot be null"); //$NON-NLS-1$
+ Repository repo = GitHub.getRepository(repository.getRepositoryUrl());
+ GitHubClient client = createClient(repository);
+ MilestoneService service = new MilestoneService(client);
+ try {
+ List<Milestone> milestones = new LinkedList<Milestone>();
+ milestones.addAll(service.getMilestones(repo.getOwner(),
+ repo.getName(), IssueService.STATE_OPEN));
+ milestones.addAll(service.getMilestones(repo.getOwner(),
+ repo.getName(), IssueService.STATE_CLOSED));
+ this.repositoryMilestones.put(repository, milestones);
+ return milestones;
+ } catch (IOException e) {
+ throw new CoreException(GitHub.createErrorStatus(e));
+ }
+ }
+
+ /**
+ * Get milestones for task repository.
+ *
+ * @param repository
+ * @return non-null but possibly empty list of milestones
+ */
+ public List<Milestone> getMilestones(TaskRepository repository) {
+ Assert.isNotNull(repository, "Repository cannot be null"); //$NON-NLS-1$
+ List<Milestone> milestones = new LinkedList<Milestone>();
+ List<Milestone> cached = this.repositoryMilestones.get(repository);
+ if (cached != null) {
+ milestones.addAll(cached);
+ }
+ return milestones;
+ }
+
+ /**
+ * Are there cached milestones for the specified task repository?
+ *
+ * @param repository
+ * @return true if contains milestones, false otherwise
+ */
+ public boolean hasCachedMilestones(TaskRepository repository) {
+ return this.repositoryMilestones.containsKey(repository);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return always {@code true}
+ */
+ @Override
+ public boolean canCreateNewTask(TaskRepository repository) {
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return always {@code true}
+ */
+ @Override
+ public boolean canCreateTaskFromKey(TaskRepository repository) {
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see #KIND
+ */
+ @Override
+ public String getConnectorKind() {
+ return KIND;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getLabel() {
+ return Messages.IssueConnector_LabelConnector;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public AbstractTaskDataHandler getTaskDataHandler() {
+ return this.taskDataHandler;
+ }
+
+ @Override
+ public IStatus performQuery(TaskRepository repository,
+ IRepositoryQuery query, TaskDataCollector collector,
+ ISynchronizationSession session, IProgressMonitor monitor) {
+ IStatus result = Status.OK_STATUS;
+ List<String> statuses = QueryUtils.getAttributes(
+ IssueService.FILTER_STATE, query);
+
+ monitor.beginTask(Messages.IssueConector_TaskQuerying,
+ statuses.size());
+ try {
+ Repository repo = GitHub.getRepository(repository
+ .getRepositoryUrl());
+
+ GitHubClient client = createClient(repository);
+ IssueService service = new IssueService(client);
+
+ Map<String, String> filterData = new HashMap<String, String>();
+ String mentions = query.getAttribute(IssueService.FILTER_MENTIONED);
+ if (mentions != null)
+ filterData.put(IssueService.FILTER_MENTIONED, mentions);
+
+ String assignee = query.getAttribute(IssueService.FILTER_ASSIGNEE);
+ if (assignee != null)
+ filterData.put(IssueService.FILTER_ASSIGNEE, assignee);
+
+ String milestone = query
+ .getAttribute(IssueService.FILTER_MILESTONE);
+ if (milestone != null)
+ filterData.put(IssueService.FILTER_MILESTONE, milestone);
+
+ List<String> labels = QueryUtils.getAttributes(
+ IssueService.FILTER_LABELS, query);
+ if (!labels.isEmpty()) {
+ StringBuilder labelsQuery = new StringBuilder();
+ for (String label : labels)
+ labelsQuery.append(label).append(',');
+ filterData.put(IssueService.FILTER_LABELS,
+ labelsQuery.toString());
+ }
+
+ for (String status : statuses) {
+ filterData.put(IssueService.FILTER_STATE, status);
+ List<Issue> issues = service.getIssues(repo.getOwner(),
+ repo.getName(), filterData);
+
+ // collect task data
+ for (Issue issue : issues) {
+ TaskData taskData = taskDataHandler.createTaskData(
+ repository, monitor, repo.getOwner(),
+ repo.getName(), issue);
+ taskData.setPartial(true);
+ collector.accept(taskData);
+ }
+ monitor.worked(1);
+ }
+
+ result = Status.OK_STATUS;
+ } catch (RequestException e) {
+ result = GitHub.createErrorStatus(new GitHubException(e));
+ } catch (IOException e) {
+ result = GitHub.createErrorStatus(e);
+ }
+
+ monitor.done();
+ return result;
+ }
+
+ @Override
+ public TaskData getTaskData(TaskRepository repository, String taskId,
+ IProgressMonitor monitor) throws CoreException {
+ Repository repo = GitHub.getRepository(repository.getRepositoryUrl());
+
+ try {
+ GitHubClient client = createClient(repository);
+ IssueService service = new IssueService(client);
+ Issue issue = service.getIssue(repo.getOwner(), repo.getName(),
+ taskId);
+ List<Comment> comments = null;
+ if (issue.getComments() > 0) {
+ comments = service.getComments(repo.getOwner(), repo.getName(),
+ taskId);
+ }
+ TaskData taskData = taskDataHandler.createTaskData(repository,
+ monitor, repo.getOwner(), repo.getName(), issue, comments);
+
+ return taskData;
+ } catch (IOException e) {
+ throw new CoreException(GitHub.createErrorStatus(e));
+ }
+ }
+
+ @Override
+ public String getRepositoryUrlFromTaskUrl(String taskFullUrl) {
+ if (taskFullUrl != null) {
+ Matcher matcher = Pattern.compile(
+ "(http://.+?)/issues/issue/([^/]+)").matcher(taskFullUrl); //$NON-NLS-1$
+ if (matcher.matches()) {
+ return matcher.group(1);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public String getTaskIdFromTaskUrl(String taskFullUrl) {
+ if (taskFullUrl != null) {
+ Matcher matcher = Pattern
+ .compile(".+?/issues/issue/([^/]+)").matcher(taskFullUrl); //$NON-NLS-1$
+ if (matcher.matches()) {
+ return matcher.group(1);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public String getTaskUrl(String repositoryUrl, String taskId) {
+ return repositoryUrl + "/issues/issue/" + taskId; //$NON-NLS-1$
+ }
+
+ @Override
+ public void updateRepositoryConfiguration(TaskRepository taskRepository,
+ IProgressMonitor monitor) throws CoreException {
+ monitor = Policy.monitorFor(monitor);
+ monitor.beginTask("", 2); //$NON-NLS-1$
+ monitor.setTaskName(Messages.IssueConnector_TaskUpdatingLabels);
+ refreshLabels(taskRepository);
+ monitor.worked(1);
+ monitor.setTaskName(Messages.IssueConnector_TaskUpdatingMilestones);
+ refreshMilestones(taskRepository);
+ monitor.done();
+ }
+
+ @Override
+ public boolean hasTaskChanged(TaskRepository repository, ITask task,
+ TaskData taskData) {
+ TaskAttribute modAttribute = taskData.getRoot().getAttribute(
+ TaskAttribute.DATE_MODIFICATION);
+ if (modAttribute == null)
+ return false;
+
+ boolean changed = true;
+ Date modDate = task.getModificationDate();
+ if (modDate != null) {
+ Date updateDate = taskData.getAttributeMapper().getDateValue(
+ modAttribute);
+ if (updateDate != null)
+ changed = updateDate.after(modDate);
+ }
+ return changed;
+ }
+
+ @Override
+ public void updateTaskFromTaskData(TaskRepository taskRepository,
+ ITask task, TaskData taskData) {
+ if (!taskData.isNew()) {
+ task.setUrl(getTaskUrl(taskRepository.getUrl(),
+ taskData.getTaskId()));
+ }
+ new TaskMapper(taskData).applyTo(task);
+ }
+
+}
diff --git a/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/issue/IssueOperation.java b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/issue/IssueOperation.java
new file mode 100644
index 00000000..d851919d
--- /dev/null
+++ b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/issue/IssueOperation.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Red Hat 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:
+ * David Green <david.green@tasktop.com> - initial contribution
+ * Christian Trutz <christian.trutz@gmail.com> - initial contribution
+ * Chris Aniszczyk <caniszczyk@gmail.com> - initial contribution
+ *******************************************************************************/
+package org.eclipse.mylyn.internal.github.core.issue;
+
+/**
+ * Enumeration of task operations
+ */
+public enum IssueOperation {
+
+ /**
+ * LEAD
+ */
+ LEAVE("Leave "),
+
+ /**
+ * REOPEN
+ */
+ REOPEN("Reopen"),
+
+ /**
+ * CLOSE
+ */
+ CLOSE("Close");
+
+ private final String label;
+
+ private IssueOperation(String label) {
+ this.label = label;
+ }
+
+ /**
+ * Get label
+ *
+ * @return label
+ */
+ public String getLabel() {
+ return label;
+ }
+
+ /**
+ * Get id
+ *
+ * @return id
+ */
+ public String getId() {
+ return name();
+ }
+
+ /**
+ * get the operation by its id
+ *
+ * @param opId
+ * the id, or null
+ * @return the operation, or null if the id was null or did not match any
+ * operation
+ */
+ public static IssueOperation fromId(String opId) {
+ for (IssueOperation op : values()) {
+ if (op.getId().equals(opId)) {
+ return op;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/issue/IssueTaskDataHandler.java b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/issue/IssueTaskDataHandler.java
new file mode 100644
index 00000000..3cb43c81
--- /dev/null
+++ b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/issue/IssueTaskDataHandler.java
@@ -0,0 +1,449 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Red Hat 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:
+ * David Green <david.green@tasktop.com> - initial contribution
+ * Christian Trutz <christian.trutz@gmail.com> - initial contribution
+ * Chris Aniszczyk <caniszczyk@gmail.com> - initial contribution
+ *******************************************************************************/
+package org.eclipse.mylyn.internal.github.core.issue;
+
+import java.io.IOException;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.egit.github.core.Comment;
+import org.eclipse.egit.github.core.Issue;
+import org.eclipse.egit.github.core.Label;
+import org.eclipse.egit.github.core.Milestone;
+import org.eclipse.egit.github.core.Repository;
+import org.eclipse.egit.github.core.User;
+import org.eclipse.egit.github.core.client.GitHubClient;
+import org.eclipse.egit.github.core.client.RequestException;
+import org.eclipse.egit.github.core.service.IssueService;
+import org.eclipse.egit.github.core.service.LabelService;
+import org.eclipse.mylyn.internal.github.core.GitHub;
+import org.eclipse.mylyn.internal.github.core.GitHubException;
+import org.eclipse.mylyn.tasks.core.IRepositoryPerson;
+import org.eclipse.mylyn.tasks.core.ITaskMapping;
+import org.eclipse.mylyn.tasks.core.RepositoryResponse;
+import org.eclipse.mylyn.tasks.core.RepositoryResponse.ResponseKind;
+import org.eclipse.mylyn.tasks.core.TaskRepository;
+import org.eclipse.mylyn.tasks.core.data.AbstractTaskDataHandler;
+import org.eclipse.mylyn.tasks.core.data.TaskAttribute;
+import org.eclipse.mylyn.tasks.core.data.TaskAttributeMapper;
+import org.eclipse.mylyn.tasks.core.data.TaskAttributeMetaData;
+import org.eclipse.mylyn.tasks.core.data.TaskCommentMapper;
+import org.eclipse.mylyn.tasks.core.data.TaskData;
+import org.eclipse.mylyn.tasks.core.data.TaskOperation;
+
+/**
+ * GitHub issue task data handler
+ */
+public class IssueTaskDataHandler extends AbstractTaskDataHandler {
+
+ private static final String DATA_VERSION = "1"; //$NON-NLS-1$
+ private static final String MILESTONE_NONE_KEY = "0"; //$NON-NLS-1$
+ private IssueAttributeMapper taskAttributeMapper = null;
+ private final IssueConnector connector;
+
+ /**
+ * Create GitHub issue task data handler for connector
+ *
+ * @param connector
+ */
+ public IssueTaskDataHandler(IssueConnector connector) {
+ this.connector = connector;
+ }
+
+ @Override
+ public TaskAttributeMapper getAttributeMapper(TaskRepository taskRepository) {
+ if (this.taskAttributeMapper == null)
+ this.taskAttributeMapper = new IssueAttributeMapper(
+ taskRepository);
+ return this.taskAttributeMapper;
+ }
+
+ public TaskData createTaskData(TaskRepository repository,
+ IProgressMonitor monitor, String user, String project, Issue issue) {
+
+ String key = Integer.toString(issue.getNumber());
+ TaskData data = new TaskData(getAttributeMapper(repository),
+ IssueConnector.KIND, repository.getRepositoryUrl(),
+ key);
+ data.setVersion(DATA_VERSION);
+
+ createOperations(data, issue);
+
+ createAttribute(data, IssueAttribute.KEY, key);
+ createAttribute(data, IssueAttribute.TITLE, issue.getTitle());
+ createAttribute(data, IssueAttribute.BODY, issue.getBody());
+ createAttribute(data, IssueAttribute.STATUS, issue.getState());
+ createAttribute(data, IssueAttribute.CREATION_DATE,
+ issue.getCreatedAt());
+ createAttribute(data, IssueAttribute.MODIFICATION_DATE,
+ issue.getUpdatedAt());
+ createAttribute(data, IssueAttribute.CLOSED_DATE,
+ issue.getClosedAt());
+
+ User reporter = issue.getUser();
+ createAttribute(data, IssueAttribute.REPORTER, reporter,
+ repository);
+ String reporterGravatar = reporter != null ? reporter.getGravatarUrl()
+ : null;
+ createAttribute(data, IssueAttribute.REPORTER_GRAVATAR,
+ reporterGravatar);
+
+ User assignee = issue.getAssignee();
+ createAttribute(data, IssueAttribute.ASSIGNEE, assignee,
+ repository);
+ String assigneeGravatar = assignee != null ? assignee.getGravatarUrl()
+ : null;
+ createAttribute(data, IssueAttribute.ASSIGNEE_GRAVATAR,
+ assigneeGravatar);
+
+ createAttribute(data, IssueAttribute.COMMENT_NEW);
+
+ createLabels(repository, data, issue);
+
+ createMilestone(repository, data, issue);
+
+ return data;
+ }
+
+ private void createMilestone(TaskRepository repository, TaskData data,
+ Issue issue) {
+ Milestone current = issue.getMilestone();
+ String number = current != null ? Integer.toString(current.getNumber())
+ : MILESTONE_NONE_KEY;
+ TaskAttribute milestoneAttribute = createAttribute(data,
+ IssueAttribute.MILESTONE, number);
+
+ if (!this.connector.hasCachedMilestones(repository))
+ try {
+ this.connector.refreshMilestones(repository);
+ } catch (CoreException ignore) {
+ // Ignored
+ }
+
+ List<Milestone> cachedMilestones = this.connector
+ .getMilestones(repository);
+ milestoneAttribute.putOption(MILESTONE_NONE_KEY,
+ Messages.IssueAttribute_MilestoneNone);
+ for (Milestone milestone : cachedMilestones)
+ milestoneAttribute.putOption(
+ Integer.toString(milestone.getNumber()),
+ milestone.getTitle());
+ }
+
+ private void createLabels(TaskRepository repository, TaskData data,
+ Issue issue) {
+ TaskAttribute labels = createAttribute(data,
+ IssueAttribute.LABELS, issue.getLabels());
+
+ if (!this.connector.hasCachedLabels(repository))
+ try {
+ this.connector.refreshLabels(repository);
+ } catch (CoreException ignore) {
+ // Ignored
+ }
+
+ List<Label> cachedLabels = this.connector.getLabels(repository);
+ for (Label label : cachedLabels)
+ labels.putOption(label.getName(), label.getName());
+ }
+
+ private void createOperations(TaskData data, Issue issue) {
+ TaskAttribute operationAttribute = data.getRoot().createAttribute(
+ TaskAttribute.OPERATION);
+ operationAttribute.getMetaData().setType(TaskAttribute.TYPE_OPERATION);
+
+ if (!data.isNew()) {
+ String state = issue.getState();
+ if (state != null) {
+ addOperation(data, issue, IssueOperation.LEAVE, true);
+ if (state.equals(IssueService.STATE_OPEN))
+ addOperation(data, issue, IssueOperation.CLOSE, false);
+ else if (state.equals(IssueService.STATE_CLOSED))
+ addOperation(data, issue, IssueOperation.REOPEN, false);
+ }
+ }
+ }
+
+ private void addOperation(TaskData data, Issue issue,
+ IssueOperation operation, boolean asDefault) {
+ TaskAttribute attribute = data.getRoot().createAttribute(
+ TaskAttribute.PREFIX_OPERATION + operation.getId());
+ String label = createOperationLabel(issue, operation);
+ TaskOperation.applyTo(attribute, operation.getId(), label);
+
+ if (asDefault) {
+ TaskAttribute operationAttribute = data.getRoot().getAttribute(
+ TaskAttribute.OPERATION);
+ TaskOperation.applyTo(operationAttribute, operation.getId(), label);
+ }
+ }
+
+ private String createOperationLabel(Issue issue,
+ IssueOperation operation) {
+ return operation == IssueOperation.LEAVE ? operation.getLabel()
+ + issue.getState() : operation.getLabel();
+ }
+
+ public TaskData createTaskData(TaskRepository repository,
+ IProgressMonitor monitor, String user, String project, Issue issue,
+ List<Comment> comments) {
+ TaskData taskData = createTaskData(repository, monitor, user, project,
+ issue);
+ taskData.setPartial(false);
+
+ if (comments != null && !comments.isEmpty()) {
+ int count = 1;
+ TaskAttribute root = taskData.getRoot();
+ for (Comment comment : comments) {
+ TaskCommentMapper commentMapper = new TaskCommentMapper();
+ User author = comment.getUser();
+ IRepositoryPerson authorPerson = repository.createPerson(author
+ .getLogin());
+ authorPerson.setName(author.getName());
+ commentMapper.setAuthor(authorPerson);
+ commentMapper.setCreationDate(comment.getCreatedAt());
+ commentMapper.setText(comment.getBody());
+ commentMapper.setCommentId(comment.getUrl());
+ commentMapper.setNumber(count);
+
+ TaskAttribute attribute = root
+ .createAttribute(TaskAttribute.PREFIX_COMMENT + count);
+ commentMapper.applyTo(attribute);
+ count++;
+ }
+ }
+
+ return taskData;
+ }
+
+ private Issue createIssue(TaskData taskData) {
+ Issue issue = new Issue();
+ if (!taskData.isNew()) {
+ issue.setNumber(Integer.parseInt(taskData.getTaskId()));
+ }
+ issue.setBody(getAttributeValue(taskData, IssueAttribute.BODY));
+ issue.setTitle(getAttributeValue(taskData, IssueAttribute.TITLE));
+
+ String assigneeValue = getAttributeValue(taskData,
+ IssueAttribute.ASSIGNEE);
+ if (assigneeValue != null) {
+ if (assigneeValue.trim().length() == 0)
+ assigneeValue = null;
+ User assignee = new User().setName(assigneeValue);
+ issue.setAssignee(assignee);
+ }
+
+ String milestoneValue = getAttributeValue(taskData,
+ IssueAttribute.MILESTONE);
+ if (milestoneValue != null) {
+ Milestone milestone = new Milestone();
+ if (milestoneValue.length() > 0)
+ milestone.setNumber(Integer.parseInt(milestoneValue));
+ issue.setMilestone(milestone);
+ }
+ return issue;
+ }
+
+ private String getAttributeValue(TaskData taskData,
+ IssueAttribute attr) {
+ TaskAttribute attribute = taskData.getRoot().getAttribute(attr.getId());
+ return attribute == null ? null : attribute.getValue();
+ }
+
+ private TaskAttribute createAttribute(TaskData data,
+ IssueAttribute attribute) {
+ TaskAttribute attr = data.getRoot().createAttribute(attribute.getId());
+ TaskAttributeMetaData metaData = attr.getMetaData();
+ metaData.defaults().setType(attribute.getType())
+ .setKind(attribute.getKind()).setLabel(attribute.getLabel())
+ .setReadOnly(attribute.isReadOnly());
+ return attr;
+ }
+
+ private TaskAttribute createAttribute(TaskData data,
+ IssueAttribute attribute, String value) {
+ TaskAttribute attr = createAttribute(data, attribute);
+ if (value != null) {
+ data.getAttributeMapper().setValue(attr, value);
+ }
+ return attr;
+ }
+
+ private TaskAttribute createAttribute(TaskData data,
+ IssueAttribute attribute, Date value) {
+ TaskAttribute attr = createAttribute(data, attribute);
+ if (value != null) {
+ data.getAttributeMapper().setDateValue(attr, value);
+ }
+ return attr;
+ }
+
+ private void createAttribute(TaskData data, IssueAttribute attribute,
+ User value, TaskRepository repository) {
+ TaskAttribute attr = createAttribute(data, attribute);
+ if (value != null) {
+ IRepositoryPerson person = repository
+ .createPerson(value.getLogin());
+ person.setName(value.getName());
+ data.getAttributeMapper().setRepositoryPerson(attr, person);
+ }
+ }
+
+ private TaskAttribute createAttribute(TaskData data,
+ IssueAttribute attribute, List<Label> values) {
+ TaskAttribute attr = createAttribute(data, attribute);
+ if (values != null) {
+ List<String> labels = new LinkedList<String>();
+ for (Label label : values) {
+ labels.add(label.getName());
+ }
+ data.getAttributeMapper().setValues(attr, labels);
+ }
+ return attr;
+ }
+
+ @Override
+ public boolean initializeTaskData(TaskRepository repository, TaskData data,
+ ITaskMapping initializationData, IProgressMonitor monitor)
+ throws CoreException {
+
+ data.setVersion(DATA_VERSION);
+
+ for (IssueAttribute attr : IssueAttribute.values()) {
+ if (attr.isInitTask()) {
+ createAttribute(data, attr, (String) null);
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Update labels for issue
+ *
+ * @param user
+ * @param repo
+ * @param client
+ * @param repository
+ * @param data
+ * @param oldAttributes
+ * @throws IOException
+ */
+ protected void updateLabels(String user, String repo, GitHubClient client,
+ TaskRepository repository, TaskData data,
+ Set<TaskAttribute> oldAttributes) throws IOException {
+ // Update labels if changed
+ TaskAttribute labelsAttribute = data.getRoot().getAttribute(
+ IssueAttribute.LABELS.getId());
+ if (oldAttributes.contains(labelsAttribute)) {
+ LabelService labelService = new LabelService(client);
+
+ if (!this.connector.hasCachedLabels(repository))
+ try {
+ this.connector.refreshLabels(repository);
+ } catch (CoreException ignore) {
+ // Ignore
+ }
+ List<Label> currentLabels = this.connector.getLabels(repository);
+ List<Label> newLabels = new LinkedList<Label>();
+ List<Label> labels = new LinkedList<Label>();
+ for (String value : labelsAttribute.getValues()) {
+ Label label = new Label().setName(value);
+ if (!currentLabels.contains(label))
+ newLabels.add(label);
+ labels.add(label);
+ }
+ for (Label label : newLabels)
+ try {
+ labelService.createLabel(user, repo, label);
+ } catch (IOException e) {
+ // TODO detect failure and handle label already created
+ }
+
+ labelService.setLabels(user, repo, data.getTaskId(), labels);
+
+ if (!newLabels.isEmpty())
+ try {
+ this.connector.refreshLabels(repository);
+ } catch (CoreException ignore) {
+ // Ignore
+ }
+
+ }
+ }
+
+ @Override
+ public RepositoryResponse postTaskData(TaskRepository repository,
+ TaskData taskData, Set<TaskAttribute> oldAttributes,
+ IProgressMonitor monitor) throws CoreException {
+ String taskId = taskData.getTaskId();
+ Issue issue = createIssue(taskData);
+ Repository repo = GitHub.getRepository(repository.getRepositoryUrl());
+ try {
+ GitHubClient client = IssueConnector
+ .createClient(repository);
+ IssueService service = new IssueService(client);
+ if (taskData.isNew()) {
+ issue.setState(IssueService.STATE_OPEN);
+ issue = service.createIssue(repo.getOwner(), repo.getName(),
+ issue);
+ taskId = Integer.toString(issue.getNumber());
+ } else {
+
+ // Handle new comment
+ String comment = getAttributeValue(taskData,
+ IssueAttribute.COMMENT_NEW);
+ if (comment != null && comment.length() > 0)
+ service.createComment(repo.getOwner(), repo.getName(),
+ taskId, comment);
+
+ updateLabels(repo.getOwner(), repo.getName(), client,
+ repository, taskData, oldAttributes);
+
+ // Handle state change
+ TaskAttribute operationAttribute = taskData.getRoot()
+ .getAttribute(TaskAttribute.OPERATION);
+ if (operationAttribute != null) {
+ IssueOperation operation = IssueOperation
+ .fromId(operationAttribute.getValue());
+ if (operation != IssueOperation.LEAVE)
+ switch (operation) {
+ case REOPEN:
+ issue.setState(IssueService.STATE_OPEN);
+ break;
+ case CLOSE:
+ issue.setState(IssueService.STATE_CLOSED);
+ break;
+ default:
+ break;
+ }
+ }
+
+ service.editIssue(repo.getOwner(), repo.getName(), issue);
+ }
+ return new RepositoryResponse(
+ taskData.isNew() ? ResponseKind.TASK_CREATED
+ : ResponseKind.TASK_UPDATED, taskId);
+ } catch (RequestException e) {
+ throw new CoreException(
+ GitHub.createErrorStatus(new GitHubException(e)));
+ } catch (IOException e) {
+ throw new CoreException(GitHub.createErrorStatus(e));
+ }
+
+ }
+}
diff --git a/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/issue/Messages.java b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/issue/Messages.java
new file mode 100644
index 00000000..6b97a831
--- /dev/null
+++ b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/issue/Messages.java
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * Copyright (c) 2011 GitHub Inc.
+ * 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:
+ * Kevin Sawicki (GitHub Inc.) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.mylyn.internal.github.core.issue;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * NLS for Mylyn GitHub Core
+ */
+public class Messages extends NLS {
+
+ private static final String BUNDLE_NAME = "org.eclipse.mylyn.internal.github.core.issue.messages"; //$NON-NLS-1$
+
+ /** */
+ public static String IssueConnector_LabelConnector;
+
+ /** */
+ public static String IssueConector_TaskQuerying;
+
+ /** */
+ public static String IssueConnector_TaskUpdatingLabels;
+
+ /** */
+ public static String IssueConnector_TaskUpdatingMilestones;
+
+ /** */
+ public static String IssueAttribute_LabekSummary;
+
+ /** */
+ public static String IssueAttribute_LabelAssignee;
+
+ /** */
+ public static String IssueAttribute_LabelAssigneeGravatar;
+
+ /** */
+ public static String IssueAttribute_LabelClosed;
+
+ /** */
+ public static String IssueAttribute_LabelComment;
+
+ /** */
+ public static String IssueAttribute_LabelCreated;
+
+ /** */
+ public static String IssueAttribute_LabelDescription;
+
+ /** */
+ public static String IssueAttribute_LabelKey;
+
+ /** */
+ public static String IssueAttribute_LabelLabels;
+
+ /** */
+ public static String IssueAttribute_LabelMilestone;
+
+ /** */
+ public static String IssueAttribute_LabelModified;
+
+ /** */
+ public static String IssueAttribute_LabelReporter;
+
+ /** */
+ public static String IssueAttribute_LabelReporterGravatar;
+
+ /** */
+ public static String IssueAttribute_LabelStatus;
+
+ /** */
+ public static String IssueAttribute_MilestoneNone;
+
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
diff --git a/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/issue/messages.properties b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/issue/messages.properties
new file mode 100644
index 00000000..b64e1b8a
--- /dev/null
+++ b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/issue/messages.properties
@@ -0,0 +1,19 @@
+IssueConnector_LabelConnector=GitHub Issues
+IssueConector_TaskQuerying=Querying repository...
+IssueConnector_TaskUpdatingLabels=Updating labels
+IssueConnector_TaskUpdatingMilestones=Updating milestones
+IssueAttribute_LabekSummary=Summary
+IssueAttribute_LabelAssignee=Assignee:
+IssueAttribute_LabelAssigneeGravatar=Assignee
+IssueAttribute_LabelClosed=Closed:
+IssueAttribute_LabelComment=Comment:
+IssueAttribute_LabelCreated=Created:
+IssueAttribute_LabelDescription=Description
+IssueAttribute_LabelKey=Key
+IssueAttribute_LabelLabels=Labels:
+IssueAttribute_LabelMilestone=Milestone:
+IssueAttribute_LabelModified=Modified:
+IssueAttribute_LabelReporter=Reporter:
+IssueAttribute_LabelReporterGravatar=Reporter
+IssueAttribute_LabelStatus=Status:
+IssueAttribute_MilestoneNone=None
diff --git a/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/messages.properties b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/messages.properties
new file mode 100644
index 00000000..52d8a86a
--- /dev/null
+++ b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/messages.properties
@@ -0,0 +1,4 @@
+FieldError_InvalidField=Invalid value for field {1}
+FieldError_InvalidFieldWithValue=Invalid value of {0} for field {1}
+FieldError_MissingField=Missing required field {0}
+FieldError_ResourceError=Error with field {0} in {1} resource

Back to the top