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
39 changes: 39 additions & 0 deletions .github/workflows/publish-sonatype.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# This workflow is triggered when a GitHub release is created.
# It can also be run manually to re-publish to Sonatype in case it failed for some reason.
# You can run this workflow by navigating to https://www.github.com/OneBusAway/java-sdk/actions/workflows/publish-sonatype.yml
name: Publish Sonatype
on:
workflow_dispatch:

release:
types: [published]

jobs:
publish:
name: publish
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Set up Java
uses: actions/setup-java@v3
with:
distribution: temurin
java-version: |
8
17
cache: gradle

- name: Set up Gradle
uses: gradle/gradle-build-action@v2

- name: Publish to Sonatype
run: |
./gradlew --parallel --no-daemon publish
env:
SONATYPE_USERNAME: ${{ secrets.ONEBUSAWAY_SDK_SONATYPE_USERNAME || secrets.SONATYPE_USERNAME }}
SONATYPE_PASSWORD: ${{ secrets.ONEBUSAWAY_SDK_SONATYPE_PASSWORD || secrets.SONATYPE_PASSWORD }}
GPG_SIGNING_KEY_ID: ${{ secrets.ONEBUSAWAY_SDK_SONATYPE_GPG_SIGNING_KEY_ID || secrets.GPG_SIGNING_KEY_ID }}
GPG_SIGNING_KEY: ${{ secrets.ONEBUSAWAY_SDK_SONATYPE_GPG_SIGNING_KEY || secrets.GPG_SIGNING_KEY }}
GPG_SIGNING_PASSWORD: ${{ secrets.ONEBUSAWAY_SDK_SONATYPE_GPG_SIGNING_PASSWORD || secrets.GPG_SIGNING_PASSWORD }}
25 changes: 25 additions & 0 deletions .github/workflows/release-doctor.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: Release Doctor
on:
pull_request:
branches:
- main
workflow_dispatch:

jobs:
release_doctor:
name: release doctor
runs-on: ubuntu-latest
if: github.repository == 'OneBusAway/java-sdk' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next')

steps:
- uses: actions/checkout@v4

- name: Check release environment
run: |
bash ./bin/check-release-environment
env:
SONATYPE_USERNAME: ${{ secrets.ONEBUSAWAY_SDK_SONATYPE_USERNAME || secrets.SONATYPE_USERNAME }}
SONATYPE_PASSWORD: ${{ secrets.ONEBUSAWAY_SDK_SONATYPE_PASSWORD || secrets.SONATYPE_PASSWORD }}
GPG_SIGNING_KEY_ID: ${{ secrets.ONEBUSAWAY_SDK_SONATYPE_GPG_SIGNING_KEY_ID || secrets.GPG_SIGNING_KEY_ID }}
GPG_SIGNING_KEY: ${{ secrets.ONEBUSAWAY_SDK_SONATYPE_GPG_SIGNING_KEY || secrets.GPG_SIGNING_KEY }}
GPG_SIGNING_PASSWORD: ${{ secrets.ONEBUSAWAY_SDK_SONATYPE_GPG_SIGNING_PASSWORD || secrets.GPG_SIGNING_PASSWORD }}
3 changes: 3 additions & 0 deletions .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
".": "0.0.1-alpha.0"
}
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
# Onebusaway SDK Java API Library

<!-- x-release-please-start-version -->

[![Maven Central](https://img.shields.io/maven-central/v/com.open_transit.api/onebusaway-sdk-java)](https://central.sonatype.com/artifact/com.open_transit.api/onebusaway-sdk-java/0.0.1-alpha.0)

<!-- x-release-please-end -->

The Onebusaway SDK Java SDK provides convenient access to the Onebusaway SDK REST API from applications written in Java. It includes helper classes with helpful types and documentation for every request and response property.

The Onebusaway SDK Java SDK is similar to the Onebusaway SDK Kotlin SDK but with minor differences that make it more ergonomic for use in Java, such as `Optional` instead of nullable values, `Stream` instead of `Sequence`, and `CompletableFuture` instead of suspend functions.
Expand All @@ -20,6 +24,8 @@ The REST API documentation can be found on [developer.onebusaway.org](https://d

#### Gradle

<!-- x-release-please-start-version -->

```kotlin
implementation("com.open_transit.api:onebusaway-sdk-java:0.0.1-alpha.0")
```
Expand All @@ -34,6 +40,8 @@ implementation("com.open_transit.api:onebusaway-sdk-java:0.0.1-alpha.0")
</dependency>
```

<!-- x-release-please-end -->

### Configure the client

Use `OnebusawaySdkOkHttpClient.builder()` to configure the client. At a minimum you need to set `.apiKey()`:
Expand Down Expand Up @@ -241,7 +249,7 @@ This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) con

We take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.

We are keen for your feedback; please open an [issue](https://www.github.com/stainless-sdks/open-transit-java/issues) with questions, bugs, or suggestions.
We are keen for your feedback; please open an [issue](https://www.github.com/OneBusAway/java-sdk/issues) with questions, bugs, or suggestions.

## Requirements

Expand Down
33 changes: 33 additions & 0 deletions bin/check-release-environment
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/usr/bin/env bash

errors=()

if [ -z "${SONATYPE_USERNAME}" ]; then
errors+=("The ONEBUSAWAY_SDK_SONATYPE_USERNAME secret has not been set. Please set it in either this repository's secrets or your organization secrets")
fi

if [ -z "${SONATYPE_PASSWORD}" ]; then
errors+=("The ONEBUSAWAY_SDK_SONATYPE_PASSWORD secret has not been set. Please set it in either this repository's secrets or your organization secrets")
fi

if [ -z "${GPG_SIGNING_KEY}" ]; then
errors+=("The ONEBUSAWAY_SDK_SONATYPE_GPG_SIGNING_KEY secret has not been set. Please set it in either this repository's secrets or your organization secrets")
fi

if [ -z "${GPG_SIGNING_PASSWORD}" ]; then
errors+=("The ONEBUSAWAY_SDK_SONATYPE_GPG_SIGNING_PASSWORD secret has not been set. Please set it in either this repository's secrets or your organization secrets")
fi

lenErrors=${#errors[@]}

if [[ lenErrors -gt 0 ]]; then
echo -e "Found the following errors in the release environment:\n"

for error in "${errors[@]}"; do
echo -e "- $error\n"
done

exit 1
fi

echo "The environment is ready to push releases!"
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ plugins {

allprojects {
group = "com.open_transit.api"
version = "0.0.1-alpha.0"
version = "0.0.1-alpha.0" // x-release-please-version
}

nexusPublishing {
Expand Down
6 changes: 3 additions & 3 deletions buildSrc/src/main/kotlin/onebusaway-sdk.publish.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ configure<PublishingExtension> {
}

scm {
connection.set("scm:git:git://github.com/stainless-sdks/open-transit-java.git")
developerConnection.set("scm:git:git://github.com/stainless-sdks/open-transit-java.git")
url.set("https://github.com/stainless-sdks/open-transit-java")
connection.set("scm:git:git://github.com/OneBusAway/java-sdk.git")
developerConnection.set("scm:git:git://github.com/OneBusAway/java-sdk.git")
url.set("https://github.com/OneBusAway/java-sdk")
}

versionMapping {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,16 @@ private constructor(

maybeAddIdempotencyHeader(request)

// Don't send the current retry count in the headers if the caller set their own value.
val shouldSendRetryCount = !request.headers.containsKey("x-stainless-retry-count")

var retries = 0

while (true) {
if (shouldSendRetryCount) {
setRetryCountHeader(request, retries)
}

val response =
try {
val response = httpClient.execute(request, requestOptions)
Expand Down Expand Up @@ -74,10 +81,21 @@ private constructor(

maybeAddIdempotencyHeader(request)

// Don't send the current retry count in the headers if the caller set their own value.
val shouldSendRetryCount = !request.headers.containsKey("x-stainless-retry-count")

var retries = 0

fun wrap(future: CompletableFuture<HttpResponse>): CompletableFuture<HttpResponse> {
return future
fun executeWithRetries(
request: HttpRequest,
requestOptions: RequestOptions,
): CompletableFuture<HttpResponse> {
if (shouldSendRetryCount) {
setRetryCountHeader(request, retries)
}

return httpClient
.executeAsync(request, requestOptions)
.handleAsync(
fun(
response: HttpResponse?,
Expand All @@ -97,15 +115,15 @@ private constructor(

val backoffMillis = getRetryBackoffMillis(retries, response)
return sleepAsync(backoffMillis.toMillis()).thenCompose {
wrap(httpClient.executeAsync(request, requestOptions))
executeWithRetries(request, requestOptions)
}
},
MoreExecutors.directExecutor()
)
.thenCompose(Function.identity())
}

return wrap(httpClient.executeAsync(request, requestOptions))
return executeWithRetries(request, requestOptions)
}

override fun close() {
Expand All @@ -118,6 +136,11 @@ private constructor(
return request.body?.repeatable() ?: true
}

private fun setRetryCountHeader(request: HttpRequest, retries: Int) {
request.headers.removeAll("x-stainless-retry-count")
request.headers.put("x-stainless-retry-count", retries.toString())
}

private fun idempotencyKey(): String = "stainless-java-retry-${UUID.randomUUID()}"

private fun maybeAddIdempotencyHeader(request: HttpRequest) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import com.open_transit.api.client.okhttp.OkHttpClient
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.ValueSource

@WireMockTest
internal class RetryingHttpClientTest {
Expand Down Expand Up @@ -50,8 +52,9 @@ internal class RetryingHttpClientTest {
verify(1, postRequestedFor(urlPathEqualTo("/something")))
}

@Test
fun retryAfterHeader() {
@ParameterizedTest
@ValueSource(booleans = [false, true])
fun retryAfterHeader(async: Boolean) {
val request =
HttpRequest.builder().method(HttpMethod.POST).addPathSegment("something").build()
stubFor(
Expand Down Expand Up @@ -79,9 +82,67 @@ internal class RetryingHttpClientTest {
)
val retryingClient =
RetryingHttpClient.builder().httpClient(httpClient).maxRetries(2).build()
val response = retryingClient.execute(request)

val response =
if (async) retryingClient.executeAsync(request).get()
else retryingClient.execute(request)

assertThat(response.statusCode()).isEqualTo(200)
verify(3, postRequestedFor(urlPathEqualTo("/something")))
verify(
1,
postRequestedFor(urlPathEqualTo("/something"))
.withHeader("x-stainless-retry-count", equalTo("0"))
)
verify(
1,
postRequestedFor(urlPathEqualTo("/something"))
.withHeader("x-stainless-retry-count", equalTo("1"))
)
verify(
1,
postRequestedFor(urlPathEqualTo("/something"))
.withHeader("x-stainless-retry-count", equalTo("2"))
)
}

@ParameterizedTest
@ValueSource(booleans = [false, true])
fun overwriteRetryCountHeader(async: Boolean) {
val request =
HttpRequest.builder()
.method(HttpMethod.POST)
.addPathSegment("something")
.putHeader("x-stainless-retry-count", "42")
.build()
stubFor(
post(urlPathEqualTo("/something"))
.inScenario("foo") // first we fail with a retry after header given as a date
.whenScenarioStateIs(Scenario.STARTED)
.willReturn(
serviceUnavailable().withHeader("Retry-After", "Wed, 21 Oct 2015 07:28:00 GMT")
)
.willSetStateTo("RETRY_AFTER_DATE")
)
stubFor(
post(urlPathEqualTo("/something"))
.inScenario("foo") // then we return a success
.whenScenarioStateIs("RETRY_AFTER_DATE")
.willReturn(ok())
.willSetStateTo("COMPLETED")
)
val retryingClient =
RetryingHttpClient.builder().httpClient(httpClient).maxRetries(2).build()

val response =
if (async) retryingClient.executeAsync(request).get()
else retryingClient.execute(request)

assertThat(response.statusCode()).isEqualTo(200)
verify(
2,
postRequestedFor(urlPathEqualTo("/something"))
.withHeader("x-stainless-retry-count", equalTo("42"))
)
}

@Test
Expand Down
67 changes: 67 additions & 0 deletions release-please-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
{
"packages": {
".": {}
},
"$schema": "https://raw.githubusercontent.com/stainless-api/release-please/main/schemas/config.json",
"include-v-in-tag": true,
"include-component-in-tag": false,
"versioning": "prerelease",
"prerelease": true,
"bump-minor-pre-major": true,
"bump-patch-for-minor-pre-major": false,
"pull-request-header": "Automated Release PR",
"pull-request-title-pattern": "release: ${version}",
"changelog-sections": [
{
"type": "feat",
"section": "Features"
},
{
"type": "fix",
"section": "Bug Fixes"
},
{
"type": "perf",
"section": "Performance Improvements"
},
{
"type": "revert",
"section": "Reverts"
},
{
"type": "chore",
"section": "Chores"
},
{
"type": "docs",
"section": "Documentation"
},
{
"type": "style",
"section": "Styles"
},
{
"type": "refactor",
"section": "Refactors"
},
{
"type": "test",
"section": "Tests",
"hidden": true
},
{
"type": "build",
"section": "Build System"
},
{
"type": "ci",
"section": "Continuous Integration",
"hidden": true
}
],
"release-type": "simple",
"extra-files": [
"README.md",
"build.gradle.kts"
]
}