Files
ansible-docs/hacking/pr_labeler/pr_labeler/github_utils.py
Maxwell G 91ebd253b4 [stable-2.14] Backport pr_labeler changes (#1918)
* pr_labeler: improve create_boilerplate_comment logging

(cherry picked from commit 5730ba9a01)

* pr_labeler: add --force-process-closed flag

(cherry picked from commit 44ffe0f210)

* pr_labeler: add warning for porting_guides changes

This adds a warning message when PRs are created that edit
porting_guides by someone outside of the Release Management WG. These
files are automatically generated during the ansible release process and
should not be modified.

Fixes: https://github.com/ansible/ansible-documentation/issues/503
(cherry picked from commit d2e6625e8b)

* pr_labeler: use @release-management-wg team for porting_guide check

Instead of hardcoding the list of release managers, we can use the
Github API to retrieve the members of the
`@ansible/release-management-wg` team.

(cherry picked from commit dddfd7eb55)

* pr_labeler: exempt bots from porting_guide check

For example, patchback is not a release manager, but we still want it to
backport Porting Guide PRs.

(cherry picked from commit 746662c255)

* pr_labeler: improve porting_guide_changes template wording

Co-authored-by: Sandra McCann <samccann@redhat.com>
(cherry picked from commit 95ece7e9d6)

* pr_labeler: refactor new_contributor_welcome code (#990)

* pr_labeler: add GlobalArgs.full_repo property

* pr_labeler: refactor new_contributor_welcome code

As of https://github.com/ansible/ansible-documentation/issues/69, the
pr_labeler responds with a welcome message when an issue or PR is opened
by a new contributor. It turns out this never actually worked properly.

The previous method that relied on Github's `author_association` flag
did not work with the app token that the pr_labeler uses. This refactors
the code to figure out whether a user is a new contributor by
searching the list of issues and PRs.

Fixes: https://github.com/ansible/ansible-documentation/issues/204

* pr_labeler: address potential race condition

(cherry picked from commit 763815d1ad)

* Bump actions/setup-python from 4 to 5 (#966)

Bumps [actions/setup-python](https://github.com/actions/setup-python) from 4 to 5.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-type: direct:production
  update-type: version-update:semver-major
...

(cherry picked from commit 466b1fdc43)

* pr_labeler: re-architect triager script (#1882)

This commit reorganizes the issue/PR triager script and updates the
workflow to run more efficiently.

- Make the script a proper Python package instead of an unwieldy single
  file
- Use locked dependencies and UV to decrease workflow runtime to under
  10 seconds.

(cherry picked from commit 7138e42716)
(cherry picked from commit 1cf9f7917b)

---------

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-20 10:49:10 +01:00

118 lines
3.1 KiB
Python

# Copyright (C) 2023 Maxwell G <maxwell@gtmx.me>
# SPDX-License-Identifier: GPL-3.0-or-later
"""
Utilities for working with the Github API
"""
from __future__ import annotations
import json
import os
from contextlib import suppress
from typing import TYPE_CHECKING, Any
import github
import github.Auth
import github.Issue
import github.PullRequest
import github.Repository
from .cli_context import IssueLabelerCtx, IssueOrPrCtx
from .utils import log
if TYPE_CHECKING:
from typing_extensions import TypeAlias
IssueOrPr: TypeAlias = "github.Issue.Issue | github.PullRequest.PullRequest"
def get_repo(
full_repo: str,
authed: bool = True,
) -> tuple[github.Github, github.Repository.Repository]:
"""
Create a Github client and return a `github.Repository.Repository` object
Args:
full_repo: OWNER/NAME of the repository
authed:
Whether to create an authenticated Github client with the
`$GITHUB_TOKEN` environment variable as the key
"""
gclient = github.Github(
auth=github.Auth.Token(os.environ["GITHUB_TOKEN"]) if authed else None,
)
repo_obj = gclient.get_repo(full_repo)
return gclient, repo_obj
def get_event_info() -> dict[str, Any]:
"""
Load Github event JSON data from `$event_data`
"""
event_json = os.environ.get("event_json")
if not event_json:
return {}
with suppress(json.JSONDecodeError):
return json.loads(event_json)
return {}
# Operations
def get_team_members(ctx: IssueOrPrCtx, team: str) -> list[str]:
"""
Get the members of a Github team
"""
return [
user.login
for user in ctx.client.get_organization(ctx.repo.organization.login)
.get_team_by_slug(team)
.get_members()
]
def create_comment(ctx: IssueOrPrCtx, body: str) -> None:
if ctx.dry_run:
return
if isinstance(ctx, IssueLabelerCtx):
ctx.issue.create_comment(body)
else:
ctx.pr.create_issue_comment(body)
def is_new_contributor_assoc(ctx: IssueOrPrCtx) -> bool:
"""
Determine whether a user has previously contributed.
Requires authentication as a regular user and does not work with an app
token.
"""
author_association = ctx.event_member.get(
"author_association", ctx.member.raw_data["author_association"]
)
log(ctx, "author_association is", author_association)
return author_association in {"FIRST_TIMER", "FIRST_TIME_CONTRIBUTOR"}
def is_new_contributor_manual(ctx: IssueOrPrCtx) -> bool:
"""
Determine whether a user has previously opened an issue or PR in this repo
without needing special API access.
"""
query_data = {
"repo": "ansible/ansible-documentation",
"author": ctx.issue.user.login,
# Avoid potential race condition where a new contributor opens multiple
# PRs or issues at once.
# Better to welcome twice than not at all.
"is": "closed",
}
issues = ctx.client.search_issues("", **query_data)
for issue in issues:
if issue.number != ctx.issue.number:
return False
return True