V tem članku želim podrobno obravnavati postopek objave Java artefakta od začetka do konca prek Github Actions v Sonatype Maven Central Repository s pomočjo Gradle.
Ta članek sem se odločil napisati zaradi pomanjkanja normalnega priročnika na enem mestu. Vse informacije sem moral zbirati po delčkih iz različnih virov, ki niso bile povsem aktualne. Kdor je radoveden, je dobrodošel pod kat.
Ustvarjanje repozitorija v Sonatype
Prvi korak je ustvariti repozitorij v Sonatype Maven Central. Za to gremo na , se prijavimo in ustvarimo novo nalogo s prošnjo za ustvaritev repozitorija. Vnesite svoj GroupId projekta, Project URL povezavo na projekt in SCM url povezavo na sistem za nadzor različic, v katerem se projekt nahaja. GroupId tu mora biti v obliki com.example, com.example.domain, com.example.testsupport, lahko pa tudi v obliki povezave do vašega githuba: -> io.github.yourusername. V vsakem primeru boste morali potrditi lastništvo tega domene ali profila. Če ste navedli profil na githubu, vas bodo prosili, da ustvarite javni repozitorij z ustreznim imenom.
Čez nekaj časa po potrditvi bo vaš GroupId ustvarjen in lahko preidemo na naslednji korak, konfiguracijo Gradle.
Konfiguriramo Gradle
Ob trenutnem pisanju članka nisem našel vtičnikov za Gradle, ki bi lahko pomagali pri objavi artefakta. Eden sam vtičnik, ki sem ga našel, pa je avtor opustil nadaljnjo podporo. Zato sem se odločil, da vse naredim sam, saj to ni prevelik izziv.
Prvo, kar je treba ugotoviti, so zahteve Sonatype za objavo. Te so naslednje:
- Zadostovati morajo izvorne kode in JavaDoc, torej morajo biti prisotni
-sources.jarin-javadoc.jardatoteke. Kot je zapisano v dokumentaciji, če ne morete predložiti izvornih kod ali dokumentacije, lahko naredite prazno datoteko-sources.jarili-javadoc.jarz enostavnim README notranjosti, da preidete preverjanje. - Vse datoteke morajo biti podpisane s pomočjo
GPG/PGP, i.ascdatoteka, ki vsebuje podpis, mora biti vključena za vsako datoteko. - Postojanje
pomdatoteke - Pravilne vrednosti
groupId,artifactIdinversion. Različica je lahko poljubna niza in se ne sme končati-SNAPSHOT - Zahtevana je prisotnost
name,opisinurl - Prisutnost informacij o licenci, razvijalcih in sistemu za nadzor različic
To so osnovna pravila, ki jih je treba upoštevati pri objavi. Celotne informacije so na voljo .
Uresničimo te zahteve v 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 'Некоторое описание артефакта'
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 '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 in-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
}
}
}
}Tukaj sonatypeUsername in sonatypePassword переменные, содержащие логин и пароль, созданные при регистрации на .
Таким образом, финальный build.gradle будет выглядеть следующим образом:
Полный код 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.sl'
}
}
}
}
}Želim napomenuti da verziju dobijamo iz promenljive okruženja: System.getenv('RELEASE_VERSION'). Postavićemo je prilikom gradnje i uzeti iz imena taga.
Generisanje PGP ključa
Jedan od zahteva Sonatype-a je potpisivanje svih fajlova putem GPG/PGP ključa. U tu svrhu preuzmite GnuPG alat za svoj operativni sistem.
- Generišemo par ključeva:
gpg --gen-key, unesite korisničko ime, e-mail, kao i postavite lozinku. - Otkrivamo
idnaš ključ komandom:gpg --list-secret-keys --keyid-format short. Id će biti naveden posle kose crte, na primer: rsa2048/9B695056 - Objavljujemo javni ključ na server komandom:
gpg --keyserver [https://keys.openpgp.org](https://keys.openpgp.org/) --send-keys 9B695056 - Eksportujemo tajni ključ na bilo koju lokaciju, biće nam potreban kasnije:
gpg --export-secret-key 9B695056 > D:\gpg\9B695056.gpg
Podešavamo Github Actions
Prelazimo na završnu fazu, podešavamo gradnju i auto publikaciju koristeći Github Actions.
Github Actions – funkcionalnost, ki omogoča avtomatizacijo delovnega toka z izvajanjem celotnega cikla CI/CD. Gradnja, testiranje in uvajanje se lahko sprožijo z različnimi dogodki: push kode, ustvarjanje izdaj ali težav. Ta funkcionalnost je popolnoma brezplačna za javne repozitorije.
V tem razdelku bom pokazal, kako nastaviti gradnjo, push kode in uvajanje v Sonatype repozitorij ob izdaji, pa tudi nastavitev skrivnosti.
Nastavitev skrivnosti
Za samodejno gradnjo in uvajanje bomo potrebovali vrsto tajnih vrednosti, kot so id ključa, geslo, ki smo ga vnesli pri generiranju ključa, sam PGP ključ in prijava/geslo za Sonatype. Te lahko nastavite v posebnem razdelku v nastavitvah repozitorija:

Nastavimo naslednje spremenljivke:
- SONATYPE_USERNAME/SONATYPE_PASSWORD — prijava/geslo, ki smo ga vnesli pri registraciji v Sonatype
- SIGNING_KEYID/SIGNING_PASSWORD — id PGP ključa in geslo, ki je bilo nastavljeno pri generiranju.
Na spremenljivki GPG_KEY_CONTENTS se bom nekoliko podrobneje ustavil. Dejstvo je, da za objavo potrebujemo tajni PGP ključ. Da bi ga vnesel v skrivnosti, sem uporabil in izvedel vrsto dodatnih dejanj.
- Šifrirajmo naš ključ s pomočjo gpg:
gpg --symmetric --cipher-algo AES256 9B695056.gpg, vnesite geslo. To geslo je treba postaviti v spremenljivko: SECRET_PASSPHRASE - Pretvorimo pridobljen šifriran ključ v besedilno obliko s pomočjo base64:
base64 9B695056.gpg.gpg > 9B695056.txt. Vsebino postavimo v spremenljivko: GPG_KEY_CONTENTS.
Nastavite gradnjo pri push kode in ustvarjanju PR
Najprej morate ustvariti mapo v korenu vašega projekta: .github/workflows.
V njej postavite datoteko, na primer, gradle-ci-build.yml s sledečo vsebino:
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}}Ta delovni proces se bo izvedel pri pushu v veje master, dev in testing, prav tako pri ustvarjanju pull requestov.
V razdelku jobs so navedeni koraki, ki jih je treba izvesti ob navedenih dogodkih. V tem primeru bomo gradili na zadnji različici ubuntu, uporabili Java 8 in tako tudi uporabljali vtičnik za Gradle eskatos/gradle-command-action@v1, ki bo z uporabo najnovejše različice graditelja zagnal ukaze, navedene v argumenti. Spremenljivke secrets.SONATYPE_USERNAME in secrets.SONATYPE_PASSWORD to so skrivnosti, ki smo jih prej navedli.
Rezultati gradnje bodo prikazani na zavihku Dejavnosti:

Samodejno nameščanje ob izdaji nove različice
Za samodejno nameščanje bomo ustvarili ločeno datoteko delovnega procesa gradle-ci-publish.yml:
name: publish
on:
push:
tags:
- 'v*'
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Nastavi JDK 8
uses: actions/setup-java@v1
with:
java-version: 8
- name: Pripravi za objavo
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: Objavi z 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}}Datoteka je praktično enaka prejšnji, razen dogodka, pri katerem bo sprožena. V tem primeru je to dogodek za ustvarjanje oznake z imenom, ki se začne na v.
Pred nameščanjem moramo pridobiti PGP ključ iz skrivnosti in ga postaviti v koren projekta, kot tudi dešifrirati. Nato moramo nastaviti posebno okoljsko spremenljivko RELEASE_VERSION na katero se sklicujemo v gradle.build datoteki. Vse to je narejeno v razdelku Pripravi za objavo. Naš ključ dobimo iz spremenljivke GPG_KEY_CONTENTS, ga preoblikujemo v gpg datoteko, nato ga dešifriramo in shranimo v datoteko secret.gpg.
Nato se sklicujemo na posebno spremenljivko GITHUB_REF, iz katere lahko pridobimo različico, ki smo jo navedli ob ustvarjanju oznake. Ta spremenljivka ima v tem primeru vrednost refs/tags/v0.0.2 , od katere odtrgamo prvih 11 znakov, da pridobimo specifično različico. Nato standardno uporabimo ukaze Gradle za objavo: test publish
Preverjanje rezultatov namestitve v Sonatype repozitorij
Po ustvarjanju različice se mora zagnati delovni proces, opisan v prejšnjem razdelku. Za to ustvarimo različico:

pri čemer se mora ime oznake začeti z v. Če po kliku na Objavi različico delovni proces uspešno izvede, lahko vstopimo v da se prepričamo o tem:

Artefakt se je pojavil v Staging repozitoriju. Takoj se prikaže v statusu Open, nato ga je treba ročno prevesti v status Close, tako da pritisnete ustrezno tipko. Po preverjanju izpolnjevanja vseh zahtevkov, artefakt preide v status Close in ni več mogoče spremeniti. V takšni obliki bo prišel v MavenCentral. Če je vse v redu, lahko pritisnete gumb Release, pri čemer artefakt pride v repozitorij Sonatype.
Da artefakt pride v MavenCentral, je treba o tem zaprositi v nalogi, ki smo jo ustvarili na začetku. To je treba storiti samo enkrat, saj objavljamo prvič. V naslednjih primerih tega ne bo treba, vse se bo samodejno sinhroniziralo. Hitro so mi omogočili sinhronizacijo, toda da je artefakt postal dostopen v MavenCentral, je minilo približno 5 dni.
S tem končujemo, objavili smo naš artefakt v MavenCentral.
Koristne poveznice
- Podoben , samo objava prek maven
- Staging Sonatype
- Sonatype, v katerem je potrebno ustvariti nalogo
- repozitorija, kjer je vse to nastavljeno
Izvor: habr.com
