ذكّر الفريق بطلبات الدمج التي تنتظر المراجعة
كل يوم عمل، انشر طلبات الدمج التي انتظرت المراجعة يومين أو أكثر في قناة المطورين.
كيف تعمل
المشغّل: جدول زمني — أيام العمل الساعة 10:00
- اجلب طلبات الدمج المفتوحة في المستودع من GitHub API.
- احتفظ بغير المسودات الأقدم من يومين.
- انشرها على Slack مع كاتبها والمراجعين.
المخطط
مشغّل تطبيق كود
الكود
كود JavaScript المستخدم في خطوات Code، وهو مضمَّن بالفعل في القالب بالأسفل.
// Lists open, non-draft pull requests waiting 2+ days, oldest first.
const DAY = 24 * 60 * 60 * 1000;
const waiting = $input.all()
.map((item) => item.json)
.filter((pr) => pr.number && !pr.draft)
.map((pr) => ({ ...pr, days: Math.floor((Date.now() - new Date(pr.created_at)) / DAY) }))
.filter((pr) => pr.days >= 2)
.sort((a, b) => b.days - a.days);
if (!waiting.length) return [];
const message =
`👀 ${waiting.length} pull request${waiting.length > 1 ? "s" : ""} waiting for review:\n` +
waiting.map((pr) => {
const reviewers = (pr.requested_reviewers || []).map((r) => r.login).join(", ") || "no reviewer";
return `• <${pr.html_url}|#${pr.number} ${pr.title}> by ${pr.user.login}, ${pr.days} days (${reviewers})`;
}).join("\n");
return [{ json: { message } }];ابنِها بأداتك
اختر أداتك — نفس الأتمتة، خطوة بخطوة.
انسخه والصقه مباشرة في مساحة عمل n8n (Ctrl+V)، أو حمّله واستخدم Import from File. بعد ذلك اربط حساباتك واستبدل كل قيمة تبدأ بـ YOUR_.
عرض الكود (132 سطر)
{
"name": "ذكّر الفريق بطلبات الدمج التي تنتظر المراجعة (Flowngn)",
"nodes": [
{
"parameters": {
"content": "## ذكّر الفريق بطلبات الدمج التي تنتظر المراجعة\nكل يوم عمل، انشر طلبات الدمج التي انتظرت المراجعة يومين أو أكثر في قناة المطورين.\n\n**Setup**\n1. Open each node and connect your own credentials.\n2. Replace every YOUR_… placeholder.\n3. Test once, then activate.\n\nFree template from Flowngn",
"height": 260,
"width": 340
},
"id": "26067c04-e776-42a7-a37a-b6a76afcb0f2",
"name": "Setup notes",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
-420,
-60
]
},
{
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 10 * * 1-5"
}
]
}
},
"id": "26067c04-e776-42a7-a37a-b6a76afcb0f2",
"name": "Weekdays 10:00",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.2,
"position": [
0,
0
]
},
{
"parameters": {
"url": "https://api.github.com/repos/YOUR_ORG/YOUR_REPO/pulls?state=open&per_page=100",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "githubApi",
"options": {}
},
"id": "26067c04-e776-42a7-a37a-b6a76afcb0f2",
"name": "Get open pull requests",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
300,
0
]
},
{
"parameters": {
"jsCode": "// Lists open, non-draft pull requests waiting 2+ days, oldest first.\nconst DAY = 24 * 60 * 60 * 1000;\n\nconst waiting = $input.all()\n .map((item) => item.json)\n .filter((pr) => pr.number && !pr.draft)\n .map((pr) => ({ ...pr, days: Math.floor((Date.now() - new Date(pr.created_at)) / DAY) }))\n .filter((pr) => pr.days >= 2)\n .sort((a, b) => b.days - a.days);\n\nif (!waiting.length) return [];\n\nconst message =\n `👀 ${waiting.length} pull request${waiting.length > 1 ? \"s\" : \"\"} waiting for review:\\n` +\n waiting.map((pr) => {\n const reviewers = (pr.requested_reviewers || []).map((r) => r.login).join(\", \") || \"no reviewer\";\n return `• <${pr.html_url}|#${pr.number} ${pr.title}> by ${pr.user.login}, ${pr.days} days (${reviewers})`;\n }).join(\"\\n\");\n\nreturn [{ json: { message } }];"
},
"id": "26067c04-e776-42a7-a37a-b6a76afcb0f2",
"name": "Waiting 2+ days",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
600,
0
]
},
{
"parameters": {
"select": "channel",
"channelId": {
"__rl": true,
"value": "#dev",
"mode": "name"
},
"text": "={{ $json.message }}",
"otherOptions": {}
},
"id": "26067c04-e776-42a7-a37a-b6a76afcb0f2",
"name": "Remind the team",
"type": "n8n-nodes-base.slack",
"typeVersion": 2.2,
"position": [
900,
0
]
}
],
"connections": {
"Weekdays 10:00": {
"main": [
[
{
"node": "Get open pull requests",
"type": "main",
"index": 0
}
]
]
},
"Get open pull requests": {
"main": [
[
{
"node": "Waiting 2+ days",
"type": "main",
"index": 0
}
]
]
},
"Waiting 2+ days": {
"main": [
[
{
"node": "Remind the team",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"meta": {
"templateCredsSetupCompleted": false
},
"tags": []
}في Make، أنشئ سيناريو جديدًا وأضف هذه الوحدات بالترتيب:
- Schedule the scenario: Weekdays 10:00
- HTTP › Make a request
- Tools › Set variable / Iterator + Array aggregator (same logic as the Code step)
- Slack › Create a Message
- كل تشغيل لوحدة يستهلك عمليات (operations) في Make — والباقة المجانية تتضمن حصة شهرية.
- دوال Make المدمجة (map و sum و formatDate…) تغني عن معظم خطوات Code؛ وللمنطق المعقد استخدم وحدة كود.
- قد تختلف أسماء الوحدات والخطوات قليلًا مع تحديث Make و Zapier لتطبيقاتهما.
في Zapier، أنشئ Zap جديدًا وأضف هذه الخطوات بالترتيب:
- Schedule by Zapier — Weekdays 10:00
- Webhooks by Zapier — GET
- Code by Zapier — Run JavaScript (paste the code from the Code section)
- Slack — Send Channel Message
- الـ Zaps التي فيها أكثر من خطوتين تحتاج باقة Zapier مدفوعة.
- الـ Webhooks والفلاتر/المسارات و Code by Zapier ميزات مدفوعة في بعض باقات Zapier.
- Code by Zapier يشغّل JavaScript: أعد استخدام الكود بالأعلى، مع قراءة المدخلات من inputData بدلًا من $json.
- قد تختلف أسماء الوحدات والخطوات قليلًا مع تحديث Make و Zapier لتطبيقاتهما.
نصائح
- استخدم توكن GitHub محدود الصلاحيات للقراءة فقط على طلبات الدمج.
أتمتات مشابهة
المطورون وتقنية المعلوماتسهل
مشكلات GitHub الجديدة في Slack
كل issue جديدة في مستودعك تُنشر في قناة فريقك على Slack.
GitHub → Slack1 س/شهر
المطورون وتقنية المعلوماتسهل
أعلن عن إصدارات GitHub في Slack
عند نشر إصدار، يرى فريقك أو مجتمعك الملاحظات فورًا.
GitHub → Slack1 س/شهر
المطورون وتقنية المعلوماتمتوسط
سجل تغييرات من طلبات الدمج
كل pull request مدمج يُضاف تلقائيًا إلى سجل التغييرات في Notion.
GitHub → Notion2 س/شهر