@@ -30,6 +30,26 @@ no_changes_pending() {
3030 git diff-index --cached --quiet --ignore-submodules HEAD --
3131}
3232
33+ # Get list of modules from aggregator POM
34+ get_modules () {
35+ grep -oP ' <module>\K[^<]+' pom.xml 2> /dev/null || true
36+ }
37+
38+ # Check if current directory is a multi-module aggregator
39+ is_aggregator () {
40+ test -f pom.xml && grep -q ' <modules>' pom.xml
41+ }
42+
43+ # Resolve snapshot dependencies to latest releases (TODO for later)
44+ resolve_snapshot_deps () {
45+ module_pom=$1
46+ debug " Resolving snapshot dependencies in $module_pom "
47+ echo " TODO: Implement automatic snapshot dependency resolution"
48+ echo " For now, please manually update any *.version properties to releases"
49+ echo " Press enter when ready to continue..."
50+ read
51+ }
52+
3353# -- Constants and settings --
3454
3555SCIJAVA_BASE_REPOSITORY=-DaltDeploymentRepository=scijava.releases::default::dav:https://maven.scijava.org/content/repositories
@@ -119,8 +139,16 @@ Options include:
119139debug " Extracting project details"
120140
121141echoArg=' ${project.version}:${license.licenseName}:${project.parent.groupId}:${project.parent.artifactId}:${project.parent.version}'
122- projectDetails=$( mvn -B -N -Dexec.executable=echo -Dexec.args=" $echoArg " exec:exec -q)
123- test $? -eq 0 || projectDetails=$( mvn -B -U -N -Dexec.executable=echo -Dexec.args=" $echoArg " exec:exec -q)
142+
143+ if test " $IS_AGGREGATOR "
144+ then
145+ projectDetails=$( mvn -B -N -f " $MODULE_NAME /pom.xml" -Dexec.executable=echo -Dexec.args=" $echoArg " exec:exec -q)
146+ test $? -eq 0 || projectDetails=$( mvn -B -U -N -f " $MODULE_NAME /pom.xml" -Dexec.executable=echo -Dexec.args=" $echoArg " exec:exec -q)
147+ else
148+ projectDetails=$( mvn -B -N -Dexec.executable=echo -Dexec.args=" $echoArg " exec:exec -q)
149+ test $? -eq 0 || projectDetails=$( mvn -B -U -N -Dexec.executable=echo -Dexec.args=" $echoArg " exec:exec -q)
150+ fi
151+
124152test $? -eq 0 || die " Could not extract version from pom.xml. Error follows:\n$projectDetails "
125153printf ' %s' " $projectDetails \n" | grep -Fqv ' [ERROR]' ||
126154 die " Error extracting version from pom.xml. Error follows:\n$projectDetails "
@@ -213,6 +241,30 @@ If you are certain you want to release from this branch,
213241try again with --skip-branch-check flag."
214242}
215243
244+ # -- Detect multi-module structure --
245+ debug " Detecting project structure"
246+
247+ IS_AGGREGATOR=
248+ MODULE_NAME=
249+
250+ if is_aggregator
251+ then
252+ IS_AGGREGATOR=t
253+ debug " Multi-module aggregator detected"
254+
255+ # Prompt for which module to release
256+ modules=$( get_modules)
257+ echo " Available modules:"
258+ echo " $modules " | sed ' s/^/ /'
259+ printf ' Which module to release?: '
260+ read MODULE_NAME
261+ test " $MODULE_NAME " || die ' Module name is required for aggregator releases'
262+
263+ # Validate module exists
264+ test -d " $MODULE_NAME " || die " Module directory '$MODULE_NAME ' not found"
265+ echo " $modules " | grep -qx " $MODULE_NAME " || die " Module '$MODULE_NAME ' not found in aggregator POM"
266+ fi
267+
216268# If REMOTE is unset, use branch's upstream remote by default.
217269REMOTE=" ${REMOTE:- $remote } "
218270
@@ -314,6 +366,37 @@ then
314366 -m ' The Discourse software updated the tags path from /tags/ to /tag/.'
315367fi
316368
369+ # For multi-module aggregators, prepare the release environment.
370+ if test " $IS_AGGREGATOR "
371+ then
372+ debug " Preparing multi-module release for $MODULE_NAME "
373+
374+ # Filter aggregator POM to only include this module
375+ $DRY_RUN awk -v module=" $MODULE_NAME " '
376+ /<modules>/,/<\/modules>/ {
377+ if ($0 ~ /<module>/) {
378+ if ($0 ~ module) {
379+ print
380+ } else {
381+ gsub(/<module>/, "<!-- <module>")
382+ gsub(/<\/module>/, "<\/module> -->")
383+ print
384+ }
385+ next
386+ }
387+ }
388+ { print }
389+ ' pom.xml > pom.xml.filtered
390+ $DRY_RUN mv pom.xml.filtered pom.xml
391+
392+ # Resolve snapshot dependencies
393+ resolve_snapshot_deps " $MODULE_NAME /pom.xml"
394+
395+ # Commit these preparation changes (Commit O)
396+ $DRY_RUN git add pom.xml " $MODULE_NAME /pom.xml"
397+ $DRY_RUN git commit -m " Prepare $MODULE_NAME for release: filter aggregator and resolve snapshot dependencies"
398+ fi
399+
317400# Ensure license headers are up-to-date.
318401test " $SKIP_LICENSE_UPDATE " -o -z " $licenseName " -o " $licenseName " = " N/A" || {
319402 debug " Ensuring that license headers are up-to-date"
@@ -330,10 +413,24 @@ exclude them by setting license.excludes in your POM; e.g.:
330413Alternately, try again with the --skip-license-update flag.'
331414}
332415
416+ # -- Set up multi-module arguments if needed --
417+ MAVEN_PL_ARGS=
418+ if test " $IS_AGGREGATOR "
419+ then
420+ debug " Configuring release:prepare for multi-module"
421+ MAVEN_PL_ARGS=" -pl $MODULE_NAME -DautoVersionSubmodules=false"
422+
423+ # Override tag name to include module name
424+ if test -z " $TAG "
425+ then
426+ TAG=" -Dtag=${MODULE_NAME} -${VERSION} "
427+ fi
428+ fi
429+
333430# Prepare new release without pushing (requires the release plugin >= 2.1).
334431debug " Preparing new release"
335432$DRY_RUN mvn $BATCH_MODE release:prepare -DpushChanges=false -Dresume=false $TAG \
336- $PROFILE $DEV_VERSION -DreleaseVersion=" $VERSION " \
433+ $PROFILE $DEV_VERSION -DreleaseVersion=" $VERSION " $MAVEN_PL_ARGS \
337434 " -Darguments=-Dgpg.skip=true ${EXTRA_ARGS# } " ||
338435 die ' The release preparation step failed -- look above for errors and fix them.
339436Use "mvn javadoc:javadoc | grep error" to check for javadoc syntax errors.'
@@ -346,10 +443,40 @@ then
346443 " $( git show -s --format=%s HEAD) " ||
347444 die " maven-release-plugin's commits are unexpectedly missing!"
348445fi
349- $DRY_RUN git reset --soft HEAD^^ &&
350- if ! git diff-index --cached --quiet --ignore-submodules HEAD --
446+
447+ if test " $IS_AGGREGATOR "
351448then
352- $DRY_RUN git commit -s -m " Bump to next development cycle"
449+ # For multi-module: revert the prep commit (O), then squash O+A+B+R
450+ debug " Reverting preparation commit and squashing"
451+
452+ # Current state: ...prev → O → A → B
453+ # Revert O to produce R
454+ $DRY_RUN git revert --no-edit HEAD~2 &&
455+
456+ # Now: ...prev → O → A → B → R
457+ # Squash the last 4 commits
458+ $DRY_RUN git reset --soft HEAD~4 &&
459+
460+ # Net changes staged: only module version bump (O+A+B+R = just the version change)
461+ if ! git diff-index --cached --quiet --ignore-submodules HEAD --
462+ then
463+ if test -z " $DRY_RUN "
464+ then
465+ next_version=$( grep ' <version>' " $MODULE_NAME /pom.xml" | head -1 | sed ' s/.*<version>\(.*\)<\/version>.*/\1/' )
466+ else
467+ next_version=" <next-version>"
468+ fi
469+ $DRY_RUN git commit -s -m " Bump to next development cycle
470+
471+ $MODULE_NAME : $VERSION → $next_version "
472+ fi
473+ else
474+ # Original single-module logic: squash A+B
475+ $DRY_RUN git reset --soft HEAD^^ &&
476+ if ! git diff-index --cached --quiet --ignore-submodules HEAD --
477+ then
478+ $DRY_RUN git commit -s -m " Bump to next development cycle"
479+ fi
353480fi &&
354481
355482# Extract the name of the new tag.
361488 tag=" <tag>"
362489fi &&
363490
364- # Rewrite the tag to include release.properties.
491+ # Rewrite the tag to include release.properties (and filtered aggregator for multi-module) .
365492debug " Rewriting tag to include release.properties"
366493test -n " $tag " &&
367494# HACK: SciJava projects use SSH (git@github.com:...) for developerConnection.
@@ -373,7 +500,18 @@ test -n "$tag" &&
373500$DRY_RUN sed -i.bak -e ' s|^scm.url=scm\\:git\\:git@github.com\\:|scm.url=scm\\:git\\:https\\://github.com/|' release.properties &&
374501$DRY_RUN rm release.properties.bak &&
375502$DRY_RUN git checkout " $tag " &&
376- $DRY_RUN git add -f release.properties &&
503+
504+ if test " $IS_AGGREGATOR "
505+ then
506+ # For multi-module: get the filtered aggregator from the parent commit (O)
507+ debug " Incorporating filtered aggregator into tag"
508+ $DRY_RUN git checkout HEAD~1 -- pom.xml &&
509+ $DRY_RUN git add -f release.properties pom.xml
510+ else
511+ # Original: just add release.properties
512+ $DRY_RUN git add -f release.properties
513+ fi &&
514+
377515$DRY_RUN git commit --amend --no-edit &&
378516$DRY_RUN git tag -d " $tag " &&
379517$DRY_RUN git tag " $tag " HEAD &&
0 commit comments