def graphql_client(self, org, repo):
        """Return a GitHub GraphQL client for the specified org and repository.

    Args:
      org: The org.
      repo: The repo
    """
        # TODO(jlewi): Should we cache these?
        ghapp = github_app.GitHubApp.create_from_env()
        token_generator = github_app.GitHubAppTokenGenerator(
            ghapp, f"{org}/{repo}")
        gh_client = graphql.GraphQLClient(headers=token_generator.auth_headers)

        return gh_client
Esempio n. 2
0
    def __init__(self):
        self._client = graphql.GraphQLClient()

        self._headers = None
        self._token_refresher = None
        # Try various methods to obtain credentials
        try:
            self._token_refresher = github_app.FixedAccessTokenGenerator.from_env(
            )

        except ValueError:
            logging.info(
                "Could not create a FixedAccessTokenGenerator; will try "
                "other methods for obtaining credentials")

        if not self._token_refresher:
            app = github_app.GitHubApp.create_from_env()
            self._token_refresher = github_app.GitHubAppTokenGenerator(
                app, "kubeflow/manifests")
    def add_labels_to_issue(self, installation_id, repo_owner, repo_name,
                            issue_num, predictions):
        """
        Add predicted labels to issue using GitHub API.
        Args:
          installation_id: repo installation id
          repo_owner: repo owner
          repo_name: repo name
          issue_num: issue index
          prediction: dict str-> float; dictionary of labels and their predicted
            probability
        """

        # TODO(jlewi): Should we cache the GitHub App? What about token
        # expiration?
        ghapp = github_app.GitHubApp.create_from_env()

        # Load IssueLabelBot config. Look for both organization configuration
        # and repo specific configuration.
        # TODO(jlewi): We should really cache these and use some form of
        # expiration to pick up changes.
        org_config = github_util.get_yaml(owner=repo_owner,
                                          repo=ORG_CONFIG_REPO,
                                          ghapp=ghapp)

        repo_config = github_util.get_yaml(owner=repo_owner,
                                           repo=repo_name,
                                           ghapp=ghapp)

        context = {
            "repo_owner": repo_owner,
            "repo_name": repo_name,
            "issue_num": issue_num
        }
        config = {}

        if org_config:
            config.update(org_config)

        if repo_config:
            config.update(repo_config)

        predictions = self.apply_repo_config(config, repo_owner, repo_name,
                                             predictions, ghapp)

        url = util.build_issue_url(repo_owner, repo_name, issue_num)

        token_generator = github_app.GitHubAppTokenGenerator(
            ghapp, f"{repo_owner}/{repo_name}")
        gh_client = graphql.GraphQLClient(headers=token_generator.auth_headers)
        issue_data = github_util.get_issue(url, gh_client)

        predicted_labels = set(predictions.keys())

        # Remove from label_names any labels which already been applied
        # or which were explicitly removed.
        label_names = set(predicted_labels) - set(issue_data["labels"])
        label_names = label_names - set(issue_data["removed_labels"])

        already_applied = predicted_labels.intersection(issue_data["labels"])
        removed = predicted_labels.intersection(issue_data["removed_labels"])

        filtered_info = {}
        filtered_info.update(context)
        filtered_info["predicted_labels"] = list(predicted_labels)
        filtered_info["already_applied"] = list(already_applied)
        filtered_info["removed"] = list(removed)

        logging.info("Filtered predictions", extra=filtered_info)
        label_names = list(label_names)

        # Check whether the bot has already commented on this issue.
        already_commented = False
        for a in LABEL_BOT_LOGINS:
            if a in issue_data["comment_authors"]:
                already_commented = True
                break

        if already_commented:
            logging.info("Label bot has already commented on issue.",
                         extra=context)
        else:
            logging.info("Label bot has not commented on issue.",
                         extra=context)

        if not installation_id:
            logging.info("No GitHub App Installation Provided Fetching it")
            installation_id = ghapp.get_installation_id(repo_owner, repo_name)
        install = ghapp.get_installation(installation_id)

        # We are using the GitHub3 library to add comments. We should
        # TODO(jlewi): We should Use GraphQL so we can use a single library.
        issue = install.issue(repo_owner, repo_name, issue_num)

        message = None
        if label_names:
            # create message
            # Create a markdown table with probabilities.
            rows = [
                "| Label  | Probability |", "| ------------- | ------------- |"
            ]

            for l in label_names:
                rows.append("| {} | {:.2f} |".format(l, predictions[l]))

            lines = [
                "Issue-Label Bot is automatically applying the labels:", ""
            ]
            lines.extend(rows)
            lines.append("")
            lines.append(
                "Please mark this comment with :thumbsup: or :thumbsdown: "
                "to give our bot feedback! ")
            lines.append(
                "Links: [app homepage](https://github.com/marketplace/issue-label-bot), "
                "[dashboard]({app_url}data/{repo_owner}/{repo_name}) and "
                "[code](https://github.com/hamelsmu/MLapp) for this bot.".
                format(app_url=self.app_url,
                       repo_owner=repo_owner,
                       repo_name=repo_name))
            message = "\n".join(lines)
            # label the issue using the GitHub api
            issue.add_labels(*label_names)
            context["labels"] = label_names
            logging.info(
                f'Add `{"`, `".join(label_names)}` to the issue # {issue_num}',
                extra=context)
        else:
            # We don't want a spam an issue with comments. So once label
            # bot comments on an issue we will not chime in to report that
            # we aren't commented.
            if not already_commented:
                # TODO(jlewi): Should we include top predictions for area and
                # platform? Maybe we should include top predictions for
                # all areas? The problem is the model only returns predictions
                # above the threshold.
                message = """Issue Label Bot is not confident enough to auto-label this issue.
                See [dashboard]({app_url}data/{repo_owner}/{repo_name}) for more details.
                """.format(app_url=self.app_url,
                           repo_owner=repo_owner,
                           repo_name=repo_name)
                logging.warning(
                    f'Not confident enough to label this issue: # {issue_num}',
                    extra=context)

        # make a comment using the GitHub api
        if message:
            comment = issue.create_comment(message)