|
| 1 | +#!/usr/bin/env python3 |
| 2 | + |
| 3 | +import os |
| 4 | +import logging |
| 5 | +import datetime |
| 6 | +from pygerrit2 import GerritRestAPI, HTTPBasicAuth |
| 7 | + |
| 8 | +LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO").upper() |
| 9 | +GERRIT_USERNAME = os.getenv("GERRIT_USERNAME") |
| 10 | +GERRIT_PASSWORD = os.getenv("GERRIT_PASSWORD") |
| 11 | +GERRIT_BASE_URL = os.getenv("GERRIT_BASE_URL", "https://review.spdk.io") |
| 12 | + |
| 13 | +def get_open_changes(gerrit): |
| 14 | + query = "".join([ |
| 15 | + "/changes/", |
| 16 | + "?q=project:spdk/spdk status:open -is:private", |
| 17 | + "&o=CURRENT_REVISION" |
| 18 | + ]) |
| 19 | + logging.info(f"Querying Gerrit with: {query}") |
| 20 | + return gerrit.get(query) |
| 21 | + |
| 22 | +def process_changes(gerrit, changes): |
| 23 | + now = datetime.datetime.now(datetime.timezone.utc) |
| 24 | + two_weeks = datetime.timedelta(weeks=2) |
| 25 | + four_weeks = datetime.timedelta(weeks=4) |
| 26 | + twelve_weeks = datetime.timedelta(weeks=12) |
| 27 | + |
| 28 | + for change in changes: |
| 29 | + change_id = change.get("_number") |
| 30 | + project = change.get("project") |
| 31 | + subject = change.get("subject", "N/A") |
| 32 | + owner = change.get("owner", {}).get("name", "Unknown") |
| 33 | + url = os.path.join(GERRIT_BASE_URL, "c", project, '+', str(change_id)) |
| 34 | + revisions = change.get("revisions", {}) |
| 35 | + current_revision = next(iter(revisions.values()), {}) |
| 36 | + created_str = current_revision.get("created") |
| 37 | + |
| 38 | + if not created_str: |
| 39 | + logging.warning(f"Change {change_id} has no 'created' field in the current revision.") |
| 40 | + continue |
| 41 | + |
| 42 | + created = datetime.datetime.strptime(created_str, "%Y-%m-%d %H:%M:%S.%f000").replace(tzinfo=datetime.timezone.utc) |
| 43 | + time_since_update = now - created |
| 44 | + if time_since_update > twelve_weeks: |
| 45 | + # Change is older than twelve weeks; we don't want VERY old changes to flood Gerrit dashboard, |
| 46 | + # so skip them. |
| 47 | + continue |
| 48 | + |
| 49 | + logging.info(f"Processing change {url} - {subject} by {owner}") |
| 50 | + logging.info(f"Time since last update: {time_since_update.days} days") |
| 51 | + message = "OUTDATED PATCH WARNING: Your change has not been updated for at least" |
| 52 | + message += f" {time_since_update.days // 7} weeks ({time_since_update.days} days)." |
| 53 | + if time_since_update > four_weeks: |
| 54 | + message += " This makes it severely outdated. Please rebase your change." |
| 55 | + send_comment(gerrit, change_id, message, -1) |
| 56 | + elif time_since_update > two_weeks: |
| 57 | + message += " Please consider rebasing, make sure you're working with latest code base." |
| 58 | + send_comment(gerrit, change_id, message, 0) |
| 59 | + |
| 60 | +def send_comment(gerrit, change_id, message, vote): |
| 61 | + logging.info(f"Sending comment to change {change_id}: {message} (Verified={vote})") |
| 62 | + try: |
| 63 | + # Commented out on a purpose for now. Will uncomment after postitive |
| 64 | + # code review, before merging. |
| 65 | + # gerrit.post(f"/changes/{change_id}/revisions/current/review", json={ |
| 66 | + # "message": message, |
| 67 | + # "labels": {"Verified": vote} |
| 68 | + # }) |
| 69 | + logging.info(f"Comment sent successfully to change {change_id}.") |
| 70 | + except Exception as e: |
| 71 | + logging.error(f"Failed to send comment to change {change_id}: {e}") |
| 72 | + |
| 73 | +def main(): |
| 74 | + logging.basicConfig( |
| 75 | + level=getattr(logging, LOG_LEVEL, logging.INFO), |
| 76 | + format="%(asctime)s - %(levelname)s - %(message)s" |
| 77 | + ) |
| 78 | + |
| 79 | + auth = HTTPBasicAuth(GERRIT_USERNAME, GERRIT_PASSWORD) |
| 80 | + gerrit = GerritRestAPI(url=GERRIT_BASE_URL, auth=auth) |
| 81 | + |
| 82 | + try: |
| 83 | + changes = get_open_changes(gerrit) |
| 84 | + process_changes(gerrit, changes) |
| 85 | + except Exception as e: |
| 86 | + logging.error(f"An error occurred: {e}") |
| 87 | + exit(1) |
| 88 | + |
| 89 | +if __name__ == "__main__": |
| 90 | + main() |
0 commit comments