half-orm-dev 1.0.0a34__tar.gz → 1.0.0a35__tar.gz
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-1.0.0a34/half_orm_dev.egg-info → half_orm_dev-1.0.0a35}/PKG-INFO +1 -1
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/file_executor.py +3 -1
- half_orm_dev-1.0.0a35/half_orm_dev/migrations/1/0/0/a35/00_drop_stale_release_schemas.py +145 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/repo.py +48 -9
- half_orm_dev-1.0.0a35/half_orm_dev/version.txt +1 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35/half_orm_dev.egg-info}/PKG-INFO +1 -1
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev.egg-info/SOURCES.txt +1 -0
- half_orm_dev-1.0.0a34/half_orm_dev/version.txt +0 -1
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/AUTHORS +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/LICENSE +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/README.md +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/__init__.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/_bootstrap_runner.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/cli/__init__.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/cli/commands/__init__.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/cli/commands/apply.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/cli/commands/check.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/cli/commands/clone.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/cli/commands/init.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/cli/commands/migrate.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/cli/commands/patch.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/cli/commands/recover.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/cli/commands/release.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/cli/commands/restore.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/cli/commands/revert_migration.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/cli/commands/rollback.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/cli/commands/set_git_origin.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/cli/commands/sync.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/cli/commands/todo.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/cli/commands/undo.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/cli/commands/upgrade.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/cli/main.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/cli_extension.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/database.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/decorators.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/hgit.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/migration_manager.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/migrations/0/17/1/00_move_to_hop.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/migrations/0/17/1/01_txt_to_toml.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/migrations/0/17/4/00_toml_dict_format.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/migrations/0/17/4/02_move_patches_to_subdirs.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/migrations/0/17/5/01_update_pyproject_dependency.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/migrations/0/18/0/00_add_async_support.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/migrations/0/18/0/01_update_default_tests.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/migrations/1/0/0/a20/01_update_gitignore.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/migrations/1/0/0/a33/00_metadata_to_data_sql.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/migrations/hop/BREAKING_CHANGES-1.0.0.md +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/modules.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/patch_manager.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/patch_validator.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/patches/0/1/0/00_half_orm_meta.database.sql +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/patches/0/1/0/01_alter_half_orm_meta.hop_release.sql +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/patches/0/1/0/02_half_orm_meta.view.hop_penultimate_release.sql +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/patches/log +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/patches/sql/half_orm_meta.sql +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/py.typed +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/release_file.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/release_manager.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/scripts/repair-metadata.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/templates/.gitignore +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/templates/MANIFEST.in +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/templates/README +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/templates/conftest_template +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/templates/git-hooks/pre-commit +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/templates/git-hooks/pre-push +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/templates/git-hooks/prepare-commit-msg +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/templates/git-hooks/reference-transaction +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/templates/init_module_template +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/templates/module_template_1 +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/templates/module_template_2 +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/templates/module_template_3 +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/templates/pyproject.toml +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/templates/relation_test +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/templates/sql_adapter +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/templates/warning +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/utils.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/venv_setup.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev.egg-info/dependency_links.txt +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev.egg-info/entry_points.txt +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev.egg-info/requires.txt +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev.egg-info/top_level.txt +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/pyproject.toml +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/setup.cfg +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/setup.py +0 -0
- {half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/tests/test_bootstrap_runner.py +0 -0
|
@@ -61,7 +61,9 @@ def execute_sql_file_psql(file_path: Path, database, database_name: str) -> None
|
|
|
61
61
|
try:
|
|
62
62
|
database.execute_pg_command('psql', '-v', 'ON_ERROR_STOP=1', '-d', database_name, '-f', str(file_path))
|
|
63
63
|
except Exception as e:
|
|
64
|
-
|
|
64
|
+
stderr = getattr(e, 'stderr', None)
|
|
65
|
+
detail = f"{e}\n{stderr.strip()}" if stderr else str(e)
|
|
66
|
+
raise FileExecutionError(f"psql execution failed for {file_path.name}: {detail}") from e
|
|
65
67
|
|
|
66
68
|
|
|
67
69
|
def execute_python_file(
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Migration 1.0.0a35 — drop stale release-X.Y.Z.sql on active branches
|
|
3
|
+
|
|
4
|
+
Before 1.0.0a33, restore_database_from_schema() rebuilt the database
|
|
5
|
+
from model/schema.sql + model/metadata-{version}.sql, and the latter
|
|
6
|
+
held half_orm_meta bookkeeping *only* - no application data.
|
|
7
|
+
generate_release_schema() then took a full pg_dump of that database, so
|
|
8
|
+
every model/release-{version}.sql produced this way captured the
|
|
9
|
+
structure plus the half_orm_meta rows and nothing else.
|
|
10
|
+
|
|
11
|
+
The a33 migration backfilled model/data-{version}.sql with the real,
|
|
12
|
+
complete snapshot, but left those release files untouched. They are
|
|
13
|
+
still what `patch apply` and `patch merge` restore from whenever a
|
|
14
|
+
release is in flight, so development databases come back up with no
|
|
15
|
+
application data at all - the symptom that motivated this migration
|
|
16
|
+
(a project whose release-0.3.10.sql carried 78 half_orm_meta.hop_release
|
|
17
|
+
rows and zero rows for its 39 other tables, against 2098 rows in
|
|
18
|
+
data-0.3.9.sql).
|
|
19
|
+
|
|
20
|
+
Rather than rebuilding those files here - which would mean restoring a
|
|
21
|
+
database and replaying every staged patch, per branch - this deletes
|
|
22
|
+
them. They are derived artifacts: the fallback already in
|
|
23
|
+
apply_patch_complete_workflow() rebuilds one from
|
|
24
|
+
restore_database_from_schema() (schema + full data) plus the staged
|
|
25
|
+
patches, then calls generate_release_schema() again. Deleting is
|
|
26
|
+
therefore self-healing, and costs one rebuild on the next `patch apply`.
|
|
27
|
+
|
|
28
|
+
A release schema is carried by every active branch: create_release()
|
|
29
|
+
commits it on ho-release/X.Y.Z, patch branches inherit a copy, and .hop/
|
|
30
|
+
syncing propagates it to ho-prod as well. All of them have to be
|
|
31
|
+
cleaned, and ho-prod in particular must not be skipped - syncing copies
|
|
32
|
+
.hop/ with `git checkout <source> -- .hop/`, so a copy left on ho-prod
|
|
33
|
+
would be restored onto every branch this migration just cleaned. For
|
|
34
|
+
the same reason the deletion never propagates on its own: that checkout
|
|
35
|
+
adds and overwrites, but never deletes.
|
|
36
|
+
|
|
37
|
+
Ordering therefore matters. Other branches are handled first, each with
|
|
38
|
+
its own commit, while ho-prod's copy is only staged - the migration
|
|
39
|
+
runner commits it, then pushes ho-prod, and only then syncs .hop/
|
|
40
|
+
outwards.
|
|
41
|
+
|
|
42
|
+
Committing on other branches is covered by the existing safety net:
|
|
43
|
+
capture_branches_snapshot() records ho-prod, release and patch branches
|
|
44
|
+
alike, and rollback_to_snapshot() resets each one should the migration
|
|
45
|
+
fail later. Following the convention in
|
|
46
|
+
Repo.sync_hop_to_active_branches(), those local commits are the
|
|
47
|
+
transaction (a failure propagates and triggers that rollback) while push
|
|
48
|
+
failures are reported rather than raised - the deletion is already
|
|
49
|
+
recorded locally, and an unpushed branch is recoverable.
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
import sys
|
|
53
|
+
from pathlib import Path
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def get_description():
|
|
57
|
+
return "Delete release-X.Y.Z.sql files generated before the metadata->data.sql switch"
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _affected_branches(repo):
|
|
61
|
+
"""Active release and patch branches, both of which carry release schemas."""
|
|
62
|
+
status = repo.hgit.get_active_branches_status()
|
|
63
|
+
names = []
|
|
64
|
+
for key in ('release_branches', 'patch_branches'):
|
|
65
|
+
for branch in status.get(key) or []:
|
|
66
|
+
name = branch.get('name')
|
|
67
|
+
if name and name not in names:
|
|
68
|
+
names.append(name)
|
|
69
|
+
return names
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _stale_release_schemas(repo, model_dir):
|
|
73
|
+
"""Repo-relative paths of the release schemas present on this branch."""
|
|
74
|
+
return [
|
|
75
|
+
str(path.relative_to(repo.base_dir))
|
|
76
|
+
for path in sorted(model_dir.glob('release-*.sql'))
|
|
77
|
+
]
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def migrate(repo):
|
|
81
|
+
model_dir = Path(repo.model_dir)
|
|
82
|
+
|
|
83
|
+
# Only projects predating the a33 metadata->data switch are affected.
|
|
84
|
+
# A leftover model/metadata-*.sql is the proof: it is what the old
|
|
85
|
+
# restore path loaded, so any release schema this project generated
|
|
86
|
+
# was dumped from a database holding half_orm_meta rows only. A
|
|
87
|
+
# project that never had those files has correct release schemas and
|
|
88
|
+
# must not be forced into a needless rebuild.
|
|
89
|
+
if not list(model_dir.glob('metadata-*.sql')):
|
|
90
|
+
return {}
|
|
91
|
+
|
|
92
|
+
git_repo = repo.hgit.git_repo
|
|
93
|
+
current_branch = repo.hgit.branch
|
|
94
|
+
deleted = []
|
|
95
|
+
to_push = []
|
|
96
|
+
|
|
97
|
+
# Other active branches first, each committed on the spot: the
|
|
98
|
+
# current branch has to stay clean while switching away from it.
|
|
99
|
+
for branch in _affected_branches(repo):
|
|
100
|
+
if branch == current_branch:
|
|
101
|
+
continue
|
|
102
|
+
with repo.hgit.on_branch(branch, silent=True):
|
|
103
|
+
stale = _stale_release_schemas(repo, model_dir)
|
|
104
|
+
if not stale:
|
|
105
|
+
continue
|
|
106
|
+
|
|
107
|
+
git_repo.index.remove(stale, working_tree=True)
|
|
108
|
+
git_repo.index.commit(
|
|
109
|
+
'[HOP] Remove stale release schema '
|
|
110
|
+
'(generated before metadata->data.sql; regenerated with '
|
|
111
|
+
'full data on the next patch apply)',
|
|
112
|
+
skip_hooks=True,
|
|
113
|
+
)
|
|
114
|
+
deleted.extend(f"{branch}:{name}" for name in stale)
|
|
115
|
+
to_push.append(branch)
|
|
116
|
+
|
|
117
|
+
# push_branch() names its target explicitly, so it does not depend on
|
|
118
|
+
# the branch currently checked out.
|
|
119
|
+
for branch in to_push:
|
|
120
|
+
try:
|
|
121
|
+
repo.hgit.push_branch(branch)
|
|
122
|
+
except Exception as e:
|
|
123
|
+
print(
|
|
124
|
+
f" ⚠ Could not push {branch}: {e}\n"
|
|
125
|
+
f" The stale release schema was removed locally; "
|
|
126
|
+
f"push {branch} manually to share the change.",
|
|
127
|
+
file=sys.stderr,
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
# ho-prod last, and removed from the working tree only. The migration
|
|
131
|
+
# runner always stages '.hop/' before committing, and `git add` on a
|
|
132
|
+
# directory records deletions inside it, so the removal lands in the
|
|
133
|
+
# migration commit - which is pushed before .hop/ is synced outwards.
|
|
134
|
+
# Skipping ho-prod would leave a copy here that the sync copies
|
|
135
|
+
# straight back onto every branch cleaned above.
|
|
136
|
+
#
|
|
137
|
+
# Staging it here instead would break that runner: it feeds every
|
|
138
|
+
# path it finds staged to `git add`, and `git add` on an
|
|
139
|
+
# already-staged deletion fails with "did not match any files".
|
|
140
|
+
stale_here = _stale_release_schemas(repo, model_dir)
|
|
141
|
+
for relative in stale_here:
|
|
142
|
+
(Path(repo.base_dir) / relative).unlink()
|
|
143
|
+
deleted.append(f"{current_branch}:{relative}")
|
|
144
|
+
|
|
145
|
+
return {'deleted_release_schemas': deleted}
|
|
@@ -66,6 +66,20 @@ def _git_origin_to_https(git_origin: str) -> str:
|
|
|
66
66
|
return url
|
|
67
67
|
|
|
68
68
|
|
|
69
|
+
def _pg_command_error_detail(e: Exception) -> str:
|
|
70
|
+
"""Format a psql/pg_dump failure with its actual stderr, when available.
|
|
71
|
+
|
|
72
|
+
str(subprocess.CalledProcessError) only shows the command and exit
|
|
73
|
+
code - the actual SQL error psql printed to stderr (e.g. which
|
|
74
|
+
statement failed and why) is on e.stderr and would otherwise be
|
|
75
|
+
silently dropped from every RepoError raised around a restore.
|
|
76
|
+
"""
|
|
77
|
+
stderr = getattr(e, 'stderr', None)
|
|
78
|
+
if stderr:
|
|
79
|
+
return f"{e}\n{stderr.strip() if isinstance(stderr, str) else stderr}"
|
|
80
|
+
return str(e)
|
|
81
|
+
|
|
82
|
+
|
|
69
83
|
class RepoError(Exception):
|
|
70
84
|
pass
|
|
71
85
|
|
|
@@ -2648,9 +2662,21 @@ INSERT INTO public.roles (name) VALUES ('admin'), ('user');
|
|
|
2648
2662
|
and should persist across schema resets.
|
|
2649
2663
|
"""
|
|
2650
2664
|
schemas_to_drop = {'half_orm_meta', 'half_orm_meta.view'}
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2665
|
+
|
|
2666
|
+
# Enumerate schemas from the PostgreSQL catalog rather than from
|
|
2667
|
+
# self.model.desc(), which only lists *relations*: a schema holding
|
|
2668
|
+
# no table/view (only functions, types, sequences - or nothing at
|
|
2669
|
+
# all) is invisible there, so it would survive the reset and then
|
|
2670
|
+
# collide with the CREATE SCHEMA emitted by the file being
|
|
2671
|
+
# restored ("schema already exists"), leaving the database in a
|
|
2672
|
+
# state that no longer matches the dump.
|
|
2673
|
+
cursor = self.model.execute_query(
|
|
2674
|
+
"SELECT nspname FROM pg_catalog.pg_namespace "
|
|
2675
|
+
"WHERE nspname NOT IN ('pg_catalog', 'information_schema') "
|
|
2676
|
+
"AND nspname NOT LIKE 'pg\\_%'"
|
|
2677
|
+
)
|
|
2678
|
+
for row in cursor:
|
|
2679
|
+
schemas_to_drop.add(row['nspname'])
|
|
2654
2680
|
|
|
2655
2681
|
# Drop each schema with CASCADE
|
|
2656
2682
|
for schema_name in schemas_to_drop:
|
|
@@ -2747,7 +2773,10 @@ INSERT INTO public.roles (name) VALUES ('admin'), ('user');
|
|
|
2747
2773
|
'psql', '-v', 'ON_ERROR_STOP=1', '-d', self.database_name, '-f', str(schema_path)
|
|
2748
2774
|
)
|
|
2749
2775
|
except Exception as e:
|
|
2750
|
-
raise RepoError(
|
|
2776
|
+
raise RepoError(
|
|
2777
|
+
f"Failed to load schema from {schema_path.name}: "
|
|
2778
|
+
f"{_pg_command_error_detail(e)}"
|
|
2779
|
+
) from e
|
|
2751
2780
|
|
|
2752
2781
|
# 4. Load data from model/data-X.Y.Z.sql (if exists)
|
|
2753
2782
|
data_path, version = self._deduce_data_path(schema_path)
|
|
@@ -2759,7 +2788,8 @@ INSERT INTO public.roles (name) VALUES ('admin'), ('user');
|
|
|
2759
2788
|
)
|
|
2760
2789
|
except Exception as e:
|
|
2761
2790
|
raise RepoError(
|
|
2762
|
-
f"Failed to load data from {data_path.name}:
|
|
2791
|
+
f"Failed to load data from {data_path.name}: "
|
|
2792
|
+
f"{_pg_command_error_detail(e)}"
|
|
2763
2793
|
) from e
|
|
2764
2794
|
# else: data file doesn't exist, continue without error (backward compatibility)
|
|
2765
2795
|
|
|
@@ -2810,7 +2840,10 @@ INSERT INTO public.roles (name) VALUES ('admin'), ('user');
|
|
|
2810
2840
|
'psql', '-v', 'ON_ERROR_STOP=1', '-d', self.database_name, '-f', str(schema_path)
|
|
2811
2841
|
)
|
|
2812
2842
|
except Exception as e:
|
|
2813
|
-
raise RepoError(
|
|
2843
|
+
raise RepoError(
|
|
2844
|
+
f"Failed to load schema from {schema_path.name}: "
|
|
2845
|
+
f"{_pg_command_error_detail(e)}"
|
|
2846
|
+
) from e
|
|
2814
2847
|
|
|
2815
2848
|
data_path = Path(self.model_dir) / f"data-{version}.sql"
|
|
2816
2849
|
if data_path.exists():
|
|
@@ -2820,7 +2853,8 @@ INSERT INTO public.roles (name) VALUES ('admin'), ('user');
|
|
|
2820
2853
|
)
|
|
2821
2854
|
except Exception as e:
|
|
2822
2855
|
raise RepoError(
|
|
2823
|
-
f"Failed to load data from {data_path.name}:
|
|
2856
|
+
f"Failed to load data from {data_path.name}: "
|
|
2857
|
+
f"{_pg_command_error_detail(e)}"
|
|
2824
2858
|
) from e
|
|
2825
2859
|
|
|
2826
2860
|
self.model.reconnect(reload=True)
|
|
@@ -2876,7 +2910,10 @@ INSERT INTO public.roles (name) VALUES ('admin'), ('user');
|
|
|
2876
2910
|
'psql', '-v', 'ON_ERROR_STOP=1', '-d', self.database_name, '-f', str(dump_path)
|
|
2877
2911
|
)
|
|
2878
2912
|
except Exception as e:
|
|
2879
|
-
raise RepoError(
|
|
2913
|
+
raise RepoError(
|
|
2914
|
+
f"Failed to load dump from {dump_path.name}: "
|
|
2915
|
+
f"{_pg_command_error_detail(e)}"
|
|
2916
|
+
) from e
|
|
2880
2917
|
|
|
2881
2918
|
# 3. Reload half_orm metadata cache
|
|
2882
2919
|
self.model.reconnect(reload=True)
|
|
@@ -3005,7 +3042,9 @@ INSERT INTO public.roles (name) VALUES ('admin'), ('user');
|
|
|
3005
3042
|
self.model.reconnect(reload=True)
|
|
3006
3043
|
|
|
3007
3044
|
except Exception as e:
|
|
3008
|
-
raise RepoError(
|
|
3045
|
+
raise RepoError(
|
|
3046
|
+
f"Failed to restore from release schema: {_pg_command_error_detail(e)}"
|
|
3047
|
+
) from e
|
|
3009
3048
|
|
|
3010
3049
|
def get_release_schema_path(self, version: str) -> Path:
|
|
3011
3050
|
"""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1.0.0-a35
|
|
@@ -55,6 +55,7 @@ half_orm_dev/migrations/0/18/0/00_add_async_support.py
|
|
|
55
55
|
half_orm_dev/migrations/0/18/0/01_update_default_tests.py
|
|
56
56
|
half_orm_dev/migrations/1/0/0/a20/01_update_gitignore.py
|
|
57
57
|
half_orm_dev/migrations/1/0/0/a33/00_metadata_to_data_sql.py
|
|
58
|
+
half_orm_dev/migrations/1/0/0/a35/00_drop_stale_release_schemas.py
|
|
58
59
|
half_orm_dev/migrations/hop/BREAKING_CHANGES-1.0.0.md
|
|
59
60
|
half_orm_dev/patches/log
|
|
60
61
|
half_orm_dev/patches/0/1/0/00_half_orm_meta.database.sql
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
1.0.0-a34
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/cli/commands/revert_migration.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/migrations/0/17/1/00_move_to_hop.py
RENAMED
|
File without changes
|
{half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/migrations/0/17/1/01_txt_to_toml.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{half_orm_dev-1.0.0a34 → half_orm_dev-1.0.0a35}/half_orm_dev/templates/git-hooks/prepare-commit-msg
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|