Bruke Gradle og Github Actions for å publisere Java Project til Sonatype Maven Central Repository

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 her, 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: github.com/dittbrukernavn -> 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 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.jar filer. Som angitt i dokumentasjonen, hvis det ikke er mulig å gi kildekoder eller dokumentasjon, kan du lage en dummy -sources.jar eller -javadoc.jar med en enkel README inni for å bestå testen.
  • Alle filer må signeres med GPG/PGPOg .asc filen som inneholder signaturen må inkluderes for hver fil.
  • tilgjengelighet pom fil
  • 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 her.

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 protected]'
                }
            }
        }
    }
}

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å sonatype.org.

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 protected]'
                }
            }
        }
    }
}

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 her 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 id vå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 https://keys.openpgp.org 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:

Bruke Gradle og Github Actions for å publisere Java Project til Sonatype Maven Central Repository

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 bruksanvisning 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.

Jobber-delen spesifiserer trinnene som skal utføres på de angitte hendelsene. I dette tilfellet vil vi bygge på den nyeste versjonen av ubuntu, bruke Java 8, og også bruke plugin for Gradle 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:

Bruke Gradle og Github Actions for å publisere Java Project til Sonatype Maven Central Repository

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:

Bruke Gradle og Github Actions for å publisere Java Project til Sonatype Maven Central Repository

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

Bruke Gradle og Github Actions for å publisere Java Project til Sonatype Maven Central Repository

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

Kilde: www.habr.com