Menggunakan Tindakan Gradle dan Github untuk Menerbitkan Projek Java ke Repositori Pusat Maven Sonatype

Dalam artikel ini, saya ingin melihat dengan lebih dekat proses penerbitan artifak Java dari awal melalui Github Actions ke Sonatype Maven Central Repository menggunakan pembina Gradle.

Saya memutuskan untuk menulis artikel ini kerana kekurangan tutorial biasa di satu tempat. Semua maklumat itu perlu dikumpul sekeping demi sekeping dari pelbagai sumber, lebih-lebih lagi, tidak sepenuhnya segar. Siapa peduli, selamat datang di bawah kucing.

Mencipta repositori dalam Sonatype

Langkah pertama ialah membuat repositori dalam Sonatype Maven Central. Untuk ini kita pergi di sini, daftar dan buat tugas baharu, meminta kami membuat repositori. Kami memandu dalam kereta kami KumpulanId projek, URL Projek pautan projek dan URL SCM pautan ke sistem kawalan versi di mana projek itu berada. KumpulanId di sini hendaklah dalam bentuk com.example, com.example.domain, com.example.testsupport, dan juga boleh dalam bentuk pautan ke github anda: github.com/nama pengguna anda -> io.github.namapengguna anda. Walau apa pun, anda perlu mengesahkan pemilikan domain atau profil ini. Jika anda menetapkan profil github, anda akan diminta untuk mencipta repositori awam dengan nama yang dikehendaki.

Beberapa ketika selepas pengesahan, GroupId anda akan dibuat dan kami boleh meneruskan ke langkah seterusnya, konfigurasi Gradle.

Mengkonfigurasi Gradle

Pada masa penulisan, saya tidak menemui pemalam Gradle yang boleh membantu menerbitkan artifak. ini satu-satunya pemalam yang saya temui, bagaimanapun, penulis enggan menyokongnya lagi. Oleh itu, saya memutuskan untuk melakukan semuanya sendiri, kerana tidak terlalu sukar untuk melakukan ini.

Perkara pertama yang perlu difikirkan ialah keperluan Sonatype untuk penerbitan. Mereka adalah berikut:

  • Ketersediaan kod sumber dan JavaDoc, iaitu. mesti hadir -sources.jar ΠΈ-javadoc.jar fail. Seperti yang dinyatakan dalam dokumentasi, jika tidak mungkin untuk menyediakan kod sumber atau dokumentasi, anda boleh membuat tiruan -sources.jar atau -javadoc.jar dengan README ringkas di dalam untuk lulus ujian.
  • Semua fail mesti ditandatangani dengan GPG/PGPdan .asc fail yang mengandungi tandatangan mesti disertakan untuk setiap fail.
  • ketersediaan pom fail
  • Nilai yang betul groupId, artifactId ΠΈ version. Versi boleh menjadi rentetan sewenang-wenang dan tidak boleh berakhir dengan -SNAPSHOT
  • Kehadiran diperlukan name, description ΠΈ url
  • Kehadiran maklumat mengenai lesen, pembangun dan sistem kawalan versi

Ini adalah peraturan asas yang mesti dipatuhi semasa menerbitkan. Maklumat penuh tersedia di sini.

Kami melaksanakan keperluan ini dalam build.gradle fail. Mula-mula, mari tambah semua maklumat yang diperlukan tentang pembangun, lesen, sistem kawalan versi, dan juga tetapkan url, nama dan perihalan projek. Mari tulis kaedah mudah untuk ini:

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]'
                }
            }
        }
    }
}

Seterusnya, anda perlu menyatakan bahawa semasa perhimpunan yang dihasilkan -sources.jar ΠΈ-javadoc.jar fail. Untuk bahagian ini java anda perlu menambah yang berikut:

java {
    withJavadocJar()
    withSourcesJar()
}

Mari kita beralih kepada keperluan terakhir, menyediakan tandatangan GPG/PGP. Untuk melakukan ini, sambungkan pemalam signing:

plugins {
    id 'signing'
}

Dan tambah bahagian:

signing {
    sign publishing.publications
}

Akhir sekali, mari tambah bahagian 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
            }
        }
    }
}

ia adalah sonatypeNama pengguna ΠΈ sonatypePassword pembolehubah yang mengandungi log masuk dan kata laluan yang dibuat semasa pendaftaran pada sonatype.org.

Oleh itu final build.gradle akan kelihatan seperti ini:

Kod build.gradle penuh

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]'
                }
            }
        }
    }
}

Saya ingin ambil perhatian bahawa kita mendapat versi daripada pembolehubah persekitaran: System.getenv('RELEASE_VERSION'). Kami akan mendedahkannya semasa pemasangan dan mengambilnya daripada nama tag.

Penjanaan kunci PGP

Salah satu keperluan Sonatype ialah semua fail ditandatangani dengan kunci GPG/PGP. Untuk ini kita pergi di sini dan muat turun utiliti GnuPG untuk sistem pengendalian anda.

  • Kami menjana pasangan kunci: gpg --gen-key, masukkan nama pengguna, e-mel, dan juga tetapkan kata laluan.
  • Kami mengetahui id kunci kami dengan arahan: gpg --list-secret-keys --keyid-format short. Id akan ditentukan selepas garis miring, contohnya: rsa2048/9B695056
  • Menerbitkan kunci awam ke pelayan https://keys.openpgp.org perintah: gpg --keyserver [https://keys.openpgp.org](https://keys.openpgp.org/) --send-keys 9B695056
  • Kami mengeksport kunci rahsia ke tempat yang sewenang-wenangnya, kami akan memerlukannya pada masa hadapan: gpg --export-secret-key 9B695056 > D:\gpg\9B695056.gpg

Menyediakan Tindakan Github

Mari kita beralih ke peringkat akhir, sediakan binaan dan terbitkan automatik menggunakan Tindakan Github.
Tindakan Github ialah ciri yang membolehkan anda mengautomasikan aliran kerja dengan melaksanakan kitaran CI / CD penuh. Bina, uji dan gunakan boleh dicetuskan oleh pelbagai peristiwa: tolak kod, penciptaan keluaran atau isu. Fungsi ini adalah percuma untuk repositori awam.

Dalam bahagian ini, saya akan menunjukkan kepada anda cara untuk menyediakan binaan dan tolak kod dan gunakan ke repositori Sonatype semasa dikeluarkan, serta menyediakan rahsia.

Kami menetapkan rahsia

Untuk pemasangan dan penggunaan automatik, kami memerlukan beberapa nilai rahsia, seperti id kunci, kata laluan yang kami masukkan semasa menjana kunci, kunci PGP itu sendiri dan log masuk/kata laluan Sonatype. Anda boleh menetapkannya dalam bahagian khas dalam tetapan repositori:

Menggunakan Tindakan Gradle dan Github untuk Menerbitkan Projek Java ke Repositori Pusat Maven Sonatype

Kami menetapkan pembolehubah berikut:

  • SONATYPE_USERNAME / SONATYPE_PASSWORD - log masuk / kata laluan yang kami masukkan semasa mendaftar dengan Sonatype
  • SIGNING_KEYID/SIGNING_PASSWORD β€” ID kunci PGP dan kata laluan ditetapkan semasa penjanaan.

Saya ingin membincangkan pembolehubah GPG_KEY_CONTENTS dengan lebih terperinci. Hakikatnya ialah untuk penerbitan kita memerlukan kunci PGP peribadi. Untuk menyiarkannya dalam rahsia, saya menggunakan arahan dan tambahan membuat beberapa tindakan.

  • Mari menyulitkan kunci kami dengan gpg: gpg --symmetric --cipher-algo AES256 9B695056.gpgdengan memasukkan kata laluan. Ia harus diletakkan dalam pembolehubah: SECRET_PASSPHRASE
  • Mari menterjemah kunci disulitkan yang diterima ke dalam bentuk teks menggunakan base64: base64 9B695056.gpg.gpg > 9B695056.txt. Kandungan akan diletakkan dalam pembolehubah: GPG_KEY_CONTENTS.

Bina persediaan apabila menolak kod dan mencipta PR

Mula-mula anda perlu membuat folder dalam akar projek anda: .github/workflows.

Di dalamnya, tandakan fail, sebagai contoh, gradle-ci-build.yml dengan kandungan berikut:

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

Aliran kerja ini akan dilaksanakan apabila menolak ke cawangan master, dev ΠΈ testing, juga semasa membuat permintaan tarik.

Bahagian kerja menentukan langkah-langkah yang akan dilaksanakan pada acara yang ditentukan. Dalam kes ini, kami akan membina versi terkini ubuntu, menggunakan Java 8, dan juga menggunakan pemalam untuk Gradle eskatos/gradle-command-action@v1yang, menggunakan versi terbaharu pembina, akan menjalankan arahan yang dinyatakan dalam arguments. Pembolehubah secrets.SONATYPE_USERNAME ΠΈ secrets.SONATYPE_PASSWORD inilah rahsia yang kami tanya tadi.

Hasil binaan akan ditunjukkan dalam tab Tindakan:

Menggunakan Tindakan Gradle dan Github untuk Menerbitkan Projek Java ke Repositori Pusat Maven Sonatype

Pasang secara automatik apabila keluaran baharu dikeluarkan

Mari buat fail aliran kerja yang berasingan untuk autodeploy 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}}

Fail itu hampir sama dengan yang sebelumnya, kecuali untuk peristiwa di mana ia akan dicetuskan. Dalam kes ini, ini ialah acara mencipta teg dengan nama bermula dengan v.

Sebelum menggunakan, kita perlu mengekstrak kunci PGP daripada rahsia dan meletakkannya dalam akar projek, serta menyahsulitnya. Seterusnya, kita perlu menetapkan pembolehubah persekitaran khas RELEASE_VERSION yang kita rujuk gradle.build fail. Semua ini dilakukan dalam bahagian Prepare to publish. Kami mendapatkan kunci kami daripada pembolehubah GPG_KEY_CONTENTS, menterjemahkannya ke dalam fail gpg, kemudian menyahsulitnya dengan meletakkannya dalam fail secret.gpg.

Seterusnya, kita beralih kepada pembolehubah khas GITHUB_REF, daripadanya kita boleh mendapatkan versi yang kita tetapkan semasa membuat teg. Pembolehubah ini adalah relevan dalam kes ini. refs/tags/v0.0.2 dari mana kami memotong 11 aksara pertama untuk mendapatkan versi tertentu. Seterusnya, kami menggunakan arahan Gradle standard untuk penerbitan: test publish

Menyemak keputusan penggunaan dalam repositori Sonatype

Setelah keluaran dibuat, aliran kerja yang diterangkan dalam bahagian sebelumnya harus bermula. Untuk melakukan ini, buat keluaran:

Menggunakan Tindakan Gradle dan Github untuk Menerbitkan Projek Java ke Repositori Pusat Maven Sonatype

nama tag mesti bermula dengan v. Jika, selepas mengklik Terbitkan keluaran, aliran kerja berjaya diselesaikan, kita boleh pergi ke Sonatype Nexus memastikan:

Menggunakan Tindakan Gradle dan Github untuk Menerbitkan Projek Java ke Repositori Pusat Maven Sonatype

Artifak itu muncul dalam repositori Pementasan. Ia serta-merta muncul dalam status Buka, kemudian ia mesti dipindahkan secara manual ke status Tutup dengan menekan butang yang sesuai. Selepas menyemak bahawa semua keperluan dipenuhi, artifak masuk ke status Tutup dan tidak lagi tersedia untuk pengubahsuaian. Dalam borang ini, ia akan berakhir di MavenCentral. Jika semuanya baik, anda boleh menekan butang Lepaskan, dan artifak akan berakhir dalam repositori Sonatype.

Agar artifak dapat masuk ke MavenCentral, anda perlu memintanya dalam tugas yang kami buat pada awalnya. Anda hanya perlu melakukan ini sekali, jadi kami menerbitkan buat kali pertama. Pada masa-masa berikutnya, ini tidak diperlukan, semuanya akan disegerakkan secara automatik. Mereka menghidupkan penyegerakan untuk saya dengan cepat, tetapi mengambil masa kira-kira 5 hari untuk artifak tersedia di MavenCentral.

Itu sahaja, kami telah menerbitkan artifak kami di MavenCentral.

Pautan berguna

  • serupa artikel, hanya terbitkan melalui maven
  • Pemeringkatan repositori Sonatype
  • Jira Sonatype untuk mencipta tugasan
  • Contoh repositori di mana semuanya telah disediakan

Sumber: www.habr.com