Neste artigo, quero dar uma olhada detalhada no processo de publicação de um artefato Java do zero por meio de Ações do Github no Repositório Central do Sonatype Maven usando o coletor Gradle.
Decidi escrever este artigo devido à falta de um tutorial normal em um só lugar. Toda a informação teve que ser coletada em pedaços de várias fontes, embora não inteiramente nova. Quem se importa, bem-vindo ao gato.
Criando um repositório no Sonatype
O primeiro passo é criar um repositório no Sonatype Maven Central. Para fazer isso, vá aqui , registre-se e crie uma nova tarefa, pedindo para criar um repositório para nós. Dirigimos em nosso GroupId do projeto, link do URL do projeto para o projeto e link de URL do SCM para o sistema de controle de versão no qual o projeto se encontra. O GroupId aqui deve estar no formato com.example, com.example.domain, com.example.testsupport e também pode ser um link para o seu github: github.com/yourusername -> io.github.yourusername. De qualquer forma, você precisará confirmar a propriedade desse domínio ou perfil. Se você especificou um perfil no github, eles solicitarão que você crie um repositório público com o nome desejado.
Algum tempo após a confirmação, seu GroupId será criado e podemos prosseguir para a próxima etapa, a configuração Gradle.
Configurando o Gradle
No momento em que escrevi este artigo, não encontrei nenhum plug-in para Gradle que pudesse ajudar na publicação do artefato. Este é o único plugin que encontrei, no entanto, o autor recusou seu suporte adicional. Por isso, decidi fazer tudo sozinho, já que não é muito difícil.
A primeira coisa a descobrir são os requisitos de publicação do Sonatype. Eles são os seguintes:
- A presença de códigos-fonte e JavaDoc, ou seja, deve estar presente
-sources.jar
e -javadoc.jar
arquivos. Conforme declarado na documentação, se não for possível fornecer códigos-fonte ou documentação, você pode criar um manequim -sources.jar
ou -javadoc.jar
um simples README para passar no teste. GPG/PGP
, .asc
, , .pom
groupId
, artifactId
version
. -SNAPSHOT
name
, description
url
- ,
, . .
build.gradle
. , , , url, . :
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@dev.ru'
}
}
}
}
}
, -sources.jar
-javadoc.jar
. java
:
java {
withJavadocJar()
withSourcesJar()
}
, GPG/PGP . signing
:
plugins {
id 'signing'
}
:
signing {
sign publishing.publications
}
, 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
}
}
}
}
sonatypeUsername sonatypePassword , , sonatype.org.
, build.gradle
:
build.gradleplugins {
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@dev.ru'
}
}
}
}
}
, : System.getenv('RELEASE_VERSION')
. .
PGP
Sonatype GPG/PGP . GnuPG .
- :
gpg --gen-key
, , e-mail, . id
: gpg --list-secret-keys --keyid-format short
. Id , : rsa2048/9B695056- https://keys.openpgp.org :
gpg --keyserver https://keys.openpgp.org/ --send-keys 9B695056
- , :
gpg --export-secret-key 9B695056 > D:\\gpg\\9B695056.gpg
Github Actions
, , Github Actions.
Github Actions – , , CI/CD. , : , issues. .
Sonatype , .
, id , , , PGP , / Sonatype. :

:
- SONATYPE_USERNAME/SONATYPE_PASSWORD — /, Sonatype
- SIGNING_KEYID/SIGNING_PASSWORD — id PGP , .
GPG_KEY_CONTENTS . , PGP . , , .
- gpg:
gpg --symmetric --cipher-algo AES256 9B695056.gpg
, . : SECRET_PASSPHRASE - base64:
base64 9B695056.gpg.gpg > 9B695056.txt
. : GPG_KEY_CONTENTS.
PR
: .github/workflows
.
, , gradle-ci-build.yml
:
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}}
master
, dev
testing
, .
jobs , . ubuntu, Java 8, Gradle eskatos/gradle-command-action@v1
, , arguments
. secrets.SONATYPE_USERNAME
secrets.SONATYPE_PASSWORD
, .
Actions:

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}}
, . , v.
PGP , . RELEASE_VERSION
gradle.build
. Prepare to publish
. GPG_KEY_CONTENTS, gpg , , secret.gpg
.
GITHUB_REF
, , . refs/tags/v0.0.2
11 , . Gradle : test publish
Sonatype
, . :

v. Publish release, , Sonatype Nexus :

Staging . Open, Close, . , Close . MavenCentral. , Release, Sonatype.
, MavenCentral, , . , . , . , MavenCentral 5 .
Isso é tudo, publicamos nosso artefato no MavenCentral.
Links Úteis
- Artigo semelhante , apenas publicando via maven
- Sonatype do repositório de armazenamento temporário
- Jira Sonatype, na qual você precisa criar uma tarefa
- Um repositório de exemplo em que tudo está configurado