Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in / Register
Toggle navigation
S
spring-boot
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
DEMO
spring-boot
Commits
363de4cf
Commit
363de4cf
authored
Jun 23, 2021
by
Andy Wilkinson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add dependency lock and constraint version alignment to Bomr
Closes gh-27044
parent
d0f12392
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
421 additions
and
42 deletions
+421
-42
build.gradle
buildSrc/build.gradle
+1
-0
BomExtension.java
...java/org/springframework/boot/build/bom/BomExtension.java
+73
-6
CheckBom.java
...ain/java/org/springframework/boot/build/bom/CheckBom.java
+1
-1
Library.java
...main/java/org/springframework/boot/build/bom/Library.java
+166
-4
InteractiveUpgradeResolver.java
...ework/boot/build/bom/bomr/InteractiveUpgradeResolver.java
+106
-18
UpgradeApplicator.java
...pringframework/boot/build/bom/bomr/UpgradeApplicator.java
+15
-9
BomPluginIntegrationTests.java
...ngframework/boot/build/bom/BomPluginIntegrationTests.java
+28
-0
UpgradeApplicatorTests.java
...framework/boot/build/bom/bomr/UpgradeApplicatorTests.java
+21
-4
bom.gradle
buildSrc/src/test/resources/bom.gradle
+10
-0
No files found.
buildSrc/build.gradle
View file @
363de4cf
...
@@ -29,6 +29,7 @@ dependencies {
...
@@ -29,6 +29,7 @@ dependencies {
testImplementation
(
"org.assertj:assertj-core:3.11.1"
)
testImplementation
(
"org.assertj:assertj-core:3.11.1"
)
testImplementation
(
"org.apache.logging.log4j:log4j-core:2.12.1"
)
testImplementation
(
"org.apache.logging.log4j:log4j-core:2.12.1"
)
testImplementation
(
"org.junit.jupiter:junit-jupiter:5.6.0"
)
testImplementation
(
"org.junit.jupiter:junit-jupiter:5.6.0"
)
testRuntimeOnly
(
"org.junit.platform:junit-platform-launcher:1.6.3"
)
}
}
checkstyle
{
checkstyle
{
...
...
buildSrc/src/main/java/org/springframework/boot/build/bom/BomExtension.java
View file @
363de4cf
...
@@ -56,10 +56,15 @@ import org.w3c.dom.Document;
...
@@ -56,10 +56,15 @@ import org.w3c.dom.Document;
import
org.w3c.dom.NodeList
;
import
org.w3c.dom.NodeList
;
import
org.springframework.boot.build.DeployedPlugin
;
import
org.springframework.boot.build.DeployedPlugin
;
import
org.springframework.boot.build.bom.Library.DependencyConstraintsDependencyVersions
;
import
org.springframework.boot.build.bom.Library.DependencyLockDependencyVersions
;
import
org.springframework.boot.build.bom.Library.DependencyVersions
;
import
org.springframework.boot.build.bom.Library.Exclusion
;
import
org.springframework.boot.build.bom.Library.Exclusion
;
import
org.springframework.boot.build.bom.Library.Group
;
import
org.springframework.boot.build.bom.Library.Group
;
import
org.springframework.boot.build.bom.Library.LibraryVersion
;
import
org.springframework.boot.build.bom.Library.Module
;
import
org.springframework.boot.build.bom.Library.Module
;
import
org.springframework.boot.build.bom.Library.ProhibitedVersion
;
import
org.springframework.boot.build.bom.Library.ProhibitedVersion
;
import
org.springframework.boot.build.bom.Library.VersionAlignment
;
import
org.springframework.boot.build.bom.bomr.version.DependencyVersion
;
import
org.springframework.boot.build.bom.bomr.version.DependencyVersion
;
import
org.springframework.boot.build.mavenplugin.MavenExec
;
import
org.springframework.boot.build.mavenplugin.MavenExec
;
import
org.springframework.util.FileCopyUtils
;
import
org.springframework.util.FileCopyUtils
;
...
@@ -101,11 +106,17 @@ public class BomExtension {
...
@@ -101,11 +106,17 @@ public class BomExtension {
this
.
upgradeHandler
.
gitHub
.
repository
,
this
.
upgradeHandler
.
gitHub
.
issueLabels
));
this
.
upgradeHandler
.
gitHub
.
repository
,
this
.
upgradeHandler
.
gitHub
.
issueLabels
));
}
}
public
void
library
(
String
name
,
Closure
<?>
closure
)
{
this
.
library
(
name
,
null
,
closure
);
}
public
void
library
(
String
name
,
String
version
,
Closure
<?>
closure
)
{
public
void
library
(
String
name
,
String
version
,
Closure
<?>
closure
)
{
LibraryHandler
libraryHandler
=
new
LibraryHandler
();
LibraryHandler
libraryHandler
=
new
LibraryHandler
(
version
);
ConfigureUtil
.
configure
(
closure
,
libraryHandler
);
ConfigureUtil
.
configure
(
closure
,
libraryHandler
);
addLibrary
(
new
Library
(
name
,
DependencyVersion
.
parse
(
version
),
libraryHandler
.
groups
,
LibraryVersion
libraryVersion
=
new
LibraryVersion
(
DependencyVersion
.
parse
(
libraryHandler
.
version
),
libraryHandler
.
prohibitedVersions
));
libraryHandler
.
versionAlignment
);
addLibrary
(
new
Library
(
name
,
libraryVersion
,
libraryHandler
.
groups
,
libraryHandler
.
prohibitedVersions
,
libraryHandler
.
dependencyVersions
));
}
}
public
void
effectiveBomArtifact
()
{
public
void
effectiveBomArtifact
()
{
...
@@ -171,17 +182,18 @@ public class BomExtension {
...
@@ -171,17 +182,18 @@ public class BomExtension {
this
.
libraries
.
add
(
library
);
this
.
libraries
.
add
(
library
);
String
versionProperty
=
library
.
getVersionProperty
();
String
versionProperty
=
library
.
getVersionProperty
();
if
(
versionProperty
!=
null
)
{
if
(
versionProperty
!=
null
)
{
this
.
properties
.
put
(
versionProperty
,
library
.
getVersion
());
this
.
properties
.
put
(
versionProperty
,
library
.
getVersion
()
.
getVersion
()
);
}
}
for
(
Group
group
:
library
.
getGroups
())
{
for
(
Group
group
:
library
.
getGroups
())
{
for
(
Module
module
:
group
.
getModules
())
{
for
(
Module
module
:
group
.
getModules
())
{
putArtifactVersionProperty
(
group
.
getId
(),
module
.
getName
(),
versionProperty
);
putArtifactVersionProperty
(
group
.
getId
(),
module
.
getName
(),
versionProperty
);
this
.
dependencyHandler
.
getConstraints
().
add
(
JavaPlatformPlugin
.
API_CONFIGURATION_NAME
,
this
.
dependencyHandler
.
getConstraints
().
add
(
JavaPlatformPlugin
.
API_CONFIGURATION_NAME
,
createDependencyNotation
(
group
.
getId
(),
module
.
getName
(),
library
.
getVersion
()));
createDependencyNotation
(
group
.
getId
(),
module
.
getName
(),
library
.
getVersion
()
.
getVersion
()
));
}
}
for
(
String
bomImport
:
group
.
getBoms
())
{
for
(
String
bomImport
:
group
.
getBoms
())
{
putArtifactVersionProperty
(
group
.
getId
(),
bomImport
,
versionProperty
);
putArtifactVersionProperty
(
group
.
getId
(),
bomImport
,
versionProperty
);
String
bomDependency
=
createDependencyNotation
(
group
.
getId
(),
bomImport
,
library
.
getVersion
());
String
bomDependency
=
createDependencyNotation
(
group
.
getId
(),
bomImport
,
library
.
getVersion
().
getVersion
());
this
.
dependencyHandler
.
add
(
JavaPlatformPlugin
.
API_CONFIGURATION_NAME
,
this
.
dependencyHandler
.
add
(
JavaPlatformPlugin
.
API_CONFIGURATION_NAME
,
this
.
dependencyHandler
.
platform
(
bomDependency
));
this
.
dependencyHandler
.
platform
(
bomDependency
));
this
.
dependencyHandler
.
add
(
BomPlugin
.
API_ENFORCED_CONFIGURATION_NAME
,
this
.
dependencyHandler
.
add
(
BomPlugin
.
API_ENFORCED_CONFIGURATION_NAME
,
...
@@ -196,6 +208,23 @@ public class BomExtension {
...
@@ -196,6 +208,23 @@ public class BomExtension {
private
final
List
<
ProhibitedVersion
>
prohibitedVersions
=
new
ArrayList
<>();
private
final
List
<
ProhibitedVersion
>
prohibitedVersions
=
new
ArrayList
<>();
private
String
version
;
private
VersionAlignment
versionAlignment
;
private
DependencyVersions
dependencyVersions
;
public
LibraryHandler
(
String
version
)
{
this
.
version
=
version
;
}
public
void
version
(
String
version
,
Closure
<?>
closure
)
{
this
.
version
=
version
;
VersionHandler
versionHandler
=
new
VersionHandler
();
ConfigureUtil
.
configure
(
closure
,
versionHandler
);
this
.
versionAlignment
=
new
VersionAlignment
(
versionHandler
.
libraryName
);
}
public
void
group
(
String
id
,
Closure
<?>
closure
)
{
public
void
group
(
String
id
,
Closure
<?>
closure
)
{
GroupHandler
groupHandler
=
new
GroupHandler
(
id
);
GroupHandler
groupHandler
=
new
GroupHandler
(
id
);
ConfigureUtil
.
configure
(
closure
,
groupHandler
);
ConfigureUtil
.
configure
(
closure
,
groupHandler
);
...
@@ -215,6 +244,21 @@ public class BomExtension {
...
@@ -215,6 +244,21 @@ public class BomExtension {
}
}
}
}
public
void
dependencyVersions
(
Closure
<?>
closure
)
{
DependencyVersionsHandler
dependencyVersionsHandler
=
new
DependencyVersionsHandler
();
ConfigureUtil
.
configure
(
closure
,
dependencyVersionsHandler
);
}
public
static
class
VersionHandler
{
private
String
libraryName
;
public
void
shouldAlignWithVersionFrom
(
String
libraryName
)
{
this
.
libraryName
=
libraryName
;
}
}
public
static
class
ProhibitedVersionHandler
{
public
static
class
ProhibitedVersionHandler
{
private
String
reason
;
private
String
reason
;
...
@@ -277,6 +321,29 @@ public class BomExtension {
...
@@ -277,6 +321,29 @@ public class BomExtension {
}
}
public
class
DependencyVersionsHandler
{
public
void
extractFrom
(
Closure
<?>
closure
)
{
ExtractFromHandler
extractFromHandler
=
new
ExtractFromHandler
();
ConfigureUtil
.
configure
(
closure
,
extractFromHandler
);
}
public
class
ExtractFromHandler
{
public
void
dependencyLock
(
String
location
)
{
LibraryHandler
.
this
.
dependencyVersions
=
new
DependencyLockDependencyVersions
(
location
,
LibraryHandler
.
this
.
version
);
}
public
void
dependencyConstraints
(
String
location
)
{
LibraryHandler
.
this
.
dependencyVersions
=
new
DependencyConstraintsDependencyVersions
(
location
,
LibraryHandler
.
this
.
version
);
}
}
}
}
}
public
static
class
UpgradeHandler
{
public
static
class
UpgradeHandler
{
...
...
buildSrc/src/main/java/org/springframework/boot/build/bom/CheckBom.java
View file @
363de4cf
...
@@ -50,7 +50,7 @@ public class CheckBom extends DefaultTask {
...
@@ -50,7 +50,7 @@ public class CheckBom extends DefaultTask {
for
(
Group
group
:
library
.
getGroups
())
{
for
(
Group
group
:
library
.
getGroups
())
{
for
(
Module
module
:
group
.
getModules
())
{
for
(
Module
module
:
group
.
getModules
())
{
if
(!
module
.
getExclusions
().
isEmpty
())
{
if
(!
module
.
getExclusions
().
isEmpty
())
{
checkExclusions
(
group
.
getId
(),
module
,
library
.
getVersion
());
checkExclusions
(
group
.
getId
(),
module
,
library
.
getVersion
()
.
getVersion
()
);
}
}
}
}
}
}
...
...
buildSrc/src/main/java/org/springframework/boot/build/bom/Library.java
View file @
363de4cf
...
@@ -16,11 +16,20 @@
...
@@ -16,11 +16,20 @@
package
org
.
springframework
.
boot
.
build
.
bom
;
package
org
.
springframework
.
boot
.
build
.
bom
;
import
java.io.BufferedReader
;
import
java.io.IOException
;
import
java.io.InputStreamReader
;
import
java.net.URI
;
import
java.util.Collections
;
import
java.util.Collections
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.List
;
import
java.util.Locale
;
import
java.util.Locale
;
import
java.util.Map
;
import
java.util.regex.Matcher
;
import
java.util.regex.Pattern
;
import
org.apache.maven.artifact.versioning.VersionRange
;
import
org.apache.maven.artifact.versioning.VersionRange
;
import
org.gradle.api.GradleException
;
import
org.springframework.boot.build.bom.bomr.version.DependencyVersion
;
import
org.springframework.boot.build.bom.bomr.version.DependencyVersion
;
...
@@ -34,7 +43,7 @@ public class Library {
...
@@ -34,7 +43,7 @@ public class Library {
private
final
String
name
;
private
final
String
name
;
private
final
Dependenc
yVersion
version
;
private
final
Librar
yVersion
version
;
private
final
List
<
Group
>
groups
;
private
final
List
<
Group
>
groups
;
...
@@ -42,6 +51,8 @@ public class Library {
...
@@ -42,6 +51,8 @@ public class Library {
private
final
List
<
ProhibitedVersion
>
prohibitedVersions
;
private
final
List
<
ProhibitedVersion
>
prohibitedVersions
;
private
final
DependencyVersions
dependencyVersions
;
/**
/**
* Create a new {@code Library} with the given {@code name}, {@code version}, and
* Create a new {@code Library} with the given {@code name}, {@code version}, and
* {@code groups}.
* {@code groups}.
...
@@ -49,22 +60,24 @@ public class Library {
...
@@ -49,22 +60,24 @@ public class Library {
* @param version version of the library
* @param version version of the library
* @param groups groups in the library
* @param groups groups in the library
* @param prohibitedVersions version of the library that are prohibited
* @param prohibitedVersions version of the library that are prohibited
* @param dependencyVersions the library's dependency versions
*/
*/
public
Library
(
String
name
,
DependencyVersion
version
,
List
<
Group
>
group
s
,
public
Library
(
String
name
,
LibraryVersion
version
,
List
<
Group
>
groups
,
List
<
ProhibitedVersion
>
prohibitedVersion
s
,
List
<
ProhibitedVersion
>
prohibited
Versions
)
{
DependencyVersions
dependency
Versions
)
{
this
.
name
=
name
;
this
.
name
=
name
;
this
.
version
=
version
;
this
.
version
=
version
;
this
.
groups
=
groups
;
this
.
groups
=
groups
;
this
.
versionProperty
=
"Spring Boot"
.
equals
(
name
)
?
null
this
.
versionProperty
=
"Spring Boot"
.
equals
(
name
)
?
null
:
name
.
toLowerCase
(
Locale
.
ENGLISH
).
replace
(
' '
,
'-'
)
+
".version"
;
:
name
.
toLowerCase
(
Locale
.
ENGLISH
).
replace
(
' '
,
'-'
)
+
".version"
;
this
.
prohibitedVersions
=
prohibitedVersions
;
this
.
prohibitedVersions
=
prohibitedVersions
;
this
.
dependencyVersions
=
dependencyVersions
;
}
}
public
String
getName
()
{
public
String
getName
()
{
return
this
.
name
;
return
this
.
name
;
}
}
public
Dependenc
yVersion
getVersion
()
{
public
Librar
yVersion
getVersion
()
{
return
this
.
version
;
return
this
.
version
;
}
}
...
@@ -80,6 +93,10 @@ public class Library {
...
@@ -80,6 +93,10 @@ public class Library {
return
this
.
prohibitedVersions
;
return
this
.
prohibitedVersions
;
}
}
public
DependencyVersions
getDependencyVersions
()
{
return
this
.
dependencyVersions
;
}
/**
/**
* A version or range of versions that are prohibited from being used in a bom.
* A version or range of versions that are prohibited from being used in a bom.
*/
*/
...
@@ -104,6 +121,27 @@ public class Library {
...
@@ -104,6 +121,27 @@ public class Library {
}
}
public
static
class
LibraryVersion
{
private
final
DependencyVersion
version
;
private
final
VersionAlignment
versionAlignment
;
public
LibraryVersion
(
DependencyVersion
version
,
VersionAlignment
versionAlignment
)
{
this
.
version
=
version
;
this
.
versionAlignment
=
versionAlignment
;
}
public
DependencyVersion
getVersion
()
{
return
this
.
version
;
}
public
VersionAlignment
getVersionAlignment
()
{
return
this
.
versionAlignment
;
}
}
/**
/**
* A collection of modules, Maven plugins, and Maven boms with the same group ID.
* A collection of modules, Maven plugins, and Maven boms with the same group ID.
*/
*/
...
@@ -194,4 +232,128 @@ public class Library {
...
@@ -194,4 +232,128 @@ public class Library {
}
}
public
interface
DependencyVersions
{
String
getVersion
(
String
groupId
,
String
artifactId
);
default
boolean
available
()
{
return
true
;
}
}
public
static
class
DependencyLockDependencyVersions
implements
DependencyVersions
{
private
final
Map
<
String
,
Map
<
String
,
String
>>
dependencyVersions
=
new
HashMap
<>();
private
final
String
sourceTemplate
;
private
final
String
libraryVersion
;
public
DependencyLockDependencyVersions
(
String
sourceTemplate
,
String
libraryVersion
)
{
this
.
sourceTemplate
=
sourceTemplate
;
this
.
libraryVersion
=
libraryVersion
;
}
@Override
public
boolean
available
()
{
return
!
this
.
libraryVersion
.
contains
(
"-SNAPSHOT"
);
}
@Override
public
String
getVersion
(
String
groupId
,
String
artifactId
)
{
if
(
this
.
dependencyVersions
.
isEmpty
())
{
loadVersions
();
}
return
this
.
dependencyVersions
.
computeIfAbsent
(
groupId
,
(
key
)
->
Collections
.
emptyMap
()).
get
(
artifactId
);
}
private
void
loadVersions
()
{
String
source
=
this
.
sourceTemplate
.
replace
(
"<libraryVersion>"
,
this
.
libraryVersion
);
try
{
try
(
BufferedReader
reader
=
new
BufferedReader
(
new
InputStreamReader
(
URI
.
create
(
source
).
toURL
().
openStream
())))
{
String
line
;
while
((
line
=
reader
.
readLine
())
!=
null
)
{
if
(!
line
.
startsWith
(
"#"
))
{
String
[]
components
=
line
.
split
(
":"
);
Map
<
String
,
String
>
groupDependencies
=
this
.
dependencyVersions
.
computeIfAbsent
(
components
[
0
],
(
key
)
->
new
HashMap
<>());
groupDependencies
.
put
(
components
[
1
],
components
[
2
]);
}
}
}
}
catch
(
IOException
ex
)
{
throw
new
GradleException
(
"Failed to load versions from dependency lock file '"
+
source
+
"'"
,
ex
);
}
}
}
public
static
class
DependencyConstraintsDependencyVersions
implements
DependencyVersions
{
private
static
final
Pattern
CONSTRAINT_PATTERN
=
Pattern
.
compile
(
"api \"(.+):(.+):(.+)\""
);
private
final
Map
<
String
,
Map
<
String
,
String
>>
dependencyVersions
=
new
HashMap
<>();
private
final
String
sourceTemplate
;
private
final
String
libraryVersion
;
public
DependencyConstraintsDependencyVersions
(
String
sourceTemplate
,
String
libraryVersion
)
{
this
.
sourceTemplate
=
sourceTemplate
;
this
.
libraryVersion
=
libraryVersion
;
}
@Override
public
String
getVersion
(
String
groupId
,
String
artifactId
)
{
if
(
this
.
dependencyVersions
.
isEmpty
())
{
loadVersions
();
}
return
this
.
dependencyVersions
.
computeIfAbsent
(
groupId
,
(
key
)
->
Collections
.
emptyMap
()).
get
(
artifactId
);
}
private
void
loadVersions
()
{
String
version
=
this
.
libraryVersion
;
if
(
version
.
endsWith
(
"-SNAPSHOT"
))
{
version
=
version
.
substring
(
0
,
version
.
lastIndexOf
(
'.'
))
+
".x"
;
}
String
source
=
this
.
sourceTemplate
.
replace
(
"<libraryVersion>"
,
version
);
try
{
try
(
BufferedReader
reader
=
new
BufferedReader
(
new
InputStreamReader
(
URI
.
create
(
source
).
toURL
().
openStream
())))
{
String
line
;
while
((
line
=
reader
.
readLine
())
!=
null
)
{
Matcher
matcher
=
CONSTRAINT_PATTERN
.
matcher
(
line
.
trim
());
if
(
matcher
.
matches
())
{
Map
<
String
,
String
>
groupDependencies
=
this
.
dependencyVersions
.
computeIfAbsent
(
matcher
.
group
(
1
),
(
key
)
->
new
HashMap
<>());
groupDependencies
.
put
(
matcher
.
group
(
2
),
matcher
.
group
(
3
));
}
}
}
}
catch
(
IOException
ex
)
{
throw
new
GradleException
(
"Failed to load versions from dependency constraints declared in '"
+
source
+
"'"
,
ex
);
}
}
}
public
static
class
VersionAlignment
{
private
final
String
libraryName
;
public
VersionAlignment
(
String
libraryName
)
{
this
.
libraryName
=
libraryName
;
}
public
String
getLibraryName
()
{
return
this
.
libraryName
;
}
}
}
}
buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/InteractiveUpgradeResolver.java
View file @
363de4cf
...
@@ -19,19 +19,25 @@ package org.springframework.boot.build.bom.bomr;
...
@@ -19,19 +19,25 @@ package org.springframework.boot.build.bom.bomr;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
import
java.util.Collection
;
import
java.util.Collection
;
import
java.util.Collections
;
import
java.util.Collections
;
import
java.util.HashMap
;
import
java.util.HashSet
;
import
java.util.LinkedHashMap
;
import
java.util.LinkedHashMap
;
import
java.util.List
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Map
;
import
java.util.Set
;
import
java.util.SortedSet
;
import
java.util.SortedSet
;
import
java.util.stream.Collectors
;
import
java.util.stream.Collectors
;
import
org.apache.maven.artifact.versioning.DefaultArtifactVersion
;
import
org.apache.maven.artifact.versioning.DefaultArtifactVersion
;
import
org.gradle.api.InvalidUserDataException
;
import
org.gradle.api.internal.tasks.userinput.UserInputHandler
;
import
org.gradle.api.internal.tasks.userinput.UserInputHandler
;
import
org.springframework.boot.build.bom.Library
;
import
org.springframework.boot.build.bom.Library
;
import
org.springframework.boot.build.bom.Library.DependencyVersions
;
import
org.springframework.boot.build.bom.Library.Group
;
import
org.springframework.boot.build.bom.Library.Group
;
import
org.springframework.boot.build.bom.Library.Module
;
import
org.springframework.boot.build.bom.Library.Module
;
import
org.springframework.boot.build.bom.Library.ProhibitedVersion
;
import
org.springframework.boot.build.bom.Library.ProhibitedVersion
;
import
org.springframework.boot.build.bom.Library.VersionAlignment
;
import
org.springframework.boot.build.bom.UpgradePolicy
;
import
org.springframework.boot.build.bom.UpgradePolicy
;
import
org.springframework.boot.build.bom.bomr.version.DependencyVersion
;
import
org.springframework.boot.build.bom.bomr.version.DependencyVersion
;
import
org.springframework.util.StringUtils
;
import
org.springframework.util.StringUtils
;
...
@@ -59,39 +65,91 @@ public final class InteractiveUpgradeResolver implements UpgradeResolver {
...
@@ -59,39 +65,91 @@ public final class InteractiveUpgradeResolver implements UpgradeResolver {
@Override
@Override
public
List
<
Upgrade
>
resolveUpgrades
(
Collection
<
Library
>
libraries
)
{
public
List
<
Upgrade
>
resolveUpgrades
(
Collection
<
Library
>
libraries
)
{
return
libraries
.
stream
().
map
(
this
::
resolveUpgrade
).
filter
((
upgrade
)
->
upgrade
!=
null
)
Map
<
String
,
Library
>
librariesByName
=
new
HashMap
<>();
.
collect
(
Collectors
.
toList
());
for
(
Library
library
:
libraries
)
{
librariesByName
.
put
(
library
.
getName
(),
library
);
}
return
libraries
.
stream
().
map
((
library
)
->
resolveUpgrade
(
library
,
librariesByName
))
.
filter
((
upgrade
)
->
upgrade
!=
null
).
collect
(
Collectors
.
toList
());
}
}
private
Upgrade
resolveUpgrade
(
Library
library
)
{
private
Upgrade
resolveUpgrade
(
Library
library
,
Map
<
String
,
Library
>
libraries
)
{
List
<
VersionOption
>
versionOptions
=
getVersionOptions
(
library
,
libraries
);
if
(
versionOptions
.
isEmpty
())
{
return
null
;
}
VersionOption
current
=
new
VersionOption
(
library
.
getVersion
().
getVersion
());
VersionOption
selected
=
this
.
userInputHandler
.
selectOption
(
library
.
getName
()
+
" "
+
library
.
getVersion
().
getVersion
(),
versionOptions
,
current
);
return
(
selected
.
equals
(
current
))
?
null
:
new
Upgrade
(
library
,
selected
.
version
);
}
private
List
<
VersionOption
>
getVersionOptions
(
Library
library
,
Map
<
String
,
Library
>
libraries
)
{
if
(
library
.
getVersion
().
getVersionAlignment
()
!=
null
)
{
VersionOption
alignedVersionOption
=
alignedVersionOption
(
library
,
libraries
);
if
(!
isPermitted
(
alignedVersionOption
.
version
,
library
.
getProhibitedVersions
()))
{
throw
new
InvalidUserDataException
(
"Version alignment failed. Version "
+
alignedVersionOption
.
version
+
" from "
+
library
.
getName
()
+
" is prohibited"
);
}
return
Collections
.
singletonList
(
alignedVersionOption
);
}
Map
<
String
,
SortedSet
<
DependencyVersion
>>
moduleVersions
=
new
LinkedHashMap
<>();
Map
<
String
,
SortedSet
<
DependencyVersion
>>
moduleVersions
=
new
LinkedHashMap
<>();
DependencyVersion
libraryVersion
=
library
.
getVersion
().
getVersion
();
for
(
Group
group
:
library
.
getGroups
())
{
for
(
Group
group
:
library
.
getGroups
())
{
for
(
Module
module
:
group
.
getModules
())
{
for
(
Module
module
:
group
.
getModules
())
{
moduleVersions
.
put
(
group
.
getId
()
+
":"
+
module
.
getName
(),
moduleVersions
.
put
(
group
.
getId
()
+
":"
+
module
.
getName
(),
getLaterVersionsForModule
(
group
.
getId
(),
module
.
getName
(),
library
.
getVersion
()
));
getLaterVersionsForModule
(
group
.
getId
(),
module
.
getName
(),
library
Version
));
}
}
for
(
String
bom
:
group
.
getBoms
())
{
for
(
String
bom
:
group
.
getBoms
())
{
moduleVersions
.
put
(
group
.
getId
()
+
":"
+
bom
,
moduleVersions
.
put
(
group
.
getId
()
+
":"
+
bom
,
getLaterVersionsForModule
(
group
.
getId
(),
bom
,
library
.
getVersion
()
));
getLaterVersionsForModule
(
group
.
getId
(),
bom
,
library
Version
));
}
}
for
(
String
plugin
:
group
.
getPlugins
())
{
for
(
String
plugin
:
group
.
getPlugins
())
{
moduleVersions
.
put
(
group
.
getId
()
+
":"
+
plugin
,
moduleVersions
.
put
(
group
.
getId
()
+
":"
+
plugin
,
getLaterVersionsForModule
(
group
.
getId
(),
plugin
,
library
.
getVersion
()
));
getLaterVersionsForModule
(
group
.
getId
(),
plugin
,
library
Version
));
}
}
}
}
List
<
DependencyVersion
>
allVersions
=
moduleVersions
.
values
().
stream
().
flatMap
(
SortedSet:
:
stream
).
distinct
()
List
<
DependencyVersion
>
allVersions
=
moduleVersions
.
values
().
stream
().
flatMap
(
SortedSet:
:
stream
).
distinct
()
.
filter
((
dependencyVersion
)
->
isPermitted
(
dependencyVersion
,
library
.
getProhibitedVersions
()))
.
filter
((
dependencyVersion
)
->
isPermitted
(
dependencyVersion
,
library
.
getProhibitedVersions
()))
.
collect
(
Collectors
.
toList
());
.
collect
(
Collectors
.
toList
());
if
(
allVersions
.
isEmpty
())
{
if
(
allVersions
.
isEmpty
())
{
return
null
;
return
Collections
.
emptyList
()
;
}
}
List
<
VersionOption
>
versionOptions
=
allVersions
.
stream
()
return
allVersions
.
stream
()
.
map
((
version
)
->
new
VersionOption
(
version
,
getMissingModules
(
moduleVersions
,
version
)))
.
map
((
version
)
->
new
Resolved
VersionOption
(
version
,
getMissingModules
(
moduleVersions
,
version
)))
.
collect
(
Collectors
.
toList
());
.
collect
(
Collectors
.
toList
());
VersionOption
current
=
new
VersionOption
(
library
.
getVersion
(),
Collections
.
emptyList
());
}
VersionOption
selected
=
this
.
userInputHandler
.
selectOption
(
library
.
getName
()
+
" "
+
library
.
getVersion
(),
versionOptions
,
current
);
private
VersionOption
alignedVersionOption
(
Library
library
,
Map
<
String
,
Library
>
libraries
)
{
return
(
selected
.
equals
(
current
))
?
null
:
new
Upgrade
(
library
,
selected
.
version
);
VersionAlignment
versionAlignment
=
library
.
getVersion
().
getVersionAlignment
();
Library
alignmentLibrary
=
libraries
.
get
(
versionAlignment
.
getLibraryName
());
DependencyVersions
dependencyVersions
=
alignmentLibrary
.
getDependencyVersions
();
if
(
dependencyVersions
==
null
)
{
throw
new
InvalidUserDataException
(
"Cannot align with library '"
+
versionAlignment
.
getLibraryName
()
+
"' as it does not define any dependency versions"
);
}
if
(!
dependencyVersions
.
available
())
{
return
null
;
}
Set
<
String
>
versions
=
new
HashSet
<>();
for
(
Group
group
:
library
.
getGroups
())
{
for
(
Module
module
:
group
.
getModules
())
{
String
version
=
dependencyVersions
.
getVersion
(
group
.
getId
(),
module
.
getName
());
if
(
version
!=
null
)
{
versions
.
add
(
version
);
}
}
}
if
(
versions
.
isEmpty
())
{
throw
new
InvalidUserDataException
(
"Cannot align with library '"
+
versionAlignment
.
getLibraryName
()
+
"' as its dependency versions do not include any of this library's modules"
);
}
if
(
versions
.
size
()
>
1
)
{
throw
new
InvalidUserDataException
(
"Cannot align with library '"
+
versionAlignment
.
getLibraryName
()
+
"' as it uses multiple different versions of this library's modules"
);
}
String
requiredVersion
=
versions
.
iterator
().
next
();
return
new
AlignedVersionOption
(
DependencyVersion
.
parse
(
requiredVersion
),
alignmentLibrary
);
}
}
private
boolean
isPermitted
(
DependencyVersion
dependencyVersion
,
List
<
ProhibitedVersion
>
prohibitedVersions
)
{
private
boolean
isPermitted
(
DependencyVersion
dependencyVersion
,
List
<
ProhibitedVersion
>
prohibitedVersions
)
{
...
@@ -125,23 +183,53 @@ public final class InteractiveUpgradeResolver implements UpgradeResolver {
...
@@ -125,23 +183,53 @@ public final class InteractiveUpgradeResolver implements UpgradeResolver {
return
versions
;
return
versions
;
}
}
private
static
final
class
VersionOption
{
private
static
class
VersionOption
{
private
final
DependencyVersion
version
;
private
final
DependencyVersion
version
;
protected
VersionOption
(
DependencyVersion
version
)
{
this
.
version
=
version
;
}
@Override
public
String
toString
()
{
return
this
.
version
.
toString
();
}
}
private
static
final
class
AlignedVersionOption
extends
VersionOption
{
private
final
Library
alignedWith
;
private
AlignedVersionOption
(
DependencyVersion
version
,
Library
alignedWith
)
{
super
(
version
);
this
.
alignedWith
=
alignedWith
;
}
@Override
public
String
toString
()
{
return
super
.
toString
()
+
" (aligned with "
+
this
.
alignedWith
.
getName
()
+
" "
+
this
.
alignedWith
.
getVersion
().
getVersion
()
+
")"
;
}
}
private
static
final
class
ResolvedVersionOption
extends
VersionOption
{
private
final
List
<
String
>
missingModules
;
private
final
List
<
String
>
missingModules
;
private
VersionOption
(
DependencyVersion
version
,
List
<
String
>
missingModules
)
{
private
Resolved
VersionOption
(
DependencyVersion
version
,
List
<
String
>
missingModules
)
{
this
.
version
=
version
;
super
(
version
)
;
this
.
missingModules
=
missingModules
;
this
.
missingModules
=
missingModules
;
}
}
@Override
@Override
public
String
toString
()
{
public
String
toString
()
{
if
(
this
.
missingModules
.
isEmpty
())
{
if
(
this
.
missingModules
.
isEmpty
())
{
return
this
.
version
.
toString
();
return
super
.
toString
();
}
}
return
this
.
version
+
" (some modules are missing: "
return
super
.
toString
()
+
" (some modules are missing: "
+
StringUtils
.
collectionToDelimitedString
(
this
.
missingModules
,
", "
)
+
")"
;
+
StringUtils
.
collectionToDelimitedString
(
this
.
missingModules
,
", "
)
+
")"
;
}
}
...
...
buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/UpgradeApplicator.java
View file @
363de4cf
...
@@ -46,8 +46,14 @@ class UpgradeApplicator {
...
@@ -46,8 +46,14 @@ class UpgradeApplicator {
Matcher
matcher
=
Pattern
.
compile
(
"library\\(\""
+
upgrade
.
getLibrary
().
getName
()
+
"\", \"(.+)\"\\)"
)
Matcher
matcher
=
Pattern
.
compile
(
"library\\(\""
+
upgrade
.
getLibrary
().
getName
()
+
"\", \"(.+)\"\\)"
)
.
matcher
(
buildFileContents
);
.
matcher
(
buildFileContents
);
if
(!
matcher
.
find
())
{
if
(!
matcher
.
find
())
{
throw
new
IllegalStateException
(
"Failed to find definition for library '"
+
upgrade
.
getLibrary
().
getName
()
matcher
=
Pattern
+
"' in bom '"
+
this
.
buildFile
+
"'"
);
.
compile
(
"library\\(\""
+
upgrade
.
getLibrary
().
getName
()
+
"\"\\) \\{\\s+version\\(\"(.+)\"\\)"
,
Pattern
.
MULTILINE
)
.
matcher
(
buildFileContents
);
if
(!
matcher
.
find
())
{
throw
new
IllegalStateException
(
"Failed to find definition for library '"
+
upgrade
.
getLibrary
().
getName
()
+
"' in bom '"
+
this
.
buildFile
+
"'"
);
}
}
}
String
version
=
matcher
.
group
(
1
);
String
version
=
matcher
.
group
(
1
);
if
(
version
.
startsWith
(
"${"
)
&&
version
.
endsWith
(
"}"
))
{
if
(
version
.
startsWith
(
"${"
)
&&
version
.
endsWith
(
"}"
))
{
...
@@ -55,7 +61,7 @@ class UpgradeApplicator {
...
@@ -55,7 +61,7 @@ class UpgradeApplicator {
return
this
.
gradleProperties
;
return
this
.
gradleProperties
;
}
}
else
{
else
{
updateBuildFile
(
upgrade
,
buildFileContents
);
updateBuildFile
(
upgrade
,
buildFileContents
,
matcher
.
start
(
1
),
matcher
.
end
(
1
)
);
return
this
.
buildFile
;
return
this
.
buildFile
;
}
}
}
}
...
@@ -63,15 +69,15 @@ class UpgradeApplicator {
...
@@ -63,15 +69,15 @@ class UpgradeApplicator {
private
void
updateGradleProperties
(
Upgrade
upgrade
,
String
version
)
throws
IOException
{
private
void
updateGradleProperties
(
Upgrade
upgrade
,
String
version
)
throws
IOException
{
String
property
=
version
.
substring
(
2
,
version
.
length
()
-
1
);
String
property
=
version
.
substring
(
2
,
version
.
length
()
-
1
);
String
gradlePropertiesContents
=
new
String
(
Files
.
readAllBytes
(
this
.
gradleProperties
),
StandardCharsets
.
UTF_8
);
String
gradlePropertiesContents
=
new
String
(
Files
.
readAllBytes
(
this
.
gradleProperties
),
StandardCharsets
.
UTF_8
);
String
modified
=
gradlePropertiesContents
.
replace
(
property
+
"="
+
upgrade
.
getLibrary
().
getVersion
(),
String
modified
=
gradlePropertiesContents
.
replace
(
property
+
"="
+
upgrade
.
getVersion
());
property
+
"="
+
upgrade
.
get
Library
().
getVersion
().
getVersion
(),
property
+
"="
+
upgrade
.
get
Version
());
overwrite
(
this
.
gradleProperties
,
modified
);
overwrite
(
this
.
gradleProperties
,
modified
);
}
}
private
void
updateBuildFile
(
Upgrade
upgrade
,
String
buildFileContents
)
throws
IOException
{
private
void
updateBuildFile
(
Upgrade
upgrade
,
String
buildFileContents
,
int
versionStart
,
int
versionEnd
)
String
modified
=
buildFileContents
.
replace
(
throws
IOException
{
"library(\""
+
upgrade
.
getLibrary
().
getName
()
+
"\", \""
+
upgrade
.
getLibrary
().
getVersion
()
+
"\")"
,
String
modified
=
buildFileContents
.
substring
(
0
,
versionStart
)
+
upgrade
.
getVersion
()
"library(\""
+
upgrade
.
getLibrary
().
getName
()
+
"\", \""
+
upgrade
.
getVersion
()
+
"\")"
);
+
buildFileContents
.
substring
(
versionEnd
);
overwrite
(
this
.
buildFile
,
modified
);
overwrite
(
this
.
buildFile
,
modified
);
}
}
...
...
buildSrc/src/test/java/org/springframework/boot/build/bom/BomPluginIntegrationTests.java
View file @
363de4cf
...
@@ -197,6 +197,34 @@ public class BomPluginIntegrationTests {
...
@@ -197,6 +197,34 @@ public class BomPluginIntegrationTests {
});
});
}
}
// @Test
// void versionAlignmentIsVerified() throws IOException {
// try (PrintWriter out = new PrintWriter(new FileWriter(this.buildFile))) {
// out.println("plugins {");
// out.println(" id 'org.springframework.boot.bom'");
// out.println("}");
// out.println("bom {");
// out.println(" library('OAuth2 OIDC SDK', '8.36.1') {");
// out.println(" alignedWith('Spring Security') {");
// out.println(
// "
// source('https://github.com/spring-projects/spring-security/blob/${libraryVersion}/config/gradle/dependency-locks/optional.lockfile')");
// out.println(" pattern('com.nimbusds:oauth2-oidc-sdk:(.+)')");
// out.println(" }");
// out.println(" group('com.nimbusds') {");
// out.println(" modules = [");
// out.println(" 'oauth2-oidc-sdk'");
// out.println(" ]");
// out.println(" }");
// out.println(" }");
// out.println(" library('Spring Security', '5.4.7') {");
// out.println(" }");
// out.println("}");
// }
// System.out.println(runGradle(DeployedPlugin.GENERATE_POM_TASK_NAME,
// "-s").getOutput());
// }
private
BuildResult
runGradle
(
String
...
args
)
{
private
BuildResult
runGradle
(
String
...
args
)
{
return
GradleRunner
.
create
().
withDebug
(
true
).
withProjectDir
(
this
.
projectDir
).
withArguments
(
args
)
return
GradleRunner
.
create
().
withDebug
(
true
).
withProjectDir
(
this
.
projectDir
).
withArguments
(
args
)
.
withPluginClasspath
().
build
();
.
withPluginClasspath
().
build
();
...
...
buildSrc/src/test/java/org/springframework/boot/build/bom/bomr/UpgradeApplicatorTests.java
View file @
363de4cf
...
@@ -28,6 +28,7 @@ import org.junit.jupiter.api.Test;
...
@@ -28,6 +28,7 @@ import org.junit.jupiter.api.Test;
import
org.junit.jupiter.api.io.TempDir
;
import
org.junit.jupiter.api.io.TempDir
;
import
org.springframework.boot.build.bom.Library
;
import
org.springframework.boot.build.bom.Library
;
import
org.springframework.boot.build.bom.Library.LibraryVersion
;
import
org.springframework.boot.build.bom.bomr.version.DependencyVersion
;
import
org.springframework.boot.build.bom.bomr.version.DependencyVersion
;
import
org.springframework.util.FileCopyUtils
;
import
org.springframework.util.FileCopyUtils
;
...
@@ -51,13 +52,28 @@ class UpgradeApplicatorTests {
...
@@ -51,13 +52,28 @@ class UpgradeApplicatorTests {
String
originalContents
=
new
String
(
Files
.
readAllBytes
(
bom
.
toPath
()),
StandardCharsets
.
UTF_8
);
String
originalContents
=
new
String
(
Files
.
readAllBytes
(
bom
.
toPath
()),
StandardCharsets
.
UTF_8
);
File
gradleProperties
=
new
File
(
this
.
temp
,
"gradle.properties"
);
File
gradleProperties
=
new
File
(
this
.
temp
,
"gradle.properties"
);
FileCopyUtils
.
copy
(
new
File
(
"src/test/resources/gradle.properties"
),
gradleProperties
);
FileCopyUtils
.
copy
(
new
File
(
"src/test/resources/gradle.properties"
),
gradleProperties
);
new
UpgradeApplicator
(
bom
.
toPath
(),
gradleProperties
.
toPath
())
new
UpgradeApplicator
(
bom
.
toPath
(),
gradleProperties
.
toPath
())
.
apply
(
new
Upgrade
(
.
apply
(
new
Upgrade
(
new
Library
(
"ActiveMQ"
,
DependencyVersion
.
parse
(
"5.15.11"
)
,
null
,
null
),
new
Library
(
"ActiveMQ"
,
new
LibraryVersion
(
DependencyVersion
.
parse
(
"5.15.11"
),
null
),
null
,
null
,
null
),
DependencyVersion
.
parse
(
"5.16"
)));
DependencyVersion
.
parse
(
"5.16"
)));
String
bomContents
=
new
String
(
Files
.
readAllBytes
(
bom
.
toPath
()),
StandardCharsets
.
UTF_8
);
String
bomContents
=
new
String
(
Files
.
readAllBytes
(
bom
.
toPath
()),
StandardCharsets
.
UTF_8
);
assertThat
(
bomContents
.
length
()).
isEqualTo
(
originalContents
.
length
()
-
3
);
assertThat
(
bomContents
.
length
()).
isEqualTo
(
originalContents
.
length
()
-
3
);
}
}
@Test
void
whenUpgradeIsAppliedToLibraryWithAlignedVersionThenBomIsUpdated
()
throws
IOException
{
File
bom
=
new
File
(
this
.
temp
,
"bom.gradle"
);
FileCopyUtils
.
copy
(
new
File
(
"src/test/resources/bom.gradle"
),
bom
);
String
originalContents
=
new
String
(
Files
.
readAllBytes
(
bom
.
toPath
()),
StandardCharsets
.
UTF_8
);
File
gradleProperties
=
new
File
(
this
.
temp
,
"gradle.properties"
);
FileCopyUtils
.
copy
(
new
File
(
"src/test/resources/gradle.properties"
),
gradleProperties
);
new
UpgradeApplicator
(
bom
.
toPath
(),
gradleProperties
.
toPath
()).
apply
(
new
Upgrade
(
new
Library
(
"OAuth2 OIDC SDK"
,
new
LibraryVersion
(
DependencyVersion
.
parse
(
"8.36.1"
),
null
),
null
,
null
,
null
),
DependencyVersion
.
parse
(
"8.36.2"
)));
String
bomContents
=
new
String
(
Files
.
readAllBytes
(
bom
.
toPath
()),
StandardCharsets
.
UTF_8
);
assertThat
(
bomContents
.
length
()).
isEqualTo
(
originalContents
.
length
());
assertThat
(
bomContents
).
contains
(
"version(\"8.36.2\")"
);
}
@Test
@Test
void
whenUpgradeIsAppliedToLibraryWithVersionPropertyThenGradlePropertiesIsUpdated
()
throws
IOException
{
void
whenUpgradeIsAppliedToLibraryWithVersionPropertyThenGradlePropertiesIsUpdated
()
throws
IOException
{
File
bom
=
new
File
(
this
.
temp
,
"bom.gradle"
);
File
bom
=
new
File
(
this
.
temp
,
"bom.gradle"
);
...
@@ -65,7 +81,8 @@ class UpgradeApplicatorTests {
...
@@ -65,7 +81,8 @@ class UpgradeApplicatorTests {
File
gradleProperties
=
new
File
(
this
.
temp
,
"gradle.properties"
);
File
gradleProperties
=
new
File
(
this
.
temp
,
"gradle.properties"
);
FileCopyUtils
.
copy
(
new
File
(
"src/test/resources/gradle.properties"
),
gradleProperties
);
FileCopyUtils
.
copy
(
new
File
(
"src/test/resources/gradle.properties"
),
gradleProperties
);
new
UpgradeApplicator
(
bom
.
toPath
(),
gradleProperties
.
toPath
()).
apply
(
new
Upgrade
(
new
UpgradeApplicator
(
bom
.
toPath
(),
gradleProperties
.
toPath
()).
apply
(
new
Upgrade
(
new
Library
(
"Kotlin"
,
DependencyVersion
.
parse
(
"1.3.70"
),
null
,
null
),
DependencyVersion
.
parse
(
"1.4"
)));
new
Library
(
"Kotlin"
,
new
LibraryVersion
(
DependencyVersion
.
parse
(
"1.3.70"
),
null
),
null
,
null
,
null
),
DependencyVersion
.
parse
(
"1.4"
)));
Properties
properties
=
new
Properties
();
Properties
properties
=
new
Properties
();
try
(
InputStream
in
=
new
FileInputStream
(
gradleProperties
))
{
try
(
InputStream
in
=
new
FileInputStream
(
gradleProperties
))
{
properties
.
load
(
in
);
properties
.
load
(
in
);
...
...
buildSrc/src/test/resources/bom.gradle
View file @
363de4cf
...
@@ -48,4 +48,14 @@ bom {
...
@@ -48,4 +48,14 @@ bom {
]
]
}
}
}
}
library
(
"OAuth2 OIDC SDK"
)
{
version
(
"8.36.1"
)
{
shouldAlignWithVersionFrom
(
"Spring Security"
)
}
group
(
"com.nimbusds"
)
{
modules
=
[
"oauth2-oidc-sdk"
]
}
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment