From 0001435d73b01050df858097f3ccec2e54603548 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Mon, 3 Aug 2026 08:51:49 -0700 Subject: [PATCH 1/6] ci: migrate release-please to upstream action --- .github/workflows/create-releases.yml | 18 ++++++++---------- release-please-config.json | 7 ++----- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/.github/workflows/create-releases.yml b/.github/workflows/create-releases.yml index f02ab6786..aed55e541 100644 --- a/.github/workflows/create-releases.yml +++ b/.github/workflows/create-releases.yml @@ -34,9 +34,12 @@ jobs: release: name: Release / select source if: github.ref == 'refs/heads/main' && github.repository == 'openai/openai-java' + permissions: + contents: write + issues: write + pull-requests: write runs-on: ubuntu-24.04 timeout-minutes: 15 - environment: publish outputs: should_publish: >- ${{ github.event_name == 'workflow_dispatch' || @@ -45,19 +48,14 @@ jobs: release_tag: ${{ steps.retry.outputs.release_tag || steps.automatic.outputs.tag_name }} steps: - - name: Check out main - if: github.event_name != 'workflow_dispatch' - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - with: - persist-credentials: false - - name: Create release if: github.event_name != 'workflow_dispatch' id: automatic - uses: stainless-api/trigger-release-please@bb6677c5a04578eec1ccfd9e1913b5b78ed64c61 # v1.4.0 + uses: googleapis/release-please-action@45996ed1f6d02564a971a2fa1b5860e934307cf7 # v5.0.0 with: - repo: ${{ github.event.repository.full_name }} - stainless-api-key: ${{ secrets.STAINLESS_API_KEY }} + target-branch: main + config-file: release-please-config.json + manifest-file: .release-please-manifest.json - name: Validate retry request if: github.event_name == 'workflow_dispatch' diff --git a/release-please-config.json b/release-please-config.json index 49224ae00..82fd20646 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -2,13 +2,9 @@ "packages": { ".": {} }, - "$schema": "https://raw.githubusercontent.com/stainless-api/release-please/main/schemas/config.json", + "$schema": "https://raw.githubusercontent.com/googleapis/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": [ @@ -61,6 +57,7 @@ ], "release-type": "simple", "extra-files": [ + "CONTRIBUTING.md", "README.md", "bedrock.md", "build.gradle.kts" From d19b4f5d20e4e53c5f8fc4051870241f0745a0ea Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Mon, 3 Aug 2026 08:57:40 -0700 Subject: [PATCH 2/6] ci: scope release permissions by job --- .github/workflows/create-releases.yml | 72 +++++++++++++++++++++------ 1 file changed, 57 insertions(+), 15 deletions(-) diff --git a/.github/workflows/create-releases.yml b/.github/workflows/create-releases.yml index aed55e541..76eadf0ba 100644 --- a/.github/workflows/create-releases.yml +++ b/.github/workflows/create-releases.yml @@ -18,8 +18,7 @@ on: type: boolean default: false -permissions: - contents: read +permissions: {} concurrency: group: create-releases @@ -31,9 +30,12 @@ env: MAVEN_ARTIFACTS: openai-java openai-java-core openai-java-client-okhttp openai-java-bedrock jobs: - release: - name: Release / select source - if: github.ref == 'refs/heads/main' && github.repository == 'openai/openai-java' + automatic_release: + name: Release / create + if: >- + github.event_name != 'workflow_dispatch' && + github.ref == 'refs/heads/main' && + github.repository == 'openai/openai-java' permissions: contents: write issues: write @@ -41,24 +43,35 @@ jobs: runs-on: ubuntu-24.04 timeout-minutes: 15 outputs: - should_publish: >- - ${{ github.event_name == 'workflow_dispatch' || - steps.automatic.outputs.releases_created == 'true' }} - source_sha: ${{ steps.retry.outputs.source_sha || steps.automatic.outputs.sha }} - release_tag: ${{ steps.retry.outputs.release_tag || steps.automatic.outputs.tag_name }} + releases_created: ${{ steps.release.outputs.releases_created }} + source_sha: ${{ steps.release.outputs.sha }} + release_tag: ${{ steps.release.outputs.tag_name }} steps: - name: Create release - if: github.event_name != 'workflow_dispatch' - id: automatic + id: release uses: googleapis/release-please-action@45996ed1f6d02564a971a2fa1b5860e934307cf7 # v5.0.0 with: target-branch: main config-file: release-please-config.json manifest-file: .release-please-manifest.json + retry_release: + name: Release / select retry source + if: >- + github.event_name == 'workflow_dispatch' && + github.ref == 'refs/heads/main' && + github.repository == 'openai/openai-java' + permissions: + contents: read + runs-on: ubuntu-24.04 + timeout-minutes: 15 + outputs: + source_sha: ${{ steps.retry.outputs.source_sha }} + release_tag: ${{ steps.retry.outputs.release_tag }} + + steps: - name: Validate retry request - if: github.event_name == 'workflow_dispatch' env: RELEASE_TAG: ${{ inputs.release_tag }} CONFIRMED: ${{ inputs.confirm_no_pending_deployment }} @@ -73,7 +86,6 @@ jobs: fi - name: Check out retry source - if: github.event_name == 'workflow_dispatch' uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false @@ -81,7 +93,6 @@ jobs: ref: refs/tags/${{ inputs.release_tag }} - name: Verify retry source - if: github.event_name == 'workflow_dispatch' id: retry env: GH_TOKEN: ${{ github.token }} @@ -121,10 +132,39 @@ jobs: echo "release_tag=$RELEASE_TAG" } >> "$GITHUB_OUTPUT" + release: + name: Release / select source + needs: + - automatic_release + - retry_release + if: >- + always() && + (needs.automatic_release.result == 'success' || + needs.retry_release.result == 'success') + permissions: {} + runs-on: ubuntu-24.04 + timeout-minutes: 1 + outputs: + should_publish: >- + ${{ needs.retry_release.result == 'success' || + needs.automatic_release.outputs.releases_created == 'true' }} + source_sha: >- + ${{ needs.retry_release.outputs.source_sha || + needs.automatic_release.outputs.source_sha }} + release_tag: >- + ${{ needs.retry_release.outputs.release_tag || + needs.automatic_release.outputs.release_tag }} + + steps: + - name: Select release source + run: echo "Release source selected" + runtime_compatibility: name: Release / runtime compatibility needs: release if: needs.release.outputs.should_publish == 'true' + permissions: + contents: read uses: ./.github/workflows/runtime-compatibility.yml with: ref: ${{ needs.release.outputs.source_sha }} @@ -137,6 +177,8 @@ jobs: if: >- needs.release.outputs.should_publish == 'true' && needs.runtime_compatibility.result == 'success' + permissions: + contents: read runs-on: ubuntu-24.04 timeout-minutes: 90 environment: publish From c749840159dfbf20c227790bd1be8f77f9081773 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Mon, 3 Aug 2026 09:09:09 -0700 Subject: [PATCH 3/6] ci: pin release-please config schema --- release-please-config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-please-config.json b/release-please-config.json index 82fd20646..d13c6399e 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -2,7 +2,7 @@ "packages": { ".": {} }, - "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", + "$schema": "https://raw.githubusercontent.com/googleapis/release-please/v17.6.0/schemas/config.json", "include-v-in-tag": true, "include-component-in-tag": false, "pull-request-header": "Automated Release PR", From 9eb639cee5d2fc417489b8c3dbcc01be1df2d33c Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Mon, 3 Aug 2026 09:32:25 -0700 Subject: [PATCH 4/6] ci: use the built-in GitHub token explicitly --- .github/workflows/create-releases.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/create-releases.yml b/.github/workflows/create-releases.yml index 76eadf0ba..0205c82fc 100644 --- a/.github/workflows/create-releases.yml +++ b/.github/workflows/create-releases.yml @@ -52,6 +52,7 @@ jobs: id: release uses: googleapis/release-please-action@45996ed1f6d02564a971a2fa1b5860e934307cf7 # v5.0.0 with: + token: ${{ secrets.GITHUB_TOKEN }} target-branch: main config-file: release-please-config.json manifest-file: .release-please-manifest.json @@ -95,7 +96,7 @@ jobs: - name: Verify retry source id: retry env: - GH_TOKEN: ${{ github.token }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} RELEASE_TAG: ${{ inputs.release_tag }} run: | set -euo pipefail From ba5195bf7d5ce984f72eb532810bc0a0a2113471 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Mon, 3 Aug 2026 10:28:48 -0700 Subject: [PATCH 5/6] ci: run required checks for release PRs --- .github/workflows/ci.yml | 20 ++++++++-- .github/workflows/create-releases.yml | 54 +++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 55cef32ed..dc81aff5a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,6 +11,12 @@ on: branches: - main - next + workflow_dispatch: + inputs: + base_sha: + description: Base commit used for API compatibility checks + required: true + type: string permissions: contents: read @@ -100,7 +106,9 @@ jobs: api_compatibility: name: CI / API compatibility - if: github.event_name == 'pull_request' + if: >- + github.event_name == 'pull_request' || + github.event_name == 'workflow_dispatch' runs-on: ubuntu-24.04 timeout-minutes: 20 @@ -123,7 +131,7 @@ jobs: - name: Compile previous tests against the proposed SDK env: - BASE_COMMIT: ${{ github.event.pull_request.base.sha }} + BASE_COMMIT: ${{ github.event.pull_request.base.sha || inputs.base_sha }} GRADLE_OPTS: -Dkotlin.compiler.execution.strategy=in-process run: | set -euo pipefail @@ -198,10 +206,12 @@ jobs: uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # v5.0.2 - name: Run consumer compatibility smoke test + env: + RUNTIME_JAVA_VERSION: ${{ matrix.java }} run: >- ./scripts/gradle :openai-java-runtime-compatibility:runRuntimeCompatibility - -PruntimeJavaVersion=${{ matrix.java }} + -PruntimeJavaVersion="$RUNTIME_JAVA_VERSION" required: name: CI / required @@ -242,7 +252,9 @@ jobs: [[ "$BUILD_RESULT" == "success" ]] || failed_jobs+=("build: $BUILD_RESULT") fi - if [[ "$EVENT_NAME" == "pull_request" && "$API_COMPATIBILITY_RESULT" != "success" ]]; then + if [[ ( "$EVENT_NAME" == "pull_request" || + "$EVENT_NAME" == "workflow_dispatch" ) && + "$API_COMPATIBILITY_RESULT" != "success" ]]; then failed_jobs+=("API compatibility: $API_COMPATIBILITY_RESULT") fi [[ "$RUNTIME_COMPATIBILITY_RESULT" == "success" ]] || diff --git a/.github/workflows/create-releases.yml b/.github/workflows/create-releases.yml index 0205c82fc..4a437f58e 100644 --- a/.github/workflows/create-releases.yml +++ b/.github/workflows/create-releases.yml @@ -43,11 +43,35 @@ jobs: runs-on: ubuntu-24.04 timeout-minutes: 15 outputs: + prs_created: ${{ steps.release.outputs.prs_created }} + release_pr: ${{ steps.release.outputs.pr }} releases_created: ${{ steps.release.outputs.releases_created }} source_sha: ${{ steps.release.outputs.sha }} release_tag: ${{ steps.release.outputs.tag_name }} steps: + - name: Check for a legacy release PR + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + LEGACY_RELEASE_BRANCH: release-please--branches--main--changes--next + run: | + set -euo pipefail + + legacy_pr="$( + gh pr list \ + --repo "$GITHUB_REPOSITORY" \ + --state open \ + --head "$LEGACY_RELEASE_BRANCH" \ + --json number,url \ + --jq '.[0] // empty' + )" + if [[ -n "$legacy_pr" ]]; then + legacy_number="$(jq -r '.number' <<< "$legacy_pr")" + legacy_url="$(jq -r '.url' <<< "$legacy_pr")" + echo "::error::Merge or close legacy release PR #$legacy_number before running upstream release-please: $legacy_url" + exit 1 + fi + - name: Create release id: release uses: googleapis/release-please-action@45996ed1f6d02564a971a2fa1b5860e934307cf7 # v5.0.0 @@ -57,6 +81,36 @@ jobs: config-file: release-please-config.json manifest-file: .release-please-manifest.json + release_pr_ci: + name: Release / run release PR CI + needs: automatic_release + if: needs.automatic_release.outputs.prs_created == 'true' + permissions: + actions: write + runs-on: ubuntu-24.04 + timeout-minutes: 5 + + steps: + # Events created by GITHUB_TOKEN do not recursively trigger pull_request workflows. + # workflow_dispatch is an explicit exception, so dispatch CI for the generated PR head. + - name: Run CI for the release PR + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + RELEASE_PR: ${{ needs.automatic_release.outputs.release_pr }} + run: | + set -euo pipefail + + release_branch="$(jq -r '.headBranchName // empty' <<< "$RELEASE_PR")" + if [[ "$release_branch" != "release-please--branches--main" ]]; then + echo "::error::Unexpected release PR branch: $release_branch" + exit 1 + fi + + gh workflow run ci.yml \ + --repo "$GITHUB_REPOSITORY" \ + --ref "$release_branch" \ + -f base_sha="$GITHUB_SHA" + retry_release: name: Release / select retry source if: >- From 676311ebb22cbb95e73bacc6ba6a14dea15ebe90 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Mon, 3 Aug 2026 11:04:24 -0700 Subject: [PATCH 6/6] ci: validate release PR dispatch context --- .github/workflows/ci.yml | 64 ++++++++++++++++++++++++--- .github/workflows/create-releases.yml | 3 +- 2 files changed, 59 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dc81aff5a..fdab4f81b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,11 +12,6 @@ on: - main - next workflow_dispatch: - inputs: - base_sha: - description: Base commit used for API compatibility checks - required: true - type: string permissions: contents: read @@ -109,6 +104,9 @@ jobs: if: >- github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' + permissions: + contents: read + pull-requests: read runs-on: ubuntu-24.04 timeout-minutes: 20 @@ -118,6 +116,58 @@ jobs: fetch-depth: 0 persist-credentials: false + - name: Validate dispatched release PR + if: github.event_name == 'workflow_dispatch' + id: release-pr + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + set -euo pipefail + + expected_ref="refs/heads/release-please--branches--main" + if [[ "$GITHUB_REF" != "$expected_ref" ]]; then + echo "::error::Release PR CI must run on $expected_ref, not $GITHUB_REF" + exit 1 + fi + + release_pr="$( + gh api \ + --method GET \ + "repos/$GITHUB_REPOSITORY/pulls" \ + -f state=open \ + -f head="$GITHUB_REPOSITORY_OWNER:$GITHUB_REF_NAME" \ + -f base=main \ + -F per_page=2 + )" + if [[ "$(jq length <<< "$release_pr")" != "1" ]]; then + echo "::error::Expected exactly one open release PR from $GITHUB_REF_NAME into main" + exit 1 + fi + + if ! jq -e \ + --arg repository "$GITHUB_REPOSITORY" \ + --arg head_ref "$GITHUB_REF_NAME" \ + --arg head_sha "$GITHUB_SHA" \ + '.[0] | + .user.id == 41898282 and + .user.type == "Bot" and + .head.repo.full_name == $repository and + .head.ref == $head_ref and + .head.sha == $head_sha and + .base.repo.full_name == $repository and + .base.ref == "main"' \ + <<< "$release_pr" > /dev/null; then + echo "::error::Release PR is not the expected github-actions[bot] PR for $GITHUB_SHA" + exit 1 + fi + + base_sha="$(jq -r '.[0].base.sha' <<< "$release_pr")" + if ! git cat-file -e "${base_sha}^{commit}"; then + echo "::error::PR base commit is not available: $base_sha" + exit 1 + fi + echo "base_sha=$base_sha" >> "$GITHUB_OUTPUT" + - name: Set up Java uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5 with: @@ -131,7 +181,9 @@ jobs: - name: Compile previous tests against the proposed SDK env: - BASE_COMMIT: ${{ github.event.pull_request.base.sha || inputs.base_sha }} + BASE_COMMIT: >- + ${{ github.event.pull_request.base.sha || + steps.release-pr.outputs.base_sha }} GRADLE_OPTS: -Dkotlin.compiler.execution.strategy=in-process run: | set -euo pipefail diff --git a/.github/workflows/create-releases.yml b/.github/workflows/create-releases.yml index 4a437f58e..69b3473b6 100644 --- a/.github/workflows/create-releases.yml +++ b/.github/workflows/create-releases.yml @@ -108,8 +108,7 @@ jobs: gh workflow run ci.yml \ --repo "$GITHUB_REPOSITORY" \ - --ref "$release_branch" \ - -f base_sha="$GITHUB_SHA" + --ref "$release_branch" retry_release: name: Release / select retry source