البحث في الموقع
المحتوى عن 'التكامل المستمر'.
-
يُعَد إعداد تطبيقات الويب لعمليتيْ التكامل المستمر Continuous Integration والنشر المستمر Continuous Deployment مرحلةً بالغة الأهمية في مجال التطوير، ويُرمَز لها اختصارًا بـ CI/CD، فقد تتعرض جميع المشاريع البرمجية للأخطاء مهما كانت أحجامها وخاصةً عندما يجتمع الفريق البرمجي ليَعمَل على مشروعٍ واحدٍ، إذ يَسُهل إيجاد وإصلاح هذه الأخطاء إذا كان هناك تكاملٌ وإعدادٌ دائمٌ لنشر التطبيقات بصورةٍ مستمرةٍ وذلك باستخدام اختباراتٍ مُحكمَة الإعداد. سنتعرّف في هذا المقال على كيفية التحقق من تغطية الاختبار test coverage، كما سنُعِدّ تطبيقات الويب لعمليتيْ التكامل المستمر والنشر المستمرة CI/CD، وذلك باستخدام CircleCI وCoveralls، وسنتطرق كذلك إلى كيفية نَشْر تطبيق Vue فيو جي إس على منصة هيروكو Heroku، ستستفيد من هذا المقال حتى إذا كنت مِمن لا يُفضّل هذا الخليط من الأدوات، حيث يمكنك أن تَستخدِم إطار عملٍ مختلفٍ عن فيو جي إس مثلًا لكتابة جافاسكربت، إذ ستبقى المبادئ الأساسية هي ذاتها. وقبل ذلك إليك بعض المصطلحات. التكامل المستمر Continuous integration: وفيها يُثبّت commit المُطوّرون الكود الذي يكتبونه مُبكرًا وبصورةٍ مستمرةٍ، مما يتيح إمكانية تطبيق اختباراتٍ وعمليات بناءٍ عديدةٍ قَبل الدمج أو النشر. النشر المستمر Continuous deployment: وفيه يَحرِص المُطوّرون على أن تَقبَل البرمجية النشْر في كل الأوقات. تغطية الاختبار Test Coverage: وهو مقياسٌ يَصِف درجة اختبار البرمجية، حيث يُشير مصطلح البرمجية ذات التغطية العالية إلى أن غالبية كود هذه البرمجية يَخضَع للاختبار. ولتحقيق أقصى استفادةٍ من هذا البرنامج التعليمي يُستحسَن أن يكون لديك ما يلي: حساب في منصة CircleCI: وهي منصةٌ للتكامل المستمر والنشر المستمر CI/CD، وسنستفيد منها في برنامجنا التعليمي عن طريق استخدامها للنّشْر الآلي الذي يتضمن اختبار وبناء التطبيق قَبل النّشْر. حساب في موقع غيت هاب Github: وهو الموقع الذي سنُخزّن في مُستودَعٍ repository فيه كود المشروع واختباراته. حساب في منصة هيروكو Heroku: وهي منصةٌ خاصةٌ بنشر وتوسيع نطاق التطبيقات، وسنستخدمه من أجل نَشْر واستضافة hosting التطبيق. حساب في منصة Coveralls: وسنستخدم هذه المنصة لإظهار وتسجيل درجة وكفاءة تغطية الكود code coverage. حزمة NYC: وسنستخدم هذه الحزمة لنتحقق من خضوع الكود للتغطية بصورةٍ جيدةٍ. سنجهز الآن ما يلزمنا للعمل سنبدأ بتثبيت حِزمة NYC في مُجلد المشروع، هكذا: npm i nyc بعدها سنُعدّل نصوص ملف package.json البرمجية لنتحقق من تغطية الاختبار، وإذا كنا سنتحقق من التغطية أثناء إجراء اختبارات الوِحدة unit tests، فسيتوجّب علينا تعديل النَّص البرمجي للاختبار، كما يأتي: "scripts": { "test:unit": "nyc vue-cli-service test:unit", }, لقد بُنَي الأمر السابق command على افتراض أننا سنبرمج تطبيق الويب باستخدام إطار عمل فيو Vue، إذ تُشير الخدمة vue-cli-service إليه، ولذلك إذا كنا سنستخدم إطار عملٍ آخرٍ في المشروع، فسيتعيّن علينا تغيير هذا الأمر؛ أما إذا كنا سنتحقق من التغطية بصورةٍ منفصلةٍ، فحينها سيتوجّب علينا إضافة سطرٍ آخرٍ إلى النصوص البرمجية، كما يلي: "scripts": { "test:unit": "nyc vue-cli-service test:unit", "coverage": "nyc npm run test:unit" }, وبعدها يمكننا التحقق من التغطية باستخدام أمر npm run coverage المُضّمن في واجهة سطر الأوامر terminal كالآتي: npm run coverage ثم سنُثبّت خدمة Coveralls، فهي مسؤولةٌ عن إيجاد وإظهار التغطية، هكذا: npm i coveralls وبعد ذلك سنضيف خدمة Coveralls مثل نَّصٍ برمجيٍ في ملف package.json، حيث سيساعدنا هذا النَّص على حفظ تقرير تغطية الاختبار في Coveralls: "scripts": { "test:unit": "nyc vue-cli-service test:unit", "coverage": "nyc npm run test:unit", "coveralls": "nyc report --reporter=text-lcov | coveralls" }, كما سنستخدم هيروكو Heroku لاستضافة تطبيقنا، ولذلك سننتقل إلى لوحة إعداد dashboard هيروكو لنُسجّل التطبيق. وسنستخدم منصة CircleCI لأتمتة عمليتيْ التكامل المستمر والنشر المستمر CI/CD، ولذلك سننتقل إلى لوحة إعداد CircleCI لنُهيّئ مشروعنا. ويمكننا استعراض قائمة مشاريعنا في غيت هاب بالانتقال إلى تبويب Projects في الشريط الجانبي لمنصة CircleCI، فبالنَّقر فوق زِرّ (أيقونة) Set Up Project أو إعداد المشروع، ستظهر صفحةٌ جديدةٌ تسألك عن ما إذا كنت تريد استخدام التهيئة config الموجودة مسبقًا أم لا، وبما أننا نمتلك تهيئةً مُعدّةً مسبقًا، فسنختار use an existing config أو استخدام تهيئةٍ موجودةٍ مسبقًا، وبعدها سننتقل إلى تبويب pipeline الخاص بالمشروع، بهذا نكون قد انتهينا من إعداد الاتصال بين مستودع repository غيت هاب ومنصة CircleCI، حيث حان دور إضافة متغيّرات البيئة إلى مشروع CircleCI. ولإضافة متغيراتٍ جديدةٍ، يجب علينا الانتقال إلى إعدادات المشروع، هكذا. ستجد في الشريط الجانبي في إعدادات المشروع تبويب Environment Variables أو متغيّرات البيئة، وهو مكان تخزين المتغيّرات التي سنضيفها. والمتغيّرات التي سنحتاجها في هذا البرنامج التعليمي هي: HEROKU_APP_NAME: اسم تطبيق هيروكو. HEROKU_API_KEY: مفتاح واجهة التطبيقات البرمجية API لمنصة هيروكو Heroku. COVERALLS_REPO_TOKEN: مفتاحٌ مساعدٌ token لمستودع Coveralls. ويمكننا إيجاد مفتاح واجهة التطبيقات البرمجية API لمنصة هيروكو Heroku في قسم account الموجود في لوحة إعداد هيروكو. ويوجد المفتاح المساعد token للمستودع repository في حساب Coveralls، ولذلك سنضيف المستودع إلى Coveralls أولًا، وهنا سنختار مستودع غيت هاب المناسب من قائمة المستودعات المتوفرة، كما هو موضح بالصورة الآتية. والآن بعد أن أضفنا المستودع إلى Coveralls، يمكننا النقر على المستودع لجَلْب المفتاح المُساعد token. دمج CircleCI بعد أن أنهينا ربط CircleCI مع مستودع غيت هاب، فسيُبَلّغ CircleCI عند حدوث تغيير ٍأو إجراءٍ في مستودع غيت هاب، وسنتّبع الآن الخطوات المناسبة لإبلاغ CircleCI بالعمليات التي نريد تنفيذها بعد حدوث تغييرٍ في المستودع، بعد ذلكسننشئ مجلدًا باسم circleci في مجلد الجذر root لمشروعنا المحلي، وسنضع فيه ملفًا باسم config.yml وهو الملف الذي سيحتوي على كلّ عمليات CircleCI. وإليك الشيفرة البرمجية التي سنضعها في الملف: version: 2.1 orbs: node: circleci/node@1.1 // node orb heroku: circleci/heroku@0.0.10 // heroku orb coveralls: coveralls/coveralls@1.0.6 // coveralls orb workflows: heroku_deploy: jobs: - build - heroku/deploy-via-git: # Use the pre-configured job requires: - build filters: branches: only: master jobs: build: docker: - image: circleci/node:10.16.0 steps: - checkout - restore_cache: key: dependency-cache-{{ checksum "package.json" }} - run: name: install-npm-dependencies command: npm install - save_cache: key: dependency-cache-{{ checksum "package.json" }} paths: - ./node_modules - run: # run tests name: test command: npm run test:unit - run: # run code coverage report name: code-coverage command: npm run coveralls - run: # run build name: Build command: npm run build # - coveralls/upload كما تلاحظ؛ تُعَد هذه الشيفرة البرمجية كبيرة ولذلك سنقسمها إلى أجزاءٍ لنشرح كلّ جزءٍ على حدةٍ. حزم Orbs orbs: node: circleci/node@1.1 // node orb heroku: circleci/heroku@0.0.10 // heroku orb coveralls: coveralls/coveralls@1.0.6 // coveralls orb تُعَد Orbs حِزمًا مفتوحة المصدر، فهي تُستَخدم لتبسيط تكامل البرامج والحِزم في المشاريع، وقد سبق وأشرنا في الكود الخاص بنا إلى حِزم orbs التي نستخدمها في عمليتيْ التكامل المستمر والنشر المستمر CI/CD، وإلى حِزمة orbs التي تَحمِل الاسم node وذلك لأننا نستخدم جافاسكربت، وإلى هيروكو Heroku لأننا نُنفّذ النشر المؤتمت باستخدام سيْر عمل workflow من هيروكو، وأيضًا إلى حِزمة coveralls من orbs لأننا نُخَطّط لإرسال نتائج تغطية الاختبار إلى Coveralls. تُعَد حزمتيْ Heroku وCoveralls من orbs حزمًا خارجيةً، فعند تشغيل التطبيق عن طريق الاختبار، فسيؤدي ذلك إلى حدوث خطأ يمكننا التخلص منه بالانتقال إلى صفحة Organization Settings في حساب CircleCI. بعد ذلك سننتقل إلى تبويب Security أو الأمان، بحيث نُفعّل حِزم orbs غير المعتمدة. سير العمل Workflow workflows: heroku_deploy: jobs: - build - heroku/deploy-via-git: # Use the pre-configured job requires: - build filters: branches: only: master يُستخدم سير العمل لتحديد مجموعةٍ من الوظائف ثم تشغيلها بالترتيب، وهذا القِسم من الكود مسؤول عن الاستضافة المؤتمتة، فهو يوعز إلى CircleCI ببناء المشروع ثم نشره، حيث تشير requires إلى أن وظيفة heroku/deploy-via-git تتطلب اكتمال البناء، مما يعني أن عملية النشر لن تَحصُل قبل اكتمال البناء. الوظائف Jobs jobs: build: docker: - image: circleci/node:10.16.0 steps: - checkout - restore_cache: key: dependency-cache-{{ checksum "package.json" }} - run: name: install-npm-dependencies command: npm install - save_cache: key: dependency-cache-{{ checksum "package.json" }} paths: - ./node_modules تُعَبر الوظيفة job عن مجموعةٍ من الخطوات، حيث سنستعيد في هذا القِسم من الكود التبعيات dependencies التي ثُبّتت أثناء عمليات البناء السابقة للمشروع وذلك من خلال الوظيفة restore_cache أو استعادة الذاكرة المؤقتة، ثم سنُثبّت التبعيات غير المخبّأة uncached dependencies، وسنحفظها كي لا نُعيد تثبيتها أثناء عملية البناء التالية. بعد ذلك سنطلب من CircleCI إجراء الاختبارات التي كتبناها للمشروع، بالإضافة إلى التحقق من التغطية الاختبارية للمشروع. رفع تغطية الكود الخاص بنا إلى منصة coveralls - run: # run tests name: test command: npm run test:unit - run: # run code coverage report name: code-coverage command: npm run coveralls # - coveralls/upload وستظهر قدرات coveralls بصورةٍ جليةٍ، بوصلنا إلى مكان إجراء اختبارات الوِحدة تَذكّر أننا أضفنا الأمر nyc إلى النص البرمجي الذي يُسمّى test:unit إلى ملف package.json، حيث ستَوفّر اختبارات الوِحدة تغطيةً الكود بفضل هذا الأمر. في النهاية، سيُشغّل الكود النَّص البرمجي الذي يُسمّى Coveralls والذي سبق وأضفناه إلى ملف package.json، حيث سيتولى هذا النَّص مَهمّة إرسال تقرير التغطية الخاص بنا إلى coveralls، ولعلك لاحظت عدم خضوع السطر coveralls/upload للتنفيذ (تعليق comment)، إذ كان من المفترض أن يكون السطر النهائي في العملية، ولكنه أصبح في النهاية مُعوّقًا كما يقول المطورون، وأوقفته عن التنفيذ بتعليقه (تعليق comment)، ولم أحذفه لأنه قد يكون ورقةً رابحةً لمطورٍ آخرٍ. تجهيز الأمور ودمجها سوية إليك تطبيقنا الجاهز بعد تطبيق كلّ من التكامل المستمر والنشر المستمر حيث تظهر فائدة التكامل والنشر المستمر في كثيرٍ من الحالات، ومن الأمثلة الشائعة لها؛ الحالة التي تكون فيها البرمجيّة في طور الاختبار، ففي هذه المرحلة تَحدُث الكثير من عمليات التصحيح على الكود، مما يؤدي إلى عمليات تثبيتٍ commit كثيرةٍ للكود البرمجي، ولنكون واقعيين، ,ولتفادي التكرار، فلا نودّ تشغيل الاختبارات ونشر التطبيق بصورةٍ يدويةٍ بعد كلّ تغييرٍ طفيفٍ يحدث. في الواقع، لقد كنا على درايةٍ بالتكامل المستمر والنشر المستمر CI/CD منذ فترةٍ طويلةٍ نسبيًا، ومع ذلك تجاهلنا هاتين العمليتين لأن الأمر كان يبدو صعبًا للغاية أو قد يستغرق وقتًا طويلاً، ولكن الآن بعد أن رأيت مدى سهولة الإعداد والفوائد التي تنتج عنهما، فيمكنك تُجرّبهما في مشروعك القادم. ترجمة -وبتصرف- للمقال A Continuous Integration and Deployment Setup with CircleCI and Coveralls من موقع CSS Tricks. اقرأ أيضًا اختبار الوحدات وأدوات تنقيح الشيفرات وتصحيح الأخطاء في Cpp لماذا عليك جعل الأذونات على الفرع الرئيسي master للقراءة فقط؟ التكامل المستمر: تثبيت Concourse CI على أوبنتو 16.04
-
- circleci
- التكامل المستمر
-
(و 1 أكثر)
موسوم في:
-
إنّ التكامل المستمر (Continuous integration) سهل للغاية. نزّل خدمة الأتمتة مفتوحة المصدر Jenkins، وثبّتها، وأنشئ وظيفة، وانقر على الزر، ثم احصل على رسالة بريد إلكتروني جميلة تفيد بأن إنشاءك مكسور أو معطّل (أفترض أن إنشاءك تلقائي). بعد ذلك، أصلح الاختبارات التي لا تعمل (أفترض كذلك أن لديك اختبارات)، واحصل على رسالة بريد إلكتروني أجمل تفيد أن إنشاءك على ما يرام. بعد ذلك، غرّد حول الموضوع مدعيا أن فريقك يستخدم التكامل المستمر. ثم في غضون أسابيع قليلة، ابدأ في فلترة تنبيهات Jenkins إلى مجلدها الخاص لكي لا تستمرّ بإزعاجك. على أي حال، ليس لدى فريقك الوقت أو الرغبة لإصلاح جميع اختبارات الوحدة في كل مرة يعطّلها شخص ما. بعد كل شيء، نعلم جميعًا أن اختبارات الوحدة لا تناسب فريقًا يعمل وفق مواعيد نهائية محدّدة، أليس كذلك؟ هذا خطأ. يمكن للتكامل المستمر أن يعمل في هذه الظروف بل ويجب أن يعمل فيها. ما هو التكامل المستمر؟ في الوقت الحاضر، تُطوّر البرمجيات في فرق نعمل على تطوير فروعٍ للميزات وعزل التعديلات أثناء تطويرها. ثم ندمج الفروع في فرع رئيسي master. وبعد كل عملية دمج، يُختبر المنتج بالكامل، وتُنفّذ جميع اختبارات الوحدة والتكامل المتاحة. وهذا ما يسمى «التكامل المستمر» (continuous integration ويعرف أيضا بالاختصار "CI"). في بعض الأحيان، تفشل بعض الاختبارات. عندما يحدث ذلك، نقول إن "البناءات مكسورة". مثل هذا الفشل هو أحد الآثار الجانبية الإيجابية لمراقبة الجودة لأنه يعطي تنبيهًا بعلامة حمراء فور حدوث خطأ ما. هذه ممارسة معروفة في تطوير البرمجيات، عندما يصبح إصلاح هذا الخطأ أولوية قصوى للمتسبّب فيه وللفريق بأكمله. إذ يتوجّب إصلاح الخطأ مباشرة بعد أن يرسل خادم التكامل المستمر تنبيهًا بالعلامة الحمراء. هناك بعض الأدوات الجيدة المتاحة في السوق، والتي تُؤتمت إجراءات DevOps. بعضها مفتوح المصدر يمكنك تنزيله وتثبيته على الخوادم الخاصة بك. نذكر منها على سبيل المثال: Jenkins و Go و CruiseControl. وبعضها الآخر متاح كخدمات سحابية، مثل: Travis و Shippable و Wercker وغيرها الكثير. لماذا لم يعد التكامل المستمر صالحًا؟ إن التكامل المستمر رائعٌ، ولكن في أغلب الأحيان كلما كان الفريق أكبر (وقاعدة الشيفرة كذلك)، كلما تعطلت الإنشاءات وكلما طالت المدة لإصلاحها. لقد رأيت العديد من الأمثلة يبدأ فيها فريق يعمل بجِدٍّ بتجاهل التنبيهات الحمراء، التي يرسلها Jenkins. بعد بضعة أسابيع، يصبح الفريق ببساطة غير قادر على إصلاح جميع الأخطاء في الوقت المناسب. وهذا، في الغالب، لأن العمل له أولويات أخرى. إذ لا يفهم مالكو المنتجات أهمية "البنية النظيفة" ولا يمكن للمدراء التقنيين شراء الوقت لتثبيت اختبارات الوحدة. كما أن الشيفرة المكسورة تكون أصلا في الفرع الرئيسي master، و في معظم الحالات، تكون قد نُشرت بالفعل على الإنتاج وسُلّمت للمستخدمين النهائيين. فما الحاجة إذن لإصلاح الاختبارات إذا كان العمل قد سُلّم فعليًا؟ لا تأخذ معظم فرق التطوير تنبيهات التكامل المستمر على محمل الجد. لا تمثّل Jenkins أو Travis بالنسبة لهم سوى مجرد أدوات لطيفة لا تلعب أي دور في عملية التطوير والتسليم بأكملها. بغض النظر عن ما يقوله خادم التكامل المستمر، مازلنا نقدم ميزات جديدة للمستخدمين النهائيين. ونترك إصلاح إنشائنا إلى وقت لاحق. وهذا منطقي بالنسبة لي. ما هو الحل؟ منذ بضع سنوات، نشرت مقالًا بعنوان "منع التعارضات في مشاريع PHP الموزّعة والمرنة". اقترحت في المقالة حلولًا لهذه الإشكالات في Subversion و PHP. منذ ذلك الوقت، استخدمت هذا النهج تجريبيًا في عدد من المشاريع مفتوحة المصدر وبعض المشاريع التجارية أيضا في PHP وجافا وروبي وجافاسكريبت و Git و Subversion. في جميع الحالات، كانت تجربتي إيجابية، ولهذا السبب رأى rultor.com النور لاحقًا. لذلك، فإن الحل بسيط للغاية: احظُر على أي شخص دمج أي شيء في الفرع الرئيسي master وأنشئ سكريبتًا يمكن لأي شخص استدعاؤه. سيقوم السكريبت بعمليات الدمج والاختبار والتنفيذ. لن تكون لدى السكريبت أي استثناءات. فإذا انكسر أي فرع في اختبار واحد، سيرفض الفرع بأكمله. بمعنى آخر، يجب أن تظهر تلك العلامة الحمراء للتنبيه قبل أن تنتقل الشيفرة إلى الفرع الرئيسي master. ويجب أن يتحمّل مسؤولية الاختبارات المكسورة من تسبّب فيها. لنفترض أنّني أقوم بتطوير ميزة في فرعي الخاص. انتهيت من التطوير وكسرت بعض الاختبارات عن طريق الخطأ. يحدث ذلك، فنحن جميعا نرتكب أخطاء. ولكن لا يمكنني دمج تعديلاتي في Master. سيرفض Git ببساطة تنفيذ الأمر push لأنني لا أملك الأذونات المناسبة. كل ما يمكنني فعله هو أن أستدعي السكريبت السحري، وأطلب منه دمج فرعي الخاص. سيحاول السكريبت الدمج، ولكن قبل الدخول إلى الرئيسية، ستشغّل جميع الاختبارات. وإذا كُسِر أي منها، سيكون الرفض نتيجة حتمية. لن تُدمج التعديلات التي أجريتها وأصبح لزامًا عليّ إصلاحها قبل استدعاء السكريبت مرة أخرى. قد يؤدي هذا النهج في البداية إلى إبطاء عملية التطوير، لأن على الجميع بدء كتابة تعليمات برمجية أنظف. ولكن في النهاية، فإن هذه الطريقة تؤتي ثمارها. إنشاءات ما قبل الإقلاع تقدم بعض خوادم التكامل المستمرّ CI ميزة "إنشاءات ما قبل الإقلاع"، وهذا يعني اختبار الفروع قبل دمجها في master رئيسي. لدى Travis، على سبيل المثال، هذه الميزة المفيدة للغاية. عندما تقوم بإيداع جديد في فرع ما، يحاول Travis إنشاءه على الفور، ويُبلغ عبر طلبات الإضافة في GitHub عن أي مشاكل قد تحدث. انتبه، فإنشاءات ما قبل الإقلاع لا تندمج. دورها فقط هو التحقّق مما إذا كان فرعك الخاصّ نظيفًا. بعد الدمج، يمكن بسهولة كسر الفرع الرئيسي master. لذا، فهذه الآلية لا تضمن أنه لا أحد يستطيع الإيداع بشكل مباشر، والتسبب بكسر عن طريق الخطأ. تبقى عمليات الإنشاء قبل الإقلاع تدبيرًا وقائيًا، لكنها لا تحل المشكلة تمامًا. موقع Rultor.com من أجل البدء في العمل وفق ما هو موضح أعلاه، كل ما عليك فعله هو إلغاء أذونات الكتابة في الفرع الرئيسي master (أو /trunk، في Subversion). لسوء الحظ، هذا غير ممكن في GitHub. الحل الوحيد هو العمل من خلال الفروع وطلبات السحب فقط. ما عليك سوى إزالة الجميع من قائمة المتعاونين (collaborators) وسيكون عليهم إرسال تعديلاتهم من خلال طلبات السحب. بعد ذلك، ابدأ في استخدام موقع rultor.com الذي سيساعدك على اختبار كل طلب للإضافة ودمجه ودفعه. في الأساس، Rultor هو السيناريو الذي كنا نتحدث عنه أعلاه، وهو متاح كخدمة سحابية مجانية. ترجمة -وبتصرف- للمقال Master Branch Must Be Read-Only لصاحبه Yegor Bugayenko
-
- التكامل المستمر
- أتمتة العمل
-
(و 2 أكثر)
موسوم في: