Java 프로젝트를 Maven Central에 업로드하도록 GitLab CI 설정

이 문서는 GitLab을 사용하여 sonatype 및/또는 Maven 중앙 저장소에 제품을 신속하게 게시해야 하는 Java 개발자를 위한 것입니다. 이 기사에서는 이 문제를 해결하기 위해 gitlab-runner, gitlab-ci 및 maven-plugin을 설정하는 방법에 대해 설명합니다.

전제 조건:

  • mvn 및 GPG 키를 안전하게 저장합니다.
  • 공개 CI 작업을 안전하게 실행합니다.
  • 공개 저장소에 아티팩트(릴리스/스냅샷) 업로드
  • Maven Central에 게시할 릴리스 버전을 자동으로 확인합니다.
  • 여러 프로젝트의 저장소에 아티팩트를 업로드하기 위한 일반적인 솔루션입니다.
  • 단순성과 사용 용이성.

내용

일반 정보

  • Sonatype OSS 리포지토리 호스팅 서비스를 통해 Maven Central에 아티팩트를 게시하는 메커니즘에 대한 자세한 설명은 이미 설명되어 있습니다. 이 기사 사용자 고골 플렉스, 그래서 나는 이 기사를 올바른 위치에서 참조할 것입니다.
  • 다음에서 사전 등록하세요. 소나타입 JIRA 저장소를 열기 위한 티켓을 시작합니다(자세한 내용은 섹션을 참조하세요). Sonatype JIRA 티켓 만들기). 저장소를 연 후 JIRA 로그인/비밀번호 쌍(이하 Sonatype 계정이라고 함)은 Sonatype 넥서스에 아티팩트를 업로드하는 데 사용됩니다.
  • 또한 GPG 키를 생성하는 과정은 매우 건조하게 설명됩니다. 자세한 내용은 섹션을 참조하세요. 아티팩트에 서명하도록 GnuPG 구성
  • Linux 콘솔을 사용하여 GPG 키(gnupg/gnupg2)를 생성하는 경우 다음을 설치해야 합니다. 도구 엔트로피를 생성합니다. 그렇지 않으면 키 생성에 매우 오랜 시간이 걸릴 수 있습니다.
  • 보관 서비스 공공의 GPG 키

콘텐츠로 돌아가기

GitLab에서 배포 프로젝트 설정

  • 우선, 아티팩트 배포를 위해 파이프라인이 저장될 프로젝트를 생성하고 구성해야 합니다. 나는 내 프로젝트를 간단하고 복잡하지 않게 불렀습니다. 배포
  • 저장소를 생성한 후에는 저장소 수정을 위한 접근을 제한해야 합니다.
    프로젝트 -> 설정 -> 저장소 -> 보호된 분기로 이동합니다. 모든 규칙을 삭제하고 유지 관리 역할을 가진 사용자에 대해서만 푸시 및 병합할 수 있는 권한이 있는 와일드카드 *가 포함된 단일 규칙을 추가합니다. 이 규칙은 이 프로젝트와 이 프로젝트가 속한 그룹 모두의 모든 사용자에게 적용됩니다.
    Java 프로젝트를 Maven Central에 업로드하도록 GitLab CI 설정
  • 관리자가 여러 명인 경우 가장 좋은 해결책은 원칙적으로 프로젝트에 대한 액세스를 제한하는 것입니다.
    프로젝트 -> 설정 -> 일반 -> 가시성, 프로젝트 기능, 권한으로 이동하여 프로젝트 가시성을 다음으로 설정하세요. 프라이빗 투어.
    저는 자체 GitLab Runner를 사용하고 나만 저장소를 수정할 수 있는 액세스 권한을 갖고 있으므로 공개 액세스 프로젝트를 보유하고 있습니다. 글쎄요, 사실 공개 파이프라인 로그에 개인 정보를 표시하는 것은 제 관심사가 아닙니다.
  • 저장소 변경 규칙 강화
    프로젝트 -> 설정 -> 리포지토리 -> 푸시 규칙으로 이동하여 커미터 제한 플래그를 설정하고 작성자가 GitLab 사용자인지 확인하세요. 저도 설정 추천드려요 서명 커밋, 서명되지 않은 커밋 거부 플래그를 설정합니다.
  • 다음으로 작업을 실행하도록 트리거를 구성해야 합니다.
    프로젝트 -> 설정 -> CI/CD -> 파이프라인 트리거로 이동하여 새 트리거 토큰을 만듭니다.
    이 토큰은 프로젝트 그룹의 일반 변수 구성에 즉시 추가될 수 있습니다.
    그룹 -> 설정 -> CI/CD -> 변수로 이동하여 변수를 추가하세요. DEPLOY_TOKEN 값에 트리거 토큰이 있습니다.

콘텐츠로 돌아가기

GitLab 러너

이 섹션에서는 기본(특정) 및 공개(공유) 실행기를 사용하여 배포 시 작업을 실행하기 위한 구성을 설명합니다.

특정 주자

나는 우선 편리하고 빠르며 저렴하기 때문에 나만의 주자를 사용합니다.
러너의 경우 CPU 1개, RAM 2GB, HDD 20GB를 갖춘 Linux VDS를 권장합니다. 발행 가격 ~ 연간 3000₽.

나의 주자

주자를 위해 VDS 4 CPU, 4GB RAM, 50GB SSD를 사용했습니다. 비용은 ~11000₽이고 결코 후회하지 않았습니다.
총 7개의 기계가 있습니다. Aruba에서는 5개, ihor에서는 2개입니다.

그래서 우리에게는 주자가 있습니다. 이제 설정하겠습니다.
SSH를 통해 머신으로 이동하여 java, git, maven, gnupg2를 설치합니다.

콘텐츠로 돌아가기

gitlab 러너 설치

  • 새 그룹 만들기 runner
    sudo groupadd runner
  • Maven 캐시용 디렉터리를 만들고 그룹 권한을 할당합니다. runner
    동일한 머신에서 여러 러너를 실행할 계획이 없다면 이 단계를 건너뛸 수 있습니다.

    mkdir -p /usr/cache/.m2/repository
    chown -R :runner /usr/cache
    chmod -R 770 /usr/cache
  • 사용자 생성 gitlab-deployer 그리고 그룹에 추가하세요 runner
    useradd -m -d /home/gitlab-deployer gitlab-deployer
    usermod -a -G runner gitlab-deployer
  • 파일에 추가 /etc/ssh/sshd_config 다음 줄
    AllowUsers root@* [email protected]
  • 재부팅 sshd
    systemctl restart sshd
  • 사용자의 비밀번호를 설정하세요 gitlab-deployer (localhost에 대한 제한이 있으므로 간단할 수 있습니다)
    passwd gitlab-deployer
  • 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
  • gitlab.com -> 배포 프로젝트 -> 설정 -> CI/CD -> 실행자 -> 특정 실행자로 이동하여 등록 토큰을 복사합니다.

스크린

Java 프로젝트를 Maven Central에 업로드하도록 GitLab CI 설정

  • 러너 등록
    gitlab-runner register --config /etc/gitlab-runner/gitlab-deployer-config.toml

Процесс

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!

  • 주자가 등록되어 있는지 확인하세요. gitlab.com으로 이동 -> 배포 프로젝트 -> 설정 -> CI/CD -> 실행자 -> 특정 실행자 -> 이 프로젝트에 대해 활성화된 실행자

스크린

Java 프로젝트를 Maven Central에 업로드하도록 GitLab CI 설정

  • 첨가 분리하다 서비스 /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
  • 서비스를 시작합니다.
    systemctl enable gitlab-deployer.service
    systemctl start gitlab-deployer.service
    systemctl status gitlab-deployer.service
  • 러너가 실행 중인지 확인합니다.

Java 프로젝트를 Maven Central에 업로드하도록 GitLab CI 설정

콘텐츠로 돌아가기

GPG 키 생성

  • 동일한 머신에서 사용자 아래의 SSH를 통해 이동합니다. gitlab-deployer (이것은 GPG 키 생성에 중요합니다)

    ssh [email protected]

  • 우리는 질문에 답하여 키를 생성합니다. 나는 내 이름과 이메일을 사용했습니다.
    키의 비밀번호를 지정하십시오. 아티팩트는 이 키로 서명됩니다.

    gpg --gen-key 

  • 확인 중

    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

  • 공개 키를 키 서버에 업로드

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

콘텐츠로 돌아가기

메이븐 설정

  • 우리는 사용자 아래로 이동합니다 gitlab-deployer
    su gitlab-deployer 
  • 메이븐 디렉토리 생성 저장소 캐시와 연결합니다(실수하지 마세요).
    동일한 머신에서 여러 러너를 실행할 계획이 없다면 이 단계를 건너뛸 수 있습니다.

    mkdir -p ~/.m2/repository
    ln -s /usr/cache/.m2/repository /home/gitlab-deployer/.m2/repository
  • 마스터 키 만들기
    mvn --encrypt-master-password password
    {hnkle5BJ9HUHUMP+CXfGBl8dScfFci/mpsur/73tR2I=}
  • ~/.m2/settings-security.xml 파일 생성
    <settingsSecurity>
    <master>{hnkle5BJ9HUHUMP+CXfGBl8dScfFci/mpsur/73tR2I=}</master>
    </settingsSecurity>
  • Sonatype 계정의 비밀번호 암호화
    mvn --encrypt-password SONATYPE_PASSWORD
    {98Wv5+u+Tn0HX2z5G/kR4R8Z0WBgcDBgi7d12S/un+SCU7uxzaZGGmJ8Cu9pAZ2J}
  • ~/.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>

어디서
GPG_SECRET_KEY_PASSPHRASE - GPG 키 비밀번호
SONATYPE_USERNAME - 소나타입 계정 로그인

이것으로 러너 설정이 완료되었습니다. 섹션으로 진행할 수 있습니다. 깃랩 CI

콘텐츠로 돌아가기

공유 러너

GPG 키 생성

  • 먼저 GPG 키를 생성해야 합니다. 이렇게 하려면 gnupg를 설치하세요.

    yum install -y gnupg

  • 우리는 질문에 답하여 키를 생성합니다. 나는 내 이름과 이메일을 사용했습니다. 키의 비밀번호를 지정하십시오.

    gpg --gen-key 

  • 주요 정보 검색

    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]

  • 공개 키를 키 서버에 업로드

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

  • 개인 키 얻기

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

  • 프로젝트 설정 -> 설정 -> CI/CD -> 변수로 이동하여 개인 키를 변수에 저장합니다. GPG_SECRET_KEY
    Java 프로젝트를 Maven Central에 업로드하도록 GitLab CI 설정

콘텐츠로 돌아가기

메이븐 설정

  • 마스터 키 만들기
    mvn --encrypt-master-password password
    {hnkle5BJ9HUHUMP+CXfGBl8dScfFci/mpsur/73tR2I=}
  • 프로젝트 설정 -> 설정 -> CI/CD -> 변수로 이동하여 변수에 저장합니다. SETTINGS_SECURITY_XML 다음 줄:
    <settingsSecurity>
    <master>{hnkle5BJ9HUHUMP+CXfGBl8dScfFci/mpsur/73tR2I=}</master>
    </settingsSecurity>
  • Sonatype 계정의 비밀번호 암호화
    mvn --encrypt-password SONATYPE_PASSWORD
    {98Wv5+u+Tn0HX2z5G/kR4R8Z0WBgcDBgi7d12S/un+SCU7uxzaZGGmJ8Cu9pAZ2J}
  • 프로젝트 설정 -> 설정 -> CI/CD -> 변수로 이동하여 변수에 저장합니다. 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>

어디서
GPG_SECRET_KEY_PASSPHRASE - GPG 키 비밀번호
SONATYPE_USERNAME - 소나타입 계정 로그인

콘텐츠로 돌아가기

도커 이미지 배포

  • 원하는 Java 버전으로 배포 시 작업을 실행하기 위해 매우 간단한 Dockerfile을 만듭니다. 아래는 알파인에 대한 예입니다.

    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/

  • 프로젝트용 컨테이너 빌드

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

  • 컨테이너를 인증하고 레지스트리에 로드합니다.

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

콘텐츠로 돌아가기

깃랩 CI

프로젝트 배포

배포 프로젝트의 루트에 .gitlab-ci.yml 파일을 추가합니다.
스크립트는 상호 배타적인 두 가지 배포 작업을 제공합니다. 각각 특정 러너 또는 공유 러너.

.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

콘텐츠로 돌아가기

자바 프로젝트

공개 저장소에 업로드해야 하는 Java 프로젝트에서 릴리스 및 스냅샷 버전을 다운로드하려면 2단계를 추가해야 합니다.

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

이 솔루션에서는 조금 더 나아가 Java 프로젝트에 하나의 CI 템플릿을 사용하기로 결정했습니다.

세부 정보

별도의 프로젝트를 만들었습니다 gitlab-ci 그는 Java 프로젝트용 CI 템플릿을 배치했습니다. 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

결과적으로 Java 프로젝트 자체에서 .gitlab-ci.yml은 매우 간결하고 장황하지 않게 보입니다.

.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

콘텐츠로 돌아가기

pom.xml 구성

이 주제는 매우 자세히 설명되어 있습니다. 고골 플렉스 в 스냅샷 및 스테이징 저장소에 아티팩트를 자동으로 서명하고 업로드하도록 Maven 설정, 그래서 플러그인 사용의 몇 가지 뉘앙스를 설명하겠습니다. 얼마나 쉽고 자연스럽게 사용할 수 있는지도 알려드릴게요 nexus-staging-maven-pluginorg.sonatype.oss:oss-parent를 프로젝트의 상위 항목으로 사용하고 싶지 않거나 사용할 수 없는 경우.

메이븐 설치 플러그인

로컬 저장소에 모듈을 설치합니다.
체크섬뿐만 아니라 다른 프로젝트의 솔루션에 대한 로컬 검증에도 매우 유용합니다.

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

콘텐츠로 돌아가기

maven-javadoc-플러그인

프로젝트에 대한 javadoc을 생성하는 중입니다.

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

Java가 포함되지 않은 모듈(예: 리소스만 포함)이 있는 경우
또는 원칙적으로 javadoc을 생성하고 싶지 않은 경우 도움을 받으려면 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>

콘텐츠로 돌아가기

maven-gpg-플러그인

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

콘텐츠로 돌아가기

넥서스-스테이징-메이븐-플러그인

구성 :

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

다중 모듈 프로젝트가 있고 특정 모듈을 저장소에 업로드할 필요가 없는 경우 이 모듈의 pom.xml에 추가해야 합니다. nexus-staging-maven-plugin 깃발이 달린 skipNexusStagingDeployMojo

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

스냅샷/릴리스 버전을 업로드한 후 다음에서 사용할 수 있습니다. 준비 저장소

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

더 많은 장점

  • 넥서스 저장소 작업을 위한 매우 풍부한 대상 목록(mvn help:describe -Dplugin=org.sonatype.plugins:nexus-staging-maven-plugin).
  • Maven Central의 다운로드 가능성에 대한 자동 릴리스 확인

콘텐츠로 돌아가기

결과

SNAPSHOT 버전 게시

프로젝트를 빌드할 때 SNAPSHOT 버전을 Nexus에 다운로드하는 작업을 수동으로 시작할 수 있습니다.

Java 프로젝트를 Maven Central에 업로드하도록 GitLab CI 설정

이 작업이 시작되면 배포 프로젝트의 해당 작업이 트리거됩니다().

자른 로그

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

결과적으로 Nexus 버전이 로드됩니다. 1.0.0-스냅샷.

모든 스냅샷 버전은 사이트 저장소에서 제거될 수 있습니다. oss.sonatype.org 귀하의 계정에서.

Java 프로젝트를 Maven Central에 업로드하도록 GitLab CI 설정

콘텐츠로 돌아가기

릴리스 버전 공개

태그가 설정되면 배포 프로젝트의 해당 작업이 자동으로 트리거되어 출시 버전을 nexus().

Java 프로젝트를 Maven Central에 업로드하도록 GitLab CI 설정

가장 좋은 점은 닫기 릴리스가 넥서스에서 자동으로 실행된다는 것입니다.

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

그리고 뭔가 잘못되면 작업이 실패하게 됩니다.

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

결과적으로 우리에게 남은 선택은 하나뿐이다. 또는 이 버전을 삭제하거나 게시하세요.

Java 프로젝트를 Maven Central에 업로드하도록 GitLab CI 설정

출시 후 일정 시간이 지나면 유물이 Java 프로젝트를 Maven Central에 업로드하도록 GitLab CI 설정

주제를 벗어

Maven이 다른 공개 저장소를 색인화한다는 것은 나에게 새로운 계시였습니다.
이전 저장소의 색인을 생성했기 때문에 robots.txt를 업로드해야 했습니다.

콘텐츠로 돌아가기

결론

우리가 가진 것

  • 다양한 개발 언어에 대한 공개 저장소에 아티팩트를 업로드하기 위한 여러 CI 작업을 구현할 수 있는 별도의 배포 프로젝트입니다.
  • 배포 프로젝트는 외부 간섭으로부터 격리되며 소유자 및 유지 관리 역할을 가진 사용자만 수정할 수 있습니다.
  • 배포 작업만 실행하기 위한 "핫" 캐시가 있는 별도의 특정 실행기.
  • 공개 저장소에 스냅샷/릴리스 버전을 게시합니다.
  • Maven Central에 게시할 준비가 되었는지 릴리스 버전을 자동으로 확인합니다.
  • Maven Central에서 "원시" 버전이 자동으로 게시되는 것을 방지합니다.
  • "클릭 시" 스냅샷 버전을 구축하고 게시합니다.
  • 스냅샷/릴리스 버전을 가져오기 위한 단일 저장소입니다.
  • Java 프로젝트 빌드/테스트/게시를 위한 일반 파이프라인입니다.

GitLab CI 설정은 언뜻 보기에 그렇게 복잡한 주제가 아닙니다. 턴키 방식으로 CI를 몇 번 설정하는 것만으로도 충분하며 이제 이 문제에 있어서 아마추어와는 거리가 멀습니다. 게다가 GitLab 문서는 매우 중복됩니다. 첫발을 내딛는 것을 두려워하지 마십시오. 걷는 사람의 발걸음 아래에 길이 나타납니다. (누가 말했는지 기억이 나지 않습니다 :)

나는 피드백을 기쁘게 생각합니다.

다음 기사에서는 Shell Runner가 하나만 있는 경우 통합 테스트 작업을 경쟁적으로 실행(docker-compose를 사용하여 테스트 서비스 실행)하도록 GitLab CI를 설정하는 방법을 보여 드리겠습니다.

콘텐츠로 돌아가기

출처 : habr.com

코멘트를 추가