Skip to content

Commit 1560e84

Browse files
adinauergithub-actions[bot]
authored andcommitted
chore: Update Spring Boot version matrices
1 parent 10288b3 commit 1560e84

File tree

3 files changed

+239
-2
lines changed

3 files changed

+239
-2
lines changed
Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
11
{
2-
"versions": ["3.0.0", "3.2.10", "3.3.5", "3.4.5", "3.5.6"]
3-
}
2+
"versions": [
3+
"3.0.0",
4+
"3.2.10",
5+
"3.3.13",
6+
"3.4.7",
7+
"3.5.3"
8+
]
9+
}

update_versions.py

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
import json
2+
import re
3+
import requests
4+
from packaging import version
5+
import sys
6+
from pathlib import Path
7+
8+
def get_spring_boot_versions():
9+
"""Fetch all Spring Boot versions from Maven Central with retry logic"""
10+
# Use the versions API instead of the general search
11+
url = "https://search.maven.org/solrsearch/select"
12+
params = {
13+
"q": "g:org.springframework.boot AND a:spring-boot",
14+
"core": "gav",
15+
"rows": 500,
16+
"wt": "json"
17+
}
18+
19+
max_retries = 3
20+
timeout = 60 # Increased timeout
21+
22+
for attempt in range(max_retries):
23+
try:
24+
print(f"Fetching versions (attempt {attempt + 1}/{max_retries})...")
25+
response = requests.get(url, params=params, timeout=timeout)
26+
response.raise_for_status()
27+
data = response.json()
28+
29+
if 'response' not in data or 'docs' not in data['response']:
30+
raise Exception(f"Unexpected API response structure: {data}")
31+
32+
docs = data['response']['docs']
33+
print(f"Found {len(docs)} documents in response")
34+
35+
if docs and len(docs) > 0:
36+
print(f"Sample doc structure: {list(docs[0].keys())}")
37+
38+
versions = []
39+
for doc in docs:
40+
# Try different possible version field names
41+
version_field = None
42+
if 'v' in doc:
43+
version_field = doc['v']
44+
elif 'version' in doc:
45+
version_field = doc['version']
46+
elif 'latestVersion' in doc:
47+
# This might be a summary doc, skip it
48+
print(f"Skipping summary doc with latestVersion: {doc.get('latestVersion')}")
49+
continue
50+
else:
51+
print(f"Warning: No version field found in doc: {doc}")
52+
continue
53+
54+
# Only include release versions (no SNAPSHOT, RC, M versions for 2.x and 3.x)
55+
if not any(suffix in version_field for suffix in ['SNAPSHOT', 'RC', 'BUILD']):
56+
versions.append(version_field)
57+
58+
print(f"Successfully fetched {len(versions)} versions")
59+
return sorted(versions, key=version.parse)
60+
except requests.exceptions.Timeout as e:
61+
print(f"Attempt {attempt + 1} timed out: {e}")
62+
if attempt < max_retries - 1:
63+
print("Retrying...")
64+
continue
65+
except Exception as e:
66+
print(f"Attempt {attempt + 1} failed: {e}")
67+
if attempt < max_retries - 1:
68+
print("Retrying...")
69+
continue
70+
71+
print("All attempts failed")
72+
return []
73+
74+
def parse_current_versions(json_file):
75+
"""Parse current Spring Boot versions from JSON data file"""
76+
if not Path(json_file).exists():
77+
return []
78+
79+
try:
80+
with open(json_file, 'r') as f:
81+
data = json.load(f)
82+
return data.get('versions', [])
83+
except Exception as e:
84+
print(f"Error reading {json_file}: {e}")
85+
return []
86+
87+
def get_latest_patch(all_versions, minor_version):
88+
"""Get the latest patch version for a given minor version"""
89+
target_minor = '.'.join(minor_version.split('.')[:2])
90+
patches = [v for v in all_versions if v.startswith(target_minor + '.')]
91+
return max(patches, key=version.parse) if patches else minor_version
92+
93+
def update_version_matrix(current_versions, all_versions, major_version):
94+
"""Update version matrix based on available versions"""
95+
if not current_versions or not all_versions:
96+
return current_versions, False
97+
98+
# Filter versions for this major version
99+
major_versions = [v for v in all_versions if v.startswith(f"{major_version}.")]
100+
if not major_versions:
101+
return current_versions, False
102+
103+
updated_versions = []
104+
changes_made = False
105+
106+
# Always keep the minimum supported version (first version)
107+
min_version = current_versions[0]
108+
updated_versions.append(min_version)
109+
110+
# Update patch versions for existing minor versions
111+
for curr_version in current_versions[1:]: # Skip min version
112+
if any(suffix in curr_version for suffix in ['M', 'RC', 'SNAPSHOT']):
113+
# Keep milestone/RC versions as-is for pre-release majors
114+
updated_versions.append(curr_version)
115+
continue
116+
117+
latest_patch = get_latest_patch(major_versions, curr_version)
118+
if latest_patch != curr_version:
119+
print(f"Updating {curr_version} -> {latest_patch}")
120+
changes_made = True
121+
updated_versions.append(latest_patch)
122+
123+
# Check for new minor versions
124+
current_minors = set()
125+
for v in current_versions:
126+
if not any(suffix in v for suffix in ['M', 'RC', 'SNAPSHOT']):
127+
current_minors.add('.'.join(v.split('.')[:2]))
128+
129+
available_minors = set()
130+
for v in major_versions:
131+
if not any(suffix in v for suffix in ['M', 'RC', 'SNAPSHOT']):
132+
available_minors.add('.'.join(v.split('.')[:2]))
133+
134+
new_minors = available_minors - current_minors
135+
if new_minors:
136+
# Add latest patch of new minor versions
137+
for new_minor in sorted(new_minors, key=version.parse):
138+
latest_patch = get_latest_patch(major_versions, new_minor + '.0')
139+
updated_versions.append(latest_patch)
140+
print(f"Adding new minor version: {latest_patch}")
141+
changes_made = True
142+
143+
# Remove second oldest minor (but keep absolute minimum)
144+
if len(updated_versions) > 7: # If we have more than 7 versions
145+
# Sort by version, keep min version and remove second oldest
146+
sorted_versions = sorted(updated_versions, key=version.parse)
147+
min_version = sorted_versions[0]
148+
other_versions = sorted_versions[1:]
149+
150+
# Keep all but the oldest of the "other" versions
151+
if len(other_versions) > 6:
152+
updated_versions = [min_version] + other_versions[1:]
153+
print(f"Removed second oldest version: {other_versions[0]}")
154+
changes_made = True
155+
156+
# Sort final versions
157+
min_version = updated_versions[0]
158+
other_versions = sorted([v for v in updated_versions if v != min_version], key=version.parse)
159+
final_versions = [min_version] + other_versions
160+
161+
return final_versions, changes_made
162+
163+
def update_json_file(json_file, new_versions):
164+
"""Update the JSON data file with new versions"""
165+
try:
166+
# Write new versions to JSON file
167+
data = {"versions": new_versions}
168+
with open(json_file, 'w') as f:
169+
json.dump(data, f, indent=2)
170+
return True
171+
except Exception as e:
172+
print(f"Error writing to {json_file}: {e}")
173+
return False
174+
175+
def main():
176+
print("Fetching Spring Boot versions...")
177+
all_versions = get_spring_boot_versions()
178+
179+
if not all_versions:
180+
print("No versions found, exiting")
181+
sys.exit(1)
182+
183+
print(f"Found {len(all_versions)} versions")
184+
185+
data_files = [
186+
(".github/data/spring-boot-2-versions.json", "2"),
187+
(".github/data/spring-boot-3-versions.json", "3"),
188+
(".github/data/spring-boot-4-versions.json", "4")
189+
]
190+
191+
changes_made = False
192+
change_summary = []
193+
194+
for json_file, major_version in data_files:
195+
if not Path(json_file).exists():
196+
continue
197+
198+
print(f"\nProcessing {json_file} (Spring Boot {major_version}.x)")
199+
200+
current_versions = parse_current_versions(json_file)
201+
if not current_versions:
202+
continue
203+
204+
print(f"Current versions: {current_versions}")
205+
206+
new_versions, file_changed = update_version_matrix(current_versions, all_versions, major_version)
207+
208+
if file_changed:
209+
print(f"New versions: {new_versions}")
210+
if update_json_file(json_file, new_versions):
211+
changes_made = True
212+
change_summary.append(f"Spring Boot {major_version}.x: {' -> '.join([str(current_versions), str(new_versions)])}")
213+
else:
214+
print("No changes needed")
215+
216+
if changes_made:
217+
print(f"\nChanges made to workflows:")
218+
for change in change_summary:
219+
print(f" - {change}")
220+
221+
# Write summary for later use
222+
with open('version_changes.txt', 'w') as f:
223+
f.write('\n'.join(change_summary))
224+
else:
225+
print("\nNo version updates needed")
226+
227+
sys.exit(0 if changes_made else 1)
228+
229+
if __name__ == "__main__":
230+
main()

version_changes.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Spring Boot 3.x: ['3.0.0', '3.2.10', '3.3.5', '3.4.5', '3.5.6'] -> ['3.0.0', '3.2.10', '3.3.13', '3.4.7', '3.5.3']

0 commit comments

Comments
 (0)