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 przez użytkownika , dlatego w odpowiednich miejscach będę odwoływał się do tego artykułu.
- Najpierw rejestrujemy się w i tworzymy zgłoszenie o otwarcie repozytorium (szczegóły można znaleźć w sekcji ). 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
- Jeśli korzystasz z konsoli Linux do generowania klucza GPG (gnupg/gnupg2), musisz zainstalować , aby generować entropię. W przeciwnym razie proces generowania klucza może trwać bardzo długo.
- Usługi przechowywania publicznych kluczy GPG
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 —
- 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.
- 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 , 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_TOKENz tokenem wyzwalacza w wartoś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.
Instalujemy gitlab runner
- Tworzymy nową grupę
runnersudo 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-deployeri dodajemy do grupyrunneruseradd -m -d /home/gitlab-deployer gitlab-deployer usermod -a -G runner gitlab-deployer - Dodajemy do pliku
/etc/ssh/sshd_confignastępującą linijkęAllowUsers root@* gitlab-deployer@127.0.0.1 - Restartujemy
sshdsystemctl 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
- 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
- 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
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
Konfiguracja Maven
- Logujemy się jako użytkownik
gitlab-deployersu 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
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 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_XMLnastę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_XMLnastę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
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
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=trueProjekt 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 w którym umieściłem szablon CI dla projektów java .
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_deployKonfiguracja pom.xml
Temat jest opisany bardzo szczegółowo. do , 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
truemaven-javadoc-plugin
Generowanie javadoc dla projektu.
org.apache.maven.plugins
maven-javadoc-plugin
jar
prepare-package
true
true
falseJeś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}/javadocmaven-gpg-plugin
org.apache.maven.plugins
maven-gpg-plugin
sign-artifacts
deploy
signnexus-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
truePo przesłaniu wersji snapshot/release będą dostępne w
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
Wynik
Publikacja wersji SNAPSHOT
Podczas budowy projektu istnieje możliwość ręcznego uruchomienia zadania przesyłania wersji SNAPSHOT do nexus
Podczas uruchamiania tego zadania wyzwalane jest odpowiednie zadanie w projekcie deploy ().
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 .
Wszystkie wersje snapshot można usunąć z repozytorium na stronie pod swoim kontem.
Publikacja wersji release
Podczas instalacji tagu automatycznie uruchamiana jest odpowiednia zadanie w projekcie deploy do załadowania wersji release do nexus ().
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ć.
Po wydaniu, po pewnym czasie artefakty znajdą się w
offtop
Dla mnie było odkryciem, że maven indeksuje inne publiczne repozytoria.
Musiałem dodać robots.txt, ponieważ zindeksował moje stare repozytorium.
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.
Źródło: habr.com
