diff --git a/melting-pot.sh b/melting-pot.sh index f7b904e..5998306 100755 --- a/melting-pot.sh +++ b/melting-pot.sh @@ -1,35 +1,560 @@ #!/bin/sh -# melting-pot.sh - A script to build the entire SciJava software stack -# from the latest code on the respective master branches. - -rm -rf melting-pot -mkdir melting-pot -cd melting-pot - -echo '' > pom.xml -echo '' >> pom.xml -echo ' 4.0.0' >> pom.xml -echo >> pom.xml -echo ' org.scijava' >> pom.xml -echo ' melting-pot' >> pom.xml -echo ' 0.0.0-SNAPSHOT' >> pom.xml -echo ' pom' >> pom.xml -echo >> pom.xml -echo ' SciJava Uber Build' >> pom.xml -echo >> pom.xml -echo ' ' >> pom.xml - -for repo in $(sj-hierarchy.pl -g) -do - git clone $repo --depth 1 - module=${repo##*/} - module=${module%.git} - echo " $module" >> pom.xml -done - -echo ' ' >> pom.xml -echo -echo '' >> pom.xml - -mvn -Pdev.scijava,dev.imglib2,dev.scifio,dev.imagej validate +# ============================================================================ +# melting-pot.sh +# ============================================================================ +# Tests all components of a project affected by changes in its dependencies. +# +# First, an anecdote illustrating the problem this script solves: +# +# Suppose you have a large application, org:app:1.0.0, with many dependencies: +# org:foo:1.2.3, org:bar:3.4.5, and many others. +# +# Now suppose you make some changes to foo, and want to know whether deploying +# them (i.e., releasing a new foo and updating app to depend on that release) +# will break the app. So you manually update your local copy of app to depend +# on org:foo:1.3.0-SNAPSHOT, and run the build (including tests, of course). +# +# The build passes, but this alone is insufficient: org:bar:3.4.5 also depends +# on org:foo:1.2.3, so you manually update bar to use org:foo:1.3.0-SNAPSHOT, +# then build bar to verify that it also is not broken by the update. +# +# This process quickly becomes very tedious when there are dozens of +# components of app which all depend on foo. +# +# And more importantly, testing each component individually in this manner is +# still insufficient to determine whether all of them will truly work together +# at runtime, where only a single version of each component is deployed. +# +# For example: suppose org:bar:3.4.5 depends on org:lib:8.0.0, while +# org:foo:1.2.3 depends on org:lib:7.0.0. The relevant facts are: +# +# * Your new foo (org:foo:1.3.0-SNAPSHOT) builds against lib 7, and portions +# of it rely on lib-7-specific API. +# +# * The bar component pinned to foo 1.3.0-SNAPSHOT builds against lib 8; it +# compiles with passing tests because bar only invokes portions of the foo +# API which do not require lib-7-specific API. +# +# In this scenario, it is lib 8 that is actually deployed at runtime with the +# app, so parts of foo will be broken, even though both foo and bar build with +# passing tests individually. +# +# This "melting pot" build seeks to overcome many of these issues by unifying +# all components of the app into a single multi-module build, with all +# versions uniformly pinned to the ones that will actually be deployed at +# runtime. +# +# This goal is achieved by synthesizing a multi-module build including all +# affected components (or optionally, all components period) of the specific +# project, and then executing a Maven build with uniformly overridden versions +# of all components to the ones resolved for the project itself. +# +# IMPORTANT IMPLEMENTATION DETAIL! The override works by setting a version +# property for each component of the form "artifactId.version"; it is assumed +# that all components declare their dependencies using version properties of +# this form. E.g.: +# +# +# com.google.guava +# guava +# ${guava.version} +# +# +# Using dependencyManagement is fine too, as long as it then uses this pattern +# to declare the versions as properties, which can be overridden. +# +# Any dependency which does not declare a version property matching this +# assumption will not be properly overridden in the melting pot! +# +# Author: Curtis Rueden +# ============================================================================ + +# -- Functions -- + +stderr() { + >&2 echo "$@" +} + +debug() { + test "$debug" && + stderr "+ $@" +} + +info() { + test "$verbose" && + stderr "[INFO] $@" +} + +error() { + stderr "[ERROR] $@" +} + +unknownArg() { + error "Unknown option: $@" + usage=1 +} + +checkPrereqs() { + while [ $# -gt 0 ] + do + which $1 > /dev/null 2> /dev/null + test $? -ne 0 && echo "Missing prerequisite: $1" && exit 255 + shift + done +} + +verifyPrereqs() { + checkPrereqs git mvn xmllint +} + +parseArguments() { + while [ $# -gt 0 ] + do + case "$1" in + -b|--branch) + branch="$2" + shift + ;; + -c|--changes) + changes="$2" + shift + ;; + -i|--includes) + includes="$2" + shift + ;; + -e|--excludes) + excludes="$2" + shift + ;; + -r|--remoteRepos) + remoteRepos="$2" + shift + ;; + -l|--localRepo) + repoBase="$2" + shift + ;; + -o|--outputDir) + outputDir="$2" + shift + ;; + -p|--prune) + prune=1 + ;; + -v|--verbose) + verbose=1 + ;; + -d|--debug) + debug=1 + ;; + -f|--force) + force=1 + ;; + -s|--skipBuild) + skipBuild=1 + ;; + -h|--help) + usage=1 + ;; + -*) + unknownArg "$1" + ;; + *) + test -z "$project" && project="$1" || + unknownArg "$1" + ;; + esac + shift + done + + test -z "$project" -a -z "$usage" && + error "No project specified!" && usage=1 + + if [ "$usage" ] + then + echo "Usage: $(basename "$0") [-b ] [-c ] \\ + [-i ] [-e ] [-r ] [-l ] [-o ] [-pvfsh] + + + The project to build, including dependencies, with consistent versions. +-b, --branch + Override the branch/tag of the project to build. By default, + the branch used will be the tag named \"artifactId-version\". +-c, --changes + Comma-separated list of GAVs to inject into the project, replacing + normal versions. E.g.: \"com.mycompany:myartifact:1.2.3-SNAPSHOT\" +-i, --includes + Comma-separated list of GAs (no version; wildcards OK for G or A) to + include in the build. All by default. E.g.: \"mystuff:*,myotherstuff:*\" +-e, --excludes + Comma-separated list of GAs (no version; wildcards OK for G or A) to + exclude from the build. E.g.: \"mystuff:extraneous,mystuff:irrelevant\" +-r, --remoteRepos + Comma-separated list of additional remote Maven repositories to check + for artifacts, in the format id::[layout]::url or just url. +-l, --localRepos + Overrides the directory of the Maven local repository cache. +-o, --outputDir + Overrides the output directory. The default is \"melting-pot\". +-p, --prune + Build only the components which themselves depend on a changed + artifact. This will make the build much faster, at the expense of + not fully testing runtime compatibility across all components. +-v, --verbose + Enable verbose/debugging output. +-f, --force + Wipe out the output directory if it already exists. +-s, --skipBuild + Skips the final build step. Useful for automated testing. +-h, --help + Display this usage information." + exit 1 + fi + + # Assign default parameter values. + test "$outputDir" || outputDir="melting-pot" + test "$repoBase" || repoBase="$HOME/.m2/repository" +} + +createDir() { + test -z "$force" -a -e "$1" && + error "Directory already exists: $1" && exit 2 + + rm -rf "$1" + mkdir -p "$1" + cd "$1" +} + +groupId() { + echo "${1%%:*}" +} + +artifactId() { + local result="${1#*:}" # strip groupId + echo "${result%%:*}" +} + +version() { + local result="${1#*:}" # strip groupId + case "$result" in + *:*) + result="${result#*:}" # strip artifactId + case "$result" in + *:*:*:*) + # G:A:P:C:V:S + result="${result#*:}" # strip packaging + result="${result#*:}" # strip classifier + ;; + *:*:*) + # G:A:P:V:S + result="${result#*:}" # strip packaging + ;; + *) + # G:A:V or G:A:V:? + ;; + esac + echo "${result%%:*}" + ;; + esac +} + +# Converts the given GAV into a path in the local repository cache. +repoPath() { + local gPath="$(echo "$(groupId "$1")" | tr :. /)" + local aPath="$(artifactId "$1")" + local vPath="$(version "$1")" + echo "$repoBase/$gPath/$aPath/$vPath" +} + +# Gets the path to the given GAV's POM file in the local repository cache. +pomPath() { + local pomFile="$(artifactId "$1")-$(version "$1").pom" + echo "$(repoPath "$1")/$pomFile" +} + +# Fetches the POM for the given GAV into the local repository cache. +downloadPOM() { + local g="$(groupId "$1")" + local a="$(artifactId "$1")" + local v="$(version "$1")" + debug "mvn dependency:get \\ + -DrepoUrl=\"$remoteRepos\" \\ + -DgroupId=\"$g\" \\ + -DartifactId=\"$a\" \\ + -Dversion=\"$v\" \\ + -Dpackaging=pom" + mvn dependency:get \ + -DrepoUrl="$remoteRepos" \ + -DgroupId="$g" \ + -DartifactId="$a" \ + -Dversion="$v" \ + -Dpackaging=pom > /dev/null +} + +# Gets the POM path for the given GAV, ensuring it exists locally. +pom() { + local pomPath="$(pomPath "$1")" + test -f "$pomPath" || downloadPOM "$1" + echo "$pomPath" +} + +# For the given XML file on disk ($1), gets the value of the +# specified XPath expression of the form "//$2/$3/$4/...". +xpath() { + local xmlFile="$1" + shift + local xpath="/" + while [ $# -gt 0 ] + do + # NB: Ignore namespace issues; see: http://stackoverflow.com/a/8266075 + xpath="$xpath/*[local-name()='$1']" + shift + done + debug "xmllint --xpath \"$xpath\" \"$xmlFile\"" + xmllint --xpath "$xpath" "$xmlFile" 2> /dev/null | + sed -E 's/^[^>]*>(.*)<[^<]*$/\1/' +} + +# For the given GAV ($1), recursively gets the value of the +# specified XPath expression of the form "//$2/$3/$4/...". +pomValue() { + local pomPath="$(pom "$1")" + shift + local value="$(xpath "$pomPath" $@)" + if [ "$value" ] + then + echo "$value" + else + # Path not found in POM; look in the parent POM. + local pg="$(xpath "$pomPath" project parent groupId)" + if [ "$pg" ] + then + # There is a parent POM declaration in this POM. + local pa="$(xpath "$pomPath" project parent artifactId)" + local pv="$(xpath "$pomPath" project parent version)" + pomValue "$pg:$pa:$pv" $@ + fi + fi +} + +# Gets the SCM URL for the given GAV. +scmURL() { + pomValue "$1" project scm connection | sed -E 's/^scm:git://' +} + +# Gets the SCM tag for the given GAV. +scmTag() { + echo "$(artifactId "$1")-$(version "$1")" +} + +# Fetches the source code for the given GAV. Returns the directory. +retrieveSource() { + local scmURL="$(scmURL "$1")" + local scmBranch + test "$2" && scmBranch="$2" || scmBranch="$(scmTag "$1")" + local dir="$(groupId "$1")/$(artifactId "$1")" + debug "git clone \"$scmURL\" --branch \"$scmBranch\" --depth 1 \"$dir\"" + git clone "$scmURL" --branch "$scmBranch" --depth 1 "$dir" 2> /dev/null + echo "$dir" +} + +# Gets the list of dependencies for the project in the CWD. +deps() { + cd "$1" + debug "mvn dependency:list" + mvn dependency:list | + grep '^\[INFO\] [^ ]' | sed 's/\[INFO\] //' | sort + cd - > /dev/null +} + +# Checks whether the given GA(V) matches the specified filter pattern. +gaMatch() { + local ga="$1" + local filter="$2" + local g="$(groupId "$ga")" + local a="$(artifactId "$ga")" + local fg="$(groupId "$filter")" + local fa="$(artifactId "$filter")" + test "$fg" = "$g" -o "$fg" = "*" || return + test "$fa" = "$a" -o "$fa" = "*" || return + echo 1 +} + +# Determines whether the given GA(V) version is being overridden. +isChanged() { + local IFS="," + + local change + for change in $changes + do + test "$(gaMatch "$1" "$change")" && echo 1 && return + done +} + +# Determines whether the given GA(V) meets the inclusion criteria. +isIncluded() { + # do not include the changed artifacts we are testing against + test "$(isChanged "$1")" && return + + local IFS="," + + # ensure GA is not excluded + local exclude + for exclude in $excludes + do + test "$(gaMatch "$1" "$exclude")" && return + done + + # ensure GA is included + test -z "$includes" && echo 1 && return + local include + for include in $includes + do + test "$(gaMatch "$1" "$include")" && echo 1 && return + done +} + +# Deletes components which do not depend on a changed GAV. +pruneReactor() { + local dir + for dir in */* + do + info "Checking relevance of component $dir" + local deps="$(deps "$dir")" + + # Determine whether the component depends on a changed GAV. + local keep + unset keep + local dep + for dep in $deps + do + test "$(isChanged "$dep")" && keep=1 && break + done + + # If the component is irrelevant, prune it. + if [ -z "$keep" ] + then + info "Pruning irrelevant component: $dir" + rm -rf "$dir" + fi + done +} + +# Tests if the given directory contains the appropriate source code. +isProject() { + local a="$(xpath "$1/pom.xml" project artifactId)" + test "$a" = "$(basename "$1")" && echo 1 +} + +# Generates an aggregator POM for all modules in the current directory. +generatePOM() { + echo '' > pom.xml + echo '> pom.xml + echo ' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"' >> pom.xml + echo ' xsi:schemaLocation="http://maven.apache.org/POM/4.0.0' >> pom.xml + echo ' http://maven.apache.org/xsd/maven-4.0.0.xsd">' >> pom.xml + echo ' 4.0.0' >> pom.xml + echo >> pom.xml + echo ' melting-pot' >> pom.xml + echo ' melting-pot' >> pom.xml + echo ' 0.0.0-SNAPSHOT' >> pom.xml + echo ' pom' >> pom.xml + echo >> pom.xml + echo ' Melting Pot' >> pom.xml + echo >> pom.xml + echo ' ' >> pom.xml + local dir + for dir in */* + do + if [ "$(isProject "$dir")" ] + then + echo " $dir" >> pom.xml + else + # Check for a child component of a multi-module project. + local childDir="$dir/$(basename "$dir")" + test "$(isProject "$childDir")" && + echo " $childDir" >> pom.xml + fi + done + echo ' ' >> pom.xml + echo '' >> pom.xml +} + +# Creates and tests an appropriate multi-module reactor for the given project. +# All relevant dependencies which match the inclusion criteria are linked into +# the multi-module build, with each changed GAV overridding the originally +# specified version for the corresponding GA. +meltDown() { + # Fetch the project source code. + info "$1: fetching project source" + local dir="$(retrieveSource "$1" "$branch")" + test ! -d "$dir" && error "Could not fetch project source" && exit 3 + + # Get the project dependencies. + info "$1: determining project dependencies" + local deps="$(deps "$dir")" + + local args="-Denforcer.skip" + + # Process the dependencies. + info "$1: processing project dependencies" + local dep + for dep in $deps + do + local g="$(groupId "$dep")" + local a="$(artifactId "$dep")" + local v="$(version "$dep")" + local gav="$g:$a:$v" + + test -z "$(isChanged "$gav")" && + args="$args -D$a.version=$v" + + if [ "$(isIncluded "$gav")" ] + then + info "$1: $a: fetching component source" + dir="$(retrieveSource "$gav")" + fi + done + + # Override versions of changed GAVs. + info "$1: processing changed components" + local TLS=, + local gav + for gav in $changes + do + local a="$(artifactId "$gav")" + local v="$(version "$gav")" + args="$args -D$a.version=$v" + done + unset TLS + + # Prune the build, if applicable. + test "$prune" && pruneReactor + + # Generate the aggregator POM. + info "Generating aggregator POM" + generatePOM + + # Build everything. + if [ "$skipBuild" ] + then + info "Skipping the build; the command would have been:" + info "mvn $args test" + else + info "Building the project!" + # NB: All code is fresh; no need to clean. + debug "mvn $args test" + mvn $args test + fi + + info "$1: complete" +} + +# -- Main -- + +verifyPrereqs +parseArguments $@ +createDir "$outputDir" +meltDown "$project" diff --git a/tests/melting-pot-multi.t b/tests/melting-pot-multi.t new file mode 100644 index 0000000..0c87511 --- /dev/null +++ b/tests/melting-pot-multi.t @@ -0,0 +1,29 @@ +Test that recursive SCM retrieval and multi-module projects work: + + $ sh "$TESTDIR/../melting-pot.sh" sc.fiji:TrakEM2_:1.0f -r http://maven.imagej.net/content/groups/public -i 'sc.fiji:TrakEM2_' -v -s -d -f + [INFO] sc.fiji:TrakEM2_:1.0f: fetching project source + \+ xmllint --xpath ".*'project'.*'scm'.*'connection'.*" ".*/sc/fiji/TrakEM2_/1.0f/TrakEM2_-1.0f.pom" (re) + \+ xmllint --xpath ".*'project'.*'parent'.*'groupId'.*" ".*/sc/fiji/TrakEM2_/1.0f/TrakEM2_-1.0f.pom" (re) + \+ xmllint --xpath ".*'project'.*'parent'.*'artifactId'.*" ".*/sc/fiji/TrakEM2_/1.0f/TrakEM2_-1.0f.pom" (re) + \+ xmllint --xpath ".*'project'.*'parent'.*'version'.*" ".*/sc/fiji/TrakEM2_/1.0f/TrakEM2_-1.0f.pom" (re) + \+ xmllint --xpath ".*'project'.*'scm'.*'connection'.*" ".*/sc/fiji/pom-trakem2/1.3.2/pom-trakem2-1.3.2.pom" (re) + + git clone "git://github.com/trakem2/TrakEM2" --branch "TrakEM2_-1.0f" --depth 1 "sc.fiji/TrakEM2_" + [INFO] sc.fiji:TrakEM2_:1.0f: determining project dependencies + + mvn dependency:list + [INFO] sc.fiji:TrakEM2_:1.0f: processing project dependencies + [INFO] sc.fiji:TrakEM2_:1.0f: processing changed components + [INFO] Generating aggregator POM + + xmllint --xpath "//*[local-name()='project']/*[local-name()='artifactId']" "sc.fiji/TrakEM2_/pom.xml" + + xmllint --xpath "//*[local-name()='project']/*[local-name()='artifactId']" "sc.fiji/TrakEM2_/TrakEM2_/pom.xml" + [INFO] Skipping the build; the command would have been: + [INFO] mvn -Denforcer.skip -Dbatik.version=1.8 -Dlogback-classic.version=1.1.1 -Dlogback-core.version=1.1.1 -Dkryo.version=2.21 -Dgentyref.version=1.1.0 -Djgoodies-common.version=1.7.0 -Djgoodies-forms.version=1.7.2 -Djai-codec.version=1.1.3 -Dtools.version=1.4.2 -Dtools.version=1.4.2 -Dmines-jtk.version=20100113 -Dudunits.version=4.3.18 -Djama.version=1.0.3 -Djama.version=1.0.3 -Dj3d-core-utils.version=1.5.2 -Dj3d-core.version=1.5.2 -Dvecmath.version=1.5.2 -Djai-core.version=1.1.3 -Djoda-time.version=2.3 -Djunit.version=4.11 -Dmpicbg.version=1.0.1 -Dmpicbg.version=1.0.1 -Dmpicbg_.version=1.0.1 -Dij1-patcher.version=0.12.0 -Dij.version=1.49p -Dij.version=1.49p -Dimagej-common.version=0.12.2 -Dimglib2-ij.version=2.0.0-beta-30 -Dimglib2-roi.version=0.3.0 -Dimglib2.version=2.2.1 -Dtrove4j.version=3.0.3 -Dnone.version= -Dformats-api.version=5.0.7 -Dformats-bsd.version=5.0.7 -Dformats-common.version=5.0.7 -Djai_imageio.version=5.0.7 -Dome-xml.version=5.0.7 -Dspecification.version=5.0.7 -Dturbojpeg.version=5.0.7 -Dcommons-math3.version=3.4.1 -Deventbus.version=1.4 -Dhamcrest-core.version=1.3 -Djavassist.version=3.16.1-GA -Djcommon.version=1.0.23 -Djfreechart.version=1.0.19 -Dperf4j.version=0.9.13 -Djython-shaded.version=2.5.3 -Dnative-lib-loader.version=2.0.2 -Dscijava-common.version=2.39.0 -Dslf4j-api.version=1.7.6 -Dpostgresql.version=8.2-507.jdbc3 -D3D_Viewer.version=3.0.1 -DAnalyzeSkeleton_.version=2.0.4 -DFiji_Plugins.version=3.0.0 -DLasso_and_Blow_Tool.version=2.0.1 -DSimple_Neurite_Tracer.version=2.0.3 -DSkeletonize3D_.version=1.0.1 -DVIB-lib.version=2.0.1 -DVIB_.version=2.0.2 -DVectorString.version=1.0.2 -DbUnwarpJ_.version=2.6.2 -Dfiji-lib.version=2.1.0 -Dlegacy-imglib1.version=1.1.2-DEPRECATED -Dlevel_sets.version=1.0.1 -Dmpicbg-trakem2.version=1.2.2 -Dpal-optimization.version=2.0.0 test + [INFO] sc.fiji:TrakEM2_:1.0f: complete + + $ find melting-pot -maxdepth 2 | sort + melting-pot + melting-pot/pom.xml + melting-pot/sc.fiji + melting-pot/sc.fiji/TrakEM2_ + + $ grep 'sc.fiji/TrakEM2_/TrakEM2_' melting-pot/pom.xml + \t\tsc.fiji/TrakEM2_/TrakEM2_ (esc) diff --git a/tests/melting-pot-out-dir.t b/tests/melting-pot-out-dir.t new file mode 100644 index 0000000..2a236ae --- /dev/null +++ b/tests/melting-pot-out-dir.t @@ -0,0 +1,5 @@ +Script should fail if output directory already exists: + + $ mkdir melting-pot && sh "$TESTDIR/../melting-pot.sh" foo:bar + [ERROR] Directory already exists: melting-pot + [2] diff --git a/tests/melting-pot-prune.t b/tests/melting-pot-prune.t new file mode 100644 index 0000000..e1c6d6b --- /dev/null +++ b/tests/melting-pot-prune.t @@ -0,0 +1,25 @@ +Test that the '--prune' flag works as intended: + + $ sh "$TESTDIR/../melting-pot.sh" net.imagej:imagej-common:0.15.1 -r http://maven.imagej.net/content/groups/public -c org.scijava:scijava-common:2.44.2 -i 'org.scijava:*,net.imagej:*,net.imglib2:*' -p -v -f -s + [INFO] net.imagej:imagej-common:0.15.1: fetching project source + [INFO] net.imagej:imagej-common:0.15.1: determining project dependencies + [INFO] net.imagej:imagej-common:0.15.1: processing project dependencies + [INFO] net.imagej:imagej-common:0.15.1: imglib2-roi: fetching component source + [INFO] net.imagej:imagej-common:0.15.1: imglib2: fetching component source + [INFO] net.imagej:imagej-common:0.15.1: processing changed components + [INFO] Checking relevance of component net.imagej/imagej-common + [INFO] Checking relevance of component net.imglib2/imglib2 + [INFO] Pruning irrelevant component: net.imglib2/imglib2 + [INFO] Checking relevance of component net.imglib2/imglib2-roi + [INFO] Pruning irrelevant component: net.imglib2/imglib2-roi + [INFO] Generating aggregator POM + [INFO] Skipping the build; the command would have been: + [INFO] mvn -Denforcer.skip -Dgentyref.version=1.1.0 -Dudunits.version=4.3.18 -Djunit.version=4.11 -Dimglib2-roi.version=0.3.0 -Dimglib2.version=2.2.1 -Dtrove4j.version=3.0.3 -Deventbus.version=1.4 -Dhamcrest-core.version=1.3 -Dscijava-common.version=2.44.2 test + [INFO] net.imagej:imagej-common:0.15.1: complete + + $ find melting-pot -maxdepth 2 | sort + melting-pot + melting-pot/net.imagej + melting-pot/net.imagej/imagej-common + melting-pot/net.imglib2 + melting-pot/pom.xml diff --git a/tests/melting-pot-simple.t b/tests/melting-pot-simple.t new file mode 100644 index 0000000..6e817b6 --- /dev/null +++ b/tests/melting-pot-simple.t @@ -0,0 +1,20 @@ +Down-the-middle test of a relatively simply project: + + $ sh "$TESTDIR/../melting-pot.sh" net.imagej:imagej-common:0.15.1 -r http://maven.imagej.net/content/groups/public -c org.scijava:scijava-common:2.44.2 -i 'org.scijava:*,net.imagej:*,net.imglib2:*,io.scif:*' -e net.imglib2:imglib2-roi -v -f -s + [INFO] net.imagej:imagej-common:0.15.1: fetching project source + [INFO] net.imagej:imagej-common:0.15.1: determining project dependencies + [INFO] net.imagej:imagej-common:0.15.1: processing project dependencies + [INFO] net.imagej:imagej-common:0.15.1: imglib2: fetching component source + [INFO] net.imagej:imagej-common:0.15.1: processing changed components + [INFO] Generating aggregator POM + [INFO] Skipping the build; the command would have been: + [INFO] mvn -Denforcer.skip -Dgentyref.version=1.1.0 -Dudunits.version=4.3.18 -Djunit.version=4.11 -Dimglib2-roi.version=0.3.0 -Dimglib2.version=2.2.1 -Dtrove4j.version=3.0.3 -Deventbus.version=1.4 -Dhamcrest-core.version=1.3 -Dscijava-common.version=2.44.2 test + [INFO] net.imagej:imagej-common:0.15.1: complete + + $ find melting-pot -maxdepth 2 | sort + melting-pot + melting-pot/net.imagej + melting-pot/net.imagej/imagej-common + melting-pot/net.imglib2 + melting-pot/net.imglib2/imglib2 + melting-pot/pom.xml diff --git a/tests/readme.txt b/tests/readme.txt new file mode 100644 index 0000000..91db61b --- /dev/null +++ b/tests/readme.txt @@ -0,0 +1,5 @@ +This directory houses automated tests for use with cram. + + https://bitheap.org/cram/ + +To run them, type "cram tests" from the toplevel directory.