def post_setup(self, repo: plug.StudentRepo, api: plug.PlatformAPI): """Add a created student repo to the teachers team.""" platform_repo = next(iter(api.get_repos([repo.url]))) teachers_team = _get_or_create_team(TEACHERS_TEAM_NAME, api) api.assign_repo( team=teachers_team, repo=platform_repo, permission=plug.TeamPermission.PULL, ) return plug.Result( name="tamanager", status=plug.Status.SUCCESS, msg=f"Added to the {TEACHERS_TEAM_NAME} team", )
def command(self, api: plug.PlatformAPI) -> Optional[plug.Result]: teachers_team = _get_or_create_team(TEACHERS_TEAM_NAME, api) existing_members = teachers_team.members new_members = list(set(self.teachers) - set(existing_members)) api.assign_members(teachers_team, new_members, permission=plug.TeamPermission.PULL) for repo in plug.cli.io.progress_bar( api.get_repos(), desc="Granting read access to repos"): api.assign_repo( repo=repo, team=teachers_team, permission=plug.TeamPermission.PULL, ) msg = (f"Added {', '.join(new_members)} to the '{TEACHERS_TEAM_NAME}' " "team") return plug.Result(name="add-teachers", status=plug.Status.SUCCESS, msg=msg)
def _create_or_fetch_repo( name: str, description: str, private: bool, api: plug.PlatformAPI, team: Optional[plug.Team] = None, ) -> Tuple[bool, plug.Repo]: try: return ( True, api.create_repo( name, description=description, private=private, team=team ), ) except plug.PlatformError: team_name = team.name if team else None repo = api.get_repo(repo_name=name, team_name=team_name) if team: api.assign_repo( team=team, repo=repo, permission=plug.TeamPermission.PUSH ) return False, repo
def assign_peer_reviews( assignment_names: Iterable[str], teams: Iterable[plug.StudentTeam], num_reviews: int, issue: Optional[plug.Issue], double_blind_key: Optional[str], api: plug.PlatformAPI, ) -> None: """Assign peer reviewers among the students to each student repo. Each student is assigned to review num_reviews repos, and consequently, each repo gets reviewed by num_reviews reviewers. In practice, each student repo has a review team generated (called <student-repo-name>-review), to which num_reviews _other_ students are assigned. The team itself is given pull-access to the student repo, so that reviewers can view code and open issues, but cannot modify the contents of the repo. Args: assignment_names: Names of assginments. teams: Team objects specifying student groups. num_reviews: Amount of reviews each student should perform (consequently, the amount of reviews of each repo) issue: An issue with review instructions to be opened in the considered repos. double_blind_key: If provided, use key to make double-blind review allocation. api: An implementation of :py:class:`repobee_plug.PlatformAPI` used to interface with the platform (e.g. GitHub or GitLab) instance. """ issue = issue or DEFAULT_REVIEW_ISSUE expected_repo_names = set(plug.generate_repo_names(teams, assignment_names)) fetched_teams = progresswrappers.get_teams(teams, api, desc="Fetching teams and repos") team_repo_tuples = [(team, list(api.get_team_repos(team))) for team in fetched_teams] fetched_repos = list( itertools.chain.from_iterable(repos for _, repos in team_repo_tuples)) fetched_repo_dict = {r.name: r for r in fetched_repos} missing = expected_repo_names - fetched_repo_dict.keys() if missing: raise plug.NotFoundError(f"Can't find repos: {', '.join(missing)}") if double_blind_key: plug.log.info(f"Creating anonymous repos with key: {double_blind_key}") fetched_repo_dict = _create_anonymized_repos( [(team, _only_expected_repos(repos, expected_repo_names)) for team, repos in team_repo_tuples], double_blind_key, api, ) allocations_for_output = [] for assignment_name in assignment_names: plug.echo("Allocating reviews") allocations = plug.manager.hook.generate_review_allocations( teams=teams, num_reviews=num_reviews) # adjust names of review teams review_team_specs, reviewed_team_names = list( zip(*[( plug.StudentTeam( members=alloc.review_team.members, name=_review_team_name( alloc.reviewed_team, assignment_name, key=double_blind_key, ), ), alloc.reviewed_team, ) for alloc in allocations])) review_teams = _repobee.command.teams.create_teams( review_team_specs, plug.TeamPermission.PULL, api) review_teams_progress = plug.cli.io.progress_bar( review_teams, desc="Creating review teams", total=len(review_team_specs), ) for review_team, reviewed_team_name in zip(review_teams_progress, reviewed_team_names): reviewed_repo = fetched_repo_dict[plug.generate_repo_name( reviewed_team_name, assignment_name)] review_teams_progress.write( # type: ignore f"Assigning {' and '.join(review_team.members)} " f"to review {reviewed_repo.name}") api.assign_repo(review_team, reviewed_repo, plug.TeamPermission.PULL) api.create_issue( issue.title, issue.body, reviewed_repo, # It's not possible to assign users with read-access in Gitea # FIXME redesign so Gitea does not require special handling assignees=review_team.members if not isinstance(api, _repobee.ext.gitea.GiteaAPI) else None, ) allocations_for_output.append({ "reviewed_repo": { "name": reviewed_repo.name, "url": reviewed_repo.url, }, "review_team": { "name": review_team.name, "members": review_team.members, }, }) if featflags.is_feature_enabled( featflags.FeatureFlag.REPOBEE_4_REVIEW_COMMANDS): output = dict(allocations=allocations_for_output, num_reviews=num_reviews) pathlib.Path("review_allocations.json").write_text( json.dumps(output, indent=4), encoding=sys.getdefaultencoding(), )
def assign_peer_reviews( assignment_names: Iterable[str], teams: Iterable[plug.StudentTeam], num_reviews: int, issue: Optional[plug.Issue], api: plug.PlatformAPI, ) -> None: """Assign peer reviewers among the students to each student repo. Each student is assigned to review num_reviews repos, and consequently, each repo gets reviewed by num_reviews reviewers. In practice, each student repo has a review team generated (called <student-repo-name>-review), to which num_reviews _other_ students are assigned. The team itself is given pull-access to the student repo, so that reviewers can view code and open issues, but cannot modify the contents of the repo. Args: assignment_names: Names of assginments. teams: Team objects specifying student groups. num_reviews: Amount of reviews each student should perform (consequently, the amount of reviews of each repo) issue: An issue with review instructions to be opened in the considered repos. api: An implementation of :py:class:`repobee_plug.PlatformAPI` used to interface with the platform (e.g. GitHub or GitLab) instance. """ issue = issue or DEFAULT_REVIEW_ISSUE expected_repo_names = plug.generate_repo_names(teams, assignment_names) fetched_teams = progresswrappers.get_teams(teams, api, desc="Fetching teams and repos") fetched_repos = list( itertools.chain.from_iterable(map(api.get_team_repos, fetched_teams))) fetched_repo_dict = {r.name: r for r in fetched_repos} missing = set(expected_repo_names) - set(fetched_repo_dict.keys()) if missing: raise plug.NotFoundError(f"Can't find repos: {', '.join(missing)}") for assignment_name in assignment_names: plug.echo("Allocating reviews") allocations = plug.manager.hook.generate_review_allocations( teams=teams, num_reviews=num_reviews) # adjust names of review teams review_team_specs, reviewed_team_names = list( zip(*[( plug.StudentTeam( members=alloc.review_team.members, name=plug.generate_review_team_name( str(alloc.reviewed_team), assignment_name), ), alloc.reviewed_team, ) for alloc in allocations])) review_teams = _repobee.command.teams.create_teams( review_team_specs, plug.TeamPermission.PULL, api) review_teams_progress = plug.cli.io.progress_bar( review_teams, desc="Creating review teams", total=len(review_team_specs), ) for review_team, reviewed_team_name in zip(review_teams_progress, reviewed_team_names): reviewed_repo = fetched_repo_dict[plug.generate_repo_name( reviewed_team_name, assignment_name)] review_teams_progress.write( # type: ignore f"Assigning {' and '.join(review_team.members)} " f"to review {reviewed_repo.name}") api.assign_repo(review_team, reviewed_repo, plug.TeamPermission.PULL) api.create_issue( issue.title, issue.body, reviewed_repo, assignees=review_team.members, )