Koristimo Gradle i Github Actions za objavljivanje Java projekta u Sonatype Maven Central Repository

U ovom članku želim detaljno razmotriti proces objavljivanja Java artefakta putem Github Actions u Sonatype Maven Central Repository koristeći Gradle.

Ovaj članak sam odlučio napisati zbog nedostatka kvalitetnog tutoriala na jednom mestu. Svaku informaciju bilo je potrebno prikupljati delić po delić iz raznih izvora, pri čemu nisu svi bili posve aktuelni. Kome je zanimljivo, dobrodošli ispod.

Kreiranje repozitorija u Sonatype

Prvi korak je da kreiramo repozitorij u Sonatype Maven Central. Za to idemo ovde, registrujemo se i kreiramo novi zahtev, sa molbom da nam naprave repozitorij. Upisujemo svoj GroupId projekta, Project URL link na projekat i SCM url link na sistem kontrole verzija u kojem se projekat nalazi. GroupId ovde treba biti u obliku com.example, com.example.domain, com.example.testsupport, ali može biti i kao link na vaš GitHub: github.com/yourusername -> io.github.yourusername. U svakom slučaju, potrebno je da potvrdite vlasništvo nad tim domenom ili profilom. Ako ste navedli GitHub profil, zatražiće da kreirate javni repozitorij sa potrebnim imenom.

Nakon nekog vremena, nakon potvrde, vaš GroupId će biti kreiran i možemo preći na sledeći korak, konfiguraciju Gradle-a.

Konfiguriramo Gradle

U trenutku pisanja ovog članka nisam našao plugine za Gradle koji bi mogli pomoći s objavljivanjem artefakta. To jedini plugin koji sam našao, međutim, autor je odustao od daljnje podrške. Zato sam odlučio da sve uradim sam, dobro je da to nije previše teško.

Prvo što treba utvrditi su zahtevi Sonatype za objavljivanje. Oni su sledeći:

  • Postojanje izvornih kodova i JavaDoc, tj. treba da postoje -sources.jar i-javadoc.jar datoteke. Kao što je navedeno u dokumentaciji, ako nije moguće dostaviti izvornik ili dokumentaciju, može se napraviti prazan fajl -sources.jar ili -javadoc.jar s jednostavnom README unutar, kako bi se prošlo provere.
  • Sve datoteke moraju biti potpisane pomoću GPG/PGP, i .asc fajl, koji sadrži potpis, mora biti uključen za svaku datoteku.
  • Prisutnost pom datoteke
  • Ispravne vrednosti groupId, artifactId i version. Verzija može biti proizvoljna niz i ne može da se završava -SNAPSHOT
  • Potrebna je prisutnost ime, opis i url
  • Prisutnost informacija o licenci, programerima i sistemu kontrole verzija

Ovo su osnovna pravila koja moraju biti ispoštovana prilikom objavljivanja. Potpune informacije su dostupne ovdje.

Implementiramo ove zahtjeve u build.gradle datoteci. Za početak ćemo dodati sve potrebne informacije o developerima, licenci, sustavu kontrole verzija, kao i postaviti URL, naziv i opis projekta. U tu svrhu ćemo napisati jednostavnu metodu:

def customizePom(pom) {
    pom.withXml {
        def root = asNode()

        root.dependencies.removeAll { dep ->
            dep.scope == "test"
        }

        root.children().last() + {
            resolveStrategy = DELEGATE_FIRST

            description 'Neki opis artifacta'
            name 'Naziv artifacta'
            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'
                }
            }
        }
    }
}

Nakon toga treba naznačiti da se prilikom kompajliranja generiraju -sources.jar i-javadoc.jar datoteke. U tu svrhu u sekciju java treba dodati sljedeće:

java {
    withJavadocJar()
    withSourcesJar()
}

Prelazimo na posljednji zahtjev, podešavanje GPG/PGP potpisa. Za to ćemo uključiti dodatak signing:

plugins {
    id 'signing'
}

I dodati sekciju:

signing {
    sign publishing.publications
}

Konačno, dodajemo sekciju 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
            }
        }
    }
}

Ovdje sonatypeUsername i sonatypePassword varijable koje sadrže korisničko ime i lozinku kreirane prilikom registracije na sonatype.org.

Tako da je konačni build.gradle trebao bi izgledati ovako:

Potpuni kod 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 'Neki opis artefakta'
            name 'Naziv artefakta'
            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 '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.hr'
                }
            }
        }
    }
}

Želim napomenuti da verziju dobivamo iz varijable okruženja: System.getenv('RELEASE_VERSION'). Postavljat ćemo je tijekom gradnje i uzimati iz imena oznake.

Generiranje PGP ključa

Jedan od zahtjeva Sonatypea je potpisivanje svih datoteka pomoću GPG/PGP ključa. U tu svrhu idemo ovde i preuzimamo GnuPG alat za svoj operativni sustav.

  • Generiramo par ključeva: gpg --gen-key, unosimo korisničko ime, e-mail, kao i postavljamo lozinku.
  • Provjeravamo id naš ključ naredbom: gpg --list-secret-keys --keyid-format short. Id će biti naveden nakon kose crte, na primjer: rsa2048/9B695056
  • Objavljujemo javni ključ na poslužitelj https://keys.openpgp.org komandom: gpg --keyserver [https://keys.openpgp.org](https://keys.openpgp.org/) --send-keys 9B695056
  • Izvozimo tajni ključ na proizvoljno mjesto, trebat će nam kasnije: gpg --export-secret-key 9B695056 > D:\gpg\9B695056.gpg

Podešavamo Github Actions

Prelazimo na završnu fazu, postavljamo izgradnju i automatsku objavu, koristeći Github Actions.
Github Actions – funkcionalnost koja omogućava automatizaciju radnih procesa kroz cjeloviti CI/CD ciklus. Izgradnja, testiranje i implementacija mogu se pokrenuti raznim događajima: slanjem koda, stvaranjem izdanja ili issues. Ova funkcionalnost je potpuno besplatna za javne repozitorije.

U ovom odjeljku ću pokazati kako postaviti izgradnju i slanje koda te implementaciju u Sonatype repozitorij prilikom izdavanja, kao i postavku tajni.

Postavimo tajne

Za automatsku izgradnju i implementaciju trebat će nam niz tajnih vrijednosti, poput ID-a ključa, lozinke koju smo unijeli prilikom generiranja ključa, samog PGP ključa, kao i korisničkog imena/lozinke za Sonatype. Mogu se postaviti u posebnom odjeljku u postavkama repozitorija:

Koristimo Gradle i Github Actions za objavljivanje Java projekta u Sonatype Maven Central Repository

Postavljamo sljedeće varijable:

  • SONATYPE_USERNAME/SONATYPE_PASSWORD – korisničko ime/lozinka koju smo unijeli prilikom registracije na Sonatype
  • SIGNING_KEYID/SIGNING_PASSWORD – ID PGP ključa i lozinka postavljena prilikom generacije.

Želim se više posvetiti varijabli GPG_KEY_CONTENTS. Naime, za objavljivanje nam je potreban privatni PGP ključ. Kako bih ga postavio u tajne, koristio sam upute i dodatno učinio nekoliko koraka.

  • Šifrirajmo naš ključ pomoću gpg: gpg --symmetric --cipher-algo AES256 9B695056.gpg, unosom lozinke. Treba je smjestiti u varijablu: SECRET_PASSPHRASE
  • Pretvorimo dobiveni šifrirani ključ u tekstualni oblik pomoću base64: base64 9B695056.gpg.gpg > 9B695056.txt. Sadržaj smjestimo u varijablu: GPG_KEY_CONTENTS.

Postavljanje izgradnje prilikom slanja koda i stvaranja PR

Za početak, potrebno je stvoriti mapu u korijenu vašeg projekta: .github/workflows.

U njoj postavite datoteku, na primjer, gradle-ci-build.yml s sljedećim sadržajem:

name: build

on:
  push:
    branches:
      - master
      - dev
      - testing
  pull_request:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v1
      - name: Postavi JDK 8
        uses: actions/setup-java@v1
        with:
          java-version: 8

      - name: Izgradi s Gradleom
        uses: eskatos/gradle-command-action@v1
        with:
          gradle-version: current
          arguments: build -PsonatypeUsername=${{secrets.SONATYPE_USERNAME}} -PsonatypePassword=${{secrets.SONATYPE_PASSWORD}}

Ovaj radni proces će se izvoditi prilikom slanja u grane master, dev i testing, također prilikom stvaranja pull zahtjeva.

U odjeljku jobs navedeni su koraci koji trebaju biti izvršeni prilikom zadanih događaja. U ovom slučaju, izgradnju ćemo vršiti na najnovijoj verziji ubuntu, koristiti Java 8, kao i koristiti dodatak za Gradle eskatos/gradle-command-action@v1, koji će koristeći najnoviju verziju graditelja pokrenuti naredbe navedene u argumenti. Varijable tajne.SONATYPE_USERNAME i tajne.SONATYPE_PASSWORD to su tajne koje smo postavili ranije.

Rezultati izrade bit će odraženi na kartici Radnje:

Koristimo Gradle i Github Actions za objavljivanje Java projekta u Sonatype Maven Central Repository

Automatizirano postavljanje pri izdavanju nove verzije

Za automatizirano postavljanje stvorit ćemo zasebnu datoteku radnog toka gradle-ci-publish.yml:

name: publish

on:
  push:
    tags:
      - 'v*'

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v1
      - name: Postavi JDK 8
        uses: actions/setup-java@v1
        with:
          java-version: 8

      - name: Pripremi za objavu
        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 s Gradleom
        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 gotovo identična prethodnoj, osim događaja uz kojeg će se aktivirati. U ovom slučaju, to je događaj stvaranja taga s imenom koje počinje na v.

Prije postavljanja trebamo izvući PGP ključ iz tajni i smjestiti ga u korijensku mapu projekta, kao i dešifrirati ga. Zatim trebamo postaviti posebnu varijablu okruženja RELEASE_VERSION na koju se pozivamo u gradle.build datoteci. Sve je to napravljeno u dijelu Pripremi za objavu. Naš ključ dobivamo iz varijable GPG_KEY_CONTENTS, pretvaramo ga u gpg datoteku, a zatim ga dešifriramo, smještajući u datoteku secret.gpg.

Nakon toga pozivamo posebnu varijablu GITHUB_REF, iz koje možemo izvući verziju koju smo postavili pri stvaranju taga. Ova varijabla u ovom slučaju ima vrijednost refs/tags/v0.0.2 iz koje izrezujemo prvih 11 znakova kako bismo dobili konkretnu verziju. Nakon toga standardno koristimo komande Gradle za objavu: test publish

Provjera rezultata postavljanja u Sonatype repozitorij

Nakon stvaranja izdanja trebao bi se pokrenuti radni proces opisan u prethodnom odlomku. Za to stvaramo izdanje:

Koristimo Gradle i Github Actions za objavljivanje Java projekta u Sonatype Maven Central Repository

pri čemu ime taga mora početi s v. Ako nakon pritiska na Objavi izdanje, radni proces uspješno završi, možemo otići u Sonatype Nexus da bismo se uvjerili u to:

Koristimo Gradle i Github Actions za objavljivanje Java projekta u Sonatype Maven Central Repository

Artefakt je pojavio u Staging repozitoriju. Odmah se pojavljuje u statusu Otvoreno, a zatim ga je potrebno ručno prebaciti u status Zatvoreno klikom na odgovarajući gumb. Nakon provjere ispunjavanja svih zahtjeva, artefakt prelazi u status Zatvoreno i više nije dostupan za promjene. U tom obliku će se poslati u MavenCentral. Ako je sve u redu, možete kliknuti na gumb Objava, pri čemu artefakt ide u repozitorij Sonatype.

Da bi artefakt dospio u MavenCentral, potrebno je to zatražiti u zadatku koji smo kreirali na samom početku. To treba učiniti samo jednom, jer objavljujemo po prvi put. U sljedećim slučajevima to nije potrebno, sve će se automatski sinkronizirati. Brzo su mi aktivirali sinkronizaciju, ali da artefakt postane dostupan u MavenCentralu prošlo je oko 5 dana.

Na tome je gotovo, objavili smo naš artefakt u MavenCentral.

Koristitne veze

  • Slična članak, samo objava preko maven
  • Staging repozitorij Sonatype
  • Jira Sonatype, u kojem je potrebno otvoriti zadatak
  • Primjer repozitorija gdje je sve to podešeno

Izvor: habr.com

Kupite pouzdan hosting za web stranice s DDoS zaštitom, VPS VDS servere 🔥 Kupite pouzdan hosting za web stranice s DDoS zaštitom, VPS VDS servere | ProHoster