إنتقل إلى المحتوى الرئيسي

أتمتة الإصدارات

تُنشأ إصدارات Libre WebUI من جذر المستودع باستخدام نص الإصدار البرمجي. يقرأ النص سجل Git الحقيقي منذ وسم الإصدار السابق، ويحدّث إصدارات الحزم، ويكتب سجل التغييرات، ويشغّل فحوصات الإصدار، وينشئ التزام الإصدار ووسمه. GitHub هو مصدر البناء ونشر الملفات الثنائية؛ وتُنسخ بيانات الإصدار وروابط العناصر المسماة إلى مستودع Forgejo الخاص بالمشروع.

الإعداد المحلي لمرة واحدة

ثبّت الاعتماديات وفعّل خطاطيف المستودع:

npm install
npm run setup-hooks

يضبط إعداد الخطاطيف ما يلي:

  • .githooks/commit-msg للتحقق من تنسيق Conventional Commit
  • .githooks/pre-commit لفحوصات التنسيق
  • .gitmessage قالبًا محليًا لرسائل الالتزام

إنشاء إصدار

شغّل نص الإصدار من شجرة عمل نظيفة على الفرع الذي تنوي وسمه:

# Patch release
npm run release

# Minor release
npm run release:minor

# Major release
npm run release:major

ينفّذ النص تلقائيًا ما يلي:

  1. يتحقق من نظافة شجرة العمل ومن توفر الوسم المحلي التالي.
  2. يجمع أدلة الالتزامات والملفات والاعتماديات واللغات وسجل التغييرات غير المنشور.
  3. يولّد ملاحظات الإصدار من تلك الأدلة.
  4. يحدّث package.json وملفات حزم مساحة العمل وpackage-lock.json وإصداري chart Helm والتطبيق وCHANGELOG.md.
  5. يشغّل npm run release:check بما يشمل التنسيق وlint والبناء والاختبارات وتدقيق الأمان ومحاكاة نشر npm.
  6. لا ينشئ التزام الإصدار ووسم الإصدار المشروح إلا بعد نجاح كل فحص.

توليد سجل التغييرات

عاين القسم التالي من سجل التغييرات من دون تعديل الملفات:

npm run changelog

حدّث CHANGELOG.md يدويًا من القسم المولّد:

npm run changelog -- update

يمكن لمولّد السجل افتراضيًا أن يطلب من نموذج محلي متوافق مع Ollama مسودة مصقولة، ثم يتحقق منها مقابل أدلة Git المجمعة. إذا لم يتوفر AI أو بدت النتيجة غير آمنة، يعود النص إلى مولّد حتمي.

تجاوزات مفيدة:

CHANGELOG_AI=0 npm run release:minor
CHANGELOG_AI_MODEL=glm-5.2:cloud npm run changelog
OLLAMA_BASE_URL=http://127.0.0.1:11434 npm run release

دفع إصدار

بعد إنشاء التزام الإصدار والوسم المشروح، انشر فقط التزام الفرع والوسم الدقيقين اللذين يعرضهما النص. يُدفع فرع الإنتاج إلى Forgejo أولًا ثم GitHub، مع تعطيل الوسوم المتبوعة صراحةً:

git -c push.followTags=false push \
https://git.kroonen.ai/libre-webui/libre-webui.git \
HEAD:refs/heads/main
git ls-remote \
https://git.kroonen.ai/libre-webui/libre-webui.git \
refs/heads/main

git -c push.followTags=false push \
https://github.com/libre-webui/libre-webui.git \
HEAD:refs/heads/main
git ls-remote \
https://github.com/libre-webui/libre-webui.git \
refs/heads/main

يجب أن يساوي SHA المعاد لكل فرع التزام الإصدار المحلي المقصود. انتظر نجاح عمليات GitHub المطلوبة لذلك الالتزام بعينه قبل نشر الوسم.

تأكد من عدم وجود وسم الإصدار على أي من الخدمتين، ثم ادفع ذلك الوسم وحده إلى Forgejo أولًا وGitHub ثانيًا:

git ls-remote \
https://git.kroonen.ai/libre-webui/libre-webui.git \
'refs/tags/vX.Y.Z' 'refs/tags/vX.Y.Z^{}'
git ls-remote \
https://github.com/libre-webui/libre-webui.git \
'refs/tags/vX.Y.Z' 'refs/tags/vX.Y.Z^{}'

git -c push.followTags=false push \
https://git.kroonen.ai/libre-webui/libre-webui.git \
refs/tags/vX.Y.Z:refs/tags/vX.Y.Z
git -c push.followTags=false push \
https://github.com/libre-webui/libre-webui.git \
refs/tags/vX.Y.Z:refs/tags/vX.Y.Z

git ls-remote \
https://git.kroonen.ai/libre-webui/libre-webui.git \
'refs/tags/vX.Y.Z' 'refs/tags/vX.Y.Z^{}'
git ls-remote \
https://github.com/libre-webui/libre-webui.git \
'refs/tags/vX.Y.Z' 'refs/tags/vX.Y.Z^{}'

استبدل vX.Y.Z بوسم الإصدار. في الوسم المشروح، تحقق من SHA لكائن الوسم ومن SHA للالتزام الذي يشير إليه. لا تستخدم git push --tags أبدًا، فقد ينشر وسومًا محلية غير ذات صلة.

مسار الإصدار في CI

يؤدي دفع وسم v* إلى تشغيل سير عمل إصدار GitHub. ويقوم هذا السير بما يلي:

  • تشغيل npm run release:check
  • بناء عناصر Electron لـ macOS وWindows وLinux
  • إنشاء إصدار GitHub من القسم المطابق في CHANGELOG.md
  • نسخ سجل الإصدار وروابط العناصر المسماة إلى Forgejo
  • بناء صور Docker
  • نشر chart Helm بالإصدار نفسه الموجود في وسم الإصدار
  • نشر حزمة npm باستخدام NPM_TOKEN

يمكن تشغيل الفحص نفسه محليًا قبل وضع الوسم:

npm run release:check

مرآة إصدارات Forgejo

تستخدم المرآة رمز وصول شخصيًا لـ Forgejo محفوظًا في سر GitHub Actions المشفّر FORGEJO_TOKEN. امنح الرمز نطاق write:repository فقط، وتأكد من أن مالكه يمكنه الكتابة إلى libre-webui/libre-webui، ولا تلتزم الرمز أو تطبعه مطلقًا.

صُممت المرآة لتكون idempotent. تبحث عن الإصدارات بالوسم، ولا تنشئ إلا سجلات الإصدار المفقودة، وتطابق بياناتها مع إصدار GitHub، وتتجاوز روابط العناصر الموجودة. لذلك تُكمل إعادة المحاولة بعد تعطل الشبكة أو سير العمل ما تبقى من دون تكرار الإصدارات أو العناصر.

عناصر إصدارات Forgejo هي روابط خارجية مسماة إلى browser_download_url العام المقابل في GitHub. يظل GitHub مضيف الملفات الثنائية، بينما يعرض Forgejo أسماء الملفات القابلة للتنزيل نفسها من دون تكرار عشرات الجيجابايت من عناصر تطبيقات سطح المكتب. وتُنشأ أرشيفات المصدر بصورة مستقلة من الوسم الدقيق في كل خدمة.

معاينة إصدار واحد أو استكماله

افحص ما سيتغير من دون الكتابة إلى Forgejo:

node scripts/mirror-forgejo-releases.mjs --tag vX.Y.Z --dry-run

بعد تحميل FORGEJO_TOKEN وGITHUB_TOKEN في بيئة العملية من مدير أسرار المشرف، انسخ ذلك الإصدار:

node scripts/mirror-forgejo-releases.mjs --tag vX.Y.Z

يجب أن يكون الوسم الدقيق موجودًا على GitHub وForgejo وأن يُحل إلى كائن الوسم والالتزام المشار إليه نفسيهما قبل نسخ الإصدار.

معاينة كل الإصدارات أو استكمالها

دقّق كل إصدار GitHub مقابل Forgejo:

node scripts/mirror-forgejo-releases.mjs --all --dry-run

استكمل كل إصدار Forgejo مفقود أو ناقص:

node scripts/mirror-forgejo-releases.mjs --all

يلزم GITHUB_TOKEN مع --all، بما في ذلك عمليات المحاكاة، لأن التحقق من تطابق الوسوم واكتشاف العناصر يتطلبان طلبات أكثر مما يسمح به حد API المجهول في GitHub. ويلزم FORGEJO_TOKEN أيضًا كلما لم يُستخدم --dry-run.

يصفّح مسار --all كلتا واجهتي API ويعالج كائنات GitHub Release، لا كل وسوم Git. يبقى الوسم الذي لا يملك إصدار GitHub عمدًا مجرد وسم على Forgejo. شغّل المحاكاة مجددًا بعد الاستكمال؛ وينبغي ألا تبلغ عن تغييرات معلقة.

سياسة ثبات الوسوم

وسوم الإصدارات المنشورة ثابتة. بعد وجود وسم على أي خادم بعيد:

  • لا تحذفه.
  • لا تدفعه بالقوة.
  • لا تنقله إلى التزام مصحح.
  • لا تعِد استخدام إصداره الدلالي لمحتوى مختلف.

إذا كان محتوى الإصدار المنشور خاطئًا، فصحح المصدر وسجل التغييرات وانشر الإصدار التصحيحي التالي. وإذا كانت صفحة الإصدار أو رابط عنصر خارجي فقط مفقودًا، فأعد تشغيل المرآة idempotent من دون لمس الوسم.

خضع وسم Forgejo ‏v0.8.6 لإعادة محاذاة استثنائية ومعتمدة صراحةً عند إدخال النسخ المزدوج للإصدارات. أصلحت العملية كائني وسم تاريخيين يصفان شجرتي مصدر متطابقتين لكنهما يتبعان سلسلتي التزامات مختلفتين. لا تشكّل تلك الهجرة المدققة سابقةً لنقل الوسوم المنشورة.

سياسة إصدارات Helm

تستخدم version الخاصة بـ chart Helm وappVersion وإصدار الحزمة الجذرية ووسم الإصدار عمدًا الإصدار الدلالي نفسه. يرفعها نص الإصدار معًا، وترفض CI أي عدم تطابق.

لا يُنشر chart إلا من وسم إصدار v* ثابت. لا تنشر محتوى chart معدلًا بإصدار chart موجود. يجب أن يمر أي تغيير في chart عبر إصدار التطبيق التالي كي يحصل على إصدار جديد.

يحمل chart الإصدار 0.14.1 تجاوز digest لمرة واحدة، لأن ذلك الإصدار يسبق وسوم Docker الدلالية. يحدد digest صورة 0.14.1 متعددة البنى التي تم التحقق منها. يمحو نص الإصدار هذا التجاوز عند إنشاء الإصدار التالي، وبعدها تُحل الصورة الافتراضية إلى appVersion الخاصة بـ chart.

ينشر سير عمل Docker وسم الإصدار الدلالي هذا إلى GHCR وDocker Hub من وسم الإصدار v* نفسه. ينتظر نشر Helm حتى 20 دقيقة ظهور صورة Docker Hub العامة المطابقة، ويفشل بدل نشر chart بصورته الافتراضية المفقودة. تظل صورة Ollama المضمّنة قابلة للضبط بصورة مستقلة، وتستخدم وسم upstream ‏latest افتراضيًا.

Conventional Commits

ينبغي أن تستخدم رسائل الالتزام تنسيق Conventional Commit:

<type>[optional scope]: <description>

الأنواع الشائعة:

  • feat: ميزة يراها المستخدم
  • fix: إصلاح خطأ
  • docs: تحديث المستندات
  • refactor: إعادة هيكلة داخلية للشيفرة
  • perf: تحسين الأداء
  • test: تغطية الاختبارات
  • chore: صيانة أو إصدار أو عمل بناء

تستخدم التغييرات الكاسرة !:

git commit -m "feat!: remove deprecated endpoint"
git commit -m "fix(auth)!: change token validation"

استكشاف الأخطاء وإصلاحها

دليل العمل غير نظيف

التزم التغييرات المحلية أو خزّنها مؤقتًا قبل الإصدار:

git status --short
git add .
git commit -m "fix: resolve pending changes"

لا توجد تغييرات قابلة للإصدار

تحقق من الالتزامات منذ الوسم السابق:

git log $(git describe --tags --abbrev=0)..HEAD --oneline

يحتاج سجل التغييرات إلى تحرير يدوي

حرر CHANGELOG.md، ثم التزم التصحيح قبل نشر الوسم:

git add CHANGELOG.md
git commit -m "docs: refine changelog"

التراجع عن التزام إصدار محلي

إذا لم يُدفع التزام الإصدار ولا وسمه:

git tag -d v0.12.0
git reset --soft HEAD~1

إذا كان الوسم موجودًا على أي خادم بعيد، فلا تحذفه ولا تستبدله. أصلح المشكلة على main، وأنشئ الإصدار التصحيحي التالي، وانشر ذلك الوسم الثابت الجديد عبر البوابة الكاملة.

مرآة Forgejo ناقصة

تحقق أولًا من تطابق SHA لكائن الوسم والالتزام المشار إليه على الخادمين. ثم عاين الإصدار المتأثر وأعد المحاولة:

node scripts/mirror-forgejo-releases.mjs --tag vX.Y.Z --dry-run
node scripts/mirror-forgejo-releases.mjs --tag vX.Y.Z

يعني فشل التفويض أن FORGEJO_TOKEN مفقود أو منتهي الصلاحية أو يملكه مستخدم لا يصل إلى المستودع أو يفتقر إلى write:repository. يجب التحقيق بصورة منفصلة في الوسم البعيد المفقود أو المختلف؛ فلا تنشئ مرآة الإصدارات وسوم Git ولا تنقلها.

ملفات المشرف

  • .gitmessage - قالب رسالة الالتزام
  • .githooks/commit-msg - التحقق من Conventional Commit
  • .githooks/pre-commit - فحص التنسيق الأولي
  • scripts/release.js - تنسيق الإصدار
  • scripts/mirror-forgejo-releases.mjs - مرآة إصدارات Forgejo ‏idempotent واستكمال الإصدارات السابقة
  • scripts/generate-changelog.js - أمر معاينة سجل التغييرات وتحديثه
  • scripts/lib/releaseNotes.js - جمع الأدلة وتوليد سجل التغييرات
  • .github/workflows/release.yml - سير إصدار CI مدفوع بالوسم
  • .github/workflows/helm-publish.yml - التحقق من Helm ونشر الوسم

لمزيد من المعلومات عن Conventional Commits، زر https://www.conventionalcommits.org/.