Keep your stuff up to date
Every codebase depends on multiple external libraries. It is good idea to stay up to date with external dependencies. It is important to update all security related stuff and it might be helpful or fun to use latest features. I’m going to share my way of staying up to date with external dependencies in maven, gradle and npm.
The first thing which in my opinion is crucial to stay up to date is to create automated checker. The best place for this will be your CI tool. Create jenkins plan (or whatever CI tool project) which will fail when there are outdated libraries. Automated tool will nudge you every time there is external library that should be updated. Without notification from the CI no one is going to execute dependency check manually in day to day development especially when there is more work then days before deadline.
I don’t recommend failing every time there is outdated library because it will be annoying to update frontend libraries every second hour ;) Failing when there is more than X outdated libraries is actually good idea. Just remember to configure X to be acceptable value. No one is going to update 15 frontend libraries at once because 4 of them will have different API after bugfix release (…), but someone might update 2 or 3 of them once in a while.
The last advice which is game changer is to configure it as commit hook not as scheduled task. When it is scheduled and it fails in the middle of the night then every developer will ignore. But when the build fails after your commit then you feel responsible for it and try to fix it to keep board green (broken windows theory).
When using npm as dependencies manager it is very simple to find out outdated packages - just run
npm outadted (docs) and you are good to go. Sample
outdated command output
Package Current Wanted Latest Location angular 1.5.9 1.5.9 1.6.3 dependenices-update lodash 3.6.0 3.6.0 4.17.4 dependenices-update mocha 3.1.0 3.1.0 3.2.0 dependenices-update
When you CI instance is configured you might want to create something more ‘sophisticated’:
#!/bin/sh npm -s install MAX_OUTDATED_PACKAGES=$1 OUTDATED_PACKAGES=`npm -s outdated | grep -v beta | grep -v rc` OUTDATED_PACKAGES_COUNT=`echo "$OUTDATED_PACKAGES" | tail -n +2 | wc -l` if [ $OUTDATED_PACKAGES_COUNT -ge $MAX_OUTDATED_PACKAGES ]; then echo "There is $OUTDATED_PACKAGES_COUNT outdated dependencies!" printf '%b\n\n' "$OUTDATED_PACKAGES" exit $OUTDATED_PACKAGES_COUNT fi
You call this script with parameter which will be the maximum number of acceptable outdated dependencies. Script is very simple and will exclude most of beta and release candidates.
To find outdated dependencies in gradle you can use gradle versions plugin. Sample output from versions plugin:
$> ./gradlew dependencyUpdates ------------------------------------------------------------ : Project Dependency Updates (report to plain text file) ------------------------------------------------------------ The following dependencies are using the latest milestone version: - com.github.ben-manes:gradle-versions-plugin:0.14.0 The following dependencies have later milestone versions: - org.apache.commons:commons-lang3 [3.4 -> 3.5] - junit:junit [3.8.1 -> 4.12] - org.springframework:spring-core [3.2.4.RELEASE -> 4.3.7.RELEASE]
Output is a bit complex, but luckily there are also other formats (json and xml) which can be
-DoutputFormatter=json switch. Output report will be generated in
build/dependencyUpdates directory. Json support in bash doesn’t exists, but you can use
jq for working with json in bash (
sudo apt-get install jq).
Or you can ask google for some advice on how to use sed and improvise:
#!/bin/sh ./gradlew -DoutputFormatter=json dependencyUpdates > /dev/null 2>&1 MAX_OUTDATED_DEPENDENCIES=$1 REPORT="build/dependencyUpdates/report.txt" OUDATED_DEPENDENCIES_COUNT=`sed -n -e '/The following dependencies have later/,$p' $REPORT | tail -n +2 | wc -l` if [ $OUDATED_DEPENDENCIES_COUNT -ge $MAX_OUTDATED_DEPENDENCIES ]; then echo "There is $OUDATED_DEPENDENCIES_COUNT outdated dependencies!" printf '%b\n\n' "$(cat $REPORT)" exit $OUDATED_DEPENDENCIES_COUNT fi
Now all you have to do is execute this script with single number param which will be maximum number of acceptable outdated libraries.
To find outdated libraries using maven you can use versions-maven-plugin. Add versions plugin to your plugins section:
<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>versions-maven-plugin</artifactId> <version>2.3</version> </plugin>
Now you can display outdated packages using
mvn versions:display-dependency-updates. If you
want to run this check on CI tool then we need to analyze versions output. Luckily we don’t have to
analyze all the stuff that maven produces. We can pass additional property value and save report to
file. Just run
mvn versions:display-dependency-updates -Dversions.outputFile=target/outdated.txt
and versions plugin will plain text file with info what should be updated:
The following dependencies in Dependencies have newer versions: junit:junit ............................................ 3.8.1 -> 4.12 org.apache.commons:commons-lang3 .......................... 3.4 -> 3.5
The output file can be easily verified if there are outdated libraries.
I like to use console for my day to day work, but I hate typing long commands so let’s wrap it up into single reusable script which can be used on CI:
#!/bin/sh MAX_OUTDATED_LIBRARIES=$1 OUTPUT="target/outdated.txt" mkdir -p target ./mvnw -q versions:display-dependency-updates -Dversions.outputFile="$OUTPUT" OUTDATED_LIBRARIES=`grep . "$OUTPUT" | tail -n +2 | wc -l` if [ $OUTDATED_LIBRARIES -ge $MAX_OUTDATED_LIBRARIES ]; then echo "There is $OUTDATED_LIBRARIES outdated libraries!\n" printf '%b\n\n' "$(cat target/outdated.txt)" exit $OUTDATED_LIBRARIES fi
As in previous examples to run script you must provide single argument which will be maximum number of acceptable outdated libraries
When using maven and versions plugin there are also additional targets you can execute (including site report generation and finding outdated plugins). Checkout documentation for more details.