def _main() -> None: """ This method takes the output of `git diff --name-status master snuba/migrations` and runs `snuba migrations run -dry-run with the proper parameters`, for a CI action """ diff_result = subprocess.run( [ "git", "diff", "--diff-filter=AM", "--name-only", "origin/master", "--", "snuba/migrations/snuba_migrations/*/[0-9]*.py", ], stdout=subprocess.PIPE, text=True, ) if diff_result.returncode != 0: raise ExecError(diff_result.stdout) else: lines = diff_result.stdout.splitlines() if len(lines) > 0: print("-- start migrations") print() for line in lines: migration_filename = os.path.basename(line) migration_group = MigrationGroup(os.path.basename(os.path.dirname(line))) migration_id, _ = os.path.splitext(migration_filename) runner = Runner() migration_key = MigrationKey(migration_group, migration_id) print(f"-- migration {migration_group.value} : {migration_id}") runner.run_migration(migration_key, dry_run=True) print(f"-- end migration {migration_group.value} : {migration_id}")
def run(group: str, migration_id: str, force: bool, fake: bool, dry_run: bool) -> None: """ Runs a single migration. --force must be passed in order to run blocking migrations. --fake marks a migration as completed without running anything. Migrations that are already in an in-progress or completed status will not be run. """ if not dry_run: check_clickhouse_connections() runner = Runner() migration_group = MigrationGroup(group) migration_key = MigrationKey(migration_group, migration_id) if dry_run: runner.run_migration(migration_key, dry_run=True) return try: if fake: click.confirm( "This will mark the migration as completed without actually running it. Your database may be in an invalid state. Are you sure?", abort=True, ) runner.run_migration(migration_key, force=force, fake=fake) except MigrationError as e: raise click.ClickException(str(e)) click.echo(f"Finished running migration {migration_key}")
def _get_migration_status(self) -> Mapping[MigrationKey, Status]: data: MutableMapping[MigrationKey, Status] = {} migration_groups = ( "(" + ( ", ".join( [ escape_string(group.value) for group in get_active_migration_groups() ] ) ) + ")" ) try: for row in self.__connection.execute( f"SELECT group, migration_id, status FROM {self.__table_name} FINAL WHERE group IN {migration_groups}" ): group_name, migration_id, status_name = row data[MigrationKey(MigrationGroup(group_name), migration_id)] = Status( status_name ) except ClickhouseError as e: # If the table wasn't created yet, no migrations have started. if e.code != errors.ErrorCodes.UNKNOWN_TABLE: raise e return data
def reverse(group: str, migration_id: str, force: bool, fake: bool, dry_run: bool) -> None: """ Reverses a single migration. --force is required to reverse an already completed migration. --fake marks a migration as reversed without doing anything. """ if not dry_run: check_clickhouse_connections() runner = Runner() migration_group = MigrationGroup(group) migration_key = MigrationKey(migration_group, migration_id) if dry_run: runner.reverse_migration(migration_key, dry_run=True) return try: if fake: click.confirm( "This will mark the migration as not started without actually reversing it. Your database may be in an invalid state. Are you sure?", abort=True, ) runner.reverse_migration(migration_key, force=force, fake=fake) except MigrationError as e: raise click.ClickException(str(e)) click.echo(f"Finished reversing migration {migration_key}")