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

sergehuber pushed a commit to branch UNOMI-943-migration
in repository https://gitbox.apache.org/repos/asf/unomi.git

commit 565c78b2550ed24a7d907a01c8f2f5214f2e22d0
Author: Serge Huber <[email protected]>
AuthorDate: Mon Jul 6 16:53:21 2026 +0200

    UNOMI-943: Fix 3.1.0 migration idempotency and missing resource errors
    
    Hoist rollover alias configuration to a top-level migration step so resume
    after failure can still configure write aliases. Fail fast in
    getFileWithoutComments when a bundled resource is missing.
---
 .../shell/migration/utils/MigrationUtils.java      |  3 ++
 .../migrate-3.1.0-01-tenantDocumentIds.groovy      | 55 +++++++++++-----------
 .../shell/migration/utils/MigrationUtilsTest.java  | 10 ++++
 3 files changed, 41 insertions(+), 27 deletions(-)

diff --git 
a/tools/shell-commands/src/main/java/org/apache/unomi/shell/migration/utils/MigrationUtils.java
 
b/tools/shell-commands/src/main/java/org/apache/unomi/shell/migration/utils/MigrationUtils.java
index 1bc480410..71755c590 100644
--- 
a/tools/shell-commands/src/main/java/org/apache/unomi/shell/migration/utils/MigrationUtils.java
+++ 
b/tools/shell-commands/src/main/java/org/apache/unomi/shell/migration/utils/MigrationUtils.java
@@ -76,6 +76,9 @@ public class MigrationUtils {
 
     public static String getFileWithoutComments(BundleContext bundleContext, 
final String resource) {
         final URL url = bundleContext.getBundle().getResource(resource);
+        if (url == null) {
+            throw new RuntimeException("Resource not found: " + resource);
+        }
         try {
             // Read the entire file into a string to preserve exact line 
endings
             String fileContent;
diff --git 
a/tools/shell-commands/src/main/resources/META-INF/cxs/migration/migrate-3.1.0-01-tenantDocumentIds.groovy
 
b/tools/shell-commands/src/main/resources/META-INF/cxs/migration/migrate-3.1.0-01-tenantDocumentIds.groovy
index 8a05cd1c6..a49916d83 100644
--- 
a/tools/shell-commands/src/main/resources/META-INF/cxs/migration/migrate-3.1.0-01-tenantDocumentIds.groovy
+++ 
b/tools/shell-commands/src/main/resources/META-INF/cxs/migration/migrate-3.1.0-01-tenantDocumentIds.groovy
@@ -146,34 +146,35 @@ context.performMigrationStep("3.1.0-get-all-indices", () 
-> {
         // Execute reindex
         MigrationUtils.reIndex(context.getHttpClient(), bundleContext, 
esAddress, indexName, newIndexSettings, updateScript, params, context, 
"3.1.0-${indexName}-update")
     }
-    
-    // Configure aliases for rollover indices after all reindexing is complete
-    // For each rollover alias, find all indices and set the latest one as 
write index
-    context.performMigrationStep("3.1.0-configure-rollover-aliases", () -> {
-        String configureAliasBody = 
MigrationUtils.resourceAsString(bundleContext, 
"requestBody/2.2.0/configure_alias_body.json")
-        
-        // Process each rollover item type
-        indexConfigs.each { itemType, config ->
-            if (config.useRollover) {
-                String alias = config.alias(indexPrefix)
-                // Find all indices that match the rollover pattern (e.g., 
context-session-000001, context-session-000002)
-                Set<String> rolloverIndices = 
MigrationUtils.getIndexesPrefixedBy(context.getHttpClient(), esAddress, 
"${indexPrefix}-${itemType}-")
-                
-                if (!rolloverIndices.isEmpty()) {
-                    // Sort indices to find the latest one (highest number)
-                    SortedSet<String> sortedIndices = new 
TreeSet<>(rolloverIndices)
-                    String writeIndex = sortedIndices.last()
-                    
-                    // All indices except the last one should be read-only
-                    SortedSet<String> readIndices = 
Collections.emptySortedSet()
-                    if (sortedIndices.size() > 1) {
-                        readIndices = 
sortedIndices.headSet(sortedIndices.last())
-                    }
-                    
-                    context.printMessage("Configuring alias ${alias}: write 
index=${writeIndex}, read indices=${readIndices}")
-                    MigrationUtils.configureAlias(context.getHttpClient(), 
esAddress, alias, writeIndex, readIndices, configureAliasBody, context)
+})
+
+// Configure aliases for rollover indices after all reindexing is complete.
+// Top-level step so resume after failure can run alias configuration even when
+// "3.1.0-get-all-indices" is already marked COMPLETED (UNOMI-943).
+context.performMigrationStep("3.1.0-configure-rollover-aliases", () -> {
+    String configureAliasBody = MigrationUtils.resourceAsString(bundleContext, 
"requestBody/2.2.0/configure_alias_body.json")
+
+    // Process each rollover item type
+    indexConfigs.each { itemType, config ->
+        if (config.useRollover) {
+            String alias = config.alias(indexPrefix)
+            // Find all indices that match the rollover pattern (e.g., 
context-session-000001, context-session-000002)
+            Set<String> rolloverIndices = 
MigrationUtils.getIndexesPrefixedBy(context.getHttpClient(), esAddress, 
"${indexPrefix}-${itemType}-")
+
+            if (!rolloverIndices.isEmpty()) {
+                // Sort indices to find the latest one (highest number)
+                SortedSet<String> sortedIndices = new 
TreeSet<>(rolloverIndices)
+                String writeIndex = sortedIndices.last()
+
+                // All indices except the last one should be read-only
+                SortedSet<String> readIndices = Collections.emptySortedSet()
+                if (sortedIndices.size() > 1) {
+                    readIndices = sortedIndices.headSet(sortedIndices.last())
                 }
+
+                context.printMessage("Configuring alias ${alias}: write 
index=${writeIndex}, read indices=${readIndices}")
+                MigrationUtils.configureAlias(context.getHttpClient(), 
esAddress, alias, writeIndex, readIndices, configureAliasBody, context)
             }
         }
-    })
+    }
 })
diff --git 
a/tools/shell-commands/src/test/java/org/apache/unomi/shell/migration/utils/MigrationUtilsTest.java
 
b/tools/shell-commands/src/test/java/org/apache/unomi/shell/migration/utils/MigrationUtilsTest.java
index aa1c0cb9d..96129f47c 100644
--- 
a/tools/shell-commands/src/test/java/org/apache/unomi/shell/migration/utils/MigrationUtilsTest.java
+++ 
b/tools/shell-commands/src/test/java/org/apache/unomi/shell/migration/utils/MigrationUtilsTest.java
@@ -27,6 +27,7 @@ import java.net.URL;
 import java.nio.charset.StandardCharsets;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
 import static org.mockito.Mockito.*;
 
 public class MigrationUtilsTest {
@@ -199,4 +200,13 @@ public class MigrationUtilsTest {
         String expected = "code1 code2 code3";
         testCommentHandling(input, expected);
     }
+
+    @Test
+    public void testGetFileWithoutCommentsMissingResource() {
+        when(bundle.getResource("missing.painless")).thenReturn(null);
+
+        RuntimeException ex = assertThrows(RuntimeException.class,
+                () -> MigrationUtils.getFileWithoutComments(bundleContext, 
"missing.painless"));
+        assertEquals("Resource not found: missing.painless", ex.getMessage());
+    }
 } 
\ No newline at end of file

Reply via email to