Skip to content

Commit

Permalink
Release version 1.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
johnsonlee committed Oct 6, 2021
1 parent be1ba9b commit b2fb9f1
Show file tree
Hide file tree
Showing 56 changed files with 7,734 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#
# https://help.github.com/articles/dealing-with-line-endings/
#
# These are explicitly windows files and should use crlf
*.bat text eol=crlf

27 changes: 27 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Build and Test

on:
push:
branches: [ '*' ]
pull_request:
branches: [ '*' ]

repository_dispatch:
types: [test]

jobs:
run-unit-test:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v2

- name: Setup Java
uses: actions/setup-java@v2
with:
distribution: 'adopt'
java-version: '8'

- name: build
run: ./gradlew build -S --no-daemon
47 changes: 47 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: Publish to Sonatype

on:
push:
tags:
- '*'
repository_dispatch:
types: [publish]

jobs:
publish:
runs-on: ubuntu-latest
if: github.repository == 'johnsonlee/sonatype-publish-plugin'

steps:
- name: Checkout
uses: actions/checkout@v2

- name: Setup Java
uses: actions/setup-java@v2
with:
distribution: 'adopt'
java-version: '8'

- name: Publish to sonatype
run: |
echo "Create GPG private key"
echo $GPG_KEY_ARMOR | base64 --decode > ${GITHUB_WORKSPACE}/secring.gpg
echo "Publish ${GITHUB_REF} to Sonatype"
./gradlew clean publishToSonatype -S --no-daemon \
-Pversion=${GITHUB_REF/refs\/tags\/v/} \
-POSSRH_USERNAME=${OSSRH_USERNAME} \
-POSSRH_PASSWORD=${OSSRH_PASSWORD} \
-Psigning.keyId=${GPG_KEY_ID} \
-Psigning.password=${GPG_PASSPHRASE} \
-Psigning.secretKeyRingFile=${GITHUB_WORKSPACE}/secring.gpg
./gradlew closeAndReleaseRepository -S --no-daemon \
-Pversion=${GITHUB_REF/refs\/tags\/v/} \
-POSSRH_USERNAME=${OSSRH_USERNAME} \
-POSSRH_PASSWORD=${OSSRH_PASSWORD} \
--no-daemon
env:
GPG_KEY_ARMOR: ${{ secrets.GPG_KEY_ARMOR }}
GPG_KEY_ID: ${{ secrets.GPG_KEY_ID }}
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
.DS_Store

.idea

.gradle
/build/

Expand All @@ -12,3 +16,8 @@ gradle-app.setting

# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
# gradle/wrapper/gradle-wrapper.properties

# Ignore Gradle build output directory
build

local.properties
141 changes: 141 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
## Introduction

Due to Sonatype's strict validation rules, the publishing requirement must be satisfied by every artifact which wants to be published to Sonatype.

For Java and Android library projects, the publishing configurations are very similar, but the configurations of creating publication are quite different, this gradle plugin is used to simplify the engineering complexity of publishing artifacts to [Sonatype](https://oss.sonatype.org/), developers don't need to write boilerplate publishing DSL for each project to satisfy Sonatype validation rules.

## Prerequisite

* [Sonatype](https://oss.sonatype.org/) Account
* [GPG](https://gnupg.org/) key

For more information, see [References](#references)

## Getting Started

### Configure buildscript classpath

```kotlin
buildscript {
repositories {
mavenCentral()
google()
gradlePluginPortal()
}
dependencies {
classpath("io.johnsonlee:sonatype-publish-plugin:1.0.0")
}
}
```

### Apply plugin

#### Plugins DSL

```kotlin
plugins {
id("io.johnsonlee.sonatype-publish-plugin")
}
```

#### Legacy DSL

```groovy
apply plugin: "io.johnsonlee.sonatype-publish-plugin"
```

### Configure env and properties

* `OSSRH_USERNAME`

The account id of [Sonatype](https://oss.sonatype.org/), searching from project properties by default, otherwise searching from system env

* `OSSRH_PASSWORD`

the account password of [Sonatype](https://oss.sonatype.org/), searching from project properties by default, otherwise searching from system env

* `OSSRH_PACKAGE_GROUP`

The package group of [Sonatype](https://oss.sonatype.org/), e.g. `io.johnsonlee`

* `signing.keyId`

The GPG key id (short format). In this example, the GPG key id is `71567BD2`

```
$ gpg --list-secret-keys --keyid-format=short
/Users/johnsonlee/.gnupg/secring.gpg
------------------------------------
sec 4096R/71567BD2 2021-03-10 [expires: 2031-03-10]
uid Johnson
ssb 4096R/4BA89E7A 2021-03-10
```
* `signing.password`
The password of GPG key
* `signing.secretKeyRingFile`
The secret key ring file, e.g. */Users/johnsonlee/.gnupg/secring.gpg*
> The best practice is putting the properties above into `~/.gradle/gradle.properties`
>
> ```properties
> OSSRH_USERNAME=johnsonlee
> OSSRH_PASSWORD=*********
> OSSRH_PACKAGE_GROUP=io.johnsonlee
> signing.keyId=71567BD2
> signing.password=*********
> signing.secretKeyRingFile=/Users/johnsonlee/.gnupg/secring.gpg
> ```
### Configure git repository
The following git configurations are be used for generating maven POM file
* `user.name`
```bash
git config user.name <username>
```
* `user.email`
```bash
git config user.email <email-address>
```
* `remote.origin.url` (optional)
The `remote.origin.url` is available by default unless the git repository is created locally
```bash
git remote add origin [email protected]:<username>/<repository>
```
### Configure License (optional)
Add a license file (`LICENSE`, `LICENSE.txt`, `LICENSE.md` or `LICENSE.rst`) into project, then the license type will be recognized automatically.
For more information on repository licenses, see "[Supported Licenses](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/licensing-a-repository#searching-github-by-license-type)"
### Publish Artifacts to Sonatype
```bash
./gradlew clean publishToSonatype
```

### Release Artifacts

```bash
./gradlew closeAndReleaseRepository
```

After release complete, the artifacts will be synced to [Maven Central](https://mvnrepository.com/repos/central) automatically

## References

- [OSSRH Requirements](https://central.sonatype.org/publish/requirements/)
- [OSSRH Guide](https://central.sonatype.org/publish/publish-guide/)
- [Generating A New GPG Key](https://docs.github.com/en/authentication/managing-commit-signature-verification/generating-a-new-gpg-key)
150 changes: 150 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import org.gradle.kotlin.dsl.*

plugins {
`java-gradle-plugin`
`maven-publish`
`kotlin-dsl`
`signing`
kotlin("jvm") version embeddedKotlinVersion
id("org.jetbrains.dokka") version "1.4.32"
id("io.codearte.nexus-staging") version "0.22.0"
id("de.marcphilipp.nexus-publish") version "0.4.0"
}

group = "io.johnsonlee"
version = project.properties["version"]?.takeUnless { it == "unspecified" } ?: "1.0.0-SNAPSHOT"
description = "Gradle plugin for publishing artifacts to Sonatype"

repositories {
mavenCentral()
google()
gradlePluginPortal()
}

dependencies {
implementation(gradleApi())
implementation(platform(kotlin("bom")))
implementation(kotlin("stdlib"))
implementation("de.marcphilipp.gradle:nexus-publish-plugin:0.4.0")
implementation("io.codearte.nexus-staging:io.codearte.nexus-staging.gradle.plugin:0.22.0")
implementation("org.jetbrains.dokka:dokka-gradle-plugin:1.4.32")
implementation("org.eclipse.jgit:org.eclipse.jgit:5.13.0.202109080827-r")
compileOnly("com.android.tools.build:gradle:4.0.0")

testImplementation(kotlin("test"))
testImplementation(kotlin("test-junit"))
}

gradlePlugin {
plugins.create("io.johnsonlee.sonatype-publish-plugin") {
id = name
implementationClass = "io.johnsonlee.gradle.publish.SonatypePublishPlugin"
}
}

java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}

val sourcesJar by tasks.registering(Jar::class) {
dependsOn(JavaPlugin.CLASSES_TASK_NAME)
archiveClassifier.set("sources")
from(sourceSets.main.get().allSource)
}

val javadocJar by tasks.registering(Jar::class) {
dependsOn(JavaPlugin.JAVADOC_TASK_NAME)
archiveClassifier.set("javadoc")
from(tasks["javadoc"])
}

val OSSRH_USERNAME = "${project.properties["OSSRH_USERNAME"] ?: System.getenv("OSSRH_USERNAME")}"
val OSSRH_PASSWORD = "${project.properties["OSSRH_PASSWORD"] ?: System.getenv("OSSRH_PASSWORD")}"

nexusPublishing {
repositories {
sonatype {
username.set(OSSRH_USERNAME)
password.set(OSSRH_PASSWORD)
}
}
}

publishing {
repositories {
maven {
url = uri("https://oss.sonatype.org/service/local/staging/deploy/maven2/")
}
}
publications {
withType(MavenPublication::class.java).configureEach {
val publication = this

groupId = "${project.group}"
artifactId = project.name
version = "${project.version}"

if ("mavenJava" == publication.name) {
from(components["java"])
}

artifact(sourcesJar.get())
artifact(javadocJar.get())

pom.withXml {
asNode().apply {
appendNode("name", project.name)
appendNode("url", "https://github.com/johnsonlee/${rootProject.name}")
appendNode("description", project.description ?: project.name)
appendNode("scm").apply {
appendNode("connection", "scm:git:git://github.com/johnsonlee/${rootProject.name}.git")
appendNode("developerConnection", "scm:git:[email protected]:johnsonlee/${rootProject.name}.git")
appendNode("url", "https://github.com/johnsonlee/${rootProject.name}")
}
appendNode("licenses").apply {
appendNode("license").apply {
appendNode("name", "Apache License")
appendNode("url", "https://www.apache.org/licenses/LICENSE-2.0")
}
}
appendNode("developers").apply {
appendNode("developer").apply {
appendNode("id", "johnsonlee")
appendNode("name", "Johnson Lee")
appendNode("email", "[email protected]")
}
}
}
}

signing {
sign(publication)
}
}
}
}


nexusStaging {
packageGroup = "io.johnsonlee"
username = OSSRH_USERNAME
password = OSSRH_PASSWORD
numberOfRetries = 50
delayBetweenRetriesInMillis = 3000
}

val functionalTestSourceSet = sourceSets.create("functionalTest") {
}

gradlePlugin.testSourceSets(functionalTestSourceSet)
configurations["functionalTestImplementation"].extendsFrom(configurations["testImplementation"])

val functionalTest by tasks.registering(Test::class) {
testClassesDirs = functionalTestSourceSet.output.classesDirs
classpath = functionalTestSourceSet.runtimeClasspath
}

tasks.check {
dependsOn(functionalTest)
}
1 change: 1 addition & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
systemProp.org.gradle.internal.publish.checksums.insecure=true
Binary file added gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
Loading

0 comments on commit b2fb9f1

Please sign in to comment.