يحتوي هذا المستند على الحلول الكاملة للمهام الأربع، والشروح سطراً سطراً لسير العمل المقدَّمة، وإصلاحات الأعطال الثلاثة، وإجابات أسئلة التفكير.
لا تفتحه إلا بعد محاولة حقيقية. قراءة الحل قبل التجريب تعني تفويت 80% من التعلّم.
config.jsonمثال ملف صالح:
{
"titre": "Portfolio de <votre nom>",
"sous_titre": "Deploiement automatique via GitHub Actions",
"couleur_fond": "#7c3aed",
"couleur_texte": "#f8fafc",
"couleur_accent": "#22d3ee",
"auteur": "<Votre Nom>",
"version": "1.0.0"
}نقاط يجب احترامها:
titre، sous_titre، couleur_fond، couleur_texte، couleur_accent، auteur، version) إلزامية.#RRGGBB (6 أحرف ست عشرية بعد #).تحقق محلي:
python .\outils\build.pyيجب أن يعرض OK dist/index.html genere و OK dist/css/style.css genere. أي خطأ ERREUR : يوقف المخطوط ثم يحجب سيرة عمل GitHub.
لوحة مقترحة لاختبار الحلقة في المهمة 2:
| اللون | الخلفية | النص | التمييز |
|---|---|---|---|
| ليل داكن | #0f172a | #f1f5f9 | #38bdf8 |
| بنفسجي حيوي | #7c3aed | #f8fafc | #22d3ee |
| أحمر فاقع | #dc2626 | #fef2f2 | #facc15 |
| أخضر غابة | #16a34a | #f0fdf4 | #fbbf24 |
| أزرق محيط | #0891b2 | #ecfeff | #f472b6 |
deployer-pages.ymlname: Deployer sur GitHub Pages # الاسم الذي يظهر في واجهة Actionsهذا الاسم تجميلي بحت — يساعد على تمييز سيرة العمل في تبويب Actions للمستودع.
on:
push:
branches: [main]
workflow_dispatch:محفّزان:
main (الحالة العادية).permissions:
contents: read
pages: write
id-token: writeثلاثي Pages السحري. بلا هذه الأسطر الثلاثة نحصل على Resource not accessible by integration في المهمة deployer (هذا تماماً عطل المهمة 3 رقم 1):
contents: read — يسمح لـ actions/checkout@v4 بقراءة الشفرة.pages: write — يخوّل actions/deploy-pages@v4 النشر.id-token: write — لازم لمصادقة OIDC بين العدّاء وخدمة Pages.concurrency:
group: pages
cancel-in-progress: falseإن وصل git push اثنان تقريباً في الوقت نفسه، لا يشغّل GitHub Actions نشرين متوازيين على المجموعة نفسها pages — تُنفَّذ التشغيلات واحداً تلو الآخر. cancel-in-progress: false = نترك التشغيل الجاري ينتهي قبل بدء التالي. هذا حاسم لـ Pages: نشران متزامنان ينتجان حالات غير متسقة.
jobs:
construire:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4 # 1. استرجاع الشفرة
- uses: actions/setup-python@v5 # 2. تثبيت Python
with:
python-version: "3.12"
- run: python outils/build.py # 3. توليد dist/
- uses: actions/upload-pages-artifact@v3 # 4. تجهيز الأثر
with:
path: dist # <-- مهم: المجلد المراد نشرهأربع خطوات متتالية. إن فشلت واحدة، لا تُنفَّذ التالية.
deployer:
needs: construire # ينتظر نجاح "construire"
environment:
name: github-pages # بيئة Pages الرسمية
url: ${{ steps.publication.outputs.page_url }} # يعرض URL في الواجهة
steps:
- uses: actions/deploy-pages@v4
id: publicationتنتظر المهمة deployer صراحة construire بفضل needs:. في النهاية تعرض واجهة GitHub رابطاً قابلاً للنقر نحو https://<vous>.github.io/<depot>/.
verifier-config.ymlon:
pull_request:
branches: [main]
push:
branches-ignore: [main]تُحفَّز عند PR نحو main وعند دفع نحو أي فرع إلا main. الهدف: التحقق قبل دمج الشفرة. لاحظ أننا نستثني main من push: — وإلا نضاعف العمل مع deployer-pages.yml.
بقية الخطوات مطابقة لـ deployer-pages.yml إلا أننا لا ننشر: نكتفي بالتحقق أن dist/ يُولَّد بلا خطأ.
تسلسل يُعاد مرتين:
# --- التكرار 1: خلفية بنفسجية ---
# حرّر site/config.json : "couleur_fond": "#7c3aed"
git add site/config.json
git commit -m "fond violet"
git push
# انتظر ~40 ث -> افتح https://<vous>.github.io/<depot>/ -> خلفية بنفسجية
# --- التكرار 2: خلفية حمراء ---
# حرّر site/config.json : "couleur_fond": "#dc2626"
git add site/config.json
git commit -m "fond rouge"
git push
# انتظر ~40 ث -> افتح العنوان نفسه -> خلفية حمراءتحققات تُدرَج في التقرير:
git log --oneline: يعرض الـ commitين مع SHA القصير.Deployer sur GitHub Pages أخضران.فرق التصحيح في .github/workflows/casse-1-permissions-manquantes.yml:
name: Casse 1 - Permissions manquantes
on:
push:
branches: [main]
workflow_dispatch:
+permissions:
+ contents: read
+ pages: write
+ id-token: write
+
concurrency:
group: pages
cancel-in-progress: false
jobs:
...تشخيص مكتوب يُوضَع في التقرير:
بلا كتلة permissions:، يمنح GitHub سيرة العمل فقط contents: read (قراءة الشفرة) — لا صلاحية النشر على Pages. يطلب الإجراء actions/deploy-pages@v4 صراحة pages: write و id-token: write (رمز OIDC). ومن هنا الخطأ Resource not accessible by integration (403 Forbidden) في المهمة deployer.
قاعدة أمنية: نعطي أقل صلاحيات ممكنة، لكن ليس أقل. مبدأ أدنى امتياز مطبَّق على CI/CD.
فرق التصحيح:
name: Casse 2 - Declencheur errone
on:
- pushh:
+ push:
branches: [main]تشخيص مكتوب يُوضَع في التقرير:
لا يبلّغ GitHub Actions عن المحفّزات المجهولة في on: — يتجاهلها بصمت. مجرد pushh (بحرفَي h) يجعل لا تشغيل يُحفَّز: لا نرى خطأ، لا نرى شيئاً على الإطلاق في تبويب Actions.
كيف نكتشف العطل؟ ندفع commit، نذهب إلى Actions، نلاحظ أن لا تشغيل يظهر لهذه سيرة العمل. الدليل الوحيد هو الغياب.
تلميح ضد الفخ: Run workflow سريع (زر يدوي، متاح إن وُجد workflow_dispatch:) يتحقق أن سيرة العمل نفسها صالحة نحوياً. يعمل workflow_dispatch: مستقلاً عن push:.
فرق التصحيح:
- name: Preparer le dossier a publier
uses: actions/upload-pages-artifact@v3
with:
- path: public
+ path: distتشخيص مكتوب يُوضَع في التقرير:
يكتب outils/build.py دائماً في dist/ (الثابت DIST = RACINE / "dist" في شفرة Python). طلبت سيرة العمل path: public — مجلد غير موجود. ومن هنا:
Error: Path does not exist: ./publicيتحقق actions/upload-pages-artifact@v3 من وجود المجلد قبل إنشاء الأثر ويفشل فوراً إن كان المسار خاطئاً. الممارسة الجيدة: دائماً توجيه سيرة العمل نحو المجلد الدقيق الذي ينتجه مخطوط البناء.
README.mdفي README.md لمستودعك على GitHub (في الجذر، ليس في مجلد projet14-github-actions-pages-tp/ للدورة)، أضف:
# Mon site portfolio

Site publie : https://<vous>.github.io/<depot>/تصير الشارة خضراء إن نجح آخر تشغيل، حمراء وإلا. تتحدّث وحدها.
config.json باطلgit checkout -b test-config-cassee
# حرّر site/config.json واستبدل "couleur_fond": "#0f172a" بـ "couleur_fond": "rouge"
git add site/config.json
git commit -m "test : couleur invalide"
git push -u origin test-config-cassee
# ثم على GitHub: افتح PR من test-config-cassee نحو mainستُحفَّز سيرة العمل Verifier la configuration، وسيصرخ build.py:
ERREUR : couleur_fond doit etre au format #RRGGBB (recu : 'rouge')تعرض PR مربعاً أحمر ويُحجب زر Merge pull request إن ضبطت حماية الفرع (Settings → Branches → Add rule → Require status checks to pass).
.github/workflows/notifier.yml:
name: Notifier une URL
on:
workflow_dispatch:
jobs:
notifier:
runs-on: ubuntu-latest
steps:
- name: Ping du webhook
env:
URL: ${{ secrets.URL_WEBHOOK }}
run: |
curl -X POST "$URL" \
-H "Content-Type: application/json" \
-d '{"texte":"Un utilisateur a declenche notifier.yml"}'يُعرَّف السر URL_WEBHOOK في Settings → Secrets and variables → Actions → New repository secret. لن يظهر أبداً في السجلات: يخفي GitHub تلقائياً أي قيمة تطابق سراً.
1. on: push بلا branches: — متى يُحفَّز؟
يُحفَّز عند كل دفع على كل الفروع. نادراً ما يكون مرغوباً: git push على فرع ميزة قيد التطوير سيشغّل نشراً لـ Pages في الإنتاج. دائماً قيّد بـ branches: [main] أو قائمة صريحة.
2. لماذا يلزم id-token: write لـ Pages؟ ما فائدة رمز OIDC؟
يستخدم actions/deploy-pages@v4 OIDC (OpenID Connect) لإثبات لخدمة Pages أن الطلب يأتي فعلاً من تشغيل GitHub Actions مخوَّل، بلا كلمة مرور ولا PAT (Personal Access Token). رمز OIDC زائل (عمره محدود بالتشغيل) وموقَّع من GitHub — أكثر أماناً من سر ثابت. يخوّل id-token: write العدّاء توليد هذا الرمز لهذه سيرة العمل.
3. دفعان متزامنان على main — ماذا يفعل concurrency؟
بلا concurrency، يشغّل GitHub سبرتَي عمل متوازيتين. ينهي الأول رفع أثره، يبدأ الثاني رفعه الخاص، وقد تتلقى Pages النشرين بترتيب معكوس ← الترتيب النهائي غير مضمون. مع concurrency: { group: pages, cancel-in-progress: false }، التشغيلان مُسلسلان: ينتظر الثاني انتهاء الأول. لـ cancel-in-progress: true أثر آخر — إلغاء التشغيل الجاري ما إن يبدأ جديد، مفيد لإعادة بناء فائقة السرعة لكنها خطرة لـ Pages.
4. هل يمكن أن يظهر سر في السجلات؟
يخفي GitHub تلقائياً أي قيمة مسجَّلة كسر: تظهر بشكل *** في السجلات. لكن إن حوّلت السر (مثلاً echo "$SECRET" | base64)، لا ينطبق الإخفاء على القيمة المحوَّلة. القاعدة: لا تحوّل سراً أبداً في run:، استخدمه كما هو عبر env: ومرّره مباشرة للأداة (هنا curl).
5. لماذا الإبقاء على سيرتَي العمل deployer-pages.yml و verifier-config.yml؟
deployer-pages.yml تنشر على main: هذه سيرة عمل التسليم. لا تدور إلا بعد دمج.verifier-config.yml تتحقق على فروع الميزة وعلى PR: هذه سيرة عمل الوقاية. تمنع وصول config.json مكسور إلى main.تشكّلان شبكة بطبقين: التحقق يحجب في المنبع، والنشر يسلّم في المصب. هذا نمط CI (تكامل مستمر) + CD (نشر مستمر).
6. ماذا لو أنشأ build.py ملفاً historique.log؟
لا شيء دائم. العدّاء آلة زائلة تُدمَّر في نهاية التشغيل. يختفي الملف مع الآلة. للحفاظ على تاريخ بين التشغيلات، يلزم إيداعه في المستودع (سيئ، يلوّث المستودع)، أو تخزينه في أثر بـ actions/upload-artifact (عمر أقصى 90 يوماً)، أو إرساله إلى خدمة خارجية (S3، Postgres، إلخ).
| العَرَض | السبب المحتمل | الحل |
|---|---|---|
Resource not accessible by integration | كتلة permissions: غائبة أو ناقصة | أضف pages: write + id-token: write |
| لا تشغيل يُحفَّز | خطأ إملائي في on: (pushh:، pull_requests:) | تحقق من إملاء مفاتيح YAML |
Path does not exist: ./xxx | المسار في upload-pages-artifact.path: لا يطابق مجلد خرج build.py | تحقق أن path: = dist |
| الصفحة المنشورة تعرض المحتوى القديم | ذاكرة المتصفح المؤقتة | Ctrl+Shift+R لإعادة تحميل قاسية |
| أول نشر يستغرق > 5 دقائق | انتشار DNS لـ GitHub Pages | طبيعي في المرة الأولى، ~40 ث بعدها |
سيرة عمل حمراء في خطوة python outils/build.py | config.json باطل | شغّل python .\outils\build.py محلياً لرؤية الخطأ الدقيق |
| تعمل سيرة العمل لكن يعيد URL خطأ 404 | مصدر Pages ما زال في وضع « Deploy from a branch » | انتقل إلى GitHub Actions في Settings → Pages |
| تشغيلان لـ Pages في الوقت نفسه ينتجان محتوى غير متسق | concurrency: غائب | أضف الكتلة concurrency: { group: pages } |
يفتح الأستاذ ثلاثة تبويبات:
config.json، وجود .github/workflows/ مع 3 سير عمل مصحَّحة على الأقل (الأصليتان deployer-pages.yml و verifier-config.yml + الأعطال الثلاثة المصلحة).Deployer sur GitHub Pages (المهمة 2)، زائد تشغيلات المهمة 3 (قبل/بعد الإصلاح).https://<vous>.github.io/<votre-depot>/ — يجب أن يظهر بألوانك المخصَّصة و SHA حديث.ثم يقرأ RAPPORT.md لديك:
تقرير نظيف + مستودع منظَّم = علامة كاملة سهلة. الصعوبة ليست تقنية، بل في صرامة الإثبات.
دورة من إعداد د. هيثم رحومة — تطوير ونشر حلول البيانات