إنشاء سير عمل اختبار تكامل مستمر باستخدام إجراءات GitHub
نشرت: 2022-03-10عند المساهمة في مشاريع على منصات التحكم في الإصدار مثل GitHub و Bitbucket ، فإن الاصطلاح هو أن هناك فرعًا رئيسيًا يحتوي على قاعدة الشفرة الوظيفية. بعد ذلك ، هناك فروع أخرى يمكن للعديد من المطورين العمل فيها على نسخ من الرئيسي إما لإضافة ميزة جديدة ، وإصلاح الخلل ، وما إلى ذلك. إنه منطقي للغاية لأنه يصبح من الأسهل مراقبة نوع التأثير الذي ستحدثه التغييرات الواردة على الكود الحالي. إذا كان هناك أي خطأ ، فيمكن تتبعه وإصلاحه بسهولة قبل دمج التغييرات في الفرع الرئيسي. قد يستغرق الأمر وقتًا طويلاً لتصفح كل سطر من التعليمات البرمجية يدويًا للبحث عن الأخطاء أو الأخطاء - حتى بالنسبة لمشروع صغير. هذا هو المكان الذي يأتي فيه التكامل المستمر.
ما هو التكامل المستمر (CI)؟
"التكامل المستمر (CI) هو ممارسة أتمتة دمج تغييرات التعليمات البرمجية من مساهمين متعددين في مشروع برمجي واحد."
- موقع Atlassian.com
الفكرة العامة وراء التكامل المستمر (CI) هي التأكد من أن التغييرات التي يتم إجراؤها على المشروع لا تؤدي إلى "كسر البنية" ، أي تدمير قاعدة الكود الحالية. سيؤدي تنفيذ التكامل المستمر في مشروعك ، بناءً على كيفية إعدادك لسير العمل ، إلى إنشاء بنية كلما قام أي شخص بإجراء تغييرات على المستودع.
إذن ، ما هو البناء؟
البناء - في هذا السياق - هو تجميع شفرة المصدر في تنسيق قابل للتنفيذ. إذا كان ناجحًا ، فهذا يعني أن التغييرات الواردة لن تؤثر سلبًا على قاعدة الشفرة ، ومن الجيد أن تبدأ. ومع ذلك ، إذا فشل الإصدار ، فسيتعين إعادة تقييم التغييرات. هذا هو السبب في أنه من المستحسن إجراء تغييرات على المشروع من خلال العمل على نسخة من المشروع في فرع مختلف قبل دمجه في قاعدة الكود الرئيسية. بهذه الطريقة ، إذا تعطل البناء ، فسيكون من الأسهل معرفة مصدر الخطأ ، كما أنه لا يؤثر على شفرة المصدر الرئيسية.
"كلما اكتشفت العيوب مبكرًا ، كان إصلاحها أرخص."
- ديفيد فارلي ، التسليم المستمر: إصدارات موثوقة للبرامج من خلال أتمتة الإنشاء والاختبار والنشر
هناك العديد من الأدوات المتاحة للمساعدة في إنشاء تكامل مستمر لمشروعك. وتشمل هذه العناصر Jenkins ، و TravisCI ، و CircleCI ، و GitLab CI ، و GitHub Actions ، وما إلى ذلك. بالنسبة لهذا البرنامج التعليمي ، سأستخدم إجراءات GitHub.
إجراءات جيثب للتكامل المستمر
CI Actions هي ميزة جديدة إلى حد ما على GitHub وتمكن من إنشاء مهام سير عمل تعمل تلقائيًا على تشغيل بناء مشروعك واختباراته. يحتوي سير العمل على مهمة واحدة أو أكثر يمكن تنشيطها عند وقوع حدث ما. يمكن أن يكون هذا الحدث بمثابة دفعة إلى أي من الفروع الموجودة في الريبو أو إنشاء طلب سحب. سأشرح هذه المصطلحات بالتفصيل ونحن نمضي قدمًا.
هيا بنا نبدأ!
المتطلبات الأساسية
هذا برنامج تعليمي للمبتدئين ، لذا سأتحدث غالبًا عن GitHub Actions CI على مستوى السطح. يجب أن يكون القراء على دراية بالفعل بإنشاء واجهة برمجة تطبيقات Node JS REST باستخدام قاعدة بيانات PostgreSQL و Sequelize ORM وكتابة الاختبارات باستخدام Mocha و Chai.
يجب أيضًا تثبيت ما يلي على جهازك:
- NodeJS ،
- PostgreSQL ،
- NPM ،
- VSCode (أو أي محرر ومحطة من اختيارك).
سأستفيد من واجهة برمجة تطبيقات REST التي قمت بإنشائها بالفعل تسمى countries-info-api
. إنها واجهة برمجة تطبيقات بسيطة بدون تراخيص تستند إلى الأدوار (كما في وقت كتابة هذا البرنامج التعليمي). هذا يعني أنه يمكن لأي شخص إضافة و / أو حذف و / أو تحديث تفاصيل الدولة. سيكون لكل بلد معرف (UUID تم إنشاؤه تلقائيًا) واسمًا ورأس مالًا وعدد سكان. لتحقيق ذلك ، استخدمت Node js و express js framework و Postgresql لقاعدة البيانات.
سأشرح بإيجاز كيف أقوم بإعداد الخادم وقاعدة البيانات قبل أن أبدأ بكتابة الاختبارات الخاصة بتغطية الاختبار وملف سير العمل من أجل التكامل المستمر.
يمكنك استنساخ country countries-info-api
repo لمتابعة أو إنشاء واجهة برمجة التطبيقات الخاصة بك.
التكنولوجيا المستخدمة : Node Js ، NPM (مدير حزم لجافا سكريبت) ، قاعدة بيانات Postgresql ، تكملة ORM ، Babel.
إعداد الخادم
قبل إعداد الخادم ، قمت بتثبيت بعض التبعيات من npm.
npm install express dotenv cors npm install --save-dev @babel/core @babel/cli @babel/preset-env nodemon
أنا أستخدم إطار العمل السريع والكتابة بتنسيق ES6 ، لذلك سأحتاج إلى Babeljs لتجميع الكود الخاص بي. يمكنك قراءة الوثائق الرسمية لمعرفة المزيد حول كيفية عملها وكيفية تكوينها لمشروعك. سيكتشف Nodemon أي تغييرات تم إجراؤها على الرمز ويعيد تشغيل الخادم تلقائيًا.
ملاحظة : حزم Npm المثبتة باستخدام علامة --save-dev
مطلوبة فقط أثناء مراحل التطوير ويمكن رؤيتها ضمن devDependencies في ملف package.json
.
أضفت ما يلي إلى ملف index.js
الخاص بي:
import express from "express"; import bodyParser from "body-parser"; import cors from "cors"; import "dotenv/config"; const app = express(); const port = process.env.PORT; app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true })); app.use(cors()); app.get("/", (req, res) => { res.send({message: "Welcome to the homepage!"}) }) app.listen(port, () => { console.log(`Server is running on ${port}...`) })
يؤدي هذا إلى إعداد واجهة برمجة التطبيقات الخاصة بنا للتشغيل على كل ما تم تعيينه لمتغير PORT
في ملف .env
. هذا أيضًا هو المكان الذي سنعلن فيه عن المتغيرات التي لا نريد أن يتمكن الآخرون من الوصول إليها بسهولة. تقوم الحزمة dotenv
npm بتحميل متغيرات بيئتنا من .env
.
الآن عندما أقوم بتشغيل npm run start
في المحطة الطرفية ، أحصل على هذا:
كما ترى ، خادمنا يعمل. ياي!
يجب أن يعرض هذا الارتباط https://127.0.0.1:your_port_number/
في متصفح الويب الخاص بك رسالة الترحيب. أي ما دام الخادم قيد التشغيل.
التالي ، قاعدة البيانات والنماذج.
لقد أنشأت نموذج البلد باستخدام Sequelize وقمت بالاتصال بقاعدة بيانات Postgres الخاصة بي. Sequelize هو ORM لـ Nodejs. الميزة الرئيسية هي أنها توفر علينا وقت كتابة استعلامات SQL الأولية.
نظرًا لأننا نستخدم Postgresql ، يمكن إنشاء قاعدة البيانات عبر سطر أوامر psql باستخدام الأمر CREATE DATABASE database_name
. يمكن القيام بذلك أيضًا على جهازك الطرفي ، لكني أفضل PSQL Shell.
في ملف env ، سنقوم بإعداد سلسلة الاتصال لقاعدة البيانات الخاصة بنا ، باتباع هذا التنسيق أدناه.
TEST_DATABASE_URL = postgres://<db_username>:<db_password>@127.0.0.1:5432/<database_name>
بالنسبة لنموذجي ، اتبعت هذا البرنامج التعليمي التكميلي. من السهل متابعة وشرح كل شيء عن إعداد Sequelize.
بعد ذلك ، سأكتب اختبارات للنموذج الذي أنشأته للتو وأعد التغطية على Coverall.
اختبارات الكتابة والتقارير التغطية
لماذا تكتب الاختبارات؟ أنا شخصياً أعتقد أن كتابة الاختبارات تساعدك كمطور على فهم أفضل للكيفية التي يُتوقع أن يعمل بها برنامجك في يد المستخدم لأنها عملية عصف ذهني. كما أنه يساعدك على اكتشاف الأخطاء في الوقت المحدد.
الاختبارات:
هناك طرق مختلفة لاختبار البرامج ، ومع ذلك ، بالنسبة لهذا البرنامج التعليمي ، استفدت من اختبار الوحدة والاختبار الشامل.
لقد كتبت اختباراتي باستخدام إطار عمل اختبار Mocha ومكتبة Chai Assertion. لقد قمت أيضًا بتثبيت sequelize-test-helpers
للمساعدة في اختبار النموذج الذي قمت بإنشائه باستخدام sequelize.define
.
تغطية الاختبار:
يُنصح بالتحقق من تغطية الاختبار الخاصة بك لأن النتيجة توضح ما إذا كانت حالات الاختبار لدينا تغطي بالفعل الرمز وأيضًا مقدار الكود المستخدم عند تشغيل حالات الاختبار الخاصة بنا.
لقد استخدمت Istanbul (أداة تغطية اختبارية) و nyc (عميل Instabul's CLI) و Coveralls.
وفقًا للمستندات ، تقوم إسطنبول بتجهيز كود ES5 و ES2015 + JavaScript مع عدادات الأسطر ، بحيث يمكنك تتبع مدى نجاح اختبارات الوحدة في ممارسة قاعدة التعليمات البرمجية الخاصة بك.
في ملف package.json
الخاص بي ، يقوم البرنامج النصي التجريبي بإجراء الاختبارات وإنشاء تقرير.
{ "scripts": { "test": "nyc --reporter=lcov --reporter=text mocha -r @babel/register ./src/test/index.js" } }
في هذه العملية ، سيتم إنشاء مجلد .nyc_output
يحتوي على معلومات التغطية الأولية ومجلد coverage
يحتوي على ملفات تقرير التغطية. كلا الملفين غير ضروريين في الريبو الخاص بي لذا قمت بوضعهما في ملف .gitignore
.
الآن وقد أنشأنا تقريرًا ، يتعين علينا إرساله إلى المعاطف. أحد الأشياء الرائعة حول المعاطف (وغيرها من أدوات التغطية ، أفترض) هو كيفية الإبلاغ عن تغطية اختبارك. يتم تقسيم التغطية على أساس ملف على حدة ويمكنك رؤية التغطية ذات الصلة ، والسطور المغطاة والمفقودة ، وما تغير في تغطية الإصدار.
للبدء ، قم بتثبيت حزمة المعاطف npm. تحتاج أيضًا إلى تسجيل الدخول إلى المعاطف وإضافة الريبو إليها.
ثم قم بإعداد المعاطف لمشروع جافا سكريبت الخاص بك عن طريق إنشاء ملف coveralls.yml
في الدليل الجذر الخاص بك. سيحتوي هذا الملف repo-token
الخاص بك الذي تم الحصول عليه من قسم الإعدادات في الريبو الخاص بك على المعاطف.
سكربت آخر مطلوب في ملف package.json هو سكربتات التغطية. سيكون هذا البرنامج النصي مفيدًا عندما نقوم بإنشاء بناء عبر الإجراءات.
{ "scripts": { "coverage": "nyc npm run test && nyc report --reporter=text-lcov --reporter=lcov | node ./node_modules/coveralls/bin/coveralls.js --verbose" } }
في الأساس ، سيتم إجراء الاختبارات والحصول على التقرير وإرساله إلى المعاطف لتحليلها.
الآن إلى النقطة الرئيسية في هذا البرنامج التعليمي.
قم بإنشاء ملف Node JS Workflow
في هذه المرحلة ، أنشأنا الوظائف الضرورية التي سنديرها في GitHub Action. (هل تتساءل ماذا تعني "الوظائف"؟ استمر في القراءة.)
سهّل GitHub إنشاء ملف سير العمل من خلال توفير قالب بداية. كما هو موضح في صفحة الإجراءات ، هناك العديد من قوالب سير العمل التي تخدم أغراضًا مختلفة. في هذا البرنامج التعليمي ، سنستخدم سير عمل Node.js (الذي اقترحه GitHub بالفعل).
يمكنك تحرير الملف مباشرة على GitHub لكنني سأقوم يدويًا بإنشاء الملف على الريبو المحلي الخاص بي. سيكون المجلد .github/workflows
الذي يحتوي على ملف node.js.yml
في الدليل الجذر.
يحتوي هذا الملف بالفعل على بعض الأوامر الأساسية ويشرح التعليق الأول ما يفعلونه.
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
سأقوم ببعض التغييرات عليه حتى أنه بالإضافة إلى التعليق أعلاه ، فإنه يعمل أيضًا على التغطية.
ملف .node.js.yml
الخاص بي:
name: NodeJS CI on: ["push"] jobs: build: name: Build runs-on: windows-latest strategy: matrix: node-version: [12.x, 14.x] steps: - uses: actions/checkout@v2 - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v1 with: node-version: ${{ matrix.node-version }} - run: npm install - run: npm run build --if-present - run: npm run coverage - name: Coveralls uses: coverallsapp/github-action@master env: COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} COVERALLS_GIT_BRANCH: ${{ github.ref }} with: github-token: ${{ secrets.GITHUB_TOKEN }}
ماذا يعني هذا؟
دعونا نكسرها.
-
name
سيكون هذا هو اسم سير العمل (NodeJS CI) أو الوظيفة (البناء) وسيعرضه GitHub في صفحة إجراءات المستودع الخاص بك. -
on
هذا هو الحدث الذي يبدأ سير العمل. هذا السطر في ملفي يخبر GitHub بشكل أساسي بتشغيل سير العمل كلما تم الدفع إلى الريبو الخاص بي. -
jobs
يمكن أن يحتوي سير العمل على وظيفة واحدة على الأقل أو أكثر ويتم تشغيل كل وظيفة في بيئة محددة بواسطةruns-on
. في نموذج الملف أعلاه ، هناك وظيفة واحدة فقط تقوم بتشغيل البنية وتشغيل التغطية أيضًا ، ويتم تشغيلها في بيئة windows. يمكنني أيضًا تقسيمها إلى وظيفتين مختلفتين مثل هذا:
ملف Node.yml المحدث
name: NodeJS CI on: [push] jobs: build: name: Build runs-on: windows-latest strategy: matrix: node-version: [12.x, 14.x] steps: - uses: actions/checkout@v2 - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v1 with: node-version: ${{ matrix.node-version }} - run: npm install - run: npm run build --if-present - run: npm run test coverage: name: Coveralls runs-on: windows-latest strategy: matrix: node-version: [12.x, 14.x] steps: - uses: coverallsapp/github-action@master env: COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} with: github-token: ${{ secrets.GITHUB_TOKEN }}
-
env
يحتوي هذا على متغيرات البيئة المتوفرة لجميع الوظائف والخطوات المحددة في سير العمل أو. في وظيفة التغطية ، يمكنك أن ترى أن متغيرات البيئة "مخفية". يمكن العثور عليها في صفحة أسرار الريبو الخاص بك ضمن الإعدادات. -
steps
هذه في الأساس قائمة بالخطوات التي يجب اتخاذها عند تشغيل هذه الوظيفة. - تقوم وظيفة
build
بعدد من الأشياء:- يستخدم إجراء السحب (v2 يشير إلى الإصدار) الذي يقوم حرفياً بفحص المستودع الخاص بك بحيث يمكن الوصول إليه من خلال سير العمل الخاص بك ؛
- يستخدم إجراء إعداد - عقدة يقوم بإعداد بيئة العقدة المراد استخدامها ؛
- يقوم بتشغيل البرامج النصية للتثبيت والبناء والاختبار الموجودة في ملف package.json الخاص بنا.
-
coverage
يستخدم هذا الإجراء المطاطي الذي ينشر بيانات تغطية LCOV لمجموعة الاختبار الخاصة بك إلى المآزر الخاصة بالتحليل.
لقد قمت في البداية بدفع إلى فرع feat-add-controllers-and-route
والمسار الخاصة بي ونسيت إضافة repo_token من Coveralls إلى ملف .coveralls.yml
بي ، لذلك حصلت على الخطأ الذي يمكنك رؤيته في السطر 132.
Bad response: 422 {"message":"Couldn't find a repository matching this job.","error":true}
بمجرد إضافة repo_token
، كان بنائي قادرًا على العمل بنجاح. بدون هذا الرمز المميز ، لن تتمكن المعاطف من الإبلاغ بشكل صحيح عن تحليل تغطية الاختبار الخاص بي. من الجيد أن GitHub Actions CI أشارت إلى الخطأ قبل دفعه إلى الفرع الرئيسي.
ملحوظة: تم أخذ هذه قبل أن أقوم بتقسيم الوظيفة إلى وظيفتين. أيضًا ، تمكنت من رؤية ملخص التغطية - ورسالة الخطأ - على الجهاز الطرفي لأنني أضفت علامة --verbose
في نهاية البرنامج النصي للتغطية
خاتمة
يمكننا معرفة كيفية إعداد التكامل المستمر لمشاريعنا وكذلك دمج تغطية الاختبار باستخدام الإجراءات التي توفرها GitHub. هناك العديد من الطرق الأخرى التي يمكن تعديلها لتناسب احتياجات مشروعك. على الرغم من أن نموذج الريبو المستخدم في هذا البرنامج التعليمي هو مشروع صغير حقًا ، يمكنك أن ترى مدى أهمية التكامل المستمر حتى في مشروع أكبر. الآن وبعد أن تم تشغيل وظيفتي بنجاح ، أنا واثق من دمج الفرع مع فرعي الرئيسي. ما زلت أنصحك بقراءة نتائج الخطوات بعد كل شوط لترى أنها ناجحة تمامًا.