Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
1ffb80f
Consolidate and harden CI workflows
jbeckwith-oai Jul 23, 2026
d9fadb7
Address CI review feedback
jbeckwith-oai Jul 23, 2026
c75b105
Make Mockito agent configuration lazy
jbeckwith-oai Jul 23, 2026
83fe31c
Remove unused Bedrock Mockito dependencies
jbeckwith-oai Jul 24, 2026
cd6b58d
Address automated CI review feedback
jbeckwith-oai Jul 24, 2026
b03c3ce
Avoid duplicate CodeQL analysis
jbeckwith-oai Jul 24, 2026
dc202fe
Close API compatibility coverage gaps
jbeckwith-oai Jul 24, 2026
ebb5f18
Preserve structured chat compatibility coverage
jbeckwith-oai Jul 24, 2026
23c787a
Make API compatibility policy self-contained
jbeckwith-oai Jul 24, 2026
8e3c187
Clean up Stainless upload logs
jbeckwith-oai Jul 24, 2026
48d02c9
Preserve structured text compatibility coverage
jbeckwith-oai Jul 24, 2026
8b42f3f
Upgrade Gradle setup action to Node 24
jbeckwith-oai Jul 24, 2026
43790fe
Use portable compatibility temp file
jbeckwith-oai Jul 24, 2026
f18474a
fix(ci): retain security CodeQL analysis
jbeckwith-oai Jul 24, 2026
3a09e35
Preserve multipart compatibility coverage
jbeckwith-oai Jul 24, 2026
8d58861
fix(ci): preserve remaining compatibility coverage
jbeckwith-oai Jul 24, 2026
b0db013
fix(ci): retain structured chat compatibility
jbeckwith-oai Jul 24, 2026
9132639
fix(ci): stabilize API compatibility fixtures
jbeckwith-oai Jul 24, 2026
7894338
fix(ci): retain codegen branch coverage
jbeckwith-oai Jul 24, 2026
112c20f
chore(ci): update CodeQL Gradle setup
jbeckwith-oai Jul 24, 2026
2ffbd43
fix(ci): harden compatibility policy validation
jbeckwith-oai Jul 24, 2026
f6ef29d
fix(ci): validate proposed compatibility sources
jbeckwith-oai Jul 24, 2026
0803a69
fix(ci): preserve structured output API surface
jbeckwith-oai Jul 24, 2026
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
212 changes: 95 additions & 117 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
name: CI

on:
push:
branches:
- '**'
- '!integrated/**'
- '!stl-preview-head/**'
- '!stl-preview-base/**'
- '!generated'
- '!codegen/**'
- main
- next
Comment thread
jbeckwith-oai marked this conversation as resolved.
Comment thread
jbeckwith-oai marked this conversation as resolved.
- 'stl/**'
Comment thread
jbeckwith-oai marked this conversation as resolved.
- 'codegen/stl/**'
pull_request:
branches-ignore:
- 'stl-preview-head/**'
- 'stl-preview-base/**'
branches:
- main
- next

permissions:
contents: read

concurrency:
group: ci-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
lint:
name: CI / lint
runs-on: ubuntu-24.04
timeout-minutes: 15
name: lint
runs-on: ${{ startsWith(github.repository, 'stainless-sdks/') && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
if: (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata')

steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
Expand All @@ -36,60 +37,21 @@ jobs:
java-version: |
8
21
cache: gradle

- name: Set up Gradle
uses: gradle/actions/setup-gradle@0b6dd653ba04f4f93bf581ec31e66cbd7dcb644d # v4
uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # v5.0.2

- name: Run lints
run: ./scripts/lint

build:
timeout-minutes: 30
name: build
runs-on: ${{ startsWith(github.repository, 'stainless-sdks/') && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
if: |-
(github.event_name == 'push' || github.event.pull_request.head.repo.fork) &&
(github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata') &&
name: CI / build + Jackson compatibility
if: >-
!(github.repository == 'stainless-sdks/openai-java' &&
github.event_name == 'push' &&
!startsWith(github.ref, 'refs/heads/stl/'))

steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false

- name: Set up Java
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5
with:
distribution: temurin
java-version: |
8
21
cache: gradle

- name: Set up Gradle
uses: gradle/actions/setup-gradle@0b6dd653ba04f4f93bf581ec31e66cbd7dcb644d # v4

- name: Build SDK
# disable gradle daemon in CI because it is flakey
env:
GRADLE_OPTS: "-Dkotlin.compiler.execution.strategy=in-process"
run: ./scripts/build

upload-maven-artifacts:
runs-on: ubuntu-24.04
timeout-minutes: 30
name: build-and-upload-maven-artifacts
permissions:
contents: read
id-token: write
runs-on: depot-ubuntu-24.04
if: |-
github.repository == 'stainless-sdks/openai-java' &&
github.event_name == 'push' &&
github.event.head_commit.message != 'codegen metadata' &&
!startsWith(github.ref, 'refs/heads/stl/')

steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
Expand All @@ -103,64 +65,20 @@ jobs:
java-version: |
8
21
cache: gradle

- name: Set up Gradle
uses: gradle/actions/setup-gradle@0b6dd653ba04f4f93bf581ec31e66cbd7dcb644d # v4
uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # v5.0.2

- name: Build SDK
# disable gradle daemon in CI because it is flakey
- name: Build SDK and run compatibility tests
env:
GRADLE_OPTS: "-Dkotlin.compiler.execution.strategy=in-process"
GRADLE_OPTS: -Dkotlin.compiler.execution.strategy=in-process
run: ./scripts/build

- name: Upload Maven artifacts
env:
URL: https://pkg.stainless.com/s
SHA: ${{ github.sha }}
PROJECT: openai-java
run: |
set -euo pipefail

max_retries=5
attempt=1

while true; do
echo "Maven artifact upload attempt ${attempt}/${max_retries}"

oidc_response="$(curl -sSf \
-H "Authorization: bearer ${ACTIONS_ID_TOKEN_REQUEST_TOKEN}" \
"${ACTIONS_ID_TOKEN_REQUEST_URL}")"
github_token="$(printf '%s' "$oidc_response" | jq -er '.value')"

upload_log="$(mktemp)"
set +e
AUTH="$github_token" ./scripts/upload-artifacts 2>&1 | tee "$upload_log"
upload_status=${PIPESTATUS[0]}
set -e

if [ "$upload_status" -eq 0 ]; then
break
fi

if [ "$attempt" -lt "$max_retries" ] && \
grep -q "Failed to get valid signed URL" "$upload_log" && \
grep -q "GitHub JWT is missing or invalid\\." "$upload_log"; then
sleep_seconds=$((3 * (1 << (attempt - 1))))
echo "Retrying after fresh OIDC token due to transient GitHub JWT validation failure"
echo "Sleeping ${sleep_seconds}s before retry"
sleep "$sleep_seconds"
attempt=$((attempt + 1))
continue
fi

exit "$upload_status"
done
test:
name: CI / tests
runs-on: ubuntu-24.04
timeout-minutes: 30
name: test
runs-on: ${{ startsWith(github.repository, 'stainless-sdks/') && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
if: github.event_name == 'push' || github.event.pull_request.head.repo.fork

steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
Expand All @@ -173,23 +91,23 @@ jobs:
java-version: |
8
21
cache: gradle

- name: Set up Gradle
uses: gradle/gradle-build-action@fe583dc97e032f41ccc310ea5176f2d7306abbc4 # v2
uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # v5.0.2

- name: Run tests
run: ./scripts/test
examples:

api_compatibility:
name: CI / API compatibility
if: github.event_name == 'pull_request'
runs-on: ubuntu-24.04
timeout-minutes: 20
name: examples
environment: CI
runs-on: ${{ startsWith(github.repository, 'stainless-sdks/') && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
if: github.repository == 'openai/openai-java' && github.event_name == 'push' && github.ref == 'refs/heads/main' && github.event.head_commit.message != 'codegen metadata'

steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
fetch-depth: 0
persist-credentials: false

- name: Set up Java
Expand All @@ -199,11 +117,71 @@ jobs:
java-version: |
8
21
cache: gradle

- name: Set up Gradle
uses: gradle/gradle-build-action@fe583dc97e032f41ccc310ea5176f2d7306abbc4 # v2
uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # v5.0.2

- env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
- name: Compile previous tests against the proposed SDK
env:
BASE_COMMIT: ${{ github.event.pull_request.base.sha }}
GRADLE_OPTS: -Dkotlin.compiler.execution.strategy=in-process
run: |
./gradlew :openai-java-example:run
set -euo pipefail

# The proposed detector verifies the current compatibility policy. Running the baseline
# detector as well prevents a PR from weakening that policy to hide an SDK break.
./scripts/detect-breaking-changes "$BASE_COMMIT"

BASE_DETECTOR="$(mktemp ./scripts/detect-breaking-changes.baseline.XXXXXX)"
trap 'rm -f "$BASE_DETECTOR"' EXIT
git show "${BASE_COMMIT}:scripts/detect-breaking-changes" > "$BASE_DETECTOR"
chmod +x "$BASE_DETECTOR"
"$BASE_DETECTOR" "$BASE_COMMIT"
Comment thread
jbeckwith-oai marked this conversation as resolved.

required:
name: CI / required
Comment thread
jbeckwith-oai marked this conversation as resolved.
if: always()
needs:
- lint
Comment thread
jbeckwith-oai marked this conversation as resolved.
- build
- test
- api_compatibility
runs-on: ubuntu-24.04
timeout-minutes: 5

steps:
- name: Verify required jobs succeeded
env:
EVENT_NAME: ${{ github.event_name }}
REPOSITORY: ${{ github.repository }}
REF: ${{ github.ref }}
LINT_RESULT: ${{ needs.lint.result }}
BUILD_RESULT: ${{ needs.build.result }}
TEST_RESULT: ${{ needs.test.result }}
API_COMPATIBILITY_RESULT: ${{ needs.api_compatibility.result }}
run: |
set -euo pipefail

failed_jobs=()
[[ "$LINT_RESULT" == "success" ]] || failed_jobs+=("lint: $LINT_RESULT")
[[ "$TEST_RESULT" == "success" ]] || failed_jobs+=("test: $TEST_RESULT")

if [[ "$EVENT_NAME" == "push" &&
"$REPOSITORY" == "stainless-sdks/openai-java" &&
"$REF" != refs/heads/stl/* ]]; then
[[ "$BUILD_RESULT" == "skipped" ]] ||
failed_jobs+=("build: expected skipped, got $BUILD_RESULT")
else
[[ "$BUILD_RESULT" == "success" ]] || failed_jobs+=("build: $BUILD_RESULT")
fi

if [[ "$EVENT_NAME" == "pull_request" && "$API_COMPATIBILITY_RESULT" != "success" ]]; then
failed_jobs+=("API compatibility: $API_COMPATIBILITY_RESULT")
fi

if (( ${#failed_jobs[@]} > 0 )); then
printf 'Required CI job did not succeed: %s\n' "${failed_jobs[@]}"
exit 1
fi

echo "All required CI jobs succeeded."
2 changes: 1 addition & 1 deletion .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
java-version: 21

- name: Set up Gradle
uses: gradle/actions/setup-gradle@0b6dd653ba04f4f93bf581ec31e66cbd7dcb644d # v4
uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # v5.0.2

- name: Initialize CodeQL
uses: github/codeql-action/init@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4
Expand Down
79 changes: 12 additions & 67 deletions .github/workflows/create-releases.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
name: Create releases

on:
schedule:
- cron: '0 5 * * *' # every day at 5am UTC
Expand All @@ -9,11 +10,16 @@ on:
permissions:
contents: read

concurrency:
group: create-releases
cancel-in-progress: false

jobs:
release:
name: release
name: Release / create
if: github.ref == 'refs/heads/main' && github.repository == 'openai/openai-java'
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
timeout-minutes: 15
environment: publish
outputs:
releases_created: ${{ steps.release.outputs.releases_created }}
Expand All @@ -23,75 +29,14 @@ jobs:
with:
persist-credentials: false

- uses: stainless-api/trigger-release-please@bb6677c5a04578eec1ccfd9e1913b5b78ed64c61 # v1.4.0
- name: Create release
id: release
uses: stainless-api/trigger-release-please@bb6677c5a04578eec1ccfd9e1913b5b78ed64c61 # v1.4.0
with:
repo: ${{ github.event.repository.full_name }}
stainless-api-key: ${{ secrets.STAINLESS_API_KEY }}

publish:
name: publish
needs: release
if: ${{ needs.release.outputs.releases_created == 'true' }}
runs-on: ubuntu-latest
environment: publish

steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false

- name: Set up Java
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5
with:
distribution: temurin
java-version: |
8
21
cache: gradle

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

- name: Compile the openai-java-core project
run: |
./gradlew :openai-java-core:compileJava :openai-java-core:compileTestJava -x test

- name: Run the mock server
run: |
./scripts/mock --daemon

- name: Setup GraalVM
uses: graalvm/setup-graalvm@03e8abf916fd0e281b2efe7b2da3378bb0a1d085 # v1
with:
java-version: 21
distribution: 'graalvm-community'
cache: gradle

- name: Run tests on the openai-java-core project with the GraalVM native-image agent
run: |
./gradlew :openai-java-core:test -x compileJava -x compileTestJava -x compileKotlin -x compileTestKotlin -PgraalvmAgent

- name: Check generated GraalVM file
run: |
echo "Checking for GraalVM agent metadata files..."
DIRECTORY=openai-java-core/src/main/resources/META-INF/native-image
if [ -d "$DIRECTORY" ] && [ "$(ls -A $DIRECTORY)" ]; then
echo "Files found in $DIRECTORY:"
ls -l $DIRECTORY
else
echo "No files found in $DIRECTORY"
exit 1
fi

- name: Publish to Sonatype
run: |-
export -- GPG_SIGNING_KEY_ID
printenv -- GPG_SIGNING_KEY | gpg --batch --passphrase-fd 3 --import 3<<< "$GPG_SIGNING_PASSWORD"
GPG_SIGNING_KEY_ID="$(gpg --with-colons --list-keys | awk -F : -- '/^pub:/ { getline; print "0x" substr($10, length($10) - 7) }')"
./gradlew publishAndReleaseToMavenCentral --stacktrace -PmavenCentralUsername="$SONATYPE_USERNAME" -PmavenCentralPassword="$SONATYPE_PASSWORD" --no-configuration-cache
env:
SONATYPE_USERNAME: ${{ secrets.OPENAI_SONATYPE_USERNAME }}
SONATYPE_PASSWORD: ${{ secrets.OPENAI_SONATYPE_PASSWORD }}
GPG_SIGNING_KEY: ${{ secrets.OPENAI_SONATYPE_GPG_SIGNING_KEY }}
GPG_SIGNING_PASSWORD: ${{ secrets.OPENAI_SONATYPE_GPG_SIGNING_PASSWORD }}
if: needs.release.outputs.releases_created == 'true'
uses: ./.github/workflows/publish-sonatype-reusable.yml
Comment thread
jbeckwith-oai marked this conversation as resolved.
Loading
Loading