In diesem Artikel möchte ich den Prozess der Veröffentlichung eines Java-Artefakts von Grund auf über Github Actions im Sonatype Maven Central Repository unter Verwendung des Build-Tools Gradle detailliert betrachten.
Ich habe diesen Artikel verfasst, da es keinen ordentlichen Tutorial an einem Ort gab. Alle Informationen mussten Stück für Stück aus verschiedenen, nicht ganz aktuellen Quellen gesammelt werden. Wer interessiert ist, ist herzlich eingeladen, weiterzulesen.
Erstellung eines Repositories in Sonatype
Im ersten Schritt müssen wir ein Repository im Sonatype Maven Central erstellen. Dazu gehen wir , registrieren uns und erstellen eine neue Anfrage, um uns ein Repository zu erstellen. Wir geben unsere GroupId des Projekts, Project URL den Link zum Projekt und SCM url den Link zum Versionsverwaltungssystem, in dem das Projekt liegt, an. GroupId Hier sollte es in der Form com.example, com.example.domain, com.example.testsupport sein, und kann auch als Link zu deinem Github sein: -> io.github.yourusername. In jedem Fall muss die Inhaberschaft dieser Domain oder dieses Profils bestätigt werden. Wenn du ein Github-Profil angegeben hast, wird um die Erstellung eines öffentlichen Repositories mit dem erforderlichen Namen gebeten.
Nach einiger Zeit nach der Bestätigung wird deine GroupId erstellt und wir können zum nächsten Schritt, der Konfiguration von Gradle, übergehen.
Konfigurieren von Gradle
Zum Zeitpunkt des Schreibens dieses Artikels habe ich keine Plugins für Gradle gefunden, die bei der Veröffentlichung von Artefakten helfen könnten. Das einzige Plugin, das ich gefunden habe, wurde jedoch vom Autor nicht mehr unterstützt. Daher habe ich beschlossen, alles selbst zu machen, was glücklicherweise nicht allzu schwierig ist.
Das erste, was herausgefunden werden muss, sind die Anforderungen von Sonatype für die Veröffentlichung. Sie sind wie folgt:
- Das Vorhandensein von Quellcodes und JavaDoc, d.h. es müssen vorhanden sein
-sources.jarund-javadoc.jarDateien. Wie in der Dokumentation angegeben, wenn es nicht möglich ist, die Quellcodes oder die Dokumentation bereitzustellen, kann man eine leere Datei-sources.jaroder-javadoc.jarmit einem einfachen README darin erstellen, um die Überprüfung zu bestehen. - Alle Dateien müssen mit
GPG/PGP, und.ascsigniert werden, die Datei, die die Signatur enthält, muss für jede Datei mit aufgenommen werden. - Vorhandensein
pomder Datei - Korrekte Werte für
groupId,artifactIdundversion. Die Version kann eine beliebige Zeichenfolge sein und darf nicht mit-SNAPSHOT - enden. Es müssen vorhanden sein
name,descriptionundurl - Vorhandensein von Informationen zu Lizenz, Entwicklern und Versionskontrollsystem
Das sind die grundlegenden Regeln, die befolgt werden müssen, um zu veröffentlichen. Vollständige Informationen sind verfügbar .
Wir setzen diese Anforderungen in build.gradle In der Datei. Zunächst fügen wir alle erforderlichen Informationen über die Entwickler, die Lizenz, das Versionskontrollsystem hinzu und definieren die URL, den Namen und die Beschreibung des Projekts. Zu diesem Zweck schreiben wir eine einfache Methode:
def customizePom(pom) {
pom.withXml {
def root = asNode()
root.dependencies.removeAll { dep ->
dep.scope == "test"
}
root.children().last() + {
resolveStrategy = DELEGATE_FIRST
description 'Eine Beschreibung des Artefakts'
name 'Artefaktsname'
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 'Die Apache-Lizenz, 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'
}
}
}
}
}Als nächstes müssen wir angeben, dass beim Bauen die -sources.jar und-javadoc.jar Dateien generiert werden. Dazu fügen wir in den Abschnitt java folgendes hinzu:
java {
withJavadocJar()
withSourcesJar()
}Kommen wir zur letzten Anforderung, der Konfiguration der GPG/PGP-Signatur. Dazu aktivieren wir das Plugin signing:
plugins {
id 'signing'
}Und fügen den Abschnitt hinzu:
signing {
sign publishing.publications
}Schließlich fügen wir den Abschnitt 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
}
}
}
}Hier sonatypeUsername und sonatypePassword Variablen, die den Benutzernamen und das Passwort enthalten, die bei der Registrierung auf .
So wird der finale build.gradle wie folgt aussehen:
Den vollständigen Code 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 = 'projektname'
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 'Eine Beschreibung des artefakts'
name 'Artefaktname'
url 'https://github.com/login/projektname'
organization {
name 'com.github.login'
url 'https://github.com/githublogin'
}
issueManagement {
system 'GitHub'
url 'https://github.com/githublogin/projektname/issues'
}
licenses {
license {
name 'Die Apache-Lizenz, Version 2.0'
url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
}
}
scm {
url 'https://github.com/githublogin/projektname'
connection 'scm:https://github.com/githublogin/projektname.git'
developerConnection 'scm:git://github.com/githublogin/projektname.git'
}
developers {
developer {
id 'dev'
name 'DevName'
email 'email@dev.ru'
}
}
}
}
}Ich möchte darauf hinweisen, dass wir die Version aus der Umgebungsvariable erhalten: System.getenv('RELEASE_VERSION'). Wir werden sie während des Builds festlegen und aus dem Tag-Namen übernehmen.
PGP-Schlüsselgenerierung
Eine der Anforderungen von Sonatype ist, dass alle Dateien mit einem GPG/PGP-Schlüssel signiert werden. Dazu gehen wir und laden das Tool GnuPG für unser Betriebssystem herunter.
- Wir generieren ein Schlüsselpaar:
gpg --gen-key, geben den Benutzernamen, die E-Mail und ein Passwort ein. - Wir ermitteln
idunseren Schlüssel mit dem Befehl:gpg --list-secret-keys --keyid-format short. Die ID wird nach dem Schrägstrich angegeben, z. B.: rsa2048/9B695056 - Wir veröffentlichen den öffentlichen Schlüssel auf dem Server mit dem Befehl:
gpg --keyserver [https://keys.openpgp.org](https://keys.openpgp.org/) --send-keys 9B695056 - Wir exportieren den privaten Schlüssel an einen beliebigen Ort, da wir ihn später benötigen:
gpg --export-secret-key 9B695056 > D:\gpg\9B695056.gpg
Github Actions konfigurieren
Kommen wir zum abschließenden Schritt, wir konfigurieren den Build und die automatische Veröffentlichung mithilfe von Github Actions.
Github Actions – eine Funktionalität, die es ermöglicht, den Arbeitsprozess zu automatisieren und einen vollständigen CI/CD-Zyklus zu implementieren. Der Build, das Testen und der Deploy können durch verschiedene Ereignisse ausgelöst werden: Code-Push, Erstellung von Releases oder Issues. Diese Funktionalität ist absolut kostenlos für öffentliche Repositories.
In diesem Abschnitt zeige ich, wie man den Build, den Code-Push und den Deploy in ein Sonatype-Repository beim Release-Management einrichtet, sowie die Konfiguration von Secrets.
Secrets festlegen
Für die automatische Erstellung und den Deploy benötigen wir eine Reihe geheimer Werte, wie z.B. die ID des Schlüssels, das Passwort, das wir bei der Generierung des Schlüssels eingegeben haben, den PGP-Schlüssel selbst sowie die Anmeldedaten (Benutzername/Passwort) für Sonatype. Diese können im speziellen Abschnitt der Repository-Einstellungen festgelegt werden:

Folgende Variablen festlegen:
- SONATYPE_USERNAME/SONATYPE_PASSWORD – Benutzername/Passwort, die wir bei der Registrierung in Sonatype eingegeben haben.
- SIGNING_KEYID/SIGNING_PASSWORD – ID des PGP-Schlüssels und das Passwort, das bei der Generierung festgelegt wurde.
Ich möchte etwas ausführlicher auf die Variable GPG_KEY_CONTENTS eingehen. Der Grund ist, dass wir für die Veröffentlichung einen privaten PGP-Schlüssel benötigen. Um ihn in den Secrets zu speichern, habe ich die befolgt und zusätzlich einige Schritte unternommen.
- Wir verschlüsseln unseren Schlüssel mit gpg:
gpg --symmetric --cipher-algo AES256 9B695056.gpg, wobei wir ein Passwort eingeben. Dieses sollte in der Variable platziert werden: SECRET_PASSPHRASE - Wir konvertieren den erhaltenen verschlüsselten Schlüssel in ein Textformat mit base64:
base64 9B695056.gpg.gpg > 9B695056.txt. Der Inhalt wird in der Variable GPG_KEY_CONTENTS platziert.
Konfiguration des Builds beim Push des Codes und bei der Erstellung von PRs
Zunächst müssen wir einen Ordner im Stammverzeichnis Ihres Projekts erstellen: .github/workflows.
Darin erstellen wir eine Datei, zum Beispiel gradle-ci-build.yml mit folgendem Inhalt:
name: build
on:
push:
branches:
- master
- dev
- testing
pull_request:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: JDK 8 einrichten
uses: actions/setup-java@v1
with:
java-version: 8
- name: Mit Gradle bauen
uses: eskatos/gradle-command-action@v1
with:
gradle-version: current
arguments: build -PsonatypeUsername=${{secrets.SONATYPE_USERNAME}} -PsonatypePassword=${{secrets.SONATYPE_PASSWORD}}Dieser Arbeitsablauf wird bei Pushs in die Branches master, dev und Testen, sowie bei der Erstellung von Pull Requests ausgeführt.
Im Abschnitt jobs sind die Schritte aufgeführt, die bei den angegebenen Ereignissen ausgeführt werden sollen. In diesem Fall werden wir auf der neuesten Version von Ubuntu bauen, Java 8 verwenden und das Plugin für Gradle eskatos/gradle-command-action@v1, das mit der neuesten Version des Builders die angegebenen Befehle ausführt. arguments. Variablen secrets.SONATYPE_USERNAME und secrets.SONATYPE_PASSWORD das sind die Geheimnisse, die wir zuvor festgelegt haben.
Die Build-Ergebnisse werden auf der Registerkarte Aktionen angezeigt:

Automatische Bereitstellung bei der Veröffentlichung einer neuen Version
Für die automatische Bereitstellung erstellen wir eine separate Workflow-Datei gradle-ci-publish.yml:
name: publish
on:
push:
tags:
- 'v*'
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: JDK 8 einrichten
uses: actions/setup-java@v1
with:
java-version: 8
- name: Vorbereitung zur Veröffentlichung
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: Mit Gradle veröffentlichen
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}}Die Datei ist praktisch identisch mit der vorherigen, mit der Ausnahme des Ereignisses, bei dem sie ausgelöst wird. In diesem Fall handelt es sich um das Ereignis der Erstellung eines Tags, dessen Name mit v beginnt.
Vor der Bereitstellung müssen wir den PGP-Schlüssel aus den Geheimnissen abrufen und ihn im Stammverzeichnis des Projekts ablegen sowie entschlüsseln. Danach müssen wir eine spezielle Umgebungsvariable festlegen RELEASE_VERSION auf die wir im gradle.build Datei zugreifen. All dies geschieht im Abschnitt Vorbereitung zur Veröffentlichung. Wir holen unseren Schlüssel aus der Variablen GPG_KEY_CONTENTS, wandeln ihn in eine gpg-Datei um, entschlüsseln ihn dann und speichern ihn in der Datei secret.gpg.
Dann greifen wir auf die spezielle Variable GITHUB_REF, zu, aus der wir die Version abrufen können, die wir bei der Erstellung des Tags festgelegt haben. Diese Variable hat in diesem Fall den Wert refs/tags/v0.0.2 , aus dem wir die ersten 11 Zeichen abschneiden, um die spezifische Version zu erhalten. Dann verwenden wir standardmäßig die Gradle-Befehle zur Veröffentlichung: test publish
Überprüfung der Bereitstellungsergebnisse im Sonatype-Repository
Nach der Erstellung des Releases sollte der Workflow, der im vorherigen Abschnitt beschrieben ist, gestartet werden. Dazu erstellen wir ein Release:

wobei der Name des Tags mit v beginnen muss. Wenn nach dem Klicken auf 'Release veröffentlichen' der Workflow erfolgreich abgeschlossen wird, können wir in das gehen, um dies zu überprüfen:

Das Artefakt wurde im Staging-Repository erstellt. Es erscheint sofort im Status Offen und muss dann manuell in den Status Geschlossen versetzt werden, indem die entsprechende Schaltfläche gedrückt wird. Nach Überprüfung der Erfüllung aller Anforderungen wechselt das Artefakt in den Status Geschlossen und ist nicht mehr änderbar. In dieser Form wird es in MavenCentral hochgeladen. Wenn alles gut ist, kann die Schaltfläche gedrückt werden Release, wobei das Artefakt in das Sonatype-Repository gelangt.
Damit das Artefakt in MavenCentral gelangt, muss dies in der Aufgabe angefordert werden, die wir zu Beginn erstellt haben. Dies muss nur einmal erfolgen, da wir es zum ersten Mal veröffentlichen. Bei den folgenden Veröffentlichungen ist dies nicht erforderlich, alles wird automatisch synchronisiert. Mir wurde die Synchronisierung schnell aktiviert, aber es dauerte etwa 5 Tage, bis das Artefakt in MavenCentral verfügbar wurde.
Das ist alles, wir haben unser Artefakt in MavenCentral veröffentlicht.
Nützliche Links
- Ähnlich , nur die Veröffentlichung über Maven
- Staging Sonatype
- Sonatype, bei dem eine Aufgabe erstellt werden muss
- Repository, in dem alles konfiguriert ist
Quelle: habr.com
