Вы написали библиотеку на Java и теперь хотите сделать ее общедоступной? Самый простой способ распространения библиотек – это загрузить ее в Maven Central.
Если вы думаете, что можно просто зарегистрироваться в Maven Central и загрузить свой шедевр через форму загрузки, то вы ошибаетесь. Придется пройти небольшой квест.
Помимо Maven Central есть и другие Nexus хранилища – Open Source Software Repository Hosting Service (OSSRH). Крупнейшим является Sonatype OSSRH.
Sonatype OSSRH синхронизируется с Maven Central. Поэтому в этой статье мы разберемся, как зарегистрироваться в Sonatype OSSRH и настроить Maven pom для деплоя в Sonatype OSSRH.
Регистрируем groupId
Зависимость в maven централ выглядит следующим образом.
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.1.1</version>
</dependency>
groupId
и artifactId
составляют идентификатор вашей библиотеки. groupId
- это идентификатор группы проекта. Как правило, он уникален среди организаций и представляет собой доменное имя наоборот. artifactId
- это идентификатор проекта в группе проектов.
Чтобы иметь возможность загружать библиотеки, необходимо купить доменное имя, которое будет вашим groupId
.
И так мы купили домен, теперь необходимо подать заявку на регистрацию groupId
и подтвердить свои права на домен. Делается это через issues в Jira Sonatype.
Поддомены отдельно регистрировать не надо. После регистрации основного домена, вы сможете использовать и его поддомены.
Тема: Publish rights for domain.name
Описание: I would like to publish my name.domain artifacts. The rights to the domain belong to me.
Group Id: ru.upagge
Project URL: Ссылка на ваш проект в GitLab или GitHub
SCM url: Тоже ссылка на ваш проект, но добавьте в конце .git
Already Synced to Central: No
Через какое-то время в ваше issue пришлют инструкцию, как подтвердить владение доменом. Мне прислали через минуту, скорее всего это автоматическое сообщение.
Пойдем самым быстрым путем - добавим TXT запись для домена. Сделать это можно у регистратора домена.
- Тип записи: TXT
- Subdomain: @
- Text: Ссылка на тикет в Jira
После этого ждем пока DNS записи обновятся. У каждого регистратора это занимает разное время. У REG.RU записи обновились за 15 минут.
После того, как вы убедились, что запись появилась, возвращаемся в тикет. Оставляем там короткий комментарий: done.
Буквально через 10 минут приходит оповещение, что все успешно.
Создание GPG ключа
Генерация GPG ключа
Перед настройкой .pom
необходимо создать GPG ключ для подписи релиза.
gpg --full-gen-key
gpg (GnuPG) 2.2.4; Copyright (C) 2017 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Выберите тип ключа:
(1) RSA и RSA (по умолчанию)
(2) DSA и Elgamal
(3) DSA (только для подписи)
(4) RSA (только для подписи)
Ваш выбор? 1
длина ключей RSA может быть от 1024 до 4096.
Какой размер ключа Вам необходим? (3072) 2048
Запрошенный размер ключа - 2048 бит
Выберите срок действия ключа.
0 = не ограничен
= срок действия ключа - n дней
w = срок действия ключа - n недель
m = срок действия ключа - n месяцев
y = срок действия ключа - n лет
Срок действия ключа? (0) 0
Срок действия ключа не ограничен
Все верно? (y/N) y
GnuPG должен составить идентификатор пользователя для идентификации ключа.
Ваше полное имя: Struchkov Mark
Адрес электронной почты: example@upagge.ru
Примечание:
Вы выбрали следующий идентификатор пользователя:
"Struchkov Mark "
Сменить (N)Имя, (C)Примечание, (E)Адрес; (O)Принять/(Q)Выход? O
Необходимо получить много случайных чисел. Желательно, чтобы Вы
в процессе генерации выполняли какие-то другие действия (печать
на клавиатуре, движения мыши, обращения к дискам); это даст генератору
случайных чисел больше возможностей получить достаточное количество энтропии.
Необходимо получить много случайных чисел. Желательно, чтобы Вы
в процессе генерации выполняли какие-то другие действия (печать
на клавиатуре, движения мыши, обращения к дискам); это даст генератору
случайных чисел больше возможностей получить достаточное количество энтропии.
gpg: ключ C7F6E84396D004C4 помечен как абсолютно доверенный
gpg: сертификат отзыва записан в '/home/upagge/.gnupg/openpgp-revocs.d/736AD6032D072F9E452911D5C7F6E84396D004C4.rev'.
открытый и секретный ключи созданы и подписаны.
pub rsa2048 2021-04-02 [SC]
736AD6032D072F9E452911D5C7F6E84396D004C4
uid Struchkov Mark
sub rsa2048 2021-04-02 [E]
- Тип ключа: RSA и RSA
- Размер ключа: 2048
- Срок действия: неограничен
Публикация ключа
Отправьте свой ключ на сервер GPG:
gpg --keyserver keyserver.ubuntu.com --send-keys 736AD6032D072F9E452911D5C7F6E84396D004C4
Чтобы получить публичный ключ в нужном формате, используйте команду:
gpg --armor --export 736AD6032D072F9E452911D5C7F6E84396D004C4
Настройка settings.xml
Сначала вам нужно создать токен доступа для публикации ваших (изменение от 2024 года). Для этого нужно:
- Перейдите в веб-интерфейс Nexus Repository Manager. Скорее всего, это oss.sonatype.org или s01.oss.sonatype.org.
- Выберите опцию «Профиль» в желтом верхнем правом раскрывающемся меню
- На вкладке «Профиль» выберите параметр «Токен пользователя» в поле выбора ввода.
- Нажмите кнопку «Токен пользователя доступа» (вам потребуется повторно ввести свои учетные данные).
Теперь перейдем в глобальные настройки Maven в файле .m2/settings.xml
. Нам необходимо указать полученный токен от OSSRH. Также добавим профиль мавена release
, в который укажем данные GPG ключа. gpg.keyname
в данном случае будет 736AD6032D072F9E452911D5C7F6E84396D004C4
.
<settings>
<servers>
<server>
<id>ossrh</id>
<username>token-username</username>
<password>token-password</password>
</server>
</servers>
<profiles>
<profile>
<id>ossrh</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<properties>
<gpg.keyname>PGP_KEY</gpg.keyname>
<gpg.passphrase>YOU_PASSWORD</gpg.passphrase>
</properties>
</profile>
</profiles>
</settings>
После сохранения файла settings.xml
перезапустите Idea, чтобы новый профиль появился в списке.
Переходим в pom.xml
вашего приложения. Укажем название, описание и ссылку на проект.
// ... ... ... ... ...
<name>uPagge Utils</name>
<description>An example to demonstrate the ability to publish to Maven Central</description>
<url>https://blog.upagge.ru/posts/guide/2021/deploy-to-maven-central/</url>
// ... ... ... ... ...
Эта информация будет использоваться в описании компонента в Maven Central.
Обязательно необходимо указать лицензию, под которой выпускается ваша библиотека. Например:
<licenses>
<license>
<name>BSD 3-Clause License</name>
<url>https://gitlab.com/uPagge/upagge-utils/-/raw/master/LICENSE</url>
</license>
</licenses>
Вы можете зайти на свой проект на GitHub, нажать кнопку Add File / Create new File. В название файла укажите LICENSE. Вы увидите появление кнопки Choose a license template. Выбирайте понравившуюся
Также указываем информацию о системе контроля версий.
// ... ... ... ... ...
<scm>
<connection>scm:git:https://gitlab.com/uPagge/upagge-utils.git</connection>
<url>https://gitlab.com/uPagge/upagge-utils</url>
<developerConnection>scm:git:https://gitlab.com/uPagge/upagge-utils.git</developerConnection>
</scm>
// ... ... ... ... ...
После этого добавляем ссылки на репозитории
// ... ... ... ... ...
<distributionManagement>
<snapshotRepository>
<id>ossrh</id>
<url>https://s01.oss.sonatype.org/content/repositories/snapshots</url>
</snapshotRepository>
</distributionManagement>
// ... ... ... ... ...
Также обязательно нужно указать разработчиков:
// ... ... ... ... ...
<developers>
<developer>
<id>uPagge</id>
<name>Struchkov Mark</name>
<url>https://struchkov.dev</url>
</developer>
</developers>
// ... ... ... ... ...
Плагины для публикации
Для публикации будем использовать плагин nexus-staging-maven-plugin
. А чтобы случайно не запустить публикацию, мы создадим отдельный maven профиль – release
.
Но сначала в проперти укажем версии необходимых плагинов.
<properties>
... ... ... ... ...
<plugin.nexus.staging.ver>1.6.12</plugin.nexus.staging.ver>
<plugin.maven.source.ver>3.2.1</plugin.maven.source.ver>
<plugin.maven.javadoc.ver>3.3.1</plugin.maven.javadoc.ver>
<plugin.maven.gpg.ver>3.0.1</plugin.maven.gpg.ver>
</properties>
Актуальные версии плагинов
Добавляем конфигурацию для плагинов:
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>${plugin.nexus.staging.ver}</version>
<extensions>true</extensions>
<configuration>
<serverId>ossrh</serverId>
<nexusUrl>https://s01.oss.sonatype.org/</nexusUrl>
<autoReleaseAfterClose>true</autoReleaseAfterClose>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>${plugin.maven.source.ver}</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>${plugin.maven.javadoc.ver}</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>${plugin.maven.gpg.ver}</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
<configuration>
<gpgArguments>
<gpgArgument>--pinentry-mode</gpgArgument>
<gpgArgument>loopback</gpgArgument>
</gpgArguments>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
</plugins>
</build>
Опционально вы можете использовать плагины maven-source-plugin
и maven-javadoc-plugin
используются для генерации исходников и javadoc соответсвенно. Сгенерированные ими jar будут также загружены в maven central.
Плагин maven-gpg-plugin
используется для финальной подписи ваших jar файлов. Его использование обязательно.
Теперь в pom.xml
добавляем новый профиль release
:
<profiles>
<profile>
<id>release</id>
<build>
<plugins>
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
</plugin>
</plugins>
</build>
</profile>
</profiles>
Все, можно опубликовывать. Делается это просто. Активируйте профиля, которые мы создали ранее и запустите команду мавена:
mvn clean deploy
// ... ... ... ... ...
[INFO] * Upload of locally staged artifacts finished.
[INFO] * Closing staging repository with ID "ruupagge-1003".
Waiting for operation to complete...
...
[INFO] Remote staged 1 repositories, finished with success.
[INFO] Remote staging repositories are being released...
Waiting for operation to complete...
...
[INFO] Remote staging repositories released.
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 34.159 s
[INFO] Finished at: 2021-04-02T19:49:31+03:00
[INFO] ------------------------------------------------------------------------
Переходим в и воспользовавшись поиском находим нашу библиотеку в Sonatype OSSHR.
Теперь возвращаемся в наш изначальный тикет и пишем, что все готово и библиотека загружена. Они включат автоматическую синхронизацию. Это надо делать только в первый раз, дальше все ваши библиотеки будут синхронизироваться автоматически.
Через 8-24 часа переходим в Maven Central и через поиск находим нашу либу.
🎉🎉🎉 Успех! Теперь любой разработчик сможет воспользоваться вашей библиотекой.
Публикация с помощью GitLab CI
Каждый раз публиковать библиотеку запуская команду мавена с компьютера не удобно, реализуем автоматическую публикацию при помощи GitLab CI.
Мы сделаем так, чтобы при каждом новом git теге формата release-*
запускалась сборка и публикация в Maven Central. Таким образом каждый ваш релиз будет автоматически попадать в Maven Central.
Даше если вы используйте GitHub для хранения кодовой базы, вы можете использовать GitLab CI. GitLab может синхронизировать ваш репозиторий с GitHub, то есть все изменения в GitHub репозитории будут появляться в GitLab. Но изменения будут синхронизироваться с задержкой.
Для этого при создании проекта выберете пункт "Run CI/CD external repository".
Если проект у вас изначально хранился в GitLab, то создавать новый проект не нужно, просто добавьте файл .gitlab-ci.yml
в текущий проект по инструкции ниже.
Теперь необходимо защитить теги формата release-*
. Для этого переходим в проекте Settings —> Repository —> Protected tags. Вводим release-*
. И нажимаем Create wilcard.
Дальше выберите тех, кому можно будет создавать эти теги. При работе в команде это разграничит возможности. Только одобренные разработчики смогут делать релизы и загружать в Maven Central.
Настроим GitLab CI. Для этого в корне проекта создаем новый файл .gitlab-ci.yml
:
image: maven:3.8.4-openjdk-11
variables:
MAVEN_OPTS: "-Dmaven.repo.local=./.m2/repository"
stages:
- deploy
deploy:
stage: deploy
only:
- /^release-.*$/
except:
- branches
before_script:
- gpg --pinentry-mode loopback --passphrase $GPG_PASSPHRASE --import $GPG_PRIVATE_KEY
script:
- 'mvn --settings $MAVEN_SETTINGS -U -P ossrh,release clean deploy'
Здесь мы указываем, что при обнаружении тега release-*
необходимо сначала импортировать GPG ключ, а далее выполнить команду Maven.
Чтобы этот конфиг работал, необходимо создать переменные CICD. Для этого перейдите в Seiitings —> CI/CD —> Variables.
При создании переменных указывайте параметр Protected. Этим вы сообщаете GitLab CI, что использовать эти переменные можно только в защищенных ветках/тегах.
В переменную GPG_PRIVATE_KEY
записываешь приватный ключ GPG. Чтобы его получить выполните в терминале следующую команду:
gpg --armor --export-secret-key 736AD6032D072F9E452911D5C7F6E84396D004C4
-----BEGIN PGP PRIVATE KEY BLOCK-----
lQPGBGGnICAB...PUKn3Q7GBXxg=
=CG7t
-----END PGP PRIVATE KEY BLOCK-----
В переменную GPG_PASSPHRASE
просто запишите пароль от GPG ключа.
В переменную MAVEN_SETTINGS
укажем такие же настройки, которые прописали в файл .m2/settings.xml
.
<settings>
<servers>
<server>
<id>ossrh</id>
<username>token-username</username>
<password>token-password</password>
</server>
</servers>
<profiles>
<profile>
<id>ossrh</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<properties>
<gpg.keyname>gpg-keyname</gpg.keyname>
<gpg.passphrase>gpg-password</gpg.passphrase>
</properties>
</profile>
</profiles>
</settings>
Чтобы запустить автоматическую сборку необходимо добавить тег формата release-*
для любого коммита и запушить его.
Теперь все релизы будут автоматически публиковаться в Maven Central.