From d979d0908208e1bdde14c59450388dba97664a34 Mon Sep 17 00:00:00 2001 From: cloudpdf-sdk-bot Date: Sun, 9 Aug 2026 09:24:07 +0000 Subject: [PATCH] chore: generate CloudPDF Java SDK 3.0.0-alpha.1 --- .fern/metadata.json | 2 +- .github/workflows/sdk-ci.yml | 2 +- .github/workflows/sdk-release.yml | 241 ++++++++++++++++++++++++++++++ build.gradle | 33 ++-- cloudpdf-generation.json | 2 +- 5 files changed, 268 insertions(+), 12 deletions(-) create mode 100644 .github/workflows/sdk-release.yml diff --git a/.fern/metadata.json b/.fern/metadata.json index f04378b..e6b0f85 100644 --- a/.fern/metadata.json +++ b/.fern/metadata.json @@ -10,7 +10,7 @@ "base-exception-class-name": "CloudPDFException", "base-api-exception-class-name": "CloudPDFApiException" }, - "originGitCommit": "a0adb9e77ef16feaef2358d71b247b4f5a98fd23", + "originGitCommit": "cfc415f2b7501e153280b32bcd6aa4af1353e860", "originGitCommitIsDirty": false, "invokedBy": "ci", "requestedVersion": "3.0.0-alpha.1", diff --git a/.github/workflows/sdk-ci.yml b/.github/workflows/sdk-ci.yml index 3522f46..99e2eb2 100644 --- a/.github/workflows/sdk-ci.yml +++ b/.github/workflows/sdk-ci.yml @@ -19,4 +19,4 @@ jobs: distribution: temurin java-version: '17' cache: gradle - - run: ./gradlew test --no-daemon + - run: ./gradlew test generatePomFileForMavenPublication jar sourcesJar javadocJar --no-daemon diff --git a/.github/workflows/sdk-release.yml b/.github/workflows/sdk-release.yml new file mode 100644 index 0000000..4779268 --- /dev/null +++ b/.github/workflows/sdk-release.yml @@ -0,0 +1,241 @@ +name: SDK Release + +on: + push: + branches: [main] + paths-ignore: + - '.github/**' + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: sdk-release + cancel-in-progress: false + +jobs: + release: + name: Publish com.cloudpdf:sdk + if: github.event_name == 'workflow_dispatch' || vars.SDK_AUTO_PUBLISH_ENABLED == 'true' + runs-on: ubuntu-latest + environment: release + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: '17' + cache: gradle + + - name: Verify generated release version + id: version + run: | + node <<'NODE' + const fs = require('node:fs'); + const generation = JSON.parse(fs.readFileSync('cloudpdf-generation.json', 'utf8')); + const build = fs.readFileSync('build.gradle', 'utf8'); + if (generation.language !== 'java') throw new Error('generation language is not java'); + const group = build.match(/^group = '([^']+)'$/m)?.[1]; + const projectVersion = build.match(/^version = '([^']+)'$/m)?.[1]; + const artifact = build.match(/^\s*artifactId = '([^']+)'$/m)?.[1]; + if (group !== 'com.cloudpdf' || artifact !== 'sdk') { + throw new Error(`unexpected Maven coordinates ${group}:${artifact}`); + } + if (projectVersion !== generation.sdkVersion) { + throw new Error(`project version ${projectVersion} does not match generated version ${generation.sdkVersion}`); + } + const prerelease = generation.canonicalVersion.includes('-'); + fs.appendFileSync(process.env.GITHUB_OUTPUT, `version=${projectVersion}\n`); + fs.appendFileSync(process.env.GITHUB_OUTPUT, `tag=v${projectVersion}\n`); + fs.appendFileSync(process.env.GITHUB_OUTPUT, `prerelease=${prerelease}\n`); + NODE + + - name: Build signed Maven Central bundle + env: + MAVEN_GPG_PRIVATE_KEY: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} + MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }} + VERSION: ${{ steps.version.outputs.version }} + CENTRAL_BUNDLE: ${{ runner.temp }}/cloudpdf-central-bundle.zip + run: | + ./gradlew clean test publishMavenPublicationToCentralStagingRepository --no-daemon + release_directory="build/central-staging/com/cloudpdf/sdk/$VERSION" + required_artifacts=( + "sdk-$VERSION.pom" + "sdk-$VERSION.jar" + "sdk-$VERSION-sources.jar" + "sdk-$VERSION-javadoc.jar" + ) + for artifact in "${required_artifacts[@]}"; do + if [ ! -f "$release_directory/$artifact" ]; then + echo "::error::Maven Central bundle is missing $artifact." + exit 1 + fi + if [ ! -f "$release_directory/$artifact.asc" ]; then + echo "::error::Maven artifact $artifact is not signed." + exit 1 + fi + done + + python3 <<'PY' + import os + import xml.etree.ElementTree as ET + + version = os.environ['VERSION'] + pom = ET.parse(f'build/central-staging/com/cloudpdf/sdk/{version}/sdk-{version}.pom').getroot() + namespace = {'m': 'http://maven.apache.org/POM/4.0.0'} + expected = { + 'm:groupId': 'com.cloudpdf', + 'm:artifactId': 'sdk', + 'm:version': version, + 'm:name': 'CloudPDF', + 'm:url': 'https://www.cloudpdf.com', + 'm:scm/m:url': 'https://github.com/embedpdf/cloudpdf-sdk-java', + } + for path, value in expected.items(): + actual = pom.findtext(path, namespaces=namespace) + if actual != value: + raise RuntimeError(f'POM {path} is {actual!r}, expected {value!r}') + PY + + bundle_root="$RUNNER_TEMP/cloudpdf-central-bundle" + bundle_release="$bundle_root/com/cloudpdf/sdk/$VERSION" + mkdir -p "$bundle_release" + for artifact in "${required_artifacts[@]}"; do + cp "$release_directory/$artifact" "$bundle_release/$artifact" + cp "$release_directory/$artifact.asc" "$bundle_release/$artifact.asc" + md5sum "$release_directory/$artifact" | awk '{ print $1 }' > "$bundle_release/$artifact.md5" + sha1sum "$release_directory/$artifact" | awk '{ print $1 }' > "$bundle_release/$artifact.sha1" + done + + cd "$bundle_root" + zip -q -r "$CENTRAL_BUNDLE" com + + - name: Protect immutable release tag + id: release-tag + env: + RELEASE_TAG: ${{ steps.version.outputs.tag }} + run: | + git fetch --force --tags origin + if git rev-parse --quiet --verify "refs/tags/$RELEASE_TAG" >/dev/null; then + tagged_commit="$(git rev-list -n 1 "$RELEASE_TAG")" + if [ "$tagged_commit" != "$GITHUB_SHA" ]; then + if git diff --quiet "$RELEASE_TAG" "$GITHUB_SHA" -- . ':(exclude).github/**'; then + echo "::notice::Reusing $RELEASE_TAG after a workflow-only change." + else + echo "::error::Release tag $RELEASE_TAG already points to different package source at $tagged_commit; bump the SDK version." + exit 1 + fi + fi + echo "existed=true" >> "$GITHUB_OUTPUT" + else + git config user.name cloudpdf-sdk-bot + git config user.email hello@cloudpdf.com + git tag -a "$RELEASE_TAG" -m "CloudPDF Java SDK $RELEASE_TAG" + git push origin "refs/tags/$RELEASE_TAG" + echo "existed=false" >> "$GITHUB_OUTPUT" + fi + + - name: Check Maven Central publication state + id: registry + env: + VERSION: ${{ steps.version.outputs.version }} + TAG_EXISTED: ${{ steps.release-tag.outputs.existed }} + run: | + package_url="https://repo1.maven.org/maven2/com/cloudpdf/sdk/$VERSION/sdk-$VERSION.pom" + http_status="$(curl --silent --show-error --output /dev/null --write-out '%{http_code}' "$package_url")" + case "$http_status" in + 200) + if [ "$TAG_EXISTED" != 'true' ]; then + echo "::error::com.cloudpdf:sdk:$VERSION exists on Maven Central but its release tag did not exist." + exit 1 + fi + echo "publish=false" >> "$GITHUB_OUTPUT" + ;; + 404) + echo "publish=true" >> "$GITHUB_OUTPUT" + ;; + *) + echo "::error::Maven Central returned HTTP $http_status while checking com.cloudpdf:sdk:$VERSION." + exit 1 + ;; + esac + + - name: Upload to Maven Central + if: steps.registry.outputs.publish == 'true' + id: central + env: + MAVEN_CENTRAL_USERNAME: ${{ secrets.MAVEN_CENTRAL_USERNAME }} + MAVEN_CENTRAL_PASSWORD: ${{ secrets.MAVEN_CENTRAL_PASSWORD }} + CENTRAL_BUNDLE: ${{ runner.temp }}/cloudpdf-central-bundle.zip + run: | + central_auth="$(printf '%s:%s' "$MAVEN_CENTRAL_USERNAME" "$MAVEN_CENTRAL_PASSWORD" | base64 --wrap=0)" + echo "::add-mask::$central_auth" + deployment_id="$(curl --fail-with-body --silent --show-error \ + --request POST \ + --header "Authorization: Bearer $central_auth" \ + --form "bundle=@$CENTRAL_BUNDLE;type=application/octet-stream" \ + 'https://central.sonatype.com/api/v1/publisher/upload?publishingType=AUTOMATIC')" + if ! printf '%s' "$deployment_id" | grep -Eq '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'; then + echo "::error::Maven Central returned an invalid deployment ID." + exit 1 + fi + echo "deployment_id=$deployment_id" >> "$GITHUB_OUTPUT" + + - name: Wait for Maven Central publication + if: steps.registry.outputs.publish == 'true' + env: + MAVEN_CENTRAL_USERNAME: ${{ secrets.MAVEN_CENTRAL_USERNAME }} + MAVEN_CENTRAL_PASSWORD: ${{ secrets.MAVEN_CENTRAL_PASSWORD }} + DEPLOYMENT_ID: ${{ steps.central.outputs.deployment_id }} + run: | + central_auth="$(printf '%s:%s' "$MAVEN_CENTRAL_USERNAME" "$MAVEN_CENTRAL_PASSWORD" | base64 --wrap=0)" + echo "::add-mask::$central_auth" + status_file="$(mktemp)" + for attempt in $(seq 1 120); do + curl --fail-with-body --silent --show-error \ + --request POST \ + --header "Authorization: Bearer $central_auth" \ + --output "$status_file" \ + "https://central.sonatype.com/api/v1/publisher/status?id=$DEPLOYMENT_ID" + deployment_state="$(jq --raw-output '.deploymentState' "$status_file")" + case "$deployment_state" in + PUBLISHED) + exit 0 + ;; + FAILED) + cat "$status_file" + echo "::error::Maven Central rejected deployment $DEPLOYMENT_ID." + exit 1 + ;; + PENDING|VALIDATING|VALIDATED|PUBLISHING) + echo "Maven Central deployment is $deployment_state (attempt $attempt/120)." + ;; + *) + cat "$status_file" + echo "::error::Maven Central returned unexpected deployment state $deployment_state." + exit 1 + ;; + esac + sleep 10 + done + echo "::error::Maven Central deployment $DEPLOYMENT_ID did not finish within 20 minutes." + exit 1 + + - name: Create GitHub release + env: + GH_TOKEN: ${{ github.token }} + RELEASE_TAG: ${{ steps.version.outputs.tag }} + PRERELEASE: ${{ steps.version.outputs.prerelease }} + run: | + if gh release view "$RELEASE_TAG" >/dev/null 2>&1; then + exit 0 + fi + args=(--verify-tag --generate-notes --title "CloudPDF Java SDK $RELEASE_TAG") + if [ "$PRERELEASE" = 'true' ]; then args+=(--prerelease); fi + gh release create "$RELEASE_TAG" "${args[@]}" diff --git a/build.gradle b/build.gradle index e2e44aa..93b43e8 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,7 @@ plugins { id 'java-library' id 'maven-publish' + id 'signing' id 'com.diffplug.spotless' version '6.11.0' } @@ -80,31 +81,45 @@ publishing { url = 'https://www.cloudpdf.com' licenses { license { - name = 'APACHE-2.0' + name = 'Apache License, Version 2.0' + url = 'https://www.apache.org/licenses/LICENSE-2.0.txt' + distribution = 'repo' } } developers { developer { + id = 'cloudpdf' name = 'CloudPDF' email = 'hello@cloudpdf.com' + organization = 'CloudPDF' + organizationUrl = 'https://www.cloudpdf.com' } } scm { - connection = 'scm:git:git://github.com/YOUR-ORG/YOUR-REPO.git' - developerConnection = 'scm:git:git://github.com/YOUR-ORG/YOUR-REPO.git' - url = 'https://github.com/YOUR-ORG/YOUR-REPO' + connection = 'scm:git:https://github.com/embedpdf/cloudpdf-sdk-java.git' + developerConnection = 'scm:git:ssh://git@github.com/embedpdf/cloudpdf-sdk-java.git' + url = 'https://github.com/embedpdf/cloudpdf-sdk-java' } } } } repositories { maven { - url "$System.env.MAVEN_PUBLISH_REGISTRY_URL" - credentials { - username "$System.env.MAVEN_USERNAME" - password "$System.env.MAVEN_PASSWORD" - } + name = 'centralStaging' + url = layout.buildDirectory.dir('central-staging') } } } + +tasks.withType(GenerateModuleMetadata) { + enabled = false +} + +signing { + useInMemoryPgpKeys( + System.getenv('MAVEN_GPG_PRIVATE_KEY'), + System.getenv('MAVEN_GPG_PASSPHRASE') + ) + sign publishing.publications.maven +} diff --git a/cloudpdf-generation.json b/cloudpdf-generation.json index 917cd3a..6ceea81 100644 --- a/cloudpdf-generation.json +++ b/cloudpdf-generation.json @@ -6,7 +6,7 @@ "repository": "embedpdf/embed-pdf-viewer", "openapi": "cloudpdf/contract/openapi.json", "openapiSha256": "6858ce7912e9063d8fb171ade95fc473db01c5971a3af241a612dda79cc05100", - "gitCommit": "a0adb9e77ef16feaef2358d71b247b4f5a98fd23", + "gitCommit": "cfc415f2b7501e153280b32bcd6aa4af1353e860", "gitCommitIsDirty": false }, "fern": {