def open_issues(with_student_repos): """Open two issues in each student repo.""" task_issue = plug.Issue( title="Task", body="The task is to do this, this and that" ) correction_issue = plug.Issue( title="Correction required", body="You need to fix this, this and that" ) issues = [task_issue, correction_issue] gl = gitlab.Gitlab(LOCAL_BASE_URL, private_token=TOKEN, ssl_verify=False) target_group = get_group(ORG_NAME, gl=gl) projects = ( gl.projects.get(p.id) for p in target_group.projects.list(include_subgroups=True, all=True) ) for project in projects: project.issues.create( dict(title=task_issue.title, description=task_issue.body) ) project.issues.create( dict( title=correction_issue.title, description=correction_issue.body ) ) assert_num_issues(STUDENT_TEAM_NAMES, assignment_names, len(issues)) assert_issues_exist(STUDENT_TEAM_NAMES, assignment_names, task_issue) assert_issues_exist(STUDENT_TEAM_NAMES, assignment_names, correction_issue) return issues
def test_opens_issue_if_update_rejected(self, tmpdir, with_student_repos): master_repo = assignment_names[0] conflict_repo = plug.generate_repo_name(STUDENT_TEAMS[0], master_repo) filename = "superfile.super" text = "some epic content\nfor this file!" # update the master repo update_repo(master_repo, filename, text) # conflicting update in the student repo update_repo(conflict_repo, "somefile.txt", "some other content") issue = plug.Issue(title="Oops, push was rejected!", body="") issue_file = pathlib.Path(str(tmpdir)) / "issue.md" issue_file.write_text(issue.title) command = " ".join([ *repobee_plug.cli.CoreCommand.repos.update.as_name_tuple(), *TEMPLATE_ORG_ARG, *BASE_ARGS, "-a", master_repo, *STUDENTS_ARG, "--issue", issue_file.name, ]) run_repobee(command, workdir=tmpdir, plugins=[_repobee.ext.gitlab]) assert_repos_contain(STUDENT_TEAMS[1:], [master_repo], filename, text) assert_issues_exist(STUDENT_TEAMS[0:1], [master_repo], issue)
class TestOpenIssues: """Tests for the open-issues command.""" _ISSUE = plug.Issue(title="This is a title", body="This is a body") def test_happy_path(self, tmpdir_volume_arg, tmpdir, extra_args): """Test opening an issue in each student repo.""" filename = "issue.md" text = "{}\n{}".format(self._ISSUE.title, self._ISSUE.body) tmpdir.join(filename).write_text(text, encoding="utf-8") command = " ".join( [ REPOBEE_GITLAB, *repobee_plug.cli.CoreCommand.issues.open.as_name_tuple(), *BASE_ARGS, *MASTER_REPOS_ARG, *STUDENTS_ARG, "-i", "{}/{}".format(VOLUME_DST, filename), ] ) result = run_in_docker_with_coverage(command, extra_args=extra_args) assert result.returncode == 0 assert_num_issues(STUDENT_TEAMS, assignment_names, 1) assert_issues_exist(STUDENT_TEAMS, assignment_names, self._ISSUE)
def _extract_issues(issue_blocks: Iterable[Tuple[int, int]], lines: List[str]): for begin, end in issue_blocks: match = re.match(BEGIN_ISSUE_PATTERN, lines[begin], re.IGNORECASE) assert match repo_name, title = match.groups() body = "".join(lines[begin + 1:end]) yield (repo_name, plug.Issue(title=title.strip(), body=body.rstrip()))
def from_magic_mock_issue(mock_issue): """Convert a MagicMock issue into a plug.Issue.""" return plug.Issue( title=mock_issue.title, body=mock_issue.body, number=mock_issue.number, created_at=mock_issue.created_at, author=mock_issue.user.login, )
def to_plug_issue(self): return plug.Issue( title=self.title, body=self.body, number=self.number, created_at=self.created_at, author=self.author, state=self.state, implementation=self, )
def _wrap_issue(self, issue_data: dict) -> plug.Issue: return plug.Issue( title=issue_data["title"], body=issue_data["body"], number=issue_data["number"], author=issue_data["user"]["login"], created_at=issue_data["created_at"], state=plug.IssueState(issue_data["state"]), implementation=issue_data, )
def _wrap_issue(self, issue) -> plug.Issue: with _try_api_request(): return plug.Issue( title=issue.title, body=issue.description, number=issue.iid, created_at=issue.created_at, author=issue.author["username"], state=_REVERSE_ISSUE_STATE_MAPPING[issue.state], implementation=issue, )
def read_issue_from_file(issue_path: str) -> plug.Issue: """Attempt to read an issue from a textfile. The first line of the file is interpreted as the issue's title. Args: issue_path: Local path to textfile with an issue. """ if not os.path.isfile(issue_path): raise ValueError(f"{issue_path} is not a file") with open(issue_path, "r", encoding=sys.getdefaultencoding()) as file: return plug.Issue(file.readline().strip(), file.read())
def _wrap_issue(self, issue: github.Issue.Issue) -> plug.Issue: with _try_api_request(): return plug.Issue( title=issue.title, body=issue.body, number=issue.number, created_at=issue.created_at.isoformat(), author=issue.user.login, state=_REVERSE_ISSUE_STATE_MAPPING[issue.state], implementation=issue, )
def create_komp_hookresult(author): komp_issue = plug.Issue( title="Komplettering", body="This is komplettering", number=1, created_at=datetime(2009, 12, 31), author=author, ) return plug.HookResult( hook="list-issues", status=plug.Status.SUCCESS, msg=None, data={komp_issue.number: komp_issue.to_dict()}, )
def create_pass_hookresult(author): pass_issue = plug.Issue( title="Pass", body="This is a pass", number=3, created_at=datetime(1992, 9, 19), author=author, ) return plug.HookResult( hook="list-issues", status=plug.Status.SUCCESS, msg=None, data={pass_issue.number: pass_issue.to_dict()}, )
class TestOpenIssues: """Tests for the open-issues command.""" _ISSUE = plug.Issue(title="This is a title", body="This is a body") def test_happy_path(self, tmpdir): """Test opening an issue in each student repo.""" filename = "issue.md" text = "{}\n{}".format(self._ISSUE.title, self._ISSUE.body) tmpdir.join(filename).write_text(text, encoding="utf-8") command = " ".join([ *repobee_plug.cli.CoreCommand.issues.open.as_name_tuple(), *BASE_ARGS, *MASTER_REPOS_ARG, *STUDENTS_ARG, "-i", f"{tmpdir}/{filename}", ]) run_repobee(command, workdir=tmpdir, plugins=[_repobee.ext.gitlab]) assert_num_issues(STUDENT_TEAMS, assignment_names, 1) assert_issues_exist(STUDENT_TEAMS, assignment_names, self._ISSUE)
plug.IssueState.OPEN: "open", plug.IssueState.CLOSED: "closed", plug.IssueState.ALL: "all", } _REVERSE_ISSUE_STATE_MAPPING = { value: key for key, value in _ISSUE_STATE_MAPPING.items() } # classes used internally in this module _Team = github.Team.Team _User = github.NamedUser.NamedUser _Repo = github.Repository.Repository DEFAULT_REVIEW_ISSUE = plug.Issue( title="Peer review", body="You have been assigned to peer review this repo.", ) @contextlib.contextmanager def _convert_404_to_not_found_error(msg): """Catch a github.GithubException with status 404 and convert to plug.NotFoundError with the provided message. If the GithubException does not have status 404, instead raise plug.UnexpectedException. """ try: yield except github.GithubException as exc: if exc.status == 404: raise plug.NotFoundError(msg) raise plug.UnexpectedException(
from unittest import mock import pytest from _repobee import plugin import repobee_plug as plug from repobee_feedback import feedback ASSIGNMENT_NAMES = ("task-1", "task-2") STUDENT_TEAMS = tuple([ plug.StudentTeam(members=members) for members in (["slarse"], ["glassey"], ["grundb", "glennol"]) ]) STUDENT_TEAM_NAMES = tuple(map(str, STUDENT_TEAMS)) PASS_ISSUE = plug.Issue(title="Pass", body="Well done!\nAbsolutely flawless!") KOMP_ISSUE = plug.Issue(title="Komplettering", body="Not perfect, you need to fix this.") FAIL_ISSUE = plug.Issue(title="Fail", body="Unfortunately, there are severe errors.") ISSUES = (PASS_ISSUE, KOMP_ISSUE, FAIL_ISSUE) random.seed(512) def _write_issue(issue: plug.Issue, path: pathlib.Path): text = "{}\n{}".format(issue.title, issue.body) path.write_text(text, encoding=sys.getdefaultencoding()) def _write_multi_issues_file(repos_and_issues, path):
def _read_issue(issue_path: pathlib.Path) -> plug.Issue: with open(str(issue_path), "r", encoding=sys.getdefaultencoding()) as file: return plug.Issue(file.readline().strip(), file.read())
"""Module for constants used throughout the test suite.""" import string import collections from datetime import datetime from itertools import permutations import repobee_plug as plug USER = "******" ORG_NAME = "test-org" TEMPLATE_ORG_NAME = "test-master-org" HOST_URL = "https://some_enterprise_host" BASE_URL = "{}/api/v3".format(HOST_URL) # 5! = 120 different students STUDENTS = tuple( plug.StudentTeam(members=["".join(perm)]) for perm in permutations(string.ascii_lowercase[:5])) ISSUE_PATH = "some/issue/path" ISSUE = plug.Issue(title="Best title", body="This is the body of the issue.") PLUGINS = ["javac", "pylint"] TOKEN = "besttoken1337" CONFIG_TOKEN = "bestconfigtoken" FIXED_DATETIME = datetime(2009, 11, 22) User = collections.namedtuple("User", ("login", ))
def from_magic_mock_issue(mock_issue): """Convert a MagicMock issue into a plug.Issue.""" return plug.Issue( title=mock_issue.title, body=mock_issue.body, number=mock_issue.number, created_at=mock_issue.created_at, author=mock_issue.user.login, ) User = constants.User CLOSE_ISSUE = plug.Issue("close this issue", "This is a body", 3, random_date(), "slarse") DONT_CLOSE_ISSUE = plug.Issue("Don't close this issue", "Another body", 4, random_date(), "glassey") OPEN_ISSUES = [CLOSE_ISSUE, DONT_CLOSE_ISSUE] CLOSED_ISSUES = [ plug.Issue( "This is a closed issue", "With an uninteresting body", 1, random_date(), "tmore", ), plug.Issue( "Yet another closed issue", "Even less interesting body",