设置 GitLab CI 将 java 项目上传到 Maven Central

本文面向需要使用 GitLab 在 sonatype 和/或 maven 中央存储库中快速发布产品的 java 开发人员。 在这篇文章中,我将讨论设置 gitlab-runner、gitlab-ci 和 maven-plugin 来解决这个问题。

先决条件:

  • mvn 和 GPG 密钥的安全存储。
  • 安全执行公共 CI 任务。
  • 将工件(发布/快照)上传到公共存储库。
  • 自动检查发布版本以在 Maven 中心发布。
  • 用于将工件上传到多个项目的存储库的通用解决方案。
  • 简单易用。

内容

一般信息

  • 通过 Sonatype OSS 存储库托管服务在 Maven Central 中发布工件的机制的详细描述已在 这篇文章 按用户 古戈尔普勒克斯,所以我会在正确的地方引用这篇文章。
  • 预注册 Sonatype JIRA 并开票以打开存储库(阅读 参考资料 部分以了解更多详细信息 在 Sonatype JIRA 上创建票证)。 打开存储库后,JIRA 的登录名/密码对(以下简称 Sonatype 帐户)将用于将工件上传到 Sonatype nexus。
  • 接下来非常干巴巴地描述生成GPG密钥的过程。 请参阅部分了解更多详细信息 配置 GnuPG 对工件进行签名
  • 如果您使用Linux控制台生成GPG密钥(gnupg/gnupg2),那么您需要安装 RNG-工具 来产生熵。 否则,密钥生成可能需要很长时间。
  • 仓储服务 公开 GPG 密钥

到内容

在 GitLab 中设置部署项目

  • 首先,您需要创建并配置一个项目,其中将存储用于部署工件的管道。 我给我的项目命名简单而不复杂 - 部署
  • 创建存储库后,您需要限制更改存储库的访问。
    转到项目 -> 设置 -> 存储库 -> 受保护的分支。 我们删除所有规则并添加带有通配符 * 的单个规则,该规则仅具有维护者角色的用户的推送和合并权限。 该规则将适用于该项目及其所属组的所有用户。
    设置 GitLab CI 将 java 项目上传到 Maven Central
  • 如果有多个维护者,那么最好的解决方案是原则上限制对项目的访问。
    转到项目 -> 设置 -> 常规 -> 可见性、项目功能、权限并将项目可见性设置为 私做.
    我有一个可公开访问的项目,因为我使用自己的 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台机器。 阿鲁巴岛 5 个,伊霍尔岛 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 (可以很简单,因为本地主机有限制)
    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 -> deploy-project -> Settings -> CI/CD -> Runners -> Specific Runners 并复制注册令牌

屏幕

设置 GitLab CI 将 java 项目上传到 Maven Central

  • 注册跑步者
    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 -> deploy-project -> Settings -> CI/CD -> Runners -> Specific Runners -> 为此项目激活的 Runners

屏幕

设置 GitLab CI 将 java 项目上传到 Maven Central

  • 新增 分开 服务 /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
  • 我们检查跑步者是否正在跑步。

例子

设置 GitLab CI 将 java 项目上传到 Maven Central

到内容

生成 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 帐户登录

这样就完成了跑步者的设置,您可以继续进行本节 亚搏体育app 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
    设置 GitLab CI 将 java 项目上传到 Maven Central

到内容

设置 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镜像

  • 我们创建一个相当简单的 Dockerfile 来使用所需的 Java 版本运行部署任务。 以下是高山的示例。

    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

到内容

亚搏体育app CI

部署项目

将 .gitlab-ci.yml 文件添加到部署项目的根目录
该脚本提供了两个互斥的部署任务。 分别为特定运行器或共享运行器。

.gitlab-ci.yml

stages:
  - deploy

Specific Runner:
  extends: .java_deploy_template
  # Задача будет выполняться на вашем shell-раннере
  tags:
    - deploy

Shared Runner:
  extends: .java_deploy_template
  # Задача будет выполняться на публичном docker-раннере
  tags:
    - docker
  # Образ из раздела GitLab Runner -> Shared Runner -> Docker
  image: registry.gitlab.com/group/deploy-project:latest
  before_script:
    # Импортируем GPG ключ
    - printf "${GPG_SECRET_KEY}" | gpg --batch --import
    # Сохраняем maven конфигурацию
    - printf "${SETTINGS_SECURITY_XML}" > ~/.m2/settings-security.xml
    - printf "${SETTINGS_XML}" > ~/.m2/settings.xml

.java_deploy_template:
  stage: deploy
  # Задача сработает по триггеру, если передана переменная DEPLOY со значением java
  only:
    variables:
    - $DEPLOY == "java"
  variables:
    # отключаем клонирование текущего проекта
    GIT_STRATEGY: none
  script:
    # Предоставляем возможность хранения пароля в незашифрованном виде
    - git config --global credential.helper store
    # Сохраняем временные креды пользователя gitlab-ci-token
    # Токен работает для всех публичных проектов gitlab.com и для проектов группы
    - echo "https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com" >> ~/.git-credentials
    # Полностью чистим текущую директорию
    - rm -rf .* *
    # Клонируем проект который, будем деплоить в Sonatype Nexus
    - git clone ${DEPLOY_CI_REPOSITORY_URL} .
    # Переключаемся на нужный коммит
    - git checkout ${DEPLOY_CI_COMMIT_SHA} -f
    # Если хоть один pom.xml содержит параметр autoReleaseAfterClose валим сборку.
    # В противном случае есть риск залить сырые артефакты в maven central
    - >
      for pom in $(find . -name pom.xml); do
        if [[ $(grep -q autoReleaseAfterClose "$pom" && echo $?) == 0 ]]; then
          echo "File $pom contains prohibited setting: <autoReleaseAfterClose>";
          exit 1;
        fi;
      done
    # Если параметр DEPLOY_CI_COMMIT_TAG пустой, то принудительно ставим SNAPSHOT-версию
    - >
      if [[ "${DEPLOY_CI_COMMIT_TAG}" != "" ]]; then
        mvn versions:set -DnewVersion=${DEPLOY_CI_COMMIT_TAG}
      else
        VERSION=$(mvn -q -Dexec.executable=echo -Dexec.args='${project.version}' --non-recursive exec:exec)
        if [[ "${VERSION}" == *-SNAPSHOT ]]; then
          mvn versions:set -DnewVersion=${VERSION}
        else
          mvn versions:set -DnewVersion=${VERSION}-SNAPSHOT
        fi
      fi
    # Запускаем задачу на сборку и деплой артефактов
    - mvn clean deploy -DskipTests=true

到内容

Java项目

在要上传到公共存储库的java项目中,您需要添加2个步骤来下载Release和Snapshot版本。

.gitlab-ci.yml

stages:
  - build
  - test
  - verify
  - deploy

<...>

Release:
  extends: .trigger_deploy
  # Запускать задачу только пo тегу.
  only:
    - tags

Snapshot:
  extends: .trigger_deploy
  # Запускаем задачу на публикацию SNAPSHOT версии вручную
  when: manual
  # Не запускать задачу, если проставлен тег.
  except:
    - tags

.trigger_deploy:
  stage: deploy
  variables:
    # Отключаем клонирование текущего проекта
    GIT_STRATEGY: none
    # Ссылка на триггер deploy-задачи
    URL: "https://gitlab.com/api/v4/projects/<deploy project ID>/trigger/pipeline"
    # Переменные deploy-задачи
    POST_DATA: "
      token=${DEPLOY_TOKEN}&
      ref=master&
      variables[DEPLOY]=${DEPLOY}&
      variables[DEPLOY_CI_REPOSITORY_URL]=${CI_REPOSITORY_URL}&
      variables[DEPLOY_CI_PROJECT_NAME]=${CI_PROJECT_NAME}&
      variables[DEPLOY_CI_COMMIT_SHA]=${CI_COMMIT_SHA}&
      variables[DEPLOY_CI_COMMIT_TAG]=${CI_COMMIT_TAG}
      "
  script:
    # Не использую cURL, так как с флагами --fail --show-error
    # он не выводит тело ответа, если HTTP код 400 и более 
    - wget --content-on-error -qO- ${URL} --post-data ${POST_DATA}

在此解决方案中,我更进一步,决定对 Java 项目使用一个 CI 模板。

更多细节

我创建了一个单独的项目 gitlab-ci 我在其中放置了 java 项目的 CI 模板 常见的.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-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-插件

配置:

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

如果您有一个多模块项目并且不需要将特定模块上传到存储库,那么您需要添加 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).
  • 自动发布检查上传到mavencentral

到内容

导致

发布快照版本

构建项目时,可以手动启动任务将 SNAPSHOT 版本下载到 nexus

设置 GitLab CI 将 java 项目上传到 Maven Central

当此任务启动时,会触发部署项目中的相应任务(例子).

修剪原木

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 在您的帐户下。

设置 GitLab CI 将 java 项目上传到 Maven Central

到内容

发布发布版本

当安装标签时,会自动触发deploy项目中相应的任务将release版本下载到nexus(例子).

设置 GitLab CI 将 java 项目上传到 Maven Central

最好的部分是,关闭释放会在 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] ------------------------------------------------------------------------

结果,我们只剩下一个选择。 要么删除这个版本,要么发布它。

设置 GitLab CI 将 java 项目上传到 Maven Central

发布后,一段时间后,工件将出现在 设置 GitLab CI 将 java 项目上传到 Maven Central

越位

对我来说,maven 索引其他公共存储库是一个发现。
我必须添加 robots.txt 因为它索引了我的旧存储库。

到内容

结论

我们有什么

  • 一个单独的部署项目,您可以在其中实现多个 CI 任务,以将工件上传到各种开发语言的公共存储库。
  • Deploy 项目与外部干扰隔离,只能由具有 Owner 和Maintainer 角色的用户进行更改。
  • 具有“热”缓存的单独特定运行器,仅运行部署任务。
  • 在公共存储库中发布快照/发布版本。
  • 自动检查发布版本是否准备好在 Maven Central 中发布。
  • 防止在 Maven Central 中自动发布“原始”版本。
  • “点击”构建和发布快照版本。
  • 用于获取快照/发布版本的单个存储库。
  • 用于构建/测试/发布 java 项目的通用管道。

设置 GitLab CI 并不像乍看起来那么复杂。 在交钥匙的基础上设置几次 CI 就足够了,现在您在这方面远非业余。 而且,GitLab 文档非常冗余。 不要害怕迈出第一步。 路出现在行走的人的脚步下(我不记得是谁说的:)

我会很高兴收到反馈。

在下一篇文章中,如果您只有一个 shell 运行程序,我将讨论如何配置 GitLab CI 以竞争性地运行带有集成测试的任务(使用 docker-compose 运行测试中的服务)。

到内容

来源: habr.com

添加评论