Dans cet article, je vais examiner en détail le processus de publication d'un artefact Java depuis le début via Github Actions dans le dépôt Maven Central de Sonatype en utilisant le système de build Gradle.
J'ai décidé d'écrire cet article en raison de l'absence d'un tutoriel adéquat en un seul endroit. J'ai dû recueillir toutes les informations par morceaux à partir de diverses sources, qui n'étaient pas toujours très récentes. Pour ceux que cela intéresse, bienvenue sous le cut.
Création d'un dépôt dans Sonatype
La première étape consiste à créer un dépôt dans Maven Central de Sonatype. Pour cela, nous allons , nous inscrire et créer une nouvelle tâche, avec une demande de création de dépôt pour nous. Nous saisissons notre GroupId du projet, URL du projet un lien vers le projet et SCM url un lien vers le système de contrôle de version dans lequel se trouve le projet. GroupId Ceci doit être sous la forme com.example, com.example.domain, com.example.testsupport, ou peut également prendre la forme d'un lien vers votre GitHub : -> io.github.yourusername. Dans tous les cas, vous devrez confirmer la propriété de ce domaine ou de ce profil. Si vous avez indiqué un profil GitHub, on vous demandera de créer un dépôt public avec le nom requis.
Après un certain temps, une fois la propriété confirmée, votre GroupId sera créé et nous pourrons passer à l'étape suivante, la configuration de Gradle.
Configuration de Gradle
Au moment de la rédaction de cet article, je n'ai trouvé aucun plugin pour Gradle qui pourrait aider à la publication de l'artefact. Le seul plugin que j'ai trouvé, cependant, l'auteur a renoncé à son soutien ultérieur. J'ai donc décidé de tout faire moi-même, d'autant plus que ce n'est pas trop compliqué.
La première chose à déterminer est les exigences de Sonatype pour la publication. Elles sont les suivantes :
- La présence des codes sources et de la JavaDoc, c'est-à-dire que doivent figurer
-sources.jaret-javadoc.jardes fichiers. Comme indiqué dans la documentation, s'il n'est pas possible de fournir les codes sources ou la documentation, vous pouvez créer un vide-sources.jarou-javadoc.jaravec un simple README à l'intérieur, afin de passer la vérification. - Tous les fichiers doivent être signés à l'aide de
GPG/PGPet.ascle fichier contenant la signature doit être inclus pour chaque fichier. - Présence
pomfichiers - Valeurs correctes
groupId,artifactIdetversion. La version peut être une chaîne arbitraire et ne peut pas se terminer par-SNAPSHOT - La présence de
nom,descriptioneturl - Informations sur la licence, les développeurs et le système de contrôle de version
Ce sont les principales règles qui doivent être respectées lors de la publication. Des informations complètes sont disponibles .
Nous allons mettre en œuvre ces exigences dans build.gradle fichier. Pour commencer, ajoutons toutes les informations nécessaires sur les développeurs, la licence, le système de contrôle de versions, ainsi que définissons l'url, le nom et la description du projet. Pour ce faire, écrivons une méthode simple :
def customizePom(pom) {
pom.withXml {
def root = asNode()
root.dependencies.removeAll { dep ->
dep.scope == "test"
}
root.children().last() + {
resolveStrategy = DELEGATE_FIRST
description 'Une description de l’artefact'
name 'Nom de l’artéfact'
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 'La Licence Apache, 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 'NomDuDev'
email 'email@dev.fr'
}
}
}
}
}Ensuite, il faut indiquer que des -sources.jar et-javadoc.jar fichiers doivent être générés lors de la compilation. Pour cela, dans la section java , il faut ajouter ce qui suit :
java {
withJavadocJar()
withSourcesJar()
}Passons à la dernière exigence, la configuration de la signature GPG/PGP. Pour cela, connectons le plugin signing:
plugins {
id 'signing'
}Et ajoutons la section :
signing {
sign publishing.publications
}Enfin, ajoutons la section 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
}
}
}
}Ici sonatypeUsername et sonatypePassword variables contenant le nom d'utilisateur et le mot de passe créés lors de l'inscription sur .
Ainsi, le final build.gradle devrait ressembler à ceci :
Code complet 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 'Une description de l'artifact'
name 'Nom de l'artifact'
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 'La licence Apache, 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 'NomDuDev'
email 'email@dev.fr'
}
}
}
}
}Je tiens à noter que nous obtenons la version à partir de la variable d'environnement : System.getenv('RELEASE_VERSION'). Nous la définirons lors de la construction et la prendrons à partir du nom de la balise.
Génération de la clé PGP
Une des exigences de Sonatype est de signer tous les fichiers à l'aide de la clé GPG/PGP. Pour cela, allons et téléchargeons l'utilitaire GnuPG pour notre système d'exploitation.
- Générons une paire de clés :
gpg --gen-key, saisissons le nom d'utilisateur, l'e-mail, et définissons également un mot de passe. - Nous découvrons
idnotre clé avec la commande :gpg --list-secret-keys --keyid-format short. L'ID sera indiqué après la barre, par exemple : rsa2048/9B695056 - Publions la clé publique sur le serveur avec la commande :
gpg --keyserver [https://keys.openpgp.org](https://keys.openpgp.org/) --send-keys 9B695056 - Exportons la clé secrète à un emplacement arbitraire, nous en aurons besoin par la suite :
gpg --export-secret-key 9B695056 > D:\gpg\9B695056.gpg
Configurer Github Actions
Passons à l'étape finale, configurons la compilation et la publication automatique en utilisant Github Actions.
Github Actions est une fonctionnalité qui permet d'automatiser le flux de travail, en réalisant un cycle CI/CD complet. La compilation, les tests et le déploiement peuvent être déclenchés par divers événements : un push de code, la création d'une release ou d'issues. Cette fonctionnalité est totalement gratuite pour les dépôts publics.
Dans cette section, je vais montrer comment configurer la compilation et le push du code ainsi que le déploiement dans le dépôt Sonatype lors de la sortie d'une release, ainsi que la configuration des secrets.
Configuration des secrets
Pour une compilation et un déploiement automatiques, nous aurons besoin d'une série de valeurs secrètes, telles que l'ID de clé, le mot de passe que nous avons saisi lors de la génération de la clé, la clé PGP elle-même ainsi que le login/mot de passe pour Sonatype. Ils peuvent être définis dans une section spéciale des paramètres du dépôt :

Nous définissons les variables suivantes :
- SONATYPE_USERNAME/SONATYPE_PASSWORD — login/mot de passe que nous avons saisi lors de l'inscription sur Sonatype
- SIGNING_KEYID/SIGNING_PASSWORD — ID de la clé PGP et mot de passe défini lors de la génération.
Je veux m'attarder un peu plus sur la variable GPG_KEY_CONTENTS. En effet, pour publier, nous avons besoin de la clé PGP privée. Pour l'intégrer dans les secrets, j'ai suivi l' et j'ai également effectué plusieurs actions supplémentaires.
- Chiffrons notre clé avec gpg :
gpg --symmetric --cipher-algo AES256 9B695056.gpg, en saisissant le mot de passe. Celui-ci doit être placé dans la variable : SECRET_PASSPHRASE - Convertissons la clé chiffrée obtenue en forme texte avec base64 :
base64 9B695056.gpg.gpg > 9B695056.txt. Le contenu sera placé dans la variable : GPG_KEY_CONTENTS.
Configuration de la compilation lors du push de code et de la création d'un PR
Tout d'abord, créez un dossier à la racine de votre projet : .github/workflows.
Dans celui-ci, placez un fichier, par exemple, gradle-ci-build.yml avec le contenu suivant :
name: build
on:
push:
branches:
- master
- dev
- testing
pull_request:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Configurer JDK 8
uses: actions/setup-java@v1
with:
java-version: 8
- name: Construire avec Gradle
uses: eskatos/gradle-command-action@v1
with:
gradle-version: current
arguments: build -PsonatypeUsername=${{secrets.SONATYPE_USERNAME}} -PsonatypePassword=${{secrets.SONATYPE_PASSWORD}}Ce workflow sera exécuté lors d'un push dans les branches master, dev et testing, ainsi que lors de la création de pull requests.
Dans la section jobs, les étapes qui doivent être réalisées selon les événements spécifiés sont indiquées. Dans ce cas, nous construirons sur la dernière version d'ubuntu, utiliserons Java 8, ainsi qu'un plugin pour Gradle. eskatos/gradle-command-action@v1, qui, en utilisant la dernière version de l'assembleur, exécutera les commandes spécifiées dans arguments. Variables secrets.SONATYPE_USERNAME et secrets.SONATYPE_PASSWORD ce sont des secrets que nous avons définis précédemment.
Les résultats de la construction seront reflétés dans l'onglet Actions :

Déploiement automatique à la publication d'une nouvelle version
Pour le déploiement automatique, nous allons créer un fichier de workflow séparé gradle-ci-publish.yml:
name: publish
on:
push:
tags:
- 'v*'
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Configurer JDK 8
uses: actions/setup-java@v1
with:
java-version: 8
- name: Préparer à publier
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: Publier avec 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}}Le fichier est pratiquement identique au précédent, à l'exception de l'événement qui va le déclencher. Dans ce cas, il s'agit de l'événement de création d'une balise dont le nom commence par v.
Avant le déploiement, nous devons extraire la clé PGP des secrets et la placer à la racine du projet, ainsi que la déchiffrer. Ensuite, nous devons définir une variable d'environnement spéciale RELEASE_VERSION à laquelle nous faisons référence dans gradle.build fichier. Tout cela est fait dans la section Préparer à publier. Nous récupérons notre clé à partir de la variable GPG_KEY_CONTENTS, convertissons-la en fichier gpg, puis la déchiffrons et la plaçons dans le fichier secret.gpg.
Ensuite, nous accédons à une variable spéciale GITHUB_REF, à partir de laquelle nous pouvons extraire la version que nous avons définie lors de la création de la balise. Cette variable a dans ce cas la valeur refs/tags/v0.0.2 de laquelle nous coupons les 11 premiers caractères pour obtenir la version exacte. Ensuite, nous utilisons normalement les commandes Gradle pour la publication : test publish
Vérification des résultats du déploiement dans le référentiel Sonatype
Après la création de la version, le workflow décrit dans la section précédente doit se déclencher. Pour ce faire, nous créons une version :

où le nom de la balise doit commencer par v. Lorsque vous appuyez sur Publier la version, si le workflow s'exécute avec succès, nous pouvons nous rendre sur pour vérifier cela :

L'artefact est apparu dans le dépôt Staging. Il apparaît immédiatement dans le statut Ouvert, puis il doit être manuellement transféré au statut Clos en appuyant sur le bouton correspondant. Après vérification du respect de toutes les exigences, l'artefact passe au statut Clos et n'est plus disponible pour modification. Sous cette forme, il sera intégré dans MavenCentral. Si tout est en ordre, vous pouvez appuyer sur le bouton Publication, l'artefact sera alors transféré dans le dépôt Sonatype.
Pour que l'artefact atteigne MavenCentral, il est nécessaire d'en faire la demande dans la tâche que nous avons créée au tout début. Cela doit être fait uniquement une fois, car c'est la première publication. Pour les fois suivantes, cela n'est pas nécessaire, tout sera synchronisé automatiquement. J'ai reçu la synchronisation rapidement, mais il a fallu environ 5 jours pour que l'artefact devienne disponible dans MavenCentral.
C'est tout, nous avons publié notre artefact dans MavenCentral.
Liens utiles
- Semblable , seulement la publication se fait par maven
- Staging Sonatype
- Sonatype, où il est nécessaire de créer une tâche
- dépôt où tout cela est configuré
Source : habr.com
