diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bee8a64 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +__pycache__ diff --git a/Pipfile b/Pipfile new file mode 100644 index 0000000..6b13324 --- /dev/null +++ b/Pipfile @@ -0,0 +1,19 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +jira = "*" +PyGithub = "*" +python-gitlab = "*" +toml = "*" + +[dev-packages] +neovim = "*" +pyflakes = "*" +pylint = "*" +mypy = "*" + +[requires] +python_version = "3.7" diff --git a/project.full.json b/project.full.json new file mode 100644 index 0000000..90498c3 --- /dev/null +++ b/project.full.json @@ -0,0 +1,26 @@ +{ + "apis": { + "branch": "master", + "vsc": "git", + "token": "token", + "type": "gitlab", + "url": "url" + }, + "projects": [{ + "vcs": "git", + "branch": null, + "issues": { + "type": "gitlab", + "api": null + }, + "reviews": { + "type": "gitlab", + "api": null + }, + "ci": { + "type": "gitlab", + "api": null + } + } + ] +} diff --git a/project.json b/project.json new file mode 100644 index 0000000..b9910a8 --- /dev/null +++ b/project.json @@ -0,0 +1,7 @@ +{ + "apis": { + "gitlab": { + "token" + } + } +} diff --git a/rplugin/python3/base/__init__.py b/rplugin/python3/base/__init__.py new file mode 100644 index 0000000..5cdf642 --- /dev/null +++ b/rplugin/python3/base/__init__.py @@ -0,0 +1,3 @@ +from .issues import IssuesProvider, Issue, IssueFilters +from .reviews import MergeRequest, ReviewsProvider +from .project import Project diff --git a/rplugin/python3/base/config.py b/rplugin/python3/base/config.py new file mode 100644 index 0000000..d02de3c --- /dev/null +++ b/rplugin/python3/base/config.py @@ -0,0 +1,50 @@ +from __future__ import annotations +import subprocess +from typing import Optional, List +from pathlib import Path +import json + +from .constants import IssuesSoftware, ReviewSoftware, VcsSoftware + + +class Config: + config_name = "project.json" + apis: List[ApiConfig] + projects: List[ProjectConfig] + + @staticmethod + def create(cwd: str) -> Config: + config_path = Config.get_config_path(cwd=Path(cwd)) + config_data = {} + if config_path != None: + with config_path.open('r') as fp: + config_data = json.parse(fp) + return Config() + + @staticmethod + def get_config_path(cwd: Path = None) -> Optional[Path]: + if cwd: + config_path = cwd / Config.config_name + if config_path.exists(): + return config_path + + commands = (['git', 'rev-parse', '--show-toplevel'], ['hg', 'root']) + for vcs, resp in ((command[0], subprocess.run(command, stdout=subprocess.PIPE)) + for command in commands): + if resp.returncode == 0: + return Path(resp.stdout.decode().strip()) + + return None + + +class ApiConfig: + url: str + token: Optional[str] + type_: str + +class ProjectConfig: + pass + +class VcsConfig: + type_: str + url: str diff --git a/rplugin/python3/base/constants.py b/rplugin/python3/base/constants.py new file mode 100644 index 0000000..2a636cc --- /dev/null +++ b/rplugin/python3/base/constants.py @@ -0,0 +1,26 @@ +from enum import Enum, unique + + +@unique +class IssuesSoftware(Enum): + bitbucket = 0 + bugzilla = 1 + github = 2 + gitlab = 3 + jira = 4 + phabricator = 5 + + +@unique +class ReviewSoftware(Enum): + bitbucket = 0 + fisheye = 1 + github = 2 + gitlab = 3 + phabricator = 4 + + +@unique +class VcsSoftware(Enum): + hg = 0 + git = 1 diff --git a/rplugin/python3/base/issues.py b/rplugin/python3/base/issues.py new file mode 100644 index 0000000..1a2d1cf --- /dev/null +++ b/rplugin/python3/base/issues.py @@ -0,0 +1,43 @@ +from typing import List +from abc import ABC, abstractmethod, abstractstaticmethod +from .config import Config + +class Issue: + identifier: str + title: str + author: str + + +class IssueFilters(ABC): + pass + + +class IssuesProvider(ABC): + def __init__(self, config: Config): + self.config = config + + @abstractmethod + def create_issue(self) -> Issue: + pass + + @staticmethod + def format_issues(issues: List[Issue]) -> List[str]: + return [ + "* #{identifier} - {title}".format( + identifier=issue.identifier, title=issue.title + ) for issue in issues + ] + + @abstractmethod + def get_issues(self, page: int, filters: IssueFilters) -> List[Issue]: + pass + + @abstractmethod + def get_releases(self): + pass + + @abstractstaticmethod + def get_project_name( + vcs_url: str, issues_url: str, review_url: str + ) -> str: + pass diff --git a/rplugin/python3/base/project.py b/rplugin/python3/base/project.py new file mode 100644 index 0000000..c30222f --- /dev/null +++ b/rplugin/python3/base/project.py @@ -0,0 +1,14 @@ +from abc import ABC, abstractmethod +from typing import Optional + +from .issues import IssuesProvider +from .reviews import ReviewsProvider + + +class Project(ABC): + issues: IssuesProvider + reviews: ReviewsProvider + + @abstractmethod + def __init__(self, repo_url: str, token: Optional[str]): + pass diff --git a/rplugin/python3/base/reviews.py b/rplugin/python3/base/reviews.py new file mode 100644 index 0000000..4b3c53b --- /dev/null +++ b/rplugin/python3/base/reviews.py @@ -0,0 +1,12 @@ +from abc import ABC, abstractmethod +from typing import List + + +class MergeRequest(ABC): + pass + + +class ReviewsProvider(ABC): + @abstractmethod + def get(self) -> List[MergeRequest]: + pass diff --git a/rplugin/python3/main.py b/rplugin/python3/main.py new file mode 100644 index 0000000..4531b82 --- /dev/null +++ b/rplugin/python3/main.py @@ -0,0 +1,27 @@ +import sys +from pathlib import Path + +sys.path.append(str(Path(__file__).parent)) + +import neovim + +from base.config import Config +from providers.gitlab import GitlabProject + + +@neovim.plugin +class VimIssues: + def __init__(self, nvim: neovim.Nvim) -> None: + self.nvim = nvim + self.config = Config.create(nvim.funcs.cwd()) + + @neovim.function("ReloadConfig", sync=True) + def reload(self, args): + Config.create(self.nvim.funcs.cwd()) + return 'some string' + + # @neovim.command('Issues', range='', nargs='*') + # def issues(self, args, range_): + # issues = self.project.get_issues(8, 2) + # formatted = self.project.format_issues(issues) + # self.nvim.current.buffer[:] = formatted diff --git a/rplugin/python3/providers/github/__init__.py b/rplugin/python3/providers/github/__init__.py new file mode 100644 index 0000000..ca3effd --- /dev/null +++ b/rplugin/python3/providers/github/__init__.py @@ -0,0 +1,2 @@ +from .issues import GithubIssues +from .reviews import GithubReviews diff --git a/rplugin/python3/providers/github/issues.py b/rplugin/python3/providers/github/issues.py new file mode 100644 index 0000000..b62283e --- /dev/null +++ b/rplugin/python3/providers/github/issues.py @@ -0,0 +1,38 @@ +from typing import List + +import github +from github import Github + +from base import Config, Issue, IssueFilters, IssuesProvider, MergeRequest + + +class GithubIssues(IssuesProvider): + def __init__(self, config: Config): + super().__init__(config) + self.api = Github() + + def create_issue(self) -> Issue: + pass + + def get_issues(self, page: int, filters: IssueFilters) -> List[Issue]: + r = self.api.get_repo('neovim/python-client') + return [self._get_issue_data(i) for i in r.get_issues()] + + def get_merge_requests(self) -> List[MergeRequest]: + pass + + def get_releases(self): + pass + + @staticmethod + def get_project_name( + vcs_url: str, issues_url: str, review_url: str + ) -> str: + pass + + @staticmethod + def _get_issue_data(issue: github.Issue.Issue) -> Issue: + i = Issue() + i.identifier = str(issue.number) + i.title = issue.title + return i diff --git a/rplugin/python3/providers/github/project.py b/rplugin/python3/providers/github/project.py new file mode 100644 index 0000000..cdfc5c3 --- /dev/null +++ b/rplugin/python3/providers/github/project.py @@ -0,0 +1,14 @@ +from typing import Optional + +from github import Github + +from base import IssuesProvider, Project, ReviewsProvider + + +class GithubProject(Project): + def __init__(self, repo_url: str, token: Optional[str]): + self.repo_url = repo_url + self.token = token + + if token is not None: + self._api = Github() diff --git a/rplugin/python3/providers/github/reviews.py b/rplugin/python3/providers/github/reviews.py new file mode 100644 index 0000000..c49a59b --- /dev/null +++ b/rplugin/python3/providers/github/reviews.py @@ -0,0 +1,8 @@ +from typing import List + +from base import MergeRequest, ReviewsProvider + + +class GithubReviews(ReviewsProvider): + def get(self) -> List[MergeRequest]: + pass diff --git a/rplugin/python3/providers/gitlab/__init__.py b/rplugin/python3/providers/gitlab/__init__.py new file mode 100644 index 0000000..4098ec2 --- /dev/null +++ b/rplugin/python3/providers/gitlab/__init__.py @@ -0,0 +1,2 @@ +class GitlabProject(): + pass diff --git a/rplugin/python3/providers/gitlab/reviews.py b/rplugin/python3/providers/gitlab/reviews.py new file mode 100644 index 0000000..97be7b3 --- /dev/null +++ b/rplugin/python3/providers/gitlab/reviews.py @@ -0,0 +1,9 @@ +from typing import List + +from base import MergeRequest, ReviewsProvider + + +class GithubReviews(ReviewsProvider): + def __init__(self, config) + def get(self) -> List[MergeRequest]: + pass diff --git a/syntax/vimissues.vim b/syntax/vimissues.vim new file mode 100644 index 0000000..ab6e229 --- /dev/null +++ b/syntax/vimissues.vim @@ -0,0 +1,12 @@ +if exists('b:current_syntax') + finish +endif + +syn match issuesId "\v#\d+" +hi def link issuesId Identifier + +syn include @Markdown syntax/markdown.vim +syn region AWKScriptCode matchgroup=AWKCommand start=+[=\\]\@+ skip=+\\$+ end=+[=\\]\@