Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 135 additions & 18 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,49 +7,166 @@ on:
- main

permissions:
# write is needed to create the tag and the GitHub release
contents: write
contents: read
pull-requests: read

env:
# Where releases go: streamRepo, central, or streamRepo,central. Central is a manual
# escape hatch for a release that has to go out when the Stream repository cannot take it.
PUBLISH_TARGETS: streamRepo

jobs:
Release:
name: 🚀 Release
if: github.event.pull_request.merged && startsWith(github.head_ref, 'release-')
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
stream_repo: ${{ steps.version.outputs.stream_repo }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
fetch-depth: 0

- uses: actions/github-script@v6
with:
script: |
const get_change_log_diff = require('./scripts/get_changelog_diff.js')
core.exportVariable('CHANGELOG', get_change_log_diff())

// Getting the release version from the PR source branch
// Source branch looks like this: release-1.0.0
const version = context.payload.pull_request.head.ref.split('-')[1]
core.exportVariable('VERSION', version)
# Getting the release version from the PR source branch
# Source branch looks like this: release-1.0.0
- name: Read the version
id: version
env:
HEAD_REF: ${{ github.head_ref }}
run: |
echo "version=${HEAD_REF#release-}" >> "$GITHUB_OUTPUT"
echo "stream_repo=${{ contains(env.PUBLISH_TARGETS, 'streamRepo') }}" >> "$GITHUB_OUTPUT"

- name: Publish to MavenCentral
- name: Write the signing keyring
run: |
sudo bash -c "echo '$GPG_KEY_CONTENTS' | base64 -d > '$SIGNING_SECRET_KEY_RING_FILE'"
./gradlew publishToSonatype --no-daemon --max-workers 1 closeAndReleaseSonatypeStagingRepository
env:
GPG_KEY_CONTENTS: ${{ secrets.GPG_KEY_CONTENTS }}
SIGNING_SECRET_KEY_RING_FILE: ${{ secrets.SIGNING_SECRET_KEY_RING_FILE }}

# An env var rather than -P, so a value with a space cannot split into a second argument.
- name: Select publish targets
run: echo "ORG_GRADLE_PROJECT_streamPublishTargets=$PUBLISH_TARGETS" >> "$GITHUB_ENV"

# Stages a signed Maven-2 tree under build/staged-repo for the upload job.
- name: Stage for the Stream repository
if: ${{ contains(env.PUBLISH_TARGETS, 'streamRepo') }}
run: ./gradlew publishAllPublicationsToStreamRepoStagingRepository --no-daemon --max-workers 1
env:
STREAM_KEY: ${{ secrets.STREAM_KEY }}
STREAM_SECRET: ${{ secrets.STREAM_SECRET }}
SIGNING_KEY_ID: ${{ secrets.SIGNING_KEY_ID }}
SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }}
SIGNING_SECRET_KEY_RING_FILE: ${{ secrets.SIGNING_SECRET_KEY_RING_FILE }}

- name: Publish to MavenCentral
if: ${{ contains(env.PUBLISH_TARGETS, 'central') }}
run: ./gradlew publishToSonatype --no-daemon --max-workers 1 closeAndReleaseSonatypeStagingRepository
env:
STREAM_KEY: ${{ secrets.STREAM_KEY }}
STREAM_SECRET: ${{ secrets.STREAM_SECRET }}
GPG_KEY_CONTENTS: ${{ secrets.GPG_KEY_CONTENTS }}
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
SIGNING_KEY_ID: ${{ secrets.SIGNING_KEY_ID }}
SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }}
SIGNING_SECRET_KEY_RING_FILE: ${{ secrets.SIGNING_SECRET_KEY_RING_FILE }}
SONATYPE_STAGING_PROFILE_ID: ${{ secrets.SONATYPE_STAGING_PROFILE_ID }}

# Handed to a job that has never seen the signing key -- the reason Gradle stages to a
# directory instead of writing to the bucket itself.
- name: Hand the staged tree to the upload job
if: ${{ contains(env.PUBLISH_TARGETS, 'streamRepo') }}
uses: actions/upload-artifact@v4
with:
name: stream-repo-staged
path: build/staged-repo
retention-days: 1
if-no-files-found: error

# Separate job: secrets are injected per job, so this one holds the R2 credential and never the
# signing key, and the Release job holds the signing key and never the R2 credential.
Upload:
name: ☁️ Upload to the Stream repository
needs: Release
if: ${{ needs.Release.outputs.stream_repo == 'true' }}
runs-on: ubuntu-latest
steps:
- name: Download the staged tree
uses: actions/download-artifact@v4
with:
name: stream-repo-staged
path: build/staged-repo

- name: Publish to the Stream repository
uses: GetStream/stream-build-conventions-android/.github/actions/publish-to-stream-repo@v1.0.1
with:
staged-directory: build/staged-repo
channel: releases
endpoint: ${{ secrets.STREAM_REPO_ENDPOINT }}
bucket: ${{ secrets.STREAM_REPO_BUCKET }}
access-key-id: ${{ secrets.STREAM_REPO_ACCESS_KEY_ID }}
secret-access-key: ${{ secrets.STREAM_REPO_SECRET_ACCESS_KEY }}

# The tag and the GitHub release only once the artifact is actually resolvable: after the
# upload when the Stream repository is a target, straight after publishing when it is not.
GitHub-Release:
name: 🏷️ Create the GitHub release
needs: [Release, Upload]
if: >-
${{ always()
&& needs.Release.result == 'success'
&& (needs.Upload.result == 'success' || needs.Upload.result == 'skipped') }}
runs-on: ubuntu-latest
permissions:
# write is needed to create the tag and the GitHub release
contents: write
steps:
- uses: actions/checkout@v4

- uses: actions/github-script@v7
with:
script: |
const get_change_log_diff = require('./scripts/get_changelog_diff.js')
require('fs').writeFileSync('changes.md', get_change_log_diff())

# Customers need a repository line to see a version that is not on Central.
- name: Write the release notes
env:
VERSION: ${{ needs.Release.outputs.version }}
run: |
: > notes.md
if [ "$PUBLISH_TARGETS" == "streamRepo" ]; then
cat > notes.md <<EOF
> [!IMPORTANT]
> **\`io.getstream:stream-chat-java:$VERSION\` is published to the Stream Maven repository, not Maven Central.**
>
> Gradle (\`build.gradle.kts\`):
> \`\`\`kotlin
> repositories {
> mavenCentral()
> maven("https://stream-io-repo.com")
> }
> \`\`\`
>
> Maven (\`pom.xml\`):
> \`\`\`xml
> <repositories>
> <repository>
> <id>stream</id>
> <url>https://stream-io-repo.com</url>
> </repository>
> </repositories>
> \`\`\`

EOF
fi
cat changes.md >> notes.md

- name: Create release on GitHub
uses: ncipollo/release-action@v1
with:
body: ${{ env.CHANGELOG }}
tag: ${{ env.VERSION }}
bodyFile: notes.md
tag: ${{ needs.Release.outputs.version }}
commit: ${{ github.event.pull_request.merge_commit_sha }}
token: ${{ secrets.GITHUB_TOKEN }}
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,36 @@ For the client-side integrations (web and mobile) have a look at the JavaScript,

> The Stream chat Java SDK is compatible with Groovy, Scala, Kotlin and Clojure.

### Repository

Releases are published to the Stream Maven repository. Add it next to Maven Central.

#### Gradle

```gradle
repositories {
mavenCentral()
maven { url "https://stream-io-repo.com" }
}
```

#### Maven

```maven
<repositories>
<repository>
<id>stream</id>
<url>https://stream-io-repo.com</url>
</repository>
</repositories>
```

#### Leiningen

```leiningen
:repositories [["stream" "https://stream-io-repo.com"]]
```

### Installation for Java

#### Gradle
Expand Down
17 changes: 17 additions & 0 deletions publish.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@ if (secretPropsFile.exists()) {
ext["sonatypeStagingProfileId"] = System.getenv('SONATYPE_STAGING_PROFILE_ID')
}

// Where to publish: "streamRepo", "central", or both, comma-separated. CI always passes it;
// with nothing passed this stays on Central so a local publishToMavenLocal behaves as before.
// streamRepo stages a Maven-2 tree under build/staged-repo for a separate upload job.
def publishTargets = (findProperty("streamPublishTargets") ?: "central").toString()
.split(",").collect { it.trim() }.findAll { !it.isEmpty() }.toSet()
if (publishTargets.isEmpty() || !(publishTargets - ["central", "streamRepo"]).isEmpty()) {
throw new GradleException("'streamPublishTargets' must be a comma-separated subset of central, streamRepo but was '$publishTargets'")
}

nexusPublishing {
repositories {
sonatype {
Expand Down Expand Up @@ -85,6 +94,14 @@ afterEvaluate {
configurePom(pom)
}
}
if ("streamRepo" in publishTargets) {
repositories {
maven {
name = "streamRepoStaging"
url = layout.buildDirectory.dir("staged-repo").get().asFile.toURI()
}
}
}
}
}

Expand Down
Loading