Vi bruker Gradle og Github Actions for Ă„ publisere Java-prosjekter i Sonatype Maven Central Repository

I denne artikkelen Þnsker jeg Ä gÄ gjennom prosessen med Ä publisere en Java-artifakt fra bunnen av via Github Actions til Sonatype Maven Central Repository ved Ä bruke Gradle-byggeren.

Jeg valgte Ä skrive denne artikkelen pÄ grunn av mangel pÄ et godt tutorial pÄ ett sted. All informasjon mÄtte samles bit for bit fra ulike kilder, som ikke alltid var helt oppdaterte. Den som er interessert, er velkommen til Ä lese videre.

Oppretting av depot i Sonatype

FÞrste steg er Ä opprette et depot i Sonatype Maven Central. For Ä gjÞre dette gÄr vi til her, registrerer oss og oppretter en ny forespÞrsel om Ä opprette depotet vÄrt. Vi fyller inn vÄr GroupId prosjektet, Prosjektets URL lenke til prosjektet og SCM-url lenke til versjonskontrollsystemet der prosjektet ligger. GroupId her mÄ vÊre i formatet com.example, com.example.domain, com.example.testsupport, og kan ogsÄ vÊre en lenke til din GitHub: github.com/yourusername -> io.github.yourusername. Uansett mÄ du bekrefte eierskapet til dette domenet eller profilen. Hvis du angav GitHub-profil, blir det bedt om Ä opprette et offentlig depot med det Þnskede navnet.

Etter en tid, etter bekreftelse, vil GroupId bli opprettet, og vi kan gÄ videre til neste steg, konfigurasjon av Gradle.

Konfigurerer Gradle

PĂ„ tidspunktet for skrivingen av artikkelen fant jeg ikke noen plugins for Gradle som kunne hjelpe med publikasjonen av artifakten. Dette den eneste pluginen jeg fant, men forfatteren har trukket seg fra videre stĂžtte. SĂ„ jeg valgte Ă„ gjĂžre alt selv, heldigvis er det ikke for vanskelig.

Det fÞrste som mÄ avklares, er Sonatype's krav til publisering. De er som fÞlger:

  • TilstedevĂŠrelse av kildekoder og JavaDoc, dvs. mĂ„ vĂŠre til stede -sources.jar og-javadoc.jar filer. Som beskrevet i dokumentasjonen, hvis du ikke kan gi kildekodene eller dokumentasjonen, kan du lage en dummy -sources.jar eller -javadoc.jar med et enkelt README inni, for Ă„ bestĂ„ kontrollen.
  • Alle filer mĂ„ vĂŠre signert med GPG/PGP, og .asc filen som inneholder signaturen, mĂ„ inkluderes for hver fil.
  • TilstedevĂŠrelsen av pom filen
  • Korrekte verdier for groupId, artifactId og version. Versjonen kan vĂŠre en vilkĂ„rlig streng og kan ikke slutte med -SNAPSHOT
  • Det mĂ„ vĂŠre tilstedevĂŠrelse av name, beskrivelse og url
  • TilstedevĂŠrelse av informasjon om lisenser, utviklere og versjonskontrollsystem

Dette er de grunnleggende reglene som mÄ fÞlges ved publisering. Fullstendig informasjon er tilgjengelig her.

Vi implementerer disse kravene i build.gradle I filen. FĂžrst vil vi legge til all nĂždvendig informasjon om utviklerne, lisensen, versjonskontrollsystemet, samt spesifisere URL, navn og beskrivelse av prosjektet. For dette vil vi skrive en enkel metode:

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

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

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

            description 'Noen beskrivelse av artefakt'
            name 'Artefaktnavn'
            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.no'
                }
            }
        }
    }
}

Deretter mÄ vi spesifisere at filene blir generert under byggingen. -sources.jar og-javadoc.jar For dette, i seksjonen java mÄ vi legge til fÞlgende:

java {
    withJavadocJar()
    withSourcesJar()
}

La oss gÄ videre til det siste kravet, oppsett av GPG/PGP-signatur. For dette vil vi aktivere pluginnen signing:

plugins {
    id 'signing'
}

Og vi legger til seksjonen:

signing {
    sign publishing.publications
}

Til slutt, la oss legge til seksjonen 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 sonatypeUsername og sonatypePassword variablene som inneholder brukernavn og passord, laget ved registrering pÄ sonatype.org.

Dermed er den endelige build.gradle vil se slik ut:

Full koden til 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'
                }
            }
        }
    }
}

Jeg vil merke at vi fÄr versjonen fra miljÞvariabelen: System.getenv('RELEASE_VERSION'). Vi vil angi den under byggingen og ta den fra tag-navnet.

Generering av PGP-nĂžkkel

En av kravene fra Sonatype er at alle filer mÄ signeres med en GPG/PGP-nÞkkel. For dette gÄr vi her og laster ned GnuPG-verktÞyet for vÄrt operativsystem.

  • Vi genererer et nĂžkkelpar: gpg --gen-key, skriver inn brukernavn, e-post, og setter et passord.
  • Vi finner ut id om nĂžkkelen vĂ„r ved Ă„ bruke kommandoen: gpg --list-secret-keys --keyid-format short. Id vil bli angitt etter skrĂ„streken, for eksempel: rsa2048/9B695056
  • Vi publiserer den offentlige nĂžkkelen til serveren https://keys.openpgp.org kommandoen: gpg --keyserver [https://keys.openpgp.org](https://keys.openpgp.org/) --send-keys 9B695056
  • Vi eksporterer den hemmelige nĂžkkelen til et vilkĂ„rlig sted, da vi vil trenge den senere: gpg --export-secret-key 9B695056 > D:\gpg\9B695056.gpg

Vi konfigurerer Github Actions

La oss gÄ til den avsluttende fasen, hvor vi konfigurerer bygging og automatisk publisering ved hjelp av Github Actions.
Github Actions – en funksjonalitet som gjĂžr det mulig Ă„ automatisere arbeidsflyten ved Ă„ implementere en full CI/CD-syklus. Bygging, testing og distribusjon kan utlĂžses av forskjellige hendelser, som koding, opprettelse av utgivelser eller issues. Denne funksjonaliteten er helt gratis for offentlige repositories.

I denne delen vil jeg vise hvordan du setter opp bygging og koding, samt distribusjon til Sonatype-repoet ved utgivelsen av en release, samt innstillingen av hemmeligheter.

Sett opp hemmeligheter

For automatisk bygging og distribusjon trenger vi en rekke hemmelige verdier, som nĂžkkel-id, passordet vi satte under genereringen av nĂžkkel, selve PGP-nĂžkkelen, samt bruker-/passord for Sonatype. Disse kan settes i en spesialseksjon i repoets innstillinger:

Vi bruker Gradle og Github Actions for Ă„ publisere Java-prosjekter i Sonatype Maven Central Repository

Angi fĂžlgende variabler:

  • SONATYPE_USERNAME/SONATYPE_PASSWORD – brukernavn/passord vi oppga ved registrering i Sonatype
  • SIGNING_KEYID/SIGNING_PASSWORD – id for PGP-nĂžkkelen og passordet satt ved genereringen.

Jeg vil gjerne stoppe opp ved variabelen GPG_KEY_CONTENTS. Det er slik at vi trenger den private PGP-nĂžkkelen for publisering. For Ă„ lagre den i hemmeligheter, benyttet jeg instruksjonen og i tillegg gjorde jeg en rekke handlinger.

  • La oss kryptere nĂžkkelen med gpg: gpg --symmetric --cipher-algo AES256 9B695056.gpg, ved Ă„ skrive inn passordet. Dette bĂžr plasseres i variabelen: SECRET_PASSPHRASE
  • La oss konvertere den krypterte nĂžkkelen til tekstformat ved hjelp av base64: base64 9B695056.gpg.gpg > 9B695056.txt. Innholdet skal plasseres i variabelen: GPG_KEY_CONTENTS.

Innstilling av bygging ved koding og opprettelse av PR

FÞrst mÄ du lage en mappe i roten av prosjektet ditt: .github/workflows.

I den legger du inn en fil, for eksempel, gradle-ci-build.yml med innholdet:

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 det pushes til grenene master, dev og testing, samt nÄr pull-forespÞrselen opprettes.

I seksjonen jobs er stegene angitt som skal utfÞres ved de angitte hendelsene. I dette tilfellet vil vi bygge pÄ den nyeste versjonen av ubuntu, bruke Java 8, samt bruke plugin for Gradle eskatos/gradle-command-action@v1, som ved Ä bruke den nyeste versjonen av byggeverktÞyet vil kjÞre kommandoene som angitt i argumentsVariabler secrets.SONATYPE_USERNAME og secrets.SONATYPE_PASSWORD dette er hemmeligheter vi satte tidligere.

Byggeresultatene vil bli vist i fanen Actions:

Vi bruker Gradle og Github Actions for Ă„ publisere Java-prosjekter i Sonatype Maven Central Repository

Automatisk distribusjon ved utgivelse av ny versjon

For automatisk distribusjon oppretter vi en egen arbeidsflyttingsfil 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 praktisk talt identisk med den forrige, unntatt for hendelsen som utlĂžser den. I dette tilfellet er det hendelsen som oppretter et tag med navn som starter med v.

FÞr distribusjon mÄ vi hente PGP-nÞkkelen fra hemmelighetene og plassere den i prosjektets rot, samt dekryptere den. Videre mÄ vi sette en spesialmiljÞvariabel RELEASE_VERSION som vi refererer til i gradle.build filen. Alt dette gjÞres i delen Prepare to publish. Vi fÄr nÞkkelen vÄr fra variabelen GPG_KEY_CONTENTS, konverterer den til en gpg-fil, deretter dekrypterer vi den og plasserer den i filen secret.gpg.

Deretter refererer vi til en spesialvariabel GITHUB_REF, fra hvilken vi kan hente versjonen vi spesifiserte ved opprettingen av taggen. Denne variabelen har i dette tilfellet verdien refs/tags/v0.0.2 fra hvilken vi kutter de fĂžrste 11 tegnene for Ă„ spesifisere versjonen. Videre bruker vi standard Gradle-kommandoer for publisering: test publish

Sjekk resultatene av distribusjonen i Sonatype-repositoriet

Etter opprettelse av versjonen bĂžr arbeidsflyten beskrevet i forrige del starte. For dette oppretter vi en utgivelse:

Vi bruker Gradle og Github Actions for Ă„ publisere Java-prosjekter i Sonatype Maven Central Repository

hvor taggnavnet mÄ starte med v. NÄr arbeidsflyten har kjÞrt vellykket etter Ä ha klikket pÄ Publiser utgivelse, kan vi gÄ til Sonatype Nexus for Ä bekrefte dette:

Vi bruker Gradle og Github Actions for Ă„ publisere Java-prosjekter i Sonatype Maven Central Repository

Artefakten har dukket opp i Staging-repositoriet. Den vises fÞrst i status Open, deretter mÄ den manuelt endres til status Close ved Ä trykke pÄ den aktuelle knappen. Etter at alle krav er oppfylt, gÄr artefakten til status Close og er ikke lenger tilgjengelig for endringer. I denne formen vil den bli sendt til MavenCentral. Hvis alt er i orden, kan du trykke pÄ knappen Release, og artefakten vil havne i Sonatype-repositoriet.

For at artefakten skal komme til MavenCentral, mÄ vi be om dette i oppgaven vi opprettet i starten. Dette mÄ gjÞres bare én gang, da vi publiserer for fÞrste gang. Ved pÄfÞlgende publiseringer er dette ikke nÞdvendig, alt vil synkroniseres automatisk. De fikk meg raskt i gang med synkroniseringen, 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

  • Lik article, bare publisering gjennom maven
  • Staging lageret Sonatype
  • Jira Sonatype, hvor det er nĂždvendig Ă„ opprette en oppgave
  • Eksempel repositoriet, hvor dette er konfigurert

Kilde: habr.com

KjĂžp pĂ„litelig hosting for nettsteder med DDoS-beskyttelse, VPS VDS-servere đŸ”„ KjĂžp pĂ„litelig hosting for nettsteder med DDoS-beskyttelse, VPS VDS-servere | ProHoster