v2.1.3 #14
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Publish to Maven Central | |
| on: | |
| release: | |
| types: [created] | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: 'Version to publish (e.g., 1.0.0)' | |
| required: true | |
| jobs: | |
| publish: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| id-token: write | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Set up JDK 11 | |
| uses: actions/setup-java@v4 | |
| with: | |
| java-version: '11' | |
| distribution: 'temurin' | |
| cache: maven | |
| - name: Configure GPG | |
| id: gpg_setup | |
| env: | |
| GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} | |
| GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} | |
| run: | | |
| mkdir -p ~/.gnupg | |
| chmod 700 ~/.gnupg | |
| echo "pinentry-mode loopback" > ~/.gnupg/gpg.conf | |
| chmod 600 ~/.gnupg/gpg.conf | |
| # Import the private key | |
| echo "Importing GPG private key..." | |
| echo "$GPG_PRIVATE_KEY" | gpg --batch --import | |
| # List keys for debugging | |
| echo "=== GPG Keys After Import ===" | |
| gpg --list-secret-keys --keyid-format LONG | |
| # Extract key ID from the imported key (always extract, don't use secret) | |
| # Try multiple methods to extract the key ID | |
| KEY_ID=$(gpg --list-secret-keys --keyid-format LONG 2>/dev/null | grep -E "^sec" | head -1 | sed -n 's/.*\/\([A-F0-9]\{16\}\).*/\1/p') | |
| if [ -z "$KEY_ID" ]; then | |
| # Fallback: try with different format | |
| KEY_ID=$(gpg --list-secret-keys --keyid-format LONG 2>/dev/null | grep -E "^sec" | head -1 | awk -F'/' '{print $2}' | awk '{print $1}') | |
| fi | |
| if [ -z "$KEY_ID" ]; then | |
| # Last resort: try with pub | |
| KEY_ID=$(gpg --list-secret-keys --keyid-format LONG 2>/dev/null | grep -E "^pub" | head -1 | sed -n 's/.*\/\([A-F0-9]\{16\}\).*/\1/p') | |
| fi | |
| if [ -z "$KEY_ID" ]; then | |
| echo "ERROR: Could not extract GPG key ID from imported key" | |
| echo "=== Full key listing ===" | |
| gpg --list-secret-keys --keyid-format LONG | |
| echo "=== Full key listing (SHORT format) ===" | |
| gpg --list-secret-keys --keyid-format SHORT | |
| exit 1 | |
| fi | |
| echo "Extracted GPG Key ID: $KEY_ID" | |
| # Verify the key exists | |
| if ! gpg --list-secret-keys --keyid-format LONG | grep -q "$KEY_ID"; then | |
| echo "ERROR: Extracted key ID $KEY_ID not found in keyring" | |
| echo "=== Full key listing ===" | |
| gpg --list-secret-keys --keyid-format LONG | |
| exit 1 | |
| fi | |
| # Trust the imported key (ultimate trust) | |
| echo "Trusting key $KEY_ID..." | |
| echo "$KEY_ID:6:" | gpg --import-ownertrust || true | |
| # Verify trust | |
| gpg --check-trustdb || true | |
| echo "key_id=$KEY_ID" >> $GITHUB_OUTPUT | |
| echo "✅ GPG Key ID configured: $KEY_ID" | |
| - name: Extract version from tag | |
| id: get_version | |
| if: github.event_name == 'release' | |
| run: | | |
| VERSION=${GITHUB_REF#refs/tags/v} | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| echo "Extracted version: $VERSION" | |
| - name: Set version from input | |
| id: set_version | |
| if: github.event_name == 'workflow_dispatch' | |
| run: | | |
| echo "version=${{ github.event.inputs.version }}" >> $GITHUB_OUTPUT | |
| - name: Update version in pom.xml | |
| run: | | |
| VERSION=${{ steps.get_version.outputs.version || steps.set_version.outputs.version }} | |
| mvn versions:set -DnewVersion=$VERSION | |
| mvn versions:commit | |
| - name: Run tests | |
| run: mvn clean test | |
| - name: Build project | |
| run: mvn clean package -DskipTests | |
| - name: Configure Maven Settings | |
| env: | |
| SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }} | |
| SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} | |
| run: | | |
| mkdir -p ~/.m2 | |
| # Sonatype Central tokens come as username/password pairs | |
| # The username is the token identifier and password is the token secret | |
| if [ -z "$SONATYPE_USERNAME" ] || [ -z "$SONATYPE_PASSWORD" ]; then | |
| echo "ERROR: Sonatype credentials not set" | |
| echo "" | |
| echo "Sonatype Central requires token-based authentication." | |
| echo "To generate a token:" | |
| echo "1. Go to https://central.sonatype.com/" | |
| echo "2. Log in and go to your profile/settings" | |
| echo "3. Generate a new User Token" | |
| echo "4. You'll receive a username and password pair" | |
| echo "5. Add them as GitHub secrets:" | |
| echo " - SONATYPE_USERNAME: (token username)" | |
| echo " - SONATYPE_PASSWORD: (token password/secret)" | |
| exit 1 | |
| fi | |
| # Create Maven settings.xml with Sonatype Central credentials | |
| # The server ID must be 'central' to match pom.xml publishingServerId | |
| cat > ~/.m2/settings.xml <<EOF | |
| <?xml version="1.0" encoding="UTF-8"?> | |
| <settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" | |
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
| xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 | |
| http://maven.apache.org/xsd/settings-1.0.0.xsd"> | |
| <servers> | |
| <server> | |
| <id>central</id> | |
| <username>${SONATYPE_USERNAME}</username> | |
| <password>${SONATYPE_PASSWORD}</password> | |
| </server> | |
| </servers> | |
| </settings> | |
| EOF | |
| echo "✅ Maven settings.xml configured with token authentication" | |
| echo "✅ Sonatype credentials configured" | |
| - name: Publish to Maven Central | |
| env: | |
| GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} | |
| run: | | |
| KEY_ID=${{ steps.gpg_setup.outputs.key_id }} | |
| if [ -z "$KEY_ID" ]; then | |
| echo "ERROR: GPG Key ID is empty" | |
| gpg --list-secret-keys --keyid-format LONG | |
| exit 1 | |
| fi | |
| echo "Using GPG Key ID: $KEY_ID" | |
| # Final verification: key must exist | |
| if ! gpg --list-secret-keys --keyid-format LONG 2>/dev/null | grep -q "$KEY_ID"; then | |
| echo "ERROR: Key $KEY_ID not found in keyring" | |
| echo "=== Available keys ===" | |
| gpg --list-secret-keys --keyid-format LONG | |
| exit 1 | |
| fi | |
| # Test signing with the key | |
| echo "Testing GPG signing..." | |
| echo "test" | gpg --batch --yes --pinentry-mode loopback --sign --local-user "$KEY_ID" --output /dev/null 2>&1 || { | |
| echo "WARNING: GPG signing test failed, but continuing..." | |
| } | |
| # Verify artifacts are built before deploying | |
| echo "Verifying artifacts before deployment..." | |
| mvn clean package -P release \ | |
| -Dgpg.keyname="$KEY_ID" \ | |
| -Dgpg.passphrase="$GPG_PASSPHRASE" \ | |
| -DskipTests | |
| echo "Checking generated artifacts..." | |
| ls -lah target/*.jar target/*.asc target/*.pom 2>/dev/null || echo "No artifacts found in target/" | |
| # Check if version already exists | |
| VERSION=${{ steps.get_version.outputs.version || steps.set_version.outputs.version }} | |
| echo "Checking if version $VERSION already exists..." | |
| if curl -s "https://repo1.maven.org/maven2/io/translateplus/translateplus-java/$VERSION/" | grep -q "$VERSION"; then | |
| echo "⚠️ WARNING: Version $VERSION may already exist on Maven Central" | |
| echo "Continuing anyway (will fail if version truly exists)..." | |
| fi | |
| echo "Publishing to Maven Central using central-publishing-maven-plugin..." | |
| echo "This plugin handles upload, validation, and release automatically." | |
| echo "With autoPublish=true, it will:" | |
| echo " 1. Upload artifacts to staging" | |
| echo " 2. Automatically close and validate" | |
| echo " 3. Automatically release to Maven Central" | |
| echo " 4. Wait until published (waitUntil=published)" | |
| echo "" | |
| echo "This may take 5-10 minutes..." | |
| # Use central-publishing-maven-plugin which handles everything | |
| # It will upload, sign, validate, and publish automatically | |
| mvn clean deploy -P release \ | |
| -Dgpg.keyname="$KEY_ID" \ | |
| -Dgpg.passphrase="$GPG_PASSPHRASE" \ | |
| 2>&1 | tee deploy.log || { | |
| echo "=== Deployment failed ===" | |
| echo "=== Last 100 lines of deploy.log ===" | |
| tail -100 deploy.log | |
| echo "" | |
| echo "=== Searching for error messages ===" | |
| grep -i "error\|fail\|exception\|401\|unauthorized" deploy.log | tail -50 | |
| echo "" | |
| echo "=== Authentication check ===" | |
| if grep -qi "401\|unauthorized\|token" deploy.log; then | |
| echo "" | |
| echo "⚠️ AUTHENTICATION ERROR DETECTED" | |
| echo "" | |
| echo "Sonatype Central requires token-based authentication." | |
| echo "To fix this:" | |
| echo "1. Go to https://central.sonatype.com/" | |
| echo "2. Log in and navigate to your profile/settings" | |
| echo "3. Generate a new User Token" | |
| echo "4. Add it as SONATYPE_TOKEN secret in GitHub repository settings" | |
| echo "5. The workflow will automatically use the token if available" | |
| echo "" | |
| fi | |
| echo "" | |
| echo "=== Full error trace (last 200 lines) ===" | |
| mvn clean deploy -P release \ | |
| -Dgpg.keyname="$KEY_ID" \ | |
| -Dgpg.passphrase="$GPG_PASSPHRASE" \ | |
| -e 2>&1 | tail -200 | |
| exit 1 | |
| } | |
| echo "" | |
| echo "Checking deployment status..." | |
| if grep -qi "published\|released\|successfully published" deploy.log; then | |
| echo "✅✅✅ SUCCESS! Artifacts have been published to Maven Central!" | |
| echo "" | |
| echo "The central-publishing-maven-plugin with autoPublish=true has:" | |
| echo " ✅ Uploaded artifacts to staging" | |
| echo " ✅ Closed and validated the staging repository" | |
| echo " ✅ Released to Maven Central" | |
| echo " ✅ Waited until published" | |
| echo "" | |
| VERSION=${{ steps.get_version.outputs.version || steps.set_version.outputs.version }} | |
| echo "📦 Published version: $VERSION" | |
| echo "🔗 Maven Central URL: https://repo1.maven.org/maven2/io/translateplus/translateplus-java/$VERSION/" | |
| echo "" | |
| echo "⏱️ Sync time: Usually available immediately, but can take up to 10 minutes" | |
| elif grep -q "central-publishing-maven-plugin" deploy.log; then | |
| echo "✅ central-publishing-maven-plugin executed" | |
| echo "⚠️ Publishing may still be in progress. Check logs above for status." | |
| echo "" | |
| VERSION=${{ steps.get_version.outputs.version || steps.set_version.outputs.version }} | |
| echo "📋 Next Steps:" | |
| echo "1. Check staging repository at: https://central.sonatype.com/" | |
| echo "2. Verify at: https://repo1.maven.org/maven2/io/translateplus/translateplus-java/$VERSION/" | |
| else | |
| echo "⚠️ Note: Check logs above for central-publishing-maven-plugin execution" | |
| echo "" | |
| VERSION=${{ steps.get_version.outputs.version || steps.set_version.outputs.version }} | |
| echo "📋 Manual verification:" | |
| echo "1. Check staging repository at: https://central.sonatype.com/" | |
| echo "2. Verify at: https://repo1.maven.org/maven2/io/translateplus/translateplus-java/$VERSION/" | |
| fi | |
| - name: Verify Publication Status | |
| run: | | |
| VERSION=${{ steps.get_version.outputs.version || steps.set_version.outputs.version }} | |
| echo "🔍 Verifying publication status..." | |
| echo "" | |
| echo "With autoPublish=true and waitUntil=published, the central-publishing-maven-plugin" | |
| echo "should have automatically handled the entire publication process." | |
| echo "" | |
| echo "If the deployment succeeded, your artifact should be:" | |
| echo " ✅ Published to Maven Central" | |
| echo " ✅ Available at: https://repo1.maven.org/maven2/io/translateplus/translateplus-java/$VERSION/" | |
| echo "" | |
| echo "If you need to manually verify or troubleshoot:" | |
| echo "1. Go to: https://central.sonatype.com/" | |
| echo "2. Log in with your Sonatype credentials" | |
| echo "3. Navigate to 'Staging Repositories'" | |
| echo "4. Look for repository with groupId 'io.translateplus' and version '$VERSION'" | |
| echo "5. Check the status:" | |
| echo " - 'Released' = ✅ Successfully published (syncing to Maven Central)" | |
| echo " - 'Closed' = ⚠️ Validated but not released (click 'Release')" | |
| echo " - 'Open' = ⚠️ Not validated (click 'Close', then 'Release')" | |
| echo "" | |
| echo "Note: With autoPublish=true, status should be 'Released' automatically." | |
| - name: Check Sonatype Central Staging Status | |
| env: | |
| SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }} | |
| SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} | |
| run: | | |
| VERSION=${{ steps.get_version.outputs.version || steps.set_version.outputs.version }} | |
| echo "🔍 Checking Sonatype Central staging repository status..." | |
| echo "" | |
| echo "⚠️ IMPORTANT: Manual verification required" | |
| echo "" | |
| echo "Please check your staging repository status at:" | |
| echo "👉 https://central.sonatype.com/" | |
| echo "" | |
| echo "Steps to verify:" | |
| echo "1. Log in with your Sonatype credentials" | |
| echo "2. Go to 'Staging Repositories' or 'Staging Profiles'" | |
| echo "3. Search for 'io.translateplus' or 'translateplus-java'" | |
| echo "4. Check the status of the repository:" | |
| echo "" | |
| echo " Status: 'Open'" | |
| echo " → Action: Click 'Close' button (validates artifacts)" | |
| echo " → Wait for validation to complete" | |
| echo "" | |
| echo " Status: 'Closed'" | |
| echo " → Action: Click 'Release' button (publishes to Maven Central)" | |
| echo " → This will make it available on Maven Central" | |
| echo "" | |
| echo " Status: 'Released'" | |
| echo " → ✅ Success! Artifact is being synced to Maven Central" | |
| echo " → Wait 10-30 minutes for sync to complete" | |
| echo "" | |
| echo " Status: 'Failed' or shows errors" | |
| echo " → Check the 'Activity' tab for validation errors" | |
| echo " → Common issues:" | |
| echo " - GPG signature not found on keyserver" | |
| echo " - Missing sources/javadoc" | |
| echo " - POM validation errors" | |
| echo "" | |
| echo "If the repository is still 'Open' or 'Closed', the autoPublish" | |
| echo "may not have worked. You'll need to manually close and release it." | |
| - name: Wait and Verify Maven Central Sync | |
| run: | | |
| VERSION=${{ steps.get_version.outputs.version || steps.set_version.outputs.version }} | |
| echo "⏳ Waiting 2 minutes before checking Maven Central..." | |
| echo "(This gives time for Sonatype Central to process the release)" | |
| sleep 120 | |
| echo "" | |
| echo "🔍 Checking if artifact is available on Maven Central..." | |
| echo "URL: https://repo1.maven.org/maven2/io/translateplus/translateplus-java/$VERSION/" | |
| echo "" | |
| MAX_ATTEMPTS=15 | |
| ATTEMPT=0 | |
| while [ $ATTEMPT -lt $MAX_ATTEMPTS ]; do | |
| ATTEMPT=$((ATTEMPT + 1)) | |
| echo "Attempt $ATTEMPT/$MAX_ATTEMPTS: Checking Maven Central..." | |
| # Check if the version directory exists | |
| HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "https://repo1.maven.org/maven2/io/translateplus/translateplus-java/$VERSION/") | |
| if [ "$HTTP_CODE" = "200" ]; then | |
| echo "" | |
| echo "✅✅✅ SUCCESS! Artifact is now available on Maven Central! ✅✅✅" | |
| echo "" | |
| echo "📦 Published version: $VERSION" | |
| echo "🔗 URL: https://repo1.maven.org/maven2/io/translateplus/translateplus-java/$VERSION/" | |
| echo "" | |
| echo "📝 Maven dependency:" | |
| echo "<dependency>" | |
| echo " <groupId>io.translateplus</groupId>" | |
| echo " <artifactId>translateplus-java</artifactId>" | |
| echo " <version>$VERSION</version>" | |
| echo "</dependency>" | |
| echo "" | |
| echo "🎉 Publication complete!" | |
| exit 0 | |
| elif [ "$HTTP_CODE" = "404" ]; then | |
| if [ $ATTEMPT -lt $MAX_ATTEMPTS ]; then | |
| echo "⏳ Not yet available (404). Waiting 3 minutes before next check..." | |
| echo " (Sync typically takes 10-30 minutes after release)" | |
| sleep 180 | |
| fi | |
| else | |
| echo "⚠️ Unexpected HTTP code: $HTTP_CODE" | |
| if [ $ATTEMPT -lt $MAX_ATTEMPTS ]; then | |
| echo " Waiting 3 minutes before retry..." | |
| sleep 180 | |
| fi | |
| fi | |
| done | |
| echo "" | |
| echo "⚠️ Artifact not yet available on Maven Central after $((MAX_ATTEMPTS * 3)) minutes" | |
| echo "" | |
| echo "This could mean:" | |
| echo "1. The artifact hasn't been released from Sonatype Central yet" | |
| echo "2. The sync is taking longer than usual (can take up to 2 hours)" | |
| echo "" | |
| echo "🔍 Please verify:" | |
| echo "1. Check Sonatype Central: https://central.sonatype.com/" | |
| echo " → Ensure repository status is 'Released' (not 'Open' or 'Closed')" | |
| echo "" | |
| echo "2. Check Maven Central directly:" | |
| echo " → https://repo1.maven.org/maven2/io/translateplus/translateplus-java/$VERSION/" | |
| echo "" | |
| echo "3. If repository is still 'Open' or 'Closed' in Sonatype Central:" | |
| echo " → Manually close and release it" | |
| echo " → Then wait 10-30 minutes for sync" | |
| echo "" | |
| echo "4. Check for validation errors in Sonatype Central Activity tab" | |
| - name: Verify publication | |
| run: | | |
| VERSION=${{ steps.get_version.outputs.version || steps.set_version.outputs.version }} | |
| echo "📦 Published version: $VERSION" | |
| echo "" | |
| echo "🔍 Check these URLs:" | |
| echo "1. Sonatype Central (staging): https://central.sonatype.com/" | |
| echo "2. Maven Central (after sync): https://repo1.maven.org/maven2/io/translateplus/translateplus-java/$VERSION/" | |
| echo "" | |
| echo "⏱️ Sync time: Usually 10-30 minutes after release" | |
| echo "" | |
| echo "📝 Maven dependency:" | |
| echo "<dependency>" | |
| echo " <groupId>io.translateplus</groupId>" | |
| echo " <artifactId>translateplus-java</artifactId>" | |
| echo " <version>$VERSION</version>" | |
| echo "</dependency>" |