في هذه المقالة ، أود أن ألقي نظرة تفصيلية على عملية نشر قطعة أثرية 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.gradleplugins {
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 ، الذي تحتاج فيه إلى إنشاء مهمة
- مثال على مستودع حيث يتم إعداد كل هذا