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

royteeuwen pushed a commit to branch feature/SLING-13253-tally-votes
in repository 
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-committer-cli.git

commit f88958a5364cf0f1431e0ad772b0935aef8d9ee7
Author: Roy Teeuwen <[email protected]>
AuthorDate: Sat Jul 4 15:04:55 2026 +0200

    SLING-13253 - release tally-votes: PMC-aware result email
    
    Makes 'release tally-votes' aware of PMC membership when counting binding vs
    non-binding votes and generating the result email.
    
    Part of splitting PR #28 into per-command changes.
---
 .../sling/cli/impl/release/TallyVotesCommand.java  | 18 ++++++++
 src/main/resources/templates/tally-votes.email     |  3 +-
 .../cli/impl/release/TallyVotesCommandTest.java    | 50 +++++++++++++++++++++-
 3 files changed, 68 insertions(+), 3 deletions(-)

diff --git 
a/src/main/java/org/apache/sling/cli/impl/release/TallyVotesCommand.java 
b/src/main/java/org/apache/sling/cli/impl/release/TallyVotesCommand.java
index 3daca17..a621168 100644
--- a/src/main/java/org/apache/sling/cli/impl/release/TallyVotesCommand.java
+++ b/src/main/java/org/apache/sling/cli/impl/release/TallyVotesCommand.java
@@ -139,6 +139,7 @@ public class TallyVotesCommand implements Command {
                         .replace("##DATE##", 
dateProvider.getCurrentDateForEmailHeader())
                         .replace("##RELEASE_NAME##", releaseFullName)
                         .replace("##BINDING_VOTERS##", String.join(", ", 
bindingVoters))
+                        .replace("##CLOSING_ACTION##", 
closingAction(releaseFullName, currentMember.isPMCMember()))
                         .replace(
                                 "##USER_NAME##",
                                 membersFinder.getCurrentMember().getName());
@@ -193,6 +194,23 @@ public class TallyVotesCommand implements Command {
         return CommandLine.ExitCode.OK;
     }
 
+    /**
+     * Builds the closing paragraph of the result email. PMC members copy the 
release to the dist
+     * directory themselves; non-PMC release managers can only promote to 
Maven Central and must ask
+     * a PMC member to handle the dist upload (which is restricted to PMC 
members). PMC membership is
+     * derived from the current user, so no flag is needed.
+     */
+    private String closingAction(String releaseFullName, boolean isPmcMember) {
+        if (isPmcMember) {
+            return "I will copy this release to the Sling dist directory and\n"
+                    + "promote the artifacts to the central Maven repository.";
+        }
+        return "I will promote the artifacts to the central Maven 
repository.\n\n"
+                + "As I am not a PMC member, I cannot copy the release to the 
dist directory myself.\n\n"
+                + "ACTION NEEDED: can a PMC member please copy " + 
releaseFullName
+                + " to the Sling dist directory 
(https://dist.apache.org/repos/dist/release/sling/)?";
+    }
+
     // TODO - better detection of '+1' votes
     private boolean isPositiveVote(Email e) {
         return cleanup(e.getBody()).contains("+1");
diff --git a/src/main/resources/templates/tally-votes.email 
b/src/main/resources/templates/tally-votes.email
index af68d64..2b08093 100644
--- a/src/main/resources/templates/tally-votes.email
+++ b/src/main/resources/templates/tally-votes.email
@@ -11,8 +11,7 @@ The vote has passed with the following result:
 +1 (binding): ##BINDING_VOTERS##
 +1 (non-binding): ##NON_BINDING_VOTERS##
 
-I will copy this release to the Sling dist directory and
-promote the artifacts to the central Maven repository.
+##CLOSING_ACTION##
 
 Regards,
 ##USER_NAME##
diff --git 
a/src/test/java/org/apache/sling/cli/impl/release/TallyVotesCommandTest.java 
b/src/test/java/org/apache/sling/cli/impl/release/TallyVotesCommandTest.java
index dcd28a2..7ab433c 100644
--- a/src/test/java/org/apache/sling/cli/impl/release/TallyVotesCommandTest.java
+++ b/src/test/java/org/apache/sling/cli/impl/release/TallyVotesCommandTest.java
@@ -110,6 +110,49 @@ public class TallyVotesCommandTest {
                         + "John Doe\n"));
     }
 
+    @Test
+    public void testDryRunNonPmc() throws Exception {
+        // Daniel (a non-PMC committer) is the release manager running 
tally-votes; PMC status is
+        // auto-detected from the current user, so the result email asks a PMC 
member to do the dist
+        // upload.
+        Mailer mailer = mock(Mailer.class);
+        List<Email> thread = new ArrayList<>() {
+            {
+                add(mockEmail("[email protected]", "Daniel"));
+                add(mockEmail("[email protected]", "Alice"));
+                add(mockEmail("[email protected]", "Bob"));
+                add(mockEmail("[email protected]", "Charlie"));
+            }
+        };
+        prepareExecution(mailer, thread, "daniel");
+        Command command = createCommand(123, ExecutionMode.DRY_RUN);
+        assertEquals(CommandLine.ExitCode.OK, (int) command.call());
+        verifyNoInteractions(mailer);
+        assertTrue(logCapture.containsMessage("""
+                From: Daniel <[email protected]>
+                To: "Sling Developers List" <[email protected]>
+                Reply-To: "Sling Developers List" <[email protected]>
+                Date: Thu, 1 Jan 1970 01:00:00 +0100
+                Subject: [RESULT] [VOTE] Release Apache Sling CLI Test 1.0.0
+
+                Hi,
+
+                The vote has passed with the following result:
+
+                +1 (binding): Alice, Bob, Charlie
+                +1 (non-binding): none
+
+                I will promote the artifacts to the central Maven repository.
+
+                As I am not a PMC member, I cannot copy the release to the 
dist directory myself.
+
+                ACTION NEEDED: can a PMC member please copy Apache Sling CLI 
Test 1.0.0 to the Sling dist directory 
(https://dist.apache.org/repos/dist/release/sling/)?
+
+                Regards,
+                Daniel
+                """));
+    }
+
     @Test
     public void testDryRunNotEnoughBindingVotes() throws Exception {
         Mailer mailer = mock(Mailer.class);
@@ -184,8 +227,13 @@ public class TallyVotesCommandTest {
     }
 
     private void prepareExecution(Mailer mailer, List<Email> thread) throws 
IOException, IllegalAccessException {
+        prepareExecution(mailer, thread, "johndoe");
+    }
+
+    private void prepareExecution(Mailer mailer, List<Email> thread, String 
currentUsername)
+            throws IOException, IllegalAccessException {
         CredentialsService credentialsService = mock(CredentialsService.class);
-        when(credentialsService.getAsfCredentials()).thenReturn(new 
Credentials("johndoe", "secret"));
+        when(credentialsService.getAsfCredentials()).thenReturn(new 
Credentials(currentUsername, "secret"));
 
         MembersFinder membersFinder = spy(new MembersFinder());
         Set<Member> members = new HashSet<>() {

Reply via email to