Einrichten von GitLab CI zum Hochladen eines Java-Projekts in Maven Central

Dieser Artikel richtet sich an Java-Entwickler, die ihre Produkte mithilfe von GitLab schnell in zentralen Sonatype- und/oder Maven-Repositorys veröffentlichen müssen. In diesem Artikel werde ich über die Einrichtung von Gitlab-Runner, Gitlab-CI und Maven-Plugin sprechen, um dieses Problem zu lösen.

Voraussetzungen:

  • Sichere Speicherung von MVN- und GPG-Schlüsseln.
  • Sichere Ausführung öffentlicher CI-Aufgaben.
  • Hochladen von Artefakten (Release/Snapshot) in öffentliche Repositorys.
  • Automatische Prüfung der Release-Versionen zur Veröffentlichung in Maven Central.
  • Eine allgemeine Lösung zum Hochladen von Artefakten in ein Repository für mehrere Projekte.
  • Einfachheit und Benutzerfreundlichkeit.

Inhalt

Allgemeine Informationen

  • Eine detaillierte Beschreibung des Mechanismus zum Veröffentlichen von Artefakten in Maven Central über den Sonatype OSS Repository Hosting Service finden Sie bereits in dieser Artikel Benutzer Googolplex, daher werde ich an den richtigen Stellen auf diesen Artikel verweisen.
  • Vorab anmelden unter Sonatyp JIRA und starten Sie ein Ticket, um das Repository zu öffnen (weitere Informationen finden Sie im Abschnitt Erstellen Sie ein Sonatype JIRA-Ticket). Nach dem Öffnen des Repositorys wird das JIRA-Login/Passwort-Paar (im Folgenden als Sonatype-Konto bezeichnet) verwendet, um Artefakte in den Sonatype-Nexus hochzuladen.
  • Darüber hinaus wird der Prozess der Generierung eines GPG-Schlüssels sehr trocken beschrieben. Weitere Einzelheiten finden Sie im Abschnitt. Konfigurieren von GnuPG zum Signieren von Artefakten
  • Wenn Sie die Linux-Konsole zum Generieren eines GPG-Schlüssels (gnupg/gnupg2) verwenden, müssen Sie ihn installieren Rng-Werkzeuge Entropie zu erzeugen. Andernfalls kann die Schlüsselgenerierung sehr lange dauern.
  • Lagerdienstleistungen öffentlich GPG-Schlüssel

Zurück zum Inhalt

Einrichten eines Bereitstellungsprojekts in GitLab

  • Zunächst müssen Sie ein Projekt erstellen und konfigurieren, in dem die Pipeline für die Bereitstellung von Artefakten gespeichert wird. Ich habe mein Projekt einfach und unkompliziert aufgerufen - einsetzen
  • Nachdem Sie das Repository erstellt haben, müssen Sie den Zugriff beschränken, um das Repository ändern zu können.
    Gehen Sie zum Projekt -> Einstellungen -> Repository -> Geschützte Zweige. Wir löschen alle Regeln und fügen eine einzelne Regel mit Wildcard * mit dem Recht zum Pushen und Zusammenführen nur für Benutzer mit der Rolle „Betreuer“ hinzu. Diese Regel gilt für alle Benutzer dieses Projekts und der Gruppe, zu der dieses Projekt gehört.
    Einrichten von GitLab CI zum Hochladen eines Java-Projekts in Maven Central
  • Wenn es mehrere Betreuer gibt, wäre es die beste Lösung, den Zugriff auf das Projekt grundsätzlich einzuschränken.
    Gehen Sie zum Projekt -> Einstellungen -> Allgemein -> Sichtbarkeit, Projektfunktionen, Berechtigungen und stellen Sie die Sichtbarkeit des Projekts auf ein Privat.
    Ich habe ein Projekt im öffentlichen Zugriff, da ich meinen eigenen GitLab Runner verwende und nur ich Zugriff zum Ändern des Repositorys habe. Nun, eigentlich liegt es nicht in meinem Interesse, private Informationen in öffentlichen Pipeline-Protokollen anzuzeigen.
  • Verschärfung der Regeln für den Wechsel des Repositorys
    Gehen Sie zum Projekt -> Einstellungen -> Repository -> Push-Regeln und setzen Sie die Flags Committer-Einschränkung. Überprüfen Sie, ob der Autor ein GitLab-Benutzer ist. Ich empfehle auch die Einstellung Unterzeichnung verpflichtenund setzen Sie das Flag „Unsignierte Commits ablehnen“.
  • Als Nächstes müssen Sie einen Auslöser zum Ausführen von Aufgaben konfigurieren
    Gehen Sie zu Projekt -> Einstellungen -> CI/CD -> Pipeline-Trigger und erstellen Sie ein neues Trigger-Token
    Dieses Token kann sofort zur allgemeinen Variablenkonfiguration für eine Gruppe von Projekten hinzugefügt werden.
    Gehen Sie zur Gruppe -> Einstellungen -> CI/CD -> Variablen und fügen Sie eine Variable hinzu DEPLOY_TOKEN mit Trigger-Token im Wert.

Zurück zum Inhalt

GitLab-Runner

In diesem Abschnitt wird die Konfiguration zum Ausführen von Aufgaben bei der Bereitstellung mithilfe des nativen (spezifischen) und öffentlichen (gemeinsam genutzten) Läufers beschrieben.

Spezifischer Läufer

Ich benutze meine eigenen Läufer, weil es vor allem bequem, schnell und günstig ist.
Für Läufer empfehle ich Linux VDS mit 1 CPU, 2 GB RAM, 20 GB HDD. Ausgabepreis ~ 3000₽ pro Jahr.

Mein Läufer

Für den Runner habe ich eine VDS 4 CPU, 4 GB RAM, 50 GB SSD genommen. Es hat ca. 11000₽ gekostet und ich habe es nie bereut.
Ich habe insgesamt 7 Maschinen. 5 auf Aruba und 2 auf Ihor.

Wir haben also einen Läufer. Jetzt werden wir es einrichten.
Wir gehen über SSH auf die Maschine und installieren Java, Git, Maven, Gnupg2.

Zurück zum Inhalt

Gitlab Runner installieren

  • Erstellen Sie eine neue Gruppe runner
    sudo groupadd runner
  • Erstellen Sie ein Verzeichnis für den Maven-Cache und weisen Sie Gruppenrechte zu runner
    Sie können diesen Schritt überspringen, wenn Sie nicht vorhaben, mehrere Läufer auf demselben Computer auszuführen.

    mkdir -p /usr/cache/.m2/repository
    chown -R :runner /usr/cache
    chmod -R 770 /usr/cache
  • Erstellen Sie einen Benutzer gitlab-deployer und zur Gruppe hinzufügen runner
    useradd -m -d /home/gitlab-deployer gitlab-deployer
    usermod -a -G runner gitlab-deployer
  • Zur Datei hinzufügen /etc/ssh/sshd_config nächste Zeile
    AllowUsers root@* [email protected]
  • Neustart sshd
    systemctl restart sshd
  • Legen Sie ein Passwort für den Benutzer fest gitlab-deployer (es kann einfach sein, da es eine Einschränkung für localhost gibt)
    passwd gitlab-deployer
  • GitLab Runner installieren (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
  • Gehen Sie zu gitlab.com -> Deploy-Project -> Einstellungen -> CI/CD -> Runners -> Spezifische Runners und kopieren Sie das Registrierungstoken

Bildschirm

Einrichten von GitLab CI zum Hochladen eines Java-Projekts in Maven Central

  • Anmeldung des Läufers
    gitlab-runner register --config /etc/gitlab-runner/gitlab-deployer-config.toml

Prozess

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!

  • Überprüfen Sie, ob der Läufer registriert ist. Gehen Sie zu gitlab.com -> Deploy-Project -> Einstellungen -> CI/CD -> Runners -> Spezifische Runners -> Für dieses Projekt aktivierte Runners

Bildschirm

Einrichten von GitLab CI zum Hochladen eines Java-Projekts in Maven Central

  • Hinzufügen trennen Service /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
  • Wir starten den Gottesdienst.
    systemctl enable gitlab-deployer.service
    systemctl start gitlab-deployer.service
    systemctl status gitlab-deployer.service
  • Überprüfen Sie, ob der Läufer läuft.

Beispiel

Einrichten von GitLab CI zum Hochladen eines Java-Projekts in Maven Central

Zurück zum Inhalt

GPG-Schlüsselgenerierung

  • Von derselben Maschine aus gehen wir über SSH unter dem Benutzer gitlab-deployer (Dies ist wichtig für die GPG-Schlüsselgenerierung)

    ssh [email protected]

  • Durch die Beantwortung von Fragen generieren wir einen Schlüssel. Ich habe meinen eigenen Namen und meine E-Mail-Adresse verwendet.
    Geben Sie unbedingt das Passwort für den Schlüssel an. Artefakte werden mit diesem Schlüssel signiert.

    gpg --gen-key 

  • Überprüfung

    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

  • Hochladen unseres öffentlichen Schlüssels auf den Schlüsselserver

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

Zurück zum Inhalt

Maven-Setup

  • Wir gehen unter den Benutzer gitlab-deployer
    su gitlab-deployer 
  • Erstellen Sie ein Maven-Verzeichnis Quelle und mit dem Cache verknüpfen (kein Fehler machen)
    Dieser Schritt kann übersprungen werden, wenn Sie nicht vorhaben, mehrere Läufer auf derselben Maschine auszuführen.

    mkdir -p ~/.m2/repository
    ln -s /usr/cache/.m2/repository /home/gitlab-deployer/.m2/repository
  • Erstellen Sie einen Hauptschlüssel
    mvn --encrypt-master-password password
    {hnkle5BJ9HUHUMP+CXfGBl8dScfFci/mpsur/73tR2I=}
  • Erstellen Sie die Datei ~/.m2/settings-security.xml
    <settingsSecurity>
    <master>{hnkle5BJ9HUHUMP+CXfGBl8dScfFci/mpsur/73tR2I=}</master>
    </settingsSecurity>
  • Verschlüsseln des Passworts vom Sonatype-Konto
    mvn --encrypt-password SONATYPE_PASSWORD
    {98Wv5+u+Tn0HX2z5G/kR4R8Z0WBgcDBgi7d12S/un+SCU7uxzaZGGmJ8Cu9pAZ2J}
  • Erstellen Sie die Datei ~/.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>

wo
GPG_SECRET_KEY_PASSPHRASE – GPG-Schlüsselpasswort
SONATYPE_USERNAME – Anmeldung für das Sonatype-Konto

Damit ist die Läufereinrichtung abgeschlossen. Sie können mit dem Abschnitt fortfahren GitLab-CI

Zurück zum Inhalt

Geteilter Läufer

GPG-Schlüsselgenerierung

  • Zunächst müssen Sie einen GPG-Schlüssel erstellen. Installieren Sie dazu gnupg.

    yum install -y gnupg

  • Durch die Beantwortung von Fragen generieren wir einen Schlüssel. Ich habe meinen eigenen Namen und meine E-Mail-Adresse verwendet. Geben Sie unbedingt das Passwort für den Schlüssel an.

    gpg --gen-key 

  • Rufen Sie wichtige Informationen ab

    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]

  • Hochladen unseres öffentlichen Schlüssels auf den Schlüsselserver

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

  • Einen privaten Schlüssel erhalten

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

  • Gehen Sie zu Projekteinstellungen -> Einstellungen -> CI/CD -> Variablen und speichern Sie den privaten Schlüssel in einer Variablen GPG_SECRET_KEY
    Einrichten von GitLab CI zum Hochladen eines Java-Projekts in Maven Central

Zurück zum Inhalt

Maven-Setup

  • Erstellen Sie einen Hauptschlüssel
    mvn --encrypt-master-password password
    {hnkle5BJ9HUHUMP+CXfGBl8dScfFci/mpsur/73tR2I=}
  • Gehen Sie zu Projekteinstellungen -> Einstellungen -> CI/CD -> Variablen und speichern Sie in einer Variablen SETTINGS_SECURITY_XML die folgenden Zeilen:
    <settingsSecurity>
    <master>{hnkle5BJ9HUHUMP+CXfGBl8dScfFci/mpsur/73tR2I=}</master>
    </settingsSecurity>
  • Verschlüsseln des Passworts vom Sonatype-Konto
    mvn --encrypt-password SONATYPE_PASSWORD
    {98Wv5+u+Tn0HX2z5G/kR4R8Z0WBgcDBgi7d12S/un+SCU7uxzaZGGmJ8Cu9pAZ2J}
  • Gehen Sie zu Projekteinstellungen -> Einstellungen -> CI/CD -> Variablen und speichern Sie in einer Variablen SETTINGS_XML die folgenden Zeilen:
    <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>

wo
GPG_SECRET_KEY_PASSPHRASE – GPG-Schlüsselpasswort
SONATYPE_USERNAME – Anmeldung für das Sonatype-Konto

Zurück zum Inhalt

Docker-Image bereitstellen

  • Wir erstellen eine ziemlich einfache Docker-Datei, um Aufgaben bei der Bereitstellung mit der gewünschten Java-Version auszuführen. Unten finden Sie ein Beispiel für 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/

  • Erstellen Sie einen Container für Ihr Projekt

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

  • Wir authentifizieren den Container und laden ihn in die Registry.

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

Zurück zum Inhalt

GitLab-CI

Projekt bereitstellen

Fügen Sie die Datei .gitlab-ci.yml zum Stammverzeichnis des Bereitstellungsprojekts hinzu
Das Skript stellt zwei sich gegenseitig ausschließende Bereitstellungsaufgaben dar. Spezifischer Runner bzw. Shared Runner.

.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

Zurück zum Inhalt

Java-Projekt

In Java-Projekten, die in öffentliche Repositorys hochgeladen werden sollen, müssen Sie zwei Schritte hinzufügen, um die Release- und Snapshot-Versionen herunterzuladen.

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

Bei dieser Lösung bin ich noch einen Schritt weiter gegangen und habe mich für die Verwendung einer CI-Vorlage für Java-Projekte entschieden.

Ausführlicher

Ich habe ein separates Projekt erstellt gitlab-ci in dem er die CI-Vorlage für Java-Projekte platzierte common.yml.

common.yml

stages:
  - build
  - test
  - verify
  - deploy

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

.build_java_project:
  stage: build
  tags:
    - touchbit-shell
  variables:
    SKIP_TEST: "false"
  script:
    - mvn clean
    - mvn package -DskipTests=${SKIP_TEST}
  artifacts:
    when: always
    expire_in: 30 day
    paths:
      - "*/target/reports"

.build_sphinx_doc:
  stage: build
  tags:
    - touchbit-shell
  variables:
    DOCKERFILE: .indirect/docs/Dockerfile
  script:
    - docker build --no-cache -t ${CI_PROJECT_NAME}/doc -f ${DOCKERFILE} .

.junit_module_test_run:
  stage: test
  tags:
    - touchbit-shell
  variables:
    MODULE: ""
  script:
    - cd ${MODULE}
    - mvn test
  artifacts:
    when: always
    expire_in: 30 day
    paths:
      - "*/target/reports"

.junit_test_run:
  stage: test
  tags:
    - touchbit-shell
  script:
    - mvn test
  artifacts:
    when: always
    expire_in: 30 day
    paths:
    - "*/target/reports"

.sonar_review:
  stage: verify
  tags:
    - touchbit-shell
  dependencies: []
  script:
    - >
      if [ "$CI_BUILD_REF_NAME" == "master" ]; then
        mvn compile sonar:sonar -Dsonar.login=$SONAR_LOGIN $SONAR_ARGS
      else
        mvn compile sonar:sonar -Dsonar.login=$SONAR_LOGIN $SONAR_ARGS -Dsonar.analysis.mode=preview
      fi

.trigger_deploy:
  stage: deploy
  tags:
    - touchbit-shell
  variables:
    URL: "https://gitlab.com/api/v4/projects/10345765/trigger/pipeline"
    POST_DATA: "
      token=${DEPLOY_TOKEN}&
      ref=master&
      variables[DEPLOY]=${DEPLOY}&
      variables[DEPLOY_CI_REPOSITORY_URL]=${CI_REPOSITORY_URL}&
      variables[DEPLOY_CI_PROJECT_NAME]=${CI_PROJECT_NAME}&
      variables[DEPLOY_CI_COMMIT_SHA]=${CI_COMMIT_SHA}&
      variables[DEPLOY_CI_COMMIT_TAG]=${CI_COMMIT_TAG}
      "
  script:
  - wget --content-on-error -qO- ${URL} --post-data ${POST_DATA}

.trigger_release_deploy:
  extends: .trigger_deploy
  only:
    - tags

.trigger_snapshot_deploy:
  extends: .trigger_deploy
  when: manual
  except:
    - tags

Infolgedessen sieht .gitlab-ci.yml in den Java-Projekten selbst sehr kompakt und nicht ausführlich aus

.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

Zurück zum Inhalt

pom.xml-Konfiguration

Dieses Thema wird ausführlich beschrieben. Googolplex в Einrichten von Maven zum automatischen Signieren und Hochladen von Artefakten in Snapshot- und Staging-Repositorys, daher werde ich einige Nuancen der Verwendung von Plugins beschreiben. Ich werde auch beschreiben, wie einfach und natürlich Sie es verwenden können nexus-staging-maven-pluginwenn Sie org.sonatype.oss:oss-parent nicht als übergeordnetes Element für Ihr Projekt verwenden möchten oder können.

maven-install-plugin

Installiert Module im lokalen Repository.
Sehr nützlich für die lokale Überprüfung von Lösungen in anderen Projekten sowie als Prüfsumme.

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

Zurück zum Inhalt

maven-javadoc-plugin

Javadoc für das Projekt generieren.

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

Wenn Sie ein Modul haben, das kein Java enthält (zum Beispiel nur Ressourcen)
Oder Sie möchten Javadoc grundsätzlich nicht generieren, um dann zu helfen 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>

Zurück zum Inhalt

maven-gpg-plugin

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-gpg-plugin</artifactId>
  <executions>
    <execution>
      <id>sign-artifacts</id>
      <!-- Сборка будет падать, если отсутствует GPG ключ -->
      <!-- Подписываем артефакты только на фазе deploy -->
      <phase>deploy</phase>
      <goals>
        <goal>sign</goal>
      </goals>
    </execution>
  </executions>
</plugin>

Zurück zum Inhalt

Nexus-Staging-Maven-Plugin

Konfiguration:

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

Wenn Sie ein Projekt mit mehreren Modulen haben und kein bestimmtes Modul in das Repository hochladen müssen, müssen Sie es zur pom.xml dieses Moduls hinzufügen nexus-staging-maven-plugin mit Fahne skipNexusStagingDeployMojo

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

Nach dem Hochladen sind Snapshot-/Release-Versionen in verfügbar Staging-Repositorys

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

Mehr Pluspunkte

  • Eine sehr umfangreiche Liste von Zielen für die Arbeit mit dem Nexus-Repository (mvn help:describe -Dplugin=org.sonatype.plugins:nexus-staging-maven-plugin).
  • Automatische Release-Prüfung auf Herunterladbarkeit in Maven Central

Zurück zum Inhalt

Erlebe die Kraft effektiver Ergebnisse

Veröffentlichen einer SNAPSHOT-Version

Beim Erstellen eines Projekts ist es möglich, manuell eine Aufgabe zu starten, um die SNAPSHOT-Version auf Nexus herunterzuladen

Einrichten von GitLab CI zum Hochladen eines Java-Projekts in Maven Central

Wenn diese Aufgabe gestartet wird, wird die entsprechende Aufgabe im Bereitstellungsprojekt ausgelöst (Beispiel).

abgeschnittenes Protokoll

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

Als Ergebnis wird die Nexus-Version geladen 1.0.0-SCHNAPPSCHUSS.

Alle Snapshot-Versionen können aus dem Repository auf der Site entfernt werden oss.sonatype.org unter Ihrem Konto.

Einrichten von GitLab CI zum Hochladen eines Java-Projekts in Maven Central

Zurück zum Inhalt

Veröffentlichung der Release-Version

Wenn das Tag gesetzt ist, wird die entsprechende Aufgabe im Bereitstellungsprojekt automatisch ausgelöst, um die Release-Version auf Nexus hochzuladen (Beispiel).

Einrichten von GitLab CI zum Hochladen eines Java-Projekts in Maven Central

Das Beste daran ist, dass die Nahfreigabe automatisch in Nexus ausgelöst wird.

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

Und wenn etwas schiefgeht, wird die Aufgabe scheitern

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

Dadurch bleibt uns nur noch eine Wahl. Oder diese Version löschen oder veröffentlichen.

Einrichten von GitLab CI zum Hochladen eines Java-Projekts in Maven Central

Nach der Veröffentlichung, nach einiger Zeit, werden die Artefakte verfügbar sein Einrichten von GitLab CI zum Hochladen eines Java-Projekts in Maven Central

Offtopic

Für mich war es eine Offenbarung, dass Maven andere öffentliche Repositories indiziert.
Ich musste robots.txt hochladen, weil es mein altes Repository indizierte.

Zurück zum Inhalt

Abschluss

Was wir haben

  • Ein separates Bereitstellungsprojekt, in dem Sie mehrere CI-Aufgaben zum Hochladen von Artefakten in öffentliche Repositorys für verschiedene Entwicklungssprachen implementieren können.
  • Das Bereitstellungsprojekt ist von externen Eingriffen isoliert und kann nur von Benutzern mit den Rollen „Eigentümer“ und „Betreuer“ geändert werden.
  • Ein separater spezifischer Runner mit einem „heißen“ Cache, um nur Bereitstellungsaufgaben auszuführen.
  • Veröffentlichung von Snapshot-/Release-Versionen in einem öffentlichen Repository.
  • Automatische Prüfung der Release-Version auf Veröffentlichungsbereitschaft in Maven Central.
  • Schutz vor der automatischen Veröffentlichung von „Rohversionen“ in Maven Central.
  • Erstellen und veröffentlichen Sie Snapshot-Versionen „auf Knopfdruck“.
  • Einzelnes Repository zum Abrufen von Snapshot-/Release-Versionen.
  • Allgemeine Pipeline zum Erstellen/Testen/Veröffentlichen eines Java-Projekts.

Das Einrichten von GitLab CI ist kein so kompliziertes Thema, wie es auf den ersten Blick scheint. Es reicht aus, CI ein paar Mal schlüsselfertig einzurichten, und jetzt sind Sie in dieser Angelegenheit alles andere als ein Amateur. Darüber hinaus ist die GitLab-Dokumentation sehr redundant. Haben Sie keine Angst, den ersten Schritt zu tun. Die Straße erscheint unter den Schritten der Person, die geht (ich weiß nicht mehr, wer das gesagt hat :)

Über Feedback freue ich mich.

Im nächsten Artikel zeige ich Ihnen, wie Sie GitLab CI einrichten, um Integrationstestaufgaben wettbewerbsfähig auszuführen (Testdienste mit Docker-Compose ausführen), wenn Sie nur einen Shell-Runner haben.

Zurück zum Inhalt

Source: habr.com

Kommentar hinzufügen