look for any migration detail for the pi and target hash to get the git revision w/ burnettk (#1959)
Co-authored-by: jasquat <jasquat@users.noreply.github.com>
This commit is contained in:
parent
038fbeedbb
commit
57c7b12e38
|
@ -27,6 +27,7 @@ from SpiffWorkflow.bpmn.util.diff import migrate_workflow
|
|||
from SpiffWorkflow.task import Task as SpiffTask # type: ignore
|
||||
from SpiffWorkflow.util.deep_merge import DeepMerge # type: ignore
|
||||
from SpiffWorkflow.util.task import TaskState # type: ignore
|
||||
from sqlalchemy import or_
|
||||
|
||||
from spiffworkflow_backend.background_processing.celery_tasks.process_instance_task_producer import (
|
||||
queue_process_instance_if_appropriate,
|
||||
|
@ -262,9 +263,7 @@ class ProcessInstanceService:
|
|||
bpmn_process_instance=processor.bpmn_process_instance,
|
||||
store_process_instance_events=False,
|
||||
)
|
||||
git_revision_to_use = cls.get_appropriate_git_revision(
|
||||
process_instance, initial_bpmn_process_hash, target_bpmn_process_hash
|
||||
)
|
||||
git_revision_to_use = cls.get_appropriate_git_revision(process_instance, target_bpmn_process_hash)
|
||||
process_instance.bpmn_version_control_identifier = git_revision_to_use
|
||||
db.session.add(process_instance)
|
||||
|
||||
|
@ -303,16 +302,21 @@ class ProcessInstanceService:
|
|||
def get_appropriate_git_revision(
|
||||
cls,
|
||||
process_instance: ProcessInstanceModel,
|
||||
initial_bpmn_process_hash: str | None,
|
||||
target_bpmn_process_hash: str | None,
|
||||
) -> str | None:
|
||||
# if target_bpmn_process_hash is set and there's an old migration event, then assume this is a revert
|
||||
# and that we should ensure that items like git revision remain consistent
|
||||
git_revision_to_use = None
|
||||
if target_bpmn_process_hash is not None:
|
||||
# NOTE: there is a potential bug where there could be many git revisions for a bpmn process hash
|
||||
# so this could pick up a different git revision than the revert event passed in.
|
||||
# This is an edge case though and the git revision is close enough and more informational
|
||||
old_migration_event = (
|
||||
ProcessInstanceMigrationDetailModel.query.filter_by(
|
||||
initial_bpmn_process_hash=target_bpmn_process_hash, target_bpmn_process_hash=initial_bpmn_process_hash
|
||||
ProcessInstanceMigrationDetailModel.query.filter(
|
||||
or_(
|
||||
ProcessInstanceMigrationDetailModel.initial_bpmn_process_hash == target_bpmn_process_hash,
|
||||
ProcessInstanceMigrationDetailModel.target_bpmn_process_hash == target_bpmn_process_hash,
|
||||
)
|
||||
)
|
||||
.join(ProcessInstanceEventModel)
|
||||
.filter(ProcessInstanceEventModel.process_instance_id == process_instance.id)
|
||||
|
@ -320,7 +324,10 @@ class ProcessInstanceService:
|
|||
.first()
|
||||
)
|
||||
if old_migration_event is not None:
|
||||
git_revision_to_use = old_migration_event.initial_git_revision
|
||||
if old_migration_event.initial_bpmn_process_hash == target_bpmn_process_hash:
|
||||
git_revision_to_use = old_migration_event.initial_git_revision
|
||||
elif old_migration_event.target_bpmn_process_hash == target_bpmn_process_hash:
|
||||
git_revision_to_use = old_migration_event.target_bpmn_process_hash
|
||||
if git_revision_to_use is None:
|
||||
try:
|
||||
git_revision_to_use = GitService.get_current_revision()
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_96f6665" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.0.0-dev">
|
||||
<bpmn:process id="Process_migration_test_wlm607w" isExecutable="true">
|
||||
<bpmn:startEvent id="StartEvent_top">
|
||||
<bpmn:outgoing>Flow_17db3yp</bpmn:outgoing>
|
||||
</bpmn:startEvent>
|
||||
<bpmn:sequenceFlow id="Flow_17db3yp" sourceRef="StartEvent_top" targetRef="subprocess_one" />
|
||||
<bpmn:endEvent id="EndEvent_1">
|
||||
<bpmn:incoming>Flow_0m0he21</bpmn:incoming>
|
||||
</bpmn:endEvent>
|
||||
<bpmn:sequenceFlow id="Flow_0m0he21" sourceRef="subprocess_one" targetRef="EndEvent_1" />
|
||||
<bpmn:subProcess id="subprocess_one">
|
||||
<bpmn:incoming>Flow_17db3yp</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_0m0he21</bpmn:outgoing>
|
||||
<bpmn:startEvent id="StartEvent_sub">
|
||||
<bpmn:outgoing>Flow_01eckoj</bpmn:outgoing>
|
||||
</bpmn:startEvent>
|
||||
<bpmn:sequenceFlow id="Flow_01eckoj" sourceRef="StartEvent_sub" targetRef="manual_task_one" />
|
||||
<bpmn:endEvent id="Event_0fx2psf">
|
||||
<bpmn:incoming>Flow_0s3wg15</bpmn:incoming>
|
||||
</bpmn:endEvent>
|
||||
<bpmn:sequenceFlow id="Flow_0s7769x" sourceRef="manual_task_one" targetRef="manual_task_two" />
|
||||
<bpmn:manualTask id="manual_task_one" name="Manual Task One">
|
||||
<bpmn:incoming>Flow_01eckoj</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_0s7769x</bpmn:outgoing>
|
||||
</bpmn:manualTask>
|
||||
<bpmn:sequenceFlow id="Flow_17fvyk2" sourceRef="manual_task_two" targetRef="manual_task_three" />
|
||||
<bpmn:manualTask id="manual_task_two">
|
||||
<bpmn:incoming>Flow_0s7769x</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_17fvyk2</bpmn:outgoing>
|
||||
</bpmn:manualTask>
|
||||
<bpmn:sequenceFlow id="Flow_0s3wg15" sourceRef="manual_task_three" targetRef="Event_0fx2psf" />
|
||||
<bpmn:manualTask id="manual_task_three">
|
||||
<bpmn:incoming>Flow_17fvyk2</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_0s3wg15</bpmn:outgoing>
|
||||
</bpmn:manualTask>
|
||||
</bpmn:subProcess>
|
||||
</bpmn:process>
|
||||
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_migration_test_wlm607w">
|
||||
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_top">
|
||||
<dc:Bounds x="179" y="159" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Event_14za570_di" bpmnElement="EndEvent_1">
|
||||
<dc:Bounds x="462" y="159" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_115q6jv_di" bpmnElement="subprocess_one">
|
||||
<dc:Bounds x="280" y="137" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="Flow_17db3yp_di" bpmnElement="Flow_17db3yp">
|
||||
<di:waypoint x="215" y="177" />
|
||||
<di:waypoint x="280" y="177" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_0m0he21_di" bpmnElement="Flow_0m0he21">
|
||||
<di:waypoint x="380" y="177" />
|
||||
<di:waypoint x="462" y="177" />
|
||||
</bpmndi:BPMNEdge>
|
||||
</bpmndi:BPMNPlane>
|
||||
</bpmndi:BPMNDiagram>
|
||||
<bpmndi:BPMNDiagram id="BPMNDiagram_0fjhef4">
|
||||
<bpmndi:BPMNPlane id="BPMNPlane_1rqwee3" bpmnElement="subprocess_one">
|
||||
<bpmndi:BPMNShape id="Event_0bneyqp_di" bpmnElement="StartEvent_sub">
|
||||
<dc:Bounds x="452" y="302" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Event_0fx2psf_di" bpmnElement="Event_0fx2psf">
|
||||
<dc:Bounds x="932" y="302" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_1lv4tyw_di" bpmnElement="manual_task_one">
|
||||
<dc:Bounds x="540" y="280" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_0938qt9_di" bpmnElement="manual_task_two">
|
||||
<dc:Bounds x="670" y="280" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_05r8cox_di" bpmnElement="manual_task_three">
|
||||
<dc:Bounds x="790" y="280" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="Flow_01eckoj_di" bpmnElement="Flow_01eckoj">
|
||||
<di:waypoint x="488" y="320" />
|
||||
<di:waypoint x="540" y="320" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_0s7769x_di" bpmnElement="Flow_0s7769x">
|
||||
<di:waypoint x="640" y="320" />
|
||||
<di:waypoint x="670" y="320" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_17fvyk2_di" bpmnElement="Flow_17fvyk2">
|
||||
<di:waypoint x="770" y="320" />
|
||||
<di:waypoint x="790" y="320" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_0s3wg15_di" bpmnElement="Flow_0s3wg15">
|
||||
<di:waypoint x="890" y="320" />
|
||||
<di:waypoint x="932" y="320" />
|
||||
</bpmndi:BPMNEdge>
|
||||
</bpmndi:BPMNPlane>
|
||||
</bpmndi:BPMNDiagram>
|
||||
</bpmn:definitions>
|
|
@ -345,6 +345,108 @@ class TestProcessInstanceService(BaseTest):
|
|||
assert pi_migration_details.target_git_revision == "rev1"
|
||||
assert process_instance.bpmn_version_control_identifier == "rev1"
|
||||
|
||||
def test_it_can_migrate_a_process_instance_multiple_times_and_revert(
|
||||
self,
|
||||
app: Flask,
|
||||
mocker: MockerFixture,
|
||||
with_db_and_bpmn_file_cleanup: None,
|
||||
) -> None:
|
||||
initiator_user = self.find_or_create_user("initiator_user")
|
||||
process_model = load_test_spec(
|
||||
process_model_id="test_group/migration-test-with-subprocess",
|
||||
process_model_source_directory="migration-test-with-subprocess",
|
||||
bpmn_file_name="migration-initial.bpmn",
|
||||
)
|
||||
mock_get_current_revision = mocker.patch.object(GitService, "get_current_revision")
|
||||
|
||||
# Set the return value for the first call
|
||||
process_instance = self.create_process_instance_from_process_model(
|
||||
process_model=process_model, user=initiator_user, bpmn_version_control_identifier="rev1"
|
||||
)
|
||||
processor = ProcessInstanceProcessor(process_instance)
|
||||
processor.do_engine_steps(save=True, execution_strategy_name="greedy")
|
||||
initial_bpmn_process_hash = process_instance.bpmn_process_definition.full_process_model_hash
|
||||
assert initial_bpmn_process_hash is not None
|
||||
|
||||
spiff_task = processor.__class__.get_task_by_bpmn_identifier("manual_task_two", processor.bpmn_process_instance)
|
||||
assert spiff_task is None
|
||||
|
||||
new_file_path = os.path.join(
|
||||
app.instance_path,
|
||||
"..",
|
||||
"..",
|
||||
"tests",
|
||||
"data",
|
||||
"migration-test-with-subprocess",
|
||||
"migration-new.bpmn",
|
||||
)
|
||||
with open(new_file_path) as f:
|
||||
new_contents = f.read().encode()
|
||||
|
||||
SpecFileService.update_file(
|
||||
process_model_info=process_model,
|
||||
file_name="migration-initial.bpmn",
|
||||
binary_data=new_contents,
|
||||
update_process_cache_only=True,
|
||||
)
|
||||
|
||||
process_instance = ProcessInstanceModel.query.filter_by(id=process_instance.id).first()
|
||||
mock_get_current_revision.return_value = "rev2"
|
||||
ProcessInstanceService.migrate_process_instance(process_instance, user=initiator_user)
|
||||
process_instance = ProcessInstanceModel.query.filter_by(id=process_instance.id).first()
|
||||
assert process_instance.bpmn_version_control_identifier == "rev2"
|
||||
processor = ProcessInstanceProcessor(process_instance)
|
||||
processor.do_engine_steps(save=True, execution_strategy_name="greedy")
|
||||
target_bpmn_process_hash_one = process_instance.bpmn_process_definition.full_process_model_hash
|
||||
assert target_bpmn_process_hash_one is not None
|
||||
spiff_task = processor.__class__.get_task_by_bpmn_identifier("manual_task_two", processor.bpmn_process_instance)
|
||||
assert spiff_task is not None
|
||||
|
||||
new_file_path = os.path.join(
|
||||
app.instance_path,
|
||||
"..",
|
||||
"..",
|
||||
"tests",
|
||||
"data",
|
||||
"migration-test-with-subprocess",
|
||||
"migration-new-2.bpmn",
|
||||
)
|
||||
with open(new_file_path) as f:
|
||||
new_contents = f.read().encode()
|
||||
|
||||
SpecFileService.update_file(
|
||||
process_model_info=process_model,
|
||||
file_name="migration-initial.bpmn",
|
||||
binary_data=new_contents,
|
||||
update_process_cache_only=True,
|
||||
)
|
||||
|
||||
process_instance = ProcessInstanceModel.query.filter_by(id=process_instance.id).first()
|
||||
mock_get_current_revision.return_value = "rev3"
|
||||
ProcessInstanceService.migrate_process_instance(process_instance, user=initiator_user)
|
||||
process_instance = ProcessInstanceModel.query.filter_by(id=process_instance.id).first()
|
||||
assert process_instance.bpmn_version_control_identifier == "rev3"
|
||||
processor = ProcessInstanceProcessor(process_instance)
|
||||
processor.do_engine_steps(save=True, execution_strategy_name="greedy")
|
||||
target_bpmn_process_hash_two = process_instance.bpmn_process_definition.full_process_model_hash
|
||||
assert target_bpmn_process_hash_two is not None
|
||||
spiff_task = processor.__class__.get_task_by_bpmn_identifier("manual_task_three", processor.bpmn_process_instance)
|
||||
assert spiff_task is not None
|
||||
|
||||
ProcessInstanceService.migrate_process_instance(
|
||||
process_instance, user=initiator_user, target_bpmn_process_hash=initial_bpmn_process_hash
|
||||
)
|
||||
processor = ProcessInstanceProcessor(process_instance)
|
||||
spiff_task = processor.__class__.get_task_by_bpmn_identifier("manual_task_two", processor.bpmn_process_instance)
|
||||
assert spiff_task is None
|
||||
human_task_one = process_instance.active_human_tasks[0]
|
||||
assert human_task_one.task_model.task_definition.bpmn_identifier == "manual_task_one"
|
||||
self.complete_next_manual_task(processor)
|
||||
assert process_instance.status == ProcessInstanceStatus.complete.value
|
||||
|
||||
process_instance = ProcessInstanceModel.query.filter_by(id=process_instance.id).first()
|
||||
assert process_instance.bpmn_version_control_identifier == "rev1"
|
||||
|
||||
def test_it_can_check_if_a_process_instance_can_be_migrated(
|
||||
self,
|
||||
app: Flask,
|
||||
|
|
Loading…
Reference in New Issue