def apply_admin_change(change: Change[Admin], org: Organization) -> Change[Admin]: if change.action not in [ChangeActions.ADD, ChangeActions.REMOVE]: print_warning("Unsupported change action for org admins: %s" % change.action) return change.skipped() from ghconf.github import gh if change.action == ChangeActions.ADD and change.after is not None: try: user = gh.get_user(change.after.username) org.add_to_members(user, role="admin") except GithubException as e: print_debug("Unable to add admin user %s: %s" % (change.after.username, str(e))) return change.failure() elif change.action == ChangeActions.REMOVE and change.before is not None: try: user = gh.get_user(change.before.username) org.remove_from_members(user) except GithubException as e: print_debug("Unable to remove admin user %s: %s" % (change.before.username, str(e))) return change.failure() return change.success()
def test_multi_roles(self, wsgi): body = {'username': fake.word(), 'password': fake.word()} with patch('github.AuthenticatedUser.AuthenticatedUser' ) as github_user_mock: # TODO: create role role1 github_user = github_user_mock.return_value github_user.create_authorization.return_value = Authorization( None, [], {"token": "123456789"}, completed=True) github_user.login = '******' admin_team = Team(None, [], {"name": "sandwich-admin"}, completed=True) admin_team.has_in_members = MagicMock(return_value=True) prefix_team = Team(None, [], {"name": "sandwich-role1"}, completed=True) prefix_team.has_in_members = MagicMock(return_value=True) org = Organization(None, [], {"login": "******"}, completed=True) org.get_teams = MagicMock(return_value=[admin_team, prefix_team]) github_user.get_orgs.return_value = [org] self.post(wsgi, '/v1/auth/github/authorization', body=body)
def apply_member_change(change: Change[BaseMember], org: Organization, team: Team) -> Change[BaseMember]: if change.action not in [ChangeActions.ADD, ChangeActions.REMOVE]: print_debug("Unsupported change action for team members: %s" % change.action) return change.skipped() from ghconf.github import gh if change.action == ChangeActions.ADD and change.after is not None: ghteam = org.get_team(team.id) ghmember = gh.get_user(change.after.username) membership = ghteam.add_membership(ghmember, role=change.after.role) if membership.state == "active": print_debug("Added member %s to team %s" % (change.after.username, team.name)) return change.success() else: print_debug( "Adding member %s to team %s failed with state %s" % (change.after.username, team.name, membership.state)) return change.failure() elif change.action == ChangeActions.REMOVE and change.before is not None: ghteam = org.get_team(team.id) ghmember = gh.get_user(change.before.username) if ghteam.remove_membership(ghmember): return change.success() else: return change.failure() return change.success()
def test_ok(self, wsgi): body = {'username': fake.word(), 'password': fake.word()} with patch('github.AuthenticatedUser.AuthenticatedUser' ) as github_user_mock: github_user = github_user_mock.return_value github_user.create_authorization.return_value = Authorization( None, [], {"token": "123456789"}, completed=True) github_user.login = '******' org = Organization(None, [], {"login": "******"}, completed=True) org.get_teams = MagicMock(return_value=[]) github_user.get_orgs.return_value = [org] self.post(wsgi, '/v1/auth/github/authorization', body=body)
def apply_subteam_change(change: Change[Team], org: Organization, parent: Team) -> Change[Team]: if change.action not in [ChangeActions.ADD, ChangeActions.REMOVE]: print_warning("Unsupported change action for subteams: %s" % change.action) return change.skipped() if change.action == ChangeActions.ADD and change.after is not None: child = org.get_team(change.after.id) # type: GithubTeam child.edit(child.name, parent_team_id=parent.id) if child.parent.id == parent.id: return change.success() else: return change.failure() elif change.action == ChangeActions.REMOVE and change.before is not None: child = org.get_team(change.before.id) if child.delete(): return change.success() else: return change.failure() return change.success()
def assemble_repolist(args: Namespace, org: Organization) -> List[Repository]: repolist = [] if not args.skip_repo_changes: print_info("Assembling repository list...") if args.repos: for reponame in args.repos: try: r = org.get_repo(reponame) repolist.append(r) except GithubException: raise utils.ErrorMessage( "Repository %s not found. At least with this API key." % utils.highlight(reponame)) if args.reporegexes: for reporegex in args.reporegexes: try: regex = re.compile(reporegex) except error as e: raise utils.ErrorMessage( "Not a valid regular expression %s (%s)" % (utils.highlight(reporegex), str(e))) for repo in org.get_repos(): if regex.match(repo.name): repolist.append(repo) if not args.repos and not args.reporegexes: print_info( "No repository regex or name specified, run against %s repos" % utils.highlight("all")) repolist = list(org.get_repos()) elif not repolist: if args.skip_org_changes: print_warning( "No repos matched and skipping org changes. Nothing to do." ) else: print_warning("No repos matched!") return repolist
def apply_team_change(change: Change[Team], org: Organization) -> Change[Team]: if change.action not in [ChangeActions.ADD, ChangeActions.REMOVE]: print_warning("Unsupported change action for teams: %s" % change.action) return change.skipped() if change.action == ChangeActions.ADD and change.after is not None: to_create = change.after # type: Team if not isinstance(to_create, Team): raise ErrorMessage("Create action without team to create") created = org.create_team(to_create.name, permission=to_create.default_permission, privacy=to_create.privacy) created.edit(created.name, description=to_create.description) to_create.id = created.id return change.success() elif change.action == ChangeActions.REMOVE and change.before is not None: try: print_debug("Retrieving team id %s for deletion" % highlight(str(change.before.id))) to_delete = org.get_team(change.before.id) # type: GithubTeam except GithubException: # if the team is already gone... ok return change.success() try: print_debug("Deleting team id %s" % highlight(str(change.before.id))) to_delete.delete() except GithubException as e: print_error("Can't delete team id %s: %s" % (highlight(str(change.before.id)), str(e))) return change.failure() change.before.id = None return change.success()
def apply_attr_change(change: Change[str], org: Organization, team: Team, attr: str) -> Change[str]: if change.action not in [ChangeActions.REPLACE]: print_warning("Unsupported change action for team attributes: %s" % change.action) return change.skipped() ghteam = org.get_team(team.id) # type: GithubTeam if getattr(ghteam, attr) == change.before: print_info( "Setting {attr} from {before} to {after} on team {id}".format( attr=attr, before=change.before, after=change.after, id=team.id)) ghteam.edit(team.name, **{attr: change.after}) return change.success() return change
def github_organization(monkeypatch, github_repo): target = Organization(Mock(), Mock(), dict(), True) monkeypatch.setattr(target, 'get_repo', lambda name: github_repo) return target
def issue_pull_request(config: Config, reponame: str, org: Organization) -> int: """Push local feedback branch to remote and issue pull request to the default branch for the specified repo :param config: The Config object for the assignment :param reponame: Name of the repository :param org: A github.Organization object :return: an error number defined in errno; or 0 if no error. """ # extract basename bn = os.path.basename(reponame) # get real repository name if hashed repo = config.deanonymize_sha1_repo(bn) \ if config.anonymize_sub_path else bn # get submissions dir path for repo rdir = config.pull_path(config.submission_path, reponame, False, False) # obtain handle to remote repository grepo = org.get_repo(repo) # ensure that the default branch exists on remote remote_branches = [] for rb in grepo.get_branches(): remote_branches.append(rb.name) if config.default_branch not in remote_branches: print( f"ABORT: {config.default_branch} branch does not exist in remote repository." ) return errno.ENOENT if config.feedback_branch in remote_branches: print(f"ABORT: {config.feedback_branch} branch already exists in " f"remote repository.") return errno.EEXIST if config.verbose: print(f"Pushing branch {config.feedback_branch} to origin.") #### Lida: needed to edit since reponame contains the relative path, not just the name #### # Dan/Bill: not sure why this is necessary... hopefully we trigger it again and figure out why... # Popen(["git", "push", "origin", self.feedback_branch], cwd=reponame).wait() Popen(["git", "push", "origin", config.feedback_branch], cwd=rdir).wait() # create pull request if config.verbose: print(f"Issuing pull request from branch '{config.feedback_branch}" f"' to branch '{config.default_branch}' in {repo}.") # push commits upstream # we get the repo name from github so that you can run # this command from other locations grepo = org.get_repo(os.path.basename(repo)) grepo.create_pull(title="Feedback", base=config.default_branch, head=config.feedback_branch, body="Feedback on " + config.assignment_name + " from " + config.course + " teaching staff.") return 0
def build_organization_changesets(self, org: Organization) -> List[ChangeSet]: admin_meta = ChangeMetadata(executor=self.apply_admin_change, ) admins = set([ Admin(username=m.login, id=m.id) for m in org.get_members(role=Role.ADMIN) ]) admin_changes = self.config['organization'][ 'admin_policy'].apply_to_set( meta=admin_meta, current=admins, plan=self.config['organization']['admins']) ret = [ ChangeSet("{name}: Admins".format(name=__name__), admin_changes) ] ext_existing = cache.lazy_get_or_store( "orgteams_%s" % org.name, lambda: list(org.get_teams())) # type: List[GithubTeam] teammap = { ext_team.name: Team.from_githubteam(ext_team) for ext_team in ext_existing } # type: Dict[str, Team] # match IDs to the Teams so we move existing teams instead of deleting and recreating them for t in self.flatten_team_structure(self.config["teams"]): if t.name in teammap: t.id = teammap[t.name].id for ext_team in ext_existing: if ext_team.parent and ext_team.parent.name in teammap: teammap[ext_team.parent.name].subteams.add( teammap[ext_team.name]) team_meta = ChangeMetadata(executor=self.apply_team_change, params=[org]) ret += [ ChangeSet( source="{name}|{org}: Teams".format(name=__name__, org=org.name), changes=self.config["organization"] ["team_policy"].apply_to_set(meta=team_meta, current=set(teammap.values()), plan=self.flatten_team_structure( self.config["teams"])), ) ] attr_changes = [] # type: List[Change[str]] for t in self.flatten_team_structure(self.config["teams"]): if t.name in teammap: changes = self.diff_team_attrs(org, teammap[t.name], t) if changes: attr_changes += changes ret += [ ChangeSet(source="{name}: attributes".format(name=__name__), changes=attr_changes) ] for team in self.config["teams"]: ret += self.walk_team(org, team, teammap) return ret
def get_repos(org: Organization): return org.get_repos()