def _create_push_tuples( teams: List[plug.Team], template_repos: Iterable[plug.TemplateRepo], api: plug.PlatformAPI, ) -> Iterable[Tuple[bool, PushSpec]]: """Create push tuples for newly created repos. Repos that already exist are ignored. Args: teams: An iterable of teams. template_repos: Template repositories. api: A platform API instance. Returns: A list of tuples (created, push_tuple) for all student repo urls that relate to any of the master repo urls. ``created`` indicates whether or not the student repo was created in this invocation. """ for team, template_repo in itertools.product(teams, template_repos): repo_name = plug.generate_repo_name(team, template_repo.name) created, repo = _create_or_fetch_repo( name=repo_name, description=f"{repo_name} created for {team.name}", private=True, team=team, api=api, ) yield created, PushSpec( local_path=template_repo.path, repo_url=api.insert_auth(repo.url), branch=git.active_branch(template_repo.path), metadata=dict(repo=repo, team=team), )
def _create_update_push_tuples( teams: Iterable[plug.StudentTeam], template_repos: Iterable[plug.TemplateRepo], api: plug.PlatformAPI, ) -> Iterable[PushSpec]: """Create push tuples for existing repos. Repos that don't exist are ignored. Args: teams: An iterable of teams. template_repos: Template repositories. api: A platform API instance. Returns: A list of PushSpec namedtuples for all student repo urls that relate to any of the master repo urls. """ urls_to_templates = {} for team, template_repo in itertools.product(teams, template_repos): repo_url, *_ = api.get_repo_urls( [template_repo.name], team_names=[team.name] ) urls_to_templates[repo_url] = template_repo for repo in api.get_repos(list(urls_to_templates.keys())): template = urls_to_templates[repo.url] branch = git.active_branch(template.path) yield PushSpec(template.path, api.insert_auth(repo.url), branch)
def _push_to_platform(student_repos: List[plug.StudentRepo], api: plug.PlatformAPI) -> None: push_tuples = [ _repobee.git.Push(repo.path, api.insert_auth(repo.url), _DEFAULT_BRANCH) for repo in student_repos ] _repobee.git.push(push_tuples)
def _try_insert_auth(repo: Union[plug.TemplateRepo, plug.StudentRepo], api: plug.PlatformAPI) -> str: """Try to insert authentication into the URL.""" try: return api.insert_auth(repo.url) except plug.InvalidURL: return repo.url
def _update_local_repos(local: List[plug.StudentRepo], api: plug.PlatformAPI) -> None: expected_basedir = local[0].path.parent.parent assert all( map(lambda repo: repo.path.parent.parent == expected_basedir, local)) specs = [ CloneSpec(repo_url=api.insert_auth(repo.url), dest=repo.path) for repo in local ] # TODO figure out what to do when a local update fails clone(specs)
def migrate_repos( template_repo_urls: plug.types.SizedIterable[str], api: plug.PlatformAPI ) -> None: """Migrate a repository from an arbitrary URL to the target organization. The new repository is added to the master_repos team, which is created if it does not already exist. Args: template_repo_urls: Local urls to repos to migrate. api: An implementation of :py:class:`repobee_plug.PlatformAPI` used to interface with the platform (e.g. GitHub or GitLab) instance. """ local_templates = [ plug.TemplateRepo(name=urlutil.extract_repo_name(url), url=url) for url in template_repo_urls ] create_repo_it = plug.cli.io.progress_bar( ( _create_or_fetch_repo( local.name, description="", private=True, api=api ) for local in local_templates ), desc="Creating remote repos", total=len(template_repo_urls), ) with tempfile.TemporaryDirectory() as tmpdir: workdir = pathlib.Path(tmpdir) _clone_all(local_templates, cwd=workdir, api=api) remote_templates = [ plug.TemplateRepo( name=repo.name, url=repo.url, _path=workdir / repo.name ) for _, repo in create_repo_it ] git.push( [ PushSpec( local_path=template_repo.path, repo_url=api.insert_auth(template_repo.url), branch=git.active_branch(template_repo.path), ) for template_repo in remote_templates ] ) plug.echo("Done!")
def clone_student_repos( repos: List[plug.StudentRepo], clone_dir: pathlib.Path, update_local: bool, api: plug.PlatformAPI, ) -> Iterable[Tuple[CloneStatus, plug.StudentRepo]]: assert all(map(lambda r: r.path is not None, repos)) local = [repo for repo in repos if repo.path.exists()] if local and update_local: _update_local_repos(local, api) elif local and not update_local: _warn_local_repos(local) non_local = [repo for repo in repos if not repo.path.exists()] plug.log.info(f"Cloning into {non_local}") non_local_specs = [ CloneSpec( dest=clone_dir / plug.fileutils.hash_path(repo.path), repo_url=api.insert_auth(repo.url), metadata=dict(repo=repo), ) for repo in non_local ] failed_specs = clone(non_local_specs) failed_repos = {spec.metadata["repo"] for spec in failed_specs} success_repos = {repo for repo in non_local if repo not in failed_repos} for repo in success_repos: shutil.copytree( src=clone_dir / plug.fileutils.hash_path(repo.path), dst=repo.path ) return ( [(CloneStatus.EXISTED, repo) for repo in local] + [(CloneStatus.CLONED, repo) for repo in success_repos] + [(CloneStatus.FAILED, repo) for repo in failed_repos] )
def _get_authed_url(assignment_name: str, org_name: str, api: plug.PlatformAPI) -> str: # FIXME temporary workaround as insert_auth is not implemented # in FakeAPI.get_repo_urls. Should be fixed in RepoBee 3.4. return api.insert_auth( api.get_repo_urls([assignment_name], org_name=org_name)[0])