Suraj Shetty | 0a6770a | 2020-10-14 10:21:31 +0530 | [diff] [blame] | 1 | import sys |
Suraj Shetty | 0a6770a | 2020-10-14 10:21:31 +0530 | [diff] [blame] | 2 | from urllib.parse import urlparse |
| 3 | |
Akhil Narang | 3effaf2 | 2024-03-27 11:37:26 +0530 | [diff] [blame] | 4 | import requests |
Suraj Shetty | 0a6770a | 2020-10-14 10:21:31 +0530 | [diff] [blame] | 5 | |
Raffael Meyer | d155042 | 2023-01-24 07:12:44 +0100 | [diff] [blame] | 6 | WEBSITE_REPOS = [ |
Suraj Shetty | 0a6770a | 2020-10-14 10:21:31 +0530 | [diff] [blame] | 7 | "erpnext_com", |
| 8 | "frappe_io", |
| 9 | ] |
| 10 | |
Raffael Meyer | d155042 | 2023-01-24 07:12:44 +0100 | [diff] [blame] | 11 | DOCUMENTATION_DOMAINS = [ |
| 12 | "docs.erpnext.com", |
| 13 | "frappeframework.com", |
| 14 | ] |
Suraj Shetty | 0a6770a | 2020-10-14 10:21:31 +0530 | [diff] [blame] | 15 | |
Suraj Shetty | 0a6770a | 2020-10-14 10:21:31 +0530 | [diff] [blame] | 16 | |
Raffael Meyer | d155042 | 2023-01-24 07:12:44 +0100 | [diff] [blame] | 17 | def is_valid_url(url: str) -> bool: |
| 18 | parts = urlparse(url) |
| 19 | return all((parts.scheme, parts.netloc, parts.path)) |
| 20 | |
| 21 | |
| 22 | def is_documentation_link(word: str) -> bool: |
| 23 | if not word.startswith("http") or not is_valid_url(word): |
| 24 | return False |
| 25 | |
| 26 | parsed_url = urlparse(word) |
| 27 | if parsed_url.netloc in DOCUMENTATION_DOMAINS: |
| 28 | return True |
| 29 | |
| 30 | if parsed_url.netloc == "github.com": |
| 31 | parts = parsed_url.path.split("/") |
| 32 | if len(parts) == 5 and parts[1] == "frappe" and parts[2] in WEBSITE_REPOS: |
| 33 | return True |
| 34 | |
| 35 | return False |
| 36 | |
| 37 | |
| 38 | def contains_documentation_link(body: str) -> bool: |
Akhil Narang | 3effaf2 | 2024-03-27 11:37:26 +0530 | [diff] [blame] | 39 | return any(is_documentation_link(word) for line in body.splitlines() for word in line.split()) |
Raffael Meyer | d155042 | 2023-01-24 07:12:44 +0100 | [diff] [blame] | 40 | |
| 41 | |
| 42 | def check_pull_request(number: str) -> "tuple[int, str]": |
| 43 | response = requests.get(f"https://api.github.com/repos/frappe/erpnext/pulls/{number}") |
| 44 | if not response.ok: |
| 45 | return 1, "Pull Request Not Found! ⚠️" |
| 46 | |
| 47 | payload = response.json() |
| 48 | title = (payload.get("title") or "").lower().strip() |
| 49 | head_sha = (payload.get("head") or {}).get("sha") |
| 50 | body = (payload.get("body") or "").lower() |
| 51 | |
Akhil Narang | 3effaf2 | 2024-03-27 11:37:26 +0530 | [diff] [blame] | 52 | if not title.startswith("feat") or not head_sha or "no-docs" in body or "backport" in body: |
Raffael Meyer | d155042 | 2023-01-24 07:12:44 +0100 | [diff] [blame] | 53 | return 0, "Skipping documentation checks... 🏃" |
| 54 | |
| 55 | if contains_documentation_link(body): |
| 56 | return 0, "Documentation Link Found. You're Awesome! 🎉" |
| 57 | |
| 58 | return 1, "Documentation Link Not Found! ⚠️" |
Suraj Shetty | 0a6770a | 2020-10-14 10:21:31 +0530 | [diff] [blame] | 59 | |
| 60 | |
| 61 | if __name__ == "__main__": |
Raffael Meyer | d155042 | 2023-01-24 07:12:44 +0100 | [diff] [blame] | 62 | exit_code, message = check_pull_request(sys.argv[1]) |
| 63 | print(message) |
| 64 | sys.exit(exit_code) |