انتقل إلى المحتوى

النشر إلى Maven

انشر مكتبات JVM باستخدام elide publish: التثبيت في مستودع Maven المحلي، والنشر إلى Nexus أو Artifactory أو GitHub Packages، والإصدار على Maven Central مع التواقيع والمجاميع الاختبارية، دون إضافات.

في هذه الصفحة

يبني الأمر elide publish ملفات JAR الخاصة بالمكتبة، ويكتب ملف POM لمستخدميها، وينشرها في مستودع ⁦Maven:⁩ المستودع المحلي افتراضيًا، أو مستودع الفريق باستخدام --to، أو Maven Central عبر Central Publisher Portal. بعدها تعتمد مشاريع Maven و Gradle ومشاريع Elide الأخرى عليها كما تعتمد على أي مُخرَج آخر. تُضبط العملية في الكتلة publishing داخل elide.pkl؛ ولا حاجة إلى أي إضافات.

الوجهةالأمرالمتطلبات
مستودع Maven المحليelide publishgroupId و version و Jar واحد
مستودع الفريقelide publish --to internalبيانات الاعتماد في متغيرات البيئة
Maven Centralelide publish --to centralرمز Portal و gpg وبيانات POM الوصفية وملفات JAR للمصادر و javadoc
لا مكان (للتحقق أولًا)elide publish --dry-runلا شيء

التثبيت محليًا

يحتاج النشر إلى groupId و version المشروع ومُخرَج واحد من النوع Jvm.Jar:

amends "elide:project.pkl"
import "elide:Jvm.pkl" as Jvm

name = "greeter"
version = "1.0.0"
description = "Greets people."

artifacts {
  ["lib"] = new Jvm.Jar {}
}

publishing {
  maven {
    groupId = "dev.example"
  }
}
elide publish

يبني Elide ملف JAR (معيدًا استخدام المخرجات المحدّثة)، ويكتب ملف POM، ويثبّت الاثنين باسم dev.example:greeter:1.0.0 تحت ~/.m2/repository مع maven-metadata-local.xml. القيمة الافتراضية لـ artifactId هي اسم المشروع. وإعادة تثبيت الإصدار نفسه تستبدله، فيحصل أي مستخدم على الجهاز نفسه على كل تغيير. من ⁦Maven:⁩

<dependency>
  <groupId>dev.example</groupId>
  <artifactId>greeter</artifactId>
  <version>1.0.0</version>
</dependency>

من ⁦Gradle:⁩

repositories { mavenLocal() }
dependencies { implementation("dev.example:greeter:1.0.0") }

من مشروع Elide آخر:

dependencies {
  maven {
    packages { "dev.example:greeter:1.0.0" }
  }
}

لا يحتاج التثبيت المحلي إلى شبكة ولا إلى بيانات اعتماد. يثبّت localRepository في مكان آخر؛ ويُحلّ المسار النسبي بالنسبة إلى ملف البيان.

التحقق قبل النشر

elide publish --dry-run

يجهّز --dry-run ملف POM وملفات JAR تحت .dev/staging/publish/maven بأسماء ملفات Maven (greeter-1.0.0.jar و greeter-1.0.0-sources.jar و greeter-1.0.0.pom) ويسردها. ويوقّعها إن كان التوقيع مفعّلًا، ويكتب الحزمة أيضًا عند النشر إلى Maven Central، فيعرض بالضبط ما سيرسله التشغيل الفعلي. لا يُكتب شيء في أي مستودع.

محتوى ملف POM

يصف ملف POM المكتبة لمستخدميها، لا عملية البناء: الإحداثيات وبيانات pom الوصفية والتبعيات، دون <build> أو <repositories> أو مسارات محلية.

elide.pklملف POM المنشور
packages، modulesتبعيات compile
runtimeOnlyتبعيات runtime
compileOnly، devPackages، processors، kotlinPlugins، testPackagesتُستبعد
exclusions دون إصدارعنصر <exclusion> على كل تبعية
مشروع في مساحة العملإحداثيات النشر لذلك المشروع
مُخرَج شقيق في Jar.fromقيم packages و modules و runtimeOnly الخاصة به، ما لم تكن مدرجة مسبقًا
مسار ملف JAR محليخطأ: لا يستطيع المستخدمون حلّه

مكتبات Kotlin

يسرد ملف POM أيضًا ما يضيفه Elide إلى مسار الأصناف لمشروع Kotlin دون تصريح، لأن المستخدمين يحتاجونه وقت التشغيل: kotlin-stdlib و kotlin-reflect بإصدار Kotlin الخاص بالمشروع، ومكتبات التشغيل التي يفعّلها kotlin.features (الروتينات المشتركة، والتسلسل). لتحديد إصدار آخر، عطّل الميزة، أو اضبط kotlin.compilerOptions.noStdlib، أو صرّح بالتبعية بنفسك.

افتراضيًا يضم النشر كل Jar و SourceJar و JavadocJar يصرّح بها المشروع؛ ويختار artifacts مجموعة فرعية منها بأسماء المُخرَجات. ويجب أن يضم Jar واحدًا بالضبط، وكل مصنِّف مرة واحدة فقط. يُولَّد JavadocJar لمصادر Kotlin باستخدام Dokka (راجع تجميع JAR).

النشر إلى مستودع الفريق

سمِّ المستودع تحت repositories، ثم انشر إليه باسمه:

publishing {
  maven {
    groupId = "dev.example"
    repositories {
      ["internal"] = "https://repo.example.dev/releases"
    }
  }
}
export ELIDE_MAVEN_INTERNAL_USERNAME=ci
export ELIDE_MAVEN_INTERNAL_PASSWORD="$REPO_TOKEN"
elide publish --to internal

تأتي بيانات الاعتماد من ELIDE_MAVEN_<NAME>_USERNAME و ELIDE_MAVEN_<NAME>_PASSWORD، حيث <NAME> هو اسم المستودع بأحرف كبيرة مع تحويل كل محرف آخر إلى _ (my-repo → ELIDE_MAVEN_MY_REPO_…)، فلا يحتوي ملف البيان على أي أسرار. يُرفع كل ملف مع المجاميع الاختبارية .md5 و .sha1 و .sha256 و .sha512، ويُحدَّث maven-metadata.xml. يعمل ذلك مع Nexus و Artifactory و GitHub Packages وأي مستودع يقبل الرفع بصيغة Maven. ويُرفض عنوان http:// عادي غير localhost ما لم يُستخدم --allow-http-repositories.

التوقيع باستخدام gpg

publishing {
  maven {
    signing { gpg { keyName = "0123ABCD" } }   // `signing {}` uses gpg's default key
  }
}

عند ضبط signing، يوقّع النشر البعيد كل ملف باستخدام الملف التنفيذي gpg (<file>.asc). ولا يوقّع التثبيت المحلي إلا مع --sign؛ ويعطّل --no-sign التوقيع. يطلب gpg-agent عبارة المرور؛ وفي CI اضبط ELIDE_GPG_PASSPHRASE فيمرّرها Elide إلى gpg عبر pinentry بوضع loopback. لا يقرأ Elide المفتاح بنفسه أبدًا. وإن غاب gpg أو فشل، فلا يُنشر شيء.

الإصدار على Maven Central

يتطلب Maven Central بيانات POM الوصفية، وملفات JAR للمصادر و javadoc، والتواقيع، وإصدارًا نهائيًا. مكتبة كاملة:

amends "elide:project.pkl"
import "elide:Jvm.pkl" as Jvm
import "elide:Publishing.pkl" as Publishing

name = "greeter"
version = "1.0.0"
description = "Greets people."

artifacts {
  ["lib"] = new Jvm.Jar {}
  ["sources"] = new Jvm.SourceJar {}
  ["javadoc"] = new Jvm.JavadocJar {}
}

publishing {
  maven {
    groupId = "dev.example"
    pom {
      name = "Greeter"
      url = "https://github.com/example/greeter"
      licenses { new { name = "Apache-2.0"; url = "https://www.apache.org/licenses/LICENSE-2.0" } }
      developers { new { id = "jdoe"; name = "J. Doe" } }
      scm { url = "https://github.com/example/greeter" }
    }
    repositories {
      ["central"] = new Publishing.CentralPortal {}
    }
  }
}

أنشئ رمز مستخدم في Central Publisher Portal ثم انشر:

export ELIDE_MAVEN_CENTRAL_USERNAME=<token user>
export ELIDE_MAVEN_CENTRAL_PASSWORD=<token password>
elide publish --to central

قبل بناء أي شيء، يتحقق Elide من متطلبات Central ويبلّغ عن كل ما ينقص دفعة واحدة: name و description و url و licenses و developers و scm.url في ملف POM، و SourceJar، و JavadocJar، وإصدار ليس -SNAPSHOT. القيمة الافتراضية لـ description في ملف POM هي وصف المشروع. والتوقيع إلزامي للنشر إلى Central، بالمفتاح الافتراضي لـ gpg ما لم يختر signing مفتاحًا آخر، لذا يُرفض --no-sign.

يرفع Elide حزمة واحدة موقّعة مع مجاميعها الاختبارية وينتظر أن يتحقق Portal منها. افتراضيًا (publishingType = "USER_MANAGED") تطلق بعدها عملية النشر من Portal؛ ويطبع Elide رابط صفحتها. ومع publishingType = "AUTOMATIC" يطلقها Portal بمجرد التحقق منها. وإن فشل التحقق، يطبع Elide أخطاء Portal. يعود --no-wait فور انتهاء الرفع.

مساحات العمل

في مساحة عمل، اضبط الإعدادات المشتركة مرة واحدة في elide.pkl الجذري:

import "elide:Publishing.pkl" as Publishing

publishing {
  maven {
    groupId = "dev.example"
    pom { url = "https://github.com/example/greeter"; scm { url = "https://github.com/example/greeter" } }
    repositories { ["central"] = new Publishing.CentralPortal {} }
  }
}

يرث الأعضاء كل شيء عدا artifactId و artifacts، إذ تبقى خاصة بكل مشروع؛ وتتقدم إعدادات العضو نفسه حقلًا بحقل، وتُدمج المستودعات حسب الاسم.

التشغيلما يُنشر
elide publish في الجذركل المشاريع
elide publish داخل عضوذلك العضو وكل مشروع في مساحة العمل يعتمد عليه ملف POM الخاص به
elide publish core utilcore و util فقط؛ ويجب أن تكون مشاريع مساحة العمل التي يعتمدان عليها موجودة مسبقًا في الوجهة
elide publish --skip-existingكل مشروع محدد لم يصل إصداره إلى الوجهة بعد

يُبنى كل مشروع ويُجهَّز ويُوقَّع قبل نشر أي منها، فلا يُنشر شيء إن حدث فشل في هذه المراحل. وعند النشر إلى Maven Central، تدخل كل المشاريع في عملية نشر واحدة يتحقق منها Portal ويطلقها معًا. ويعيد --skip-existing أيضًا تشغيل إصدار فشل في منتصفه: فيتخطى ما وصل بالفعل، ولا يتخطى أبدًا إصدار snapshot.

في CI

- run: elide publish --to central --skip-existing
  env:
    ELIDE_MAVEN_CENTRAL_USERNAME: ${{ secrets.CENTRAL_USERNAME }}
    ELIDE_MAVEN_CENTRAL_PASSWORD: ${{ secrets.CENTRAL_PASSWORD }}
    ELIDE_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}

استورد مفتاح التوقيع إلى حلقة مفاتيح gpg على المشغّل في خطوة سابقة. راجع التكامل المستمر لتثبيت Elide على المشغّل.

المرجع

هل كانت هذه الصفحة مفيدة؟