AnvÀnder Gradle och Github Actions för att publicera Java-projekt till Sonatype Maven Central Repository

I denna artikel vill jag detaljerat gÄ igenom processen för publicering frÄn grunden av en Java-artifact via Github Actions i Sonatype Maven Central Repository med hjÀlp av Gradle.

Jag beslutade mig för att skriva denna artikel pÄ grund av bristen pÄ en ordentlig handledning pÄ ett stÀlle. All information fick jag samla in bit för bit frÄn olika kÀllor, som dessutom inte var helt aktuella. Om nÄgon Àr intresserad, varmt vÀlkommen under kat.

Skapande av repository i Sonatype

Som första steg mÄste vi skapa ett repository i Sonatype Maven Central. För att göra detta gÄr vi till hit, registrerar oss och skapar en ny uppgift, dÀr vi ber om att fÄ ett repository skapat. Vi anger vÄr GroupId projektet, Projekt-URL lÀnken till projektet och SCM-url lÀnken till versionshanteringssystemet dÀr projektet ligger. GroupId hÀr bör vara i formatet com.example, com.example.domain, com.example.testsupport, och kan ocksÄ vara en lÀnk till din Github: github.com/yourusername -> io.github.yourusername. I vilket fall som helst behöver du bekrÀfta Àgande av denna domÀn eller profil. Om du angav din Github-profil kommer de att be dig skapa ett offentligt repository med det önskade namnet.

Efter en tid, efter bekrÀftelse, kommer din GroupId att skapas och vi kan gÄ vidare till nÀsta steg, konfiguration av Gradle.

Konfigurera Gradle

Vid tidpunkten för denna artikels skrivande fann jag inga plugins för Gradle som kunde hjÀlpa till med publiceringen av artifactet. Detta Den enda plugin jag hittade, men författaren har avsagt sig vidare support. DÀrför beslutade jag mig för att göra allt sjÀlv, tack och lov Àr det inte alltför svÄrt.

Det första som behöver klargöras Àr kraven frÄn Sonatype för publicering. De Àr följande:

  • NĂ€rvaro av kĂ€llkoder och JavaDoc, d.v.s. de mĂ„ste finnas -sources.jar och-javadoc.jar filer. Som det anges i dokumentationen, om det inte Ă€r möjligt att tillhandahĂ„lla kĂ€llkoder eller dokumentation, kan man göra en dummy -sources.jar eller -javadoc.jar med en enkel README inuti för att klara av inspektionen.
  • Alla filer mĂ„ste signeras med hjĂ€lp av GPG/PGP, och .asc filen som innehĂ„ller signaturen mĂ„ste inkluderas för varje fil.
  • NĂ€rvaron av pom filen
  • Korrekt vĂ€rden groupId, artifactId och version. Versionen kan vara en godtycklig strĂ€ng och fĂ„r inte sluta med -SNAPSHOT
  • Det mĂ„ste finnas name, description och url
  • NĂ€rvaro av information om licens, utvecklare och versionshanteringssystem

Detta Àr de grundlÀggande regler som mÄste följas vid publicering. FullstÀndig information finns tillgÀnglig hÀr.

Vi genomför dessa krav i build.gradle filen. För att börja lÀgger vi till all nödvÀndig information om utvecklarna, licensen, versionshanteringssystemet, samt stÀller in url, namn och beskrivning av projektet. För detta ska vi skriva en enkel metod:

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

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

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

            description 'NÄgon beskrivning av artefakten'
            name 'Artefaktnamn'
            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.ru'
                }
            }
        }
    }
}

DÀrefter behöver vi ange att filer ska genereras vid byggandet -sources.jar och-javadoc.jar filer. För detta lÀgger vi till följande i sektionen java vi behöver lÀgga till följande:

java {
    withJavadocJar()
    withSourcesJar()
}

LÄt oss gÄ vidare till det sista kravet, konfigurationen av GPG/PGP signaturen. För detta ansluter vi till pluginen signing:

plugins {
    id 'signing'
}

Och lÀgger till sektionen:

signing {
    sign publishing.publications
}

Slutligen lÀgger vi till sektionen 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
            }
        }
    }
}

HÀr sonatypeUsername och sonatypePassword variabler som innehÄller inloggning och lösenord som skapades vid registreringen pÄ sonatype.org.

SÄledes kommer den slutgiltiga build.gradle att se ut pÄ följande sÀtt:

Hela koden 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 'NÄgon beskrivning av artefakten'
            name 'Artefaktnamn'
            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'
                }
            }
        }
    }
}

Jag vill pÄpeka att vi fÄr versionen frÄn miljövariabeln: System.getenv('RELEASE_VERSION'). Vi kommer att stÀlla in den vid byggandet och hÀmta den frÄn taggens namn.

Generering av PGP-nyckel

Ett av kraven frÄn Sonatype Àr att signera alla filer med GPG/PGP-nyckeln. För detta gÄr vi hit och laddar ner GnuPG-verktyget för vÄrt operativsystem.

  • Vi genererar ett nyckelpar: gpg --gen-key, ange anvĂ€ndarnamn, e-post och stĂ€ll Ă€ven in ett lösenord.
  • Vi tar reda pĂ„ id vĂ„r nyckel med kommandot: gpg --list-secret-keys --keyid-format short. Id kommer att anges efter snedstrecket, till exempel: rsa2048/9B695056
  • Publicera den offentliga nyckeln pĂ„ servern https://keys.openpgp.org med kommandot: gpg --keyserver [https://keys.openpgp.org](https://keys.openpgp.org/) --send-keys 9B695056
  • Exportera den hemliga nyckeln till en valfri plats, vi kommer att behöva den senare: gpg --export-secret-key 9B695056 > D:\gpg\9B695056.gpg

Konfigurera Github Actions

LÄt oss gÄ vidare till den avslutande fasen, vi konfigurerar byggandet och automatisk publicering med hjÀlp av Github Actions.
Github Actions – en funktionalitet som möjliggör automatisering av arbetsflödet genom att implementera hela CI/CD-cykeln. Byggande, testning och distribution kan utlösas av olika hĂ€ndelser: kodpush, skapande av releaser eller issues. Denna funktionalitet Ă€r helt gratis för offentliga repositorier.

I det hÀr avsnittet visar jag hur man stÀller in bygg och kodpush samt distribution till Sonatype-repositoriet vid release, samt hur man hanterar hemligheter.

Ange hemligheter

För automatisk bygg och distribution behöver vi en rad hemliga vÀrden, sÄsom nyckel-ID, lösenord som vi angav vid nyckelgenerering, sjÀlva PGP-nyckeln samt anvÀndarnamn/lösenord till Sonatype. Dessa kan definieras i ett sÀrskilt avsnitt i repositoryinstÀllningarna:

AnvÀnder Gradle och Github Actions för att publicera Java-projekt till Sonatype Maven Central Repository

Ange följande variabler:

  • SONATYPE_USERNAME/SONATYPE_PASSWORD – anvĂ€ndarnamn/lösenord som vi angav vid registreringen i Sonatype
  • SIGNING_KEYID/SIGNING_PASSWORD – ID för PGP-nyckeln och lösenordet som stĂ€lldes in vid generering.

Jag vill stanna vid variabeln GPG_KEY_CONTENTS och gÄ in pÄ den lite mer. Problemet Àr att vi behöver den privata PGP-nyckeln för publicering. För att placera den i hemligheterna anvÀnde jag instruktionen och utförde dessutom en rad ÄtgÀrder.

  • Vi krypterar vĂ„r nyckel med hjĂ€lp av gpg: gpg --symmetric --cipher-algo AES256 9B695056.gpg, ange lösenordet. Det bör placeras i variabeln: SECRET_PASSPHRASE
  • ÖversĂ€tt den erhĂ„llna krypterade nyckeln till textformat med hjĂ€lp av base64: base64 9B695056.gpg.gpg > 9B695056.txt. InnehĂ„llet lĂ€ggs i variabeln: GPG_KEY_CONTENTS.

InstÀllning av bygg vid kodpush och skapande av PR

Först behöver du skapa en mapp i rotkatalogen av ditt projekt: .github/workflows.

I den placerar du en fil, till exempel, gradle-ci-build.yml med följande innehÄll:

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}}

Denna arbetsprocess kommer att köras vid kodpush till grenarna master, dev och testing, samt vid skapande av pull requests.

I avsnittet jobs anges stegen som ska utföras vid angivna hÀndelser. I det hÀr fallet kommer vi att bygga pÄ den senaste versionen av ubuntu, anvÀnda Java 8 och Àven anvÀnda pluginet för Gradle eskatos/gradle-command-action@v1, som, med den senaste versionen av byggverktyget, kommer att köra kommandona som angivits i argument. Variabler secrets.SONATYPE_USERNAME och secrets.SONATYPE_PASSWORD det hÀr Àr hemligheter som vi angav tidigare.

Byggresultaten kommer att Äterspeglas i fliken Actions:

AnvÀnder Gradle och Github Actions för att publicera Java-projekt till Sonatype Maven Central Repository

Automatisk distribution vid utgivning av en ny release

För automatisk distribution kommer vi att skapa en separat arbetsflödesfil gradle-ci-publish.yml:

name: publish

on:
  push:
    tags:
      - 'v*'

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

      - name: Förbered för publicering
        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: Publicera med 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}}

Denna fil Àr praktiskt taget identisk med den föregÄende förutom hÀndelsen som den kommer att utlösas av. I detta fall Àr det en hÀndelse av taggskapande med ett namn som börjar med v.

Innan distributionen mÄste vi hÀmta PGP-nyckeln frÄn hemligheterna och placera den i projektets rot samt avkryptera den. DÀrefter behöver vi stÀlla in en speciell miljövariabel RELEASE_VERSION som vi hÀnvisar till i gradle.build filen. Allt detta görs i avsnittet Förbered för publicering. Vi hÀmtar vÄr nyckel frÄn variabeln GPG_KEY_CONTENTS, konverterar den till en gpg-fil, och avkrypterar den och placerar den i filen secret.gpg.

DÀrefter hÀnvisar vi till en speciell variabel GITHUB_REF, frÄn vilken vi kan hÀmta versionen vi angav nÀr vi skapade taggen. Denna variabel har i det hÀr fallet vÀrdet refs/tags/v0.0.2 frÄn vilken vi klipper bort de första 11 tecknen för att fÄ den faktiska versionen. DÀrefter anvÀnder vi standardkommandon för Gradle för publicering: test publish

Kontrollera resultaten av distributionen till Sonatype-repositoriet

Efter att ha skapat en release bör arbetsflödet som beskrivs i föregÄende avsnitt starta. För att göra detta skapar vi en release:

AnvÀnder Gradle och Github Actions för att publicera Java-projekt till Sonatype Maven Central Repository

namnet pÄ taggen mÄste börja med v. Om arbetsflödet lyckas efter att du har klickat pÄ Publicera release, kan vi gÄ till Sonatype Nexus för att kontrollera detta:

AnvÀnder Gradle och Github Actions för att publicera Java-projekt till Sonatype Maven Central Repository

Artefakten har dykt upp i Staging-arkivet. Den visas omedelbart med status Öppen och mĂ„ste sedan manuellt Ă€ndras till status StĂ€ngd genom att trycka pĂ„ motsvarande knapp. Efter att alla krav har verifierats kommer artefakten att övergĂ„ till status StĂ€ngd och kan inte lĂ€ngre Ă€ndras. I den formen kommer den att hamna i MavenCentral. Om allt ser bra ut kan man trycka pĂ„ knappen Release, varvid artefakten hamnar i Sonatype-arkivet.

För att artefakten ska hamna i MavenCentral mÄste man be om detta i uppgiften som vi skapade i början. Detta behöver göras endast en gÄng, eftersom vi publicerar för första gÄngen. Vid senare tillfÀllen behövs detta inte, allt kommer att synkroniseras automatiskt. Jag fick snabbt pÄ plats synkroniseringen, men det tog ungefÀr 5 dagar innan artefakten blev tillgÀnglig i MavenCentral.

Det Àr allt, vi har publicerat vÄr artefakt i MavenCentral.

Nyttiga lÀnkar

  • Liknande artikeln, men endast publicering via maven
  • Staging arkiv Sonatype
  • Jira Sonatype, dĂ€r en uppgift mĂ„ste skapas
  • Exempel arkivet dĂ€r allt detta Ă€r konfigurerat

KĂ€lla: habr.com

Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar đŸ”„ Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar | ProHoster