-
-
Notifications
You must be signed in to change notification settings - Fork 475
Expand file tree
/
Copy pathupdate-spring-boot-versions.yml
More file actions
285 lines (228 loc) · 11.2 KB
/
Copy pathupdate-spring-boot-versions.yml
File metadata and controls
285 lines (228 loc) · 11.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
name: Update Spring Boot Versions
on:
schedule:
# Run every Monday at 9:00 AM UTC
- cron: '0 9 * * 1'
workflow_dispatch: # Allow manual triggering
pull_request: # remove this before merging
permissions:
contents: write
pull-requests: write
jobs:
update-spring-boot-versions:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v5
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.11'
- name: Install dependencies
run: |
pip install requests packaging
- name: Update Spring Boot versions
run: |
cat << 'EOF' > update_versions.py
import json
import re
import requests
from packaging import version
import sys
from pathlib import Path
def get_spring_boot_versions():
"""Fetch all Spring Boot versions from Maven Central"""
url = "https://search.maven.org/solrsearch/select"
params = {
"q": "g:org.springframework.boot AND a:spring-boot",
"rows": 200,
"wt": "json"
}
try:
response = requests.get(url, params=params, timeout=30)
response.raise_for_status()
data = response.json()
versions = []
for doc in data['response']['docs']:
v = doc['v']
# Only include release versions (no SNAPSHOT, RC, M versions for 2.x and 3.x)
if not any(suffix in v for suffix in ['SNAPSHOT', 'RC', 'BUILD']):
versions.append(v)
return sorted(versions, key=version.parse)
except Exception as e:
print(f"Error fetching versions: {e}")
return []
def parse_current_versions(workflow_file):
"""Parse current Spring Boot versions from workflow file"""
content = Path(workflow_file).read_text()
# Find the springboot-version matrix line
pattern = r'springboot-version:\s*\[\s*([^\]]+)\s*\]'
match = re.search(pattern, content)
if not match:
return []
# Extract versions from the match
versions_str = match.group(1)
versions = []
for v in versions_str.split(','):
v = v.strip().strip("'\"")
if v:
versions.append(v)
return versions
def get_latest_patch(all_versions, minor_version):
"""Get the latest patch version for a given minor version"""
target_minor = '.'.join(minor_version.split('.')[:2])
patches = [v for v in all_versions if v.startswith(target_minor + '.')]
return max(patches, key=version.parse) if patches else minor_version
def update_version_matrix(current_versions, all_versions, major_version):
"""Update version matrix based on available versions"""
if not current_versions or not all_versions:
return current_versions, False
# Filter versions for this major version
major_versions = [v for v in all_versions if v.startswith(f"{major_version}.")]
if not major_versions:
return current_versions, False
updated_versions = []
changes_made = False
# Always keep the minimum supported version (first version)
min_version = current_versions[0]
updated_versions.append(min_version)
# Update patch versions for existing minor versions
for curr_version in current_versions[1:]: # Skip min version
if any(suffix in curr_version for suffix in ['M', 'RC', 'SNAPSHOT']):
# Keep milestone/RC versions as-is for pre-release majors
updated_versions.append(curr_version)
continue
latest_patch = get_latest_patch(major_versions, curr_version)
if latest_patch != curr_version:
print(f"Updating {curr_version} -> {latest_patch}")
changes_made = True
updated_versions.append(latest_patch)
# Check for new minor versions
current_minors = set()
for v in current_versions:
if not any(suffix in v for suffix in ['M', 'RC', 'SNAPSHOT']):
current_minors.add('.'.join(v.split('.')[:2]))
available_minors = set()
for v in major_versions:
if not any(suffix in v for suffix in ['M', 'RC', 'SNAPSHOT']):
available_minors.add('.'.join(v.split('.')[:2]))
new_minors = available_minors - current_minors
if new_minors:
# Add latest patch of new minor versions
for new_minor in sorted(new_minors, key=version.parse):
latest_patch = get_latest_patch(major_versions, new_minor + '.0')
updated_versions.append(latest_patch)
print(f"Adding new minor version: {latest_patch}")
changes_made = True
# Remove second oldest minor (but keep absolute minimum)
if len(updated_versions) > 7: # If we have more than 7 versions
# Sort by version, keep min version and remove second oldest
sorted_versions = sorted(updated_versions, key=version.parse)
min_version = sorted_versions[0]
other_versions = sorted_versions[1:]
# Keep all but the oldest of the "other" versions
if len(other_versions) > 6:
updated_versions = [min_version] + other_versions[1:]
print(f"Removed second oldest version: {other_versions[0]}")
changes_made = True
# Sort final versions
min_version = updated_versions[0]
other_versions = sorted([v for v in updated_versions if v != min_version], key=version.parse)
final_versions = [min_version] + other_versions
return final_versions, changes_made
def update_workflow_file(workflow_file, new_versions):
"""Update the workflow file with new versions"""
content = Path(workflow_file).read_text()
# Format new versions for YAML
versions_str = ", ".join([f"'{v}'" for v in new_versions])
new_matrix_line = f" springboot-version: [ {versions_str} ]"
# Replace the matrix line
pattern = r'(\s*)springboot-version:\s*\[\s*[^\]]+\s*\]'
replacement = new_matrix_line
updated_content = re.sub(pattern, replacement, content)
if updated_content != content:
Path(workflow_file).write_text(updated_content)
return True
return False
def main():
print("Fetching Spring Boot versions...")
all_versions = get_spring_boot_versions()
if not all_versions:
print("No versions found, exiting")
sys.exit(1)
print(f"Found {len(all_versions)} versions")
workflows = [
(".github/workflows/spring-boot-2-matrix.yml", "2"),
(".github/workflows/spring-boot-3-matrix.yml", "3"),
(".github/workflows/spring-boot-4-matrix.yml", "4")
]
changes_made = False
change_summary = []
for workflow_file, major_version in workflows:
if not Path(workflow_file).exists():
continue
print(f"\nProcessing {workflow_file} (Spring Boot {major_version}.x)")
current_versions = parse_current_versions(workflow_file)
if not current_versions:
continue
print(f"Current versions: {current_versions}")
new_versions, file_changed = update_version_matrix(current_versions, all_versions, major_version)
if file_changed:
print(f"New versions: {new_versions}")
if update_workflow_file(workflow_file, new_versions):
changes_made = True
change_summary.append(f"Spring Boot {major_version}.x: {' -> '.join([str(current_versions), str(new_versions)])}")
else:
print("No changes needed")
if changes_made:
print(f"\nChanges made to workflows:")
for change in change_summary:
print(f" - {change}")
# Write summary for later use
with open('version_changes.txt', 'w') as f:
f.write('\n'.join(change_summary))
else:
print("\nNo version updates needed")
sys.exit(0 if changes_made else 1)
if __name__ == "__main__":
main()
EOF
python update_versions.py
- name: Check for changes
id: changes
run: |
if git diff --quiet; then
echo "has_changes=false" >> $GITHUB_OUTPUT
else
echo "has_changes=true" >> $GITHUB_OUTPUT
fi
- name: Create Pull Request
if: steps.changes.outputs.has_changes == 'true'
uses: peter-evans/create-pull-request@v7
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: "chore: Update Spring Boot version matrices"
title: "Automated Spring Boot Version Update"
body: |
## Automated Spring Boot Version Update
This PR updates the Spring Boot version matrices in our test workflows based on the latest available versions.
### Changes Made:
$(cat version_changes.txt 2>/dev/null || echo "See diff for changes")
### Update Strategy:
- **Patch updates**: Updated to latest patch version of existing minor versions
- **New minor versions**: Added new minor versions and removed second oldest (keeping minimum supported)
- **Minimum version preserved**: Always keeps the minimum supported version for compatibility testing
This ensures our CI tests stay current with Spring Boot releases while maintaining coverage of older versions that users may still be using.
branch: automated-spring-boot-version-update
delete-branch: true
draft: false
- name: Summary
run: |
if [ "${{ steps.changes.outputs.has_changes }}" = "true" ]; then
echo "✅ Spring Boot version updates found and PR created"
cat version_changes.txt 2>/dev/null || true
else
echo "ℹ️ No Spring Boot version updates needed"
fi