Истифодаи амалҳои Gradle ва Github барои интишори лоиҳаи Java дар анбори марказии Sonatype Maven

Дар ин мақола, ман мехоҳам ба раванди интишори артефакти Java аз сифр тавассути Github Actions то анбори марказии Sonatype Maven бо истифода аз созандаи Gradle муфассал назар кунам.

Ман тасмим гирифтам, ки ин мақоларо аз сабаби дар як ҷо мавҷуд набудани дарси муқаррарӣ нависам. Ҳама маълумотро қисм ба қисм аз сарчашмаҳои гуногун ҷамъоварӣ кардан лозим буд, илова бар ин, на комилан тоза. Кӣ ғамхорӣ мекунад, дар зери гурба хуш омадед.

Эҷоди як анбор дар Sonatype

Қадами аввал ин сохтани анбор дар Sonatype Maven Central мебошад. Барои ин мо меравем дар ин ҷо, сабти ном кунед ва вазифаи нав эҷод кунед ва аз мо хоҳиш кунед, ки анбор эҷод кунед. Мо дар мошинамон мошин меронем GroupId лоиҳа, URL-и лоиҳа пайванди лоиҳа ва URL-и SCM пайванд ба системаи идоракунии версия, ки дар он лоиҳа ҷойгир аст. GroupId ин ҷо бояд дар шакли com.example, com.example.domain, com.example.testsupport бошад ва инчунин метавонад дар шакли истинод ба github-и шумо бошад: github.com/yurusername -> io.github. номи шумо. Дар ҳар сурат, шумо бояд соҳиби ин домен ё профилро тафтиш кунед. Агар шумо профили github-ро муайян карда бошед, аз шумо хоҳиш карда мешавад, ки як анбори ҷамъиятӣ бо номи дилхоҳ эҷод кунед.

Чанде пас аз тасдиқ, GroupId-и шумо эҷод мешавад ва мо метавонем ба қадами оянда, конфигуратсияи Gradle гузарем.

Танзими Gradle

Ҳангоми навиштан ман плагинҳои Gradle наёфтам, ки метавонанд дар нашри артефакт кӯмак кунанд. ин ягона плагин, ки ман пайдо кардам, аммо муаллиф аз дастгирии минбаъдаи он худдорӣ кард. Аз ин рӯ, ман қарор додам, ки ҳама чизро худам иҷро кунам, зеро ин кор душвор нест.

Аввалин чизе, ки бояд муайян кард, талаботи Sonatype барои нашр аст. Онҳо инҳоянд:

  • Мавҷудияти рамзҳои манбаъ ва JavaDoc, яъне. бояд иштирок намояд -sources.jar и-javadoc.jar файлҳо. Тавре ки дар ҳуҷҷатҳо гуфта шудааст, агар пешниҳоди рамзҳои манбаъ ё ҳуҷҷатҳо имконнопазир бошад, шумо метавонед як dummy созед. -sources.jar ё -javadoc.jar бо README оддӣ дар дохили барои гузаштан аз санҷиш.
  • Ҳама файлҳо бояд бо имзо карда шаванд GPG/PGPва .asc файли дорои имзо бояд барои ҳар як файл дохил карда шавад.
  • дастрас pom файл
  • Арзишҳои дуруст groupId, artifactId и version. Версия метавонад як сатри ихтиёрӣ бошад ва бо он хотима ёфта наметавонад -SNAPSHOT
  • Ҳузур талаб карда мешавад name, description и url
  • Мавҷудияти маълумот дар бораи иҷозатнома, таҳиягарон ва системаи идоракунии версия

Инҳо қоидаҳои асосӣ мебошанд, ки ҳангоми нашр бояд риоя шаванд. Маълумоти пурра дастрас аст дар ин ҷо.

Мо ин талаботро дар build.gradle файл. Аввалан, биёед тамоми маълумоти заруриро дар бораи таҳиягарон, иҷозатномаҳо, системаи идоракунии версия илова кунем ва инчунин URL, ном ва тавсифи лоиҳаро муқаррар кунем. Биёед як усули оддиро барои ин нависед:

def customizePom(pom) {
    pom.withXml {
        def root = asNode()

        root.dependencies.removeAll { dep ->
            dep.scope == "test"
        }

        root.children().last() + {
            resolveStrategy = DELEGATE_FIRST

            description 'Some description of artifact'
            name 'Artifct name'
            url 'https://github.com/login/projectname'
            organization {
                name 'com.github.login'
                url 'https://github.com/login'
            }
            issueManagement {
                system 'GitHub'
                url 'https://github.com/login/projectname/issues'
            }
            licenses {
                license {
                    name 'The Apache License, Version 2.0'
                    url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
                }
            }
            scm {
                url 'https://github.com/login/projectname'
                connection 'scm:https://github.com/login/projectname.git'
                developerConnection 'scm:git://github.com/login/projectname.git'
            }
            developers {
                developer {
                    id 'dev'
                    name 'DevName'
                    email '[email protected]'
                }
            }
        }
    }
}

Баъдан, шумо бояд муайян кунед, ки дар ҷараёни ҷамъомад тавлидшуда -sources.jar и-javadoc.jar файлҳо. Барои ин бахш java шумо бояд зеринро илова кунед:

java {
    withJavadocJar()
    withSourcesJar()
}

Биёед ба талаботи охирин, насб кардани имзои GPG/PGP гузарем. Барои ин, плагинро пайваст кунед signing:

plugins {
    id 'signing'
}

Ва як бахш илова кунед:

signing {
    sign publishing.publications
}

Дар охир, биёед як бахш илова кунем publishing:

publishing {
    publications {
        mavenJava(MavenPublication) {
            customizePom(pom)
            groupId group
            artifactId archivesBaseName
            version version

            from components.java
        }
    }
    repositories {
        maven {
            url "https://oss.sonatype.org/service/local/staging/deploy/maven2"
            credentials {
                username sonatypeUsername
                password sonatypePassword
            }
        }
    }
}

Ин аст, sonatype номи корбар и sonatypePassword тағирёбандаҳое, ки дорои логин ва пароле мебошанд, ки ҳангоми бақайдгирӣ сохта шудаанд sonatype.org.

Ҳамин тариқ финал build.gradle чунин ба назар мерасад:

Рамзи пурраи build.gradle

plugins {
    id 'java'
    id 'maven-publish'
    id 'signing'
}

java {
    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8
    withJavadocJar()
    withSourcesJar()
}

group 'io.github.githublogin'
archivesBaseName = 'projectname'
version = System.getenv('RELEASE_VERSION') ?: "0.0.1"

repositories {
    mavenCentral()
}

dependencies {
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.5.2'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.5.2'
}

test {
    useJUnitPlatform()
}

jar {
    from sourceSets.main.output
    from sourceSets.main.allJava
}

signing {
    sign publishing.publications
}

publishing {
    publications {
        mavenJava(MavenPublication) {
            customizePom(pom)
            groupId group
            artifactId archivesBaseName
            version version

            from components.java
        }
    }
    repositories {
        maven {
            url "https://oss.sonatype.org/service/local/staging/deploy/maven2"
            credentials {
                username sonatypeUsername
                password sonatypePassword
            }
        }
    }
}

def customizePom(pom) {
    pom.withXml {
        def root = asNode()

        root.dependencies.removeAll { dep ->
            dep.scope == "test"
        }

        root.children().last() + {
            resolveStrategy = DELEGATE_FIRST

            description 'Some description of artifact'
            name 'Artifct name'
            url 'https://github.com/login/projectname'
            organization {
                name 'com.github.login'
                url 'https://github.com/githublogin'
            }
            issueManagement {
                system 'GitHub'
                url 'https://github.com/githublogin/projectname/issues'
            }
            licenses {
                license {
                    name 'The Apache License, Version 2.0'
                    url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
                }
            }
            scm {
                url 'https://github.com/githublogin/projectname'
                connection 'scm:https://github.com/githublogin/projectname.git'
                developerConnection 'scm:git://github.com/githublogin/projectname.git'
            }
            developers {
                developer {
                    id 'dev'
                    name 'DevName'
                    email '[email protected]'
                }
            }
        }
    }
}

Ман мехоҳам қайд намоям, ки мо версияро аз тағирёбандаи муҳити зист мегирем: System.getenv('RELEASE_VERSION'). Мо онро ҳангоми васлкунӣ фош мекунем ва онро аз номи тег мегирем.

Насли калиди PGP

Яке аз талаботи Sonatype ин аст, ки ҳама файлҳо бо калиди GPG/PGP имзо карда шаванд. Барои ин мо меравем дар ин ҷо ва утилитаи GnuPG-ро барои системаи оператсионии худ зеркашӣ кунед.

  • Мо як ҷуфти калидиро тавлид мекунем: gpg --gen-key, номи корбар, почтаи электрониро ворид кунед ва инчунин парол таъин кунед.
  • Мо мефаҳмем id калиди мо бо фармон: gpg --list-secret-keys --keyid-format short. Идентификатсия пас аз рахи хат муайян карда мешавад, масалан: rsa2048/9B695056
  • Интишори калиди ҷамъиятӣ ба сервер https://keys.openpgp.org бо фармон: gpg --keyserver [https://keys.openpgp.org](https://keys.openpgp.org/) --send-keys 9B695056
  • Мо калиди махфиро ба ҷои худсарона содир мекунем, дар оянда ба мо лозим меояд: gpg --export-secret-key 9B695056 > D:\gpg\9B695056.gpg

Танзими амалҳои Github

Биёед ба марҳилаи ниҳоӣ гузарем, бо истифода аз Github Actions сохтан ва худкор интишор кунем.
Github Actions як хусусиятест, ки ба шумо имкон медиҳад, ки ҷараёни корро тавассути татбиқи як давраи пурраи CI / CD автоматӣ кунед. Сохтан, санҷидан ва ҷойгиркунӣ метавонад аз ҷониби рӯйдодҳои гуногун ба амал ояд: пахши код, эҷоди релиз ё мушкилот. Ин функсия барои анборҳои ҷамъиятӣ комилан ройгон аст.

Дар ин бахш, ман ба шумо нишон медиҳам, ки чӣ гуна насб кардан ва пахш кардани код ва ҷойгир кардани анбори Sonatype ҳангоми баровардан, инчунин танзим кардани асрор.

Мо сирҳоро муқаррар кардем

Барои васлкунӣ ва ҷойгиркунии худкор ба мо як қатор арзишҳои махфӣ лозим аст, ба монанди ID калид, пароле, ки мо ҳангоми тавлиди калид ворид кардаем, худи калиди PGP ва логин/пароли Sonatype. Шумо метавонед онҳоро дар як бахши махсус дар танзимоти анбор насб кунед:

Истифодаи амалҳои Gradle ва Github барои интишори лоиҳаи Java дар анбори марказии Sonatype Maven

Мо тағирёбандаҳои зеринро муқаррар мекунем:

  • SONATYPE_USERNAME / SONATYPE_PASSWORD - логин / парол, ки мо ҳангоми сабти ном бо Sonatype ворид кардем
  • SIGNING_KEYID/SIGNING_PASSWORD — ID калиди PGP ва парол ҳангоми тавлид муқаррар карда мешавад.

Ман мехоҳам дар бораи тағирёбандаи GPG_KEY_CONTENTS муфассалтар таваққуф кунам. Далели он аст, ки барои нашр ба мо калиди хусусии PGP лозим аст. Барои интишори он дар асрор, ман истифода бурдам таълим ва ба таври илова як катор чорабинихоро ба чо овард.

  • Биёед калиди худро бо gpg рамзгузорӣ кунем: gpg --symmetric --cipher-algo AES256 9B695056.gpgбо ворид кардани парол. Он бояд дар як тағирёбанда ҷойгир карда шавад: SECRET_PASSPHRASE
  • Биёед калиди рамзгузории гирифташударо бо истифода аз base64 ба шакли матнӣ тарҷума кунем: base64 9B695056.gpg.gpg > 9B695056.txt. Мундариҷа дар тағирёбанда ҷойгир карда мешавад: GPG_KEY_CONTENTS.

Ҳангоми пахш кардани код ва эҷоди PR насб созед

Аввалан шумо бояд дар решаи лоиҳаи худ папка эҷод кунед: .github/workflows.

Дар он файлро қайд кунед, масалан, gradle-ci-build.yml бо мазмуни зерин:

name: build

on:
  push:
    branches:
      - master
      - dev
      - testing
  pull_request:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v1
      - name: Set up JDK 8
        uses: actions/setup-java@v1
        with:
          java-version: 8

      - name: Build with Gradle
        uses: eskatos/gradle-command-action@v1
        with:
          gradle-version: current
          arguments: build -PsonatypeUsername=${{secrets.SONATYPE_USERNAME}} -PsonatypePassword=${{secrets.SONATYPE_PASSWORD}}

Ин ҷараёни корӣ ҳангоми пахш кардан ба филиалҳо иҷро карда мешавад master, dev и testing, инчунин ҳангоми эҷоди дархостҳои кашидан.

Бахши корҳо қадамҳоеро, ки бояд дар рӯйдодҳои мушаххас иҷро шаванд, муайян мекунад. Дар ин ҳолат, мо дар версияи охирини ubuntu бунёд мекунем, Java 8-ро истифода мебарем ва инчунин плагинро барои Gradle истифода мебарем. eskatos/gradle-command-action@v1ки бо истифода аз версияи охирини бинокор фармонҳои дар arguments. Тағйирёбандаҳо secrets.SONATYPE_USERNAME и secrets.SONATYPE_PASSWORD ин асрорест, ки мо пештар пурсидем.

Натиҷаҳои сохтмон дар ҷадвали Амалҳо инъикос карда мешаванд:

Истифодаи амалҳои Gradle ва Github барои интишори лоиҳаи Java дар анбори марказии Sonatype Maven

Ҳангоми баровардани версияи нав худкор ҷойгир кунед

Биёед файли ҷараёни кориро барои худкорсозӣ эҷод кунем gradle-ci-publish.yml:

name: publish

on:
  push:
    tags:
      - 'v*'

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v1
      - name: Set up JDK 8
        uses: actions/setup-java@v1
        with:
          java-version: 8

      - name: Prepare to publish
        run: |
          echo '${{secrets.GPG_KEY_CONTENTS}}' | base64 -d > publish_key.gpg
          gpg --quiet --batch --yes --decrypt --passphrase="${{secrets.SECRET_PASSPHRASE}}" 
          --output secret.gpg publish_key.gpg
          echo "::set-env name=RELEASE_VERSION::${GITHUB_REF:11}"

      - name: Publish with Gradle
        uses: eskatos/gradle-command-action@v1
        with:
          gradle-version: current
          arguments: test publish -Psigning.secretKeyRingFile=secret.gpg -Psigning.keyId=${{secrets.SIGNING_KEYID}} -Psigning.password=${{secrets.SIGNING_PASSWORD}} -PsonatypeUsername=${{secrets.SONATYPE_USERNAME}} -PsonatypePassword=${{secrets.SONATYPE_PASSWORD}}

Файл бо файли қаблӣ тақрибан якхела аст, ба истиснои ҳодисае, ки дар он оғоз мешавад. Дар ин ҳолат, ин ҳодисаи эҷоди тег бо ном бо v сар мешавад.

Пеш аз ҷойгиркунӣ, мо бояд калиди PGP-ро аз асрор ҷудо кунем ва онро дар решаи лоиҳа ҷойгир кунем ва инчунин рамзкушоӣ кунем. Баъдан, мо бояд тағирёбандаи махсуси муҳити зистро муқаррар кунем RELEASE_VERSION ки мо ба он ишора мекунем gradle.build файл. Ҳамаи ин дар қисмат анҷом дода мешавад Prepare to publish. Мо калиди худро аз тағирёбандаи GPG_KEY_CONTENTS мегирем, онро ба файли gpg тарҷума мекунем ва пас онро бо гузоштани он дар файл рамзкушо мекунем. secret.gpg.

Баъдан, мо ба тағирёбандаи махсус муроҷиат мекунем GITHUB_REF, ки аз он мо метавонем версияеро гирем, ки ҳангоми сохтани тег муқаррар кардаем. Ин тағирёбанда дар ин ҳолат мувофиқ аст. refs/tags/v0.0.2 ки аз он мо 11 аломати аввалро барои гирифтани версияи мушаххас буридаем. Баъдан, мо фармонҳои стандартии Gradle-ро барои интишор истифода мебарем: test publish

Санҷиши ҷойгиркунӣ дар анбори Sonatype натиҷаҳои

Пас аз таҳияи релиз, ҷараёни кори дар боби қаблӣ тавсифшуда бояд оғоз шавад. Барои ин, як релиз эҷод кунед:

Истифодаи амалҳои Gradle ва Github барои интишори лоиҳаи Java дар анбори марказии Sonatype Maven

номи тег бояд бо v сар шавад. Агар пас аз пахш кардани пахши Нашр, ҷараёни кор бомуваффақият анҷом ёбад, мо метавонем ба Навъи Nexus то боварӣ ҳосил кунед:

Истифодаи амалҳои Gradle ва Github барои интишори лоиҳаи Java дар анбори марказии Sonatype Maven

Артефакт дар анбори Staging пайдо шуд. Он фавран дар ҳолати Кушодан пайдо мешавад, пас он бояд ба таври дастӣ бо пахш кардани тугмаи мувофиқ ба ҳолати пӯшида интиқол дода шавад. Пас аз санҷидани он, ки ҳамаи талаботҳо иҷро мешаванд, артефакт ба ҳолати пӯшида мегузарад ва дигар барои тағир додан дастрас нест. Дар ин шакл, он дар MavenCentral хотима меёбад. Агар ҳама чиз хуб бошад, шумо метавонед тугмаро пахш кунед озод кардан, ва артефакт дар анбори Sonatype хотима меёбад.

Барои он ки артефакт ба MavenCentral ворид шавад, шумо бояд онро дар вазифае, ки мо дар ибтидо офаридаем, пурсед. Шумо бояд ин корро танҳо як маротиба кунед, бинобар ин мо бори аввал нашр мекунем. Дар вақтҳои минбаъда, ин талаб карда намешавад, ҳама чиз ба таври худкор ҳамоҳанг карда мешавад. Онҳо синхронизатсияро барои ман зуд фаъол карданд, аммо барои дастрас шудани артефакт дар MavenCentral тақрибан 5 рӯз лозим шуд.

Ҳамааш ин аст, ки мо артефакти худро дар MavenCentral нашр кардем.

Пайвандҳои муфид

  • Монанд мақола, танҳо тавассути maven нашр кунед
  • Насбкунӣ анбор Сонатип
  • Ҷира Sonatype, ки дар он вазифа эҷод карда мешавад
  • Мисол анборе, ки дар он ҳамааш насб шудааст

Манбаъ: will.com