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
71 changes: 71 additions & 0 deletions .github/scripts/udpate-spring-versions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import json
import re
from collections import defaultdict
from packaging.version import Version
from xml.etree import ElementTree as ET
import urllib.request

# Configuration
managed_minors = {"3.0", "3.1", "3.2", "3.3", "3.4"}
boot_java_compatibility = {
"3.0": ["17"], # Java 21 not supported
"3.1": ["17", "21"],
"3.2": ["17", "21"],
"3.3": ["17", "21"],
"3.4": ["17", "21"]
}
output_path = ".github/spring-versions.json"

# Step 1: Fetch Spring Boot versions
metadata_url = "https://repo1.maven.org/maven2/org/springframework/boot/spring-boot-starter/maven-metadata.xml"
with urllib.request.urlopen(metadata_url) as response:
xml_data = response.read()

root = ET.fromstring(xml_data)
versions = [v.text for v in root.findall(".//version")]

boot_versions = defaultdict(list)
for v in versions:
if not re.match(r"^\d+\.\d+\.\d+$", v):
continue
minor = ".".join(v.split(".")[:2])
if minor in managed_minors:
boot_versions[minor].append(Version(v))

latest_boot_versions = {minor: str(max(vlist)) for minor, vlist in boot_versions.items()}

# Step 2: Resolve Spring Framework version
def get_spring_framework_version(boot_version: str) -> str:
pom_url = f"https://repo1.maven.org/maven2/org/springframework/boot/spring-boot-starter/{boot_version}/spring-boot-starter-{boot_version}.pom"
try:
with urllib.request.urlopen(pom_url) as response:
pom_data = response.read()
pom_root = ET.fromstring(pom_data)
ns = {'m': 'http://maven.apache.org/POM/4.0.0'}
for dep in pom_root.findall(".//m:dependency", ns):
gid = dep.find("m:groupId", ns)
aid = dep.find("m:artifactId", ns)
ver = dep.find("m:version", ns)
if gid is not None and aid is not None and ver is not None:
if gid.text == "org.springframework" and aid.text == "spring-core":
return ver.text
except Exception as e:
print(f"Warning: Failed to fetch framework version for {boot_version}: {e}")
return "unknown"

# Step 3: Build matrix
matrix_entries = []
for minor, boot_version in sorted(latest_boot_versions.items()):
framework_version = get_spring_framework_version(boot_version)
for java_version in boot_java_compatibility.get(minor, []):
matrix_entries.append({
"boot": boot_version,
"framework": framework_version,
"java": str(java_version)
})

# Step 4: Save result
with open(output_path, "w") as f:
json.dump({"matrix": matrix_entries}, f, indent=2)

print(f"Updated {output_path} with {len(matrix_entries)} matrix entries.")
49 changes: 49 additions & 0 deletions .github/spring-versions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"matrix": [
{
"boot": "3.0.13",
"framework": "6.0.14",
"java": "17"
},
{
"boot": "3.1.11",
"framework": "6.0.20",
"java": "17"
},
{
"boot": "3.1.12",
"framework": "6.0.21",
"java": "21"
},
{
"boot": "3.2.12",
"framework": "6.1.15",
"java": "17"
},
{
"boot": "3.2.12",
"framework": "6.1.15",
"java": "21"
},
{
"boot": "3.3.12",
"framework": "6.1.20",
"java": "17"
},
{
"boot": "3.3.12",
"framework": "6.1.20",
"java": "21"
},
{
"boot": "3.4.6",
"framework": "6.2.7",
"java": "17"
},
{
"boot": "3.4.6",
"framework": "6.2.7",
"java": "21"
}
]
}
56 changes: 51 additions & 5 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,56 @@ on:
workflow_dispatch:

jobs:
generate-matrix:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
name: Generate version matrix
steps:
- uses: actions/checkout@v4
- name: Read matrix from JSON
id: set-matrix
run: |
MATRIX=$(jq -c '.matrix' .github/spring-versions.json)
echo "matrix={\"include\":$MATRIX}" >> $GITHUB_OUTPUT

regression-tests:
needs: generate-matrix
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}
name: Test Spring Boot ${{ matrix.boot }} / Java ${{ matrix.java }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: ${{ matrix.java }}

- name: Run tests and generate reports
run: ./gradlew testAndReport -PspringBootVersion=${{ matrix.boot }} -PspringFrameworkVersion=${{ matrix.framework }}

- name: Upload Artifact
uses: actions/upload-artifact@v4
if: always()
with:
name: report-java-${{ matrix.java }}-spring-boot-${{ matrix.boot }}
path: build/reports/**
retention-days: 5

test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
java: [ '17', '21' ]
name: Test with Java ${{ matrix.Java }}
name: Test Spring Boot latest / Java ${{ matrix.java }}
steps:
- name: Checkout code
uses: actions/checkout@v4
Expand All @@ -32,12 +76,12 @@ jobs:
uses: actions/upload-artifact@v4
if: always()
with:
name: report-java-${{ matrix.Java }}
name: report-java-${{ matrix.java }}-spring-boot-latest
path: build/reports/**
retention-days: 5

- name: Run Sonar analysis
if: matrix.Java == '17'
if: matrix.java == '17'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
Expand All @@ -47,9 +91,11 @@ jobs:
runs-on: ubuntu-latest
needs: [test]
steps:
- uses: actions/checkout@v4
- name: Checkout code
uses: actions/checkout@v4

- uses: actions/setup-java@v4
- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17
Expand Down
38 changes: 38 additions & 0 deletions .github/workflows/update-spring-versions.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: Update Spring Versions Matrix

on:
schedule:
- cron: '0 3 1 * *' # Monthly on the 1st at 03:00 UTC
workflow_dispatch: # Allow manual trigger as well

jobs:
update-matrix:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'

- name: Install Python dependencies
run: pip install packaging

- name: Run update script
run: python .github/scripts/update-spring-versions.py

- name: Create Pull Request
uses: peter-evans/create-pull-request@v6
with:
commit-message: "chore: update Spring Boot/Framework testing matrix"
title: "Update Spring Versions Matrix"
body: |
This PR updates the `spring-versions.json` matrix with the latest patch versions of Spring Boot and their corresponding Spring Framework versions for Java 17 and 21.
branch: update/spring-versions-matrix
labels: |
dependencies
spring
author: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
13 changes: 10 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
buildscript {
ext {
springBootVersion = '3.5.0'
springVersion = '6.2.7'
springBootVersion = project.hasProperty('springBootVersion') ? project.springBootVersion : '3.5.0'
springVersion = project.hasProperty('springFrameworkVersion') ? project.springFrameworkVersion : '6.2.7'
jacksonVersion = '2.19.0'
retrofitVersion = '2.11.0'
mockitoVersion = '5.2.+' // At least Mockito 5.2.0 is required to Mock final classes
}
dependencies {
classpath 'org.owasp:dependency-check-gradle'
Expand Down Expand Up @@ -79,7 +80,7 @@ dependencies {
compileOnly group: 'com.squareup.okhttp3', name: 'logging-interceptor', version: '4.12.0'

// https://mvnrepository.com/artifact/de.siegmar/logback-gelf
compileOnly group: 'de.siegmar', name: 'logback-gelf', version: '6.1.1'
compileOnly group: 'de.siegmar', name: 'logback-gelf', version: '5.0.+'

// https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web
testImplementation group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: "${springBootVersion}"
Expand All @@ -99,6 +100,12 @@ dependencies {
// https://mvnrepository.com/artifact/ee.bitweb/spring-test-core
testImplementation group: 'ee.bitweb', name: 'spring-test-core', version: '2.+'

// https://mvnrepository.com/artifact/org.mockito/mockito-core
testImplementation group: 'org.mockito', name: 'mockito-core', version: "${mockitoVersion}"

// https://mvnrepository.com/artifact/org.mockito/mockito-junit-jupiter
testImplementation group: 'org.mockito', name: 'mockito-junit-jupiter', version: "${mockitoVersion}"

// https://mvnrepository.com/artifact/org.mock-server/mockserver-netty
testImplementation ("org.mock-server:mockserver-netty:5.15.0") {
exclude group: 'junit', module: 'junit'
Expand Down