يحصل مستخدمو GitHub على 2000 دقيقة شهريًا لتشغيل إجراءات GitHub على البنية التحتية للخدمة. دعونا نستفيد من وقت الفراغ هذا.
أعطي تعليمات لمطوري تطبيقات Flutter: كيفية إجراء الاختبارات ومحلل التعليمات البرمجية لكل طلب سحب باستخدام إجراءات GitHub ، وإنشاء أداة ونشرها للاختبار في Firebase.
يعتاد الشخص بسرعة على الأشياء الجيدة. وقد اعتاد على ذلك كثيرًا لدرجة أنه لا يفكر حتى في حقيقة أنه لم يكن دائمًا على هذا النحو. كما تقول الحكاية القديمة عن رجل وماعز ، فإن تحقيق كل مباهج الحياة يحدث في نفس اللحظة التي تُحرم فيها من هذه المسرات.
إذا كان مشروع عملك يعمل بشكل جيد مع CI / CD ، فأنت شخص محظوظ.
ربما كنت تعمل في شركة ناشئة وقمت بتهيئة جميع خطوط الأنابيب والخطافات بيديك بعناية.
قد يكون فريق DevOps بأكمله يعتني برفاهيتك: كل شهر يجعلك سعيدًا بالتكامل الجديد ، ووقت البناء الذي يذوب أمام أعيننا والتقنيات المتقدمة لنشر التجميعات في جميع الأماكن التي يمكن تخيلها والتي لا يمكن تصورها.
هذا لا يهم. الشيء الرئيسي هو أنك متأكد دائمًا من أن بنياتك قابلة للتطبيق ، وفي نفس الوقت تشعر أنت بالراحة من الكثير من المهام الروتينية المملة للغاية ، والتي يؤدي التفكير فيها دائمًا إلى إغراق المطورين في الكآبة واليأس. بالمناسبة ، سأكون سعيدًا إذا كتبت في التعليقات متى كانت آخر مرة قمت فيها يدويًا بتغيير حالة مشكلة في Jira؟
ترك منطقة الراحة الخاصة بك
أين يغادرون منطقة الراحة ، والأهم من ذلك ، لماذا؟ الكثير من الأسباب. طلب مني أحد الأصدقاء المساعدة في كتابة تطبيق صغير لشريطك الخاص ، لقد وجدت أخيرًا وقتًا لتنفيذ مشروع حيوان أليف أحلامك ، أو قررت إطلاق مكتبة ولدت عن طريق الخطأ كجزء من مشروع. أخيرًا ، قررت أنت وزميلك للتو كتابة مشروع نموذج صغير لورشة العمل.
أراهن أنه في أي من السيناريوهات ، فإن إلهامك من المهام الجديدة المثيرة للاهتمام سيتعارض بسرعة مع الواقع القاسي لتطوير البرامج في "بيئة خالية من الهواء" (نعم ، في مرحلة ما ، ستحتاج إلى جامع ذكي مثل الهواء).
"CI / CD صعب ..."
ماذا تقول لنفسك عادة في مثل هذه اللحظات؟ "أنا لا أفهم هذا! أنا أكتب فقط واجهة أمامية / هاتف محمول ولا أعرف أي شيء عن جينكينز! " ماذا لو أخبرتك أنك لست بحاجة إلى معرفة أي شيء من هذا القبيل؟
نعم ، نعم ، ما عليك سوى أن تكون قادرًا على بناء مشروعك باستخدام أوامر وحدة التحكم - وهذا كل شيء. يمكنك تبسيط حياتك بشكل كبير ، حتى لو كان مشروعًا شخصيًا صغيرًا ، وليس وحشًا عملاقًا متعدد الوحدات يصعب بالفعل هضمه IDE.
إجراءات Github بسيطة للغاية لدرجة أن جدتك ستضعها دون صعوبة كبيرة.
ثم ما هو موضوع المنشور؟
إذا كان كل شيء بهذه البساطة ، فلماذا نضيع الوقت في قراءة هذا التأليف؟ سأجيب بقائمة نقطية:
- Flutter. CI . , Flutter- . ,
- . Github Actions — . 2 000 ( ). - , .
- . Flutter Android iOS , - . , , , .
c CI/CD , . . ($).
Github Actions, !
Github Actions هي خدمة تتيح لك أتمتة سير عمل المستودع الخاص بك. أي شيء تفعله يدويًا مع مشروعك - بخلاف كتابة التعليمات البرمجية مباشرةً - يمكنك التفويض إلى إجراءات Github. إذا كنت تفضل التعرف على المصادر الأولية على الفور ، فانتقل إلى الوثائق الرسمية .
في كثير من الأحيان لا نعرف حتى ما نحتاجه للأتمتة على الإطلاق. ليس لدى الفريق الوقت الكافي لفهم واجهة برمجة التطبيقات المعقدة للخدمة ثم كتابة الحل وتصحيحه من البداية. يحل Marketplace هذه المشكلة : يتم نشر ما يقرب من 5 آلاف إجراء جاهز هناك لحل الكثير من المهام النموذجية (على سبيل المثال ، إرسال إشعارات حول الأحداث في Telegram ، وتحليل مصادر المشروع للديون الفنية ،وضع الملصقات على العلاقات العامة اعتمادًا على الملفات التي تم تغييرها فيه ). أخبار سيئة: العديد منها عبارة عن برامج تجريبية - مع حدود استخدام صارمة جدًا.
عملية العمل
يدور كل شيء في إجراءات Github حول مهام سير العمل . يجيب كل سير عمل على سؤالين: ما يجب القيام به ومتى يتم القيام به.
ما العمل . هناك خيارات لا حصر لها هنا: يمكنك بناء واختبار ونشر البنيات الخاصة بك باستخدام البرامج النصية الجاهزة أو المنشأة بنفسك. تعرف على المزيد حول تكوين سير العمل
وقت القيام بذلك . يمكنك تشغيل مهام سير العمل على الأحداث التي تحدث في المستودع. إنشاء طلب سحب أو دفع علامة التزام أو حتى إضافة نجمة جديدة إلى مشروعك. قائمة كاملة من الخطافات
إذا كان يجب تنفيذ سير العمل ليس في حدث ، ولكن في وقت معين أو بتردد معين ، فلديك تحت تصرفك بنية POSIX cron .اقرأ المزيد حول الأحداث المنتظمة
يمكن أن يحتوي المستودع على العديد من مهام سير العمل المختلفة التي تريدها في نفس الوقت. يتم وصف كل سير عمل في ملف YAML منفصل ، يجب تخزين كل منها في دليل .github / workflows في جذر المستودع الخاص بك. تعرف على المزيد حول بناء جملة مهام سير العمل
بيئة التشغيل
تقدم Github Actions خيارين لتنفيذ مهام سير العمل:
- Github-hosted runners — , . Windows, Linux macOS. , Codemagic, ( ). , , ;
- Self-hosted runners — , . Github , .
في مقالتي ، سأركز على الخيار الأول. نحن نسير في أبسط طريق ممكن ، أليس كذلك؟
إعداد سير العمل الأساسي لـ Flutter
قبل أن نبدأ في تكوين سير العمل ، نحتاج إلى الاتفاق على شيئين.
أولاً ، سيكون الدور الرئيسي لسير العمل هو تعقيد انهيار قاعدة الكود. يجب ألا تدخل التعليمات البرمجية التي لا تُنشئ أو تحتوي على مشكلات محتملة أو الاختبارات الفاصلة في الاتجاه السائد.
ثانيًا: قد تكون هناك بعض التفاصيل الدقيقة في تكويني لن تكون ذات صلة بمشروعك. سأحاول أن أشرح لهم. ومع ذلك ، إذا كنت تستخدم هذه المقالة كدليل ، فاستعيرها بعناية.
أخيرًا ، دعنا نقرر ما يجب أن يفعله سير العمل لدينا على الإطلاق. نحن بحاجة إلى خطة لمساعدتنا على التحرك في الاتجاه الصحيح.
خطوة بخطوة إلى التجميع النهائي
يمكن استخدام الخطة أعلاه كقائمة مراجعة عند إعداد سير العمل الخاص بك. علينا أن:
- إعطاء اسم ذي معنى لسير العمل ؛
- الإشارة إلى الحدث الذي سيبدأ سير العمل لدينا ؛
- تحديد الجهاز الذي سيبدأ به التكوين ؛
- قرر الخطوات التي سيتألف منها سير العمل لدينا:
- تحقق من المشروع ،
- تثبيت جافا
- تثبيت Flutter (كما تتذكر ، في كل مرة لدينا مثيل نظيف تحت تصرفنا) ،
- تنزيل حزم المشروع ،
- بدء محلل ثابت ،
- اختبارات التشغيل ،
- تجميع البناء نفسه ،
- نشر التصميم في مكان ما حيث يمكن للمختبرين الحصول عليه.
الآن اتخذ عملنا شكلا ملموسا. دعنا ننتقل إلى التنفيذ.
كيف سيبدو سير العمل لدينا في النهاية
— . , , .
name: Flutter PR
on:
pull_request:
branches:
- "dev/sprint-**"
paths-ignore:
- "docs/**"
- "openapi/**"
- ".vscode/**"
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/setup-java@v1
with:
java-version: "12.x"
- uses: subosito/flutter-action@v1
with:
channel: "stable"
- run: sh ./scripts/flutter_pub_get.sh
- run: sh ./scripts/flutter_analyze.sh
- run: flutter test
- run: flutter build apk --release
- uses: actions/upload-artifact@v1
with:
name: APK for QA
path: build/app/outputs/apk/dev/debug/apk_name.apk
- name: Upload artifact to Firebase App Distribution
uses: wzieba/Firebase-Distribution-Github-Action@v1
with:
appId: ${{ secrets.FIREBASE_ANDROID_PROD_APP_ID }}
token: ${{ secrets.FIREBASE_TOKEN }}
groups: testers
file: build/app/outputs/apk/dev/debug/apk_name.apk
debug: true
اسم
من الواضح أننا بحاجة إلى تسمية سير العمل لدينا بحيث يعكس الاسم جوهره بأكبر قدر ممكن من الدقة. الاسم ( المستندات ) هو أول شيء نراه في وحدة تحكم الإجراءات عند تنفيذ سير العمل. لماذا سميت سير العمل الخاص بي بهذه الطريقة ، سوف تكتشف ذلك بعد قليل.
name: Flutter PR
بدء الحدث
تسمح لنا كتلة "on" ( المستندات ) بتحديد حدث واحد أو أكثر ، وعند التسجيل نريد بدء سير العمل لدينا. علاوة على ذلك ، يمكن ضبط بعض الأحداث.
أي حدث تختار؟ حتى لا تفوت أي تفاصيل ، يمكنك تحديد جميع الأحداث الموجودة على الأقل. ثم سوف يستمر التجمع بشكل شبه مستمر ، ولكن هل نريد ذلك؟ لا ، ففي هذه الحالة سينتهي الحد الأقصى لخطتنا للرسوم المجانية بسرعة مذهلة. سنبحث عن الحل الأمثل.
لنفترض أن مشروعنا يلتزم بالاتفاقيات التي بموجبها لا يمكن دفع الكود إلى الفرع الرئيسي للمشروع مباشرة - فقط من خلال إنشاء طلب سحب. من المنطقي إذا كان سير العمل لدينا سيستجيب لإنشاء طلب سحب وبناء مشروع من قاعدة كود معدلة:
on: pull_request
$ هذا كافٍ للعمل ، لكن الحل ليس هو الأمثل بعد. سيتم تشغيل البناء عند كل طلب سحب يتم إنشاؤه. هذا زائدة عن الحاجة ، لأننا مهتمون فقط بطلبات السحب الموجهة إلى الفرع الرئيسي للمشروع. تسمح لنا صيغة Github Actions بتحديد أسماء (أو أقنعة) الفروع التي نهتم بها.
on:
pull_request:
branches:
- "dev/sprint-**"
$ ومرة أخرى نحن نبحث عن طرق لتحسين العملية. هناك ملفات ، حتى من الناحية النظرية ، لا يمكن أن تضر بمشروعك: وثائق المشروع ، Swagger ، نمط الكود العام وإعدادات IDE. لحسن الحظ ، لدينا القدرة على تجاهل مثل هذه الملفات بواسطة قناع المسار. نتيجة لذلك ، ستبدو كتلة "تشغيل" على النحو التالي:
on:
pull_request:
branches:
- "dev/sprint-**"
paths-ignore:
- "docs/**"
- "drz-swagger/**"
- ".vscode/**"
هام : قدم طلب سحب فقط إذا كنت مستعدًا لدمجه. ستؤدي كل دفعة تالية إلى طلب سحب تم إنشاؤه بالفعل إلى إعادة تشغيل سير العمل.
تكوين الوظيفة
أخيرًا ، نحن جاهزون لتهيئة الوظيفة ( المستندات ). حان الوقت الآن لتوضيح الدور الذي تلعبه الوظيفة في سير العمل.
يجب أن يتضمن كل سير عمل وظيفة واحدة على الأقل. إنها الوظيفة التي تحتوي على وصف خطوة بخطوة للخطوات التي نقوم بها مع مشروعنا. عدد الوظائف في سير عمل واحد غير محدود ، وكذلك عدد الخطوات في وظيفة واحدة. بشكل افتراضي ، يتم تنفيذ جميع الوظائف بالتوازي ، ما لم يتم تحديد اعتماد وظيفة واحدة على نتائج وظيفة أخرى. سيكون لمشروعنا الوظيفة الوحيدة التي ستكون مسؤولة عن بناء المشروع.
تهيئة البيئة
في كل مرة يتم تشغيل سير العمل على مثيل جهاز ظاهري نظيف. الشيء الوحيد الذي يمكننا اختياره هو نظام التشغيل الذي سيتم تثبيته على هذا الجهاز. ماذا تختار؟
من المغري اختيار macOS ، لأننا نخطط لإنشاء تطبيق Flutter للأنظمة الأساسية المستهدفة: Android و iOS. اخبار سيئة. دقيقة واحدة من استخدام مثيل مع macOS تتم محاسبتها على أنها عشر دقائق (10 !!!) من استخدام مثيل مع Ubuntu. في حالة مع Windows ، في حالتنا ، لا فائدة على الإطلاق ، نظرًا لأن تجميع iOS لن يعمل هناك ، ووقت استخدامه هو ضعف تكلفة مثيل مع Ubuntu. المزيد حول فوترة
$كيف يمكننا التأكد من أن 2000 دقيقة مجانية لدينا لا تتحول إلى 200؟ لا يوجد حل جيد. قررت عدم إنشاء البنية على iOS عند إنشاء طلب سحب. من المحتمل أن يؤثر هذا على استقرار بنية iOS. هناك أيضًا خيار تسوية - لإنشاء نظام iOS على نظام macOS فقط عند تغيير pubspec.yaml أو أي ملف من دليل / ios ، وفي حالات أخرى ، قم فقط ببناء Android على مثيل مع Ubuntu. يمكن القيام بذلك عن طريق القياس مع كيفية إعدادنا لملفات التجاهل للكتلة "on" .
jobs:
build:
runs-on: ubuntu-latest
يمكنك الاطلاع على المواصفات الفنية ، بالإضافة إلى قائمة البرامج المثبتة "الجاهزة" . للأسف ، لم يتم تضمين Flutter و Java في هذه القائمة. يجب أن يتم تثبيتها يدويًا في كل مرة يتم فيها تنفيذ سير العمل.
لا تكن في عجلة من أمرها لتغضب. ستساعدنا الإجراءات الجاهزة ، والتي يمكننا استخدامها في خطوات عملنا. سوف نستخدم اثنين:
- Actions / setup-java - الإجراء الرسمي لإعداد بيئة Java ؛
- subosito / flutter-action هو إجراء غير رسمي لتنزيل وتثبيت Flutter SDK. لقد أثبتت نفسها جيدًا: فهي تتيح لك القيام بكل ما قد تحتاجه - على سبيل المثال ، تحديد قناة إطار العمل المطلوبة أو التبديل إلى إصدار SDK معين.
steps:
- uses: actions/setup-java@v1
with:
java-version: "12.x"
- uses: subosito/flutter-action@v1
with:
channel: "stable"
استنساخ المستودع
لدينا مثيل نظيف لآلة مستأجرة من Github لبضع دقائق. في الخطوة السابقة ، قمنا بتثبيت جميع البرامج اللازمة عليها. نحن الآن بحاجة إلى استنساخ مستودع المصدر لمشروعنا. للقيام بذلك ، سوف نستخدم أداة جاهزة:
- الإجراءات / الخروج هو الإجراء الرسمي لاستنساخ مستودع يحتوي على الكثير من الإعدادات التي لن نحتاجها في معظم الحالات. نظرًا لأن سير العمل يعمل مباشرة على المستودع الذي نقوم باستنساخه ، لا نحتاج إلى تحديده بشكل صريح.
- uses: actions/checkout@v1
تحميل التبعيات
حتى هذه اللحظة ، لم ننفذ خطوات بأيدينا ، لكننا استخدمنا فقط ما أقدمه من إجراءات جاهزة. نحن الآن ننتقل إلى تنفيذ المرحلة النشطة لبناء مشروعنا ، لذلك حان الوقت لكتابة تنفيذ الخطوة بنفسك.
قبل البناء ، نحتاج إلى تنزيل جميع الحزم المحددة في كتلة التبعيات في ملف pubspec.yaml الخاص بنا ، بالإضافة إلى جميع تبعياتها متعدية. للقيام بذلك ، تقدم Flutter SDK أمرًا بسيطًا خارج الصندوق
flutter pub get. يمكن أن يتكون تنفيذ الخطوة من استدعاء أمر طرفي واحد. في هذه الحالة ، لن يتم استدعاء الخطوة التالية إلا عند الانتهاء من هذا الأمر.
- run: flutter pub get
إذا كان مشروعك يحتوي على هيكل معقد ويحتوي على عدد من حزم dart المتصلة محليًا ، فستواجه مشكلة. من
flutter pub getالمستحيل بناء مشروع بدون دعوة صريحة لكل من هذه الحزم. في مشروعي ، يتم جمع هذه الحزم في المجلد / core الموجود في الدليل الجذر. يوجد أدناه برنامج نصي يحل هذه المشكلة. يتم وصفه في ملف flutter_pub_get.sh في مجلد / scripts في نفس الدليل الجذر.
flutter pub get
cd core
for dir in */ ; do
echo ${dir}
cd ${dir}
pwd
flutter pub get
cd ..
pwd
if [ "$#" -gt 0 ]; then shift; fi
# shift
done
نظرًا لأن تنفيذ الخطوة يمكن أن يكون أي أمر طرفي ، فلا شيء يمنعنا من تنفيذ برنامج شل النصي.
- run: sh ./scripts/flutter_pub_get.sh
تحليل الكود الثابت
يدعونا Flutter لاستخدام أمر مضمن
flutter analyzeلتشغيل محلل ثابت. سيساعد هذا في تحديد المشكلات المحتملة في قاعدة الشفرة الخاصة بنا في مرحلة مبكرة: قبل أن يصل الخطأ إلى الإنتاج ، أو يتحول الكود إلى فوضى غير قابلة للقراءة وغير مدعومة.
كان بإمكاننا الاستفادة من الميزة الجاهزة ، ولكن للأسف ، فإن سلوك الفريق الافتراضي
flutter analyzeبه عيب يفسد سير العمل لدينا في الوقت الخطأ.
يتم تصنيف المشكلات التي تم العثور عليها بواسطة المحلل إلى ثلاثة مستويات من الخطورة: المعلومات والتحذير والخطأ. في هذا العدديوصف أنه حتى لو تم العثور على مشكلات فئة المعلومات فقط أثناء التحليل (ولا يستحق دائمًا قضاء الوقت في إصلاحها هنا والآن) ، يقوم الأمر بإرجاع الكود "1" ، ونتيجة لذلك سيتعطل التجميع الخاص بك.
أقترح استخدام البرنامج النصي التالي كحل مؤقت. من الآن فصاعدًا ، سيتعطل التجميع فقط إذا كانت هناك مشاكل في مستوى الخطأ :
OUTPUT="$(flutter analyze)"
echo "$OUTPUT"
echo
if grep -q "error •" echo "$OUTPUT"; then
echo "flutter analyze found errors"
exit 1
else
echo "flutter analyze didn't find any errors"
exit 0
fi
نقوم بتنفيذ البرنامج النصي shell في الخطوة التالية من سير العمل لدينا:
- run: sh ./scripts/flutter_analyze.sh
اختبارات التشغيل
إذا كانت لديك اختبارات في مشروعك ، فأنت على الطريق الصحيح! لكي تنجح الاختبارات ، لا يكفي كتابتها - يجب تشغيلها بانتظام لتصحيح عيوب التنفيذ في الوقت المناسب أو تحديثها إذا لزم الأمر. لذلك ، في الخطوة التالية ، سننفذ
- run: flutter test
كن حذرًا: فصول الاختبار الفارغة التي لا تحتوي على أي اختبارات تم تنفيذها ستؤدي إلى تعطيل سير العمل بالكامل. هناك مخرج واحد فقط: لا تعلن عن فئات الاختبار حتى تكون مستعدًا لتنفيذ اختبار واحد على الأقل داخلها.
بناء وتوقيع
كل الأعمال التحضيرية قد انتهت. لقد تحققنا من أن الشفرة على الأرجح لا تحتوي على مشاكل واضحة. ننتقل الآن إلى أهم مرحلة - إنتاج القطعة الأثرية. بمعنى آخر ، سنبني ملف APK.
التجميع نفسه سهل التنفيذ للغاية. لدينا تحت تصرفنا بناء رفرفة الأوامر الطرفية ، وهو قابل للتكوين بعمق للغاية ويسمح لك ببناء قطعة أثرية لنكهة معينة ، الملف الرئيسي ، ABI. نحن لا نغطي هذه الفروق الدقيقة في المقالة ، لذلك استخدم علامات أوامر إضافية إذا لزم الأمر.
- run: flutter build apk --release
هدفنا هو الحصول على تجميع موقّع بمفتاح تحرير. وفي هذه المرحلة سيتعين علينا حل مشكلة الأمان ، لأننا نحتاج إلى تخزين مخزن مفاتيح الإصدار في مكان ما ، بالإضافة إلى جميع الأسماء المستعارة وكلمات المرور الخاصة به.
يتيح لك Github تخزين قيم السلسلة بأمان في مستودع Secrets مخصص . يتم تخزين البيانات المتوفرة هنا في المستودع المقابل ويمكن قراءتها برمجيًا من أي خطوة في سير عملك. في الوقت نفسه ، لا يمكن رؤية القيم من خلال واجهة ويب Github. يسمح فقط بالحذف أو الكتابة فوق.
يبدو هذا كحل جيد للأسماء المستعارة وكلمات المرور ، خاصة إذا كنت تمثل خدمة الأمان الخاصة بك ، ولكن ماذا عن ملف * .jks نفسه؟ لا يبدو دفعه إلى المستودع فكرة جيدة ، حتى لو كان مستودعك خاصًا. لسوء الحظ ، لا يوفر Github أي طريقة آمنة لتخزين الملفات ، لذلك عليك تفاديها.
سيكون من الجيد تمثيل ملف keystore الخاص بنا كسلسلة. وهو حقيقي - ما عليك سوى ترميزه في base64. للقيام بذلك ، افتح Terminal في الدليل الذي يحتوي على ملف * .jks الخاص بنا وقم بتنفيذ الأمر التالي. بعد ذلك ، سيتم إنشاء ملف نصي يمكنك من خلاله نسخ تمثيل base64 لمخزن المفاتيح الخاص بنا ، ثم ... حفظه في Github Secrets.
openssl base64 < key_store_filename.jks | tr -d '\n' | tee keystore.jks.base64.txt
الآن بعد أن أصبح لدينا جميع المكونات الضرورية لتوقيع التجميع الناجح ، سنواصل تكوين الخطوة. في الكتلة env ، نعلن عن جميع متغيرات البيئة لتلك الخطوة المعينة. سنأخذ قيم هذه المتغيرات من الأسرار.
- run: flutter build apk --release
env:
STORE_PASSWORD: ${{ secrets.STORE_PASSWORD }}
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
STORE_FILE: ${{ secrets.STORE_FILE }}
في مضيف Android الخاص بنا ، يتعين علينا وصف تكوين التجميع بطريقة تجعلنا نتمتع بالقدرة على توقيع ملف * .apk في CI دون فقد القدرة على إنشاء التجميع الموقع محليًا. ملف keystoreConfig.gradle هو المسؤول عن هذه اللحظة .
إذا تم العثور على ملف keystore_release.properties ، فمن المعروف أن الإنشاء يحدث محليًا ، مما يعني أنه يمكنك تهيئة جميع خصائص keystoreConfig بمجرد قراءتها من الملف. خلاف ذلك ، يتم التجميع في CI ، مما يعني أن المصدر الوحيد للبيانات الحساسة هو Github Secrets.
ext {
def releaseKeystorePropsFile = rootProject.file("keystore/keystore_release.properties")
if (releaseKeystorePropsFile.exists()) {
println "Start extract release keystore config from keystore_release.properties"
def keystoreProps = new Properties()
keystoreProps.load(new FileInputStream(releaseKeystorePropsFile))
keystoreConfig = [
storePassword: keystoreProps['storePassword'],
keyPassword : keystoreProps['keyPassword'],
keyAlias : keystoreProps['keyAlias'],
storeFile : keystoreProps['storeFile']
]
} else {
println "Start extract release keystore config from global vars"
keystoreConfig = [
storePassword: "$System.env.STORE_PASSWORD",
keyPassword : "$System.env.KEY_PASSWORD",
keyAlias : "$System.env.KEY_ALIAS",
storeFile : "$System.env.STORE_FILE"
]
}
println "Extracted keystore config: $keystoreConfig"
}
وهذه هي الطريقة التي يبدو بها ملف keystore_release.properties :
storePassword={___}
keyPassword={___}
keyAlias={___}
storeFile=../keystore/keystore.jks
الخطوة الأخيرة في ملف build.gradle لمضيف Android الخاص بنا هي تطبيق ملف keystoreConfig على تكوين توقيع بناء الإصدار:
android {
signingConfigs {
release {
apply from: '../keystore/keystoreConfig.gradle'
keyAlias keystoreConfig.keyAlias
keyPassword keystoreConfig.keyPassword
storeFile file(keystoreConfig.storeFile)
storePassword keystoreConfig.storePassword
}
}
}
التجمع الموقع في أيدينا بالفعل! ولكن كيف يمكنك توسيعه ليشمل زملائك للاختبار؟
التفريغ
تتيح لك إجراءات Github تكوين تحميل العناصر الأثرية إلى أي أداة معروفة تقريبًا لتوزيع التجميعات ، لكننا سننظر في خيارين فقط:
- Github Storage - أسهل طريقة لتحميل التجميعات إلى وحدة تخزين Github الخاصة بك ، والتي تعمل خارج الصندوق ، ولكن بها بعض القيود ؛
- Firebase App Distribution هي خدمة من نظام Firebase البيئي حلت محل Beta بـ Crashlytics. يعد الدمج أكثر صعوبة في التهيئة ، لكن الخدمة نفسها أكثر ملاءمة للاستخدام.
Github Storage
يتكامل Github Storage بسهولة من خلال الإجراء الرسمي. ما عليك سوى تحديد اسم التجميع حيث سيراه زملاؤك في واجهة الويب ، بالإضافة إلى المسار إلى ملف * .apk المجمع في CI.
- uses: actions/upload-artifact@v1
with:
name: APK for QA
path: build/app/outputs/apk/dev/debug/apk_name.apk
المشكلة الرئيسية هي مساحة التخزين المحدودة. في الباقة المجانية ، يتم تزويدك بـ 500 ميجابايت فقط. أغرب شيء هو أنني لم أجد أي طريقة لمسح التخزين بالكامل يدويًا مرة واحدة عبر واجهة الويب ، لذلك خرجت من الموقف من خلال ... كتابة سير عمل منفصل مسؤول فقط عن مسح التخزين من القطع الأثرية المطحونة.
يتم تشغيل سير العمل يوميًا في الساعة 1 صباحًا ويزيل جميع القطع الأثرية التي مضى عليها أكثر من أسبوع:
name: Github Storage clear
on:
schedule:
- cron: '0 1 * * *'
jobs:
remove-old-artifacts:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Remove old artifacts
uses: c-hive/gha-remove-artifacts@v1
with:
age: '1 week'
توزيع تطبيقات Firebase
بالنسبة لتوزيع تطبيقات Firebase ، استخدمت الإجراء الجاهز wzieba / Firebase-Distribution-Github-Action للتكامل معه .
- name: Upload artifact to Firebase App Distribution
uses: wzieba/Firebase-Distribution-Github-Action@v1
with:
appId: ${{ secrets.FIREBASE_ANDROID_PROD_APP_ID }}
token: ${{ secrets.FIREBASE_TOKEN }}
groups: testers
file: build/app/outputs/apk/dev/debug/apk_name.apk
debug: true
لكي يعمل الإجراء بشكل صحيح ، يجب تمرير المعلمات:
- معرف التطبيق - معرف التطبيق ، والذي يمكن العثور عليه في إعدادات مشروع Firebase ؛
- الرمز المميز - رمز للمصادقة على مشروع FIrebase الخاص بك ، وهو مطلوب لتحميل التجميع في الخدمة. يمكنك الحصول على رمز فقط من خلال Firebase CLI ، حيث يمكنك قراءة المزيد في الوثائق الرسمية ؛
- ملف - المسار إلى ملف * .apk المترجم على CI ؛
- المجموعات - هذه المعلمة اختيارية ، ولكنها تسمح لك بتحديد الاسم المستعار لمجموعة المختبرين التي ستتم مشاركة التجميع المحمّل عليها تلقائيًا.
الانطلاق والمراقبة
أبسط سير عمل لدينا جاهز! كل ما تبقى لنا فعله هو إطلاق الحدث المشغل ومشاهدة تقدم سير العمل.
نصائح وفراق كلام
يمكنك الآن الاستمتاع بجميع مزايا آلية CI / CD البسيطة في مشروع Flutter الخاص بك ، بغض النظر عن حجمها ، أو كثافة التطوير ، أو محفظتك.
أخيرًا ، إليك بعض النصائح والملاحظات التي توصلت إليها أثناء العمل على سير العمل هذا:
- workflow . workflow , , . - . , - workflow , .
- step’ shell-. workflow . . .
- Run Duration workflow. workflow , . workflow , step’. . Flutter SDK . — 5-6 .
لا يزال هناك الكثير من التحسينات والتحسينات المحتملة في المستقبل. اكتب في التعليقات أفكارك لتحسين سير العمل. ما الذي تفتقر إليه شخصيًا؟ ربما سيشكل تنفيذ أفكار القراء الأكثر إثارة للاهتمام أساس المقالة التالية حول هذا الموضوع.
يمكن العثور على جميع البرامج النصية وسير العمل في المستودع باستخدام تطبيق الاختبار .
شكرآ لك على أهتمامك.
ملاحظة: يطلق فريق Surf لدينا العديد من المكتبات المفيدة لـ Flutter. نقوم بتحميلها إلى مستودع SurfGear .