Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Publish library #3

Merged
merged 4 commits into from
Dec 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
38 changes: 38 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: Publish

on:
release:
# We'll run this workflow when a new GitHub release is created
types: [released]

jobs:
publish:
name: Release build and publish
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v2
- name: Set up JDK 11
uses: actions/setup-java@v2
with:
distribution: adopt
java-version: 11

# Builds the release artifacts of the library
- name: Release build
run: ./gradlew :savedstateflow:assembleRelease

# Generates other artifacts (javadocJar is optional)
- name: Source jar and dokka
run: ./gradlew androidSourcesJar

# Runs upload, and then closes & releases the repository
- name: Publish to MavenCentral
run: ./gradlew publishReleasePublicationToSonatypeRepository --max-workers 1 closeAndReleaseSonatypeStagingRepository
env:
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
SIGNING_KEY_ID: ${{ secrets.SIGNING_KEY_ID }}
SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }}
SIGNING_KEY: ${{ secrets.SIGNING_KEY }}
SONATYPE_STAGING_PROFILE_ID: ${{ secrets.SONATYPE_STAGING_PROFILE_ID }}
78 changes: 74 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,77 @@
# SavedStateFlow
A Kotlin StateFlow that persists the Android process death

* [SavedStateFlow.kt](https://github.com/plusmobileapps/SavedStateFlow/blob/main/savedstateflow/src/main/java/com/plusmobileapps/savedstateflow/SavedStateFlow.kt)
* [ViewModel example](https://github.com/plusmobileapps/SavedStateFlow/blob/main/sample/src/main/java/com/plusmobileapps/savedstateflow/MainViewModel.kt)
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)

![](docs/saved-state-flow.gif)
* [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
* [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`

![](docs/saved-state-flow.gif)

## Setup

[![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)

### Groovy Gradle

```groovy
implementation "com.plusmobileapps:saved-state-flow:<version>"
```

### Kotlin Gradle

```kotlin
implementation("com.plusmobileapps:saved-state-flow:<version>")
```

## Usage

Inject a `SavedStateHandle` into a `ViewModel`, now use the `SavedStateFlow` extension function.

```kotlin
class MainViewModel(savedStateHandle: SavedStateHandle) : ViewModel() {

private val query = SavedStateFlow(
savedStateHandle = savedStateHandle,
key = "main-viewmodel-query-key",
defaultValue = ""
)

init {
observeQuery()
}

fun updateQuery(query: String) {
this.query.value = query
}

private fun observeQuery() {
viewModelScope.launch {
query.asStateFlow()
.flatMapLatest { query ->
NewsRepository.fetchQuery(query) // fetch latest query results
}
.collect { results ->
// TODO post latest results
}
}
}

}
```

## How To Publish Locally

Add the following properties in your `local.properties` file.

```
signing.keyId=gpg-key-id
signing.password=gpg-key-passphrase
signing.key=gpg-key
ossrhUsername=jira-username
ossrhPassword=jira-password
sonatypeStagingProfileId=some-profile-id
```

## Resources

* [How to publish libraries in 2021](https://getstream.io/blog/publishing-libraries-to-mavencentral-2021/)
6 changes: 5 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@ plugins {
id 'com.android.application' version '7.0.0' apply false
id 'com.android.library' version '7.0.0' apply false
id 'org.jetbrains.kotlin.android' version '1.5.31' apply false
id("io.github.gradle-nexus.publish-plugin") version "1.1.0"
id("org.jetbrains.dokka") version "1.6.10"
}

task clean(type: Delete) {
delete rootProject.buildDir
}
}

apply from: "${rootDir}/scripts/publish-root.gradle"
10 changes: 9 additions & 1 deletion savedstateflow/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ plugins {
id 'org.jetbrains.kotlin.android'
}

ext {
PUBLISH_GROUP_ID = 'com.plusmobileapps'
PUBLISH_VERSION = '0.2'
PUBLISH_ARTIFACT_ID = 'saved-state-flow'
}

android {
compileSdk 31

Expand Down Expand Up @@ -39,4 +45,6 @@ dependencies {
testImplementation "io.mockk:mockk:1.12.1"
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.0'
testImplementation 'app.cash.turbine:turbine:0.7.0'
}
}

apply from: "${rootProject.projectDir}/scripts/publish-module.gradle"
85 changes: 85 additions & 0 deletions scripts/publish-module.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
apply plugin: 'maven-publish'
apply plugin: 'signing'
apply plugin: 'org.jetbrains.dokka'

task androidSourcesJar(type: Jar) {
archiveClassifier.set('sources')
if (project.plugins.findPlugin("com.android.library")) {
// For Android libraries
from android.sourceSets.main.java.srcDirs
from android.sourceSets.main.kotlin.srcDirs
} else {
// For pure Kotlin libraries, in case you have them
from sourceSets.main.java.srcDirs
from sourceSets.main.kotlin.srcDirs
}
}

artifacts {
archives androidSourcesJar
}

group = PUBLISH_GROUP_ID
version = PUBLISH_VERSION

afterEvaluate {
publishing {
publications {
release(MavenPublication) {
// The coordinates of the library, being set from variables that
// we'll set up later
groupId PUBLISH_GROUP_ID
artifactId PUBLISH_ARTIFACT_ID
version PUBLISH_VERSION

// Two artifacts, the `aar` (or `jar`) and the sources
if (project.plugins.findPlugin("com.android.library")) {
from components.release
} else {
from components.java
}

artifact androidSourcesJar
// artifact javadocJar //FIXME
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure why this was breaking the build


// Mostly self-explanatory metadata
pom {
name = PUBLISH_ARTIFACT_ID
description = 'SavedStateFlow - StateFlow wrapper around SavedStateHandle'
url = 'https://github.com/plusmobileapps/SavedStateFlow'
licenses {
license {
name = 'SavedStateFlow License'
url = 'https://github.com/plusmobileapps/SavedStateFlow/blob/main/LICENSE'
}
}
developers {
developer {
id = 'andrew@plusmobileapps.com'
name = 'Andrew Steinmetz'
email = 'andrew@plusmobileapps.com'
}
// Add all other devs here...
}

// Version control info - if you're using GitHub, follow the
// format as seen here
scm {
connection = 'scm:git:github.com/plusmobileapps/SavedStateFlow.git'
developerConnection = 'scm:git:ssh://github.com/plusmobileapps/SavedStateFlow.git'
url = 'https://github.com/plusmobileapps/SavedStateFlow/tree/main'
}
}
}
}
}
}

signing {
useInMemoryPgpKeys(
rootProject.ext["signing.keyId"],
rootProject.ext["signing.key"],
rootProject.ext["signing.password"],
)
sign publishing.publications
}
36 changes: 36 additions & 0 deletions scripts/publish-root.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Create variables with empty default values
ext["signing.keyId"] = ''
ext["signing.password"] = ''
ext["signing.key"] = ''
ext["ossrhUsername"] = ''
ext["ossrhPassword"] = ''
ext["sonatypeStagingProfileId"] = ''

File secretPropsFile = project.rootProject.file('local.properties')
if (secretPropsFile.exists()) {
// Read local.properties file first if it exists
Properties p = new Properties()
new FileInputStream(secretPropsFile).withCloseable { is -> p.load(is) }
p.each { name, value -> ext[name] = value }
} else {
// Use system environment variables
ext["ossrhUsername"] = System.getenv('OSSRH_USERNAME')
ext["ossrhPassword"] = System.getenv('OSSRH_PASSWORD')
ext["sonatypeStagingProfileId"] = System.getenv('SONATYPE_STAGING_PROFILE_ID')
ext["signing.keyId"] = System.getenv('SIGNING_KEY_ID')
ext["signing.password"] = System.getenv('SIGNING_PASSWORD')
ext["signing.key"] = System.getenv('SIGNING_KEY')
}

// Set up Sonatype repository
nexusPublishing {
repositories {
sonatype {
nexusUrl.set(uri("https://s01.oss.sonatype.org/service/local/"))
snapshotRepositoryUrl.set(uri("https://s01.oss.sonatype.org/content/repositories/snapshots/"))
stagingProfileId = sonatypeStagingProfileId
username = ossrhUsername
password = ossrhPassword
}
}
}