ProHoster > Blog > administração > Configurando o GitLab CI para fazer upload de um projeto java para o maven central
Configurando o GitLab CI para fazer upload de um projeto java para o maven central
Este artigo é destinado a desenvolvedores java que precisam publicar rapidamente seus produtos em repositórios centrais sonatype e/ou maven usando GitLab. Neste artigo, falarei sobre como configurar o gitlab-runner, o gitlab-ci e o maven-plugin para resolver esse problema.
Pré-requisitos:
Armazenamento seguro de chaves mvn e GPG.
Execução segura de tarefas públicas de CI.
Upload de artefatos (versão/instantâneo) para repositórios públicos.
Verificação automática de versões de lançamento para publicação no maven central.
Uma solução geral para fazer upload de artefatos para um repositório para vários projetos.
Uma descrição detalhada do mecanismo de publicação de artefatos no Maven Central via Sonatype OSS Repository Hosting Service já foi descrita em este artigo do utilizador Googolplex, então vou me referir a este artigo nos lugares certos.
Faça sua pré-inscrição em Sonatipo JIRA e inicie um ticket para abrir o repositório (para mais detalhes, leia a seção Crie um tíquete Sonatype JIRA). Depois de abrir o repositório, o par login/senha do JIRA (doravante denominado conta Sonatype) será usado para fazer upload de artefatos para o Sonatype nexus.
Se você estiver usando o console Linux para gerar uma chave GPG (gnupg/gnupg2), será necessário instalar ferramentas de rng para gerar entropia. Caso contrário, a geração de chaves poderá demorar muito.
Primeiramente, é necessário criar e configurar um projeto no qual será armazenado o pipeline para implantação dos artefatos. Chamei meu projeto de forma simples e descomplicada - implantar
Depois de criar o repositório, você precisa restringir o acesso para alterar o repositório.
Vá para o projeto -> Configurações -> Repositório -> Ramos Protegidos. Excluímos todas as regras e adicionamos uma única regra com Wildcard * com direito de push e merge apenas para usuários com função de Mantenedores. Esta regra funcionará para todos os usuários deste projeto e do grupo ao qual este projeto pertence.
Se houver vários mantenedores, a melhor solução seria, em princípio, restringir o acesso ao projeto.
Vá para projeto -> Configurações -> Geral -> Visibilidade, recursos do projeto, permissões e defina a visibilidade do projeto como Privado.
Tenho um projeto em acesso público, pois utilizo meu próprio GitLab Runner e somente eu tenho acesso para modificar o repositório. Bem, na verdade não é do meu interesse mostrar informações privadas em registros de pipelines públicos.
Apertando as regras para alteração do repositório
Vá para o projeto -> Configurações -> Repositório -> Regras de Push e defina os sinalizadores Restrição do Committer, Verifique se o autor é um usuário do GitLab. Eu também recomendo configurar confirmar assinaturae defina o sinalizador Rejeitar confirmações não assinadas.
Em seguida, você precisa configurar um gatilho para executar tarefas
Vá para projeto -> Configurações -> CI / CD -> Gatilhos de pipeline e crie um novo token de gatilho
Este token pode ser adicionado imediatamente à configuração geral de variáveis de um grupo de projetos.
Vá para o grupo -> Configurações -> CI/CD -> Variáveis e adicione uma variável DEPLOY_TOKEN com token de gatilho no valor.
Esta seção descreve a configuração para execução de tarefas na implantação usando o executor nativo (específico) e público (compartilhado).
Corredor Específico
Eu uso meus próprios corredores porque antes de tudo é conveniente, rápido e barato.
Para runner eu recomendo Linux VDS com 1 CPU, 2 GB de RAM, 20 GB de HDD. Preço de emissão ~ 3000₽ por ano.
Meu corredor
Para o corredor usei CPU VDS 4, 4 GB de RAM e SSD de 50 GB. Custou ~11000₽ e nunca me arrependi.
Tenho um total de 7 máquinas. 5 em Aruba e 2 em Ihor.
Então, temos um corredor. Agora vamos configurá-lo.
Vamos para a máquina via SSH e instalamos java, git, maven, gnupg2.
Crie um diretório para o cache maven e atribua direitos de grupo runner
Você pode pular este ponto se não planeja executar vários executores em uma máquina.
Runtime platform arch=amd64 os=linux pid=17594 revision=3001a600 version=11.10.0
Running in system-mode.
Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/):
https://gitlab.com/
Please enter the gitlab-ci token for this runner:
REGISTRATION_TOKEN
Please enter the gitlab-ci description for this runner:
[ih1174328.vds.myihor.ru]: Deploy Runner
Please enter the gitlab-ci tags for this runner (comma separated):
deploy
Registering runner... succeeded runner=ZvKdjJhx
Please enter the executor: docker-ssh, parallels, virtualbox, docker-ssh+machine, kubernetes, docker, ssh, docker+machine, shell:
shell
Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!
Verifique se o corredor está registrado. Vá para gitlab.com -> deploy-project -> Configurações -> CI/CD -> Corredores -> Corredores Específicos -> Corredores ativados para este projeto
Geramos uma chave respondendo a perguntas. Usei meu próprio nome e e-mail.
Certifique-se de especificar a senha da chave. Os artefatos serão assinados com esta chave.
gpg --gen-key
Verificar
gpg --list-keys -a
/home/gitlab-deployer/.gnupg/pubring.gpg
----------------------------------------
pub 4096R/00000000 2019-04-19
uid Petruha Petrov <[email protected]>
sub 4096R/11111111 2019-04-19
Fazendo upload de nossa chave pública para o servidor de chaves
gpg --keyserver keys.gnupg.net --send-key 00000000
gpg: sending key 00000000 to hkp server keys.gnupg.net
Crie um diretório maven repositório e link com o cache (não se engane)
Esta etapa pode ser ignorada se você não planeja executar vários executores na mesma máquina.
Adicione o arquivo .gitlab-ci.yml à raiz do projeto de implantação
O script apresenta duas tarefas de implantação mutuamente exclusivas. Corredor Específico ou Corredor Compartilhado respectivamente.
.gitlab-ci.yml
stages:
- deploy
Specific Runner:
extends: .java_deploy_template
# Задача будет выполняться на вашем shell-раннере
tags:
- deploy
Shared Runner:
extends: .java_deploy_template
# Задача будет выполняться на публичном docker-раннере
tags:
- docker
# Образ из раздела GitLab Runner -> Shared Runner -> Docker
image: registry.gitlab.com/group/deploy-project:latest
before_script:
# Импортируем GPG ключ
- printf "${GPG_SECRET_KEY}" | gpg --batch --import
# Сохраняем maven конфигурацию
- printf "${SETTINGS_SECURITY_XML}" > ~/.m2/settings-security.xml
- printf "${SETTINGS_XML}" > ~/.m2/settings.xml
.java_deploy_template:
stage: deploy
# Задача сработает по триггеру, если передана переменная DEPLOY со значением java
only:
variables:
- $DEPLOY == "java"
variables:
# отключаем клонирование текущего проекта
GIT_STRATEGY: none
script:
# Предоставляем возможность хранения пароля в незашифрованном виде
- git config --global credential.helper store
# Сохраняем временные креды пользователя gitlab-ci-token
# Токен работает для всех публичных проектов gitlab.com и для проектов группы
- echo "https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com" >> ~/.git-credentials
# Полностью чистим текущую директорию
- rm -rf .* *
# Клонируем проект который, будем деплоить в Sonatype Nexus
- git clone ${DEPLOY_CI_REPOSITORY_URL} .
# Переключаемся на нужный коммит
- git checkout ${DEPLOY_CI_COMMIT_SHA} -f
# Если хоть один pom.xml содержит параметр autoReleaseAfterClose валим сборку.
# В противном случае есть риск залить сырые артефакты в maven central
- >
for pom in $(find . -name pom.xml); do
if [[ $(grep -q autoReleaseAfterClose "$pom" && echo $?) == 0 ]]; then
echo "File $pom contains prohibited setting: <autoReleaseAfterClose>";
exit 1;
fi;
done
# Если параметр DEPLOY_CI_COMMIT_TAG пустой, то принудительно ставим SNAPSHOT-версию
- >
if [[ "${DEPLOY_CI_COMMIT_TAG}" != "" ]]; then
mvn versions:set -DnewVersion=${DEPLOY_CI_COMMIT_TAG}
else
VERSION=$(mvn -q -Dexec.executable=echo -Dexec.args='${project.version}' --non-recursive exec:exec)
if [[ "${VERSION}" == *-SNAPSHOT ]]; then
mvn versions:set -DnewVersion=${VERSION}
else
mvn versions:set -DnewVersion=${VERSION}-SNAPSHOT
fi
fi
# Запускаем задачу на сборку и деплой артефактов
- mvn clean deploy -DskipTests=true
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
<!-- Генерация javadoc должна быть после фазы генерации ресурсов -->
<phase>prepare-package</phase>
<configuration>
<!-- Очень помогает в публичных проектах -->
<failOnError>true</failOnError>
<failOnWarnings>true</failOnWarnings>
<!-- Убирает ошибку поиска документации в target директории -->
<detectOfflineLinks>false</detectOfflineLinks>
</configuration>
</execution>
</executions>
</plugin>
Se você possui um módulo que não contém java (por exemplo, apenas recursos)
Ou você não quer gerar javadoc em princípio, então para ajudar maven-jar-plugin
Se você possui um projeto com vários módulos e não precisa fazer upload de um módulo específico para o repositório, será necessário adicioná-lo ao pom.xml deste módulo nexus-staging-maven-plugin com bandeira skipNexusStagingDeployMojo
Após o upload, as versões de snapshot/lançamento estarão disponíveis em repositórios de teste
<repositories>
<repository>
<id>SonatypeNexus</id>
<url>https://oss.sonatype.org/content/groups/staging/</url>
<!-- Не надо указывать флаги snapshot/release для репозитория -->
</repository>
</repositories>
Mais vantagens
Uma lista muito rica de objetivos para trabalhar com o repositório Nexus (mvn help:describe -Dplugin=org.sonatype.plugins:nexus-staging-maven-plugin).
Verificação automática de liberação para upload para maven central
Quando a tag é definida, a tarefa correspondente no projeto de implantação é automaticamente acionada para fazer upload da versão de lançamento para o Nexus (exemplo).
A melhor parte é que a liberação próxima é acionada automaticamente no nexo.
[INFO] Performing remote staging...
[INFO]
[INFO] * Remote staging into staging profile ID "9043b43f77dcc9"
[INFO] * Created staging repository with ID "orgtouchbit-1037".
[INFO] * Staging repository at https://oss.sonatype.org:443/service/local/staging/deployByRepositoryId/orgtouchbit-1037
[INFO] * Uploading locally staged artifacts to profile org.touchbit
[INFO] * Upload of locally staged artifacts finished.
[INFO] * Closing staging repository with ID "orgtouchbit-1037".
Waiting for operation to complete...
.........
[INFO] Remote staged 1 repositories, finished with success.
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO]
[INFO] Shields4J 1.0.0 .................................... SUCCESS [ 9.603 s]
[INFO] test-core .......................................... SUCCESS [ 3.419 s]
[INFO] Shields4J client ................................... SUCCESS [ 9.793 s]
[INFO] TestNG listener 1.0.0 .............................. SUCCESS [01:23 min]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 01:47 min
[INFO] Finished at: 2019-04-21T04:05:46+03:00
[INFO] ------------------------------------------------------------------------
E se algo der errado, a tarefa irá falhar
[INFO] Performing remote staging...
[INFO]
[INFO] * Remote staging into staging profile ID "9043b43f77dcc9"
[INFO] * Created staging repository with ID "orgtouchbit-1038".
[INFO] * Staging repository at https://oss.sonatype.org:443/service/local/staging/deployByRepositoryId/orgtouchbit-1038
[INFO] * Uploading locally staged artifacts to profile org.touchbit
[INFO] * Upload of locally staged artifacts finished.
[INFO] * Closing staging repository with ID "orgtouchbit-1038".
Waiting for operation to complete...
.......
[ERROR] Rule failure while trying to close staging repository with ID "orgtouchbit-1039".
[ERROR]
[ERROR] Nexus Staging Rules Failure Report
[ERROR] ==================================
[ERROR]
[ERROR] Repository "orgtouchbit-1039" failures
[ERROR] Rule "signature-staging" failures
[ERROR] * No public key: Key with id: (1f42b618d1cbe1b5) was not able to be located on <a href=http://keys.gnupg.net:11371/>http://keys.gnupg.net:11371/</a>. Upload your public key and try the operation again.
...
[ERROR] Cleaning up local stage directory after a Rule failure during close of staging repositories: [orgtouchbit-1039]
[ERROR] * Deleting context 9043b43f77dcc9.properties
[ERROR] Cleaning up remote stage repositories after a Rule failure during close of staging repositories: [orgtouchbit-1039]
[ERROR] * Dropping failed staging repository with ID "orgtouchbit-1039" (Rule failure during close of staging repositories: [orgtouchbit-1039]).
[ERROR] Remote staging finished with a failure: Staging rules failure!
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO]
[INFO] Shields4J 1.0.0 .................................... SUCCESS [ 4.073 s]
[INFO] test-core .......................................... SUCCESS [ 2.788 s]
[INFO] Shields4J client ................................... SUCCESS [ 3.962 s]
[INFO] TestNG listener 1.0.0 .............................. FAILURE [01:07 min]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
Como resultado, ficamos com apenas uma escolha. Ou exclua esta versão ou publique.
Após o lançamento, depois de algum tempo, os artefatos estarão em
oftop
Foi uma revelação para mim que o maven indexa outros repositórios públicos.
Tive que fazer upload do robots.txt porque ele indexava meu antigo repositório.
Um projeto de implantação separado no qual é possível implementar diversas tarefas de CI para fazer upload de artefatos para repositórios públicos para diversas linguagens de desenvolvimento.
O projeto de implantação é isolado de interferências externas e só pode ser modificado por usuários com funções de Proprietário e Mantenedor.
Um executor específico separado com um cache “quente” para executar apenas tarefas de implantação.
Publicação de versões de snapshot/lançamento em um repositório público.
Verificação automática da versão de lançamento quanto à disponibilidade para publicação no maven central.
Proteção contra publicação automática de versões “brutas” no maven central.
Crie e publique versões de snapshot “com um clique”.
Repositório único para obter versões de snapshot/lançamento.
Pipeline geral para construção/teste/publicação de um projeto java.
Configurar o GitLab CI não é um tópico tão complicado quanto parece à primeira vista. Basta configurar o CI pronto para uso algumas vezes e agora você está longe de ser um amador nesse assunto. Além disso, a documentação do GitLab é muito redundante. Não tenha medo de dar o primeiro passo. A estrada aparece sob os passos de quem anda (não me lembro quem disse isso :)
Ficarei feliz em receber feedback.
No próximo artigo, mostrarei como configurar o GitLab CI para executar tarefas de teste de integração de forma competitiva (executando serviços de teste com docker-compose) se você tiver apenas um executor de shell.