Agordante GitLab CI por alŝuti java projekton al maven central

Ĉi tiu artikolo estas destinita por java-programistoj, kiuj bezonas rapide publikigi siajn produktojn al sonataj kaj/aŭ maven-centraj deponejoj uzante GitLab. En ĉi tiu artikolo, mi parolos pri agordo de gitlab-runner, gitlab-ci kaj maven-plugin por solvi ĉi tiun problemon.

Antaŭkondiĉoj:

  • Sekura stokado de mvn kaj GPG-ŝlosiloj.
  • Sekura plenumo de publikaj CI-taskoj.
  • Alŝuto de artefaktoj (eldono/momentfoto) al publikaj deponejoj.
  • Aŭtomata kontrolo de eldonversioj por publikigo en Maven Central.
  • Ĝenerala solvo por alŝuti artefaktojn al deponejo por pluraj projektoj.
  • Simpleco kaj facileco de uzo.

Enhavo

Ĝeneralaj informoj

  • Detala priskribo de la mekanismo por publikigado de artefaktoj al Maven Central per la Sonatype OSS Repository Hosting Service jam estas priskribita en ĉi tiu artikolo uzanto Googlelplex, do mi referencos ĉi tiun artikolon en la ĝustaj lokoj.
  • Antaŭregistru por Sonatipo JIRA kaj komencu bileton por malfermi la deponejon (por pliaj detaloj, legu la sekcion Kreu Sonatype JIRA-bileton). Post malfermo de la deponejo, la JIRA-ensaluto/pasvortparo (ĉi-poste nomata Sonatype-konto) estos uzata por alŝuti artefaktojn al la Sonatype ligilo.
  • Plue, la procezo de generado de GPG-ŝlosilo estas priskribita tre seke. Vidu la sekcion por pliaj detaloj. Agordante GnuPG por subskribi artefaktojn
  • Se vi uzas la Linuksan konzolon por generi GPG-ŝlosilon (gnupg/gnupg2), tiam vi devas instali rng-iloj por generi entropion. Alie, ŝlosila generacio povas daŭri tre longan tempon.
  • Servoj de stokado publiko GPG-ŝlosiloj

Al la enhavo

Agordi deplojan projekton en GitLab

  • Antaŭ ĉio, vi devas krei kaj agordi projekton, en kiu la dukto estos stokita por la disfaldiĝo de artefaktoj. Mi nomis mian projekton simple kaj nekomplika - disfaldi
  • Post kreado de la deponejo, vi devas limigi aliron por ŝanĝi la deponejon.
    Iru al la projekto -> Agordoj -> Deponejo -> Protektitaj branĉoj. Ni forigas ĉiujn regulojn kaj aldonas ununuran regulon kun Wildcard * kun la rajto puŝi kaj kunfandi nur por uzantoj kun la rolo Prizorgantoj. Ĉi tiu regulo funkcios por ĉiuj uzantoj kaj de ĉi tiu projekto kaj de la grupo al kiu ĉi tiu projekto apartenas.
    Agordante GitLab CI por alŝuti java projekton al maven central
  • Se estas pluraj prizorgantoj, tiam la plej bona solvo estus principe limigi aliron al la projekto.
    Iru al la projekto -> Agordoj -> Ĝenerala -> Videbleco, projektaj funkcioj, permesoj kaj agordu Projektan videblecon al privata.
    Mi havas projekton en publika aliro, ĉar mi uzas mian propran GitLab Runner kaj nur mi havas aliron por modifi la deponejon. Nu, fakte ne estas en mia intereso montri privatajn informojn en publikaj protokoloj.
  • Streĉigi la regulojn por ŝanĝi la deponejon
    Iru al la projekto -> Agordoj -> Deponejo -> Push Rules kaj starigu la flagojn Committer-limigo, Kontrolu ĉu aŭtoro estas GitLab-uzanto. Mi ankaŭ rekomendas agordi commit subskribo, kaj starigu la flagon Malakcepti nesubskribitajn.
  • Poste, vi devas agordi ellasilon por ruli taskojn
    Iru al projekto -> Agordoj -> CI / KD -> Pipeline-eksiloj kaj kreu novan ellasilon
    Ĉi tiu signo povas esti tuj aldonita al la ĝenerala agordo de variabloj por grupo de projektoj.
    Iru al la grupo -> Agordoj -> CI / KD -> Variabloj kaj aldonu variablon DEPLOY_TOKEN kun ellasilo-ĵetono en la valoro.

Al la enhavo

GitLab Runner

Ĉi tiu sekcio priskribas la agordon por funkciigado de taskoj dum deplojo uzante la denaskan (Specifa) kaj publikan (Kundividita) kuristo.

Specifa Kuristo

Mi uzas miajn proprajn kuristojn ĉar, antaŭ ĉio, ĝi estas oportuna, rapida kaj malmultekosta.
Por kuristo mi rekomendas Linukson VDS kun 1 CPU, 2 GB RAM, 20 GB HDD. Eldonprezo ~ 3000₽ jare.

Mia kuristo

Por la kuristo mi prenis VDS 4 CPU, 4 GB RAM, 50 GB SSD. Ĝi kostis ~11000₽ kaj neniam bedaŭris ĝin.
Mi havas entute 7 maŝinojn. 5 sur arubo kaj 2 sur ihor.

Do, ni havas kuriston. Nun ni starigos ĝin.
Ni iras al la maŝino per SSH kaj instalas java, git, maven, gnupg2.

Al la enhavo

Instalante gitlab runner

  • Kreu novan grupon runner
    sudo groupadd runner
  • Kreu dosierujon por la kaŝmemoro de Maven kaj asignu grupajn permesojn runner
    Vi povas preterlasi ĉi tiun paŝon se vi ne planas funkciigi plurajn kuristojn sur la sama maŝino.

    mkdir -p /usr/cache/.m2/repository
    chown -R :runner /usr/cache
    chmod -R 770 /usr/cache
  • Kreu uzanton gitlab-deployer kaj aldonu al la grupo runner
    useradd -m -d /home/gitlab-deployer gitlab-deployer
    usermod -a -G runner gitlab-deployer
  • Aldoni al dosiero /etc/ssh/sshd_config sekva linio
    AllowUsers root@* [email protected]
  • Rekomencu sshd
    systemctl restart sshd
  • Agordu pasvorton por la uzanto gitlab-deployer (ĝi povas esti simpla, ĉar ekzistas limigo por localhost)
    passwd gitlab-deployer
  • Instalu GitLab Runner (Linukso 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
  • Iru al gitlab.com -> deploy-project -> Agordoj -> CI/CD -> Runners -> Specifaj Runners kaj kopiu la registriĝan ĵetonon

Ekrano

Agordante GitLab CI por alŝuti java projekton al maven central

  • Registrante la kuriston
    gitlab-runner register --config /etc/gitlab-runner/gitlab-deployer-config.toml

procezo

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!

  • Kontrolu, ke la kuristo estas registrita. Iru al gitlab.com -> deploy-project -> Agordoj -> CI/CD -> Runners -> Specifaj Runners -> Runners aktivigitaj por ĉi tiu projekto

Ekrano

Agordante GitLab CI por alŝuti java projekton al maven central

  • Aldoni apartigi servo /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
  • Ni komencas la servon.
    systemctl enable gitlab-deployer.service
    systemctl start gitlab-deployer.service
    systemctl status gitlab-deployer.service
  • Kontrolu, ke la kuristo kuras.

Ekzemplo:

Agordante GitLab CI por alŝuti java projekton al maven central

Al la enhavo

GPG-ŝlosila generacio

  • De la sama maŝino ni iras per ssh sub la uzanto gitlab-deployer (ĉi tio estas grava por GPG-ŝlosila generacio)

    ssh [email protected]

  • Ni generas ŝlosilon respondante demandojn. Mi uzis mian propran nomon kaj retpoŝton.
    Nepre specifu la pasvorton por la ŝlosilo. Artefaktoj estos subskribitaj per ĉi tiu ŝlosilo.

    gpg --gen-key 

  • Kontrolante

    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

  • Alŝutante nian publikan ŝlosilon al la ŝlosilservilo

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

Al la enhavo

Maven-aranĝo

  • Ni iras sub la uzanton gitlab-deployer
    su gitlab-deployer 
  • Kreu maven-dosierujon repositorio kaj ligu kun la kaŝmemoro (ne eraru)
    Ĉi tiu paŝo povas esti preterlasita se vi ne planas funkciigi plurajn kuristojn sur la sama maŝino.

    mkdir -p ~/.m2/repository
    ln -s /usr/cache/.m2/repository /home/gitlab-deployer/.m2/repository
  • Kreu majstran ŝlosilon
    mvn --encrypt-master-password password
    {hnkle5BJ9HUHUMP+CXfGBl8dScfFci/mpsur/73tR2I=}
  • Kreu dosieron ~/.m2/settings-security.xml
    <settingsSecurity>
    <master>{hnkle5BJ9HUHUMP+CXfGBl8dScfFci/mpsur/73tR2I=}</master>
    </settingsSecurity>
  • Ĉifrado de la pasvorto de la Sonatype-konto
    mvn --encrypt-password SONATYPE_PASSWORD
    {98Wv5+u+Tn0HX2z5G/kR4R8Z0WBgcDBgi7d12S/un+SCU7uxzaZGGmJ8Cu9pAZ2J}
  • Kreu dosieron ~/.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>

kie,
GPG_SECRET_KEY_PASSPHRASE - GPG-ŝlosila pasvorto
SONATYPE_USERNAME - ensaluto de konto sonatype

Ĉi tio kompletigas la agordon de la kuristo, vi povas iri al la sekcio GitLab CI

Al la enhavo

Kunigita Kuristo

GPG-ŝlosila generacio

  • Antaŭ ĉio, vi devas krei GPG-ŝlosilon. Por fari tion, instalu gnupg.

    yum install -y gnupg

  • Ni generas ŝlosilon respondante demandojn. Mi uzis mian propran nomon kaj retpoŝton. Nepre specifu la pasvorton por la ŝlosilo.

    gpg --gen-key 

  • Reakiru ŝlosilajn informojn

    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]

  • Alŝutante nian publikan ŝlosilon al la ŝlosilservilo

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

  • Akiro de privata ŝlosilo

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

  • Iru al projektaj agordoj -> Agordoj -> CI / KD -> Variabloj kaj konservu la privatan ŝlosilon en variablo GPG_SECRET_KEY
    Agordante GitLab CI por alŝuti java projekton al maven central

Al la enhavo

Maven-aranĝo

  • Kreu majstran ŝlosilon
    mvn --encrypt-master-password password
    {hnkle5BJ9HUHUMP+CXfGBl8dScfFci/mpsur/73tR2I=}
  • Iru al projektaj agordoj -> Agordoj -> CI / KD -> Variabloj kaj konservu en variablo SETTINGS_SECURITY_XML la sekvaj linioj:
    <settingsSecurity>
    <master>{hnkle5BJ9HUHUMP+CXfGBl8dScfFci/mpsur/73tR2I=}</master>
    </settingsSecurity>
  • Ĉifrado de la pasvorto de la Sonatype-konto
    mvn --encrypt-password SONATYPE_PASSWORD
    {98Wv5+u+Tn0HX2z5G/kR4R8Z0WBgcDBgi7d12S/un+SCU7uxzaZGGmJ8Cu9pAZ2J}
  • Iru al projektaj agordoj -> Agordoj -> CI / KD -> Variabloj kaj konservu en variablo SETTINGS_XML la sekvaj linioj:
    <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>

kie,
GPG_SECRET_KEY_PASSPHRASE - GPG-ŝlosila pasvorto
SONATYPE_USERNAME - ensaluto de konto sonatype

Al la enhavo

Deploji docker-bildon

  • Ni kreas sufiĉe simplan Dockerfile por ruli taskojn sur deplojo kun la dezirata versio de Java. Malsupre estas ekzemplo por alpa.

    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/

  • Konstruante ujon por via projekto

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

  • Ni aŭtentikigas kaj ŝarĝas la ujon en la registron.

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

Al la enhavo

GitLab CI

Deploji projekton

Aldonu la dosieron .gitlab-ci.yml al la radiko de la deploja projekto
La skripto prezentas du reciproke ekskluzivajn deplojajn taskojn. Specifa Kurulo aŭ Kunigita Kurulo respektive.

.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

Al la enhavo

Java projekto

En javaj projektoj, kiuj supozeble estas alŝutitaj al publikaj deponejoj, vi devas aldoni 2 paŝojn por elŝuti la versiojn Eldonaĵo kaj Snapshot.

.gitlab-ci.yml

stages:
  - build
  - test
  - verify
  - deploy

<...>

Release:
  extends: .trigger_deploy
  # Запускать задачу только пo тегу.
  only:
    - tags

Snapshot:
  extends: .trigger_deploy
  # Запускаем задачу на публикацию SNAPSHOT версии вручную
  when: manual
  # Не запускать задачу, если проставлен тег.
  except:
    - tags

.trigger_deploy:
  stage: deploy
  variables:
    # Отключаем клонирование текущего проекта
    GIT_STRATEGY: none
    # Ссылка на триггер deploy-задачи
    URL: "https://gitlab.com/api/v4/projects/<deploy project ID>/trigger/pipeline"
    # Переменные deploy-задачи
    POST_DATA: "
      token=${DEPLOY_TOKEN}&
      ref=master&
      variables[DEPLOY]=${DEPLOY}&
      variables[DEPLOY_CI_REPOSITORY_URL]=${CI_REPOSITORY_URL}&
      variables[DEPLOY_CI_PROJECT_NAME]=${CI_PROJECT_NAME}&
      variables[DEPLOY_CI_COMMIT_SHA]=${CI_COMMIT_SHA}&
      variables[DEPLOY_CI_COMMIT_TAG]=${CI_COMMIT_TAG}
      "
  script:
    # Не использую cURL, так как с флагами --fail --show-error
    # он не выводит тело ответа, если HTTP код 400 и более 
    - wget --content-on-error -qO- ${URL} --post-data ${POST_DATA}

En ĉi tiu solvo, mi iris iom plu kaj decidis uzi unu CI-ŝablonon por javaj projektoj.

Pli da detaloj

Mi kreis apartan projekton gitlab-ci en kiu li metis la CI-ŝablonon por javaj projektoj komuna.yml.

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

Kiel rezulto, en la java projektoj mem, .gitlab-ci.yml aspektas tre kompakta kaj ne multvorta

.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

Al la enhavo

agordo pom.xml

Ĉi tiu temo estas priskribita tre detale. Googlelplex в Agordante maven por aŭtomate subskribi kaj alŝuti artefaktojn al momentfotoj kaj enscenigantaj deponejoj, do mi priskribos kelkajn el la nuancoj de uzado de kromaĵoj. Mi ankaŭ priskribos kiom facila kaj malstreĉa vi povas uzi nexus-staging-maven-pluginse vi ne volas aŭ ne povas uzi org.sonatype.oss:oss-parent kiel la gepatron por via projekto.

maven-install-plugin

Instalas modulojn en la lokan deponejon.
Tre utila por loka kontrolado de solvoj en aliaj projektoj, kaj ankaŭ ĉeksumo.

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

Al la enhavo

maven-javadoc-kromaĵo

Generante javadoc por la projekto.

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

Se vi havas modulon kiu ne enhavas java (ekzemple nur rimedoj)
Aŭ vi ne volas generi javadoc principe, tiam helpi 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>

Al la enhavo

maven-gpg-kromaĵo

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

Al la enhavo

nexus-staging-maven-plugin

Agordo:

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

Se vi havas multmodulan projekton, kaj vi ne bezonas alŝuti specifan modulon al la deponejo, tiam vi devas aldoni al la pom.xml de ĉi tiu modulo. nexus-staging-maven-plugin kun flago skipNexusStagingDeployMojo

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

Post alŝuto de momentfoto/eldonaj versioj estas disponeblaj en enscenigantaj deponejoj

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

Pli da plusoj

  • Tre riĉa listo de celoj por labori kun la nexus-deponejo (mvn help:describe -Dplugin=org.sonatype.plugins:nexus-staging-maven-plugin).
  • Aŭtomata liberigokontrolo por elŝutebleco en Maven Central

Al la enhavo

rezulto

Eldonante SNAPSHOT-Version

Konstruante projekton, eblas mane komenci taskon por elŝuti la SNAPSHOT-version al nexus

Agordante GitLab CI por alŝuti java projekton al maven central

Kiam ĉi tiu tasko estas lanĉita, la responda tasko en la deploja projekto estas ekigita (ekzemplo).

tondita ŝtipo

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

Kiel rezulto, la nexus-versio estas ŝarĝita 1.0.0-IMANTA FOTO.

Ĉiuj momentfotoversioj povas esti forigitaj de la deponejo sur la retejo oss.sonatype.org sub via konto.

Agordante GitLab CI por alŝuti java projekton al maven central

Al la enhavo

Eldonante eldonan version

Kiam la etikedo estas agordita, la responda tasko en la deploja projekto aŭtomate ekfunkciiĝas por alŝuti la eldonan version al nexus (ekzemplo).

Agordante GitLab CI por alŝuti java projekton al maven central

La plej bona parto estas, ke proksima liberigo aŭtomate ekfunkciigas en nexus.

[INFO] Performing remote staging...
[INFO] 
[INFO]  * Remote staging into staging profile ID "9043b43f77dcc9"
[INFO]  * Created staging repository with ID "orgtouchbit-1037".
[INFO]  * Staging repository at https://oss.sonatype.org:443/service/local/staging/deployByRepositoryId/orgtouchbit-1037
[INFO]  * Uploading locally staged artifacts to profile org.touchbit
[INFO]  * Upload of locally staged artifacts finished.
[INFO]  * Closing staging repository with ID "orgtouchbit-1037".
Waiting for operation to complete...
.........
[INFO] Remote staged 1 repositories, finished with success.
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO] 
[INFO] Shields4J 1.0.0 .................................... SUCCESS [  9.603 s]
[INFO] test-core .......................................... SUCCESS [  3.419 s]
[INFO] Shields4J client ................................... SUCCESS [  9.793 s]
[INFO] TestNG listener 1.0.0 .............................. SUCCESS [01:23 min]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 01:47 min
[INFO] Finished at: 2019-04-21T04:05:46+03:00
[INFO] ------------------------------------------------------------------------

Kaj se io misfunkciis, tiam la tasko malsukcesos

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

Kiel rezulto, ni restas kun nur unu elekto. Aŭ forigu ĉi tiun version aŭ publikigu ĝin.

Agordante GitLab CI por alŝuti java projekton al maven central

Post la liberigo, post iom da tempo, la artefaktoj estos enen Agordante GitLab CI por alŝuti java projekton al maven central

ekstertema

Estis revelacio por mi, ke Maven indeksas aliajn publikajn deponejojn.
Mi devis aldoni robots.txt ĉar ĝi indeksigis mian malnovan deponejon.

Al la enhavo

konkludo

Kion ni havas

  • Aparta deploja projekto en kiu vi povas efektivigi plurajn CI-taskojn por alŝuti artefaktojn al publikaj deponejoj por diversaj evolulingvoj.
  • La deplojprojekto estas izolita de ekstera interfero kaj povas esti modifita nur de uzantoj kun la Posedanto kaj Prizorganto-roloj.
  • Aparta Specifa Kurilo kun "varma" kaŝmemoro por ruli nur deploji taskojn.
  • Publikigo de momentfoto/eldonaj versioj en publika deponejo.
  • Aŭtomata kontrolo de la eldonversio por preteco por publikigo en Maven Central.
  • Protekto kontraŭ aŭtomata publikigo de "krudaj" versioj en maven central.
  • Konstruu kaj publikigu momentajn versiojn "alklakante".
  • Ununura deponejo por akiri momentajn/eldonajn versiojn.
  • Ĝenerala dukto por konstrui / testi / publikigi java projekton.

Agordo de GitLab CI ne estas tiel komplika temo kiel ŝajnas unuavide. Sufiĉas agordi CI surŝlosilbaze kelkajn fojojn, kaj nun vi estas malproksime de amatoro en ĉi tiu afero. Plie, GitLab-dokumentado estas tre redunda. Ne timu fari la unuan paŝon. La vojo aperas sub la ŝtupoj de la marŝanto (mi ne memoras, kiu diris ĝin :)

Mi ĝojos respondi.

En la sekva artikolo, mi montros al vi kiel agordi GitLab CI por ruli integrajn testajn taskojn konkurencive (funkciigi testajn servojn kun docker-compose) se vi havas nur unu ŝelan kuriston.

Al la enhavo

fonto: www.habr.com

Aldoni komenton