Skip to content

Commit d04a1f1

Browse files
Publish library to maven central ci/cd (#3)
* successful build and upload of artifact to nexus central repository * update readme * add a workflow * update publish version as a test
1 parent d73174a commit d04a1f1

File tree

6 files changed

+247
-6
lines changed

6 files changed

+247
-6
lines changed

.github/workflows/publish.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
name: Publish
2+
3+
on:
4+
release:
5+
# We'll run this workflow when a new GitHub release is created
6+
types: [released]
7+
8+
jobs:
9+
publish:
10+
name: Release build and publish
11+
runs-on: ubuntu-latest
12+
steps:
13+
- name: Check out code
14+
uses: actions/checkout@v2
15+
- name: Set up JDK 11
16+
uses: actions/setup-java@v2
17+
with:
18+
distribution: adopt
19+
java-version: 11
20+
21+
# Builds the release artifacts of the library
22+
- name: Release build
23+
run: ./gradlew :savedstateflow:assembleRelease
24+
25+
# Generates other artifacts (javadocJar is optional)
26+
- name: Source jar and dokka
27+
run: ./gradlew androidSourcesJar
28+
29+
# Runs upload, and then closes & releases the repository
30+
- name: Publish to MavenCentral
31+
run: ./gradlew publishReleasePublicationToSonatypeRepository --max-workers 1 closeAndReleaseSonatypeStagingRepository
32+
env:
33+
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
34+
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
35+
SIGNING_KEY_ID: ${{ secrets.SIGNING_KEY_ID }}
36+
SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }}
37+
SIGNING_KEY: ${{ secrets.SIGNING_KEY }}
38+
SONATYPE_STAGING_PROFILE_ID: ${{ secrets.SONATYPE_STAGING_PROFILE_ID }}

README.md

Lines changed: 74 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,77 @@
11
# SavedStateFlow
2-
A Kotlin StateFlow that persists the Android process death
32

4-
* [SavedStateFlow.kt](https://github.com/plusmobileapps/SavedStateFlow/blob/main/savedstateflow/src/main/java/com/plusmobileapps/savedstateflow/SavedStateFlow.kt)
5-
* [ViewModel example](https://github.com/plusmobileapps/SavedStateFlow/blob/main/sample/src/main/java/com/plusmobileapps/savedstateflow/MainViewModel.kt)
3+
A Kotlin [StateFlow](https://developer.android.com/kotlin/flow/stateflow-and-sharedflow) wrapper around [SavedStateHandle.getLiveData()](https://developer.android.com/topic/libraries/architecture/viewmodel-savedstate)
64

7-
![](docs/saved-state-flow.gif)
5+
* [SavedStateFlow.kt](https://github.com/plusmobileapps/SavedStateFlow/blob/main/savedstateflow/src/main/java/com/plusmobileapps/savedstateflow/SavedStateFlow.kt) - all the code for this simple library
6+
* [ViewModel example](https://github.com/plusmobileapps/SavedStateFlow/blob/main/sample/src/main/java/com/plusmobileapps/savedstateflow/MainViewModel.kt) - sample usage of `SavedStateFlow` in a `ViewModel`
7+
8+
![](docs/saved-state-flow.gif)
9+
10+
## Setup
11+
12+
[![Maven Central](https://img.shields.io/maven-central/v/com.plusmobileapps/saved-state-flow?color=blue)](https://search.maven.org/artifact/com.plumobileapps/saved-state-flow)
13+
14+
### Groovy Gradle
15+
16+
```groovy
17+
implementation "com.plusmobileapps:saved-state-flow:<version>"
18+
```
19+
20+
### Kotlin Gradle
21+
22+
```kotlin
23+
implementation("com.plusmobileapps:saved-state-flow:<version>")
24+
```
25+
26+
## Usage
27+
28+
Inject a `SavedStateHandle` into a `ViewModel`, now use the `SavedStateFlow` extension function.
29+
30+
```kotlin
31+
class MainViewModel(savedStateHandle: SavedStateHandle) : ViewModel() {
32+
33+
private val query = SavedStateFlow(
34+
savedStateHandle = savedStateHandle,
35+
key = "main-viewmodel-query-key",
36+
defaultValue = ""
37+
)
38+
39+
init {
40+
observeQuery()
41+
}
42+
43+
fun updateQuery(query: String) {
44+
this.query.value = query
45+
}
46+
47+
private fun observeQuery() {
48+
viewModelScope.launch {
49+
query.asStateFlow()
50+
.flatMapLatest { query ->
51+
NewsRepository.fetchQuery(query) // fetch latest query results
52+
}
53+
.collect { results ->
54+
// TODO post latest results
55+
}
56+
}
57+
}
58+
59+
}
60+
```
61+
62+
## How To Publish Locally
63+
64+
Add the following properties in your `local.properties` file.
65+
66+
```
67+
signing.keyId=gpg-key-id
68+
signing.password=gpg-key-passphrase
69+
signing.key=gpg-key
70+
ossrhUsername=jira-username
71+
ossrhPassword=jira-password
72+
sonatypeStagingProfileId=some-profile-id
73+
```
74+
75+
## Resources
76+
77+
* [How to publish libraries in 2021](https://getstream.io/blog/publishing-libraries-to-mavencentral-2021/)

build.gradle

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,12 @@ plugins {
77
id 'com.android.application' version '7.0.0' apply false
88
id 'com.android.library' version '7.0.0' apply false
99
id 'org.jetbrains.kotlin.android' version '1.5.31' apply false
10+
id("io.github.gradle-nexus.publish-plugin") version "1.1.0"
11+
id("org.jetbrains.dokka") version "1.6.10"
1012
}
1113

1214
task clean(type: Delete) {
1315
delete rootProject.buildDir
14-
}
16+
}
17+
18+
apply from: "${rootDir}/scripts/publish-root.gradle"

savedstateflow/build.gradle

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@ plugins {
33
id 'org.jetbrains.kotlin.android'
44
}
55

6+
ext {
7+
PUBLISH_GROUP_ID = 'com.plusmobileapps'
8+
PUBLISH_VERSION = '0.2'
9+
PUBLISH_ARTIFACT_ID = 'saved-state-flow'
10+
}
11+
612
android {
713
compileSdk 31
814

@@ -39,4 +45,6 @@ dependencies {
3945
testImplementation "io.mockk:mockk:1.12.1"
4046
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.0'
4147
testImplementation 'app.cash.turbine:turbine:0.7.0'
42-
}
48+
}
49+
50+
apply from: "${rootProject.projectDir}/scripts/publish-module.gradle"

scripts/publish-module.gradle

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
apply plugin: 'maven-publish'
2+
apply plugin: 'signing'
3+
apply plugin: 'org.jetbrains.dokka'
4+
5+
task androidSourcesJar(type: Jar) {
6+
archiveClassifier.set('sources')
7+
if (project.plugins.findPlugin("com.android.library")) {
8+
// For Android libraries
9+
from android.sourceSets.main.java.srcDirs
10+
from android.sourceSets.main.kotlin.srcDirs
11+
} else {
12+
// For pure Kotlin libraries, in case you have them
13+
from sourceSets.main.java.srcDirs
14+
from sourceSets.main.kotlin.srcDirs
15+
}
16+
}
17+
18+
artifacts {
19+
archives androidSourcesJar
20+
}
21+
22+
group = PUBLISH_GROUP_ID
23+
version = PUBLISH_VERSION
24+
25+
afterEvaluate {
26+
publishing {
27+
publications {
28+
release(MavenPublication) {
29+
// The coordinates of the library, being set from variables that
30+
// we'll set up later
31+
groupId PUBLISH_GROUP_ID
32+
artifactId PUBLISH_ARTIFACT_ID
33+
version PUBLISH_VERSION
34+
35+
// Two artifacts, the `aar` (or `jar`) and the sources
36+
if (project.plugins.findPlugin("com.android.library")) {
37+
from components.release
38+
} else {
39+
from components.java
40+
}
41+
42+
artifact androidSourcesJar
43+
// artifact javadocJar //FIXME
44+
45+
// Mostly self-explanatory metadata
46+
pom {
47+
name = PUBLISH_ARTIFACT_ID
48+
description = 'SavedStateFlow - StateFlow wrapper around SavedStateHandle'
49+
url = 'https://github.com/plusmobileapps/SavedStateFlow'
50+
licenses {
51+
license {
52+
name = 'SavedStateFlow License'
53+
url = 'https://github.com/plusmobileapps/SavedStateFlow/blob/main/LICENSE'
54+
}
55+
}
56+
developers {
57+
developer {
58+
id = 'andrew@plusmobileapps.com'
59+
name = 'Andrew Steinmetz'
60+
email = 'andrew@plusmobileapps.com'
61+
}
62+
// Add all other devs here...
63+
}
64+
65+
// Version control info - if you're using GitHub, follow the
66+
// format as seen here
67+
scm {
68+
connection = 'scm:git:github.com/plusmobileapps/SavedStateFlow.git'
69+
developerConnection = 'scm:git:ssh://github.com/plusmobileapps/SavedStateFlow.git'
70+
url = 'https://github.com/plusmobileapps/SavedStateFlow/tree/main'
71+
}
72+
}
73+
}
74+
}
75+
}
76+
}
77+
78+
signing {
79+
useInMemoryPgpKeys(
80+
rootProject.ext["signing.keyId"],
81+
rootProject.ext["signing.key"],
82+
rootProject.ext["signing.password"],
83+
)
84+
sign publishing.publications
85+
}

scripts/publish-root.gradle

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Create variables with empty default values
2+
ext["signing.keyId"] = ''
3+
ext["signing.password"] = ''
4+
ext["signing.key"] = ''
5+
ext["ossrhUsername"] = ''
6+
ext["ossrhPassword"] = ''
7+
ext["sonatypeStagingProfileId"] = ''
8+
9+
File secretPropsFile = project.rootProject.file('local.properties')
10+
if (secretPropsFile.exists()) {
11+
// Read local.properties file first if it exists
12+
Properties p = new Properties()
13+
new FileInputStream(secretPropsFile).withCloseable { is -> p.load(is) }
14+
p.each { name, value -> ext[name] = value }
15+
} else {
16+
// Use system environment variables
17+
ext["ossrhUsername"] = System.getenv('OSSRH_USERNAME')
18+
ext["ossrhPassword"] = System.getenv('OSSRH_PASSWORD')
19+
ext["sonatypeStagingProfileId"] = System.getenv('SONATYPE_STAGING_PROFILE_ID')
20+
ext["signing.keyId"] = System.getenv('SIGNING_KEY_ID')
21+
ext["signing.password"] = System.getenv('SIGNING_PASSWORD')
22+
ext["signing.key"] = System.getenv('SIGNING_KEY')
23+
}
24+
25+
// Set up Sonatype repository
26+
nexusPublishing {
27+
repositories {
28+
sonatype {
29+
nexusUrl.set(uri("https://s01.oss.sonatype.org/service/local/"))
30+
snapshotRepositoryUrl.set(uri("https://s01.oss.sonatype.org/content/repositories/snapshots/"))
31+
stagingProfileId = sonatypeStagingProfileId
32+
username = ossrhUsername
33+
password = ossrhPassword
34+
}
35+
}
36+
}

0 commit comments

Comments
 (0)