مراسم دمج طلب السحب للمشرف المنفرد
متى يستطيع المشرف دمج طلب السحب الخاص به مباشرةً، والمراسم الخاصة بحماية فرع تشترط موافقةً وتفرضها على المسؤولين.
المرجع المعياري لدمج طلبات السحب ذاتيًا في ظل حماية الفرع الخاصة بالمشروع. تشترط الحماية الفعّالة على
main0 مراجعات موافِقة وتتركenforce_adminsمُعطَّلًا، كما هو مُسجَّل في صفحة حماية الفرع. لذلك يدمج المشرف طلب السحب الخاص به مباشرةً. ولا تنطبق مراسم التبديل المؤقت الواردة في هذه الصفحة إلا عندما تشترط الحماية موافقةً وتفرضها على المسؤولين.
1. الانسداد
تحمل حماية main الفعّالة ما يلي:
-
required_pull_request_reviews.required_approving_review_count: 0 -
enforce_admins: false
في ظل هذه الإعدادات لا يوجد انسداد. يُدمَج طلب سحب المشرف باستخدام gh pr merge <pr-number> --squash --delete-branch متى أصبحت فحوص الحالة المطلوبة الخاصة به خضراء وحُلَّت محادثات المراجعة الخاصة به.
لا يوجد انسداد إلا عندما تحمل الحماية كلا هذين الإعدادين الأكثر صرامة:
-
required_pull_request_reviews.required_approving_review_count: 1 -
enforce_admins: true
هذه القواعد صحيحة لسيناريوهات تعدّد المشرفين (كل تغيير يصل إلى main عبر طلب سحب راجعه قرين؛ والمسؤولون غير مُعفَين). لكنها تُنتِج انسدادًا للمشرفين المنفردين: تمنع سياسة GitHub الموافقة الذاتية على طلب سحب أنشأته بنفسك، ويمنع enforce_admins=true تجاوز gh pr merge --admin لمتطلّب الموافقة على المراجعة. ومع enforce_admins: false، يتجاوز --admin متطلّب الموافقة ولا حاجة إلى أي تبديل، لكنه يتجاوز أيضًا الفحوص المطلوبة الحمراء، لذا تأكّد من أنها خضراء قبل استخدامه.
توجد ثلاثة مسارات للحلّ:
| المسار | متى يُستخدَم |
|---|---|
تعيين required_approving_review_count: 0 بشكل دائم (الإعداد الفعّال) | اعتمِده فقط إذا كان المستودع سيبقى بمشرف منفرد إلى أجل غير مسمّى؛ فهو ينقض نية المراجعة في الحماية |
| مراسم التبديل المؤقت | للدمج الذاتي من المشرف المنفرد بينما تشترط الحماية موافقةً مع enforce_admins=true؛ تحافظ على ثابت الحماية خارج نافذة الدمج |
| توفير هوية روبوت CI بصلاحية كتابة | اعتمِده فقط إذا كان انضمام عدة مشرفين وشيكًا؛ فموافقة الروبوت تُقوّض نية المراجعة البشرية في الحماية |
يستخدم هذا المستودع حاليًا مسار الموافقة الصفرية الدائمة. ومراسم التبديل المؤقت هي المسار المعياري متى اشترطت الحماية موافقةً وفرضتها على المسؤولين.
2. مراسم التبديل المؤقت
ثابت المراسم: حالة الحماية في بداية المراسم تساوي حالة الحماية في نهايتها. ولا يعيش التخفيف إلا داخل نافذة الدمج.
الصيغة اليدوية:
# 1. Open the PR, push branch, wait for CI green.
gh pr create --base main --head <feature-branch> --title "..." --body "..."
gh pr checks <pr-number> # poll until all green
# 2. Relax approver-count to 0.
gh api repos/<owner>/<repo>/branches/main/protection/required_pull_request_reviews \
-X PATCH -F required_approving_review_count=0
# 3. Squash-merge with admin override (admin override now succeeds because the
# review-approval requirement is the only block enforce_admins refuses).
gh pr merge <pr-number> --squash --delete-branch --admin
# 4. Restore approver-count to 1.
gh api repos/<owner>/<repo>/branches/main/protection/required_pull_request_reviews \
-X PATCH -F required_approving_review_count=1الصيغة المُغلَّفة: راجِع scripts/dev/admin_merge.py للاطّلاع على غلاف Python الذرّي الذي ينفّذ الخطوات 2 ← 3 ← 4 في تسلسل واحد غير تفاعلي مع أمان التراجع عبر try / finally عند فشل الخطوة 3.
python scripts/dev/admin_merge.py <pr-number>3. الثوابت
- تقليص نافذة التبديل إلى أدنى حدّ. تُنفَّذ الخطوات 2 ← 3 ← 4 في تسلسل واحد غير تفاعلي. لا تكون الحماية في حالتها المُخفَّفة إلا طوال مدة استدعاء واجهة برمجة تطبيقات الدمج — أقل من ثانية واحدة في كل تشغيل مُلاحَظ.
- الاستعادة غير مشروطة. تُنفَّذ الخطوة 4 حتى عند فشل الخطوة 3 (تضمن عبارة
try/finallyفي الغلاف الاستعادة في أي مسار خروج). ولا تترك محاولة دمج فاشلة الحماية مُخفَّفة. - بوابة CI محفوظة طوال الوقت، ما دام
enforce_adminsمُفعَّلًا. لا يتأثّرrequired_status_checksبالتبديل؛ ومعenforce_admins: trueلا يزال الدمج يتطلّب أن تكون سياقات فحص الحالة المُهيَّأة خضراء. ومعenforce_admins: false، يتجاوز دمج--adminفي الخطوة 3 أيضًا الفحوص المطلوبة الحمراء، لذا لا تُشغِّل المراسم في تلك الحالة. - مسار التدقيق مرئي. يظهر تعليق
gh pr merge --adminفي البيانات الوصفية لدمج طلب السحب؛ وتظهر عمليات التبديل عبر واجهة برمجة تطبيقات الحماية في سجلّ تدقيق المستودع تحت هوية المشرف.
4. متى لا تُستخدَم المراسم
ما دامت الحماية تشترط 0 مراجعات موافِقة أو تترك enforce_admins مُعطَّلًا، فالمراسم غير ضرورية: ادمج مباشرةً كما يصف القسم 1.
المراسم مخصّصة لـ الدمج الذاتي لطلبات سحب المشرف نفسه. وعندما يتوفّر مراجع قرين (مساهم بصلاحية كتابة)، يكون المسار القياسي gh pr review --approve + gh pr merge --squash --delete-branch هو الصحيح، وتغدو المراسم غير ضرورية.
إذا ضمّ المستودع مشرفًا ثانيًا، فأحِل المراسم إلى التقاعد: يستعيد مسار مراجعة طلبات السحب القياسي نية المراجعة البشرية في الحماية دون أي تبديل.
5. تدقيق تشغيل سابق
يترك كل استدعاء للمراسم أثرًا على ثلاثة أسطح دائمة يمكن للمُشغِّل تفحّصها لاحقًا:
- بيانات الدمج الوصفية لطلب السحب. يُرجِع
gh pr view <pr-number> --json mergedBy,mergedAt,mergeCommitالجهة المُنفِّذة للدمج، وطابع وقت الدمج، وقيمة SHA لكوميت الـsquash. وتطابق الجهةmergedByهوية المُشرِف الذي نفّذ الخطوة 3. - سجلّ تدقيق المستودع. يربط
gh api /repos/<owner>/<repo>/actions/runs --jq '.workflow_runs[] | select(.event=="push")'تشغيل CI اللاحق للدمج بكوميت الدمج؛ ويُظهر سجلّ تدقيق قاعدة الحماية في المستودع (السجلّ عبرgh api /repos/<owner>/<repo>/branches/main/protectionأو عبر واجهة Settings → Branches) عمليتَي التبديل في الخطوة 2 والخطوة 4 المُحيطتين بنافذة الدمج. - تاريخ git لدى المُشرِف. يسرد
git log main --first-parent --onelineكل كوميت دمج squash علىmainمع رقم طلب السحب المقابل في عنوان الكوميت (اللاحقة(#<pr-number>)وفق الافتراضي فيgh pr merge --squash)، ويتيح للمُشغِّل تتبّع أي إنزال سابق رجوعًا إلى طلب السحب الخاص به وإلى استدعاء إجراء الدمج الإداري.
عندما يكون scripts/dev/admin_merge.py هو نقطة الدخول، يُسمّي سجلّه غير التفاعلي (stderr) استدعاءات واجهة برمجة تطبيقات الحماية الثلاثة واستدعاء واجهة برمجة تطبيقات الدمج بالتسلسل؛ وتوجيه stderr عبر أنبوب إلى tee (2>&1 | tee) يلتقط جزءًا تدقيقيًا لكل تشغيل دون الاعتماد على احتفاظ GitHub بالسجلّ من جانبه.