Skip to content
Merged
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
6 changes: 5 additions & 1 deletion .claude/settings.local.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@
"Bash(done)",
"Bash(grep:*)",
"Bash(ls:*)",
"Bash(xargs:*)"
"Bash(xargs:*)",
"Bash(./gradlew tasks:*)",
"Bash(./gradlew jreleaserConfig 2>&1 | tail -30)",
"Bash(find:*)",
"Bash(chmod:*)"
]
}
}
25 changes: 23 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,33 @@ jobs:
JRELEASER_MAVENCENTRAL_USERNAME: ${{ secrets.FLAMINGOCK_JRELEASER_MAVENCENTRAL_USERNAME }}
JRELEASER_MAVENCENTRAL_PASSWORD: ${{ secrets.FLAMINGOCK_JRELEASER_MAVENCENTRAL_PASSWORD }}

- name: Release to Maven Central portal
run: ./gradlew jreleaserFullRelease
- name: Deploy to Maven Central portal
run: ./infra/release-with-retry.sh 900 100 20
env:
JRELEASER_MAVENCENTRAL_USERNAME: ${{ secrets.FLAMINGOCK_JRELEASER_MAVENCENTRAL_USERNAME }}
JRELEASER_MAVENCENTRAL_PASSWORD: ${{ secrets.FLAMINGOCK_JRELEASER_MAVENCENTRAL_PASSWORD }}
JRELEASER_GPG_PUBLIC_KEY: ${{ secrets.FLAMINGOCK_JRELEASER_GPG_PUBLIC_KEY }}
JRELEASER_GPG_SECRET_KEY: ${{ secrets.FLAMINGOCK_JRELEASER_GPG_SECRET_KEY }}
JRELEASER_GPG_PASSPHRASE: ${{ secrets.FLAMINGOCK_JRELEASER_GPG_PASSPHRASE }}

- name: Generate changelog
run: ./gradlew jreleaserChangelog --no-daemon
env:
JRELEASER_GITHUB_TOKEN: ${{ secrets.FLAMINGOCK_JRELEASER_GITHUB_TOKEN }}
JRELEASER_MAVENCENTRAL_USERNAME: ${{ secrets.FLAMINGOCK_JRELEASER_MAVENCENTRAL_USERNAME }}
JRELEASER_MAVENCENTRAL_PASSWORD: ${{ secrets.FLAMINGOCK_JRELEASER_MAVENCENTRAL_PASSWORD }}
JRELEASER_GPG_PUBLIC_KEY: ${{ secrets.FLAMINGOCK_JRELEASER_GPG_PUBLIC_KEY }}
JRELEASER_GPG_SECRET_KEY: ${{ secrets.FLAMINGOCK_JRELEASER_GPG_SECRET_KEY }}
JRELEASER_GPG_PASSPHRASE: ${{ secrets.FLAMINGOCK_JRELEASER_GPG_PASSPHRASE }}

- name: Create GitHub release
run: |
VERSION=$(grep '^version' build.gradle.kts | head -1 | sed 's/.*"\(.*\)".*/\1/')
PRERELEASE_FLAG=$(echo "$VERSION" | grep -qiE '(beta|alpha|rc|snapshot)' && echo "--prerelease" || echo "")
gh release create "v${VERSION}" \
--title "Release v${VERSION}" \
--notes-file build/jreleaser/release/CHANGELOG.md \
$PRERELEASE_FLAG \
--repo "${{ github.repository }}"
env:
GH_TOKEN: ${{ secrets.FLAMINGOCK_JRELEASER_GITHUB_TOKEN }}
96 changes: 89 additions & 7 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ plugins {
`java-library`
`maven-publish`
id("com.diffplug.spotless") version "6.25.0"
id("org.jreleaser") version "1.15.0"
}


group = "io.flamingock"
version = "1.0.0-SNAPSHOT"
version = "1.0.0-beta.7"

val flamingockVersion = "1.2.0-beta.1"

Expand Down Expand Up @@ -37,7 +38,8 @@ java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(8))
}

withSourcesJar()
withJavadocJar()
}

tasks.withType<JavaCompile>().configureEach {
Expand Down Expand Up @@ -67,19 +69,43 @@ publishing {
description.set("MongoDB change templates for document database operations using Flamingock")
url.set("https://flamingock.io")

organization {
name.set("Flamingock")
url.set("https://flamingock.io")
}

issueManagement {
system.set("GitHub")
url.set("https://github.com/flamingock/flamingock-java-template-mongodb/issues")
}

licenses {
license {
name.set("Apache License, Version 2.0")
name.set("Apache-2.0")
url.set("https://www.apache.org/licenses/LICENSE-2.0")
}
}

developers {
developer {
id.set("flamingock")
name.set("Flamingock Team")
organization.set("Flamingock")
organizationUrl.set("https://flamingock.io")
id.set("dieppa")
name.set("Antonio Perez Dieppa")
email.set("dieppa@flamingock.io")
}
developer {
id.set("osantana")
name.set("Oscar Santana")
email.set("osantana@flamingock.io")
}
developer {
id.set("bercianor")
name.set("Berciano Ramiro")
email.set("bercianor@flamingock.io")
}
developer {
id.set("dfrigolet")
name.set("Daniel Frigolet")
email.set("dfrigolet@flamingock.io")
}
}

Expand All @@ -91,6 +117,11 @@ publishing {
}
}
}
repositories {
maven {
url = uri(layout.buildDirectory.dir("staging-deploy"))
}
}
}

val licenseHeaderText = """/*
Expand Down Expand Up @@ -130,3 +161,54 @@ afterEvaluate {
description = "Check license headers (manual task - not part of build)"
}
}

jreleaser {
project {
inceptionYear = "2024"
author("dieppa")
author("osantana")
author("bercianor")
author("dfrigolet")
description = "MongoDB change templates for document database operations using Flamingock"
}
signing {
active = org.jreleaser.model.Active.ALWAYS
armored = true
}
deploy {
maven {
mavenCentral {
create("sonatype") {
active = org.jreleaser.model.Active.ALWAYS
url = "https://central.sonatype.com/api/v1/publisher"
stagingRepository("build/staging-deploy")
applyMavenCentralRules = true
maxRetries = 90
retryDelay = 20
}
}
}
}
release {
github {
overwrite = true
changelog {
formatted = org.jreleaser.model.Active.ALWAYS
preset = "conventional-commits"
}
prerelease {
pattern = ".*(?:beta|alpha|rc|snapshot).*"
}
}
}
}

tasks.register("createStagingDeployFolder") {
doLast {
mkdir(layout.buildDirectory.dir("staging-deploy"))
}
}

tasks.matching { it.name == "publish" }.configureEach {
finalizedBy("createStagingDeployFolder")
}
134 changes: 134 additions & 0 deletions infra/release-with-retry.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
#!/bin/bash
set -euo pipefail

# -------------------------------------------------------------------
# Maven Central release script with curl-based upload fallback.
#
# JReleaser's Feign HTTP client has a hard read-timeout (~6 min) that
# cannot be reliably overridden via Gradle DSL for large bundles.
# This script first attempts jreleaserDeploy; if that fails, it falls
# back to uploading the bundle via curl with a generous timeout,
# then polls the Central Portal for deployment status.
# -------------------------------------------------------------------

UPLOAD_TIMEOUT=${1:-900} # curl upload timeout in seconds (default 15 min)
MAX_STATUS_CHECKS=${2:-100} # max status poll attempts
STATUS_CHECK_INTERVAL=${3:-20} # seconds between status polls

CENTRAL_API="https://central.sonatype.com/api/v1/publisher"

# Credentials from environment (set by GitHub Actions)
USERNAME="${JRELEASER_MAVENCENTRAL_USERNAME:?JRELEASER_MAVENCENTRAL_USERNAME not set}"
PASSWORD="${JRELEASER_MAVENCENTRAL_PASSWORD:?JRELEASER_MAVENCENTRAL_PASSWORD not set}"
AUTH_TOKEN=$(echo -n "${USERNAME}:${PASSWORD}" | base64)

# --- Step 1: Try jreleaserDeploy (signs artifacts and creates bundle) ---
echo "==> Attempting jreleaserDeploy (signs + bundles + uploads)..."
if ./gradlew jreleaserDeploy --no-daemon --stacktrace; then
echo "==> jreleaserDeploy succeeded"
exit 0
fi

echo "==> jreleaserDeploy failed (likely upload timeout). Falling back to curl upload."

# --- Step 2: Locate the bundle created by JReleaser ---
BUNDLE_DIR="build/jreleaser/deploy/mavenCentral/sonatype"
BUNDLE=$(find "$BUNDLE_DIR" -name "*.zip" -type f 2>/dev/null | head -1)

if [ -z "$BUNDLE" ]; then
echo "ERROR: No bundle zip found in $BUNDLE_DIR"
echo "Contents of build/jreleaser/deploy/:"
find build/jreleaser/deploy/ -type f 2>/dev/null || true
exit 1
fi

echo "==> Found bundle: $BUNDLE"

# --- Step 3: Upload bundle via curl with retries ---
upload_bundle() {
local attempt=$1
echo "==> Upload attempt $attempt — timeout ${UPLOAD_TIMEOUT}s"

HTTP_RESPONSE=$(curl -s -w "\n%{http_code}" \
--max-time "$UPLOAD_TIMEOUT" \
--connect-timeout 60 \
-X POST "$CENTRAL_API/upload" \
-H "Authorization: Bearer $AUTH_TOKEN" \
-F "bundle=@$BUNDLE;type=application/octet-stream" \
-F "publishingType=AUTOMATIC" \
2>&1) || true

HTTP_CODE=$(echo "$HTTP_RESPONSE" | tail -1)
RESPONSE_BODY=$(echo "$HTTP_RESPONSE" | sed '$d')

echo "==> Upload response: HTTP $HTTP_CODE"

if [ "$HTTP_CODE" = "201" ]; then
DEPLOYMENT_ID="$RESPONSE_BODY"
echo "==> Upload successful. Deployment ID: $DEPLOYMENT_ID"
return 0
else
echo "==> Upload failed: $RESPONSE_BODY"
return 1
fi
}

DEPLOYMENT_ID=""
for attempt in 1 2 3 4 5; do
if upload_bundle "$attempt"; then
break
fi
if [ "$attempt" -eq 5 ]; then
echo "ERROR: All upload attempts failed"
exit 1
fi
echo "==> Retrying upload in 30 seconds..."
sleep 30
done

# --- Step 4: Poll for deployment status ---
if [ -z "$DEPLOYMENT_ID" ]; then
echo "ERROR: No deployment ID obtained"
exit 1
fi

echo "==> Polling deployment status (max $MAX_STATUS_CHECKS checks, every ${STATUS_CHECK_INTERVAL}s)..."

for (( i=1; i<=MAX_STATUS_CHECKS; i++ )); do
sleep "$STATUS_CHECK_INTERVAL"

STATUS_RESPONSE=$(curl -s \
--max-time 60 \
-X POST "$CENTRAL_API/status?id=$DEPLOYMENT_ID" \
-H "Authorization: Bearer $AUTH_TOKEN" \
-H "Accept: application/json" \
2>&1) || true

DEPLOYMENT_STATE=$(echo "$STATUS_RESPONSE" | grep -o '"deploymentState":"[^"]*"' | head -1 | cut -d'"' -f4)

echo " [$i/$MAX_STATUS_CHECKS] Deployment state: ${DEPLOYMENT_STATE:-UNKNOWN}"

case "$DEPLOYMENT_STATE" in
PUBLISHED)
echo "==> Deployment published successfully!"
exit 0
;;
FAILED)
echo "ERROR: Deployment failed on Maven Central"
echo "Response: $STATUS_RESPONSE"
exit 1
;;
VALIDATED|PUBLISHING)
echo " Deployment is progressing..."
;;
PENDING|VALIDATING)
echo " Still processing..."
;;
*)
echo " Unexpected state, continuing to poll..."
;;
esac
done

echo "ERROR: Timed out waiting for deployment status after $MAX_STATUS_CHECKS checks"
exit 1
Loading