ProHoster > blog > amministrazione > Utilizzo delle azioni Gradle e Github per pubblicare il progetto Java nel repository centrale di Sonatype Maven
Utilizzo delle azioni Gradle e Github per pubblicare il progetto Java nel repository centrale di Sonatype Maven
In questo articolo, voglio dare un'occhiata più da vicino al processo di pubblicazione di un artefatto Java da zero tramite Github Actions nel Sonatype Maven Central Repository utilizzando il builder Gradle.
Ho deciso di scrivere questo articolo a causa della mancanza di un normale tutorial in un unico posto. Tutte le informazioni dovevano essere raccolte pezzo per pezzo da varie fonti, per di più non del tutto fresche. Chi se ne frega, benvenuto sotto cat.
Creazione di un repository in Sonatype
Il primo passo è creare un repository in Sonatype Maven Central. Per questo andiamo qui, registrati e crea una nuova attività, chiedendoci di creare un repository. Guidiamo nel nostro ID gruppo del progetto, URL del progetto collegamento al progetto e URL SCM un collegamento al sistema di controllo della versione in cui si trova il progetto. ID gruppo qui dovrebbe essere nella forma com.example, com.example.domain, com.example.testsupport e può anche essere nella forma di un collegamento al tuo github: github.com/tuonomeutente -> io.github.tuonomeutente. In ogni caso, dovrai verificare la proprietà di questo dominio o profilo. Se hai specificato un profilo github, ti verrà chiesto di creare un repository pubblico con il nome desiderato.
Qualche tempo dopo la conferma, il tuo GroupId verrà creato e potremo passare al passaggio successivo, la configurazione di Gradle.
Configurazione di Gradle
Al momento in cui scrivo, non ho trovato plugin Gradle che potessero aiutare con la pubblicazione dell'artefatto. Essa l'unico plugin che ho trovato, tuttavia, l'autore si è rifiutato di supportarlo ulteriormente. Pertanto, ho deciso di fare tutto da solo, poiché non è troppo difficile farlo.
La prima cosa da capire sono i requisiti di Sonatype per la pubblicazione. Sono i seguenti:
Disponibilità di codici sorgente e JavaDoc, ie. deve frequentare -sources.jar и-javadoc.jar File. Come indicato nella documentazione, se non è possibile fornire codici sorgente o documentazione, è possibile creare un manichino -sources.jar o -javadoc.jar con un semplice README all'interno per superare il test.
Tutti i file devono essere firmati con GPG/PGPE .asc per ogni file deve essere incluso il file contenente la firma.
disponibilità pom файла
Valori corretti groupId, artifactId и version. La versione può essere una stringa arbitraria e non può terminare con -SNAPSHOT
Presenza richiesta name, description и url
La presenza di informazioni sulla licenza, gli sviluppatori e il sistema di controllo della versione
Queste sono le regole di base che devono essere seguite durante la pubblicazione. Informazioni complete disponibili qui.
Implementiamo questi requisiti in build.gradle file. Innanzitutto, aggiungiamo tutte le informazioni necessarie su sviluppatori, licenze, sistema di controllo della versione e impostiamo anche l'URL, il nome e la descrizione del progetto. Scriviamo un metodo semplice per questo:
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]'
}
}
}
}
}
Successivamente, è necessario specificarlo durante l'assembly generato -sources.jar и-javadoc.jar File. Per questa sezione java è necessario aggiungere quanto segue:
java {
withJavadocJar()
withSourcesJar()
}
Passiamo all'ultimo requisito, impostare una firma GPG/PGP. Per fare ciò, collega il plugin signing:
plugins {
id 'signing'
}
E aggiungi una sezione:
signing {
sign publishing.publications
}
Infine, aggiungiamo una sezione 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
}
}
}
}
Qui sonatypeNomeutente и sonatypePassword variabili contenenti il login e la password creati durante la registrazione su sonatype.org.
Così la finale build.gradle sarà simile a questo:
Codice build.gradle completo
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]'
}
}
}
}
}
Voglio notare che otteniamo la versione dalla variabile d'ambiente: System.getenv('RELEASE_VERSION'). Lo esporremo durante l'assemblaggio e lo prenderemo dal nome del tag.
Generazione di chiavi PGP
Uno dei requisiti di Sonatype è che tutti i file siano firmati con una chiave GPG/PGP. Per questo andiamo qui e scarica l'utility GnuPG per il tuo sistema operativo.
Generiamo una coppia di chiavi: gpg --gen-key, inserisci un nome utente, un'e-mail e imposta anche una password.
Lo scopriamo id la nostra chiave con il comando: gpg --list-secret-keys --keyid-format short. L'ID verrà specificato dopo la barra, ad esempio: rsa2048/9B695056
Pubblicazione della chiave pubblica sul server https://keys.openpgp.org per comando: gpg --keyserver [https://keys.openpgp.org](https://keys.openpgp.org/) --send-keys 9B695056
Esportiamo la chiave segreta in un luogo arbitrario, ne avremo bisogno in futuro: gpg --export-secret-key 9B695056 > D:\gpg\9B695056.gpg
Configurazione delle azioni Github
Passiamo alla fase finale, impostiamo la build e pubblichiamo automaticamente utilizzando Github Actions.
Github Actions è una funzionalità che consente di automatizzare il flusso di lavoro implementando un ciclo CI/CD completo. La compilazione, il test e la distribuzione possono essere attivati da vari eventi: push del codice, creazione della versione o problemi. Questa funzionalità è assolutamente gratuita per i repository pubblici.
In questa sezione, ti mostrerò come configurare il codice di compilazione e push e distribuirlo nel repository Sonatype al momento del rilascio, oltre a impostare i segreti.
Stabiliamo segreti
Per l'assemblaggio e la distribuzione automatici, abbiamo bisogno di un numero di valori segreti, come l'id della chiave, la password che abbiamo inserito durante la generazione della chiave, la chiave PGP stessa e il login/password Sonatype. Puoi impostarli in una sezione speciale nelle impostazioni del repository:
Impostiamo le seguenti variabili:
SONATYPE_USERNAME / SONATYPE_PASSWORD - login / password che abbiamo inserito durante la registrazione con Sonatype
SIGNING_KEYID/SIGNING_PASSWORD — ID chiave PGP e password impostati durante la generazione.
Voglio soffermarmi sulla variabile GPG_KEY_CONTENTS in modo più dettagliato. Il fatto è che per la pubblicazione abbiamo bisogno di una chiave PGP privata. Per pubblicarlo nei segreti, ho usato istruzione e inoltre ha fatto una serie di azioni.
Crittografiamo la nostra chiave con gpg: gpg --symmetric --cipher-algo AES256 9B695056.gpginserendo una password. Dovrebbe essere inserito in una variabile: SECRET_PASSPHRASE
Traduciamo la chiave crittografata ricevuta in un modulo di testo utilizzando base64: base64 9B695056.gpg.gpg > 9B695056.txt. Il contenuto verrà inserito nella variabile: GPG_KEY_CONTENTS.
Crea configurazione durante l'inserimento del codice e la creazione di PR
Per prima cosa devi creare una cartella nella root del tuo progetto: .github/workflows.
In esso, contrassegna il file, ad esempio, gradle-ci-build.yml con il seguente contenuto:
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}}
Questo flusso di lavoro verrà eseguito durante il push ai rami master, dev и testing, anche durante la creazione di richieste pull.
La sezione lavori specifica i passaggi da eseguire sugli eventi specificati. In questo caso, costruiremo sull'ultima versione di Ubuntu, utilizzeremo Java 8 e utilizzeremo anche il plug-in per Gradle eskatos/gradle-command-action@v1che, utilizzando l'ultima versione del builder, eseguirà i comandi specificati in arguments. Variabili secrets.SONATYPE_USERNAME и secrets.SONATYPE_PASSWORD questi sono i segreti che abbiamo chiesto prima.
I risultati della compilazione si rifletteranno nella scheda Azioni:
Distribuzione automatica quando viene rilasciata una nuova versione
Creiamo un file di flusso di lavoro separato per la distribuzione automatica 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}}
Il file è quasi identico al precedente, ad eccezione dell'evento in cui verrà attivato. In questo caso, questo è l'evento di creazione di un tag con un nome che inizia con v.
Prima della distribuzione, dobbiamo estrarre la chiave PGP dai segreti e posizionarla nella radice del progetto, oltre a decrittografarla. Successivamente, dobbiamo impostare una variabile d'ambiente speciale RELEASE_VERSION a cui facciamo riferimento gradle.build file. Tutto questo viene fatto nella sezione Prepare to publish. Otteniamo la nostra chiave dalla variabile GPG_KEY_CONTENTS, la traduciamo in un file gpg, quindi la decodifichiamo inserendola nel file secret.gpg.
Successivamente, passiamo a una variabile speciale GITHUB_REF, da cui possiamo ottenere la versione che abbiamo impostato durante la creazione del tag. Questa variabile è rilevante in questo caso. refs/tags/v0.0.2 da cui abbiamo tagliato i primi 11 caratteri per ottenere una versione specifica. Successivamente, usiamo i comandi Gradle standard per la pubblicazione: test publish
Controllo dei risultati della distribuzione nel repository Sonatype
Una volta creata la versione, dovrebbe iniziare il flusso di lavoro descritto nella sezione precedente. Per fare ciò, crea una versione:
il nome del tag deve iniziare con v. Se, dopo aver fatto clic su Pubblica versione, il flusso di lavoro viene completato correttamente, possiamo passare a Nesso sonatipico assicurarsi:
L'artefatto è apparso nel repository Staging. Appare subito nello stato Aperto, poi deve essere trasferito manualmente nello stato Chiudi premendo l'apposito pulsante. Dopo aver verificato che tutti i requisiti siano soddisfatti, l'artefatto passa allo stato Chiudi e non è più disponibile per la modifica. In questa forma, finirà in MavenCentral. Se tutto va bene, puoi premere il pulsante Rilasciaree l'artefatto finirà nel repository Sonatype.
Affinché l'artefatto entri in MavenCentral, devi richiederlo nell'attività che abbiamo creato all'inizio. Devi farlo solo una volta, quindi pubblichiamo per la prima volta. In tempi successivi, questo non è richiesto, tutto verrà sincronizzato automaticamente. Hanno attivato rapidamente la sincronizzazione per me, ma ci sono voluti circa 5 giorni prima che l'artefatto diventasse disponibile in MavenCentral.
Questo è tutto, abbiamo pubblicato il nostro artefatto in MavenCentral.