Compare commits

..

2 Commits

Author SHA1 Message Date
François TERROT 9322d65b8b
Deploy GPG public signature file.
Signed-off-by: François TERROT <fterrot@april.org>
2021-04-18 11:58:11 +02:00
fterrot 80aa91908b Merge pull request 'Decision is to use MIT License' (#3) from development into main
Reviewed-on: #3
2021-03-06 19:14:47 +01:00
96 changed files with 37 additions and 4179 deletions

5
.gitignore vendored
View File

@ -21,8 +21,3 @@
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
signature.conf
secret.txt
.sign.conf

6
.gitmodules vendored
View File

@ -1,6 +0,0 @@
[submodule "io.gitea.mylyn.updatesite"]
path = io.gitea.mylyn.updatesite
url = https://forge.chapril.org/gitea/mylyn-gitea-updatesite.git
[submodule "java.gitea.api"]
path = java.gitea.api
url = https://forge.chapril.org/gitea/java.gitea.api.git

View File

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>mylyn-gitea</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.python.pydev.PyDevBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.python.pydev.pythonNature</nature>
</natures>
</projectDescription>

View File

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?eclipse-pydev version="1.0"?><pydev_project>
<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python interpreter</pydev_property>
</pydev_project>

View File

@ -1,58 +0,0 @@
#!/usr/bin/env bash
#
# Mylyn Gitea - Signature tools parameters
#
# THIS FILE SHALL NEVER AND EVER BE COMMITED ONCE FILLED
#
# ==========================================================================
# jarsign.sh parameters
# ==========================================================================
#
# JARSIGN - Uncomment the next to sign with java key
#
#JARSIGN=1
#
# JAVA_HOME - required for keytool Optional if already set)
#
[ -z "${JAVA_HOME}"] && JAVA_HOME=/usr/lib/jvm/java-11-openjdk-adm64
#
# KEY_STORE - Java Key store file : keytool -keystore option, keytool default is $HOME/.keytool
#
KEYSTORE=
#
# STOREPASS - Java key store password : keytool -storepass option, default is "changeit"
#
STOREPASS=
#
# KEYALIAS - Java Key alias : keytool -alias options
#
KEYALIAS=
#
# KEYPASS - Java Key password : keytool
#
KEYPASS=
# ==========================================================================
# gpgsign.sh
# ==========================================================================
#
# GPGSIGN - Uncomment next line to sign with GPG Key
#
GPGSIGN=1
#
# GPGKEY - GPG Key identifier
#
GPGKEY=
#
# GPGPASS - GPG Key pass
#
GPGPASS=

View File

@ -1,40 +1,34 @@
# mylyn-gitea
Mylyn/Gitea Tasks Connector : Gitea's issues management for Eclipse/Mylyn.
Gitea Mylyn Connector : Gitea Issues management for Eclipse/Mylyn.
This Mylyn connector will allow you to connect Mylyn to a Gitea's instance (self hosted or not) in order to manage your issues from your local Eclipse instance.
The update site for the Mylyn/Gitea Tasks Connector plug-in is https://teilginn.github.io/mylyn-gitea-updatesite/.
This Mylyn connector will allow you to connect Mylyn to a Gitea instance (self hosted or not) in order to manage your issues on Gitea with your local Eclipse instance.
## Thanks and Credits
I want to thanks and credit:
* pweingardt for the "Mylyn Gilab Connector" https://github.com/pweingardt/mylyn-gitlab, the "Mylyn Gitlab Connector" which helps me in my initial plug-ins setup.
* zeripath for the "Java Gitea API" https://github.com/zeripath/java-gitea-api , I used first to communicate with Gitea's instance before facing ssl and JDK 11 compliance issues.
* pweingardt for the "Mylyn Gilab Connector" https://github.com/pweingardt/mylyn-gitlab, the "Mylyn Gitea Connector" which helps me in my initial plugin setup.
* zeripath for the "Java Gitea API" https://github.com/zeripath/java-gitea-api , I used first to communicate with Gitea instance before facing ssl and JDK 11 compliance issues.
## Changes
* 08.02.2021 - I'm currently working to make the connector working, resolving package and installation issues (plug-ins crash on eclipse start due to missing class Exception), then I will debug basic features (repository connectorion ...) before I will upload first code and binaries.
* 28.02.2021 - First connector version is working in debug in front of https://forge.chapril.org. I still have maven/jdk 11 generation issue. So I switch to a newly generated "Java Gitea API", OpenAPI based.
* 08.02.2021 - I'm currently working to make the connector working, resolving package and installation issues (plugins crash on eclipse start due to missing class Exception), then I will debug basic features (repository connectorion ...) before I will upload first code and binaries.
* 28.02.2021 - First connector version is working in debug in front og https://forge.chapril.org. I still have maven/jdk 11 generation issue. So I switch to a newly generated "Java Gitea API", OpenAPI based.
## Planned Features
### Version 0.1.x - prove of concept
- [ ] use basic (user,password) or token authentication (preferred)
- [ ] list and query for issues
- [ ] handles issues on a repository basis
- [ ] installation though update site
* use basic (user,password) or token authentication (preferred)
* list and query for issues
* handles issues on a repository basis
### Planned features
- [ ] edit issue - add comment on issues
- [ ] edit issue - close/reopen issue
- [ ] edit issue - change assignee list, labels, project, milestone
- [ ] create issue
- [ ] enhance query hmi - labels selection per list
* edit issue - add comment on issues
* edit issue - close/reopen issue
* edit issue - change assignee list, labels, project, milestone
* create issue
* enhance query hmi - labels selection per list
### Missing features
@ -42,26 +36,34 @@ I want to thanks and credit:
### Won't be implemented
The goal of this connector is not to replaced the Gitea's web interface, so everything which is not Issue related or not link with what may help a developer in his day-to-day issues management
like Team/Repository management and milestone management will not be implemented.
The goal of this connector is not to replaced the Gitea web interfac, so everything which is not Issue related or not link with what may help a developper in his day-to-day issue management will not be implemented, typically Team/Repository management and milestone management.
## Usage
see (Mylyn/Gitea Tasks Connector plug-ins update site)[https://forge.chapril.org/gitea/mylyn-gitea-updatesite]
1. Install the plugin obviously (you can use the https://github.com/teilginn/mylyn-gitea update site)
2. Add a new Connector, using the new Gitea Connector
1. enter the project URL (something like `http(s)://my-gitea-instance.org/myname_or_organisation/myrepository`)
2. enter your usename and your password
3. **Do not forget to check the "Save Password" checkbox**. I don't know how to create a password prompt...
3. You can now create queries and issues
If you use https instead of http (and you absolutely should use https), be sure you have a valid certificate. That means it is signed by a trusted CA. If you don't have a valid certificate (like a self signed certificate), the plugin will refuse to connect. If you want to add your CA certificate to the java keystore, you have to:
1. find the keystore which is used by your JVM (on my machine it is /etc/ssl/certs/java/cacerts)
2. find out the password for the keystore (the default is "changeit")
3. add the CA certificate to this keystore
1. On Linux, Mac OS X, or Unix systems, use `keytool -import -alias A-UNIQUE-ALIAS -file YOUR-CA.crt -keystore $PATH_TO_YOUR_KEYSTORE` (root permissions may be necessary)
2. On Windows, in an Administrator Command Prompt use `"%PROGRAMFILES%\java\jre7\bin\keytool" -import -alias A-UNIQUE-ALIAS -file YOUR-CA.cer -keystore "%PROGRAMFILES%\Java\jre7\lib\security\cacerts"`
I don't kown if I will introduce the option to ignore certificate errors. It is not a good way to do those kind of things, especially as it's now not so difficult to get a valid certificate for self hosted services thanks to Let's Encrypt.
## Known issues/Limitations
* [Known issues](https://github.com/teilginn/mylyn-gitea/issues?q=is%3Aopen+is%3Aissue)
* [known limitations](https://github.com/teilginn/mylyn-gitea/labels/known_limitation)
## Report an issue
To avoid any account management activity, issues tracker is handled at [Github](https://github.com/teilginn/mylyn-gitea/issues).
Feel free to open issues to report bugs or request new features.
* List of Eclipse versions plugins is compliant with, is to be defined. It will be test with the version of Eclipse I'm using (Linux/Windows) in front of an always up to date gitea instance.
* Version 1.x will only support read acess and queries, we have may to wait the Version 2.x to create and modify issues.
* If you created a new milestone or added a new project member via the web interface, you have to update the repository configuration, so that the connector reloads the project members and milestones. Right click on the Gitea repository in the Task repositories view and click on "Update Repository Configuration".
* Offline mode does not work.
* Out of the box support for valid certificates only.
* Ssl connection issue with some servers

View File

@ -1,278 +0,0 @@
#!/usr/bin/env python3
"""
gpgsign.py - Helper to "GPG" sign Mylyn Gitea Release files
Limitations:
Too many limitations to be listed here.
Usage:
1. Set GPG configuration in signature.conf file
2. run gpgsign.py
Caveats:
Must be run AFTER jarsign.sh to avoid gpg signature modification
Generated files are similar to maven-gpg-plugin ones (default configuration)
"""
import logging
import subprocess
from pathlib import Path, PurePath
from dataclasses import dataclass
from typing import Tuple
from enum import Enum
import configparser
# pylint: disable=logging-fstring-interpolation, line-too-long
__PROG__ = "gpgsign"
WORKSPACEDIR = Path(__file__).parent.parent # <workspace>/bin/gpgsign.py
ASC_DIRECTORY = "gpg"
class GPGLockMode(Enum):
ONCE = "once"
MULTIPLE = "multiple"
NEVER = "never"
@dataclass
class GPGConfiguration:
keyname: str
passphrase: str = ""
verbose:bool = False
skip: bool = False
interactive : bool = True
executable : Path = None
use_agent: bool = False
home_dir: str = ""
secret_keyring : str = ""
public_keyring : str = ""
lock_mode : GPGLockMode = None # gpg lock mode, could be : None -> lock mode not used, "once", "multiple", "never" => SyntaxError
args = "" # list, of additional arguments as list or tuple or comma separated as string
@dataclass
class Configuration:
gpg: GPGConfiguration
class GPGSigner:
"""Compute signature.
"""
SIGNATURE_EXTENSION : str = ".asc"
def __init__(self, gpg:GPGConfiguration , output_dir: Path ):
self.output_dir = output_dir
self.gpg = gpg
self.interactive = False
def generate_signature_for_file(self, file: Path, signature: Path) -> int:
"""Generate a detached signature file for provided file.
Args:
file: Path of file to be signed
signature: Path of file where the signature will be written.
Returns:
return code of signature application
"""
# Configure command line
cmd = ['gpg']
if self.gpg.executable:
cmd = [str(self.gpg.executable)]
if self.gpg.args:
if isinstance(self.gpg.args, (list, tuple)):
cmd += self.gpg.args
else:
cmd += self.gpg.args.split(",")
if self.gpg.verbose:
cmd.append("-v")
if self.gpg.home_dir:
cmd += [ "--homedir", self.gpg.home_dir]
cmd.append(f"--{'' if self.gpg.use_agent else 'no-'}use-agent")
# required for subprocess input:
# 1. to disable input when self.gpg.passphrase is "" (run is waiting None)
# 2. run is waiting bytes for input
in_passphrase=None
if self.gpg.passphrase:
cmd += ["--batch", "--passphrase-fd", "0"]
in_passphrase = bytes(self.gpg.passphrase,"UTF-8")
if self.gpg.keyname:
cmd += ["--local-user", self.gpg.keyname]
cmd.append("--armor")
cmd.append("--detach-sign")
if not self.gpg.interactive:
cmd.append("--no-tty") #
if self.gpg.secret_keyring or self.gpg.public_keyring:
cmd.append("--no-default-keyring")
if self.gpg.secret_keyring:
cmd += ["--secret-keyring", self.gpg.secret_keyring]
if self.gpg.public_keyring:
cmd +=[ "--keyring", self.gpg.public_keyring]
if self.gpg.lock_mode:
cmd.append(f"--lock-{self.gpg.lock_mode}")
cmd += ["--output", str(signature)]
cmd.append(str(file))
logging.debug(f"GPGSigner> {cmd}")
# Execute command line
completed_process = subprocess.run(cmd, input=in_passphrase)
logging.debug(str(completed_process))
return completed_process.returncode
def generate_signature_for_artifact (self, file: Path) -> int:
"""Create a detached signature file for the provided file
managing valide signature file destination.
"""
# Setup file and directory for signature
signature = file.with_suffix ( file.suffix + GPGSigner.SIGNATURE_EXTENSION)
if self.output_dir:
# ugly but working way to get common parts
for i,part in enumerate(signature.parts):
try:
if part == self.output_dir.parts[i]:
continue
except IndexError: # output_dir is smaller than signature
pass
break
common_dir = Path(*signature.parts[:i])
if common_dir:
signature = self.output_dir / signature.relative_to(common_dir)
# Create destination directory
logging.debug(f"GPGSigner> artifact:{file}")
logging.debug(f"GPGSigner> signature:{signature}")
if not signature.parent.is_dir():
signature.parent.mkdir(parents=True, exist_ok=True)
if signature.exists():
signature.unlink()
# Generate signature file
return self.generate_signature_for_file(file, signature)
def get_passphrase(self):
return ""
class Project:
""" Project as list of artifacts """
ARTIFACTS_EXTENSIONS = ('.jar', '.xml', '.md')
DEFAULT_EXCLUDES = ('.asc', ".gpg", ".sig", ".git", ".externalToolBuilders")
def __init__(self, projectdir):
self.projectdir = projectdir
logging.debug(f"Project> {projectdir}")
@property
def name(self):
return self.projectdir.name
def get_attached_artifacts(self, iter_in_dir :Path = None) -> Path:
"""
Yields:
artifact
"""
iter_in_dir = self.projectdir if iter_in_dir is None else iter_in_dir
for e in iter_in_dir.iterdir():
if e.is_dir() :
logging.debug(f"Project.get_artifacts> entering in {str(e)}")
yield from self.get_attached_artifacts(e)
if e.suffix.lower() in Project.DEFAULT_EXCLUDES:
logging.debug(f"Project.get_artifacts> excluding {e}")
continue
if e.suffix.lower() in Project.ARTIFACTS_EXTENSIONS or e.name == 'LICENSE':
logging.debug(f"Project.get_artifacts> {e}")
yield e
class GPGSignAttached:
"""Sign artifacts attached to the project."""
def __init__(self, project: Project, config: Configuration):
self.project = project
self.config = config
def execute(self):
if self.config.gpg.skip:
logging.warning(f"GPGSign> Skipping GPG Signature for {self.project.name}")
return
logging.info(f"GPGSign> Signing {self.project.name} artifacts")
signer = GPGSigner(config.gpg, self.project.projectdir / ASC_DIRECTORY)
for artifact in self.project.get_attached_artifacts():
signer.generate_signature_for_artifact(artifact)
if __name__ == "__main__":
# pylint: disable=invalid-name
import argparse
import sys
import os
# backup working directory
OLDPWD = os.path.curdir
# Configure the command line arguments parser
parser = argparse.ArgumentParser(prog=__PROG__,
description=__PROG__ + " Sign (Java + GPG) updatesite artifacts",
prefix_chars="-+")
parser.add_argument("-c", "--config-file",
help="Configuration file (default <workspacedir>/signature.conf",
dest="config_file",
default=str((WORKSPACEDIR / "signature.conf").absolute()),
required=False)
parser.add_argument("-x",
help="Active 'debug' level for logging",
dest='debug',
action='store_true',
default=False,
required=False)
# Parse the command line
args = parser.parse_args()
# Configuration file
config_ini = configparser.ConfigParser()
config_ini.read(args.config_file)
config = Configuration(
gpg=GPGConfiguration(
skip = config_ini.getboolean('GPG','skip', fallback=True),
verbose = config_ini.getboolean('GPG','verbose', fallback=False),
keyname = config_ini.get('GPG', 'keyname', fallback=None),
passphrase= config_ini.get('GPG','passphrase', fallback=None),
)
)
# Configure logging
# see https://docs.python.org/2/howto/logging.html
logging.basicConfig(
format='%(asctime)s:%(levelname)s:%(message)s' if args.debug else '%(levelname)s:%(message)s',
level=logging.DEBUG if args.debug else logging.INFO)
siteupdate_project = Project(WORKSPACEDIR / "io.gitea.mylyn.updatesite")
GPGSignAttached(siteupdate_project, config).execute()
sys.exit(0)
# vim: tabstop=4:shiftwidth=4:expandtab

View File

@ -1,55 +0,0 @@
#!/usr/bin/env bash
#
# Helper script to sign Mylyn Gitea eclipse plugin
#
# Usage:
# 1. Configure the .sign.conf file
# 2. jarsign.sh [-x]
#
# Inspired from https://nirmalsasidharan.wordpress.com/2010/09/04/signing_eclipse_plugins/
#
# set debug
case "x$1" in "x-x" ) shift ; set -x ;; esac
#
# Sign all "not already signed" jar in a directory
# usage: jarsign_dir <directory>
#
jarsign_dir() {
for jarfile in ${1}/*.jar ; do
[ -e "$jarfile" ] || continue
unset result
case ${result:-$(jarsigner -verify -verbose ${opt_keystore} ${opt_storepass} ${opt_alias} ${jarfile} ${KEYALIAS} | egrep 'jar is unsigned|jar verified')} in
'jar is unsigned.' )
jarsigner ${opt_keystore} ${opt_storepass} -verbose ${opt_alias} ${jarfile} ${KEYALIAS} ;;
'jar verified.' )
echo "$jarfile already signed"
;;
* )
echo "***ERROR Raised by ${jarfile} signature verification..."
echo $result
;;
esac
done
}
WORKSPACEDIR=$(realpath "$(dirname $0)/.." )
SIGNPARAMS=${WORKSPACEDIR}/.sign.conf
if [ -x $SIGNPARAMS ] ; then
source $SIGNPARAMS
else
echo "Missing configuration file" && exit 1
fi
if (( $JARSIGN == 1)) ; then
[ -f "${KEYSTORE}" ] && opt_keystore="-keystore ${KEYSTORE}"
[ -n "${STOREPASS}" ] && opt_storepass="-storepass ${STOREPASS}"
jarsign_dir ${WORKSPACEDIR}/io.gitea.mylyn.updatesite
jarsign_dir ${WORKSPACEDIR}/io.gitea.mylyn.updatesite/features
jarsign_dir ${WORKSPACEDIR}/io.gitea.mylyn.updatesite/plugins
fi

View File

@ -1,28 +0,0 @@
<?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/JavaSE-1.8">
<attributes>
<attribute name="module" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry exported="true" kind="lib" path="lib/annotations-13.0.jar"/>
<classpathentry exported="true" kind="lib" path="lib/commons-lang3-3.11.jar"/>
<classpathentry exported="true" kind="lib" path="lib/gson-2.8.6.jar"/>
<classpathentry exported="true" kind="lib" path="lib/gson-fire-1.8.5.jar"/>
<classpathentry exported="true" kind="lib" path="lib/hamcrest-core-1.3.jar"/>
<classpathentry exported="true" kind="lib" path="lib/java.gitea.api-1.13.0.jar"/>
<classpathentry exported="true" kind="lib" path="lib/javax.annotation-api-1.3.2.jar"/>
<classpathentry exported="true" kind="lib" path="lib/jsr305-3.0.2.jar"/>
<classpathentry exported="true" kind="lib" path="lib/junit-4.13.1.jar"/>
<classpathentry exported="true" kind="lib" path="lib/kotlin-stdlib-1.4.10.jar"/>
<classpathentry exported="true" kind="lib" path="lib/kotlin-stdlib-common-1.4.0.jar"/>
<classpathentry exported="true" kind="lib" path="lib/kotlin-stdlib-jdk7-1.4.10.jar"/>
<classpathentry exported="true" kind="lib" path="lib/kotlin-stdlib-jdk8-1.4.10.jar"/>
<classpathentry exported="true" kind="lib" path="lib/logging-interceptor-4.9.1.jar"/>
<classpathentry exported="true" kind="lib" path="lib/okhttp-4.9.1.jar"/>
<classpathentry exported="true" kind="lib" path="lib/okio-2.8.0.jar"/>
<classpathentry exported="true" kind="lib" path="lib/swagger-annotations-1.6.2.jar"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.ant.AntBuilderLaunchConfigurationType">
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_BUILDER_ENABLED" value="false"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_DISABLED_BUILDER" value="org.eclipse.pde.api.tools.apiAnalysisBuilder"/>
<mapAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS"/>
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
</launchConfiguration>

View File

@ -1,24 +0,0 @@
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
/bin/

View File

@ -1,38 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>io.gitea.mylyn.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>
<buildCommand>
<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
<triggers>full,incremental,</triggers>
<arguments>
<dictionary>
<key>LaunchConfigHandle</key>
<value>&lt;project&gt;/.externalToolBuilders/org.eclipse.pde.api.tools.apiAnalysisBuilder.launch</value>
</dictionary>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@ -1,15 +0,0 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.8
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.enablePreviewFeatures=disabled
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
org.eclipse.jdt.core.compiler.release=disabled
org.eclipse.jdt.core.compiler.source=1.8

View File

@ -1,2 +0,0 @@
eclipse.preferences.version=1
org.eclipse.ltk.core.refactoring.enable.project.refactoring.history=false

View File

@ -1,19 +0,0 @@
MIT License Copyright (c) 2021 F.Terrot
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,37 +0,0 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Mylyn Gitea Connector Core
Bundle-SymbolicName: io.gitea.mylyn.core;singleton:=true
Bundle-Version: 0.3.1
Bundle-Activator: io.gitea.mylyn.core.GiteaPluginCore
Bundle-Vendor: io.gitea
Require-Bundle: org.eclipse.core.runtime,
org.eclipse.mylyn.tasks.core;bundle-version="[3.8.0,4.0.0)",
org.eclipse.mylyn.tasks.ui,
org.eclipse.mylyn.commons.net;bundle-version="[3.8.0,4.0.0)"
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Automatic-Module-Name: io.gitea.mylyn.core
Bundle-ActivationPolicy: lazy
Export-Package: io.gitea,
io.gitea.api,
io.gitea.model,
io.gitea.mylyn.core,
io.gitea.mylyn.core.exceptions
Bundle-ClassPath: lib/annotations-13.0.jar,
lib/commons-lang3-3.11.jar,
lib/gson-2.8.6.jar,
lib/gson-fire-1.8.5.jar,
lib/hamcrest-core-1.3.jar,
lib/java.gitea.api-1.13.0.jar,
lib/javax.annotation-api-1.3.2.jar,
lib/jsr305-3.0.2.jar,
lib/junit-4.13.1.jar,
lib/kotlin-stdlib-1.4.10.jar,
lib/kotlin-stdlib-common-1.4.0.jar,
lib/kotlin-stdlib-jdk7-1.4.10.jar,
lib/kotlin-stdlib-jdk8-1.4.10.jar,
lib/logging-interceptor-4.9.1.jar,
lib/okhttp-4.9.1.jar,
lib/okio-2.8.0.jar,
lib/swagger-annotations-1.6.2.jar,
.

View File

@ -1,22 +0,0 @@
source.. = src/
bin.includes = META-INF/,\
.,\
plugin.xml,\
lib/annotations-13.0.jar,\
lib/commons-lang3-3.11.jar,\
lib/gson-2.8.6.jar,\
lib/gson-fire-1.8.5.jar,\
lib/hamcrest-core-1.3.jar,\
lib/java.gitea.api-1.13.0.jar,\
lib/javax.annotation-api-1.3.2.jar,\
lib/jsr305-3.0.2.jar,\
lib/junit-4.13.1.jar,\
lib/kotlin-stdlib-1.4.10.jar,\
lib/kotlin-stdlib-common-1.4.0.jar,\
lib/kotlin-stdlib-jdk7-1.4.10.jar,\
lib/kotlin-stdlib-jdk8-1.4.10.jar,\
lib/logging-interceptor-4.9.1.jar,\
lib/okhttp-4.9.1.jar,\
lib/okio-2.8.0.jar,\
lib/swagger-annotations-1.6.2.jar
jre.compilation.profile = JavaSE-1.8

View File

@ -1,14 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>
<extension
id="io.gitea.mylyn.core"
name="%repository.name"
point="org.eclipse.mylyn.tasks.ui.repositories">
<connectorCore
class="io.gitea.mylyn.core.GiteaConnector"
id="io.gitea.mylyn.core"
name="Gitea Connector"/>
</extension>
</plugin>

View File

@ -1,52 +0,0 @@
// Copyright (c) 2021, Fr.Terrot. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package io.gitea.api;
import io.gitea.ApiClient;
/** Version of the Gitea API to communicate with. */
public enum ApiVersion {
V1;
/** API namespace to be used in URL. */
public String getApiNamespace() {
return "/api/" + name().toLowerCase();
}
/**
* Build the client Api base path (URL) adapted to the selected Api version.
*
* @param hostUrl Uri of the server hosting the Gitea service (with protocol,
* without trailing /).
*
* @return Url to be use to communication with Gitea
*
* @implNote No check is done on the validity of hostUrl
*/
public String getBasePath(String hostUrl) {
return hostUrl + getApiNamespace();
}
/**
* Set the client Api base path adapted to the selected Api version.
*
* @param apiClient Gitea Api client object to configure.
* @param hostUrl Uri of the server hosting the Gitea service (with protocol,
* without trailing /).
*
* @implNote No check is done on the validity of hostUrl
*
* <pre>
* {@code
* ApiClient defaultConfiguration = Configuration.getDefaultApiClient();
* String host = "https://forge.chapril.org" ;
* ApiVersion.V1.setBasePath(defaultConfiguration, host);
* }
* </pre>
*/
public void setBasePath(ApiClient apiClient, String hostUrl) {
apiClient.setBasePath(hostUrl + getApiNamespace());
}
}

View File

@ -1,6 +0,0 @@
// Copyright (c) 2021, Fr.Terrot. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
/** <i>local</i> extension of the generated Java Gitea API "io.gitea.api" package. */
package io.gitea.api;

View File

@ -1,51 +0,0 @@
// Copyright (c) 2021, Fr.Terrot. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package io.gitea.model;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.OffsetDateTime;
import java.util.Date;
/** Handles Gitea to Mylyn date conversions */
public class GiteaDateTimeUtils {
private static final String dateFormat_from_LocalDateTime = "yyyy-MM-dd'T'HH:mm:ss"; //$NON-NLS-1$
private static final String dateFormat_from_Offset = "yyyy-MM-dd'T'HH:mm:ssX"; //$NON-NLS-1$
private static final String dateFormat_1 = "yyyy-MM-dd HH:mm:ss"; //$NON-NLS-1$
private static final String dateFormat_2 = "yyyy-MM-dd HH:mm"; //$NON-NLS-1$
private static final String dateFormat_3 = "yyyy-MM-dd"; //$NON-NLS-1$
private static final String dateFormat_1_TimeZone = "yyyy-MM-dd HH:mm:ss Z"; //$NON-NLS-1$
private static final String dateFormat_2_TimeZone = "yyyy-MM-dd HH:mm z"; //$NON-NLS-1$
private static final String dateFormat_3_TimeZone = "yyyy-MM-dd z"; //$NON-NLS-1$
// Order is significant
private static final String[] dateFormats = { dateFormat_from_Offset, dateFormat_from_LocalDateTime,
dateFormat_1_TimeZone, dateFormat_1, dateFormat_2_TimeZone, dateFormat_2, dateFormat_3_TimeZone,
dateFormat_3 };
/**
* Note: Date formatter constructed within method for thread safety
*/
public static final Date parseDate(String dateString) {
for (String format : dateFormats) {
try {
SimpleDateFormat simpleFormatter = new SimpleDateFormat(format);
return simpleFormatter.parse(dateString);
} catch (ParseException e) {
} catch (NumberFormatException e) {
}
}
return null;
}
/** Convert OffsetDateTime to Date */
public static final Date toDate(OffsetDateTime offset) {
return parseDate(offset.toString()); // FIXME: use better Offset to date convertion
}
}

View File

@ -1,129 +0,0 @@
// Copyright (c) 2021, Fr.Terrot. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package io.gitea.model;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
import org.eclipse.mylyn.tasks.core.ITask.PriorityLevel;
import io.gitea.StringUtil;
/**
* Extract Mylyn PriorityLevel from Issue label
*
*/
public enum GiteaPriorityLevel {
HIGHEST(PriorityLevel.P1), HIGH(PriorityLevel.P2), MIDDLE(PriorityLevel.P3), LOW(PriorityLevel.P4),
LOWEST(PriorityLevel.P5);
private PriorityLevel level;
/**
* Constructor.
*
* @private
*/
private GiteaPriorityLevel(PriorityLevel p) {
this.level = p;
}
/**
* Get GiteaPriority level.
*
* @return PriorityLevel
*/
public PriorityLevel getLevel() {
return level;
}
/**
* GiteaPriority level as String
*
* {@code giteaPriority.ToString() <=> giteaPriority.GetLevel().toString()}
*
* To Get GiteaPriority as String use standard Enum name() API.
*
* @{code HIGHEST.toString() -> "P1" HIGHEST.name() -> "HIGHEST"}
*/
public String toString() {
return level.toString();
}
/**
* Get GiteaPriority from PriorityLevel
*
* @param level
* @return
* @throws IllegalArgumentException
*/
public static GiteaPriorityLevel getPriority(PriorityLevel level) throws IllegalArgumentException {
return Arrays.stream(values()).filter(v -> v.level.equals(level)).findFirst()
.orElseThrow(() -> new IllegalArgumentException("unknown priority level:" + level.toString()));
}
// P1 .. P5
private static String valueRegex = "(?::?priority:)?(p[1-5])";
private static Pattern valuePattern = Pattern.compile(valueRegex, Pattern.CASE_INSENSITIVE);
// Xtra very_normal is supported, surprising but not a big issue, kept it regexp
// 'simple'
private static String alternativeRegex = "(?::?priority:)?(?:very_?)?(high|low|normal)";
private static Pattern alternativePattern = Pattern.compile(alternativeRegex, Pattern.CASE_INSENSITIVE);
private static String priorityRegex = "(?::?priority:)?(highest|middle|low|lowest)";
private static Pattern priorityPattern = Pattern.compile(priorityRegex, Pattern.CASE_INSENSITIVE);
private static String allPrioritiesRegex = "((?::?priority:)?(?:p[1-5]|(?:high|low)(?:est)?|(?:very_?)(?:high|low)|normal|middle))";
private static Pattern allPrioritiesPattern = Pattern.compile(allPrioritiesRegex, Pattern.CASE_INSENSITIVE);
/**
* Return the Priority from labels value.
*
* @param labels as string
*
* @return found priority or MIDDLE if no priority found.
*/
public static GiteaPriorityLevel getPriority(String labels) {
Matcher m = priorityPattern.matcher(labels);
if (m.find()) {
return GiteaPriorityLevel.valueOf(m.group(1).toUpperCase());
}
m = valuePattern.matcher(labels);
if (m.find()) {
return GiteaPriorityLevel.getPriority(PriorityLevel.valueOf(m.group(1).toUpperCase()));
}
m = alternativePattern.matcher(labels);
if (m.find()) {
switch (m.group(1).toLowerCase()) {
case "high":
return GiteaPriorityLevel.HIGHEST;
case "normal":
return GiteaPriorityLevel.MIDDLE;
case "low":
return GiteaPriorityLevel.LOWEST;
default:
}
}
return GiteaPriorityLevel.MIDDLE;
}
/** Extract for the labels list the ones which are priority level.
*
*/
public static List<String> getAllPriorityLabels(List<String> labels) {
List<String> priorities = new ArrayList<String>();
labels.forEach((label) -> {
if (allPrioritiesPattern.matcher(label).find()) priorities.add(label);
});
return priorities;
}
}

View File

@ -1,18 +0,0 @@
// Copyright (c) 2021, Fr.Terrot. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package io.gitea.model;
public class GiteaUser {
/** Name is user FullName or Login when FullName is empty. */
static public String getName(User user) {
String name = "";
if (user != null) {
name = user.getFullName();
if (name.isBlank() || name.isEmpty())
name = user.getLogin();
}
return name;
}
}

View File

@ -1,48 +0,0 @@
// Copyright (c) 2021, Fr.Terrot. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package io.gitea.model;
public enum IssueAction {
CLOSE("close"),
LEAVE("leave"),
REOPEN("reopen");
IssueAction(String label) {
this.label = label;
}
public final String label;
public static IssueAction getEnum(String other) {
if ((other == null)||(other.isBlank()) || (other.isEmpty()))
return LEAVE;
for (IssueAction a : IssueAction.values())
if (a.equals(other)) return a;
throw new IllegalArgumentException(other + " is not a IssueAction value");
}
/**Compute targeted state when apply action as transition to a state.
*
* [from State: OPENED] --> Action: CLOSE --> [to State:CLOSED]
* [from State: CLOSED] --> Action: REOPEN --> [to State: OPENDED]
* All other cases have no impact on State.
*
* @param fromState
* @return Targeted state as IssueState.
*/
public IssueState toState(IssueState fromState) {
if ((this == CLOSE) && (fromState == IssueState.STATE_OPENED)) return IssueState.STATE_CLOSED;
if ((this == REOPEN) && (fromState == IssueState.STATE_CLOSED)) return IssueState.STATE_OPENED;
return fromState;
}
static public IssueState toState(IssueState from, IssueAction onAction) {
return onAction.toState(from);
}
public boolean equals(IssueAction arg0) {
return this.label.equals(arg0.toString());
}
public boolean equals(String arg0) {
return this.label.equals(arg0);
}
}

View File

@ -1,72 +0,0 @@
// Copyright (c) 2021, Fr.Terrot. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package io.gitea.model;
import io.gitea.model.Issue;
/** Gitea Issue State
*
* Note: Constructor is private to limit IssueState to predefined ones.
*/
public enum IssueState {
STATE_ANY("all"),STATE_OPENED("open"),STATE_CLOSED("closed");
private String value;
private IssueState(String value) {
this.value = value;
}
public static IssueState getEnum(String value) {
for(IssueState s: IssueState.values()) {
if (s.equals(value)) return s;
}
throw new IllegalArgumentException(value + " is not a IssueState value");
}
public String toString() {
return this.value;
}
public boolean equals(IssueState arg0) {
return this.value.equals(arg0.toString());
}
public boolean equals(String arg0) {
return this.value.equals(arg0);
}
/**Check if an issue is "open"
*
* @param issue Gitea Issue
* @return True if the state is "open".
*
* @apiNote isOpen() is not the opposite of isClose()
* "isOpen() == false" doesn't means that "isClose() == true"
*
*/
public static boolean isOpen(Issue issue) {
return IssueState.isOpen(issue.getState());
}
/**Check if a status value is "open".
*
* @param status Status value as String
*/
public static boolean isOpen(String value) {
return STATE_OPENED.equals(value);
}
/**Check if the issue is "closed".
*
* @param issue GItea Issue
* @return True if the issue state is "closed"
*/
public static boolean isClosed(Issue issue) {
return IssueState.isClosed(issue.getState());
}
/**Check if a status value is "closed".
*
* @param status Status value as String
*/
public static boolean isClosed(String value) {
return STATE_CLOSED.equals(value);
}
}

View File

@ -1,53 +0,0 @@
// Copyright (c) 2021, Fr.Terrot. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package io.gitea.model;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
public enum IssueType {
EPIC("epic"), STORY("story"), FEATURE("feature"), BUG("bug"), TASK("task"), ENHANCEMENT("enhancement"),
QUESTION("question"), IMPEDIMENT("impediment");
static public final Pattern PATTERN = Pattern.compile("(" + StringUtils.join(IssueType.values(), "|") + ")");
private String value;
private IssueType(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public String toString() {
return value;
}
public boolean equals(IssueType arg0) {
return this.value.contentEquals(arg0.getValue());
}
public boolean equals(String arg0) {
return this.value.equals(arg0);
}
public static boolean contains(String value) {
for (IssueType t : IssueType.values()) {
if (t.equals(value))
return true;
}
return false;
}
public static List<String> getAllIssueType(List<String> labels){
List<String> types = new ArrayList<String>();
labels.forEach((label) -> { if (IssueType.contains(label)) types.add(label);});
return types;
}
}

View File

@ -1,6 +0,0 @@
// Copyright (c) 2021, Fr.Terrot. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
/** <i>local</i> extension of the generated Java Gitea API "io.gitea.model" package. */
package io.gitea.model;

View File

@ -1,200 +0,0 @@
// Copyright (c) 2021, Fr.Terrot. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package io.gitea.mylyn.core;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.mylyn.commons.net.AuthenticationType;
import org.eclipse.mylyn.tasks.core.TaskRepository;
import io.gitea.*;
import io.gitea.auth.*;
import io.gitea.model.*;
import io.gitea.api.UserApi;
import io.gitea.mylyn.core.exceptions.GiteaException;
import io.gitea.mylyn.core.exceptions.GiteaExceptionHandler;
import io.gitea.mylyn.core.exceptions.UnknownRepositoryException;
/**
* The ConnectionManager is a singleton that handles all GiteaConnection
* instances in a HashMap. The key in this HashMap is the URL to the Gitea
* instance constructed using a TaskRepository class.
*/
public class ConnectionManager {
/**
* The HashMap used to store all GiteaConnections
*/
private static HashMap<String, GiteaConnection> connections = new HashMap<String, GiteaConnection>();
/**
* The pattern is used to verify a ULR to a valid Gitea repository URL. group 1
* -> server including protocol (without trailing '/') group 2 ->
* repository/project path excluding potential ".git"
*
* trick: for server we are locking for any character which is not / which is
* same as looking not greedy to all character until /
*
* example: https://forge.chapril.org/gitea/mylyn-gitea.git group 1 =>
* https//forge.chapril.org group 2 => gitea/mylyn-gitea
*/
private static Pattern URLPattern = Pattern.compile("(https?://(?:[^\\/]*))/((?:.*?)/(?:[^\\/]*?))(?:\\.git)?$");
/**
* Returns the GiteaConnection for the given task repository
*
* @param repository
* @return
* @throws GiteaException
*/
static public GiteaConnection get(TaskRepository repository) throws GiteaException {
return get(repository, false);
}
/**
* Returns the GiteaConnection for the given task repository. If it fails for
* whatever reason, it returns null.
*
* @param repository
* @return
*/
static public GiteaConnection getSafe(TaskRepository repository) {
try {
return get(repository);
} catch (GiteaException e) {
return null;
}
}
/**
* Gitea connection configuration.
*/
static public ApiClient getConfiguration() {
return Configuration.getDefaultApiClient();
}
/**
* Constructs a "pseudo" URL string for the given task repository.
*
* @param repository
* @return
*/
private static String constructHash(TaskRepository repository) {
String username = repository.getCredentials(AuthenticationType.REPOSITORY).getUserName();
String password = repository.getCredentials(AuthenticationType.REPOSITORY).getPassword();
return repository.getUrl() + "?username=" + username + "&password=" + password.hashCode();
}
/**
* Validates the given task repository and returns a GiteaConnection if the task
* repository is a valid repository.
*
* @param repository
* @return
* @throws GiteaException
*/
// FIXME: redesign to limit this function to validation but not configuration
static GiteaConnection validate(TaskRepository repository) throws GiteaException {
try {
String projectPath = null;
String host = null;
// Extract host&project path from valid url
if (repository.getProperty("giteaBaseUrl").trim().length() > 0) {
host = repository.getProperty("giteaBaseUrl").trim();
if (!repository.getUrl().startsWith(host)) {
throw new GiteaException("Invalid repository URL!");
}
projectPath = repository.getUrl().replaceFirst(Matcher.quoteReplacement(host), "");
if (projectPath.startsWith("/")) {
projectPath = projectPath.substring(1);
}
} else {
Matcher matcher = URLPattern.matcher(repository.getUrl());
if (!matcher.find()) {
throw new GiteaException("Invalid Project-URL!");
}
projectPath = matcher.group(2);
host = matcher.group(1);
}
// Configure credentials
String username = repository.getCredentials(AuthenticationType.REPOSITORY).getUserName();
String password = repository.getCredentials(AuthenticationType.REPOSITORY).getPassword();
ApiClient defaultClient = Configuration.getDefaultApiClient();
defaultClient.setBasePath(GiteaConnection.apiVersion.getBasePath(host));
if (repository.getProperty("usePrivateToken") != null
&& repository.getProperty("usePrivateToken").equals("true")) {
ApiKeyAuth accessToken = (ApiKeyAuth) defaultClient.getAuthentication("AccessToken");
accessToken.setApiKey(password); // token is stored in the password field.
} else {
HttpBasicAuth basicAuth = (HttpBasicAuth) defaultClient.getAuthentication("BasicAuth");
basicAuth.setUsername(username);
basicAuth.setPassword(password);
}
// Get user related repository list
UserApi userApi = new UserApi();
List<Repository> repositories = userApi.userCurrentListRepos(0, 0);
for (Repository p : repositories) {
if (p.getFullName().equals(projectPath)) {
GiteaConnection connection = new GiteaConnection(host, p, new GiteaAttributeMapper(repository));
return connection;
}
}
// At this point the authentication was successful, but the corresponding
// repository
// could not be found! which not not occurs with Gitea.
throw new UnknownRepositoryException(projectPath);
} catch (GiteaException e) {
throw e;
} catch (Exception e) {
throw GiteaExceptionHandler.handle(e);
} catch (Error e) {
throw GiteaExceptionHandler.handle(e);
}
}
/**
* Returns a *valid* GiteaConnection, otherwise this method throws an exception.
*
* @param repository
* @param forceUpdate if true, a new GiteaConnection instance will be created,
* even if a Gitea Connection already exists for the given
* task repository
* @return connection
* @throws GiteaException
*/
static GiteaConnection get(TaskRepository repository, boolean forceUpdate) throws GiteaException {
try {
String hash = constructHash(repository);
if (connections.containsKey(hash) && !forceUpdate) {
return connections.get(hash);
} else {
GiteaConnection connection = validate(repository);
connections.put(hash, connection);
connection.update();
return connection;
}
} catch (GiteaException e) {
throw e;
} catch (Exception e) {
throw GiteaExceptionHandler.handle(e);
} catch (Error e) {
throw GiteaExceptionHandler.handle(e);
}
}
}

View File

@ -1,65 +0,0 @@
// Copyright (c) 2021, Fr.Terrot. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package io.gitea.mylyn.core;
import io.gitea.model.IssueState;
import io.gitea.model.Issue;
/**
* Represents an action that tell Gitea what to do with the issue, e.g. "close"
* will close the issue in Gitea. This wrapper is necessary.
*
*/
public enum GiteaAction {
LEAVE("leave"), CLOSE("close"), REOPEN("reopen");
/**
* The valid actions for an open issue
*/
private final static GiteaAction[] opened = { LEAVE, CLOSE };
/**
* The valid actions for a closed issue
*/
private final static GiteaAction[] closed = { LEAVE, REOPEN };
private GiteaAction(String label) {
this.label = label;
}
public final String label;
/**
* Returns all valid actions for the given issue.
*
* @param issue
* @return
*/
public static GiteaAction[] getActions(Issue issue) {
if (IssueState.isClosed(issue)) {
return closed;
} else {
return opened;
}
}
/**
* Returns the GiteaAction enum for the given action string.
*
* @param action
* @return
*/
public static GiteaAction find(String action) {
for (GiteaAction a : values()) {
if (a.label.equals(action)) {
return a;
}
}
return LEAVE;
}
}

View File

@ -1,116 +0,0 @@
// Copyright (c) 2021, Fr.Terrot. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package io.gitea.mylyn.core;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.Set;
import org.eclipse.mylyn.tasks.core.data.TaskAttribute;
public enum GiteaAttribute {
BODY("Description", TaskAttribute.DESCRIPTION, TaskAttribute.TYPE_LONG_RICH_TEXT),
TITLE("Summary", TaskAttribute.SUMMARY, TaskAttribute.TYPE_SHORT_RICH_TEXT),
STATUS("Status", TaskAttribute.STATUS, TaskAttribute.TYPE_SHORT_TEXT, GiteaFlag.ATTRIBUTE, GiteaFlag.READ_ONLY),
LABELS("Labels", "io.gitea.mylyn.issue.labels", TaskAttribute.TYPE_LONG_TEXT, GiteaFlag.ATTRIBUTE),
UPDATED("Updated", TaskAttribute.DATE_MODIFICATION, TaskAttribute.TYPE_DATETIME, GiteaFlag.READ_ONLY,
GiteaFlag.ATTRIBUTE),
CREATED("Created", TaskAttribute.DATE_CREATION, TaskAttribute.TYPE_DATETIME, GiteaFlag.READ_ONLY,
GiteaFlag.ATTRIBUTE),
COMPLETED("Completed", TaskAttribute.DATE_COMPLETION, TaskAttribute.TYPE_DATETIME, GiteaFlag.READ_ONLY),
DUE_DATE("Due Date", TaskAttribute.DATE_DUE, TaskAttribute.TYPE_DATE, GiteaFlag.ATTRIBUTE),
AUTHOR("Author", TaskAttribute.USER_REPORTER, TaskAttribute.TYPE_PERSON, GiteaFlag.READ_ONLY, GiteaFlag.ATTRIBUTE),
PROJECT("Project", TaskAttribute.PRODUCT, TaskAttribute.TYPE_SHORT_TEXT, GiteaFlag.READ_ONLY, GiteaFlag.ATTRIBUTE),
ASSIGNEE("Assignee", TaskAttribute.USER_ASSIGNED, TaskAttribute.TYPE_PERSON, GiteaFlag.ATTRIBUTE),
MILESTONE("Milestone", "io.gitea.mylyn.issue.milestone", TaskAttribute.TYPE_SINGLE_SELECT, GiteaFlag.ATTRIBUTE),
IID("IID", TaskAttribute.TASK_KEY, TaskAttribute.TYPE_INTEGER, GiteaFlag.READ_ONLY),
PRIORITY("Priority", TaskAttribute.PRIORITY, TaskAttribute.TYPE_SHORT_TEXT, GiteaFlag.READ_ONLY),
TYPE("Type", TaskAttribute.TASK_KIND, TaskAttribute.TYPE_SHORT_TEXT, GiteaFlag.READ_ONLY);
private Set<GiteaFlag> flags;
private final String prettyName;
private final String taskKey;
private final String type;
public String getKind() {
if (type.equals(TaskAttribute.TYPE_PERSON)) {
return TaskAttribute.KIND_PEOPLE;
} else if (flags.contains(GiteaFlag.ATTRIBUTE)) {
return TaskAttribute.KIND_DEFAULT;
}
return null;
}
public boolean isReadOnly() {
return flags.contains(GiteaFlag.READ_ONLY);
}
GiteaAttribute(String prettyName, String taskKey, String type, GiteaFlag... flags) {
this.taskKey = taskKey;
this.prettyName = prettyName;
this.type = type;
if (flags == null || flags.length == 0) {
this.setFlags(EnumSet.noneOf(GiteaFlag.class));
} else {
this.setFlags(EnumSet.copyOf(Arrays.asList(flags)));
}
}
GiteaAttribute(String prettyName, String taskKey, String type) {
this(prettyName, taskKey, type, new GiteaFlag[] {});
}
public Set<GiteaFlag> getFlags() {
return flags;
}
public void setFlags(Set<GiteaFlag> flags) {
this.flags = flags;
}
public String getPrettyName() {
return prettyName;
}
public String getTaskKey() {
return taskKey;
}
public String getType() {
return type;
}
public String toString() {
return this.prettyName;
}
public static GiteaAttribute get(String key) {
for (GiteaAttribute attr : GiteaAttribute.values()) {
if (attr.getTaskKey().equals(key)) {
return attr;
}
}
return null;
}
}

View File

@ -1,117 +0,0 @@
// Copyright (c) 2021, Fr.Terrot. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package io.gitea.mylyn.core;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.mylyn.tasks.core.TaskRepository;
import org.eclipse.mylyn.tasks.core.data.TaskAttribute;
import org.eclipse.mylyn.tasks.core.data.TaskAttributeMapper;
import io.gitea.model.GiteaDateTimeUtils;
import io.gitea.model.Label;
import io.gitea.model.Milestone;
import io.gitea.model.User;
public class GiteaAttributeMapper extends TaskAttributeMapper {
public GiteaAttributeMapper(TaskRepository taskRepository) throws CoreException, IOException {
super(taskRepository);
}
@Override
public Map<String, String> getOptions(TaskAttribute attribute) {
if (attribute.getId().equals(GiteaAttribute.MILESTONE.getTaskKey())) {
return getAsMap(getMilestones());
} else {
return super.getOptions(attribute);
}
}
private GiteaConnection getConnection() throws CoreException {
return ConnectionManager.get(getTaskRepository());
}
@Override
public Date getDateValue(TaskAttribute attribute) {
if (attribute == null) {
return null;
}
Date parsedDate = GiteaDateTimeUtils.parseDate(attribute.getValue());
if (parsedDate != null) {
return parsedDate;
}
return super.getDateValue(attribute);
}
public User findProjectMemberByName(String name) {
try {
List<User> members = getConnection().getRepositoryCollaborators();
for (User member : members) {
if (member.getFullName().equals(name) || member.getLogin().equals(name)) {
return member;
}
}
} catch (CoreException e) {
}
return null;
}
public Milestone findMilestoneByName(String name) {
try {
List<Milestone> milestones = getConnection().getMilestones();
for (Milestone m : milestones) {
if (m.getTitle().equals(name)) {
return m;
}
}
} catch (CoreException e) {
}
return null;
}
private List<String> getMilestones() {
List<String> target = new ArrayList<String>();
try {
List<Milestone> milestones = getConnection().getMilestones();
for (Milestone m : milestones) {
target.add(m.getTitle());
}
} catch (CoreException e) {
}
return target;
}
public List<Label> findLabelsByNames(String names) {
List<Label> found = new ArrayList<Label>();
try {
List<Label> labels = getConnection().getLabels();
HashMap<String, Label> map = new HashMap<String,Label>();
for (Label l : labels) {
map.put(l.getName(),l);
}
for (String n: names.split(",")) {
found.add(map.get(n));
}
} catch (CoreException e) {
}
return found;
}
private HashMap<String, String> getAsMap(List<String> list) {
HashMap<String, String> map = new HashMap<String, String>();
map.put("", "");
for (String s : list) {
map.put(s, s);
}
return map;
}
}

View File

@ -1,224 +0,0 @@
// Copyright (c) 2021, Fr.Terrot. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package io.gitea.mylyn.core;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import io.gitea.ApiException;
import io.gitea.api.ApiVersion;
import io.gitea.api.IssueApi;
import io.gitea.api.RepositoryApi;
import io.gitea.api.UserApi;
import io.gitea.model.Comment;
import io.gitea.model.CreateIssueCommentOption;
import io.gitea.model.CreateIssueOption;
import io.gitea.model.EditIssueCommentOption;
import io.gitea.model.EditIssueOption;
import io.gitea.model.EditLabelOption;
import io.gitea.model.Issue;
import io.gitea.model.IssueLabelsOption;
import io.gitea.model.IssueState;
import io.gitea.model.Label;
import io.gitea.model.Milestone;
import io.gitea.model.Repository;
import io.gitea.model.User;
/**
* Handle Gitea connection and provides helpers to API.
*
*/
public class GiteaConnection {
public final String owner;
public final String repo;
public final String host;
public final Repository repository;
public final GiteaAttributeMapper mapper;
private List<Milestone> milestones;
private List<User> members;
private List<Label> labels;
/** Targetted Gitea Api Version */
public static final ApiVersion apiVersion = ApiVersion.V1;
public GiteaConnection(String host, Repository project, GiteaAttributeMapper mapper) {
this.host = host;
this.repository = project;
this.mapper = mapper;
this.owner = project.getOwner().getLogin();
this.repo = project.getName();
}
public UserApi userApi() {
return new UserApi();
}
public IssueApi issueApi() {
return new IssueApi();
}
public RepositoryApi repositoryApi() {
return new RepositoryApi();
}
public void refreshMilestones() {
try {
milestones = issueGetAllMilestones();
} catch (ApiException e1) {
e1.printStackTrace();
}
}
public void refreshLabels() {
try {
labels = issueGetAllLabels();
} catch (ApiException e2) {
e2.printStackTrace();
}
}
public void refreshMembers() {
ArrayList<User> memberList = new ArrayList<User>();
try {
memberList.addAll(repoListAllCollaborators());
} catch (ApiException e1) {
e1.printStackTrace();
}
members = Collections.unmodifiableList(memberList);
}
public void update() throws IOException {
refreshMilestones();
refreshLabels();
refreshMembers();
}
public List<Repository> userCurrentListRepos() throws ApiException {
return userApi().userCurrentListRepos(null, null);
}
public List<Milestone> getMilestones() {
return Collections.unmodifiableList(milestones);
}
public List<Label> getLabels() {
return Collections.unmodifiableList(labels);
}
public List<User> getRepositoryCollaborators() {
return Collections.unmodifiableList(members);
}
public List<User> repoListAllCollaborators() throws ApiException {
return repositoryApi().repoListCollaborators(owner, repo, null, null);
}
public List<Label> issueGetAllLabels() throws ApiException {
return issueApi().issueListLabels(owner, repo, 0, 0);
}
public List<Milestone> issueGetMilestones(IssueState state, String filterByName) throws ApiException {
return issueApi().issueGetMilestonesList(owner, repo, state.toString(), filterByName, null, null);
}
public List<Milestone> issueGetAllMilestones() throws ApiException {
return issueGetMilestones(IssueState.STATE_ANY, null);
}
public List<Milestone> issueGetOpenMilestones() throws ApiException {
return issueGetMilestones(IssueState.STATE_OPENED, null);
}
/**
* Get issues list by state.
*
* @param state
* @return
* @throws ApiException
*/
public List<Issue> repoGetIssues(IssueState state, String labels, Integer page, String query, String milestones) throws ApiException {
return issueApi().issueListIssues(owner, repo, state.toString(), labels, "", query, milestones, page, 0);
}
public List<Issue> repoGetIssues(String state, String labels, Integer page, String query, String milestones) throws ApiException {
return issueApi().issueListIssues(owner, repo, state, labels, query, "", milestones, page, 0);
}
public List<Issue> repoGetAllIssues() throws ApiException {
return repoGetIssues(IssueState.STATE_ANY, "", 0, "", "");
}
public List<Issue> repoGetOpenIssues() throws ApiException {
return repoGetIssues(IssueState.STATE_OPENED, "", 0, "", "");
}
/**
* Get a specific Issue.
*
* @param issueId : issue id
* @return Issue
* @throws ApiException
*/
public Issue issueGetIssue(Long issueId) throws ApiException {
return issueApi().issueGetIssue(owner, repo, issueId);
}
/**
* Get all comments attached to an issue.
*
* @param issue Issue to retrieve comments from.
* @param since
* @return List<Comment>
* @throws ApiException
*/
public List<Comment> issueGetComments(Issue issue, String since, String before) throws ApiException {
return issueApi().issueGetComments(owner, repo, issue.getNumber(), null, null); // FIXME: support since and before
}
/**
* Get all comments attached to an issue identified by its id.
*
* @param issueId
* @param since
* @return
* @throws ApiException
*/
public List<Comment> issueGetComments(Long issueId, String since) throws ApiException {
return issueGetComments(issueGetIssue(issueId), since, null); // FIXME: support since and before
}
public List<Comment> issueGetComments(Issue issue) throws ApiException {
return issueGetComments(issue, null, null);
}
/** Add a new comment to an issue.
*
* @param issueId
* @param body
* @return
* @throws ApiException
*/
public Comment issueAddComment(Long issueId, CreateIssueCommentOption body) throws ApiException {
return issueApi().issueCreateComment(owner, repo, issueId, body);
}
public Comment issueAddComment(Issue issue, CreateIssueCommentOption body) throws ApiException {
return issueAddComment(issue.getId(), body);
}
/** Create an issue.
*
* @param body
* @return
* @throws ApiException
*/
public Issue createIssue(CreateIssueOption body) throws ApiException {
return issueApi().issueCreateIssue(owner, repo, body);
}
public Issue editIssue(Long issueId, EditIssueOption body) throws ApiException {
return issueApi().issueEditIssue(owner, repo, issueId, body);
}
public List<Label> issueReplaceLabels(Long issueId, IssueLabelsOption labels) throws ApiException {
return issueApi().issueReplaceLabels(owner, repo, issueId, labels);
}
}

View File

@ -1,160 +0,0 @@
// Copyright (c) 2021, Fr.Terrot. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package io.gitea.mylyn.core;
import java.util.Date;
import java.util.List;
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;
import io.gitea.*;
import io.gitea.model.Issue;
import io.gitea.mylyn.core.exceptions.GiteaException;
/**
* Establishes a connection to the Gitea Instance and handles all requests like
* search requests etc.
*/
public class GiteaConnector extends AbstractRepositoryConnector {
private GiteaTaskDataHandler handler = new GiteaTaskDataHandler();
@Override
public boolean canCreateNewTask(TaskRepository repository) {
return true;
}
@Override
public boolean canCreateTaskFromKey(TaskRepository repository) {
return false;
}
@Override
public String getConnectorKind() {
return GiteaPluginCore.CONNECTOR_KIND;
}
@Override
public String getLabel() {
return "Gitea Issues";
}
@Override
public String getRepositoryUrlFromTaskUrl(String arg0) {
return null;
}
@Override
public TaskData getTaskData(TaskRepository repository, String id, IProgressMonitor monitor) throws CoreException {
try {
monitor.beginTask("Task Download", IProgressMonitor.UNKNOWN);
return handler.downloadTaskData(repository, GiteaConnector.getTicketId(id));
} finally {
monitor.done();
}
}
@Override
public String getTaskIdFromTaskUrl(String url) {
return null;
}
@Override
public String getTaskUrl(String arg0, String arg1) {
return null;
}
@Override
public boolean hasTaskChanged(TaskRepository repository, ITask task, TaskData data) {
TaskMapper mapper = new GiteaTaskMapper(data);
if (data.isPartial()) {
return mapper.hasChanges(task);
} else {
Date repositoryDate = mapper.getModificationDate();
Date localDate = task.getModificationDate();
if (repositoryDate != null && repositoryDate.equals(localDate)) {
return false;
}
return true;
}
}
@Override
public IStatus performQuery(TaskRepository repository, IRepositoryQuery query, TaskDataCollector collector,
ISynchronizationSession session, IProgressMonitor monitor) {
try {
monitor.beginTask("Tasks querying", IProgressMonitor.UNKNOWN);
GiteaConnection connection = ConnectionManager.get(repository);
GiteaIssueSearch search = new GiteaIssueSearch(query);
List<Issue> issues = connection.repoGetAllIssues();
for (Issue i : issues) {
if (search.doesMatch(i)) {
collector.accept(
handler.createTaskDataFromGiteaIssue(i, repository, connection.issueGetComments(i)));
}
}
return Status.OK_STATUS;
} catch (ApiException e) {
return new Status(Status.ERROR, GiteaPluginCore.ID_PLUGIN, "Unable to execute Query: " + e.getMessage());
} catch (CoreException e) {
return new Status(Status.ERROR, GiteaPluginCore.ID_PLUGIN, "Unable to execute Query: " + e.getMessage());
} finally {
monitor.done();
}
}
@Override
public void updateRepositoryConfiguration(TaskRepository repository, IProgressMonitor monitor)
throws CoreException {
try {
monitor.beginTask("Updating repository configuration", IProgressMonitor.UNKNOWN);
ConnectionManager.get(repository, true);
} finally {
monitor.done();
}
}
@Override
public void updateTaskFromTaskData(TaskRepository repository, ITask task, TaskData data) {
GiteaTaskMapper mapper = new GiteaTaskMapper(data);
mapper.applyTo(task);
}
public static void validate(TaskRepository taskRepo) throws CoreException {
try {
ConnectionManager.validate(taskRepo);
} catch (GiteaException e) {
throw e;
} catch (Exception e) {
throw new GiteaException("Connection not successful or repository not found: " + e.getMessage());
} catch (Error e) {
throw new GiteaException("Connection not successful or repository not found: " + e.getMessage());
}
}
@Override
public AbstractTaskDataHandler getTaskDataHandler() {
return handler;
}
public static Long getTicketId(String id) {
return (long) Integer.parseInt(id);
}
}

View File

@ -1,26 +0,0 @@
// Copyright (c) 2021, Fr.Terrot. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package io.gitea.mylyn.core;
/**
* A flag for Gitea attributes.
*
*/
public enum GiteaFlag {
/**
* Sets the attribute to ReadOnly.
*/
READ_ONLY,
/**
* Default Attribute
*/
ATTRIBUTE,
/**
* A flag to indicate, that an attribute describes a person.
*/
PEOPLE;
}

View File

@ -1,76 +0,0 @@
// Copyright (c) 2021, Fr.Terrot. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package io.gitea.mylyn.core;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import org.eclipse.mylyn.tasks.core.IRepositoryQuery;
import io.gitea.model.IssueState;
import io.gitea.model.Issue;
import io.gitea.model.Label;
public class GiteaIssueSearch {
private String assignee;
private String milestone;
private Boolean opened;
private Boolean closed;
private List<Pattern> labels = new ArrayList<Pattern>();
public GiteaIssueSearch(IRepositoryQuery query) {
assignee = query.getAttribute("assignee");
milestone = query.getAttribute("milestone");
opened = Boolean.parseBoolean(query.getAttribute("opened"));
closed = Boolean.parseBoolean(query.getAttribute("closed"));
for (String label : query.getAttribute("labels").split(",")) {
if (label.trim().length() > 0) {
labels.add(Pattern.compile(label.trim()));
}
}
}
public boolean doesMatch(Issue issue) {
if (!assignee.equals("") && (issue.getAssignee() == null || !(assignee.equals(issue.getAssignee().getLogin())
|| assignee.equals(issue.getAssignee().getFullName())))) {
return false;
}
if (!milestone.equals("")
&& (issue.getMilestone() == null || !milestone.equals(issue.getMilestone().getTitle()))) {
return false;
}
List<Pattern> matchedLabels = new ArrayList<Pattern>();
for (Pattern p : labels) {
for (Label label : issue.getLabels()) {
if (p.matcher(label.getName()).find()) {
matchedLabels.add(p);
}
}
}
if (matchedLabels.size() < labels.size()) {
return false;
}
if (!closed && IssueState.isClosed(issue)) {
return false;
}
if (!opened && IssueState.isOpen(issue)) {
return false;
}
return true;
}
}

View File

@ -1,39 +0,0 @@
// Copyright (c) 2021, Fr.Terrot. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package io.gitea.mylyn.core;
import org.eclipse.core.runtime.Plugin;
import org.osgi.framework.BundleContext;
public class GiteaPluginCore extends Plugin {
private static GiteaPluginCore plugin;
public static final String ID_PLUGIN = "io.gitea.mylyn.core";
public static final String CONNECTOR_KIND = "gitea";
public static final String ENCODING_UTF_8 = "UTF-8";
public GiteaPluginCore() {
}
public static GiteaPluginCore get() {
return plugin;
}
@Override
public void start(BundleContext context) throws Exception {
super.start(context);
plugin = this;
}
@Override
public void stop(BundleContext context) throws Exception {
plugin = null;
super.stop(context);
}
}

View File

@ -1,336 +0,0 @@
// Copyright (c) 2021, Fr.Terrot. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package io.gitea.mylyn.core;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import org.apache.commons.lang.StringUtils;
import org.eclipse.core.internal.registry.OffsetTable;
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.RepositoryResponse.ResponseKind;
import org.eclipse.mylyn.tasks.core.TaskRepository;
import org.eclipse.mylyn.tasks.core.data.AbstractTaskDataHandler;
import org.eclipse.mylyn.tasks.core.data.TaskAttribute;
import org.eclipse.mylyn.tasks.core.data.TaskAttributeMapper;
import org.eclipse.mylyn.tasks.core.data.TaskAttributeMetaData;
import org.eclipse.mylyn.tasks.core.data.TaskCommentMapper;
import org.eclipse.mylyn.tasks.core.data.TaskData;
import org.eclipse.mylyn.tasks.core.data.TaskOperation;
import io.gitea.ApiException;
import io.gitea.api.IssueApi;
import io.gitea.model.Comment;
import io.gitea.model.CreateIssueCommentOption;
import io.gitea.model.CreateIssueOption;
import io.gitea.model.EditIssueOption;
import io.gitea.model.GiteaDateTimeUtils;
import io.gitea.model.GiteaPriorityLevel;
import io.gitea.model.GiteaUser;
import io.gitea.model.Issue;
import io.gitea.model.IssueAction;
import io.gitea.model.IssueLabelsOption;
import io.gitea.model.IssueState;
import io.gitea.model.IssueType;
import io.gitea.model.Label;
import io.gitea.model.Milestone;
import io.gitea.model.User;
import io.gitea.mylyn.core.exceptions.GiteaException;
/**
* Handles the Issue<=>Task management. Downloads issues to tasks for a specific
* repository, update issue and creates new issues.
*/
public class GiteaTaskDataHandler extends AbstractTaskDataHandler {
public GiteaTaskDataHandler() {
}
@Override
public TaskAttributeMapper getAttributeMapper(TaskRepository repository) {
try {
return ConnectionManager.get(repository).mapper;
} catch (CoreException e) {
throw new Error(e);
}
}
/**
* Initialize Task from local repository.
*
*/
@Override
public boolean initializeTaskData(TaskRepository repository, TaskData data, ITaskMapping mapping,
IProgressMonitor monitor) throws CoreException {
createDefaultAttributes(data, false);
GiteaConnection connection = ConnectionManager.get(repository);
TaskAttribute root = data.getRoot();
root.getAttribute(GiteaAttribute.PROJECT.getTaskKey()).setValue(connection.repository.getName());// FIXME: not
// the
// project
root.getAttribute(GiteaAttribute.LABELS.getTaskKey()).setValue("");
root.getAttribute(GiteaAttribute.STATUS.getTaskKey()).setValue("open");
root.getAttribute(GiteaAttribute.MILESTONE.getTaskKey()).setValue("");
return true;
}
/**
* Send Update to remote issues repository (create issue when required).
*
*/
@Override
public RepositoryResponse postTaskData(TaskRepository repository, TaskData data, Set<TaskAttribute> attributes,
IProgressMonitor monitor) throws CoreException {
GiteaAttributeMapper attributeMapper = (GiteaAttributeMapper) data.getAttributeMapper();
TaskAttribute root = data.getRoot();
String taskId = data.getTaskId();
// newLabelsList could be null or may content only one 'null' item when no label
// is defined for the task
List<Label> newLabelsList = attributeMapper
.findLabelsByNames(root.getAttribute(GiteaAttribute.LABELS.getTaskKey()).getValue());
List<Long> newLabelIds = new ArrayList<Long>();
if (newLabelsList != null)
newLabelsList.forEach(label -> {
if (label != null)
newLabelIds.add(label.getId());
});
String title = root.getAttribute(GiteaAttribute.TITLE.getTaskKey()).getValue();
String body = root.getAttribute(GiteaAttribute.BODY.getTaskKey()).getValue();
User assignee = null;
// Check assignee is still part of team member
for (TaskAttribute a : attributes) {
if (a.getId().equals(GiteaAttribute.ASSIGNEE.getTaskKey())) {
assignee = attributeMapper
.findProjectMemberByName(root.getAttribute(GiteaAttribute.ASSIGNEE.getTaskKey()).getValue());
}
}
Milestone milestone = attributeMapper
.findMilestoneByName(root.getAttribute(GiteaAttribute.MILESTONE.getTaskKey()).getValue());
Long milestoneId = (milestone == null ? 0 : milestone.getId());
GiteaConnection connection = ConnectionManager.get(repository);
// FIXME:TODO: support due date
// OffsetDateTime dueDate =
// OffsetDateTime.GiteaDateTimeUtils.parseDate(root.getAttribute(GiteaAttribute.DUE_DATE.getTaskKey()).getValue());
try {
//monitor.beginTask("Uploading task", IProgressMonitor.UNKNOWN);
Issue issue = null;
if (data.isNew()) {
issue = connection.createIssue(
new CreateIssueOption().title(title).body(body).assignee(GiteaUser.getName(assignee))
.closed(false).milestone(milestoneId).labels(newLabelIds));
// FIXME Additional attributes like due date have to be set after issue creation
// Always the same caveats about TaskId:
// - represented by Issue number and not the issue Id which is internal Gitea database id.
// - Issue number is Long where TaskId is string representing an Integer
taskId = Integer.toString(issue.getNumber().intValue());
return new RepositoryResponse(ResponseKind.TASK_CREATED, taskId);
} else {
Long issueId = GiteaConnector.getTicketId(taskId);
issue = connection.issueGetIssue(issueId);
// A new comment is available
if (root.getAttribute(TaskAttribute.COMMENT_NEW) != null
&& !root.getAttribute(TaskAttribute.COMMENT_NEW).getValue().equals("")) {
connection.issueAddComment(issueId, new CreateIssueCommentOption()
.body(root.getAttribute(TaskAttribute.COMMENT_NEW).getValue()));
}
// Update labels if label list has changed
List<Label>oldLabels = issue.getLabels();
if (!issue.getLabels().equals(newLabelsList)) {
connection.issueReplaceLabels(issueId, new IssueLabelsOption().labels(newLabelIds));
}
// Kept Step by step only for debugging purpose ...
String action = root.getAttribute(TaskAttribute.OPERATION).getValue();
String state = issue.getState();
String newState = IssueAction.getEnum(action).toState(IssueState.getEnum(state)).toString();
// OffsetDateTime dueDate = new OffsetDateTime();
// FIXME:TODO: Support DueDate
boolean unsetDueDate = true;
issue = connection.editIssue(issueId,
new EditIssueOption().assignee(GiteaUser.getName(assignee)).milestone(milestoneId).body(body)
.state(newState).title(title)
// .dueDate(dueDate)
.unsetDueDate(unsetDueDate));
return new RepositoryResponse(ResponseKind.TASK_UPDATED, taskId);
}
} catch (Exception e) {
throw new GiteaException("Unknown connection error!");
} finally {
//monitor.done();
}
}
/**
* Get task data including comments from remote issue id.
*
* @param repository
* @param ticketId
* @return
* @throws CoreException
*/
public TaskData downloadTaskData(TaskRepository repository, Long ticketId) throws CoreException {
try {
GiteaConnection connection = ConnectionManager.get(repository);
Issue issue = connection.issueGetIssue(ticketId);
List<Comment> notes = connection.issueGetComments(issue);
return createTaskDataFromGiteaIssue(issue, repository, notes);
} catch (ApiException e) {
throw new GiteaException("Unknown connection error!");
}
}
public TaskData createTaskDataFromGiteaIssue(Issue issue, TaskRepository repository, List<Comment> notes)
throws CoreException {
GiteaConnection connection = ConnectionManager.get(repository);
TaskData data = new TaskData(connection.mapper, GiteaPluginCore.CONNECTOR_KIND, repository.getUrl(),
issue.getNumber().toString());
// Labels
List<String> labelsNames = new ArrayList<String>();
List<Label> issueLabels = issue.getLabels();
issueLabels.forEach((label) -> labelsNames.add(label.getName()));
String labels = StringUtils.join(labelsNames, ", ");
createDefaultAttributes(data, true);
TaskAttribute root = data.getRoot();
root.getAttribute(GiteaAttribute.AUTHOR.getTaskKey()).setValue(GiteaUser.getName(issue.getUser()));
root.getAttribute(GiteaAttribute.CREATED.getTaskKey()).setValue(issue.getCreatedAt().toString());
root.getAttribute(GiteaAttribute.BODY.getTaskKey()).setValue(issue.getBody() == null ? "" : issue.getBody());
root.getAttribute(GiteaAttribute.LABELS.getTaskKey()).setValue(labels);
root.getAttribute(GiteaAttribute.PROJECT.getTaskKey()).setValue(connection.repository.getName()); // FIXME:
root.getAttribute(GiteaAttribute.STATUS.getTaskKey()).setValue(issue.getState());
root.getAttribute(GiteaAttribute.TITLE.getTaskKey()).setValue(issue.getTitle());
root.getAttribute(GiteaAttribute.IID.getTaskKey()).setValue("" + issue.getNumber().toString());
root.getAttribute(GiteaAttribute.PRIORITY.getTaskKey())
.setValue(GiteaPriorityLevel.getPriority(labels).toString());
root.getAttribute(GiteaAttribute.TYPE.getTaskKey()).setValue(getType(labels));
if (issue.getMilestone() != null) {
root.getAttribute(GiteaAttribute.MILESTONE.getTaskKey()).setValue(issue.getMilestone().getTitle());
}
if (issue.getUpdatedAt() != null) {
root.getAttribute(GiteaAttribute.UPDATED.getTaskKey()).setValue(issue.getUpdatedAt().toString());
}
if (IssueState.isClosed(issue.getState())) {
root.getAttribute(GiteaAttribute.COMPLETED.getTaskKey()).setValue(issue.getUpdatedAt().toString());
}
// Assignee name is either FulleName either Login either empty
List<String> assigneesNames = new ArrayList<String>();
List<User> assignees = issue.getAssignees();
if (assignees != null) {
assignees.forEach((assignee) -> assigneesNames.add(GiteaUser.getName(assignee)));
root.getAttribute(GiteaAttribute.ASSIGNEE.getTaskKey()).setValue(StringUtils.join(assigneesNames, ", "));
}
Collections.sort(notes, new Comparator<Comment>() {
@Override
public int compare(Comment o1, Comment o2) {
return o1.getCreatedAt().compareTo(o2.getCreatedAt());
}
});
int i = 0;
for (Comment note : notes) {
TaskCommentMapper cmapper = new TaskCommentMapper();
cmapper.setAuthor(repository.createPerson(GiteaUser.getName(note.getUser())));
cmapper.setCreationDate(GiteaDateTimeUtils.toDate(note.getCreatedAt()));// FIXME:
cmapper.setText(note.getBody());
cmapper.setNumber(++i);
TaskAttribute attribute = data.getRoot().createAttribute(TaskAttribute.PREFIX_COMMENT + (i + 1));
cmapper.applyTo(attribute);
}
GiteaAction[] actions = GiteaAction.getActions(issue);
for (GiteaAction action : actions) {
TaskAttribute attribute = data.getRoot().createAttribute(TaskAttribute.PREFIX_OPERATION + action.label);
TaskOperation.applyTo(attribute, action.label, action.label);
}
return data;
}
private void createDefaultAttributes(TaskData data, boolean existingTask) {
createAttribute(data, GiteaAttribute.BODY);
createAttribute(data, GiteaAttribute.TITLE);
createAttribute(data, GiteaAttribute.LABELS);
createAttribute(data, GiteaAttribute.STATUS);
createAttribute(data, GiteaAttribute.PROJECT);
createAttribute(data, GiteaAttribute.CREATED);
createAttribute(data, GiteaAttribute.COMPLETED);
createAttribute(data, GiteaAttribute.UPDATED);
createAttribute(data, GiteaAttribute.ASSIGNEE);
createAttribute(data, GiteaAttribute.MILESTONE);
createAttribute(data, GiteaAttribute.IID);
createAttribute(data, GiteaAttribute.PRIORITY);
createAttribute(data, GiteaAttribute.TYPE);
data.getRoot().getAttribute(GiteaAttribute.CREATED.getTaskKey()).setValue("" + (new Date().getTime()));
if (existingTask) {
data.getRoot().createAttribute(TaskAttribute.COMMENT_NEW).getMetaData()
.setType(TaskAttribute.TYPE_LONG_RICH_TEXT).setReadOnly(false);
createAttribute(data, GiteaAttribute.AUTHOR);
}
TaskAttribute operation = data.getRoot().createAttribute(TaskAttribute.OPERATION);
operation.getMetaData().setType(TaskAttribute.TYPE_OPERATION);
}
private void createAttribute(TaskData data, GiteaAttribute attribute) {
TaskAttribute attr = data.getRoot().createAttribute(attribute.getTaskKey());
TaskAttributeMetaData metaData = attr.getMetaData();
metaData.setType(attribute.getType());
metaData.setKind(attribute.getKind());
metaData.setLabel(attribute.toString());
metaData.setReadOnly(attribute.isReadOnly());
}
/**
* Returns the type string for Mylyn. Uses a regular expression to check for
* types in the given label.
*
* @param labels
* @return
*/
private String getType(String labels) {
Matcher m = IssueType.PATTERN.matcher(labels);
if (m.find()) {
return m.group(1);
}
return "";
}
}

View File

@ -1,16 +0,0 @@
// Copyright (c) 2021, Fr.Terrot. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package io.gitea.mylyn.core;
import org.eclipse.mylyn.tasks.core.data.TaskData;
import org.eclipse.mylyn.tasks.core.data.TaskMapper;
public class GiteaTaskMapper extends TaskMapper {
public GiteaTaskMapper(TaskData taskData) {
super(taskData);
}
}

View File

@ -1,28 +0,0 @@
// Copyright (c) 2021, Fr.Terrot. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package io.gitea.mylyn.core.exceptions;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.Status;
import io.gitea.mylyn.core.GiteaPluginCore;
/**
* Gitea Exception class
*/
public class GiteaException extends CoreException {
private static final long serialVersionUID = 7631319898671055531L;
/**
* Constructor
*
* @param message : Exception message
*/
public GiteaException(String message) {
super(new Status(Status.ERROR, GiteaPluginCore.ID_PLUGIN, message));
}
}

View File

@ -1,32 +0,0 @@
// Copyright (c) 2021, Fr.Terrot. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package io.gitea.mylyn.core.exceptions;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.ConnectException;
import java.net.NoRouteToHostException;
import javax.net.ssl.SSLHandshakeException;
public class GiteaExceptionHandler {
public static GiteaException handle(Throwable e) {
if (e instanceof SSLHandshakeException) {
return new GiteaException("Invalid TLS Certificate: " + e.getMessage());
} else if (e instanceof ConnectException) {
return new GiteaException("Connection refused");
} else if (e instanceof NoRouteToHostException) {
return new GiteaException("No route to host");
} else if (e instanceof FileNotFoundException) {
return new GiteaException("Invalid path in host");
} else if (e instanceof IOException) {
return new GiteaException("Invalid username/password/private token combination");
}
return new GiteaException("Unknown Exception: " + e.getMessage());
}
}

View File

@ -1,19 +0,0 @@
// Copyright (c) 2021, Fr.Terrot. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package io.gitea.mylyn.core.exceptions;
/**
* Exception raised when trying to access unkown repository.
*
*/
public class UnknownRepositoryException extends GiteaException {
private static final long serialVersionUID = 4976633904836890061L;
public UnknownRepositoryException(String project) {
super("Unknown repository " + project + " or insufficient access rights");
}
}

View File

@ -1,6 +0,0 @@
// Copyright (c) 2021, Fr.Terrot. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
/** <i>local</i> extension of the generated Java Gitea API "io.gitea" package. */
package io.gitea;

View File

@ -1 +0,0 @@
/classes/

View File

@ -1,12 +0,0 @@
<?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/JavaSE-1.8">
<attributes>
<attribute name="module" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src"/>
<classpathentry combineaccessrules="false" kind="src" path="/io.gitea.mylyn.core"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.ant.AntBuilderLaunchConfigurationType">
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_BUILDER_ENABLED" value="false"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_DISABLED_BUILDER" value="org.eclipse.pde.api.tools.apiAnalysisBuilder"/>
<mapAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS"/>
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
</launchConfiguration>

View File

@ -1 +0,0 @@
/target/

View File

@ -1,39 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>io.gitea.mylyn.ui</name>
<comment></comment>
<projects>
<project>io.gitea.mylyn.core</project>
</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>
<buildCommand>
<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
<triggers>full,incremental,</triggers>
<arguments>
<dictionary>
<key>LaunchConfigHandle</key>
<value>&lt;project&gt;/.externalToolBuilders/org.eclipse.pde.api.tools.apiAnalysisBuilder (1).launch</value>
</dictionary>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@ -1,108 +0,0 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled
org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull
org.eclipse.jdt.core.compiler.annotation.nonnull.secondary=
org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
org.eclipse.jdt.core.compiler.annotation.nonnullbydefault.secondary=
org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
org.eclipse.jdt.core.compiler.annotation.nullable.secondary=
org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.APILeak=warning
org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
org.eclipse.jdt.core.compiler.problem.deadCode=warning
org.eclipse.jdt.core.compiler.problem.deprecation=warning
org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
org.eclipse.jdt.core.compiler.problem.forbiddenReference=ignore
org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning
org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore
org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled
org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning
org.eclipse.jdt.core.compiler.problem.nonnullTypeVariableFromLegacyInvocation=warning
org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error
org.eclipse.jdt.core.compiler.problem.nullReference=warning
org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning
org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
org.eclipse.jdt.core.compiler.problem.pessimisticNullAnalysisForFreeTypeVariables=warning
org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore
org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore
org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore
org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
org.eclipse.jdt.core.compiler.problem.suppressWarningsNotFullyAnalysed=info
org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled
org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
org.eclipse.jdt.core.compiler.problem.terminalDeprecation=warning
org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning
org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentType=warning
org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentTypeStrict=disabled
org.eclipse.jdt.core.compiler.problem.unlikelyEqualsArgumentType=info
org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore
org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
org.eclipse.jdt.core.compiler.problem.unstableAutoModuleName=warning
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
org.eclipse.jdt.core.compiler.problem.unusedImport=warning
org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore
org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
org.eclipse.jdt.core.compiler.source=1.8

View File

@ -1,19 +0,0 @@
MIT License Copyright (c) 2021 F.Terrot
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,20 +0,0 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Bundle-SymbolicName: io.gitea.mylyn.ui;singleton:=true
Bundle-Version: 0.3.1
Automatic-Module-Name: io.gitea.mylyn.ui
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-Activator: io.gitea.mylyn.ui.GiteaUIPlugin
Require-Bundle: org.eclipse.core.runtime,
org.eclipse.ui,
org.eclipse.ui.forms,
org.eclipse.mylyn.commons.net;bundle-version="[3.8.0,4.0.0)",
org.eclipse.mylyn.commons.core;bundle-version="[3.8.0,4.0.0)",
org.eclipse.mylyn.tasks.ui;bundle-version="[3.8.0,4.0.0)",
org.eclipse.mylyn.tasks.core;bundle-version="[3.8.0,4.0.0)",
org.eclipse.mylyn.commons.workbench;bundle-version="[3.8.0,4.0.0)",
org.eclipse.mylyn.commons.ui;bundle-version="[3.8.0,4.0.0)",
io.gitea.mylyn.core
Bundle-ActivationPolicy: lazy
Export-Package: io.gitea.mylyn.ui

View File

@ -1,2 +0,0 @@
#Properties file for io.gitea.mylyn.ui
Bundle-Name = Mylyn Gitea Connector UI

View File

@ -1,9 +0,0 @@
source.. = src/
bin.includes = META-INF/,.,plugin.xml,icons/
bin.includes = META-INF/,\
.,\
plugin.xml,\
LICENSE,\
icons/,\
OSGI-INF/l10n/bundle.properties
jre.compilation.profile = JavaSE-1.8

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1007 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 768 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 718 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 667 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 687 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

View File

@ -1,22 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>
<extension
id="io.gitea.mylyn.ui"
name="%repository.name"
point="org.eclipse.mylyn.tasks.ui.repositories">
<connectorUi
brandingIcon="icons/gitea-icon.png"
class="io.gitea.mylyn.ui.GiteaConnectorUI"
id="io.gitea.mylyn.ui"
name="GiteaConnector Ui"
overlayIcon="icons/gitea-overlay.png"/>
</extension>
<extension point="org.eclipse.mylyn.tasks.ui.editors">
<pageFactory
class="io.gitea.mylyn.ui.GiteaEditorPageFactory"
id="io.gitea.mylyn.ui.pageFactory">
</pageFactory>
</extension>
</plugin>

View File

@ -1,78 +0,0 @@
// Copyright (c) 2021, Fr.Terrot. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package io.gitea.mylyn.ui;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.wizard.IWizard;
import org.eclipse.mylyn.tasks.core.IRepositoryQuery;
import org.eclipse.mylyn.tasks.core.ITask;
import org.eclipse.mylyn.tasks.core.ITaskComment;
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.wizards.ITaskRepositoryPage;
import org.eclipse.mylyn.tasks.ui.wizards.NewTaskWizard;
import org.eclipse.mylyn.tasks.ui.wizards.RepositoryQueryWizard;
import io.gitea.model.IssueType;
import io.gitea.mylyn.core.GiteaPluginCore;
public class GiteaConnectorUI extends AbstractRepositoryConnectorUi {
@Override
public String getConnectorKind() {
return GiteaPluginCore.CONNECTOR_KIND;
}
@Override
public IWizard getNewTaskWizard(TaskRepository repository, ITaskMapping mapping) {
return new NewTaskWizard(repository, mapping);
}
@Override
public IWizard getQueryWizard(TaskRepository repository, IRepositoryQuery query) {
RepositoryQueryWizard wizard = new RepositoryQueryWizard(repository);
wizard.addPage(new GiteaQueryPage(Labels.NEW_PAGE, repository, query));
return wizard;
}
@Override
public ITaskRepositoryPage getSettingsPage(TaskRepository repository) {
return new GiteaRepositorySettingsPage(Labels.NEW_REPOSITORY, Labels.SETTINGS_PAGE, repository);
}
@Override
public boolean hasSearchPage() {
return false;
}
@Override
public ImageDescriptor getTaskKindOverlay(ITask task) {
//FIXME: complete with other kind epic,...enhancement ...
String kind = task.getTaskKind();
try {
switch(IssueType.valueOf(kind)) {
case BUG:
return GiteaImages.ISSUE;
case FEATURE:
return GiteaImages.OVERLAY_FEATURE;
case STORY:
return GiteaImages.OVERLAY_STORY;
default:
}
}
catch (IllegalArgumentException e) {
// unhandled task kind.
}
return super.getTaskKindOverlay(task);
}
@Override
public String getReplyText(TaskRepository taskRepository, ITask task, ITaskComment taskComment,
boolean includeTask) {
return "Reply to " + taskComment.getAuthor();
}
}

View File

@ -1,36 +0,0 @@
// Copyright (c) 2021, Fr.Terrot. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package io.gitea.mylyn.ui;
import java.util.Iterator;
import java.util.Set;
import org.eclipse.mylyn.tasks.ui.editors.AbstractTaskEditorPage;
import org.eclipse.mylyn.tasks.ui.editors.TaskEditor;
import org.eclipse.mylyn.tasks.ui.editors.TaskEditorPartDescriptor;
public class GiteaEditorPage extends AbstractTaskEditorPage {
public GiteaEditorPage(TaskEditor editor, String connectorKind) {
super(editor, connectorKind);
setNeedsPrivateSection(false);
setNeedsSubmitButton(true);
setNeedsAddToCategory(false);
}
@Override
protected Set<TaskEditorPartDescriptor> createPartDescriptors() {
Set<TaskEditorPartDescriptor> descriptors = super.createPartDescriptors();
// FIXME: remove unnecessary default editor parts
for (Iterator<TaskEditorPartDescriptor> it = descriptors.iterator(); it.hasNext();) {
TaskEditorPartDescriptor descriptor = it.next();
if (descriptor.getId().equals(ID_PART_PLANNING)) {
it.remove();
}
}
return descriptors;
}
}

View File

@ -1,56 +0,0 @@
// Copyright (c) 2021, Fr.Terrot. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package io.gitea.mylyn.ui;
import org.eclipse.mylyn.commons.ui.CommonImages;
import org.eclipse.mylyn.tasks.ui.ITasksUiConstants;
import org.eclipse.mylyn.tasks.ui.TasksUiImages;
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.ui.forms.editor.IFormPage;
import io.gitea.mylyn.core.GiteaPluginCore;
public class GiteaEditorPageFactory extends AbstractTaskEditorPageFactory {
@Override
public boolean canCreatePageFor(TaskEditorInput input) {
if (input.getTask().getConnectorKind().equals(GiteaPluginCore.CONNECTOR_KIND)) {
return true;
} else if (TasksUiUtil.isOutgoingNewTask(input.getTask(), GiteaPluginCore.CONNECTOR_KIND)) {
return true;
}
return false;
}
@Override
public IFormPage createPage(TaskEditor editor) {
return new GiteaEditorPage(editor, GiteaPluginCore.CONNECTOR_KIND);
}
@Override
public int getPriority() {
return 0;
}
@Override
public Image getPageImage() {
return CommonImages.getImage(TasksUiImages.TASK);
}
@Override
public String getPageText() {
return Labels.GITEA_ISSUE;
}
@Override
public String[] getConflictingIds(TaskEditorInput input) {
return new String[] { ITasksUiConstants.ID_PAGE_PLANNING };
}
}

View File

@ -1,47 +0,0 @@
// Copyright (c) 2021, Fr.Terrot. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package io.gitea.mylyn.ui;
import java.net.MalformedURLException;
import java.net.URL;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.graphics.Image;
//FIXME: complete with other kind of issue
public class GiteaImages {
private static final URL baseURL = GiteaUIPlugin.getDefault().getBundle().getEntry("/icons/"); //$NON-NLS-1$
public static final ImageDescriptor ISSUE = create("gitea-issue.png"); //$NON-NLS-1$
public static final ImageDescriptor ISSUE_OPEN = create("gitea-issue-open.png"); //$NON-NLS-1$
public static final ImageDescriptor ISSUE_CLOSED = create("gitea-issue-closed.png"); //$NON-NLS-1$
public static final ImageDescriptor OVERLAY_FEATURE = create("overlay-feature.png"); //$NON-NLS-1$
public static final ImageDescriptor OVERLAY_STORY = create("overlay-story.png"); //$NON-NLS-1$
public static final Image LABEL = create("gitea-label.png").createImage();
public static final Image MILESTONE = create("gitea-milestone.png").createImage();
public static final Image REPOSITORY = create("gitea-repository.png").createImage();
private static ImageDescriptor create(String name) {
try {
return ImageDescriptor.createFromURL(makeIconFileURL(name));
} catch (MalformedURLException e) {
return ImageDescriptor.getMissingImageDescriptor();
}
}
private static URL makeIconFileURL(String name) throws MalformedURLException {
if (baseURL == null) {
throw new MalformedURLException();
}
StringBuilder buffer = new StringBuilder();
buffer.append(name);
return new URL(baseURL, buffer.toString());
}
}

View File

@ -1,701 +0,0 @@
// Copyright (c) 2021, Fr.Terrot. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package io.gitea.mylyn.ui;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.operation.IRunnableContext;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.CheckboxTableViewer;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.wizard.IWizardPage;
import org.eclipse.mylyn.commons.core.ICoreRunnable;
import org.eclipse.mylyn.commons.net.Policy;
import org.eclipse.mylyn.commons.ui.CommonUiUtil;
import org.eclipse.mylyn.tasks.core.IRepositoryQuery;
import org.eclipse.mylyn.tasks.core.TaskRepository;
import org.eclipse.mylyn.tasks.ui.TasksUiImages;
import org.eclipse.mylyn.tasks.ui.wizards.AbstractRepositoryQueryPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import org.eclipse.ui.PlatformUI;
import io.gitea.ApiException;
import io.gitea.model.GiteaUser;
import io.gitea.model.IssueState;
import io.gitea.model.Milestone;
import io.gitea.mylyn.core.ConnectionManager;
import io.gitea.mylyn.core.GiteaConnection;
public class GiteaQueryPage extends AbstractRepositoryQueryPage implements IWizardPage {
private SelectionListener completeListener = new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
setPageComplete(isPageComplete());
}
};
/**
* @param pageName
* @param taskRepository
* @param query
*/
public GiteaQueryPage(String pageName, TaskRepository taskRepository, IRepositoryQuery query) {
super(pageName, taskRepository, query);
setDescription("Specify your query");
setPageComplete(false);
}
// ---------------------------------------------------------------------
// DEFINE QUERY TITLE AREA
// ---------------------------------------------------------------------
private Text titleText;
/**
* Create Query title area . Query title is 2 columns based (not same size)
*
* @implNote allocate {@titleText} private Text widget.
*/
private void createQueryTitleArea(Composite parent) {
Composite titleArea = new Composite(parent, SWT.NONE);
GridLayoutFactory.fillDefaults().numColumns(2).applyTo(titleArea);
GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo(titleArea);
new Label(titleArea, SWT.NONE).setText(Labels.QUERY_TITLE);
titleText = new Text(titleArea, SWT.SINGLE | SWT.BORDER);
GridDataFactory.fillDefaults().grab(true, false).applyTo(titleText);
titleText.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
setPageComplete(isPageComplete());
}
});
}
// ---------------------------------------------------------------------
// FILTER BY ISSUE STATE AREA
// ---------------------------------------------------------------------
private Button openButton;
private Button closedButton;
/**
* Create issue state filter area.
*
* @param parent Composite the state filter area is attached to.
* @implNote allocate {@openButton} and @{closedButton} private buttons.
*/
private void createIssueStateArea(Composite parent) {
Composite statusArea = new Composite(parent, SWT.NONE);
GridLayoutFactory.fillDefaults().numColumns(4).equalWidth(false).applyTo(statusArea);
GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo(statusArea);
new Label(statusArea, SWT.NONE).setText(Labels.QUERY_STATE);
openButton = new Button(statusArea, SWT.CHECK);
openButton.setSelection(true);
openButton.setText(IssueState.STATE_OPENED.toString());
openButton.addSelectionListener(completeListener);
closedButton = new Button(statusArea, SWT.CHECK);
closedButton.setSelection(true);
closedButton.setText(IssueState.STATE_CLOSED.toString());
closedButton.addSelectionListener(completeListener);
createRefreshButton(statusArea);
}
// ---------------------------------------------------------------------
// REFRESH BUTTON
// ---------------------------------------------------------------------
private void createRefreshButton(Composite parent) {
ToolBar toolbar = new ToolBar(parent, SWT.FLAT);
ToolItem updateItem = new ToolItem(toolbar, SWT.PUSH);
final Image updateImage = TasksUiImages.REPOSITORY_UPDATE_CONFIGURATION.createImage();
toolbar.addDisposeListener(new DisposeListener() {
@Override
public void widgetDisposed(DisposeEvent e) {
updateImage.dispose();
}
});
updateItem.setImage(updateImage);
updateItem.setToolTipText(Messages.MylynGiteaUIQueryPage_TooltipUpdateRepository);
GridDataFactory.fillDefaults().align(SWT.END, SWT.FILL).grab(true, false).applyTo(toolbar);
updateItem.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
refreshRepository();
}
});
}
// ---------------------------------------------------------------------
// FILTER BY MILESTONE AREA
// ---------------------------------------------------------------------
private Combo milestoneCombo;
/**
* Create milestones selection area.
*
* @param parent Composite the milestone selection area is attached to.
* @implNote Allocate {@literal milestoneCombo} private Combo.
*/
private void createFilterByMilestoneArea(Composite parent) {
Composite milestonesArea = new Composite(parent, SWT.NONE);
GridLayoutFactory.fillDefaults().numColumns(4).equalWidth(false).applyTo(milestonesArea);
GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo(milestonesArea);
Label milestonesLabel = new Label(milestonesArea, SWT.NONE);
milestonesLabel.setText(Labels.QUERY_MILESTONE);
milestoneCombo = new Combo(milestonesArea, SWT.DROP_DOWN | SWT.READ_ONLY);
GridDataFactory.fillDefaults().grab(true, false).applyTo(milestoneCombo);
updateMilestones();
}
// ---------------------------------------------------------------------
// FILTER BY ASSIGNED MEMBER AREA
// ---------------------------------------------------------------------
private Text assigneeText;
private CheckboxTableViewer assignedViewer;
private void refreshAssignedText() {
if ((assigneeText != null) && (assignedViewer != null)) {
List<String> checkedItemsList = new ArrayList<String>();
for (Object o : assignedViewer.getCheckedElements()) {
checkedItemsList.add(((String) o));
}
assigneeText.setText(StringUtils.join(checkedItemsList, ",")); //$NON-NLS-1$
}
}
/**
* Create filter by assigned member area.
*
* @param parent Composite the filter by assigned member area is attached to.
* @implNote Allocate {@literal assignedViewer} private attribute.
*/
private void createFilterByAssignedMembersArea(Composite parent) {
Group assignedArea = new Group(parent, SWT.NONE);
assignedArea.setText(Labels.QUERY_ASSIGNEE);
GridDataFactory.fillDefaults().grab(true, true).applyTo(assignedArea);
GridLayoutFactory.swtDefaults().applyTo(assignedArea);
assigneeText = new Text(assignedArea, SWT.BORDER | SWT.SINGLE);
GridDataFactory.fillDefaults().grab(true, false).applyTo(assigneeText);
assignedViewer = CheckboxTableViewer.newCheckList(assignedArea, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
GridDataFactory.fillDefaults().grab(true, true).hint(100, 80).applyTo(assignedViewer.getControl());
assignedViewer.setContentProvider(ArrayContentProvider.getInstance());
assignedViewer.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {
setPageComplete(isPageComplete());
refreshAssignedText();
}
});
Composite buttonsArea = new Composite(assignedArea, SWT.BORDER | SWT.NONE);
GridDataFactory.fillDefaults().grab(true, false).applyTo(buttonsArea);
GridLayoutFactory.swtDefaults().numColumns(2).equalWidth(true).applyTo(buttonsArea);
final Button selectAllButton = new Button(buttonsArea, SWT.BORDER);
selectAllButton.setText(Labels.QUERY_SELECT_ALL_BUTTON);
GridDataFactory.fillDefaults().grab(true, false).applyTo(selectAllButton);
selectAllButton.addSelectionListener(new SelectionListener() {
@Override
public void widgetSelected(SelectionEvent e) {
assignedViewer.setAllChecked(true);
refreshAssignedText();
}
@Override
public void widgetDefaultSelected(SelectionEvent e) {
}
});
Button selectNoneButton = new Button(buttonsArea, SWT.BORDER);
selectNoneButton.setText(Labels.QUERY_SELECT_NONE_BUTTON);
GridDataFactory.fillDefaults().grab(true, false).applyTo(selectNoneButton);
selectNoneButton.addSelectionListener(new SelectionListener() {
@Override
public void widgetSelected(SelectionEvent e) {
assignedViewer.setAllChecked(false);
refreshAssignedText();
}
@Override
public void widgetDefaultSelected(SelectionEvent e) {
}
});
try {
updateAssigned();
} catch (ApiException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// ---------------------------------------------------------------------
// FILTER BY LABELS AREA
// ---------------------------------------------------------------------
// private TableViewer labelsViewer;
private Text labelsText;
private CheckboxTableViewer labelsViewer; // not issue type, not priority
private void refreshLabelsText() {
if ((labelsText != null) && (labelsViewer != null)) {
List<String> checkedItemsList = new ArrayList<String>();
for (Object o : labelsViewer.getCheckedElements()) {
checkedItemsList.add(((String) o));
}
labelsText.setText(StringUtils.join(checkedItemsList, ",")); //$NON-NLS-1$
}
}
// --private CheckboxTableViewer prioritiesViewer; // 'priority' labels
// --private CheckboxTableViewer issueTypesViewer;// 'issue' type labels
private void createFilterByLabelsArea(Composite parent) {
// Group labelsArea = new Group(parent, SWT.NONE);
// labelsArea.setText(Labels.QUERY_GROUP_LABELS);
// GridDataFactory.fillDefaults().grab(true, true).applyTo(labelsArea);
// GridLayoutFactory.swtDefaults().applyTo(labelsArea);
/**
* -- Group issuesArea = new Group(parent, SWT.NONE);
* issuesArea.setText(Labels.QUERY_GROUP_LABELS_ISSUE_TYPES);
* GridDataFactory.fillDefaults().grab(true, true).applyTo(issuesArea);
* GridLayoutFactory.swtDefaults().applyTo(issuesArea);
*
* Group prioritiesArea = new Group(parent, SWT.NONE);
* prioritiesArea.setText(Labels.QUERY_GROUP_LABELS_PRIORITIES);
* GridDataFactory.fillDefaults().grab(true, true).applyTo(prioritiesArea);
* GridLayoutFactory.swtDefaults().applyTo(prioritiesArea); --
*/
Group labelsArea = new Group(parent, SWT.READ_ONLY);
labelsArea.setText(Labels.QUERY_GROUP_LABELS);
GridDataFactory.fillDefaults().grab(true, true).applyTo(labelsArea);
GridLayoutFactory.swtDefaults().applyTo(labelsArea);
labelsText = new Text(labelsArea, SWT.BORDER);
GridDataFactory.fillDefaults().grab(true, false).applyTo(labelsText);
labelsViewer = CheckboxTableViewer.newCheckList(labelsArea, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
GridDataFactory.fillDefaults().grab(true, true).hint(100, 80).applyTo(labelsViewer.getControl());
labelsViewer.setContentProvider(ArrayContentProvider.getInstance());
labelsViewer.setLabelProvider(new LabelProvider() {
public Image getImage(Object element) {
return GiteaImages.LABEL;
}
});
labelsViewer.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {
setPageComplete(isPageComplete());
refreshLabelsText();
}
});
/*
* -- TODO: filter labels by priority prioritiesViewer =
* CheckboxTableViewer.newCheckList(prioritiesArea, SWT.BORDER | SWT.V_SCROLL |
* SWT.H_SCROLL);
*
* GridDataFactory.fillDefaults().grab(true, true).hint(100,
* 80).applyTo(prioritiesViewer.getControl());
* prioritiesViewer.setContentProvider(ArrayContentProvider.getInstance());
* prioritiesViewer.setLabelProvider(new LabelProvider() { public Image
* getImage(Object element) { return GiteaImages.LABEL; } });
* prioritiesViewer.addSelectionChangedListener(new ISelectionChangedListener()
* {
*
* @Override public void selectionChanged(SelectionChangedEvent event) {
* setPageComplete(isPageComplete()); } }); --
*/
/*
* -- TODO: filter labels by issue type issueTypesViewer =
* CheckboxTableViewer.newCheckList(issuesArea, SWT.BORDER | SWT.V_SCROLL |
* SWT.H_SCROLL);
*
* GridDataFactory.fillDefaults().grab(true, true).hint(100,
* 80).applyTo(issueTypesViewer.getControl());
* issueTypesViewer.setContentProvider(ArrayContentProvider.getInstance());
* issueTypesViewer.setLabelProvider(new LabelProvider() { public Image
* getImage(Object element) { return GiteaImages.LABEL; } });
* issueTypesViewer.addSelectionChangedListener(new ISelectionChangedListener()
* {
*
* @Override public void selectionChanged(SelectionChangedEvent event) {
* setPageComplete(isPageComplete()); } }); --
*/
Composite buttonsArea = new Composite(labelsArea, SWT.BORDER | SWT.NONE);
GridDataFactory.fillDefaults().grab(true, false).applyTo(buttonsArea);
GridLayoutFactory.swtDefaults().numColumns(2).equalWidth(true).applyTo(buttonsArea);
final Button selectAllButton = new Button(buttonsArea, SWT.BORDER);
selectAllButton.setText(Labels.QUERY_SELECT_ALL_BUTTON);
GridDataFactory.fillDefaults().grab(true, false).applyTo(selectAllButton);
selectAllButton.addSelectionListener(new SelectionListener() {
@Override
public void widgetSelected(SelectionEvent e) {
labelsViewer.setAllChecked(true);
refreshLabelsText();
}
@Override
public void widgetDefaultSelected(SelectionEvent e) {
}
});
Button selectNoneButton = new Button(buttonsArea, SWT.BORDER);
selectNoneButton.setText(Labels.QUERY_SELECT_NONE_BUTTON);
GridDataFactory.fillDefaults().grab(true, false).applyTo(selectNoneButton);
selectNoneButton.addSelectionListener(new SelectionListener() {
@Override
public void widgetSelected(SelectionEvent e) {
labelsViewer.setAllChecked(false);
refreshLabelsText();
}
@Override
public void widgetDefaultSelected(SelectionEvent e) {
}
});
/*
* newLabel.addFocusListener(new FocusListener() {
*
* @Override public void focusLost(FocusEvent e) {
* getShell().setDefaultButton(null); setPageComplete(isPageComplete()); }
*
* @Override public void focusGained(FocusEvent e) {
* getShell().setDefaultButton(btnAdd); } });
* labelsViewer.getTable().addKeyListener(new KeyListener() {
*
* @Override public void keyReleased(KeyEvent e) { if (e.keyCode == SWT.DEL) {
* removeSelection(); } }
*
* @Override public void keyPressed(KeyEvent e) { } });
*/
updateLabels();
}
private void createLeftColumnArea(Composite parent) {
Composite leftArea = new Composite(parent, SWT.NONE);
GridLayoutFactory.fillDefaults().numColumns(2).applyTo(leftArea);
GridDataFactory.fillDefaults().grab(true, true).applyTo(leftArea);
createIssueStateArea(leftArea);
createFilterByAssignedMembersArea(leftArea);
}
private void createRightColumnArea(Composite parent) {
Composite rightArea = new Composite(parent, SWT.NONE);
GridLayoutFactory.fillDefaults().numColumns(2).applyTo(rightArea);
GridDataFactory.fillDefaults().grab(true, true).applyTo(rightArea);
createFilterByMilestoneArea(rightArea);
createFilterByLabelsArea(rightArea);
}
/**
* Create Composite displayArea (2 columns based).
* |---------------------------------------| |
* <QueryTitleArea.....................> | | <LeftColumnArea> |
* <RightColumnArea> | |---------------------------------------|
*/
public void createControl(Composite parent) {
Composite displayArea = new Composite(parent, SWT.NONE);
GridLayoutFactory.fillDefaults().numColumns(2).equalWidth(true).applyTo(displayArea);
GridDataFactory.fillDefaults().grab(true, true).applyTo(displayArea);
if (!inSearchContainer()) {
createQueryTitleArea(displayArea);
}
createLeftColumnArea(displayArea);
createRightColumnArea(displayArea);
initialize();
setControl(displayArea);
}
private void initialize() {
IRepositoryQuery query = getQuery();
if (query == null) {
return;
}
titleText.setText(query.getSummary());
// assigneeText.setText(query.getAttribute("assignee"));
milestoneCombo.setText(query.getAttribute("milestone"));
openButton.setSelection(Boolean.parseBoolean(query.getAttribute("opened")));
closedButton.setSelection(Boolean.parseBoolean(query.getAttribute("closed")));
try {
updateAssigned();
} catch (ApiException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
updateLabels();
/*
* for (String label : query.getAttribute("labels").split(",")) { if
* (label.trim().length() > 0) { labelsViewer.add(label.trim()); } }
*/
}
public boolean isPageComplete() {
boolean complete = inSearchContainer() ? true : super.isPageComplete();
if (complete) {
String message = null;
if (!openButton.getSelection() && !closedButton.getSelection()) {
message = "Select either closed, opened or both issue states";
}
setErrorMessage(message);
complete = message == null;
}
return complete;
}
public String getQueryTitle() {
return titleText != null ? titleText.getText() : null;
}
public void applyTo(IRepositoryQuery query) {
query.setSummary(titleText.getText());
query.setAttribute("assignee", labelsText.getText());
query.setAttribute("milestone", milestoneCombo.getText());
query.setAttribute("opened", "" + openButton.getSelection());
query.setAttribute("closed", "" + closedButton.getSelection());
ArrayList<String> labels = new ArrayList<String>();
/*
* TODO: filter labels by issue type or priorities {{{ for (Object o :
* issueTypesViewer.getCheckedElements()) { labels.add(((String)o)); } for
* (Object o : prioritiesViewer.getCheckedElements()) { labels.add(((String)o));
* } }}}
*/
for (Object o : labelsViewer.getCheckedElements()) {
labels.add(((String) o));
}
query.setAttribute("labels", StringUtils.join(labels, ","));
}
private boolean updateLabels() {
if (labelsViewer == null)
return false;
if (labelsViewer.getControl().isDisposed())
return false;
boolean hasLabels = false;
GiteaConnection connection = ConnectionManager.getSafe(getTaskRepository());
if (connection != null) {
List<io.gitea.model.Label> labels = connection.getLabels();
// Collections.sort(labels, Comparator.comparing(
// io.gitea.model.Label::getName, String.CASE_INSENSITIVE_ORDER));
hasLabels = !labels.isEmpty();
List<String> allLabelsNames = new ArrayList<String>();
labels.forEach((label) -> allLabelsNames.add(label.getName()));
labelsViewer.setInput(allLabelsNames);
/*
* TODO: filter labels by issue types and priorities {{{ List<String>
* issueTypesNames = IssueType.getAllIssueType(allLabelsNames); List<String>
* prioritiesNames = GiteaPriorityLevel.getAllPriorityLabels(allLabelsNames);
* List<String> otherLabelsNames = new ArrayList<String>();
* allLabelsNames.forEach((label) -> { if ((!prioritiesNames.contains(label))
* &&(!issueTypesNames.contains(label))) otherLabelsNames.add(label); });
*
* labelsViewer.setInput(otherLabelsNames);
* prioritiesViewer.setInput(prioritiesNames);
* issueTypesViewer.setInput(issueTypesNames); }}}
*/
// When coming from existing query, update the dialog to reflect query ...
IRepositoryQuery query = getQuery();
if (query != null) {
List<String> labelsInQuery = new ArrayList<String>();
Arrays.asList(query.getAttribute("labels").split(",")).forEach((label) -> {
if (label.trim().length() > 0)
labelsInQuery.add(label.trim());
});
List<String> labelsToCheck = new ArrayList<String>();
/*
* TODO: filter labels by issue types and priority {{{ List<String>
* priorityToCheck = new ArrayList<String>(); List<String> issueTypeToCheck =
* new ArrayList<String>(); }}}
*/
List<String> labelToGreyed = new ArrayList<String>();
labelsInQuery.forEach((label) -> {
if (allLabelsNames.contains(label))
labelsToCheck.add(label);
/*
* TODO: filter labels by issue types or priorities {{{ if
* (prioritiesNames.contains(label)) priorityToCheck.add(label); else if
* (otherLabelsNames.contains(label)) labelsToCheck.add(label); else
* labelToGreyed.add(label); }}}
*/
});
labelsViewer.setCheckedElements(labelsToCheck.toArray());
refreshLabelsText();
/*
* TODO: filter labels by issue types or priorities {{{
* prioritiesViewer.setCheckedElements(labelsToCheck.toArray()); }}}
*/
// labelsViewer.setGrayedElements(labelsToGreyed.toArray());
}
}
return hasLabels;
}
private boolean updateMilestones() {
if (milestoneCombo.isDisposed())
return false;
boolean hasMilestones = false;
GiteaConnection connection = ConnectionManager.getSafe(getTaskRepository());
if (connection != null) {
List<Milestone> milestones = connection.getMilestones();
hasMilestones = !milestones.isEmpty();
milestoneCombo.removeAll();
// Collections.sort(milestones, Comparator.comparing(
// Milestone::getTitle, String.CASE_INSENSITIVE_ORDER));
milestoneCombo.add("");
for (Milestone s : milestones) {
milestoneCombo.add(s.getTitle());
}
milestoneCombo.select(0);
}
return hasMilestones;
}
private boolean updateAssigned() throws ApiException {
boolean hasAssigned = false;
if (labelsViewer == null)
return false;
if (labelsViewer.getControl().isDisposed())
return false;
GiteaConnection connection = ConnectionManager.getSafe(getTaskRepository());
if (connection != null) {
IRepositoryQuery query = getQuery();
List<String> usersNames = new ArrayList<String>();
connection.repoListAllCollaborators().forEach((user) -> usersNames.add(GiteaUser.getName(user)));
List<String> assignedInQuery = new ArrayList<String>();
Arrays.asList(query.getAttribute("assignee").split(",")).forEach((assignee) -> {
if (assignee.trim().length() > 0)
assignedInQuery.add(assignee.trim());
});
List<String> assignedList = new ArrayList<String>();
usersNames.forEach((assignee) -> {
if (assignedInQuery.contains(assignee))
assignedList.add(assignee);
});
assignedViewer.setInput(usersNames);
assignedViewer.setCheckedElements(assignedList.toArray());
}
return hasAssigned;
}
private void refreshRepository() {
try {
ICoreRunnable runnable = new ICoreRunnable() {
@Override
public void run(IProgressMonitor monitor) throws CoreException {
Policy.monitorFor(monitor);
monitor.beginTask("", 3); //$NON-NLS-1$
GiteaConnection connection = ConnectionManager.getSafe(getTaskRepository());
monitor.setTaskName(Messages.MylynGiteaUIQueryPage_LoadingLabels);
connection.refreshLabels();
monitor.worked(1);
monitor.setTaskName(Messages.MylynGiteaUIQueryPage_LoadingMembers);
connection.refreshMembers();
monitor.worked(1);
monitor.setTaskName(Messages.MylynGiteaUIQueryPage_LoadingMilestones);
connection.refreshMilestones();
monitor.done();
PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
@Override
public void run() {
updateLabels();
updateMilestones();
initialize();
}
});
}
};
IRunnableContext context = getContainer();
if (context == null)
if (inSearchContainer())
context = getSearchContainer().getRunnableContext();
else
context = PlatformUI.getWorkbench().getProgressService();
CommonUiUtil.run(context, runnable);
} catch (CoreException e) {
IStatus status = e.getStatus();
ErrorDialog.openError(getShell(), Messages.MylynGiteaUIQueryPage_ErrorLoading, e.getLocalizedMessage(),
status);
}
}
}

View File

@ -1,150 +0,0 @@
// Copyright (c) 2021, Fr.Terrot. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package io.gitea.mylyn.ui;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.mylyn.tasks.core.TaskRepository;
import org.eclipse.mylyn.tasks.ui.wizards.AbstractRepositorySettingsPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import io.gitea.mylyn.core.GiteaConnector;
import io.gitea.mylyn.core.GiteaPluginCore;
/** Mylyn Gitea repository configuration page. */
public class GiteaRepositorySettingsPage extends AbstractRepositorySettingsPage {
private Button useToken;
private Text giteaBaseUrl;
public GiteaRepositorySettingsPage(String title, String description, TaskRepository taskRepository) {
super(title, description, taskRepository);
setNeedsValidateOnFinish(true);
}
@Override
protected void createAdditionalControls(final Composite composite) {
savePasswordButton.setSelection(true);
useToken = new Button(composite, SWT.CHECK);
useToken.setText("Use private token instead of username/password");
GridDataFactory.fillDefaults().span(2, 1).applyTo(useToken);
useToken.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
setUsernameFieldEnabled(!useToken.getSelection());
getWizard().getContainer().updateButtons();
}
@Override
public void widgetDefaultSelected(SelectionEvent e) {
}
});
Label l = new Label(composite, SWT.NONE);
l.setText("Gitea base URL");
giteaBaseUrl = new Text(composite, SWT.SINGLE | SWT.BORDER);
GridDataFactory.fillDefaults().span(1, 1).applyTo(giteaBaseUrl);
/**
* Set widget texts and check boxes if necessary.
*/
if (serverUrlCombo.getText().length() == 0) {
// This means, that there the user is *not* editing an existing repository
// configuration
serverUrlCombo.setText("https://your-host.org/namespace/repository.git");
serverUrlCombo.setText(Labels.SAMPLE_URL);
}
if (getRepository() != null) {
if ("true".equals(getRepository().getProperty("usePrivateToken"))) {
useToken.setSelection(true);
setUsernameFieldEnabled(false);
}
if (getRepository().getProperty("giteaBaseUrl") != null) {
giteaBaseUrl.setText(getRepository().getProperty("giteaBaseUrl"));
}
} else {
// Default is to use token
useToken.setSelection(true); // Let select use token by default
setUsernameFieldEnabled(false);
}
}
private void setUsernameFieldEnabled(boolean enabled) {
if (enabled) {
repositoryUserNameEditor.getTextControl(compositeContainer).setEnabled(true);
repositoryUserNameEditor.setEmptyStringAllowed(false);
repositoryPasswordEditor.setLabelText(LABEL_PASSWORD);
compositeContainer.layout();
} else {
repositoryUserNameEditor.setStringValue("");
repositoryUserNameEditor.getTextControl(compositeContainer).setEnabled(false);
repositoryUserNameEditor.setEmptyStringAllowed(true);
repositoryPasswordEditor.setLabelText("Private token:");
compositeContainer.layout();
}
}
@Override
public String getConnectorKind() {
return GiteaPluginCore.CONNECTOR_KIND;
}
@Override
public TaskRepository createTaskRepository() {
TaskRepository repo = super.createTaskRepository();
return repo;
}
@Override
public void applyTo(TaskRepository repository) {
repository.setCategory(TaskRepository.CATEGORY_BUGS);
super.applyTo(repository);
if (useToken.getSelection()) {
repository.setProperty("usePrivateToken", "true");
} else {
repository.setProperty("usePrivateToken", "false");
}
repository.setProperty("giteaBaseUrl", giteaBaseUrl.getText());
}
@Override
protected boolean isMissingCredentials() {
if (useToken != null && useToken.getSelection()) {
return repositoryPasswordEditor.getStringValue().trim().equals("");
} else {
return super.isMissingCredentials();
}
}
@Override
protected Validator getValidator(final TaskRepository repository) {
return new Validator() {
@Override
public void run(IProgressMonitor monitor) throws CoreException {
GiteaConnector.validate(repository);
}
};
}
}

View File

@ -1,33 +0,0 @@
// Copyright (c) 2021, Fr.Terrot. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package io.gitea.mylyn.ui;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;
public class GiteaUIPlugin extends AbstractUIPlugin {
private static GiteaUIPlugin plugin;
public GiteaUIPlugin() {
plugin = this;
}
@Override
public void start(BundleContext context) throws Exception {
super.start(context);
}
@Override
public void stop(BundleContext context) throws Exception {
plugin = null;
super.stop(context);
}
public static GiteaUIPlugin getDefault() {
return plugin;
}
}

View File

@ -1,33 +0,0 @@
// Copyright (c) 2021, Fr.Terrot. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package io.gitea.mylyn.ui;
public class Labels {
public final static String SAMPLE_URL = "https://forge.chapril.org/gitea/mylyn-gitea.git";
public final static String NEW_REPOSITORY = "New repository";
public final static String SETTINGS_PAGE = "Enter the HTTPS-URL to your Gitea repository";
public final static String QUERY_TITLE = "Query title: ";
public final static String QUERY_GROUP_LABELS = "Labels";
public final static String QUERY_GROUP_LABELS_ISSUE_TYPES = "Issue Types Labels";
public final static String QUERY_GROUP_LABELS_PRIORITIES = "Priorities Labels";
public final static String QUERY_GROUP_LABELS_OTHERS = "Others Labels";
public final static String QUERY_SELECT_ALL_BUTTON = "Check All";
public final static String QUERY_SELECT_NONE_BUTTON = "Uncheck All";
public final static String QUERY_NEW_LABEL_REGEX = "Add label regex";
public final static String QUERY_REMOVE_LABEL_REGEX = "Remove selected label";
public final static String QUERY_ASSIGNEE = "Assignee: ";
public final static String QUERY_MILESTONE = "Milestone: ";
public final static String QUERY_STATE = "State: ";
public final static String GITEA_ISSUE = "Gitea issue";
public final static String GITEA_CONNETOR_NAME = "Mylyn/Gitea Tasks Connector";
public final static String NEW_PAGE = "New Page";
}

View File

@ -1,23 +0,0 @@
// Copyright (c) 2021, Fr.Terrot. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package io.gitea.mylyn.ui;
import org.eclipse.osgi.util.NLS;
public class Messages extends NLS {
private static final String BUNDLE_NAME = "io.gitea.mylyn.ui.messages"; //$NON-NLS-1$
public static String MylynGiteaUIQueryPage_TooltipUpdateRepository;
public static String MylynGiteaUIQueryPage_ErrorLoading;
public static String MylynGiteaUIQueryPage_LoadingLabels;
public static String MylynGiteaUIQueryPage_LoadingMilestones;
public static String MylynGiteaUIQueryPage_LoadingMembers;
static {
// initialize resource bundle
NLS.initializeMessages(BUNDLE_NAME, Messages.class);
}
private Messages() {
}
}

View File

@ -1,5 +0,0 @@
MylynGiteaUIQueryPage_TooltipUpdateRepository=Update milestones, labels and team members
MylynGiteaUIQueryPage_ErrorLoading=Error loading labels and milestones
MylynGiteaUIQueryPage_TaskLoadingLabels=Loading labels...
MylynGiteaUIQueryPage_TaskLoadingMilestones=Loading Milestones...
MylynGiteaUIQueryPage_TaskLoadingMembers=Loading team members...

@ -1 +0,0 @@
Subproject commit d35302a7f02e58e3bcb8aaa03baee563793967b6

View File

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>io.gitea.mylyn</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>

View File

@ -1,32 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.pde.ui.RuntimeWorkbench">
<booleanAttribute key="append.args" value="true"/>
<booleanAttribute key="askclear" value="true"/>
<booleanAttribute key="automaticAdd" value="true"/>
<booleanAttribute key="automaticValidate" value="true"/>
<stringAttribute key="bootstrap" value=""/>
<stringAttribute key="checked" value="[NONE]"/>
<booleanAttribute key="clearConfig" value="true"/>
<booleanAttribute key="clearws" value="false"/>
<booleanAttribute key="clearwslog" value="false"/>
<stringAttribute key="configLocation" value="${workspace_loc}/.metadata/.plugins/org.eclipse.pde.core/Debug"/>
<booleanAttribute key="default" value="true"/>
<booleanAttribute key="includeOptional" value="true"/>
<stringAttribute key="location" value="${workspace_loc}/../runtime-Debug"/>
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
</listAttribute>
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11"/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog"/>
<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
<stringAttribute key="pde.version" value="3.3"/>
<stringAttribute key="product" value="org.eclipse.platform.ide"/>
<booleanAttribute key="show_selected_only" value="false"/>
<stringAttribute key="templateConfig" value="${target_home}/configuration/config.ini"/>
<booleanAttribute key="tracing" value="false"/>
<booleanAttribute key="useCustomFeatures" value="false"/>
<booleanAttribute key="useDefaultConfig" value="true"/>
<booleanAttribute key="useDefaultConfigArea" value="true"/>
<booleanAttribute key="useProduct" value="true"/>
</launchConfiguration>

View File

@ -1,19 +0,0 @@
MIT License Copyright (c) 2021 F.Terrot
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sub-license, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,3 +0,0 @@
bin.includes = feature.xml,\
feature.properties,\
LICENSE

View File

@ -1,46 +0,0 @@
#/* **************************************************************************
# *
# * Copyright (c) 2021, Fr.Terrot
# *
# * All rights reserved.
# *
# * This program and the accompanying materials are made available under the terms
# * of the Eclipse Public License v2.0 which accompanies this distribution, and is
# * available at http://www.eclipse.org/legal/epl-v20.html
# *
# * ************************************************************************** */
featureName=Mylyn Gitea Connector
providerName=Gitea
description=Mylyn Tasks connector for the open source management software Gitea.
# "licenseURL" property - URL of the "Feature License"
# do not translate value - just change to point to a locale-specific HTML page
licenseURL=
# "license" property - text of the "Feature Update License"
# should be plain text version of license agreement pointed to be "licenseURL"
license=\
\n
MIT License Copyright (c) 2021 F.Terrot\n
\n
Permission is hereby granted, free of charge, to any person obtaining a copy\n
of this software and associated documentation files (the "Software"), to deal\n
in the Software without restriction, including without limitation the rights\n
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n
copies of the Software, and to permit persons to whom the Software is furnished\n
to do so, subject to the following conditions:\n
\n
The above copyright notice and this permission notice (including the next\n
paragraph) shall be included in all copies or substantial portions of the\n
Software.\n
\n
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS\n
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF\n
OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n
\n
########### end of license property ##########################################

View File

@ -1,87 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<feature
id="io.gitea.mylyn"
label="Mylyn/Gitea Tasks Connector"
version="0.3.1"
provider-name="io.gitea">
<description>
%description
</description>
<copyright>
MIT License Copyright (c) 2021 F.Terrot
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the &quot;Software&quot;), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sub-license, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
</copyright>
<license url="">
MIT License Copyright (c) 2021 F.Terrot
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the &quot;Software&quot;), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sub-license, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
</license>
<url>
<update label="Mylyn/Gitea Tasks Connector Update Site" url="https://teilginn.github.io/mylyn-gitea-updatesite/"/>
</url>
<requires>
<import plugin="org.eclipse.core.runtime"/>
<import plugin="org.eclipse.mylyn.tasks.core" version="3.8.0" match="compatible"/>
<import plugin="org.eclipse.mylyn.tasks.ui"/>
<import plugin="org.eclipse.mylyn.commons.net" version="3.8.0" match="compatible"/>
<import plugin="org.eclipse.ui"/>
<import plugin="org.eclipse.ui.forms"/>
<import plugin="org.eclipse.mylyn.commons.core" version="3.8.0" match="compatible"/>
<import plugin="org.eclipse.mylyn.tasks.ui" version="3.8.0" match="compatible"/>
<import plugin="org.eclipse.mylyn.commons.workbench" version="3.8.0" match="compatible"/>
<import plugin="org.eclipse.mylyn.commons.ui" version="3.8.0" match="compatible"/>
</requires>
<plugin
id="io.gitea.mylyn.core"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
<plugin
id="io.gitea.mylyn.ui"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
</feature>

@ -1 +0,0 @@
Subproject commit 0f63be058234fcfa1bce7d09f3b4caff06f84ffc

View File

@ -1,11 +0,0 @@
[JARSIGN]
skip:false
keyname:
storepass:
keystore:
[GPG]
skip=false
keyname:
passphrase:
verbose: