اذهب إلى المحتوى

استخدام GitHub Actions لتحقيق التكامل المستمر والنشر المستمر


ابراهيم الخضور

سنلقي نظرةً قبل أن نبدأ التعامل مع GitHub Actions على ماهيته والطريقة التي يعمل بها.

يعمل GitHub Actions على مبدأ مخططات العمل workflows؛ ومخطط العمل هو سلسلة من الأعمال التي تُنفَّذ عندما يقع حدثٌ معين، وتتضمن هذه الأعمال بحد ذاتها التعليمات التي يجب أن يُنفّذها GitHub Actions.

سيبدو تنفيذ مخطط عمل نموذجي على النحو التالي:

  • وقوع حدثٌ ما، مثل دفع push شيفرة إلى الفرع الرئيسي.
  • البدء بتنفيذ مخطط العمل.
  • الإنهاء والتنظيف.

الاحتياجات الأساسية

نحتاج عمومًا إلى المتطلبات التالية لتشغيل منظومة التكامل المتواصل Continuous Integration -أو اختصارًا CI- ضمن مستودع:

  • مستودع.
  • بعض التعريفات بالمهام التي ستنفذها منظومة CI، وقد يكون ذلك على هيئة ملف ضمن المستودع، أو يمكن أن يُعرَّف ضمن منظومة CI.
  • يجب أن تعرف المنظومة أنّ المستودع (والملف في داخله) موجودٌ فعلًا.
  • تحتاج المنظومة إلى الأذونات اللازمة لتنفيذ الأفعال التي يفترض أن تُنفذها، فلو أردنا من المنظومة أن تكون قادرةً على النشر في بيئة الإنتاج مثلًا، فستحتاج إلى بيانات الاستيثاق الخاصة بهذه البيئة.

سنحتاج ما ذكرناه على الأقل في النموذج التقليدي للمنظومة. سنرى لاحقًا كيفية اختصار بعض الخطوات أو تنفيذها بطريقة مريحة لا تسبب لك أية مشاكل تقلق منها.

لاستضافة GitHub Actions إيجابياتٌ عظيمة بالموازنة مع الاستضافة الذاتية؛ إذ سيُستضاف المستودع مع مزوِّد لمنظومة CI، أي سيؤمن لك GitHub Actions المستودع ومنظومة CI معًا، ويعني ذلك أننا عندما نُمكِّن الأفعال ضمن المستودع، سيكون GitHub Actions على علم مسبقًا بأنه لدينا مخططات عمل مُعرًّفة، وبما تعنيه هذه التعريفات.

التمرين 11.2

سننفذ في معظم تمرينات هذا القسم خط إنتاج لمنظومة CI/CD من أجل المشروع الصغير الموجود على غيت هب GitHub.

تنبيه: قد لا تعمل الشيفرة مع الإصدار 15 من Node، وإذا حدث ذلك ولم يُقلع المشروع، انتقل للعمل على الإصدار 14 وإلا عليك حل مشاكلك بنفسك.

المشروع النموذجي

عليك أولًا إنشاء نسخةٍ من مستودع المشروع ضمن حسابك الخاص ولاستخدامك الشخصي.

لاشتقاق المستودع، انقر على الزر "Fork" في أعلى ويمين واجهة المستودع بجانب الزر "Star":

fork_repository_01.png

سيبدأ بعد ذلك بإنشاء مستودع جديد يُدعى "github_username}/full-stack-open-pokedex}"، وستُنقل بعد انتهاء العملية إلى مستودعك الجديد تلقائيًا:

new_repository_created_02.png

انسخ المشروع الآن إلى جهازك، وكما جرت العادة إبدأ بتفقد الملف "package.json" فهو المكان الأنسب للاطلاع على تفاصيل مشروع جديد.

حاول أن تنفّذ ما يلي:

  • تثبيت الاعتماديات باستخدام الأمر npm install.
  • تشغيل الشيفرة في وضع التطوير.
  • إجراء الاختبارات.
  • تدقيق lint الشيفرة.

قد تلاحظ وجود بعض أخطاء التدقيق والاختبارات المخفقة في المشروع، دعها كما هي حاليًا، إذ سنتكفل بحلها في التمارين القادمة.

وكما ذكرنا في القسم 3، لا ينبغي تشغيل شيفرة React في وضع التطوير بعد نشرها في وضع الإنتاج، لذلك حاول أن تُنفِّذ ما يلي:

  • أنشئ نسخة إنتاج من المشروع.
  • شغل نسخة الإنتاج على جهازك محليًا.

ستجد سكربتًا خاصًا لتنفيذ المهمتين السابقتين في المشروع.

خذ وقتًا لدراسة هيكيلية المشروع.

وكما ستلاحظ، فإن الواجهتين الأمامية والخلفية موجودتان في نفس المستودع، وقد اعتدنا في الأقسام الأولى على وجودهما في مستودعين منفصلين. لكن هذا الأمر سيبسط الأمور عند إعداد بيئة CI.

ستجد بالمقابل أنّ الواجهة الأمامية في معظم مشاريع منهاجنا لم تُنفّذ باستخدام "create-react-app"، لكنها تمتلك إعدادات تهيئة بسيطة باستخدام webpack تتكفل بإنشاء بيئة التطوير وبإنشاء حزمة الإنتاج.

التعامل مع مخططات العمل

تُعد مخططات العمل الأساس الذي تبنى عليه منظومات CI في غيت هب GitHub، فهي مساراتٌ لعملية يمكنك إعدادها لتنفيذ مهام تلقائيًا، مثل بناء التطبيقات واختبارها وتدقيقها وإصدارها ونشرها. تبدو عادةً هيكلية مخططات العمل على النحو التالي:

مخطط العمل

  • مهمة
  • خطوة
  • خطوة
  • مهمة
  • خطوة

ينبغي أن يحدد كل مخطط مهمةً واحدةً على الأقل تحتوي على خطوات لتنفيذ إجراءات مستقلة. ستُشغّل هذه المهمات على التوازي بينما تُنفًّذ الخطوات في كل مهمة على التتالي.

تتنوع الخطوات من تنفيذ سطر أوامر محدد إلى الأفعال المعرَّفة مسبقًا، لهذا تحمل الاستضافة اسم أفعال غيت هب "GitHub Actions". يمكنك إنشاء الأفعال الخاصة بك أو أن تستخدم أفعالُا نشرها آخرون، وهي في الواقع كثيرة، وسنعود إليها لاحقًا.

ينبغي أن تُحدِّد مخططات العمل الخاصة بك ضمن المجلد "github/workflows." في مستودعك كي يميزها غيت هب، ولكل مخطط عمل ملفٌ مستقلٌ خاصٌ به والذي يجب تهيئته باستخدام لغة تقسيم البيانات YAML.

يُشتق الاسم YAML من العبارة "YAML Ain't Markup Language" والتي تعني "ليست لغة توصيف"؛ فكما تُلمّح إليه التسمية، فالهدف منها أن تكون مفهومةً للبشر. تُستخدم هذه اللغة في كتابة ملفات التهيئة، وستجد أنها سهلة الفهم فعلًا.

عليك الانتباه إلى أهمية الانزياحات Indentation في بداية الأسطر البرمجية في YAML، وللاطلاع أكثر حول قواعد اللغة يمكنك الرجوع إلى شبكة الإنترنت.

يتضمن مخطط العمل في مستند YAML هذه العناصر الثلاث:

  • name الاسم: ويشير إلى اسم المخطط.
  • triggers المُسبب: الأحداث التي تؤدي إلى تنفيذ المخطط.
  • jobs المهام: المهام المختلفة التي سيُنفّذها المخطط، وقد يحتوي المخطط البسيط مهمةً واحدةً فقط.

سيبدو تعريف مخطط بسيط على النحو التالي:

name: Hello World!

on:
  push:
    branches:
      - master

jobs:
  hello_world_job:
    runs-on: ubuntu-20.04
    steps:
      - name: Say hello
        run: |
          echo "Hello World!"

وكما هو واضح، سيكون المُسبب هو عملية دفع الشيفرة إلى الفرع الرئيسي. يحتوي المخطط أيضًا على مهمة واحدة اسمها hello_world_job سيجري تنفيذها ضمن بيئة افتراضية تعمل على نظام التشغيل أوبنتو Ubuntu 20.04، وتتضمن هذه المهمة خطوة واحدة اسمها Say hello ستُنفِّذ الأمر "!echo "Hello World ضمن الصدفة shell.

ربما تتساءل، متى يبدأ غيت هب بتنفيذ مخطط معين؟ هناك العديد من الخيارات المتاحة، لكن وبصراحة، يمكنك أن تهيئ المخطط ليعمل حالما:

  • يقع حدث ما، مثل الحالة التي يدفع فيها أحدهم اعتمادًا commit إلى مستودع، أو عندما تحدث مشكلة أو يقدم أحدهم طلب سحب pull request.
  • تُنفَّذ مهمةٌ مجدولةٌ مسبقًا ومحددة باستخدام تعابير cron.
  • يقع حدث خارجي، كأن يُنفَّذ أمر ضمن تطبيق خارجي، مثل تطبيق الرسائل Slack.

وللاطلاع على مزيدٍ من الأحداث المسببة لبدء تنفيذ مخطط عمل، عُد إلى توثيق GitHub Actions.

التمرينان 11.3- 11.4

لنربط كل ما خلصنا إليه، دعونا نشغِّل GitHub Actions ضمن المشروع النموذجي.

11.3: تطبيق Hello world

أنشئ مخططًا يُظهر العبارة "!Hello World" للمستخدم. عليك أن تنشئ المجلد "github/workflows."، والملف "hello.yml" الذي سيحتوي الإعدادات ضمن مستودعك.

ولتطلع على ما أنجزه مخطط عمل GitHub Actions الخاص بك، يمكن التوجه إلى النافذة Action ضمن واجهة غيت هب GitHub، حيث من المفترض أن ترى مخطط العمل في مستودعك والخطوات التي أنجزها. ستبدو نتيجة تنفيذ مخططك على النحو التالي إن كانت تهيئة المخطط صحيحة:

workflows_output_03.png

يُفترض أن ترى الرسالة "!Hello World" نتيجةً لتنفيذ المخطط، وإذا حدث ذلك، ستكون جميع الخطوات قد نُفِّذت بنجاح، وسيكون أول مخططات عمل GitHub Actions الخاصة بك قيد العمل.

سيعطيك أيضًا GitHub Actions معلومات عن البيئة (نظام التشغيل، وإعداداته) التي يعمل ضمنها مخطط العمل. وتظهر أهمية ذلك أثناء حدوث أمر طارئ، إذ سيسهل هذا الأمر تنقيح الأخطاء إن استطعت تكرار كل الخطوات على جهازك.

11.4: التاريخ ومحتويات المجلد

وسًع مخطط العمل لإضافة خطوات لطباعة التاريخ ومحتويات المجلد الحالي بالصياغة الطويلة long format. يمكن تنفيذ هاتين الخطوتين باستخدام الأمرين date و ls بكل بساطة.

سيبدو مخطط عملك الآن على النحو التالي:

extended_workflow_04.png

وطالما أن الأمر ls -l سيُظهر افتراضيًا البيئة الافتراضية التي يعمل عليها مخطط العمل، ستلاحظ أنها لا تحتوي على أية شيفرات.

إعداد وتجهيز خطوات التدقيق والاختبار والبناء

بعد إنجاز التمارين الأولى، سيكون لدينا مخطط عمل بسيط لكنه لن يفيدنا في عملية الإعداد. لنجعل مخطط العمل قادرًا على فعل مهمة حقيقية.

سننجز فعلًا action قادرًا على تدقيق الشيفرة. فإذا أخفق التدقيق، سيُظهر Github Actions الحالة الحمراء.

سيبدو المخطط الذي سنخزنه ضمن الملف "pipeline.yml" مبدئيًا على النحو التالي:

name: Deployment pipeline

on:
  push:
    branches:
      - master

jobs:

قبل أن نتمكن من تنفيذ الأمر الذي سيبدأ خطوة التدقيق، لا بدّ من تنفيذ فعلين لإعداد البيئة الملائمة للمهمة.

إعداد بيئة العمل

إعداد بيئة العمل أمرٌ ضروري لتهيئة خط الإنتاج Pipeline، لذلك سنستخدم بيئة العمل الافتراضية Ubuntu 20.04 لأنها ستكون البيئة التي ستعمل عليها نسخة الإنتاج.

ولا بدّ من تطابق البيئة نفسها في منظومة CI وفي وضع الإنتاج قدر المستطاع، لتحاشي الحالات التي تعمل فيها الشيفرة نفسها بصورةٍ مختلفة في كليهما، وبالتالي لن تتحقق الغاية من استخدام CI.

سنوضح تاليًا الخطوات في مهمة "البناء" لكي تستطيع منظومة CI تنفيذها. وكما لاحظنا في التمارين السابقة، لن تحتوي بيئة العمل افتراضيًا أية شيفرات، لذلك لا بدّ من التحقق من الشيفرة من المستودع.

هذه الخطوة سهلة وهي على النحو التالي:

name: Deployment pipeline

on:
  push:
    branches:
      - master

jobs:
  simple_deployment_pipeline:    
    runs-on: ubuntu-20.04
    steps:      
     - uses: actions/checkout@v3

تُستخدم التعليمة uses لإخبار المخطط أن يُنفِّذ فعلًا محددًا. ويُعرَّف الفعل بأنه قطعة من الشيفرة قابلة لإعادة الاستخدام مثل الدوال، ويمكن تعريف الأفعال داخل المستودع ضمن ملف مستقل، أو استخدام الأفعال الموجودة في المستودعات العامة.

سنستخدم هنا الفعل العام actions/checkout وبنسخة محددة هي "v3@" لتلافي فشل التعديلات إن جرى تحديث الفعل. ويُنفِّذ الفعل checkout ما يوحي به اسمه، إذ يتحقق من شيفرة المشروع المصدرية من git.

وطالما أنّ التطبيق قد كتب باستخدام جافا سكربت، فلا بدّ من تهيئة "Node.js" لكي نتمكن من استخدام الأوامر الموجودة في الملف "package.json". ولإعداد "Node.js" يمكن استخدام الفعل actions/setup-node. سنختار الإصدار "16" لأنه الإصدار الذي تستخدمه بيئة الإنتاج.

# name and trigger not shown anymore...

jobs:
  simple_deployment_pipeline:
    runs-on: ubuntu-20.04
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v2        
        with:          
        node-version: '16'

تُستخدم التعليمة with لإسناد معامل parameter إلى الفعل، إذ يحدد المعامل هنا نسخة Node.js التي ننوي استخدامها.

أخيرًا، لا بُد من تثبيت الاعتماديات اللازمة. وكما تفعل عادةً على جهازك، نفِّذ الأمر npm install. ستبدو خطوات المهمة على النحو التالي:

jobs:
  simple_deployment_pipeline:
    runs-on: ubuntu-20.04
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v2
        with:
          node-version: '16'
      - name: npm install
        run: npm install

وهكذا ستكون البيئة الآن جاهزةً لأداء مهمة حقيقية ومهمة.

التدقيق Lint

يمكنك الآن تنفيذ السكربتات التي يحتويها الملف "package.json" كما لو أنك تنفذها على حاسوبك الشخصي، فكل ما عليك فعله لتدقيق الشيفرة، هو إضافة إعدادٍ لتشغيل الأمر npm run eslint:

jobs:
  simple_deployment_pipeline:
    runs-on: ubuntu-20.04
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v2
        with:
          node-version: '16'
      - name: npm install 
        run: npm install  
      - name: lint        
        run: npm run eslint

التمرينات 11.5 - 11.9

11.5: تدقيق مخطط عمل

نفّذ أو انسخ والصق مخطط العمل "Lint" واعتمد شيفرته في مستودعك، ثم أنشئ ملف yml جديد لهذا المخطط، يمكنك تسميته "pipeline.yml".

ادفع بشيفرتك إلى الفرع الرئيسي ثم توجه إلى النافذة "ِActions" وانقر على المخطط الذي أنشأته على اليسار. ستجد أن هذا المخطط سيفشل في الإقلاع:

Lint_workflow_failed_05.png

11.6: إصلاح الشيفرة

ستجد بعض المشاكل في الشيفرة تتطلب الإصلاح. افتح سِجِل مخطط العمل وتحقق من وجود أخطاء.

إليك تليمحين مهمين: من الأفضل أن تصلح أحد الأخطاء بتحديد ملف مناسب لعملية التدقيق (راجع القسم الثالث لمزيد من المعلومات عن كيفية تنفيذ ذلك)؛ كما يمكن إيقاف أحد الاعتراضات التي تخص تنفيذ الأمر console.log بإيقاف القاعدة التي تسببه في السطر الذي توجد به.

أجرِ التعديلات اللازمة على الشيفرة المصدرية لكي ينجح مخطط العمل في الإقلاع، وحالما تعتمد الشيفرة الجديدة سيعمل المخطط وستجد خرجًا مُحدَّثًا باللون الأخضر من جديد.

lint_workflow_starts_06.png

11.7: البناء والاختبار

لنوسِّع مخطط العمل الذي يُنفِّذ حاليًا مهمة التدقيق. أضف أوامر البناء والاختبار إلى مخطط العمل، وستبدو النتيجة قريبةً من التالي:

workflow_test_07.png

ستلاحظ أيضًا وجود بعض المشاكل.

11.8: العودة إلى الوضع الصحيح

تحقق من الاختبارات التي أخفقت وأصلح المشكلة في الشيفرة (لا تُغيّر الاختبارات). سيعمل المخطط ويظهر الخرج باللون الأخضر مجددًا عند إصلاح المشاكل.

workflow_test_works_08.png

11.9: اختبار مشترك بسيط للواجهتين

تستخدم مجموعة الاختبارات الحالية jest لتتأكد من عمل مكونات React بالطريقة المطلوبة، وهذا تمامًا ما فعلناه في فصل "اختبار تطبيقات React" من القسم 5.

يُعد اختبار كل مكوًن بصورةٍ منفصلة أمرًا مفيدًا لكنه لا يضمن عمل كل النظام بالطريقة المطلوبة. وللتأكد أكثر، سنكتب اختبارًا بسيطًا مشتركًا بين الواجهتين الأمامية والخلفية end to end testing، مستخدمين المكتبة Cypress وعلى نحوٍ مشابه للعمل الذي أنجزناه في الفصل الذي يحمل العنوان "الاختبار المشترك للواجهتين" في القسم 5.

سنهيئ cypress (ستجد الطريقة في الفصل الذي أشرنا إليه)، ثم سننفذ الاختبار التالي:

describe('Pokedex', function() {
  it('front page can be opened', function() {
    cy.visit('http://localhost:5000')
    cy.contains('ivysaur')
    cy.contains('Pokémon and Pokémon character names are trademarks of Nintendo.')
  })
})

عرِّف سكربت npm التالي: test:e2e لتشغيل الاختبار المشترك للواجهتين "e2e" باستخدام سطر الأوامر.

تنبيه: لا تستخدم الكلمة "spec" في تسمية ملف اختبار cypress، لأنها ستجعل jest ينفذ شيفرة الملف أيضًا، وقد يسبب ذلك عدة مشاكل.

تنبيه آخر: على الرغم من قدرة الصفحة على تصيير أسماء "مخلوقات البوكيمون Pokemon" لتبدأ بأحرف كبيرة، إلا أنها مكتوبةٌ بأحرف صغيرة في المصدر، فاسم البوكيمون "Ivysaur" هو أصلًا "ivysaur"

تحقق من نجاح الاختبار على جهازك، وتذكر أن الاختبارات ستفترض أن تطبيقك يعمل عندما تُنفِّذ الاختبار. وإن كنت قد نسيت بعض التفاصيل، راجع القسم 5.

حالما يعمل الاختبار المشترك للواجهتين على جهازك، ضعه في مخطط عمل GitHub Action، وأسهل الطرق لتنفيذ ذلك هو استخدام الفعل الجاهز cypress-io/github-action، وستكون الخطوة المناسبة لحالتنا على النحو التالي:

- name: e2e tests
  uses: cypress-io/github-action@v2
  with:
    command: npm run test:e2e
    start: npm run start-prod
    wait-on: http://localhost:5000

لقد استخدمنا ثلاثة خيارات:

  • command: ويحدد كيف سنشغل اختبار cypress.
  • start: يزودنا بسكربت npm الذي يُشغِّل الخادم.
  • wait-on: يمنع الاختبار من العمل قبل أن يقلع الخادم على العنوان http://localhost:5000.

عندما تتأكد من عمل خط الإنتاج، اكتب اختبارًا آخر للتأكد أنّ المستخدم قادرٌ على الانتقال من الصفحة الرئيسية إلى صفحة "بوكيمون" محدد مثل "ivysaur". لا حاجة لتعقيد الاختبار، بل تأكد فقط أن الصفحة التي تنتقل إليها بنقر الرابط، ستحتوي بعض المعلومات الصحيحة مثل النص "chlorophyll" في حالة البوكيمون "ivysaur".

ملاحظة: تُكتب أسماء البوكيمون بالأحرف الصغيرة، ويمكن الكتابة بالأحرف الكبيرة في CSS، لذلك لا تكتب أثناء البحث الاسم "Chlorophyll"، بل اكتب "chlorophyll".

ملاحظة: لا تحاول الانتقال إلى صفحة البوكيمون "bulbasaur"، فربما لسببٍ ما لن تعمل صفحة هذا البوكيمون.

ستبدو النتيجة النهائية على الشكل التالي:

workflow_e2e_test_09.png

إن الأمر الجيد المتعلق بالاختبار المشترك للواجهتين هو الثقة بأنّ البرنامج سيعمل على نحوٍ جيد من وجهة نظر المستخدم النهائي. لكن سيكون الثمن الذي تدفعه بالمقابل هو الاستجابة البطيئة، إذ سيستغرق تنفيذ مخطط العمل بالكامل وقتًا أطول بكثير.

ترجمة -وبتصرف- للفصل Getting started with GitHub Actions من سلسلة Deep Dive Into Modern Web Development.

اقرأ أيضًا


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...