Brug af Gradle og Github Actions til at publicere Java Project til Sonatype Maven Central Repository

I denne artikel vil jeg tage et detaljeret kig på processen med at udgive en Java-artefakt fra bunden gennem Github Actions til Sonatype Maven Central Repository ved hjælp af Gradle-builderen.

Jeg besluttede at skrive denne artikel på grund af manglen på en normal tutorial på ét sted. Alle oplysninger skulle indsamles stykke for stykke fra forskellige kilder, i øvrigt ikke helt friske. Hvem bekymrer sig, velkommen under kat.

Oprettelse af et lager i Sonatype

Det første trin er at oprette et depot i Sonatype Maven Central. For dette går vi her, registrer og opret en ny opgave, og beder os om at oprette et lager. Vi kører i vores GroupId projekt, Projekt URL projekt link og SCM url et link til det versionskontrolsystem, som projektet er placeret i. GroupId her skal have formen com.example, com.example.domain, com.example.testsupport, og kan også være i form af et link til din github: github.com/ditbrugernavn -> io.github.ditbrugernavn. Under alle omstændigheder skal du bekræfte ejerskabet af dette domæne eller denne profil. Hvis du har angivet en github-profil, bliver du bedt om at oprette et offentligt lager med det ønskede navn.

Nogen tid efter bekræftelsen vil dit GroupId blive oprettet, og vi kan gå videre til næste trin, Gradle-konfiguration.

Konfigurerer Gradle

I skrivende stund fandt jeg ikke Gradle-plugins, der kunne hjælpe med at udgive artefakten. Det det eneste plugin jeg fandt, men forfatteren nægtede at støtte det yderligere. Derfor besluttede jeg at gøre alt selv, da det ikke er for svært at gøre dette.

Den første ting at finde ud af er Sonatypes krav til udgivelse. De er følgende:

  • Tilgængelighed af kildekoder og JavaDoc, dvs. skal deltage -sources.jar и-javadoc.jar filer. Som angivet i dokumentationen, hvis det ikke er muligt at levere kildekoder eller dokumentation, kan du lave en dummy -sources.jar eller -javadoc.jar med en simpel README indeni for at bestå testen.
  • Alle filer skal signeres med GPG/PGPOg .asc filen med signaturen skal inkluderes for hver fil.
  • tilgængelighed pom fil
  • Korrekte værdier groupId, artifactId и version. Versionen kan være en vilkårlig streng og kan ikke slutte med -SNAPSHOT
  • Tilstedeværelse påkrævet name, description и url
  • Tilstedeværelsen af ​​oplysninger om licensen, udviklerne og versionskontrolsystemet

Det er de grundlæggende regler, der skal følges ved udgivelse. Fuld information tilgængelig her.

Vi implementerer disse krav i build.gradle fil. Lad os først tilføje alle de nødvendige oplysninger om udviklerne, licenserne, versionskontrolsystemet og også indstille url, navn og beskrivelse af projektet. Lad os skrive en simpel metode til 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]'
                }
            }
        }
    }
}

Dernæst skal du angive det under den genererede samling -sources.jar и-javadoc.jar filer. Til dette afsnit java du skal tilføje følgende:

java {
    withJavadocJar()
    withSourcesJar()
}

Lad os gå videre til det sidste krav, opsætning af en GPG/PGP-signatur. For at gøre dette skal du tilslutte plugin'et signing:

plugins {
    id 'signing'
}

Og tilføj et afsnit:

signing {
    sign publishing.publications
}

Lad os endelig tilføje et afsnit 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 sonatypeBrugernavn и sonatypePassword variabler, der indeholder login og adgangskode oprettet under registrering på sonatype.org.

Altså finalen build.gradle vil se sådan ud:

Fuld 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 bemærke, at vi får versionen fra miljøvariablen: System.getenv('RELEASE_VERSION'). Vi vil blotlægge det under montering og tage det fra tagnavnet.

Generering af PGP-nøgler

Et af Sonatypes krav er, at alle filer skal signeres med en GPG/PGP-nøgle. For dette går vi her og download GnuPG-værktøjet til dit operativsystem.

  • Vi genererer et nøglepar: gpg --gen-key, indtast et brugernavn, e-mail, og indstil også en adgangskode.
  • Vi finder ud af det id vores nøgle med kommandoen: gpg --list-secret-keys --keyid-format short. Id vil blive angivet efter skråstreg, for eksempel: rsa2048/9B695056
  • Udgivelse af den offentlige nøgle til serveren https://keys.openpgp.org med kommandoen: gpg --keyserver [https://keys.openpgp.org](https://keys.openpgp.org/) --send-keys 9B695056
  • Vi eksporterer den hemmelige nøgle til et vilkårligt sted, vi får brug for den i fremtiden: gpg --export-secret-key 9B695056 > D:\gpg\9B695056.gpg

Opsætning af Github Actions

Lad os gå videre til den sidste fase, opsætte build og auto-publicere ved hjælp af Github Actions.
Github Actions er en funktion, der giver dig mulighed for at automatisere arbejdsgangen ved at implementere en fuld CI/CD-cyklus. Byg, test og implementering kan udløses af forskellige hændelser: kode-push, oprettelse af udgivelser eller problemer. Denne funktionalitet er helt gratis for offentlige arkiver.

I dette afsnit viser jeg dig, hvordan du opsætter build- og push-kode og implementerer til Sonatype-lageret ved frigivelse, samt opsætter hemmeligheder.

Vi sætter hemmeligheder

Til automatisk samling og implementering har vi brug for en række hemmelige værdier, såsom nøgle-id, adgangskoden, som vi indtastede, da vi genererede nøglen, selve PGP-nøglen og Sonatype-login/adgangskode. Du kan indstille dem i en særlig sektion i lagerindstillingerne:

Brug af Gradle og Github Actions til at publicere Java Project til Sonatype Maven Central Repository

Vi indstiller følgende variable:

  • SONATYPE_USERNAME / SONATYPE_PASSWORD - login / adgangskode, som vi indtastede ved registrering hos Sonatype
  • SIGNING_KEYID/SIGNING_PASSWORD — PGP-nøgle-id og adgangskode indstillet under generering.

Jeg vil dvæle ved variablen GPG_KEY_CONTENTS mere detaljeret. Faktum er, at vi har brug for en privat PGP-nøgle til offentliggørelse. For at poste det i hemmelighederne brugte jeg instruktioner og derudover lavet en række handlinger.

  • Lad os kryptere vores nøgle med gpg: gpg --symmetric --cipher-algo AES256 9B695056.gpgved at indtaste en adgangskode. Det skal placeres i en variabel: SECRET_PASSPHRASE
  • Lad os oversætte den modtagne krypterede nøgle til en tekstform ved hjælp af base64: base64 9B695056.gpg.gpg > 9B695056.txt. Indholdet vil blive placeret i variablen: GPG_KEY_CONTENTS.

Byg setup, når du trykker kode og skaber PR

Først skal du oprette en mappe i roden af ​​dit projekt: .github/workflows.

I den skal du markere filen, f.eks. gradle-ci-build.yml med følgende indhold:

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 arbejdsgang vil blive udført, når der trykkes til filialer master, dev и testing, også når du opretter pull-anmodninger.

Jobafsnittet specificerer de trin, der skal udføres på de angivne hændelser. I dette tilfælde vil vi bygge på den nyeste version af ubuntu, bruge Java 8 og også bruge pluginnet til Gradle eskatos/gradle-command-action@v1som ved at bruge den seneste version af builderen kører de kommandoer, der er angivet i arguments. Variabler secrets.SONATYPE_USERNAME и secrets.SONATYPE_PASSWORD det er de hemmeligheder, vi spurgte om tidligere.

Byggeresultaterne vil blive afspejlet på fanen Handlinger:

Brug af Gradle og Github Actions til at publicere Java Project til Sonatype Maven Central Repository

Implementer automatisk, når en ny udgivelse frigives

Lad os oprette en separat workflow-fil til autodeploy 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 næsten identisk med den forrige, bortset fra den hændelse, hvor den vil blive udløst. I dette tilfælde er dette tilfældet med oprettelse af et tag med et navn, der starter med v.

Før implementering skal vi udtrække PGP-nøglen fra hemmelighederne og placere den i roden af ​​projektet, samt dekryptere den. Dernæst skal vi indstille en speciel miljøvariabel RELEASE_VERSION som vi henviser til gradle.build fil. Alt dette gøres i afsnittet Prepare to publish. Vi henter vores nøgle fra variabelen GPG_KEY_CONTENTS, oversætter den til en gpg-fil og dekrypterer den derefter ved at lægge den i filen secret.gpg.

Dernæst vender vi os til en speciel variabel GITHUB_REF, hvorfra vi kan få den version, som vi indstillede ved oprettelse af tagget. Denne variabel er relevant i dette tilfælde. refs/tags/v0.0.2 hvorfra vi afskærer de første 11 tegn for at få en bestemt version. Dernæst bruger vi standard Gradle-kommandoer til udgivelse: test publish

Kontrol af implementeringsresultater i Sonatype-lageret

Når udgivelsen er oprettet, bør arbejdsgangen beskrevet i det foregående afsnit starte. For at gøre dette skal du oprette en udgivelse:

Brug af Gradle og Github Actions til at publicere Java Project til Sonatype Maven Central Repository

tagnavnet skal starte med v. Hvis workflowet er fuldført efter at have klikket på Udgiv udgivelse, kan vi gå til Sonatype Nexus for at være sikker:

Brug af Gradle og Github Actions til at publicere Java Project til Sonatype Maven Central Repository

Artefakten dukkede op i Staging-lageret. Den vises med det samme i Åbn-status, derefter skal den manuelt overføres til Luk-status ved at trykke på den relevante knap. Efter at have kontrolleret, at alle krav er opfyldt, går artefakten i Luk-status og er ikke længere tilgængelig for ændring. I denne form ender den i MavenCentral. Hvis alt er i orden, kan du trykke på knappen Slip, og artefakten ender i Sonatype-depotet.

For at artefakten kan komme ind i MavenCentral, skal du bede om den i opgaven, som vi lavede helt i begyndelsen. Du behøver kun at gøre dette én gang, så vi udgiver for første gang. I efterfølgende tider er dette ikke påkrævet, alt vil blive synkroniseret automatisk. De aktiverede hurtigt synkronisering for mig, men det tog omkring 5 dage for artefakten at blive tilgængelig i MavenCentral.

Det er alt, vi har offentliggjort vores artefakt i MavenCentral.

Nyttige links

  • Lignende artiklen, udgiv kun via maven
  • Iscenesættelse depot Sonatype
  • Jira Sonatype, hvor opgaven skal oprettes
  • Eksempel repository, hvor det hele er sat op

Kilde: www.habr.com