3636 import re
3737 import requests
3838 from packaging import version
39- import yaml
4039 import sys
4140 from pathlib import Path
4241
@@ -48,19 +47,19 @@ jobs:
4847 "rows": 200,
4948 "wt": "json"
5049 }
51-
50+
5251 try:
5352 response = requests.get(url, params=params, timeout=30)
5453 response.raise_for_status()
5554 data = response.json()
56-
55+
5756 versions = []
5857 for doc in data['response']['docs']:
5958 v = doc['v']
6059 # Only include release versions (no SNAPSHOT, RC, M versions for 2.x and 3.x)
6160 if not any(suffix in v for suffix in ['SNAPSHOT', 'RC', 'BUILD']):
6261 versions.append(v)
63-
62+
6463 return sorted(versions, key=version.parse)
6564 except Exception as e:
6665 print(f"Error fetching versions: {e}")
@@ -69,22 +68,22 @@ jobs:
6968 def parse_current_versions(workflow_file):
7069 """Parse current Spring Boot versions from workflow file"""
7170 content = Path(workflow_file).read_text()
72-
71+
7372 # Find the springboot-version matrix line
7473 pattern = r'springboot-version:\s*\[\s*([^\]]+)\s*\]'
7574 match = re.search(pattern, content)
76-
75+
7776 if not match:
7877 return []
79-
78+
8079 # Extract versions from the match
8180 versions_str = match.group(1)
8281 versions = []
8382 for v in versions_str.split(','):
8483 v = v.strip().strip("'\"")
8584 if v:
8685 versions.append(v)
87-
86+
8887 return versions
8988
9089 def get_latest_patch(all_versions, minor_version):
@@ -97,43 +96,43 @@ jobs:
9796 """Update version matrix based on available versions"""
9897 if not current_versions or not all_versions:
9998 return current_versions, False
100-
99+
101100 # Filter versions for this major version
102101 major_versions = [v for v in all_versions if v.startswith(f"{major_version}.")]
103102 if not major_versions:
104103 return current_versions, False
105-
104+
106105 updated_versions = []
107106 changes_made = False
108-
107+
109108 # Always keep the minimum supported version (first version)
110109 min_version = current_versions[0]
111110 updated_versions.append(min_version)
112-
111+
113112 # Update patch versions for existing minor versions
114113 for curr_version in current_versions[1:]: # Skip min version
115114 if any(suffix in curr_version for suffix in ['M', 'RC', 'SNAPSHOT']):
116115 # Keep milestone/RC versions as-is for pre-release majors
117116 updated_versions.append(curr_version)
118117 continue
119-
118+
120119 latest_patch = get_latest_patch(major_versions, curr_version)
121120 if latest_patch != curr_version:
122121 print(f"Updating {curr_version} -> {latest_patch}")
123122 changes_made = True
124123 updated_versions.append(latest_patch)
125-
124+
126125 # Check for new minor versions
127126 current_minors = set()
128127 for v in current_versions:
129128 if not any(suffix in v for suffix in ['M', 'RC', 'SNAPSHOT']):
130129 current_minors.add('.'.join(v.split('.')[:2]))
131-
130+
132131 available_minors = set()
133132 for v in major_versions:
134133 if not any(suffix in v for suffix in ['M', 'RC', 'SNAPSHOT']):
135134 available_minors.add('.'.join(v.split('.')[:2]))
136-
135+
137136 new_minors = available_minors - current_minors
138137 if new_minors:
139138 # Add latest patch of new minor versions
@@ -142,41 +141,41 @@ jobs:
142141 updated_versions.append(latest_patch)
143142 print(f"Adding new minor version: {latest_patch}")
144143 changes_made = True
145-
144+
146145 # Remove second oldest minor (but keep absolute minimum)
147146 if len(updated_versions) > 7: # If we have more than 7 versions
148147 # Sort by version, keep min version and remove second oldest
149148 sorted_versions = sorted(updated_versions, key=version.parse)
150149 min_version = sorted_versions[0]
151150 other_versions = sorted_versions[1:]
152-
151+
153152 # Keep all but the oldest of the "other" versions
154153 if len(other_versions) > 6:
155154 updated_versions = [min_version] + other_versions[1:]
156155 print(f"Removed second oldest version: {other_versions[0]}")
157156 changes_made = True
158-
157+
159158 # Sort final versions
160159 min_version = updated_versions[0]
161160 other_versions = sorted([v for v in updated_versions if v != min_version], key=version.parse)
162161 final_versions = [min_version] + other_versions
163-
162+
164163 return final_versions, changes_made
165164
166165 def update_workflow_file(workflow_file, new_versions):
167166 """Update the workflow file with new versions"""
168167 content = Path(workflow_file).read_text()
169-
168+
170169 # Format new versions for YAML
171170 versions_str = ", ".join([f"'{v}'" for v in new_versions])
172171 new_matrix_line = f" springboot-version: [ {versions_str} ]"
173-
172+
174173 # Replace the matrix line
175174 pattern = r'(\s*)springboot-version:\s*\[\s*[^\]]+\s*\]'
176175 replacement = new_matrix_line
177-
176+
178177 updated_content = re.sub(pattern, replacement, content)
179-
178+
180179 if updated_content != content:
181180 Path(workflow_file).write_text(updated_content)
182181 return True
@@ -185,55 +184,55 @@ jobs:
185184 def main():
186185 print("Fetching Spring Boot versions...")
187186 all_versions = get_spring_boot_versions()
188-
187+
189188 if not all_versions:
190189 print("No versions found, exiting")
191190 sys.exit(1)
192-
191+
193192 print(f"Found {len(all_versions)} versions")
194-
193+
195194 workflows = [
196195 (".github/workflows/spring-boot-2-matrix.yml", "2"),
197196 (".github/workflows/spring-boot-3-matrix.yml", "3"),
198197 (".github/workflows/spring-boot-4-matrix.yml", "4")
199198 ]
200-
199+
201200 changes_made = False
202201 change_summary = []
203-
202+
204203 for workflow_file, major_version in workflows:
205204 if not Path(workflow_file).exists():
206205 continue
207-
206+
208207 print(f"\nProcessing {workflow_file} (Spring Boot {major_version}.x)")
209-
208+
210209 current_versions = parse_current_versions(workflow_file)
211210 if not current_versions:
212211 continue
213-
212+
214213 print(f"Current versions: {current_versions}")
215-
214+
216215 new_versions, file_changed = update_version_matrix(current_versions, all_versions, major_version)
217-
216+
218217 if file_changed:
219218 print(f"New versions: {new_versions}")
220219 if update_workflow_file(workflow_file, new_versions):
221220 changes_made = True
222221 change_summary.append(f"Spring Boot {major_version}.x: {' -> '.join([str(current_versions), str(new_versions)])}")
223222 else:
224223 print("No changes needed")
225-
224+
226225 if changes_made:
227226 print(f"\nChanges made to workflows:")
228227 for change in change_summary:
229228 print(f" - {change}")
230-
229+
231230 # Write summary for later use
232231 with open('version_changes.txt', 'w') as f:
233232 f.write('\n'.join(change_summary))
234233 else:
235234 print("\nNo version updates needed")
236-
235+
237236 sys.exit(0 if changes_made else 1)
238237
239238 if __name__ == "__main__":
@@ -260,17 +259,17 @@ jobs:
260259 title : " Automated Spring Boot Version Update"
261260 body : |
262261 ## Automated Spring Boot Version Update
263-
262+
264263 This PR updates the Spring Boot version matrices in our test workflows based on the latest available versions.
265-
264+
266265 ### Changes Made:
267266 $(cat version_changes.txt 2>/dev/null || echo "See diff for changes")
268-
267+
269268 ### Update Strategy:
270269 - **Patch updates**: Updated to latest patch version of existing minor versions
271270 - **New minor versions**: Added new minor versions and removed second oldest (keeping minimum supported)
272271 - **Minimum version preserved**: Always keeps the minimum supported version for compatibility testing
273-
272+
274273 This ensures our CI tests stay current with Spring Boot releases while maintaining coverage of older versions that users may still be using.
275274 branch : automated-spring-boot-version-update
276275 delete-branch : true
0 commit comments