This is an automated email from the ASF dual-hosted git repository. royteeuwen pushed a commit to branch feature/SLING-13253-update-dist-same-major in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-committer-cli.git
commit 6ae0e2ddeb1a98ba6f3d38966cbafd474d3a4987 Author: Roy Teeuwen <[email protected]> AuthorDate: Mon Aug 3 18:18:57 2026 +0200 SLING-13253 - update-dist: only remove the previous release of the same major version Auto-deducing the release to remove from dist/release picked the closest older version regardless of major, so releasing the first version of a new major line would delete the still-maintained previous line. Restrict the candidates to the major version being released. --- .../sling/cli/impl/release/FinalizeCommand.java | 3 +- .../sling/cli/impl/release/UpdateDistCommand.java | 24 ++++++---- .../cli/impl/release/UpdateDistCommandTest.java | 55 ++++++++++++++++++++++ 3 files changed, 71 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/apache/sling/cli/impl/release/FinalizeCommand.java b/src/main/java/org/apache/sling/cli/impl/release/FinalizeCommand.java index 44d4aaf..69f15fd 100644 --- a/src/main/java/org/apache/sling/cli/impl/release/FinalizeCommand.java +++ b/src/main/java/org/apache/sling/cli/impl/release/FinalizeCommand.java @@ -63,7 +63,8 @@ import picocli.CommandLine; * when the current user (resolved from the ASF credentials) is a PMC member and skipped otherwise. * When skipped, a PMC member must complete it separately (the {@code tally-votes} result email asks * for this when run by a non-PMC member). The previous version to remove from dist/release is - * deduced from the current contents of the release directory. + * deduced from the current contents of the release directory, restricted to the major version being + * released so parallel major version streams stay published. */ @Component( service = Command.class, diff --git a/src/main/java/org/apache/sling/cli/impl/release/UpdateDistCommand.java b/src/main/java/org/apache/sling/cli/impl/release/UpdateDistCommand.java index dcdba3c..76d45dc 100644 --- a/src/main/java/org/apache/sling/cli/impl/release/UpdateDistCommand.java +++ b/src/main/java/org/apache/sling/cli/impl/release/UpdateDistCommand.java @@ -97,7 +97,8 @@ public class UpdateDistCommand implements Command { @CommandLine.Option( names = {"--previous-version"}, description = "Previous release version to remove from dist/release (e.g. 1.0.0)." - + " Optional: if omitted, the closest older version currently in dist/release is removed.") + + " Optional: if omitted, the closest older version with the same major version currently in" + + " dist/release is removed; other major version streams are left untouched.") private String previousVersion; @CommandLine.Mixin @@ -290,10 +291,11 @@ public class UpdateDistCommand implements Command { /** * Determines which files to remove from {@code dist/release} when publishing {@code newVersion} * of {@code artifactId}. When {@code explicitPreviousVersion} is given, only that version's files - * are returned. Otherwise only the <em>closest older</em> version's files are returned — the highest - * version strictly lower than {@code newVersion} currently present for this artifact. This keeps - * parallel maintenance streams intact (publishing {@code 2.0.4} removes {@code 2.0.2} but keeps - * {@code 1.2.4}) and never removes a newer version. + * are returned. Otherwise only the <em>closest older version with the same major version</em> is + * returned — the highest version strictly lower than {@code newVersion} sharing its major. This + * keeps parallel maintenance streams intact (publishing {@code 1.2.16} removes {@code 1.2.14} but + * keeps {@code 2.1.0}, and publishing {@code 2.1.2} leaves {@code 1.2.14} alone) and never removes + * a newer version. */ static List<String> listPreviousReleaseFiles(String artifactId, String newVersion, String explicitPreviousVersion) throws IOException { @@ -305,7 +307,7 @@ public class UpdateDistCommand implements Command { // right after the prefix excludes sibling artifacts such as artifactId-extra-...) .filter(f -> isVersionedArtifactFile(f, artifactId)) .toList(); - String previousVersion = closestOlderVersion(artifactFiles, artifactId, newVersion); + String previousVersion = closestOlderVersionInSameMajor(artifactFiles, artifactId, newVersion); if (previousVersion == null) { return List.of(); } @@ -315,10 +317,12 @@ public class UpdateDistCommand implements Command { } /** - * Returns the highest version among {@code artifactFiles} that is strictly lower than - * {@code newVersion}, or {@code null} if there is none. + * Returns the highest version among {@code artifactFiles} that shares {@code newVersion}'s major + * version and is strictly lower than it, or {@code null} if there is none. Versions from other + * major streams are never candidates, so an older major line stays published. */ - private static String closestOlderVersion(List<String> artifactFiles, String artifactId, String newVersion) { + private static String closestOlderVersionInSameMajor( + List<String> artifactFiles, String artifactId, String newVersion) { org.osgi.framework.Version target = parseOsgiVersion(newVersion); if (target == null) { return null; @@ -328,7 +332,7 @@ public class UpdateDistCommand implements Command { for (String file : artifactFiles) { String candidateName = extractVersion(file, artifactId); org.osgi.framework.Version candidate = parseOsgiVersion(candidateName); - if (candidate == null || candidate.compareTo(target) >= 0) { + if (candidate == null || candidate.getMajor() != target.getMajor() || candidate.compareTo(target) >= 0) { continue; } if (closestVersion == null || candidate.compareTo(closestVersion) > 0) { diff --git a/src/test/java/org/apache/sling/cli/impl/release/UpdateDistCommandTest.java b/src/test/java/org/apache/sling/cli/impl/release/UpdateDistCommandTest.java index 07d4e0a..05fd408 100644 --- a/src/test/java/org/apache/sling/cli/impl/release/UpdateDistCommandTest.java +++ b/src/test/java/org/apache/sling/cli/impl/release/UpdateDistCommandTest.java @@ -150,6 +150,61 @@ public class UpdateDistCommandTest { } } + @Test + public void testAutoDeduceRemovesOnlySameMajorVersion() throws Exception { + // publishing 1.2.16 must remove 1.2.14 and leave the 2.x stream untouched + List<String> releaseDir = List.of( + ARTIFACT + "-1.2.14.pom", + ARTIFACT + "-1.2.14-source-release.zip", + ARTIFACT + "-2.1.0.pom", + ARTIFACT + "-2.1.0-source-release.zip"); + try (MockedStatic<UpdateDistCommand> dist = mockStatic(UpdateDistCommand.class, CALLS_REAL_METHODS)) { + dist.when(() -> UpdateDistCommand.listDistFiles(eq(UpdateDistCommand.DIST_RELEASE_URL), anyString())) + .thenReturn(releaseDir); + + List<String> old = UpdateDistCommand.listPreviousReleaseFiles(ARTIFACT, "1.2.16", null); + + assertEquals(2, old.size()); + assertTrue(old.contains(ARTIFACT + "-1.2.14.pom")); + assertTrue(old.contains(ARTIFACT + "-1.2.14-source-release.zip")); + assertFalse(old.contains(ARTIFACT + "-2.1.0.pom")); + assertFalse(old.contains(ARTIFACT + "-2.1.0-source-release.zip")); + } + } + + @Test + public void testAutoDeduceIgnoresOlderMajorVersions() throws Exception { + // publishing 2.1.2 must remove 2.1.0 and never touch the older 1.x stream + List<String> releaseDir = + List.of(ARTIFACT + "-1.2.14.pom", ARTIFACT + "-2.1.0.pom", ARTIFACT + "-2.1.0-source-release.zip"); + try (MockedStatic<UpdateDistCommand> dist = mockStatic(UpdateDistCommand.class, CALLS_REAL_METHODS)) { + dist.when(() -> UpdateDistCommand.listDistFiles(eq(UpdateDistCommand.DIST_RELEASE_URL), anyString())) + .thenReturn(releaseDir); + + List<String> old = UpdateDistCommand.listPreviousReleaseFiles(ARTIFACT, "2.1.2", null); + + assertEquals(2, old.size()); + assertTrue(old.contains(ARTIFACT + "-2.1.0.pom")); + assertTrue(old.contains(ARTIFACT + "-2.1.0-source-release.zip")); + assertFalse(old.contains(ARTIFACT + "-1.2.14.pom")); + } + } + + @Test + public void testAutoDeduceKeepsOlderMajorWhenNoSameMajorPredecessorExists() throws Exception { + // the first release of a new major stream: nothing in dist/release shares its major, so the + // previous major line stays published (it is still maintained separately) + List<String> releaseDir = List.of(ARTIFACT + "-1.2.14.pom", ARTIFACT + "-1.2.14-source-release.zip"); + try (MockedStatic<UpdateDistCommand> dist = mockStatic(UpdateDistCommand.class, CALLS_REAL_METHODS)) { + dist.when(() -> UpdateDistCommand.listDistFiles(eq(UpdateDistCommand.DIST_RELEASE_URL), anyString())) + .thenReturn(releaseDir); + + List<String> old = UpdateDistCommand.listPreviousReleaseFiles(ARTIFACT, "2.0.0", null); + + assertTrue("a different major version must never be removed", old.isEmpty()); + } + } + @Test public void testExplicitPreviousVersionWins() throws Exception { try (MockedStatic<UpdateDistCommand> dist = mockStatic(UpdateDistCommand.class, CALLS_REAL_METHODS)) {
