Logo

dev-resources.site

for different kinds of informations.

Check for newer versions of dependencies in pom.xml

Published at
5/8/2024
Categories
maven
groovy
Author
adzubla
Categories
2 categories in total
maven
open
groovy
open
Author
7 person written this
adzubla
open
Check for newer versions of dependencies in pom.xml

I made a script in Groovy language to look for newer versions of all declared dependencies in a Maven project. The script supports multi-module projects.

It searches the current folder for pom.xml files and checks the central.sonatype.com website for a newer versions. Only dependencies that have an explicit version defined in pom will be checked. Versions defined by properties will be resolved if the properties were declared in one of the pom files. (If a property is defined more than once, the result is undefined.)

Example of use:

check-versions.sh example

I recommend installing Java 17 (or newer) and Groovy 4 with sdkman!

Put these two files in a folder that is included in PATH.

check-versions.sh:



#!/usr/bin/env bash
BASEDIR=$(unset CDPATH; cd `dirname $0`; pwd)

JAVA_VER=$(java -version 2>&1 | awk -F '"' '/version/ {print $2}' | awk -F '.' '{sub("^$", "0", $2); print $1$2}')
if [ "$JAVA_VER" -lt 170 ]; then
    echo "Java 17 necessario"
    exit 1
fi

#$PROXY="-DproxySet=true -DproxyHost=10.0.0.24 -DproxyPort=8080"

groovy -Dgroovy.grape.report.downloads=true $PROXY $BASEDIR/check-versions.groovy 2>/dev/null


Enter fullscreen mode Exit fullscreen mode

check-versions.groovy:



import groovy.json.JsonSlurper
import groovy.xml.XmlParser
@Grab('org.jodd:jodd-lagarto:6.0.6')
import jodd.jerry.Jerry
@Grab('org.fusesource.jansi:jansi:2.4.1')
import org.fusesource.jansi.AnsiConsole
@Grab('org.slf4j:slf4j-jdk-platform-logging:2.0.13')
import org.slf4j.Logger

import static org.fusesource.jansi.Ansi.Color.GREEN
import static org.fusesource.jansi.Ansi.Color.RED
import static org.fusesource.jansi.Ansi.ansi

AnsiConsole.systemInstall()

record Dependency(String groupId, String artifactId, String version) {}

static def findAllDependencies() {
    //println("-- findAllDependencies")
    def allDeps = []
    def mvnProperties = [:]
    new File(".").traverse(type: groovy.io.FileType.FILES, nameFilter: ~/pom.xml/) {
        processPom(new XmlParser().parse(it), allDeps, mvnProperties)
    }
    return allDeps.unique().sort { k1, k2 -> k1.groupId + k1.artifactId <=> k2.groupId + k2.artifactId }
}

static def processPom(def project, def allDeps, def mvnProperties) {
    collectProperties(project, mvnProperties)
    collectDependencies(project.'**'.dependencies.dependency, allDeps, mvnProperties)
    collectDependencies(project.parent, allDeps, mvnProperties)
    collectDependencies(project.'**'.plugin, allDeps, mvnProperties)
}

static def collectProperties(def project, def mvnProperties) {
    //println("-- collectProperties")
    for (def p : project.properties) {
        for (def c : p.children()) {
            def name = c.name().localPart
            def value = c.text()
            mvnProperties[name] = value
        }
    }
}

static def collectDependencies(def dependencies, def allDeps, def mvnProperties) {
    //println("-- collectDependencies")
    for (def d : dependencies) {
        def groupId = d.groupId.text()
        if (groupId.isEmpty()) {
            // assume default groupId for maven plugins
            groupId = "org.apache.maven.plugins"
        }
        def artifactId = d.artifactId.text()
        def version = d.version.text()
        if (version.isEmpty())
            continue
        if (version.startsWith("\$")) {
            def matcher = (version =~ /\$\{(.+?)\}/)
            if (matcher.find()) {
                def property = matcher.group(1)
                version = mvnProperties[property]
                if (version == null) {
                    continue
                }
            }
        }
        def x = new Dependency(groupId, artifactId, version)
        allDeps.add(x)
    }
}

/**
 * This method is highly dependable on the html format returned by central.sonatype.com
 *
 * Return this map:
 * [name:logstash-logback-encoder, namespace:net.logstash.logback, version:7.4, versions:[7.4, 7.3, 7.2, 7.1.1, 7.1, 7.0.1, 7.0, 6.6, 6.5, 6.4, 6.3, 6.2, 6.1, 6.0, 5.3, 5.2, 5.1, 5.0, 4.11, 4.10], tags:[], usedIn:1600, tab:versions]
 */
def findLatestVersion(String groupId, String artifactId) {
    //println("-- findLatestVersion ${groupId}:${artifactId}")
    def url = "https://central.sonatype.com/artifact/${groupId}/${artifactId}/versions"
    def body = url.toURL().getText()
    def doc = Jerry.of(body)
    def scripts = doc.find('html.nx-html.nx-html--page-scrolling body.nx-body script')

    def text = ""
    scripts.each {
        def element ->
            if (element.text().contains('self.__next_f.push')) {
                text = element.text()
            }
    }

    int i = text.indexOf(':')
    int j = text.lastIndexOf('"')
    text = text.substring(i + 1, j - 2)
    text = text.replaceAll('\\\\"', '"')
    text = text.replaceAll('\\\\"', '"')

    def json = new JsonSlurper().parseText(text)
    try {
        def result = json[0][3].children[0][3]
        return result
    }
    catch (Exception ignored) {
        return null
    }
}

//skipVersions = [:]
skipVersions = [
        "org.springframework.boot:spring-boot-starter-parent"  : "3.2",
        "org.springframework.boot:spring-boot-starter-data-jpa": "3.2",
        "org.springframework.boot:spring-boot-starter-web"     : "3.2",
        "org.springframework.boot:spring-boot-dependencies"    : "3.2",
        "org.springframework.cloud:spring-cloud-dependencies"  : "2023",
]

def getLatestVersion(String groupId, String artifactId) {
    //println("-- getLatestVersion")
    def versions = findLatestVersion(groupId, artifactId)
    def skip = skipVersions["${groupId}:${artifactId}"]
    if (skip == null) {
        return versions?.version
    }

    for (def v in versions.versions) {
        if (v.startsWith(skip)) {
            continue
        }
        return v
    }
}

def allDeps = findAllDependencies()

for (def d : allDeps) {
    def latest = getLatestVersion(d.groupId, d.artifactId)
    if (latest == null) {
        continue
    }

    print("${d.groupId}:${d.artifactId}:${d.version} ")

    if (d.version.equals(latest)) {
        println("${ansi().fg(GREEN)}[OK]${ansi().reset()}")
    } else {
        println("${ansi().fg(RED)}[${latest}]${ansi().reset()}")
    }
}


Enter fullscreen mode Exit fullscreen mode

By changing the skipVersions variable, it is possible to ignore a version of some dependencies.

For example: I'm stuck with Spring Boot 3.1, so the config below will ignore version 3.2, but will still notify for newer 3.1.x version.



skipVersions = [
        "org.springframework.boot:spring-boot-starter-parent"  : "3.2",
        "org.springframework.boot:spring-boot-starter-data-jpa": "3.2",
        "org.springframework.boot:spring-boot-starter-web"     : "3.2",
        "org.springframework.boot:spring-boot-dependencies"    : "3.2",
        "org.springframework.cloud:spring-cloud-dependencies"  : "2023",
]


Enter fullscreen mode Exit fullscreen mode

If there is no dependency to skip, just use an empty map:



skipVersions = [:]


Enter fullscreen mode Exit fullscreen mode
maven Article's
30 articles in total
Favicon
SpringBoot Web Service - Part 5 - Github Action
Favicon
SpringBoot Web Service - Part 2 - Preparing Using Spring Initializr
Favicon
SpringBoot Web Service - Part 1 - Create Repository
Favicon
SpringBoot Web Service - Part 4 - Initial Configuration
Favicon
Identifying and Removing Unused Dependencies in pom.xml
Favicon
JeKa: The Simplest Way to Start with Java for Real
Favicon
JeKa: The Simplest Way to Create Uber and Shade Jars
Favicon
JeKa: The Simplest Way to Publish on Maven Central
Favicon
Preparando o ambiente de desenvolvimento da melhor API de tabelas de campeonato que vocรช jรก viu!
Favicon
Maven Guide for Beginners
Favicon
Wednesday Links - Edition 2024-10-16
Favicon
Unlock 10% Discounts in 5 Minutes: Build a Drools Project with Maven
Favicon
Getting Started with Maven
Favicon
Quick fix: com.github.everit-org.json-schema:org.everit.json.schema:jar:1.12.2 was not found
Favicon
How to deploy to maven central repo
Favicon
No SNAPSHOTs
Favicon
Maven Commands Cheat Sheet
Favicon
Apache Maven Kirish
Favicon
Difference between mvn install and mvn package
Favicon
Adding Liquibase plugin into Apache Maven managed project
Favicon
Accelerate Maven Application Builds: Maximizing Efficiency with Docker Volumes for Maven Repository Sharing
Favicon
Check for newer versions of dependencies in pom.xml
Favicon
Accelerate Your Automation Testing with Maven: A Step-by-Step Guide ๐Ÿš€
Favicon
Junit Badge For Git Project
Favicon
Jenkins CICD
Favicon
Set JVM Timezone when running JUnit 5 tests
Favicon
Maven 4 - Part I - Easier Versions
Favicon
An Updated Guide to Maven Archetypes
Favicon
H2 database Setup Error Unable to load name org.hibernate.dialect.Oracle10gDialect
Favicon
Why I prefer Maven over Gradle

Featured ones: