Vi bruger Gradle og Github Actions til at offentliggøre Java-projektet i Sonatype Maven Central Repository

I denne artikel vil jeg detaljeret gennemgå processen med at offentliggøre en Java-artefakt fra bunden via Github Actions til Sonatype Maven Central Repository ved hjælp af Gradle buildværktøjet.

Jeg besluttede at skrive denne artikel på grund af manglen på et ordentligt tutorial samlet ét sted. Al information måtte samles på kryds og tværs fra forskellige kilder, som ikke var helt opdaterede. Interessede er velkomne til at læse videre.

Oprettelse af et repository i Sonatype

Det første skridt er at oprette et repository i Sonatype Maven Central. For at gøre dette går vi til herhen, registrerer os og opretter en ny opgave med anmodning om at oprette et repository for os. Vi indtaster vores GroupId for projektet, Projekt URL link til projektet og SCM url link til versionskontrolsystemet, hvor projektet findes. GroupId her bør være af formen com.example, com.example.domain, com.example.testsupport, eller det kan også være et link til din GitHub: github.com/yourusername -> io.github.yourusername. Under alle omstændigheder vil du skulle bekræfte ejerskabet af dette domæne eller profil. Hvis du angav en GitHub-profil, vil de anmode om at oprette et offentligt repository med det ønskede navn.

Efter et stykke tid efter bekræftelsen vil din GroupId blive oprettet, og vi kan gå videre til næste trin, konfiguration af Gradle.

Konfigurerer Gradle

På tidspunktet for skrivningen af denne artikel kunne jeg ikke finde plugins til Gradle, der kunne hjælpe med offentliggørelsen af artefakten. Dette det eneste plugin, jeg fandt, men forfatteren har opgivet dets videre support. Derfor besluttede jeg at klare det hele selv, da det ikke er alt for besværligt.

Det første, der skal afklares, er Sonatype's krav til offentliggørelse. De er som følger:

  • Tilstedeværelsen af kildekoder og JavaDoc, dvs. der skal være -sources.jar og-javadoc.jar filer. Som nævnt i dokumentationen, hvis det ikke er muligt at levere kildekoder eller dokumentation, kan man lave en tom fil -sources.jar eller -javadoc.jar c med et simpelt README indeni for at bestå kontrol.
  • Alle filer skal være underskrevet med hjælp af GPG/PGP, og .asc filen, der indeholder underskriften, skal inkluderes for hver fil.
  • Tilstedeværelsen af pom filen
  • Korrekte værdier groupId, artifactId og version. Versionen kan være en vilkårlig streng og må ikke slutte med -SNAPSHOT
  • Det er nødvendigt at have name, description og url
  • Tilstedeværelsen af oplysninger om licens, udviklere og versionskontrolsystem

Dette er de grundlæggende regler, der skal overholdes ved offentliggørelse. Fulde oplysninger er tilgængelige her.

Implementerer disse krav i build.gradle filen. For at komme i gang, lad os tilføje alle nødvendige oplysninger om udviklerne, licensen, versionskontrolsystemet, samt angive URL, navn og beskrivelse af projektet. For dette skal vi skrive en simpel metode:

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

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

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

            description 'Nogle beskrivelser af artefakten'
            name 'Artefakt navn'
            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'
                }
            }
        }
    }
}

Dernæst skal vi angive, at der skal genereres -sources.jar og-javadoc.jar filer under bygningen. For dette i sektionen java skal der tilføjes følgende:

java {
    withJavadocJar()
    withSourcesJar()
}

Lad os gå videre til det sidste krav, opsætning af GPG/PGP signatur. For dette vil vi tilføje plug-in signing:

plugins {
    id 'signing'
}

Og tilføje sektionen :

signing {
    sign publishing.publications
}

Endelig tilføj 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
            }
        }
    }
}

Her sonatypeUsername og sonatypePassword variabler, der indeholder login og adgangskode, oprettet ved registrering på sonatype.org.

Således vil den endelige build.gradle se således ud:

Hele 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 'Nogle beskrivelser af artefakt'
            name 'Artefaktnavn'
            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 Licens, 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 'UdviklerNavn'
                    email 'email@dev.dk'
                }
            }
        }
    }
}

Jeg vil bemærke, at vi henter versionen fra miljøvariablen: System.getenv('RELEASE_VERSION'). Vi vil angive den under bygningen og tage den fra tagnavnet.

Generering af PGP-nøgle

Et af kravene fra Sonatype er, at alle filer skal signeres med en GPG/PGP-nøgle. Til dette går vi herhen og downloader GnuPG-værktøjet til dit operativsystem.

  • Vi genererer et nøglepar: gpg --gen-key, indtaster brugernavn, e-mail og angiver et kodeord.
  • Vi finder ud af id vores nøgle med kommandoen: gpg --list-secret-keys --keyid-format short. Id'et vil være angivet efter skråstregen, for eksempel: rsa2048/9B695056
  • Offentliggør den offentlige nøgle på serveren https://keys.openpgp.org med kommandoen: gpg --keyserver [https://keys.openpgp.org](https://keys.openpgp.org/) --send-keys 9B695056
  • Eksporter den private nøgle til et vilkårligt sted, vi får brug for den senere: gpg --export-secret-key 9B695056 > D:\gpg\9B695056.gpg

Konfigurerer GitHub Actions

Lad os gå videre til den afsluttende fase, hvor vi konfigurerer bygningen og automatisk offentliggørelse ved hjælp af GitHub Actions.
Github Actions – en funktionalitet, der gør det muligt at automatisere arbejdsprocessen ved at implementere en fuld CI/CD-cyklus. Bygning, testning og implementering kan udløses af forskellige hændelser: kodepush, oprettelse af en udgivelse eller issues. Denne funktionalitet er helt gratis for offentlige repositories.

I dette afsnit vil jeg vise, hvordan man konfigurerer bygning og push af kode samt implementering i Sonatype-repository ved udgivelse af en release, samt opsætning af hemmeligheder.

Opsæt hemmeligheder

Til automatisk bygning og implementering har vi brug for en række hemmelige værdier, såsom nøgle-id, adgangskode, som vi indtastede ved generering af nøglen, selve PGP-nøglen samt login/adgangskode til Sonatype. Disse kan indstilles i et særligt afsnit i repository-indstillingerne:

Vi bruger Gradle og Github Actions til at offentliggøre Java-projektet i Sonatype Maven Central Repository

Indstil følgende variabler:

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

Jeg vil gerne fokusere lidt mere på variablen GPG_KEY_CONTENTS. Faktisk har vi brug for den private PGP-nøgle til offentliggørelse. For at placere den i hemmeligheder, benyttede jeg mig af instruktionen og udførte desuden en række handlinger.

  • Lad os kryptere vores nøgle med gpg: gpg --symmetric --cipher-algo AES256 9B695056.gpg, indtast adgangskoden. Denne skal placeres i variablen: SECRET_PASSPHRASE
  • Lad os konvertere den krypterede nøgle til tekstformat ved hjælp af base64: base64 9B695056.gpg.gpg > 9B695056.txt. Indholdet placeres i variablen: GPG_KEY_CONTENTS.

Konfiguration af bygning ved kodepush og oprettelse af PR

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

I denne mappe placeres en fil, for eksempel, 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 arbejdsproces vil blive udført ved push til grenene master, dev og testing, samt ved oprettelse af pull requests.

I jobs-sektionen er der angivet trin, der skal udføres ved de angivne hændelser. I dette tilfælde vil vi bygge på den seneste version af ubuntu, bruge Java 8, samt benytte en plugin til Gradle eskatos/gradle-command-action@v1, som ved anvendelse af den seneste version af builderen vil køre de angivne kommandoer. argumentsVariabler secrets.SONATYPE_USERNAME og secrets.SONATYPE_PASSWORD dette er hemmelighederne, vi har angivet tidligere.

Resultaterne af buildet vil blive vist under fanen Actions:

Vi bruger Gradle og Github Actions til at offentliggøre Java-projektet i Sonatype Maven Central Repository

Autodeploy ved udgivelse af en ny version

For autodeply skal vi oprette en separat arbejdsprocessfil 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 ligner næsten den forrige undtagen for den hændelse, der vil udløse den. I dette tilfælde er det hændelsen af at oprette et tag med et navn, der begynder med v.

Før deployment skal vi trække PGP-nøglen fra hemmelighederne og placere den i roden af projektet samt dekryptere den. Derefter skal vi indstille en speciel miljøvariabel RELEASE_VERSION som vi refererer til i gradle.build filen. Alt dette gøres i sektionen Prepare to publish. Vi får vores nøgle fra variablen GPG_KEY_CONTENTS, konverterer den til en gpg-fil, dekrypterer den, og placerer den i filen secret.gpg.

Derefter refererer vi til en speciel variabel GITHUB_REF, hvorfra vi kan hente den version, vi angav, da vi oprettede tagget. Denne variabel har i dette tilfælde værdien refs/tags/v0.0.2 fra hvilken vi skærer de første 11 tegn for at få den specifikke version. Derefter bruger vi standard Gradle-kommandoer til publikation: test publish

Kontrol af resultaterne af deployment til Sonatype-repositoriet

Efter oprettelsen af en udgivelse skal arbejdsprocessen beskrevet i den forrige sektion starte. For at gøre dette opretter vi en udgivelse:

Vi bruger Gradle og Github Actions til at offentliggøre Java-projektet i Sonatype Maven Central Repository

hvor navnet på tagget skal begynde med v. Hvis arbejdsprocessen kører korrekt efter at have klikket på Publish release, kan vi gå til Sonatype Nexus for at bekræfte dette:

Vi bruger Gradle og Github Actions til at offentliggøre Java-projektet i Sonatype Maven Central Repository

Artefakten er dukket op i Staging-repositoriet. Den vises straks med status Open, hvorefter den skal manuelt ændres til status Close ved at klikke på den relevante knap. Efter kontrol af, at alle krav er opfyldt, ændres artefakten til status Close og er ikke længere tilgængelig for ændringer. I denne form vil den blive sendt til MavenCentral. Hvis alt ser godt ud, kan du klikke på knappen Release, hvorefter artefakten vil blive sendt til Sonatype-repositoriet.

For at artefakten kan komme til MavenCentral, skal du anmode om det i opgaven, vi oprettede i starten. Dette skal kun gøres én gang, da vi offentliggør for første gang. Ved fremtidige udgivelser er dette ikke nødvendigt, alt vil synkronisere automatisk. Synkroniseringen blev aktiveret hurtigt for mig, men det tog omkring 5 dage, før artefakten blev tilgængelig i MavenCentral.

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

Nyttige links

  • Lignende artikel, kun offentliggørelse via maven
  • Staging repository Sonatype
  • Jira Sonatype, hvor der skal oprettes en opgave
  • Eksempel repositoriet, hvor alt dette er indstillet

Kilde: habr.com

Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere 🔥 Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere | ProHoster