I denne artikkelen ønsker jeg å ta en detaljert titt på prosessen med å publisere en Java-artefakt fra bunnen av gjennom Github Actions til Sonatype Maven Central Repository ved å bruke Gradle-byggeren.
Jeg bestemte meg for å skrive denne artikkelen på grunn av mangelen på en vanlig opplæring på ett sted. All informasjon måtte samles inn bit for bit fra ulike kilder, dessuten ikke helt ferske. Hvem bryr seg, velkommen under katt.
Opprette et depot i Sonatype
Det første trinnet er å lage et depot i Sonatype Maven Central. For dette går vi , registrer deg og opprett en ny oppgave, og ber oss om å opprette et depot. Vi kjører i vår Gruppe-ID prosjekt, Prosjekt-URL prosjektkobling og SCM url en lenke til versjonskontrollsystemet som prosjektet ligger i. Gruppe-ID her skal ha formen com.example, com.example.domain, com.example.testsupport, og kan også være i form av en lenke til githuben din: -> io.github.dittbrukernavn. I alle fall må du bekrefte eierskapet til dette domenet eller profilen. Hvis du spesifiserte en github-profil, vil du bli bedt om å opprette et offentlig depot med ønsket navn.
En tid etter bekreftelsen vil gruppe-IDen din bli opprettet, og vi kan gå videre til neste trinn, Gradle-konfigurasjon.
Konfigurerer Gradle
I skrivende stund fant jeg ikke Gradle-plugins som kunne hjelpe med å publisere artefakten. den eneste plugin-modulen jeg fant, men forfatteren nektet å støtte det ytterligere. Derfor bestemte jeg meg for å gjøre alt selv, siden det ikke er så vanskelig å gjøre dette.
Det første du må finne ut er Sonatypes krav til publisering. De er følgende:
- Tilgjengelighet av kildekoder og JavaDoc, dvs. må delta
-sources.jarи-javadoc.jarfiler. Som angitt i dokumentasjonen, hvis det ikke er mulig å gi kildekoder eller dokumentasjon, kan du lage en dummy-sources.jareller-javadoc.jarmed en enkel README inni for å bestå testen. - Alle filer må signeres med
GPG/PGPOg.ascfilen som inneholder signaturen må inkluderes for hver fil. - tilgjengelighet
pomfil - Riktige verdier
groupId,artifactIdиversion. Versjonen kan være en vilkårlig streng og kan ikke slutte med-SNAPSHOT - Tilstedeværelse påkrevd
name,descriptionиurl - Tilstedeværelsen av informasjon om lisensen, utviklerne og versjonskontrollsystemet
Dette er de grunnleggende reglene som må følges ved publisering. Full informasjon tilgjengelig .
Vi implementerer disse kravene i build.gradle fil. Først, la oss legge til all nødvendig informasjon om utviklerne, lisensene, versjonskontrollsystemet, og også angi url, navn og beskrivelse av prosjektet. La oss skrive en enkel metode for dette:
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'
}
}
}
}
}Deretter må du spesifisere det under den genererte monteringen -sources.jar и-javadoc.jar filer. For denne delen java du må legge til følgende:
java {
withJavadocJar()
withSourcesJar()
}La oss gå videre til det siste kravet, å sette opp en GPG/PGP-signatur. For å gjøre dette, koble til plugin signing:
plugins {
id 'signing'
}Og legg til en seksjon:
signing {
sign publishing.publications
}Til slutt, la oss legge til en seksjon 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
}
}
}
}Her sonatype Brukernavn и sonatypePassord variabler som inneholder login og passord opprettet under registrering på .
Dermed finalen build.gradle vil se slik ut:
Full build.gradle-kode
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'
}
}
}
}
}Jeg vil merke meg at vi får versjonen fra miljøvariabelen: System.getenv('RELEASE_VERSION'). Vi vil avsløre det under montering og ta det fra merkenavnet.
Generering av PGP-nøkler
Et av Sonatypes krav er at alle filer signeres med en GPG/PGP-nøkkel. For dette går vi og last ned GnuPG-verktøyet for ditt operativsystem.
- Vi genererer et nøkkelpar:
gpg --gen-key, skriv inn et brukernavn, e-post, og angi også et passord. - Vi finner ut
idvår nøkkel med kommandoen:gpg --list-secret-keys --keyid-format short. ID vil bli spesifisert etter skråstreken, for eksempel: rsa2048/9B695056 - Publiserer den offentlige nøkkelen til serveren kommando:
gpg --keyserver [https://keys.openpgp.org](https://keys.openpgp.org/) --send-keys 9B695056 - Vi eksporterer den hemmelige nøkkelen til et vilkårlig sted, vi vil trenge den i fremtiden:
gpg --export-secret-key 9B695056 > D:\gpg\9B695056.gpg
Sette opp Github Actions
La oss gå videre til det siste stadiet, sette opp byggingen og autopublisere ved hjelp av Github Actions.
Github Actions er en funksjon som lar deg automatisere arbeidsflyten ved å implementere en full CI/CD-syklus. Bygg, test og distribusjon kan utløses av ulike hendelser: kodepush, oppretting av utgivelser eller problemer. Denne funksjonaliteten er helt gratis for offentlige depoter.
I denne delen vil jeg vise deg hvordan du setter opp bygge- og push-kode og distribuerer til Sonatype-depotet ved utgivelse, samt setter opp hemmeligheter.
Vi legger hemmeligheter
For automatisk montering og distribusjon trenger vi en rekke hemmelige verdier, for eksempel nøkkel-ID, passordet som vi skrev inn da vi genererte nøkkelen, selve PGP-nøkkelen og Sonatype-pålogging/passord. Du kan sette dem i en spesiell seksjon i depotinnstillingene:

Vi setter følgende variabler:
- SONATYPE_USERNAME / SONATYPE_PASSWORD - pålogging / passord som vi oppga ved registrering hos Sonatype
- SIGNING_KEYID/SIGNING_PASSWORD — PGP-nøkkel-ID og passord satt under generering.
Jeg vil dvele ved variabelen GPG_KEY_CONTENTS mer detaljert. Faktum er at for publisering trenger vi en privat PGP-nøkkel. For å legge det ut i hemmelighetene, brukte jeg og i tillegg gjort en rekke handlinger.
- La oss kryptere nøkkelen vår med gpg:
gpg --symmetric --cipher-algo AES256 9B695056.gpgved å skrive inn et passord. Den skal plasseres i en variabel: SECRET_PASSPHRASE - La oss oversette den mottatte krypterte nøkkelen til et tekstskjema ved å bruke base64:
base64 9B695056.gpg.gpg > 9B695056.txt. Innholdet vil bli plassert i variabelen: GPG_KEY_CONTENTS.
Bygg oppsett når du trykker kode og lager PR
Først må du opprette en mappe i roten til prosjektet: .github/workflows.
Marker filen i den, for eksempel, gradle-ci-build.yml med følgende innhold:
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}}Denne arbeidsflyten vil bli utført når du skyver til grener master, dev и testing, også når du oppretter pull-forespørsler.
Jobbdelen spesifiserer trinnene som skal utføres basert på de spesifiserte hendelsene. I dette tilfellet bygger vi på den nyeste versjonen. ubuntu, bruk Java 8, og bruk også Gradle-pluginen eskatos/gradle-command-action@v1som, ved å bruke den nyeste versjonen av byggeren, kjører kommandoene spesifisert i arguments. Variabler secrets.SONATYPE_USERNAME и secrets.SONATYPE_PASSWORD dette er hemmelighetene vi spurte om tidligere.
Byggeresultatene gjenspeiles i fanen Handlinger:

Automatisk distribusjon når en ny utgivelse er utgitt
La oss lage en egen arbeidsflytfil for automatisk distribusjon 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}}Filen er nesten identisk med den forrige, bortsett fra hendelsen der den vil bli utløst. I dette tilfellet er dette tilfellet med å lage en tag med et navn som begynner med v.
Før distribusjon må vi trekke ut PGP-nøkkelen fra hemmelighetene og plassere den i roten av prosjektet, samt dekryptere den. Deretter må vi sette en spesiell miljøvariabel RELEASE_VERSION som vi viser til gradle.build fil. Alt dette gjøres i seksjonen Prepare to publish. Vi henter nøkkelen vår fra variabelen GPG_KEY_CONTENTS, oversetter den til en gpg-fil, og dekrypterer den deretter ved å legge den inn i filen secret.gpg.
Deretter går vi til en spesiell variabel GITHUB_REF, hvorfra vi kan hente versjonen som vi anga når vi opprettet taggen. Denne variabelen er relevant i dette tilfellet. refs/tags/v0.0.2 hvorfra vi kuttet av de første 11 tegnene for å få en spesifikk versjon. Deretter bruker vi standard Gradle-kommandoer for publisering: test publish
Kontroll av distribusjonsresultater i Sonatype-depotet
Etter at utgivelsen er opprettet, skal arbeidsflyten beskrevet i forrige avsnitt starte. For å gjøre dette, opprette en utgivelse:

tagnavnet må begynne med v. Hvis arbeidsflyten er fullført etter å ha klikket på Publiser utgivelse, kan vi gå til å sørge for at:

Artefakten dukket opp i Staging-depotet. Den vises umiddelbart i Åpen-status, deretter må den manuelt overføres til Lukk-status ved å trykke på den aktuelle knappen. Etter å ha kontrollert at alle krav er oppfylt, går artefakten inn i Lukk-status og er ikke lenger tilgjengelig for endring. I denne formen vil den havne i MavenCentral. Hvis alt er bra, kan du trykke på knappen Slipp, og artefakten vil ende opp i Sonatype-depotet.
For at artefakten skal komme inn i MavenCentral, må du be om den i oppgaven vi opprettet helt i begynnelsen. Du trenger bare å gjøre dette én gang, så vi publiserer for første gang. I påfølgende tider er dette ikke nødvendig, alt vil bli synkronisert automatisk. De slo raskt på synkronisering for meg, men det tok omtrent 5 dager før artefakten ble tilgjengelig i MavenCentral.
Det er alt, vi har publisert artefakten vår i MavenCentral.
Nyttige lenker
- Lignende , publiser kun via maven
- Iscenesettelse Sonatype
- Sonatype for å lage oppgaven
- repository hvor alt er satt opp
Kilde: www.habr.com
