half-orm-dev 0.16.0a9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- half_orm_dev/__init__.py +1 -0
- half_orm_dev/cli/__init__.py +9 -0
- half_orm_dev/cli/commands/__init__.py +56 -0
- half_orm_dev/cli/commands/apply.py +13 -0
- half_orm_dev/cli/commands/clone.py +102 -0
- half_orm_dev/cli/commands/init.py +331 -0
- half_orm_dev/cli/commands/new.py +15 -0
- half_orm_dev/cli/commands/patch.py +317 -0
- half_orm_dev/cli/commands/prepare.py +21 -0
- half_orm_dev/cli/commands/prepare_release.py +119 -0
- half_orm_dev/cli/commands/promote_to.py +127 -0
- half_orm_dev/cli/commands/release.py +344 -0
- half_orm_dev/cli/commands/restore.py +14 -0
- half_orm_dev/cli/commands/sync.py +13 -0
- half_orm_dev/cli/commands/todo.py +73 -0
- half_orm_dev/cli/commands/undo.py +17 -0
- half_orm_dev/cli/commands/update.py +73 -0
- half_orm_dev/cli/commands/upgrade.py +191 -0
- half_orm_dev/cli/main.py +103 -0
- half_orm_dev/cli_extension.py +38 -0
- half_orm_dev/database.py +1389 -0
- half_orm_dev/hgit.py +1025 -0
- half_orm_dev/hop.py +167 -0
- half_orm_dev/manifest.py +43 -0
- half_orm_dev/modules.py +456 -0
- half_orm_dev/patch.py +281 -0
- half_orm_dev/patch_manager.py +1694 -0
- half_orm_dev/patch_validator.py +335 -0
- half_orm_dev/patches/0/1/0/00_half_orm_meta.database.sql +34 -0
- half_orm_dev/patches/0/1/0/01_alter_half_orm_meta.hop_release.sql +2 -0
- half_orm_dev/patches/0/1/0/02_half_orm_meta.view.hop_penultimate_release.sql +3 -0
- half_orm_dev/patches/log +2 -0
- half_orm_dev/patches/sql/half_orm_meta.sql +208 -0
- half_orm_dev/release_manager.py +2841 -0
- half_orm_dev/repo.py +1562 -0
- half_orm_dev/templates/.gitignore +15 -0
- half_orm_dev/templates/MANIFEST.in +1 -0
- half_orm_dev/templates/Pipfile +13 -0
- half_orm_dev/templates/README +25 -0
- half_orm_dev/templates/conftest_template +42 -0
- half_orm_dev/templates/init_module_template +10 -0
- half_orm_dev/templates/module_template_1 +12 -0
- half_orm_dev/templates/module_template_2 +6 -0
- half_orm_dev/templates/module_template_3 +3 -0
- half_orm_dev/templates/relation_test +23 -0
- half_orm_dev/templates/setup.py +81 -0
- half_orm_dev/templates/sql_adapter +9 -0
- half_orm_dev/templates/warning +12 -0
- half_orm_dev/utils.py +49 -0
- half_orm_dev/version.txt +1 -0
- half_orm_dev-0.16.0a9.dist-info/METADATA +935 -0
- half_orm_dev-0.16.0a9.dist-info/RECORD +58 -0
- half_orm_dev-0.16.0a9.dist-info/WHEEL +5 -0
- half_orm_dev-0.16.0a9.dist-info/licenses/AUTHORS +3 -0
- half_orm_dev-0.16.0a9.dist-info/licenses/LICENSE +14 -0
- half_orm_dev-0.16.0a9.dist-info/top_level.txt +2 -0
- tests/__init__.py +0 -0
- tests/conftest.py +329 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
half_orm_dev/__init__.py,sha256=0JpUPey1gacxXuIFGcpD2nTGso73fkak72qzTHttAJk,18
|
|
2
|
+
half_orm_dev/cli_extension.py,sha256=0F54AZpUfnuj4h1thwUORTSmwCuaoTyG8WqRH8DdWpQ,1109
|
|
3
|
+
half_orm_dev/database.py,sha256=t4zIw9MXghj15Nln28ZBUegrbicCBAQlDHdu0cCSjzY,60084
|
|
4
|
+
half_orm_dev/hgit.py,sha256=b1DeJhy-Y_kbY1L0ZmVRqcQk8rrxDcqJXiP6pmfsx9w,36746
|
|
5
|
+
half_orm_dev/hop.py,sha256=MXae6KV8bRsnXznfItk1V3PaEefLbV3znxgKDD5vCU8,5237
|
|
6
|
+
half_orm_dev/manifest.py,sha256=1BKDQf64baI8KOacW6Jx6IiopUtYitZcM44wrBwQhQw,1265
|
|
7
|
+
half_orm_dev/modules.py,sha256=c6R08hYbatUQMJQ1Wt4-crKWQPvxYprwvnqtSfrZOGc,16791
|
|
8
|
+
half_orm_dev/patch.py,sha256=HgzszYSuay2fXdViiSuG5OGstcZLLZvJJosciLk5OU0,11297
|
|
9
|
+
half_orm_dev/patch_manager.py,sha256=A2L3CV7Gijv6ChqyvGQkow9dK56_ZqUA1QB2Ot7i2PI,61729
|
|
10
|
+
half_orm_dev/patch_validator.py,sha256=x17WZXJtXWs8yRzW3SbitZQyW7YJAGYwIYSUyiYRrms,10842
|
|
11
|
+
half_orm_dev/release_manager.py,sha256=9fPXiGU3_h8xZ5lSEHO1VbnNGFFSkLt0ilA7JkSSjoI,106538
|
|
12
|
+
half_orm_dev/repo.py,sha256=wXa5YLrR08vR5XH9ZgE753PbzIIhOa983wYsGgapGCw,56190
|
|
13
|
+
half_orm_dev/utils.py,sha256=NTGvUZy6RHdgC3Rn7wCY-lSwBdeRV7vlLJ2D7-qiibw,1501
|
|
14
|
+
half_orm_dev/version.txt,sha256=U5aFjIuK_CjhhMNWk5s-Y3zOpurWsjIcNI5AjVfUVY0,10
|
|
15
|
+
half_orm_dev/cli/__init__.py,sha256=0CbMj8OIhZmglWakK7NhYPn302erUTEg2VHOdm1hRTQ,163
|
|
16
|
+
half_orm_dev/cli/main.py,sha256=hrXw3ShhzRCfcaSHjcWmXswWOm-WAzhvhwY4d1MS6x0,3836
|
|
17
|
+
half_orm_dev/cli/commands/__init__.py,sha256=KzaFOfRuNRly67wf5qjgGwVaErDmXvkzYt0phB7iFQs,1363
|
|
18
|
+
half_orm_dev/cli/commands/apply.py,sha256=6Sne5T6DQlPmHzY_9XR6srjAQnDNguB-jbA2IEDnzCk,211
|
|
19
|
+
half_orm_dev/cli/commands/clone.py,sha256=JUDDt-vz_WvGkm5HDFuZ3KZbclLyPaE4h665n8QfEEQ,3989
|
|
20
|
+
half_orm_dev/cli/commands/init.py,sha256=ZLwxlua-5-Nm1o20igAFcW2GAQGMPzD5mecXOe-oSjc,12551
|
|
21
|
+
half_orm_dev/cli/commands/new.py,sha256=OuTIoCG36OzE-3MPMQg6BEjG0IXbgsJgodIdUmKCnkI,365
|
|
22
|
+
half_orm_dev/cli/commands/patch.py,sha256=x6gnAZp8SQTBkuzF1c9DECvGUNYCLzd2AFC7PiKzKfU,11056
|
|
23
|
+
half_orm_dev/cli/commands/prepare.py,sha256=sYCt1p57hR7ob8IOzUiuLAcbIBtdyoZ1iYKSM0IxqRQ,466
|
|
24
|
+
half_orm_dev/cli/commands/prepare_release.py,sha256=ZPf-dSsnB_Vl6iJXT2F8xr-zWrGhoeXsPTapZjp1obs,3934
|
|
25
|
+
half_orm_dev/cli/commands/promote_to.py,sha256=2SsE45gf-rJddEJzEQgr7zX0kc5Odr4B_TWpBOtcCew,4965
|
|
26
|
+
half_orm_dev/cli/commands/release.py,sha256=E6nkP350ZwFK9teu40nWVxvAFMU7R9n1GKYYMIQe6QM,11642
|
|
27
|
+
half_orm_dev/cli/commands/restore.py,sha256=n9SP8n1EQUduvDoA0qxpSUQpphc48X-NovnocyGl98I,236
|
|
28
|
+
half_orm_dev/cli/commands/sync.py,sha256=D0Prr8W1ySYjP3D8H4MB05KHccFbhB8z2qB3Bs00swA,274
|
|
29
|
+
half_orm_dev/cli/commands/todo.py,sha256=av64TpieK0yHcn-gFDQlk-MCMG0Y4b74yur7vhAn4RI,2988
|
|
30
|
+
half_orm_dev/cli/commands/undo.py,sha256=GWUawPd71YPpY5Lx4E7zyoGlY0ZD4c8zIbh-ddo1DXk,343
|
|
31
|
+
half_orm_dev/cli/commands/update.py,sha256=OarpDkC8hF08UUv1l2i-2qpHICgpB6WDn9ziYvRB3I8,2325
|
|
32
|
+
half_orm_dev/cli/commands/upgrade.py,sha256=eOs29Bqpn6j6gi2ysvHLFgeFQYFDJIZeLZn6Ts7Ae3M,6301
|
|
33
|
+
half_orm_dev/patches/log,sha256=n7MNnGR09Obd87gXLzIi6zA76sI4RhOJzC25wb0TbKE,22
|
|
34
|
+
half_orm_dev/patches/0/1/0/00_half_orm_meta.database.sql,sha256=gMZ94YlyrftxcqDn0l-ToCTee4A_bnP58DpHcIT_T1w,1074
|
|
35
|
+
half_orm_dev/patches/0/1/0/01_alter_half_orm_meta.hop_release.sql,sha256=nhRbDi6sUenvVfOnoRuWSbLEC1cEfzrXbxDof2weq04,183
|
|
36
|
+
half_orm_dev/patches/0/1/0/02_half_orm_meta.view.hop_penultimate_release.sql,sha256=Bd0lXJ6vC0JNe06yqTWYVSrwVDElCI3McSS5pm-Ijlo,306
|
|
37
|
+
half_orm_dev/patches/sql/half_orm_meta.sql,sha256=Vl2YzEWpWdam-tC0ZE8iNMeTRzEHpxtNhdBThbHb2u4,5864
|
|
38
|
+
half_orm_dev/templates/.gitignore,sha256=-h7-1dAPCvvmejrw27rCiuLDmLeDoKeRNX9A86iJD9U,108
|
|
39
|
+
half_orm_dev/templates/MANIFEST.in,sha256=53BeBuKi8UtBWB6IG3VQZk9Ow8Iye6Zs14sP-gVyVDA,25
|
|
40
|
+
half_orm_dev/templates/Pipfile,sha256=u3lGJSk5HZwz-EOTrOdBYrkhGV6zgVtrrRPivrO5rmA,182
|
|
41
|
+
half_orm_dev/templates/README,sha256=Jb26Qv41KGSfD-6FpyqF7EEiPpI5nmhtpdsCJolg1pA,904
|
|
42
|
+
half_orm_dev/templates/conftest_template,sha256=i1-CR326a-AxYYREXlY_0_5nItwRR7myKH0H6elP40s,1136
|
|
43
|
+
half_orm_dev/templates/init_module_template,sha256=o3RAnhGayYUF7NEyI8bcI6JHmAZb2wPVNF-FdrjOnQU,345
|
|
44
|
+
half_orm_dev/templates/module_template_1,sha256=hRa0PiI6-dpBKNXJ9PuDuGocdrq712ujlSJGfJcXOh8,271
|
|
45
|
+
half_orm_dev/templates/module_template_2,sha256=CUqf-MwVeCc_sU_VScfI2nPsi9a8H_4EwVtjrLiD9Cw,156
|
|
46
|
+
half_orm_dev/templates/module_template_3,sha256=yjpQYT0EsIA6TI8KeyFaw_nHP9zCBma6o7g3P1MDs_M,187
|
|
47
|
+
half_orm_dev/templates/relation_test,sha256=5OMnz39mzYe3eVGsB44rgZckhUWOrDv7dWI8urC6MiI,574
|
|
48
|
+
half_orm_dev/templates/setup.py,sha256=hnnJ4cLnECbxzaTLeVBYd3aR-2kk6KuF1xkAoXWQN5A,2061
|
|
49
|
+
half_orm_dev/templates/sql_adapter,sha256=kAP5y7Qml3DKsbZLUeoVpeXjbQcWltHjkDznEDKNpek,190
|
|
50
|
+
half_orm_dev/templates/warning,sha256=4hlZ_rRdpmkXxOeRoVd9xnXBARYXn95e-iXrD1f2u7k,490
|
|
51
|
+
half_orm_dev-0.16.0a9.dist-info/licenses/AUTHORS,sha256=eWxqzRdLOt2gX0FMQj_wui03Od3jdlwa8xNe9tl84g0,113
|
|
52
|
+
half_orm_dev-0.16.0a9.dist-info/licenses/LICENSE,sha256=ufhxlSi6mttkGQTsGWrEoB3WA_fCPJ6-k07GSVBgyPw,644
|
|
53
|
+
tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
54
|
+
tests/conftest.py,sha256=uTtMgXULNB2tjon0y3cwBoEoRu20rHM_aGTreMX8kHk,9604
|
|
55
|
+
half_orm_dev-0.16.0a9.dist-info/METADATA,sha256=xk4b6bMN4A6K1KyhJJuoi9V74hlfa18W209ntIJvErU,27760
|
|
56
|
+
half_orm_dev-0.16.0a9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
57
|
+
half_orm_dev-0.16.0a9.dist-info/top_level.txt,sha256=-BjeqhKatJi7KdYuwzJ2pwpV-tMItvIf7HbY8tmK3ls,19
|
|
58
|
+
half_orm_dev-0.16.0a9.dist-info/RECORD,,
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
This file is part of half_orm_dev.
|
|
2
|
+
|
|
3
|
+
half_orm_dev is free software: you can redistribute it and/or modify
|
|
4
|
+
it under the terms of the GNU General Public License as published by
|
|
5
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
6
|
+
(at your option) any later version.
|
|
7
|
+
|
|
8
|
+
half_orm is distributed in the hope that it will be useful,
|
|
9
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
11
|
+
GNU General Public License for more details.
|
|
12
|
+
|
|
13
|
+
You should have received a copy of the GNU General Public License
|
|
14
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
tests/__init__.py
ADDED
|
File without changes
|
tests/conftest.py
ADDED
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Shared pytest fixtures for half_orm_dev tests.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
import tempfile
|
|
7
|
+
import shutil
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from unittest.mock import Mock, patch
|
|
10
|
+
from half_orm_dev.database import Database
|
|
11
|
+
from half_orm_dev.repo import Repo
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@pytest.fixture
|
|
15
|
+
def temp_repo():
|
|
16
|
+
"""
|
|
17
|
+
Create temporary directory structure for testing.
|
|
18
|
+
"""
|
|
19
|
+
temp_dir = tempfile.mkdtemp()
|
|
20
|
+
patches_dir = Path(temp_dir) / "Patches"
|
|
21
|
+
patches_dir.mkdir()
|
|
22
|
+
|
|
23
|
+
repo = Mock()
|
|
24
|
+
repo.base_dir = temp_dir
|
|
25
|
+
repo.devel = True
|
|
26
|
+
repo.name = "test_database"
|
|
27
|
+
repo.git_origin = "https://github.com/test/repo.git"
|
|
28
|
+
|
|
29
|
+
# Create default HGit mock with tag methods
|
|
30
|
+
mock_hgit = Mock()
|
|
31
|
+
mock_hgit.fetch_tags = Mock()
|
|
32
|
+
mock_hgit.tag_exists = Mock(return_value=False)
|
|
33
|
+
mock_hgit.create_tag = Mock()
|
|
34
|
+
mock_hgit.push_tag = Mock()
|
|
35
|
+
repo.hgit = mock_hgit
|
|
36
|
+
|
|
37
|
+
yield repo, temp_dir, patches_dir
|
|
38
|
+
|
|
39
|
+
shutil.rmtree(temp_dir)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@pytest.fixture
|
|
43
|
+
def patch_manager(temp_repo):
|
|
44
|
+
"""
|
|
45
|
+
Create PatchManager instance with temporary repo.
|
|
46
|
+
|
|
47
|
+
The repo.hgit already has default tag mocks configured in temp_repo fixture.
|
|
48
|
+
Tests can override repo.hgit if needed, but should use mock_hgit_complete fixture.
|
|
49
|
+
"""
|
|
50
|
+
from half_orm_dev.patch_manager import PatchManager
|
|
51
|
+
|
|
52
|
+
repo, temp_dir, patches_dir = temp_repo
|
|
53
|
+
repo.restore_database_from_schema = Repo.restore_database_from_schema.__get__(repo, type(repo))
|
|
54
|
+
mock_get_version = Mock(return_value=(16, 1))
|
|
55
|
+
repo.database.get_postgres_version = mock_get_version
|
|
56
|
+
patch_mgr = PatchManager(repo)
|
|
57
|
+
return patch_mgr, repo, temp_dir, patches_dir
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@pytest.fixture
|
|
61
|
+
def mock_hgit_complete():
|
|
62
|
+
"""
|
|
63
|
+
Create complete mock HGit for create_patch workflow tests.
|
|
64
|
+
|
|
65
|
+
Provides all necessary mocks for successful patch creation workflow:
|
|
66
|
+
- Branch validation (on ho-prod)
|
|
67
|
+
- Repository clean check
|
|
68
|
+
- Remote configuration check
|
|
69
|
+
- Remote fetch operations
|
|
70
|
+
- Branch synchronization check (NEW)
|
|
71
|
+
- Tag availability check
|
|
72
|
+
- Git operations (checkout, add, commit, tag, push)
|
|
73
|
+
- Branch operations (create, delete, checkout)
|
|
74
|
+
"""
|
|
75
|
+
mock_hgit = Mock()
|
|
76
|
+
|
|
77
|
+
# Branch and repo state
|
|
78
|
+
mock_hgit.branch = "ho-prod"
|
|
79
|
+
mock_hgit.repos_is_clean.return_value = True
|
|
80
|
+
mock_hgit.has_remote.return_value = True
|
|
81
|
+
|
|
82
|
+
# NEW: Branch synchronization check
|
|
83
|
+
# Returns (is_synced, status) tuple
|
|
84
|
+
mock_hgit.is_branch_synced.return_value = (True, "synced")
|
|
85
|
+
|
|
86
|
+
# Fetch operations
|
|
87
|
+
mock_hgit.fetch_from_origin.return_value = None
|
|
88
|
+
mock_hgit.fetch_tags.return_value = None
|
|
89
|
+
|
|
90
|
+
# Tag operations
|
|
91
|
+
mock_hgit.tag_exists.return_value = False # No existing tags
|
|
92
|
+
mock_hgit.create_tag.return_value = None
|
|
93
|
+
mock_hgit.push_tag.return_value = None
|
|
94
|
+
mock_hgit.delete_local_tag.return_value = None
|
|
95
|
+
|
|
96
|
+
# Branch operations
|
|
97
|
+
mock_hgit.checkout.return_value = None
|
|
98
|
+
mock_hgit.delete_local_branch.return_value = None
|
|
99
|
+
mock_hgit.push_branch.return_value = None
|
|
100
|
+
|
|
101
|
+
# Git proxy methods
|
|
102
|
+
mock_hgit.add.return_value = None
|
|
103
|
+
mock_hgit.commit.return_value = None
|
|
104
|
+
|
|
105
|
+
# Git repo access for reset operations
|
|
106
|
+
mock_git_repo = Mock()
|
|
107
|
+
mock_git_repo.git.reset.return_value = None
|
|
108
|
+
mock_hgit._HGit__git_repo = mock_git_repo
|
|
109
|
+
|
|
110
|
+
return mock_hgit
|
|
111
|
+
|
|
112
|
+
@pytest.fixture
|
|
113
|
+
def sample_patch_files():
|
|
114
|
+
"""
|
|
115
|
+
Provide sample patch file contents for testing.
|
|
116
|
+
"""
|
|
117
|
+
return {
|
|
118
|
+
'01_create_table.sql': 'CREATE TABLE users (id SERIAL PRIMARY KEY);',
|
|
119
|
+
'02_add_indexes.sql': 'CREATE INDEX idx_users_id ON users(id);',
|
|
120
|
+
'migrate.py': 'print("Running migration")',
|
|
121
|
+
'cleanup.py': 'print("Cleanup complete")',
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
@pytest.fixture
|
|
126
|
+
def mock_database():
|
|
127
|
+
"""
|
|
128
|
+
Mock database connection for testing.
|
|
129
|
+
|
|
130
|
+
Provides a mock database connection object that can be used
|
|
131
|
+
to test SQL execution without requiring a real database.
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
Mock: Mock database connection with execute_query method
|
|
135
|
+
"""
|
|
136
|
+
mock_db = Mock()
|
|
137
|
+
mock_db.execute_query = Mock()
|
|
138
|
+
mock_db.execute = Mock()
|
|
139
|
+
mock_db.cursor = Mock()
|
|
140
|
+
|
|
141
|
+
return mock_db
|
|
142
|
+
|
|
143
|
+
@pytest.fixture
|
|
144
|
+
def mock_database_for_schema_generation():
|
|
145
|
+
"""
|
|
146
|
+
Create complete Database mock for _generate_schema_sql() testing.
|
|
147
|
+
|
|
148
|
+
Provides a mock with all necessary attributes and methods for schema
|
|
149
|
+
generation tests, including mangled private attributes.
|
|
150
|
+
|
|
151
|
+
Returns:
|
|
152
|
+
Mock: Configured Database mock with:
|
|
153
|
+
- _Database__name: Database name (mangled private attribute)
|
|
154
|
+
- _collect_connection_params(): Returns connection parameters
|
|
155
|
+
- _get_connection_params(): Returns connection parameters
|
|
156
|
+
- _execute_pg_command(): Mock for pg_dump execution
|
|
157
|
+
|
|
158
|
+
Example:
|
|
159
|
+
def test_something(self, mock_database_for_schema_generation, tmp_path):
|
|
160
|
+
database = mock_database_for_schema_generation
|
|
161
|
+
model_dir = tmp_path / "model"
|
|
162
|
+
model_dir.mkdir()
|
|
163
|
+
|
|
164
|
+
result = Database._generate_schema_sql(database, "1.0.0", model_dir)
|
|
165
|
+
"""
|
|
166
|
+
mock_db = Mock(spec=Database)
|
|
167
|
+
|
|
168
|
+
# Set mangled private attribute for database name
|
|
169
|
+
mock_db._Database__name = "test_db"
|
|
170
|
+
|
|
171
|
+
# Mock connection parameter methods
|
|
172
|
+
connection_params = {
|
|
173
|
+
'user': 'test_user',
|
|
174
|
+
'password': 'test_pass',
|
|
175
|
+
'host': 'localhost',
|
|
176
|
+
'port': 5432,
|
|
177
|
+
'production': False
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
mock_db._collect_connection_params = Mock(return_value=connection_params)
|
|
181
|
+
mock_db._get_connection_params = Mock(return_value=connection_params)
|
|
182
|
+
|
|
183
|
+
# Mock pg_dump execution
|
|
184
|
+
mock_db._execute_pg_command = Mock()
|
|
185
|
+
|
|
186
|
+
return mock_db
|
|
187
|
+
|
|
188
|
+
"""
|
|
189
|
+
Additional fixtures for ReleaseManager tests.
|
|
190
|
+
Add these to tests/conftest.py
|
|
191
|
+
"""
|
|
192
|
+
|
|
193
|
+
@pytest.fixture
|
|
194
|
+
def mock_release_manager_basic(tmp_path):
|
|
195
|
+
"""
|
|
196
|
+
Create basic ReleaseManager with minimal mocks.
|
|
197
|
+
|
|
198
|
+
Provides:
|
|
199
|
+
- ReleaseManager instance
|
|
200
|
+
- Mock repo with base_dir
|
|
201
|
+
- Temporary releases/ directory
|
|
202
|
+
|
|
203
|
+
Returns:
|
|
204
|
+
Tuple of (release_mgr, mock_repo, tmp_path)
|
|
205
|
+
"""
|
|
206
|
+
from unittest.mock import Mock
|
|
207
|
+
from half_orm_dev.release_manager import ReleaseManager
|
|
208
|
+
|
|
209
|
+
mock_repo = Mock()
|
|
210
|
+
mock_repo.base_dir = str(tmp_path)
|
|
211
|
+
|
|
212
|
+
# Create releases/ directory
|
|
213
|
+
releases_dir = tmp_path / "releases"
|
|
214
|
+
releases_dir.mkdir()
|
|
215
|
+
|
|
216
|
+
release_mgr = ReleaseManager(mock_repo)
|
|
217
|
+
|
|
218
|
+
return release_mgr, mock_repo, tmp_path
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
@pytest.fixture
|
|
222
|
+
def mock_release_manager_with_hgit(mock_release_manager_basic):
|
|
223
|
+
"""
|
|
224
|
+
Create ReleaseManager with fully mocked HGit.
|
|
225
|
+
|
|
226
|
+
Provides:
|
|
227
|
+
- ReleaseManager instance
|
|
228
|
+
- Mock repo with HGit configured
|
|
229
|
+
- HGit mocked for all Git operations
|
|
230
|
+
- Default "happy path" configuration
|
|
231
|
+
|
|
232
|
+
Returns:
|
|
233
|
+
Tuple of (release_mgr, mock_repo, mock_hgit, tmp_path)
|
|
234
|
+
"""
|
|
235
|
+
from unittest.mock import Mock
|
|
236
|
+
|
|
237
|
+
release_mgr, mock_repo, tmp_path = mock_release_manager_basic
|
|
238
|
+
|
|
239
|
+
# Mock HGit with all required methods
|
|
240
|
+
mock_hgit = Mock()
|
|
241
|
+
|
|
242
|
+
# Branch and repo state
|
|
243
|
+
mock_hgit.branch = "ho-prod"
|
|
244
|
+
mock_hgit.repos_is_clean.return_value = True
|
|
245
|
+
|
|
246
|
+
# Fetch and sync
|
|
247
|
+
mock_hgit.fetch_from_origin.return_value = None
|
|
248
|
+
mock_hgit.is_branch_synced.return_value = (True, "synced")
|
|
249
|
+
mock_hgit.pull.return_value = None
|
|
250
|
+
|
|
251
|
+
# Git operations
|
|
252
|
+
mock_hgit.add.return_value = None
|
|
253
|
+
mock_hgit.commit.return_value = None
|
|
254
|
+
mock_hgit.push.return_value = None
|
|
255
|
+
|
|
256
|
+
mock_repo.hgit = mock_hgit
|
|
257
|
+
|
|
258
|
+
return release_mgr, mock_repo, mock_hgit, tmp_path
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
@pytest.fixture
|
|
262
|
+
def mock_release_manager_with_production(mock_release_manager_with_hgit):
|
|
263
|
+
"""
|
|
264
|
+
Create ReleaseManager with production version mocking.
|
|
265
|
+
|
|
266
|
+
Provides:
|
|
267
|
+
- Everything from mock_release_manager_with_hgit
|
|
268
|
+
- Mock _get_production_version() to return "1.3.5"
|
|
269
|
+
- Mock model/schema.sql symlink (for tests that directly test _get_production_version)
|
|
270
|
+
- Default production version: 1.3.5
|
|
271
|
+
|
|
272
|
+
Returns:
|
|
273
|
+
Tuple of (release_mgr, mock_repo, mock_hgit, tmp_path, prod_version)
|
|
274
|
+
"""
|
|
275
|
+
from unittest.mock import Mock, patch
|
|
276
|
+
|
|
277
|
+
release_mgr, mock_repo, mock_hgit, tmp_path = mock_release_manager_with_hgit
|
|
278
|
+
|
|
279
|
+
# Create model/ directory with schema files (for tests that test _get_production_version directly)
|
|
280
|
+
model_dir = tmp_path / "model"
|
|
281
|
+
model_dir.mkdir()
|
|
282
|
+
|
|
283
|
+
# Create versioned schema file
|
|
284
|
+
prod_version = "1.3.5"
|
|
285
|
+
schema_file = model_dir / f"schema-{prod_version}.sql"
|
|
286
|
+
schema_file.write_text("-- Schema version 1.3.5")
|
|
287
|
+
|
|
288
|
+
# Create symlink schema.sql -> schema-1.3.5.sql
|
|
289
|
+
schema_symlink = model_dir / "schema.sql"
|
|
290
|
+
schema_symlink.symlink_to(f"schema-{prod_version}.sql")
|
|
291
|
+
|
|
292
|
+
# Mock database last_release_s
|
|
293
|
+
mock_database = Mock()
|
|
294
|
+
mock_database.last_release_s = prod_version
|
|
295
|
+
mock_repo.database = mock_database
|
|
296
|
+
|
|
297
|
+
# CRITICAL: Mock _get_production_version() to avoid reading symlink in most tests
|
|
298
|
+
# This allows tests to focus on workflow without setting up full file structure
|
|
299
|
+
release_mgr._get_production_version = Mock(return_value=prod_version)
|
|
300
|
+
|
|
301
|
+
return release_mgr, mock_repo, mock_hgit, tmp_path, prod_version
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
@pytest.fixture
|
|
305
|
+
def sample_release_files(tmp_path):
|
|
306
|
+
"""
|
|
307
|
+
Create sample release files in releases/ directory.
|
|
308
|
+
|
|
309
|
+
Creates:
|
|
310
|
+
- releases/1.3.4.txt (production)
|
|
311
|
+
- releases/1.3.5-rc2.txt (rc)
|
|
312
|
+
- releases/1.4.0-stage.txt (stage)
|
|
313
|
+
|
|
314
|
+
Returns:
|
|
315
|
+
Tuple of (releases_dir, dict of created files)
|
|
316
|
+
"""
|
|
317
|
+
releases_dir = tmp_path / "releases"
|
|
318
|
+
releases_dir.mkdir()
|
|
319
|
+
|
|
320
|
+
files = {
|
|
321
|
+
'1.3.4.txt': '',
|
|
322
|
+
'1.3.5-rc2.txt': '',
|
|
323
|
+
'1.4.0-stage.txt': '',
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
for filename, content in files.items():
|
|
327
|
+
(releases_dir / filename).write_text(content)
|
|
328
|
+
|
|
329
|
+
return releases_dir, files
|