أتمتة تنبيه Pull Requests القديمة إلى Slack
هتطلع من المقال ده بـ workflow عملي يقلل PRs المنسية قبل ما تتحول لتعطيل يوم كامل في الفريق.
مستوى القارئ: متوسط
المشكلة باختصار
لو فريقك عنده 6 مطورين وبيفتح 20 Pull Request في الأسبوع، غالبًا فيه PR أو اثنين بيتأخروا أكتر من 48 ساعة. التأخير ده مش بس رقم في GitHub. اللي بيحصل فعلاً إن المطور يبدّل context، ويرجع بعد يومين يفتكر ليه كتب التغيير أصلاً.
الطريقة الشائعة الغلط إنك تعتمد على إن كل واحد يفتح GitHub بنفسه كل صباح. الطريقة دي بتفشل لما الفريق يدخل في deploy أو incident أو ضغط دعم. البديل الأفضل: فحص آلي يومي يجيب PRs المفتوحة، يفلتر القديمة، ويرسل Slack message فيها الرابط والمالك والعمر بالساعات.
الفكرة الأساسية
الافتراض إن عندك repository واحد أو عدة repositories على GitHub، وقناة Slack داخلية اسمها مثلًا #engineering-review. هنستخدم GitHub REST API لقائمة Pull Requests المفتوحة، وSlack Incoming Webhook لإرسال الرسالة. حسب توثيق GitHub، endpoint قائمة Pull Requests يدعم state=open وsort=updated وper_page. وحسب توثيق Slack، الـ webhook يستقبل طلب HTTP POST فيه JSON يحتوي على text أو blocks.
ركز في نقطة مهمة: إحنا مش بنعمل bot معقد. إحنا بنعمل guardrail. يعني النظام لا يقرر بدل الفريق، لكنه يقول: “فيه PR بقاله 54 ساعة من غير merge”. المكسب إنك تكتشف التعطيل بدري. التكلفة إنك ممكن تبعت تنبيه زائد لو PR متعمد يفضل مفتوح.
الخطوات العملية
- اعمل Slack Incoming Webhook وخزّن الرابط في secret اسمه
SLACK_WEBHOOK_URL. - اعمل GitHub token بصلاحية قراءة Pull Requests فقط لو المستودع private.
- حدد حد التأخير. في فرق صغيرة، 48 ساعة رقم مناسب كبداية.
- شغّل سكربت يومي من cron أو GitHub Actions.
الملف التالي يشتغل كـ GitHub Actions job يوميًا الساعة 8 صباحًا UTC. لو عايزها تدعم توقيت الرياض، خليه 5 صباحًا UTC تقريبًا لمعظم السنة، أو استخدم scheduling خارجي يدعم timezone صريح.
name: stale-pr-alert
on:
schedule:
- cron: "0 8 * * *"
workflow_dispatch:
jobs:
alert:
runs-on: ubuntu-latest
steps:
- name: Find old open pull requests
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }}
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
OWNER: your-org
REPO: your-repo
MAX_AGE_HOURS: "48"
run: |
python - <<'PY'
import os, requests
from datetime import datetime, timezone
owner = os.environ["OWNER"]
repo = os.environ["REPO"]
max_age = int(os.environ.get("MAX_AGE_HOURS", "48"))
headers = {
"Accept": "application/vnd.github+json",
"Authorization": f"Bearer {os.environ['GH_TOKEN']}",
"X-GitHub-Api-Version": "2022-11-28",
}
url = f"https://api.github.com/repos/{owner}/{repo}/pulls"
params = {"state": "open", "sort": "updated", "direction": "asc", "per_page": 100}
pulls = requests.get(url, headers=headers, params=params, timeout=20).json()
now = datetime.now(timezone.utc)
old = []
for pr in pulls:
updated = datetime.fromisoformat(pr["updated_at"].replace("Z", "+00:00"))
age_hours = int((now - updated).total_seconds() // 3600)
if age_hours >= max_age:
old.append(f"• <{pr['html_url']}|#{pr['number']} {pr['title']}> — {age_hours}h — @{pr['user']['login']}")
if not old:
print("No stale PRs")
raise SystemExit(0)
text = "Pull Requests محتاجة مراجعة:\n" + "\n".join(old[:10])
response = requests.post(os.environ["SLACK_WEBHOOK_URL"], json={"text": text}, timeout=20)
response.raise_for_status()
PYسيناريو واقعي وقياس
لو عندك 20 PR في الأسبوع، وكل PR متأخر يضيف في المتوسط 30 دقيقة context switching، فـ 4 PRs متأخرة شهريًا تساوي ساعتين ضايعين على الأقل. بعد تفعيل التنبيه، الهدف الواقعي مش “صفر تأخير”. الهدف إن P90 لعمر PR قبل أول مراجعة ينزل من 72 ساعة إلى 36 أو 48 ساعة خلال شهر.
أفضل طريقة للقياس: سجّل عدد PRs التي تجاوزت 48 ساعة قبل وبعد التشغيل بأسبوعين. لو العدد نزل من 8 إلى 3، أنت وفرت تقريبًا 62% من حالات التأخير. الرقم تقديري، لكنه كافي لاتخاذ قرار هل تكمل في الأوتوميشن أو تعدّل الحد.
الـ trade-offs وما يجب الانتباه له
الـ trade-off هنا واضح. بتكسب visibility سريع بتكلفة شبه صفرية، لكن بتخسر جزء من الهدوء في Slack. لو التنبيه طلع كل يوم وفيه 15 PR، الناس هتتجاهله بعد أسبوع. لذلك خلي الرسالة مختصرة، واعرض أول 10 فقط، وخلي threshold يبدأ من 48 ساعة وليس 12 ساعة.
فيه تفصيلة أمنية مهمة: Slack يحذر إن webhook URL يعتبر secret ولا يجب نشره في public repo. كمان GitHub token لازم يكون بأقل صلاحية ممكنة. بدل ما تستخدم personal token واسع، استخدم fine-grained token أو GitHub App لو النظام كبر.
متى لا تستخدم هذه الطريقة
لا تستخدمها لو فريقك أقل من 3 أشخاص وكل المراجعات بتحصل في نفس اليوم طبيعيًا. ولا تستخدم Slack webhook فقط لو محتاج threads، حذف رسائل، أو تفاعل بأزرار approve وassign. في الحالات دي استخدم Slack Web API مثل chat.postMessage بدل Incoming Webhook.
كمان لا تعتمد على التنبيه كبديل لسياسة مراجعة واضحة. لو مفيش owner لكل PR، الأوتوميشن هيكشف المشكلة لكنه مش هيحلها.
مصادر التفاصيل
- GitHub REST API: List pull requests
- GitHub Actions workflow syntax وجدولة cron
- Slack Incoming Webhooks
الخطوة التالية
الخطوة التالية: طبّق الـ workflow على repository واحد فقط لمدة أسبوعين، وقِس عدد PRs التي تجاوزت 48 ساعة قبل وبعد. لو التنبيه مزعج، ارفع الحد إلى 72 ساعة بدل ما تلغي الأوتوميشن بالكامل.