この記事は、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 キー
http://keys.gnupg.net http://pool.sks-keyservers.net http://keyserver.ubuntu.com
GitLab でのデプロイ プロジェクトのセットアップ
- まず、アーティファクトのデプロイのためにパイプラインが保存されるプロジェクトを作成して構成する必要があります。 私は自分のプロジェクトをシンプルかつ単純な名前にしました -
展開します - リポジトリを作成した後、リポジトリを変更するにはアクセスを制限する必要があります。
プロジェクト -> 設定 -> リポジトリ -> 保護されたブランチに移動します。 すべてのルールを削除し、Maintainers ロールを持つユーザーのみにプッシュおよびマージする権限を持つワイルドカード * を含む XNUMX つのルールを追加します。 このルールは、このプロジェクトとこのプロジェクトが属するグループの両方のすべてのユーザーに対して機能します。
- メンテナが複数いる場合、原則としてプロジェクトへのアクセスを制限することが最善の解決策となります。
プロジェクト -> 設定 -> 一般 -> 可視性、プロジェクト機能、権限に移動し、プロジェクトの可視性を に設定します。 プライベート.
私は独自の 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 -> ランナー -> 特定のランナーに移動し、登録トークンをコピーします。
スクリーン
- ランナーの登録
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 -> ランナー -> 特定のランナー -> このプロジェクトに対してアクティブ化されたランナーに移動します
スクリーン
- 追加 別れる サービス
/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
- ランナーが走行していることを確認してください。
例
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 アカウントのログイン
これでランナーのセットアップが完了しました。次のセクションに進むことができます。
共有ランナー
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
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 テンプレートを使用することにしました。
詳細
別のプロジェクトを作成しました
共通.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 構成
このトピックについては非常に詳細に説明されています。 nexus-staging-maven-plugin
org.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 にダウンロードするタスクを手動で開始することができます。
このタスクが起動されると、デプロイ プロジェクト内の対応するタスクがトリガーされます (
切り取られた丸太
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 バージョンがロードされます
すべてのスナップショット バージョンはサイト上のリポジトリから削除できます
リリース版の公開
タグが設定されると、デプロイ プロジェクト内の対応するタスクが自動的にトリガーされ、リリース バージョンを Nexus にアップロードします (
最も良い点は、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 <a href=http://keys.gnupg.net:11371/>http://keys.gnupg.net:11371/</a>. 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 つだけです。 または、このバージョンを削除するか、公開します。
オフトピック
Maven が他のパブリック リポジトリのインデックスを作成していることは私にとって啓示でした。
robots.txt は古いリポジトリにインデックスを付けていたため、アップロードする必要がありました。
まとめ
私たちが持っているもの
- さまざまな開発言語のパブリック リポジトリにアーティファクトをアップロードするためのいくつかの CI タスクを実装できる別のデプロイ プロジェクト。
- デプロイメント プロジェクトは外部の干渉から隔離されており、所有者およびメンテナの役割を持つユーザーのみが変更できます。
- デプロイタスクのみを実行する「ホット」キャッシュを備えた別の特定のランナー。
- パブリック リポジトリでのスナップショット/リリース バージョンの公開。
- Maven Central での公開の準備ができているかどうかのリリース バージョンの自動チェック。
- Maven Central での「生」バージョンの自動公開に対する保護。
- 「クリック時」にスナップショット バージョンを構築して公開します。
- スナップショット/リリース バージョンを取得するための単一リポジトリ。
- Java プロジェクトを構築/テスト/公開するための一般的なパイプライン。
GitLab CI のセットアップは、一見したほど複雑なトピックではありません。 ターンキー ベースで CI を数回セットアップするだけで十分です。これで、この点に関してはまったくの素人ではなくなります。 さらに、GitLab のドキュメントは非常に冗長です。 最初の一歩を踏み出すことを恐れないでください。 歩いている人の階段の下に道が現れます(誰が言ったか覚えていません:)
喜んでフィードバックさせていただきます。
次の記事では、シェル ランナーが XNUMX つしかない場合に、統合テスト タスクを競合的に実行する (docker-compose を使用してテスト サービスを実行する) ように GitLab CI をセットアップする方法を説明します。
出所: habr.com