Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Nov 9, 2025

Implements Google Drive backup synchronization for local-db with db push and db pull subcommands.

Changes

New module: commands/drive_sync.py

  • push_to_drive(): Stash local-db and upload to Drive /datastore folder
  • pull_from_drive(): Download from Drive and restore local-db
  • Google Drive auth via pydrive2, auto-creates /datastore folder
  • Fail-fast validation for missing local-db binary

CLI commands

  • db push [VERSION] [-o]: Defaults to today's date (YYYY-mm-DD), -o to overwrite
  • db pull [VERSION]: Downloads latest backup if VERSION omitted

The commands are grouped under the db command for better organization of database backup management operations.

Configuration

  • Added local_db_path to AppConfig
  • Accepts path from config.yaml or --local-db flag

Dependencies

  • Added pydrive2>=1.20.0 for Drive API

Usage

# Push with auto-version
lsu db push --local-db ./local-db

# Pull latest backup
lsu db pull --local-db ./local-db

# Or configure once in config.yaml
echo "local_db_path: ./local-db" >> config.yaml
lsu db push 2024-01-15 -o
lsu db pull 2024-01-15

Testing

15 unit tests covering path resolution, Drive operations, command execution, and error handling.

Original prompt

This section details on the original issue you should resolve

<issue_title>Drive-sync feature</issue_title>
<issue_description>I need to include support for pushing / downloading a local-db version to/from google drive
Requirements:

  • The script must expose two commands: push and pull.
  • As part of config, we need to put a setting where local-db binary is. It can be provided as setting or as a var when invoking the command.
  • At the moment only Google Drive should be supported, but we can leave it open for the future (ex: OneDrive).
    • I think pydrive2 can be used for google drive; ensure invoke whatever is required to authenticate against your account

Behavior:

  • push [VERSION] [-o]:

    • Run ./local-db stash VERSION.
    • If VERSION is omitted, use today’s date in format YYYY-mm-DD.
    • The stash produces a binary file named local-db-VERSION.bin.
    • Upload that file to Google Drive inside the /datastore folder.
    • If -o is passed, overwrite any existing file with the same name.
  • pull [VERSION]:

    • If VERSION is omitted, download the latest backup from /datastore.
    • If VERSION is provided, download that specific file (local-db-VERSION.bin).
    • Save it locally and run ./local-db restore VERSION.

Other requirements:

  • Fail fast if commands or files are missing.
  • Script must be auditable, modular, and portable.
  • Keep comments minimal, only if strictly necessary.
  • It should be another command, following same format as the ones we have.
  • As usual, add tests to cover as possible and ensure code is being compiled and executed without issues.
    </issue_description>

Comments on the Issue (you are @copilot in this section)


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Copilot AI self-assigned this Nov 9, 2025
Copilot AI changed the title [WIP] Add drive-sync feature for local-db Add drive-sync feature: push/pull local-db backups to Google Drive Nov 10, 2025
Copilot AI requested a review from khnumdev November 10, 2025 00:11
cli.py Outdated
typer.echo(f"Total entities {'to delete' if dry_run else 'deleted'}: {deleted_sum}")


@app.command("push")
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about this name. Command name should reflect something like to generate the stash and pulling. Maybe db push, being db the command and push/pull the subcommands

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot check my comment

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to db command with push and pull as subcommands in commit 6ba91e9.

Usage is now:

  • lsu db push [VERSION] [-o]
  • lsu db pull [VERSION]

The db command groups all database backup management operations.

Copilot AI changed the title Add drive-sync feature: push/pull local-db backups to Google Drive Add drive-sync feature: db push/pull local-db backups to Google Drive Nov 10, 2025
Copilot AI requested a review from khnumdev November 10, 2025 00:45
@khnumdev khnumdev requested a review from Copilot November 15, 2025 21:53
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR implements Google Drive backup synchronization for local-db databases, adding db push and db pull subcommands to the CLI for uploading and downloading database backups.

  • Added new module commands/drive_sync.py with Google Drive integration using pydrive2
  • Implemented db push and db pull commands under a new db command group
  • Added local_db_path configuration option to AppConfig

Reviewed Changes

Copilot reviewed 6 out of 7 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
commands/drive_sync.py New module implementing push/pull operations with Google Drive authentication, folder management, and local-db command execution
commands/config.py Added local_db_path configuration field to support the new drive sync feature
commands/init.py Exported new push_to_drive and pull_from_drive functions for the drive sync feature
cli.py Added db command group with push and pull subcommands for database backup management
requirements.txt Added pydrive2>=1.20.0 dependency for Google Drive API integration
pyproject.toml Added pydrive2>=1.20.0 to project dependencies
tests/test_drive_sync_unit.py Comprehensive unit tests covering path resolution, Drive operations, command execution, and error handling scenarios

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@db_app.command("push")
def db_push(
version: Annotated[
Optional[str], typer.Argument(help="Version name (defaults to today's date YYYY-mm-DD)")
Copy link

Copilot AI Nov 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The date format in the help text should be YYYY-MM-DD (capital M for months), not YYYY-mm-DD. The lowercase 'mm' typically represents minutes, while 'MM' represents months. The actual code implementation at line 64 of drive_sync.py correctly uses %Y-%m-%d format.

Suggested change
Optional[str], typer.Argument(help="Version name (defaults to today's date YYYY-mm-DD)")
Optional[str], typer.Argument(help="Version name (defaults to today's date YYYY-MM-DD)")

Copilot uses AI. Check for mistakes.
def _run_local_db_command(local_db_path: str, args: list[str]) -> None:
cmd = [local_db_path] + args
logger.info(f"Running: {' '.join(cmd)}")
result = subprocess.run(cmd, capture_output=True, text=True)
Copy link

Copilot AI Nov 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Consider adding a timeout parameter to subprocess.run() to prevent the command from hanging indefinitely. For example: subprocess.run(cmd, capture_output=True, text=True, timeout=300) for a 5-minute timeout. This is especially important for network operations that might hang.

Suggested change
result = subprocess.run(cmd, capture_output=True, text=True)
result = subprocess.run(cmd, capture_output=True, text=True, timeout=300)

Copilot uses AI. Check for mistakes.
logger.info(f"Downloading {backup_file} from Google Drive")
file_to_download.GetContentFile(backup_file)

version_to_restore = backup_file.replace("local-db-", "").replace(".bin", "")
Copy link

Copilot AI Nov 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The version extraction using chained .replace() calls could be fragile if filenames contain the substrings "local-db-" or ".bin" in unexpected places. Consider using a more robust approach with regex, such as:

import re
match = re.match(r'local-db-(.+)\.bin$', backup_file)
if not match:
    raise ValueError(f"Invalid backup filename format: {backup_file}")
version_to_restore = match.group(1)

This ensures the filename strictly matches the expected format and extracts the version correctly.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Drive-sync feature

3 participants