استخدام إجراءات Gradle و Github لنشر مشروع Java في مستودع Sonatype Maven المركزي

في هذه المقالة ، أود إلقاء نظرة مفصلة على عملية نشر أداة Java من البداية من خلال إجراءات Github إلى مستودع Sonatype Maven المركزي باستخدام Gradle builder.

قررت كتابة هذا المقال بسبب عدم وجود برنامج تعليمي عادي في مكان واحد. كان لابد من جمع كل المعلومات قطعة قطعة من مصادر مختلفة ، علاوة على ذلك ، ليست جديدة تمامًا. من يهتم ، أهلا بك تحت القط.

إنشاء مستودع في Sonatype

الخطوة الأولى هي إنشاء مستودع في Sonatype Maven Central. لهذا نذهب هنا، قم بالتسجيل وإنشاء مهمة جديدة ، وطلب منا إنشاء مستودع. نحن نقود في منطقتنا معرف مجموعة مشروع، عنوان المشروع رابط المشروع و عنوان url لـ SCM ارتباط إلى نظام التحكم في الإصدار الذي يقع فيه المشروع. معرف مجموعة هنا يجب أن يكون بالصيغة com.example ، com.example.domain ، com.example.testsupport ، ويمكن أيضًا أن يكون في شكل رابط إلى github الخاص بك: github.com/yourusername -> io.github. اسم المستخدم الخاص بك. في أي حال ، ستحتاج إلى التحقق من ملكية هذا المجال أو الملف الشخصي. إذا قمت بتحديد ملف تعريف github ، فسيُطلب منك إنشاء مستودع عام بالاسم المطلوب.

بعد التأكيد ببعض الوقت ، سيتم إنشاء GroupId الخاص بك ويمكننا الانتقال إلى الخطوة التالية ، تكوين Gradle.

تكوين Gradle

في وقت كتابة هذا التقرير ، لم أجد مكونات إضافية لـ Gradle يمكن أن تساعد في نشر الأداة. هذا المكون الإضافي الوحيد الذي وجدته ، ومع ذلك ، رفض المؤلف تقديم المزيد من الدعم له. لذلك ، قررت أن أفعل كل شيء بنفسي ، لأنه ليس من الصعب جدًا القيام بذلك.

أول شيء يجب معرفته هو متطلبات Sonatype للنشر. هم كالتالي:

  • توافر أكواد المصدر و JavaDoc ، أي. واجب الحضور -sources.jar и-javadoc.jar الملفات. كما هو مذكور في الوثائق ، إذا لم يكن من الممكن توفير رموز المصدر أو الوثائق ، يمكنك عمل دمية -sources.jar أو -javadoc.jar مع README بسيط بالداخل لاجتياز الاختبار.
  • يجب توقيع جميع الملفات باستخدام GPG/PGPو .asc يجب تضمين الملف الذي يحتوي على التوقيع لكل ملف.
  • توفر pom ملف
  • القيم الصحيحة groupId, artifactId и version. يمكن أن يكون الإصدار عبارة عن سلسلة عشوائية ولا يمكن أن ينتهي بـ -SNAPSHOT
  • الحضور مطلوب name, description и url
  • وجود معلومات حول الترخيص والمطورين ونظام التحكم في الإصدار

هذه هي القواعد الأساسية التي يجب اتباعها عند النشر. المعلومات الكاملة متوفرة هنا.

نقوم بتنفيذ هذه المتطلبات في build.gradle ملف. أولاً ، دعنا نضيف جميع المعلومات الضرورية حول المطورين والتراخيص ونظام التحكم في الإصدار ، وكذلك تعيين عنوان url واسم ووصف المشروع. لنكتب طريقة بسيطة لهذا:

def customizePom(pom) {
    pom.withXml {
        def root = asNode()

        root.dependencies.removeAll { dep ->
            dep.scope == "test"
        }

        root.children().last() + {
            resolveStrategy = DELEGATE_FIRST

            description 'Some description of artifact'
            name 'Artifct name'
            url 'https://github.com/login/projectname'
            organization {
                name 'com.github.login'
                url 'https://github.com/login'
            }
            issueManagement {
                system 'GitHub'
                url 'https://github.com/login/projectname/issues'
            }
            licenses {
                license {
                    name 'The Apache License, Version 2.0'
                    url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
                }
            }
            scm {
                url 'https://github.com/login/projectname'
                connection 'scm:https://github.com/login/projectname.git'
                developerConnection 'scm:git://github.com/login/projectname.git'
            }
            developers {
                developer {
                    id 'dev'
                    name 'DevName'
                    email '[email protected]'
                }
            }
        }
    }
}

بعد ذلك ، تحتاج إلى تحديد ذلك أثناء التجميع الذي تم إنشاؤه -sources.jar и-javadoc.jar الملفات. لهذا القسم java تحتاج إلى إضافة ما يلي:

java {
    withJavadocJar()
    withSourcesJar()
}

دعنا ننتقل إلى الشرط الأخير ، إعداد توقيع GPG / PGP. للقيام بذلك ، قم بتوصيل المكون الإضافي signing:

plugins {
    id 'signing'
}

وإضافة قسم:

signing {
    sign publishing.publications
}

أخيرًا ، دعنا نضيف قسمًا publishing:

publishing {
    publications {
        mavenJava(MavenPublication) {
            customizePom(pom)
            groupId group
            artifactId archivesBaseName
            version version

            from components.java
        }
    }
    repositories {
        maven {
            url "https://oss.sonatype.org/service/local/staging/deploy/maven2"
            credentials {
                username sonatypeUsername
                password sonatypePassword
            }
        }
    }
}

ومن اسم المستخدم и سوناتايب المتغيرات التي تحتوي على تسجيل الدخول وكلمة المرور التي تم إنشاؤها أثناء التسجيل على sonatype.org.

هكذا النهائي build.gradle سوف تبدو مثل هذا:

كود build.gradle كامل

plugins {
    id 'java'
    id 'maven-publish'
    id 'signing'
}

java {
    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8
    withJavadocJar()
    withSourcesJar()
}

group 'io.github.githublogin'
archivesBaseName = 'projectname'
version = System.getenv('RELEASE_VERSION') ?: "0.0.1"

repositories {
    mavenCentral()
}

dependencies {
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.5.2'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.5.2'
}

test {
    useJUnitPlatform()
}

jar {
    from sourceSets.main.output
    from sourceSets.main.allJava
}

signing {
    sign publishing.publications
}

publishing {
    publications {
        mavenJava(MavenPublication) {
            customizePom(pom)
            groupId group
            artifactId archivesBaseName
            version version

            from components.java
        }
    }
    repositories {
        maven {
            url "https://oss.sonatype.org/service/local/staging/deploy/maven2"
            credentials {
                username sonatypeUsername
                password sonatypePassword
            }
        }
    }
}

def customizePom(pom) {
    pom.withXml {
        def root = asNode()

        root.dependencies.removeAll { dep ->
            dep.scope == "test"
        }

        root.children().last() + {
            resolveStrategy = DELEGATE_FIRST

            description 'Some description of artifact'
            name 'Artifct name'
            url 'https://github.com/login/projectname'
            organization {
                name 'com.github.login'
                url 'https://github.com/githublogin'
            }
            issueManagement {
                system 'GitHub'
                url 'https://github.com/githublogin/projectname/issues'
            }
            licenses {
                license {
                    name 'The Apache License, Version 2.0'
                    url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
                }
            }
            scm {
                url 'https://github.com/githublogin/projectname'
                connection 'scm:https://github.com/githublogin/projectname.git'
                developerConnection 'scm:git://github.com/githublogin/projectname.git'
            }
            developers {
                developer {
                    id 'dev'
                    name 'DevName'
                    email '[email protected]'
                }
            }
        }
    }
}

أريد أن أشير إلى أننا حصلنا على الإصدار من متغير البيئة: System.getenv('RELEASE_VERSION'). سوف نكشفها أثناء التجميع ونأخذها من اسم العلامة.

جيل مفتاح PGP

أحد متطلبات Sonatype هو أن يتم توقيع جميع الملفات باستخدام مفتاح GPG / PGP. لهذا نذهب هنا وقم بتنزيل أداة GnuPG لنظام التشغيل الخاص بك.

  • نقوم بإنشاء زوج مفاتيح: gpg --gen-key، أدخل اسم المستخدم والبريد الإلكتروني وقم أيضًا بتعيين كلمة مرور.
  • اكتشفنا id مفتاحنا مع الأمر: gpg --list-secret-keys --keyid-format short. سيتم تحديد المعرف بعد الشرطة المائلة ، على سبيل المثال: rsa2048 / 9B695056
  • نشر المفتاح العام على الخادم https://keys.openpgp.org بالأمر: gpg --keyserver [https://keys.openpgp.org](https://keys.openpgp.org/) --send-keys 9B695056
  • نقوم بتصدير المفتاح السري إلى مكان تعسفي وسنحتاجه في المستقبل: gpg --export-secret-key 9B695056 > D:\gpg\9B695056.gpg

إعداد إجراءات جيثب

دعنا ننتقل إلى المرحلة النهائية ، وقم بإعداد الإنشاء والنشر التلقائي باستخدام إجراءات Github.
إجراءات Github هي ميزة تسمح لك بأتمتة سير العمل من خلال تنفيذ دورة CI / CD كاملة. يمكن تشغيل الإنشاء والاختبار والنشر من خلال أحداث مختلفة: دفع التعليمات البرمجية أو إنشاء الإصدار أو المشكلات. هذه الوظيفة مجانية تمامًا للمستودعات العامة.

في هذا القسم ، سأوضح لك كيفية إعداد كود البناء والدفع ونشره في مستودع Sonatype عند الإصدار ، وكذلك إعداد الأسرار.

نضع الأسرار

للتجميع والنشر التلقائي ، نحتاج إلى عدد من القيم السرية ، مثل معرف المفتاح ، وكلمة المرور التي أدخلناها عند إنشاء المفتاح ، ومفتاح PGP نفسه ، وتسجيل الدخول / كلمة مرور Sonatype. يمكنك ضبطها في قسم خاص في إعدادات المستودع:

استخدام إجراءات Gradle و Github لنشر مشروع Java في مستودع Sonatype Maven المركزي

نضع المتغيرات التالية:

  • SONATYPE_USERNAME / SONATYPE_PASSWORD - تسجيل الدخول / كلمة المرور التي أدخلناها عند التسجيل في Sonatype
  • SIGNING_KEYID / SIGNING_PASSWORD - تم تعيين معرف مفتاح PGP وكلمة المرور أثناء الإنشاء.

أريد أن أسهب في الحديث عن المتغير GPG_KEY_CONTENTS بمزيد من التفصيل. الحقيقة هي أننا نحتاج إلى مفتاح PGP خاص للنشر. من أجل نشرها في الأسرار ، اعتدت تعليمات بالإضافة إلى اتخاذ عدد من الإجراءات.

  • لنقم بتشفير مفتاحنا باستخدام gpg: gpg --symmetric --cipher-algo AES256 9B695056.gpgعن طريق إدخال كلمة مرور. يجب وضعها في متغير: SECRET_PASSPHRASE
  • دعنا نترجم المفتاح المشفر المستلم إلى نموذج نصي باستخدام base64: base64 9B695056.gpg.gpg > 9B695056.txt. سيتم وضع المحتوى في المتغير: GPG_KEY_CONTENTS.

بناء الإعداد عند دفع التعليمات البرمجية وإنشاء العلاقات العامة

تحتاج أولاً إلى إنشاء مجلد في جذر مشروعك: .github/workflows.

في ذلك ، قم بترميز الملف ، على سبيل المثال ، gradle-ci-build.yml بالمحتوى التالي:

name: build

on:
  push:
    branches:
      - master
      - dev
      - testing
  pull_request:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v1
      - name: Set up JDK 8
        uses: actions/setup-java@v1
        with:
          java-version: 8

      - name: Build with Gradle
        uses: eskatos/gradle-command-action@v1
        with:
          gradle-version: current
          arguments: build -PsonatypeUsername=${{secrets.SONATYPE_USERNAME}} -PsonatypePassword=${{secrets.SONATYPE_PASSWORD}}

سيتم تنفيذ سير العمل هذا عند الدفع إلى الفروع master, dev и testing، أيضًا عند إنشاء طلبات السحب.

يحدد قسم الوظائف الخطوات المطلوب تنفيذها على الأحداث المحددة. في هذه الحالة ، سنبني على أحدث إصدار من ubuntu ، ونستخدم Java 8 ، ونستخدم أيضًا المكون الإضافي لـ Gradle eskatos/gradle-command-action@v1والتي ، باستخدام أحدث إصدار من المنشئ ، ستقوم بتشغيل الأوامر المحددة في arguments. المتغيرات secrets.SONATYPE_USERNAME и secrets.SONATYPE_PASSWORD هذه هي الأسرار التي سألناها سابقًا.

ستنعكس نتائج البناء في علامة تبويب الإجراءات:

استخدام إجراءات Gradle و Github لنشر مشروع Java في مستودع Sonatype Maven المركزي

النشر التلقائي عند طرح إصدار جديد

لنقم بإنشاء ملف سير عمل منفصل للنشر التلقائي gradle-ci-publish.yml:

name: publish

on:
  push:
    tags:
      - 'v*'

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v1
      - name: Set up JDK 8
        uses: actions/setup-java@v1
        with:
          java-version: 8

      - name: Prepare to publish
        run: |
          echo '${{secrets.GPG_KEY_CONTENTS}}' | base64 -d > publish_key.gpg
          gpg --quiet --batch --yes --decrypt --passphrase="${{secrets.SECRET_PASSPHRASE}}" 
          --output secret.gpg publish_key.gpg
          echo "::set-env name=RELEASE_VERSION::${GITHUB_REF:11}"

      - name: Publish with Gradle
        uses: eskatos/gradle-command-action@v1
        with:
          gradle-version: current
          arguments: test publish -Psigning.secretKeyRingFile=secret.gpg -Psigning.keyId=${{secrets.SIGNING_KEYID}} -Psigning.password=${{secrets.SIGNING_PASSWORD}} -PsonatypeUsername=${{secrets.SONATYPE_USERNAME}} -PsonatypePassword=${{secrets.SONATYPE_PASSWORD}}

الملف مطابق تقريبًا للملف السابق ، باستثناء الحدث الذي سيتم تشغيله فيه. في هذه الحالة ، هذا هو حدث إنشاء علامة باسم يبدأ بـ v.

قبل النشر ، نحتاج إلى استخراج مفتاح PGP من الأسرار ووضعه في جذر المشروع ، وكذلك فك تشفيره. بعد ذلك ، نحتاج إلى تعيين متغير بيئة خاص RELEASE_VERSION الذي نشير إليه gradle.build ملف. كل هذا يتم في القسم Prepare to publish. نحصل على مفتاحنا من المتغير GPG_KEY_CONTENTS ، نترجمه إلى ملف gpg ، ثم نفك تشفيره بوضعه في الملف secret.gpg.

بعد ذلك ، ننتقل إلى متغير خاص GITHUB_REF، حيث يمكننا الحصول على الإصدار الذي قمنا بتعيينه عند إنشاء العلامة. هذا المتغير مناسب في هذه الحالة. refs/tags/v0.0.2 التي قطعنا منها أول 11 حرفًا للحصول على نسخة محددة. بعد ذلك ، نستخدم أوامر Gradle القياسية للنشر: test publish

التحقق من نتائج النشر في مستودع Sonatype

بمجرد إنشاء الإصدار ، يجب أن يبدأ سير العمل الموضح في القسم السابق. للقيام بذلك ، قم بإنشاء إصدار:

استخدام إجراءات Gradle و Github لنشر مشروع Java في مستودع Sonatype Maven المركزي

يجب أن يبدأ اسم العلامة بـ v. إذا اكتمل سير العمل بنجاح بعد النقر فوق نشر الإصدار ، فيمكننا الانتقال إلى Sonatype Nexus للتأكد:

استخدام إجراءات Gradle و Github لنشر مشروع Java في مستودع Sonatype Maven المركزي

ظهرت القطعة الأثرية في مستودع التدريج. يظهر فورًا في حالة الفتح ، ثم يجب نقله يدويًا إلى حالة الإغلاق بالضغط على الزر المناسب. بعد التحقق من استيفاء جميع المتطلبات ، تنتقل الأداة إلى حالة الإغلاق ولم تعد متاحة للتعديل. في هذا النموذج ، سينتهي الأمر في MavenCentral. إذا كان كل شيء على ما يرام ، يمكنك الضغط على الزر الإفراج عن، وستنتهي الأداة في مستودع Sonatype.

لكي تصل الأداة إلى MavenCentral ، عليك أن تطلبها في المهمة التي أنشأناها في البداية. ما عليك سوى القيام بذلك مرة واحدة ، لذلك ننشر للمرة الأولى. في الأوقات اللاحقة ، هذا غير مطلوب ، ستتم مزامنة كل شيء تلقائيًا. لقد قاموا بتشغيل المزامنة بالنسبة لي بسرعة ، لكن الأمر استغرق حوالي 5 أيام حتى تصبح الأداة متاحة في MavenCentral.

هذا كل شيء ، لقد نشرنا أعمالنا في MavenCentral.

وصلات مفيدة

  • مماثل مقالة، فقط النشر عبر المخضرم
  • التدريج مخزن سوناتايب
  • جيرا Sonatype حيث يتم إنشاء المهمة
  • مثال المستودع حيث تم إعداده بالكامل

المصدر: www.habr.com