مراسم دمج طلب السحب للمشرف المنفرد
مراسم لدمج طلبات السحب ذاتيًا عندما تؤدي قواعد حماية الفرع وenforce_admins إلى تعطّل المشرف المنفرد.
المرجع المعياري لدمج طلبات السحب ذاتيًا في ظل ثابت حماية الفرع للمشروع. عندما يكون المشرف هو المساهم الوحيد الذي يملك صلاحية الكتابة، تنشئ قواعد حماية الفرع في GitHub
enforce_admins=true+required_approving_review_count=1تعطّلًا في الدمج الذاتي توثّق هذه الصفحة طريقة حلّه.
1. التعطّل
يحمل فرع main في المستودع مجموعة الحماية التالية:
-
required_pull_request_reviews.required_approving_review_count: 1 -
enforce_admins: true
هذه القواعد صحيحة لسيناريوهات تعدد المشرفين (كل تغيير يصل إلى main عبر طلب سحب مُراجَع من قِبل قرين؛ والمسؤولون غير معفيين). لكنها تنتج تعطّلًا للمشرفين المنفردين: تمنع سياسة GitHub الموافقة الذاتية على طلب سحب أنشأته بنفسك، ويمنع enforce_admins=true تجاوز gh pr merge --admin لمتطلب موافقة المراجعة.
توجد ثلاثة مسارات للحل:
| المسار | متى يُستخدَم |
|---|---|
| مراسم التبديل المؤقت (المعيارية لهذا المستودع) | الافتراضية للدمج الذاتي للمشرف المنفرد؛ تحافظ على ثابت الحماية خارج نافذة الدمج |
| توفير هوية روبوت تكامل مستمر بصلاحية كتابة | اعتمِدها فقط إذا كان انضمام عدة مشرفين وشيكًا؛ فموافقة الروبوت تقوّض نية المراجعة البشرية للحماية |
تعيين required_approving_review_count: 0 بشكل دائم | اعتمِدها فقط إذا كان المستودع سيبقى بمشرف منفرد إلى أجل غير مسمى؛ فهي تعكس نية المراجعة في الحماية |
يصادق هذا المستودع على مراسم التبديل المؤقت بوصفها المسار المعياري. أما الاثنان الآخران فهما مخرجا طوارئ موثَّقان، لا الخيار الافتراضي.
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في الغلاف الاستعادة في أي مسار خروج). ولا تترك محاولة دمج فاشلة الحماية مُخفَّفة. - بوابة التكامل المستمر محفوظة طوال الوقت. لا يتأثر
required_status_checksبالتبديل؛ ولا يزال الدمج يتطلب أن تكون سياقات فحص الحالة المُهيَّأة خضراء. - مسار التدقيق مرئي. يظهر تعليق
gh pr merge --adminفي بيانات دمج طلب السحب الوصفية؛ وتظهر عمليات تبديل واجهة برمجة تطبيقات الحماية في سجل تدقيق المستودع تحت هوية المشرف.
4. متى لا تُستخدَم المراسم
المراسم مخصصة لـالدمج الذاتي لطلبات سحب المشرف نفسه. وعندما يتوفر مراجع قرين (مساهم بصلاحية كتابة)، يكون المسار القياسي 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")'تشغيل التكامل المستمر اللاحق للدمج بكوميت الدمج؛ ويُظهر سجل تدقيق قاعدة حماية المستودع (تاريخgh api /repos/<owner>/<repo>/branches/main/protectionعبر واجهة Settings → Branches) عمليتي تبديل الخطوة 2 والخطوة 4 المُحيطتين بنافذة الدمج. - تاريخ git للمشرف. يسرد
git log main --merges --first-parentكل كوميت دمج squash علىmainمع رقم طلب السحب المقابل في موضوع الكوميت (لاحقة(#<pr-number>)وفق افتراضيgh pr merge --squash)، مما يتيح للمُشغِّل تتبّع أي هبوط سابق رجوعًا إلى طلب السحب الخاص به واستدعاء المراسم.
عندما تكون scripts/dev/admin_merge.py هي نقطة الدخول، يُسمّي سجلّها غير التفاعلي (stdout) استدعاءات واجهة برمجة تطبيقات الحماية الثلاثة واستدعاء واجهة برمجة تطبيقات الدمج بالتسلسل؛ وتوجيه الغلاف عبر أنبوب إلى tee يلتقط جزءًا تدقيقيًا لكل تشغيل دون الاعتماد على احتفاظ GitHub بالسجل من جانبه.