Skip to content

Commit ee5c43a

Browse files
committed
WIP: Support releasing within a multi-module repo
THIS IS NOT YET FUNCTIONAL. It is a first-cut AI-supported modification to release-version.sh that implements an approach we think is ultimately going to work, but still needs refinement and testing. Bugs: - the version prompt logic happens before the multi-module detection - reverting the snapshot-to-release prep commit is insufficient: we also need to bump the released component version snapshot to next dev version everywhere it is a dependency in other modules The workflow is to release only one module per invocation. The steps are: 1. comment out all modules other than the one being released 2. roll back the target module's SNAPSHOT deps to newest release versions 3. run mvn release:prepare with the -pl flag pointing at target module - this excludes the aggregator itself from the reactor, to avoid future useless scijava-aggregator POMs on Central 4. squash the release + prep + bump commits into one on the main branch 5. continue business as usual: push main, rewrite release tag and push The ci-build.sh probably still needs modification to use -pl as well. Open questions: - is -pl with release:prepare really needed? or only at perform step? - do we squash the release prep commits into a single release commit? - or do we leave them as a sequence on the orphaned tag?
1 parent c51053a commit ee5c43a

File tree

1 file changed

+146
-8
lines changed

1 file changed

+146
-8
lines changed

release-version.sh

Lines changed: 146 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -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

3555
SCIJAVA_BASE_REPOSITORY=-DaltDeploymentRepository=scijava.releases::default::dav:https://maven.scijava.org/content/repositories
@@ -119,8 +139,16 @@ Options include:
119139
debug "Extracting project details"
120140

121141
echoArg='${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+
124152
test $? -eq 0 || die "Could not extract version from pom.xml. Error follows:\n$projectDetails"
125153
printf '%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,
213241
try 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.
217269
REMOTE="${REMOTE:-$remote}"
218270

@@ -314,6 +366,37 @@ then
314366
-m 'The Discourse software updated the tags path from /tags/ to /tag/.'
315367
fi
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.
318401
test "$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.:
330413
Alternately, 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).
334431
debug "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.
339436
Use "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!"
348445
fi
349-
$DRY_RUN git reset --soft HEAD^^ &&
350-
if ! git diff-index --cached --quiet --ignore-submodules HEAD --
446+
447+
if test "$IS_AGGREGATOR"
351448
then
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
353480
fi &&
354481

355482
# Extract the name of the new tag.
@@ -361,7 +488,7 @@ else
361488
tag="<tag>"
362489
fi &&
363490

364-
# Rewrite the tag to include release.properties.
491+
# Rewrite the tag to include release.properties (and filtered aggregator for multi-module).
365492
debug "Rewriting tag to include release.properties"
366493
test -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

Comments
 (0)