CI/CD عمليّ لتطبيقات WinForms / WPF ── أتمتة البناء والتوقيع والتوزيع عبر GitHub Actions
· آخر تحديث: · غو كومورا · CI/CD, GitHub Actions, WinForms, WPF, C#, .NET, توقيع الشيفرة, MSIX, Deployment, تطوير Windows, جدول القرار
سجل التعديلات (2 تحديثات، آخر تحديث 2 Sep، 2026)
سجل بالتغييرات التي أُجريت على هذا المقال. وحيثما حُفظت نسخة سابقة، تبقى متاحة للقراءة عبر رابط دائم يحمل معرّف DOI.
- أُعيدَت الترجمة العربية كترجمة كاملة عن النص الياباني الأصلي، وأُضيفَت خريطة المعرفة.
- أعيدت الترجمة كترجمة كاملة عن النص الياباني الأصلي. كانت النسخة العربية السابقة مختصراً يسقط أبواباً وجداول ورسوم Mermaid وتعليقات الأشكال وFAQ. أُعيدت هذه العناصر وفق الأصل الياباني، والادّعاءات التقنية مطابقة للنسخة اليابانية.
- النشر الأول
الاستشهاد بهذا المقال(DOI: 10.5281/zenodo.21621720)
هذا المقال محفوظ على Zenodo. يرد أدناه معرّف DOI الذي يشير دائمًا إلى أحدث نسخة، ومعرّف DOI المثبَّت على النسخة التي تقرؤها.
غو كومورا (2026). CI/CD عمليّ لتطبيقات WinForms / WPF ── أتمتة البناء والتوقيع والتوزيع عبر GitHub Actions. شركة كومورا سوفت ذ.م.م.. https://doi.org/10.5281/zenodo.21621720 https://comcomponent.com/ar/blog/winforms-wpf-cicd-github-actions/
- DOI (أحدث نسخة)
- 10.5281/zenodo.21621720
- DOI (هذه النسخة)
- 10.5281/zenodo.22241049
«الإصدار لا يمكن بناؤه إلّا على حاسوب ذلك الشخص» ── جملة نسمعها كثيراً حقّاً في استشارات تطبيقات الأعمال المبنيّة بـ WinForms أو WPF. بناء Release على Visual Studio في الجهاز المحلّي، وضغطه في zip، ووضعه في مجلّد مشترَك. الأمر يعمل، لكن لا أحد يستطيع الإجابة عمّا إذا كان بالإمكان إصدار نسخة إصلاح خطأ في اليوم الذي يتغيّب فيه ذلك المطوّر.
معلومات CI/CD لتطبيقات الويب متوفّرة بكثرة، لكن بمجرّد الانتقال إلى تطبيقات سطح المكتب تصبح شحيحة فجأة. وجود اختلاف جذريّ يتمثّل في «وجهة النشر ليست خادماً بل حاسوب العميل» يجعل من غير الممكن تقليد مقالات الويب كما هي. لكن حتّى أتمتة البناء والاختبار، يمكن بناؤها في تطبيقات سطح المكتب بجهد يماثل تقريباً الويب. العائق يكمن فيما بعد ذلك، أي التوقيع والتوزيع، وهناك يختلف الحلّ الواقعيّ حسب أسلوب التوزيع.
في هذه المدوّنة رتّبنا كيفيّة اختيار أسلوب التوزيع في «جدول القرار حول أساليب توزيع تطبيقات Windows»، وفكرة التوقيع في «SmartScreen وتوقيع الشيفرة». هذا المقال يفترض هذين المقالين، ويرتّب إلى أيّ مدى نؤتمت البناء والاختبار وترقيم الإصدار والتوقيع وإنشاء ملفّات التوزيع لتطبيقات WinForms / WPF باستخدام GitHub Actions من منظور عمليّ.
الجمهور المستهدف والافتراضات
حتّى تتمكّن من قراءة المقال بإسقاطه على وضعك، نذكر أوّلاً الشروط التي يفترضها.
- الجمهور: المطوّرون والفرق الذين يبنون تطبيق سطح مكتب Windows مكتوب بـ WinForms / WPF على Visual Studio في أجهزتهم ثمّ يوزّعونه. لا يُشترَط وجود خبرة سابقة في CI/CD.
- المستودع: أن يكون المصدر في مستودع GitHub (عامّ أو خاصّ، لا فرق). في المستودعات العامّة عوامل التشغيل القياسيّة مجّانيّة، وفي المستودعات الخاصّة يخضع زمن التنفيذ للفوترة بالدقيقة.1
- شكل المشروع: يفترض YAML في المتن صيغة csproj الخاصّة بـ .NET SDK (
net8.0-windowsوما شابه). الفكرة نفسها تنطبق على csproj القديم لـ .NET Framework 4.x، مع استبدالdotnet buildبـ MSBuild وNuGet CLI (الفصل 3). - التوقيع: يعالج الفصل 5 الموضوع بدءاً من «كيف نوفّر الشهادة من الآن». تختلف الخلاصة بحسب ما إذا كان لديك بالفعل ملفّ PFX أو CA داخليّ، أو كنت ستحصل على شهادة رسميّة، فاقرأ مع التحقّق من وضعك الحاليّ.
- الهدف: ليس التوزيع الآليّ الكامل، بل أوّلاً حالة «يمكن إعادة إنتاج البناء والاختبار على أيّ جهاز، ويمكن أخذ النواتج» (الفصل 3). ومن هناك نضيف التوقيع والتوزيع على مراحل.
شكل خطّ الأنابيب ككلّ يكون كالتالي. مدى ما ندخله في نطاق الأتمتة نعالجه في الفصل 2.
[يوميّاً] push إلى main / طلب سحب (pull request)
└→ checkout → setup-dotnet → build → test → publish → upload-artifact (الفصل 3)
[إصدار] push لوسم v1.2.3
└→ checkout → setup-dotnet → test
→ حقن الإصدار من الوسم ثمّ publish (الفصل 4)
→ التوقيع (signtool / خدمة توقيع سحابيّة) (الفصل 5)
→ إنشاء ملفّ التوزيع (zip / MSI / MSIX / ClickOnce) (الفصل 6)
→ الإرفاق بإصدار GitHub (حفظ طويل الأمد) (الفصل 4)
1. الخلاصة أوّلاً
- أكبر خطر هو حالة «لا يمكن البناء إلّا على حاسوب المطوّر». الهدف الأوّل لـ CI/CD ليس أتمتة التوزيع بالكامل، بل أن يُعاد إنتاج البناء دون الاعتماد على جهاز أحد بعينه.
- التكوين الأدنى، أي أتمتة البناء والاختبار وحدهما، ذو قيمة كافية. يمكن بناؤه بملفّ YAML واحد:
windows-latest+actions/checkout+actions/setup-dotnet+dotnet build / test+actions/upload-artifact.12 - WinForms / WPF يفترضان عامل تشغيل Windows. لأنّ المشروع يستهدف TFM خاصّاً بـ Windows مثل
net8.0-windows،3 فإنّ تنفيذ الاختبارات داخل CI يحتاج بيئة Windows. - ترقيم الإصدار يستقرّ عند الإصدار المدفوع بالوسم. دفع وسم
v1.2.3يشغّل بناء الإصدار، ويُحقَن قيمة الوسم في خاصّيّةVersionلـ MSBuild.4 - التوقيع هو أكبر عائق أمام الأتمتة. منذ يونيو 2023 أصبح حفظ المفتاح الخاصّ لشهادات OV الرسميّة في HSM إلزاميّاً، فلم تعد الطريقة التقليديّة «وضع PFX في الأسرار ثمّ signtool» صالحة كما هي. Azure Artifact Signing (المعروفة سابقاً باسم Trusted Signing)، الأسهل في الربط مع CI، لا تشمل اليابان ضمن المناطق المستهدفة، لذلك الحلّ الواقعيّ للمطوّر في اليابان هو خيار HSM السحابيّ لدى جهة الاعتماد (CA)، أو إبقاء خطوة التوقيع فقط على الجهاز المحلّي (الفقرة 5.2).5
- سهولة إدماج CI تختلف اختلافاً كبيراً حسب شكل التوزيع. الأسهل هو xcopy (zip)، ثمّ MSIX الذي يشترط التوقيع،6 ثمّ MSI عبر ربط CLI لأدوات مثل WiX، ثمّ ClickOnce الذي يحتاج
msbuild /target:publishوله طباع خاصّة.7 - لا تجعل الاختبار الآليّ لواجهة المستخدم بوّابة إلزاميّة في CI. اختبارات الوحدة إلزاميّة في CI، أمّا اختبارات الواجهة فتُضيَّق إلى دخان (smoke) وتُشغَّل في مهمّة منفصلة. هذا هو الحلّ الواقعيّ.
في المخطّط، يشير الخطّ المتّصل إلى علاقة قائمة دائماً، ويشير الخطّ المتقطّع إلى علاقة مشروطة (شروط قيامها مذكورة في شرح كلّ علاقة في الصفحة التفصيليّة). القائمة الكاملة للعلاقات (المجموع 21، مع الأدلّة ودرجة اليقين) وتعريفات المفاهيم الرئيسة مجمّعة في صفحة تفاصيل خريطة المعرفة (باليابانية). البيانات: JSON-LD / Turtle
2. ما الذي يختلف في CI/CD لتطبيق سطح المكتب عن الويب؟
نرتّب أوّلاً أسباب تعذّر نقل قالب CI/CD لتطبيقات الويب (push ثمّ بناء ثمّ اختبار ثمّ نشر إلى الخادم) كما هو.
| زاوية النظر | تطبيق ويب | تطبيق سطح مكتب WinForms / WPF |
|---|---|---|
| وجهة النشر | خادم نديره نحن | حواسيب العملاء والميدان (خارج إدارتنا) |
| وحدة التوزيع | تبديل جماعيّ على الخادم | متنوّعة: MSI / MSIX / ClickOnce / zip. توقيت النشر بيد الطرف الآخر |
| التراجع (rollback) | يمكن إرجاعه من جهة الخادم | يصعب إرجاعه من الحواسيب التي وُزِّع عليها. حفظ مثبّت الإصدار السابق إلزاميّ |
| التوقيع | عادة غير مطلوب (TLS من جهة البنية) | توقيع الشيفرة على الملفّ التنفيذيّ والحزمة إلزاميّ عمليّاً |
| بيئة البناء | تكتمل غالباً على عامل تشغيل Linux | عامل تشغيل Windows هو الافتراض |
| الاختبار | يكتمل غالباً دون واجهة (headless) | اختبارات الوحدة نفسها. اختبارات الواجهة تحتاج جلسة سطح مكتب |
| معنى «النشر» | حتّى الانعكاس على الإنتاج | نطاق CI ينتهي عند «اكتمال ملفّ التوزيع». التثبيت خطوة منفصلة |
المهمّ هو الصفّ الأخير. في تطبيق سطح المكتب، مخرج خطّ أنابيب CI/CD ليس «انعكاساً على الإنتاج» بل «وجود ملفّ توزيع موقَّع في مكان يمكن أخذه منه في أيّ وقت». ما بعد ذلك (النشر لدى العميل، التحديث الآليّ) حديث عن تصميم أسلوب التوزيع، وهو المجال الذي عالجناه في «جدول القرار حول أساليب التوزيع». وبالمقابل، إن حدّدنا المخرج على هذا النحو، يمكن بناء CI/CD لتطبيق سطح المكتب بأدوات الويب نفسها.
3. التكوين الأدنى ── البناء والاختبار عبر GitHub Actions
هذا هو أوّل ما ينبغي إدخاله. تخصّص عوامل التشغيل المستضافة من GitHub آلة افتراضيّة جديدة لكلّ مهمّة،1 لذلك عند كلّ push يجري البناء والاختبار على Windows نظيف، وينكشف فوراً الاعتماد على «SDK غير موجود إلّا على حاسوب ذلك الشخص».
name: build-and-test
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: windows-latest # WinForms / WPF は Windows ランナー必須
steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
- name: Restore
run: dotnet restore
- name: Build
run: dotnet build --configuration Release --no-restore
- name: Test
run: dotnet test --configuration Release --no-build
- name: Publish
run: dotnet publish src/MyApp/MyApp.csproj -c Release -o publish
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: MyApp
path: publish
ضع هذا YAML باسم .github/workflows/build-and-test.yml فيعمل مباشرة عند الدفع. لكن استبدل جزء src/MyApp/MyApp.csproj بمسار المشروع في مستودعك. نستخدم المسار نفسه مثالاً في YAML اللاحق أيضاً. إن كان في جذر المستودع حلّ ومشروع csproj واحد فقط، يعمل أيضاً اختصار المسار مثل dotnet publish -c Release -o publish.
ثلاث نقاط إضافيّة.
أوّلاً، الأساس هو runs-on: windows-latest. مشاريع WinForms / WPF هي مشاريع .NET Desktop SDK يكون فيها TargetFramework من نوع TFM خاصّ بـ Windows مثل net8.0-windows، مع تفعيل UseWindowsForms أو UseWPF.3 بدقّة، يكفي للتجميع وحده عامل تشغيل Linux إن فعّلت EnableWindowsTargeting، لكن الخطوات التي تتضمّن تشغيلاً مثل dotnet test تحتاج بيئة Windows، لذلك في هذا التكوين الذي يشغّل الاختبارات في المهمّة نفسها نستخدم عامل تشغيل Windows بصراحة. في حالة .NET Framework 4.x (csproj القديم) نستخدم MSBuild وNuGet CLI بدل dotnet build، وكلاهما مثبَّت مسبقاً على عامل تشغيل Windows، والفكرة نفسها.
ثانياً، احرص دائماً على إبقاء النواتج عبر actions/upload-artifact. جوهر الخروج من «جهاز شخص بعينه» هو أن «مجموعة نواتج ذلك البناء يمكن أخذها من GitHub». حتّى نسخة التحقّق العاجلة تصبح مجرّد تنزيل zip من شاشة Actions.
ثالثاً، في هذه المرحلة لا نفعل توقيعاً ولا توزيعاً بعد. بهذا التكوين الأدنى وحده تحصل على ضمانين: «يمكن دائماً بناء main واختباره» و«أيّ شخص يأخذ النواتج نفسها»، وتجربة الكاتب أنّ معظم هموم الفرق الصغيرة تُحَلّ بهذا.
4. الترقيم الآليّ لرقم الإصدار ── إصدار مدفوع بالوسم
المرحلة التالية هي حلّ مشكلة «هذا الـ zip، أيّ إصدار هو؟». في تشغيل البناء المحلّي، الحادث التقليديّ هو نسيان تعديل Version في csproj فيبقى 1.0.0 لأجيال عدّة. الاستقرار العمليّ هو الإصدار المدفوع بالوسم: تضع وسماً مثل v1.2.3 على الـ commit المراد إصداره، فيشغّل ذلك سير العمل، ويُحقَن في البناء الإصدار المستخرج من اسم الوسم.
name: release
on:
push:
tags: [ 'v*' ]
jobs:
release:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
# タグのpushでは3章のビルド+テストのワークフローは発火しないため、
# リリースの成果物を作る前にここでもテストを通す
- name: Test
run: dotnet test --configuration Release
- name: Publish with version from tag
shell: pwsh
run: |
$version = $env:GITHUB_REF_NAME.TrimStart('v') # v1.2.3 -> 1.2.3
dotnet publish src/MyApp/MyApp.csproj `
-c Release -o publish `
-p:Version=$version
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: MyApp-${{ github.ref_name }}
path: publish
عند التمرير كخاصّيّة MSBuild مثل -p:Version=1.2.3، يولَّد في مشروع .NET SDK افتراضيّاً AssemblyVersion وFileVersion من بادئة Version (الجزء دون اللاحقة)، وInformationalVersion من Version نفسه.4 يبقى في csproj قيمة مؤقّتة للتطوير فقط، وتصبح الإدارة موحَّدة بحيث لا يملك الإصدار الرسميّ عند الإصدار سوى الوسم.
ملاحظة واحدة. لنواتج actions/upload-artifact مدّة احتفاظ في المستودع (الافتراضيّ 90 يوماً)، وتُحذف عند انتهاء الأجل. في تطبيقات سطح المكتب يلزم حفظ مثبّت الإصدار السابق للتراجع حفظاً طويل الأمد، لذلك أصدِر نواتج بناء الوسم إلى مكان دائم مثل إرفاقها بإصدار GitHub، واعتبر نواتج Actions تسليماً مؤقّتاً فقط.
لإرفاق الملفّ بإصدار GitHub طريقان: استخدام إجراء مخصّص، أو استخدام GitHub CLI (gh) المضمَّن في عامل التشغيل من الأصل.8 وكلاهما يحتاج صلاحيّة contents: write على المهمّة.
jobs:
release:
runs-on: windows-latest
permissions:
contents: write # リリースの作成・アセット添付に必要
steps:
# ...(ビルドと publish は前掲のとおり)
- name: Zip
shell: pwsh
run: Compress-Archive -Path publish\* -DestinationPath MyApp-${{ github.ref_name }}.zip
# 方法A: 専用アクションを使う
- name: Create GitHub Release
uses: softprops/action-gh-release@v3
with:
files: MyApp-${{ github.ref_name }}.zip
# 方法B: ランナー同梱の GitHub CLI を使う(上のどちらか一方でよい)
- name: Create GitHub Release (gh)
shell: pwsh
run: gh release create ${{ github.ref_name }} MyApp-${{ github.ref_name }}.zip --generate-notes
env:
GH_TOKEN: ${{ github.token }}
gh مثبَّت مسبقاً على عوامل التشغيل المستضافة من GitHub، لكن يلزم تمرير رمز ذي النطاق المطلوب إلى متغيّر البيئة GH_TOKEN في كلّ خطوة.8
الميزة أنّ التشغيل يبقى داخل Git. «إصدار 1.2.3 لدى العميل أيّ commit هو؟» يُحسَم بالوسم، ويتطابق رقم ملفّ الإصدار الظاهر في خصائص EXE مع وسم Git تطابقاً آليّاً. علاوة على ذلك، يُلحَق بـ InformationalVersion افتراضيّاً منذ .NET 8 SDK hash الـ commit في Git (SourceRevisionId)،4 فإن عرضته في شاشة الإصدار أمكن تحديد الـ commit مباشرة من الناتج.
5. إدماج توقيع الشيفرة في CI ── هنا أكبر عائق
الفِرَق التي نجحت في أتمتة البناء والإصدار حتّى هنا تتوقّف تقريباً دائماً عند التوقيع. سبب كون توقيع الشيفرة إلزاميّاً عمليّاً لتطبيق Windows يُوزَّع خارج Store (SmartScreen، منتجات الأمن في الشركات، كشف التلاعب) رتّبناه في «SmartScreen وتوقيع الشيفرة»، فنقتصر هنا على أين في CI وكيف ننفّذه.
5.1 الصيغة الأساسيّة لـ signtool
تنفيذ التوقيع نفسه أمر واحد. signtool مضمَّن في Windows SDK، ويمكن استخدامه أيضاً على عامل تشغيل Windows لدى GitHub. في SDK الحاليّ يلزم تحديد /fd (ملخّص الملفّ) و/td (ملخّص الختم الزمنيّ)، ويُوصى بـ SHA256.9
signtool sign /f MyCert.pfx /p $env:PFX_PASSWORD `
/fd SHA256 /tr http://timestamp.digicert.com /td SHA256 `
publish\MyApp.exe
الختم الزمنيّ (/tr) اختياريّ، لكن نضعه دائماً. بوجود الختم الزمنيّ يمكن التحقّق بعد انتهاء أجل الشهادة من أنّها «كانت سارية وقت التوقيع»، فيبقى توقيع الملفّات الموزَّعة حيّاً.96
5.2 نوع الشهادة وواقع إدماجها في CI
المشكلة ليست الأمر، بل أين نضع المفتاح الخاصّ. بحسب شكل الحصول على الشهادة يتغيّر أسلوب إدماجها في CI جذريّاً.
| شكل الشهادة | موضع المفتاح الخاصّ | إدماجها في CI | ملاحظات |
|---|---|---|---|
| خدمة توقيع سحابيّة (Azure Artifact Signing = Trusted Signing سابقاً، وغيرها) | جهة السحابة | سهلة الإدماج. التصميم يفترض الربط مع GitHub Actions ونحوها | قيود على الدول والمناطق المتاحة، واليابان خارج النطاق (للشركات: الولايات المتّحدة وكندا والاتّحاد الأوروبيّ والمملكة المتّحدة، وللأفراد: الولايات المتّحدة وكندا فقط). التفاصيل أدناه5 |
| شهادة OV (إصدار جديد منذ يونيو 2023) | HSM / رمز USB إلزاميّ | الرمز لا يُدخَل في عامل التشغيل لذلك غير ممكن كما هو. خيار HSM السحابيّ لدى CA يجعله ممكناً | بموجب متطلّبات CA/Browser Forum5 |
| شهادة EV | HSM / رمز USB | كما سبق | أثر الثقة الفوريّة في SmartScreen أُلغي في 2024. في تشغيل التوقيع تُعامَل مع OV في الصفّ نفسه5 |
| ملفّ PFX قديم (صادر سابقاً، أو CA داخليّ، أو توقيع ذاتيّ) | ملفّ | تخزين Base64 في الأسرار ثمّ الاستعادة (أدناه) | للحصول الجديد لأغراض التوزيع العامّ لم يعد هذا الشكل متاحاً من حيث المبدأ |
أي أنّ التكوين الشائع في نتائج البحث «ضع PFX في أسرار GitHub ووقّع بـ signtool» ما زال صالحاً مع CA داخليّ أو PFX قائم، لكنّ افتراضه ينهار في حالة الحصول على شهادة رسميّة من الآن. عند البناء من جديد، الواقعيّ أن تدرس أساساً خدمة توقيع سحابيّة تدعم الربط مع CI من الأصل.5 إن كنت تشغّل برمز USB، يصبح التكوين الوسط إبقاء خطوة التوقيع فقط على الجهاز المحلّي أو على عامل تشغيل ذاتيّ الاستضافة يُدخَل فيه الرمز.
الموضوع الأساس للمطوّر في اليابان ── هل يمكن استخدام Azure Artifact Signing؟
كتبنا في الصفّ الأوّل من الجدول «قيود على الدول والمناطق المتاحة»، لكن هذا أهمّ عنصر قرار للقارئ في اليابان فنرتّبه مستقلاً.
توثيق Microsoft ينصّ صراحة على أنّ Azure Artifact Signing (Trusted Signing سابقاً) متاح للشركات في الولايات المتّحدة وكندا والاتّحاد الأوروبيّ والمملكة المتّحدة فقط، وللمطوّرين الأفراد في الولايات المتّحدة وكندا فقط.5 أي أنّ الشركات اليابانيّة والمطوّرين الأفراد المقيمين في اليابان خارج النطاق في الوقت الحاليّ. إن نُقِل القول العامّ «التوقيع السحابيّ هو الخيار الأساس» كما هو، تتوقّف عند إنشاء الحساب. الخيارات على افتراض هذا القيد كالتالي.
| الوضع | الاختيار الواقعيّ |
|---|---|
| ستحصل على شهادة رسميّة من الآن (شركة يابانيّة) | شهادة OV + خيار HSM السحابيّ لدى CA. منذ يونيو 2023 صار حفظ المفتاح الخاصّ لشهادة OV في HSM أو رمز عتاد إلزاميّاً، لكن كثيراً من جهات الاعتماد توفّر إلى جانب رمز USB خيار HSM سحابيّ، ومنه يمكن استدعاء التوقيع من CI.5 إن كنت تخطّط لإدخاله في CI، تحقّق لدى CA، عند اختيار الشهادة، من وجود دعم HSM السحابيّ. بعد شراء الرمز لا يمكن التغيير |
| تشغّل بالفعل برمز USB | أبقِ خطوة التوقيع فقط على الجهاز المحلّي الذي يُدخَل فيه الرمز، أو على عامل تشغيل ذاتيّ الاستضافة. التكوين هو أتمتة البناء والاختبار وترقيم الإصدار على عامل التشغيل المستضاف من GitHub، وإبقاء التوقيع الأخير يداً بشريّة |
| يمكن التوزيع عبر Microsoft Store (MSIX) | تعيد Microsoft التوقيع من جهة Store، فلا تعود شهادة خاصّة بك لازمة.5 إن أمكن إعادة اختيار أسلوب التوزيع، فهذا أقصر طريق لاختفاء همّ التوقيع (لكن عند طرح مثبّت MSI/EXE في Store يلزم توقيع جهة الناشر) |
| مشروع مفتوح المصدر | تقدّم SignPath Foundation توقيع شيفرة مجّانيّاً لمشاريع OSS المستوفية للشروط.5 |
| توزيع داخليّ فقط | تكفي شهادة صادرة من CA داخليّ مع أسلوب PFX القائم (الفقرة 5.3). إن أمكن توزيع الشهادة كجذر موثوق عبر Group Policy أو Intune، فلا حاجة لشهادة رسميّة |
قد تتّسع مناطق Azure Artifact Signing مستقبلاً، لذلك عند تثبيت تصميم توقيع CI/CD تحقّق من المناطق المستهدفة في ذلك الوقت من المصدر الأوّليّ.5
5.3 ملاحظات إدارة الأسرار
هذا هو الأسلوب المتّبع عند إدخال أسلوب PFX (CA داخليّ أو شهادة قائمة) في CI.
- حوّل PFX إلى سلسلة Base64 وخزّنه في أسرار GitHub، ثمّ استعده كملفّ داخل المهمّة. هذا هو الإجراء الذي تعرضه GitHub Docs للتعامل مع الثنائيّات في الأسرار.10
- اجعل كلمة المرور سرّاً منفصلاً. تُقنَّع قيم الأسرار تلقائيّاً في السجلات،10 لكنّ القيم المشتقّة بعد المعالجة لا تُحمى. لا تمرّر متغيّرات البيئة إلّا إلى خطوة التوقيع.
- طلبات السحب من التفرّعات لا تصلها الأسرار (باستثناء
GITHUB_TOKEN).10 لكن المهمّة نفسها تُنفَّذ بأسرار فارغة، لذلك تفشل خطوة الاستعادة أعلاه بفكّ ترميز Base64 لسلسلة فارغة. افصل خطوة التوقيع في سير عمل إصدار يُشغَّل بالوسم كما في الفصل 4 (لا ينطلق من طلب سحب من تفرّع)، أو أضف شرطاً مثلif: github.event_name != 'pull_request'لتجاوزها صراحة.
- name: Restore signing certificate
shell: pwsh
run: |
$bytes = [Convert]::FromBase64String($env:PFX_BASE64)
[IO.File]::WriteAllBytes("$env:RUNNER_TEMP\sign.pfx", $bytes)
env:
PFX_BASE64: ${{ secrets.SIGNING_PFX_BASE64 }}
5.4 سير العمل المكتمل لأسلوب PFX
نعرض شكلاً يصل الشظايا السابقة (حقن الإصدار من الوسم، استعادة PFX، تنفيذ signtool، إصدار النواتج) في سلسلة واحدة. هذا تكوين يفترض وجود CA داخليّ أو PFX قائم، ويمكن وضعه كما هو في .github/workflows/release.yml في المستودع فيعمل. استبدل مسار المشروع وعنوان خادم الختم الزمنيّ ببيئتك.
name: release
on:
push:
tags: [ 'v*' ]
jobs:
release:
runs-on: windows-latest
# 署名鍵に触れるジョブは、承認者付きの Environment に紐づける(5.5節)。
# ここを省いてリポジトリシークレットのまま置くと、書き込み権限を持つ人
# (または乗っ取られたアカウント)がワークフローを書き換えてタグを1本
# push するだけで、署名鍵を取り出せます。この environment を指定し、
# SIGNING_PFX_BASE64 と SIGNING_PFX_PASSWORD は Environment 側に置きます
environment: release-signing
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
- name: Test
run: dotnet test --configuration Release
- name: Publish with version from tag
shell: pwsh
run: |
$version = $env:GITHUB_REF_NAME.TrimStart('v')
dotnet publish src/MyApp/MyApp.csproj `
-c Release -o publish `
-p:Version=$version
# --- ここから署名 ---
- name: Restore signing certificate
shell: pwsh
run: |
$bytes = [Convert]::FromBase64String($env:PFX_BASE64)
[IO.File]::WriteAllBytes("$env:RUNNER_TEMP\sign.pfx", $bytes)
env:
PFX_BASE64: ${{ secrets.SIGNING_PFX_BASE64 }}
- name: Sign
shell: pwsh
run: |
# signtool مضمَّن في Windows SDK. حِلّ المسار دون تثبيته كتابة
$signtool = Get-ChildItem `
"${env:ProgramFiles(x86)}\Windows Kits\10\bin\*\x64\signtool.exe" |
Sort-Object FullName | Select-Object -Last 1
# وقِّع أيضا DLL البناء الذاتي الداخل في التوزيع لا exe فقط.
# إن نظرت جهة التوزيع إلى DLL أيضا بقواعد الناشر في App Control / AppLocker،
# يتوقف عند أول DLL بلا توقيع.
#
# لكن قصُر الهدف على البناء الذاتي. في publish تدخل أيضا DLL من NuGet
# والإطار، فالتقاط الكل بwildcard يكتب شهادتك فوق DLL وقّعها البائع
# (sign بلا /as يستبدل التوقيع القائم) ويخرج DLL طرف ثالث غير موقَّع
# بوصفها «منتجك». تنكسر قواعد السماح حسب الناشر وتحقّق الأصل،
# لذا اذكر الأسماء صراحة
$ownAssemblies = @('MyApp', 'MyApp.Core', 'MyApp.Plugins')
$targets = Get-ChildItem publish -Recurse -Include *.exe, *.dll |
Where-Object { $ownAssemblies -contains $_.BaseName } |
Select-Object -ExpandProperty FullName
if (-not $targets) { throw 'لا هدف توقيع. تحقّق من محتويات publish.' }
& $signtool.FullName sign `
/f "$env:RUNNER_TEMP\sign.pfx" /p $env:PFX_PASSWORD `
/fd SHA256 /tr http://timestamp.digicert.com /td SHA256 `
$targets
if ($LASTEXITCODE -ne 0) { throw "فشل التوقيع (exit $LASTEXITCODE)" }
env:
PFX_PASSWORD: ${{ secrets.SIGNING_PFX_PASSWORD }}
- name: Remove certificate
if: always()
shell: pwsh
run: Remove-Item "$env:RUNNER_TEMP\sign.pfx" -ErrorAction SilentlyContinue
# --- ここから成果物 ---
- name: Zip
shell: pwsh
run: Compress-Archive -Path publish\* -DestinationPath MyApp-${{ github.ref_name }}.zip
- name: Create GitHub Release
uses: softprops/action-gh-release@v3
with:
files: MyApp-${{ github.ref_name }}.zip
عند القراءة خمس نقاط جوهر.
- لا تحذف
environment: release-signing. إن بقي مفتاح التوقيع في أسرار المستودع، فإنّ أيّ شخص يملك صلاحيّة الكتابة على المستودع يستطيع إعادة كتابة سير العمل ودفع وسم واحد ليأخذ المفتاح. ضع الأسرار في Environment له موافقون، واجعل هذه المهمّة وحدها تشير إليها (الفقرة 5.5). لا تشغّل سير عمل بلا هذا السطر بوصفه «شكلاً مكتملاً». - ضيّق أهداف التوقيع إلى بناء شركتك فقط. يدخل
publishأيضاً DLL لحزم التبعيّة. التوقيع جملة واحدة يستبدل توقيع البائع بشهادتك، ويوزّع DLL طرف ثالث غير موقَّع بوصفها نواتج شركتك. إن اضطررت لإضافة توقيع على ثنائيّ طرف ثالث، أضفه بـ/asبدل الاستبدال. - التوقيع بعد
dotnet publishوقبل الضغط. التوقيع بعد التثبيت في zip لا يوقّع EXE الداخليّ. عند صنع MSI أو MSIX أيضاً، الترتيب هو توقيع EXE/DLL الداخليّ أوّلاً، ثمّ صنع الحزمة، ثمّ توقيع الحزمة نفسها أخيراً. - احذف PFX بعد الانتهاء. أضف
if: always()حتّى تعمل خطوة الحذف ولو فشل التوقيع. عوامل التشغيل المستضافة من GitHub تُتلف بعد كلّ مهمّة1 لذلك ليست إلزاميّة، لكنّها تصبح حادثاً عند الانتقال إلى عامل تشغيل ذاتيّ الاستضافة. - هذا السير لا يعمل إلّا بدفع الوسم. لا ينطلق من طلب سحب من تفرّع، فيُتجنَّب بنيويّاً مشكل الأسرار الفارغة المذكور في الفقرة 5.3.
عند استخدام خدمة توقيع سحابيّة أو HSM سحابيّ، لا يتغيّر الشكل قبل الخطوتين وبعدهما؛ تُستبدل خطوتا «Restore signing certificate» و«Sign» فقط بإجراء أو استدعاء CLI توفّره الخدمة.
5.5 تضييق سير العمل الذي يلمس مفتاح التوقيع
إلى جانب أسلوب التعامل مع الأسرار (الفقرة 5.3)، نقطة حاسمة أخرى هي تضييق سير العمل الذي يستطيع الوصول إلى مفتاح التوقيع. من يملك صلاحيّة الكتابة على المستودع يستطيع إعادة كتابة سير العمل، لذلك تُوضَع أسرار التوقيع في Environment له موافقون، ولا يشير إليها سوى سير عمل الإصدار. الثنائيّ الموقَّع هو إثبات «أنّ شركتنا صنعته» نفسه، فصمم التعامل مع المفتاح كحدود ثقة من المستوى نفسه لبنية توزيع التحديث الآليّ (هذا المنظور في «أمن التحديث الآليّ»).
6. جدول قرار إدماج CI/CD حسب شكل التوزيع
بعد الوصول إلى التوقيع، الأخير هو شكل ملفّ التوزيع. نترك اختيار الأسلوب نفسه لـ «جدول القرار حول أساليب التوزيع»، ونقارن هنا من منظور CI/CD فقط.
| شكل التوزيع | سهولة الصنع في CI | وسيلة الصنع في CI | متطلّب التوقيع | التحديث الآليّ |
|---|---|---|---|---|
| xcopy (توزيع zip) | الأسهل | dotnet publish + ضغط فقط |
توقيع EXE/DLL (موصى به) | لا يوجد (نشر يدويّ) |
| xcopy + محدّث خاصّ | سهل (البناء). تصميم توزيع التحديث ثقيل على حدة | dotnet publish + توليد بيان (manifest) |
توقيع EXE + تصميم التحقّق من ملفّات التحديث إلزاميّ | خاصّ (يلزم تصميم حدود الثقة) |
| MSI | متوسّط | تنفيذ أدوات مثل WiX عبر CLI | توقيع ملفّ MSI (موصى به إلى إلزاميّ عمليّاً) | لا يوجد (يلزم آليّة توزيع منفصلة) |
| MSIX | متوسّط | MSBuild / MakeAppx + signtool | توقيع الحزمة إلزاميّ (غير الموقَّع لا يُثبَّت)6 | يمكن عبر App Installer ونحوه |
| ClickOnce | طباع خاصّة | msbuild /target:publish + ملفّ نشر (dotnet CLI غير مدعوم)7 |
توقيع البيان + توقيع EXE | مضمَّن (الغرض الرئيس للأسلوب) |
نضيف.
- xcopy (zip): سير عمل الفصلين 3 و4 شبه مكتمل كما هو. أيّاً كان أسلوب التوزيع النهائيّ، المرور بهذا الشكل مرّة أوّلاً هو أقصر طريق.
- MSI: تضمّن تعريف المثبّت (WiX ونحوه) في المستودع وابنِه عبر CLI. جوهر الأمر ليس التوليد نفسه بل تصميم «ماذا يُضمَّن في MSI (تسجيل الخدمة، per-machine/per-user)».
- MSIX: Windows لا يسمح بتثبيت MSIX غير موقَّع، لذلك لا تكتمل أتمتة CI ما لم تقترن بأتمتة التوقيع.6 وبالمقابل، إن اكتملت بنية التوقيع فهو شكل سهل الإدخال في CI. لتوزيع Microsoft Store حلّ آخر: يعاد التوقيع من جهة Store فلا تعود شهادة خاصّة بك لازمة.5
- ClickOnce: لا يمكن الإصدار من dotnet CLI، بل يُستخدم
msbuild /target:publish /p:PublishProfile=...مع تحديد ملفّ نشر (.pubxml). رقم المراجعة (ApplicationRevision) الذي يُزاد تلقائيّاً عند كلّ إصدار من IDE لا يُزاد في سطر الأوامر،7 لذلك يلزم تصميم تمرير الإصدار صراحة بالإصدار المدفوع بالوسم في الفصل 4. وانتبه هنا إلى أنّ حكم تحديث ClickOnce لا يتمّ بـ-p:Version(معلومات التجميعة) بل بإصدار جهة النشر (ApplicationVersion/ApplicationRevision)، فإن لم تمرّر القيمة الرباعيّة المصنوعة من الوسم على حدة مثل/p:ApplicationVersion=1.2.3.0، لن يُتعرَّف الإصدار الجديد كتحديث. الآليّة ومواضع الملاءمة مشروحة في «ما هو ClickOnce».
من منظور CI/CD وحده، «البدء بـ zip، ثمّ إضافة MSIX أو MSI كمهمّة بعد ثبات متطلّبات التوزيع» هو أسلوب أقلّ زيادة. المقدّمة (البناء والاختبار والإصدار) مشتركة بين كلّ الأشكال، لذلك استبدال خطوة شكل التوزيع لاحقاً لا يضيّع الأصل.
7. إلى أيّ مدى نؤتمت الاختبار؟
أخيراً، خطّ الفصل في ما نفرضه كبوّابة (فحص إلزاميّ) في CI.
| طبقة الاختبار | التعامل في CI | السبب |
|---|---|---|
| اختبارات الوحدة (المنطق) | بوّابة إلزاميّة. تُنفَّذ عند كلّ طلب سحب | سريعة ومستقرّة وتعمل كما هي على عامل تشغيل Windows |
| اختبارات تكامل بلا شاشة (قاعدة بيانات وإدخال/إخراج ملفّات) | إلزاميّة من حيث المبدأ. إن بطُأت تُفصَل إلى تشغيل ليليّ | تحتاج ابتكاراً في تهيئة التبعيّات الخارجيّة، لكن قيمة الأتمتة عالية |
| اختبار آليّ للواجهة (دخان) | عدد قليل في مهمّة منفصلة. من الإقلاع إلى انتقال الشاشات الرئيسة تقريباً | جلسة سطح مكتب إلزاميّة وعوامل عدم الاستقرار كثيرة |
| اختبار آليّ للواجهة (شامل) | لا يُجعَل بوّابة CI | تكلفة الصيانة غالباً تفوق الفائدة |
في تطبيق سطح المكتب أعلى قيمة للأتمتة ليست الواجهة بل ما تحتها. إن دُفن منطق العمل في code-behind تعذّر كتابة اختبارات الوحدة، لذلك فصل المنطق عن الشاشة نفسه استثمار مسبق لـ CI/CD. الاختبار الآليّ للواجهة يُضيَّق إلى دخان «إقلاع، ثمّ تسجيل دخول، ثمّ فتح الشاشات الرئيسة»، ويُشغَّل بمحفّز منفصل مثل الليل. اختبارات الواجهة على عامل التشغيل مليئة بفخاخ جلسة الشاشة والدقّة والتوقيت، وهذا المجال نعالجه بما فيه فخاخ CI والتشغيل بلا مراقب في «الاختبار الآلي لواجهة المستخدم في تطبيقات سطح مكتب Windows».
8. الخلاصة
- CI/CD لتطبيق سطح المكتب يمكن بناؤه بأدوات الويب نفسها إن عرّفنا المخرج بأنّه «اكتمال ملفّ توزيع موقَّع».
- التكوين الأدنى هو
windows-latest+actions/checkout+actions/setup-dotnet+dotnet build / test+actions/upload-artifact. بهذا وحده يزول خطر «لا يمكن البناء إلّا على حاسوب المطوّر».12 - WinForms / WPF يستهدفان TFM خاصّاً بـ Windows مثل
net8.0-windows، لذلك عامل تشغيل Windows هو الافتراض.3 - الإصدار يُوحَّد بوسم
v1.2.3ثمّ حقن-p:Version.4 - التوقيع أكبر عائق أمام أتمتة CI. بعد أن صار حفظ HSM إلزاميّاً أيضاً لشهادة OV، واليابان خارج مناطق Azure Artifact Signing، مدخل العمل هو التحقّق من خيار HSM السحابيّ لدى CA عند اختيار الشهادة. أسلوب PFX + الأسرار موجَّه لـ CA داخليّ والشهادات القائمة، وقد أوردنا سير العمل المكتمل في الفقرة 5.4.510
- نواتج بناء الوسم تُرفَق بإصدار GitHub عبر
softprops/action-gh-releaseأوgh release createالمضمَّن في عامل التشغيل، وتُحفَظ طويل الأمد (يلزمcontents: writeعلى المهمّة).8 - سهولة إدخال شكل التوزيع في CI بالترتيب: xcopy (zip) ثمّ MSI / MSIX ثمّ ClickOnce. MSIX يشترط التوقيع،6 وClickOnce يحتاج الانتباه إلى
msbuild /target:publishوعدم الزيادة التلقائيّة للمراجعة.7 - اجعل اختبارات الوحدة بوّابة إلزاميّة في CI، وضيّق اختبارات الواجهة إلى دخان في مهمّة منفصلة. فصل المنطق عن الشاشة استثمار مسبق.
مقالات ذات صلة
- كيف تختار أسلوب توزيع تطبيق Windows - MSI وMSIX وClickOnce وxcopy والتحديث الخاص
- لماذا تظهر رسالة «قامت Windows بحماية جهاز الكمبيوتر الخاص بك» - SmartScreen وتوقيع الشيفرة
- ما هو ClickOnce - كيف يعمل، وكيف تعمل التحديثات، ومتى يلائم العمل الفعليّ ومتى لا يلائمه
- تصميم أمن التحديث التلقائي - لماذا لا يكفي HTTPS
- الاختبار الآلي لواجهة المستخدم في تطبيقات سطح مكتب Windows
مجالات الاستشارة ذات الصلة
تتولّى شركة كومورا سوفت ذ.م.م.، إلى جانب تطوير تطبيقات WinForms / WPF، الانتقال من تشغيل البناء المحلّي إلى CI/CD، وتصميم خطّ أنابيب البناء والتوقيع والتوزيع عبر GitHub Actions، وجعل تطبيقات سطح المكتب القائمة قابلة للاختبار (فصل المنطق).
- تطوير تطبيقات Windows
- تعديل وصيانة برمجيّات Windows القائمة
- الاستشارة التقنيّة ومراجعة التصميم
- الاتّصال بنا
روابط مرجعية
-
GitHub Docs, GitHub-hosted runners reference. حول تسميات عوامل التشغيل مثل
windows-latest، وتخصيص آلة افتراضيّة جديدة لكلّ مهمّة، ومجّانيّة عوامل التشغيل القياسيّة في المستودعات العامّة. ↩ ↩2 ↩3 ↩4 ↩5 -
Microsoft Learn, GitHub Actions and .NET. حول CI/CD لـ .NET عبر GitHub Actions، ودور actions/checkout وactions/setup-dotnet، واستخدام dotnet restore / build / test / publish داخل سير العمل. ↩ ↩2
-
Microsoft Learn, MSBuild reference for .NET Desktop SDK projects. حول أنّ مشاريع WinForms / WPF تحدّد TFM خاصّاً بـ Windows مثل
net8.0-windows، وتفعّل .NET Desktop SDK عبرUseWindowsForms/UseWPF. ↩ ↩2 ↩3 -
Microsoft Learn, Set assembly attributes in a project file. حول توليد
AssemblyVersion/FileVersion(دون اللاحقة) وInformationalVersionافتراضيّاً من خاصّيّةVersion، وإلحاقSourceRevisionId(hash الـ commit) بـInformationalVersionمنذ .NET 8 SDK. ↩ ↩2 ↩3 ↩4 -
Microsoft Learn, Code signing options for Windows app developers. حول إلزام حفظ المفتاح الخاصّ لشهادة OV في HSM / رمز عتاد بموجب متطلّبات CA/Browser Forum منذ يونيو 2023، وإلغاء تجنّب SmartScreen الأوّل لشهادة EV في 2024، وأنّ Azure Artifact Signing (Trusted Signing سابقاً) لا يحتاج رمزاً ويمكن دمجه مع GitHub Actions ونحوها مع قيود على المناطق، وأنّ Microsoft تعيد التوقيع عند توزيع MSIX عبر Store. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11 ↩12
-
Microsoft Learn, Sign an MSIX package. حول أنّ Windows يشترط توقيع شيفرة سارياً على حزمة MSIX، وأنّ الختم الزمنيّ يُبقي التحقّق من التوقيع سارياً بعد انتهاء أجل الشهادة. ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, Build .NET ClickOnce applications from the command line. حول أنّ إصدار ClickOnce لـ .NET يحتاج
msbuild /target:publishمع تحديد ملفّ نشر، وأنّApplicationRevisionلا يُزاد تلقائيّاً في بناء سطر الأوامر. ↩ ↩2 ↩3 ↩4 -
GitHub Docs, Using GitHub CLI in workflows. حول أنّ GitHub CLI (
gh) مثبَّت مسبقاً على كلّ عوامل التشغيل المستضافة من GitHub، وأنّ كلّ خطوة تستخدمghتحتاج ضبط رمز بالنطاق المطلوب في متغيّر البيئةGH_TOKEN. ↩ ↩2 ↩3 -
Microsoft Learn, SignTool. حول أنّ SignTool مضمَّن في Windows SDK، وأنّ الإصدارات الحاليّة تلزم تحديد
/fdو/tdويُوصى بـ SHA256، وتحديد ختم زمنيّ RFC 3161 عبر/tr. ↩ ↩2 -
GitHub Docs, Using secrets in GitHub Actions. حول الإخفاء التلقائيّ لقيم الأسرار من السجلات، وإجراء تخزين الثنائيّات مثل الشهادات كـ Base64 في الأسرار ثمّ استعادتها داخل المهمّة، وعدم تمرير الأسرار إلى سير العمل الذي ينطلق من تفرّع. ↩ ↩2 ↩3 ↩4
مقالات ذات صلة
أحدث المقالات التي تشترك في نفس الوسوم. عمّق فهمك بمواضيع مرتبطة.
إقامة تطبيقات Windows في علبة النظام والإشعارات المنبثقة ── مطبات NotifyIcon وكيفية اختيار AppNotification
نرتّب إقامة تطبيقات Windows للأعمال في علبة النظام والإشعارات المنبثقة. نشرح الاستخدام الصحيح لـ NotifyIcon، وإعادة التسجيل عند إعادة تشغ...
الاختبار الآلي لواجهة المستخدم في تطبيقات سطح مكتب Windows ── آلية UI Automation وبناء اختبارات لا تنكسر بسهولة باستخدام FlaUI
نرتّب الاختبار الآلي لواجهة المستخدم في تطبيقات WinForms/WPF انطلاقاً من آلية Windows UI Automation. نشرح التنفيذ الأدنى عبر FlaUI، وتصمي...
لماذا نستخدم Generic Host و BackgroundService في تطبيق سطح المكتب
تنظيم البدء والمعالجة الدوريّة والإيقاف والسجلات والإعدادات و DI في أدوات Windows والتطبيقات المقيمة باستخدام Generic Host و BackgroundSe...
انتهاء خدمة برامج تشغيل الطابعات في Windows ── كيف تستعد تطبيقات الأعمال لطباعة التقارير والملصقات
تُنهى Microsoft تدريجيّاً خدمة برامج تشغيل الطابعات v3/v4، ومن تمّوز/يوليو 2026 يُفضَّل برنامج تشغيل فئة IPP. نرتّب في جداول قرار ما يختف...
إدارة إصدارات مخطّط قاعدة بيانات تطبيقات الأعمال ── ممارسات الترحيل لمنع «اختلاف قاعدة البيانات من عميل لآخر»
دليل عمليّ لإدارة إصدارات مخطّط قاعدة بيانات تطبيقات الأعمال الموزَّعة على عملاء متعدّدين. نشرح PRAGMA user_version وتنفيذ الترحيل الأمام...
أين يتصل هذا الموضوع
ترتبط هذه المقالة بشكل طبيعي بصفحات الخدمات التالية.
تطوير تطبيقات ويندوز
ندعم تطوير برامج ويندوز للأعمال، وتكامل الأجهزة، وأدوات التواصل.
صيانة وتحديث برامج ويندوز الحالية
ندعم إضافة الميزات، والصيانة، والتحديث المتدرّج لبرامج ويندوز الحالية.
الأسئلة الشائعة
أسئلة شائعة حول موضوع هذه المقالة.
- على أيّ عامل تشغيل (runner) في GitHub Actions ينبغي تشغيل بناء تطبيقات WinForms / WPF؟
- استخدم عوامل تشغيل Windows مثل windows-latest. تستهدف مشاريع WinForms / WPF إطار عمل مستهدَف (TFM) خاصّاً بـ Windows مثل net8.0-windows، ويحتاج التحقّق من عمل نواتج البناء وتنفيذ الاختبارات عبر dotnet test إلى بيئة Windows. بما أنّ عوامل التشغيل المستضافة من GitHub تُخصَّص لها آلة افتراضيّة جديدة لكلّ مهمّة (job)، يُحصَل على بناء قابل لإعادة الإنتاج لا يعتمد على حاسوب المطوّر. في المستودعات العامّة، عوامل التشغيل القياسيّة مجّانيّة، وفي المستودعات الخاصّة تخضع للفوترة بالدقيقة.
- هل يمكن أتمتة توقيع الشيفرة بالكامل عبر CI؟
- يعتمد على طريقة حفظ الشهادة. الطريقة السابقة المتمثّلة في وضع ملفّ PFX في الأسرار (secrets) والتوقيع عبر signtool لم تعد صالحة من حيث المبدأ للشهادات المُصدَرة حديثاً، بعد أن أصبح متطلّب CA/Browser Forum منذ يونيو 2023 يفرض حفظ المفتاح الخاصّ لشهادات OV الرسميّة في HSM (عتاد). لا يمكن إدخال الشهادات من نوع رمز USB في عامل تشغيل سحابيّ، لذا إن أردت الأتمتة الكاملة عبر CI، فالحلّ الواقعيّ هو خدمة توقيع سحابيّة مثل Azure Artifact Signing (المعروفة سابقاً باسم Trusted Signing)، أو المرور عبر HSM سحابيّ توفّره جهة الاعتماد (CA). أمّا إذا استمرّ استخدام الرمز، فسيصبح التكوين إبقاء خطوة التوقيع فقط يدويّاً أو على عامل تشغيل ذاتيّ الاستضافة.
- من أين ينبغي البدء بالأتمتة؟
- ابدأ بأتمتة البناء والاختبار فقط. مجرّد جعل dotnet build / dotnet test يعملان على عامل تشغيل windows-latest عند كلّ push يزيل أكبر خطر، وهو حالة «لا يمكن البناء إلّا على حاسوب المطوّر» أو «لا يُلاحَظ انكسار البناء بسبب الدمج (merge) إلّا قبيل التوزيع مباشرة». يمكن إضافة أتمتة التوقيع وإنشاء المثبّت (installer) والتوزيع تدريجيّاً بعد ذلك، ومحاولة بناء كلّ شيء دفعة واحدة من البداية غالباً ما تتوقّف عند مسائل التوقيع.
- هل تختلف سهولة بناء CI/CD حسب شكل التوزيع (MSI / MSIX / ClickOnce / xcopy)؟
- تختلف اختلافاً كبيراً. توزيع xcopy (zip) هو الأبسط لأنّه مجرّد ضغط لناتج dotnet publish. يمكن إدماج MSIX في CI عبر MSBuild وsigntool، لكن توقيع الحزمة إلزاميّ. يمكن أتمتة MSI عبر استدعاء أدوات مثل WiX من CI. أمّا ClickOnce فلا يمكن نشره عبر dotnet CLI، بل يحتاج مزيجاً من msbuild /target:publish وملفّ النشر (profile)، مع الانتباه إلى أنّ رقم المراجعة (revision) لا يُضاف تلقائيّاً عند استخدام سطر الأوامر. ينبغي إدراج مدى سهولة الدمج مع CI ضمن معايير القرار عند تحديد أسلوب التوزيع.
الملف الشخصي للمؤلف
صفحة الملف الشخصي لمؤلف المقالة.
غو كومورا
مؤسّس شركة كومورا سوفت ذ.م.م.
يركّز على تطوير برامج ويندوز، والاستشارات التقنية، والتحقيق في الأخطاء، ويتميّز في المشاريع التي تبقى فيها الأصول القديمة ناشطة، وفي تشخيص الأعطال التي يصعب تحديد سببها.