ในบทความนี้ ฉันต้องการดูรายละเอียดเกี่ยวกับกระบวนการเผยแพร่สิ่งประดิษฐ์ Java ตั้งแต่เริ่มต้นผ่าน Github Actions ไปยัง Sonatype Maven Central Repository โดยใช้ Gradle builder
ฉันตัดสินใจเขียนบทความนี้เนื่องจากไม่มีการสอนแบบปกติในที่เดียว ข้อมูลทั้งหมดต้องรวบรวมทีละส่วนจากแหล่งต่าง ๆ ยิ่งกว่านั้นไม่สดทั้งหมด ใครสนใจยินดีต้อนรับภายใต้แมว
การสร้างที่เก็บใน Sonatype
ขั้นตอนแรกคือการสร้างที่เก็บใน Sonatype Maven Central สำหรับสิ่งนี้เราไป
หลังจากการยืนยันสักครู่ 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ชื่อผู้ใช้ и sonatypeรหัสผ่าน ตัวแปรที่มีการเข้าสู่ระบบและรหัสผ่านที่สร้างขึ้นระหว่างการลงทะเบียนบน
ดังนั้นขั้นสุดท้าย 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 สำหรับสิ่งนี้เราไป
- เราสร้างคู่กุญแจ:
gpg --gen-key
ป้อนชื่อผู้ใช้ อีเมล และตั้งรหัสผ่าน - เราค้นพบ
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
ไปที่ขั้นตอนสุดท้าย ตั้งค่าการสร้างและเผยแพร่อัตโนมัติโดยใช้ Github Actions
Github Actions เป็นคุณสมบัติที่ช่วยให้คุณทำให้เวิร์กโฟลว์เป็นไปโดยอัตโนมัติโดยใช้วงจร CI / CD เต็มรูปแบบ สร้าง ทดสอบ และปรับใช้สามารถทริกเกอร์ได้จากเหตุการณ์ต่างๆ เช่น การพุชรหัส การสร้างรุ่น หรือปัญหา ฟังก์ชันนี้ใช้งานได้ฟรีสำหรับที่เก็บข้อมูลสาธารณะ
ในส่วนนี้ ฉันจะแสดงวิธีตั้งค่าบิลด์และพุชโค้ด และปรับใช้กับที่เก็บ Sonatype เมื่อเผยแพร่ ตลอดจนตั้งค่าความลับ
เราตั้งความลับ
สำหรับการประกอบและการปรับใช้โดยอัตโนมัติ เราต้องการค่าลับจำนวนหนึ่ง เช่น ID ของคีย์ รหัสผ่านที่เราป้อนเมื่อสร้างคีย์ คีย์ PGP เอง และการเข้าสู่ระบบ/รหัสผ่าน Sonatype คุณสามารถตั้งค่าได้ในส่วนพิเศษในการตั้งค่าที่เก็บ:
เราตั้งค่าตัวแปรต่อไปนี้:
- 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
ซึ่งใช้ตัวสร้างเวอร์ชันล่าสุดเพื่อเรียกใช้คำสั่งที่ระบุใน arguments
. ตัวแปร secrets.SONATYPE_USERNAME
и secrets.SONATYPE_PASSWORD
นี่คือความลับที่เราถามก่อนหน้านี้
ผลลัพธ์ของบิลด์จะแสดงในแท็บการดำเนินการ:
ปรับใช้อัตโนมัติเมื่อมีการเปิดตัวรุ่นใหม่
มาสร้างไฟล์เวิร์กโฟลว์แยกต่างหากสำหรับการปรับใช้อัตโนมัติ 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
เมื่อสร้างรุ่นแล้ว เวิร์กโฟลว์ที่อธิบายไว้ในส่วนก่อนหน้าควรเริ่มต้น ในการดำเนินการนี้ ให้สร้างรุ่น:
ชื่อแท็กต้องขึ้นต้นด้วย v หากหลังจากคลิกเผยแพร่เผยแพร่เวิร์กโฟลว์เสร็จสมบูรณ์แล้ว เราสามารถไปที่
สิ่งประดิษฐ์ปรากฏในที่เก็บ Staging ทันทีปรากฏในสถานะเปิด จากนั้นจะต้องโอนไปยังสถานะปิดด้วยตนเองโดยกดปุ่มที่เหมาะสม หลังจากตรวจสอบว่าตรงตามข้อกำหนดทั้งหมดแล้ว อาร์ติแฟกต์จะเข้าสู่สถานะปิดและไม่สามารถแก้ไขได้อีกต่อไป ในรูปแบบนี้จะจบลงใน MavenCentral หากทุกอย่างเรียบร้อยดี คุณสามารถกดปุ่ม ปล่อยและสิ่งประดิษฐ์จะจบลงในที่เก็บ Sonatype
เพื่อให้สิ่งประดิษฐ์เข้าสู่ MavenCentral คุณต้องขอในงานที่เราสร้างขึ้นในตอนเริ่มต้น คุณต้องทำเช่นนี้เพียงครั้งเดียว เราจึงเผยแพร่เป็นครั้งแรก ในครั้งต่อไป ไม่จำเป็น ทุกอย่างจะถูกซิงโครไนซ์โดยอัตโนมัติ พวกเขาเปิดการซิงโครไนซ์ให้ฉันอย่างรวดเร็ว แต่ใช้เวลาประมาณ 5 วันกว่าที่สิ่งประดิษฐ์จะพร้อมใช้งานใน MavenCentral
นั่นคือทั้งหมด เราได้เผยแพร่สิ่งประดิษฐ์ของเราใน MavenCentral
ลิงค์ที่มีประโยชน์
- คล้ายกัน
บทความ เผยแพร่ผ่าน maven เท่านั้น - การแสดงละคร
ที่เก็บ โซนาไทป์ จิระ Sonatype ในการสร้างงานตัวอย่าง พื้นที่เก็บข้อมูลที่มีการตั้งค่าทั้งหมด
ที่มา: will.com