Konfigurowanie GitLab CI do przesyłania projektu java do maven central

Ten artykuł jest przeznaczony dla programistów Java, którzy muszą szybko opublikować swoje produkty w centralnych repozytoriach sonatype i/lub maven przy użyciu GitLab. W tym artykule omówię konfigurację gitlab-runner, gitlab-ci i maven-plugin, aby rozwiązać ten problem.

Wymagania wstępne:

  • Bezpieczne przechowywanie kluczy mvn i GPG.
  • Bezpieczne wykonywanie publicznych zadań CI.
  • Przesyłanie artefaktów (wersja/migawka) do repozytoriów publicznych.
  • Automatyczne sprawdzanie wersji wydań pod kątem publikacji w centrali maven.
  • Ogólne rozwiązanie umożliwiające przesyłanie artefaktów do repozytorium dla wielu projektów.
  • Prostota i łatwość obsługi.

Zawartość

Informacje ogólne

  • Szczegółowy opis mechanizmu publikowania artefaktów do Maven Central za pośrednictwem usługi hostingowej repozytorium Sonatype OSS opisano już w Ten artykuł użytkownik Googolplex, dlatego odniosę się do tego artykułu w odpowiednich miejscach.
  • Zarejestruj się wcześniej pod adresem Sonatyp JIRA i otwórz bilet, aby otworzyć repozytorium (przeczytaj sekcję, aby uzyskać więcej informacji Utwórz zgłoszenie w Sonatype JIRA). Po otwarciu repozytorium para login/hasło z JIRA (zwana dalej kontem Sonatype) zostanie użyta do przesłania artefaktów do Sonatype nexus.
  • Dalej proces generowania klucza GPG jest opisany bardzo sucho. Więcej szczegółów znajdziesz w sekcji. Konfigurowanie GnuPG do podpisywania artefaktów
  • Jeśli używasz konsoli Linux do generowania klucza GPG (gnupg/gnupg2), musisz zainstalować rng-tools do generowania entropii. W przeciwnym razie generowanie klucza może zająć bardzo dużo czasu.
  • Usługi magazynowania publiczny Klucze GPG

Powrót do treści

Konfigurowanie projektu wdrożenia w GitLab

  • Przede wszystkim musisz utworzyć i skonfigurować projekt, w którym będzie przechowywany potok na potrzeby wdrażania artefaktów. Nazwałem swój projekt prosto i nieskomplikowanie - rozwijać
  • Po utworzeniu repozytorium musisz ograniczyć dostęp, aby móc zmieniać repozytorium.
    Przejdź do projektu -> Ustawienia -> Repozytorium -> Chronione gałęzie. Usuwamy wszystkie reguły i dodajemy pojedynczą regułę z symbolem wieloznacznym * z prawem do wypychania i łączenia tylko dla użytkowników z rolą Opiekunowie. Ta reguła będzie działać dla wszystkich użytkowników zarówno tego projektu, jak i grupy, do której ten projekt należy.
    Konfigurowanie GitLab CI do przesyłania projektu java do maven central
  • Jeżeli opiekunów jest kilku, to najlepszym rozwiązaniem byłoby w zasadzie ograniczenie dostępu do projektu.
    Przejdź do projektu -> Ustawienia -> Ogólne -> Widoczność, funkcje projektu, uprawnienia i ustaw Widoczność projektu na Sprawy Prywatne.
    Mam projekt dostępny publicznie, ponieważ korzystam z własnego GitLab Runnera i tylko ja mam dostęp do zmiany repozytorium. Cóż, właściwie nie leży w moim interesie pokazywanie prywatnych informacji w publicznych dziennikach potoków.
  • Zaostrzenie zasad zmiany repozytorium
    Przejdź do projektu -> Ustawienia -> Repozytorium -> Reguły Push i ustaw flagi Ograniczenie Committer, Sprawdź, czy autor jest użytkownikiem GitLab. Polecam również ustawienie zobowiązać się do podpisaniai ustaw flagę Odrzuć niepodpisane zatwierdzenia.
  • Następnie musisz skonfigurować wyzwalacz do uruchamiania zadań
    Przejdź do projektu -> Ustawienia -> CI / CD -> Wyzwalacze potokowe i utwórz nowy token wyzwalacza
    Token ten można od razu dodać do ogólnej konfiguracji zmiennych dla grupy projektów.
    Przejdź do grupy -> Ustawienia -> CI/CD -> Zmienne i dodaj zmienną DEPLOY_TOKEN z tokenem wyzwalacza w wartości.

Powrót do treści

Biegacz GitLab

W tej sekcji opisano konfigurację uruchamiania zadań podczas wdrażania przy użyciu własnego (określonego) i publicznego (współdzielonego) modułu uruchamiającego.

Konkretny biegacz

Korzystam z własnych biegaczy, bo przede wszystkim jest wygodnie, szybko, tanio.
Dla biegaczy polecam Linux VDS z 1 procesorem, 2 GB RAM, 20 GB HDD. Cena emisyjna ~3000₽ rocznie.

Mój biegacz

Na biegacza wziąłem procesor VDS 4, 4 GB RAM, 50 GB SSD. Kosztowało ~ 11000 ₽ i nigdy tego nie żałowałem.
Mam w sumie 7 maszyn. 5 na Arubie i 2 na ihor.

Mamy więc biegacza. Teraz to skonfigurujemy.
Wchodzimy na maszynę przez SSH i instalujemy Java, git, maven, gnupg2.

Powrót do treści

Instalowanie modułu gitlab runner

  • Utwórz nową grupę runner
    sudo groupadd runner
  • Utwórz katalog dla pamięci podręcznej maven i przypisz uprawnienia grupy runner
    Możesz pominąć ten punkt, jeśli nie planujesz uruchamiania kilku programów uruchamiających na jednej maszynie.

    mkdir -p /usr/cache/.m2/repository
    chown -R :runner /usr/cache
    chmod -R 770 /usr/cache
  • Utwórz użytkownika gitlab-deployer i dodaj do grupy runner
    useradd -m -d /home/gitlab-deployer gitlab-deployer
    usermod -a -G runner gitlab-deployer
  • Dodaj do pliku /etc/ssh/sshd_config następna linia
    AllowUsers root@* [email protected]
  • Ponowne uruchomienie sshd
    systemctl restart sshd
  • Ustaw hasło dla użytkownika gitlab-deployer (może to być proste, ponieważ istnieje ograniczenie dla localhost)
    passwd gitlab-deployer
  • Zainstaluj 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
  • Przejdź do gitlab.com -> Deploy-Project -> Ustawienia -> CI/CD -> Runners ->Specific Runners i skopiuj token rejestracji

Screen

Konfigurowanie GitLab CI do przesyłania projektu java do maven central

  • Rejestracja biegacza
    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!

  • Sprawdzamy, czy biegacz jest zarejestrowany. Przejdź do strony gitlab.com -> Deploy-project -> Ustawienia -> CI/CD -> Runners -> Określeni Runnerzy -> Runnerzy aktywowani dla tego projektu

Screen

Konfigurowanie GitLab CI do przesyłania projektu java do maven central

  • Dodać osobne usługa /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
  • Uruchamiamy usługę.
    systemctl enable gitlab-deployer.service
    systemctl start gitlab-deployer.service
    systemctl status gitlab-deployer.service
  • Sprawdź, czy biegacz biegnie.

Przykład

Konfigurowanie GitLab CI do przesyłania projektu java do maven central

Powrót do treści

Generowanie klucza GPG

  • Z tej samej maszyny przechodzimy przez ssh pod użytkownikiem gitlab-deployer (jest to ważne przy generowaniu klucza GPG)

    ssh [email protected]

  • Generujemy klucz odpowiadając na pytania. Użyłem własnego imienia i nazwiska oraz adresu e-mail.
    Pamiętaj o podaniu hasła dla klucza. Artefakty będą podpisane tym kluczem.

    gpg --gen-key 

  • Kontrola

    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

  • Przesyłanie naszego klucza publicznego na serwer kluczy

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

Powrót do treści

Konfigurowanie Mavena

  • Zaloguj się jako użytkownik gitlab-deployer
    su gitlab-deployer 
  • Utwórz katalog maven składnica i link do pamięci podręcznej (nie popełnij błędu)
    Ten krok można pominąć, jeśli nie planujesz uruchamiania kilku programów uruchamiających na tej samej maszynie.

    mkdir -p ~/.m2/repository
    ln -s /usr/cache/.m2/repository /home/gitlab-deployer/.m2/repository
  • Utwórz klucz główny
    mvn --encrypt-master-password password
    {hnkle5BJ9HUHUMP+CXfGBl8dScfFci/mpsur/73tR2I=}
  • Utwórz plik ~/.m2/settings-security.xml
    <settingsSecurity>
    <master>{hnkle5BJ9HUHUMP+CXfGBl8dScfFci/mpsur/73tR2I=}</master>
    </settingsSecurity>
  • Szyfrowanie hasła z konta Sonatype
    mvn --encrypt-password SONATYPE_PASSWORD
    {98Wv5+u+Tn0HX2z5G/kR4R8Z0WBgcDBgi7d12S/un+SCU7uxzaZGGmJ8Cu9pAZ2J}
  • Utwórz plik ~/.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>

Gdzie,
GPG_SECRET_KEY_PASSPHRASE - hasło do klucza GPG
SONATYPE_USERNAME - logowanie do konta sonatype

To kończy konfigurację prowadnicy, możesz przejść do tej sekcji GitLab CI

Powrót do treści

Wspólny biegacz

Generowanie klucza GPG

  • Przede wszystkim musisz utworzyć klucz GPG. Aby to zrobić, zainstaluj gnupg.

    yum install -y gnupg

  • Generujemy klucz odpowiadając na pytania. Użyłem własnego imienia i nazwiska oraz adresu e-mail. Pamiętaj o podaniu hasła dla klucza.

    gpg --gen-key 

  • Odzyskaj kluczowe informacje

    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]

  • Przesyłanie naszego klucza publicznego na serwer kluczy

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

  • Uzyskanie klucza prywatnego

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

  • Przejdź do ustawień projektu -> Ustawienia -> CI / CD -> Zmienne i zapisz klucz prywatny w zmiennej GPG_SECRET_KEY
    Konfigurowanie GitLab CI do przesyłania projektu java do maven central

Powrót do treści

Konfigurowanie Mavena

  • Utwórz klucz główny
    mvn --encrypt-master-password password
    {hnkle5BJ9HUHUMP+CXfGBl8dScfFci/mpsur/73tR2I=}
  • Przejdź do ustawień projektu -> Ustawienia -> CI / CD -> Zmienne i zapisz w zmiennej SETTINGS_SECURITY_XML następujące linie:
    <settingsSecurity>
    <master>{hnkle5BJ9HUHUMP+CXfGBl8dScfFci/mpsur/73tR2I=}</master>
    </settingsSecurity>
  • Szyfrowanie hasła z konta Sonatype
    mvn --encrypt-password SONATYPE_PASSWORD
    {98Wv5+u+Tn0HX2z5G/kR4R8Z0WBgcDBgi7d12S/un+SCU7uxzaZGGmJ8Cu9pAZ2J}
  • Przejdź do ustawień projektu -> Ustawienia -> CI / CD -> Zmienne i zapisz w zmiennej SETTINGS_XML następujące linie:
    <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>

Gdzie,
GPG_SECRET_KEY_PASSPHRASE - hasło do klucza GPG
SONATYPE_USERNAME - logowanie do konta sonatype

Powrót do treści

Wdróż obraz okna dokowanego

  • Tworzymy dość prosty plik Dockerfile do uruchamiania zadań podczas wdrażania z żądaną wersją Java. Poniżej znajduje się przykład dla alpejskiego.

    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/

  • Montaż kontenera dla Twojego projektu

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

  • Uwierzytelniamy i ładujemy kontener do rejestru.

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

Powrót do treści

GitLab CI

Wdróż projekt

Dodaj plik .gitlab-ci.yml do katalogu głównego projektu wdrażania
Skrypt przedstawia dwa wzajemnie wykluczające się zadania wdrażania. Odpowiednio konkretny biegacz lub wspólny biegacz.

.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

Powrót do treści

Projekt Java

W projektach Java, które mają zostać przesłane do publicznych repozytoriów, należy dodać 2 kroki, aby pobrać wersje 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}

W tym rozwiązaniu poszedłem trochę dalej i zdecydowałem się użyć jednego szablonu CI dla projektów Java.

Więcej szczegółów

Stworzyłem osobny projekt gitlab-ci w którym umieścił szablon CI dla projektów Java wspólny.yml.

wspólny.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

W rezultacie w samych projektach Java plik .gitlab-ci.yml wygląda bardzo zwięźle i niezbyt szczegółowo

.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

Powrót do treści

konfiguracja pom.xml

Temat ten jest bardzo szczegółowo opisany. Googolplex в Konfigurowanie mavena do automatycznego podpisywania i przesyłania artefaktów do repozytoriów migawek i przemieszczania, więc opiszę niektóre niuanse korzystania z wtyczek. Opiszę również, jak łatwo i zrelaksowany możesz z niego korzystać nexus-staging-maven-pluginjeśli nie chcesz lub nie możesz używać org.sonatype.oss:oss-parent jako elementu nadrzędnego dla swojego projektu.

wtyczka maven-install

Instaluje moduły w lokalnym repozytorium.
Bardzo przydatny do lokalnej weryfikacji rozwiązań w innych projektach, a także sumy kontrolnej.

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

Powrót do treści

wtyczka maven-javadoc

Generowanie javadoc dla projektu.

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

Jeśli masz moduł, który nie zawiera Java (na przykład tylko zasoby)
Lub w zasadzie nie chcesz generować javadoc, a następnie pomóc 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>

Powrót do treści

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

Powrót do treści

wtyczka-nexus-staging-maven

Konfiguracja:

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

Jeśli masz projekt wielomodułowy i nie musisz wgrywać konkretnego modułu do repozytorium, to musisz dodać nexus-staging-maven-plugin z flagą skipNexusStagingDeployMojo

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

Po przesłaniu wersji migawek/wydań dostępne są w repozytoria pomostowe

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

Więcej plusów

  • Bardzo bogata lista celów do pracy z repozytorium nexusa (mvn help:describe -Dplugin=org.sonatype.plugins:nexus-staging-maven-plugin).
  • Automatyczne sprawdzanie wersji pod kątem możliwości pobrania w Maven Central

Powrót do treści

Doświadcz mocnych i skutecznych rezultatów

Publikacja wersji SNAPSHOT

Podczas budowania projektu istnieje możliwość ręcznego uruchomienia zadania pobrania wersji SNAPSHOT na nexusa

Konfigurowanie GitLab CI do przesyłania projektu java do maven central

Po uruchomieniu tego zadania wyzwalane jest odpowiednie zadanie w projekcie wdrażania (przykład).

Przycięty dziennik

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

W rezultacie wersja zostanie załadowana do nexusa 1.0.0-MIGAWKA.

Wszystkie wersje snapshotów można usunąć z repozytorium na stronie oss.sonatype.org pod Twoim kontem.

Konfigurowanie GitLab CI do przesyłania projektu java do maven central

Powrót do treści

Publikacja wersji wydania

Po ustawieniu tagu automatycznie uruchamiane jest odpowiednie zadanie w projekcie wdrażania w celu przesłania wersji wydania do nexusa (przykład).

Konfigurowanie GitLab CI do przesyłania projektu java do maven central

Najlepsze jest to, że bliskie zwolnienie automatycznie uruchamia się w Nexusie.

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

A jeśli coś pójdzie nie tak, zadanie na pewno się nie powiedzie

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

W rezultacie pozostaje nam tylko jeden wybór. Usuń tę wersję lub opublikuj ją.

Konfigurowanie GitLab CI do przesyłania projektu java do maven central

Po wydaniu, po pewnym czasie, artefakty będą dostępne Konfigurowanie GitLab CI do przesyłania projektu java do maven central

poza tematem

To było dla mnie odkrycie, że Maven indeksuje inne publiczne repozytoria.
Musiałem przesłać plik robots.txt, ponieważ zaindeksował on moje stare repozytorium.

Powrót do treści

wniosek

Co mamy

  • Oddzielny projekt wdrożenia, w którym można zaimplementować kilka zadań CI w celu przesyłania artefaktów do publicznych repozytoriów dla różnych języków programowania.
  • Projekt Deploy jest odizolowany od ingerencji z zewnątrz i może być zmieniany wyłącznie przez użytkowników z rolami właściciela i opiekuna.
  • Oddzielny konkretny moduł uruchamiający z „gorącą” pamięcią podręczną do uruchamiania tylko zadań wdrażania.
  • Publikowanie wersji migawek/wydań w publicznym repozytorium.
  • Automatyczne sprawdzenie wersji wydania pod kątem gotowości do publikacji w centrali maven.
  • Ochrona przed automatyczną publikacją wersji „surowych” w maven central.
  • Twórz i publikuj wersje migawek „po kliknięciu”.
  • Pojedyncze repozytorium do uzyskiwania wersji migawek/wydań.
  • Ogólny potok budowania/testowania/publikowania projektu Java.

Konfiguracja GitLab CI nie jest tak skomplikowanym tematem jak się wydaje na pierwszy rzut oka. Wystarczy kilka razy skonfigurować CI pod klucz i teraz nie jesteś w tej kwestii amatorem. Co więcej, dokumentacja GitLaba jest bardzo zbędna. Nie bój się zrobić pierwszego kroku. Droga pojawia się pod schodami idącej osoby (nie pamiętam kto to powiedział :)

Z przyjemnością przekażę informację zwrotną.

W następnym artykule opowiem o tym, jak skonfigurować GitLab CI, aby konkurencyjnie uruchamiał zadania z testami integracyjnymi (uruchamiając testowane usługi za pomocą docker-compose), jeśli masz tylko jednego Shell Runnera.

Powrót do treści

Źródło: www.habr.com

Dodaj komentarz