1
1
/*
2
- * Copyright 2012-2022 the original author or authors.
2
+ * Copyright 2012-2023 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
16
16
17
17
package org .springframework .boot .build .bom .bomr ;
18
18
19
- import java .util .ArrayList ;
20
19
import java .util .Collection ;
21
- import java .util .Collections ;
22
20
import java .util .HashMap ;
23
- import java .util .HashSet ;
24
- import java .util .LinkedHashMap ;
25
21
import java .util .List ;
26
22
import java .util .Map ;
27
23
import java .util .Objects ;
28
- import java .util .Set ;
29
- import java .util .SortedSet ;
30
24
import java .util .stream .Collectors ;
31
25
32
- import org .apache .maven .artifact .versioning .DefaultArtifactVersion ;
33
- import org .gradle .api .InvalidUserDataException ;
34
26
import org .gradle .api .internal .tasks .userinput .UserInputHandler ;
35
27
36
28
import org .springframework .boot .build .bom .Library ;
37
- import org .springframework .boot .build .bom .Library .DependencyVersions ;
38
- import org .springframework .boot .build .bom .Library .Group ;
39
- import org .springframework .boot .build .bom .Library .Module ;
40
- import org .springframework .boot .build .bom .Library .ProhibitedVersion ;
41
- import org .springframework .boot .build .bom .Library .VersionAlignment ;
42
- import org .springframework .boot .build .bom .UpgradePolicy ;
43
- import org .springframework .boot .build .bom .bomr .version .DependencyVersion ;
44
- import org .springframework .util .StringUtils ;
45
29
46
30
/**
47
31
* Interactive {@link UpgradeResolver} that uses command line input to choose the upgrades
51
35
*/
52
36
public final class InteractiveUpgradeResolver implements UpgradeResolver {
53
37
54
- private final VersionResolver versionResolver ;
55
-
56
- private final UpgradePolicy upgradePolicy ;
57
-
58
38
private final UserInputHandler userInputHandler ;
59
39
60
- InteractiveUpgradeResolver (VersionResolver versionResolver , UpgradePolicy upgradePolicy ,
61
- UserInputHandler userInputHandler ) {
62
- this .versionResolver = versionResolver ;
63
- this .upgradePolicy = upgradePolicy ;
40
+ private final LibraryUpdateResolver libraryUpdateResolver ;
41
+
42
+ InteractiveUpgradeResolver (UserInputHandler userInputHandler , LibraryUpdateResolver libraryUpdateResolver ) {
64
43
this .userInputHandler = userInputHandler ;
44
+ this .libraryUpdateResolver = libraryUpdateResolver ;
65
45
}
66
46
67
47
@ Override
@@ -70,196 +50,22 @@ public List<Upgrade> resolveUpgrades(Collection<Library> librariesToUpgrade, Col
70
50
for (Library library : libraries ) {
71
51
librariesByName .put (library .getName (), library );
72
52
}
73
- return librariesToUpgrade . stream (). filter (( library ) -> ! library . getName (). equals ( "Spring Boot" ))
74
- .map (( library ) -> resolveUpgrade ( library , librariesByName )). filter ( Objects :: nonNull )
75
- .collect (Collectors .toList ());
53
+ List < LibraryWithVersionOptions > libraryUpdates = this . libraryUpdateResolver
54
+ .findLibraryUpdates ( librariesToUpgrade , librariesByName );
55
+ return libraryUpdates . stream (). map ( this :: resolveUpgrade ). filter ( Objects :: nonNull ) .collect (Collectors .toList ());
76
56
}
77
57
78
- private Upgrade resolveUpgrade (Library library , Map <String , Library > libraries ) {
79
- List <VersionOption > versionOptions = getVersionOptions (library , libraries );
80
- if (versionOptions .isEmpty ()) {
58
+ private Upgrade resolveUpgrade (LibraryWithVersionOptions libraryWithVersionOptions ) {
59
+ if (libraryWithVersionOptions .getVersionOptions ().isEmpty ()) {
81
60
return null ;
82
61
}
83
- VersionOption current = new VersionOption (library .getVersion ().getVersion ());
84
- VersionOption selected = this .userInputHandler
85
- .selectOption (library .getName () + " " + library .getVersion ().getVersion (), versionOptions , current );
86
- return (selected .equals (current )) ? null : new Upgrade (library , selected .version );
87
- }
88
-
89
- private List <VersionOption > getVersionOptions (Library library , Map <String , Library > libraries ) {
90
- if (library .getVersion ().getVersionAlignment () != null ) {
91
- return determineAlignedVersionOption (library , libraries );
92
- }
93
- return determineResolvedVersionOptions (library );
94
- }
95
-
96
- private List <VersionOption > determineResolvedVersionOptions (Library library ) {
97
- Map <String , SortedSet <DependencyVersion >> moduleVersions = new LinkedHashMap <>();
98
- DependencyVersion libraryVersion = library .getVersion ().getVersion ();
99
- for (Group group : library .getGroups ()) {
100
- for (Module module : group .getModules ()) {
101
- moduleVersions .put (group .getId () + ":" + module .getName (),
102
- getLaterVersionsForModule (group .getId (), module .getName (), libraryVersion ));
103
- }
104
- for (String bom : group .getBoms ()) {
105
- moduleVersions .put (group .getId () + ":" + bom ,
106
- getLaterVersionsForModule (group .getId (), bom , libraryVersion ));
107
- }
108
- for (String plugin : group .getPlugins ()) {
109
- moduleVersions .put (group .getId () + ":" + plugin ,
110
- getLaterVersionsForModule (group .getId (), plugin , libraryVersion ));
111
- }
112
- }
113
- List <DependencyVersion > allVersions = moduleVersions .values ().stream ().flatMap (SortedSet ::stream ).distinct ()
114
- .filter ((dependencyVersion ) -> isPermitted (dependencyVersion , library .getProhibitedVersions ()))
115
- .collect (Collectors .toList ());
116
- if (allVersions .isEmpty ()) {
117
- return Collections .emptyList ();
118
- }
119
- return allVersions .stream ()
120
- .map ((version ) -> new ResolvedVersionOption (version , getMissingModules (moduleVersions , version )))
121
- .collect (Collectors .toList ());
122
- }
123
-
124
- private List <VersionOption > determineAlignedVersionOption (Library library , Map <String , Library > libraries ) {
125
- VersionOption alignedVersionOption = alignedVersionOption (library , libraries );
126
- if (alignedVersionOption == null ) {
127
- return Collections .emptyList ();
128
- }
129
- if (!isPermitted (alignedVersionOption .version , library .getProhibitedVersions ())) {
130
- throw new InvalidUserDataException ("Version alignment failed. Version " + alignedVersionOption .version
131
- + " from " + library .getName () + " is prohibited" );
132
- }
133
- return Collections .singletonList (alignedVersionOption );
134
- }
135
-
136
- private VersionOption alignedVersionOption (Library library , Map <String , Library > libraries ) {
137
- VersionAlignment versionAlignment = library .getVersion ().getVersionAlignment ();
138
- Library alignmentLibrary = libraries .get (versionAlignment .getLibraryName ());
139
- DependencyVersions dependencyVersions = alignmentLibrary .getDependencyVersions ();
140
- if (dependencyVersions == null ) {
141
- throw new InvalidUserDataException ("Cannot align with library '" + versionAlignment .getLibraryName ()
142
- + "' as it does not define any dependency versions" );
143
- }
144
- if (!dependencyVersions .available ()) {
145
- return null ;
146
- }
147
- Set <String > versions = new HashSet <>();
148
- for (Group group : library .getGroups ()) {
149
- for (Module module : group .getModules ()) {
150
- String version = dependencyVersions .getVersion (group .getId (), module .getName ());
151
- if (version != null ) {
152
- versions .add (version );
153
- }
154
- }
155
- }
156
- if (versions .isEmpty ()) {
157
- throw new InvalidUserDataException ("Cannot align with library '" + versionAlignment .getLibraryName ()
158
- + "' as its dependency versions do not include any of this library's modules" );
159
- }
160
- if (versions .size () > 1 ) {
161
- throw new InvalidUserDataException ("Cannot align with library '" + versionAlignment .getLibraryName ()
162
- + "' as it uses multiple different versions of this library's modules" );
163
- }
164
- DependencyVersion version = DependencyVersion .parse (versions .iterator ().next ());
165
- return library .getVersion ().getVersion ().equals (version ) ? null
166
- : new AlignedVersionOption (version , alignmentLibrary );
167
- }
168
-
169
- private boolean isPermitted (DependencyVersion dependencyVersion , List <ProhibitedVersion > prohibitedVersions ) {
170
- for (ProhibitedVersion prohibitedVersion : prohibitedVersions ) {
171
- String dependencyVersionToString = dependencyVersion .toString ();
172
- if (prohibitedVersion .getRange () != null && prohibitedVersion .getRange ()
173
- .containsVersion (new DefaultArtifactVersion (dependencyVersionToString ))) {
174
- return false ;
175
- }
176
- for (String startsWith : prohibitedVersion .getStartsWith ()) {
177
- if (dependencyVersionToString .startsWith (startsWith )) {
178
- return false ;
179
- }
180
- }
181
- for (String endsWith : prohibitedVersion .getEndsWith ()) {
182
- if (dependencyVersionToString .endsWith (endsWith )) {
183
- return false ;
184
- }
185
- }
186
- for (String contains : prohibitedVersion .getContains ()) {
187
- if (dependencyVersionToString .contains (contains )) {
188
- return false ;
189
- }
190
- }
191
- }
192
- return true ;
193
- }
194
-
195
- private List <String > getMissingModules (Map <String , SortedSet <DependencyVersion >> moduleVersions ,
196
- DependencyVersion version ) {
197
- List <String > missingModules = new ArrayList <>();
198
- moduleVersions .forEach ((name , versions ) -> {
199
- if (!versions .contains (version )) {
200
- missingModules .add (name );
201
- }
202
- });
203
- return missingModules ;
204
- }
205
-
206
- private SortedSet <DependencyVersion > getLaterVersionsForModule (String groupId , String artifactId ,
207
- DependencyVersion currentVersion ) {
208
- SortedSet <DependencyVersion > versions = this .versionResolver .resolveVersions (groupId , artifactId );
209
- versions .removeIf ((candidate ) -> !this .upgradePolicy .test (candidate , currentVersion ));
210
- return versions ;
211
- }
212
-
213
- private static class VersionOption {
214
-
215
- private final DependencyVersion version ;
216
-
217
- protected VersionOption (DependencyVersion version ) {
218
- this .version = version ;
219
- }
220
-
221
- @ Override
222
- public String toString () {
223
- return this .version .toString ();
224
- }
225
-
226
- }
227
-
228
- private static final class AlignedVersionOption extends VersionOption {
229
-
230
- private final Library alignedWith ;
231
-
232
- private AlignedVersionOption (DependencyVersion version , Library alignedWith ) {
233
- super (version );
234
- this .alignedWith = alignedWith ;
235
- }
236
-
237
- @ Override
238
- public String toString () {
239
- return super .toString () + " (aligned with " + this .alignedWith .getName () + " "
240
- + this .alignedWith .getVersion ().getVersion () + ")" ;
241
- }
242
-
243
- }
244
-
245
- private static final class ResolvedVersionOption extends VersionOption {
246
-
247
- private final List <String > missingModules ;
248
-
249
- private ResolvedVersionOption (DependencyVersion version , List <String > missingModules ) {
250
- super (version );
251
- this .missingModules = missingModules ;
252
- }
253
-
254
- @ Override
255
- public String toString () {
256
- if (this .missingModules .isEmpty ()) {
257
- return super .toString ();
258
- }
259
- return super .toString () + " (some modules are missing: "
260
- + StringUtils .collectionToDelimitedString (this .missingModules , ", " ) + ")" ;
261
- }
262
-
62
+ VersionOption current = new VersionOption (libraryWithVersionOptions .getLibrary ().getVersion ().getVersion ());
63
+ VersionOption selected = this .userInputHandler .selectOption (
64
+ libraryWithVersionOptions .getLibrary ().getName () + " "
65
+ + libraryWithVersionOptions .getLibrary ().getVersion ().getVersion (),
66
+ libraryWithVersionOptions .getVersionOptions (), current );
67
+ return (selected .equals (current )) ? null
68
+ : new Upgrade (libraryWithVersionOptions .getLibrary (), selected .getVersion ());
263
69
}
264
70
265
71
}
0 commit comments