V tomto článku sa podrobne pozriem na proces publikácie Java artefaktu od nuly cez Github Actions do Sonatype Maven Central Repository s využitím build systému Gradle.
Tento článok som sa rozhodol napísať kvôli absencii kvalitného tutoriálu na jednom mieste. Všetky informácie bolo potrebné poskladať z rôznych zdrojov, pričom nie všetky boli aktuálne. Kto má záujem, vitajte v článku.
Vytvorenie repozitára v Sonatype
Prvým krokom je vytvorenie repozitára v Sonatype Maven Central. Na to ideme , registrujeme sa a vytvoríme novú úlohu so žiadosťou o vytvorenie repozitára. Vyplníme svoj GroupId projektu, URL projektu odkaz na projekt a SCM url odkaz na verzionovací systém, v ktorom projekt leží. GroupId tu by mal byť vo formáte com.example, com.example.domain, com.example.testsupport, a tiež môže byť vo forme odkazu na váš github: -> io.github.yourusername. Každopádne, budete musieť potvrdiť vlastníctvo daného domény alebo profilu. Ak ste uviedli profil na github, požiadajú vás o vytvorenie verejného repozitára s potrebným názvom.
Po chvíli po potvrdení bude váš GroupId vytvorený a môžeme prejsť na ďalší krok, konfiguráciu Gradle.
Konfigurácia Gradle
V čase písania článku som nenašiel pluginy pre Gradle, ktoré by mohli pomôcť s publikovaním artefaktu. je jediný plugin, ktorý som našiel, avšak autor sa vzdal ďalšej podpory. Preto som sa rozhodol to urobiť všetko sám, našťastie je to celkom jednoduché.
Prvé, čo treba zistiť, sú požiadavky Sonatype na publikáciu. Tie sú nasledovné:
- Prítomnosť zdrojových kódov a JavaDoc, t.j. musia byť prítomné
-sources.jara-javadoc.jarsúbory. Ako uvádza dokumentácia, ak nie je možné poskytnúť zdrojové kódy alebo dokumentáciu, je možné vytvoriť prázdny súbor-sources.jaralebo-javadoc.jars jednoduchým README vo vnútri, aby ste prešli kontrolou. - Všetky súbory musia byť podpísané pomocou
GPG/PGP, a.ascsúbor obsahujúci podpis musí byť zahrnutý pre každý súbor. - Prítomnosť
pomsúboru - Správne hodnoty
groupId,artifactIdaversion. Verzia môže byť ľubovoľný reťazec a nemôže končiť-SNAPSHOT - Je potrebné prítomnosť
name,descriptionaurl - Prítomnosť informácií o licencii, vývojároch a verziovacom systéme
Toto sú základné pravidlá, ktoré musia byť dodržiavané pri publikovaní. Kompletné informácie sú dostupné .
Implementujeme tieto požiadavky v build.gradle súbore. Na začiatok pridáme všetky potrebné informácie o vývojároch, licenciách, systéme správy verzií a taktiež nastavíme URL, názov a popis projektu. Na tento účel napíšeme jednoduchú metódu:
def customizePom(pom) {
pom.withXml {
def root = asNode()
root.dependencies.removeAll { dep ->
dep.scope == "test"
}
root.children().last() + {
resolveStrategy = DELEGATE_FIRST
description 'Niektorý popis artefaktu'
name 'Názov artefaktu'
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'
}
}
}
}
}Ďalej je potrebné uviesť, aby sa pri zostavovaní generovali -sources.jar a-javadoc.jar súbory. Na to musíme do sekcie java pridať nasledujúce:
java {
withJavadocJar()
withSourcesJar()
}Prejdeme k poslednej požiadavke, nastaveniu GPG/PGP podpisu. Na to pripojíme plugin signing:
plugins {
id 'signing'
}A pridáme sekciu:
signing {
sign publishing.publications
}Nakoniec pridáme sekciu 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
}
}
}
}Tu sonatypeUsername a sonatypePassword premenné, obsahujúce prihlásenie a heslo, vytvorené pri registrácii na .
Takže finálny build.gradle bude vyzerať nasledovne:
Úplný kód 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'
}
}
}
}
}Chcem upozorniť, že verziu získavame z premennej prostredia: System.getenv('RELEASE_VERSION'). Nastavíme ju pri zostavovaní a vezmeme z názvu tagu.
Generovanie PGP kľúča
Jednou z požiadaviek Sonatype je podpis všetkých súborov pomocou GPG/PGP kľúča. Preto ideme a stiahneme nástroj GnuPG pre svoj operačný systém.
- Vygenerujeme pár kľúčov:
gpg --gen-key, zadáme používateľské meno, e-mail a nastavíme heslo. - Zistíme
idnášho kľúča príkazom:gpg --list-secret-keys --keyid-format short. Id bude uvedené za lomítkom, napríklad: rsa2048/9B695056 - Zverejníme verejný kľúč na server príkazu:
gpg --keyserver [https://keys.openpgp.org](https://keys.openpgp.org/) --send-keys 9B695056 - Exportujeme tajný kľúč na náhodné miesto, bude nám potrebný neskôr:
gpg --export-secret-key 9B695056 > D:\gpg\9B695056.gpg
Nastavíme Github Actions
Prejdeme k finálnemu kroku, nastavíme zostavenie a automatickú publikáciu pomocou Github Actions.
Github Actions – funkčnosť, ktorá umožňuje automatizovať pracovný proces a realizovať kompletný cyklus CI/CD. Skladanie, testovanie a nasadenie môžu byť vyvolané rôznymi udalosťami: pushovanie kódu, vytváranie vydania alebo issues. Táto funkcia je úplne zadarmo pre verejné repozitáre.
V tejto časti ukážem, ako nastaviť skladanie, pushovanie kódu a nasadenie do repozitára Sonatype pri vydaní, ako aj nastavenie tajomstiev.
Nastavíme tajomstvá
Pre automatické skladanie a nasadenie budeme potrebovať množstvo tajných hodnôt, ako sú id kľúča, heslo, ktoré sme zadali pri generovaní kľúča, samotný PGP kľúč a prihlasovacie údaje k Sonatype. Môžeme ich nastaviť v špeciálnej sekcii nastavení repozitára:

Nastavujeme nasledujúce premenné:
- SONATYPE_USERNAME/SONATYPE_PASSWORD — prihlasovacie meno/heslo, ktoré sme zadali pri registrácii v Sonatype
- SIGNING_KEYID/SIGNING_PASSWORD — id PGP kľúča a heslo zadané pri generovaní.
Na premennú GPG_KEY_CONTENTS chcem venovať viac pozornosti. Ide o to, že na publikovanie potrebujeme súkromný PGP kľúč. Na to, aby sme ho umiestnili do tajomstiev, som využil a navyše vykonal množstvo krokov.
- Zašifrujeme náš kľúč pomocou gpg:
gpg --symmetric --cipher-algo AES256 9B695056.gpg, zadaním hesla. To by sme mali umiestniť do premennej: SECRET_PASSPHRASE - Prevedieme získaný zašifrovaný kľúč na textovú formu pomocou base64:
base64 9B695056.gpg.gpg > 9B695056.txt. Obsah umiestnime do premennej: GPG_KEY_CONTENTS.
Nastavenie skladania pri pushovaní kódu a vytváraní PR
Pre začiatok musíme vytvoriť priečinok v koreňovom adresári vášho projektu: .github/workflows.
V ňom umiestnite súbor, napríklad gradle-ci-build.yml s nasledujúcim obsahom:
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}}Tento pracovný proces sa bude vykonávať pri pushovaní do vetiev master, dev a testing, rovnako aj pri vytváraní pull requestov.
V sekcii jobs sú uvedené kroky, ktoré musia byť vykonané pri uvedených udalostiach. V tomto prípade budeme skladanie vykonávať na najnovšej verzii ubuntu, použiť Java 8 a využiť plugin pre Gradle eskatos/gradle-command-action@v1, ktorý pomocou poslednej verzie build systému spustí príkazy uvedené v argumentoch. Premenné secrets.SONATYPE_USERNAME a secrets.SONATYPE_PASSWORD sú to tajomstvá, ktoré sme nastavili skôr.
Výsledky buildovania sa zobrazia na karte Actions:

Automatické nasadenie pri vydaní novej verzie
Na automatické nasadenie vytvoríme samostatný súbor pracovného postupu 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ť sa na publikovanie
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: Publikovať pomocou 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}}Súbor je takmer identický s predchádzajúcim s výnimkou udalosti, pri ktorej sa spustí. V tomto prípade je to udalosť vytvorenia tagu s názvom, ktorý začína na v.
Pred nasadením musíme vytiahnuť PGP kľúč zo tajomstiev a umiestniť ho do koreňového adresára projektu, ako aj ho dešifrovať. Potom musíme nastaviť špeciálnu premennú prostredia RELEASE_VERSION , na ktorú sa odvolávame v gradle.build súbore. To všetko je vykonané v sekcii Pripraviť sa na publikovanie. Náš kľúč získavame z premennej GPG_KEY_CONTENTS, prevádzame ho do gpg súboru, potom ho dešifrujeme a umiestnime do súboru secret.gpg.
Potom sa odvolávame na špeciálnu premennú GITHUB_REF, z ktorej môžeme získať verziu, ktorú sme nastavili pri vytvorení tagu. Táto premenná má v tomto prípade hodnotu refs/tags/v0.0.2 , z ktorej odstránime prvých 11 znakov, aby sme získali konkrétnu verziu. Potom štandardne používame príkazy Gradle na publikovanie: test publish
Kontrola výsledkov nasadenia do Sonatype repozitára
Po vytvorení vydania by sa mal spustiť pracovný postup opísaný v predchádzajúcej sekcii. Na to vytvárame vydanie:

pričom názov tagu by mal začínať na v. Ak sa po stlačení tlačidla Publikovať vydanie pracovní postup úspešne vykoná, môžeme sa prihlásiť do aby sme sa o tom presvedčili:

Artifact sa objavil v Staging repozitári. Hneď sa zobrazuje v stave Open, potom ho treba ručne preložiť do stavu Close kliknutím na príslušné tlačidlo. Po overení splnenia všetkých požiadaviek artifact prechádza do stavu Close a nie je už dostupný na zmenu. V tejto podobe sa dostane do MavenCentral. Ak je všetko v poriadku, môžete stlačiť tlačidlo Verzia, pričom artifact sa dostane do repozitára Sonatype.
Aby sa artifact dostal do MavenCentral, je potrebné o to požiadať v úlohe, ktorú sme vytvorili na začiatku. Toto je potrebné urobiť iba raz, keďže publikujeme prvýkrát. Pri nasledujúcich prípadoch to nie je potrebné, všetko sa bude synchronizovať automaticky. Synchronizáciu mi zapli rýchlo, ale aby bol artifact dostupný v MavenCentral, trvalo to približne 5 dní.
Na tomto je všetko, publikovali sme náš artifact v MavenCentral.
Užitočné odkazy
- Podobná , len publikácia cez maven
- Staging Sonatype
- Sonatype, v ktorej je potrebné vytvoriť úlohu
- repozitára, kde je to všetko nastavené
Zdroj: habr.com
