Χρήση Gradle και Github Actions για δημοσίευση Java Project στο Sonatype Maven Central Repository

Σε αυτό το άρθρο, θέλω να ρίξω μια λεπτομερή ματιά στη διαδικασία δημοσίευσης ενός τεχνουργήματος Java από την αρχή μέσω του Github Actions στο κεντρικό αποθετήριο Sonatype Maven χρησιμοποιώντας το πρόγραμμα δημιουργίας Gradle.

Αποφάσισα να γράψω αυτό το άρθρο λόγω της έλλειψης ενός κανονικού σεμιναρίου σε ένα μέρος. Όλες οι πληροφορίες έπρεπε να συγκεντρωθούν κομμάτι-κομμάτι από διάφορες πηγές, επιπλέον, όχι εντελώς φρέσκες. Ποιος νοιάζεται, καλώς ήρθες κάτω από τη γάτα.

Δημιουργία αποθετηρίου στο Sonatype

Το πρώτο βήμα είναι να δημιουργήσετε ένα αποθετήριο στο Sonatype Maven Central. Για αυτό πάμε εδώ, εγγραφείτε και δημιουργήστε μια νέα εργασία, ζητώντας μας να δημιουργήσουμε ένα αποθετήριο. Οδηγούμε στο δικό μας GroupId έργο, URL έργου σύνδεσμος έργου και SCM url έναν σύνδεσμο προς το σύστημα ελέγχου έκδοσης στο οποίο βρίσκεται το έργο. GroupId εδώ θα πρέπει να είναι της μορφής com.example, com.example.domain, com.example.testsupport και μπορεί επίσης να έχει τη μορφή συνδέσμου προς το github σας: github.com/το όνομα χρήστη σας -> io.github.όνομα χρήστη σας. Σε κάθε περίπτωση, θα πρέπει να επαληθεύσετε την ιδιοκτησία αυτού του τομέα ή του προφίλ. Εάν καθορίσατε ένα προφίλ github, θα σας ζητηθεί να δημιουργήσετε ένα δημόσιο αποθετήριο με το επιθυμητό όνομα.

Λίγο καιρό μετά την επιβεβαίωση, θα δημιουργηθεί το GroupId σας και μπορούμε να προχωρήσουμε στο επόμενο βήμα, τη διαμόρφωση Gradle.

Διαμόρφωση Gradle

Τη στιγμή της γραφής, δεν βρήκα πρόσθετα Gradle που θα μπορούσαν να βοηθήσουν στη δημοσίευση του τεχνουργήματος. Το το μόνο πρόσθετο που βρήκα, ωστόσο, ο συγγραφέας αρνήθηκε να το υποστηρίξει περαιτέρω. Ως εκ τούτου, αποφάσισα να κάνω τα πάντα μόνος μου, καθώς δεν είναι πολύ δύσκολο να το κάνω αυτό.

Το πρώτο πράγμα που πρέπει να καταλάβουμε είναι οι απαιτήσεις της Sonatype για δημοσίευση. Είναι οι εξής:

  • Διαθεσιμότητα πηγαίων κωδίκων και JavaDoc, π.χ. πρέπει να παρευρεθούν -sources.jar и-javadoc.jar αρχεία. Όπως αναφέρεται στην τεκμηρίωση, εάν δεν είναι δυνατό να παρέχετε πηγαίους κωδικούς ή τεκμηρίωση, μπορείτε να δημιουργήσετε ένα ομοίωμα -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, πληκτρολογήστε ένα όνομα χρήστη, e-mail και ορίστε επίσης έναν κωδικό πρόσβασης.
  • Ανακαλύπτουμε 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 Actions

Ας προχωρήσουμε στο τελικό στάδιο, ρυθμίζουμε την κατασκευή και κάνουμε αυτόματη δημοσίευση χρησιμοποιώντας το Github Actions.
Το Github Actions είναι μια δυνατότητα που σας επιτρέπει να αυτοματοποιήσετε τη ροή εργασίας υλοποιώντας έναν πλήρη κύκλο CI/CD. Η δημιουργία, η δοκιμή και η ανάπτυξη μπορούν να ενεργοποιηθούν από διάφορα συμβάντα: ώθηση κώδικα, δημιουργία κυκλοφορίας ή προβλήματα. Αυτή η λειτουργία είναι εντελώς δωρεάν για δημόσια αποθετήρια.

Σε αυτήν την ενότητα, θα σας δείξω πώς να ρυθμίζετε τον κώδικα build και push και να αναπτύσσετε στο αποθετήριο Sonatype κατά την κυκλοφορία, καθώς και πώς να ρυθμίζετε μυστικά.

Βάζουμε μυστικά

Για αυτόματη συναρμολόγηση και ανάπτυξη, χρειαζόμαστε έναν αριθμό μυστικών τιμών, όπως το αναγνωριστικό κλειδιού, τον κωδικό πρόσβασης που πληκτρολογήσαμε κατά τη δημιουργία του κλειδιού, το ίδιο το κλειδί PGP και τη σύνδεση/κωδικό πρόσβασης Sonatype. Μπορείτε να τα ορίσετε σε μια ειδική ενότητα στις ρυθμίσεις του αποθετηρίου:

Χρήση Gradle και Github Actions για δημοσίευση Java Project στο Sonatype Maven Central Repository

Ορίζουμε τις ακόλουθες μεταβλητές:

  • SONATYPE_USERNAME / SONATYPE_PASSWORD - σύνδεση / κωδικός πρόσβασης που πληκτρολογήσαμε κατά την εγγραφή στο Sonatype
  • SIGNING_KEYID/SIGNING_PASSWORD — Το αναγνωριστικό και ο κωδικός πρόσβασης κλειδιού 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το οποίο, χρησιμοποιώντας την πιο πρόσφατη έκδοση του builder, θα εκτελέσει τις εντολές που καθορίζονται στο arguments. Μεταβλητές secrets.SONATYPE_USERNAME и secrets.SONATYPE_PASSWORD αυτά είναι τα μυστικά που ρωτήσαμε νωρίτερα.

Τα αποτελέσματα της κατασκευής θα αντικατοπτρίζονται στην καρτέλα Ενέργειες:

Χρήση Gradle και Github Actions για δημοσίευση Java Project στο Sonatype Maven Central Repository

Αυτόματη ανάπτυξη όταν κυκλοφορήσει μια νέα έκδοση

Ας δημιουργήσουμε ένα ξεχωριστό αρχείο ροής εργασίας για αυτόματη ανάπτυξη 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 Actions για δημοσίευση Java Project στο Sonatype Maven Central Repository

το όνομα της ετικέτας πρέπει να ξεκινά με v. Εάν, αφού κάνουμε κλικ στο Δημοσίευση έκδοσης, η ροή εργασίας ολοκληρωθεί με επιτυχία, μπορούμε να μεταβούμε στο Sonatype Nexus για να βεβαιωθείτε ότι:

Χρήση Gradle και Github Actions για δημοσίευση Java Project στο Sonatype Maven Central Repository

Το τεχνούργημα εμφανίστηκε στο αποθετήριο Staging. Εμφανίζεται αμέσως στην κατάσταση Άνοιγμα και στη συνέχεια πρέπει να μεταφερθεί χειροκίνητα στην κατάσταση Κλείσιμο πατώντας το κατάλληλο κουμπί. Αφού ελέγξετε ότι πληρούνται όλες οι απαιτήσεις, το τεχνούργημα μεταβαίνει στην κατάσταση Κλείσιμο και δεν είναι πλέον διαθέσιμο για τροποποίηση. Σε αυτή τη μορφή, θα καταλήξει στο MavenCentral. Εάν όλα πάνε καλά, μπορείτε να πατήσετε το κουμπί Απελευθερώστε, και το τεχνούργημα θα καταλήξει στο αποθετήριο Sonatype.

Για να μπει το τεχνούργημα στο MavenCentral, πρέπει να το ζητήσετε στην εργασία που δημιουργήσαμε στην αρχή. Χρειάζεται να το κάνετε μόνο μία φορά, γι' αυτό δημοσιεύουμε για πρώτη φορά. Στις επόμενες φορές, αυτό δεν απαιτείται, όλα θα συγχρονιστούν αυτόματα. Ενεργοποίησαν τον συγχρονισμό για μένα γρήγορα, αλλά χρειάστηκαν περίπου 5 ημέρες για να γίνει διαθέσιμο το τεχνούργημα στο MavenCentral.

Αυτό είναι όλο, έχουμε δημοσιεύσει το τεχνούργημα μας στο MavenCentral.

χρήσιμοι σύνδεσμοι

  • Παρόμοιος άρθρο, δημοσιεύεται μόνο μέσω maven
  • Σκαλωσιά αποθήκη Sonatype
  • JIRA Sonatype για τη δημιουργία της εργασίας
  • Παράδειγμα αποθετήριο όπου είναι όλα ρυθμισμένα

Πηγή: www.habr.com