I denne artikkelen Þnsker jeg Ä gÄ gjennom prosessen med Ä publisere en Java-artifakt fra bunnen av via Github Actions til Sonatype Maven Central Repository ved Ä bruke Gradle-byggeren.
Jeg valgte Ä skrive denne artikkelen pÄ grunn av mangel pÄ et godt tutorial pÄ ett sted. All informasjon mÄtte samles bit for bit fra ulike kilder, som ikke alltid var helt oppdaterte. Den som er interessert, er velkommen til Ä lese videre.
Oppretting av depot i Sonatype
FÞrste steg er Ä opprette et depot i Sonatype Maven Central. For Ä gjÞre dette gÄr vi til , registrerer oss og oppretter en ny forespÞrsel om Ä opprette depotet vÄrt. Vi fyller inn vÄr GroupId prosjektet, Prosjektets URL lenke til prosjektet og SCM-url lenke til versjonskontrollsystemet der prosjektet ligger. GroupId her mÄ vÊre i formatet com.example, com.example.domain, com.example.testsupport, og kan ogsÄ vÊre en lenke til din GitHub: -> io.github.yourusername. Uansett mÄ du bekrefte eierskapet til dette domenet eller profilen. Hvis du angav GitHub-profil, blir det bedt om Ä opprette et offentlig depot med det Þnskede navnet.
Etter en tid, etter bekreftelse, vil GroupId bli opprettet, og vi kan gÄ videre til neste steg, konfigurasjon av Gradle.
Konfigurerer Gradle
PĂ„ tidspunktet for skrivingen av artikkelen fant jeg ikke noen plugins for Gradle som kunne hjelpe med publikasjonen av artifakten. den eneste pluginen jeg fant, men forfatteren har trukket seg fra videre stĂžtte. SĂ„ jeg valgte Ă„ gjĂžre alt selv, heldigvis er det ikke for vanskelig.
Det fÞrste som mÄ avklares, er Sonatype's krav til publisering. De er som fÞlger:
- TilstedevÊrelse av kildekoder og JavaDoc, dvs. mÄ vÊre til stede
-sources.jarog-javadoc.jarfiler. Som beskrevet i dokumentasjonen, hvis du ikke kan gi kildekodene eller dokumentasjonen, kan du lage en dummy-sources.jareller-javadoc.jarmed et enkelt README inni, for Ä bestÄ kontrollen. - Alle filer mÄ vÊre signert med
GPG/PGP, og.ascfilen som inneholder signaturen, mÄ inkluderes for hver fil. - TilstedevÊrelsen av
pomfilen - Korrekte verdier for
groupId,artifactIdogversion. Versjonen kan vÊre en vilkÄrlig streng og kan ikke slutte med-SNAPSHOT - Det mÄ vÊre tilstedevÊrelse av
name,beskrivelseogurl - TilstedevĂŠrelse av informasjon om lisenser, utviklere og versjonskontrollsystem
Dette er de grunnleggende reglene som mÄ fÞlges ved publisering. Fullstendig informasjon er tilgjengelig .
Vi implementerer disse kravene i build.gradle I filen. FĂžrst vil vi legge til all nĂždvendig informasjon om utviklerne, lisensen, versjonskontrollsystemet, samt spesifisere URL, navn og beskrivelse av prosjektet. For dette vil vi skrive en enkel metode:
def customizePom(pom) {
pom.withXml {
def root = asNode()
root.dependencies.removeAll { dep ->
dep.scope == "test"
}
root.children().last() + {
resolveStrategy = DELEGATE_FIRST
description 'Noen beskrivelse av artefakt'
name 'Artefaktnavn'
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.no'
}
}
}
}
}Deretter mÄ vi spesifisere at filene blir generert under byggingen. -sources.jar og-javadoc.jar For dette, i seksjonen java mÄ vi legge til fÞlgende:
java {
withJavadocJar()
withSourcesJar()
}La oss gÄ videre til det siste kravet, oppsett av GPG/PGP-signatur. For dette vil vi aktivere pluginnen signing:
plugins {
id 'signing'
}Og vi legger til seksjonen:
signing {
sign publishing.publications
}Til slutt, la oss legge til seksjonen 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 sonatypeUsername og sonatypePassword variablene som inneholder brukernavn og passord, laget ved registrering pÄ .
Dermed er den endelige build.gradle vil se slik ut:
Full koden til 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 'Artifact 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 at vi fÄr versjonen fra miljÞvariabelen: System.getenv('RELEASE_VERSION'). Vi vil angi den under byggingen og ta den fra tag-navnet.
Generering av PGP-nĂžkkel
En av kravene fra Sonatype er at alle filer mÄ signeres med en GPG/PGP-nÞkkel. For dette gÄr vi og laster ned GnuPG-verktÞyet for vÄrt operativsystem.
- Vi genererer et nĂžkkelpar:
gpg --gen-key, skriver inn brukernavn, e-post, og setter et passord. - Vi finner ut
idom nÞkkelen vÄr ved Ä bruke kommandoen:gpg --list-secret-keys --keyid-format short. Id vil bli angitt etter skrÄstreken, for eksempel: rsa2048/9B695056 - Vi publiserer den offentlige nÞkkelen til serveren kommandoen:
gpg --keyserver [https://keys.openpgp.org](https://keys.openpgp.org/) --send-keys 9B695056 - Vi eksporterer den hemmelige nÞkkelen til et vilkÄrlig sted, da vi vil trenge den senere:
gpg --export-secret-key 9B695056 > D:\gpg\9B695056.gpg
Vi konfigurerer Github Actions
La oss gÄ til den avsluttende fasen, hvor vi konfigurerer bygging og automatisk publisering ved hjelp av Github Actions.
Github Actions â en funksjonalitet som gjĂžr det mulig Ă„ automatisere arbeidsflyten ved Ă„ implementere en full CI/CD-syklus. Bygging, testing og distribusjon kan utlĂžses av forskjellige hendelser, som koding, opprettelse av utgivelser eller issues. Denne funksjonaliteten er helt gratis for offentlige repositories.
I denne delen vil jeg vise hvordan du setter opp bygging og koding, samt distribusjon til Sonatype-repoet ved utgivelsen av en release, samt innstillingen av hemmeligheter.
Sett opp hemmeligheter
For automatisk bygging og distribusjon trenger vi en rekke hemmelige verdier, som nĂžkkel-id, passordet vi satte under genereringen av nĂžkkel, selve PGP-nĂžkkelen, samt bruker-/passord for Sonatype. Disse kan settes i en spesialseksjon i repoets innstillinger:

Angi fĂžlgende variabler:
- SONATYPE_USERNAME/SONATYPE_PASSWORD â brukernavn/passord vi oppga ved registrering i Sonatype
- SIGNING_KEYID/SIGNING_PASSWORD â id for PGP-nĂžkkelen og passordet satt ved genereringen.
Jeg vil gjerne stoppe opp ved variabelen GPG_KEY_CONTENTS. Det er slik at vi trenger den private PGP-nĂžkkelen for publisering. For Ă„ lagre den i hemmeligheter, benyttet jeg og i tillegg gjorde jeg en rekke handlinger.
- La oss kryptere nĂžkkelen med gpg:
gpg --symmetric --cipher-algo AES256 9B695056.gpg, ved Ă„ skrive inn passordet. Dette bĂžr plasseres i variabelen: SECRET_PASSPHRASE - La oss konvertere den krypterte nĂžkkelen til tekstformat ved hjelp av base64:
base64 9B695056.gpg.gpg > 9B695056.txt. Innholdet skal plasseres i variabelen: GPG_KEY_CONTENTS.
Innstilling av bygging ved koding og opprettelse av PR
FÞrst mÄ du lage en mappe i roten av prosjektet ditt: .github/workflows.
I den legger du inn en fil, for eksempel, gradle-ci-build.yml med innholdet:
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 det pushes til grenene master, dev og testing, samt nÄr pull-forespÞrselen opprettes.
I seksjonen jobs er stegene angitt som skal utfÞres ved de angitte hendelsene. I dette tilfellet vil vi bygge pÄ den nyeste versjonen av ubuntu, bruke Java 8, samt bruke plugin for Gradle eskatos/gradle-command-action@v1, som ved Ä bruke den nyeste versjonen av byggeverktÞyet vil kjÞre kommandoene som angitt i argumentsVariabler secrets.SONATYPE_USERNAME og secrets.SONATYPE_PASSWORD dette er hemmeligheter vi satte tidligere.
Byggeresultatene vil bli vist i fanen Actions:

Automatisk distribusjon ved utgivelse av ny versjon
For automatisk distribusjon oppretter vi en egen arbeidsflyttingsfil 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 praktisk talt identisk med den forrige, unntatt for hendelsen som utlĂžser den. I dette tilfellet er det hendelsen som oppretter et tag med navn som starter med v.
FÞr distribusjon mÄ vi hente PGP-nÞkkelen fra hemmelighetene og plassere den i prosjektets rot, samt dekryptere den. Videre mÄ vi sette en spesialmiljÞvariabel RELEASE_VERSION som vi refererer til i gradle.build filen. Alt dette gjÞres i delen Prepare to publish. Vi fÄr nÞkkelen vÄr fra variabelen GPG_KEY_CONTENTS, konverterer den til en gpg-fil, deretter dekrypterer vi den og plasserer den i filen secret.gpg.
Deretter refererer vi til en spesialvariabel GITHUB_REF, fra hvilken vi kan hente versjonen vi spesifiserte ved opprettingen av taggen. Denne variabelen har i dette tilfellet verdien refs/tags/v0.0.2 fra hvilken vi kutter de fĂžrste 11 tegnene for Ă„ spesifisere versjonen. Videre bruker vi standard Gradle-kommandoer for publisering: test publish
Sjekk resultatene av distribusjonen i Sonatype-repositoriet
Etter opprettelse av versjonen bĂžr arbeidsflyten beskrevet i forrige del starte. For dette oppretter vi en utgivelse:

hvor taggnavnet mÄ starte med v. NÄr arbeidsflyten har kjÞrt vellykket etter Ä ha klikket pÄ Publiser utgivelse, kan vi gÄ til for Ä bekrefte dette:

Artefakten har dukket opp i Staging-repositoriet. Den vises fÞrst i status Open, deretter mÄ den manuelt endres til status Close ved Ä trykke pÄ den aktuelle knappen. Etter at alle krav er oppfylt, gÄr artefakten til status Close og er ikke lenger tilgjengelig for endringer. I denne formen vil den bli sendt til MavenCentral. Hvis alt er i orden, kan du trykke pÄ knappen Release, og artefakten vil havne i Sonatype-repositoriet.
For at artefakten skal komme til MavenCentral, mÄ vi be om dette i oppgaven vi opprettet i starten. Dette mÄ gjÞres bare én gang, da vi publiserer for fÞrste gang. Ved pÄfÞlgende publiseringer er dette ikke nÞdvendig, alt vil synkroniseres automatisk. De fikk meg raskt i gang med synkroniseringen, 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
- Lik , bare publisering gjennom maven
- Staging Sonatype
- Sonatype, hvor det er nĂždvendig Ă„ opprette en oppgave
- repositoriet, hvor dette er konfigurert
Kilde: habr.com
