diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ea35f9b9b..4e2000db7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,6 +40,9 @@ jobs: build: timeout-minutes: 15 name: build + permissions: + contents: read + id-token: write runs-on: ${{ github.repository == 'stainless-sdks/increase-java' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: github.event_name == 'push' || github.event.pull_request.head.repo.fork @@ -61,6 +64,21 @@ jobs: - name: Build SDK run: ./scripts/build + - name: Get GitHub OIDC Token + if: github.repository == 'stainless-sdks/increase-java' + id: github-oidc + uses: actions/github-script@v6 + with: + script: core.setOutput('github_token', await core.getIDToken()); + + - name: Build and upload Maven artifacts + if: github.repository == 'stainless-sdks/increase-java' + env: + URL: https://pkg.stainless.com/s + AUTH: ${{ steps.github-oidc.outputs.github_token }} + SHA: ${{ github.sha }} + PROJECT: increase-java + run: ./scripts/upload-artifacts test: timeout-minutes: 15 name: test diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 02bfb399e..842d1edb2 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.395.0" + ".": "0.396.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index af0e17b5e..4b965774e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 232 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/increase%2Fincrease-7a47821c7d33caac95ba05890682dde6da257dbe86033e4f119aa626c11ae387.yml -openapi_spec_hash: 0ccabc90834936bc2fcdeeee01e77a64 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/increase%2Fincrease-a559a6a1a1f3781fad8db5bcb96c40b69a78b952d659395840accce782098e0c.yml +openapi_spec_hash: 2ae62041468e5cf6fe653d65b1b7a58a config_hash: 8a9bb9e2d5dd0ccc3e78ad59f924fd3c diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f3be5af3..887ad68e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## 0.396.0 (2026-01-14) + +Full Changelog: [v0.395.0...v0.396.0](https://github.com/Increase/increase-java/compare/v0.395.0...v0.396.0) + +### Features + +* **api:** api update ([7a3f167](https://github.com/Increase/increase-java/commit/7a3f1676006a0ebdabcb9557b432b0068b9fc19b)) +* **client:** allow configuring dispatcher executor service ([cb9ec15](https://github.com/Increase/increase-java/commit/cb9ec1516cfc976ef1f7ac5256804193c569033a)) + + +### Chores + +* **internal:** support uploading Maven repo artifacts to stainless package server ([86f6e2f](https://github.com/Increase/increase-java/commit/86f6e2f373c8117a7ff2c84cb76c177b9945fb28)) + ## 0.395.0 (2026-01-08) Full Changelog: [v0.394.0...v0.395.0](https://github.com/Increase/increase-java/compare/v0.394.0...v0.395.0) diff --git a/README.md b/README.md index bb2fa23ab..8b57c83a4 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ -[![Maven Central](https://img.shields.io/maven-central/v/com.increase.api/increase-java)](https://central.sonatype.com/artifact/com.increase.api/increase-java/0.395.0) -[![javadoc](https://javadoc.io/badge2/com.increase.api/increase-java/0.395.0/javadoc.svg)](https://javadoc.io/doc/com.increase.api/increase-java/0.395.0) +[![Maven Central](https://img.shields.io/maven-central/v/com.increase.api/increase-java)](https://central.sonatype.com/artifact/com.increase.api/increase-java/0.396.0) +[![javadoc](https://javadoc.io/badge2/com.increase.api/increase-java/0.396.0/javadoc.svg)](https://javadoc.io/doc/com.increase.api/increase-java/0.396.0) @@ -13,7 +13,7 @@ The Increase Java SDK is similar to the Increase Kotlin SDK but with minor diffe -The REST API documentation can be found on [increase.com](https://increase.com/documentation). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.increase.api/increase-java/0.395.0). +The REST API documentation can be found on [increase.com](https://increase.com/documentation). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.increase.api/increase-java/0.396.0). @@ -24,7 +24,7 @@ The REST API documentation can be found on [increase.com](https://increase.com/d ### Gradle ```kotlin -implementation("com.increase.api:increase-java:0.395.0") +implementation("com.increase.api:increase-java:0.396.0") ``` ### Maven @@ -33,7 +33,7 @@ implementation("com.increase.api:increase-java:0.395.0") com.increase.api increase-java - 0.395.0 + 0.396.0 ``` diff --git a/build.gradle.kts b/build.gradle.kts index c7fd06b53..83eb758c8 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,7 +8,7 @@ repositories { allprojects { group = "com.increase.api" - version = "0.395.0" // x-release-please-version + version = "0.396.0" // x-release-please-version } subprojects { diff --git a/buildSrc/src/main/kotlin/increase.publish.gradle.kts b/buildSrc/src/main/kotlin/increase.publish.gradle.kts index 6269c49ab..bc25185b4 100644 --- a/buildSrc/src/main/kotlin/increase.publish.gradle.kts +++ b/buildSrc/src/main/kotlin/increase.publish.gradle.kts @@ -7,6 +7,17 @@ plugins { id("com.vanniktech.maven.publish") } +publishing { + repositories { + if (project.hasProperty("publishLocal")) { + maven { + name = "LocalFileSystem" + url = uri("${rootProject.layout.buildDirectory.get()}/local-maven-repo") + } + } + } +} + repositories { gradlePluginPortal() mavenCentral() @@ -17,8 +28,10 @@ extra["signingInMemoryKeyId"] = System.getenv("GPG_SIGNING_KEY_ID") extra["signingInMemoryKeyPassword"] = System.getenv("GPG_SIGNING_PASSWORD") configure { - signAllPublications() - publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL) + if (!project.hasProperty("publishLocal")) { + signAllPublications() + publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL) + } coordinates(project.group.toString(), project.name, project.version.toString()) configure( diff --git a/increase-java-client-okhttp/src/main/kotlin/com/increase/api/client/okhttp/IncreaseOkHttpClient.kt b/increase-java-client-okhttp/src/main/kotlin/com/increase/api/client/okhttp/IncreaseOkHttpClient.kt index 8d8f55ae4..849f2ac30 100644 --- a/increase-java-client-okhttp/src/main/kotlin/com/increase/api/client/okhttp/IncreaseOkHttpClient.kt +++ b/increase-java-client-okhttp/src/main/kotlin/com/increase/api/client/okhttp/IncreaseOkHttpClient.kt @@ -18,6 +18,7 @@ import java.time.Clock import java.time.Duration import java.util.Optional import java.util.concurrent.Executor +import java.util.concurrent.ExecutorService import javax.net.ssl.HostnameVerifier import javax.net.ssl.SSLSocketFactory import javax.net.ssl.X509TrustManager @@ -46,11 +47,31 @@ class IncreaseOkHttpClient private constructor() { class Builder internal constructor() { private var clientOptions: ClientOptions.Builder = ClientOptions.builder() + private var dispatcherExecutorService: ExecutorService? = null private var proxy: Proxy? = null private var sslSocketFactory: SSLSocketFactory? = null private var trustManager: X509TrustManager? = null private var hostnameVerifier: HostnameVerifier? = null + /** + * The executor service to use for running HTTP requests. + * + * Defaults to OkHttp's + * [default executor service](https://github.com/square/okhttp/blob/ace792f443b2ffb17974f5c0d1cecdf589309f26/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Dispatcher.kt#L98-L104). + * + * This class takes ownership of the executor service and shuts it down when closed. + */ + fun dispatcherExecutorService(dispatcherExecutorService: ExecutorService?) = apply { + this.dispatcherExecutorService = dispatcherExecutorService + } + + /** + * Alias for calling [Builder.dispatcherExecutorService] with + * `dispatcherExecutorService.orElse(null)`. + */ + fun dispatcherExecutorService(dispatcherExecutorService: Optional) = + dispatcherExecutorService(dispatcherExecutorService.getOrNull()) + fun proxy(proxy: Proxy?) = apply { this.proxy = proxy } /** Alias for calling [Builder.proxy] with `proxy.orElse(null)`. */ @@ -323,6 +344,7 @@ class IncreaseOkHttpClient private constructor() { OkHttpClient.builder() .timeout(clientOptions.timeout()) .proxy(proxy) + .dispatcherExecutorService(dispatcherExecutorService) .sslSocketFactory(sslSocketFactory) .trustManager(trustManager) .hostnameVerifier(hostnameVerifier) diff --git a/increase-java-client-okhttp/src/main/kotlin/com/increase/api/client/okhttp/IncreaseOkHttpClientAsync.kt b/increase-java-client-okhttp/src/main/kotlin/com/increase/api/client/okhttp/IncreaseOkHttpClientAsync.kt index d80607c7e..525f508ee 100644 --- a/increase-java-client-okhttp/src/main/kotlin/com/increase/api/client/okhttp/IncreaseOkHttpClientAsync.kt +++ b/increase-java-client-okhttp/src/main/kotlin/com/increase/api/client/okhttp/IncreaseOkHttpClientAsync.kt @@ -18,6 +18,7 @@ import java.time.Clock import java.time.Duration import java.util.Optional import java.util.concurrent.Executor +import java.util.concurrent.ExecutorService import javax.net.ssl.HostnameVerifier import javax.net.ssl.SSLSocketFactory import javax.net.ssl.X509TrustManager @@ -46,11 +47,31 @@ class IncreaseOkHttpClientAsync private constructor() { class Builder internal constructor() { private var clientOptions: ClientOptions.Builder = ClientOptions.builder() + private var dispatcherExecutorService: ExecutorService? = null private var proxy: Proxy? = null private var sslSocketFactory: SSLSocketFactory? = null private var trustManager: X509TrustManager? = null private var hostnameVerifier: HostnameVerifier? = null + /** + * The executor service to use for running HTTP requests. + * + * Defaults to OkHttp's + * [default executor service](https://github.com/square/okhttp/blob/ace792f443b2ffb17974f5c0d1cecdf589309f26/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Dispatcher.kt#L98-L104). + * + * This class takes ownership of the executor service and shuts it down when closed. + */ + fun dispatcherExecutorService(dispatcherExecutorService: ExecutorService?) = apply { + this.dispatcherExecutorService = dispatcherExecutorService + } + + /** + * Alias for calling [Builder.dispatcherExecutorService] with + * `dispatcherExecutorService.orElse(null)`. + */ + fun dispatcherExecutorService(dispatcherExecutorService: Optional) = + dispatcherExecutorService(dispatcherExecutorService.getOrNull()) + fun proxy(proxy: Proxy?) = apply { this.proxy = proxy } /** Alias for calling [Builder.proxy] with `proxy.orElse(null)`. */ @@ -323,6 +344,7 @@ class IncreaseOkHttpClientAsync private constructor() { OkHttpClient.builder() .timeout(clientOptions.timeout()) .proxy(proxy) + .dispatcherExecutorService(dispatcherExecutorService) .sslSocketFactory(sslSocketFactory) .trustManager(trustManager) .hostnameVerifier(hostnameVerifier) diff --git a/increase-java-client-okhttp/src/main/kotlin/com/increase/api/client/okhttp/OkHttpClient.kt b/increase-java-client-okhttp/src/main/kotlin/com/increase/api/client/okhttp/OkHttpClient.kt index 29560cac0..dc73395b5 100644 --- a/increase-java-client-okhttp/src/main/kotlin/com/increase/api/client/okhttp/OkHttpClient.kt +++ b/increase-java-client-okhttp/src/main/kotlin/com/increase/api/client/okhttp/OkHttpClient.kt @@ -15,11 +15,13 @@ import java.net.Proxy import java.time.Duration import java.util.concurrent.CancellationException import java.util.concurrent.CompletableFuture +import java.util.concurrent.ExecutorService import javax.net.ssl.HostnameVerifier import javax.net.ssl.SSLSocketFactory import javax.net.ssl.X509TrustManager import okhttp3.Call import okhttp3.Callback +import okhttp3.Dispatcher import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.MediaType import okhttp3.MediaType.Companion.toMediaType @@ -198,6 +200,7 @@ private constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClien private var timeout: Timeout = Timeout.default() private var proxy: Proxy? = null + private var dispatcherExecutorService: ExecutorService? = null private var sslSocketFactory: SSLSocketFactory? = null private var trustManager: X509TrustManager? = null private var hostnameVerifier: HostnameVerifier? = null @@ -208,6 +211,10 @@ private constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClien fun proxy(proxy: Proxy?) = apply { this.proxy = proxy } + fun dispatcherExecutorService(dispatcherExecutorService: ExecutorService?) = apply { + this.dispatcherExecutorService = dispatcherExecutorService + } + fun sslSocketFactory(sslSocketFactory: SSLSocketFactory?) = apply { this.sslSocketFactory = sslSocketFactory } @@ -229,6 +236,8 @@ private constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClien .callTimeout(timeout.request()) .proxy(proxy) .apply { + dispatcherExecutorService?.let { dispatcher(Dispatcher(it)) } + val sslSocketFactory = sslSocketFactory val trustManager = trustManager if (sslSocketFactory != null && trustManager != null) { diff --git a/increase-java-core/src/main/kotlin/com/increase/api/models/files/File.kt b/increase-java-core/src/main/kotlin/com/increase/api/models/files/File.kt index e5f09ea54..89b9273f7 100644 --- a/increase-java-core/src/main/kotlin/com/increase/api/models/files/File.kt +++ b/increase-java-core/src/main/kotlin/com/increase/api/models/files/File.kt @@ -754,6 +754,9 @@ private constructor( /** The results of an Export you requested via the dashboard or API. */ @JvmField val EXPORT = of("export") + /** A fee statement. */ + @JvmField val FEE_STATEMENT = of("fee_statement") + /** An attachment to an Unusual Activity Report. */ @JvmField val UNUSUAL_ACTIVITY_REPORT_ATTACHMENT = of("unusual_activity_report_attachment") @@ -859,6 +862,8 @@ private constructor( ENTITY_SUPPLEMENTAL_DOCUMENT, /** The results of an Export you requested via the dashboard or API. */ EXPORT, + /** A fee statement. */ + FEE_STATEMENT, /** An attachment to an Unusual Activity Report. */ UNUSUAL_ACTIVITY_REPORT_ATTACHMENT, /** A document granting another entity access to the funds into your account. */ @@ -961,6 +966,8 @@ private constructor( ENTITY_SUPPLEMENTAL_DOCUMENT, /** The results of an Export you requested via the dashboard or API. */ EXPORT, + /** A fee statement. */ + FEE_STATEMENT, /** An attachment to an Unusual Activity Report. */ UNUSUAL_ACTIVITY_REPORT_ATTACHMENT, /** A document granting another entity access to the funds into your account. */ @@ -1015,6 +1022,7 @@ private constructor( DOCUMENT_REQUEST -> Value.DOCUMENT_REQUEST ENTITY_SUPPLEMENTAL_DOCUMENT -> Value.ENTITY_SUPPLEMENTAL_DOCUMENT EXPORT -> Value.EXPORT + FEE_STATEMENT -> Value.FEE_STATEMENT UNUSUAL_ACTIVITY_REPORT_ATTACHMENT -> Value.UNUSUAL_ACTIVITY_REPORT_ATTACHMENT DEPOSIT_ACCOUNT_CONTROL_AGREEMENT -> Value.DEPOSIT_ACCOUNT_CONTROL_AGREEMENT PROOF_OF_AUTHORIZATION_REQUEST_SUBMISSION -> @@ -1062,6 +1070,7 @@ private constructor( DOCUMENT_REQUEST -> Known.DOCUMENT_REQUEST ENTITY_SUPPLEMENTAL_DOCUMENT -> Known.ENTITY_SUPPLEMENTAL_DOCUMENT EXPORT -> Known.EXPORT + FEE_STATEMENT -> Known.FEE_STATEMENT UNUSUAL_ACTIVITY_REPORT_ATTACHMENT -> Known.UNUSUAL_ACTIVITY_REPORT_ATTACHMENT DEPOSIT_ACCOUNT_CONTROL_AGREEMENT -> Known.DEPOSIT_ACCOUNT_CONTROL_AGREEMENT PROOF_OF_AUTHORIZATION_REQUEST_SUBMISSION -> diff --git a/increase-java-core/src/main/kotlin/com/increase/api/models/files/FileListParams.kt b/increase-java-core/src/main/kotlin/com/increase/api/models/files/FileListParams.kt index c3a66695b..dba7537d2 100644 --- a/increase-java-core/src/main/kotlin/com/increase/api/models/files/FileListParams.kt +++ b/increase-java-core/src/main/kotlin/com/increase/api/models/files/FileListParams.kt @@ -687,6 +687,9 @@ private constructor( /** The results of an Export you requested via the dashboard or API. */ @JvmField val EXPORT = of("export") + /** A fee statement. */ + @JvmField val FEE_STATEMENT = of("fee_statement") + /** An attachment to an Unusual Activity Report. */ @JvmField val UNUSUAL_ACTIVITY_REPORT_ATTACHMENT = of("unusual_activity_report_attachment") @@ -792,6 +795,8 @@ private constructor( ENTITY_SUPPLEMENTAL_DOCUMENT, /** The results of an Export you requested via the dashboard or API. */ EXPORT, + /** A fee statement. */ + FEE_STATEMENT, /** An attachment to an Unusual Activity Report. */ UNUSUAL_ACTIVITY_REPORT_ATTACHMENT, /** A document granting another entity access to the funds into your account. */ @@ -894,6 +899,8 @@ private constructor( ENTITY_SUPPLEMENTAL_DOCUMENT, /** The results of an Export you requested via the dashboard or API. */ EXPORT, + /** A fee statement. */ + FEE_STATEMENT, /** An attachment to an Unusual Activity Report. */ UNUSUAL_ACTIVITY_REPORT_ATTACHMENT, /** A document granting another entity access to the funds into your account. */ @@ -948,6 +955,7 @@ private constructor( DOCUMENT_REQUEST -> Value.DOCUMENT_REQUEST ENTITY_SUPPLEMENTAL_DOCUMENT -> Value.ENTITY_SUPPLEMENTAL_DOCUMENT EXPORT -> Value.EXPORT + FEE_STATEMENT -> Value.FEE_STATEMENT UNUSUAL_ACTIVITY_REPORT_ATTACHMENT -> Value.UNUSUAL_ACTIVITY_REPORT_ATTACHMENT DEPOSIT_ACCOUNT_CONTROL_AGREEMENT -> Value.DEPOSIT_ACCOUNT_CONTROL_AGREEMENT PROOF_OF_AUTHORIZATION_REQUEST_SUBMISSION -> @@ -995,6 +1003,7 @@ private constructor( DOCUMENT_REQUEST -> Known.DOCUMENT_REQUEST ENTITY_SUPPLEMENTAL_DOCUMENT -> Known.ENTITY_SUPPLEMENTAL_DOCUMENT EXPORT -> Known.EXPORT + FEE_STATEMENT -> Known.FEE_STATEMENT UNUSUAL_ACTIVITY_REPORT_ATTACHMENT -> Known.UNUSUAL_ACTIVITY_REPORT_ATTACHMENT DEPOSIT_ACCOUNT_CONTROL_AGREEMENT -> Known.DEPOSIT_ACCOUNT_CONTROL_AGREEMENT PROOF_OF_AUTHORIZATION_REQUEST_SUBMISSION -> diff --git a/scripts/upload-artifacts b/scripts/upload-artifacts new file mode 100755 index 000000000..729e6f222 --- /dev/null +++ b/scripts/upload-artifacts @@ -0,0 +1,96 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# ANSI Color Codes +GREEN='\033[32m' +RED='\033[31m' +NC='\033[0m' # No Color + +log_error() { + local msg="$1" + local headers="$2" + local body="$3" + echo -e "${RED}${msg}${NC}" + [[ -f "$headers" ]] && echo -e "${RED}Headers:$(cat "$headers")${NC}" + echo -e "${RED}Body: ${body}${NC}" + exit 1 +} + +upload_file() { + local file_name="$1" + local tmp_headers + tmp_headers=$(mktemp) + + if [ -f "$file_name" ]; then + echo -e "${GREEN}Processing file: $file_name${NC}" + pkg_file_name="mvn${file_name#./build/local-maven-repo}" + + # Get signed URL for uploading artifact file + signed_url_response=$(curl -X POST -G "$URL" \ + -sS --retry 5 \ + -D "$tmp_headers" \ + --data-urlencode "filename=$pkg_file_name" \ + -H "Authorization: Bearer $AUTH" \ + -H "Content-Type: application/json") + + # Validate JSON and extract URL + if ! signed_url=$(echo "$signed_url_response" | jq -e -r '.url' 2>/dev/null) || [[ "$signed_url" == "null" ]]; then + log_error "Failed to get valid signed URL" "$tmp_headers" "$signed_url_response" + fi + + # Set content-type based on file extension + local extension="${file_name##*.}" + local content_type + case "$extension" in + jar) content_type="application/java-archive" ;; + md5|sha1|sha256|sha512) content_type="text/plain" ;; + module) content_type="application/json" ;; + pom|xml) content_type="application/xml" ;; + *) content_type="application/octet-stream" ;; + esac + + # Upload file + upload_response=$(curl -v -X PUT \ + --retry 5 \ + -D "$tmp_headers" \ + -H "Content-Type: $content_type" \ + --data-binary "@${file_name}" "$signed_url" 2>&1) + + if ! echo "$upload_response" | grep -q "HTTP/[0-9.]* 200"; then + log_error "Failed upload artifact file" "$tmp_headers" "$upload_response" + fi + + # Insert small throttle to reduce rate limiting risk + sleep 0.1 + fi +} + +walk_tree() { + local current_dir="$1" + + for entry in "$current_dir"/*; do + # Check that entry is valid + [ -e "$entry" ] || [ -h "$entry" ] || continue + + if [ -d "$entry" ]; then + walk_tree "$entry" + else + upload_file "$entry" + fi + done +} + +cd "$(dirname "$0")/.." + +echo "::group::Creating local Maven content" +./gradlew publishMavenPublicationToLocalFileSystemRepository -PpublishLocal +echo "::endgroup::" + +echo "::group::Uploading to pkg.stainless.com" +walk_tree "./build/local-maven-repo" +echo "::endgroup::" + +echo "::group::Generating instructions" +echo "Configure maven or gradle to use the repo located at 'https://pkg.stainless.com/s/${PROJECT}/${SHA}/mvn'" +echo "::endgroup::"