Օգտագործելով Gradle-ի և Github Actions-ը՝ Java նախագիծը Sonatype Maven կենտրոնական պահեստում հրապարակելու համար

Այս հոդվածում ես ուզում եմ ավելի մոտիկից նայել Java արտեֆակտի հրապարակման գործընթացին զրոյից Github Actions-ի միջոցով Sonatype Maven կենտրոնական պահեստարան՝ օգտագործելով Gradle builder-ը:

Ես որոշեցի գրել այս հոդվածը մեկ տեղում նորմալ ձեռնարկի բացակայության պատճառով: Ամբողջ տեղեկատվությունը պետք էր մաս առ մաս հավաքել տարբեր աղբյուրներից, ընդ որում՝ ոչ ամբողջովին թարմ։ Ով մտածում է, բարի գալուստ կատվի տակ:

Sonatype-ում պահեստի ստեղծում

Առաջին քայլը Sonatype Maven Central-ում պահոց ստեղծելն է: Դրա համար մենք գնում ենք այստեղ, գրանցվեք և ստեղծեք նոր առաջադրանք՝ խնդրելով մեզ ստեղծել պահեստ։ Մենք քշում ենք մեր մեջ GroupId նախագիծ, Ծրագրի URL նախագծի հղում և SCM url հղում դեպի տարբերակի կառավարման համակարգ, որտեղ գտնվում է նախագիծը: GroupId այստեղ պետք է լինի com.example, com.example.domain, com.example.testsupport ձևը և կարող է լինել նաև ձեր github-ի հղման տեսքով. github.com/ձեր օգտանունը -> io.github.yourusername. Ամեն դեպքում, դուք պետք է հաստատեք այս տիրույթի կամ պրոֆիլի սեփականությունը: Եթե ​​դուք նշել եք 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 ստորագրություն։ Դա անելու համար միացրեք plugin-ը 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. ID-ն կնշվի կտրվածքից հետո, օրինակ՝ 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 պահեստում թողարկման պահին, ինչպես նաև ստեղծել գաղտնիքներ:

Մենք գաղտնիքներ ենք դնում

Ավտոմատ հավաքման և տեղակայման համար մեզ անհրաժեշտ են մի շարք գաղտնի արժեքներ, ինչպիսիք են բանալու ID-ն, գաղտնաբառը, որը մենք մուտքագրել ենք բանալին ստեղծելիս, հենց PGP ստեղնը և Sonatype-ի մուտքի/գաղտնաբառը: Դուք կարող եք դրանք տեղադրել պահեստի կարգավորումների հատուկ բաժնում.

Օգտագործելով Gradle-ի և Github Actions-ը՝ Java նախագիծը Sonatype Maven կենտրոնական պահեստում հրապարակելու համար

Մենք սահմանում ենք հետևյալ փոփոխականները.

  • SONATYPE_USERNAME / SONATYPE_PASSWORD - մուտք / գաղտնաբառ, որը մենք մուտքագրել ենք Sonatype-ում գրանցվելիս
  • SIGNING_KEYID/SIGNING_PASSWORD — PGP բանալի id-ն և գաղտնաբառը սահմանվել են ստեղծման ընթացքում:

Ես ուզում եմ ավելի մանրամասն անդրադառնալ 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 Actions-ը՝ 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 Actions-ը՝ Java նախագիծը Sonatype Maven կենտրոնական պահեստում հրապարակելու համար

պիտակի անունը պետք է սկսվի v. Եթե ​​Հրապարակել թողարկումը սեղմելուց հետո աշխատանքային հոսքը հաջողությամբ ավարտվի, մենք կարող ենք գնալ Sonatype Nexus- ը որպեսզի համոզվեք, որ:

Օգտագործելով Gradle-ի և Github Actions-ը՝ Java նախագիծը Sonatype Maven կենտրոնական պահեստում հրապարակելու համար

Արտեֆակտը հայտնվել է Staging պահեստում: Այն անմիջապես հայտնվում է Open կարգավիճակում, այնուհետև այն պետք է ձեռքով փոխանցվի Փակման կարգավիճակին՝ սեղմելով համապատասխան կոճակը: Ստուգելուց հետո, որ բոլոր պահանջները բավարարված են, արտեֆակտը անցնում է Փակ կարգավիճակի մեջ և այլևս հասանելի չէ փոփոխման համար: Այս տեսքով այն կհայտնվի MavenCentral-ում: Եթե ​​ամեն ինչ լավ է, կարող եք սեղմել կոճակը Ազատ, և արտեֆակտը կհայտնվի Sonatype-ի պահոցում:

Որպեսզի արտեֆակտը մտնի MavenCentral, դուք պետք է այն խնդրեք այն առաջադրանքում, որը մենք ստեղծել ենք հենց սկզբում: Ձեզ անհրաժեշտ է դա անել միայն մեկ անգամ, ուստի մենք առաջին անգամ ենք հրապարակում: Հետագա ժամանակներում դա չի պահանջվում, ամեն ինչ ինքնաբերաբար կհամաժամեցվի: Նրանք ինձ համար արագ միացրին համաժամացումը, բայց մոտ 5 օր պահանջվեց, որպեսզի արտեֆակտը հասանելի դառնա MavenCentral-ում:

Այսքանը, մենք հրապարակել ենք մեր արտեֆակտը MavenCentral-ում:

Օգտակար հղումներ

  • Նմանատիպ հոդված, հրապարակել միայն maven-ի միջոցով
  • երթեւեկելը պահոց Սոնատիպ
  • Ջիրա Սոնատիպ, որում պետք է ստեղծվի առաջադրանքը
  • Օրինակ պահեստ, որտեղ ամեն ինչ տեղադրված է

Source: www.habr.com