Merge pull request #70 from TrueNine/dev #65
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: | |
| push: | |
| branches: [ main ] | |
| tags: [ 'v*' ] | |
| release: | |
| types: [ published ] | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: 'Release version (e.g., 1.0.0)' | |
| required: true | |
| type: string | |
| dry_run: | |
| description: 'Execute dry run (no actual publish)' | |
| type: boolean | |
| default: false | |
| force_publish: | |
| description: 'Force publish (ignore Maven Central version existence check)' | |
| type: boolean | |
| default: false | |
| skip_tests: | |
| description: 'Skip tests (for emergency releases only)' | |
| type: boolean | |
| default: false | |
| concurrency: | |
| group: maven-publish-${{ github.ref }} | |
| cancel-in-progress: false | |
| env: | |
| GRADLE_OPTS: "-Dorg.gradle.daemon=false -Dorg.gradle.caching=true -Dorg.gradle.logging.level=lifecycle -Dorg.gradle.console=plain" | |
| jobs: | |
| pre-publish-validation: | |
| name: Pre-publish Validation | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 3 | |
| outputs: | |
| version: ${{ steps.version-info.outputs.version }} | |
| is-snapshot: ${{ steps.version-info.outputs.is-snapshot }} | |
| should-publish: ${{ steps.version-info.outputs['should-publish'] }} | |
| version-exists-on-central: ${{ steps.version-info.outputs['version-exists-on-central'] }} | |
| java-version: ${{ steps.libs-versions.outputs.java-version }} | |
| gradle-version: ${{ steps.libs-versions.outputs.gradle-version }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v5.0.0 | |
| with: | |
| fetch-depth: 0 | |
| - name: Extract versions from libs.versions.toml | |
| id: libs-versions | |
| run: | | |
| JAVA_VERSION=$(sed -n 's/^java\s*=\s*"\(.*\)"/\1/p' gradle/libs.versions.toml | head -n1) | |
| GRADLE_VERSION=$(sed -n 's/^org-gradle\s*=\s*"\(.*\)"/\1/p' gradle/libs.versions.toml | head -n1) | |
| echo "java-version=$JAVA_VERSION" >> $GITHUB_OUTPUT | |
| echo "gradle-version=$GRADLE_VERSION" >> $GITHUB_OUTPUT | |
| echo "Extracted Java version: $JAVA_VERSION from libs.versions.toml" | |
| echo "Extracted Gradle version: $GRADLE_VERSION from libs.versions.toml" | |
| - name: Set up JDK ${{ steps.libs-versions.outputs.java-version }} | |
| uses: actions/setup-java@v5.0.0 | |
| with: | |
| java-version: ${{ steps.libs-versions.outputs.java-version }} | |
| distribution: 'temurin' | |
| cache: gradle | |
| - name: Cache Gradle wrapper | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.gradle/wrapper | |
| key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} | |
| restore-keys: | | |
| ${{ runner.os }}-gradle-wrapper- | |
| - name: Cache Gradle dependencies | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.gradle/caches | |
| ~/.gradle/jdks | |
| ~/.gradle/buildOutputCleanup | |
| ~/.gradle/kotlin | |
| ~/.konan | |
| key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties', 'gradle/libs.versions.toml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-gradle- | |
| save-always: true | |
| - name: Setup Gradle | |
| uses: gradle/actions/setup-gradle@v4 | |
| with: | |
| gradle-version: ${{ steps.libs-versions.outputs.gradle-version }} | |
| - name: Grant execute permission | |
| run: chmod +x gradlew | |
| - name: Extract version and check Maven Central | |
| id: version-info | |
| run: | | |
| validate_semver() { | |
| local version="$1" | |
| if [[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9\.-]+)?(\+[a-zA-Z0-9\.-]+)?$ ]]; then | |
| return 0 | |
| else | |
| return 1 | |
| fi | |
| } | |
| check_artifact_exists() { | |
| local group="$1" | |
| local artifact="$2" | |
| local version="$3" | |
| # Method 1: Check via Maven Central REST API | |
| local rest_url="https://repo1.maven.org/maven2/${group//\.//}/${artifact}/${version}/" | |
| echo "Checking REST API: $rest_url" >> $GITHUB_STEP_SUMMARY | |
| if curl -f -s --max-time 15 --head "$rest_url" > /dev/null 2>&1; then | |
| echo "Found via REST API: $artifact-$version exists" >> $GITHUB_STEP_SUMMARY | |
| return 0 | |
| fi | |
| # Additional check: try to access the POM file specifically | |
| local pom_url="https://repo1.maven.org/maven2/${group//\.//}/${artifact}/${version}/${artifact}-${version}.pom" | |
| echo "Checking POM file: $pom_url" >> $GITHUB_STEP_SUMMARY | |
| if curl -f -s --max-time 15 --head "$pom_url" > /dev/null 2>&1; then | |
| echo "Found via POM check: $artifact-$version exists" >> $GITHUB_STEP_SUMMARY | |
| return 0 | |
| fi | |
| # Method 2: Check via Search API | |
| local search_url="https://search.maven.org/solrsearch/select?q=g:\"${group}\"+AND+a:\"${artifact}\"+AND+v:\"${version}\"&rows=1&wt=json" | |
| echo "Checking Search API: $search_url" >> $GITHUB_STEP_SUMMARY | |
| local response=$(curl -f -s --max-time 15 "$search_url" 2>/dev/null || echo '{"response":{"numFound":0}}') | |
| local found=$(echo "$response" | jq -r '.response.numFound' 2>/dev/null || echo "0") | |
| if [[ "$found" -gt 0 ]]; then | |
| echo "Found via Search API: $artifact-$version exists" >> $GITHUB_STEP_SUMMARY | |
| return 0 | |
| fi | |
| echo "Not found: $artifact-$version does not exist" >> $GITHUB_STEP_SUMMARY | |
| return 1 | |
| } | |
| echo "Determining release version..." >> $GITHUB_STEP_SUMMARY | |
| if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then | |
| version="${{ github.event.inputs.version }}" | |
| echo "Manual version: $version" >> $GITHUB_STEP_SUMMARY | |
| elif [[ "${{ github.event_name }}" == "release" ]]; then | |
| version="${{ github.event.release.tag_name }}" | |
| version=${version#v} | |
| echo "Release tag version: $version" >> $GITHUB_STEP_SUMMARY | |
| elif [[ "${{ github.ref_type }}" == "tag" ]]; then | |
| version="${{ github.ref_name }}" | |
| version=${version#v} | |
| echo "Tag triggered version: $version" >> $GITHUB_STEP_SUMMARY | |
| else | |
| version=$(sed -n 's/^project\s*=\s*"\(.*\)"/\1/p' gradle/libs.versions.toml | head -n1) | |
| echo "Version from libs.versions.toml: $version" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| if ! validate_semver "$version"; then | |
| echo "Invalid version format: $version" >> $GITHUB_STEP_SUMMARY | |
| echo "Version must follow semantic versioning (x.y.z[-prerelease][+build])" >> $GITHUB_STEP_SUMMARY | |
| exit 1 | |
| fi | |
| echo "version=$version" >> $GITHUB_OUTPUT | |
| echo "Version format validated: $version" >> $GITHUB_STEP_SUMMARY | |
| if [[ "$version" == *"-SNAPSHOT" ]] || [[ "$version" == *"-alpha"* ]] || [[ "$version" == *"-beta"* ]] || [[ "$version" == *"-rc"* ]]; then | |
| echo "is-snapshot=true" >> $GITHUB_OUTPUT | |
| echo "Pre-release version type" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "is-snapshot=false" >> $GITHUB_OUTPUT | |
| echo "Stable release version type" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| should_publish="false" | |
| version_exists_on_central="false" | |
| force_publish="${{ github.event.inputs.force_publish }}" | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "Publishing decision analysis..." >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| if [[ "$force_publish" == "true" ]]; then | |
| should_publish="true" | |
| echo "Force publish mode enabled - skipping Maven Central version check" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "Checking if version $version exists on Maven Central..." >> $GITHUB_STEP_SUMMARY | |
| group="io.github.truenine" | |
| # Check core artifacts to determine if version exists | |
| core_artifacts=("composeserver-shared" "composeserver-cacheable" "composeserver-bom") | |
| version_found_count=0 | |
| for artifact in "${core_artifacts[@]}"; do | |
| if check_artifact_exists "$group" "$artifact" "$version"; then | |
| version_found_count=$((version_found_count + 1)) | |
| fi | |
| done | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "Version check summary: Found $version_found_count out of ${#core_artifacts[@]} core artifacts" >> $GITHUB_STEP_SUMMARY | |
| # If any core artifact exists, consider version as published | |
| if [[ "$version_found_count" -gt 0 ]]; then | |
| should_publish="false" | |
| version_exists_on_central="true" | |
| echo "Version already exists - Maven Central already has version $version, skipping publish" >> $GITHUB_STEP_SUMMARY | |
| else | |
| should_publish="true" | |
| version_exists_on_central="false" | |
| echo "Version does not exist - Maven Central does not have version $version, will publish" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| fi | |
| echo "should-publish=$should_publish" >> $GITHUB_OUTPUT | |
| echo "version-exists-on-central=$version_exists_on_central" >> $GITHUB_OUTPUT | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Publishing Decision Result" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| if [[ "$should_publish" == "true" ]]; then | |
| if [[ "$force_publish" == "true" ]]; then | |
| echo "Publishing decision: Force publish - will ignore all checks and publish directly" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "Publishing decision: Continue publish - this version does not exist on Maven Central" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| else | |
| if [[ "$version_exists_on_central" == "true" ]]; then | |
| echo "Publishing decision: Skip publish - this version already exists on Maven Central" >> $GITHUB_STEP_SUMMARY | |
| echo "GitHub Release will still be created for existing Maven Central version" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "Publishing decision: Skip publish - unknown reason" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| fi | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Trigger method:** ${{ github.event_name }}" >> $GITHUB_STEP_SUMMARY | |
| echo "**Check version:** $version" >> $GITHUB_STEP_SUMMARY | |
| - name: Generate pre-publish report | |
| run: | | |
| echo "## Publishing Readiness" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "| Check Item | Status |" >> $GITHUB_STEP_SUMMARY | |
| echo "|------------|--------|" >> $GITHUB_STEP_SUMMARY | |
| echo "| Version format validation | ✅ Pass |" >> $GITHUB_STEP_SUMMARY | |
| if [[ "${{ steps.version-info.outputs.version-exists-on-central }}" == "true" ]]; then | |
| echo "| Maven Central version check | 📦 Already exists |" >> $GITHUB_STEP_SUMMARY | |
| elif [[ "${{ steps.version-info.outputs.should-publish }}" == "true" ]]; then | |
| echo "| Maven Central version check | ✅ Not published |" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "| Maven Central version check | ❓ Unknown |" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Version:** ${{ steps.version-info.outputs.version }}" >> $GITHUB_STEP_SUMMARY | |
| echo "**Type:** ${{ steps.version-info.outputs.is-snapshot == 'true' && 'Snapshot version' || 'Stable version' }}" >> $GITHUB_STEP_SUMMARY | |
| if [[ "${{ steps.version-info.outputs.should-publish }}" == "true" ]]; then | |
| echo "**Publishing status:** 🚀 Will publish to Maven Central" >> $GITHUB_STEP_SUMMARY | |
| elif [[ "${{ steps.version-info.outputs.version-exists-on-central }}" == "true" ]]; then | |
| echo "**Publishing status:** ⏭️ Skip publish (already exists), will create GitHub Release" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "**Publishing status:** ⏸️ Skip publish" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| publish: | |
| name: Publish to Maven Central | |
| needs: pre-publish-validation | |
| if: ${{ needs.pre-publish-validation.outputs.should-publish == 'true' }} | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 120 | |
| environment: maven-central | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v5.0.0 | |
| with: | |
| fetch-depth: 0 | |
| - name: Set up JDK ${{ needs.pre-publish-validation.outputs.java-version }} | |
| uses: actions/setup-java@v5.0.0 | |
| with: | |
| java-version: ${{ needs.pre-publish-validation.outputs.java-version }} | |
| distribution: 'temurin' | |
| cache: gradle | |
| - name: Cache Gradle wrapper | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.gradle/wrapper | |
| key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} | |
| restore-keys: | | |
| ${{ runner.os }}-gradle-wrapper- | |
| - name: Cache Gradle dependencies | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.gradle/caches | |
| ~/.gradle/jdks | |
| ~/.gradle/buildOutputCleanup | |
| ~/.konan | |
| key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties', 'gradle/libs.versions.toml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-gradle- | |
| - name: Setup Gradle | |
| uses: gradle/actions/setup-gradle@v4 | |
| with: | |
| gradle-version: ${{ needs.pre-publish-validation.outputs.gradle-version }} | |
| cache-cleanup: on-success | |
| - name: Grant execute permission | |
| run: chmod +x gradlew | |
| - name: Dry run publication | |
| if: github.event.inputs.dry_run == 'true' | |
| run: | | |
| echo "Executing publication dry run..." | |
| # Aggressively clean build services to prevent duplicate entries | |
| ./gradlew --stop || true | |
| rm -rf ~/.gradle/daemon/ || true | |
| rm -rf ~/.gradle/caches/ || true | |
| rm -rf .gradle/ || true | |
| find . -name "build" -type d -exec rm -rf {} + || true | |
| # Clean Maven local repository for this project's artifacts to prevent conflicts | |
| rm -rf ~/.m2/repository/io/github/truenine/ || true | |
| # First clean everything | |
| ./gradlew clean \ | |
| --no-daemon \ | |
| --no-parallel \ | |
| --no-build-cache \ | |
| --no-configuration-cache | |
| # Then run dry publication with additional safeguards | |
| ./gradlew publishToMavenLocal \ | |
| --no-daemon \ | |
| --no-parallel \ | |
| --no-build-cache \ | |
| --no-configuration-cache \ | |
| --rerun-tasks \ | |
| --max-workers=1 \ | |
| -PsigningInMemoryKeyId="${{ secrets.GPG_KEY_ID }}" \ | |
| -PsigningInMemoryKey="${{ secrets.GPG_PRIVATE_KEY }}" \ | |
| -PsigningInMemoryKeyPassword="${{ secrets.GPG_PASSPHRASE }}" | |
| env: | |
| GRADLE_OPTS: "${{ env.GRADLE_OPTS }} ${{ env.JVM_OPTS }}" | |
| CI: true | |
| - name: Pre-publish validation | |
| if: github.event.inputs.dry_run != 'true' | |
| run: | | |
| echo "Pre-publish validation..." | |
| missing_secrets=() | |
| [[ -z "${{ secrets.GPG_KEY_ID }}" ]] && missing_secrets+=("GPG_KEY_ID") | |
| [[ -z "${{ secrets.GPG_PRIVATE_KEY }}" ]] && missing_secrets+=("GPG_PRIVATE_KEY") | |
| [[ -z "${{ secrets.MAVENCENTRAL_USERNAME }}" ]] && missing_secrets+=("MAVENCENTRAL_USERNAME") | |
| [[ -z "${{ secrets.MAVENCENTRAL_PASSWORD }}" ]] && missing_secrets+=("MAVENCENTRAL_PASSWORD") | |
| [[ -z "${{ secrets.GPG_PASSPHRASE }}" ]] && missing_secrets+=("GPG_PASSPHRASE") | |
| if [[ ${#missing_secrets[@]} -gt 0 ]]; then | |
| echo "Missing required secrets: ${missing_secrets[*]}" >> $GITHUB_STEP_SUMMARY | |
| exit 1 | |
| fi | |
| echo "Verifying network connectivity..." | |
| curl -f -s --max-time 10 https://oss.sonatype.org/ > /dev/null || { | |
| echo "Sonatype network connectivity issue" >> $GITHUB_STEP_SUMMARY | |
| } | |
| echo "Validation passed" >> $GITHUB_STEP_SUMMARY | |
| - name: Final version existence check | |
| if: github.event.inputs.dry_run != 'true' | |
| run: | | |
| echo "Performing final version existence check before publishing..." | |
| version="${{ needs.pre-publish-validation.outputs.version }}" | |
| group="io.github.truenine" | |
| force_publish="${{ github.event.inputs.force_publish }}" | |
| # Double-check that version doesn't exist unless force_publish is enabled | |
| if [[ "$force_publish" != "true" ]]; then | |
| echo "Checking if version $version exists on Maven Central one more time..." | |
| # Check a few core artifacts to be absolutely sure | |
| core_artifacts=("composeserver-shared" "composeserver-cacheable" "composeserver-bom") | |
| for artifact in "${core_artifacts[@]}"; do | |
| pom_url="https://repo1.maven.org/maven2/${group//\.//}/${artifact}/${version}/${artifact}-${version}.pom" | |
| echo "Final check for: $pom_url" | |
| if curl -f -s --max-time 15 --head "$pom_url" > /dev/null 2>&1; then | |
| echo "ABORT: Version $version already exists on Maven Central!" | |
| echo "Found existing artifact: $artifact-$version" | |
| echo "If you want to force republish, use force_publish: true" | |
| exit 1 | |
| fi | |
| done | |
| echo "Final check passed - version $version does not exist on Maven Central" | |
| else | |
| echo "Force publish enabled - skipping final version existence check" | |
| fi | |
| - name: Publish to Maven Central | |
| if: github.event.inputs.dry_run != 'true' | |
| uses: nick-fields/retry@v3 | |
| with: | |
| timeout_minutes: 20 | |
| max_attempts: 2 | |
| retry_wait_seconds: 60 | |
| shell: bash | |
| command: | | |
| echo "Starting publication to Maven Central (attempt: ${{ github.run_attempt }})..." | |
| set -euo pipefail | |
| handle_error() { | |
| local exit_code=$1 | |
| local error_context="$2" | |
| echo "Publication failed (exit code: $exit_code)" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| case $exit_code in | |
| 1|2) echo "**Error type:** Build or configuration error" >> $GITHUB_STEP_SUMMARY ;; | |
| 3|4) echo "**Error type:** GPG signing failed" >> $GITHUB_STEP_SUMMARY ;; | |
| 5|6) echo "**Error type:** Maven Central connection failed" >> $GITHUB_STEP_SUMMARY ;; | |
| *) echo "**Error type:** Unknown error" >> $GITHUB_STEP_SUMMARY ;; | |
| esac | |
| echo "**Error context:** $error_context" >> $GITHUB_STEP_SUMMARY | |
| exit $exit_code | |
| } | |
| trap 'handle_error $? "Publication execution phase"' ERR | |
| echo "Verifying publication credentials..." >> $GITHUB_STEP_SUMMARY | |
| echo "Cleaning build services to prevent duplicate entries..." >> $GITHUB_STEP_SUMMARY | |
| # Stop all running Gradle daemons and aggressively clean build services | |
| ./gradlew --stop || true | |
| rm -rf ~/.gradle/daemon/ || true | |
| rm -rf ~/.gradle/caches/ || true | |
| rm -rf .gradle/ || true | |
| find . -name "build" -type d -exec rm -rf {} + || true | |
| # Clean Maven local repository for this project's artifacts to prevent conflicts | |
| rm -rf ~/.m2/repository/io/github/truenine/ || true | |
| echo "Cleaned build services and Maven local repository" >> $GITHUB_STEP_SUMMARY | |
| echo "Starting clean publication process..." >> $GITHUB_STEP_SUMMARY | |
| # First clean everything to ensure no stale artifacts | |
| ./gradlew clean \ | |
| --no-daemon \ | |
| --no-parallel \ | |
| --no-build-cache \ | |
| --no-configuration-cache | |
| # Then publish with fresh state and additional safeguards | |
| ./gradlew publishToMavenCentral \ | |
| --no-daemon \ | |
| --no-parallel \ | |
| --no-build-cache \ | |
| --no-configuration-cache \ | |
| --rerun-tasks \ | |
| --max-workers=1 \ | |
| -PsigningInMemoryKeyId="${{ secrets.GPG_KEY_ID }}" \ | |
| -PsigningInMemoryKey="${{ secrets.GPG_PRIVATE_KEY }}" \ | |
| -PmavenCentralUsername="${{ secrets.MAVENCENTRAL_USERNAME }}" \ | |
| -PmavenCentralPassword="${{ secrets.MAVENCENTRAL_PASSWORD }}" \ | |
| -PsigningInMemoryKeyPassword="${{ secrets.GPG_PASSPHRASE }}" | |
| echo "Successfully published to Maven Central" >> $GITHUB_STEP_SUMMARY | |
| env: | |
| GRADLE_OPTS: "${{ env.GRADLE_OPTS }} ${{ env.JVM_OPTS }}" | |
| MAVENCENTRAL_USERNAME: ${{ secrets.MAVENCENTRAL_USERNAME }} | |
| MAVENCENTRAL_PASSWORD: ${{ secrets.MAVENCENTRAL_PASSWORD }} | |
| GPG_KEY_ID: ${{ secrets.GPG_KEY_ID }} | |
| GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} | |
| GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} | |
| CI: true | |
| - name: Generate publication summary | |
| run: | | |
| echo "## Publication Completed" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Version:** ${{ needs.pre-publish-validation.outputs.version }}" >> $GITHUB_STEP_SUMMARY | |
| echo "**Status:** ${{ github.event.inputs.dry_run == 'true' && 'Dry run completed' || 'Official publication completed' }}" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| if [[ "${{ github.event.inputs.dry_run }}" != "true" ]]; then | |
| echo "### Post-publication Checklist" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "- [ ] Verify artifacts on Maven Central" >> $GITHUB_STEP_SUMMARY | |
| echo "- [ ] Update project documentation" >> $GITHUB_STEP_SUMMARY | |
| echo "- [ ] Publish GitHub Release notes" >> $GITHUB_STEP_SUMMARY | |
| echo "- [ ] Notify team members" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Maven Central Link:** https://search.maven.org/search?q=g:io.github.truenine" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "Dry run successful, all modules built and signed correctly!" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| create-github-release: | |
| name: Create GitHub Release | |
| needs: [ pre-publish-validation, publish ] | |
| if: | | |
| github.event.inputs.dry_run != 'true' && | |
| needs.pre-publish-validation.outputs.is-snapshot == 'false' && | |
| (needs.publish.result == 'success' || | |
| needs.publish.result == 'skipped' || | |
| needs.pre-publish-validation.outputs.version-exists-on-central == 'true') | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v5.0.0 | |
| with: | |
| fetch-depth: 0 | |
| - name: Generate release notes | |
| id: release-notes | |
| run: | | |
| version="${{ needs.pre-publish-validation.outputs.version }}" | |
| version_exists="${{ needs.pre-publish-validation.outputs.version-exists-on-central }}" | |
| publish_status="${{ needs.publish.result }}" | |
| cat > release_notes.md << 'EOF' | |
| ## Release ${{ needs.pre-publish-validation.outputs.version }} | |
| ### Maven Central Artifacts | |
| This release is available on Maven Central Repository: | |
| ```kotlin | |
| implementation("io.github.truenine:composeserver-{module-name}:${{ needs.pre-publish-validation.outputs.version }}") | |
| ``` | |
| ```xml | |
| <dependency> | |
| <groupId>io.github.truenine</groupId> | |
| <artifactId>composeserver-{module-name}</artifactId> | |
| <version>${{ needs.pre-publish-validation.outputs.version }}</version> | |
| </dependency> | |
| ``` | |
| ### Release Status | |
| EOF | |
| if [[ "$publish_status" == "success" ]]; then | |
| echo "✅ **New Release**: This version was just published to Maven Central." >> release_notes.md | |
| elif [[ "$version_exists" == "true" ]]; then | |
| echo "📦 **Existing Release**: This version already exists on Maven Central. Creating GitHub Release for reference." >> release_notes.md | |
| else | |
| echo "🔄 **Release**: This version is available on Maven Central." >> release_notes.md | |
| fi | |
| cat >> release_notes.md << 'EOF' | |
| ### Links | |
| - [Maven Central Search](https://search.maven.org/search?q=g:io.github.truenine%20AND%20v:${{ needs.pre-publish-validation.outputs.version }}) | |
| - [Project Documentation](https://github.com/TrueNine/compose-server) | |
| - [API Documentation](https://github.com/TrueNine/compose-server/tree/main/docs) | |
| --- | |
| **Full Changelog**: https://github.com/TrueNine/compose-server/compare/v${{ needs.pre-publish-validation.outputs.version }}...HEAD | |
| EOF | |
| echo "Generated release notes for version $version (publish_status: $publish_status, version_exists: $version_exists)" | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: ${{ needs.pre-publish-validation.outputs.version }} | |
| name: ${{ needs.pre-publish-validation.outputs.version }} | |
| body_path: release_notes.md | |
| draft: false | |
| prerelease: false | |
| generate_release_notes: true | |
| make_latest: true | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Update release summary | |
| run: | | |
| echo "## GitHub Release Created" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Version tag:** v${{ needs.pre-publish-validation.outputs.version }}" >> $GITHUB_STEP_SUMMARY | |
| echo "**Release link:** https://github.com/TrueNine/compose-server/releases/tag/v${{ needs.pre-publish-validation.outputs.version }}" >> $GITHUB_STEP_SUMMARY | |
| post-publish-verification: | |
| name: Post-publish Verification | |
| needs: [ pre-publish-validation, publish, create-github-release ] | |
| if: | | |
| github.event.inputs.dry_run != 'true' && | |
| always() && | |
| (needs.publish.result == 'success' || | |
| needs.pre-publish-validation.outputs.version-exists-on-central == 'true') | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - name: Skip verification (save time) | |
| run: | | |
| echo "Skipping Maven Central sync verification to save time" | |
| echo "Publication completed, Maven Central sync usually takes several hours" | |
| - name: Generate verification report | |
| run: | | |
| version="${{ needs.pre-publish-validation.outputs.version }}" | |
| publish_result="${{ needs.publish.result }}" | |
| version_exists="${{ needs.pre-publish-validation.outputs.version-exists-on-central }}" | |
| echo "## Publication Verification Report" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Version:** $version" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Publication Status" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| if [[ "$publish_result" == "success" ]]; then | |
| echo "- ✅ Publication task completed successfully" >> $GITHUB_STEP_SUMMARY | |
| echo "- 🔄 Maven Central sync may take several hours" >> $GITHUB_STEP_SUMMARY | |
| echo "- 📝 Recommend manual verification in 4-6 hours" >> $GITHUB_STEP_SUMMARY | |
| elif [[ "$version_exists" == "true" ]]; then | |
| echo "- 📦 Version already exists on Maven Central" >> $GITHUB_STEP_SUMMARY | |
| echo "- ⏭️ Publication was skipped (no need to republish)" >> $GITHUB_STEP_SUMMARY | |
| echo "- 🏷️ GitHub Release created for existing version" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "- ⚠️ Publication was skipped" >> $GITHUB_STEP_SUMMARY | |
| echo "- 🔍 Check workflow logs for details" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Related Links" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "- [Maven Central Search](https://search.maven.org/search?q=g:io.github.truenine%20AND%20v:$version)" >> $GITHUB_STEP_SUMMARY | |
| echo "- [Maven Central - All Versions](https://search.maven.org/search?q=g:io.github.truenine)" >> $GITHUB_STEP_SUMMARY | |
| echo "- [Sonatype Repository](https://oss.sonatype.org/)" >> $GITHUB_STEP_SUMMARY | |
| if [[ "${{ needs.create-github-release.result }}" == "success" ]]; then | |
| echo "- [GitHub Release](https://github.com/TrueNine/compose-server/releases/tag/v${{ needs.pre-publish-validation.outputs.version }})" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**GitHub Release created successfully**" >> $GITHUB_STEP_SUMMARY | |
| elif [[ "${{ needs.create-github-release.result }}" == "skipped" ]]; then | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**GitHub Release skipped** (pre-release version)" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**GitHub Release creation failed**, please create manually" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| failure-handler: | |
| name: Handle Failure | |
| needs: [ pre-publish-validation, publish, create-github-release, post-publish-verification ] | |
| if: always() && (needs.publish.result == 'failure' || needs.create-github-release.result == 'failure') | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| steps: | |
| - name: Generate failure report | |
| run: | | |
| echo "## Publication Failure Report" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Version:** ${{ needs.pre-publish-validation.outputs.version }}" >> $GITHUB_STEP_SUMMARY | |
| echo "**Trigger event:** ${{ github.event_name }}" >> $GITHUB_STEP_SUMMARY | |
| echo "**Failure time:** $(date -u '+%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Failure Status Analysis" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| if [[ "${{ needs.publish.result }}" == "failure" ]]; then | |
| echo "- Maven Central publication failed" >> $GITHUB_STEP_SUMMARY | |
| echo " - Check GPG signing configuration" >> $GITHUB_STEP_SUMMARY | |
| echo " - Verify Maven Central credentials" >> $GITHUB_STEP_SUMMARY | |
| echo " - Confirm network connectivity" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "- Maven Central publication succeeded" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| if [[ "${{ needs.create-github-release.result }}" == "failure" ]]; then | |
| echo "- GitHub Release creation failed" >> $GITHUB_STEP_SUMMARY | |
| echo " - Check GITHUB_TOKEN permissions" >> $GITHUB_STEP_SUMMARY | |
| echo " - Verify tag does not already exist" >> $GITHUB_STEP_SUMMARY | |
| echo " - Confirm repository write permissions" >> $GITHUB_STEP_SUMMARY | |
| elif [[ "${{ needs.create-github-release.result }}" == "success" ]]; then | |
| echo "- GitHub Release creation succeeded" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Suggested Fix Steps" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "1. Check the configuration of failed components above" >> $GITHUB_STEP_SUMMARY | |
| echo "2. Verify all necessary GitHub Secrets are correctly configured" >> $GITHUB_STEP_SUMMARY | |
| echo "3. If network issue, you can re-run the workflow" >> $GITHUB_STEP_SUMMARY | |
| echo "4. If problems persist, please create an Issue to report the problem" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Get Help" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "- [Create Issue](https://github.com/TrueNine/compose-server/issues/new)" >> $GITHUB_STEP_SUMMARY | |
| echo "- [View Documentation](https://github.com/TrueNine/compose-server/tree/main/docs)" >> $GITHUB_STEP_SUMMARY | |
| workflow-summary: | |
| name: Workflow Summary | |
| needs: [ pre-publish-validation, publish, create-github-release, post-publish-verification, failure-handler ] | |
| if: always() | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| steps: | |
| - name: Generate workflow summary | |
| run: | | |
| echo "# Maven Central Publication Workflow Summary" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Workflow execution time:** $(date -u '+%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_STEP_SUMMARY | |
| echo "**Trigger event:** ${{ github.event_name }}" >> $GITHUB_STEP_SUMMARY | |
| echo "**Branch/Tag:** ${{ github.ref_name }}" >> $GITHUB_STEP_SUMMARY | |
| echo "**Commit SHA:** ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "## Task Execution Status" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "| Task | Status | Result |" >> $GITHUB_STEP_SUMMARY | |
| echo "|------|--------|--------|" >> $GITHUB_STEP_SUMMARY | |
| echo "| Pre-publish Validation | ${{ needs.pre-publish-validation.result }} | ${{ needs.pre-publish-validation.result == 'success' && 'Pass' || needs.pre-publish-validation.result == 'failure' && 'Failed' || needs.pre-publish-validation.result == 'skipped' && 'Skipped' || 'Running' }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Maven Central Publication | ${{ needs.publish.result }} | ${{ needs.publish.result == 'success' && 'Pass' || needs.publish.result == 'failure' && 'Failed' || needs.publish.result == 'skipped' && 'Skipped' || 'Running' }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "| GitHub Release | ${{ needs.create-github-release.result }} | ${{ needs.create-github-release.result == 'success' && 'Pass' || needs.create-github-release.result == 'failure' && 'Failed' || needs.create-github-release.result == 'skipped' && 'Skipped' || 'Running' }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Post-publish Verification | ${{ needs.post-publish-verification.result }} | ${{ needs.post-publish-verification.result == 'success' && 'Pass' || needs.post-publish-verification.result == 'failure' && 'Failed' || needs.post-publish-verification.result == 'skipped' && 'Skipped' || 'Running' }} |" >> $GITHUB_STEP_SUMMARY | |
| if [[ "${{ needs.pre-publish-validation.outputs.version }}" != "" ]]; then | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "## Version Information" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Version number:** ${{ needs.pre-publish-validation.outputs.version }}" >> $GITHUB_STEP_SUMMARY | |
| echo "**Version type:** ${{ needs.pre-publish-validation.outputs.is-snapshot == 'true' && 'Pre-release version' || 'Stable version' }}" >> $GITHUB_STEP_SUMMARY | |
| echo "**Publication status:** ${{ needs.pre-publish-validation.outputs.should-publish == 'true' && 'Published' || 'Skipped' }}" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "## Overall Status" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| if [[ "${{ needs.publish.result }}" == "success" ]]; then | |
| echo "✅ **Publication successful!** New version has been successfully published to Maven Central" >> $GITHUB_STEP_SUMMARY | |
| elif [[ "${{ needs.pre-publish-validation.outputs.version-exists-on-central }}" == "true" ]]; then | |
| echo "📦 **Publication skipped** - this version already exists on Maven Central. GitHub Release created for reference." >> $GITHUB_STEP_SUMMARY | |
| elif [[ "${{ needs.publish.result }}" == "skipped" ]]; then | |
| echo "⏭️ **Publication skipped** - check pre-publish validation for details" >> $GITHUB_STEP_SUMMARY | |
| elif [[ "${{ needs.publish.result }}" == "failure" ]]; then | |
| echo "❌ **Publication failed** - please check error logs and retry" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "🔄 **Workflow in progress** - please wait for completion" >> $GITHUB_STEP_SUMMARY | |
| fi |