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

egonzalez pushed a commit to branch main
in repository 
https://gitbox.apache.org/repos/asf/incubator-kie-kogito-runtimes.git


The following commit(s) were added to refs/heads/main by this push:
     new 5ef8b2f5b6 [incubator-kie-issues-1086] PIM revisited functionality 
feature (#3472)
5ef8b2f5b6 is described below

commit 5ef8b2f5b666cf875be4db1a7f4087983dbbffd0
Author: Enrique <[email protected]>
AuthorDate: Fri Apr 19 11:50:04 2024 +0200

    [incubator-kie-issues-1086] PIM revisited functionality feature (#3472)
    
    * [incubator-kie-issues-1086] PIM revisited functionality feature
---
 .../jbpm/flow/migration/MigrationPlanService.java  | 76 ++++++++++++++++++---
 .../impl/FileSystemMigrationPlanFileProvider.java  |  8 ++-
 ...MigrationProcessInstanceMarshallerListener.java | 18 +++--
 .../flow/migration/MigrationPlanProviderTest.java  |  4 +-
 .../flow/migration/MigrationPlanServiceTest.java   | 79 +++++++++++++++++++---
 .../META-INF/migration-plan/simple_migration.mpf   |  6 +-
 ..._migration.mpf => simple_migration_version.mpf} |  0
 7 files changed, 158 insertions(+), 33 deletions(-)

diff --git 
a/jbpm/jbpm-flow-migration/src/main/java/org/jbpm/flow/migration/MigrationPlanService.java
 
b/jbpm/jbpm-flow-migration/src/main/java/org/jbpm/flow/migration/MigrationPlanService.java
index 12951dfb16..662eefaf91 100644
--- 
a/jbpm/jbpm-flow-migration/src/main/java/org/jbpm/flow/migration/MigrationPlanService.java
+++ 
b/jbpm/jbpm-flow-migration/src/main/java/org/jbpm/flow/migration/MigrationPlanService.java
@@ -25,14 +25,21 @@ import org.jbpm.flow.migration.model.MigrationPlan;
 import org.jbpm.flow.migration.model.ProcessDefinitionMigrationPlan;
 import org.jbpm.ruleflow.instance.RuleFlowProcessInstance;
 import org.jbpm.workflow.instance.impl.NodeInstanceImpl;
+import org.kie.kogito.Model;
 import org.kie.kogito.internal.process.runtime.KogitoNodeInstance;
 import org.kie.kogito.internal.process.runtime.KogitoWorkflowProcessInstance;
+import org.kie.kogito.process.Processes;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import static com.google.common.base.Functions.identity;
 import static java.util.stream.Collectors.toMap;
 
+/**
+ * The migration system is limited in this way.
+ * Cannot have more that one identifier process deployed (version is fixed)
+ * if there are several migration plans defined for the same source only one 
is taken into account
+ */
 public class MigrationPlanService {
     private static final Logger LOGGER = 
LoggerFactory.getLogger(MigrationPlanService.class);
 
@@ -49,8 +56,8 @@ public class MigrationPlanService {
         
this.migrations.putAll(this.migrationPlanProvider.findMigrationPlans().stream().collect(toMap(MigrationPlan::getSource,
 identity())));
     }
 
-    public void migrateProcessElement(KogitoWorkflowProcessInstance 
processInstance) {
-        MigrationPlan plan = getMigrationPlan(processInstance);
+    public void migrateProcessElement(Processes processes, 
KogitoWorkflowProcessInstance processInstance) {
+        MigrationPlan plan = getMigrationPlan(processes, processInstance);
         if (plan != null) {
             // the process will have to do nothing as it is done by the engine 
itself
             LOGGER.info("Process instance {} will be migrated from {} to {} 
with plan {}",
@@ -67,9 +74,9 @@ public class MigrationPlanService {
         }
     }
 
-    public void migrateNodeElement(KogitoNodeInstance nodeInstance) {
+    public void migrateNodeElement(Processes processes, KogitoNodeInstance 
nodeInstance) {
         KogitoWorkflowProcessInstance pi = (KogitoWorkflowProcessInstance) 
nodeInstance.getProcessInstance();
-        MigrationPlan plan = getMigrationPlan(pi);
+        MigrationPlan plan = getMigrationPlan(processes, pi);
         if (plan == null) {
             return;
         }
@@ -79,14 +86,63 @@ public class MigrationPlanService {
         
impl.setNodeId(plan.getProcessMigrationPlan().getNodeMigratedFor(nodeInstance));
     }
 
-    private MigrationPlan getMigrationPlan(KogitoWorkflowProcessInstance 
processInstance) {
+    // we check the target deployed in the container is the same as the target 
in the migration plan
+    private MigrationPlan getMigrationPlan(Processes processes, 
KogitoWorkflowProcessInstance processInstance) {
+        // first check if we need a migration as the process being set should 
be not be the same as the process set in the 
+        // process being loaded.
+        String currentProcessId = processInstance.getProcess().getId();
+        String currentVersion = processInstance.getProcess().getVersion();
+        ProcessDefinitionMigrationPlan currentProcessDefinition = new 
ProcessDefinitionMigrationPlan(currentProcessId, currentVersion);
+
+        RuleFlowProcessInstance pi = (RuleFlowProcessInstance) processInstance;
+        ProcessDefinitionMigrationPlan processStateDefinition = new 
ProcessDefinitionMigrationPlan(pi.getProcessId(), pi.getProcessVersion());
+
+        // check if definition and state match. we don't need to perform any 
migration.
+        if (currentProcessDefinition.equals(processStateDefinition)) {
+            return null;
+        }
+
+        // there is no migration plan define for the source
+        MigrationPlan plan = migrations.get(processStateDefinition);
+        if (plan == null) {
+            LOGGER.debug("No migration plan defined for process state {}.", 
processStateDefinition);
+            return null;
+        }
+
+        // current process definition matches the target process of the 
migration plan
+        ProcessDefinitionMigrationPlan targetDefinition = 
plan.getProcessMigrationPlan().getTargetProcessDefinition();
+        if (!targetDefinition.equals(currentProcessDefinition)) {
+            LOGGER.debug("Migration plan found for {} does not match target 
definition {}, Found plan to {}.", processStateDefinition, 
currentProcessDefinition, targetDefinition);
+            return null;
+        }
+
+        // target process not being deployed
+        if (!processes.processIds().contains(targetDefinition.getProcessId())) 
{
+            LOGGER.debug("No migration target defintion deployed in this 
container {} for migrating {}.", targetDefinition, processStateDefinition);
+            return null;
+        }
+
+        // target process not matching version
+        org.kie.kogito.process.Process<? extends Model> process = 
processes.processById(targetDefinition.getProcessId());
+        ProcessDefinitionMigrationPlan targetDeployed =
+                new ProcessDefinitionMigrationPlan(process.id(), 
process.version());
+
+        return targetDeployed.equals(targetDefinition) ? plan : null;
+    }
+
+    public boolean isEqualVersion(Processes processes, 
KogitoWorkflowProcessInstance processInstance) {
+        String currentProcessId = processInstance.getProcess().getId();
+        String currentVersion = processInstance.getProcess().getVersion();
+        ProcessDefinitionMigrationPlan currentProcessDefinition = new 
ProcessDefinitionMigrationPlan(currentProcessId, currentVersion);
+
         RuleFlowProcessInstance pi = (RuleFlowProcessInstance) processInstance;
-        ProcessDefinitionMigrationPlan pd =
-                new ProcessDefinitionMigrationPlan(pi.getProcessId(), 
pi.getProcessVersion());
-        return migrations.get(pd);
+        ProcessDefinitionMigrationPlan processStateDefinition = new 
ProcessDefinitionMigrationPlan(pi.getProcessId(), pi.getProcessVersion());
+
+        // check if definition and state match. we don't need to perform any 
migration.
+        return currentProcessDefinition.equals(processStateDefinition);
     }
 
-    public boolean shouldMigrate(KogitoWorkflowProcessInstance 
processInstance) {
-        return getMigrationPlan(processInstance) != null;
+    public boolean hasMigrationPlan(Processes processes, 
KogitoWorkflowProcessInstance processInstance) {
+        return getMigrationPlan(processes, processInstance) != null;
     }
 }
diff --git 
a/jbpm/jbpm-flow-migration/src/main/java/org/jbpm/flow/migration/impl/FileSystemMigrationPlanFileProvider.java
 
b/jbpm/jbpm-flow-migration/src/main/java/org/jbpm/flow/migration/impl/FileSystemMigrationPlanFileProvider.java
index 7d26bc7f96..a4aacf1a2c 100644
--- 
a/jbpm/jbpm-flow-migration/src/main/java/org/jbpm/flow/migration/impl/FileSystemMigrationPlanFileProvider.java
+++ 
b/jbpm/jbpm-flow-migration/src/main/java/org/jbpm/flow/migration/impl/FileSystemMigrationPlanFileProvider.java
@@ -31,7 +31,9 @@ import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Optional;
+import java.util.Set;
 import java.util.function.Predicate;
+import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 import org.jbpm.flow.migration.MigrationPlanFile;
@@ -49,7 +51,7 @@ public class FileSystemMigrationPlanFileProvider implements 
MigrationPlanFilePro
     public static final String EXPLODED_MIGRATION_PLAN_FOLDER = 
"META-INF/migration-plan/";
     public static final String MIGRATION_PLAN_FOLDER = 
"/META-INF/migration-plan/";
 
-    private List<URI> rootPaths;
+    private Set<URI> rootPaths;
 
     public FileSystemMigrationPlanFileProvider() {
         try {
@@ -57,7 +59,7 @@ public class FileSystemMigrationPlanFileProvider implements 
MigrationPlanFilePro
             if (url.isEmpty()) {
                 url = 
Collections.list(JbpmClassLoaderUtil.findClassLoader().getResources(EXPLODED_MIGRATION_PLAN_FOLDER));
             }
-            this.rootPaths = 
url.stream().map(this::toURI).filter(Optional::isPresent).map(Optional::get).toList();
+            this.rootPaths = 
url.stream().map(this::toURI).filter(Optional::isPresent).map(Optional::get).collect(Collectors.toSet());
         } catch (IOException e) {
             throw new IllegalArgumentException("error trying to get Migration 
Plan folder");
         }
@@ -72,7 +74,7 @@ public class FileSystemMigrationPlanFileProvider implements 
MigrationPlanFilePro
     }
 
     public FileSystemMigrationPlanFileProvider(URI rootPath) {
-        this.rootPaths = List.of(rootPath);
+        this.rootPaths = Set.of(rootPath);
     }
 
     @Override
diff --git 
a/jbpm/jbpm-flow-migration/src/main/java/org/jbpm/flow/serialization/migration/StandardMigrationProcessInstanceMarshallerListener.java
 
b/jbpm/jbpm-flow-migration/src/main/java/org/jbpm/flow/serialization/migration/StandardMigrationProcessInstanceMarshallerListener.java
index 22ac0cdf03..b938110a99 100644
--- 
a/jbpm/jbpm-flow-migration/src/main/java/org/jbpm/flow/serialization/migration/StandardMigrationProcessInstanceMarshallerListener.java
+++ 
b/jbpm/jbpm-flow-migration/src/main/java/org/jbpm/flow/serialization/migration/StandardMigrationProcessInstanceMarshallerListener.java
@@ -20,9 +20,11 @@ package org.jbpm.flow.serialization.migration;
 
 import org.jbpm.flow.migration.MigrationPlanService;
 import org.jbpm.flow.serialization.ProcessInstanceMarshallerListener;
+import org.jbpm.ruleflow.instance.RuleFlowProcessInstance;
 import org.kie.kogito.internal.process.runtime.KogitoNodeInstance;
 import org.kie.kogito.internal.process.runtime.KogitoProcessRuntime;
 import org.kie.kogito.internal.process.runtime.KogitoWorkflowProcessInstance;
+import org.kie.kogito.process.Processes;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -41,22 +43,28 @@ public class 
StandardMigrationProcessInstanceMarshallerListener implements Proce
     @SuppressWarnings("deprecation")
     @Override
     public void afterUnmarshallProcess(KogitoProcessRuntime runtime, 
KogitoWorkflowProcessInstance processInstance) {
-        if (!migrationPlanService.shouldMigrate(processInstance)) {
+        if 
(!migrationPlanService.hasMigrationPlan(runtime.getApplication().get(Processes.class),
 processInstance)) {
+            if 
(!this.migrationPlanService.isEqualVersion(runtime.getApplication().get(Processes.class),
 processInstance)) {
+                LOGGER.debug("Process State version and process container 
mismatch. Migrating process without plan.");
+                RuleFlowProcessInstance ruleFlowProcessInstance = 
(RuleFlowProcessInstance) processInstance;
+                
ruleFlowProcessInstance.setProcess(ruleFlowProcessInstance.getProcess());
+            }
             return;
         }
-        LOGGER.debug("Migration processInstance {}", processInstance);
-        migrationPlanService.migrateProcessElement(processInstance);
+        LOGGER.debug("Migration processInstance state {}-{} and definition 
{}-{}",
+                processInstance.getProcessId(), 
processInstance.getProcessVersion(), processInstance.getProcess().getId(), 
processInstance.getProcess().getVersion());
+        
migrationPlanService.migrateProcessElement(runtime.getApplication().get(Processes.class),
 processInstance);
         runtime.getProcessEventSupport().fireOnMigration(processInstance, 
runtime.getKieRuntime());
 
     }
 
     @Override
     public void afterUnmarshallNode(KogitoProcessRuntime runtime, 
KogitoNodeInstance nodeInstance) {
-        if 
(!migrationPlanService.shouldMigrate((KogitoWorkflowProcessInstance) 
nodeInstance.getProcessInstance())) {
+        if 
(!migrationPlanService.hasMigrationPlan(runtime.getApplication().get(Processes.class),
 (KogitoWorkflowProcessInstance) nodeInstance.getProcessInstance())) {
             return;
         }
         LOGGER.debug("Migration nodeInstance {}", nodeInstance);
-        migrationPlanService.migrateNodeElement(nodeInstance);
+        
migrationPlanService.migrateNodeElement(runtime.getApplication().get(Processes.class),
 nodeInstance);
     }
 
 }
diff --git 
a/jbpm/jbpm-flow-migration/src/test/java/org/jbpm/flow/migration/MigrationPlanProviderTest.java
 
b/jbpm/jbpm-flow-migration/src/test/java/org/jbpm/flow/migration/MigrationPlanProviderTest.java
index 2a279c20f1..d417066b96 100644
--- 
a/jbpm/jbpm-flow-migration/src/test/java/org/jbpm/flow/migration/MigrationPlanProviderTest.java
+++ 
b/jbpm/jbpm-flow-migration/src/test/java/org/jbpm/flow/migration/MigrationPlanProviderTest.java
@@ -55,8 +55,8 @@ public class MigrationPlanProviderTest {
         plan.setProcessMigrationPlan(pdmp);
 
         assertThat(plans)
-                .hasSize(1)
-                .containsExactly(plan);
+                .hasSize(2)
+                .contains(plan);
 
     }
 
diff --git 
a/jbpm/jbpm-flow-migration/src/test/java/org/jbpm/flow/migration/MigrationPlanServiceTest.java
 
b/jbpm/jbpm-flow-migration/src/test/java/org/jbpm/flow/migration/MigrationPlanServiceTest.java
index 1e2f141110..2df1b83775 100644
--- 
a/jbpm/jbpm-flow-migration/src/test/java/org/jbpm/flow/migration/MigrationPlanServiceTest.java
+++ 
b/jbpm/jbpm-flow-migration/src/test/java/org/jbpm/flow/migration/MigrationPlanServiceTest.java
@@ -18,23 +18,64 @@
  */
 package org.jbpm.flow.migration;
 
+import java.util.Collections;
+
 import org.jbpm.ruleflow.instance.RuleFlowProcessInstance;
 import org.jbpm.workflow.instance.impl.ExtendedNodeInstanceImpl;
 import org.jbpm.workflow.instance.impl.WorkflowProcessInstanceImpl;
+import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.TestInstance.Lifecycle;
+import org.kie.kogito.process.Processes;
+import org.mockito.Mockito;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static 
org.jbpm.ruleflow.core.WorkflowElementIdentifierFactory.fromExternalFormat;
+import static org.mockito.Mockito.when;
 
+@TestInstance(Lifecycle.PER_CLASS)
 public class MigrationPlanServiceTest {
 
+    Processes processes;
+    org.kie.kogito.process.Process processB;
+
+    @BeforeAll
+    public void init() {
+        processes = Mockito.mock(Processes.class);
+        
when(processes.processIds()).thenReturn(Collections.singletonList("process_B"));
+
+        processB = Mockito.mock(org.kie.kogito.process.Process.class);
+        when(processes.processById("process_B")).thenReturn(processB);
+        when(processB.id()).thenReturn("process_B");
+        when(processB.version()).thenReturn("2");
+    }
+
+    @Test
+    public void testMigrationProcessInstanceSameProcessDefinition() {
+        MigrationPlanService service = new MigrationPlanService();
+
+        WorkflowProcessInstanceImpl processImpl = new 
RuleFlowProcessInstance();
+        processImpl.setInternalProcess(new DummyProcess("process_A", "1"));
+        processImpl.setProcessId("process_A");
+        processImpl.setProcessVersion("1");
+        service.migrateProcessElement(processes, processImpl);
+
+        assertThat(processImpl)
+                .hasFieldOrPropertyWithValue("processId", "process_A")
+                .hasFieldOrPropertyWithValue("processVersion", "1");
+
+    }
+
     @Test
     public void testMigrationProcessInstance() {
         MigrationPlanService service = new MigrationPlanService();
 
         WorkflowProcessInstanceImpl processImpl = new 
RuleFlowProcessInstance();
-        processImpl.setProcess(new DummyProcess("process_A", "1"));
-        service.migrateProcessElement(processImpl);
+        processImpl.setInternalProcess(new DummyProcess("process_B", "2"));
+        processImpl.setProcessId("process_A");
+        processImpl.setProcessVersion("1");
+        service.migrateProcessElement(processes, processImpl);
 
         assertThat(processImpl)
                 .hasFieldOrPropertyWithValue("processId", "process_B")
@@ -42,12 +83,26 @@ public class MigrationPlanServiceTest {
 
     }
 
+    @Test
+    public void testMigrationProcessInstanceNotMatchingVersion() {
+        MigrationPlanService service = new MigrationPlanService();
+
+        WorkflowProcessInstanceImpl processImpl = new 
RuleFlowProcessInstance();
+        processImpl.setProcess(new DummyProcess("process_D", "1"));
+        service.migrateProcessElement(processes, processImpl);
+
+        assertThat(processImpl)
+                .hasFieldOrPropertyWithValue("processId", "process_D")
+                .hasFieldOrPropertyWithValue("processVersion", "1");
+
+    }
+
     @Test
     public void testMigrationProcessNonExisting() {
         MigrationPlanService service = new MigrationPlanService();
         WorkflowProcessInstanceImpl processImpl = new 
RuleFlowProcessInstance();
         processImpl.setProcess(new DummyProcess("process_C", "1"));
-        service.migrateProcessElement(processImpl);
+        service.migrateProcessElement(processes, processImpl);
 
         assertThat(processImpl)
                 .hasFieldOrPropertyWithValue("processId", "process_C")
@@ -59,7 +114,7 @@ public class MigrationPlanServiceTest {
         MigrationPlanService service = new MigrationPlanService();
         WorkflowProcessInstanceImpl processImpl = new 
RuleFlowProcessInstance();
         processImpl.setProcess(new DummyProcess("process_A", "3"));
-        service.migrateProcessElement(processImpl);
+        service.migrateProcessElement(processes, processImpl);
 
         assertThat(processImpl)
                 .hasFieldOrPropertyWithValue("processId", "process_A")
@@ -70,12 +125,14 @@ public class MigrationPlanServiceTest {
     public void testMigrationNode() {
         MigrationPlanService service = new MigrationPlanService();
         WorkflowProcessInstanceImpl processImpl = new 
RuleFlowProcessInstance();
-        processImpl.setProcess(new DummyProcess("process_A", "1"));
+        processImpl.setInternalProcess(new DummyProcess("process_B", "2"));
+        processImpl.setProcessId("process_A");
+        processImpl.setProcessVersion("1");
         ExtendedNodeInstanceImpl nodeInstanceImpl = new 
ExtendedNodeInstanceImpl() {
         };
         nodeInstanceImpl.setProcessInstance(processImpl);
         nodeInstanceImpl.setNodeId(fromExternalFormat("node_1"));
-        service.migrateNodeElement(nodeInstanceImpl);
+        service.migrateNodeElement(processes, nodeInstanceImpl);
 
         assertThat(nodeInstanceImpl)
                 .hasFieldOrPropertyWithValue("nodeId", 
fromExternalFormat("node_2"));
@@ -85,12 +142,14 @@ public class MigrationPlanServiceTest {
     public void testMigrationNodeNextItem() {
         MigrationPlanService service = new MigrationPlanService();
         WorkflowProcessInstanceImpl processImpl = new 
RuleFlowProcessInstance();
-        processImpl.setProcess(new DummyProcess("process_A", "1"));
+        processImpl.setInternalProcess(new DummyProcess("process_B", "2"));
+        processImpl.setProcessId("process_A");
+        processImpl.setProcessVersion("1");
         ExtendedNodeInstanceImpl nodeInstanceImpl = new 
ExtendedNodeInstanceImpl() {
         };
         nodeInstanceImpl.setProcessInstance(processImpl);
         nodeInstanceImpl.setNodeId(fromExternalFormat("node_2"));
-        service.migrateNodeElement(nodeInstanceImpl);
+        service.migrateNodeElement(processes, nodeInstanceImpl);
 
         assertThat(nodeInstanceImpl)
                 .hasFieldOrPropertyWithValue("nodeId", 
fromExternalFormat("node_3"));
@@ -105,7 +164,7 @@ public class MigrationPlanServiceTest {
         };
         nodeInstanceImpl.setProcessInstance(processImpl);
         nodeInstanceImpl.setNodeId(fromExternalFormat("node_3"));
-        service.migrateNodeElement(nodeInstanceImpl);
+        service.migrateNodeElement(processes, nodeInstanceImpl);
 
         assertThat(nodeInstanceImpl)
                 .hasFieldOrPropertyWithValue("nodeId", 
fromExternalFormat("node_3"));
@@ -120,7 +179,7 @@ public class MigrationPlanServiceTest {
         };
         nodeInstanceImpl.setProcessInstance(processImpl);
         nodeInstanceImpl.setNodeId(fromExternalFormat("node_3"));
-        service.migrateNodeElement(nodeInstanceImpl);
+        service.migrateNodeElement(processes, nodeInstanceImpl);
 
         assertThat(nodeInstanceImpl)
                 .hasFieldOrPropertyWithValue("nodeId", 
fromExternalFormat("node_3"));
diff --git 
a/jbpm/jbpm-flow-migration/src/test/resources/META-INF/migration-plan/simple_migration.mpf
 
b/jbpm/jbpm-flow-migration/src/test/resources/META-INF/migration-plan/simple_migration.mpf
index 98d93052b2..9daed6fad1 100644
--- 
a/jbpm/jbpm-flow-migration/src/test/resources/META-INF/migration-plan/simple_migration.mpf
+++ 
b/jbpm/jbpm-flow-migration/src/test/resources/META-INF/migration-plan/simple_migration.mpf
@@ -1,13 +1,13 @@
 {
-    "name" : "my simple migration",
+    "name" : "my simple migration versioned",
     "processMigrationPlan" : {
         "sourceProcessDefinition" : {
-            "processId" : "process_A",
+            "processId" : "process_D",
             "processVersion" : "1"
         },
         "targetProcessDefinition" : {
             "processId" : "process_B",
-            "processVersion" : "2"
+            "processVersion" : "3"
         },
         "nodeInstanceMigrationPlan" : [
             {
diff --git 
a/jbpm/jbpm-flow-migration/src/test/resources/META-INF/migration-plan/simple_migration.mpf
 
b/jbpm/jbpm-flow-migration/src/test/resources/META-INF/migration-plan/simple_migration_version.mpf
similarity index 100%
copy from 
jbpm/jbpm-flow-migration/src/test/resources/META-INF/migration-plan/simple_migration.mpf
copy to 
jbpm/jbpm-flow-migration/src/test/resources/META-INF/migration-plan/simple_migration_version.mpf


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to