Configurazione di GitLab CI per caricare un progetto Java su Maven Central

Questo articolo è destinato agli sviluppatori Java che necessitano di pubblicare rapidamente i propri prodotti su sonatype e/o repository centrali Maven utilizzando GitLab. In questo articolo parlerò della configurazione di gitlab-runner, gitlab-ci e maven-plugin per risolvere questo problema.

Prerequisiti:

  • Archiviazione sicura delle chiavi mvn e GPG.
  • Esecuzione sicura delle attività CI pubbliche.
  • Caricamento di artefatti (rilascio/istantanea) nei repository pubblici.
  • Controllo automatico delle versioni di rilascio per la pubblicazione in Maven Central.
  • Una soluzione generale per caricare artefatti in un repository per più progetti.
  • Semplicità e facilità d'uso.

contenuto

Informazioni generali

  • Una descrizione dettagliata del meccanismo per la pubblicazione degli artefatti su Maven Central tramite il servizio di hosting del repository OSS Sonatype è già descritta in questo articolo per utente Googolplex, quindi farò riferimento a questo articolo nei posti giusti.
  • Preregistrati su Sonatipo JIRA e avviare un ticket per aprire il repository (per maggiori dettagli leggere la sezione Crea un biglietto Sonatype JIRA). Dopo aver aperto il repository, la coppia login/password JIRA (di seguito denominata account Sonatype) verrà utilizzata per caricare gli artefatti sul nexus Sonatype.
  • Inoltre, il processo di generazione di una chiave GPG è descritto in modo molto secco. Consulta la sezione per maggiori dettagli. Configurazione di GnuPG per firmare artefatti
  • Se stai utilizzando la console Linux per generare una chiave GPG (gnupg/gnupg2), devi installare rng-strumenti per generare entropia. Altrimenti, la generazione delle chiavi può richiedere molto tempo.
  • Servizi di archiviazione pubblico Chiavi GPG

Al contenuto

Configurazione di un progetto di distribuzione in GitLab

  • Prima di tutto, è necessario creare e configurare un progetto in cui verrà archiviata la pipeline per la distribuzione degli artefatti. Ho chiamato il mio progetto in modo semplice e senza complicazioni: schierare
  • Dopo aver creato il repository, è necessario limitare l'accesso per modificare il repository.
    Vai al progetto -> Impostazioni -> Repository -> Rami protetti. Eliminiamo tutte le regole e aggiungiamo una singola regola con Wildcard* con diritto di push e merge solo per gli utenti con ruolo Manutentori. Questa regola funzionerà per tutti gli utenti sia di questo progetto che del gruppo a cui appartiene questo progetto.
    Configurazione di GitLab CI per caricare un progetto Java su Maven Central
  • Se ci sono più manutentori, la soluzione migliore sarebbe in linea di principio limitare l’accesso al progetto.
    Vai al progetto -> Impostazioni -> Generale -> Visibilità, funzionalità del progetto, autorizzazioni e imposta Visibilità del progetto su Privata.
    Ho un progetto ad accesso pubblico, poiché utilizzo il mio GitLab Runner e solo io ho accesso per modificare il repository. Beh, in realtà non è nel mio interesse mostrare informazioni private nei registri della pipeline pubblica.
  • Inasprimento delle regole per la modifica del repository
    Vai al progetto -> Impostazioni -> Repository -> Regole push e imposta i flag Restrizione committente, Controlla se l'autore è un utente GitLab. Consiglio anche l'impostazione impegnarsi a firmaree imposta il flag Rifiuta commit non firmati.
  • Successivamente, è necessario configurare un trigger per eseguire le attività
    Vai a progetto -> Impostazioni -> CI/CD -> Trigger pipeline e crea un nuovo token trigger
    Questo token può essere immediatamente aggiunto alla configurazione generale delle variabili per un gruppo di progetti.
    Vai al gruppo -> Impostazioni -> CI/CD -> Variabili e aggiungi una variabile DEPLOY_TOKEN con trigger-token nel valore.

Al contenuto

Corridore di GitLab

Questa sezione descrive la configurazione per l'esecuzione delle attività durante la distribuzione utilizzando il runner nativo (Specifico) e pubblico (Condiviso).

Corridore specifico

Utilizzo i miei runner, perché prima di tutto è comodo, veloce, economico.
Per i corridori consiglio Linux VDS con 1 CPU, 2 GB RAM, 20 GB HDD. Prezzo di emissione ~ 3000₽ all'anno.

Il mio corridore

Per il corridore ho preso CPU VDS 4, 4 GB RAM, SSD 50 GB. È costato ~ 11000₽ e non me ne sono mai pentito.
Ho un totale di 7 macchine. 5 su Aruba e 2 su ihor.

Quindi, abbiamo un corridore. Adesso lo sistemeremo.
Andiamo alla macchina tramite SSH e installiamo java, git, maven, gnupg2.

Al contenuto

Installazione di gitlab runner

  • Crea un nuovo gruppo runner
    sudo groupadd runner
  • Crea una directory per la cache Maven e assegna i diritti al gruppo runner
    Puoi saltare questo passaggio se non prevedi di correre più corridori sulla stessa macchina.

    mkdir -p /usr/cache/.m2/repository
    chown -R :runner /usr/cache
    chmod -R 770 /usr/cache
  • Crea un utente gitlab-deployer e aggiungi al gruppo runner
    useradd -m -d /home/gitlab-deployer gitlab-deployer
    usermod -a -G runner gitlab-deployer
  • Aggiungi al file /etc/ssh/sshd_config riga successiva
    AllowUsers root@* [email protected]
  • Riavviare sshd
    systemctl restart sshd
  • Imposta una password per l'utente gitlab-deployer (può essere semplice, poiché esiste una restrizione per localhost)
    passwd gitlab-deployer
  • Installa GitLab Runner (Linux x86-64)
    sudo wget -O /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64
    sudo chmod +x /usr/local/bin/gitlab-runner
    ln -s /usr/local/bin/gitlab-runner /etc/alternatives/gitlab-runner
    ln -s /etc/alternatives/gitlab-runner /usr/bin/gitlab-runner
  • Vai su gitlab.com -> deploy-project -> Impostazioni -> CI/CD -> Runner -> Runner specifici e copia il token di registrazione

schermo

Configurazione di GitLab CI per caricare un progetto Java su Maven Central

  • Iscrizione del corridore
    gitlab-runner register --config /etc/gitlab-runner/gitlab-deployer-config.toml

Процесс

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!

  • Verificare che il corridore sia iscritto. Vai su gitlab.com -> deploy-project -> Impostazioni -> CI/CD -> Runner -> Runner specifici -> Runner attivati ​​per questo progetto

schermo

Configurazione di GitLab CI per caricare un progetto Java su Maven Central

  • Aggiunta separato servizio /etc/systemd/system/gitlab-deployer.service
    [Unit]
    Description=GitLab Deploy Runner
    After=syslog.target network.target
    ConditionFileIsExecutable=/usr/local/bin/gitlab-runner
    [Service]
    StartLimitInterval=5
    StartLimitBurst=10
    ExecStart=/usr/local/bin/gitlab-runner "run" "--working-directory" "/home/gitlab-deployer" "--config" "/etc/gitlab-runner/gitlab-deployer-config.toml" "--service" "gitlab-deployer" "--syslog" "--user" "gitlab-deployer"
    Restart=always
    RestartSec=120
    [Install]
    WantedBy=multi-user.target
  • Iniziamo il servizio.
    systemctl enable gitlab-deployer.service
    systemctl start gitlab-deployer.service
    systemctl status gitlab-deployer.service
  • Controlla che il corridore stia correndo.

esempio

Configurazione di GitLab CI per caricare un progetto Java su Maven Central

Al contenuto

Generazione di chiavi GPG

  • Dalla stessa macchina passiamo tramite ssh sotto l'utente gitlab-deployer (questo è importante per la generazione della chiave GPG)

    ssh [email protected]

  • Generiamo una chiave rispondendo alle domande. Ho usato il mio nome e la mia email.
    Assicurati di specificare la password per la chiave. Gli artefatti verranno firmati con questa chiave.

    gpg --gen-key 

  • controllare la

    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

  • Caricando la nostra chiave pubblica sul keyserver

    gpg --keyserver keys.gnupg.net --send-key 00000000
    gpg: sending key 00000000 to hkp server keys.gnupg.net

Al contenuto

Configurazione Maven

  • Andiamo sotto l'utente gitlab-deployer
    su gitlab-deployer 
  • Crea una directory esperti deposito e collegarsi alla cache (non commettere errori)
    Questo passaggio può essere saltato se non prevedi di correre più corridori sulla stessa macchina.

    mkdir -p ~/.m2/repository
    ln -s /usr/cache/.m2/repository /home/gitlab-deployer/.m2/repository
  • Crea una chiave principale
    mvn --encrypt-master-password password
    {hnkle5BJ9HUHUMP+CXfGBl8dScfFci/mpsur/73tR2I=}
  • Crea il file ~/.m2/settings-security.xml
    <settingsSecurity>
    <master>{hnkle5BJ9HUHUMP+CXfGBl8dScfFci/mpsur/73tR2I=}</master>
    </settingsSecurity>
  • Crittografia della password dall'account Sonatype
    mvn --encrypt-password SONATYPE_PASSWORD
    {98Wv5+u+Tn0HX2z5G/kR4R8Z0WBgcDBgi7d12S/un+SCU7uxzaZGGmJ8Cu9pAZ2J}
  • Crea il file ~/.m2/settings.xml
    <settings>  
    <profiles>
        <profile>
            <id>env</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <properties>
                <gpg.passphrase>GPG_SECRET_KEY_PASSPHRASE</gpg.passphrase>
            </properties>
        </profile>
    </profiles>
    <servers>
        <server>
            <id>sonatype</id>
            <username>SONATYPE_USERNAME</username>
            <password>{98Wv5+u+Tn0HX2z5G/kR4R8Z0WBgcDBgi7d12S/un+SCU7uxzaZGGmJ8Cu9pAZ2J}</password>
        </server>
    </servers>
    </settings>

dove,
GPG_SECRET_KEY_PASSPHRASE: password della chiave GPG
SONATYPE_USERNAME - accesso all'account sonatype

Questo completa la configurazione del corridore, puoi procedere alla sezione CI GitLab

Al contenuto

Corridore condiviso

Generazione di chiavi GPG

  • Prima di tutto, devi creare una chiave GPG. Per fare ciò, installa gnupg.

    yum install -y gnupg

  • Generiamo una chiave rispondendo alle domande. Ho usato il mio nome e la mia email. Assicurati di specificare la password per la chiave.

    gpg --gen-key 

  • Recuperare le informazioni chiave

    gpg --list-keys -a
    pub   rsa3072 2019-04-24 [SC] [expires: 2021-04-23]
      2D0D1706366FC4AEF79669E24D09C55BBA3FD728
    uid           [ultimate] tttemp <[email protected]>
    sub   rsa3072 2019-04-24 [E] [expires: none]

  • Caricando la nostra chiave pubblica sul keyserver

    gpg --keyserver keys.gnupg.net --send-key 2D0D1706366FC4AEF79669E24D09C55BBA3FD728
    gpg: sending key 2D0D1706366FC4AEF79669E24D09C55BBA3FD728 to hkp server keys.gnupg.net

  • Ottenere una chiave privata

    gpg --export-secret-keys --armor 2D0D1706366FC4AEF79669E24D09C55BBA3FD728
    -----BEGIN PGP PRIVATE KEY BLOCK-----
    lQWGBFzAqp8BDADN41CPwJ/gQwiKEbyA902DKw/WSB1AvZQvV/ZFV77xGeG4K7k5
    ...
    =2Wd2
    -----END PGP PRIVATE KEY BLOCK-----

  • Vai alle impostazioni del progetto -> Impostazioni -> CI/CD -> Variabili e salva la chiave privata in una variabile GPG_SECRET_KEY
    Configurazione di GitLab CI per caricare un progetto Java su Maven Central

Al contenuto

Configurazione Maven

  • Crea una chiave principale
    mvn --encrypt-master-password password
    {hnkle5BJ9HUHUMP+CXfGBl8dScfFci/mpsur/73tR2I=}
  • Vai alle impostazioni del progetto -> Impostazioni -> CI/CD -> Variabili e salva in una variabile SETTINGS_SECURITY_XML le seguenti righe:
    <settingsSecurity>
    <master>{hnkle5BJ9HUHUMP+CXfGBl8dScfFci/mpsur/73tR2I=}</master>
    </settingsSecurity>
  • Crittografia della password dall'account Sonatype
    mvn --encrypt-password SONATYPE_PASSWORD
    {98Wv5+u+Tn0HX2z5G/kR4R8Z0WBgcDBgi7d12S/un+SCU7uxzaZGGmJ8Cu9pAZ2J}
  • Vai alle impostazioni del progetto -> Impostazioni -> CI/CD -> Variabili e salva in una variabile SETTINGS_XML le seguenti righe:
    <settings>  
    <profiles>
        <profile>
            <id>env</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <properties>
                <gpg.passphrase>GPG_SECRET_KEY_PASSPHRASE</gpg.passphrase>
            </properties>
        </profile>
    </profiles>
    <servers>
        <server>
            <id>sonatype</id>
            <username>sonatype_username</username>
            <password>{98Wv5+u+Tn0HX2z5G/kR4R8Z0WBgcDBgi7d12S/un+SCU7uxzaZGGmJ8Cu9pAZ2J}</password>
        </server>
    </servers>
    </settings>

dove,
GPG_SECRET_KEY_PASSPHRASE: password della chiave GPG
SONATYPE_USERNAME - accesso all'account sonatype

Al contenuto

Distribuisci l'immagine della finestra mobile

  • Creiamo un Dockerfile abbastanza semplice per eseguire attività al momento della distribuzione con la versione desiderata di Java. Di seguito è riportato un esempio per alpine.

    FROM java:8u111-jdk-alpine
    RUN apk add gnupg maven git --update-cache 
    --repository http://dl-4.alpinelinux.org/alpine/edge/community/ --allow-untrusted && 
    mkdir ~/.m2/

  • Costruisci un contenitore per il tuo progetto

    docker build -t registry.gitlab.com/group/deploy .

  • Autentichiamo e carichiamo il contenitore nel registro.

    docker login -u USER -p PASSWORD registry.gitlab.com
    docker push registry.gitlab.com/group/deploy

Al contenuto

CI GitLab

Distribuire il progetto

Aggiungi il file .gitlab-ci.yml alla radice del progetto di distribuzione
Lo script presenta due attività di distribuzione che si escludono a vicenda. Rispettivamente Runner specifico o Runner condiviso.

.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

Al contenuto

progetto Java

Nei progetti Java che dovrebbero essere caricati su repository pubblici, è necessario aggiungere 2 passaggi per scaricare le versioni Release e Snapshot.

.gitlab-ci.yml

stages:
  - build
  - test
  - verify
  - deploy

<...>

Release:
  extends: .trigger_deploy
  # Запускать задачу только пo тегу.
  only:
    - tags

Snapshot:
  extends: .trigger_deploy
  # Запускаем задачу на публикацию SNAPSHOT версии вручную
  when: manual
  # Не запускать задачу, если проставлен тег.
  except:
    - tags

.trigger_deploy:
  stage: deploy
  variables:
    # Отключаем клонирование текущего проекта
    GIT_STRATEGY: none
    # Ссылка на триггер deploy-задачи
    URL: "https://gitlab.com/api/v4/projects/<deploy project ID>/trigger/pipeline"
    # Переменные deploy-задачи
    POST_DATA: "
      token=${DEPLOY_TOKEN}&
      ref=master&
      variables[DEPLOY]=${DEPLOY}&
      variables[DEPLOY_CI_REPOSITORY_URL]=${CI_REPOSITORY_URL}&
      variables[DEPLOY_CI_PROJECT_NAME]=${CI_PROJECT_NAME}&
      variables[DEPLOY_CI_COMMIT_SHA]=${CI_COMMIT_SHA}&
      variables[DEPLOY_CI_COMMIT_TAG]=${CI_COMMIT_TAG}
      "
  script:
    # Не использую cURL, так как с флагами --fail --show-error
    # он не выводит тело ответа, если HTTP код 400 и более 
    - wget --content-on-error -qO- ${URL} --post-data ${POST_DATA}

In questa soluzione sono andato un po' oltre e ho deciso di utilizzare un modello CI per i progetti Java.

Maggiori dettagli

Ho creato un progetto separato gitlab-ci in cui ha inserito il modello CI per i progetti Java comune.yml.

comune.yml

stages:
  - build
  - test
  - verify
  - deploy

variables:
  SONAR_ARGS: "
  -Dsonar.gitlab.commit_sha=${CI_COMMIT_SHA} 
  -Dsonar.gitlab.ref_name=${CI_COMMIT_REF_NAME} 
  "

.build_java_project:
  stage: build
  tags:
    - touchbit-shell
  variables:
    SKIP_TEST: "false"
  script:
    - mvn clean
    - mvn package -DskipTests=${SKIP_TEST}
  artifacts:
    when: always
    expire_in: 30 day
    paths:
      - "*/target/reports"

.build_sphinx_doc:
  stage: build
  tags:
    - touchbit-shell
  variables:
    DOCKERFILE: .indirect/docs/Dockerfile
  script:
    - docker build --no-cache -t ${CI_PROJECT_NAME}/doc -f ${DOCKERFILE} .

.junit_module_test_run:
  stage: test
  tags:
    - touchbit-shell
  variables:
    MODULE: ""
  script:
    - cd ${MODULE}
    - mvn test
  artifacts:
    when: always
    expire_in: 30 day
    paths:
      - "*/target/reports"

.junit_test_run:
  stage: test
  tags:
    - touchbit-shell
  script:
    - mvn test
  artifacts:
    when: always
    expire_in: 30 day
    paths:
    - "*/target/reports"

.sonar_review:
  stage: verify
  tags:
    - touchbit-shell
  dependencies: []
  script:
    - >
      if [ "$CI_BUILD_REF_NAME" == "master" ]; then
        mvn compile sonar:sonar -Dsonar.login=$SONAR_LOGIN $SONAR_ARGS
      else
        mvn compile sonar:sonar -Dsonar.login=$SONAR_LOGIN $SONAR_ARGS -Dsonar.analysis.mode=preview
      fi

.trigger_deploy:
  stage: deploy
  tags:
    - touchbit-shell
  variables:
    URL: "https://gitlab.com/api/v4/projects/10345765/trigger/pipeline"
    POST_DATA: "
      token=${DEPLOY_TOKEN}&
      ref=master&
      variables[DEPLOY]=${DEPLOY}&
      variables[DEPLOY_CI_REPOSITORY_URL]=${CI_REPOSITORY_URL}&
      variables[DEPLOY_CI_PROJECT_NAME]=${CI_PROJECT_NAME}&
      variables[DEPLOY_CI_COMMIT_SHA]=${CI_COMMIT_SHA}&
      variables[DEPLOY_CI_COMMIT_TAG]=${CI_COMMIT_TAG}
      "
  script:
  - wget --content-on-error -qO- ${URL} --post-data ${POST_DATA}

.trigger_release_deploy:
  extends: .trigger_deploy
  only:
    - tags

.trigger_snapshot_deploy:
  extends: .trigger_deploy
  when: manual
  except:
    - tags

Di conseguenza, negli stessi progetti Java, .gitlab-ci.yml appare molto compatto e non dettagliato

.gitlab-ci.yml

include: https://gitlab.com/TouchBIT/gitlab-ci/raw/master/common.yml

Shields4J:
  extends: .build_java_project

Sphinx doc:
  extends: .build_sphinx_doc
  variables:
    DOCKERFILE: .docs/Dockerfile

Sonar review:
  extends: .sonar_review
  dependencies:
    - Shields4J

Release:
  extends: .trigger_release_deploy

Snapshot:
  extends: .trigger_snapshot_deploy

Al contenuto

configurazione pom.xml

Questo argomento è descritto in grande dettaglio. Googolplex в Configurazione di Maven per firmare e caricare automaticamente gli artefatti nei repository di snapshot e staging, quindi descriverò alcune sfumature dell'utilizzo dei plugin. Descriverò anche quanto puoi usarlo in modo semplice e rilassato nexus-staging-maven-pluginse non vuoi o non puoi utilizzare org.sonatype.oss:oss-parent come genitore per il tuo progetto.

plugin-install-maven

Installa i moduli nel repository locale.
Molto utile per la verifica locale di soluzioni in altri progetti, nonché per un checksum.

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-install-plugin</artifactId>
  <executions>
    <execution>
      <id>install-project</id>
      <!-- Если у вас многомодульный проект с деплоем родительского помика -->
      <phase>install</phase>
      <!-- Явно указываем файлы для локальной установки -->
      <configuration>
        <file>target/${project.artifactId}-${project.version}.jar</file>
```target/${project.artifactId}-${project.version}-sources.jar</sources>
        <pomFile>dependency-reduced-pom.xml</pomFile>
        <!-- Принудительное обновление метаданных проекта -->
        <updateReleaseInfo>true</updateReleaseInfo>
        <!-- Контрольные суммы для проверки целостности -->
        <createChecksum>true</createChecksum>
      </configuration>
    </execution>
  </executions>
</plugin>

Al contenuto

plugin-maven-javadoc

Generazione di Javadoc per il progetto.

<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 hai un modulo che non contiene Java (ad esempio solo risorse)
Oppure non vuoi generare Javadoc in linea di principio, quindi per aiutare maven-jar-plugin

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-jar-plugin</artifactId>
  <executions>
    <execution>
      <id>empty-javadoc-jar</id>
      <phase>generate-resources</phase>
      <goals>
        <goal>jar</goal>
      </goals>
      <configuration>
        <classifier>javadoc</classifier>
        <classesDirectory>${basedir}/javadoc</classesDirectory>
      </configuration>
    </execution>
  </executions>
</plugin>

Al contenuto

plugin-maven-gpg

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-gpg-plugin</artifactId>
  <executions>
    <execution>
      <id>sign-artifacts</id>
      <!-- Сборка будет падать, если отсутствует GPG ключ -->
      <!-- Подписываем артефакты только на фазе deploy -->
      <phase>deploy</phase>
      <goals>
        <goal>sign</goal>
      </goals>
    </execution>
  </executions>
</plugin>

Al contenuto

nexus-staging-maven-plugin

configurazione:

<project>
  <!-- ... -->
  <build>
    <plugins>
      <!-- ... -->
      <plugin>
        <groupId>org.sonatype.plugins</groupId>
        <artifactId>nexus-staging-maven-plugin</artifactId>
      </plugin>
    </plugins>
    <pluginManagement>
      <plugins>
        <plugin>
          <groupId>org.sonatype.plugins</groupId>
          <artifactId>nexus-staging-maven-plugin</artifactId>
          <extensions>true</extensions>
          <configuration>
            <serverId>sonatype</serverId>
            <nexusUrl>https://oss.sonatype.org/</nexusUrl>
            <!-- Обновляем метаданные, чтобы пометить артефакт как release -->
            <!-- Не влияет на snapshot версии -->
            <updateReleaseInfo>true</updateReleaseInfo>
          </configuration>
        </plugin>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-deploy-plugin</artifactId>
          <configuration>
            <!-- Отключаем плагин -->
            <skip>true</skip>
          </configuration>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
  <distributionManagement>
    <snapshotRepository>
      <id>sonatype</id>
      <name>Nexus Snapshot Repository</name>
      <url>https://oss.sonatype.org/content/repositories/snapshots/</url>
    </snapshotRepository>
    <repository>
      <id>sonatype</id>
      <name>Nexus Release Repository</name>
      <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
    </repository>
  </distributionManagement>
</project>

Se hai un progetto multi-modulo e non hai bisogno di caricare un modulo specifico nel repository, devi aggiungere al pom.xml di questo modulo nexus-staging-maven-plugin con bandiera skipNexusStagingDeployMojo

<build>
  <plugins>
    <plugin>
      <groupId>org.sonatype.plugins</groupId>
      <artifactId>nexus-staging-maven-plugin</artifactId>
      <configuration>
        <skipNexusStagingDeployMojo>true</skipNexusStagingDeployMojo>
      </configuration>
    </plugin>
  </plugins>
</build>

Dopo il caricamento delle versioni snapshot/release sono disponibili in repository di staging

<repositories>
  <repository>
    <id>SonatypeNexus</id>
    <url>https://oss.sonatype.org/content/groups/staging/</url>
    <!-- Не надо указывать флаги snapshot/release для репозитория -->
  </repository>
</repositories>

Più vantaggi

  • Un elenco molto ricco di obiettivi per lavorare con il repository Nexus (mvn help:describe -Dplugin=org.sonatype.plugins:nexus-staging-maven-plugin).
  • Controllo automatico del rilascio per la scaricabilità in Maven Central

Al contenuto

risultato

Pubblicazione di una versione ISTANTANEA

Quando si crea un progetto, è possibile avviare manualmente un'attività per scaricare la versione SNAPSHOT su nexus

Configurazione di GitLab CI per caricare un progetto Java su Maven Central

Quando questa attività viene avviata, viene attivata l'attività corrispondente nel progetto di distribuzione (esempio).

tronco ritagliato

Running with gitlab-runner 11.10.0 (3001a600)
  on Deploy runner JSKWyxUw
Using Shell executor...
Running on ih1174328.vds.myihor.ru...
Skipping Git repository setup
Skipping Git checkout
Skipping Git submodules setup
$ rm -rf .* *
$ git config --global credential.helper store
$ echo "https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com" >> ~/.git-credentials
$ git clone ${DEPLOY_CI_REPOSITORY_URL} .
Cloning into 'shields4j'...
$ git checkout ${DEPLOY_CI_COMMIT_SHA}
Note: checking out '850f86aa317194395c5387790da1350e437125a7'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:
  git checkout -b new_branch_name
HEAD is now at 850f86a... skip deploy test-core
$ for pom in $(find . -name pom.xml); do # collapsed multi-line command
$ if [[ "${DEPLOY_CI_COMMIT_TAG}" != "" ]]; then # collapsed multi-line command
[INFO] Scanning for projects...
[INFO] Inspecting build with total of 4 modules...
[INFO] Installing Nexus Staging features:
[INFO]   ... total of 4 executions of maven-deploy-plugin replaced with nexus-staging-maven-plugin
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Build Order:
[INFO] 
[INFO] Shields4J                                                          [pom]
[INFO] test-core                                                          [jar]
[INFO] Shields4J client                                                   [jar]
[INFO] TestNG listener                                                    [jar]
[INFO] 
[INFO] --------------< org.touchbit.shields4j:shields4j-parent >---------------
[INFO] Building Shields4J 1.0.0                                           [1/4]
[INFO] --------------------------------[ pom ]---------------------------------
[INFO] 
[INFO] --- versions-maven-plugin:2.5:set (default-cli) @ shields4j-parent ---
[INFO] Searching for local aggregator root...
[INFO] Local aggregation root: /home/gitlab-deployer/JSKWyxUw/0/TouchBIT/deploy/shields4j
[INFO] Processing change of org.touchbit.shields4j:shields4j-parent:1.0.0 -> 1.0.0-SNAPSHOT
[INFO] Processing org.touchbit.shields4j:shields4j-parent
[INFO]     Updating project org.touchbit.shields4j:shields4j-parent
[INFO]         from version 1.0.0 to 1.0.0-SNAPSHOT
[INFO] 
[INFO] Processing org.touchbit.shields4j:client
[INFO]     Updating parent org.touchbit.shields4j:shields4j-parent
[INFO]         from version 1.0.0 to 1.0.0-SNAPSHOT
[INFO]     Updating dependency org.touchbit.shields4j:test-core
[INFO]         from version 1.0.0 to 1.0.0-SNAPSHOT
[INFO] 
[INFO] Processing org.touchbit.shields4j:test-core
[INFO]     Updating parent org.touchbit.shields4j:shields4j-parent
[INFO]         from version 1.0.0 to 1.0.0-SNAPSHOT
[INFO] 
[INFO] Processing org.touchbit.shields4j:testng
[INFO]     Updating parent org.touchbit.shields4j:shields4j-parent
[INFO]         from version 1.0.0 to 1.0.0-SNAPSHOT
[INFO]     Updating dependency org.touchbit.shields4j:client
[INFO]         from version 1.0.0 to 1.0.0-SNAPSHOT
[INFO]     Updating dependency org.touchbit.shields4j:test-core
[INFO]         from version 1.0.0 to 1.0.0-SNAPSHOT
[INFO] 
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO] 
[INFO] Shields4J 1.0.0 .................................... SUCCESS [  0.992 s]
[INFO] test-core .......................................... SKIPPED
[INFO] Shields4J client ................................... SKIPPED
[INFO] TestNG listener 1.0.0 .............................. SKIPPED
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.483 s
[INFO] Finished at: 2019-04-21T02:40:42+03:00
[INFO] ------------------------------------------------------------------------
$ mvn clean deploy -DskipTests=${SKIP_TESTS}
[INFO] Scanning for projects...
[INFO] Inspecting build with total of 4 modules...
[INFO] Installing Nexus Staging features:
[INFO]   ... total of 4 executions of maven-deploy-plugin replaced with nexus-staging-maven-plugin
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Build Order:
[INFO] 
[INFO] Shields4J                                                          [pom]
[INFO] test-core                                                          [jar]
[INFO] Shields4J client                                                   [jar]
[INFO] TestNG listener                                                    [jar]
[INFO] 
[INFO] --------------< org.touchbit.shields4j:shields4j-parent >---------------
[INFO] Building Shields4J 1.0.0-SNAPSHOT                                  [1/4]
[INFO] --------------------------------[ pom ]---------------------------------
...
DELETED
...
[INFO]  * Bulk deploy of locally gathered snapshot artifacts finished.
[INFO] Remote deploy finished with success.
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO] 
[INFO] Shields4J 1.0.0-SNAPSHOT ........................... SUCCESS [  2.375 s]
[INFO] test-core .......................................... SUCCESS [  3.929 s]
[INFO] Shields4J client ................................... SUCCESS [  3.815 s]
[INFO] TestNG listener 1.0.0-SNAPSHOT ..................... SUCCESS [ 36.134 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 47.629 s
[INFO] Finished at: 2019-04-21T02:41:32+03:00
[INFO] ------------------------------------------------------------------------

Di conseguenza, viene caricata la versione Nexus 1.0.0-ISTANTANEA.

Tutte le versioni degli snapshot possono essere rimosse dal repository sul sito oss.sonatype.org sotto il tuo account.

Configurazione di GitLab CI per caricare un progetto Java su Maven Central

Al contenuto

Pubblicazione della versione di rilascio

Quando il tag è impostato, l'attività corrispondente nel progetto di distribuzione viene attivata automaticamente per caricare la versione di rilascio su nexus (esempio).

Configurazione di GitLab CI per caricare un progetto Java su Maven Central

La parte migliore è che il rilascio ravvicinato si attiva automaticamente in Nexus.

[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 qualcosa è andato storto, l'attività fallirà

[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 &lt;a href=http://keys.gnupg.net:11371/&gt;http://keys.gnupg.net:11371/&lt;/a&gt;. 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] ------------------------------------------------------------------------

Di conseguenza, ci resta solo una scelta. Oppure elimina questa versione o pubblica.

Configurazione di GitLab CI per caricare un progetto Java su Maven Central

Dopo il rilascio, dopo un po' di tempo, gli artefatti saranno disponibili Configurazione di GitLab CI per caricare un progetto Java su Maven Central

offtop

È stata una rivelazione per me che Maven indicizzi altri repository pubblici.
Ho dovuto aggiungere robots.txt perché indicizzava il mio vecchio repository.

Al contenuto

conclusione

Quello che abbiamo

  • Un progetto di distribuzione separato in cui è possibile implementare diverse attività CI per caricare gli artefatti nei repository pubblici per vari linguaggi di sviluppo.
  • Il progetto di distribuzione è isolato da interferenze esterne e può essere modificato solo dagli utenti con i ruoli di Proprietario e Manutentore.
  • Un Runner specifico separato con una cache "attiva" per eseguire solo le attività di distribuzione.
  • Pubblicazione delle versioni snapshot/release in un repository pubblico.
  • Controllo automatico della versione di rilascio per essere pronta per la pubblicazione in Maven Central.
  • Protezione contro la pubblicazione automatica delle versioni "grezze" in Maven Central.
  • Crea e pubblica versioni di snapshot “al clic”.
  • Repository unico per ottenere versioni snapshot/release.
  • Pipeline generale per creare/testare/pubblicare un progetto Java.

La configurazione di GitLab CI non è un argomento così complicato come sembra a prima vista. È sufficiente impostare la CI chiavi in ​​\uXNUMXb\uXNUMXbmano un paio di volte e ora sei tutt'altro che un dilettante in questa materia. Inoltre, la documentazione di GitLab è molto ridondante. Non aver paura di fare il primo passo. La strada appare sotto i passi di chi cammina (non ricordo chi lo ha detto :)

Sarò felice di ricevere un feedback.

Nel prossimo articolo, ti mostrerò come configurare GitLab CI per eseguire attività di test di integrazione in modo competitivo (eseguendo servizi di test con docker-compose) se disponi di un solo shell runner.

Al contenuto

Fonte: habr.com

Aggiungi un commento