예제 #1
0
def setup_student_repos_and_user_accounts(usernames: List[str],
                                          platform_url: str):
    funcs.run_repobee(
        f"repos setup -a {const.TEMPLATE_REPOS_ARG} "
        f"--base-url {platform_url}", )
    api = funcs.get_api(platform_url)
    api._add_users(usernames)
예제 #2
0
    def test_assign_one_review(self, with_student_repos, tmpdir):
        assignment_name = assignment_names[1]
        expected_review_teams = [
            plug.StudentTeam(
                members=[],
                name=plug.generate_review_team_name(student_team_name,
                                                    assignment_name),
            ) for student_team_name in STUDENT_TEAM_NAMES
        ]
        command = " ".join([
            *repobee_plug.cli.CoreCommand.reviews.assign.as_name_tuple(),
            *BASE_ARGS,
            "-a",
            assignment_name,
            *STUDENTS_ARG,
            "-n",
            "1",
        ])
        group_assertion = expected_num_members_group_assertion(
            expected_num_members=1)

        run_repobee(command, workdir=tmpdir, plugins=[_repobee.ext.gitlab])

        assert_on_groups(expected_review_teams,
                         single_group_assertion=group_assertion)
        assert_num_issues(STUDENT_TEAMS, [assignment_name], 1)
        assert_issues_exist(
            STUDENT_TEAMS,
            [assignment_name],
            _repobee.command.peer.DEFAULT_REVIEW_ISSUE,
            expected_num_asignees=1,
        )
예제 #3
0
    def test_end_double_blind_reviews_when_review_teams_are_missing(
            self, platform_url, with_student_repos):
        """Even if the review teams are missing, the anonymous repos should be
        deleted when running end. Such cases can occurr when there is failure
        in setup, see issue #825 for details.
        """
        # arrange
        assignment_name = const.TEMPLATE_REPO_NAMES[0]
        api = funcs.get_api(platform_url)
        num_repos_before = len(list(api.get_repos()))
        key = 1234

        funcs.run_repobee(f"reviews assign --num-reviews 1 "
                          f"--base-url {platform_url} "
                          f"--double-blind-key {key} "
                          f"--assignments {assignment_name}")

        api._restore_platform_state()
        review_teams = [
            team for team in api.get_teams() if "-" not in team.name
        ]
        for team in review_teams:
            api.delete_team(team)

        # act
        funcs.run_repobee(f"reviews end "
                          f"--base-url {platform_url} "
                          f"--double-blind-key {key} "
                          f"--assignments {assignment_name}")

        # assert
        api._restore_platform_state()
        num_repos_after = len(list(api.get_repos()))
        assert num_repos_after == num_repos_before
예제 #4
0
    def test_setup_with_default_branch_protection_does_not_carry_over(
            self, tmpdir):
        """Student repositories created when global default branch
        protection is enabled on the GitLab instance, should still not have
        default branch protection.
        """
        # arrange
        gl = gitlab.Gitlab(url=BASE_URL,
                           private_token=ADMIN_TOKEN,
                           ssl_verify=False)
        gl.auth()
        settings = gl.settings.get()
        settings.default_branch_protection = (
            _repobee.ext.gitlab.DefaultBranchProtection.FULL.value)
        settings.save()
        command = " ".join([
            *repobee_plug.cli.CoreCommand.repos.setup.as_name_tuple(),
            *BASE_ARGS,
            *TEMPLATE_ORG_ARG,
            *MASTER_REPOS_ARG,
            *STUDENTS_ARG,
        ])

        # act
        run_repobee(command, workdir=tmpdir, plugins=[_repobee.ext.gitlab])

        # assert
        api = api_instance(ORG_NAME)
        loop_ran = False
        for repo in api.get_repos():
            loop_ran = True
            assert not repo.implementation.protectedbranches.list()

        assert loop_ran, "assertion loop did not execute"
예제 #5
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)
예제 #6
0
    def test_opens_issue_when_push_fails(self, platform_url,
                                         with_student_repos, tmp_path):
        """Test running update when a student repo has been modified such that
        the push is rejected. The specified issues should then be opened in
        that student's repo, but not in any of the others.
        """
        # arrange
        title = "You done goofed"
        body = "You need to fix these things manually."
        issue_path = tmp_path / "issue.md"
        issue_path.write_text(f"{title}\n{body}", encoding="utf8")

        # modify a student repo
        repo_path = tmp_path / "repo"
        selected_repo = funcs.get_repos(platform_url)[0]
        repo = git.Repo.clone_from(selected_repo.path, to_path=repo_path)
        repo.git.commit("--amend", "-m", "Best commit")
        repo.git.push("--force")

        # act
        funcs.run_repobee(f"repos update -a {const.TEMPLATE_REPOS_ARG} "
                          f"--base-url {platform_url} "
                          f"--issue {issue_path}")

        # assert
        for platform_repo in funcs.get_repos(platform_url):
            if platform_repo.name == selected_repo.name:
                assert len(platform_repo.issues) == 1
                issue = platform_repo.issues[0]
                assert issue.title == title
                assert issue.body == body
            else:
                assert not platform_repo.issues
예제 #7
0
    def test_clone_does_not_alter_existing_dirs(self, with_student_repos,
                                                tmpdir):
        """Test that clone does not clobber existing directories."""
        team_with_local_repos = STUDENT_TEAMS[0]
        teams_without_local_repos = STUDENT_TEAMS[1:]

        expected_dir_hashes = []
        for template_repo_name in assignment_names:
            new_dir = plug.fileutils.generate_repo_path(
                str(tmpdir), team_with_local_repos.name, template_repo_name)
            new_dir.mkdir(parents=True)
            new_file = new_dir / "file"
            new_file.write_text(str(new_dir), encoding="utf-8")
            expected_dir_hashes.append((new_dir, hash_directory(new_dir)))
            repobee_testhelpers.funcs.initialize_repo(new_dir)

        command = " ".join([
            *repobee_plug.cli.CoreCommand.repos.clone.as_name_tuple(),
            *BASE_ARGS,
            *MASTER_REPOS_ARG,
            *STUDENTS_ARG,
        ])

        run_repobee(command, workdir=tmpdir, plugins=[_repobee.ext.gitlab])

        assert_cloned_repos(teams_without_local_repos, assignment_names,
                            tmpdir)
        for dirpath, expected_hash in expected_dir_hashes:
            dirhash = hash_directory(dirpath)
            assert dirhash == expected_hash, "hash mismatch for " + dirpath
예제 #8
0
    def test_setup_multiple_template_repos(self, platform_dir, platform_url):
        funcs.run_repobee(f"repos setup -a {TEMPLATE_REPOS_ARG} "
                          f"--base-url {platform_url}")

        assert_student_repos_match_templates(STUDENT_TEAMS,
                                             TEMPLATE_REPO_NAMES,
                                             funcs.get_repos(platform_url))
예제 #9
0
    def test_setup_with_local_repos(self, platform_url, tmp_path):
        """Test running the setup command with the names of local
        repositories. That is to say, repos that are not in the
        template organization.
        """
        # arrange
        template_repo_hashes = {}

        task_34 = tmp_path / "task-34"
        task_55 = tmp_path / "task-55"
        template_repo_hashes[task_34.name] = create_local_repo(
            task_34, [("somefile.txt", "This is task 34!")])
        template_repo_hashes[task_55.name] = create_local_repo(
            task_55, [("hello.py", "print('hello, world!')")])

        # act
        funcs.run_repobee(
            f"repos setup -a {task_55.name} {task_34.name} "
            f"--base-url {platform_url} "
            "--allow-local-templates",
            workdir=tmp_path,
        )

        # assert
        repo_dict = {
            repo.name: repo.path
            for repo in funcs.get_repos(platform_url)
        }

        _assert_repos_match_templates(
            STUDENT_TEAMS,
            [task_34.name, task_55.name],
            template_repo_hashes,
            repo_dict,
        )
예제 #10
0
def test_create_repo_with_plugin(platform_url):
    team = const.STUDENT_TEAMS[0]
    repo_name = "super-repo"
    description = "This is the description"
    private = True

    class CreateSingle(plug.Plugin, plug.cli.Command):
        __settings__ = plug.cli.command_settings(
            category=plug.cli.CoreCommand.repos, action="create-single")
        team_name = plug.cli.option()
        repo_name = plug.cli.option()

        def command(self, api: plug.PlatformAPI):
            team = api.get_teams(team_names=[self.team_name])
            api.create_repo(
                self.repo_name,
                description=description,
                private=private,
                team=team,
            )

    funcs.run_repobee(
        f"repos create-single --bu {platform_url} "
        f"--team-name {team.name} --repo-name {repo_name}",
        plugins=[CreateSingle],
    )

    existing_repos = funcs.get_repos(platform_url)

    matching_repo = next(
        (repo for repo in existing_repos if repo.name == repo_name), None)

    assert matching_repo.name == repo_name
    assert matching_repo.description == description
    assert matching_repo.private == private
예제 #11
0
def test_discover_repos_parser_does_not_discover_repos_if_flag_not_specified(
        platform_url, with_student_repos):
    """Test that the discovery mechanism is inactive if --discover-repos flag
    is not specified.
    """
    args = []
    student = "slarse"
    assignment = "epic-task"

    class Check(plug.Plugin, plug.cli.Command):
        __settings__ = plug.cli.command_settings(base_parsers=[
            plug.cli.BaseParser.STUDENTS,
            plug.cli.BaseParser.REPO_DISCOVERY,
        ])

        def command(self, api):
            nonlocal args
            args = self.args

    funcs.run_repobee(
        f"check --base-url {platform_url} "
        f"-s {student} "
        f"-a {assignment}",
        plugins=[Check],
    )

    assert "repos" not in args
예제 #12
0
def test_discover_repos_parser_discovers_repos_if_flag_is_specified(
        platform_url, with_student_repos):
    """Test that the discovery mechanism kicks in if --discover-repos is
    specified.
    """
    discovered_repos = []

    class Check(plug.Plugin, plug.cli.Command):
        __settings__ = plug.cli.command_settings(base_parsers=[
            plug.cli.BaseParser.STUDENTS,
            plug.cli.BaseParser.REPO_DISCOVERY,
        ])

        def command(self, api):
            nonlocal discovered_repos
            discovered_repos = list(self.args.repos)

    funcs.run_repobee(
        f"check --base-url {platform_url} "
        f"--sf {const.STUDENTS_FILE} "
        f"--discover-repos",
        plugins=[Check],
    )

    expected_num_repos = len(const.TEMPLATE_REPO_NAMES) * len(
        const.STUDENT_TEAMS)
    assert len(discovered_repos) == expected_num_repos
예제 #13
0
    def test_closes_correct_issues(self, with_student_repos, platform_url):
        issue_to_close, open_issue = _open_predefined_issues(platform_url)

        funcs.run_repobee([
            *f"issues close --base-url {platform_url} "
            f"--assignments {const.TEMPLATE_REPOS_ARG} ".split(),
            "--title-regex",
            issue_to_close.title,
        ])

        iterations = 0
        for repo in funcs.get_repos(platform_url, const.TARGET_ORG_NAME):
            iterations += 1
            assert len(repo.issues) == 2
            actual_open_issue, *_ = [
                i for i in repo.issues if i.state == plug.IssueState.OPEN
            ]
            actual_closed_issue, *_ = [
                i for i in repo.issues if i.state == plug.IssueState.CLOSED
            ]
            assert actual_open_issue.title == open_issue.title
            assert actual_closed_issue.title == issue_to_close.title

        assert iterations == len(const.STUDENT_TEAMS) * len(
            const.TEMPLATE_REPO_NAMES)
예제 #14
0
    def test_open_issue_for_all_repos(self, with_student_repos, platform_url,
                                      issue):
        expected_repo_names = plug.generate_repo_names(
            const.STUDENT_TEAMS, const.TEMPLATE_REPO_NAMES)

        funcs.run_repobee(
            f"issues open --assignments {const.TEMPLATE_REPOS_ARG} "
            f"--base-url {platform_url} "
            f"--issue {issue.path} ")

        repos = funcs.get_repos(platform_url, const.TARGET_ORG_NAME)
        issues_dict = {repo.name: repo.issues for repo in repos}

        num_asserts = 0
        for name in expected_repo_names:
            num_asserts += 1
            issues = issues_dict[name]
            first_issue = issues[0]

            assert len(issues) == 1
            assert first_issue.title == issue.title
            assert first_issue.body == issue.body
            assert first_issue.state == plug.IssueState.OPEN

        assert num_asserts == len(expected_repo_names)
예제 #15
0
    def test_update_local_stashes_local_changes(self, platform_url,
                                                with_student_repos, tmp_path):
        """Test that updating local repositories with unstaged changes causes
        the changes to be stashed, and the update to proceed.
        """
        new_file_name = "suspicious_file.txt"
        target_repo = funcs.get_repos(platform_url)[-1]
        self._clone_all_student_repos(platform_url, tmp_path)

        # update remote repo
        with funcs.update_repository(target_repo.url) as repo_path:
            (repo_path / new_file_name).write_text(new_file_name)
        # update local repo
        local_repo_path = list(tmp_path.rglob(target_repo.name))[0]
        next(file for file in local_repo_path.iterdir()
             if file.is_file()).write_text("this is an update!")

        # act
        funcs.run_repobee(
            f"repos clone -a {const.TEMPLATE_REPOS_ARG} "
            f"--update-local "
            f"--base-url {platform_url}",
            workdir=tmp_path,
        )

        # assert
        assert local_repo_path.parent.parent == tmp_path
        local_new_file = local_repo_path / new_file_name
        assert local_new_file.is_file()
        assert local_new_file.read_text() == new_file_name
        assert git.Repo(local_repo_path).git.stash("list")
예제 #16
0
    def test_does_not_push_to_existing_repos(self, platform_url,
                                             with_student_repos, capsys,
                                             tmp_path):
        """This command should not push to existing repos, that's for the
        ``update`` command to do.
        """
        # arrange
        task = tmp_path / TEMPLATE_REPO_NAMES[0]
        create_local_repo(task, [("best/file/ever.txt", "content")])

        # act
        # this push would fail if it was attempted, as the repo
        # content of the local template does not match that of
        # the remote template
        funcs.run_repobee(
            f"repos setup -a {TEMPLATE_REPOS_ARG} "
            f"--base-url {platform_url} "
            "--allow-local-templates",
            workdir=tmp_path,
        )

        # nothing should have changed, and there should be no errors
        assert_student_repos_match_templates(STUDENT_TEAMS,
                                             TEMPLATE_REPO_NAMES,
                                             funcs.get_repos(platform_url))
        assert "[ERROR]" not in capsys.readouterr().out
예제 #17
0
    def test_does_not_update_local_by_default(self, platform_url,
                                              with_student_repos, tmp_path,
                                              capsys):
        """Test that cloning an update repository that exists locally does not
        cause it to be updated by default.
        """
        # arrange
        new_file_name = "suspicious_file.txt"
        target_repo = funcs.get_repos(platform_url)[-1]
        self._clone_all_student_repos(platform_url, tmp_path)

        with funcs.update_repository(target_repo.url) as repo_path:
            (repo_path / new_file_name).write_text(new_file_name)

        # act
        funcs.run_repobee(
            f"repos clone -a {const.TEMPLATE_REPOS_ARG} "
            f"--base-url {platform_url}",
            workdir=tmp_path,
        )

        # assert
        local_repo_path = list(tmp_path.rglob(target_repo.name))[0]
        local_new_file = local_repo_path / new_file_name
        assert not local_new_file.is_file()
        assert "--update-local" in capsys.readouterr().err
예제 #18
0
    def test_use_local_template_with_strangely_named_default_branch(
            self, platform_url, tmp_path):
        """Test setting up student repos with a template repo that has a
        non-standard default branch name. The student repos should get
        the same default branch.
        """
        strange_branch_name = "definitelynotmaster"
        task_99 = tmp_path / "task-99"
        create_local_repo(
            task_99,
            [("README.md", "Read me plz.")],
            default_branch=strange_branch_name,
        )

        funcs.run_repobee(
            f"repos setup -a {task_99.name} "
            f"--base-url {platform_url} "
            "--allow-local-templates",
            workdir=tmp_path,
        )

        repo = git.Repo(funcs.get_repos(platform_url)[0].path)

        assert len(repo.branches) == 1
        assert repo.branches[0].name == strange_branch_name
예제 #19
0
파일: fixtures.py 프로젝트: repobee/repobee
def with_student_repos(platform_url):
    funcs.run_repobee(f"repos setup -a {TEMPLATE_REPOS_ARG} "
                      f"--students-file {STUDENTS_FILE} "
                      f"--base-url {platform_url} "
                      f"--user {TEACHER} "
                      f"--org-name {TARGET_ORG_NAME} "
                      f"--template-org-name {TEMPLATE_ORG_NAME}")
예제 #20
0
    def test_use_non_standard_repo_names(self, platform_url):
        """Test setting up repos with non-standard repo names using an
        implementation of the ``generate_repo_name`` hook.
        """
        def generate_repo_name(team_name, assignment_name):
            return f"{assignment_name}-BONKERS-{team_name}"

        expected_repo_names = [
            generate_repo_name(team, assignment_name)
            for team, assignment_name in itertools.product(
                const.STUDENT_TEAMS, const.TEMPLATE_REPO_NAMES)
        ]

        class StrangeNamingConvention(plug.Plugin):
            def generate_repo_name(self, team_name, assignment_name):
                return generate_repo_name(team_name, assignment_name)

        funcs.run_repobee(
            f"repos setup -a {const.TEMPLATE_REPOS_ARG} "
            f"--base-url {platform_url}",
            plugins=[StrangeNamingConvention],
        )

        actual_repo_names = [
            repo.name for repo in funcs.get_repos(platform_url)
        ]
        assert sorted(actual_repo_names) == sorted(expected_repo_names)
예제 #21
0
    def test_clean_setup_in_subgroup(self, tmpdir):
        """It should be possible to use a subgroup as the target org."""
        gl, template_group, target_group = gitlab_and_groups()
        subgroup_name = "bestgroup"
        subgroup_full_path = f"{target_group.path}/{subgroup_name}"
        gl.groups.create(
            dict(
                name=subgroup_name,
                path=subgroup_name,
                parent_id=target_group.id,
            ))

        base_args = [
            arg if arg != ORG_NAME else subgroup_full_path for arg in BASE_ARGS
        ]

        command = " ".join([
            *repobee_plug.cli.CoreCommand.repos.setup.as_name_tuple(),
            *base_args,
            *TEMPLATE_ORG_ARG,
            *MASTER_REPOS_ARG,
            *STUDENTS_ARG,
        ])

        run_repobee(command, workdir=tmpdir, plugins=[_repobee.ext.gitlab])
        assert_repos_exist(STUDENT_TEAMS,
                           assignment_names,
                           org_name=subgroup_full_path)
예제 #22
0
    def test_post_setup_hook_called_on_correct_repos(self, platform_url):
        """Test that the repos are correctly marked as newly created or not."""
        # arrange
        first_template = TEMPLATE_REPO_NAMES[0]
        funcs.run_repobee(
            f"repos setup -a {first_template} --base-url {platform_url}")
        executed = False

        class PostSetupRecorder(plug.Plugin):
            def post_setup(self, repo, api, newly_created):
                nonlocal executed
                executed = True
                if first_template in repo.name:
                    assert (not newly_created
                            ), f"expected {repo.name} to be newly created"
                else:
                    assert (
                        newly_created), f"expected {repo.name} to be existing"

        # act/assert
        funcs.run_repobee(
            f"repos setup -a {TEMPLATE_REPOS_ARG} --base-url {platform_url}",
            plugins=[PostSetupRecorder],
        )

        assert executed, "Test plugin was never executed"
예제 #23
0
    def test_setup_with_wrong_case_on_student(self, tmpdir):
        """User names are case insensitive on GitLab, and so setup should work
        fine even if the case of some character in a student's username is
        "incorrect".

        See https://github.com/repobee/repobee/issues/900
        """
        student = STUDENT_TEAMS[0].members[0]
        student_wrong_case = student.upper()
        assert (student !=
                student_wrong_case), "cases match, test is pointless :("

        command = " ".join([
            *repobee_plug.cli.CoreCommand.repos.setup.as_name_tuple(),
            *BASE_ARGS,
            *TEMPLATE_ORG_ARG,
            *MASTER_REPOS_ARG,
            "--students",
            student_wrong_case,
        ])

        run_repobee(command, workdir=tmpdir, plugins=[_repobee.ext.gitlab])

        assert_repos_exist([plug.StudentTeam(members=[student])],
                           assignment_names)
예제 #24
0
    def test_squashed_student_repos_contain_only_squash_commit(
            self, platform_url, tmp_path):
        """When using the squash plugin, student repos should initially only
        contain the squash commit.
        """
        assignment_name = "repo-with-multiple-commits"
        repo_path = tmp_path / assignment_name
        self._setup_local_repo_with_multiple_commits(repo_path)

        squash_message = "This is a strange commit message"
        funcs.run_repobee(
            [
                *plug.cli.CoreCommand.repos.setup.as_name_tuple(),
                "--assignments",
                assignment_name,
                "--allow-local-templates",
                "--base-url",
                platform_url,
                "--squash-message",
                squash_message,
            ],
            plugins=[_repobee.ext.squash],
            workdir=tmp_path,
        )

        repos = funcs.get_repos(platform_url)
        assert repos
        for repo in repos:
            self._assert_single_commit_with_message(repo, squash_message)
예제 #25
0
    def test_closes_only_matched_issues(self, open_issues, tmpdir):
        """Test that close-issues respects the regex."""
        assert len(open_issues) == 2, "expected there to be only 2 open issues"
        close_issue = open_issues[0]
        open_issue = open_issues[1]
        command = " ".join([
            *repobee_plug.cli.CoreCommand.issues.close.as_name_tuple(),
            *BASE_ARGS,
            *MASTER_REPOS_ARG,
            *STUDENTS_ARG,
            "-r",
            close_issue.title,
        ])

        run_repobee(command, workdir=tmpdir, plugins=[_repobee.ext.gitlab])

        assert_issues_exist(
            STUDENT_TEAM_NAMES,
            assignment_names,
            close_issue,
            expected_state="closed",
        )
        assert_issues_exist(
            STUDENT_TEAM_NAMES,
            assignment_names,
            open_issue,
            expected_state="opened",
        )
예제 #26
0
    def test_use_extended_students_syntax(self, platform_url, tmp_path):
        students_file = tmp_path / "students.yml"
        students_file.write_text(
            """
some-team:
    members: [simon]
other-team:
    members: [eve, alice]
        """.strip(),
            encoding=sys.getdefaultencoding(),
        )
        expected_repo_names = plug.generate_repo_names(
            team_names=["some-team", "other-team"],
            assignment_names=const.TEMPLATE_REPO_NAMES,
        )

        funcs.run_repobee(
            f"{plug.cli.CoreCommand.repos.setup} --base-url {platform_url} "
            f"--students-file {students_file} "
            f"--assignments {const.TEMPLATE_REPOS_ARG}",
            plugins=[_repobee.ext.studentsyml],
        )

        actual_repo_names = [
            repo.name for repo in funcs.get_repos(platform_url)
        ]
        assert sorted(actual_repo_names) == sorted(expected_repo_names)
예제 #27
0
    def test_assign_to_nonexisting_students(self, with_student_repos, tmpdir):
        """If you try to assign reviews where one or more of the allocated
        student repos don't exist, there should be an error.
        """
        assignment_name = assignment_names[1]
        non_existing_group = "non-existing-group"
        student_team_names = STUDENT_TEAM_NAMES + [non_existing_group]

        command = " ".join([
            *repobee_plug.cli.CoreCommand.reviews.assign.as_name_tuple(),
            *BASE_ARGS_NO_TB,
            "-a",
            assignment_name,
            "-s",
            *student_team_names,
            "-n",
            "1",
        ])

        with pytest.raises(plug.NotFoundError) as exc_info:
            run_repobee(command, workdir=tmpdir, plugins=[_repobee.ext.gitlab])

        non_existing_repo_name = plug.generate_repo_name(
            non_existing_group, assignment_name)
        assert f"Can't find repos: {non_existing_repo_name}" in str(
            exc_info.value)
        assert_num_issues(STUDENT_TEAMS, [assignment_name], 0)
예제 #28
0
    def test_update_local(self, platform_url, with_student_repos, tmp_path):
        """Test cloning an updated repository that already exists locally, when
        there are no incompatible changes between the remote copy and the local
        copy and --update-local is specified.
        """
        # arrange
        new_file_name = "suspicious_file.txt"
        target_repo = funcs.get_repos(platform_url)[-1]
        self._clone_all_student_repos(platform_url, tmp_path)

        with funcs.update_repository(target_repo.url) as repo_path:
            (repo_path / new_file_name).write_text(new_file_name)

        # act
        funcs.run_repobee(
            f"repos clone -a {const.TEMPLATE_REPOS_ARG} "
            f"--update-local "
            f"--base-url {platform_url}",
            workdir=tmp_path,
        )

        # assert
        local_repo_path = list(tmp_path.rglob(target_repo.name))[0]
        assert local_repo_path.parent.parent == tmp_path
        local_new_file = local_repo_path / new_file_name
        assert local_new_file.is_file()
        assert local_new_file.read_text() == new_file_name
예제 #29
0
def test_auto_truncation_retains_final_lines(monkeypatch, tmp_path_factory):
    """The log file should be truncated by any command when it gets too large."""
    # arrange
    log_dir = tmp_path_factory.mktemp("logs")
    logfile = log_dir / "repobee.log"
    max_size = 1024 * 10

    logfile.write_bytes(b"a\n" * max_size * 10)
    last_lines = [b"these are", b"the last lines", b"of the log"]

    with open(logfile, mode="ab") as f:
        for line in last_lines:
            f.write(line)

    monkeypatch.setattr("_repobee.constants.LOG_DIR", log_dir)
    monkeypatch.setattr("_repobee.constants.MAX_LOGFILE_SIZE", max_size)

    # act
    with pytest.raises(SystemExit):
        funcs.run_repobee("-h")

    # assert
    log_contents = logfile.read_bytes()
    for line in last_lines:
        assert line in log_contents
예제 #30
0
def test_add_teachers_command_happy_path(platform_url):
    """The add-teachers command should add all existing repos to the teachers
    team, as well as the specified teachers.
    """
    # arrange
    teachers = ["gork", "mork", "slanesh"]
    setup_student_repos_and_user_accounts(teachers, platform_url)

    # act
    funcs.run_repobee(
        f"teams add-teachers --teachers {' '.join(teachers)} "
        f"--base-url {platform_url}",
        plugins=[tamanager],
    )

    # assert
    teachers_team = get_teachers_team(platform_url)
    num_expected_repos = len(const.STUDENT_TEAMS) * len(
        const.TEMPLATE_REPO_NAMES)
    assert len(teachers_team.repos) == num_expected_repos
    expected_repo_names = [r.name for r in funcs.get_repos(platform_url)]
    actual_repo_names = [r.name for r in teachers_team.repos]
    assert sorted(expected_repo_names) == sorted(actual_repo_names)
    assert sorted([m.username
                   for m in teachers_team.members]) == sorted(teachers)