Предисловие
Данная статья основана на статье с Baeldung – Hosting a Maven Repository on GitHub.
Если интересно сразу перейти к делу, то пожалуйста)
Уже как три года я работаю над проектом со стеком Kotlin, Spring Boot, Maven. Все начиналось как небольшая учебная практика в вузе на коленке за пару недель и разрослось в приличную систему, которая уже использовалась по всей России.
В связи с ростом проекта, монорепозитория стало мало и появилась необходимость часть логики выделять в отдельные репозитории. Вот здесь и возникает вопрос: как управлять этими зависимостями?
Разбор решений
Для управления несколькими репозиториями был сделан небольшой обзор имеющихся решений
Использование Git Submodules
Изначально при появлении новых репозиториев они добавлялись как подмодули и собирались вместе со всем проектом, на тот момент это было оптимальным решением.
Плюсы
Простая настройка.
Простое обновление модулей (если берется всегда последний коммит мастер-ветки).
Минусы
Если у модуля сложное версионирование (с минорами и патчами), появляются сложности с обновлением (по крайней мере не отображается информация о версии модуля).
В случае нескольких модулей первый пункт становится еще сложнее.
Когда стоит использовать
Если зависимость не имеет версионирования с патчами и минорами (то есть всегда используется версия последнего коммита в мастер).
Если зависимость не меняется вообще (по сути первый пункт, только модули не нужно обновлять вообще).
Если подмодулей не больше двух.
Публикация артефактов в maven-репозиторий
Этот вариант выглядит более взрослым и сложным, по этой причине изначально я даже не стал смотреть в его сторону (на тот момент это и не было нужно).
Плюсы
Более удобное управление зависимостями: просто меняем версию в pom'нике.
Можно разделять версии на нестабильные (*-SNAPSHOT) и стабильные/релизные (.RELEASE): первые использовать во время активной разработки для обкатки фичей, вторые при релизе.
Зависимости собираются отдельно от основного репозитория, что ускоряет сборку (иногда значительно). Особенно это полезно при частой переборке всего проекта.
Минусы
Более сложная настройка.
Для использования зависимостей нужно публиковать новые версии артефактов. Это минус в случае ручной публикации и в случае автоматизации (в сравнении с подмодулями): в первом случае просто неприлично в ручную публиковать зависимость, когда можно сделать автоматизацию, во втором случае нужно написать автоматизацию.
Когда стоит использовать
Есть время разобраться в настройке публикации и в ее автоматизации.
В проекте используется больше двух зависимостей.
В версионировании зависимостей используются миноры и патчи.
По итогу во время роста числа зависимостей выбор был сделан в пользу публикации артефактов в maven-репозиторий.
Как можно публиковать в maven-репозиторий
Когда было принято решение публиковать зависимости как отдельные артефакты, я начал искать, как можно осуществить мою задумку. В итоге нашлось два варианта.
Публикация в Maven Central Portal
Для публикации в Maven Central Portal существует целая инструкция, здесь я не буду подробно описывать как это сделать. Опишу лишь причины, по которым я отказался от этого варианта:
Инструкция показалась достаточно сложной, для не самой приоритетной задачи.
Необходимо иметь собственный домен, если не нравится использовать
io.<github/gitlab/gitee/bitbucket>.username
как группу проекта.Необходимо соблюсти много стандартов, не соблюдая которые могут удалить артефакты (если артефакты нужны лишь для собственных проектов, то эти стандарты ни к чему).
Публикация в кастомный репозиторий
Для кастомных репозиториев есть несколько вариантов, но мне пригляделась инструкция по публикации артефактов в репозитории на GitHub. Почему же?
Простая инструкция.
Можно использовать любое имя группы проекта.
Стандарты можно не соблюдать, никто не удалит артефакты (чтобы ими пользоваться, разработчик должен сам осознанно добавить ваш репозиторий как maven-репозиторий).
В общем все вело к тому, чтобы публиковать артефакты в GitHub репозиторий.
Инструкция
Приступим!
-
Создадим проект (я использую IntelliJ IDEA в качестве среды разработки)
Создание проекта в IntelliJ IDEA По итогу получим вот такой pom-файл (с точностью до вынесения версий в блок
properties
):<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.test.publish</groupId> <artifactId>publish-test</artifactId> <version>1.0.0-SNAPSHOT</version> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <kotlin.code.style>official</kotlin.code.style> <kotlin.compiler.jvmTarget>1.8</kotlin.compiler.jvmTarget> <kotlin.version>2.1.20</kotlin.version> <junit.version>5.10.0</junit.version> <maven.plugin.surfire.version>2.22.2</maven.plugin.surfire.version> </properties> <repositories> <repository> <id>mavenCentral</id> <url>https://repo1.maven.org/maven2/</url> </repository> </repositories> <build> <sourceDirectory>src/main/kotlin</sourceDirectory> <testSourceDirectory>src/test/kotlin</testSourceDirectory> <plugins> <plugin> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-maven-plugin</artifactId> <version>${kotlin.version}</version> <executions> <execution> <id>compile</id> <phase>compile</phase> <goals> <goal>compile</goal> </goals> </execution> <execution> <id>test-compile</id> <phase>test-compile</phase> <goals> <goal>test-compile</goal> </goals> </execution> </executions> </plugin> <plugin> <artifactId>maven-surefire-plugin</artifactId> <version>${maven.plugin.surfire.version}</version> </plugin> <plugin> <artifactId>maven-failsafe-plugin</artifactId> <version>${maven.plugin.surfire.version}</version> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-test-junit5</artifactId> <version>${kotlin.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-stdlib</artifactId> <version>${kotlin.version}</version> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> </dependencies> </project>
-
Создадим репозиторий на GitHub для хранения в нем текущего и будущих артефактов.
Создание репозитория на GitHub для хранения в нем артефактов -
Добавим временное локальное хранилище артефактов.
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.test.publish</groupId> <artifactId>publish-test</artifactId> <version>1.0.0-SNAPSHOT</version> <properties> ... <!-- Путь к временному хранилищу артефактов --> <deploy.temporaryArtifactDir>${project.build.outputDirectory}/mvn-artifact</deploy.temporaryArtifactDir> </properties> ... <distributionManagement> <!-- Репозиторий для временного хранилища артефактов --> <repository> <id>internal.repo</id> <name>Temporary Staging Repository</name> <url>file://${deploy.temporaryArtifactDir}</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> </repository> </distributionManagement> ... </project>
-
Добавим все необходимые плагины.
-
maven-deploy-plugin
– для включения после сборки артефактов в локальный репозиторий:<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.test.publish</groupId> <artifactId>publish-test</artifactId> <version>1.0.0-SNAPSHOT</version> <properties> ... <!-- Версия для Maven Deploy PLugin --> <maven.plugin.deploy.version>2.8.2</maven.plugin.deploy.version> ... </properties> ... <build> ... <!-- Maven Deploy Plugin --> <plugins> <plugin> <artifactId>maven-deploy-plugin</artifactId> <version>${maven.plugin.deploy.version}</version> <configuration> <altDeploymentRepository> internal.repo::default::file://${deploy.temporaryArtifactDir} </altDeploymentRepository> </configuration> </plugin> ... </plugins> </build> ... </project>
-
maven-source-plugin
(опционально) – для публикации вместе с артефактами самих исходников:<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.test.publish</groupId> <artifactId>publish-test</artifactId> <version>1.0.0-SNAPSHOT</version> <properties> ... <!-- Версия Maven Source Plugin --> <maven.plugin.source.version>3.1.0</maven.plugin.source.version> </properties> ... <build> ... <plugins> ... <!-- Maven Source Plugin --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-source-plugin</artifactId> <version>${maven.plugin.source.version}</version> <executions> <execution> <id>attach-sources</id> <goals> <goal>jar</goal> </goals> </execution> </executions> </plugin> ... </plugins> </build> ... </project>
-
site-maven-plugin
– для публикации артефактов в GitHub репозиторий:<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.test.publish</groupId> <artifactId>publish-test</artifactId> <version>1.0.0-SNAPSHOT</version> <properties> ... <!-- Ветка, куда будут пушиться коммиты с артефактами --> <deploy.branch.name>master</deploy.branch.name> <!-- Название репозиторий, куда будут публиковаться артефакты --> <deploy.repository.name>maven-test-repo</deploy.repository.name> <!-- Имя пользователя или название организации GitHub (TODO: заменить на свое) --> <deploy.repository.owner>your-username/your-oraganization-name</deploy.repository.owner> </properties> ... <build> ... <plugins> ... <plugin> <groupId>com.github.github</groupId> <artifactId>site-maven-plugin</artifactId> <version>${maven.plugin.site.version}</version> <configuration> <!-- Коммит-месседж при пуше коммитов (TODO: опционально измененить) --> <message>${project.groupId}:${project.artifactId}:${project.version}</message> <noJekyll>true</noJekyll> <outputDirectory>${deploy.temporaryArtifactDir}</outputDirectory> <branch>refs/heads/${deploy.branch.name}</branch> <includes> <include>*/**</include> </includes> <merge>true</merge> <repositoryName>${deploy.repository.name}</repositoryName> <repositoryOwner>${deploy.repository.owner}</repositoryOwner> <server>github</server> </configuration> <executions> <execution> <goals> <goal>site</goal> </goals> <phase>deploy</phase> </execution> </executions> </plugin> ... </plugins> </build> ... </project>
Также обязательно добавить данные для аутентификации на GitHub в
~/.m2/settings.xml
. Для этого необходимо сгенерировать GitHub PAT с правамиrepo
иuser
и добавить его в файл.<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd"> ... <servers> <server> <id>github</id> <!-- GitHub PAT (TODO: обновить на свой) --> <password>your-personal-access-token</password> </server> </servers> ... </settings>
По итогу получим следующий pom-файл:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.test.publish</groupId> <artifactId>publish-test</artifactId> <version>1.0.0-SNAPSHOT</version> <properties> ... <maven.plugin.surfire.version>2.22.2</maven.plugin.surfire.version> <maven.plugin.deploy.version>2.8.2</maven.plugin.deploy.version> <maven.plugin.source.version>3.1.0</maven.plugin.source.version> <maven.plugin.site.version>0.12</maven.plugin.site.version> <!-- Deployment --> <deploy.temporaryArtifactDir>${project.build.outputDirectory}/mvn-artifact</deploy.temporaryArtifactDir> <deploy.branch.name>master</deploy.branch.name> <deploy.repository.name>maven-test-repo</deploy.repository.name> <deploy.repository.owner>your-username/organization-name</deploy.repository.owner> </properties> <repositories> <repository> <id>mavenCentral</id> <url>https://repo1.maven.org/maven2/</url> </repository> </repositories> <distributionManagement> <repository> <id>internal.repo</id> <name>Temporary Staging Repository</name> <url>file://${deploy.temporaryArtifactDir}</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> </repository> </distributionManagement> <build> ... <plugins> <plugin> <artifactId>maven-deploy-plugin</artifactId> <version>${maven.plugin.deploy.version}</version> <configuration> <altDeploymentRepository> internal.repo::default::file://${deploy.temporaryArtifactDir} </altDeploymentRepository> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-source-plugin</artifactId> <version>${maven.plugin.source.version}</version> <executions> <execution> <id>attach-sources</id> <goals> <goal>jar</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>com.github.github</groupId> <artifactId>site-maven-plugin</artifactId> <version>${maven.plugin.site.version}</version> <configuration> <message>${project.groupId}:${project.artifactId}:${project.version}</message> <noJekyll>true</noJekyll> <outputDirectory>${deploy.temporaryArtifactDir}</outputDirectory> <branch>refs/heads/${deploy.branch.name}</branch> <includes> <include>*/**</include> </includes> <excludes> <exclude>demo-app/**</exclude> <exclude>**/demo-app/**</exclude> </excludes> <merge>true</merge> <repositoryName>${deploy.repository.name}</repositoryName> <repositoryOwner>${deploy.repository.owner}</repositoryOwner> <server>github</server> </configuration> <executions> <execution> <goals> <goal>site</goal> </goals> <phase>deploy</phase> </execution> </executions> </plugin> ... </plugins> </build> ... </project>
-
-
Опубликуем артефакты.
Достаточно запустить команду
mvn clean deploy
. В итоге будет следующая картина:Репозиторий после запуска команды Файлы включенные в коммит Проект собрался и все артефакты теперь лежат в нашем репозитории на GitHub.
Для возможности использовать созданные артефакты необходимо добавить свой репозиторий в проект:
<repositories> ... <repository> <id>github-maven-repo</id> <name>GitHub Maven Repository</name> <url>https://raw.githubusercontent.com/*username*/*repo-name*/master/</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> </repository> </repositories>
Заключение
Прочитав эту статью вы научились публиковать артефакты в собственный GitHub репозиторий и использовать их в своих проектах.
Если данная статья будет интересна, напишу статью об автоматизации процесса публикации с использованием GitHub Actions.
l1lo4ka
Спасибо! успехов Вам с проектом!