Konfiguracja GitLab CI do publikacji projektu Java w Maven Central

Artykuł ten jest skierowany do programistów Java, którzy potrzebują szybko publikować swoje produkty w repozytoriach Sonatype i/lub Maven Central z użyciem GitLab. W tym artykule omówię konfigurację gitlab-runner, gitlab-ci oraz maven-plugin, aby rozwiązać ten problem.

Wymagania wstępne:

  • Bezpieczne przechowywanie kluczy mvn i GPG.
  • Bezpieczne wykonywanie publicznych zadań CI.
  • Wysyłanie artefaktów (release/snapshot) do publicznych repozytoriów.
  • Automatyczne sprawdzanie wersji release do publikacji w Maven Central.
  • Ogólne rozwiązanie dla przesyłania artefaktów do repozytoriów dla wielu projektów.
  • Prostota i wygoda użycia.

Spis treści

Informacje ogólne

  • Szczegółowy opis mechanizmu publikacji artefaktów w Maven Central za pośrednictwem usługi Sonatype OSS Repository Hosting został już opisany w tym artykule przez użytkownika Googolplex, dlatego w odpowiednich miejscach będę odwoływał się do tego artykułu.
  • Najpierw rejestrujemy się w Sonatype JIRA i tworzymy zgłoszenie o otwarcie repozytorium (szczegóły można znaleźć w sekcji Tworzymy zgłoszenie w Sonatype JIRA). Po otwarciu repozytorium para login/hasło z JIRA (dalej konto Sonatype) będzie używana do przesyłania artefaktów do Sonatype Nexus.
  • Proces generowania klucza GPG jest opisany dość lakonicznie. Bardziej szczegółowe informacje znajdują się w sekcji Konfiguracja GnuPG do podpisywania artefaktów
  • Jeśli korzystasz z konsoli Linux do generowania klucza GPG (gnupg/gnupg2), musisz zainstalować rng-tools , aby generować entropię. W przeciwnym razie proces generowania klucza może trwać bardzo długo.
  • Usługi przechowywania publicznych kluczy GPG

Do treści

Konfiguracja projektu deploy w GitLab

  • Przede wszystkim należy utworzyć i skonfigurować projekt, w którym będzie przechowywany pipeline do wdrażania artefaktów. Mój projekt nazwałem prosto i bez zbędnych ceremoni — deploy
  • Po utworzeniu repozytorium należy ograniczyć dostęp do zmiany repozytoriów.
    Przechodzimy do projektu -> Ustawienia -> Repozytorium -> Protected Branches. Usuwamy wszystkie zasady i dodajemy jedną zasadę z Wildcard *, z prawem do push i merge tylko dla użytkowników z rolą Maintainers. Ta zasada będzie działać dla wszystkich użytkowników zarówno w tym projekcie, jak i grupie, do której ten projekt należy.
    Konfiguracja GitLab CI do publikacji projektu Java w Maven Central
  • Jeśli jest kilku maintainerów, najlepszym rozwiązaniem będzie ograniczenie dostępu do projektu w ogóle.
    Przechodzimy do projektu -> Ustawienia -> Ogólne -> Widoczność, funkcje projektu, uprawnienia i ustawiamy widoczność projektu na Prywatny.
    Mój projekt jest publicznie dostępny, ponieważ używam własnego GitLab Runner, a dostęp do edytowania repozytorium mam tylko ja. Zresztą nie leży w moim interesie ujawniać prywatnych informacji w publicznych logach pipeline.
  • Zaostrzenie zasad dotyczących edytowania repozytorium
    Przechodzimy do projektu -> Ustawienia -> Repozytorium -> Zasady Push i ustawiamy flagi Ograniczenie committera, Sprawdź, czy autor jest użytkownikiem GitLab. Zalecam także skonfigurowanie podpisywania commitów, oraz ustawiamy flagę Odrzuć niesygnowane commity.
  • Następnie należy skonfigurować wyzwalacz do uruchamiania zadań
    Przechodzimy do projektu -> Ustawienia -> CI / CD -> Wyzwalacze pipeline i tworzymy nowy token wyzwalacza
    Ten token można od razu dodać do ogólnej konfiguracji zmiennych dla grupy projektów.
    Przechodzimy do grupy -> Ustawienia -> CI / CD -> Zmienne i dodajemy zmienną DEPLOY_TOKEN z tokenem wyzwalacza w wartości.

Do treści

GitLab Runner

W tej sekcji opisano konfigurację do uruchamiania zadań na deploy z wykorzystaniem własnego (Specific) i publicznego (Shared) runnera.

Specyficzny Runner

Używam własnych runnerów, ponieważ w pierwszej kolejności jest to wygodne, szybkie, tanie.
Dla runnera polecam linuksowy VDS z 1 CPU, 2 GB RAM, 20 GB HDD. Koszt to ~3000₽ rocznie.

Mój runner

Dla runnera wybrałem VDS 4 CPU, 4 GB RAM, 50 GB SSD. Kosztował ~11000₽ i ani razu tego nie żałowałem.
Mam w sumie 7 maszyn. 5 w aruba i 2 w ihor.

No to mamy runnera. Teraz go skonfigurujemy.
Logujemy się na maszynę przez SSH i instalujemy java, git, maven, gnupg2.

Do treści

Instalujemy gitlab runner

  • Tworzymy nową grupę runner
    sudo groupadd runner
  • Tworzymy katalog dla pamięci podręcznej maven i przypisujemy prawa grupie runner
    Ten krok można pominąć, jeśli nie planujesz uruchamiać kilku runnerów na jednej maszynie.
    mkdir -p /usr/cache/.m2/repository
    chown -R :runner /usr/cache
    chmod -R 770 /usr/cache
  • Tworzymy użytkownika gitlab-deployer i dodajemy do grupy runner
    useradd -m -d /home/gitlab-deployer gitlab-deployer
    usermod -a -G runner gitlab-deployer
  • Dodajemy do pliku /etc/ssh/sshd_config następującą linijkę
    AllowUsers root@* gitlab-deployer@127.0.0.1
  • Restartujemy sshd
    systemctl restart sshd
  • Ustawiamy hasło dla użytkownika gitlab-deployer (może być proste, ponieważ dotyczy localhost)
    passwd gitlab-deployer
  • Instalujemy 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
  • Przechodzimy na stronę gitlab.com -> deploy-project -> Ustawienia -> CI/CD -> Runners -> Specific Runners i kopiujemy token rejestracji

Zrzut ekranu

Konfiguracja GitLab CI do publikacji projektu Java w Maven Central

  • Rejestrujemy runnera
    gitlab-runner register --config /etc/gitlab-runner/gitlab-deployer-config.toml

Proces

Platforma runtime arch=amd64 os=linux pid=17594 revision=3001a600 version=11.10.0
Uruchamianie w trybie systemowym.
Proszę podać adres URL koordynatora gitlab-ci (np. https://gitlab.com/):
https://gitlab.com/
Proszę podać token gitlab-ci dla tego runnera:
REGISTRATION_TOKEN
Proszę podać opis gitlab-ci dla tego runnera:
[ih1174328.vds.myihor.ru]: Deploy Runner
Proszę podać tagi gitlab-ci dla tego runnera (oddzielone przecinkami):
deploy
Rejestracja runnera... zakończona sukcesem                     runner=ZvKdjJhx
Proszę podać executor: docker-ssh, parallels, virtualbox, docker-ssh+machine, kubernetes, docker, ssh, docker+machine, shell:
shell
Runner zarejestrowany pomyślnie. Możesz go uruchomić, ale jeśli już działa, konfiguracja powinna zostać automatycznie załadowana!
  • Sprawdzamy, czy runner jest zarejestrowany. Przechodzimy na stronę gitlab.com -> deploy-project -> Ustawienia -> CI/CD -> Runners -> Specific Runners -> Runners aktywowane dla tego projektu

Zrzut ekranu

Konfiguracja GitLab CI do publikacji projektu Java w Maven Central

  • Dodajemy oddzielny 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
  • Sprawdzamy, czy runner jest uruchomiony.

Przykład

Konfiguracja GitLab CI do publikacji projektu Java w Maven Central

Do treści

Generowanie kluczy GPG

  • Z tej samej maszyny logujemy się przez ssh jako użytkownik gitlab-deployer (to ważne dla generowania klucza GPG)
    ssh gitlab-deployer@127.0.0.1
  • Generujemy klucz odpowiadając na pytania. Użyłem własnego imienia i e-maila.
    Koniecznie podajemy hasło dla klucza. Ten klucz będzie używany do podpisywania artefaktów.
    gpg --gen-key 
  • Sprawdzamy
    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
  • Wgrywamy nasz klucz publiczny na serwer kluczy
    gpg --keyserver keys.gnupg.net --send-key 00000000
    gpg: wysyłanie klucza 00000000 do serwera hkp keys.gnupg.net

Do treści

Konfiguracja Maven

  • Logujemy się jako użytkownik gitlab-deployer
    su gitlab-deployer 
  • Tworzymy katalog maven repository i łączymy z cache (nie pomyl się)
    Ten krok można pominąć, jeśli nie planujesz uruchamiać kilku runnerów na jednej maszynie.
    mkdir -p ~/.m2/repository
    ln -s /usr/cache/.m2/repository /home/gitlab-deployer/.m2/repository
  • Tworzymy master key
    mvn --encrypt-master-password password
    {hnkle5BJ9HUHUMP+CXfGBl8dScfFci/mpsur/73tR2I=}
  • Tworzymy plik ~/.m2/settings-security.xml
    {hnkle5BJ9HUHUMP+CXfGBl8dScfFci/mpsur/73tR2I=}
  • Szyfrujemy hasło do konta Sonatype
    mvn --encrypt-password SONATYPE_PASSWORD
    {98Wv5+u+Tn0HX2z5G/kR4R8Z0WBgcDBgi7d12S/un+SCU7uxzaZGGmJ8Cu9pAZ2J}
  • Tworzymy plik ~/.m2/settings.xml
    env
            
                true
            
            
                GPG_SECRET_KEY_PASSPHRASE
            
        
    
    
        
            sonatype
            SONATYPE_USERNAME
            {98Wv5+u+Tn0HX2z5G/kR4R8Z0WBgcDBgi7d12S/un+SCU7uxzaZGGmJ8Cu9pAZ2J}

gdzie,
GPG_SECRET_KEY_PASSPHRASE — hasło do klucza GPG
SONATYPE_USERNAME — login do konta sonatype

Na tym zakończono konfigurację runnera, możemy przejść do sekcji GitLab CI

Do treści

Wspólny Runner

Generowanie kluczy GPG

  • Najpierw należy stworzyć klucz GPG. W tym celu instalujemy gnupg.
    yum install -y gnupg
  • Generujemy klucz odpowiadając na pytania. Użyłem własnego imienia i adresu e-mail. Należy podać hasło do klucza.
    gpg --gen-key 
  • Wyświetlamy informacje o kluczu
    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]
  • Wgrywamy nasz klucz publiczny na serwer kluczy
    gpg --keyserver keys.gnupg.net --send-key 2D0D1706366FC4AEF79669E24D09C55BBA3FD728
    gpg: wysyłanie klucza 2D0D1706366FC4AEF79669E24D09C55BBA3FD728 do serwera hkp keys.gnupg.net
  • Otrzymujemy klucz prywatny
    gpg --export-secret-keys --armor 2D0D1706366FC4AEF79669E24D09C55BBA3FD728
    -----BEGIN PGP PRIVATE KEY BLOCK-----
    lQWGBFzAqp8BDADN41CPwJ/gQwiKEbyA902DKw/WSB1AvZQvV/ZFV77xGeG4K7k5
    ...
    =2Wd2
    -----END PGP PRIVATE KEY BLOCK-----
  • Przechodzimy do ustawień projektu -> Ustawienia -> CI / CD -> Zmienne i zapisujemy klucz prywatny w zmiennej GPG_SECRET_KEY
    Konfiguracja GitLab CI do publikacji projektu Java w Maven Central

Do treści

Konfiguracja Maven

  • Tworzymy master key
    mvn --encrypt-master-password password
    {hnkle5BJ9HUHUMP+CXfGBl8dScfFci/mpsur/73tR2I=}
  • Przechodzimy do ustawień projektu -> Ustawienia -> CI / CD -> Zmienne i zapisujemy w zmiennej SETTINGS_SECURITY_XML następujące linie:
    {hnkle5BJ9HUHUMP+CXfGBl8dScfFci/mpsur/73tR2I=}
  • Szyfrujemy hasło do konta Sonatype
    mvn --encrypt-password SONATYPE_PASSWORD
    {98Wv5+u+Tn0HX2z5G/kR4R8Z0WBgcDBgi7d12S/un+SCU7uxzaZGGmJ8Cu9pAZ2J}
  • Przechodzimy do ustawień projektu -> Ustawienia -> CI / CD -> Zmienne i zapisujemy w zmiennej SETTINGS_XML następujące linie:
    env
            
                true
            
            
                GPG_SECRET_KEY_PASSPHRASE
            
        
    
    
        
            sonatype
            sonatype_username
            {98Wv5+u+Tn0HX2z5G/kR4R8Z0WBgcDBgi7d12S/un+SCU7uxzaZGGmJ8Cu9pAZ2J}

gdzie,
GPG_SECRET_KEY_PASSPHRASE — hasło do klucza GPG
SONATYPE_USERNAME — login do konta sonatype

Do treści

Wdrożenie obrazu docker

  • Tworzymy wystarczająco prosty Dockerfile do uruchamiania zadań wdrożeniowych z odpowiednią wersją Javy. Poniżej znajduje się przykład dla 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/
  • Budujemy kontener dla twojego projektu
    docker build -t registry.gitlab.com/group/deploy .
  • Logujemy się i przesyłamy kontener do rejestru.
    docker login -u USER -p PASSWORD registry.gitlab.com
    docker push registry.gitlab.com/group/deploy

Do treści

GitLab CI

Wdrożenie projektu

Dodajemy plik .gitlab-ci.yml do głównego katalogu projektu deploy
Skrypt przedstawia dwa wzajemnie wykluczające się zadania wdrożenia. Specific Runner lub Shared Runner odpowiednio.

.gitlab-ci.yml

stages:
  - deploy

Specific Runner:
  extends: .java_deploy_template
  # Zadanie będzie wykonywane na twoim runnerze shell
  tags:
    - deploy

Shared Runner:
  extends: .java_deploy_template
  # Zadanie będzie wykonywane na publicznym docker runnerze
  tags:
    - docker
  # Obraz z sekcji GitLab Runner -> Shared Runner -> Docker
  image: registry.gitlab.com/group/deploy-project:latest
  before_script:
    # Importujemy klucz GPG
    - printf "${GPG_SECRET_KEY}" | gpg --batch --import
    # Zapisujemy konfigurację maven
    - printf "${SETTINGS_SECURITY_XML}" > ~/.m2/settings-security.xml
    - printf "${SETTINGS_XML}" > ~/.m2/settings.xml

.java_deploy_template:
  stage: deploy
  # Zadanie uruchomi się po wyzwoleniu, jeśli przekazana zostanie zmienna DEPLOY o wartości java
  only:
    variables:
    - $DEPLOY == "java"
  variables:
    # wyłączamy klonowanie aktualnego projektu
    GIT_STRATEGY: none
  script:
    # Umożliwiamy przechowywanie hasła w niezaszyfrowanej formie
    - git config --global credential.helper store
    # Zapisujemy tymczasowe poświadczenia użytkownika gitlab-ci-token
    # Token działa dla wszystkich publicznych projektów gitlab.com oraz dla projektów grupy
    - echo "https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com" >> ~/.git-credentials
    # Całkowicie czyścimy bieżący katalog
    - rm -rf .* *
    # Klonujemy projekt, który będziemy wdrażać w Sonatype Nexus
    - git clone ${DEPLOY_CI_REPOSITORY_URL} .
    # Przełączamy się na odpowiedni commit
    - git checkout ${DEPLOY_CI_COMMIT_SHA} -f
    # Jeśli jakikolwiek pom.xml zawiera parametr autoReleaseAfterClose, przerywamy budowę.
    # W przeciwnym razie istnieje ryzyko przesłania surowych artefaktów do Maven Central
    - >
      for pom in $(find . -name pom.xml); do
        if [[ $(grep -q autoReleaseAfterClose "$pom" && echo $?) == 0 ]]; then
          echo "Plik $pom zawiera zabronione ustawienie: ";
          exit 1;
        fi;
      done
    # Jeśli parametr DEPLOY_CI_COMMIT_TAG jest pusty, wymuszamy ustawienie wersji 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
    # Uruchamiamy zadanie na budowę i wdrożenie artefaktów
    - mvn clean deploy -DskipTests=true

Do treści

Projekt Java

W projektach java, które mają być przesyłane do publicznych repozytoriów, należy dodać 2 kroki do przesyłania wersji Release i Snapshot.

.gitlab-ci.yml

etapy:
  - budować
  - testować
  - weryfikować
  - wdrażać



Wydanie:
  rozszerza: .trigger_deploy
  # Uruchamiać zadanie tylko po tagu.
  tylko:
    - tagi

Migawka:
  rozszerza: .trigger_deploy
  # Uruchamiamy zadanie na publikację wersji SNAPSHOT ręcznie
  kiedy: ręcznie
  # Nie uruchamiać zadania, jeśli ustawiono tag.
  z wyjątkiem:
    - tagi

.trigger_deploy:
  etap: wdrożenie
  zmienne:
    # Wyłączamy klonowanie bieżącego projektu
    GIT_STRATEGY: none
    # Link do wyzwalacza zadania wdrożenia
    URL: "https://gitlab.com/api/v4/projects//trigger/pipeline"
    # Zmienne zadania wdrożenia
    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}
      "
  skrypt:
    # Nie używam cURL, ponieważ z flagami --fail --show-error
    # nie wyświetla ciała odpowiedzi, jeśli kod HTTP 400 i więcej
    - wget --content-on-error -qO- ${URL} --post-data ${POST_DATA}

W tym rozwiązaniu poszedłem nieco dalej i postanowiłem użyć jednego szablonu CI dla projektów java.

Bardziej szczegółowo

Stworzyłem oddzielny projekt gitlab-ci w którym umieściłem szablon CI dla projektów java common.yml.

common.yml

etapy:
  - budować
  - testować
  - weryfikować
  - wdrażać

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

.build_java_project:
  etap: budować
  tagi:
    - touchbit-shell
  zmienne:
    SKIP_TEST: "false"
  skrypt:
    - mvn clean
    - mvn package -DskipTests=${SKIP_TEST}
  artefakty:
    gdy: zawsze
    wygasa: 30 dni
    ścieżki:
      - "*\/target\/reports"

.build_sphinx_doc:
  etap: budować
  tagi:
    - touchbit-shell
  zmienne:
    DOCKERFILE: .indirect\/docs\/Dockerfile
  skrypt:
    - docker build --no-cache -t ${CI_PROJECT_NAME}\/doc -f ${DOCKERFILE} .

.junit_module_test_run:
  etap: testować
  tagi:
    - touchbit-shell
  zmienne:
    MODUŁ: ""
  skrypt:
    - cd ${MODUŁ}
    - mvn test
  artefakty:
    gdy: zawsze
    wygasa: 30 dni
    ścieżki:
      - "*\/target\/reports"

.junit_test_run:
  etap: testować
  tagi:
    - touchbit-shell
  skrypt:
    - mvn test
  artefakty:
    gdy: zawsze
    wygasa: 30 dni
    ścieżki:
    - "*\/target\/reports"

.sonar_review:
  etap: weryfikować
  tagi:
    - touchbit-shell
  zależności: []
  skrypt:
    - >
      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:
  etap: wdrożenie
  tagi:
    - touchbit-shell
  zmienne:
    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}
      "
  skrypt:
  - wget --content-on-error -qO- ${URL} --post-data ${POST_DATA}

.trigger_release_deploy:
  rozszerza: .trigger_deploy
  tylko:
    - tagi

.trigger_snapshot_deploy:
  rozszerza: .trigger_deploy
  kiedy: ręcznie
  z wyjątkiem:
    - tagi

W rezultacie pliki .gitlab-ci.yml w projektach java wyglądają bardzo kompaktowo i nie są zbyt rozbudowane.

.gitlab-ci.yml

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

Shields4J:
  extends: .build_java_project

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

Recenzja Sonar:
  extends: .sonar_review
  dependencies:
    - Shields4J

Wydanie:
  extends: .trigger_release_deploy

Snapshot:
  extends: .trigger_snapshot_deploy

Do treści

Konfiguracja pom.xml

Temat jest opisany bardzo szczegółowo. Googolplex do Konfiguracja Mavena dla automatycznego podpisywania i ładowania artefaktów do repozytoriów snapshot i staging., dlatego opiszę niektóre niuanse korzystania z wtyczek. Opiszę również, jak łatwo i bez wysiłku można je wykorzystać. nexus-staging-maven-plugin, jeśli nie chcesz lub nie możesz użyć org.sonatype.oss:oss-parent jako rodzica dla swojego projektu.

maven-install-plugin

Instaluje moduły w lokalnym repozytorium.
Bardzo przydatny do lokalnego sprawdzania rozwiązań w innych projektach, a także dla sum kontrolnych.

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

Do treści

maven-javadoc-plugin

Generowanie javadoc dla projektu.

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

Jeśli masz moduł, który nie zawiera java (na przykład tylko zasoby)
Lub w ogóle nie chcesz generować javadoc, to w pomocą maven-jar-plugin

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

Do treści

maven-gpg-plugin

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

Do treści

nexus-staging-maven-plugin

Konfiguracja:


  
    
      
      
        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/

Jeśli masz projekt wielomodułowy i nie musisz przesyłać konkretnego modułu do repozytorium, musisz dodać w pom.xml tego modułu nexus-staging-maven-plugin z flagą skipNexusStagingDeployMojo

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

Po przesłaniu wersji snapshot/release będą dostępne w repozytoria stagingowe

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

Kolejne zalety

  • Bardzo bogata lista celów do pracy z repozytorium nexus (mvn help:describe -Dplugin=org.sonatype.plugins:nexus-staging-maven-plugin).
  • Automatyczna weryfikacja wydania pod kątem możliwości przesłania do maven central

Do treści

Wynik

Publikacja wersji SNAPSHOT

Podczas budowy projektu istnieje możliwość ręcznego uruchomienia zadania przesyłania wersji SNAPSHOT do nexus

Konfiguracja GitLab CI do publikacji projektu Java w Maven Central

Podczas uruchamiania tego zadania wyzwalane jest odpowiednie zadanie w projekcie deploy (przykład).

Przycięty log

Uruchamianie z gitlab-runner 11.10.0 (3001a600)
  na uruchamiaczu wdrożeniowym JSKWyxUw
Używanie wykonawcy powłoki...
Uruchamianie na ih1174328.vds.myihor.ru...
Pomijanie konfiguracji repozytorium Git
Pomijanie checkoutu Git
Pomijanie konfiguracji submodułów 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} .
Klonowanie do 'shields4j'...
$ git checkout ${DEPLOY_CI_COMMIT_SHA}
Uwaga: wyjście '850f86aa317194395c5387790da1350e437125a7'.
Jesteś w stanie 'detached HEAD'. Możesz rozejrzeć się, wprowadzić eksperymentalne
zmiany i je zatwierdzić, a także możesz zignorować wszelkie komity,
które dokonasz w tym stanie bez wpływu na jakiekolwiek gałęzie, wykonując kolejny checkout.
Jeśli chcesz utworzyć nową gałąź, aby zachować komity, które tworzysz,
możesz to zrobić (teraz lub później), używając -b z poleceniem checkout ponownie. Przykład:
  git checkout -b new_branch_name
HEAD jest teraz na 850f86a... pomiń test wdrożeniowy test-core
$ for pom in $(find . -name pom.xml); do # całkowita komenda w wielu linijkach
$ if [[ "${DEPLOY_CI_COMMIT_TAG}" != "" ]]; then # całkowita komenda w wielu linijkach
[INFO] Skanowanie projektów...
[INFO] Inspekcja budowy z łącznie 4 modułami...
[INFO] Instalowanie funkcji Nexus Staging:
[INFO]   ... łącznie 4 wywołania maven-deploy-plugin zostały zastąpione nexus-staging-maven-plugin
[INFO] ------------------------------------------------------------------------
[INFO] Kolejność budowy reaktora:
[INFO] 
[INFO] Shields4J                                                          [pom]
[INFO] test-core                                                          [jar]
[INFO] klient Shields4J                                                  [jar]
[INFO] listener TestNG                                                    [jar]
[INFO] 
[INFO] -----------------------------
[INFO] Budowanie Shields4J 1.0.0                                           [1/4]
[INFO] --------------------------------[ pom ]---------------------------------
[INFO] 
[INFO] --- versions-maven-plugin:2.5:set (default-cli) @ shields4j-parent ---
[INFO] Szukanie lokalnego korzenia agregatora...
[INFO] Lokalny korzeń agregacji: /home/gitlab-deployer/JSKWyxUw/0/TouchBIT/deploy/shields4j
[INFO] Przetwarzanie zmiany org.touchbit.shields4j:shields4j-parent:1.0.0 -> 1.0.0-SNAPSHOT
[INFO] Przetwarzanie org.touchbit.shields4j:shields4j-parent
[INFO]     Aktualizacja projektu org.touchbit.shields4j:shields4j-parent
[INFO]         z wersji 1.0.0 do 1.0.0-SNAPSHOT
[INFO] 
[INFO] Przetwarzanie org.touchbit.shields4j:client
[INFO]     Aktualizacja rodzica org.touchbit.shields4j:shields4j-parent
[INFO]         z wersji 1.0.0 do 1.0.0-SNAPSHOT
[INFO]     Aktualizacja zależności org.touchbit.shields4j:test-core
[INFO]         z wersji 1.0.0 do 1.0.0-SNAPSHOT
[INFO] 
[INFO] Przetwarzanie org.touchbit.shields4j:test-core
[INFO]     Aktualizacja rodzica org.touchbit.shields4j:shields4j-parent
[INFO]         z wersji 1.0.0 do 1.0.0-SNAPSHOT
[INFO] 
[INFO] Przetwarzanie org.touchbit.shields4j:testng
[INFO]     Aktualizacja rodzica org.touchbit.shields4j:shields4j-parent
[INFO]         z wersji 1.0.0 do 1.0.0-SNAPSHOT
[INFO]     Aktualizacja zależności org.touchbit.shields4j:client
[INFO]         z wersji 1.0.0 do 1.0.0-SNAPSHOT
[INFO]     Aktualizacja zależności org.touchbit.shields4j:test-core
[INFO]         z wersji 1.0.0 do 1.0.0-SNAPSHOT
[INFO] 
[INFO] ------------------------------------------------------------------------
[INFO] Podsumowanie reaktora:
[INFO] 
[INFO] Shields4J 1.0.0 .................................... SUKCES [  0.992 s]
[INFO] test-core .......................................... POMINIĘTO
[INFO] klient Shields4J ................................... POMINIĘTO
[INFO] listener TestNG 1.0.0 .............................. POMINIĘTO
[INFO] ------------------------------------------------------------------------
[INFO] BUDOWA SUKCESU
[INFO] ------------------------------------------------------------------------
[INFO] Całkowity czas: 2.483 s
[INFO] Zakończono o: 2019-04-21T02:40:42+03:00
[INFO] ------------------------------------------------------------------------
$ mvn clean deploy -DskipTests=${SKIP_TESTS}
[INFO] Skanowanie projektów...
[INFO] Inspekcja budowy z łącznie 4 modułami...
[INFO] Instalowanie funkcji Nexus Staging:
[INFO]   ... łącznie 4 wywołania maven-deploy-plugin zostały zastąpione nexus-staging-maven-plugin
[INFO] ------------------------------------------------------------------------
[INFO] Kolejność budowy reaktora:
[INFO] 
[INFO] Shields4J                                                          [pom]
[INFO] test-core                                                          [jar]
[INFO] klient Shields4J                                                  [jar]
[INFO] listener TestNG                                                    [jar]
[INFO] 
[INFO] -----------------------------
[INFO] Budowanie Shields4J 1.0.0-SNAPSHOT                                  [1/4]
[INFO] --------------------------------[ pom ]---------------------------------
...
USUNIĘTO
...
[INFO]  * Hurtowe wdrożenie lokalnie zgromadzonych artefaktów snapshot zakończone.
[INFO] Zdalne wdrożenie zakończone sukcesem.
[INFO] ------------------------------------------------------------------------
[INFO] Podsumowanie reaktora:
[INFO] 
[INFO] Shields4J 1.0.0-SNAPSHOT ........................... SUKCES [  2.375 s]
[INFO] test-core .......................................... SUKCES [  3.929 s]
[INFO] klient Shields4J ................................... SUKCES [  3.815 s]
[INFO] listener TestNG 1.0.0-SNAPSHOT ..................... SUKCES [ 36.134 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUDOWA SUKCESU
[INFO] ------------------------------------------------------------------------
[INFO] Całkowity czas: 47.629 s
[INFO] Zakończono o: 2019-04-21T02:41:32+03:00
[INFO] ------------------------------------------------------------------------

W wyniku tego w nexus załadowana została wersja 1.0.0-SNAPSHOT.

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

Konfiguracja GitLab CI do publikacji projektu Java w Maven Central

Do treści

Publikacja wersji release

Podczas instalacji tagu automatycznie uruchamiana jest odpowiednia zadanie w projekcie deploy do załadowania wersji release do nexus (przykład).

Konfiguracja GitLab CI do publikacji projektu Java w Maven Central

Najprzyjemniejsze jest to, że automatycznie uruchamia się close release w nexus.

[INFO] Wykonywanie zdalnego stanu...
[INFO] 
[INFO]  * Zdalne stany w profilu stanu ID "9043b43f77dcc9"
[INFO]  * Utworzone repozytorium stanu z ID "orgtouchbit-1037".
[INFO]  * Repozytorium stanu w https://oss.sonatype.org:443/service/local/staging/deployByRepositoryId/orgtouchbit-1037
[INFO]  * Przesyłanie lokalnie zainicjowanych artefaktów do profilu org.touchbit
[INFO]  * Przesyłanie lokalnie zainicjowanych artefaktów zakończone.
[INFO]  * Zamknięcie repozytorium stanu z ID "orgtouchbit-1037".
Czekanie na zakończenie operacji...
.........
[INFO] Zdalnie zainicjowane 1 repozytoriów, zakończone sukcesem.
[INFO] ------------------------------------------------------------------------
[INFO] Podsumowanie Reactor:
[INFO] 
[INFO] Shields4J 1.0.0 .................................... SUKCES [  9.603 s]
[INFO] test-core .......................................... SUKCES [  3.419 s]
[INFO] Klient Shields4J ................................... SUKCES [  9.793 s]
[INFO] Słuchacz TestNG 1.0.0 .............................. SUKCES [01:23 min]
[INFO] ------------------------------------------------------------------------
[INFO] BUDOWA SUKCES
[INFO] ------------------------------------------------------------------------
[INFO] Łączny czas: 01:47 min
[INFO] Zakończono: 2019-04-21T04:05:46+03:00
[INFO] ------------------------------------------------------------------------

A jeśli coś poszło nie tak, zadanie na pewno się nie powiedzie

[INFO] Wykonywanie zdalnego stagingu...
[INFO] 
[INFO]  * Zdalne staging do profilu staging ID "9043b43f77dcc9"
[INFO]  * Utworzono repozytorium staging z ID "orgtouchbit-1038".
[INFO]  * Repozytorium staging na https://oss.sonatype.org:443/service/local/staging/deployByRepositoryId/orgtouchbit-1038
[INFO]  * Wgrywanie lokalnie wstępnie przygotowanych artefaktów do profilu org.touchbit
[INFO]  * Wgranie lokalnie wstępnie przygotowanych artefaktów zakończone.
[INFO]  * Zamykanie repozytorium staging z ID "orgtouchbit-1038".
Oczekiwanie na zakończenie operacji...
.......
[ERROR] Błąd reguły podczas próby zamknięcia repozytorium staging z ID "orgtouchbit-1039".
[ERROR] 
[ERROR] Raport błędów reguł Nexus Staging
[ERROR] ==================================
[ERROR] 
[ERROR] Błędy repozytorium "orgtouchbit-1039"
[ERROR]   Błędy reguły "signature-staging"
[ERROR]     * Brak klucza publicznego: Klucz o id: (1f42b618d1cbe1b5) nie został zlokalizowany na http://keys.gnupg.net:11371/. Wgraj swój klucz publiczny i spróbuj wykonać operację ponownie.
...
[ERROR] Czyszczenie lokalnego katalogu staging po błędzie reguły podczas zamykania repozytoriów staging: [orgtouchbit-1039]
[ERROR]  * Usunięcie kontekstu 9043b43f77dcc9.properties
[ERROR] Czyszczenie zdalnych repozytoriów staging po błędzie reguły podczas zamykania repozytoriów staging: [orgtouchbit-1039]
[ERROR]  * Usunięcie nieudanego repozytorium staging z ID "orgtouchbit-1039" (Błąd reguły podczas zamykania repozytoriów staging: [orgtouchbit-1039]).
[ERROR] Zdalne staging zakończyło się niepowodzeniem: Nieprawidłowe zasady stagingu!
[INFO] ------------------------------------------------------------------------
[INFO] Podsumowanie reakcji:
[INFO] 
[INFO] Shields4J 1.0.0 .................................... SUKCES [  4.073 s]
[INFO] test-core .......................................... SUKCES [  2.788 s]
[INFO] Klient Shields4J ................................... SUKCES [  3.962 s]
[INFO] Słuchacz TestNG 1.0.0 .............................. NIEPOWODZENIE [01:07 min]
[INFO] ------------------------------------------------------------------------
[INFO] NIEPOWODZENIE BUDOWY
[INFO] ------------------------------------------------------------------------

Pozostaje nam tylko jeden wybór. Albo usunąć tę wersję, albo ją opublikować.

Konfiguracja GitLab CI do publikacji projektu Java w Maven Central

Po wydaniu, po pewnym czasie artefakty znajdą się w Konfiguracja GitLab CI do publikacji projektu Java w Maven Central

offtop

Dla mnie było odkryciem, że maven indeksuje inne publiczne repozytoria.
Musiałem dodać robots.txt, ponieważ zindeksował moje stare repozytorium.

Do treści

Podsumowanie

Co posiadamy

  • Osobny projekt deploy, w którym można zrealizować kilka zadań CI dotyczących ładowania artefaktów do publicznych repozytoriów dla różnych języków programowania.
  • Projekt deploy jest izolowany od zewnętrznych ingerencji i może być zmieniany tylko przez użytkowników z rolą Właściciel i Utrzymujący.
  • Osobny Specific Runner z „gorącą” pamięcią podręczną, aby uruchamiać tylko zadania deploy.
  • Publikacja wersji snapshot/release w publicznym repozytorium.
  • Automatyczna weryfikacja wersji release pod kątem gotowości do publikacji w maven central.
  • Ochrona przed automatyczną publikacją „surowych” wersji w maven central.
  • Budowa i publikacja wersji snapshot „na kliknięcie”.
  • Jedno repozytorium do uzyskiwania wersji snapshot/release.
  • Ogólny pipeline do budowy/testowania/publikacji projektu Java.

Konfiguracja GitLab CI nie jest tak skomplikowana, jak się wydaje na pierwszy rzut oka. Wystarczy kilka razy skonfigurować CI „pod klucz”, a już nie jesteś nowicjuszem w tej dziedzinie. Zwłaszcza, że dokumentacja GitLab jest dość obszerna. Nie bój się zrobić pierwszego kroku. Droga ukazuje się pod krokami idącego (nie pamiętam, kto to powiedział 🙂 ).

Będę wdzięczny za opinie.

W następnym artykule opowiem, jak skonfigurować GitLab CI do równoległego uruchamiania zadań z testami integracyjnymi (z uruchamianiem testowanych usług za pomocą docker-compose), jeśli masz tylko jeden runner shell.

Do treści

Źródło: habr.com

Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS 🔥 Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS | ProHoster