Menggunakan Tindakan Gradle dan Github untuk Memublikasikan Proyek Java ke Sonatype Maven Central Repository

Pada artikel ini, saya ingin melihat secara mendetail proses penerbitan artefak Java dari awal melalui Github Actions ke Sonatype Maven Central Repository menggunakan Gradle builder.

Saya memutuskan untuk menulis artikel ini karena kurangnya tutorial normal di satu tempat. Semua informasi harus dikumpulkan sepotong demi sepotong dari berbagai sumber, apalagi tidak sepenuhnya segar. Siapa peduli, selamat datang di bawah kucing.

Membuat repositori di Sonatype

Langkah pertama adalah membuat repositori di Sonatype Maven Central. Untuk ini kita pergi di sini, daftar dan buat tugas baru, minta kami membuat repositori. Kami mengemudi di milik kami Id Grup proyek, URL proyek tautan proyek dan URL SCM tautan ke sistem kontrol versi tempat proyek berada. Id Grup disini harus berbentuk com.example, com.example.domain, com.example.testsupport, dan bisa juga berupa link ke github anda: github.com/namapenggunaAnda -> io.github.namapenggunaAnda. Bagaimanapun, Anda harus memverifikasi kepemilikan domain atau profil ini. Jika Anda menentukan profil github, Anda akan diminta untuk membuat repositori publik dengan nama yang diinginkan.

Beberapa saat setelah konfirmasi, GroupId Anda akan dibuat dan kita dapat melanjutkan ke langkah berikutnya, konfigurasi Gradle.

Konfigurasi Gradle

Pada saat penulisan, saya tidak menemukan plugin Gradle yang dapat membantu menerbitkan artefak. Itu satu-satunya plugin yang saya temukan, bagaimanapun, penulis menolak untuk mendukungnya lebih lanjut. Oleh karena itu, saya memutuskan untuk melakukan semuanya sendiri, karena tidak terlalu sulit untuk melakukannya.

Hal pertama yang harus diketahui adalah persyaratan Sonatype untuk penerbitan. Mereka adalah sebagai berikut:

  • Ketersediaan kode sumber dan JavaDoc, yaitu. harus hadir -sources.jar ΠΈ-javadoc.jar file. Seperti yang dinyatakan dalam dokumentasi, jika tidak memungkinkan untuk memberikan kode sumber atau dokumentasi, Anda dapat membuat dummy -sources.jar ΠΈΠ»ΠΈ -javadoc.jar dengan README sederhana di dalam untuk lulus ujian.
  • Semua file harus ditandatangani GPG/PGPDan .asc file yang berisi tanda tangan harus disertakan untuk setiap file.
  • tersedianya pom mengajukan
  • Nilai yang benar groupId, artifactId ΠΈ version. Versi dapat berupa string arbitrer dan tidak dapat diakhiri dengan -SNAPSHOT
  • Diperlukan kehadiran name, description ΠΈ url
  • Kehadiran informasi tentang lisensi, pengembang, dan sistem kontrol versi

Ini adalah aturan dasar yang harus diikuti saat menerbitkan. Informasi lengkap tersedia di sini.

Kami menerapkan persyaratan ini di build.gradle mengajukan. Pertama, mari tambahkan semua informasi yang diperlukan tentang pengembang, lisensi, sistem kontrol versi, dan juga atur url, nama, dan deskripsi proyek. Mari kita tulis metode sederhana 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]'
                }
            }
        }
    }
}

Selanjutnya, Anda perlu menentukan bahwa selama perakitan dihasilkan -sources.jar ΠΈ-javadoc.jar file. Untuk bagian ini java anda perlu menambahkan yang berikut ini:

java {
    withJavadocJar()
    withSourcesJar()
}

Mari beralih ke persyaratan terakhir, menyiapkan tanda tangan GPG/PGP. Untuk melakukan ini, sambungkan plugin signing:

plugins {
    id 'signing'
}

Dan tambahkan bagian:

signing {
    sign publishing.publications
}

Akhirnya, mari tambahkan bagian 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
            }
        }
    }
}

Di sini sonatypeNama Pengguna ΠΈ sonatypePassword variabel yang berisi login dan kata sandi yang dibuat saat pendaftaran aktif sonatype.org.

Demikian finalnya build.gradle akan terlihat seperti ini:

Kode build.gradle lengkap

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 mencatat bahwa kami mendapatkan versi dari variabel lingkungan: System.getenv('RELEASE_VERSION'). Kami akan memaparkannya selama perakitan dan mengambilnya dari nama tag.

pembuatan kunci PGP

Salah satu persyaratan Sonatype adalah semua file ditandatangani dengan kunci GPG/PGP. Untuk ini kita pergi di sini dan unduh utilitas GnuPG untuk sistem operasi Anda.

  • Kami menghasilkan pasangan kunci: gpg --gen-key, masukkan nama pengguna, email, dan juga atur kata sandi.
  • Mencari tahu id kunci kita dengan perintah: gpg --list-secret-keys --keyid-format short. Id akan ditentukan setelah garis miring, misalnya: rsa2048/9B695056
  • Menerbitkan kunci publik ke server https://keys.openpgp.org dengan perintah: gpg --keyserver [https://keys.openpgp.org](https://keys.openpgp.org/) --send-keys 9B695056
  • Kami mengekspor kunci rahasia ke tempat yang sewenang-wenang, kami akan membutuhkannya di masa mendatang: gpg --export-secret-key 9B695056 > D:\gpg\9B695056.gpg

Menyiapkan Tindakan Github

Mari beralih ke tahap akhir, menyiapkan build, dan menerbitkan secara otomatis menggunakan Github Actions.
Github Actions adalah fitur yang memungkinkan Anda mengotomatiskan alur kerja dengan mengimplementasikan siklus CI/CD penuh. Bangun, uji, dan terapkan dapat dipicu oleh berbagai peristiwa: dorongan kode, pembuatan rilis, atau masalah. Fungsionalitas ini benar-benar gratis untuk repositori publik.

Di bagian ini, saya akan menunjukkan cara menyiapkan kode build dan push serta menerapkan ke repositori Sonatype saat rilis, serta menyiapkan rahasia.

Kami mengatur rahasia

Untuk perakitan dan penerapan otomatis, kami memerlukan sejumlah nilai rahasia, seperti id kunci, kata sandi yang kami masukkan saat membuat kunci, kunci PGP itu sendiri, dan login/kata sandi Sonatype. Anda dapat mengaturnya di bagian khusus di pengaturan repositori:

Menggunakan Tindakan Gradle dan Github untuk Memublikasikan Proyek Java ke Sonatype Maven Central Repository

Kami menetapkan variabel berikut:

  • SONATYPE_USERNAME / SONATYPE_PASSWORD - login / kata sandi yang kami masukkan saat mendaftar dengan Sonatype
  • SIGNING_KEYID/SIGNING_PASSWORD β€” ID kunci dan kata sandi PGP ditetapkan selama pembuatan.

Saya ingin membahas variabel GPG_KEY_CONTENTS lebih terinci. Faktanya adalah untuk publikasi kita memerlukan kunci PGP pribadi. Untuk mempostingnya di rahasia, saya menggunakan instruksi dan juga membuat sejumlah tindakan.

  • Mari mengenkripsi kunci kita dengan gpg: gpg --symmetric --cipher-algo AES256 9B695056.gpgdengan memasukkan kata sandi. Itu harus ditempatkan dalam variabel: SECRET_PASSPHRASE
  • Mari terjemahkan kunci terenkripsi yang diterima ke dalam bentuk teks menggunakan base64: base64 9B695056.gpg.gpg > 9B695056.txt. Konten akan ditempatkan dalam variabel: GPG_KEY_CONTENTS.

Bangun penyiapan saat mendorong kode dan membuat PR

Pertama, Anda perlu membuat folder di root proyek Anda: .github/workflows.

Di dalamnya, tandai file, misalnya, gradle-ci-build.yml dengan konten sebagai 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}}

Alur kerja ini akan dijalankan saat mendorong ke cabang master, dev ΠΈ testing, juga saat membuat permintaan tarik.

Bagian pekerjaan menentukan langkah-langkah yang akan dieksekusi pada acara yang ditentukan. Dalam hal ini, kami akan membangun versi terbaru ubuntu, menggunakan Java 8, dan juga menggunakan plugin untuk Gradle eskatos/gradle-command-action@v1yang, menggunakan versi pembuat terbaru, akan menjalankan perintah yang ditentukan di arguments. Variabel secrets.SONATYPE_USERNAME ΠΈ secrets.SONATYPE_PASSWORD ini adalah rahasia yang kami tanyakan sebelumnya.

Hasil build akan tercermin di tab Actions:

Menggunakan Tindakan Gradle dan Github untuk Memublikasikan Proyek Java ke Sonatype Maven Central Repository

Deploy otomatis saat rilis baru dirilis

Mari buat file alur kerja terpisah untuk penerapan otomatis 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}}

File tersebut hampir identik dengan yang sebelumnya, kecuali untuk acara yang akan memicunya. Dalam hal ini, ini adalah acara pembuatan tag dengan nama yang dimulai dengan v.

Sebelum menerapkan, kita perlu mengekstrak kunci PGP dari rahasia dan meletakkannya di root proyek, serta mendekripsinya. Selanjutnya, kita perlu mengatur variabel lingkungan khusus RELEASE_VERSION yang kami rujuk gradle.build mengajukan. Semua ini dilakukan di bagian tersebut Prepare to publish. Kami mendapatkan kunci kami dari variabel GPG_KEY_CONTENTS, menerjemahkannya menjadi file gpg, lalu mendekripsi dengan memasukkannya ke dalam file secret.gpg.

Selanjutnya, kita beralih ke variabel khusus GITHUB_REF, dari situ kita bisa mendapatkan versi yang kita atur saat membuat tag. Variabel ini relevan dalam kasus ini. refs/tags/v0.0.2 dari mana kami memotong 11 karakter pertama untuk mendapatkan versi tertentu. Selanjutnya, kami menggunakan perintah Gradle standar untuk menerbitkan: test publish

Memeriksa hasil penerapan di repositori Sonatype

Setelah rilis dibuat, alur kerja yang dijelaskan di bagian sebelumnya akan dimulai. Untuk melakukan ini, buat rilis:

Menggunakan Tindakan Gradle dan Github untuk Memublikasikan Proyek Java ke Sonatype Maven Central Repository

nama tag harus dimulai dengan v. Jika, setelah mengklik Publikasikan rilis, alur kerja berhasil diselesaikan, kita dapat membuka Nexus Sonatype untuk memastikan:

Menggunakan Tindakan Gradle dan Github untuk Memublikasikan Proyek Java ke Sonatype Maven Central Repository

Artefak muncul di repositori Staging. Itu langsung muncul di status Buka, lalu harus ditransfer secara manual ke status Tutup dengan menekan tombol yang sesuai. Setelah memeriksa bahwa semua persyaratan terpenuhi, artefak masuk ke status Tutup dan tidak lagi tersedia untuk dimodifikasi. Dalam formulir ini, itu akan berakhir di MavenCentral. Jika semuanya baik-baik saja, Anda dapat menekan tombol Lepaskan, dan artefak akan berakhir di repositori Sonatype.

Agar artefak masuk ke MavenCentral, Anda perlu memintanya di tugas yang kami buat di awal. Anda hanya perlu melakukan ini sekali, jadi kami menerbitkan untuk pertama kalinya. Di waktu berikutnya, ini tidak diperlukan, semuanya akan disinkronkan secara otomatis. Mereka mengaktifkan sinkronisasi untuk saya dengan cepat, tetapi butuh waktu sekitar 5 hari hingga artefak tersedia di MavenCentral.

Itu saja, kami telah menerbitkan artefak kami di MavenCentral.

Berguna Link

  • Serupa artikel, hanya publikasikan melalui maven
  • Pementasan gudang sonatipe
  • Jira Sonatype untuk membuat tugas
  • Contoh repositori tempat semuanya diatur

Sumber: www.habr.com