Ús de les accions de Gradle i Github per publicar el projecte Java al repositori central de Sonatype Maven

En aquest article, vull fer una ullada més de prop al procés de publicació d'un artefacte Java des de zero mitjançant accions de Github al Repositori central de Sonatype Maven mitjançant el creador Gradle.

Vaig decidir escriure aquest article a causa de la manca d'un tutorial normal en un sol lloc. Tota la informació s'havia de recollir peça per peça de diverses fonts, a més, no del tot fresca. A qui li importa, benvingut sota el gat.

Creació d'un repositori a Sonatype

El primer pas és crear un repositori a Sonatype Maven Central. Per això anem aquí, registreu-vos i creeu una tasca nova, demanant-nos que creem un repositori. Conduïm al nostre GroupId projecte, URL del projecte enllaç del projecte i URL SCM un enllaç al sistema de control de versions on es troba el projecte. GroupId aquí hauria de tenir la forma com.example, com.example.domain, com.example.testsupport i també pot tenir la forma d'un enllaç al vostre github: github.com/yourusername -> io.github.yourusername. En qualsevol cas, hauràs de verificar la propietat d'aquest domini o perfil. Si heu especificat un perfil github, se us demanarà que creeu un repositori públic amb el nom desitjat.

Un temps després de la confirmació, es crearà el vostre GroupId i podem passar al següent pas, la configuració de Gradle.

Configuració de Gradle

En el moment d'escriure, no vaig trobar complements de Gradle que poguessin ajudar a publicar l'artefacte. El l'únic connector que vaig trobar, però, l'autor es va negar a donar-li més suport. Per tant, vaig decidir fer-ho tot jo mateix, ja que no és massa difícil fer-ho.

El primer que cal esbrinar són els requisits de Sonatype per publicar. Són els següents:

  • Disponibilitat de codis font i JavaDoc, és a dir. ha d'assistir -sources.jar и-javadoc.jar Fitxers. Tal com s'indica a la documentació, si no és possible proporcionar codis font o documentació, podeu fer un simulacre -sources.jar o -javadoc.jar amb un simple README dins per passar la prova.
  • Tots els fitxers han d'estar signats amb GPG/PGPI .asc l'expedient que conté la signatura s'ha d'incloure per a cada expedient.
  • disponibilitat pom dossier
  • Valors correctes groupId, artifactId и version. La versió pot ser una cadena arbitrària i no pot acabar amb -SNAPSHOT
  • Presència necessària name, description и url
  • La presència d'informació sobre la llicència, els desenvolupadors i el sistema de control de versions

Aquestes són les normes bàsiques que s'han de seguir a l'hora de publicar. Informació completa disponible aquí.

Implementem aquests requisits a build.gradle dossier. En primer lloc, afegim tota la informació necessària sobre els desenvolupadors, les llicències, el sistema de control de versions i també establim l'URL, el nom i la descripció del projecte. Escrivim un mètode senzill per a això:

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

A continuació, heu d'especificar-ho durant el muntatge generat -sources.jar и-javadoc.jar Fitxers. Per aquest apartat java cal afegir el següent:

java {
    withJavadocJar()
    withSourcesJar()
}

Passem a l'últim requisit, configurar una signatura GPG/PGP. Per fer-ho, connecteu el connector signing:

plugins {
    id 'signing'
}

I afegeix una secció:

signing {
    sign publishing.publications
}

Finalment, afegim una secció 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
            }
        }
    }
}

Aquí sonatypeNom d'usuari и sonatypePassword variables que contenen l'inici de sessió i la contrasenya creades durant el registre sonatype.org.

Així la final build.gradle quedarà així:

Codi build.gradle complet

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

Vull assenyalar que obtenim la versió de la variable d'entorn: System.getenv('RELEASE_VERSION'). L'exposarem durant el muntatge i l'agafarem del nom de l'etiqueta.

Generació de claus PGP

Un dels requisits de Sonatype és que tots els fitxers estiguin signats amb una clau GPG/PGP. Per això anem aquí i descarregueu la utilitat GnuPG per al vostre sistema operatiu.

  • Generem un parell de claus: gpg --gen-key, introduïu un nom d'usuari, un correu electrònic i també establiu una contrasenya.
  • Ho descobrim id la nostra clau amb l'ordre: gpg --list-secret-keys --keyid-format short. L'identificador s'especificarà després de la barra inclinada, per exemple: rsa2048/9B695056
  • Publicació de la clau pública al servidor https://keys.openpgp.org amb l'ordre: gpg --keyserver [https://keys.openpgp.org](https://keys.openpgp.org/) --send-keys 9B695056
  • Exportem la clau secreta a un lloc arbitrari, la necessitarem en el futur: gpg --export-secret-key 9B695056 > D:\gpg\9B695056.gpg

Configuració d'accions de Github

Passem a l'etapa final, configureu la compilació i la publicació automàtica mitjançant Github Actions.
Github Actions és una característica que us permet automatitzar el flux de treball mitjançant la implementació d'un cicle CI / CD complet. La creació, prova i implementació es poden activar per diversos esdeveniments: emissió de codi, creació de llançaments o problemes. Aquesta funcionalitat és totalment gratuïta per als repositoris públics.

En aquesta secció, us mostraré com configurar el codi de compilació i push i desplegar-lo al repositori de Sonatype en el llançament, així com configurar els secrets.

Posem secrets

Per al muntatge i el desplegament automàtic, necessitem una sèrie de valors secrets, com ara l'identificador de clau, la contrasenya que hem introduït en generar la clau, la pròpia clau PGP i l'inici de sessió/contrasenya de Sonatype. Podeu configurar-los en una secció especial a la configuració del repositori:

Ús de les accions de Gradle i Github per publicar el projecte Java al repositori central de Sonatype Maven

Posem les variables següents:

  • SONATYPE_USERNAME / SONATYPE_PASSWORD - inici de sessió / contrasenya que vam introduir en registrar-nos amb Sonatype
  • SIGNING_KEYID/SIGNING_PASSWORD — Identificació de clau PGP i contrasenya establertes durant la generació.

Vull aprofundir en la variable GPG_KEY_CONTENTS amb més detall. El cas és que per a la publicació necessitem una clau PGP privada. Per publicar-ho als secrets, vaig utilitzar instrucció i, a més, va realitzar una sèrie d'accions.

  • Xifrem la nostra clau amb gpg: gpg --symmetric --cipher-algo AES256 9B695056.gpgintroduint una contrasenya. S'ha de col·locar en una variable: SECRET_PASSPHRASE
  • Traduïm la clau xifrada rebuda a un formulari de text mitjançant base64: base64 9B695056.gpg.gpg > 9B695056.txt. El contingut es col·locarà a la variable: GPG_KEY_CONTENTS.

Configuració de la compilació en empènyer el codi i crear PR

Primer heu de crear una carpeta a l'arrel del vostre projecte: .github/workflows.

En ell, marqueu el fitxer, per exemple, gradle-ci-build.yml amb el següent contingut:

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

Aquest flux de treball s'executarà en empènyer a les branques master, dev и testing, també en crear sol·licituds d'extracció.

La secció de treballs especifica els passos que s'han d'executar en els esdeveniments especificats. En aquest cas, basarem la darrera versió d'ubuntu, utilitzarem Java 8 i també utilitzarem el connector per a Gradle eskatos/gradle-command-action@v1que, utilitzant la darrera versió del constructor, executarà les ordres especificades a arguments. Les variables secrets.SONATYPE_USERNAME и secrets.SONATYPE_PASSWORD aquests són els secrets que vam demanar abans.

Els resultats de la compilació es reflectiran a la pestanya Accions:

Ús de les accions de Gradle i Github per publicar el projecte Java al repositori central de Sonatype Maven

Desplega automàticament quan es publica una versió nova

Creem un fitxer de flux de treball independent per a la implementació automàtica 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}}

El fitxer és gairebé idèntic a l'anterior, excepte l'esdeveniment en què s'activarà. En aquest cas, aquest és l'esdeveniment de creació d'una etiqueta amb un nom que comença per v.

Abans del desplegament, hem d'extreure la clau PGP dels secrets i col·locar-la a l'arrel del projecte, així com desxifrar-la. A continuació, hem d'establir una variable d'entorn especial RELEASE_VERSION al qual ens referim gradle.build dossier. Tot això es fa a l'apartat Prepare to publish. Obtenim la nostra clau de la variable GPG_KEY_CONTENTS, la traduïm a un fitxer gpg i després la desxifram posant-la al fitxer secret.gpg.

A continuació, passem a una variable especial GITHUB_REF, de la qual podem obtenir la versió que hem establert en crear l'etiqueta. Aquesta variable és rellevant en aquest cas. refs/tags/v0.0.2 de la qual vam tallar els 11 primers caràcters per obtenir una versió concreta. A continuació, utilitzem les ordres estàndard de Gradle per publicar: test publish

Comprovació dels resultats del desplegament al repositori Sonatype

Després de crear la versió, s'hauria d'iniciar el flux de treball descrit a la secció anterior. Per fer-ho, creeu una versió:

Ús de les accions de Gradle i Github per publicar el projecte Java al repositori central de Sonatype Maven

el nom de l'etiqueta ha de començar per v. Si, després de fer clic a Publica la versió, el flux de treball es completa correctament, podem anar a Nexus de tipus sonat per assegurar:

Ús de les accions de Gradle i Github per publicar el projecte Java al repositori central de Sonatype Maven

L'artefacte va aparèixer al repositori Staging. Apareix immediatament a l'estat Obert, després s'ha de transferir manualment a l'estat Tanca prement el botó corresponent. Després de comprovar que es compleixen tots els requisits, l'artefacte passa a l'estat Tanca i ja no està disponible per a la modificació. D'aquesta forma, acabarà a MavenCentral. Si tot va bé, podeu prémer el botó Deixeu anar, i l'artefacte acabarà al dipòsit de Sonatype.

Perquè l'artefacte entri a MavenCentral, heu de demanar-lo a la tasca que vam crear al principi. Només heu de fer-ho una vegada, així que publiquem per primera vegada. En temps posteriors, això no és necessari, tot es sincronitzarà automàticament. Em van activar la sincronització ràpidament, però van trigar uns 5 dies perquè l'artefacte estigui disponible a MavenCentral.

Això és tot, hem publicat el nostre artefacte a MavenCentral.

links útils

  • Similars article, només es publica a través de maven
  • Posada en escena repositori Sonatip
  • Jira Sonatip en què crear la tasca
  • Exemple repositori on està tot configurat

Font: www.habr.com