Maven only requires you to specify versions of dependencies that you use directly. Transitive dependencies aren't visible in the pom.xml and their version is chosen in a seemingly random way.
This Maven plugin enables you to:
It is a bit like mvn dependency:list
but the output is intended to be tracked by you SCM
and the check goal makes sure you don't forget to update the file.
mvn se.vandmo:dependency-lock-maven-plugin:lock
will create a file named dependencies-lock.json by default.
You should then commit that file to your source control of choice.
Choose between JSON format and POM XML format. The latter is more verbose but will be detected by Dependabot Security Alerts.
The following snippet in your pom.xml file will make sure that the actual dependencies are the same as in the dependencies-lock.json file.
<build>
<plugins>
<plugin>
<groupId>se.vandmo</groupId>
<artifactId>dependency-lock-maven-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<id>check</id>
<phase>validate</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Adding the following in ~/.m2/settings.xml will allow you to write mvn dependency-lock:lock
<pluginGroups>
<pluginGroup>se.vandmo</pluginGroup>
</pluginGroups>
Configuration shared between all goals.
The filename of the lock file.
Which lock file format to use, defaults to json.
Checks that actual dependencies matches the lock file. Fails the build if there is no match. Expects a lock file to exist.
If some dependencies are part of the same multi-module project you might want those dependencies to be the same version as the artifact where the dependencies are locked. You can achieve this by configuring the plugin like such:
<configuration>
<dependencySets>
<dependencySet>
<includes>
<include>org.myorg:myapplication-*</include>
</includes>
<version>use-project-version</version>
</dependencySet>
</dependencySets>
</configuration>
The filter syntax is [groupId]:[artifactId]:[type]:[version]
where each pattern segment is optional and supports full and partial *
wildcards.
An empty pattern segment is treated as an implicit wildcard.
For example, org.myorg.*
will match all artifacts whose group id starts with org.myorg.
, and :::*-SNAPSHOT
will match all snapshot artifacts.
dependencySets are ordered in reverse priority which means that a dependencySet at the end of the list will override any previously set configuration for the matching dependencies. A dependencySet is configured as follows:
Field | Description |
---|---|
includes | Patterns describing dependencies that should be included |
excludes | Patterns describing dependencies that should be excluded |
allowExtraneous | Whether extraneous dependencies should be allowed or not |
allowMissing | Whether missing dependencies should be allowed or not |
version | "check", "ignore", "use-project-version" or "snapshot" |
integrity | "check" or "ignore" |
"snapshot" version matching means that 1.2.3-SNAPSHOT will match something like 1.2.3-20221104.072032-1 and similar.
Creates a lock file from the actual dependencies.
Ignored fields can be actually marked as ignored
in the lock file with markIgnoredAsIgnored
configuration property.
<configuration>
<markIgnoredAsIgnored>true</markIgnoredAsIgnored>
<dependencySets>
<dependencySet>
<includes>
<include>com.company:our-subproject-*</include>
</includes>
<version>ignore</version>
<integrity>ignore</integrity>
</dependencySet>
</dependencySets>
</configuration>
Dependabot Updates currently creates a single PR for each change. If you use pom format and merge all PRs from Dependabot then that combined build might work, but each single PR will fail. There are feature requests for combined PRs for Dependabot which, if implemented, could make a combined PR work. Another approach to automate the creation of PRs would be to have a GitHub workflow that creates a combined PR based on the Dependabot PRs.