royteeuwen commented on code in PR #56:
URL: 
https://github.com/apache/sling-org-apache-sling-committer-cli/pull/56#discussion_r3890413659


##########
src/main/java/org/apache/sling/cli/impl/release/UpdateDistCommand.java:
##########
@@ -169,22 +189,50 @@ record DistReleasePlan(
      * Shared by this command and {@link FinalizeCommand} so the flow is not 
duplicated. When the version is
      * already present in {@code dist/release} the returned plan is marked 
{@link DistReleasePlan#alreadyPublished()}.
      */
-    static DistReleasePlan planDistRelease(
+    static List<DistReleasePlan> planDistRelease(
             RepositoryService repositoryService, StagingRepository repository, 
String previousVersion)
             throws IOException {
         LocalRepository localRepository = 
repositoryService.download(repository);
-        Artifact primary = localRepository.getArtifacts().stream()
+        List<Artifact> artifacts = localRepository.getArtifacts().stream()
                 .filter(a -> "pom".equals(a.getType()))
-                .findFirst()
-                .orElseThrow(() -> new IllegalStateException("No POM artifact 
found in staging repository"));
-        String artifactId = primary.getArtifactId();
-        String newVersion = primary.getVersion();
-        if (DistRepository.isVersionPublished(artifactId, newVersion)) {
-            return new DistReleasePlan(artifactId, newVersion, List.of(), 
List.of(), true);
+                .toList();
+
+        if (artifacts.isEmpty()) {
+            throw new IllegalStateException("No POM artifact found in staging 
repository");
+        }
+
+        List<DistReleasePlan> plans = artifacts.stream()
+                .filter(a -> {
+                    try {
+                        return 
DistRepository.isVersionPublished(a.getArtifactId(), a.getVersion());
+                    } catch (IOException e) {
+                        throw new UncheckedIOException(e);
+                    }
+                })
+                .map(a -> new DistReleasePlan(a.getArtifactId(), 
a.getVersion(), List.of(), List.of(), true))
+                .toList();
+
+        if (!plans.isEmpty()) {
+            return plans;
+        } else {
+            return artifacts.stream()
+                    .map(a -> {
+                        try {
+                            String artifactId = a.getArtifactId();
+                            String newVersion = a.getVersion();
+                            List<Path> newFiles = 
collectDownloadedFiles(localRepository.getRootFolder()).stream()
+                                    .filter(path ->
+                                            
path.getFileName().toString().startsWith(artifactId + "-" + newVersion))
+                                    .toList();
+                            List<String> oldFiles =
+                                    
DistRepository.listPreviousReleaseFiles(artifactId, newVersion, 
previousVersion);

Review Comment:
   **Blocking: `--previous-version` is broken for multi-artifact releases — it 
aborts the run half-way and lands you in the unrecoverable state from my other 
comment.**
   
   `listPreviousReleaseFiles` short-circuits on an explicit previous version 
and returns `listFiles(DIST_RELEASE_URL, artifactId + "-" + 
explicitPreviousVersion)` — it never consults `newVersion`. Since every plan 
here is handed the same single `previousVersion`, two plans for the same 
`artifactId` get an **identical `oldFiles` list**, both computed before any 
publish runs.
   
   Using this PR's own motivating scenario 
(`org.apache.sling.servlets.resolver` 2.12.0 + 3.0.10 staged together) with 
`--previous-version 2.11.4`:
   
   1. plan 1 commits: adds 2.12.0, deletes the 2.11.4 files
   2. plan 2 commits: `deleteEntry` on those same files, which no longer exist 
at HEAD
   
   I reproduced this against a real local SVN repo using the harness already in 
`UpdateDistCommandTest` (`createLocalRepoWithReleaseFiles`), calling the 6-arg 
`publish` twice with the same `oldFiles`:
   
   ```
   >>> after plan 1: [org.apache.sling.servlets.resolver-2.12.0.pom]
   >>> plan 2 FAILED: java.io.IOException: Failed to update dist.apache.org
   >>> final:        [org.apache.sling.servlets.resolver-2.12.0.pom]
   ```
   
   `commitFiles` aborts the edit and rethrows, so **3.0.10 never reaches 
dist**. And because 2.12.0 *did* land, re-running `update-dist` now hits the 
already-published short-circuit and reports "nothing to do" — so the release 
cannot be completed by re-running, only by hand.
   
   Even leaving the failure aside, the option is semantically unusable for a 
multi-artifact release: you can only name one previous version, so 3.0.8 (the 
actual predecessor of the 3.0.x stream) is never removed. And for two 
*different* artifact ids it would delete `B-<thatVersion>` if such a file 
happens to exist for B, which isn't what the operator asked for.
   
   Options, roughly in order of how much work they are:
   
   - reject `--previous-version` when the staging repository contains more than 
one artifact (smallest fix, keeps the flag honest)
   - make it accept per-artifact values, e.g. `--previous-version 
<artifactId>=<version>` (repeatable)
   - at minimum, if the per-plan `publish` calls are collapsed into one atomic 
commit as suggested above, de-duplicate `oldFiles` across plans so the 
double-delete can't happen
   
   A regression test for this is cheap — `createLocalRepoWithReleaseFiles` plus 
two plans sharing a previous version reproduces it in a few lines with no 
network.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to