اعمل Stale PR Reminder Bot على GitHub: ذكّر الفريق بـ 50 سطر بصفر تكلفة
المستوى المطلوب: متوسط. محتاج تكون مرتاح مع GitHub Actions YAML، JavaScript الأساسي، وفكرة Webhooks. مش لازم تكون كتبت بوت قبل كده.
في آخر 6 شهور، 23 PR على ريبو شركتي قعدت أكتر من 4 أيام بدون مراجعة. اتنين منهم اتقفلوا في الآخر بـ "نعمل ده في sprint جاي" وما اتعملوش. الموضوع مش كسل من الفريق؛ الموضوع إن مفيش حد كان شايف القائمة دي في مكان واحد. البوت اللي هتبنيه دلوقتي بيجمعها ويبعتها في Slack كل صباح، في 50 سطر كود، وعلى الـ free tier بتاع GitHub Actions بصفر تكلفة شهرية.
المشكلة باختصار
الـ PR بيتفتح، حد بيراجع نص الكود، بيسيب 3 تعليقات، الكاتب بيرد على واحد، وبعدين الموضوع بينام. بعد أسبوع، الـ branch ورا master بـ 47 commit، ومحدش فاكر هي كانت ليه أصلاً. تقرير State of the Octoverse 2024 على github.blog بيقول إن أكتر من 30% من الـ PRs المفتوحة في فرق 5+ مهندسين بتعدّي 5 أيام قبل أول مراجعة. ده مش رقم تقديري، ده على عيّنة من ملايين الـ PRs.
التذكير اليدوي مش حل. لو حاطط حد عامل "PR triage" يومي، انت بتدفع له ساعة في اليوم على شغل آلة بتعمله في 4 ثوانٍ. الأسوأ إن الإنسان بيفوّت PRs بسبب bias، الآلة لأ.
المفهوم بمثال للمبتدئ
تخيّل مكتبة بترسل خطاب لكل عميل عنده كتاب فات ميعاد رجوعه. مفيش موظف بيمشي على كل سجل واحد واحد؛ في query واحدة بترجّع كل الكتب اللي تاريخ رجوعها قبل اليوم، ومنها بتطبع الخطابات. البوت اللي هنبنيه بيعمل نفس الفكرة بالظبط: بيسأل GitHub "ايه الـ PRs المفتوحة اللي عمرها أكتر من X يوم؟"، وبعدين بيقدّم القائمة في رسالة Slack منسّقة.
الفرق إن "تاريخ الرجوع" هنا اسمه updated_at، و"المكتبة" اسمها GitHub REST API، و"الخطاب" بقى Slack Block Kit message. كله نفس النمط: استعلام واحد، تجميع، إرسال. لو فهمت مثال المكتبة، انت فهمت 80% من البوت.
التعريف العلمي
البوت تطبيق لنمط Scheduled Polling: مكوّن يعمل HTTP request دوري على API، يصفّي النتائج بشرط زمني، ويبعت إشعار لو الشرط اتحقق. الـ scheduling بيتم عبر cron expression مخزّنة في GitHub Actions workflow file. الـ filtering بيتم على client-side لأن GitHub REST API ما بيدعمش filter مباشر على عمر الـ PR. الـ delivery بيتم عبر Incoming Webhook من Slack، اللي بيقبل HTTP POST برسالة JSON بصيغة Block Kit.
الحل في 4 أركان
- GitHub Actions workflow بـ cron schedule (9 صباحاً من الأحد للخميس بتوقيت القاهرة).
- Node.js script يستدعي
GET /repos/{owner}/{repo}/pulls?state=openويفلتر بـupdated_at. - Slack Incoming Webhook منفصل عن الـ workflow عشان متغيّر الـ URL ما يخرجش من الـ secrets.
- Block Kit JSON ينظّم الرسالة في sections قابلة للقراءة بلمحة بدون scrolling.