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) を生成している場合は、以下をインストールする必要があります。 rng-tools エントロピーを生成します。 そうしないと、キーの生成に非常に長い時間がかかる可能性があります。
  • ストレージサービス 公の GPG キー

コンテンツへ

GitLab でのデプロイ プロジェクトのセットアップ

  • まず、アーティファクトのデプロイのためにパイプラインが保存されるプロジェクトを作成して構成する必要があります。 私は自分のプロジェクトをシンプルかつ単純な名前にしました - 展開します
  • リポジトリを作成した後、リポジトリを変更するにはアクセスを制限する必要があります。
    プロジェクト -> 設定 -> リポジトリ -> 保護されたブランチに移動します。 すべてのルールを削除し、Maintainers ロールを持つユーザーのみにプッシュおよびマージする権限を持つワイルドカード * を含む XNUMX つのルールを追加します。 このルールは、このプロジェクトとこのプロジェクトが属するグループの両方のすべてのユーザーに対して機能します。
    Java プロジェクトを Maven Central にアップロードするための GitLab CI のセットアップ
  • メンテナが複数いる場合、原則としてプロジェクトへのアクセスを制限することが最善の解決策となります。
    プロジェクト -> 設定 -> 一般 -> 可視性、プロジェクト機能、権限に移動し、プロジェクトの可視性を に設定します。 プライベート.
    私は独自の GitLab Runner を使用しており、私だけがリポジトリを変更するアクセス権を持っているため、プロジェクトをパブリック アクセスにしています。 そうですね、実際のところ、パブリック パイプライン ログに個人情報を表示することは私の利益にはなりません。
  • リポジトリ変更ルールの厳格化
    プロジェクト -> 設定 -> リポジトリ -> プッシュ ルールに移動し、コミッター制限、作成者が GitLab ユーザーであるかどうかを確認するフラグを設定します。 セッティングもオススメです コミット署名、署名されていないコミットを拒否するフラグを設定します。
  • 次に、タスクを実行するためのトリガーを構成する必要があります
    プロジェクト -> 設定 -> CI / CD -> パイプライントリガーに移動し、新しいトリガートークンを作成します
    このトークンは、プロジェクトのグループの変数の一般的な構成にすぐに追加できます。
    グループ -> 設定 -> CI / CD -> 変数に移動し、変数を追加します DEPLOY_TOKEN 値にトリガートークンが含まれています。

コンテンツへ

GitLab ランナー

このセクションでは、ネイティブ (特定) ランナーとパブリック (共有) ランナーを使用してデプロイ時にタスクを実行するための構成について説明します。

特定のランナー

私は自分のランナーを使用しています。なぜなら、第一に便利で、速く、安いからです。
ランナーには、1 CPU、2 GB RAM、20 GB HDD を搭載した Linux VDS をお勧めします。 発行価格は年間 ~ 3000₽。

私のランナー

ランナーには、VDS 4 CPU、4 GB RAM、50 GB 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

コンテンツへ

Maven のセットアップ

  • ユーザーの下に行きます gitlab-deployer
    su gitlab-deployer 
  • Maven ディレクトリを作成する 倉庫 そしてキャッシュとリンクします(間違えないでください)
    同じマシン上で複数のランナーを実行する予定がない場合は、この手順を省略できます。

    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 - sonatype アカウントのログイン

これでランナーのセットアップが完了しました。次のセクションに進むことができます。 GitLab 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 のセットアップ

コンテンツへ

Maven のセットアップ

  • マスターキーを作成する
    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 - sonatype アカウントのログイン

コンテンツへ

Dockerイメージをデプロイする

  • 必要なバージョンの 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

コンテンツへ

GitLab CI

プロジェクトのデプロイ

ファイル .gitlab-ci.yml をデプロイ プロジェクトのルートに追加します。
このスクリプトは、XNUMX つの相互に排他的な展開タスクを示します。 それぞれ、特定のランナーまたは共有ランナー。

.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プロジェクト

パブリック リポジトリにアップロードすることが想定されている 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 プロジェクトに XNUMX つの CI テンプレートを使用することにしました。

詳細

別のプロジェクトを作成しました gitlab-ci 彼はそこに Java プロジェクトの CI テンプレートを配置しました 共通.yml.

共通.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 をプロジェクトの親として使用したくない場合、または使用できない場合。

maven-インストール-プラグイン

ローカル リポジトリにモジュールをインストールします。
チェックサムだけでなく、他のプロジェクトのソリューションのローカル検証にも非常に役立ちます。

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

コンテンツへ

nexus-staging-maven-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>

その他のプラス

  • Nexus リポジトリを操作するためのターゲットの非常に豊富なリスト (mvn help:describe -Dplugin=org.sonatype.plugins:nexus-staging-maven-plugin).
  • Maven Central でのダウンロード可能性の自動リリースチェック

コンテンツへ

結果

スナップショットバージョンの公開

プロジェクトをビルドするときに、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 のセットアップ

最も良い点は、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] ------------------------------------------------------------------------

何か問題が発生した場合、タスクは失敗します

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

その結果、私たちに残された選択肢は XNUMX つだけです。 または、このバージョンを削除するか、公開します。

Java プロジェクトを Maven Central にアップロードするための GitLab CI のセットアップ

リリース後、しばらくするとアーティファクトが追加されます。 Java プロジェクトを Maven Central にアップロードするための GitLab CI のセットアップ

オフトピック

Maven が他のパブリック リポジトリのインデックスを作成していることは私にとって啓示でした。
robots.txt は古いリポジトリにインデックスを付けていたため、アップロードする必要がありました。

コンテンツへ

まとめ

私たちが持っているもの

  • さまざまな開発言語のパブリック リポジトリにアーティファクトをアップロードするためのいくつかの CI タスクを実装できる別のデプロイ プロジェクト。
  • デプロイメント プロジェクトは外部の干渉から隔離されており、所有者およびメンテナの役割を持つユーザーのみが変更できます。
  • デプロイタスクのみを実行する「ホット」キャッシュを備えた別の特定のランナー。
  • パブリック リポジトリでのスナップショット/リリース バージョンの公開。
  • Maven Central での公開の準備ができているかどうかのリリース バージョンの自動チェック。
  • Maven Central での「生」バージョンの自動公開に対する保護。
  • 「クリック時」にスナップショット バージョンを構築して公開します。
  • スナップショット/リリース バージョンを取得するための単一リポジトリ。
  • Java プロジェクトを構築/テスト/公開するための一般的なパイプライン。

GitLab CI のセットアップは、一見したほど複雑なトピックではありません。 ターンキー ベースで CI を数回セットアップするだけで十分です。これで、この点に関してはまったくの素人ではなくなります。 さらに、GitLab のドキュメントは非常に冗長です。 最初の一歩を踏み出すことを恐れないでください。 歩いている人の階段の下に道が現れます(誰が言ったか覚えていません:)

喜んでフィードバックさせていただきます。

次の記事では、シェル ランナーが XNUMX つしかない場合に、統合テスト タスクを競合的に実行する (docker-compose を使用してテスト サービスを実行する) ように GitLab CI をセットアップする方法を説明します。

コンテンツへ

出所: habr.com

コメントを追加します