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.
Files changed (58) hide show
  1. half_orm_dev/__init__.py +1 -0
  2. half_orm_dev/cli/__init__.py +9 -0
  3. half_orm_dev/cli/commands/__init__.py +56 -0
  4. half_orm_dev/cli/commands/apply.py +13 -0
  5. half_orm_dev/cli/commands/clone.py +102 -0
  6. half_orm_dev/cli/commands/init.py +331 -0
  7. half_orm_dev/cli/commands/new.py +15 -0
  8. half_orm_dev/cli/commands/patch.py +317 -0
  9. half_orm_dev/cli/commands/prepare.py +21 -0
  10. half_orm_dev/cli/commands/prepare_release.py +119 -0
  11. half_orm_dev/cli/commands/promote_to.py +127 -0
  12. half_orm_dev/cli/commands/release.py +344 -0
  13. half_orm_dev/cli/commands/restore.py +14 -0
  14. half_orm_dev/cli/commands/sync.py +13 -0
  15. half_orm_dev/cli/commands/todo.py +73 -0
  16. half_orm_dev/cli/commands/undo.py +17 -0
  17. half_orm_dev/cli/commands/update.py +73 -0
  18. half_orm_dev/cli/commands/upgrade.py +191 -0
  19. half_orm_dev/cli/main.py +103 -0
  20. half_orm_dev/cli_extension.py +38 -0
  21. half_orm_dev/database.py +1389 -0
  22. half_orm_dev/hgit.py +1025 -0
  23. half_orm_dev/hop.py +167 -0
  24. half_orm_dev/manifest.py +43 -0
  25. half_orm_dev/modules.py +456 -0
  26. half_orm_dev/patch.py +281 -0
  27. half_orm_dev/patch_manager.py +1694 -0
  28. half_orm_dev/patch_validator.py +335 -0
  29. half_orm_dev/patches/0/1/0/00_half_orm_meta.database.sql +34 -0
  30. half_orm_dev/patches/0/1/0/01_alter_half_orm_meta.hop_release.sql +2 -0
  31. half_orm_dev/patches/0/1/0/02_half_orm_meta.view.hop_penultimate_release.sql +3 -0
  32. half_orm_dev/patches/log +2 -0
  33. half_orm_dev/patches/sql/half_orm_meta.sql +208 -0
  34. half_orm_dev/release_manager.py +2841 -0
  35. half_orm_dev/repo.py +1562 -0
  36. half_orm_dev/templates/.gitignore +15 -0
  37. half_orm_dev/templates/MANIFEST.in +1 -0
  38. half_orm_dev/templates/Pipfile +13 -0
  39. half_orm_dev/templates/README +25 -0
  40. half_orm_dev/templates/conftest_template +42 -0
  41. half_orm_dev/templates/init_module_template +10 -0
  42. half_orm_dev/templates/module_template_1 +12 -0
  43. half_orm_dev/templates/module_template_2 +6 -0
  44. half_orm_dev/templates/module_template_3 +3 -0
  45. half_orm_dev/templates/relation_test +23 -0
  46. half_orm_dev/templates/setup.py +81 -0
  47. half_orm_dev/templates/sql_adapter +9 -0
  48. half_orm_dev/templates/warning +12 -0
  49. half_orm_dev/utils.py +49 -0
  50. half_orm_dev/version.txt +1 -0
  51. half_orm_dev-0.16.0a9.dist-info/METADATA +935 -0
  52. half_orm_dev-0.16.0a9.dist-info/RECORD +58 -0
  53. half_orm_dev-0.16.0a9.dist-info/WHEEL +5 -0
  54. half_orm_dev-0.16.0a9.dist-info/licenses/AUTHORS +3 -0
  55. half_orm_dev-0.16.0a9.dist-info/licenses/LICENSE +14 -0
  56. half_orm_dev-0.16.0a9.dist-info/top_level.txt +2 -0
  57. tests/__init__.py +0 -0
  58. tests/conftest.py +329 -0
@@ -0,0 +1,191 @@
1
+ """
2
+ Upgrade command - Apply releases sequentially to production database.
3
+
4
+ Equivalent to 'apt upgrade' - applies available releases incrementally
5
+ to existing production database without data destruction.
6
+ """
7
+
8
+ import click
9
+ from pathlib import Path
10
+ from half_orm_dev.repo import Repo
11
+ from half_orm_dev.release_manager import ReleaseManagerError
12
+ from half_orm import utils
13
+
14
+
15
+ @click.command()
16
+ @click.option(
17
+ '--to-release', '-t',
18
+ type=str,
19
+ default=None,
20
+ help='Stop at specific version (e.g., 1.3.7). Default: upgrade to latest'
21
+ )
22
+ @click.option(
23
+ '--dry-run', '-d',
24
+ is_flag=True,
25
+ help='Simulate upgrade without making changes'
26
+ )
27
+ @click.option(
28
+ '--force',
29
+ is_flag=True,
30
+ help='Overwrite existing backup without confirmation'
31
+ )
32
+ @click.option(
33
+ '--skip-backup',
34
+ is_flag=True,
35
+ help='Skip backup creation (DANGEROUS - for testing only)'
36
+ )
37
+ def upgrade(to_release, dry_run, force, skip_backup):
38
+ """
39
+ Apply releases sequentially to production database.
40
+
41
+ Upgrades production database by applying releases incrementally
42
+ to existing data. NEVER destroys or recreates the database.
43
+ Creates automatic backup before any changes.
44
+
45
+ CRITICAL: This command works on EXISTING production database.
46
+ It does NOT use restore operations that would destroy data.
47
+
48
+ Must be run from ho-prod branch.
49
+
50
+ Workflow:
51
+ 1. CREATE BACKUP (backups/{version}.sql) - FIRST ACTION
52
+ 2. Validate environment (ho-prod branch, clean repo)
53
+ 3. Apply releases sequentially on existing database
54
+ 4. Update database version after each release
55
+
56
+ Examples:
57
+ # Upgrade to latest (all available releases)
58
+ half_orm dev upgrade
59
+
60
+ # Upgrade to specific version
61
+ half_orm dev upgrade --to-release=1.3.7
62
+
63
+ # Simulate upgrade (no changes)
64
+ half_orm dev upgrade --dry-run
65
+
66
+ # Force overwrite existing backup
67
+ half_orm dev upgrade --force
68
+
69
+ Options:
70
+ --to-release=VERSION Stop at specific version
71
+ --dry-run Simulate without changes
72
+ --force Overwrite existing backup
73
+ --skip-backup Skip backup (DANGEROUS)
74
+
75
+ Requires:
76
+ - Current branch: ho-prod
77
+ - Repository: clean (no uncommitted changes)
78
+ - Permissions: Database write access
79
+ """
80
+ try:
81
+ # Get repository instance
82
+ repo = Repo()
83
+
84
+ # Delegate to ReleaseManager
85
+ click.echo("🔄 Starting production upgrade...\n")
86
+
87
+ result = repo.release_manager.upgrade_production(
88
+ to_version=to_release,
89
+ dry_run=dry_run,
90
+ force_backup=force,
91
+ skip_backup=skip_backup
92
+ )
93
+
94
+ # Display results
95
+ _display_upgrade_results(result)
96
+
97
+ except ReleaseManagerError as e:
98
+ click.echo(f"\n❌ {utils.Color.red('Upgrade failed:')}")
99
+ click.echo(f" {str(e)}\n")
100
+ raise click.Abort()
101
+
102
+
103
+ def _display_upgrade_results(result):
104
+ """
105
+ Format and display upgrade results to user.
106
+
107
+ Args:
108
+ result: Dict from ReleaseManager.upgrade_production()
109
+ """
110
+ # === DRY RUN MODE ===
111
+ if result.get('dry_run'):
112
+ click.echo(f"{utils.Color.bold('DRY RUN')} - Simulation only, no changes made\n")
113
+
114
+ current = result['current_version']
115
+ click.echo(f"Current version: {utils.Color.bold(current)}")
116
+
117
+ if not result['releases_would_apply']:
118
+ click.echo(f"\n✓ {utils.Color.green('Already at latest version')}")
119
+ return
120
+
121
+ # Show what would happen
122
+ click.echo(f"\nWould create backup: {utils.Color.bold(result['backup_would_be_created'])}")
123
+
124
+ click.echo(f"\nWould apply releases:")
125
+ for version in result['releases_would_apply']:
126
+ patches = result['patches_would_apply'][version]
127
+ patch_count = len(patches)
128
+ click.echo(f" → {utils.Color.bold(version)} - {patch_count} patches")
129
+ for patch_id in patches:
130
+ click.echo(f" • {patch_id}")
131
+
132
+ final = result['final_version']
133
+ click.echo(f"\nWould upgrade: {current} → {utils.Color.green(final)}")
134
+
135
+ click.echo(f"\n{utils.Color.yellow('To apply this upgrade, run without --dry-run')}")
136
+ return
137
+
138
+ # === ACTUAL UPGRADE ===
139
+
140
+ current = result['current_version']
141
+
142
+ # Backup confirmation
143
+ if result['backup_created']:
144
+ backup_path = result['backup_created']
145
+ click.echo(f"✓ Backup created: {utils.Color.bold(backup_path)}")
146
+ elif result.get('message') and 'already at latest' in result['message'].lower():
147
+ # Up to date scenario
148
+ pass
149
+ else:
150
+ click.echo(f"⚠️ {utils.Color.yellow('No backup created (--skip-backup used)')}")
151
+
152
+ click.echo(f"\nCurrent version: {utils.Color.bold(current)}")
153
+
154
+ # Check if already up to date
155
+ if not result['releases_applied']:
156
+ click.echo(f"\n✓ {utils.Color.green('Production already at latest version')}")
157
+ return
158
+
159
+ # Show applied releases
160
+ click.echo(f"\n{utils.Color.green('Applied releases:')}")
161
+
162
+ for version in result['releases_applied']:
163
+ patches = result['patches_applied'][version]
164
+ patch_count = len(patches)
165
+
166
+ if patch_count == 0:
167
+ click.echo(f" ✓ {utils.Color.bold(version)} - (empty release)")
168
+ else:
169
+ click.echo(f" ✓ {utils.Color.bold(version)} - {patch_count} patches")
170
+ for patch_id in patches:
171
+ click.echo(f" • {patch_id}")
172
+
173
+ # Final status
174
+ final = result['final_version']
175
+ click.echo(f"\n{utils.Color.green('✓ Upgrade complete!')}")
176
+ click.echo(f" {current} → {utils.Color.bold(utils.Color.green(final))}")
177
+
178
+ # Next steps
179
+ if result['target_version']:
180
+ # Partial upgrade
181
+ click.echo(f"\n📝 Partial upgrade to {result['target_version']} complete.")
182
+ click.echo(f" To upgrade further, run: half_orm dev upgrade")
183
+ else:
184
+ # Full upgrade
185
+ click.echo(f"\n📝 Production is now at latest version.")
186
+
187
+ # Rollback information
188
+ if result['backup_created']:
189
+ backup_path = result['backup_created']
190
+ click.echo(f"\n💡 To rollback if needed:")
191
+ click.echo(f" psql -d {result.get('db_name', 'DATABASE')} -f {backup_path}")
@@ -0,0 +1,103 @@
1
+ """
2
+ Main CLI module - Creates and configures the CLI group
3
+ """
4
+
5
+ import click
6
+ from half_orm_dev.repo import Repo
7
+ from half_orm import utils
8
+ from .commands import ALL_COMMANDS
9
+
10
+
11
+ class Hop:
12
+ """Sets the options available to the hop command"""
13
+
14
+ def __init__(self):
15
+ self.__repo: Repo = Repo() # Utilise le singleton
16
+ self.__available_cmds = self._determine_available_commands()
17
+
18
+ def _determine_available_commands(self):
19
+ """
20
+ Determine which commands are available based on context.
21
+
22
+ Returns different command sets based on:
23
+ - Repository status (checked/unchecked)
24
+ - Development mode (devel flag - metadata presence)
25
+ - Environment (production flag)
26
+ """
27
+ if not self.repo_checked:
28
+ # Outside hop repository - commands for project initialization
29
+ return ['init', 'clone']
30
+
31
+ # Inside hop repository
32
+ if not self.__repo.devel:
33
+ # Sync-only mode (no metadata)
34
+ return ['sync-package']
35
+
36
+ # Development mode (metadata present)
37
+ if self.__repo.database.production:
38
+ # PRODUCTION ENVIRONMENT - Release deployment only
39
+ return ['update', 'upgrade']
40
+ else:
41
+ # DEVELOPMENT ENVIRONMENT - Patch development
42
+ return ['patch', 'release']
43
+
44
+ @property
45
+ def repo_checked(self):
46
+ """Returns whether we are in a repo or not."""
47
+ return self.__repo.checked
48
+
49
+ @property
50
+ def state(self):
51
+ """Returns the state of the repo."""
52
+ return self.__repo.state
53
+
54
+ @property
55
+ def available_commands(self):
56
+ """Returns the list of available commands."""
57
+ return self.__available_cmds
58
+
59
+
60
+ def create_cli_group():
61
+ """
62
+ Creates and returns the CLI group with appropriate commands.
63
+
64
+ Returns:
65
+ click.Group: Configured CLI group
66
+ """
67
+ hop = Hop()
68
+
69
+ @click.group(invoke_without_command=True)
70
+ @click.pass_context
71
+ def dev(ctx):
72
+ """halfORM development tools - Git-centric patch management and database synchronization"""
73
+ if ctx.invoked_subcommand is None:
74
+ # Show repo state when no subcommand is provided
75
+ if hop.repo_checked:
76
+ click.echo(hop.state)
77
+ click.echo(f"\n{utils.Color.bold('Available commands:')}")
78
+
79
+ # Adapt displayed commands based on environment
80
+ if hop.__repo.database.production:
81
+ # Production commands
82
+ click.echo(f" • {utils.Color.bold('update')} - Fetch and list available releases")
83
+ click.echo(f" • {utils.Color.bold('upgrade [--to-release=X.Y.Z]')} - Apply releases to production")
84
+ else:
85
+ # Development commands
86
+ click.echo(f" • {utils.Color.bold('patch')}")
87
+ click.echo(f" • {utils.Color.bold('prepare-release <level>')} - Prepare next release stage file (patch/minor/major)")
88
+ click.echo(f" • {utils.Color.bold('promote-to <target>')} - Promote stage to rc or prod")
89
+
90
+ click.echo(f"\nTry {utils.Color.bold('half_orm dev <command> --help')} for more information.\n")
91
+ else:
92
+ click.echo(hop.state)
93
+ click.echo("\nNot in a hop repository.")
94
+ click.echo(f"\n{utils.Color.bold('Available commands:')}")
95
+ click.echo(f"\n • {utils.Color.bold('init <package_name>')} - Create new halfORM project.")
96
+ click.echo(f"\n • {utils.Color.bold('clone <git origin>')} - Clone an existing halfORM project.\n")
97
+
98
+ # Add only available commands to the group
99
+ for cmd_name in hop.available_commands:
100
+ if cmd_name in ALL_COMMANDS:
101
+ dev.add_command(ALL_COMMANDS[cmd_name])
102
+
103
+ return dev
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+
4
+ """
5
+ CLI extension integration for half-orm-dev
6
+
7
+ Provides the halfORM development tools through the unified half_orm CLI interface.
8
+ Generates/Patches/Synchronizes a hop Python package with a PostgreSQL database.
9
+ """
10
+
11
+ import sys
12
+ from half_orm.cli_utils import create_and_register_extension
13
+ from .cli import create_cli_group
14
+
15
+
16
+ def add_commands(main_group):
17
+ """
18
+ Required entry point for halfORM extensions.
19
+
20
+ Args:
21
+ main_group: The main Click group for the half_orm command
22
+ """
23
+
24
+ # Create the dev CLI group with all commands
25
+ dev_group = create_cli_group()
26
+
27
+ # Register it as an extension
28
+ @create_and_register_extension(main_group, sys.modules[__name__])
29
+ def dev():
30
+ """halfORM development tools - project management, patches, and database synchronization"""
31
+ pass
32
+
33
+ # Copy all commands from the created group to the registered extension
34
+ for name, command in dev_group.commands.items():
35
+ dev.add_command(command)
36
+
37
+ # Copy the callback from the created group
38
+ dev.callback = dev_group.callback