-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added abstract backend base with Gitlab implementation (#102)
* Fixed pyflakes errors, upgraded to 1.6.0. * Added *Base backend, separated Gitlab backends. Added decorator to get backend. * Changelog update. Fixed pyflakes error about imports in __init__.py Converted to @require_backend calling @config_context. Added basic mock backend. Updated double decorator calls. Removed changelog message about backend. * Added MockBackend with config hooks. Added hook for MockBackend in config. Mock backend now works but doesn't do much. Updated doc / references to base repo to now reference template repo. Added linting error exception. * Moved Access into backends, renamed config/backend decorators. Moved Access into backend, fixed unit tests and remaining TODOs. Renamed requires_backend to requires_backend_and_config renamed config_context to requires_config. Added changelog messages. Added note about base repo -> template repo. Send integer Access level rather than enum name * Added catch to print warnings for backend missing in config. Updated tests. Rembed unneeded pyflakes override. Ran sed on files to appease nitpicks. Moved changelog to the correct spot. Fixed linting error with asigner_test test case. * Fixed merge conflicts, updated tests. Removed artifact config.py Fixed get integration test errors. * Select backend based on backend name * Split name-to-backend conversion into its own function and associated exception * py3.4/3.5 compatible type annotations * Add classmethod return type signatures Also add a couple git ones that got missed.
- Loading branch information
Showing
27 changed files
with
643 additions
and
123 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
from assigner.backends.base import BackendBase, RepoError | ||
from assigner.backends.gitlab import GitlabBackend | ||
from assigner.backends.mock import MockBackend | ||
|
||
pyflakes = [BackendBase, RepoError, GitlabBackend, MockBackend] | ||
|
||
backend_names = { | ||
"gitlab": GitlabBackend, | ||
"mock": MockBackend, | ||
} | ||
|
||
class NoSuchBackend(Exception): | ||
pass | ||
|
||
def from_name(name: str): | ||
try: | ||
return backend_names[name] | ||
except KeyError: | ||
raise NoSuchBackend("Cannot find backend with name {}".format(name)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
import git | ||
import re | ||
from typing import Optional, Type, TypeVar | ||
|
||
|
||
class RepoError(Exception): | ||
pass | ||
|
||
|
||
T = TypeVar('T', bound='RepoBase') | ||
class RepoBase: | ||
"""Generic Repo base""" | ||
|
||
PATH_RE = re.compile( | ||
r"^/(?P<namespace>[\w\-\.]+)/(?P<name>[\w\-\.]+)\.git$" | ||
) | ||
|
||
def __init__(self, url_base: str, namespace: str, name: str, token: str, url: Optional[str] = None): | ||
raise NotImplementedError | ||
|
||
@classmethod | ||
def build_url(cls, config, namespace: str, name: str) -> str: | ||
""" Builds a url for a repository """ | ||
raise NotImplementedError | ||
|
||
@classmethod | ||
def from_url(cls: Type[T], url: str, token: str) -> T: | ||
raise NotImplementedError | ||
|
||
@property | ||
def name_with_namespace(self) -> str: | ||
raise NotImplementedError | ||
|
||
@property | ||
def namespace_id(self) -> str: | ||
raise NotImplementedError | ||
|
||
@property | ||
def id(self) -> str: | ||
raise NotImplementedError | ||
|
||
@property | ||
def info(self) -> Optional[str]: | ||
raise NotImplementedError | ||
|
||
@property | ||
def repo(self) -> Optional[git.Repo]: | ||
raise NotImplementedError | ||
|
||
@property | ||
def ssh_url(self) -> str: | ||
raise NotImplementedError | ||
|
||
def already_exists(self) -> bool: | ||
raise NotImplementedError | ||
|
||
def get_head(self, branch: str) -> git.refs.head.Head: | ||
raise NotImplementedError | ||
|
||
def checkout(self, branch: str) -> git.refs.head.Head: | ||
raise NotImplementedError | ||
|
||
def pull(self, branch: str) -> None: | ||
raise NotImplementedError | ||
|
||
def clone_to(self, dir_name: str, branch: Optional[str]) -> None: | ||
raise NotImplementedError | ||
|
||
def add_local_copy(self, dir_name: str) -> None: | ||
raise NotImplementedError | ||
|
||
def delete(self) -> None: | ||
raise NotImplementedError | ||
|
||
@classmethod | ||
def get_user_id(cls, username: str, config) -> str: | ||
raise NotImplementedError | ||
|
||
def list_members(self) -> str: | ||
raise NotImplementedError | ||
|
||
def get_member(self, user_id: str) -> str: | ||
raise NotImplementedError | ||
|
||
def add_member(self, user_id: str, level: str) -> str: | ||
raise NotImplementedError | ||
|
||
def edit_member(self, user_id: str, level: str) -> str: | ||
raise NotImplementedError | ||
|
||
def delete_member(self, user_id: str) -> str: | ||
raise NotImplementedError | ||
|
||
def list_commits(self, ref_name: str = "master") -> str: | ||
raise NotImplementedError | ||
|
||
def list_pushes(self) -> str: | ||
raise NotImplementedError | ||
|
||
def get_last_HEAD_commit(self, ref: str = "master") -> str: | ||
raise NotImplementedError | ||
|
||
def list_branches(self) -> str: | ||
raise NotImplementedError | ||
|
||
def get_branch(self, branch: str) -> str: | ||
raise NotImplementedError | ||
|
||
def archive(self) -> str: | ||
raise NotImplementedError | ||
|
||
def unarchive(self) -> str: | ||
raise NotImplementedError | ||
|
||
def protect(self, branch: str = "master", developer_push: bool = True, developer_merge: bool = True) -> str: | ||
raise NotImplementedError | ||
|
||
def unprotect(self, branch: str = "master") -> str: | ||
raise NotImplementedError | ||
|
||
def unlock(self, student_id: str) -> None: | ||
raise NotImplementedError | ||
|
||
def lock(self, student_id: str) -> None: | ||
raise NotImplementedError | ||
|
||
|
||
T = TypeVar('T', bound='StudentRepoBase') | ||
class StudentRepoBase(RepoBase): | ||
"""Repository for a student's solution to a homework assignment""" | ||
|
||
@classmethod | ||
def new(cls, base_repo: str, semester: str, section: str, username: str) -> T: | ||
raise NotImplementedError | ||
|
||
@classmethod | ||
def build_name(cls, semester: str, section: str, assignment: str, user: str) -> str: | ||
raise NotImplementedError | ||
|
||
def push(self, base_repo, branch: str = "master") -> None: | ||
"""Push base_repo code to this repo""" | ||
raise NotImplementedError | ||
|
||
|
||
T = TypeVar('T', bound='StudentRepoBase') | ||
class TemplateRepoBase(RepoBase): | ||
"""A repo from which StudentRepos are cloned from (Homework Repo).""" | ||
@classmethod | ||
def new(cls, name: str, namespace: str, config) -> T: | ||
raise NotImplementedError | ||
|
||
def push_to(self, student_repo: StudentRepoBase, branch: str = "master") -> None: | ||
raise NotImplementedError | ||
|
||
|
||
class BackendBase: | ||
""" | ||
Common abstract base backend for all assigner backends (gitlab or mock). | ||
""" | ||
repo = RepoBase # type: RepoBase | ||
template_repo = TemplateRepoBase # type: TemplateRepoBase | ||
student_repo = StudentRepoBase # type: StudentRepoBase | ||
access = None |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import logging | ||
|
||
from assigner.backends import from_name | ||
from assigner.config import requires_config | ||
|
||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
def requires_config_and_backend(func): | ||
"""Provides a backend depending on configuration.""" | ||
@requires_config | ||
def wrapper(config, cmdargs, *args, **kwargs): | ||
|
||
backend = from_name(config.backend["name"]) | ||
|
||
return func(config, backend, cmdargs, *args, **kwargs) | ||
return wrapper |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.