half-orm-dev 0.17.2a6__tar.gz → 0.17.2a7__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.
Files changed (66) hide show
  1. {half_orm_dev-0.17.2a6/half_orm_dev.egg-info → half_orm_dev-0.17.2a7}/PKG-INFO +1 -1
  2. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/cli/main.py +69 -5
  3. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/repo.py +26 -8
  4. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/templates/git-hooks/pre-commit +37 -0
  5. half_orm_dev-0.17.2a7/half_orm_dev/version.txt +1 -0
  6. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7/half_orm_dev.egg-info}/PKG-INFO +1 -1
  7. half_orm_dev-0.17.2a6/half_orm_dev/version.txt +0 -1
  8. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/AUTHORS +0 -0
  9. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/LICENSE +0 -0
  10. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/README.md +0 -0
  11. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/__init__.py +0 -0
  12. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/cli/__init__.py +0 -0
  13. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/cli/commands/__init__.py +0 -0
  14. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/cli/commands/apply.py +0 -0
  15. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/cli/commands/check.py +0 -0
  16. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/cli/commands/clone.py +0 -0
  17. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/cli/commands/init.py +0 -0
  18. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/cli/commands/migrate.py +0 -0
  19. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/cli/commands/new.py +0 -0
  20. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/cli/commands/patch.py +0 -0
  21. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/cli/commands/release.py +0 -0
  22. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/cli/commands/restore.py +0 -0
  23. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/cli/commands/sync.py +0 -0
  24. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/cli/commands/todo.py +0 -0
  25. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/cli/commands/undo.py +0 -0
  26. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/cli/commands/update.py +0 -0
  27. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/cli/commands/upgrade.py +0 -0
  28. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/cli_extension.py +0 -0
  29. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/database.py +0 -0
  30. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/decorators.py +0 -0
  31. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/hgit.py +0 -0
  32. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/migration_manager.py +0 -0
  33. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/migrations/0/17/1/00_move_to_hop.py +0 -0
  34. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/migrations/0/17/1/01_txt_to_toml.py +0 -0
  35. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/modules.py +0 -0
  36. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/patch_manager.py +0 -0
  37. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/patch_validator.py +0 -0
  38. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/patches/0/1/0/00_half_orm_meta.database.sql +0 -0
  39. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/patches/0/1/0/01_alter_half_orm_meta.hop_release.sql +0 -0
  40. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/patches/0/1/0/02_half_orm_meta.view.hop_penultimate_release.sql +0 -0
  41. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/patches/log +0 -0
  42. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/patches/sql/half_orm_meta.sql +0 -0
  43. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/release_file.py +0 -0
  44. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/release_manager.py +0 -0
  45. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/templates/.gitignore +0 -0
  46. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/templates/MANIFEST.in +0 -0
  47. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/templates/Pipfile +0 -0
  48. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/templates/README +0 -0
  49. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/templates/conftest_template +0 -0
  50. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/templates/git-hooks/prepare-commit-msg +0 -0
  51. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/templates/init_module_template +0 -0
  52. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/templates/module_template_1 +0 -0
  53. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/templates/module_template_2 +0 -0
  54. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/templates/module_template_3 +0 -0
  55. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/templates/pyproject.toml +0 -0
  56. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/templates/relation_test +0 -0
  57. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/templates/sql_adapter +0 -0
  58. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/templates/warning +0 -0
  59. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev/utils.py +0 -0
  60. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev.egg-info/SOURCES.txt +0 -0
  61. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev.egg-info/dependency_links.txt +0 -0
  62. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev.egg-info/requires.txt +0 -0
  63. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/half_orm_dev.egg-info/top_level.txt +0 -0
  64. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/pyproject.toml +0 -0
  65. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/setup.cfg +0 -0
  66. {half_orm_dev-0.17.2a6 → half_orm_dev-0.17.2a7}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: half_orm_dev
3
- Version: 0.17.2a6
3
+ Version: 0.17.2a7
4
4
  Summary: half_orm development Framework.
5
5
  Author-email: Joël Maïzi <joel.maizi@collorg.org>
6
6
  License-Expression: GPL-3.0-or-later
@@ -3,7 +3,8 @@ Main CLI module - Creates and configures the CLI group
3
3
  """
4
4
 
5
5
  import click
6
- from half_orm_dev.repo import Repo
6
+ import functools
7
+ from half_orm_dev.repo import Repo, OutdatedHalfORMDevError
7
8
  from half_orm import utils
8
9
  from .commands import ALL_COMMANDS
9
10
 
@@ -12,7 +13,16 @@ class Hop:
12
13
  """Sets the options available to the hop command"""
13
14
 
14
15
  def __init__(self):
15
- self.__repo: Repo = Repo() # Utilise le singleton
16
+ self.__repo: Repo = None
17
+ self.__hop_upgrade_error: OutdatedHalfORMDevError = None
18
+
19
+ # Try to initialize Repo, catch version errors
20
+ try:
21
+ self.__repo = Repo() # Utilise le singleton
22
+ except OutdatedHalfORMDevError as e:
23
+ # Capture the error but don't raise it yet
24
+ self.__hop_upgrade_error = e
25
+
16
26
  self.__available_cmds = self._determine_available_commands()
17
27
 
18
28
  def _determine_available_commands(self):
@@ -23,7 +33,16 @@ class Hop:
23
33
  - Repository status (checked/unchecked)
24
34
  - Development mode (devel flag - metadata presence)
25
35
  - Environment (production flag)
36
+
37
+ Note: When needs_hop_upgrade is true, commands will still be added
38
+ but will be blocked by the decorator at execution time.
26
39
  """
40
+ if self.needs_hop_upgrade:
41
+ # Version downgrade detected - return a minimal set of commands
42
+ # Commands will be blocked by decorator, but we need them in the list
43
+ # so Click doesn't show "No such command" error
44
+ return ['check', 'migrate']
45
+
27
46
  if not self.repo_checked:
28
47
  # Outside hop repository - commands for project initialization
29
48
  return ['init', 'clone']
@@ -47,12 +66,22 @@ class Hop:
47
66
  @property
48
67
  def repo_checked(self):
49
68
  """Returns whether we are in a repo or not."""
50
- return self.__repo.checked
69
+ return self.__repo and self.__repo.checked
70
+
71
+ @property
72
+ def needs_hop_upgrade(self):
73
+ """Returns whether half_orm_dev needs to be upgraded."""
74
+ return self.__hop_upgrade_error is not None
75
+
76
+ @property
77
+ def hop_upgrade_error(self):
78
+ """Returns the upgrade error if any."""
79
+ return self.__hop_upgrade_error
51
80
 
52
81
  @property
53
82
  def state(self):
54
83
  """Returns the state of the repo."""
55
- return self.__repo.state
84
+ return self.__repo.state if self.__repo else "Not in a repository"
56
85
 
57
86
  @property
58
87
  def available_commands(self):
@@ -69,8 +98,43 @@ def create_cli_group():
69
98
  """
70
99
  hop = Hop()
71
100
 
72
- @click.group(invoke_without_command=True)
101
+ def check_version_before_invoke(f, allow_on_downgrade=False):
102
+ """Decorator to check version before invoking any command.
103
+
104
+ Args:
105
+ f: Function to wrap
106
+ allow_on_downgrade: If True, allow this command even when version is outdated
107
+ """
108
+ @functools.wraps(f)
109
+ def wrapper(*args, **kwargs):
110
+ if hop.needs_hop_upgrade and not allow_on_downgrade:
111
+ # Display formatted error message for version downgrade
112
+ error = hop.hop_upgrade_error
113
+ click.echo("=" * 70, err=True)
114
+ click.echo(f"{utils.Color.red('❌ OUTDATED half_orm_dev VERSION')}", err=True)
115
+ click.echo("=" * 70, err=True)
116
+ click.echo(f"\n Repository requires: {utils.Color.bold(error.required_version)}", err=True)
117
+ click.echo(f" Installed version: {utils.Color.bold(error.installed_version)}", err=True)
118
+ click.echo(f"\n Your installed version is OLDER than the repository requirement.", err=True)
119
+ click.echo(f" All commands are blocked for safety.", err=True)
120
+ click.echo(f"\n Please upgrade half_orm_dev:", err=True)
121
+ click.echo(f" {utils.Color.bold('pip install --upgrade half_orm_dev')}", err=True)
122
+ click.echo("\n" + "=" * 70 + "\n", err=True)
123
+ raise click.Abort()
124
+ return f(*args, **kwargs)
125
+ return wrapper
126
+
127
+ # Create custom Group that auto-decorates commands
128
+ class VersionCheckGroup(click.Group):
129
+ def add_command(self, cmd, name=None):
130
+ """Override to decorate all commands with version check."""
131
+ if isinstance(cmd, click.Command) and cmd.callback:
132
+ cmd.callback = check_version_before_invoke(cmd.callback)
133
+ super().add_command(cmd, name)
134
+
135
+ @click.group(cls=VersionCheckGroup, invoke_without_command=True)
73
136
  @click.pass_context
137
+ @check_version_before_invoke
74
138
  def dev(ctx):
75
139
  """halfORM development tools - Git-centric patch management and database synchronization"""
76
140
  if ctx.invoked_subcommand is None:
@@ -37,6 +37,17 @@ from .utils import TEMPLATE_DIRS, hop_version, resolve_database_config_name
37
37
  class RepoError(Exception):
38
38
  pass
39
39
 
40
+ class OutdatedHalfORMDevError(RepoError):
41
+ """Raised when installed half_orm_dev version is older than repository requirement."""
42
+ def __init__(self, required_version: str, installed_version: str):
43
+ self.required_version = required_version
44
+ self.installed_version = installed_version
45
+ super().__init__(
46
+ f"Repository requires half_orm_dev >= {required_version} "
47
+ f"but {installed_version} is installed.\n"
48
+ f"Please upgrade: pip install --upgrade half_orm_dev"
49
+ )
50
+
40
51
  class Config:
41
52
  """
42
53
  """
@@ -259,6 +270,10 @@ class Repo:
259
270
  self.__checked = True
260
271
  # NOTE: Migration is no longer automatic - user must run `half_orm dev migrate`
261
272
  # This prevents implicit changes and gives user control over when migration happens
273
+
274
+ # Automatically check and update hooks/config (silent, uses cache)
275
+ # This ensures Git hooks are always up-to-date for all commands
276
+ self.check_and_update(silent=True)
262
277
  return
263
278
  par_dir = os.path.split(base_dir)[0]
264
279
  if par_dir == base_dir:
@@ -292,15 +307,11 @@ class Repo:
292
307
  try:
293
308
  # Use centralized comparison method
294
309
  if self.compare_versions(installed_version, required_version) < 0:
295
- raise RepoError(
296
- f"Repository requires half_orm_dev >= {required_version} "
297
- f"but {installed_version} is installed.\n"
298
- f"Please upgrade: pip install --upgrade half_orm_dev"
299
- )
310
+ raise OutdatedHalfORMDevError(required_version, installed_version)
311
+ except OutdatedHalfORMDevError:
312
+ # Re-raise downgrade errors immediately
313
+ raise
300
314
  except RepoError as e:
301
- # If it's a version validation error (not comparison error), re-raise it
302
- if "requires half_orm_dev" in str(e):
303
- raise
304
315
  # If version parsing fails, log warning but don't block
305
316
  warnings.warn(
306
317
  f"Could not parse version: installed={installed_version}, "
@@ -1120,6 +1131,9 @@ class Repo:
1120
1131
  hooks_source_dir = os.path.join(TEMPLATE_DIRS, 'git-hooks')
1121
1132
  hooks_dest_dir = os.path.join(self.__base_dir, '.git', 'hooks')
1122
1133
 
1134
+ # Create .git/hooks directory if it doesn't exist
1135
+ os.makedirs(hooks_dest_dir, exist_ok=True)
1136
+
1123
1137
  any_installed = False
1124
1138
  overall_action = 'skipped'
1125
1139
 
@@ -2215,6 +2229,7 @@ See docs/half_orm_dev.md for complete documentation.
2215
2229
  5. Create .hop/alt_config if custom database_name provided
2216
2230
  6. Setup database (create + metadata if create_db=True)
2217
2231
  7. Restore database from model/schema.sql to production version
2232
+ 8. Install Git hooks (pre-commit, prepare-commit-msg)
2218
2233
 
2219
2234
  Examples:
2220
2235
  # Interactive with prompts for connection params
@@ -2338,3 +2353,6 @@ See docs/half_orm_dev.md for complete documentation.
2338
2353
  raise RepoError(
2339
2354
  f"Failed to restore database from schema: {e}"
2340
2355
  ) from e
2356
+
2357
+ # Step 9: Install Git hooks
2358
+ repo.install_git_hooks()
@@ -3,11 +3,48 @@
3
3
  # Half-ORM pre-commit hook
4
4
  # 1. Checks if current ho-* branch exists on remote origin
5
5
  # 2. Protects ho-prod branch from direct commits
6
+ # 3. Optionally calls pre-commit-custom if it exists
6
7
  # Generated by half_orm_dev
7
8
 
8
9
  # Get current branch
9
10
  CURRENT_BRANCH=$(git symbolic-ref --short HEAD 2>/dev/null)
10
11
 
12
+ # =============================================================================
13
+ # CUSTOM PRE-COMMIT HOOK SUPPORT
14
+ # =============================================================================
15
+ # If a pre-commit-custom script exists in .git/hooks/, execute it first.
16
+ # This allows users to add their own custom checks (linting, formatting, etc.)
17
+ #
18
+ # ⚠️ WARNING: pre-commit-custom is NOT tracked by Git and NOT cloned.
19
+ # It must be added manually to each local repository clone.
20
+ #
21
+ # To create a custom hook:
22
+ # 1. Create .git/hooks/pre-commit-custom (executable)
23
+ # 2. Add your custom checks
24
+ # 3. Exit with 0 (success) or non-zero (failure) to block the commit
25
+ #
26
+ # Example .git/hooks/pre-commit-custom:
27
+ # #!/usr/bin/env bash
28
+ # # Run Python linter
29
+ # python -m pylint $(git diff --cached --name-only --diff-filter=ACM | grep '\.py$')
30
+ # exit $?
31
+ # =============================================================================
32
+
33
+ CUSTOM_HOOK=".git/hooks/pre-commit-custom"
34
+ if [ -x "$CUSTOM_HOOK" ]; then
35
+ "$CUSTOM_HOOK"
36
+ CUSTOM_EXIT_CODE=$?
37
+ if [ $CUSTOM_EXIT_CODE -ne 0 ]; then
38
+ echo ""
39
+ echo "❌ Custom pre-commit hook failed (exit code: $CUSTOM_EXIT_CODE)"
40
+ exit $CUSTOM_EXIT_CODE
41
+ fi
42
+ fi
43
+
44
+ # =============================================================================
45
+ # HALF-ORM STANDARD CHECKS
46
+ # =============================================================================
47
+
11
48
  # Check if current ho-* branch (except ho-prod) still exists on remote origin
12
49
  # This prevents committing to ho-* branches that were deleted remotely
13
50
  if [[ "$CURRENT_BRANCH" == ho-* ]] && [ "$CURRENT_BRANCH" != "ho-prod" ]; then
@@ -0,0 +1 @@
1
+ 0.17.2-a7
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: half_orm_dev
3
- Version: 0.17.2a6
3
+ Version: 0.17.2a7
4
4
  Summary: half_orm development Framework.
5
5
  Author-email: Joël Maïzi <joel.maizi@collorg.org>
6
6
  License-Expression: GPL-3.0-or-later
@@ -1 +0,0 @@
1
- 0.17.2-a6
File without changes
File without changes