Skip to content

Commit 6384f73

Browse files
authored
👷 Refactor label-approved, make it an internal script instead of an external GitHub Action (fastapi#12280)
1 parent 84ef149 commit 6384f73

File tree

2 files changed

+63
-1
lines changed

2 files changed

+63
-1
lines changed

‎.github/workflows/label-approved.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ jobs:
2020
env:
2121
GITHUB_CONTEXT: ${{ toJson(github) }}
2222
run: echo "$GITHUB_CONTEXT"
23-
- uses: docker://tiangolo/label-approved:0.0.4
23+
- uses: actions/checkout@v4
24+
- name: Set up Python
25+
uses: actions/setup-python@v5
2426
with:
2527
python-version: "3.11"
2628
- name: Setup uv

‎scripts/label_approved.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import logging
2+
from typing import Literal
3+
4+
from github import Github
5+
from github.PullRequestReview import PullRequestReview
6+
from pydantic import BaseModel, SecretStr
7+
from pydantic_settings import BaseSettings
8+
9+
10+
class LabelSettings(BaseModel):
11+
await_label: str | None = None
12+
number: int
13+
14+
15+
default_config = {"approved-2": LabelSettings(await_label="awaiting-review", number=2)}
16+
17+
18+
class Settings(BaseSettings):
19+
github_repository: str
20+
token: SecretStr
21+
debug: bool | None = False
22+
config: dict[str, LabelSettings] | Literal[""] = default_config
23+
24+
25+
settings = Settings()
26+
if settings.debug:
27+
logging.basicConfig(level=logging.DEBUG)
28+
else:
29+
logging.basicConfig(level=logging.INFO)
30+
logging.debug(f"Using config: {settings.json()}")
31+
g = Github(settings.token.get_secret_value())
32+
repo = g.get_repo(settings.github_repository)
33+
for pr in repo.get_pulls(state="open"):
34+
logging.info(f"Checking PR: #{pr.number}")
35+
pr_labels = list(pr.get_labels())
36+
pr_label_by_name = {label.name: label for label in pr_labels}
37+
reviews = list(pr.get_reviews())
38+
review_by_user: dict[str, PullRequestReview] = {}
39+
for review in reviews:
40+
if review.user.login in review_by_user:
41+
stored_review = review_by_user[review.user.login]
42+
if review.submitted_at >= stored_review.submitted_at:
43+
review_by_user[review.user.login] = review
44+
else:
45+
review_by_user[review.user.login] = review
46+
approved_reviews = [
47+
review for review in review_by_user.values() if review.state == "APPROVED"
48+
]
49+
config = settings.config or default_config
50+
for approved_label, conf in config.items():
51+
logging.debug(f"Processing config: {conf.json()}")
52+
if conf.await_label is None or (conf.await_label in pr_label_by_name):
53+
logging.debug(f"Processable PR: {pr.number}")
54+
if len(approved_reviews) >= conf.number:
55+
logging.info(f"Adding label to PR: {pr.number}")
56+
pr.add_to_labels(approved_label)
57+
if conf.await_label:
58+
logging.info(f"Removing label from PR: {pr.number}")
59+
pr.remove_from_labels(conf.await_label)
60+
logging.info("Finished")

0 commit comments

Comments
 (0)