Skip to content
Closed
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
59 changes: 59 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,65 @@ jobs:
exit 1
fi

- name: Verify Maven visibility contract
run: |
set -euo pipefail
workflow=.github/workflows/create-releases.yml
scratch="$(mktemp -d)"
trap 'rm -rf "$scratch"' EXIT
yq -er '.jobs.maven_visibility.steps[] | select(.name == "Wait for Maven Central").run' "$workflow" > "$scratch/poll.sh"
yq -er '.jobs.release_outcome.steps[] | select(.name == "Verify release outcome").run' "$workflow" > "$scratch/outcome.sh"
cat > "$scratch/mock.sh" <<'SH'
curl() {
printf '%s\n' "${!#}" >> "$PROBE_LOG"
[[ "${!#}" != "$MISSING_URL" || ( "$RECOVER_MISSING" == true && -f "$RECOVERY_FILE" ) ]]
}
sleep() { touch "$RECOVERY_FILE"; }
date() {
if [[ "${EXPIRE_AFTER_SLEEP:-false}" == true && -f "$RECOVERY_FILE" ]]; then
printf '%s\n' "$PUBLISH_DEADLINE"
else
command date "$@"
fi
}
SH
export RELEASE_TAG=v1.2.3 MAVEN_CENTRAL_BASE_URL=https://maven.invalid/com/openai
MAVEN_ARTIFACTS="$(yq -er '.env.MAVEN_ARTIFACTS' "$workflow")"
export MAVEN_ARTIFACTS
export PUBLISH_ATTEMPT="$GITHUB_RUN_ATTEMPT" PUBLISH_DEADLINE="$(( $(date +%s) + 90 ))"
export PROBE_LOG="$scratch/probes" RECOVERY_FILE="$scratch/recovered" RECOVER_MISSING=true
export MISSING_URL="$MAVEN_CENTRAL_BASE_URL/openai-java-vertex/1.2.3/openai-java-vertex-1.2.3-javadoc.jar"

BASH_ENV="$scratch/mock.sh" bash "$scratch/poll.sh" > "$scratch/poll.log"
for artifact in openai-java openai-java-core openai-java-client-okhttp openai-java-bedrock openai-java-vertex; do
for suffix in .pom .jar -sources.jar -javadoc.jar; do
echo "$MAVEN_CENTRAL_BASE_URL/$artifact/1.2.3/$artifact-1.2.3$suffix"
done
done | sort > "$scratch/expected"
sort -u "$PROBE_LOG" > "$scratch/observed"
diff -u "$scratch/expected" "$scratch/observed"
test "$(wc -l < "$PROBE_LOG")" -eq 41 # 20 initial, 1 pending, 20 final

rm "$RECOVERY_FILE"
: > "$PROBE_LOG"
if EXPIRE_AFTER_SLEEP=true RECOVER_MISSING=false BASH_ENV="$scratch/mock.sh" bash "$scratch/poll.sh" > "$scratch/poll.log" 2>&1; then
echo "::error::Maven visibility passed with a missing file"
exit 1
fi
grep -Fq "Maven visibility deadline expired" "$scratch/poll.log"
test "$(wc -l < "$PROBE_LOG")" -eq 20
GITHUB_RUN_ATTEMPT="$((PUBLISH_ATTEMPT + 1))" PUBLISH_DEADLINE=1 BASH_ENV="$scratch/mock.sh" bash "$scratch/poll.sh" > "$scratch/poll.log"

export EVENT_NAME=push AUTOMATIC_RESULT=success RETRY_RESULT=skipped RELEASE_RESULT=success
export SHOULD_PUBLISH=true RUNTIME_RESULT=success PUBLISH_RESULT=success VISIBILITY_RESULT=success
bash "$scratch/outcome.sh"
EVENT_NAME=workflow_dispatch AUTOMATIC_RESULT=skipped RETRY_RESULT=success bash "$scratch/outcome.sh"
if VISIBILITY_RESULT=skipped bash "$scratch/outcome.sh" > "$scratch/outcome.log" 2>&1; then
echo "::error::Release outcome passed with skipped visibility"
exit 1
fi
SHOULD_PUBLISH=false RUNTIME_RESULT=skipped PUBLISH_RESULT=skipped VISIBILITY_RESULT=skipped bash "$scratch/outcome.sh"

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

Expand Down
105 changes: 91 additions & 14 deletions .github/workflows/create-releases.yml
Original file line number Diff line number Diff line change
Expand Up @@ -260,8 +260,18 @@ jobs:
runs-on: ${{ vars.SDK_GHA_RUNNER || 'ubuntu-24.04' }}
timeout-minutes: 90
environment: publish
outputs:
visibility_deadline: ${{ steps.visibility_window.outputs.deadline }}
publish_attempt: ${{ steps.visibility_window.outputs.attempt }}

steps:
- name: Record publication window
id: visibility_window
run: |
# Match the publisher timeout across the visibility handoff.
echo "deadline=$(( $(date +%s) + 90 * 60 ))" >> "$GITHUB_OUTPUT"
echo "attempt=$GITHUB_RUN_ATTEMPT" >> "$GITHUB_OUTPUT"

- name: Check out workflow scripts
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
with:
Expand Down Expand Up @@ -480,38 +490,97 @@ jobs:
- name: Verify attested Maven artifacts
run: sha256sum --check "$RUNNER_TEMP/maven-artifact-provenance.sha256"

maven_visibility:
name: Release / verify Maven visibility
needs:
- release
- publish
if: >-
!cancelled() &&
needs.release.result == 'success' &&
needs.release.outputs.should_publish == 'true' &&
needs.publish.result == 'success'
permissions: {}
runs-on: ubuntu-24.04
timeout-minutes: 90

steps:
- name: Wait for Maven Central
env:
RELEASE_TAG: ${{ needs.release.outputs.release_tag }}
PUBLISH_DEADLINE: ${{ needs.publish.outputs.visibility_deadline }}
PUBLISH_ATTEMPT: ${{ needs.publish.outputs.publish_attempt }}
run: |
set -euo pipefail

version="${RELEASE_TAG#v}"
for attempt in {1..31}; do
missing=()
for artifact in $MAVEN_ARTIFACTS; do
for suffix in .pom .jar -sources.jar -javadoc.jar; do
file="$artifact-$version$suffix"
url="$MAVEN_CENTRAL_BASE_URL/$artifact/$version/$file"
if [[ ! "$RELEASE_TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ||
! "$PUBLISH_DEADLINE" =~ ^[1-9][0-9]*$ ||
! "$PUBLISH_ATTEMPT" =~ ^[1-9][0-9]*$ ||
! "$GITHUB_RUN_ATTEMPT" =~ ^[1-9][0-9]*$ ]] ||
(( GITHUB_RUN_ATTEMPT < PUBLISH_ATTEMPT )); then
echo "::error::Invalid publication window or release tag"
exit 1
fi
deadline=$PUBLISH_DEADLINE
if (( GITHUB_RUN_ATTEMPT > PUBLISH_ATTEMPT )); then
# Rerunning only this job must not reuse the original attempt's expired window.
deadline=$(( $(date +%s) + 90 * 60 ))
fi

check_files() {
local remaining
remaining=$((deadline - $(date +%s)))
if (( remaining <= 0 )); then
echo "::error::Maven visibility deadline expired; rerun this job to recheck without republishing" >&2
return 1
fi
if ! printf '%s\0' "$@" |
timeout "$remaining" xargs -0 -n 1 -P 10 bash -c '
if ! curl --fail --silent --show-error --head --location \
--connect-timeout 10 --max-time 30 "$url" >/dev/null; then
missing+=("$file")
--connect-timeout 10 --max-time 30 "$MAVEN_CENTRAL_BASE_URL/$1" >/dev/null; then
printf "%s\n" "$1"
fi
done
' _; then
echo "::error::Maven visibility probe failed; rerun this job to recheck without republishing" >&2
return 1
fi
}

version="${RELEASE_TAG#v}"
files=()
for artifact in $MAVEN_ARTIFACTS; do
for suffix in .pom .jar -sources.jar -javadoc.jar; do
files+=("$artifact/$version/$artifact-$version$suffix")
done
done
if [[ "${#files[@]}" -ne 20 ]]; then
echo "::error::Expected exactly 20 Maven files, got ${#files[@]}"
exit 1
fi

if [[ "${#missing[@]}" -eq 0 ]]; then
pending=("${files[@]}")
for attempt in {1..31}; do
missing="$(check_files "${pending[@]}")"
if [[ -z "$missing" && "${#pending[@]}" -lt "${#files[@]}" ]]; then
# Recheck the whole release together before reporting success.
missing="$(check_files "${files[@]}")"
fi
if [[ -z "$missing" ]]; then
echo "Maven Central serves every expected $version artifact"
exit 0
fi

echo "Attempt $attempt/31; waiting for: ${missing[*]}"
mapfile -t pending <<< "$missing"
echo "Attempt $attempt/31; waiting for: ${pending[*]}"
if [[ "$attempt" -lt 31 ]]; then
sleep 60
remaining=$((deadline - $(date +%s)))
if (( remaining > 0 )); then
sleep "$((remaining < 60 ? remaining : 60))"
fi
fi
done

echo "::error::Upload completed, but $version was not fully public after 30 minutes"
echo "::error::Upload completed, but $version was not fully public after 31 checks; rerun this job to recheck without republishing"
exit 1

release_outcome:
Expand All @@ -522,6 +591,7 @@ jobs:
- release
- runtime_compatibility
- publish
- maven_visibility
# Run after failures and intentional skips, but do not keep a cancelled
# workflow alive. This makes an unexpected skipped publication fail closed.
if: ${{ !cancelled() && github.repository == 'openai/openai-java' }}
Expand All @@ -539,6 +609,7 @@ jobs:
SHOULD_PUBLISH: ${{ needs.release.outputs.should_publish }}
RUNTIME_RESULT: ${{ needs.runtime_compatibility.result }}
PUBLISH_RESULT: ${{ needs.publish.result }}
VISIBILITY_RESULT: ${{ needs.maven_visibility.result }}
run: |
set -euo pipefail

Expand Down Expand Up @@ -585,6 +656,9 @@ jobs:
if [[ "$PUBLISH_RESULT" != "success" ]]; then
fail "Maven Central publication concluded $PUBLISH_RESULT"
fi
if [[ "$VISIBILITY_RESULT" != "success" ]]; then
fail "Maven Central visibility concluded $VISIBILITY_RESULT"
fi
;;
false)
if [[ "$RUNTIME_RESULT" != "skipped" ]]; then
Expand All @@ -593,6 +667,9 @@ jobs:
if [[ "$PUBLISH_RESULT" != "skipped" ]]; then
fail "No-release run expected Maven Central publication to be skipped, got $PUBLISH_RESULT"
fi
if [[ "$VISIBILITY_RESULT" != "skipped" ]]; then
fail "No-release run expected Maven Central visibility to be skipped, got $VISIBILITY_RESULT"
fi
;;
*)
fail "Invalid should_publish output: $SHOULD_PUBLISH"
Expand Down
Loading