Pagse-set up ng GitLab CI para mag-upload ng java project sa maven central

Ang artikulong ito ay inilaan para sa mga developer ng java na kailangang mabilis na mag-publish ng kanilang mga produkto sa sonatype at/o maven central repository gamit ang GitLab. Sa artikulong ito, magsasalita ako tungkol sa pag-set up ng gitlab-runner, gitlab-ci at maven-plugin upang malutas ang problemang ito.

Mga Pangangailangan:

  • Ligtas na imbakan ng mvn at GPG key.
  • Secure na pagpapatupad ng mga pampublikong gawain sa CI.
  • Pag-upload ng mga artifact (release/snapshot) sa mga pampublikong repository.
  • Awtomatikong pagsusuri ng mga bersyon ng release para sa publikasyon sa maven central.
  • Isang pangkalahatang solusyon para sa pag-upload ng mga artifact sa isang repository para sa maraming proyekto.
  • Ang pagiging simple at kadalian ng paggamit.

nilalaman

Pangkalahatang impormasyon

  • Ang isang detalyadong paglalarawan ng mekanismo para sa pag-publish ng mga artifact sa Maven Central sa pamamagitan ng Sonatype OSS Repository Hosting Service ay inilarawan na sa Ang artikulong ito gumagamit Googolplex, kaya sasangguni ako sa artikulong ito sa mga tamang lugar.
  • Pre-register sa Sonatype JIRA at magsimula ng tiket para buksan ang repositoryo (para sa higit pang mga detalye, basahin ang seksyon Gumawa ng Sonatype JIRA ticket). Pagkatapos buksan ang repository, ang pares ng login/password ng JIRA (mula rito ay tinutukoy bilang ang Sonatype account) ay gagamitin upang mag-upload ng mga artifact sa Sonatype nexus.
  • Dagdag pa, ang proseso ng pagbuo ng isang GPG key ay inilarawan nang tuyo. Tingnan ang seksyon para sa higit pang mga detalye. Pag-configure ng GnuPG upang Mag-sign Artifact
  • Kung gumagamit ka ng Linux console para bumuo ng GPG key (gnupg/gnupg2), kailangan mong mag-install rng-tool upang makabuo ng entropy. Kung hindi man, maaaring tumagal ng napakatagal na panahon ang pagbuo ng key.
  • Mga serbisyo sa imbakan pampubliko GPG key

Sa nilalaman

Pagse-set up ng deploy project sa GitLab

  • Una sa lahat, kailangan mong lumikha at mag-configure ng isang proyekto kung saan maiimbak ang pipeline para sa pag-deploy ng mga artifact. Tinawag ko ang aking proyekto nang simple at hindi kumplikado - lumawak
  • Pagkatapos gumawa ng repositoryo, kailangan mong paghigpitan ang pag-access para baguhin ang repositoryo.
    Pumunta sa proyekto -> Mga Setting -> Imbakan -> Mga Protektadong Sangay. Tinatanggal namin ang lahat ng panuntunan at nagdaragdag kami ng iisang panuntunan gamit ang Wildcard * na may karapatang itulak at pagsamahin lang para sa mga user na may tungkuling Mga Tagapag-maintain. Gagana ang panuntunang ito para sa lahat ng user ng proyektong ito at sa pangkat kung saan kabilang ang proyektong ito.
    Pagse-set up ng GitLab CI para mag-upload ng java project sa maven central
  • Kung mayroong ilang mga tagapangasiwa, kung gayon ang pinakamahusay na solusyon ay ang paghigpitan ang pag-access sa proyekto sa prinsipyo.
    Pumunta sa proyekto -> Mga Setting -> Pangkalahatan -> Visibility, mga tampok ng proyekto, mga pahintulot at itakda ang visibility ng Project sa pribado.
    Mayroon akong proyekto sa pampublikong pag-access, dahil ginagamit ko ang aking sariling GitLab Runner at ako lang ang may access upang baguhin ang repositoryo. Sa totoo lang, wala sa aking interes na magpakita ng pribadong impormasyon sa mga pampublikong pipeline log.
  • Paghigpit sa mga patakaran para sa pagbabago ng imbakan
    Pumunta sa project -> Settings -> Repository -> Push Rules at itakda ang mga flag Restriction ng Committer, Suriin kung user ng GitLab ang may-akda. Inirerekomenda ko rin ang setting gumawa ng pagpirma, at itakda ang flag na Tanggihan ang mga hindi napirmahang commit.
  • Susunod, kailangan mong i-configure ang isang trigger upang magpatakbo ng mga gawain
    Pumunta sa project -> Settings -> CI / CD -> Pipeline triggers at gumawa ng bagong trigger-token
    Ang token na ito ay maaaring idagdag kaagad sa pangkalahatang configuration ng mga variable para sa isang pangkat ng mga proyekto.
    Pumunta sa grupo -> Mga Setting -> CI / CD -> Mga Variable at magdagdag ng variable DEPLOY_TOKEN na may trigger-token sa halaga.

Sa nilalaman

Runner ng GitLab

Inilalarawan ng seksyong ito ang configuration para sa pagpapatakbo ng mga gawain sa pag-deploy gamit ang native (Specific) at public (Shared) runner.

Tiyak na Runner

Gumagamit ako ng sarili kong mga runner, dahil una sa lahat ito ay maginhawa, mabilis, mura.
Para sa runner, inirerekomenda ko ang Linux VDS na may 1 CPU, 2 GB RAM, 20 GB HDD. Presyo ng isyu ~ 3000₽ bawat taon.

Ang runner ko

Para sa runner kinuha ko ang VDS 4 CPU, 4 GB RAM, 50 GB SSD. Nagkakahalaga ito ng ~11000₽ at hinding-hindi ito pinagsisihan.
Mayroon akong kabuuang 7 makina. 5 sa aruba at 2 sa ihor.

Kaya, mayroon kaming isang runner. Ngayon ay ise-set up natin ito.
Pumunta kami sa makina sa pamamagitan ng SSH at i-install ang java, git, maven, gnupg2.

Sa nilalaman

Pag-install ng gitlab runner

  • Gumawa ng bagong grupo runner
    sudo groupadd runner
  • Gumawa ng direktoryo para sa maven cache at magtalaga ng mga karapatan ng grupo runner
    Maaari mong laktawan ang hakbang na ito kung hindi mo planong magpatakbo ng maraming runner sa parehong makina.

    mkdir -p /usr/cache/.m2/repository
    chown -R :runner /usr/cache
    chmod -R 770 /usr/cache
  • Gumawa ng user gitlab-deployer at idagdag sa grupo runner
    useradd -m -d /home/gitlab-deployer gitlab-deployer
    usermod -a -G runner gitlab-deployer
  • Idagdag sa file /etc/ssh/sshd_config susunod na linya
    AllowUsers root@* [email protected]
  • I-reboot sshd
    systemctl restart sshd
  • Magtakda ng password para sa user gitlab-deployer (maaari itong maging simple, dahil mayroong isang paghihigpit para sa localhost)
    passwd gitlab-deployer
  • I-install ang 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
  • Pumunta sa gitlab.com -> deploy-project -> Settings -> CI/CD -> Runners -> Specific Runners at kopyahin ang registration token

Screen

Pagse-set up ng GitLab CI para mag-upload ng java project sa maven central

  • Pagrehistro ng runner
    gitlab-runner register --config /etc/gitlab-runner/gitlab-deployer-config.toml

paraan

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!

  • Suriin na ang runner ay nakarehistro. Pumunta sa gitlab.com -> deploy-project -> Settings -> CI/CD -> Runners -> Specific Runners -> Runners activated para sa proyektong ito

Screen

Pagse-set up ng GitLab CI para mag-upload ng java project sa maven central

  • Idagdag paghiwalayin serbisyo /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
  • Sinimulan namin ang serbisyo.
    systemctl enable gitlab-deployer.service
    systemctl start gitlab-deployer.service
    systemctl status gitlab-deployer.service
  • Suriin kung tumatakbo ang runner.

Halimbawa

Pagse-set up ng GitLab CI para mag-upload ng java project sa maven central

Sa nilalaman

GPG key generation

  • Mula sa parehong makina pumunta kami sa pamamagitan ng ssh sa ilalim ng gumagamit gitlab-deployer (ito ay mahalaga para sa GPG key generation)

    ssh [email protected]

  • Bumubuo kami ng isang susi sa pamamagitan ng pagsagot sa mga tanong. Ginamit ko ang sarili kong pangalan at email.
    Tiyaking tukuyin ang password para sa susi. Ang mga artifact ay pipirmahan gamit ang key na ito.

    gpg --gen-key 

  • Suriin

    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

  • Pag-upload ng aming pampublikong susi sa keyserver

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

Sa nilalaman

Setup ng Maven

  • Pumunta kami sa ilalim ng gumagamit gitlab-deployer
    su gitlab-deployer 
  • Lumikha ng isang direktoryo ng maven repositoryo at mag-link sa cache (huwag magkamali)
    Maaaring laktawan ang hakbang na ito kung hindi mo planong magpatakbo ng ilang runner sa parehong makina.

    mkdir -p ~/.m2/repository
    ln -s /usr/cache/.m2/repository /home/gitlab-deployer/.m2/repository
  • Gumawa ng master key
    mvn --encrypt-master-password password
    {hnkle5BJ9HUHUMP+CXfGBl8dScfFci/mpsur/73tR2I=}
  • Lumikha ng file ~/.m2/settings-security.xml
    <settingsSecurity>
    <master>{hnkle5BJ9HUHUMP+CXfGBl8dScfFci/mpsur/73tR2I=}</master>
    </settingsSecurity>
  • Pag-encrypt ng password mula sa Sonatype account
    mvn --encrypt-password SONATYPE_PASSWORD
    {98Wv5+u+Tn0HX2z5G/kR4R8Z0WBgcDBgi7d12S/un+SCU7uxzaZGGmJ8Cu9pAZ2J}
  • Lumikha ng file ~/.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>

saan,
GPG_SECRET_KEY_PASSPHRASE - GPG key password
SONATYPE_USERNAME - pag-login ng sonatype account

Nakumpleto nito ang pag-setup ng runner, maaari kang magpatuloy sa seksyon GitLab CI

Sa nilalaman

Nakabahaging Runner

GPG key generation

  • Una sa lahat, kailangan mong lumikha ng GPG key. Upang gawin ito, i-install ang gnupg.

    yum install -y gnupg

  • Bumubuo kami ng isang susi sa pamamagitan ng pagsagot sa mga tanong. Ginamit ko ang sarili kong pangalan at email. Tiyaking tukuyin ang password para sa susi.

    gpg --gen-key 

  • Kunin ang pangunahing impormasyon

    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]

  • Pag-upload ng aming pampublikong susi sa keyserver

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

  • Pagkuha ng pribadong susi

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

  • Pumunta sa mga setting ng proyekto -> Mga Setting -> CI / CD -> Mga Variable at i-save ang pribadong key sa isang variable GPG_SECRET_KEY
    Pagse-set up ng GitLab CI para mag-upload ng java project sa maven central

Sa nilalaman

Setup ng Maven

  • Gumawa ng master key
    mvn --encrypt-master-password password
    {hnkle5BJ9HUHUMP+CXfGBl8dScfFci/mpsur/73tR2I=}
  • Pumunta sa mga setting ng proyekto -> Mga Setting -> CI / CD -> Mga Variable at i-save sa isang variable SETTINGS_SECURITY_XML ang mga sumusunod na linya:
    <settingsSecurity>
    <master>{hnkle5BJ9HUHUMP+CXfGBl8dScfFci/mpsur/73tR2I=}</master>
    </settingsSecurity>
  • Pag-encrypt ng password mula sa Sonatype account
    mvn --encrypt-password SONATYPE_PASSWORD
    {98Wv5+u+Tn0HX2z5G/kR4R8Z0WBgcDBgi7d12S/un+SCU7uxzaZGGmJ8Cu9pAZ2J}
  • Pumunta sa mga setting ng proyekto -> Mga Setting -> CI / CD -> Mga Variable at i-save sa isang variable SETTINGS_XML ang mga sumusunod na linya:
    <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>

saan,
GPG_SECRET_KEY_PASSPHRASE - GPG key password
SONATYPE_USERNAME - pag-login ng sonatype account

Sa nilalaman

I-deploy ang larawan ng docker

  • Gumagawa kami ng medyo simpleng Dockerfile para magpatakbo ng mga gawain sa pag-deploy gamit ang gustong bersyon ng Java. Nasa ibaba ang isang halimbawa para sa 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/

  • Pagbuo ng lalagyan para sa iyong proyekto

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

  • Pinapatotohanan at nilo-load namin ang lalagyan sa registry.

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

Sa nilalaman

GitLab CI

I-deploy ang proyekto

Idagdag ang .gitlab-ci.yml file sa root ng deploy project
Ang script ay nagpapakita ng dalawang eksklusibong gawain sa pag-deploy. Tukoy na Runner o Shared Runner ayon sa pagkakabanggit.

.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

Sa nilalaman

proyekto ng Java

Sa mga proyektong java na dapat i-upload sa mga pampublikong repositoryo, kailangan mong magdagdag ng 2 hakbang upang i-download ang mga bersyon ng Release at 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}

Sa solusyon na ito, lumayo pa ako nang kaunti at nagpasyang gumamit ng isang template ng CI para sa mga proyektong java.

Higit pang mga detalye

Gumawa ako ng isang hiwalay na proyekto gitlab-ci kung saan inilagay niya ang template ng CI para sa mga proyekto ng java karaniwan.yml.

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

Bilang resulta, sa mga proyekto ng java mismo, ang .gitlab-ci.yml ay mukhang napaka-compact at hindi verbose

.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

Sa nilalaman

pom.xml configuration

Ang paksang ito ay inilarawan nang detalyado. Googolplex в Pagse-set up ng maven para awtomatikong pumirma at mag-upload ng mga artifact sa snapshot at staging na mga repository, kaya ilalarawan ko ang ilan sa mga nuances ng paggamit ng mga plugin. Ilalarawan ko rin kung gaano kadali at natural na magagamit mo nexus-staging-maven-pluginkung ayaw mo o hindi mo magagamit ang org.sonatype.oss:oss-parent bilang magulang para sa iyong proyekto.

maven-install-plugin

Nag-i-install ng mga module sa lokal na imbakan.
Napaka-kapaki-pakinabang para sa lokal na pag-verify ng mga solusyon sa iba pang mga proyekto, pati na rin ang checksum.

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

Sa nilalaman

maven-javadoc-plugin

Pagbuo ng javadoc para sa proyekto.

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

Kung mayroon kang isang module na hindi naglalaman ng java (halimbawa, mga mapagkukunan lamang)
O hindi mo nais na bumuo ng javadoc sa prinsipyo, pagkatapos ay tumulong 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>

Sa nilalaman

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>

Sa nilalaman

nexus-staging-maven-plugin

Configuration:

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

Kung mayroon kang multi-module na proyekto, at hindi mo kailangang mag-upload ng isang partikular na module sa repositoryo, kailangan mong magdagdag sa pom.xml ng module na ito nexus-staging-maven-plugin may bandila skipNexusStagingDeployMojo

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

Pagkatapos mag-upload ng snapshot/release na mga bersyon ay available sa mga pagtatanghal ng dula

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

Higit pang mga plus

  • Isang napakaraming listahan ng mga target para sa pagtatrabaho sa nexus repository (mvn help:describe -Dplugin=org.sonatype.plugins:nexus-staging-maven-plugin).
  • Awtomatikong release check para sa downloadability sa maven central

Sa nilalaman

Resulta

Pag-publish ng SNAPSHOT na Bersyon

Kapag gumagawa ng proyekto, posibleng manu-manong simulan ang isang gawain upang i-download ang bersyon ng SNAPSHOT sa nexus

Pagse-set up ng GitLab CI para mag-upload ng java project sa maven central

Kapag inilunsad ang gawaing ito, ma-trigger ang kaukulang gawain sa proyekto sa pag-deploy (halimbawa).

crop na log

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

Bilang resulta, na-load ang bersyon ng nexus 1.0.0-SNAPSHOT.

Ang lahat ng mga bersyon ng snapshot ay maaaring alisin mula sa repositoryo sa site oss.sonatype.org sa ilalim ng iyong account.

Pagse-set up ng GitLab CI para mag-upload ng java project sa maven central

Sa nilalaman

Paglalathala ng bersyon ng paglabas

Kapag naitakda ang tag, awtomatikong ma-trigger ang kaukulang gawain sa proyekto sa pag-deploy upang i-upload ang bersyon ng release sa nexus (halimbawa).

Pagse-set up ng GitLab CI para mag-upload ng java project sa maven central

Ang pinakamagandang bahagi ay ang malapit na release ay awtomatikong nagti-trigger sa 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] ------------------------------------------------------------------------

At kung may nangyaring mali, mabibigo ang gawain

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

Bilang isang resulta, tayo ay naiwan na may isang pagpipilian lamang. O tanggalin ang bersyon na ito o i-publish.

Pagse-set up ng GitLab CI para mag-upload ng java project sa maven central

Pagkatapos ng paglabas, pagkaraan ng ilang oras, ilalagay ang mga artifact Pagse-set up ng GitLab CI para mag-upload ng java project sa maven central

wala sa pinaguusapan

Ito ay isang paghahayag sa akin na ang maven ay nag-index ng iba pang mga pampublikong repositoryo.
Kinailangan kong mag-upload ng robots.txt dahil na-index nito ang aking lumang repository.

Sa nilalaman

Konklusyon

Kung anong meron tayo

  • Isang hiwalay na proyekto sa pag-deploy kung saan maaari kang magpatupad ng ilang mga gawain sa CI para sa pag-upload ng mga artifact sa mga pampublikong repositoryo para sa iba't ibang wika ng pag-unlad.
  • Ang proyekto sa pag-deploy ay nakahiwalay mula sa panghihimasok sa labas at maaari lamang baguhin ng mga user na may mga tungkuling May-ari at Tagapamahala.
  • Isang hiwalay na Specific Runner na may "mainit" na cache upang patakbuhin lamang ang mga gawain sa pag-deploy.
  • Paglalathala ng mga bersyon ng snapshot/release sa isang pampublikong repositoryo.
  • Awtomatikong suriin ang bersyon ng release para sa kahandaan para sa publikasyon sa maven central.
  • Proteksyon laban sa awtomatikong paglalathala ng "raw" na mga bersyon sa maven central.
  • Bumuo at mag-publish ng mga bersyon ng snapshot "sa pag-click".
  • Isang imbakan para sa pagkuha ng mga bersyon ng snapshot/release.
  • Pangkalahatang pipeline para sa pagbuo / pagsubok / pag-publish ng isang java project.

Ang pag-set up ng GitLab CI ay hindi kasing kumplikado ng isang paksa na tila sa unang tingin. Ito ay sapat na upang i-set up ang CI sa isang turnkey na batayan ng ilang beses, at ngayon ay malayo ka sa isang baguhan sa bagay na ito. Bukod dito, ang dokumentasyon ng GitLab ay napakalabis. Huwag matakot na gawin ang unang hakbang. Lumilitaw ang kalsada sa ilalim ng mga hakbang ng taong naglalakad (hindi ko matandaan kung sino ang nagsabi nito :)

Ako ay magiging masaya sa feedback.

Sa susunod na artikulo, ipapakita ko sa iyo kung paano i-set up ang GitLab CI upang patakbuhin ang mga gawain sa pagsubok sa pagsasama nang mapagkumpitensya (pagpapatakbo ng mga serbisyo ng pagsubok na may docker-compose) kung mayroon ka lamang isang shell runner.

Sa nilalaman

Pinagmulan: www.habr.com

Magdagdag ng komento