This is an automated email from the ASF dual-hosted git repository.

royteeuwen pushed a commit to branch feature/sling-cli-release-automation
in repository 
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-committer-cli.git

commit c3ed3d4080791fdbf715c365fd584fe90bd29a91
Author: Roy Teeuwen <[email protected]>
AuthorDate: Mon Jun 1 22:08:37 2026 +0200

    release: allow post-vote commands to act on a release by name
    
    The release-identity commands resolved the release(s) solely from the 
staging
    repository via find(repositoryId), so they stopped working once the 
repository
    was promoted (released and dropped). Add a --release option to
    create-new-jira-version, release-jira-version, update-reporter and
    update-local-site: when given, the release is parsed directly from the name
    instead of being looked up from the staging repository, so these steps can 
be
    completed even after promotion. --repository is no longer required when 
--release
    is supplied; create-new-jira-version keeps --version-name as an alias.
---
 .../cli/impl/release/CreateJiraVersionCommand.java | 29 ++++++++++++++--------
 .../impl/release/ReleaseJiraVersionCommand.java    | 29 ++++++++++++++++++----
 .../cli/impl/release/UpdateLocalSiteCommand.java   | 28 +++++++++++++++++----
 .../cli/impl/release/UpdateReporterCommand.java    | 28 +++++++++++++++++----
 .../release/ReleaseJiraVersionCommandTest.java     | 25 +++++++++++++++++++
 .../impl/release/UpdateReporterCommandTest.java    | 27 ++++++++++++++++++++
 6 files changed, 140 insertions(+), 26 deletions(-)

diff --git 
a/src/main/java/org/apache/sling/cli/impl/release/CreateJiraVersionCommand.java 
b/src/main/java/org/apache/sling/cli/impl/release/CreateJiraVersionCommand.java
index 226e01a..8d2083a 100644
--- 
a/src/main/java/org/apache/sling/cli/impl/release/CreateJiraVersionCommand.java
+++ 
b/src/main/java/org/apache/sling/cli/impl/release/CreateJiraVersionCommand.java
@@ -30,7 +30,6 @@ import org.apache.sling.cli.impl.jira.Issue;
 import org.apache.sling.cli.impl.jira.Version;
 import org.apache.sling.cli.impl.jira.VersionClient;
 import org.apache.sling.cli.impl.nexus.RepositoryService;
-import org.apache.sling.cli.impl.nexus.StagingRepository;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Reference;
 import org.slf4j.Logger;
@@ -56,8 +55,7 @@ public class CreateJiraVersionCommand implements Command {
 
     @CommandLine.Option(
             names = {"-r", "--repository"},
-            description = "Nexus repository id",
-            required = true)
+            description = "Nexus staging repository id to derive the 
release(s) from")
     private Integer repositoryId;
 
     @Reference
@@ -67,9 +65,10 @@ public class CreateJiraVersionCommand implements Command {
     private VersionClient versionClient;
 
     @CommandLine.Option(
-            names = {"--version-name"},
-            description = "Jira version name to use",
-            required = false)
+            names = {"--release", "--version-name"},
+            description = "Release name(s) to act on, e.g. \"Apache Sling Foo 
1.2.0\" (comma-separated for multiple)."
+                    + " Use instead of --repository when the staging 
repository no longer exists,"
+                    + " e.g. after the release has been promoted.")
     private String jiraVersionName;
 
     @CommandLine.Mixin
@@ -80,7 +79,12 @@ public class CreateJiraVersionCommand implements Command {
     @Override
     public Integer call() {
         try {
-            for (Release release : releases()) {
+            Collection<Release> releases = releases();
+            if (releases == null) {
+                logger.error("Provide either --repository or --release.");
+                return CommandLine.ExitCode.USAGE;
+            }
+            for (Release release : releases) {
                 Version version = versionClient.find(release);
                 logger.info("Found {}.", version);
                 Version successorVersion = 
versionClient.findSuccessorVersion(release);
@@ -145,9 +149,12 @@ public class CreateJiraVersionCommand implements Command {
     }
 
     private Collection<Release> releases() throws IOException {
-        if (jiraVersionName != null) return 
Release.fromString(jiraVersionName);
-
-        StagingRepository repo = repositoryService.find(repositoryId);
-        return repositoryService.getReleases(repo);
+        if (jiraVersionName != null && !jiraVersionName.isBlank()) {
+            return Release.fromString(jiraVersionName);
+        }
+        if (repositoryId == null) {
+            return null;
+        }
+        return 
repositoryService.getReleases(repositoryService.find(repositoryId));
     }
 }
diff --git 
a/src/main/java/org/apache/sling/cli/impl/release/ReleaseJiraVersionCommand.java
 
b/src/main/java/org/apache/sling/cli/impl/release/ReleaseJiraVersionCommand.java
index 5aa9a1c..9947e0f 100644
--- 
a/src/main/java/org/apache/sling/cli/impl/release/ReleaseJiraVersionCommand.java
+++ 
b/src/main/java/org/apache/sling/cli/impl/release/ReleaseJiraVersionCommand.java
@@ -18,6 +18,7 @@
  */
 package org.apache.sling.cli.impl.release;
 
+import java.io.IOException;
 import java.util.List;
 import java.util.Set;
 
@@ -28,7 +29,6 @@ import org.apache.sling.cli.impl.UserInput;
 import org.apache.sling.cli.impl.jira.Issue;
 import org.apache.sling.cli.impl.jira.VersionClient;
 import org.apache.sling.cli.impl.nexus.RepositoryService;
-import org.apache.sling.cli.impl.nexus.StagingRepository;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Reference;
 import org.slf4j.Logger;
@@ -58,10 +58,16 @@ public class ReleaseJiraVersionCommand implements Command {
 
     @CommandLine.Option(
             names = {"-r", "--repository"},
-            description = "Nexus repository id",
-            required = true)
+            description = "Nexus staging repository id to derive the 
release(s) from")
     private Integer repositoryId;
 
+    @CommandLine.Option(
+            names = {"--release"},
+            description = "Release name(s) to act on, e.g. \"Apache Sling Foo 
1.2.0\" (comma-separated for multiple)."
+                    + " Use instead of --repository when the staging 
repository no longer exists,"
+                    + " e.g. after the release has been promoted.")
+    private String releaseName;
+
     @Reference
     private RepositoryService repositoryService;
 
@@ -71,11 +77,24 @@ public class ReleaseJiraVersionCommand implements Command {
     @CommandLine.Mixin
     private ReusableCLIOptions reusableCLIOptions;
 
+    private Set<Release> resolveReleases() throws IOException {
+        if (releaseName != null && !releaseName.isBlank()) {
+            return Set.copyOf(Release.fromString(releaseName));
+        }
+        if (repositoryId == null) {
+            return null;
+        }
+        return 
repositoryService.getReleases(repositoryService.find(repositoryId));
+    }
+
     @Override
     public Integer call() {
         try {
-            StagingRepository repo = repositoryService.find(repositoryId);
-            Set<Release> releases = repositoryService.getReleases(repo);
+            Set<Release> releases = resolveReleases();
+            if (releases == null) {
+                LOGGER.error("Provide either --repository or --release.");
+                return CommandLine.ExitCode.USAGE;
+            }
             ExecutionMode executionMode = reusableCLIOptions.executionMode;
             LOGGER.info(
                     "The following Jira versions {} be released:{}",
diff --git 
a/src/main/java/org/apache/sling/cli/impl/release/UpdateLocalSiteCommand.java 
b/src/main/java/org/apache/sling/cli/impl/release/UpdateLocalSiteCommand.java
index b9a3e6e..5e35d55 100644
--- 
a/src/main/java/org/apache/sling/cli/impl/release/UpdateLocalSiteCommand.java
+++ 
b/src/main/java/org/apache/sling/cli/impl/release/UpdateLocalSiteCommand.java
@@ -28,7 +28,6 @@ import java.util.Set;
 import org.apache.sling.cli.impl.Command;
 import org.apache.sling.cli.impl.jbake.JBakeContentUpdater;
 import org.apache.sling.cli.impl.nexus.RepositoryService;
-import org.apache.sling.cli.impl.nexus.StagingRepository;
 import org.eclipse.jgit.api.Git;
 import org.eclipse.jgit.api.ResetCommand.ResetType;
 import org.eclipse.jgit.api.errors.GitAPIException;
@@ -63,18 +62,37 @@ public class UpdateLocalSiteCommand implements Command {
 
     @CommandLine.Option(
             names = {"-r", "--repository"},
-            description = "Nexus repository id",
-            required = true)
+            description = "Nexus staging repository id to derive the 
release(s) from")
     private Integer repositoryId;
 
+    @CommandLine.Option(
+            names = {"--release"},
+            description = "Release name(s) to act on, e.g. \"Apache Sling Foo 
1.2.0\" (comma-separated for multiple)."
+                    + " Use instead of --repository when the staging 
repository no longer exists,"
+                    + " e.g. after the release has been promoted.")
+    private String releaseName;
+
+    private Set<Release> resolveReleases() throws IOException {
+        if (releaseName != null && !releaseName.isBlank()) {
+            return Set.copyOf(Release.fromString(releaseName));
+        }
+        if (repositoryId == null) {
+            return null;
+        }
+        return 
repositoryService.getReleases(repositoryService.find(repositoryId));
+    }
+
     @Override
     public Integer call() {
         try {
             ensureRepo();
             try (Git git = Git.open(new File(GIT_CHECKOUT))) {
 
-                StagingRepository repository = 
repositoryService.find(repositoryId);
-                Set<Release> releases = 
repositoryService.getReleases(repository);
+                Set<Release> releases = resolveReleases();
+                if (releases == null) {
+                    logger.error("Provide either --repository or --release.");
+                    return CommandLine.ExitCode.USAGE;
+                }
 
                 JBakeContentUpdater updater = new JBakeContentUpdater();
 
diff --git 
a/src/main/java/org/apache/sling/cli/impl/release/UpdateReporterCommand.java 
b/src/main/java/org/apache/sling/cli/impl/release/UpdateReporterCommand.java
index 983618c..db4bed0 100644
--- a/src/main/java/org/apache/sling/cli/impl/release/UpdateReporterCommand.java
+++ b/src/main/java/org/apache/sling/cli/impl/release/UpdateReporterCommand.java
@@ -37,7 +37,6 @@ import org.apache.sling.cli.impl.InputOption;
 import org.apache.sling.cli.impl.UserInput;
 import org.apache.sling.cli.impl.http.HttpClientFactory;
 import org.apache.sling.cli.impl.nexus.RepositoryService;
-import org.apache.sling.cli.impl.nexus.StagingRepository;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Reference;
 import org.slf4j.Logger;
@@ -69,18 +68,37 @@ public class UpdateReporterCommand implements Command {
 
     @CommandLine.Option(
             names = {"-r", "--repository"},
-            description = "Nexus repository id",
-            required = true)
+            description = "Nexus staging repository id to derive the 
release(s) from")
     private Integer repositoryId;
 
+    @CommandLine.Option(
+            names = {"--release"},
+            description = "Release name(s) to act on, e.g. \"Apache Sling Foo 
1.2.0\" (comma-separated for multiple)."
+                    + " Use instead of --repository when the staging 
repository no longer exists,"
+                    + " e.g. after the release has been promoted.")
+    private String releaseName;
+
     @CommandLine.Mixin
     private ReusableCLIOptions reusableCLIOptions;
 
+    private Set<Release> resolveReleases() throws IOException {
+        if (releaseName != null && !releaseName.isBlank()) {
+            return Set.copyOf(Release.fromString(releaseName));
+        }
+        if (repositoryId == null) {
+            return null;
+        }
+        return 
repositoryService.getReleases(repositoryService.find(repositoryId));
+    }
+
     @Override
     public Integer call() {
         try {
-            StagingRepository repository = 
repositoryService.find(repositoryId);
-            Set<Release> releases = repositoryService.getReleases(repository);
+            Set<Release> releases = resolveReleases();
+            if (releases == null) {
+                LOGGER.error("Provide either --repository or --release.");
+                return CommandLine.ExitCode.USAGE;
+            }
             String releaseReleases = releases.size() > 1 ? "releases" : 
"release";
             switch (reusableCLIOptions.executionMode) {
                 case DRY_RUN:
diff --git 
a/src/test/java/org/apache/sling/cli/impl/release/ReleaseJiraVersionCommandTest.java
 
b/src/test/java/org/apache/sling/cli/impl/release/ReleaseJiraVersionCommandTest.java
index e80f289..d7715da 100644
--- 
a/src/test/java/org/apache/sling/cli/impl/release/ReleaseJiraVersionCommandTest.java
+++ 
b/src/test/java/org/apache/sling/cli/impl/release/ReleaseJiraVersionCommandTest.java
@@ -40,6 +40,7 @@ import picocli.CommandLine;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.mockStatic;
@@ -111,6 +112,16 @@ public class ReleaseJiraVersionCommandTest {
         verify(versionClient, times(1)).release(any());
     }
 
+    @Test
+    public void testReleaseByName() throws Exception {
+        // the release is resolved from --release, so the command works 
without the (now-gone) staging repo
+        prepare();
+        Command command = createCommandByName("Apache Sling CLI Test 1.0.0", 
ExecutionMode.AUTO);
+        assertEquals(CommandLine.ExitCode.OK, (int) command.call());
+        verify(versionClient, times(1)).release(any());
+        verify(repositoryService, never()).find(anyInt());
+    }
+
     private Command createCommand(int repositoryId, ExecutionMode 
executionMode) throws Exception {
         ReleaseJiraVersionCommand releaseJiraVersionCommand = spy(new 
ReleaseJiraVersionCommand());
         FieldUtils.writeField(releaseJiraVersionCommand, "repositoryId", 
repositoryId, true);
@@ -124,4 +135,18 @@ public class ReleaseJiraVersionCommandTest {
                 result instanceof ReleaseJiraVersionCommand);
         return result;
     }
+
+    private Command createCommandByName(String releaseName, ExecutionMode 
executionMode) throws Exception {
+        ReleaseJiraVersionCommand releaseJiraVersionCommand = spy(new 
ReleaseJiraVersionCommand());
+        FieldUtils.writeField(releaseJiraVersionCommand, "releaseName", 
releaseName, true);
+        ReusableCLIOptions reusableCLIOptions = mock(ReusableCLIOptions.class);
+        FieldUtils.writeField(reusableCLIOptions, "executionMode", 
executionMode, true);
+        FieldUtils.writeField(releaseJiraVersionCommand, "reusableCLIOptions", 
reusableCLIOptions, true);
+        osgiContext.registerInjectActivateService(releaseJiraVersionCommand);
+        Command result = osgiContext.getService(Command.class);
+        assertTrue(
+                "Expected to retrieve the ReleaseJiraVersionCommand from the 
mocked OSGi environment.",
+                result instanceof ReleaseJiraVersionCommand);
+        return result;
+    }
 }
diff --git 
a/src/test/java/org/apache/sling/cli/impl/release/UpdateReporterCommandTest.java
 
b/src/test/java/org/apache/sling/cli/impl/release/UpdateReporterCommandTest.java
index 10f53fa..c8670c6 100644
--- 
a/src/test/java/org/apache/sling/cli/impl/release/UpdateReporterCommandTest.java
+++ 
b/src/test/java/org/apache/sling/cli/impl/release/UpdateReporterCommandTest.java
@@ -118,6 +118,19 @@ public class UpdateReporterCommandTest {
         verify(client, times(2)).execute(any());
     }
 
+    @Test
+    public void testAutoByName() throws Exception {
+        // resolves the release from --release rather than a (possibly gone) 
staging repository
+        Command updateReporter = createCommandByName("Apache Sling CLI 1", 
ExecutionMode.AUTO);
+        CloseableHttpResponse response = mock(CloseableHttpResponse.class);
+        StatusLine statusLine = mock(StatusLine.class);
+        when(response.getStatusLine()).thenReturn(statusLine);
+        when(statusLine.getStatusCode()).thenReturn(200);
+        when(client.execute(any())).thenReturn(response);
+        assertEquals(0, (int) updateReporter.call());
+        verify(client, times(1)).execute(any());
+    }
+
     private Command createCommand(int repositoryId, ExecutionMode 
executionMode) throws IllegalAccessException {
         UpdateReporterCommand updateReporterCommand = spy(new 
UpdateReporterCommand());
         FieldUtils.writeField(updateReporterCommand, "repositoryId", 
repositoryId, true);
@@ -131,4 +144,18 @@ public class UpdateReporterCommandTest {
                 result instanceof UpdateReporterCommand);
         return result;
     }
+
+    private Command createCommandByName(String releaseName, ExecutionMode 
executionMode) throws IllegalAccessException {
+        UpdateReporterCommand updateReporterCommand = spy(new 
UpdateReporterCommand());
+        FieldUtils.writeField(updateReporterCommand, "releaseName", 
releaseName, true);
+        ReusableCLIOptions reusableCLIOptions = mock(ReusableCLIOptions.class);
+        FieldUtils.writeField(reusableCLIOptions, "executionMode", 
executionMode, true);
+        FieldUtils.writeField(updateReporterCommand, "reusableCLIOptions", 
reusableCLIOptions, true);
+        osgiContext.registerInjectActivateService(updateReporterCommand);
+        Command result = osgiContext.getService(Command.class);
+        assertTrue(
+                "Expected to retrieve the UpdateReporterCommand from the 
mocked OSGi environment.",
+                result instanceof UpdateReporterCommand);
+        return result;
+    }
 }

Reply via email to