v0.11.3 #57
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: Multi-module Release | |
| on: | |
| release: | |
| types: [published] | |
| env: | |
| GROUP_ID: io.testomat | |
| MAVEN_CENTRAL_BASE: https://repo1.maven.org/maven2 | |
| MAVEN_SEARCH_BASE: https://search.maven.org/remotecontent | |
| MAVEN_SEARCH_API: https://search.maven.org/solrsearch/select | |
| MAVEN_TIMEOUT: 3600 | |
| MAVEN_CENTRAL_WAIT_TIMEOUT: 7200 | |
| MAX_RETRY_ATTEMPTS: 3 | |
| RETRY_DELAY: 30 | |
| jobs: | |
| release: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Validate project structure | |
| run: | | |
| set -e | |
| REQUIRED_DIRS=("java-reporter-core" "java-reporter-junit" "java-reporter-testng" "java-reporter-cucumber" "java-reporter-karate" "testomat-allure-adapter") | |
| for dir in "${REQUIRED_DIRS[@]}"; do | |
| if [[ ! -d "$dir" ]] || [[ ! -f "$dir/pom.xml" ]]; then | |
| echo "❌ Missing: $dir" | |
| exit 1 | |
| fi | |
| done | |
| echo "✅ Project structure OK" | |
| - name: Validate required secrets | |
| run: | | |
| set -e | |
| MISSING_SECRETS=() | |
| [[ -z "${{ secrets.GPG_PRIVATE_KEY }}" ]] && MISSING_SECRETS+=("GPG_PRIVATE_KEY") | |
| [[ -z "${{ secrets.CENTRAL_USERNAME }}" ]] && MISSING_SECRETS+=("CENTRAL_USERNAME") | |
| [[ -z "${{ secrets.CENTRAL_PASSWORD }}" ]] && MISSING_SECRETS+=("CENTRAL_PASSWORD") | |
| [[ -z "${{ secrets.GPG_PASSPHRASE }}" ]] && MISSING_SECRETS+=("GPG_PASSPHRASE") | |
| if [[ ${#MISSING_SECRETS[@]} -gt 0 ]]; then | |
| echo "❌ Missing secrets: ${MISSING_SECRETS[*]}" | |
| exit 1 | |
| fi | |
| echo "✅ Secrets OK" | |
| - name: Set up JDK 17 | |
| uses: actions/setup-java@v4 | |
| with: | |
| java-version: '17' | |
| distribution: 'temurin' | |
| - name: Cache Maven dependencies | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.m2 | |
| key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} | |
| restore-keys: ${{ runner.os }}-m2 | |
| - name: Configure Maven settings | |
| run: | | |
| set -e | |
| mkdir -p ~/.m2 | |
| cat > ~/.m2/settings.xml << 'EOF' | |
| <settings> | |
| <servers> | |
| <server> | |
| <id>central</id> | |
| <username>${env.CENTRAL_USERNAME}</username> | |
| <password>${env.CENTRAL_PASSWORD}</password> | |
| </server> | |
| </servers> | |
| </settings> | |
| EOF | |
| echo "✅ Maven settings configured" | |
| - name: Get version from release tag | |
| id: version | |
| run: | | |
| set -e | |
| TAG_NAME="${{ github.event.release.tag_name }}" | |
| if [[ -z "$TAG_NAME" ]]; then | |
| echo "❌ No tag name" | |
| exit 1 | |
| fi | |
| VERSION=${TAG_NAME#v} | |
| if ! echo "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.-]+)?$'; then | |
| echo "❌ Invalid version: $VERSION" | |
| exit 1 | |
| fi | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| echo "✅ Version: $VERSION" | |
| - name: Set versions in all modules | |
| run: | | |
| set -e | |
| VERSION=${{ steps.version.outputs.version }} | |
| echo "🔄 Setting version $VERSION in all modules individually..." | |
| # List of all modules (each has its own pom.xml) | |
| MODULES=("java-reporter-core" "java-reporter-junit" "java-reporter-testng" "java-reporter-cucumber" "java-reporter-karate" "testomat-allure-adapter") | |
| for module in "${MODULES[@]}"; do | |
| if [[ -d "$module" && -f "$module/pom.xml" ]]; then | |
| echo "Setting version in $module..." | |
| cd "$module" || { echo "❌ Cannot enter $module"; exit 1; } | |
| # Set version in this module | |
| if ! mvn versions:set -DnewVersion="$VERSION" -DgenerateBackupPoms=false -B; then | |
| echo "❌ Failed to set version in $module" | |
| exit 1 | |
| fi | |
| echo "✅ Version set to $VERSION in $module" | |
| cd .. || exit 1 | |
| else | |
| echo "⚠️ Module $module not found or missing pom.xml" | |
| fi | |
| done | |
| echo "✅ All module versions set to $VERSION" | |
| - name: Update internal dependencies (excluding Core) | |
| run: | | |
| set -e | |
| VERSION=${{ steps.version.outputs.version }} | |
| echo "🔄 Updating internal dependencies to version $VERSION..." | |
| # Only modules that have internal dependencies (excluding Core) | |
| MODULES_WITH_DEPS=("java-reporter-junit" "java-reporter-testng" "java-reporter-cucumber" "java-reporter-karate" "testomat-allure-adapter") | |
| for module in "${MODULES_WITH_DEPS[@]}"; do | |
| if [[ -d "$module" && -f "$module/pom.xml" ]]; then | |
| echo "Updating dependencies in $module..." | |
| cd "$module" || continue | |
| # Update java-reporter-core dependency (most modules depend on it) | |
| echo " Updating java-reporter-core dependency..." | |
| if mvn versions:use-dep-version \ | |
| -Dincludes="${{ env.GROUP_ID }}:java-reporter-core" \ | |
| -DdepVersion="$VERSION" \ | |
| -DforceVersion=true \ | |
| -DgenerateBackupPoms=false \ | |
| -B 2>/dev/null; then | |
| echo " ✅ Updated java-reporter-core to $VERSION" | |
| else | |
| echo " ⚠️ java-reporter-core dependency not found" | |
| fi | |
| cd .. || exit 1 | |
| fi | |
| done | |
| echo "✅ All internal dependencies updated" | |
| - name: Verify all versions are set correctly | |
| run: | | |
| set -e | |
| VERSION=${{ steps.version.outputs.version }} | |
| echo "🔍 Verifying all module versions are set to $VERSION..." | |
| MODULES=("java-reporter-core" "java-reporter-junit" "java-reporter-testng" "java-reporter-cucumber" "java-reporter-karate" "testomat-allure-adapter") | |
| FAILED_MODULES=() | |
| for module in "${MODULES[@]}"; do | |
| if [[ -d "$module" && -f "$module/pom.xml" ]]; then | |
| cd "$module" || continue | |
| CURRENT_VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout 2>/dev/null) | |
| if [[ "$CURRENT_VERSION" == "$VERSION" ]]; then | |
| echo "✅ $module version: $CURRENT_VERSION" | |
| else | |
| echo "❌ $module version mismatch: expected $VERSION, got $CURRENT_VERSION" | |
| FAILED_MODULES+=("$module") | |
| fi | |
| cd .. || exit 1 | |
| fi | |
| done | |
| if [[ ${#FAILED_MODULES[@]} -gt 0 ]]; then | |
| echo "❌ Version verification failed for modules: ${FAILED_MODULES[*]}" | |
| exit 1 | |
| fi | |
| echo "✅ All module versions verified successfully" | |
| - name: Setup GPG | |
| run: | | |
| set -e | |
| echo "${{ secrets.GPG_PRIVATE_KEY }}" | base64 --decode | gpg --batch --import | |
| echo "✅ GPG configured" | |
| - name: Deploy Core module | |
| run: | | |
| set -e | |
| echo "🚀 Deploying Core..." | |
| cd java-reporter-core || { echo "❌ Cannot enter core directory"; exit 1; } | |
| # Verify version is set correctly | |
| CURRENT_VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout) | |
| if [[ "$CURRENT_VERSION" != "${{ steps.version.outputs.version }}" ]]; then | |
| echo "❌ Version mismatch: expected ${{ steps.version.outputs.version }}, got $CURRENT_VERSION" | |
| exit 1 | |
| fi | |
| for i in $(seq 1 ${{ env.MAX_RETRY_ATTEMPTS }}); do | |
| echo "Core deployment attempt $i..." | |
| if timeout ${{ env.MAVEN_TIMEOUT }} mvn clean deploy -P release -DskipTests -B; then | |
| echo "✅ Core deployed successfully" | |
| cd .. || exit 1 | |
| break | |
| elif [[ $i -eq ${{ env.MAX_RETRY_ATTEMPTS }} ]]; then | |
| echo "❌ Core deployment failed after ${{ env.MAX_RETRY_ATTEMPTS }} attempts" | |
| cd .. || exit 1 | |
| exit 1 | |
| else | |
| echo "Retrying in ${{ env.RETRY_DELAY }}s..." | |
| sleep ${{ env.RETRY_DELAY }} | |
| fi | |
| done | |
| env: | |
| CENTRAL_USERNAME: ${{ secrets.CENTRAL_USERNAME }} | |
| CENTRAL_PASSWORD: ${{ secrets.CENTRAL_PASSWORD }} | |
| GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} | |
| - name: Wait for Core availability | |
| run: | | |
| set -e | |
| VERSION=${{ steps.version.outputs.version }} | |
| MODULE="java-reporter-core" | |
| GROUP_PATH=$(echo "${{ env.GROUP_ID }}" | tr '.' '/') | |
| echo "⏳ Waiting for Core availability..." | |
| WAIT_ITERATIONS=$((MAVEN_CENTRAL_WAIT_TIMEOUT / 120)) | |
| for i in $(seq 1 $WAIT_ITERATIONS); do | |
| echo "Checking availability attempt $i/$WAIT_ITERATIONS..." | |
| # Check Maven Central directly | |
| if curl -s -f --max-time 30 "${{ env.MAVEN_CENTRAL_BASE }}/$GROUP_PATH/$MODULE/$VERSION/$MODULE-$VERSION.pom" >/dev/null 2>&1; then | |
| echo "✅ Core available on Maven Central" | |
| break | |
| fi | |
| # Try dependency resolution | |
| if timeout 60 mvn dependency:get -Dartifact="${{ env.GROUP_ID }}:$MODULE:$VERSION" -B >/dev/null 2>&1; then | |
| echo "✅ Core available via Maven dependency resolution" | |
| break | |
| fi | |
| if [[ $i -eq $WAIT_ITERATIONS ]]; then | |
| echo "❌ Core not available after waiting" | |
| exit 1 | |
| fi | |
| echo "Core not yet available, waiting 2 minutes..." | |
| sleep 120 | |
| done | |
| - name: Deploy Framework modules | |
| run: | | |
| set -e | |
| VERSION=${{ steps.version.outputs.version }} | |
| echo "🚀 Deploying Framework modules..." | |
| # Create temporary directory for logs | |
| mkdir -p /tmp/deploy_logs | |
| deploy_framework_module() { | |
| local module="$1" | |
| local log_file="/tmp/deploy_logs/${module}.log" | |
| { | |
| echo "Deploying $module..." | |
| cd "$module" || exit 1 | |
| # Verify version is set correctly | |
| CURRENT_VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout) | |
| if [[ "$CURRENT_VERSION" != "$VERSION" ]]; then | |
| echo "❌ Version mismatch in $module: expected $VERSION, got $CURRENT_VERSION" | |
| exit 1 | |
| fi | |
| # Simple verification that core dependency exists and will be updated | |
| echo "Verifying java-reporter-core dependency in $module..." | |
| if grep -q "java-reporter-core" pom.xml; then | |
| echo "✅ Core dependency found in $module" | |
| # Force update core dependency to ensure correct version | |
| mvn versions:use-dep-version \ | |
| -Dincludes="${{ env.GROUP_ID }}:java-reporter-core" \ | |
| -DdepVersion="$VERSION" \ | |
| -DforceVersion=true \ | |
| -DgenerateBackupPoms=false \ | |
| -B || echo "⚠️ Failed to update core dependency" | |
| else | |
| echo "ℹ️ No core dependency found in $module (normal for core module itself)" | |
| fi | |
| # Deploy module | |
| for i in $(seq 1 ${{ env.MAX_RETRY_ATTEMPTS }}); do | |
| echo "Deployment attempt $i for $module" | |
| if timeout ${{ env.MAVEN_TIMEOUT }} mvn clean deploy -P release -DskipTests -B; then | |
| echo "$module deployed successfully" | |
| cd .. || exit 1 | |
| exit 0 | |
| elif [[ $i -eq ${{ env.MAX_RETRY_ATTEMPTS }} ]]; then | |
| echo "$module deployment failed after ${{ env.MAX_RETRY_ATTEMPTS }} attempts" | |
| exit 1 | |
| else | |
| sleep ${{ env.RETRY_DELAY }} | |
| fi | |
| done | |
| } > "$log_file" 2>&1 | |
| } | |
| # Export function and variables for subshells | |
| export -f deploy_framework_module | |
| export VERSION | |
| export MAVEN_TIMEOUT=${{ env.MAVEN_TIMEOUT }} | |
| export MAX_RETRY_ATTEMPTS=${{ env.MAX_RETRY_ATTEMPTS }} | |
| export RETRY_DELAY=${{ env.RETRY_DELAY }} | |
| # Deploy modules in parallel | |
| deploy_framework_module "java-reporter-junit" & | |
| JUNIT_PID=$! | |
| deploy_framework_module "java-reporter-testng" & | |
| TESTNG_PID=$! | |
| deploy_framework_module "java-reporter-cucumber" & | |
| CUCUMBER_PID=$! | |
| deploy_framework_module "java-reporter-karate" & | |
| KARATE_PID=$! | |
| deploy_framework_module "testomat-allure-adapter" & | |
| TAADAPTER_PID=$! | |
| # Wait for all modules and collect results | |
| FAILED_MODULES=() | |
| if ! wait $JUNIT_PID; then | |
| FAILED_MODULES+=("junit") | |
| echo "❌ JUnit deployment failed" | |
| cat /tmp/deploy_logs/java-reporter-junit.log | |
| else | |
| echo "✅ JUnit deployed" | |
| fi | |
| if ! wait $TESTNG_PID; then | |
| FAILED_MODULES+=("testng") | |
| echo "❌ TestNG deployment failed" | |
| cat /tmp/deploy_logs/java-reporter-testng.log | |
| else | |
| echo "✅ TestNG deployed" | |
| fi | |
| if ! wait $CUCUMBER_PID; then | |
| FAILED_MODULES+=("cucumber") | |
| echo "❌ Cucumber deployment failed" | |
| cat /tmp/deploy_logs/java-reporter-cucumber.log | |
| else | |
| echo "✅ Cucumber deployed" | |
| fi | |
| if ! wait $KARATE_PID; then | |
| FAILED_MODULES+=("karate") | |
| cat /tmp/deploy_logs/java-reporter-karate.log | |
| else | |
| echo "✅ Karate deployed" | |
| fi | |
| if ! wait $TAADAPTER_PID; then | |
| FAILED_MODULES+=("taadapter") | |
| cat /tmp/deploy_logs/testomat-allure-adapter.log | |
| else | |
| echo "✅ Testomat Allure adapter deployed" | |
| fi | |
| # Cleanup logs | |
| rm -rf /tmp/deploy_logs | |
| if [[ ${#FAILED_MODULES[@]} -gt 0 ]]; then | |
| echo "❌ Failed modules: ${FAILED_MODULES[*]}" | |
| exit 1 | |
| fi | |
| echo "✅ All Framework modules deployed successfully" | |
| env: | |
| CENTRAL_USERNAME: ${{ secrets.CENTRAL_USERNAME }} | |
| CENTRAL_PASSWORD: ${{ secrets.CENTRAL_PASSWORD }} | |
| GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} | |
| - name: Wait for Framework availability | |
| run: | | |
| set -e | |
| VERSION=${{ steps.version.outputs.version }} | |
| GROUP_PATH=$(echo "${{ env.GROUP_ID }}" | tr '.' '/') | |
| modules=("java-reporter-junit" "java-reporter-testng" "java-reporter-cucumber" "java-reporter-karate" "testomat-allure-adapter") | |
| echo "⏳ Waiting for Framework modules availability..." | |
| WAIT_ITERATIONS=$((MAVEN_CENTRAL_WAIT_TIMEOUT / 120 / 3)) | |
| for module in "${modules[@]}"; do | |
| echo "Checking $module availability..." | |
| for i in $(seq 1 $WAIT_ITERATIONS); do | |
| # Check Maven Central | |
| if curl -s -f --max-time 30 "${{ env.MAVEN_CENTRAL_BASE }}/$GROUP_PATH/$module/$VERSION/$module-$VERSION.pom" >/dev/null 2>&1; then | |
| echo "✅ $module available" | |
| break | |
| fi | |
| # Try dependency resolution | |
| if timeout 60 mvn dependency:get -Dartifact="${{ env.GROUP_ID }}:$module:$VERSION" -B >/dev/null 2>&1; then | |
| echo "✅ $module available" | |
| break | |
| fi | |
| if [[ $i -eq $WAIT_ITERATIONS ]]; then | |
| echo "❌ $module not available after waiting" | |
| exit 1 | |
| fi | |
| sleep 120 | |
| done | |
| done | |
| echo "✅ All Framework modules available" | |
| - name: Verify deployment | |
| run: | | |
| set -e | |
| VERSION=${{ steps.version.outputs.version }} | |
| modules=("java-reporter-core" "java-reporter-junit" "java-reporter-testng" "java-reporter-cucumber" "java-reporter-karate" "testomat-allure-adapter") | |
| echo "🔍 Verifying deployment..." | |
| echo "Waiting 5 minutes for Maven Central propagation..." | |
| sleep 300 | |
| failed_modules=() | |
| for module in "${modules[@]}"; do | |
| echo "Verifying $module..." | |
| if timeout 120 mvn dependency:get -Dartifact="${{ env.GROUP_ID }}:$module:$VERSION" -B >/dev/null 2>&1; then | |
| echo "✅ $module verified" | |
| else | |
| echo "⚠️ $module verification failed" | |
| failed_modules+=("$module") | |
| fi | |
| done | |
| if [[ ${#failed_modules[@]} -gt 0 ]]; then | |
| echo "⚠️ Verification failed for: ${failed_modules[*]}" | |
| echo "This might be due to Maven Central propagation delays." | |
| else | |
| echo "✅ All modules verified successfully" | |
| fi | |
| - name: Cleanup GPG | |
| if: always() | |
| run: | | |
| if command -v gpg >/dev/null 2>&1; then | |
| KEY_IDS=$(gpg --list-secret-keys --keyid-format LONG 2>/dev/null | grep sec | awk '{print $2}' | cut -d'/' -f2 2>/dev/null || true) | |
| if [[ -n "$KEY_IDS" ]]; then | |
| for key_id in $KEY_IDS; do | |
| gpg --batch --yes --delete-secret-keys "$key_id" 2>/dev/null || true | |
| done | |
| echo "✅ GPG keys cleaned up" | |
| fi | |
| fi | |
| - name: Release notification | |
| if: always() | |
| run: | | |
| if [[ "${{ job.status }}" == "success" ]]; then | |
| echo "🎉 Release v${{ steps.version.outputs.version }} completed successfully!" | |
| echo "" | |
| echo "Deployed modules with correct dependency chain:" | |
| echo "• Core v${{ steps.version.outputs.version }}" | |
| echo "• Framework modules v${{ steps.version.outputs.version }} (depend on Core v${{ steps.version.outputs.version }})" | |
| else | |
| echo "❌ Release v${{ steps.version.outputs.version }} failed!" | |
| echo "Check the workflow logs for detailed error information." | |
| fi |