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

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


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


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


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


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


تكوين Gradle


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


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


  • وجود أكواد المصدر و JavaDoc ، أي يجب أن تكون موجودة -sources.jarو -javadoc.jarالملفات. كما هو مذكور في الوثائق ، إذا لم يكن من الممكن توفير رموز المصدر أو الوثائق ، يمكنك عمل دمية -sources.jarأو -javadoc.jarقراءة بسيطة في الداخل لاجتياز الاختبار.
  • 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@dev.ru'
                }
            }
        }
    }
}

, -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
            }
        }
    }
}

sonatypeUsername 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@dev.ru'
                }
            }
        }
    }
}

, : System.getenv('RELEASE_VERSION'). .


PGP


Sonatype GPG/PGP . GnuPG .


  • : gpg --gen-key, , e-mail, .
  • id : gpg --list-secret-keys --keyid-format short. Id , : rsa2048/9B695056
  • https://keys.openpgp.org : gpg --keyserver https://keys.openpgp.org/ --send-keys 9B695056
  • , : gpg --export-secret-key 9B695056 > D:\\gpg\\9B695056.gpg

Github Actions


, , Github Actions.
Github Actions – , , CI/CD. , : , issues. .


Sonatype , .



, id , , , PGP , / Sonatype. :



:


  • SONATYPE_USERNAME/SONATYPE_PASSWORD — /, Sonatype
  • SIGNING_KEYID/SIGNING_PASSWORD — id 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.

PR


: .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, .


jobs , . ubuntu, Java 8, Gradle eskatos/gradle-command-action@v1, , arguments. secrets.SONATYPE_USERNAME secrets.SONATYPE_PASSWORD , .


Actions:




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


, . :



v. Publish release, , Sonatype Nexus :



Staging . Open, Close, . , Close . MavenCentral. , Release, Sonatype.


, MavenCentral, , . , . , . , MavenCentral 5 .


هذا كل شيء ، نشرنا قطعة أثرية في MavenCentral.


روابط مفيدة


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

All Articles