Configurarea GitLab CI pentru încărcarea proiectului Java în Maven Central

Acest articol este destinat dezvoltatorilor Java care au nevoie să publice rapid produsele lor în depozitele Sonatype și/sau Maven Central folosind GitLab. În acest articol, voi explica cum se configurează gitlab-runner, gitlab-ci și maven-plugin pentru a rezolva această problemă.

Prerequisites:

  • Stocarea sigură a cheilor mvn și GPG.
  • Executarea în siguranță a sarcinilor CI publice.
  • Încărcarea artefactelor (release/snapshot) în depozitele publice.
  • Verificarea automată a versiunilor release pentru publicare în Maven Central.
  • O soluție generală pentru încărcarea artefactelor în depozit pentru mai multe proiecte.
  • Simplitate și ușurință în utilizare.

Cuprins

Informații generale

  • O descriere detaliată a mecanismului de publicare a artefactelor în Maven Central prin serviciul de găzduire a depozitelor Sonatype OSS este deja descrisă în acest articol de către utilizator Googolplex, prin urmare, în locurile necesare voi face referire la acest articol.
  • În prealabil, ne înregistrăm în Sonatype JIRA și deschidem un tichet pentru deschiderea depozitului (citiți mai multe în secțiunea Creăm un tichet pe Sonatype JIRA). După deschiderea depozitului, combinația login/parolă de la JIRA (ulterior contul Sonatype) va fi folosită pentru încărcarea artefactelor în Sonatype Nexus.
  • A doua parte a procesului de generare a cheii GPG este descrisă foarte succint. Citiți mai multe în secțiunea Configurarea GnuPG pentru semnarea artefactelor
  • Dacă folosiți consola Linux pentru a genera cheia GPG (gnupg/gnupg2), atunci trebuie să instalați rng-tools pentru generarea entropiei. În caz contrar, generarea cheii poate dura foarte mult.
  • Servicii de stocare a cheilor GPG publice

La conținut

Configurarea proiectului de deploy în GitLab

  • În primul rând, este necesar să creați și să configurați un proiect în care să fie stocat pipeline-ul pentru deploy-ul artefactelor. Proiectul meu se numește simplu și fără pretenții — deploy
  • După crearea depozitului, este necesar să restricționăm accesul la modificarea depozitului.
    Accesăm proiectul -> Setări -> Repositoriu -> Ramuri protejate. Eliminăm toate regulile și adăugăm o singură regulă cu Wildcard * având drepturi de push și merge doar pentru utilizatorii cu rol de Menținători. Această regulă va funcționa pentru toți utilizatorii atât ai acestui proiect, cât și ai grupului din care face parte acest proiect.
    Configurarea GitLab CI pentru încărcarea proiectului Java în Maven Central
  • Dacă există mai mulți menținători, cea mai bună soluție va fi limitarea accesului la proiect în general.
    Accesăm proiectul -> Setări -> General -> Vizibilitate, funcții ale proiectului, permisiuni și setăm Vizibilitatea proiectului la valoarea Privat.
    Am un proiect public, deoarece folosesc propriul meu GitLab Runner și accesul la modificarea repertoriului este disponibil doar pentru mine. De asemenea, nu este în interesul meu să expun informații private în jurnalele pipeline-urilor publice.
  • Restricționarea regulilor de modificare a repertoriului
    Accesăm proiectul -> Setări -> Repositoriu -> Reguli de push și setăm flagurile Restricționare a autorului, Verifică dacă autorul este un utilizator GitLab. De asemenea, recomand configurarea semnăturii commit-urilor, și setăm flagul Refuză commit-urile nesemnate.
  • Apoi trebuie să configurăm un trigger pentru a lansa sarcini.
    Accesăm proiectul -> Setări -> CI / CD -> Trigger-e ale pipeline-ului și creăm un nou token de trigger.
    Acest token poate fi adăugat imediat în configurația globală a variabilelor pentru grupul de proiecte.
    Accesăm grupul -> Setări -> CI / CD -> Variabile și adăugăm variabila DEPLOY_TOKEN cu token-ul de trigger în valoare.

La conținut

GitLab Runner

În această secțiune este descrisă configurația pentru lansarea sarcinilor pe deplasare folosind un runner propriu (Specific) și unul public (Shared).

Runner specific

Folosesc runner-e proprii, deoarece, înainte de toate, este convenabil, rapid și ieftin.
Pentru runner recomand un VDS linux cu 1 CPU, 2 GB RAM, 20 GB HDD. Prețul este de aproximativ ~3000₽ pe an.

Runner-ul meu

Pentru runner am ales un VDS cu 4 CPU, 4 GB RAM, 50 GB SSD. A costat ~11000₽ și nu am regretat niciodată.
Am în total 7 mașini. 5 pe aruba și 2 pe ihor.

Deci, avem un runner. Acum îl vom configura.
Ne conectăm la mașină prin SSH și instalăm java, git, maven, gnupg2.

La conținut

Instalăm gitlab runner

  • Creăm un nou grup runner
    sudo groupadd runner
  • Creăm un director pentru cache-ul maven și atribuim drepturile grupului runner
    Acest pas poate fi sărit dacă nu intenționați să rulați mai multe runner-e pe aceeași mașină.
    mkdir -p /usr/cache/.m2/repository
    chown -R :runner /usr/cache
    chmod -R 770 /usr/cache
  • Creăm utilizatorul gitlab-deployer și îl adăugăm în grup runner
    useradd -m -d /home/gitlab-deployer gitlab-deployer
    usermod -a -G runner gitlab-deployer
  • Adăugăm în fișier /etc/ssh/sshd_config următoarea linie
    AllowUsers root@* gitlab-deployer@127.0.0.1
  • Revenim sshd
    systemctl restart sshd
  • Setăm o parolă pentru utilizator gitlab-deployer (poate fi simplă, deoarece există o limitare pentru localhost)
    passwd gitlab-deployer
  • Instalăm 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
  • Accesăm site-ul gitlab.com -> deploy-project -> Settings -> CI/CD -> Runners -> Specific Runners și copiem token-ul de înregistrare

Screenshot

Configurarea GitLab CI pentru încărcarea proiectului Java în Maven Central

  • Înregistrăm runner-ul
    gitlab-runner register --config /etc/gitlab-runner/gitlab-deployer-config.toml

Procesul

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!
  • Verificăm că runner-ul este înregistrat. Accesăm site-ul gitlab.com -> deploy-project -> Settings -> CI/CD -> Runners -> Specific Runners -> Runners activated for this project

Screenshot

Configurarea GitLab CI pentru încărcarea proiectului Java în Maven Central

  • Adăugăm separat serviciul /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
  • Pornim serviciul.
    systemctl enable gitlab-deployer.service
    systemctl start gitlab-deployer.service
    systemctl status gitlab-deployer.service
  • Verificăm că runner-ul este pornit.

Exemplu

Configurarea GitLab CI pentru încărcarea proiectului Java în Maven Central

La conținut

Generarea cheilor GPG

  • De pe aceeași mașină, ne conectăm prin ssh cu utilizatorul gitlab-deployer (acest detaliu este important pentru generarea cheii GPG)
    ssh gitlab-deployer@127.0.0.1
  • Generăm cheia răspunzând la întrebări. Am folosit numele și emailul proprii.
    Asigurați-vă că specificați o parolă pentru cheie. Această cheie va fi folosită pentru a semna artefactele.
    gpg --gen-key 
  • Verificăm
    gpg --list-keys -a
    /home/gitlab-deployer/.gnupg/pubring.gpg
    ----------------------------------------
    pub   4096R/00000000 2019-04-19
    uid                  Petruha Petrov 
    sub   4096R/11111111 2019-04-19
  • Încărcăm cheia noastră publică pe serverul de chei
    gpg --keyserver keys.gnupg.net --send-key 00000000
    gpg: sending key 00000000 to hkp server keys.gnupg.net

La conținut

Configurarea Maven

  • Ne conectăm cu utilizatorul gitlab-deployer
    su gitlab-deployer 
  • Creăm directorul maven repository și creăm un link către cache (nu greșiți)
    Această etapă poate fi sărită dacă nu intenționați să rulați mai multe runner-e pe aceeași mașină.
    mkdir -p ~/\.m2/repository
    ln -s /usr/cache/\.m2/repository /home/gitlab-deployer/\.m2/repository
  • Creăm cheia principală
    mvn --encrypt-master-password parola
    {hnkle5BJ9HUHUMP+CXfGBl8dScfFci/mpsur/73tR2I=}
  • Creăm fișierul ~/\.m2/settings-security.xml
    {hnkle5BJ9HUHUMP+CXfGBl8dScfFci/mpsur/73tR2I=}
  • Criptăm parola pentru contul Sonatype
    mvn --encrypt-password SONATYPE_PASSWORD
    {98Wv5+u+Tn0HX2z5G/kR4R8Z0WBgcDBgi7d12S/un+SCU7uxzaZGGmJ8Cu9pAZ2J}
  • Creăm fișierul ~/\.m2/settings.xml
    env
            
                true
            
            
                GPG_SECRET_KEY_PASSPHRASE
            
        
    
    
        
            sonatype
            SONATYPE_USERNAME
            {98Wv5+u+Tn0HX2z5G/kR4R8Z0WBgcDBgi7d12S/un+SCU7uxzaZGGmJ8Cu9pAZ2J}

unde,
GPG_SECRET_KEY_PASSPHRASE — parola pentru cheia GPG
SONATYPE_USERNAME — utilizatorul contului sonatype

Aici configurarea runner-ului este completă, putem să trecem la secțiunea GitLab CI

La conținut

Shared Runner

Generarea cheilor GPG

  • În primul rând, trebuie să creăm cheia GPG. Pentru aceasta, instalăm gnupg.
    yum install -y gnupg
  • Generăm cheia răspunzând la întrebări. Am folosit numele și emailul proprii. Asigurați-vă că specificați o parolă pentru cheie.
    gpg --gen-key 
  • Afișăm informațiile despre cheie
    gpg --list-keys -a
    pub   rsa3072 2019-04-24 [SC] [expires: 2021-04-23]
      2D0D1706366FC4AEF79669E24D09C55BBA3FD728
    uid           [ultimate] tttemp 
    sub   rsa3072 2019-04-24 [E] [expires: none]
  • Încărcăm cheia noastră publică pe serverul de chei
    gpg --keyserver keys.gnupg.net --send-key 2D0D1706366FC4AEF79669E24D09C55BBA3FD728
    gpg: trimitere cheie 2D0D1706366FC4AEF79669E24D09C55BBA3FD728 către server hkp keys.gnupg.net
  • Obținem cheia privată
    gpg --export-secret-keys --armor 2D0D1706366FC4AEF79669E24D09C55BBA3FD728
    -----BEGIN PGP PRIVATE KEY BLOCK-----
    lQWGBFzAqp8BDADN41CPwJ/gQwiKEbyA902DKw/WSB1AvZQvV/ZFV77xGeG4K7k5
    ...
    =2Wd2
    -----END PGP PRIVATE KEY BLOCK-----
  • Trecem la setările proiectului -> Settings -> CI / CD -> Variables și salvăm cheia privată în variabila GPG_SECRET_KEY
    Configurarea GitLab CI pentru încărcarea proiectului Java în Maven Central

La conținut

Configurarea Maven

  • Creăm cheia principală
    mvn --encrypt-master-password parola
    {hnkle5BJ9HUHUMP+CXfGBl8dScfFci/mpsur/73tR2I=}
  • Trecem la setările proiectului -> Settings -> CI / CD -> Variables și salvăm în variabila SETTINGS_SECURITY_XML următoarele linii:
    {hnkle5BJ9HUHUMP+CXfGBl8dScfFci/mpsur/73tR2I=}
  • Criptăm parola pentru contul Sonatype
    mvn --encrypt-password SONATYPE_PASSWORD
    {98Wv5+u+Tn0HX2z5G/kR4R8Z0WBgcDBgi7d12S/un+SCU7uxzaZGGmJ8Cu9pAZ2J}
  • Trecem la setările proiectului -> Settings -> CI / CD -> Variables și salvăm în variabila SETTINGS_XML următoarele linii:
    env
            
                true
            
            
                GPG_SECRET_KEY_PASSPHRASE
            
        
    
    
        
            sonatype
            sonatype_username
            {98Wv5+u+Tn0HX2z5G/kR4R8Z0WBgcDBgi7d12S/un+SCU7uxzaZGGmJ8Cu9pAZ2J}

unde,
GPG_SECRET_KEY_PASSPHRASE — parola pentru cheia GPG
SONATYPE_USERNAME — utilizatorul contului sonatype

La conținut

Deploy imagine docker

  • Creăm un Dockerfile destul de simplu pentru a rula sarcini de deploy cu versiunea dorită de Java. Mai jos este un exemplu pentru 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/
  • Construim un container pentru proiectul dumneavoastră
    docker build -t registry.gitlab.com/group/deploy .
  • Ne autentificăm și încărcăm containerul în registry.
    docker login -u USER -p PASSWORD registry.gitlab.com
    docker push registry.gitlab.com/group/deploy

La conținut

GitLab CI

Deploy proiect

Adăugăm în rădăcina proiectului un fișier .gitlab-ci.yml
Scriptul conține două sarcini mutual exclusive pentru deploy. Specific Runner sau Shared Runner respectiv.

.gitlab-ci.yml

stages:
  - deploy

Specific Runner:
  extends: .java_deploy_template
  # Sarcina va fi executată pe shell-runner-ul dumneavoastră
  tags:
    - deploy

Shared Runner:
  extends: .java_deploy_template
  # Sarcina va fi executată pe public docker-runner
  tags:
    - docker
  # Imaginea din secțiunea GitLab Runner -> Shared Runner -> Docker
  image: registry.gitlab.com/group/deploy-project:latest
  before_script:
    # Importăm cheia GPG
    - printf "${GPG_SECRET_KEY}" | gpg --batch --import
    # Salvăm configurația maven
    - printf "${SETTINGS_SECURITY_XML}" > ~/.m2/settings-security.xml
    - printf "${SETTINGS_XML}" > ~/.m2/settings.xml

.java_deploy_template:
  stage: deploy
  # Sarcina va fi declanșată printr-un trigger, dacă variabila DEPLOY are valoarea java
  only:
    variables:
    - $DEPLOY == "java"
  variables:
    # dezactivăm clonarea proiectului curent
    GIT_STRATEGY: none
  script:
    # Oferim posibilitatea de a salva parola în forma necriptată
    - git config --global credential.helper store
    # Salvăm credențialele temporare ale utilizatorului gitlab-ci-token
    # Tokenul funcționează pentru toate proiectele publice gitlab.com și pentru proiectele grupului
    - echo "https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com" >> ~/.git-credentials
    # Curățăm complet directorul curent
    - rm -rf .* *
    # Clonăm proiectul pe care îl vom desfășura în Sonatype Nexus
    - git clone ${DEPLOY_CI_REPOSITORY_URL} .
    # Ne schimbăm pe commitul dorit
    - git checkout ${DEPLOY_CI_COMMIT_SHA} -f
    # Dacă vreun pom.xml conține parametru autoReleaseAfterClose, terminăm build-ul.
    # În caz contrar, există riscul de a încărca artefacte brute în maven central
    - >
      for pom in $(find . -name pom.xml); do
        if [[ $(grep -q autoReleaseAfterClose "$pom" && echo $?) == 0 ]]; then
          echo "File $pom contains prohibited setting: ";
          exit 1;
        fi;
      done
    # Dacă parametrul DEPLOY_CI_COMMIT_TAG este gol, forțăm setarea versiunii 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
    # Rulăm sarcina de build și desfășurare a artefactelor
    - mvn clean deploy -DskipTests=true

La conținut

Proiect Java

În proiectele Java care sunt destinate să fie încărcate în repositoare publice, este necesar să se adauge 2 etape pentru încărcarea versiunilor Release și Snapshot.

.gitlab-ci.yml

etape:
  - construire
  - testare
  - verificare
  - desfășurare



Release:
  extinde: .trigger_deploy
  # Rulează sarcina doar pe etichete.
  doar:
    - etichete

Snapshot:
  extinde: .trigger_deploy
  # Executăm sarcina de publicare a versiunii SNAPSHOT manual
  când: manual
  # Nu rulați sarcina, dacă este setată o etichetă.
  except:
    - etichete

.trigger_deploy:
  stadiu: desfășurare
  variabile:
    # Dezactivăm clonarea proiectului curent
    GIT_STRATEGY: none
    # Link către trigger-ul sarcinii de desfășurare
    URL: "https://gitlab.com/api/v4/projects//trigger/pipeline"
    # Variabilele sarcinii de desfășurare
    POST_DATA: "
      token=${DEPLOY_TOKEN}&
      ref=master&
      variabile[DEPLOY]=${DEPLOY}&
      variabile[DEPLOY_CI_REPOSITORY_URL]=${CI_REPOSITORY_URL}&
      variabile[DEPLOY_CI_PROJECT_NAME]=${CI_PROJECT_NAME}&
      variabile[DEPLOY_CI_COMMIT_SHA]=${CI_COMMIT_SHA}&
      variabile[DEPLOY_CI_COMMIT_TAG]=${CI_COMMIT_TAG}
      "
  script:
    # Nu folosesc cURL deoarece cu opțiunile --fail --show-error
    # nu afișează corpul răspunsului, dacă codul HTTP este 400 sau mai mare 
    - wget --content-on-error -qO- ${URL} --post-data ${POST_DATA}

În această soluție, am mers puțin mai departe și am decis să folosesc un singur șablon CI pentru proiectele Java.

Mai în detaliu

Am creat un proiect separat gitlab-ci în care am plasat un șablon CI pentru proiectele Java common.yml.

common.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

Ca urmare, fișierele .gitlab-ci.yml din proiectele java sunt foarte compacte și concise.

.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

La conținut

Configurarea pom.xml

Această temă este descrisă foarte detaliat. Googolplex în Configurarea Maven pentru semnarea automată și încărcarea artefactelor în repozitoarele snapshot și staging., așa că voi descrie câteva nuanțe ale utilizării plugin-urilor. De asemenea, voi explica cât de ușor și fără stres poate fi utilizat. nexus-staging-maven-plugin, dacă nu doriți sau nu puteți folosi org.sonatype.oss:oss-parent ca părinte pentru proiectul dvs.

maven-install-plugin

Instalează modulele în depozitul local.
Este foarte util pentru verificarea locală a soluțiilor în alte proiecte, dar și pentru suma de control.

org.apache.maven.plugins
  maven-install-plugin
  
    
      install-project
      
      install
      
      
        target/${project.artifactId}-${project.version}.jar
        target/${project.artifactId}-${project.version}-sources.jar
        dependency-reduced-pom.xml
        
        true
        
        true

La conținut

maven-javadoc-plugin

Generarea javadoc pentru proiect.

org.apache.maven.plugins
  maven-javadoc-plugin
  
    
      
        jar
      
      
      prepare-package
      
        
        true
        true
        
        false

Dacă aveți un modul care nu conține java (de exemplu doar resurse)
Sau dacă nu doriți să generați javadoc, atunci acesta este de ajutor maven-jar-plugin

org.apache.maven.plugins
  maven-jar-plugin
  
    
      empty-javadoc-jar
      generate-resources
      
        jar
      
      
        javadoc
        ${basedir}/javadoc

La conținut

maven-gpg-plugin

org.apache.maven.plugins
  maven-gpg-plugin
  
    
      sign-artifacts
      
      
      deploy
      
        sign

La conținut

nexus-staging-maven-plugin

Configurație:


  
    
      
      
        org.sonatype.plugins
        nexus-staging-maven-plugin
      
    
    
      
        
          org.sonatype.plugins
          nexus-staging-maven-plugin
          true
          
            sonatype
            https://oss.sonatype.org/
            
            
            true
          
        
        
          org.apache.maven.plugins
          maven-deploy-plugin
          
            
            true
          
        
      
    
  
  
    
      sonatype
      Nexus Snapshot Repository
      https://oss.sonatype.org/content/repositories/snapshots/
    
    
      sonatype
      Nexus Release Repository
      https://oss.sonatype.org/service/local/staging/deploy/maven2/

Dacă aveți un proiect multimodul și nu aveți nevoie să încărcați un anumit modul în depozit, atunci în pom.xml al acelui modul trebuie să adăugați nexus-staging-maven-plugin cu flag-ul skipNexusStagingDeployMojo

org.sonatype.plugins
      nexus-staging-maven-plugin
      
        true

După încărcarea versiunilor snapshot/release, acestea sunt disponibile în depozitul staging

SonatypeNexus
    https://oss.sonatype.org/content/groups/staging/
    

Încă câteva avantaje

  • O listă foarte bogată de scopuri pentru lucrul cu depozitul nexus (mvn help:describe -Dplugin=org.sonatype.plugins:nexus-staging-maven-plugin).
  • Verificarea automată a release-ului pentru posibilitatea de încărcare în maven central

La conținut

Rezultatul

Publicarea versiunii SNAPSHOT

La construirea proiectului există posibilitatea de a porni manual sarcina de încărcare a versiunii SNAPSHOT în nexus

Configurarea GitLab CI pentru încărcarea proiectului Java în Maven Central

La declanșarea acestei sarcini, se declanșează sarcina corespunzătoare în proiectul deploy (exemplu).

Log redus

Rulând cu gitlab-runner 11.10.0 (3001a600)
  pe Deploy runner JSKWyxUw
Folosind executor Shell...
Rulând pe ih1174328.vds.myihor.ru...
Omit configurarea repository-ului Git
Omit checkout-ul Git
Omit configurarea submodulelor Git
$ 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} .
Clonare în 'shields4j'...
$ git checkout ${DEPLOY_CI_COMMIT_SHA}
Notă: verificând '850f86aa317194395c5387790da1350e437125a7'.
Ești în starea 'HEAD detașat'. Poți explora, face modificări experimentale și să le comiți, iar tu poți arunca orice comite ai făcut în această stare fără a afecta ramurile, executând un alt checkout.
Dacă vrei să creezi o nouă ramură pentru a reține comitele pe care le creezi, poți să o faci (acum sau mai târziu) folosind -b cu comanda checkout din nou. Exemplu:
  git checkout -b nume_nou_de_ramură
HEAD este acum la 850f86a... sări peste test-core
$ for pom in $(find . -name pom.xml); do # comanda pe mai multe linii îngropată
$ if [[ "${DEPLOY_CI_COMMIT_TAG}" != "" ]]; then # comanda pe mai multe linii îngropată
[INFO] Scanning for projects...
[INFO] Inspectând build-ul cu un total de 4 module...
[INFO] Instalând caracteristici Nexus Staging:
[INFO]   ... un total de 4 execuții ale maven-deploy-plugin înlocuite cu nexus-staging-maven-plugin
[INFO] ------------------------------------------------------------------------
[INFO] Ordinea de construire a reactorului:
[INFO] 
[INFO] Shields4J                                                          [pom]
[INFO] test-core                                                          [jar]
[INFO] Client Shields4J                                                  [jar]
[INFO] Listener TestNG                                                   [jar]
[INFO] 
[INFO] -----------------------------
[INFO] Construind Shields4J 1.0.0                                           [1/4]
[INFO] --------------------------------[ pom ]---------------------------------
[INFO] 
[INFO] --- versions-maven-plugin:2.5:set (default-cli) @ shields4j-parent ---
[INFO] Căutând rădăcina agregatorului local...
[INFO] Rădăcina agregării locale: /home/gitlab-deployer/JSKWyxUw/0/TouchBIT/deploy/shields4j
[INFO] Procesând schimbarea org.touchbit.shields4j:shields4j-parent:1.0.0 -> 1.0.0-SNAPSHOT
[INFO] Procesând org.touchbit.shields4j:shields4j-parent
[INFO]     Actualizând proiectul org.touchbit.shields4j:shields4j-parent
[INFO]         din versiunea 1.0.0 la 1.0.0-SNAPSHOT
[INFO] 
[INFO] Procesând org.touchbit.shields4j:client
[INFO]     Actualizând părintelui org.touchbit.shields4j:shields4j-parent
[INFO]         din versiunea 1.0.0 la 1.0.0-SNAPSHOT
[INFO]     Actualizând dependența org.touchbit.shields4j:test-core
[INFO]         din versiunea 1.0.0 la 1.0.0-SNAPSHOT
[INFO] 
[INFO] Procesând org.touchbit.shields4j:test-core
[INFO]     Actualizând părintelui org.touchbit.shields4j:shields4j-parent
[INFO]         din versiunea 1.0.0 la 1.0.0-SNAPSHOT
[INFO] 
[INFO] Procesând org.touchbit.shields4j:testng
[INFO]     Actualizând părintelui org.touchbit.shields4j:shields4j-parent
[INFO]         din versiunea 1.0.0 la 1.0.0-SNAPSHOT
[INFO]     Actualizând dependența org.touchbit.shields4j:client
[INFO]         din versiunea 1.0.0 la 1.0.0-SNAPSHOT
[INFO]     Actualizând dependența org.touchbit.shields4j:test-core
[INFO]         din versiunea 1.0.0 la 1.0.0-SNAPSHOT
[INFO] 
[INFO] ------------------------------------------------------------------------
[INFO] Rezumatul reactorului:
[INFO] 
[INFO] Shields4J 1.0.0 .................................... SUCCES [  0.992 s]
[INFO] test-core .......................................... S-A SĂRIT
[INFO] Client Shields4J ................................... S-A SĂRIT
[INFO] Listener TestNG 1.0.0 .............................. S-A SĂRIT
[INFO] ------------------------------------------------------------------------
[INFO] CONSTRUCȚIE SUCCES
[INFO] ------------------------------------------------------------------------
[INFO] Timp total: 2.483 s
[INFO] Finalizat la: 2019-04-21T02:40:42+03:00
[INFO] ------------------------------------------------------------------------
$ mvn clean deploy -DskipTests=${SKIP_TESTS}
[INFO] Scanning for projects...
[INFO] Inspectând build-ul cu un total de 4 module...
[INFO] Instalând caracteristici Nexus Staging:
[INFO]   ... un total de 4 execuții ale maven-deploy-plugin înlocuite cu nexus-staging-maven-plugin
[INFO] ------------------------------------------------------------------------
[INFO] Ordinea de construire a reactorului:
[INFO] 
[INFO] Shields4J                                                          [pom]
[INFO] test-core                                                          [jar]
[INFO] Client Shields4J                                                  [jar]
[INFO] Listener TestNG                                                   [jar]
[INFO] 
[INFO] -----------------------------
[INFO] Construind Shields4J 1.0.0-SNAPSHOT                                  [1/4]
[INFO] --------------------------------[ pom ]---------------------------------
...
ȘTERS
...
[INFO]  * Dezvoltarea în masă a artefactelor snapshot adunate local a fost finalizată.
[INFO] Implementarea la distanță a fost finalizată cu succes.
[INFO] ------------------------------------------------------------------------
[INFO] Rezumatul reactorului:
[INFO] 
[INFO] Shields4J 1.0.0-SNAPSHOT ........................... SUCCES [  2.375 s]
[INFO] test-core .......................................... SUCCES [  3.929 s]
[INFO] Client Shields4J ................................... SUCCES [  3.815 s]
[INFO] Listener TestNG 1.0.0-SNAPSHOT ..................... SUCCES [ 36.134 s]
[INFO] ------------------------------------------------------------------------
[INFO] CONSTRUCȚIE SUCCES
[INFO] ------------------------------------------------------------------------
[INFO] Timp total: 47.629 s
[INFO] Finalizat la: 2019-04-21T02:41:32+03:00
[INFO] ------------------------------------------------------------------------

Ca urmare, în nexus a fost încărcată versiunea 1.0.0-SNAPSHOT.

Toate versiunile snapshot pot fi șterse din depozitul de pe site oss.sonatype.org sub contul tău.

Configurarea GitLab CI pentru încărcarea proiectului Java în Maven Central

La conținut

Publicarea versiunii release

La instalarea etichetei, se activează automat sarcina corespunzătoare în proiectul de deploy pentru încărcarea versiunii de release în nexus (exemplu).

Configurarea GitLab CI pentru încărcarea proiectului Java în Maven Central

Cel mai plăcut este că se activează automat close release în nexus.

[INFO] Executarea staging-ului de la distanță...
[INFO] 
[INFO]  * Staging de la distanță în profilul de staging ID "9043b43f77dcc9"
[INFO]  * Repositoriu de staging creat cu ID "orgtouchbit-1037".
[INFO]  * Repositoriu de staging la https://oss.sonatype.org:443/service/local/staging/deployByRepositoryId/orgtouchbit-1037
[INFO]  * Încărcarea artefactelor local staging în profilul org.touchbit
[INFO]  * Încărcarea artefactelor local staging s-a finalizat.
[INFO]  * Închiderea repositorului de staging cu ID "orgtouchbit-1037".
Așteptând finalizarea operației...
.........
[INFO] 1 repositorii staged la distanță, finalizat cu succes.
[INFO] ------------------------------------------------------------------------
[INFO] Rezumat reactor:
[INFO] 
[INFO] Shields4J 1.0.0 .................................... SUCCES [  9.603 s]
[INFO] test-core .......................................... SUCCES [  3.419 s]
[INFO] Shields4J client ................................... SUCCES [  9.793 s]
[INFO] TestNG listener 1.0.0 .............................. SUCCES [01:23 min]
[INFO] ------------------------------------------------------------------------
[INFO] CONSTRUCȚIE SUCCES
[INFO] ------------------------------------------------------------------------
[INFO] Timp total: 01:47 min
[INFO] Finalizat la: 2019-04-21T04:05:46+03:00
[INFO] ------------------------------------------------------------------------

Și dacă ceva nu a mers bine, atunci sarcina se va încheia cu siguranță

[INFO] Efectuarea staging-ului la distanță...
[INFO] 
[INFO]  * Staging la distanță în profilul de staging ID "9043b43f77dcc9"
[INFO]  * Repositoriu de staging creat cu ID "orgtouchbit-1038".
[INFO]  * Repositoriu de staging la https://oss.sonatype.org:443/service/local/staging/deployByRepositoryId/orgtouchbit-1038
[INFO]  * Încărcarea artefactelor staging locale în profilul org.touchbit
[INFO]  * Încărcarea artefactelor staging locale s-a terminat.
[INFO]  * Închiderea repositorului de staging cu ID "orgtouchbit-1038".
Așteptând finalizarea operațiunii...
.......
[ERROR] Eșec de regulă în timp ce se încerca închiderea repositorului de staging cu ID "orgtouchbit-1039".
[ERROR] 
[ERROR] Raport de eșec al regulilor Nexus Staging
[ERROR] ==================================
[ERROR] 
[ERROR] Eșecuri pentru repositorul "orgtouchbit-1039"
[ERROR]   Eșecuri ale regulii "signature-staging"
[ERROR]     * Fără cheie publică: Cheia cu id: (1f42b618d1cbe1b5) nu a putut fi localizată pe http://keys.gnupg.net:11371/. Încărcați cheia dumneavoastră publică și încercați din nou operațiunea.
...
[ERROR] Curățând directorul local de staging după un eșec de regulă în timpul închiderii repositoarelor de staging: [orgtouchbit-1039]
[ERROR]  * Ștergerea contextului 9043b43f77dcc9.properties
[ERROR] Curățând repositorile de staging la distanță după un eșec de regulă în timpul închiderii repositoarelor de staging: [orgtouchbit-1039]
[ERROR]  * Renunțând la repositorul de staging eșuat cu ID "orgtouchbit-1039" (Eșec de regulă în timpul închiderii repositoarelor de staging: [orgtouchbit-1039]).
[ERROR] Staging-ul la distanță s-a terminat cu un eșec: Eșec al regulilor de staging!
[INFO] ------------------------------------------------------------------------
[INFO] Rezumat Reactor:
[INFO] 
[INFO] Shields4J 1.0.0 .................................... SUCCES [  4.073 s]
[INFO] test-core .......................................... SUCCES [  2.788 s]
[INFO] Client Shields4J ................................... SUCCES [  3.962 s]
[INFO] TestNG listener 1.0.0 .............................. EȘEC [01:07 min]
[INFO] ------------------------------------------------------------------------
[INFO] EȘEC ÎN CONSTRUCȚIE
[INFO] ------------------------------------------------------------------------

În consecință, rămâne o singură opțiune. Fie să ștergem această versiune, fie să o publicăm.

Configurarea GitLab CI pentru încărcarea proiectului Java în Maven Central

După lansare, după un timp, artefactele vor apărea în Configurarea GitLab CI pentru încărcarea proiectului Java în Maven Central

off-topic

A fost o surpriză pentru mine că maven indicează alte repozitorii publice.
A trebuit să adaug robots.txt, deoarece a indexat vechiul meu repositoriu.

La conținut

Concluzie

Ce avem aici

  • Un proiect de deploy separat în care se pot implementa mai multe sarcini CI pentru a încărca artefacte în repozitorii publice pentru diverse limbaje de programare.
  • Proiectul de deploy este izolat de interferențe externe și poate fi modificat doar de utilizatori cu rolurile Proprietar și Mentenant.
  • Un Runner Specific separat cu cache 'cald' pentru a rula doar sarcinile de deploy.
  • Publicarea versiunilor snapshot/release în repositorii publice.
  • Verificare automată a versiunii release pentru a determina dacă este pregătită pentru publicare în maven central.
  • Protecție împotriva publicării automată a versiunilor 'raw' în maven central.
  • Construire și publicare a versiunilor snapshot 'cu un clic'.
  • Un singur repositoriu pentru obținerea versiunilor snapshot/release.
  • Pipeline-ul general pentru construire/testare/publicare a proiectului Java.

Configurarea GitLab CI nu este atât de complicată pe cât pare la prima vedere. E suficient să configurezi CI „cheie în mână” de câteva ori și iată, deja nu mai ești un novice în acest domeniu. Mai ales că documentația GitLab este destul de abundentă. Nu te teme să faci primul pas. Calea apare sub pașii celor care merg (nu-mi amintesc cine a spus asta 🙂 ).

Aș aprecia feedback-ul.

În articolul următor, voi vorbi despre cum să configurezi GitLab CI pentru a rula concurent sarcini cu teste de integrare (pornind serviciile testate cu ajutorul docker-compose), dacă ai doar un shell runner.

La conținut

Sursa: habr.com

Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS 🔥 Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS | ProHoster