Пример #1
0
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
Пример #2
0
    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)
Пример #3
0
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)
Пример #4
0
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()))
Пример #5
0
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,
    )
Пример #6
0
 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,
     )
Пример #7
0
 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,
     )
Пример #8
0
 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,
         )
Пример #9
0
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())
Пример #10
0
 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,
         )
Пример #11
0
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()},
    )
Пример #12
0
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()},
    )
Пример #13
0
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)
Пример #14
0
    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(
Пример #15
0
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):
Пример #16
0
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())
Пример #17
0
"""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", ))
Пример #18
0

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",