From d268e85e1fbef2afea747ab8d218e2e9cb8d9029 Mon Sep 17 00:00:00 2001 From: mike cullerton Date: Mon, 26 Sep 2022 13:40:09 -0400 Subject: [PATCH] First stab --- .../{8fca9cdfb5be_.py => 838230f05aa0_.py} | 8 ++++--- .../models/process_instance.py | 3 +++ .../routes/process_api_blueprint.py | 13 +++++++--- .../services/git_service.py | 24 +++++++++++++++++++ .../services/process_instance_service.py | 5 ++++ .../integration/test_process_api.py | 4 ++++ 6 files changed, 51 insertions(+), 6 deletions(-) rename migrations/versions/{8fca9cdfb5be_.py => 838230f05aa0_.py} (98%) create mode 100644 src/spiffworkflow_backend/services/git_service.py diff --git a/migrations/versions/8fca9cdfb5be_.py b/migrations/versions/838230f05aa0_.py similarity index 98% rename from migrations/versions/8fca9cdfb5be_.py rename to migrations/versions/838230f05aa0_.py index 35204a48..214c96ed 100644 --- a/migrations/versions/8fca9cdfb5be_.py +++ b/migrations/versions/838230f05aa0_.py @@ -1,8 +1,8 @@ """empty message -Revision ID: 8fca9cdfb5be +Revision ID: 838230f05aa0 Revises: -Create Date: 2022-09-26 10:38:30.015462 +Create Date: 2022-09-26 12:12:48.657804 """ from alembic import op @@ -10,7 +10,7 @@ import sqlalchemy as sa # revision identifiers, used by Alembic. -revision = '8fca9cdfb5be' +revision = '838230f05aa0' down_revision = None branch_labels = None depends_on = None @@ -105,6 +105,8 @@ def upgrade(): sa.Column('updated_at_in_seconds', sa.Integer(), nullable=True), sa.Column('created_at_in_seconds', sa.Integer(), nullable=True), sa.Column('status', sa.String(length=50), nullable=True), + sa.Column('bpmn_version_control_type', sa.String(length=50), nullable=True), + sa.Column('bpmn_version_control_identifier', sa.String(length=255), nullable=True), sa.ForeignKeyConstraint(['process_initiator_id'], ['user.id'], ), sa.PrimaryKeyConstraint('id') ) diff --git a/src/spiffworkflow_backend/models/process_instance.py b/src/spiffworkflow_backend/models/process_instance.py index ac0bb315..c331c5fb 100644 --- a/src/spiffworkflow_backend/models/process_instance.py +++ b/src/spiffworkflow_backend/models/process_instance.py @@ -106,6 +106,8 @@ class ProcessInstanceModel(SpiffworkflowBaseDBModel): status: str = db.Column(db.String(50)) bpmn_xml_file_contents: bytes | None = None + bpmn_version_control_type: str = db.Column(db.String(50)) + bpmn_version_control_identifier: str = db.Column(db.String(255)) @property def serialized(self) -> dict[str, Any]: @@ -159,6 +161,7 @@ class ProcessInstanceModelSchema(Schema): "updated_at_in_seconds", "created_at_in_seconds", "status", + "bpmn_version_control_identifier" ] status = marshmallow.fields.Method("get_status", dump_only=True) diff --git a/src/spiffworkflow_backend/routes/process_api_blueprint.py b/src/spiffworkflow_backend/routes/process_api_blueprint.py index 898d9f11..a8748a55 100644 --- a/src/spiffworkflow_backend/routes/process_api_blueprint.py +++ b/src/spiffworkflow_backend/routes/process_api_blueprint.py @@ -49,6 +49,7 @@ from spiffworkflow_backend.models.spiff_logging import SpiffLoggingModel from spiffworkflow_backend.models.user import UserModel from spiffworkflow_backend.services.error_handling_service import ErrorHandlingService from spiffworkflow_backend.services.file_system_service import FileSystemService +from spiffworkflow_backend.services.git_service import GitService from spiffworkflow_backend.services.message_service import MessageService from spiffworkflow_backend.services.process_instance_processor import ( ProcessInstanceProcessor, @@ -609,12 +610,18 @@ def process_instance_show( ) -> flask.wrappers.Response: """Create_process_instance.""" process_instance = find_process_instance_by_id_or_raise(process_instance_id) + current_version_control_revision = GitService.get_current_revision() process_model = get_process_model(process_model_id, process_group_id) if process_model.primary_file_name: - bpmn_xml_file_contents = SpecFileService.get_data( - process_model, process_model.primary_file_name - ) + if process_instance.bpmn_version_control_identifier == current_version_control_revision: + bpmn_xml_file_contents = SpecFileService.get_data( + process_model, process_model.primary_file_name + ) + else: + bpmn_xml_file_contents = GitService.get_instance_file_contents_for_revision( + process_model, process_instance.bpmn_version_control_identifier + ) process_instance.bpmn_xml_file_contents = bpmn_xml_file_contents return make_response(jsonify(process_instance), 200) diff --git a/src/spiffworkflow_backend/services/git_service.py b/src/spiffworkflow_backend/services/git_service.py new file mode 100644 index 00000000..1a296cdd --- /dev/null +++ b/src/spiffworkflow_backend/services/git_service.py @@ -0,0 +1,24 @@ +import os +from flask import current_app + +from spiffworkflow_backend.models.process_model import ProcessModelInfo +from spiffworkflow_backend.services.file_system_service import FileSystemService + + +class GitService: + + @staticmethod + def get_current_revision() -> str: + bpmn_spec_absolute_dir = current_app.config["BPMN_SPEC_ABSOLUTE_DIR"] + # The value includes a carriage return character at the end, so we don't grab the last character + current_git_revision = os.popen(f"cd {bpmn_spec_absolute_dir} && git rev-parse --short HEAD").read()[:-1] + return current_git_revision + + @staticmethod + def get_instance_file_contents_for_revision(process_model: ProcessModelInfo, revision: str) -> str: + bpmn_spec_absolute_dir = current_app.config["BPMN_SPEC_ABSOLUTE_DIR"] + process_model_relative_path = FileSystemService.process_model_relative_path(process_model) + shell_command = f"cd {bpmn_spec_absolute_dir} && git show {revision}:{process_model_relative_path}/{process_model.primary_file_name}" + # git show 78ae5eb:category_number_one/script-task/script-task.bpmn + file_contents = os.popen(shell_command).read()[:-1] + return file_contents diff --git a/src/spiffworkflow_backend/services/process_instance_service.py b/src/spiffworkflow_backend/services/process_instance_service.py index 6db9312b..69e15a2b 100644 --- a/src/spiffworkflow_backend/services/process_instance_service.py +++ b/src/spiffworkflow_backend/services/process_instance_service.py @@ -1,4 +1,5 @@ """Process_instance_service.""" +import os import time from typing import Any from typing import Dict @@ -27,6 +28,7 @@ from spiffworkflow_backend.models.task import Task from spiffworkflow_backend.models.task_event import TaskAction from spiffworkflow_backend.models.task_event import TaskEventModel from spiffworkflow_backend.models.user import UserModel +from spiffworkflow_backend.services.git_service import GitService from spiffworkflow_backend.services.process_instance_processor import ( ProcessInstanceProcessor, ) @@ -47,12 +49,15 @@ class ProcessInstanceService: process_group_identifier: Optional[str] = None, ) -> ProcessInstanceModel: """Get_process_instance_from_spec.""" + current_git_revision = GitService.get_current_revision() process_instance_model = ProcessInstanceModel( status=ProcessInstanceStatus.not_started.value, process_initiator=user, process_model_identifier=process_model_identifier, process_group_identifier=process_group_identifier, start_in_seconds=round(time.time()), + bpmn_version_control_type='git', + bpmn_version_control_identifier=current_git_revision, ) db.session.add(process_instance_model) db.session.commit() diff --git a/tests/spiffworkflow_backend/integration/test_process_api.py b/tests/spiffworkflow_backend/integration/test_process_api.py index f08a66b2..75ea4716 100644 --- a/tests/spiffworkflow_backend/integration/test_process_api.py +++ b/tests/spiffworkflow_backend/integration/test_process_api.py @@ -25,6 +25,7 @@ from spiffworkflow_backend.models.process_model import NotificationType from spiffworkflow_backend.models.process_model import ProcessModelInfoSchema from spiffworkflow_backend.models.task_event import TaskEventModel from spiffworkflow_backend.models.user import UserModel +from spiffworkflow_backend.services.git_service import GitService from spiffworkflow_backend.services.process_instance_processor import ( ProcessInstanceProcessor, ) @@ -689,6 +690,9 @@ class TestProcessApi(BaseTest): assert response.json["updated_at_in_seconds"] is not None assert response.json["status"] == "not_started" assert response.json["process_model_identifier"] == test_process_model_id + # TODO: mock out the responses for the git service so we can do something like this + # current_revision = GitService.get_current_revision() + # assert response.json["bpmn_version_control_identifier"] == current_revision def test_process_instance_run( self, app: Flask, client: FlaskClient, with_db_and_bpmn_file_cleanup: None