Skip to content

Commit 8e98ad5

Browse files
drewhannayDrew Hannay
andauthored
Set up publishing for Maven Central (#115)
Initial work to publish to Maven Central Co-authored-by: Drew Hannay <dhannay@linkedin.com>
1 parent 269b863 commit 8e98ad5

File tree

12 files changed

+299
-225
lines changed

12 files changed

+299
-225
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
name: Deploy snapshot
2+
on:
3+
push:
4+
branches:
5+
- master
6+
jobs:
7+
publish:
8+
runs-on: ubuntu-latest
9+
if: ${{ !contains(github.event.head_commit.message, 'Prepare for release') }}
10+
steps:
11+
- uses: actions/checkout@v2
12+
13+
- name: Cache Gradle Files
14+
uses: actions/cache@v2
15+
with:
16+
path: |
17+
~/.gradle/caches/
18+
~/.gradle/wrapper/
19+
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
20+
restore-keys: |
21+
${{ runner.os }}-gradle-
22+
23+
- name: Set up Java
24+
uses: actions/setup-java@v1
25+
with:
26+
java-version: 1.8
27+
28+
- name: Build
29+
run: ./gradlew build
30+
31+
- name: Publish package
32+
run: ./gradlew publishAllPublicationsToSonatypeSnapshotRepository
33+
env:
34+
SONATYPE_USER: ${{ secrets.SONATYPE_USER }}
35+
SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: Publish package to the Maven Central Repository
2+
on:
3+
release:
4+
types: [published]
5+
branches:
6+
- master
7+
jobs:
8+
publish:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- uses: actions/checkout@v2
12+
13+
- name: Set up Java
14+
uses: actions/setup-java@v1
15+
with:
16+
java-version: 1.8
17+
18+
- name: Build
19+
run: ./gradlew build
20+
21+
- name: Publish package
22+
run: ./gradlew publishAllPublicationsToMavenCentralRepository
23+
env:
24+
SONATYPE_USER: ${{ secrets.SONATYPE_USER }}
25+
SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}
26+
SPYGLASS_GPG_PRIVATE_KEY: ${{ secrets.SPYGLASS_GPG_PRIVATE_KEY }}
27+
SPYGLASS_GPG_PRIVATE_KEY_PASSWORD: ${{ secrets.SPYGLASS_GPG_PRIVATE_KEY_PASSWORD }}

README.md

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,18 @@
1-
Spyglass [![Build Status](https://img.shields.io/github/workflow/status/linkedin/Spyglass/Merge%20checks)](https://img.shields.io/github/workflow/status/linkedin/Spyglass/Merge%20checks)
2-
========
1+
# Spyglass [![Build Status](https://img.shields.io/github/workflow/status/linkedin/Spyglass/Merge%20checks)](https://img.shields.io/github/workflow/status/linkedin/Spyglass/Merge%20checks)
32

43
A powerful Android library that provides highly-customizable widgets (with smart defaults) to easily add social-media-esque mention (aka tag) support to your app
54

65
*For a broad overview, check out our [blog post](https://engineering.linkedin.com/android/open-sourcing-spyglass-flexible-library-implementing-mentions-android) at the LinkedIn engineering blog.*
76

8-
Features
9-
--------
7+
## Features
108

119
- A subclass of `EditText` that contains enhanced functionality in order to tokenize user input and display mentions
1210
- A custom view, similar to a `MultiAutoCompleteTextView`, that displays suggestions in an embedded `ListView` rather than a `Popup`
1311
- Custom tokenizer interface, including a default implementation containing several options for customization
1412
- Designed to handle suggestions dynamically as are retrieved from multiple data sources
1513
- Supports both implicit and explicit (i.e. "@User Name") mentions
1614

17-
Getting Started
18-
---------------
15+
## Getting Started
1916

2017
Grab via Maven:
2118
```xml
@@ -30,8 +27,7 @@ or Gradle:
3027
api 'com.linkedin.android.spyglass:spyglass:2.2.0'
3128
```
3229

33-
Overview
34-
---------------
30+
## Overview
3531

3632
Spyglass is divided into three, customizable layers: *tokenization*, *suggestions*, and *mentions*. Together, these layers form the update lifecycle used within Spyglass:
3733

@@ -66,21 +62,34 @@ As the suggestions come in from multiple data sources, the suggestions must be d
6662

6763
All mentions that Spyglass insert must be a subclass of the `MentionSpan`. By default, you can easily tweak how your mentions appear (i.e. highlight and text colors). Additionally, you may alter how they behave when they are deleted via multi-stage deletions. We use this extensively in the LinkedIn app to allow users to delete only the last name of a mentioned member (leaving just the first name).
6864

69-
Usage
70-
-----
65+
## Usage
7166

7267
To use Spyglass, you have two options: the `MentionsEditText` and the `RichEditorView`.
7368

7469
The `MentionsEditText` is a subclass of `EditText`. It contains extra functionality for tokenizing user input into query tokens and inserting new mentions to be displayed. Note that it does not have any view associated with displaying suggestions. You must provide that. This gives you the most power to customize how your mentions-enabled text box feels and behaves. See the "Grid Mentions" example in the sample app for a demo.
7570

7671
The `RichEditorView` is the quickest way to add mentions into your app. It is built on top of the aforementioned `MentionsEditText` and displays suggestions in an embedded `ListView`. It serves a similar functionality as Android's `MultiAutoCompleteTextView`. Note that you can still alter how suggestion items are displayed in the list, and you can still alter the tokenization and mention displaying options used by the underlying `MentionsEditText`.
7772

78-
Sample App
79-
----------
73+
## Sample App
8074

8175
The ''spyglass-sample'' app contains several examples of using the library. For more detailed information, see the documentation [here](spyglass-sample/README.md).
8276

83-
Testing
84-
-------
77+
## Testing
8578

8679
We use the Robolectric framework coupled with Mockito for our unit tests. You can run them via the `gradle clean test` command.
80+
81+
## Snapshots
82+
83+
You can use snapshot builds to test the latest unreleased changes. A new snapshot is published
84+
after every merge to the main branch by the [Deploy Snapshot Github Action workflow](.github/workflows/deploy-snapshot.yml).
85+
86+
Just add the Sonatype snapshot repository to your Gradle scripts:
87+
```gradle
88+
repositories {
89+
maven {
90+
url "https://oss.sonatype.org/content/repositories/snapshots/"
91+
}
92+
}
93+
```
94+
95+
You can find the latest snapshot version to use in the [gradle.properties](gradle.properties) file.

RELEASING.md

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,24 @@
1-
Releasing
2-
=========
1+
# Releasing
32

4-
1. Change the version in `gradle.properties` to a non-SNAPSHOT version.
5-
2. Update the `CHANGELOG.md` for the impending release.
6-
3. Update the `README.md` with the new version.
7-
4. `git commit -am "Prepare for release X.Y.Z."` (where X.Y.Z is the new version)
8-
5. `git tag -a X.Y.Z -m "Version X.Y.Z"` (where X.Y.Z is the new version)
9-
6. `./gradlew clean bintrayUpload`
10-
7. Update the `gradle.properties` to the next SNAPSHOT version.
11-
8. `git commit -am "Prepare next development version."`
12-
9. `git push && git push --tags`
3+
1. Change the version in `gradle.properties` to a non-SNAPSHOT version.
4+
2. Update the `CHANGELOG.md` for the impending release.
5+
3. Update the `README.md` with the new version.
6+
4. `git commit -am "Prepare for release X.Y.Z."` (where X.Y.Z is the new version)
7+
5. `git tag -a X.Y.Z -m "Version X.Y.Z"` (where X.Y.Z is the new version)
8+
6. Update the `gradle.properties` to the next SNAPSHOT version.
9+
7. `git commit -am "Prepare next development version."`
10+
8. `git push && git push --tags`
11+
9. Create a new release in the releases tab on GitHub
12+
10. Wait for the [publish-maven-central.yml](.github/workflows/publish-maven-central.yml) action to complete.
13+
11. Visit [Sonatype Nexus](https://oss.sonatype.org/) and promote the artifact.
1314

15+
## How it works
1416

15-
Prerequisites
16-
-------------
17+
The [deploy-snapshot.yml](.github/workflows/deploy-snapshot.yml) workflow runs on every
18+
push to the main branch as long as the commit message does not contain `Prepare for release`. This
19+
workflow calls Gradle to publish to the Sonatype snapshot repository.
1720

18-
First, you will need a Bintray account with access to the [linkedin-spyglass](https://bintray.com/linkedin-spyglass) organization.
19-
20-
Then, set the following environment variables:
21-
22-
* `BINTRAY_USER` - Bintray username
23-
* `BINTRAY_KEY` - Bintray API key for the given user account
21+
For actual releases, there is a separate [publish-maven-central.yml](.github/workflows/publish-maven-central.yml)
22+
workflow which runs after a new release is created in the GitHub UI. This will call Gradle on the
23+
tagged release commit and upload to the staging repository. After that completes, you will need to
24+
go and promote the artifacts to production.

build.gradle

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
buildscript {
2-
32
repositories {
4-
jcenter()
53
google()
4+
mavenCentral()
5+
jcenter()
66
}
77

88
dependencies {
9-
classpath 'com.android.tools.build:gradle:3.5.3'
9+
classpath 'com.android.tools.build:gradle:4.1.2'
1010
}
1111
}
1212

@@ -22,8 +22,11 @@ ext {
2222

2323
subprojects {
2424
repositories {
25-
jcenter()
2625
google()
26+
mavenCentral()
27+
jcenter()
2728
}
28-
tasks.withType(Javadoc).all { enabled = false }
29+
30+
group = GROUP_ID
31+
version = VERSION_NAME
2932
}

gradle/publishing.gradle

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// Ideally AGP should provide sources and javadoc integration for their components:
2+
// https://issuetracker.google.com/issues/145670440
3+
tasks.register("sourcesJar", Jar) {
4+
classifier 'sources'
5+
from android.sourceSets.main.java.srcDirs
6+
}
7+
8+
tasks.register("javadoc", Javadoc) {
9+
failOnError false
10+
source = android.sourceSets.main.java.srcDirs
11+
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
12+
}
13+
14+
tasks.register("javadocJar", Jar) {
15+
dependsOn javadoc
16+
classifier 'javadoc'
17+
from javadoc.destinationDir
18+
}
19+
20+
// AGP creates the components in afterEvaluate, so we need to use it too
21+
// https://developer.android.com/studio/build/maven-publish-plugin
22+
afterEvaluate {
23+
publishing {
24+
publications {
25+
maven(MavenPublication) {
26+
from components.release
27+
28+
artifact sourcesJar
29+
artifact javadocJar
30+
31+
pom {
32+
name = 'Spyglass'
33+
description = 'Flexible library extending EditText to support mentions on Android.'
34+
url = 'https://github.com/linkedin/Spyglass'
35+
licenses {
36+
license {
37+
name = 'The Apache Software License, Version 2.0'
38+
url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
39+
}
40+
}
41+
developers {
42+
developer {
43+
id = 'com.linkedin'
44+
name = 'LinkedIn Corp'
45+
}
46+
}
47+
scm {
48+
connection = 'scm:git:git://github.com/linkedin/Spyglass.git'
49+
developerConnection = 'scm:git:ssh://github.com:linkedin/Spyglass.git'
50+
url = 'https://github.com/linkedin/Spyglass/tree/master'
51+
}
52+
}
53+
54+
repositories {
55+
def sonatypeUsername = System.getenv("SONATYPE_USER")
56+
def sonatypePassword = System.getenv("SONATYPE_PASSWORD")
57+
maven {
58+
name = "sonatypeSnapshot"
59+
url = "https://oss.sonatype.org/content/repositories/snapshots"
60+
credentials {
61+
username = sonatypeUsername
62+
password = sonatypePassword
63+
}
64+
}
65+
maven {
66+
name = "mavenCentral"
67+
url = "https://oss.sonatype.org/service/local/staging/deploy/maven2"
68+
credentials {
69+
username = sonatypeUsername
70+
password = sonatypePassword
71+
}
72+
}
73+
}
74+
}
75+
}
76+
}
77+
78+
// SPYGLASS_GPG_PRIVATE_KEY should contain the armoured private key that
79+
// starts with -----BEGIN PGP PRIVATE KEY BLOCK-----
80+
// It can be obtained with gpg --armour --export-secret-keys KEY_ID
81+
def signingKey = System.getenv("SPYGLASS_GPG_PRIVATE_KEY")
82+
def signingPassword = System.getenv("SPYGLASS_GPG_PRIVATE_KEY_PASSWORD")
83+
signing {
84+
required { signingKey != null && signingPassword != null }
85+
useInMemoryPgpKeys(signingKey, signingPassword)
86+
sign publishing.publications.maven
87+
}
88+
}

gradle/wrapper/gradle-wrapper.jar

7.99 KB
Binary file not shown.
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
#Wed Sep 26 10:14:49 PDT 2018
21
distributionBase=GRADLE_USER_HOME
32
distributionPath=wrapper/dists
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.2-bin.zip
44
zipStoreBase=GRADLE_USER_HOME
55
zipStorePath=wrapper/dists
6-
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.3-all.zip

0 commit comments

Comments
 (0)