def setup_student_repos( template_repo_urls: Iterable[str], teams: Iterable[plug.StudentTeam], api: plug.PlatformAPI, ) -> Mapping[str, List[plug.Result]]: """Setup student repositories based on master repo templates. Performs three primary tasks: 1. Create the specified teams on the target platform and add the specified members to their teams. If a team already exists, it is left as-is. If a student is already in a team they are assigned to, nothing happens. If no account exists for some specified username, that particular student is ignored, but any associated teams are still created (even if a missing user is the only member of that team). 2. For each master repository, create one student repo per team and add it to the corresponding student team. If a repository already exists, it is skipped. 3. Push files from the master repos to the corresponding student repos. Args: template_repo_urls: URLs to master repos. teams: An iterable of student teams specifying the teams to be setup. api: An implementation of :py:class:`repobee_plug.PlatformAPI` used to interface with the platform (e.g. GitHub or GitLab) instance. """ teams = list(teams) with tempfile.TemporaryDirectory() as tmpdir: workdir = pathlib.Path(tmpdir) template_repos = [ plug.TemplateRepo( name=urlutil.extract_repo_name(url), url=url, _path=workdir / api.extract_repo_name(url), ) for url in template_repo_urls ] plug.log.info("Cloning into master repos ...") _clone_all(template_repos, cwd=workdir, api=api) pre_setup_results = plugin.execute_setup_tasks( template_repos, api, cwd=pathlib.Path(tmpdir) ) platform_teams = _create_platform_teams(teams, api) to_push, preexisting = _create_state_separated_push_tuples( platform_teams, template_repos, api ) successful_pts, _ = git.push(push_tuples=to_push) post_setup_results = _execute_post_setup_hook( successful_pts, preexisting, api ) return _combine_dicts(pre_setup_results, post_setup_results)
def update_student_repos( template_repo_urls: plug.types.SizedIterable[str], teams: plug.types.SizedIterable[plug.StudentTeam], api: plug.PlatformAPI, issue: Optional[plug.Issue] = None, ) -> Mapping[str, List[plug.Result]]: """Attempt to update all student repos related to one of the master repos. Args: template_repo_urls: URLs to master repos. Must be in the organization that the api is set up for. teams: An iterable of student teams. api: An implementation of :py:class:`repobee_plug.PlatformAPI` used to interface with the platform (e.g. GitHub or GitLab) instance. issue: An optional issue to open in repos to which pushing fails. """ if len(set(template_repo_urls)) != len(template_repo_urls): raise ValueError("template_repo_urls contains duplicates") with tempfile.TemporaryDirectory() as tmpdir: workdir = pathlib.Path(tmpdir) template_repos = [ plug.TemplateRepo( name=urlutil.extract_repo_name(url), url=url, _path=workdir / api.extract_repo_name(url), ) for url in template_repo_urls ] plug.log.info("Cloning into master repos ...") _clone_all(template_repos, cwd=workdir, api=api) hook_results = plugin.execute_setup_tasks( template_repos, api, cwd=pathlib.Path(tmpdir) ) push_tuple_iter = _create_update_push_tuples( teams, template_repos, api ) push_tuple_iter_progress = plug.cli.io.progress_bar( push_tuple_iter, desc="Setting up student repos", total=len(teams) * len(template_repos), ) successful_pts, failed_pts = git.push( push_tuples=push_tuple_iter_progress ) if failed_pts and issue: plug.echo("Opening issue in repos to which push failed") urls_without_auth = [ re.sub("https://.*?@", "https://", pt.repo_url) for pt in failed_pts ] _open_issue_by_urls(urls_without_auth, issue, api) plug.log.info("Done!") return hook_results