Example #1
0
    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()
Example #2
0
    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)
Example #3
0
    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()
Example #4
0
    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)
Example #5
0
    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()
Example #6
0
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
Example #7
0
    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()
Example #8
0
    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
Example #9
0
def github_organization(monkeypatch, github_repo):
    target = Organization(Mock(), Mock(), dict(), True)
    monkeypatch.setattr(target, 'get_repo', lambda name: github_repo)
    return target
Example #10
0
    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
Example #11
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
Example #12
0
def get_repos(org: Organization):
    return org.get_repos()