Sử dụng các hành động Gradle và Github để xuất bản Dự án Java lên Kho lưu trữ trung tâm Sonatype Maven

Trong bài viết này, tôi muốn xem xét kỹ hơn quá trình xuất bản một tạo phẩm Java từ đầu thông qua Tác vụ Github đến Kho lưu trữ trung tâm Sonatype Maven bằng trình tạo Gradle.

Tôi quyết định viết bài này do thiếu hướng dẫn bình thường ở một nơi. Tất cả thông tin phải được thu thập từng mảnh từ nhiều nguồn khác nhau, hơn nữa, không hoàn toàn mới. Ai quan tâm, chào mừng dưới con mèo.

Tạo một kho lưu trữ trong Sonatype

Bước đầu tiên là tạo một kho lưu trữ trong Sonatype Maven Central. Đối với điều này, chúng tôi đi đây, đăng ký và tạo một nhiệm vụ mới, yêu cầu chúng tôi tạo một kho lưu trữ. Chúng tôi lái xe trong của chúng tôi Id nhóm dự án, Dự án URL liên kết dự án và url SCM một liên kết đến hệ thống kiểm soát phiên bản chứa dự án. Id nhóm ở đây phải ở dạng com.example, com.example.domain, com.example.testsupport và cũng có thể ở dạng liên kết đến github của bạn: github.com/tên người dùng của bạn -> io.github.tên người dùng của bạn. Trong mọi trường hợp, bạn sẽ cần xác minh quyền sở hữu tên miền hoặc hồ sơ này. Nếu bạn đã chỉ định một hồ sơ github, bạn sẽ được yêu cầu tạo một kho lưu trữ công khai với tên mong muốn.

Một thời gian sau khi xác nhận, GroupId của bạn sẽ được tạo và chúng ta có thể chuyển sang bước tiếp theo, cấu hình Gradle.

Cấu hình lớp

Tại thời điểm viết bài, tôi không tìm thấy các plugin Gradle có thể giúp xuất bản tạo phẩm. plugin duy nhất mà tôi tìm thấy, tuy nhiên, tác giả đã từ chối hỗ trợ thêm cho nó. Vì vậy, tôi quyết định tự mình làm mọi thứ, vì làm việc này không quá khó.

Điều đầu tiên cần tìm ra là các yêu cầu của Sonatype đối với việc xuất bản. Họ là những điều sau đây:

  • Tính khả dụng của mã nguồn và JavaDoc, tức là. phải tham gia -sources.jar и-javadoc.jar các tập tin. Như đã nêu trong tài liệu, nếu không thể cung cấp mã nguồn hoặc tài liệu, bạn có thể tạo một hình nộm -sources.jar hoặc -javadoc.jar với một README đơn giản bên trong để vượt qua bài kiểm tra.
  • Tất cả các tập tin phải được ký với GPG/PGP.asc tệp chứa chữ ký phải được bao gồm cho mỗi tệp.
  • tính sẵn sàng pom tập tin
  • giá trị đúng groupId, artifactId и version. Phiên bản có thể là một chuỗi tùy ý và không thể kết thúc bằng -SNAPSHOT
  • bắt buộc phải có mặt name, description и url
  • Sự hiện diện của thông tin về giấy phép, nhà phát triển và hệ thống kiểm soát phiên bản

Đây là những quy tắc cơ bản phải được tuân theo khi xuất bản. Thông tin đầy đủ có sẵn đây.

Chúng tôi thực hiện các yêu cầu này trong build.gradle tài liệu. Trước tiên, hãy thêm tất cả thông tin cần thiết về nhà phát triển, giấy phép, hệ thống kiểm soát phiên bản, đồng thời đặt url, tên và mô tả của dự án. Hãy viết một phương thức đơn giản cho việc này:

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

Tiếp theo, bạn cần xác định rằng trong quá trình lắp ráp đã tạo -sources.jar и-javadoc.jar các tập tin. Đối với phần này java bạn cần thêm vào như sau:

java {
    withJavadocJar()
    withSourcesJar()
}

Hãy chuyển sang yêu cầu cuối cùng, thiết lập chữ ký GPG/PGP. Để làm điều này, hãy kết nối plugin signing:

plugins {
    id 'signing'
}

Và thêm một phần:

signing {
    sign publishing.publications
}

Cuối cùng, hãy thêm một phần 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
            }
        }
    }
}

Здесь sonatypeTên người dùng и sonatypeMật khẩu các biến chứa thông tin đăng nhập và mật khẩu được tạo trong quá trình đăng ký trên sonatype.org.

Như vậy trận chung kết build.gradle sẽ trông như thế này:

Mã build.gradle đầy đủ

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

Tôi muốn lưu ý rằng chúng tôi lấy phiên bản từ biến môi trường: System.getenv('RELEASE_VERSION'). Chúng tôi sẽ hiển thị nó trong quá trình lắp ráp và lấy nó từ tên thẻ.

Tạo khóa PGP

Một trong những yêu cầu của Sonatype là tất cả các tệp phải được ký bằng khóa GPG/PGP. Đối với điều này, chúng tôi đi đây và tải xuống tiện ích GnuPG cho hệ điều hành của bạn.

  • Chúng tôi tạo một cặp khóa: gpg --gen-key, nhập tên người dùng, e-mail và cũng có thể đặt mật khẩu.
  • chúng tôi tìm ra id chìa khóa của chúng tôi với lệnh: gpg --list-secret-keys --keyid-format short. Id sẽ được chỉ định sau dấu gạch chéo, ví dụ: rsa2048/9B695056
  • Xuất bản khóa công khai lên máy chủ https://keys.openpgp.org bằng lệnh: gpg --keyserver [https://keys.openpgp.org](https://keys.openpgp.org/) --send-keys 9B695056
  • Chúng tôi xuất khóa bí mật đến một nơi tùy ý, chúng tôi sẽ cần nó trong tương lai: gpg --export-secret-key 9B695056 > D:\gpg\9B695056.gpg

Thiết lập hành động Github

Hãy chuyển sang giai đoạn cuối cùng, thiết lập bản dựng và tự động xuất bản bằng Github Actions.
Github Actions là một tính năng cho phép bạn tự động hóa quy trình làm việc bằng cách triển khai chu trình CI/CD đầy đủ. Quá trình xây dựng, thử nghiệm và triển khai có thể được kích hoạt bởi nhiều sự kiện khác nhau: đẩy mã, tạo bản phát hành hoặc sự cố. Chức năng này hoàn toàn miễn phí cho các kho lưu trữ công cộng.

Trong phần này, tôi sẽ chỉ cho bạn cách thiết lập mã xây dựng và đẩy và triển khai vào kho lưu trữ Sonatype khi phát hành, cũng như thiết lập các bí mật.

Chúng tôi đặt bí mật

Để lắp ráp và triển khai tự động, chúng tôi cần một số giá trị bí mật, chẳng hạn như id khóa, mật khẩu mà chúng tôi đã nhập khi tạo khóa, chính khóa PGP và thông tin đăng nhập/mật khẩu Sonatype. Bạn có thể đặt chúng trong một phần đặc biệt trong cài đặt kho lưu trữ:

Sử dụng các hành động Gradle và Github để xuất bản Dự án Java lên Kho lưu trữ trung tâm Sonatype Maven

Chúng tôi đặt các biến sau:

  • SONATYPE_USERNAME / SONATYPE_PASSWORD - thông tin đăng nhập / mật khẩu mà chúng tôi đã nhập khi đăng ký với Sonatype
  • SIGNING_KEYID/SIGNING_PASSWORD — ID khóa PGP và mật khẩu được đặt trong quá trình tạo.

Tôi muốn xem chi tiết hơn về biến GPG_KEY_CONTENTS. Thực tế là để xuất bản, chúng tôi cần một khóa PGP riêng. Để đăng nó trong phần bí mật, tôi đã sử dụng hướng dẫn và bổ sung thực hiện một số hành động.

  • Hãy mã hóa khóa của chúng tôi bằng gpg: gpg --symmetric --cipher-algo AES256 9B695056.gpgbằng cách nhập mật khẩu. Nó nên được đặt trong một biến: SECRET_PASSPHRASE
  • Hãy dịch khóa được mã hóa đã nhận thành dạng văn bản bằng base64: base64 9B695056.gpg.gpg > 9B695056.txt. Nội dung sẽ được đặt trong biến: GPG_KEY_CONTENTS.

Build setup khi đẩy code và tạo PR

Trước tiên, bạn cần tạo một thư mục trong thư mục gốc của dự án: .github/workflows.

Trong đó, đánh dấu tệp, ví dụ, gradle-ci-build.yml với nội dung như sau:

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

Luồng công việc này sẽ được thực thi khi đẩy đến các nhánh master, dev и testing, cả khi tạo yêu cầu kéo.

Phần công việc chỉ định các bước sẽ được thực hiện trên các sự kiện được chỉ định. Trong trường hợp này, chúng tôi sẽ xây dựng trên phiên bản Ubuntu mới nhất, sử dụng Java 8 và cũng sử dụng plugin cho Gradle eskatos/gradle-command-action@v1trong đó, sử dụng phiên bản mới nhất của trình tạo, sẽ chạy các lệnh được chỉ định trong arguments. Biến secrets.SONATYPE_USERNAME и secrets.SONATYPE_PASSWORD đây là những bí mật chúng tôi đã hỏi trước đó.

Kết quả xây dựng sẽ được phản ánh trong tab Hành động:

Sử dụng các hành động Gradle và Github để xuất bản Dự án Java lên Kho lưu trữ trung tâm Sonatype Maven

Tự động triển khai khi phát hành bản phát hành mới

Hãy tạo một tệp quy trình công việc riêng cho triển khai tự động 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}}

Tệp này gần giống với tệp trước đó, ngoại trừ sự kiện mà nó sẽ được kích hoạt. Trong trường hợp này, đây là sự kiện tạo thẻ có tên bắt đầu bằng v.

Trước khi triển khai, chúng tôi cần trích xuất khóa PGP từ các bí mật và đặt nó vào thư mục gốc của dự án, cũng như giải mã nó. Tiếp theo, chúng ta cần đặt một biến môi trường đặc biệt RELEASE_VERSION mà chúng tôi đề cập đến gradle.build tài liệu. Tất cả điều này được thực hiện trong phần Prepare to publish. Chúng tôi lấy khóa của mình từ biến GPG_KEY_CONTENTS, dịch nó thành tệp gpg, sau đó giải mã nó bằng cách đặt nó vào tệp secret.gpg.

Tiếp theo, chúng ta chuyển sang một biến đặc biệt GITHUB_REF, từ đó chúng tôi có thể lấy phiên bản mà chúng tôi đã đặt khi tạo thẻ. Biến này có liên quan trong trường hợp này. refs/tags/v0.0.2 từ đó chúng tôi cắt bỏ 11 ký tự đầu tiên để có phiên bản cụ thể. Tiếp theo, chúng tôi sử dụng các lệnh Gradle tiêu chuẩn để xuất bản: test publish

Kiểm tra kết quả triển khai trong kho lưu trữ Sonatype

Sau khi tạo bản phát hành, quy trình làm việc được mô tả trong phần trước sẽ bắt đầu. Để làm điều này, hãy tạo một bản phát hành:

Sử dụng các hành động Gradle và Github để xuất bản Dự án Java lên Kho lưu trữ trung tâm Sonatype Maven

tên thẻ phải bắt đầu bằng v. Nếu sau khi nhấp vào Xuất bản bản phát hành, quy trình công việc hoàn tất thành công, chúng ta có thể chuyển đến Sonatype Nexus để chắc chắn:

Sử dụng các hành động Gradle và Github để xuất bản Dự án Java lên Kho lưu trữ trung tâm Sonatype Maven

Hiện vật đã xuất hiện trong kho lưu trữ Giai đoạn. Nó ngay lập tức xuất hiện ở trạng thái Mở, sau đó nó phải được chuyển thủ công sang trạng thái Đóng bằng cách nhấn nút thích hợp. Sau khi kiểm tra để đảm bảo rằng tất cả các yêu cầu đều được đáp ứng, hiện vật sẽ chuyển sang trạng thái Đóng và không còn khả dụng để sửa đổi. Ở dạng này, nó sẽ kết thúc ở MavenCentral. Nếu tất cả đều ổn, bạn có thể nhấn nút Phát hành, và hiện vật sẽ kết thúc trong kho lưu trữ Sonatype.

Để hiện vật vào MavenCentral, bạn cần yêu cầu nó trong nhiệm vụ mà chúng tôi đã tạo ngay từ đầu. Bạn chỉ cần làm điều này một lần, vì vậy chúng tôi xuất bản lần đầu tiên. Những lần sau không cần thao tác này, mọi thứ sẽ được tự động đồng bộ. Họ đã nhanh chóng bật đồng bộ hóa cho tôi, nhưng phải mất khoảng 5 ngày để tạo phẩm có sẵn trong MavenCentral.

Đó là tất cả, chúng tôi đã xuất bản tạo phẩm của mình trong MavenCentral.

Liên kết hữu ích

  • Tương tự bài viết, chỉ xuất bản qua maven
  • Dàn dựng kho sonatype
  • Jira Sonatype để tạo tác vụ
  • Ví dụ kho lưu trữ nơi tất cả được thiết lập

Nguồn: www.habr.com