11from pathlib import Path
22
33from docker .models .networks import Network
4+ from loguru import logger
45
56from robotics_integration_tests .custom_containers .image_builder import build_image_once
67from robotics_integration_tests .custom_containers .stream_logging_docker_container import (
78 StreamLoggingDockerContainer ,
89)
910from robotics_integration_tests .settings .settings import settings
1011
12+ # Where a local checkout is mounted inside the migrations runner.
13+ _LOCAL_REPO_MOUNT = "/src"
14+
15+
16+ def _with_migrations_source (
17+ container : StreamLoggingDockerContainer ,
18+ source_dir : str ,
19+ project_folder : str ,
20+ setting_name : str ,
21+ ) -> StreamLoggingDockerContainer :
22+ """Take migrations from a local checkout instead of cloning from GitHub.
23+
24+ Mounted read-only; the entrypoint copies it into the container so that nothing
25+ can be written back into the working tree. The copy means uncommitted and
26+ untracked migrations are picked up, which is the reason to use this at all.
27+
28+ Validation is deliberately strict and happens here, before the container
29+ starts: silently falling back to the GitHub clone would leave you believing
30+ you had tested a local migration when you had not.
31+ """
32+ if not source_dir :
33+ return container
34+
35+ resolved : Path = Path (source_dir ).expanduser ().resolve ()
36+ if not resolved .is_dir ():
37+ raise ValueError (
38+ f"{ setting_name } is set to '{ source_dir } ' (resolved to '{ resolved } '), "
39+ "which is not a directory."
40+ )
41+
42+ project_dir : Path = resolved / project_folder
43+ if not list (project_dir .glob ("*.csproj" )):
44+ raise ValueError (
45+ f"{ setting_name } is set to '{ resolved } ', but no .csproj was found in "
46+ f"'{ project_dir } '. Point it at the repository root of the service, not "
47+ "at the project folder."
48+ )
49+
50+ logger .info (f"Using migrations from local checkout: { resolved } " )
51+ return container .with_volume_mapping (
52+ str (resolved ), _LOCAL_REPO_MOUNT , "ro"
53+ ).with_env ("LOCAL_REPO_PATH" , _LOCAL_REPO_MOUNT )
54+
1155
1256def _with_design_time_database_config (
1357 container : StreamLoggingDockerContainer , postgres_connection_string : str
@@ -54,6 +98,12 @@ def create_migrations_runner_container(
5498 .with_env ("EF_PROJECT_PATH" , settings .BACKEND_PROJECT_FILE_FOLDER )
5599 .with_env ("EF_STARTUP_PATH" , settings .BACKEND_PROJECT_FILE_FOLDER )
56100 )
101+ container = _with_migrations_source (
102+ container ,
103+ source_dir = settings .MIGRATIONS_SOURCE_DIR ,
104+ project_folder = settings .BACKEND_PROJECT_FILE_FOLDER ,
105+ setting_name = "MIGRATIONS_SOURCE_DIR" ,
106+ )
57107 return _with_design_time_database_config (container , postgres_connection_string )
58108
59109
@@ -78,4 +128,10 @@ def create_sara_migrations_runner_container(
78128 .with_env ("EF_PROJECT_PATH" , settings .SARA_BACKEND_PROJECT_FILE_FOLDER )
79129 .with_env ("EF_STARTUP_PATH" , settings .SARA_BACKEND_PROJECT_FILE_FOLDER )
80130 )
131+ container = _with_migrations_source (
132+ container ,
133+ source_dir = settings .SARA_MIGRATIONS_SOURCE_DIR ,
134+ project_folder = settings .SARA_BACKEND_PROJECT_FILE_FOLDER ,
135+ setting_name = "SARA_MIGRATIONS_SOURCE_DIR" ,
136+ )
81137 return _with_design_time_database_config (container , postgres_connection_string )
0 commit comments