Skip to content

Added maven compatibility test #22

Added maven compatibility test

Added maven compatibility test #22

name: Maven Compatibility Test
# This workflow proactively tests build-info-extractor-maven3 compatibility with multiple Maven versions
# to catch breaking changes early (e.g., new required fields in DefaultMavenPluginManager).
#
# When a compatibility issue is detected:
# 1. Check error logs for NullPointerException, NoSuchMethodError, etc.
# 2. Compare Maven's DefaultMavenPluginManager with our components.xml
# 3. Add missing field declarations to components.xml
# 4. See CHECK-MAVEN-FIELDS.sh for a helper script to identify missing fields
on:
# Run on PRs for testing (remove after initial validation)
pull_request:
branches: [ master, main ]
# Run nightly to catch new Maven releases
schedule:
- cron: '0 2 * * *' # Every night at 2 AM UTC
# Allow manual trigger for testing
workflow_dispatch:
jobs:
check-latest-maven-versions:
name: Determine Maven versions to test
runs-on: ubuntu-latest
outputs:
maven-versions: ${{ steps.set-versions.outputs.maven-versions }}
steps:
- name: Get latest Maven versions from Maven Central
id: maven-versions
run: |
echo "Fetching latest Maven versions from Maven Central..."
# Fetch Maven metadata
curl -s https://repo.maven.apache.org/maven2/org/apache/maven/maven-core/maven-metadata.xml > maven-metadata.xml
# Extract all versions
VERSIONS=$(grep -oP '(?<=<version>)[^<]+' maven-metadata.xml | grep -E '^[0-9]+\.[0-9]+\.[0-9]+' | sort -V)
echo "Available Maven versions:"
echo "$VERSIONS"
# Get latest versions for each major.minor series
LATEST_3_8=$(echo "$VERSIONS" | grep '^3\.8\.' | tail -1)
LATEST_3_9=$(echo "$VERSIONS" | grep '^3\.9\.' | tail -1)
LATEST_4_0=$(echo "$VERSIONS" | grep '^4\.0\.' | tail -1)
echo ""
echo "Latest versions by series:"
echo " 3.8.x: $LATEST_3_8"
echo " 3.9.x: $LATEST_3_9"
echo " 4.0.x: ${LATEST_4_0:-not released yet}"
# Export for next step
echo "LATEST_3_8=$LATEST_3_8" >> $GITHUB_ENV
echo "LATEST_3_9=$LATEST_3_9" >> $GITHUB_ENV
echo "LATEST_4_0=$LATEST_4_0" >> $GITHUB_ENV
- name: Build version matrix
id: set-versions
run: |
# Build JSON array of versions to test
# Include: first 3.9, some mid versions, and all latest versions
VERSIONS='["3.9.0"' # First 3.9.x
# Add latest 3.8.x
if [ -n "$LATEST_3_8" ]; then
VERSIONS+=', "'$LATEST_3_8'"'
fi
# Add latest 3.9.x
if [ -n "$LATEST_3_9" ]; then
VERSIONS+=', "'$LATEST_3_9'"'
fi
# Add latest 4.0.x if it exists
if [ -n "$LATEST_4_0" ]; then
VERSIONS+=', "'$LATEST_4_0'"'
else
# Fallback to beta if no stable 4.0 yet
VERSIONS+=', "4.0.0-beta-4"'
fi
VERSIONS+=']'
echo "Maven versions to test: $VERSIONS"
echo "maven-versions=$VERSIONS" >> $GITHUB_OUTPUT
test-maven-compatibility:
name: Test with Maven ${{ matrix.maven-version }}
runs-on: ubuntu-latest
needs: check-latest-maven-versions
strategy:
fail-fast: false # Test all versions even if one fails
matrix:
# Dynamically fetched versions from previous job
maven-version: ${{ fromJSON(needs.check-latest-maven-versions.outputs.maven-versions) }}
java-version:
- '8'
- '11'
- '17'
- '21'
exclude:
# Maven 4 requires Java 17+
- maven-version: '4.0.0-beta-4'
java-version: '8'
- maven-version: '4.0.0-beta-4'
java-version: '11'
steps:
- name: Set up test JDK ${{ matrix.java-version }}
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: ${{ matrix.java-version }}
- name: Set up Maven ${{ matrix.maven-version }}
uses: stCarolas/setup-maven@v5
with:
maven-version: ${{ matrix.maven-version }}
- name: Verify Maven version
run: |
mvn --version
echo "M2_HOME=$M2_HOME"
- name: Set up JFrog CLI
uses: jfrog/setup-jfrog-cli@v4
env:
JF_URL: ${{ secrets.PLATFORM_URL }}
JF_USER: ${{ secrets.PLATFORM_USER }}
JF_ACCESS_TOKEN: ${{ secrets.PLATFORM_ADMIN_TOKEN }}
with:
version: latest
# JFrog CLI will automatically download the latest released build-info extractor
# This tests the version users actually use in production
- name: Create test Maven project
run: |
# Create project structure
mkdir -p ${{ github.workspace }}/test-project/src/main/java/com/test
cd ${{ github.workspace }}/test-project
cat > pom.xml << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.jfrog.test</groupId>
<artifactId>maven-compatibility-test</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<!-- Use Maven Central as fallback to ensure plugins can be downloaded -->
<repositories>
<repository>
<id>central</id>
<url>https://repo.maven.apache.org/maven2</url>
<releases><enabled>true</enabled></releases>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>central</id>
<url>https://repo.maven.apache.org/maven2</url>
<releases><enabled>true</enabled></releases>
</pluginRepository>
</pluginRepositories>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.14.0</version>
</dependency>
</dependencies>
</project>
EOF
cat > src/main/java/com/test/App.java << 'EOF'
package com.test;
import org.apache.commons.lang3.StringUtils;
public class App {
public static void main(String[] args) {
System.out.println("Maven version test: " +
StringUtils.capitalize("success"));
}
}
EOF
# Verify project was created
echo ""
echo "Test project structure:"
ls -la ${{ github.workspace }}/test-project/
echo ""
echo "✅ Test project created successfully"
- name: Configure JFrog CLI server
env:
JF_URL: ${{ secrets.PLATFORM_URL }}
JF_USER: ${{ secrets.PLATFORM_USER }}
JF_ACCESS_TOKEN: ${{ secrets.PLATFORM_ADMIN_TOKEN }}
run: |
# Create JFrog CLI server configuration
echo "Creating JFrog CLI server configuration..."
if [ -z "$JF_URL" ] || [ -z "$JF_ACCESS_TOKEN" ]; then
echo "⚠️ Missing Artifactory credentials in secrets"
echo "Creating dummy config for testing (will fail, but we can still test extractor loading)"
jf config add artifactory --url=http://localhost:8081/artifactory --access-token=dummy --interactive=false || true
else
echo "Using real Artifactory instance from secrets"
jf config add artifactory \
--url="$JF_URL" \
--access-token="$JF_ACCESS_TOKEN" \
--interactive=false
fi
# Verify configuration
echo ""
echo "JFrog CLI servers:"
jf config show
- name: Configure Maven with JFrog
working-directory: ${{ github.workspace }}/test-project
run: |
# Configure Maven to use JFrog Platform
jf mvn-config \
--server-id-resolve=artifactory \
--server-id-deploy=artifactory \
--repo-resolve-releases=maven-remote \
--repo-resolve-snapshots=maven-remote \
--repo-deploy-releases=maven-local \
--repo-deploy-snapshots=maven-local 2>&1 | tee config-output.log
if grep -q "maven build config successfully created" config-output.log; then
echo "✅ Maven configured with JFrog Platform"
else
echo "⚠️ Maven config had issues:"
cat config-output.log
fi
- name: Test Maven with build-info extractor
id: maven_test
continue-on-error: true
working-directory: ${{ github.workspace }}/test-project
run: |
echo "Testing Maven ${{ matrix.maven-version }} with build-info extractor"
echo ""
# Run jf mvn - this will:
# 1. Download the build-info extractor (if not cached)
# 2. Load it as a Maven extension
# 3. If Maven incompatibility exists, NullPointerException happens immediately
# 4. Otherwise, will build successfully with real Artifactory
jf mvn clean compile 2>&1 | tee maven-output.log || true
echo ""
echo "Build complete - checking for compatibility issues..."
- name: Check for compatibility errors
if: always()
working-directory: ${{ github.workspace }}/test-project
run: |
# Check if the test actually ran
if [ ! -f maven-output.log ]; then
echo "❌ ERROR: No output log found!"
echo "This usually means configuration or test setup failed."
echo "Check previous steps for errors."
exit 1
fi
echo "Analyzing Maven output..."
echo ""
# Check for success
if grep -q "BUILD SUCCESS" maven-output.log; then
echo "✅ Maven build completed successfully"
echo "Maven ${{ matrix.maven-version }} with Java ${{ matrix.java-version }} - COMPATIBLE"
exit 0
fi
# Build failed - check for Maven COMPATIBILITY issues (not build issues)
echo "⚠️ Maven build failed - analyzing for compatibility errors..."
echo ""
# Check for Maven version compatibility issues
if grep -q "NullPointerException.*is null" maven-output.log; then
echo "❌ COMPATIBILITY ERROR: NullPointerException detected!"
echo "Maven ${{ matrix.maven-version }} is INCOMPATIBLE with build-info extractor"
echo ""
echo "This indicates missing field declarations in components.xml"
echo ""
echo "Error details:"
grep -B3 -A5 "NullPointerException" maven-output.log | head -20
exit 1
elif grep -q "NoSuchMethodError\|NoClassDefFoundError\|IncompatibleClassChangeError" maven-output.log; then
echo "❌ COMPATIBILITY ERROR: Class/method compatibility issue detected!"
echo "Maven ${{ matrix.maven-version }} is INCOMPATIBLE with build-info extractor"
echo ""
echo "Error details:"
grep -B3 -A5 "NoSuchMethodError\|NoClassDefFoundError\|IncompatibleClassChangeError" maven-output.log | head -20
exit 1
else
# Build failed but not due to Maven compatibility - could be:
# - Compilation errors (test code issue)
# - Network issues (transient)
# - Missing dependencies (test setup issue)
echo "⚠️ Build failed, but NO Maven compatibility errors detected"
echo ""
# Check if extractor actually ran
if grep -q "Running Mvn\|Running mvn command\|Downloading JFrog's Dependency\|Initializing Artifactory Build-Info Recording" maven-output.log; then
echo "✅ Build-info extractor loaded and ran successfully"
echo "Maven ${{ matrix.maven-version }} with Java ${{ matrix.java-version }} - COMPATIBLE"
echo ""
echo "Note: Build failed for other reasons (not Maven compatibility)"
echo "Last 30 lines of output:"
tail -30 maven-output.log
exit 0
else
echo "❓ Extractor may not have loaded - manual review needed"
echo "Last 50 lines of output:"
tail -50 maven-output.log
exit 1
fi
fi
- name: Upload logs (on failure)
if: failure()
uses: actions/upload-artifact@v4
with:
name: failure-logs-maven-${{ matrix.maven-version }}-java-${{ matrix.java-version }}
path: |
${{ github.workspace }}/test-project/maven-output.log
${{ github.workspace }}/test-project/config-output.log
retention-days: 30
if-no-files-found: ignore
create-issue-on-failure:
name: Create issue if compatibility test fails
needs: [test-maven-compatibility]
# Only run on main branch or non-fork PRs (to avoid permission errors on fork PRs)
if: failure() && (github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository)
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Create issue
uses: actions/github-script@v7
continue-on-error: true
with:
script: |
const title = '🚨 Maven Compatibility Test Failed';
const body = `## Maven Compatibility Test Failure
The automated Maven compatibility test has detected a failure with one or more Maven versions.
**Details:**
- Run: ${{ github.run_number }}
- Workflow: ${{ github.workflow }}
- Triggered by: ${{ github.event_name }}
- Link: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
**Possible Causes:**
1. A new Maven version has been released with breaking changes
2. New required fields have been added to DefaultMavenPluginManager
3. Method signatures have changed in Maven core classes
4. New dependencies or requirements were introduced
5. Our Plexus components.xml is missing field declarations
**Action Required:**
1. Check the "Check for new Maven versions" job output to see if new versions were detected
2. Check the workflow logs for specific error messages
3. Download the failure logs artifact from the workflow run
4. Look for error patterns:
- \`NullPointerException\` → Missing field in components.xml
- \`NoSuchMethodError\` → Method signature changed
- \`NoClassDefFoundError\` → Missing dependency
5. If NullPointerException on a field:
- Identify the missing field name from the error
- Download Maven source for that version
- Use \`CHECK-MAVEN-FIELDS.sh <maven-version>\` to compare fields
- Update \`build-info-extractor-maven3/src/main/resources/META-INF/plexus/components.xml\`
- Add missing field requirements to the ArtifactoryEclipsePluginManager component
6. If a new Maven version was detected, update the workflow matrix to include it
**Helpful Commands:**
\`\`\`bash
# Check for missing fields in a specific Maven version
./CHECK-MAVEN-FIELDS.sh <maven-version>
# Compare Maven's DefaultMavenPluginManager with our components.xml
# Look for new fields that need to be added
\`\`\`
**Resources:**
- Maven release notes: https://maven.apache.org/docs/history.html
- Our components.xml: \`build-info-extractor-maven3/src/main/resources/META-INF/plexus/components.xml\`
- DefaultMavenPluginManager source: Search in Maven's GitHub repository
`;
// Check if issue already exists
const issues = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
labels: 'maven-compatibility'
});
if (issues.data.length === 0) {
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: title,
body: body,
labels: ['bug', 'maven-compatibility', 'automated']
});
} else {
console.log('Issue already exists, adding comment instead');
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issues.data[0].number,
body: `Another failure detected in run #${{ github.run_number }}\n\nLink: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}`
});
}