Configurarea GitLab CI pentru a încărca un proiect java în Maven Central

Acest articol este destinat dezvoltatorilor java care au nevoie să-și publice rapid produsele în depozitele centrale Sonatype și/sau Maven folosind GitLab. În acest articol voi vorbi despre configurarea gitlab-runner, gitlab-ci și maven-plugin pentru a rezolva această problemă.

Condiții preliminare:

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

Conținut

Informații generale

  • O descriere detaliată a mecanismului de publicare a artefactelor în Maven Central prin Sonatype OSS Repository Hosting Service a fost deja descrisă în Acest articol utilizator Googlelplex, așa că mă voi referi la acest articol în locurile potrivite.
  • Pre-înregistrați pentru Sonatip JIRA și deschideți un bilet pentru a deschide depozitul (citiți secțiunea pentru mai multe detalii Creați un bilet pe Sonatype JIRA). După deschiderea depozitului, perechea de autentificare/parolă de la JIRA (denumită în continuare contul Sonatype) va fi utilizată pentru a încărca artefacte în Sonatype nexus.
  • În continuare, procesul de generare a unei chei GPG este descris foarte sec. Consultați secțiunea pentru mai multe detalii Configurarea GnuPG pentru a semna artefacte
  • Dacă utilizați consola Linux pentru a genera o cheie GPG (gnupg/gnupg2), atunci trebuie să instalați rng-instrumente pentru a genera entropie. În caz contrar, generarea cheii poate dura foarte mult.
  • Servicii de depozitare public chei GPG

La conținut

Configurarea unui proiect de implementare în GitLab

  • În primul rând, trebuie să creați și să configurați un proiect în care conducta va fi stocată pentru implementarea artefactelor. Mi-am numit proiectul simplu și necomplicat - implementa
  • După crearea depozitului, trebuie să restricționați accesul pentru a schimba depozitul.
    Accesați proiect -> Setări -> Repository -> Ramuri protejate. Ștergem toate regulile și adăugăm o singură regulă cu Wildcard * cu drept de împingere și îmbinare numai pentru utilizatorii cu rolul de întreținere. Această regulă va funcționa atât pentru toți utilizatorii acestui proiect, cât și pentru grupul căruia îi aparține acest proiect.
    Configurarea GitLab CI pentru a încărca un proiect java în Maven Central
  • Dacă există mai mulți menținători, atunci cea mai bună soluție ar fi limitarea accesului la proiect în principiu.
    Accesați proiect -> Setări -> General -> Vizibilitate, caracteristici ale proiectului, permisiuni și setați vizibilitatea proiectului la Privat.
    Am un proiect accesibil public, deoarece folosesc propriul meu GitLab Runner și doar eu am acces pentru a schimba depozitul. Ei bine, de fapt, nu este în interesul meu să arăt informații private în jurnalele de conducte publice.
  • Înăsprirea regulilor de modificare a depozitului
    Accesați proiect -> Setări -> Depozit -> Reguli Push și setați restricția Committer, verificați dacă autorul este un utilizator GitLab. De asemenea, recomand configurarea commit semnătură, și setați indicatorul Respingere comiterilor nesemnate.
  • Apoi, trebuie să configurați un declanșator pentru a lansa sarcini
    Accesați proiect -> Setări -> CI / CD -> Declanșatoare pipeline și creați un nou simbol de declanșare
    Acest token poate fi adăugat imediat la configurația generală a variabilelor pentru un grup de proiecte.
    Mergeți la grup -> Setări -> CI / CD -> Variabile și adăugați o variabilă DEPLOY_TOKEN cu token de declanșare în valoare.

La conținut

GitLab Runner

Această secțiune descrie configurația pentru rularea sarcinilor la implementare folosind propriul ruler (Specific) și public (Partajat).

Alergator specific

Folosesc propriile mele alergători pentru că, în primul rând, este convenabil, rapid și ieftin.
Pentru un alergător, recomand un Linux VDS cu 1 CPU, 2 GB RAM, 20 GB HDD. Prețul de emisiune este de ~3000₽ pe an.

Alergatorul meu

Pentru alergător am luat CPU VDS 4, 4 GB RAM, 50 GB SSD. A costat ~11000₽ și nu am regretat niciodată.
Am un total de 7 mașini. 5 pe aruba si 2 pe ihor.

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

La conținut

Se instalează gitlab runner

  • Creați un grup nou runner
    sudo groupadd runner
  • Creați un director pentru memoria cache Maven și atribuiți permisiuni de grup runner
    Puteți sări peste acest punct dacă nu intenționați să rulați mai mulți alergători pe o singură mașină.

    mkdir -p /usr/cache/.m2/repository
    chown -R :runner /usr/cache
    chmod -R 770 /usr/cache
  • Creați un utilizator gitlab-deployer și adăugați la grup runner
    useradd -m -d /home/gitlab-deployer gitlab-deployer
    usermod -a -G runner gitlab-deployer
  • Adăugați la fișier /etc/ssh/sshd_config rândul următor
    AllowUsers root@* [email protected]
  • Reporniți sshd
    systemctl restart sshd
  • Setarea unei parole pentru utilizator gitlab-deployer (poate fi simplu, deoarece există o restricție pentru localhost)
    passwd gitlab-deployer
  • Instalați 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
  • Accesați site-ul web gitlab.com -> deploy-project -> Settings -> CI/CD -> Runners -> Specific Runners și copiați jetonul de înregistrare

Ecran

Configurarea GitLab CI pentru a încărca un proiect java în Maven Central

  • Înregistrarea unui alergător
    gitlab-runner register --config /etc/gitlab-runner/gitlab-deployer-config.toml

proces

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 dacă alergătorul este înscris. Accesați site-ul gitlab.com -> deploy-project -> Settings -> CI/CD -> Runners -> Specific Runners -> Runners activați pentru acest proiect

Ecran

Configurarea GitLab CI pentru a încărca un proiect java în Maven Central

  • adăugare separa serviciu /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
  • Să începem serviciul.
    systemctl enable gitlab-deployer.service
    systemctl start gitlab-deployer.service
    systemctl status gitlab-deployer.service
  • Verificăm dacă alergătorul rulează.

Exemplu

Configurarea GitLab CI pentru a încărca un proiect java în Maven Central

La conținut

Generarea cheilor GPG

  • De la aceeași mașină ne conectăm prin ssh sub utilizator gitlab-deployer (acest lucru este important pentru generarea cheii GPG)

    ssh [email protected]

  • Generam o cheie răspunzând la întrebări. Mi-am folosit propriul nume și e-mail.
    Asigurați-vă că specificați parola pentru cheie. Artefactele vor fi semnate cu această cheie.

    gpg --gen-key 

  • Control

    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

  • Încărcarea cheii noastre publice 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 lui Maven

  • Conectați-vă ca utilizator gitlab-deployer
    su gitlab-deployer 
  • Creați un director Maven depozit și link la cache (nu faceți greșeli)
    Puteți sări peste acest punct dacă nu intenționați să rulați mai mulți alergători pe o singură mașină.

    mkdir -p ~/.m2/repository
    ln -s /usr/cache/.m2/repository /home/gitlab-deployer/.m2/repository
  • Creați o cheie principală
    mvn --encrypt-master-password password
    {hnkle5BJ9HUHUMP+CXfGBl8dScfFci/mpsur/73tR2I=}
  • Creați un fișier ~/.m2/settings-security.xml
    <settingsSecurity>
    <master>{hnkle5BJ9HUHUMP+CXfGBl8dScfFci/mpsur/73tR2I=}</master>
    </settingsSecurity>
  • Criptarea parolei pentru contul Sonatype
    mvn --encrypt-password SONATYPE_PASSWORD
    {98Wv5+u+Tn0HX2z5G/kR4R8Z0WBgcDBgi7d12S/un+SCU7uxzaZGGmJ8Cu9pAZ2J}
  • Creați un fișier ~/.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>

Unde,
GPG_SECRET_KEY_PASSPHRASE - parola pentru cheia GPG
SONATYPE_USERNAME — conectare la contul sonatype

Acest lucru completează configurarea alergătorului, puteți trece la secțiune GitLab CI

La conținut

Runner comun

Generarea cheilor GPG

  • În primul rând, trebuie să creați o cheie GPG. Pentru a face acest lucru, instalați gnupg.

    yum install -y gnupg

  • Generam o cheie răspunzând la întrebări. Mi-am folosit propriul nume și e-mail. Asigurați-vă că specificați parola pentru cheie.

    gpg --gen-key 

  • Afișarea informațiilor pe cheie

    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]

  • Încărcarea cheii noastre publice pe serverul de chei

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

  • Primim cheia privată

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

  • Accesați setările proiectului -> Setări -> CI / CD -> Variabile și salvați cheia privată într-o variabilă GPG_SECRET_KEY
    Configurarea GitLab CI pentru a încărca un proiect java în Maven Central

La conținut

Configurarea lui Maven

  • Creați o cheie principală
    mvn --encrypt-master-password password
    {hnkle5BJ9HUHUMP+CXfGBl8dScfFci/mpsur/73tR2I=}
  • Accesați setările proiectului -> Setări -> CI / CD -> Variabile și salvați într-o variabilă SETTINGS_SECURITY_XML următoarele rânduri:
    <settingsSecurity>
    <master>{hnkle5BJ9HUHUMP+CXfGBl8dScfFci/mpsur/73tR2I=}</master>
    </settingsSecurity>
  • Criptarea parolei pentru contul Sonatype
    mvn --encrypt-password SONATYPE_PASSWORD
    {98Wv5+u+Tn0HX2z5G/kR4R8Z0WBgcDBgi7d12S/un+SCU7uxzaZGGmJ8Cu9pAZ2J}
  • Accesați setările proiectului -> Setări -> CI / CD -> Variabile și salvați într-o variabilă SETTINGS_XML următoarele rânduri:
    <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>

Unde,
GPG_SECRET_KEY_PASSPHRASE - parola pentru cheia GPG
SONATYPE_USERNAME — conectare la contul sonatype

La conținut

Implementați imaginea docker

  • Creăm un Dockerfile destul de simplu pentru a rula sarcini de implementare cu versiunea necesară de Java. Mai jos este un exemplu pentru alpin.

    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/

  • Asamblarea unui container pentru proiectul dvs

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

  • Ne autentificăm și încărcăm containerul în registru.

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

La conținut

GitLab CI

Implementează proiect

Adăugați fișierul .gitlab-ci.yml la rădăcina proiectului de implementare
Scriptul prezintă două sarcini de implementare care se exclud reciproc. Alergator specific sau, respectiv, alergător partajat.

.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

La conținut

Proiect Java

În proiectele java care ar trebui să fie încărcate în depozitele publice, trebuie să adăugați 2 pași pentru a descărca versiunile Release și 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}

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

Mai multe detalii

Am creat un proiect separat gitlab-ci în care am plasat un șablon CI pentru proiecte java comun.yml.

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

Drept urmare, în proiectele java în sine, .gitlab-ci.yml arată foarte compact și nu pronunțat

.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

Configurație Pom.xml

Acest subiect este descris în detaliu. Googlelplex в Configurarea Maven pentru a semna și a încărca automat artefacte în depozitele de instantanee și staging, așa că voi descrie câteva dintre nuanțele utilizării pluginurilor. De asemenea, voi descrie cât de ușor și relaxat puteți folosi nexus-staging-maven-plugindacă nu doriți sau nu puteți utiliza org.sonatype.oss:oss-parent ca părinte pentru proiectul dvs.

maven-install-plugin

Instalează module în depozitul local.
Foarte util pentru verificarea locală a soluțiilor în alte proiecte, precum și o sumă de control.

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

La conținut

maven-javadoc-plugin

Generarea javadoc pentru proiect.

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

Dacă aveți un modul care nu conține java (de exemplu doar resurse)
Sau nu doriți să generați javadoc în principiu, apoi ajutați 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>

La conținut

maven-gpg-plugin

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

La conținut

nexus-staging-maven-plugin

Configurare:

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

Dacă aveți un proiect cu mai multe module și nu trebuie să încărcați un anumit modul în depozit, atunci trebuie să adăugați nexus-staging-maven-plugin cu steag skipNexusStagingDeployMojo

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

După descărcare, versiunile instantanee/de lansare sunt disponibile în depozite de staging

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

Mai multe plusuri

  • O listă foarte bogată de obiective pentru lucrul cu depozitul nexus (mvn help:describe -Dplugin=org.sonatype.plugins:nexus-staging-maven-plugin).
  • Verificare automată a eliberării pentru încărcare în Maven Central

La conținut

Rezultat

Se publică versiunea SNAPSHOT

Când construiți un proiect, este posibil să lansați manual o sarcină pentru a descărca versiunea SNAPSHOT pe nexus

Configurarea GitLab CI pentru a încărca un proiect java în Maven Central

Când această sarcină este lansată, este declanșată sarcina corespunzătoare din proiectul de implementare (exemplu).

Bușten tăiat

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] ------------------------------------------------------------------------

Ca rezultat, versiunea este încărcată în nexus 1.0.0-INSTANTANĂ.

Toate versiunile de instantanee pot fi șterse din depozitul de pe site oss.sonatype.org sub contul dvs.

Configurarea GitLab CI pentru a încărca un proiect java în Maven Central

La conținut

Publicarea unei versiuni de lansare

Când este instalată o etichetă, sarcina corespunzătoare din proiectul de implementare este declanșată automat pentru a descărca versiunea de lansare pe nexus (exemplu).

Configurarea GitLab CI pentru a încărca un proiect java în Maven Central

Cea mai bună parte este că eliberarea apropiată este declanșată automat în 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] ------------------------------------------------------------------------

Și dacă ceva nu merge bine, sarcina va eșua cu siguranță

[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] ------------------------------------------------------------------------

Drept urmare, ne rămâne cu o singură alegere. Fie ștergeți această versiune, fie publicați-o.

Configurarea GitLab CI pentru a încărca un proiect java în Maven Central

După eliberare, după ceva timp artefactele vor intra Configurarea GitLab CI pentru a încărca un proiect java în Maven Central

pe langa subiect

Pentru mine a fost o descoperire că Maven indexează alte depozite publice.
A trebuit să adaug robots.txt pentru că îmi indexa vechiul depozit.

La conținut

Concluzie

Ce avem

  • Un proiect de implementare separat în care puteți implementa mai multe sarcini CI pentru încărcarea artefactelor în depozitele publice pentru diferite limbaje de dezvoltare.
  • Proiectul Deploy este izolat de interferența exterioară și poate fi modificat numai de utilizatorii cu rolurile de proprietar și de întreținere.
  • Un Specific Runner separat cu un cache „fierbinte” pentru a rula numai sarcini de implementare.
  • Publicarea versiunilor instantanee/de lansare într-un depozit public.
  • Verificare automată a versiunii de lansare pentru pregătirea pentru publicare în Maven Central.
  • Protecție împotriva publicării automate a versiunilor „brute” în Maven Central.
  • Creați și publicați versiuni instantanee „la clic”.
  • Un singur depozit pentru obținerea versiunilor instantanee/de lansare.
  • Conductă generală pentru construirea/testarea/publicarea unui proiect java.

Configurarea GitLab CI nu este un subiect atât de complicat pe cât pare la prima vedere. Este suficient să configurați CI la cheie de câteva ori, iar acum sunteți departe de a fi un amator în această chestiune. Mai mult, documentația GitLab este foarte redundantă. Nu vă fie teamă să faceți primul pas. Drumul apare sub treptele celui care merge (nu-mi amintesc cine a spus-o :)

Voi fi bucuros să primesc feedback.

În articolul următor voi vorbi despre cum să configurați GitLab CI pentru a rula sarcini cu teste de integrare în mod competitiv (rularea serviciilor testate folosind docker-compose) dacă aveți un singur shell runner.

La conținut

Sursa: www.habr.com

Adauga un comentariu