Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Aniszczyk2011-03-23 19:04:34 -0400
committerChris Aniszczyk2011-03-23 19:04:34 -0400
commit8758fb2dd13ed6031ead593e4fc092c9c2e7f1eb (patch)
treec20c312bdf7da473e6fe3e435c0670cd8dc0b82a
downloadegit-github-8758fb2dd13ed6031ead593e4fc092c9c2e7f1eb.tar.gz
egit-github-8758fb2dd13ed6031ead593e4fc092c9c2e7f1eb.tar.xz
egit-github-8758fb2dd13ed6031ead593e4fc092c9c2e7f1eb.zip
Initial commit of Mylyn GitHub Integration
Signed-off-by: Chris Aniszczyk <caniszczyk@gmail.com>
-rw-r--r--org.eclipse.mylyn.github-feature/.gitignore2
-rw-r--r--org.eclipse.mylyn.github-feature/.project17
-rw-r--r--org.eclipse.mylyn.github-feature/build.properties1
-rw-r--r--org.eclipse.mylyn.github-feature/feature.xml46
-rw-r--r--org.eclipse.mylyn.github-feature/pom.xml23
-rw-r--r--org.eclipse.mylyn.github-site/.gitignore2
-rw-r--r--org.eclipse.mylyn.github-site/.project17
-rw-r--r--org.eclipse.mylyn.github-site/assembly.xml13
-rw-r--r--org.eclipse.mylyn.github-site/pom.xml75
-rw-r--r--org.eclipse.mylyn.github-site/site.xml4
-rw-r--r--org.eclipse.mylyn.github.core/.classpath7
-rw-r--r--org.eclipse.mylyn.github.core/.gitignore2
-rw-r--r--org.eclipse.mylyn.github.core/.project28
-rw-r--r--org.eclipse.mylyn.github.core/.settings/org.eclipse.core.resources.prefs3
-rw-r--r--org.eclipse.mylyn.github.core/.settings/org.eclipse.core.runtime.prefs3
-rw-r--r--org.eclipse.mylyn.github.core/.settings/org.eclipse.jdt.core.prefs12
-rw-r--r--org.eclipse.mylyn.github.core/META-INF/MANIFEST.MF13
-rw-r--r--org.eclipse.mylyn.github.core/build.properties3
-rw-r--r--org.eclipse.mylyn.github.core/pom.xml25
-rw-r--r--org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHub.java96
-rw-r--r--org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubCredentials.java44
-rw-r--r--org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubIssue.java172
-rw-r--r--org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubIssues.java31
-rw-r--r--org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubRepositoryConnector.java217
-rw-r--r--org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubService.java557
-rw-r--r--org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubServiceException.java58
-rw-r--r--org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubShowIssue.java26
-rw-r--r--org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubTaskAttributeMapper.java49
-rw-r--r--org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubTaskAttributes.java71
-rw-r--r--org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubTaskDataHandler.java265
-rw-r--r--org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubTaskOperation.java48
-rw-r--r--org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/PermissionDeniedException.java37
-rw-r--r--org.eclipse.mylyn.github.tests/.classpath7
-rw-r--r--org.eclipse.mylyn.github.tests/.gitignore2
-rw-r--r--org.eclipse.mylyn.github.tests/.project28
-rw-r--r--org.eclipse.mylyn.github.tests/.settings/org.eclipse.jdt.core.prefs8
-rw-r--r--org.eclipse.mylyn.github.tests/META-INF/MANIFEST.MF15
-rw-r--r--org.eclipse.mylyn.github.tests/build.properties4
-rw-r--r--org.eclipse.mylyn.github.tests/src/org/eclipse/mylyn/github/tests/AllHeadlessTests.java26
-rw-r--r--org.eclipse.mylyn.github.tests/src/org/eclipse/mylyn/github/tests/GitHubServiceTest.java121
-rw-r--r--org.eclipse.mylyn.github.tests/src/org/eclipse/mylyn/github/tests/MarshalingTest.java86
-rw-r--r--org.eclipse.mylyn.github.tests/src/org/eclipse/mylyn/github/tests/resources/issues.json1
-rw-r--r--org.eclipse.mylyn.github.tests/src/org/eclipse/mylyn/github/tests/ui/GitHubRepositoryConnectorUITest.java41
-rw-r--r--org.eclipse.mylyn.github.ui/.classpath7
-rw-r--r--org.eclipse.mylyn.github.ui/.gitignore2
-rw-r--r--org.eclipse.mylyn.github.ui/.project28
-rw-r--r--org.eclipse.mylyn.github.ui/.settings/org.eclipse.core.resources.prefs3
-rw-r--r--org.eclipse.mylyn.github.ui/.settings/org.eclipse.core.runtime.prefs3
-rw-r--r--org.eclipse.mylyn.github.ui/.settings/org.eclipse.jdt.core.prefs12
-rw-r--r--org.eclipse.mylyn.github.ui/META-INF/MANIFEST.MF17
-rw-r--r--org.eclipse.mylyn.github.ui/build.properties7
-rw-r--r--org.eclipse.mylyn.github.ui/images/git-logo.pngbin0 -> 202 bytes
-rw-r--r--org.eclipse.mylyn.github.ui/plugin.properties2
-rw-r--r--org.eclipse.mylyn.github.ui/plugin.xml27
-rw-r--r--org.eclipse.mylyn.github.ui/pom.xml23
-rw-r--r--org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/github/ui/internal/GitHubRepositoryConnectorUI.java147
-rw-r--r--org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/github/ui/internal/GitHubRepositoryQueryPage.java119
-rw-r--r--org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/github/ui/internal/GitHubRepositorySettingsPage.java147
-rw-r--r--org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/github/ui/internal/GitHubTaskEditorPage.java73
-rw-r--r--org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/github/ui/internal/GitHubTaskEditorPageFactory.java82
-rw-r--r--org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/github/ui/internal/GitHubUi.java54
-rw-r--r--pom.xml145
62 files changed, 3204 insertions, 0 deletions
diff --git a/org.eclipse.mylyn.github-feature/.gitignore b/org.eclipse.mylyn.github-feature/.gitignore
new file mode 100644
index 00000000..d567ba01
--- /dev/null
+++ b/org.eclipse.mylyn.github-feature/.gitignore
@@ -0,0 +1,2 @@
+bin
+target
diff --git a/org.eclipse.mylyn.github-feature/.project b/org.eclipse.mylyn.github-feature/.project
new file mode 100644
index 00000000..54d8c9d5
--- /dev/null
+++ b/org.eclipse.mylyn.github-feature/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.mylyn.github-feature</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.pde.FeatureBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.FeatureNature</nature>
+ </natures>
+</projectDescription>
diff --git a/org.eclipse.mylyn.github-feature/build.properties b/org.eclipse.mylyn.github-feature/build.properties
new file mode 100644
index 00000000..82ab19c6
--- /dev/null
+++ b/org.eclipse.mylyn.github-feature/build.properties
@@ -0,0 +1 @@
+bin.includes = feature.xml
diff --git a/org.eclipse.mylyn.github-feature/feature.xml b/org.eclipse.mylyn.github-feature/feature.xml
new file mode 100644
index 00000000..cac9ad47
--- /dev/null
+++ b/org.eclipse.mylyn.github-feature/feature.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<feature
+ id="org.eclipse.mylyn.github.feature"
+ label="Eclipse EGit Mylyn GitHub Feature"
+ version="0.1.0.qualifier"
+ provider-name="Eclipse EGit">
+
+ <description url="http://github.com/smilebase/org.eclipse.mylyn.github">
+ Eclipse Mylyn to GitHub connector.
+ </description>
+
+ <copyright url="http://smilebase.github.com/org.eclipse.mylyn.github/">
+ Copyright 2009
+
+Christian Trutz (christian.trutz@gmail.com)
+Brian Gianforcaro (b.gianfo@gmail.com)
+ </copyright>
+
+ <license url="http://www.apache.org/licenses/LICENSE-2.0.html">
+ Apache License
+Version 2.0, January 2004
+ </license>
+
+ <requires>
+ <import plugin="org.eclipse.core.runtime" version="3.5.0" match="greaterOrEqual"/>
+ <import plugin="org.eclipse.ui" version="3.5.0" match="greaterOrEqual"/>
+ <import plugin="org.eclipse.ui.forms" version="3.4.0" match="greaterOrEqual"/>
+ <import plugin="org.eclipse.mylyn.tasks.core" version="3.2.0" match="greaterOrEqual"/>
+ <import plugin="org.eclipse.mylyn.tasks.ui" version="3.2.0" match="greaterOrEqual"/>
+ </requires>
+
+ <plugin
+ id="org.eclipse.mylyn.github.core"
+ download-size="0"
+ install-size="0"
+ version="0.0.0"
+ unpack="false"/>
+
+ <plugin
+ id="org.eclipse.mylyn.github.ui"
+ download-size="0"
+ install-size="0"
+ version="0.0.0"
+ unpack="false"/>
+
+</feature>
diff --git a/org.eclipse.mylyn.github-feature/pom.xml b/org.eclipse.mylyn.github-feature/pom.xml
new file mode 100644
index 00000000..f782928c
--- /dev/null
+++ b/org.eclipse.mylyn.github-feature/pom.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2011, Chris Aniszczyk <caniszczyk@gmail.com>
+
+ 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
+-->
+<project
+ xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <artifactId>github-parent</artifactId>
+ <groupId>org.eclipse.mylyn.github</groupId>
+ <version>0.1.0-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>feature</artifactId>
+ <packaging>eclipse-feature</packaging>
+ <name>Eclipse EGit Mylyn GitHub Feature (Incubation)</name>
+</project>
diff --git a/org.eclipse.mylyn.github-site/.gitignore b/org.eclipse.mylyn.github-site/.gitignore
new file mode 100644
index 00000000..d567ba01
--- /dev/null
+++ b/org.eclipse.mylyn.github-site/.gitignore
@@ -0,0 +1,2 @@
+bin
+target
diff --git a/org.eclipse.mylyn.github-site/.project b/org.eclipse.mylyn.github-site/.project
new file mode 100644
index 00000000..b96eff24
--- /dev/null
+++ b/org.eclipse.mylyn.github-site/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.mylyn.github-site</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.pde.UpdateSiteBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.UpdateSiteNature</nature>
+ </natures>
+</projectDescription>
diff --git a/org.eclipse.mylyn.github-site/assembly.xml b/org.eclipse.mylyn.github-site/assembly.xml
new file mode 100644
index 00000000..907a49c0
--- /dev/null
+++ b/org.eclipse.mylyn.github-site/assembly.xml
@@ -0,0 +1,13 @@
+<assembly>
+ <id>site</id>
+ <formats>
+ <format>zip</format>
+ </formats>
+ <includeBaseDirectory>false</includeBaseDirectory>
+ <fileSets>
+ <fileSet>
+ <directory>${project.build.directory}/site</directory>
+ <outputDirectory>/</outputDirectory>
+ </fileSet>
+ </fileSets>
+</assembly>
diff --git a/org.eclipse.mylyn.github-site/pom.xml b/org.eclipse.mylyn.github-site/pom.xml
new file mode 100644
index 00000000..69ad2ae9
--- /dev/null
+++ b/org.eclipse.mylyn.github-site/pom.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2011, Chris Aniszczyk <caniszczyk@gmail.com>
+
+ 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.eclipse.mylyn.github</groupId>
+ <artifactId>github-parent</artifactId>
+ <version>0.1.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>org.eclipse.mylyn.github-updatesite</artifactId>
+ <packaging>eclipse-update-site</packaging>
+
+ <name>Eclipse EGit Mylyn GitHub Repository (Incubation)</name>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <version>2.2-beta-4</version>
+ <configuration>
+ <descriptors>
+ <descriptor>assembly.xml</descriptor>
+ </descriptors>
+ </configuration>
+ <executions>
+ <execution>
+ <id>make-assembly</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <artifactId>maven-resources-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>copy-resources</id>
+ <phase>validate</phase>
+ <goals>
+ <goal>copy-resources</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${basedir}/target/site</outputDirectory>
+ <resources>
+ <resource>
+ <directory>.</directory>
+ <includes>
+ <include>index.html</include>
+ <include>web/*</include>
+ </includes>
+ </resource>
+ </resources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/org.eclipse.mylyn.github-site/site.xml b/org.eclipse.mylyn.github-site/site.xml
new file mode 100644
index 00000000..617b6a77
--- /dev/null
+++ b/org.eclipse.mylyn.github-site/site.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<site>
+ <feature url="features/org.eclipse.mylyn.github.feature_0.0.0.qualifier.jar" id="org.eclipse.mylyn.github.feature" version="0.0.0"/>
+</site>
diff --git a/org.eclipse.mylyn.github.core/.classpath b/org.eclipse.mylyn.github.core/.classpath
new file mode 100644
index 00000000..64c5e31b
--- /dev/null
+++ b/org.eclipse.mylyn.github.core/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/org.eclipse.mylyn.github.core/.gitignore b/org.eclipse.mylyn.github.core/.gitignore
new file mode 100644
index 00000000..d567ba01
--- /dev/null
+++ b/org.eclipse.mylyn.github.core/.gitignore
@@ -0,0 +1,2 @@
+bin
+target
diff --git a/org.eclipse.mylyn.github.core/.project b/org.eclipse.mylyn.github.core/.project
new file mode 100644
index 00000000..3ae827bb
--- /dev/null
+++ b/org.eclipse.mylyn.github.core/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.mylyn.github.core</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/org.eclipse.mylyn.github.core/.settings/org.eclipse.core.resources.prefs b/org.eclipse.mylyn.github.core/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 00000000..315bf27c
--- /dev/null
+++ b/org.eclipse.mylyn.github.core/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,3 @@
+#Tue Jun 09 20:22:30 CEST 2009
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/org.eclipse.mylyn.github.core/.settings/org.eclipse.core.runtime.prefs b/org.eclipse.mylyn.github.core/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 00000000..5b9dcff1
--- /dev/null
+++ b/org.eclipse.mylyn.github.core/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,3 @@
+#Tue Jun 09 20:22:30 CEST 2009
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/org.eclipse.mylyn.github.core/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.mylyn.github.core/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000..1d6b3c18
--- /dev/null
+++ b/org.eclipse.mylyn.github.core/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,12 @@
+#Fri Jul 30 10:22:35 CEST 2010
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.5
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.5
diff --git a/org.eclipse.mylyn.github.core/META-INF/MANIFEST.MF b/org.eclipse.mylyn.github.core/META-INF/MANIFEST.MF
new file mode 100644
index 00000000..f05d1b0d
--- /dev/null
+++ b/org.eclipse.mylyn.github.core/META-INF/MANIFEST.MF
@@ -0,0 +1,13 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: EGit Mylyn GitHub Core Plug-in (Incubation)
+Bundle-SymbolicName: org.eclipse.mylyn.github.core
+Bundle-Version: 0.1.0.qualifier
+Bundle-Vendor: Eclipse EGit
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
+Export-Package: org.eclipse.mylyn.github.internal;x-friends:="org.eclipse.mylyn.github.ui"
+Require-Bundle: org.eclipse.core.runtime;bundle-version="3.5.0",
+ org.eclipse.mylyn.tasks.core;bundle-version="3.2.0",
+ org.eclipse.mylyn.commons.net;bundle-version="3.2.0"
+Import-Package: com.google.gson;version="1.6.0",
+ org.apache.commons.logging
diff --git a/org.eclipse.mylyn.github.core/build.properties b/org.eclipse.mylyn.github.core/build.properties
new file mode 100644
index 00000000..e1e6580a
--- /dev/null
+++ b/org.eclipse.mylyn.github.core/build.properties
@@ -0,0 +1,3 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/ \ No newline at end of file
diff --git a/org.eclipse.mylyn.github.core/pom.xml b/org.eclipse.mylyn.github.core/pom.xml
new file mode 100644
index 00000000..12b22700
--- /dev/null
+++ b/org.eclipse.mylyn.github.core/pom.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2011, Chris Aniszczyk <caniszczyk@gmail.com>
+
+ 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
+-->
+<project
+ xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <parent>
+ <groupId>org.eclipse.mylyn.github</groupId>
+ <artifactId>github-parent</artifactId>
+ <version>0.1.0-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>core</artifactId>
+ <packaging>eclipse-plugin</packaging>
+ <name>Eclipse EGit Mylyn GitHub Core (Incubation)</name>
+</project>
diff --git a/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHub.java b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHub.java
new file mode 100644
index 00000000..708f39c5
--- /dev/null
+++ b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHub.java
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * 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.github.internal;
+
+import java.util.regex.Matcher;
+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;
+
+public class GitHub {
+ public static final String BUNDLE_ID = "org.eclipse.mylyn.github.core";
+ public static final String CONNECTOR_KIND = "github";
+
+ public static final String HTTP_WWW_GITHUB_ORG = "http://www.github.org";
+ public static final String HTTP_GITHUB_COM = "http://github.com";
+
+ public static final Pattern URL_PATTERN = Pattern.compile("(?:"+Pattern.quote(HTTP_WWW_GITHUB_ORG)+"|"+Pattern.quote(HTTP_GITHUB_COM)+")/([^/]+)/([^/]+)");
+
+ public static IStatus createStatus(int severity, String message) {
+ return new Status(severity, BUNDLE_ID, message);
+ }
+
+ public static IStatus createStatus(int severity, String message, Throwable e) {
+ return new Status(severity, BUNDLE_ID, message, e);
+ }
+
+ public static IStatus createErrorStatus(String message) {
+ return createStatus(IStatus.ERROR, message);
+ }
+
+ public static IStatus createErrorStatus(String message, Throwable t) {
+ return createStatus(IStatus.ERROR, message, t);
+ }
+
+ public static IStatus createErrorStatus(Throwable e) {
+ return createStatus(IStatus.ERROR, "Unexpected error: "
+ + e.getMessage(), e);
+ }
+
+ public static ILog getLog() {
+ return Platform.getLog(Platform.getBundle(BUNDLE_ID));
+ }
+
+ public static void logError(String message,Throwable t) {
+ getLog().log(createErrorStatus(message, t));
+ }
+
+ public static void logError(Throwable t) {
+ getLog().log(createErrorStatus(t.getMessage(), t));
+ }
+
+ public static String computeTaskRepositoryUser(String repositoryUrl) {
+ Matcher matcher = URL_PATTERN.matcher(repositoryUrl);
+ if (matcher.matches()) {
+ return matcher.group(1);
+ }
+ return null;
+ }
+
+ public static String computeTaskRepositoryProject(String repositoryUrl) {
+ Matcher matcher = URL_PATTERN.matcher(repositoryUrl);
+ if (matcher.matches()) {
+ return matcher.group(2);
+ }
+ return null;
+ }
+
+ /**
+ * uses github.com
+ * @see #createGitHubUrlAlternate(String, String)
+ */
+ public static String createGitHubUrl(String user,String project) {
+ return HTTP_GITHUB_COM+'/'+user+'/'+project;
+ }
+
+ /**
+ * Uses www.github.org
+ * @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/github/internal/GitHubCredentials.java b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubCredentials.java
new file mode 100644
index 00000000..19cd580c
--- /dev/null
+++ b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubCredentials.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * 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.github.internal;
+
+import org.eclipse.mylyn.commons.net.AuthenticationCredentials;
+import org.eclipse.mylyn.commons.net.AuthenticationType;
+import org.eclipse.mylyn.tasks.core.TaskRepository;
+
+public class GitHubCredentials {
+ private final String username;
+ private final String apiToken;
+
+
+ public GitHubCredentials(String username, String apiToken) {
+ this.username = username;
+ this.apiToken = apiToken;
+ }
+
+ public GitHubCredentials(AuthenticationCredentials credentials) {
+ this(credentials.getUserName(),credentials.getPassword());
+ }
+
+ public static GitHubCredentials create(TaskRepository repository) {
+ return new GitHubCredentials(repository.getCredentials(AuthenticationType.REPOSITORY));
+ }
+
+ public String getUsername() {
+ return username;
+ }
+ public String getApiToken() {
+ return apiToken;
+ }
+
+}
diff --git a/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubIssue.java b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubIssue.java
new file mode 100644
index 00000000..9a989e00
--- /dev/null
+++ b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubIssue.java
@@ -0,0 +1,172 @@
+/*******************************************************************************
+ * 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.github.internal;
+
+
+/**
+ * GitHub Issue object to hold all the properties of an individual issue.
+ */
+public class GitHubIssue {
+
+ private String number;
+
+ private String user;
+
+ private String title;
+
+ private String body;
+
+ /**
+ * open, closed
+ */
+ private String state;
+
+ private String created_at;
+ private String updated_at;
+ private String closed_at;
+
+ /**
+ * Create a new GitHub Issue Object
+ *
+ * @param number
+ * - GitHub Issue number
+ * @param user
+ * - User who the posted issue belongs too.
+ * @param title
+ * - Issue title
+ * @param body
+ * - The text body of the issue;
+ */
+ public GitHubIssue(final String number, final String user,
+ final String title, final String body) {
+ this.number = number;
+ this.user = user;
+ this.title = title;
+ this.body = body;
+ }
+
+ /**
+ * Create a GitHub Issue with all parameters set to empty.
+ */
+ public GitHubIssue() {
+ this.number = "";
+ this.user = "";
+ this.title = "";
+ this.body = "";
+ }
+
+ /**
+ * Getter for the issue number
+ *
+ * @return The string representation of the issue number.
+ */
+ public String getNumber() {
+ return number;
+ }
+
+ /**
+ * Set the issues's number
+ *
+ * @param number
+ * - String representation of the number to set to.
+ */
+ public void setNumber(final String number) {
+ this.number = number;
+ }
+
+ /**
+ * Getter for the user name of the issue creator
+ *
+ * @return The user name of the person who created the issue
+ */
+ public String getUser() {
+ return user;
+ }
+
+ /**
+ * Set the issue user name to
+ *
+ * @param user
+ * - The user name to set the issue creator to.
+ */
+ public void setUser(final String user) {
+ this.user = user;
+ }
+
+ /**
+ * Getter for the issue Title
+ *
+ * @return The title text of this issue
+ */
+ public String getTitle() {
+ return title;
+ }
+
+ /**
+ * @param title
+ */
+ public void setTitle(final String title) {
+ this.title = title;
+ }
+
+ /**
+ * Getter of the body of an issue
+ *
+ * @return The text body of the issue
+ */
+ public String getBody() {
+ return body;
+ }
+
+ /**
+ * Setter for the body of an issue
+ *
+ * @param body
+ * - The text body to set for this issue
+ */
+ public void setBody(final String body) {
+ this.body = body;
+ }
+
+ public String getState() {
+ return state;
+ }
+
+ public void setState(String state) {
+ this.state = state;
+ }
+
+ public String getCreated_at() {
+ return created_at;
+ }
+
+ public void setCreated_at(String created_at) {
+ this.created_at = created_at;
+ }
+
+ public String getUpdated_at() {
+ return updated_at;
+ }
+
+ public void setUpdated_at(String updated_at) {
+ this.updated_at = updated_at;
+ }
+
+ public String getClosed_at() {
+ return closed_at;
+ }
+
+ public void setClosed_at(String closed_at) {
+ this.closed_at = closed_at;
+ }
+}
diff --git a/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubIssues.java b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubIssues.java
new file mode 100644
index 00000000..02100590
--- /dev/null
+++ b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubIssues.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * 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.github.internal;
+
+/**
+ * Container of multiple GitHub Issues, used when returning JSON objects
+ */
+public class GitHubIssues {
+
+ private GitHubIssue[] issues;
+
+ /**
+ * Getter for all issues inside this object
+ *
+ * @return The array of individual GitHub Issues
+ */
+ public GitHubIssue[] getIssues() {
+ return issues;
+ }
+
+}
diff --git a/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubRepositoryConnector.java b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubRepositoryConnector.java
new file mode 100644
index 00000000..c263cb9a
--- /dev/null
+++ b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubRepositoryConnector.java
@@ -0,0 +1,217 @@
+/*******************************************************************************
+ * 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.github.internal;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+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.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.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 GitHubRepositoryConnector extends AbstractRepositoryConnector {
+
+
+ /**
+ * GitHub kind.
+ */
+ protected static final String KIND = GitHub.CONNECTOR_KIND;
+
+ /**
+ * GitHub service which creates, lists, deletes, etc. GitHub tasks.
+ */
+ private final GitHubService service = new GitHubService();
+
+ /**
+ * GitHub specific {@link AbstractTaskDataHandler}.
+ */
+ private final GitHubTaskDataHandler taskDataHandler;
+
+ public GitHubRepositoryConnector() {
+ taskDataHandler = new GitHubTaskDataHandler(this);
+ }
+
+ /**
+ * {@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 "GitHub";
+ }
+
+ /**
+ * {@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;
+ String queryStatus = query.getAttribute("status");
+
+ String[] statuses;
+ if (queryStatus.equals("all")) {
+ statuses = new String[] {"open","closed"};
+ } else {
+ statuses = new String[] { queryStatus };
+ }
+
+ monitor.beginTask("Querying repository ...", statuses.length);
+ try {
+ String user = GitHub.computeTaskRepositoryUser(repository.getUrl());
+ String project = GitHub.computeTaskRepositoryProject(repository.getUrl());
+
+ // perform query
+
+ for (String status: statuses) {
+ GitHubIssues issues = service.searchIssues(user,project,
+ status, query
+ .getAttribute("queryText"));
+
+ // collect task data
+ for (GitHubIssue issue : issues.getIssues()) {
+ TaskData taskData = taskDataHandler.createPartialTaskData(
+ repository, monitor,user, project, issue);
+ collector.accept(taskData);
+ }
+ monitor.worked(1);
+ }
+
+ result = Status.OK_STATUS;
+ } catch (GitHubServiceException e) {
+ result = GitHub.createErrorStatus(e);
+ }
+
+ monitor.done();
+ return result;
+ }
+
+
+ @Override
+ public TaskData getTaskData(TaskRepository repository, String taskId,
+ IProgressMonitor monitor) throws CoreException {
+
+ String user = GitHub.computeTaskRepositoryUser(repository.getUrl());
+ String project = GitHub.computeTaskRepositoryProject(repository.getUrl());
+
+ try {
+ GitHubIssue issue = service.showIssue(user, project, taskId);
+ TaskData taskData = taskDataHandler.createTaskData(repository, monitor, user, project, issue);
+
+ return taskData;
+ } catch (GitHubServiceException 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);
+ 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);
+ if (matcher.matches()) {
+ return matcher.group(1);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public String getTaskUrl(String repositoryUrl, String taskId) {
+ return repositoryUrl+"/issues/issue/"+taskId;
+ }
+
+ @Override
+ public void updateRepositoryConfiguration(TaskRepository taskRepository,
+ IProgressMonitor monitor) throws CoreException {
+ }
+
+ @Override
+ public boolean hasTaskChanged(TaskRepository repository, ITask task,
+ TaskData taskData) {
+ return new TaskMapper(taskData).hasChanges(task);
+ }
+
+ @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);
+ }
+
+ public GitHubService getService() {
+ return service;
+ }
+}
diff --git a/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubService.java b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubService.java
new file mode 100644
index 00000000..07d884d8
--- /dev/null
+++ b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubService.java
@@ -0,0 +1,557 @@
+/*******************************************************************************
+ * 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.github.internal;
+
+import java.io.IOException;
+
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.HttpException;
+import org.apache.commons.httpclient.HttpMethod;
+import org.apache.commons.httpclient.HttpStatus;
+import org.apache.commons.httpclient.NameValuePair;
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.commons.httpclient.methods.PostMethod;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import com.google.gson.Gson;
+
+/**
+ * Facility to perform API operations on a GitHub issue tracker.
+ */
+public class GitHubService {
+
+ private static final Log LOG = LogFactory.getLog(GitHubService.class);
+
+ /**
+ * GitHub Issues API Documentation: http://develop.github.com/p/issues.html
+ */
+ private final String gitURLBase = "https://github.com/api/v2/json/";
+
+ private final String gitIssueRoot = "issues/";
+ private final String gitUserRoot = "user/";
+
+ private final HttpClient httpClient;
+
+ private final Gson gson;
+
+ /**
+ * Helper class, describing all of the possible GitHub API actions.
+ */
+ private final static String OPEN = "open/"; // Implemented
+ private static final String REOPEN = "reopen/";
+ private final static String CLOSE = "close/";
+ private final static String EDIT = "edit/"; // Implemented
+ // private final static String VIEW = "view/";
+ private final static String SHOW = "show/"; // :user/:repo/:number
+ private final static String LIST = "list/"; // Implemented
+ private final static String SEARCH = "search/"; // Implemented
+ // private final static String REOPEN = "reopen/";
+ // private final static String COMMENT = "comment/";
+ private final static String ADD_LABEL = "label/add/"; // Implemented
+ private final static String REMOVE_LABEL = "label/remove/"; // Implemented
+
+ private static final String EMAILS = "emails";
+
+
+ /**
+ * Constructor, create the client and JSON/Java interface object.
+ */
+ public GitHubService() {
+ httpClient = new HttpClient();
+ gson = new Gson();
+ }
+
+ /**
+ * Verify that the provided credentials are correct
+ * @param credentials
+ *
+ * @return true if and only if the credentials are correct
+ */
+ public boolean verifyCredentials(GitHubCredentials credentials) throws GitHubServiceException {
+ PostMethod method = null;
+
+ boolean success = false;
+
+ try {
+ method = new PostMethod(gitURLBase + gitUserRoot + EMAILS);
+
+ // Set the users login and API token
+ final NameValuePair login = new NameValuePair("login", credentials.getUsername());
+ final NameValuePair token = new NameValuePair("token", credentials.getApiToken());
+ method.setRequestBody(new NameValuePair[] { login, token });
+
+ executeMethod(method);
+
+ // if we reach here we know that credentials were good
+ success = true;
+ } catch (PermissionDeniedException e) {
+ // if we provide bad credentials, GitHub will return 403 or 401
+ return false;
+ } catch (GitHubServiceException e) {
+ throw e;
+ } catch (final RuntimeException runtimeException) {
+ throw runtimeException;
+ } catch (final Exception exception) {
+ throw new GitHubServiceException(exception);
+ } finally {
+ if (method != null)
+ method.releaseConnection();
+ }
+ return success;
+ }
+
+ /**
+ * Search the GitHub Issues API for a given search term
+ *
+ * @param user
+ * - The user the repository is owned by
+ * @param repo
+ * - The Git repository where the issue tracker is hosted
+ * @param state
+ * - The issue state you want to filter your search by
+ * @param searchTerm
+ * - The text search term to find in the issues.
+ *
+ * @return A GitHubIssues object containing all issues from the search
+ * results
+ *
+ * @throws GitHubServiceException
+ *
+ * @note API Doc: /issues/search/:user/:repo/:state/:search_term
+ */
+ public GitHubIssues searchIssues(final String user, final String repo,
+ final String state, final String searchTerm)
+ throws GitHubServiceException {
+ GitHubIssues issues = null;
+ GetMethod method = null;
+ try {
+ // build HTTP GET method
+ if (searchTerm.trim().length() == 0) { // no search term: list all
+ method = new GetMethod(gitURLBase + gitIssueRoot + LIST + user
+ + "/" + repo + "/" + state);
+ } else {
+ method = new GetMethod(gitURLBase + gitIssueRoot + SEARCH
+ + user + "/" + repo + "/" + state + "/" + searchTerm);
+ }
+ // execute HTTP GET method
+ executeMethod(method);
+ // transform JSON to Java object
+ issues = gson.fromJson(new String(method.getResponseBody()),
+ GitHubIssues.class);
+ } catch (GitHubServiceException e) {
+ throw e;
+ } catch (final RuntimeException runtimeException) {
+ throw runtimeException;
+ } catch (final Exception exception) {
+ throw new GitHubServiceException(exception);
+ } finally {
+ if (method != null)
+ method.releaseConnection();
+ }
+ return issues;
+ }
+
+ /**
+ * Add a label to an existing GitHub issue.
+ *
+ * @param user
+ * - The user the repository is owned by
+ * @param repo
+ * - The git repository where the issue tracker is hosted
+ * @param label
+ * - The text label to add to the existing issue
+ * @param issueNumber
+ * - The issue number to add a label to
+ * @param api
+ * - The users GitHub
+ *
+ * @return A boolean representing the success of the function call
+ *
+ * @throws GitHubServiceException
+ *
+ * @note API Doc: issues/label/add/:user/:repo/:label/:number API POST
+ * Variables: login, api-token
+ */
+ public boolean addLabel(final String user, final String repo,
+ final String label, final int issueNumber,final GitHubCredentials credentials)
+ throws GitHubServiceException {
+ PostMethod method = null;
+
+ boolean success = false;
+
+ try {
+ // build HTTP GET method
+ method = new PostMethod(gitURLBase + gitIssueRoot + ADD_LABEL
+ + user + "/" + repo + "/" + label + "/"
+ + Integer.toString(issueNumber));
+
+ // Set the users login and API token
+ final NameValuePair login = new NameValuePair("login", credentials.getUsername());
+ final NameValuePair token = new NameValuePair("token", credentials.getApiToken());
+ method.setRequestBody(new NameValuePair[] { login, token });
+
+ // execute HTTP GET method
+ executeMethod(method);
+ // Check the response, make sure the action was successful
+ final String response = method.getResponseBodyAsString();
+ if (response.contains(label.subSequence(0, label.length()))) {
+ success = true;
+ }
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Response: " + method.getResponseBodyAsString());
+ LOG.debug("URL: " + method.getURI());
+ }
+ } catch (GitHubServiceException e) {
+ throw e;
+ } catch (final RuntimeException runtimeException) {
+ throw runtimeException;
+ } catch (final Exception exception) {
+ throw new GitHubServiceException(exception);
+ } finally {
+ if (method != null)
+ method.releaseConnection();
+ }
+ return success;
+ }
+
+ /**
+ * Remove an existing label from an existing GitHub issue.
+ *
+ * @param user
+ * - The user the repository is owned by
+ * @param repo
+ * - The git repository where the issue tracker is hosted
+ * @param label
+ * @param issueNumber
+ * @param api
+ *
+ * @return A list of GitHub issues in the response text.
+ *
+ * @throws GitHubServiceException
+ *
+ * API Doc: issues/label/remove/:user/:repo/:label/:number API
+ * POST Variables: login, api-token
+ */
+ public boolean removeLabel(final String user, final String repo,
+ final String label, final int issueNumber, final GitHubCredentials credentials)
+ throws GitHubServiceException {
+ PostMethod method = null;
+ boolean success = false;
+ try {
+ // build HTTP GET method
+ method = new PostMethod(gitURLBase + gitIssueRoot + REMOVE_LABEL
+ + user + "/" + repo + "/" + label + "/"
+ + Integer.toString(issueNumber));
+
+ // Set the users login and API token
+ final NameValuePair login = new NameValuePair("login", credentials.getUsername());
+ final NameValuePair token = new NameValuePair("token", credentials.getUsername());
+ method.setRequestBody(new NameValuePair[] { login, token });
+
+ // execute HTTP GET method
+ executeMethod(method);
+ // Check the response, make sure the action was successful
+ final String response = method.getResponseBodyAsString();
+ if (!response.contains(label.subSequence(0, label.length()))) {
+ success = true;
+ }
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Response: " + method.getResponseBodyAsString());
+ LOG.debug("URL: " + method.getURI());
+ }
+ } catch (GitHubServiceException e) {
+ throw e;
+ } catch (final RuntimeException runtimeException) {
+ throw runtimeException;
+ } catch (final Exception exception) {
+ throw new GitHubServiceException(exception);
+ } finally {
+ if (method != null)
+ method.releaseConnection();
+ }
+ return success;
+ }
+
+ /**
+ * Open a new issue using the GitHub Issues API.
+ *
+ * @param user
+ * - The user the repository is owned by
+ * @param repo
+ * - The git repository where the issue tracker is hosted
+ * @param issue
+ * - The GitHub issue object to create on the issue tracker.
+ *
+ * @return the issue that was created
+ *
+ * @throws GitHubServiceException
+ *
+ * API Doc: issues/open/:user/:repo API POST Variables: login,
+ * api-token, title, body
+ */
+ public GitHubIssue openIssue(final String user, final String repo,
+ final GitHubIssue issue, final GitHubCredentials credentials)
+ throws GitHubServiceException {
+
+ GitHubShowIssue showIssue = null;
+
+ PostMethod method = null;
+ try {
+ // Create the HTTP POST method
+ method = new PostMethod(gitURLBase + gitIssueRoot + OPEN + user
+ + "/" + repo);
+ // Set the users login and API token
+ final NameValuePair login = new NameValuePair("login", credentials.getUsername());
+ final NameValuePair token = new NameValuePair("token", credentials.getApiToken());
+ final NameValuePair body = new NameValuePair("body", issue
+ .getBody());
+ final NameValuePair title = new NameValuePair("title", issue
+ .getTitle());
+
+ method.setRequestBody(new NameValuePair[] { login, token, body,
+ title });
+
+ executeMethod(method);
+ showIssue = gson.fromJson(new String(method.getResponseBody()),
+ GitHubShowIssue.class);
+
+
+ if (showIssue == null || showIssue.getIssue() == null) {
+ if (LOG.isErrorEnabled()) {
+ LOG.error("Unexpected server response: "+method.getResponseBodyAsString());
+ }
+ throw new GitHubServiceException("Unexpected server response");
+ }
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Response: " + method.getResponseBodyAsString());
+ LOG.debug("URL: " + method.getURI());
+ }
+ return showIssue.getIssue();
+ } catch (GitHubServiceException e) {
+ throw e;
+ } catch (final RuntimeException runTimeException) {
+ throw runTimeException;
+ } catch (final Exception e) {
+ throw new GitHubServiceException(e);
+ } finally {
+ if (method != null) {
+ method.releaseConnection();
+ }
+ }
+ }
+
+ /**
+ * Edit an existing issue using the GitHub Issues API.
+ *
+ * @param user
+ * - The user the repository is owned by
+ * @param repo
+ * - The git repository where the issue tracker is hosted
+ * @param issue
+ * - The GitHub issue object to create on the issue tracker.
+ *
+ * @return the issue with changes
+ *
+ * @throws GitHubServiceException
+ *
+ * API Doc: issues/edit/:user/:repo/:number API POST Variables:
+ * login, api-token, title, body
+ */
+ public GitHubIssue editIssue(final String user, final String repo,
+ final GitHubIssue issue,final GitHubCredentials credentials)
+ throws GitHubServiceException {
+ PostMethod method = null;
+ try {
+
+ // Create the HTTP POST method
+ method = new PostMethod(gitURLBase + gitIssueRoot + EDIT + user
+ + "/" + repo + "/" + issue.getNumber());
+ // Set the users login and API token
+ final NameValuePair login = new NameValuePair("login", credentials.getUsername());
+ final NameValuePair token = new NameValuePair("token", credentials.getApiToken());
+ final NameValuePair body = new NameValuePair("body", issue
+ .getBody());
+ final NameValuePair title = new NameValuePair("title", issue
+ .getTitle());
+
+ method.setRequestBody(new NameValuePair[] { login, token, body,
+ title });
+
+ executeMethod(method);
+ GitHubShowIssue showIssue = gson.fromJson(method.getResponseBodyAsString(),
+ GitHubShowIssue.class);
+
+ // Make sure the changes were made properly
+ if (showIssue == null || showIssue.getIssue() == null) {
+ if (LOG.isErrorEnabled()) {
+ LOG.error("Unexpected server response: "+method.getResponseBodyAsString());
+ }
+ throw new GitHubServiceException("Unexpected server response");
+ }
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Response: " + method.getResponseBodyAsString());
+ LOG.debug("URL: " + method.getURI());
+ }
+ return showIssue.getIssue();
+ } catch (final RuntimeException runTimeException) {
+ throw runTimeException;
+ } catch (final Exception e) {
+ throw new GitHubServiceException(e);
+ } finally {
+ if (method != null) {
+ method.releaseConnection();
+ }
+ }
+ }
+
+
+ public GitHubIssue showIssue(final String user, final String repo,final String issueNumber) throws GitHubServiceException {
+ GetMethod method = null;
+ try {
+ // build HTTP GET method
+ method = new GetMethod(gitURLBase + gitIssueRoot + SHOW
+ + user + "/" + repo + "/" + issueNumber);
+
+ // execute HTTP GET method
+ executeMethod(method);
+ // transform JSON to Java object
+ GitHubShowIssue issue = gson.fromJson(new String(method.getResponseBody()),
+ GitHubShowIssue.class);
+
+ return issue.getIssue();
+ } catch (GitHubServiceException e) {
+ throw e;
+ } catch (final RuntimeException runtimeException) {
+ throw runtimeException;
+ } catch (final Exception exception) {
+ throw new GitHubServiceException(exception);
+ } finally {
+ if (method != null) {
+ method.releaseConnection();
+ }
+ }
+ }
+
+ private void executeMethod(HttpMethod method) throws GitHubServiceException {
+ int status;
+ try {
+ status = httpClient.executeMethod(method);
+ } catch (HttpException e) {
+ throw new GitHubServiceException(e);
+ } catch (IOException e) {
+ throw new GitHubServiceException(e);
+ }
+ if (status != HttpStatus.SC_OK) {
+ switch (status) {
+ case HttpStatus.SC_UNAUTHORIZED:
+ case HttpStatus.SC_FORBIDDEN:
+ throw new PermissionDeniedException(method.getStatusLine());
+ default:
+ throw new GitHubServiceException(method.getStatusLine());
+ }
+ }
+ }
+
+ /**
+ * Edit an existing issue using the GitHub Issues API and change its status to open.
+ *
+ * @param user
+ * - The user the repository is owned by
+ * @param repo
+ * - The git repository where the issue tracker is hosted
+ * @param issue
+ * - The GitHub issue object to create on the issue tracker.
+ *
+ * @return the issue with changes
+ *
+ * @throws GitHubServiceException
+ *
+ * API Doc: issues/reopen/:user/:repo/:number API POST Variables:
+ * login, api-token, title, body
+ */
+ public GitHubIssue reopenIssue(String user, String repo, GitHubIssue issue,
+ GitHubCredentials credentials) throws GitHubServiceException {
+ issue = editIssue(user, repo, issue, credentials);
+ return changeIssueStatus(user, repo, REOPEN, issue, credentials);
+ }
+
+ /**
+ * Edit an existing issue using the GitHub Issues API and change its status to closed.
+ *
+ * @param user
+ * - The user the repository is owned by
+ * @param repo
+ * - The git repository where the issue tracker is hosted
+ * @param issue
+ * - The GitHub issue object to create on the issue tracker.
+ *
+ * @return the issue with changes
+ *
+ * @throws GitHubServiceException
+ *
+ * API Doc: issues/close/:user/:repo/:number API POST Variables:
+ * login, api-token, title, body
+ */
+ public GitHubIssue closeIssue(String user, String repo, GitHubIssue issue,
+ GitHubCredentials credentials) throws GitHubServiceException {
+ issue = editIssue(user, repo, issue, credentials);
+ return changeIssueStatus(user, repo, CLOSE, issue, credentials);
+
+ }
+
+ private GitHubIssue changeIssueStatus(final String user, final String repo,
+ String githubOperation, final GitHubIssue issue,
+ final GitHubCredentials credentials) throws GitHubServiceException {
+ PostMethod method = null;
+ try {
+
+ // Create the HTTP POST method
+ method = new PostMethod(gitURLBase + gitIssueRoot + githubOperation + user
+ + "/" + repo + "/" + issue.getNumber());
+ // Set the users login and API token
+ final NameValuePair login = new NameValuePair("login", credentials.getUsername());
+ final NameValuePair token = new NameValuePair("token", credentials.getApiToken());
+
+ method.setRequestBody(new NameValuePair[] { login, token });
+
+ executeMethod(method);
+ GitHubShowIssue showIssue = gson.fromJson(method.getResponseBodyAsString(),
+ GitHubShowIssue.class);
+
+ // Make sure the changes were made properly
+ if (showIssue == null || showIssue.getIssue() == null) {
+ if (LOG.isErrorEnabled()) {
+ LOG.error("Unexpected server response: "+method.getResponseBodyAsString());
+ }
+ throw new GitHubServiceException("Unexpected server response");
+ }
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Response: " + method.getResponseBodyAsString());
+ LOG.debug("URL: " + method.getURI());
+ }
+ return showIssue.getIssue();
+ } catch (final RuntimeException runTimeException) {
+ throw runTimeException;
+ } catch (final Exception e) {
+ throw new GitHubServiceException(e);
+ } finally {
+ if (method != null) {
+ method.releaseConnection();
+ }
+ }
+ }
+}
diff --git a/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubServiceException.java b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubServiceException.java
new file mode 100644
index 00000000..3e9a51c2
--- /dev/null
+++ b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubServiceException.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * 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.github.internal;
+
+import org.apache.commons.httpclient.StatusLine;
+
+/**
+ * Exception generated by the GitHubService
+ */
+public class GitHubServiceException extends Exception {
+
+ /**
+ * Auto generated serialVersionUID
+ */
+ private static final long serialVersionUID = -6287902058352190022L;
+
+ private int httpStatusCode = Integer.MIN_VALUE;
+
+ /**
+ * Constructor for the GitHubServiceException
+ *
+ * @param exception
+ * - Exception to wrap around
+ */
+ protected GitHubServiceException(final Exception exception) {
+ super(exception);
+ }
+
+ protected GitHubServiceException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ protected GitHubServiceException(String message) {
+ super(message);
+ }
+
+ protected GitHubServiceException(StatusLine statusLine) {
+ this(String.format("HTTP %s: %s",statusLine.getStatusCode(),statusLine.getReasonPhrase()));
+ httpStatusCode = statusLine.getStatusCode();
+ }
+
+ /**
+ * the HTTP status code, or -1 if unknown or not applicable.
+ */
+ public int getHttpStatusCode() {
+ return httpStatusCode;
+ }
+}
diff --git a/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubShowIssue.java b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubShowIssue.java
new file mode 100644
index 00000000..f249c53f
--- /dev/null
+++ b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubShowIssue.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * 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.github.internal;
+
+public class GitHubShowIssue {
+ private GitHubIssue issue;
+
+ public GitHubIssue getIssue() {
+ return issue;
+ }
+
+ public void setIssue(GitHubIssue issue) {
+ this.issue = issue;
+ }
+
+}
diff --git a/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubTaskAttributeMapper.java b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubTaskAttributeMapper.java
new file mode 100644
index 00000000..2d42de8d
--- /dev/null
+++ b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubTaskAttributeMapper.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * 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.github.internal;
+
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import org.eclipse.mylyn.tasks.core.TaskRepository;
+import org.eclipse.mylyn.tasks.core.data.TaskAttribute;
+import org.eclipse.mylyn.tasks.core.data.TaskAttributeMapper;
+
+public class GitHubTaskAttributeMapper extends TaskAttributeMapper {
+
+ private DateFormat dateFormat = SimpleDateFormat.getDateTimeInstance();
+
+ public GitHubTaskAttributeMapper(TaskRepository taskRepository) {
+ super(taskRepository);
+ }
+
+ @Override
+ public String mapToRepositoryKey(TaskAttribute parent, String key) {
+ return key;
+ }
+
+ @Override
+ public Date getDateValue(TaskAttribute attribute) {
+ String value = attribute.getValue();
+ if (value != null) {
+ try {
+ return dateFormat.parse(value);
+ } catch (ParseException e) {
+ return super.getDateValue(attribute);
+ }
+ }
+ return null;
+ }
+}
diff --git a/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubTaskAttributes.java b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubTaskAttributes.java
new file mode 100644
index 00000000..b43694d0
--- /dev/null
+++ b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubTaskAttributes.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * 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.github.internal;
+
+import org.eclipse.mylyn.tasks.core.data.TaskAttribute;
+
+public enum GitHubTaskAttributes {
+
+ KEY("Key",TaskAttribute.TASK_KEY,TaskAttribute.TYPE_SHORT_TEXT,true,true,true),
+ TITLE("Summary",TaskAttribute.SUMMARY,TaskAttribute.TYPE_SHORT_TEXT,true,false,true),
+ BODY("Description",TaskAttribute.DESCRIPTION,TaskAttribute.TYPE_LONG_RICH_TEXT,true,false,true),
+
+ CREATION_DATE("Created",TaskAttribute.DATE_CREATION,TaskAttribute.TYPE_DATETIME,true,true,false),
+ MODIFICATION_DATE("Modified",TaskAttribute.DATE_MODIFICATION,TaskAttribute.TYPE_DATETIME,true,true,false),
+ CLOSED_DATE("Closed",TaskAttribute.DATE_COMPLETION,TaskAttribute.TYPE_DATETIME,false,true,false),
+
+ STATUS("Status",TaskAttribute.STATUS,TaskAttribute.TYPE_SHORT_TEXT,true,false,true)
+ ;
+
+
+ private final String id;
+ private final String label;
+ private final boolean readOnly;
+ private final boolean initTask;
+ private final boolean requiredForFullTaskData;
+ private final String type;
+
+ private GitHubTaskAttributes(String label, String id,String type,boolean requiredForFullTaskData, boolean readOnly, boolean initTask) {
+ this.label = label;
+ this.requiredForFullTaskData = requiredForFullTaskData;
+ this.id = id==null?"github."+name():id;
+ this.type = type;
+ this.readOnly = readOnly;
+ this.initTask = initTask;
+ }
+
+ public String getLabel() {
+ return label;
+ }
+ public String getId() {
+ return id;
+ }
+ public String getType() {
+ return type;
+ }
+ public boolean isReadOnly() {
+ return readOnly;
+ }
+
+ public String getKind() {
+ return TaskAttribute.KIND_DEFAULT;
+ }
+
+ public boolean isInitTask() {
+ return initTask;
+ }
+
+ public boolean isRequiredForFullTaskData() {
+ return requiredForFullTaskData;
+ }
+}
diff --git a/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubTaskDataHandler.java b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubTaskDataHandler.java
new file mode 100644
index 00000000..62649e79
--- /dev/null
+++ b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubTaskDataHandler.java
@@ -0,0 +1,265 @@
+/*******************************************************************************
+ * 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.github.internal;
+
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Set;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.mylyn.tasks.core.ITaskMapping;
+import org.eclipse.mylyn.tasks.core.RepositoryResponse;
+import org.eclipse.mylyn.tasks.core.TaskRepository;
+import org.eclipse.mylyn.tasks.core.RepositoryResponse.ResponseKind;
+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.TaskData;
+import org.eclipse.mylyn.tasks.core.data.TaskOperation;
+
+public class GitHubTaskDataHandler extends AbstractTaskDataHandler {
+
+ private static final String DATA_VERSION = "1";
+ /**
+ *
+ */
+ private GitHubTaskAttributeMapper taskAttributeMapper = null;
+ private final GitHubRepositoryConnector connector;
+ private DateFormat dateFormat = SimpleDateFormat.getDateTimeInstance();
+
+ private DateFormat githubDateFormat = new SimpleDateFormat("yyyy/mm/dd HH:MM:ss Z");
+
+ public GitHubTaskDataHandler(GitHubRepositoryConnector connector) {
+ this.connector = connector;
+ }
+
+ @Override
+ public TaskAttributeMapper getAttributeMapper(TaskRepository taskRepository) {
+ if (this.taskAttributeMapper == null)
+ this.taskAttributeMapper = new GitHubTaskAttributeMapper(
+ taskRepository);
+ return this.taskAttributeMapper;
+ }
+
+ public TaskData createPartialTaskData(TaskRepository repository,
+ IProgressMonitor monitor,String user, String project, GitHubIssue issue) {
+
+ TaskData data = new TaskData(getAttributeMapper(repository),
+ GitHubRepositoryConnector.KIND, repository.getRepositoryUrl(),
+ issue.getNumber());
+ data.setVersion(DATA_VERSION);
+
+ createOperations(data,issue);
+
+
+ createAttribute(data, GitHubTaskAttributes.KEY,issue.getNumber());
+ createAttribute(data, GitHubTaskAttributes.TITLE, issue.getTitle());
+ createAttribute(data, GitHubTaskAttributes.BODY, issue.getBody());
+ createAttribute(data, GitHubTaskAttributes.STATUS, issue.getState());
+ createAttribute(data, GitHubTaskAttributes.CREATION_DATE, toLocalDate(issue.getCreated_at()));
+ createAttribute(data, GitHubTaskAttributes.MODIFICATION_DATE, toLocalDate(issue.getCreated_at()));
+ createAttribute(data, GitHubTaskAttributes.CLOSED_DATE, toLocalDate(issue.getClosed_at()));
+
+ if (isPartial(data)) {
+ data.setPartial(true);
+ }
+
+ return data;
+ }
+
+
+ private boolean isPartial(TaskData data) {
+ for (GitHubTaskAttributes attribute: GitHubTaskAttributes.values()) {
+ if (attribute.isRequiredForFullTaskData()) {
+ TaskAttribute taskAttribute = data.getRoot().getAttribute(attribute.getId());
+ if (taskAttribute == null) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private void createOperations(TaskData data, GitHubIssue issue) {
+ TaskAttribute operationAttribute = data.getRoot().createAttribute(TaskAttribute.OPERATION);
+ operationAttribute.getMetaData().setType(TaskAttribute.TYPE_OPERATION);
+
+ if (!data.isNew()) {
+ if (issue.getState() != null) {
+ addOperation(data,issue,GitHubTaskOperation.LEAVE,true);
+ if (issue.getState().equals("open")) {
+ addOperation(data,issue,GitHubTaskOperation.CLOSE,false);
+ } else if (issue.getState().equals("closed")) {
+ addOperation(data,issue,GitHubTaskOperation.REOPEN,false);
+ }
+ }
+ }
+ }
+
+ private void addOperation(TaskData data, GitHubIssue issue, GitHubTaskOperation 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(GitHubIssue issue,
+ GitHubTaskOperation operation) {
+ return operation==GitHubTaskOperation.LEAVE?operation.getLabel()+issue.getState():operation.getLabel();
+ }
+
+ private String toLocalDate(String date) {
+ if (date != null && date.trim().length() > 0) {
+ // expect "2010/02/02 22:58:39 -0800"
+ try {
+ Date d = githubDateFormat.parse(date);
+ date = dateFormat.format(d);
+ } catch (ParseException e) {
+ // ignore
+ }
+ }
+ return date;
+ }
+
+ private String toGitHubDate(TaskData taskData,
+ GitHubTaskAttributes attr) {
+ TaskAttribute attribute = taskData.getRoot().getAttribute(attr.name());
+ String value = attribute==null?null:attribute.getValue();
+ if (value != null) {
+ try {
+ Date d = dateFormat.parse(value);
+ value = githubDateFormat.format(d);
+ } catch (ParseException e) {
+ // ignore
+ }
+ }
+ return value;
+ }
+
+ public TaskData createTaskData(TaskRepository repository,
+ IProgressMonitor monitor, String user, String project,
+ GitHubIssue issue) {
+ TaskData taskData = createPartialTaskData(repository, monitor, user, project, issue);
+ taskData.setPartial(false);
+
+ return taskData;
+ }
+
+ private GitHubIssue createIssue(TaskData taskData) {
+ GitHubIssue issue = new GitHubIssue();
+ if (!taskData.isNew()) {
+ issue.setNumber(taskData.getTaskId());
+ }
+ issue.setBody(getAttributeValue(taskData,GitHubTaskAttributes.BODY));
+ issue.setTitle(getAttributeValue(taskData,GitHubTaskAttributes.TITLE));
+ issue.setState(getAttributeValue(taskData,GitHubTaskAttributes.STATUS));
+ issue.setCreated_at(toGitHubDate(taskData,GitHubTaskAttributes.CREATION_DATE));
+ issue.setCreated_at(toGitHubDate(taskData,GitHubTaskAttributes.MODIFICATION_DATE));
+ issue.setCreated_at(toGitHubDate(taskData,GitHubTaskAttributes.CLOSED_DATE));
+ return issue;
+ }
+
+ private String getAttributeValue(TaskData taskData,
+ GitHubTaskAttributes attr) {
+ TaskAttribute attribute = taskData.getRoot().getAttribute(attr.getId());
+ return attribute==null?null:attribute.getValue();
+ }
+
+ private void createAttribute(TaskData data, GitHubTaskAttributes attribute, String value) {
+ 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());
+
+ if (value != null) {
+ attr.addValue(value);
+ }
+ }
+
+ @Override
+ public boolean initializeTaskData(TaskRepository repository, TaskData data,
+ ITaskMapping initializationData, IProgressMonitor monitor)
+ throws CoreException {
+
+ data.setVersion(DATA_VERSION);
+
+ for (GitHubTaskAttributes attr: GitHubTaskAttributes.values()) {
+ if (attr.isInitTask()) {
+ createAttribute(data, attr,null);
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public RepositoryResponse postTaskData(TaskRepository repository,
+ TaskData taskData, Set<TaskAttribute> oldAttributes,
+ IProgressMonitor monitor) throws CoreException {
+
+ GitHubIssue issue = createIssue(taskData);
+ String user = GitHub.computeTaskRepositoryUser(repository.getUrl());
+ String repo = GitHub.computeTaskRepositoryProject(repository.getUrl());
+ try {
+
+ GitHubService service = connector.getService();
+ GitHubCredentials credentials = GitHubCredentials.create(repository);
+ if (taskData.isNew()) {
+ issue = service.openIssue(user , repo, issue, credentials);
+ } else {
+ TaskAttribute operationAttribute = taskData.getRoot().getAttribute(TaskAttribute.OPERATION);
+
+ GitHubTaskOperation operation = null;
+
+
+ if (operationAttribute != null) {
+ String opId = operationAttribute.getValue();
+ operation = GitHubTaskOperation.fromId(opId);
+
+ }
+ if (operation != null && operation != GitHubTaskOperation.LEAVE) {
+ service.editIssue(user , repo, issue, credentials);
+ switch (operation) {
+ case REOPEN:
+ service.reopenIssue(user,repo,issue,credentials);
+ break;
+ case CLOSE:
+ service.closeIssue(user,repo,issue,credentials);
+ break;
+ default:
+ throw new IllegalStateException("not implemented: "+operation);
+ }
+ } else {
+ service.editIssue(user , repo, issue, credentials);
+ }
+ }
+ return new RepositoryResponse(taskData.isNew()?ResponseKind.TASK_CREATED:ResponseKind.TASK_UPDATED,issue.getNumber());
+ } catch (GitHubServiceException e) {
+ throw new CoreException(GitHub.createErrorStatus(e));
+ }
+
+ }
+
+
+}
diff --git a/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubTaskOperation.java b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubTaskOperation.java
new file mode 100644
index 00000000..7043d477
--- /dev/null
+++ b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/GitHubTaskOperation.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * 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.github.internal;
+
+public enum GitHubTaskOperation {
+ LEAVE("Leave as "),
+ REOPEN("Reopen"),
+ CLOSE("Close");
+
+ private final String label;
+
+ private GitHubTaskOperation(String label) {
+ this.label = label;
+ }
+
+ public String getLabel() {
+ return label;
+ }
+
+ 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 GitHubTaskOperation fromId(String opId) {
+ for (GitHubTaskOperation op: values()) {
+ if (op.getId().equals(opId)) {
+ return op;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/PermissionDeniedException.java b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/PermissionDeniedException.java
new file mode 100644
index 00000000..f2401048
--- /dev/null
+++ b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/github/internal/PermissionDeniedException.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * 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.github.internal;
+
+import org.apache.commons.httpclient.StatusLine;
+
+public class PermissionDeniedException extends GitHubServiceException {
+
+ private static final long serialVersionUID = -4635370712942848361L;
+
+ protected PermissionDeniedException(Exception exception) {
+ super(exception);
+ }
+
+ protected PermissionDeniedException(StatusLine statusLine) {
+ super(statusLine);
+ }
+
+ protected PermissionDeniedException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ protected PermissionDeniedException(String message) {
+ super(message);
+ }
+
+}
diff --git a/org.eclipse.mylyn.github.tests/.classpath b/org.eclipse.mylyn.github.tests/.classpath
new file mode 100644
index 00000000..64c5e31b
--- /dev/null
+++ b/org.eclipse.mylyn.github.tests/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/org.eclipse.mylyn.github.tests/.gitignore b/org.eclipse.mylyn.github.tests/.gitignore
new file mode 100644
index 00000000..d567ba01
--- /dev/null
+++ b/org.eclipse.mylyn.github.tests/.gitignore
@@ -0,0 +1,2 @@
+bin
+target
diff --git a/org.eclipse.mylyn.github.tests/.project b/org.eclipse.mylyn.github.tests/.project
new file mode 100644
index 00000000..c3fa2b20
--- /dev/null
+++ b/org.eclipse.mylyn.github.tests/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.mylyn.github.tests</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/org.eclipse.mylyn.github.tests/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.mylyn.github.tests/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000..593ea92a
--- /dev/null
+++ b/org.eclipse.mylyn.github.tests/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,8 @@
+#Wed Feb 03 20:29:30 PST 2010
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+org.eclipse.jdt.core.compiler.compliance=1.5
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.5
diff --git a/org.eclipse.mylyn.github.tests/META-INF/MANIFEST.MF b/org.eclipse.mylyn.github.tests/META-INF/MANIFEST.MF
new file mode 100644
index 00000000..2076b5bc
--- /dev/null
+++ b/org.eclipse.mylyn.github.tests/META-INF/MANIFEST.MF
@@ -0,0 +1,15 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Eclipse EGit Mylyn GitHub Tests (Incubation)
+Bundle-SymbolicName: org.eclipse.mylyn.github.tests
+Bundle-Version: 0.1.0.qualifier
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
+Require-Bundle: org.junit4;bundle-version="4.5.0",
+ org.eclipse.mylyn.github.core;bundle-version="0.1.0",
+ org.eclipse.mylyn.github.ui;bundle-version="0.1.0",
+ org.eclipse.jface.text;bundle-version="3.5.0",
+ org.eclipse.mylyn.tasks.ui;bundle-version="3.2.0",
+ org.eclipse.equinox.security;bundle-version="1.0.100",
+ org.eclipse.mylyn.tasks.core
+Bundle-Vendor: Eclipse EGit
+Import-Package: com.google.gson;version="1.6.0"
diff --git a/org.eclipse.mylyn.github.tests/build.properties b/org.eclipse.mylyn.github.tests/build.properties
new file mode 100644
index 00000000..34d2e4d2
--- /dev/null
+++ b/org.eclipse.mylyn.github.tests/build.properties
@@ -0,0 +1,4 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .
diff --git a/org.eclipse.mylyn.github.tests/src/org/eclipse/mylyn/github/tests/AllHeadlessTests.java b/org.eclipse.mylyn.github.tests/src/org/eclipse/mylyn/github/tests/AllHeadlessTests.java
new file mode 100644
index 00000000..009f6db0
--- /dev/null
+++ b/org.eclipse.mylyn.github.tests/src/org/eclipse/mylyn/github/tests/AllHeadlessTests.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * 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.github.tests;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+import org.junit.runners.Suite.SuiteClasses;
+
+@RunWith(Suite.class)
+@SuiteClasses( { //
+ GitHubServiceTest.class,
+ MarshalingTest.class
+ })
+public class AllHeadlessTests {
+
+}
diff --git a/org.eclipse.mylyn.github.tests/src/org/eclipse/mylyn/github/tests/GitHubServiceTest.java b/org.eclipse.mylyn.github.tests/src/org/eclipse/mylyn/github/tests/GitHubServiceTest.java
new file mode 100644
index 00000000..d05be84a
--- /dev/null
+++ b/org.eclipse.mylyn.github.tests/src/org/eclipse/mylyn/github/tests/GitHubServiceTest.java
@@ -0,0 +1,121 @@
+/*******************************************************************************
+ * 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.github.tests;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.eclipse.mylyn.github.internal.GitHubCredentials;
+import org.eclipse.mylyn.github.internal.GitHubIssue;
+import org.eclipse.mylyn.github.internal.GitHubIssues;
+import org.eclipse.mylyn.github.internal.GitHubService;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Run All the JUnit Tests for the GitHub API implementation
+ */
+@RunWith(JUnit4.class)
+public class GitHubServiceTest {
+
+ // GitHub API key for user "eclipse-github-plugin"
+ String API_KEY = "8b35af675fcdca9d254ae7a6ad4d0be8";
+
+ String TEST_USER = "eclipse-github-plugin";
+
+ String TEST_PASS = "plugin";
+
+ String TEST_PROJECT = "org.eclipse.mylyn.github.issues";
+
+ /**
+ * Test the GitHubService issue searching implementation
+ */
+ @SuppressWarnings("restriction")
+ @Test
+ public void searchIssues() throws Exception {
+ final GitHubService service = new GitHubService();
+ final GitHubIssues issues = service.searchIssues(TEST_USER,
+ TEST_PROJECT, "open", "test");
+ assertEquals(0, issues.getIssues().length);
+ }
+
+ /**
+ * Test the GitHubService implementation for opening a new issue.
+ */
+ @Test
+ public void openIssue() throws Exception {
+ final GitHubService service = new GitHubService();
+ final GitHubIssue issue = new GitHubIssue();
+ issue.setUser(TEST_USER);
+ issue.setBody("This is a test body");
+ issue.setTitle("Issue Title");
+ GitHubIssue newIssue = service.openIssue(TEST_USER, TEST_PROJECT, issue,
+ new GitHubCredentials(TEST_USER,API_KEY));
+ assertTrue(newIssue != null);
+ assertEquals(issue.getUser(),newIssue.getUser());
+ assertEquals(issue.getBody(),newIssue.getBody());
+ assertEquals(issue.getTitle(),newIssue.getTitle());
+ assertTrue(newIssue.getNumber() != null && newIssue.getNumber().length() > 0);
+ }
+ /**
+ * Test the GitHubService implementation for opening a new issue.
+ */
+ @Test
+ public void editIssue() throws Exception {
+ final GitHubService service = new GitHubService();
+ final GitHubIssue issue = new GitHubIssue();
+ issue.setUser(TEST_USER);
+ issue.setBody("This is a test body");
+ issue.setTitle("Issue Title");
+ GitHubIssue newIssue = service.openIssue(TEST_USER, TEST_PROJECT, issue,
+ new GitHubCredentials(TEST_USER,API_KEY));
+ assertTrue(newIssue != null);
+
+ newIssue.setTitle(newIssue.getTitle()+" - modified");
+ newIssue.setBody(newIssue.getBody()+" - modified");
+
+ service.editIssue(TEST_USER, TEST_PROJECT, issue, new GitHubCredentials(TEST_USER,API_KEY));
+
+ GitHubIssue showIssue = service.showIssue(TEST_USER, TEST_PROJECT, issue.getNumber());
+
+ assertTrue(showIssue != null);
+ assertEquals(newIssue.getTitle(),showIssue.getTitle());
+ }
+
+
+
+ /**
+ * Test the GitHubService implementation for adding a label to an existing
+ * issue.
+ */
+ @Test
+ public void addLabel() throws Exception {
+ final GitHubService service = new GitHubService();
+ final boolean result = service.addLabel(TEST_USER, TEST_PROJECT,
+ "lame", 1, new GitHubCredentials(TEST_USER,API_KEY));
+ assertTrue(result);
+ }
+
+ /**
+ * Test the GitHubService implementation for removing an existing label from
+ * any GitHub issue.
+ */
+ @Test
+ public void removeLable() throws Exception {
+ final GitHubService service = new GitHubService();
+ final boolean result = service.removeLabel(TEST_USER, TEST_PROJECT,
+ "lame", 1, new GitHubCredentials(TEST_USER,API_KEY));
+ assertTrue(result);
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.mylyn.github.tests/src/org/eclipse/mylyn/github/tests/MarshalingTest.java b/org.eclipse.mylyn.github.tests/src/org/eclipse/mylyn/github/tests/MarshalingTest.java
new file mode 100644
index 00000000..e6c80fe9
--- /dev/null
+++ b/org.eclipse.mylyn.github.tests/src/org/eclipse/mylyn/github/tests/MarshalingTest.java
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * 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.github.tests;
+
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringWriter;
+
+import org.eclipse.mylyn.github.internal.GitHubIssue;
+import org.eclipse.mylyn.github.internal.GitHubIssues;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import com.google.gson.Gson;
+
+@SuppressWarnings("restriction")
+@RunWith(JUnit4.class)
+public class MarshalingTest {
+
+ private Gson gson;
+
+ @Before
+ public void beforeTest() {
+ gson = new Gson();
+ }
+
+ @Test
+ public void unmarshalIssues() {
+ GitHubIssues issues = gson.fromJson(
+ getResource("resources/issues.json"), GitHubIssues.class);
+
+ assertTrue(issues != null);
+ assertTrue(issues.getIssues() != null);
+
+ assertEquals(10,issues.getIssues().length);
+
+ GitHubIssue issue = issues.getIssues()[9];
+ //{"number":10,"votes":0,"created_at":"2010/02/04 21:03:54 -0800","body":"test description 2 ","title":"test issue for testing mylyn github connector2",
+ // "updated_at":"2010/02/04 21:09:37 -0800","closed_at":null,"user":"dgreen99","labels":[],"state":"open"}]}
+ assertEquals("10",issue.getNumber());
+ assertEquals("2010/02/04 21:03:54 -0800",issue.getCreated_at());
+ assertEquals("test description 2 ",issue.getBody());
+ assertEquals("test issue for testing mylyn github connector2",issue.getTitle());
+ assertEquals("2010/02/04 21:09:37 -0800",issue.getUpdated_at());
+ assertNull(issue.getClosed_at());
+ assertEquals("dgreen99",issue.getUser());
+ assertEquals("open",issue.getState());
+ }
+
+ private String getResource(String resource) {
+ try {
+ InputStream stream = MarshalingTest.class
+ .getResourceAsStream(resource);
+ try {
+ StringWriter writer = new StringWriter();
+ Reader reader = new InputStreamReader(stream);
+ int c;
+ while ((c = reader.read()) != -1) {
+ writer.write(c);
+ }
+ return writer.toString();
+ } finally {
+ stream.close();
+ }
+ } catch (Throwable t) {
+ throw new IllegalStateException(t);
+ }
+ }
+}
diff --git a/org.eclipse.mylyn.github.tests/src/org/eclipse/mylyn/github/tests/resources/issues.json b/org.eclipse.mylyn.github.tests/src/org/eclipse/mylyn/github/tests/resources/issues.json
new file mode 100644
index 00000000..d99eb9f3
--- /dev/null
+++ b/org.eclipse.mylyn.github.tests/src/org/eclipse/mylyn/github/tests/resources/issues.json
@@ -0,0 +1 @@
+{"issues":[{"number":1,"votes":0,"created_at":"2010/02/02 22:58:39 -0800","body":"","title":"Test objective-c marshaling code","updated_at":"2010/02/02 22:58:39 -0800","closed_at":null,"user":"dgreen99","labels":[],"state":"open"},{"number":2,"votes":0,"created_at":"2010/02/02 22:59:02 -0800","body":"","title":"Provide instructions for use","updated_at":"2010/02/02 22:59:02 -0800","closed_at":null,"user":"dgreen99","labels":[],"state":"open"},{"number":3,"votes":0,"created_at":"2010/02/02 22:59:26 -0800","body":"","title":"add support for JSON marshalling","updated_at":"2010/02/04 17:56:02 -0800","closed_at":null,"user":"dgreen99","labels":[],"state":"open"},{"number":4,"votes":0,"created_at":"2010/02/02 22:59:45 -0800","body":"","title":"provide working sample project","updated_at":"2010/02/02 22:59:45 -0800","closed_at":null,"user":"dgreen99","labels":[],"state":"open"},{"number":5,"votes":0,"created_at":"2010/02/02 23:00:19 -0800","body":"","title":"support object inheritance","updated_at":"2010/02/02 23:00:19 -0800","closed_at":null,"user":"dgreen99","labels":[],"state":"open"},{"number":6,"votes":0,"created_at":"2010/02/02 23:00:37 -0800","body":"","title":"provide support for nested types","updated_at":"2010/02/02 23:00:37 -0800","closed_at":null,"user":"dgreen99","labels":[],"state":"open"},{"number":7,"votes":0,"created_at":"2010/02/02 23:00:49 -0800","body":"","title":"client enum support","updated_at":"2010/02/02 23:00:49 -0800","closed_at":null,"user":"dgreen99","labels":[],"state":"open"},{"number":8,"votes":0,"created_at":"2010/02/02 23:01:09 -0800","body":"","title":"refactor templates to use field iterator","updated_at":"2010/02/02 23:01:09 -0800","closed_at":null,"user":"dgreen99","labels":[],"state":"open"},{"number":9,"votes":0,"created_at":"2010/02/02 23:01:35 -0800","body":"","title":"wiki should explain target architecture","updated_at":"2010/02/02 23:01:35 -0800","closed_at":null,"user":"dgreen99","labels":[],"state":"open"},{"number":10,"votes":0,"created_at":"2010/02/04 21:03:54 -0800","body":"test description 2 ","title":"test issue for testing mylyn github connector2","updated_at":"2010/02/04 21:09:37 -0800","closed_at":null,"user":"dgreen99","labels":[],"state":"open"}]} \ No newline at end of file
diff --git a/org.eclipse.mylyn.github.tests/src/org/eclipse/mylyn/github/tests/ui/GitHubRepositoryConnectorUITest.java b/org.eclipse.mylyn.github.tests/src/org/eclipse/mylyn/github/tests/ui/GitHubRepositoryConnectorUITest.java
new file mode 100644
index 00000000..fe58f09e
--- /dev/null
+++ b/org.eclipse.mylyn.github.tests/src/org/eclipse/mylyn/github/tests/ui/GitHubRepositoryConnectorUITest.java
@@ -0,0 +1,41 @@
+package org.eclipse.mylyn.github.tests.ui;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertTrue;
+import junit.framework.Assert;
+
+import org.eclipse.jface.text.Region;
+import org.eclipse.jface.text.hyperlink.IHyperlink;
+import org.eclipse.mylyn.github.internal.GitHub;
+import org.eclipse.mylyn.github.ui.internal.GitHubRepositoryConnectorUI;
+import org.eclipse.mylyn.tasks.core.TaskRepository;
+import org.eclipse.mylyn.tasks.ui.TaskHyperlink;
+import org.junit.Before;
+import org.junit.Test;
+
+public class GitHubRepositoryConnectorUITest {
+
+ private GitHubRepositoryConnectorUI connectorUI;
+ private TaskRepository repository;
+
+ @Before
+ public void before() {
+ connectorUI = new GitHubRepositoryConnectorUI();
+ repository = new TaskRepository(GitHub.CONNECTOR_KIND, GitHub.createGitHubUrl("foo", "bar"));
+ }
+
+ @Test
+ public void testFindHyperlinksTaskRepositoryStringIntInt() {
+ IHyperlink[] hyperlinks = connectorUI.findHyperlinks(repository, "one #2 three", -1, 0);
+ assertNotNull(hyperlinks);
+ assertEquals(1,hyperlinks.length);
+ assertEquals(new Region(4,2),hyperlinks[0].getHyperlinkRegion());
+
+ hyperlinks = connectorUI.findHyperlinks(repository, "one #2 three", -1, 4);
+ assertNotNull(hyperlinks);
+ assertEquals(1,hyperlinks.length);
+ assertEquals(new Region(8,2),hyperlinks[0].getHyperlinkRegion());
+ }
+
+}
diff --git a/org.eclipse.mylyn.github.ui/.classpath b/org.eclipse.mylyn.github.ui/.classpath
new file mode 100644
index 00000000..64c5e31b
--- /dev/null
+++ b/org.eclipse.mylyn.github.ui/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/org.eclipse.mylyn.github.ui/.gitignore b/org.eclipse.mylyn.github.ui/.gitignore
new file mode 100644
index 00000000..d567ba01
--- /dev/null
+++ b/org.eclipse.mylyn.github.ui/.gitignore
@@ -0,0 +1,2 @@
+bin
+target
diff --git a/org.eclipse.mylyn.github.ui/.project b/org.eclipse.mylyn.github.ui/.project
new file mode 100644
index 00000000..6b7553c4
--- /dev/null
+++ b/org.eclipse.mylyn.github.ui/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.mylyn.github.ui</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/org.eclipse.mylyn.github.ui/.settings/org.eclipse.core.resources.prefs b/org.eclipse.mylyn.github.ui/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 00000000..84f3fcc6
--- /dev/null
+++ b/org.eclipse.mylyn.github.ui/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,3 @@
+#Tue Jun 09 20:22:15 CEST 2009
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/org.eclipse.mylyn.github.ui/.settings/org.eclipse.core.runtime.prefs b/org.eclipse.mylyn.github.ui/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 00000000..f96d6778
--- /dev/null
+++ b/org.eclipse.mylyn.github.ui/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,3 @@
+#Tue Jun 09 20:22:15 CEST 2009
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/org.eclipse.mylyn.github.ui/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.mylyn.github.ui/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000..094b3472
--- /dev/null
+++ b/org.eclipse.mylyn.github.ui/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,12 @@
+#Sun Aug 23 18:34:16 EDT 2009
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.5
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.5
diff --git a/org.eclipse.mylyn.github.ui/META-INF/MANIFEST.MF b/org.eclipse.mylyn.github.ui/META-INF/MANIFEST.MF
new file mode 100644
index 00000000..356db6d0
--- /dev/null
+++ b/org.eclipse.mylyn.github.ui/META-INF/MANIFEST.MF
@@ -0,0 +1,17 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Eclipse EGit Mylyn GitHub UI Plug-in (Incubation)
+Bundle-SymbolicName: org.eclipse.mylyn.github.ui;singleton:=true
+Bundle-Version: 0.1.0.qualifier
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
+Bundle-Vendor: Eclipse EGit
+Bundle-Localization: plugin
+Require-Bundle: org.eclipse.core.runtime;bundle-version="3.5.0",
+ org.eclipse.ui;bundle-version="3.5.0",
+ org.eclipse.ui.forms;bundle-version="3.4.0",
+ org.eclipse.mylyn.tasks.ui;bundle-version="3.2.0",
+ org.eclipse.mylyn.github.core;bundle-version="0.1.0",
+ org.eclipse.jface.text;bundle-version="3.5.0",
+ org.eclipse.mylyn.commons.net;bundle-version="3.2.0",
+ org.eclipse.mylyn.tasks.core
+Export-Package: org.eclipse.mylyn.github.ui.internal;x-internal:=true
diff --git a/org.eclipse.mylyn.github.ui/build.properties b/org.eclipse.mylyn.github.ui/build.properties
new file mode 100644
index 00000000..3a0c53af
--- /dev/null
+++ b/org.eclipse.mylyn.github.ui/build.properties
@@ -0,0 +1,7 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ plugin.xml,\
+ plugin.properties,\
+ images/
diff --git a/org.eclipse.mylyn.github.ui/images/git-logo.png b/org.eclipse.mylyn.github.ui/images/git-logo.png
new file mode 100644
index 00000000..dd98d355
--- /dev/null
+++ b/org.eclipse.mylyn.github.ui/images/git-logo.png
Binary files differ
diff --git a/org.eclipse.mylyn.github.ui/plugin.properties b/org.eclipse.mylyn.github.ui/plugin.properties
new file mode 100644
index 00000000..da940291
--- /dev/null
+++ b/org.eclipse.mylyn.github.ui/plugin.properties
@@ -0,0 +1,2 @@
+org.eclipse.mylyn.github.ui.internal.GitHubRepositoryConnector=GitHub repository connector
+org.eclipse.mylyn.github.ui.internal.GitHubRepositoryConnectorUI=GitHub repository connector UI \ No newline at end of file
diff --git a/org.eclipse.mylyn.github.ui/plugin.xml b/org.eclipse.mylyn.github.ui/plugin.xml
new file mode 100644
index 00000000..57da2a54
--- /dev/null
+++ b/org.eclipse.mylyn.github.ui/plugin.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>
+ <extension
+ point="org.eclipse.mylyn.tasks.ui.repositories">
+ <connectorCore
+ class="org.eclipse.mylyn.github.internal.GitHubRepositoryConnector"
+ id="org.eclipse.mylyn.github.ui.internal.GitHubRepositoryConnector"
+ name="%org.eclipse.mylyn.github.ui.internal.GitHubRepositoryConnector">
+ </connectorCore>
+ <connectorUi
+ brandingIcon="images/git-logo.png"
+ class="org.eclipse.mylyn.github.ui.internal.GitHubRepositoryConnectorUI"
+ id="org.eclipse.mylyn.github.ui.internal.GitHubRepositoryConnectorUI"
+ name="%org.eclipse.mylyn.github.ui.internal.GitHubRepositoryConnectorUI"
+ overlayIcon="images/git-logo.png">
+ </connectorUi>
+ </extension>
+ <extension
+ point="org.eclipse.mylyn.tasks.ui.editors">
+ <pageFactory
+ class="org.eclipse.mylyn.github.ui.internal.GitHubTaskEditorPageFactory"
+ id="org.eclipse.mylyn.github.ui.internal.GitHubTaskEditorPageFactory">
+ </pageFactory>
+ </extension>
+
+</plugin>
diff --git a/org.eclipse.mylyn.github.ui/pom.xml b/org.eclipse.mylyn.github.ui/pom.xml
new file mode 100644
index 00000000..1accffc8
--- /dev/null
+++ b/org.eclipse.mylyn.github.ui/pom.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2011, Chris Aniszczyk <caniszczyk@gmail.com>
+
+ 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
+-->
+<project
+ xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <artifactId>github-parent</artifactId>
+ <groupId>org.eclipse.mylyn.github</groupId>
+ <version>0.1.0-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>ui</artifactId>
+ <packaging>eclipse-plugin</packaging>
+ <name>Eclipse EGit Mylyn GitHub UI (Incubation)</name>
+</project>
diff --git a/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/github/ui/internal/GitHubRepositoryConnectorUI.java b/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/github/ui/internal/GitHubRepositoryConnectorUI.java
new file mode 100644
index 00000000..eda7565f
--- /dev/null
+++ b/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/github/ui/internal/GitHubRepositoryConnectorUI.java
@@ -0,0 +1,147 @@
+/*******************************************************************************
+ * 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.github.ui.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.eclipse.jface.text.Region;
+import org.eclipse.jface.text.hyperlink.IHyperlink;
+import org.eclipse.jface.text.hyperlink.URLHyperlink;
+import org.eclipse.jface.wizard.IWizard;
+import org.eclipse.mylyn.github.internal.GitHub;
+import org.eclipse.mylyn.tasks.core.IRepositoryQuery;
+import org.eclipse.mylyn.tasks.core.ITaskMapping;
+import org.eclipse.mylyn.tasks.core.TaskRepository;
+import org.eclipse.mylyn.tasks.ui.AbstractRepositoryConnectorUi;
+import org.eclipse.mylyn.tasks.ui.TaskHyperlink;
+import org.eclipse.mylyn.tasks.ui.TasksUi;
+import org.eclipse.mylyn.tasks.ui.wizards.AbstractRepositorySettingsPage;
+import org.eclipse.mylyn.tasks.ui.wizards.ITaskRepositoryPage;
+import org.eclipse.mylyn.tasks.ui.wizards.NewTaskWizard;
+import org.eclipse.mylyn.tasks.ui.wizards.RepositoryQueryWizard;
+
+/**
+ * GitHub connector specific UI extensions.
+ */
+public class GitHubRepositoryConnectorUI extends AbstractRepositoryConnectorUi {
+
+ private final Pattern issuePattern = Pattern.compile("(?:([a-zA-Z0-9_\\.-]+)(?:/([a-zA-Z0-9_\\.-]+))?)?\\#(\\d+)");
+
+ /**
+ *
+ *
+ * @return the unique type of the repository: "github"
+ */
+ @Override
+ public String getConnectorKind() {
+ return GitHub.CONNECTOR_KIND;
+ }
+
+ /**
+ *
+ *
+ * @return {@link AbstractRepositorySettingsPage} with GitHub specific
+ * parameter like user name, password, ...
+ */
+ @Override
+ public ITaskRepositoryPage getSettingsPage(
+ final TaskRepository taskRepository) {
+ return new GitHubRepositorySettingsPage(taskRepository);
+ }
+
+ /**
+ *
+ *
+ * @return {@link NewTaskWizard} with GitHub specific tab
+ */
+ @Override
+ public IWizard getNewTaskWizard(final TaskRepository taskRepository,
+ final ITaskMapping taskSelection) {
+ return new NewTaskWizard(taskRepository, taskSelection);
+ }
+
+ /**
+ * This {@link AbstractRepositoryConnectorUi} has search page.
+ *
+ * @return {@code true}
+ */
+ @Override
+ public boolean hasSearchPage() {
+ return true;
+ }
+
+ /**
+ * Returns {@link IWizard} used in Mylyn for creating new queries. This
+ * {@link IWizard} has a wizard page for creating GitHub specific task
+ * queries.
+ *
+ * @return {@link RepositoryQueryWizard} with GitHub specific query page
+ */
+ @Override
+ public IWizard getQueryWizard(final TaskRepository taskRepository,
+ final IRepositoryQuery queryToEdit) {
+ RepositoryQueryWizard wizard = new RepositoryQueryWizard(taskRepository);
+ GitHubRepositoryQueryPage queryPage = new GitHubRepositoryQueryPage(
+ taskRepository, queryToEdit);
+ wizard.addPage(queryPage);
+ return wizard;
+ }
+
+
+ public IHyperlink[] findHyperlinks(TaskRepository repository, String text, int index, int textOffset) {
+ List<IHyperlink> hyperlinks = new ArrayList<IHyperlink>();
+
+ Matcher matcher = issuePattern.matcher(text);
+ while (matcher.find()) {
+ if (index == -1 || (index >= matcher.start() && index <= matcher.end())) {
+ String user = matcher.group(1);
+ String project = matcher.group(2);
+ String taskId = matcher.group(3);
+
+ if (project == null && user != null) {
+ // same project name, different user
+ String url = repository.getUrl();
+ project = GitHub.computeTaskRepositoryProject(url);
+ }
+
+ TaskRepository taskRepository = null;
+ if (user == null && project == null) {
+ taskRepository = repository;
+ } else if (user != null && project != null) {
+ String repositoryUrl = GitHub.createGitHubUrl(user,project);
+ taskRepository = TasksUi.getRepositoryManager().getRepository(GitHub.CONNECTOR_KIND, repositoryUrl);
+ if (taskRepository == null) {
+ repositoryUrl = GitHub.createGitHubUrlAlternate(user,project);
+ taskRepository = TasksUi.getRepositoryManager().getRepository(GitHub.CONNECTOR_KIND, repositoryUrl);
+ }
+ }
+ if (taskRepository != null) {
+ Region region = createRegion(textOffset, matcher);
+ hyperlinks.add(new TaskHyperlink(region, repository, taskId));
+ } else if (user != null && project != null) {
+ Region region = createRegion(textOffset, matcher);
+ String url = GitHub.createGitHubUrl(user, project)+"/issues/issue/"+taskId;
+ hyperlinks.add(new URLHyperlink(region, url));
+ }
+ }
+ }
+ return hyperlinks.toArray(new IHyperlink[hyperlinks.size()]);
+ }
+
+ private Region createRegion(int textOffset, Matcher matcher) {
+ return new Region(matcher.start()+textOffset,matcher.end()-matcher.start());
+ }
+}
diff --git a/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/github/ui/internal/GitHubRepositoryQueryPage.java b/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/github/ui/internal/GitHubRepositoryQueryPage.java
new file mode 100644
index 00000000..b55e72a5
--- /dev/null
+++ b/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/github/ui/internal/GitHubRepositoryQueryPage.java
@@ -0,0 +1,119 @@
+/*******************************************************************************
+ * 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.github.ui.internal;
+
+import org.eclipse.mylyn.tasks.core.IRepositoryQuery;
+import org.eclipse.mylyn.tasks.core.TaskRepository;
+import org.eclipse.mylyn.tasks.ui.wizards.AbstractRepositoryQueryPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * GitHub connector specific extensions.
+ */
+public class GitHubRepositoryQueryPage extends AbstractRepositoryQueryPage {
+
+ private static final String ATTR_QUERY_TEXT = "queryText";
+
+ private static final String ATTR_STATUS = "status";
+
+ private Text queryText = null;
+
+ private Combo status = null;
+
+ /**
+ * @param taskRepository
+ * @param query
+ */
+ public GitHubRepositoryQueryPage(final TaskRepository taskRepository,
+ final IRepositoryQuery query) {
+ super("GitHub", taskRepository, query);
+ setTitle("GitHub search query parameters");
+ setDescription("Valid search query parameters entered.");
+ setPageComplete(false);
+ }
+
+ @Override
+ public String getQueryTitle() {
+ return "GitHub Query";
+ }
+
+ @Override
+ public void applyTo(IRepositoryQuery query) {
+ String statusString = status.getText();
+ String queryString = queryText.getText();
+
+ String summary = statusString;
+ summary += " issues";
+ if (queryString!=null && queryString.trim().length() > 0) {
+ summary += " matching "+queryString;
+ }
+ query.setSummary(summary);
+ query.setAttribute(ATTR_STATUS, statusString);
+ query.setAttribute(ATTR_QUERY_TEXT, queryString);
+ }
+
+ /**
+ *
+ *
+ */
+ public void createControl(Composite parent) {
+ Composite composite = new Composite(parent, SWT.NONE);
+ GridLayout gridLayout = new GridLayout(2, false);
+ gridLayout.marginTop = 20;
+ gridLayout.marginLeft = 25;
+ gridLayout.verticalSpacing = 8;
+ gridLayout.horizontalSpacing = 8;
+ composite.setLayout(gridLayout);
+
+
+ // create the status option combo box
+ new Label(composite, SWT.NONE).setText("Status:");
+ status = new Combo(composite, SWT.READ_ONLY);
+ String[] queryValues = new String[] { "all", "open", "closed" };
+ status.setItems(queryValues);
+ status.select(0);
+ String queryModelStatus = getQuery()==null?null:getQuery().getAttribute(ATTR_STATUS);
+ if (queryModelStatus != null) {
+ for (int x = 0;x<queryValues.length;++x) {
+ if (queryValues[x].equals(queryModelStatus)) {
+ status.select(x);
+ break;
+ }
+ }
+ }
+
+ // create the query entry box
+ new Label(composite, SWT.NONE).setText("Query text:");
+ queryText = new Text(composite, SWT.BORDER);
+ GridData gridData = new GridData();
+ gridData.widthHint = 250;
+ queryText.setLayoutData(gridData);
+ String queryModelText = getQuery()==null?null:getQuery().getAttribute(ATTR_QUERY_TEXT);
+ queryText.setText(queryModelText==null?"":queryModelText);
+
+ setControl(composite);
+ }
+
+ @Override
+ public boolean isPageComplete() {
+ setErrorMessage(null);
+ return true;
+ }
+
+}
diff --git a/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/github/ui/internal/GitHubRepositorySettingsPage.java b/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/github/ui/internal/GitHubRepositorySettingsPage.java
new file mode 100644
index 00000000..28cd3a55
--- /dev/null
+++ b/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/github/ui/internal/GitHubRepositorySettingsPage.java
@@ -0,0 +1,147 @@
+/*******************************************************************************
+ * 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.github.ui.internal;
+
+import java.util.regex.Matcher;
+
+
+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.mylyn.commons.net.AuthenticationCredentials;
+import org.eclipse.mylyn.commons.net.AuthenticationType;
+import org.eclipse.mylyn.github.internal.GitHub;
+import org.eclipse.mylyn.github.internal.GitHubCredentials;
+import org.eclipse.mylyn.github.internal.GitHubService;
+import org.eclipse.mylyn.github.internal.GitHubServiceException;
+import org.eclipse.mylyn.tasks.core.TaskRepository;
+import org.eclipse.mylyn.tasks.ui.wizards.AbstractRepositorySettingsPage;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * GitHub connector specific extensions.
+ */
+public class GitHubRepositorySettingsPage extends
+ AbstractRepositorySettingsPage {
+
+ static final String URL = "http://github.com";
+
+ private static final String PASS_LABEL_TEXT = "GitHub API Token:";
+
+ /**
+ * Populate taskRepository with repository settings.
+ *
+ * @param taskRepository
+ * - Object to populate
+ */
+ public GitHubRepositorySettingsPage(final TaskRepository taskRepository) {
+ super("GitHub Repository Settings", "", taskRepository);
+ this.setHttpAuth(false);
+ this.setNeedsAdvanced(false);
+ this.setNeedsAnonymousLogin(false);
+ this.setNeedsTimeZone(false);
+ this.setNeedsHttpAuth(false);
+ }
+
+ @Override
+ public String getConnectorKind() {
+ return GitHub.CONNECTOR_KIND;
+ }
+
+ @Override
+ protected void createAdditionalControls(Composite parent) {
+ // Set the URL now, because serverURL is definitely instantiated .
+ if (serverUrlCombo != null && (serverUrlCombo.getText() == null || serverUrlCombo.getText().trim().length() == 0)) {
+ String fullUrlText = URL+"/user/project";
+ serverUrlCombo.setText(fullUrlText);
+ // select the user/project part of the URL so that the user can just start
+ // typing to replace the text.
+ serverUrlCombo.setSelection(new Point(URL.length()+1,fullUrlText.length()));
+ }
+
+ // Specify that you need the GitHub User Name
+ if (repositoryUserNameEditor != null) {
+ String text = repositoryUserNameEditor.getLabelText();
+ repositoryUserNameEditor.setLabelText("GitHub " + text);
+ }
+
+ // Use the password field for the API Token Key
+ if (repositoryPasswordEditor != null) {
+ repositoryPasswordEditor.setLabelText(PASS_LABEL_TEXT);
+ }
+ }
+
+ @Override
+ protected Validator getValidator(final TaskRepository repository) {
+ Validator validator = new Validator() {
+ @Override
+ public void run(IProgressMonitor monitor) throws CoreException {
+ int totalWork = 1000;
+ monitor.beginTask("Validating settings", totalWork);
+ try {
+
+ String urlText = repository.getUrl();
+ Matcher urlMatcher = GitHub.URL_PATTERN.matcher(urlText==null?"":urlText);
+ if (!urlMatcher.matches()) {
+ setStatus(GitHubUi.createErrorStatus("Server URL must be in the form http://github.com/user/project or\nhttp://www.github.org/user/project"));
+ return;
+ }
+ monitor.worked(100);
+
+ String user = urlMatcher.group(1);
+ String repo = urlMatcher.group(2);
+ AuthenticationCredentials auth = repository.getCredentials(AuthenticationType.REPOSITORY);
+
+ GitHubService service = new GitHubService();
+
+ monitor.subTask("Contacting server...");
+ try {
+ // verify the repo
+ service.searchIssues(user, repo, new String("open"),"");
+ monitor.worked(400);
+
+ // verify the credentials
+ if (auth == null) {
+ setStatus(GitHubUi.createErrorStatus("Credentials are required. Please specify username and API Token."));
+ return;
+ }
+ GitHubCredentials credentials = new GitHubCredentials(auth.getUserName(), auth.getPassword());
+ if (!service.verifyCredentials(credentials)) {
+ setStatus(GitHubUi.createErrorStatus("Invalid credentials. Please check your GitHub User ID and API Token.\nYou can find your API Token on your GitHub account settings page."));
+ return;
+ }
+ } catch (GitHubServiceException e) {
+ setStatus(GitHubUi.createErrorStatus("Repository Test failed:"+ e.getMessage()));
+ return;
+ }
+
+ setStatus(new Status(IStatus.OK,GitHubUi.BUNDLE_ID, "Success!"));
+ } finally {
+ monitor.done();
+ }
+ }
+ };
+ return validator;
+ }
+
+ @Override
+ protected boolean isValidUrl(final String url) {
+ if (url.contains("github")) {
+ return true;
+ }
+ return false;
+ }
+
+}
diff --git a/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/github/ui/internal/GitHubTaskEditorPage.java b/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/github/ui/internal/GitHubTaskEditorPage.java
new file mode 100644
index 00000000..a24d8cb1
--- /dev/null
+++ b/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/github/ui/internal/GitHubTaskEditorPage.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * 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.github.ui.internal;
+
+import java.util.Iterator;
+import java.util.Set;
+
+import org.eclipse.mylyn.github.internal.GitHub;
+import org.eclipse.mylyn.tasks.core.data.TaskAttribute;
+import org.eclipse.mylyn.tasks.ui.editors.AbstractAttributeEditor;
+import org.eclipse.mylyn.tasks.ui.editors.AbstractTaskEditorPage;
+import org.eclipse.mylyn.tasks.ui.editors.AttributeEditorFactory;
+import org.eclipse.mylyn.tasks.ui.editors.TaskEditor;
+import org.eclipse.mylyn.tasks.ui.editors.TaskEditorPartDescriptor;
+
+/**
+ * Editor page for GitHub.
+ */
+public class GitHubTaskEditorPage extends AbstractTaskEditorPage {
+
+ /**
+ * Constructor for the GitHubTaskEditorPage
+ *
+ * @param editor
+ * The task editor to create for GitHub
+ */
+ public GitHubTaskEditorPage(final TaskEditor editor) {
+ super(editor, GitHub.CONNECTOR_KIND);
+ setNeedsPrivateSection(true);
+ setNeedsSubmitButton(true);
+ }
+
+ @Override
+ protected Set<TaskEditorPartDescriptor> createPartDescriptors() {
+ Set<TaskEditorPartDescriptor> partDescriptors = super.createPartDescriptors();
+ Iterator<TaskEditorPartDescriptor> descriptorIt = partDescriptors.iterator();
+ while (descriptorIt.hasNext()) {
+ TaskEditorPartDescriptor partDescriptor = descriptorIt.next();
+ if (partDescriptor.getId().equals(ID_PART_ATTRIBUTES)) {
+ descriptorIt.remove();
+ } else if (partDescriptor.getId().equals(ID_PART_COMMENTS)) {
+ // currently the API doesn't support reading existing comments,
+ // though it does allow for creating them. Silly really.
+ // see http://support.github.com/discussions/feature-requests/696-issues-api-improvement
+ descriptorIt.remove();
+ }
+ }
+ return partDescriptors;
+ }
+
+
+ @Override
+ protected AttributeEditorFactory createAttributeEditorFactory() {
+ return new AttributeEditorFactory(getModel(), getTaskRepository(), getEditorSite()) {
+ @Override
+ public AbstractAttributeEditor createEditor(String type,
+ TaskAttribute taskAttribute) {
+ // TODO Auto-generated method stub
+ return super.createEditor(type, taskAttribute);
+ }
+ };
+ }
+}
diff --git a/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/github/ui/internal/GitHubTaskEditorPageFactory.java b/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/github/ui/internal/GitHubTaskEditorPageFactory.java
new file mode 100644
index 00000000..b442b494
--- /dev/null
+++ b/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/github/ui/internal/GitHubTaskEditorPageFactory.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * 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.github.ui.internal;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.mylyn.github.internal.GitHub;
+import org.eclipse.mylyn.tasks.ui.ITasksUiConstants;
+import org.eclipse.mylyn.tasks.ui.TasksUiUtil;
+import org.eclipse.mylyn.tasks.ui.editors.AbstractTaskEditorPageFactory;
+import org.eclipse.mylyn.tasks.ui.editors.TaskEditor;
+import org.eclipse.mylyn.tasks.ui.editors.TaskEditorInput;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.forms.editor.IFormPage;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+/**
+ * Editor page factory for GitHub.
+ */
+public class GitHubTaskEditorPageFactory extends AbstractTaskEditorPageFactory {
+
+ private Image gitLogoImage = null;
+
+ @Override
+ public boolean canCreatePageFor(TaskEditorInput input) {
+ if (GitHub.CONNECTOR_KIND.equals(
+ input.getTask().getConnectorKind())) {
+ return true;
+ }
+ if (TasksUiUtil.isOutgoingNewTask(input.getTask(),
+ GitHub.CONNECTOR_KIND)) {
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public Image getPageImage() {
+ if (gitLogoImage != null)
+ return gitLogoImage;
+ ImageDescriptor imageDescriptor = AbstractUIPlugin
+ .imageDescriptorFromPlugin("org.eclipse.mylyn.github.ui",
+ "images/git-logo.png");
+ if (imageDescriptor == null) {
+ return null;
+ }
+
+ return gitLogoImage = new Image(Display.getCurrent(), imageDescriptor
+ .getImageData());
+ }
+
+ @Override
+ public String getPageText() {
+ return "GitHub";
+ }
+
+ @Override
+ public int getPriority() {
+ return PRIORITY_TASK;
+ }
+
+ @Override
+ public IFormPage createPage(TaskEditor parentEditor) {
+ return new GitHubTaskEditorPage(parentEditor);
+ }
+
+ @Override
+ public String[] getConflictingIds(TaskEditorInput input) {
+ return new String[] { ITasksUiConstants.ID_PAGE_PLANNING };
+ }
+
+}
diff --git a/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/github/ui/internal/GitHubUi.java b/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/github/ui/internal/GitHubUi.java
new file mode 100644
index 00000000..6b2bdb60
--- /dev/null
+++ b/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/github/ui/internal/GitHubUi.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * 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.github.ui.internal;
+
+import org.eclipse.core.runtime.ILog;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+
+class GitHubUi {
+ public static final String BUNDLE_ID = "org.eclipse.mylyn.github.ui";
+
+ public static IStatus createStatus(int severity,String message) {
+ return new Status(severity,BUNDLE_ID,message);
+ }
+
+ public static IStatus createStatus(int severity,String message,Throwable e) {
+ return new Status(severity,BUNDLE_ID,message,e);
+ }
+
+ public static IStatus createErrorStatus(String message) {
+ return createStatus(IStatus.ERROR, message);
+ }
+
+ public static IStatus createErrorStatus(String message,Throwable t) {
+ return createStatus(IStatus.ERROR, message,t);
+ }
+
+ public static IStatus createErrorStatus(Throwable e) {
+ return createStatus(IStatus.ERROR, "Unexpected error: "+e.getMessage(),e);
+ }
+
+ public static ILog getLog() {
+ return Platform.getLog(Platform.getBundle(BUNDLE_ID));
+ }
+
+ public static void logError(String message,Throwable t) {
+ getLog().log(createErrorStatus(message, t));
+ }
+
+ public static void logError(Throwable t) {
+ getLog().log(createErrorStatus(t.getMessage(), t));
+ }
+}
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 00000000..d97f8771
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,145 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2011, Chris Aniszczyk <caniszczyk@gmail.com>
+
+ 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
+-->
+<project
+ xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <version>0.1.0-SNAPSHOT</version>
+ <prerequisites>
+ <maven>3.0</maven>
+ </prerequisites>
+
+ <groupId>org.eclipse.mylyn.github</groupId>
+ <artifactId>github-parent</artifactId>
+ <packaging>pom</packaging>
+
+ <name>Eclipse EGit Mylyn GitHub Connector Parent</name>
+
+ <licenses>
+ <license>
+ <name>Eclipse Public License v1.0</name>
+ <comments>
+ 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.htm
+ </comments>
+ </license>
+ </licenses>
+
+ <properties>
+ <tycho-version>0.10.0</tycho-version>
+ <platform-version-name>helios</platform-version-name>
+ <eclipse-site>http://download.eclipse.org/releases/${platform-version-name}</eclipse-site>
+ <orbit-site>http://download.eclipse.org/tools/orbit/downloads/drops/S20110124210048/repository</orbit-site>
+ </properties>
+
+ <modules>
+ <module>org.eclipse.mylyn.github.core</module>
+ <module>org.eclipse.mylyn.github.ui</module>
+ <module>org.eclipse.mylyn.github-feature</module>
+ <module>org.eclipse.mylyn.github-site</module>
+ </modules>
+
+ <repositories>
+ <repository>
+ <id>helios</id>
+ <layout>p2</layout>
+ <url>${eclipse-site}</url>
+ </repository>
+ <repository>
+ <id>orbit</id>
+ <layout>p2</layout>
+ <url>${orbit-site}</url>
+ </repository>
+ </repositories>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.sonatype.tycho</groupId>
+ <artifactId>tycho-maven-plugin</artifactId>
+ <version>${tycho-version}</version>
+ <extensions>true</extensions>
+ </plugin>
+ <plugin>
+ <groupId>org.sonatype.tycho</groupId>
+ <artifactId>target-platform-configuration</artifactId>
+ <version>${tycho-version}</version>
+ <configuration>
+ <resolver>p2</resolver>
+ </configuration>
+ </plugin>
+ </plugins>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.sonatype.tycho</groupId>
+ <artifactId>maven-osgi-compiler-plugin</artifactId>
+ <version>${tycho-version}</version>
+ <configuration>
+ <encoding>UTF-8</encoding>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-resources-plugin</artifactId>
+ <version>2.4.1</version>
+ <configuration>
+ <encoding>UTF-8</encoding>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.sonatype.tycho</groupId>
+ <artifactId>target-platform-configuration</artifactId>
+ <version>${tycho-version}</version>
+ <configuration>
+ <resolver>p2</resolver>
+ <pomDependencies>consider</pomDependencies>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ <sourceDirectory>src/</sourceDirectory>
+ </build>
+
+<profiles>
+ <profile>
+ <id>platform-helios</id>
+ <activation>
+ <property>
+ <name>platform-version-name</name>
+ <value>helios</value>
+ </property>
+ </activation>
+ <properties>
+ <eclipse-site>http://download.eclipse.org/releases/helios</eclipse-site>
+ <platform-version>[3.6,3.7)</platform-version>
+ </properties>
+ </profile>
+ <profile>
+ <id>platform-indigo</id>
+ <activation>
+ <property>
+ <name>platform-version-name</name>
+ <value>indigo</value>
+ </property>
+ </activation>
+ <properties>
+ <eclipse-site>http://download.eclipse.org/releases/indigo</eclipse-site>
+ <platform-version>[3.7,3.8)</platform-version>
+ </properties>
+ </profile>
+ </profiles>
+</project>

Back to the top