Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ mongocryptd.pid
.python-version
build/
uv.lock
secrets-export.sh
63 changes: 60 additions & 3 deletions django_mongodb_cli/repo.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import typer
import os
import shlex

from .utils import Package, Repo, Test

Expand Down Expand Up @@ -106,9 +107,7 @@ def cd(
ctx: typer.Context,
repo_name: str = typer.Argument(None),
):
"""
Change directory to the specified repository.
"""
"""Change directory to the specified repository."""
repo = Repo()
repo.ctx = ctx

Expand All @@ -122,6 +121,52 @@ def cd(
)


@repo.command()
def run(
ctx: typer.Context,
repo_name: str = typer.Argument(..., help="Repository name"),
command: list[str] = typer.Argument(
..., metavar="CMD...", help="Command (and args) to run in the repo directory"
),
):
"""Run an arbitrary command inside the repository directory.

Examples:
dm repo run mongo-python-driver just setup tests encryption
dm repo run mongo-python-driver "just setup tests encryption"

Environment variables can be configured per-repo under
``[tool.django-mongodb-cli.run.<repo_name>.env_vars]`` in ``pyproject.toml``.
"""
repo = Repo()
repo.ctx = ctx

# Allow a single shell-style string (e.g. "just setup tests encryption").
if len(command) == 1:
command = shlex.split(command[0])

path, _ = repo.ensure_repo(repo_name)
if not path:
return

# Build environment from current process plus any configured env_vars.
env = os.environ.copy()
run_cfg = repo.run_cfg(repo_name)
env_vars_list = run_cfg.get("env_vars")
if env_vars_list:
repo.info("Setting environment variables from pyproject.toml:")
for item in env_vars_list:
name = item.get("name")
value = str(item.get("value"))
if name is None:
continue
env[name] = value
typer.echo(f" {name}={value}")

repo.info(f"Running in {path}: {' '.join(command)}")
repo.run(command, cwd=path, env=env)


@repo.command()
def checkout(
ctx: typer.Context,
Expand Down Expand Up @@ -448,6 +493,18 @@ def reset_repo(name):
)


@repo.command()
def show(
ctx: typer.Context,
repo_name: str = typer.Argument(..., help="Repository name"),
commit_hash: str = typer.Argument(..., help="Commit hash to show"),
):
"""Show the git diff for a specific commit hash in the given repository."""
repo = Repo()
repo.ctx = ctx
repo.show_commit(repo_name, commit_hash)


@repo.command()
def set_default(
repo_name: str = typer.Argument(None),
Expand Down
31 changes: 30 additions & 1 deletion django_mongodb_cli/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,16 @@ def run(
args,
cwd: Path | str | None = None,
check: bool = True,
env: str | None = None,
env: dict[str, str] | None = None,
) -> bool:
"""Run a subprocess with optional working directory and environment.

Args:
args: Command and arguments to run.
cwd: Optional working directory.
check: Whether to raise on non-zero exit code.
env: Optional environment mapping to pass to the subprocess.
"""
try:
subprocess.run(args, cwd=str(cwd) if cwd else None, check=check, env=env)
return True
Expand All @@ -82,6 +90,14 @@ def tool_cfg(self) -> dict:
def test_cfg(self, repo_name: str) -> dict:
return self.tool_cfg.get("test", {}).get(repo_name, {}) or {}

def run_cfg(self, repo_name: str) -> dict:
"""Return configuration for arbitrary repo commands.

The config is read from [tool.django-mongodb-cli.run.<repo_name>] in
pyproject.toml and can contain keys like ``env_vars``.
"""
return self.tool_cfg.get("run", {}).get(repo_name, {}) or {}

def evergreen_cfg(self, repo_name: str) -> dict:
return self.tool_cfg.get("evergreen", {}).get(repo_name, {}) or {}

Expand Down Expand Up @@ -466,6 +482,19 @@ def get_repo_diff(self, repo_name: str) -> None:
except GitCommandError as e:
self.err(f"❌ Failed to diff working tree: {e}")

def show_commit(self, repo_name: str, commit_hash: str) -> None:
"""Show the diff for a specific commit hash in the given repository."""
self.info(f"Showing diff for {repo_name}@{commit_hash}")
path, repo = self.ensure_repo(repo_name)
if not repo or not path:
return

try:
output = repo.git.show(commit_hash)
typer.echo(output)
except GitCommandError as e:
self.err(f"❌ Failed to show commit {commit_hash}: {e}")

def _list_repos(self) -> tuple[set, set]:
map_repos = set(self.map.keys())

Expand Down
18 changes: 17 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ value = "/Users/alex.clark/Developer/django-mongodb-cli/src/drivers-evergreen-to

[[tool.django-mongodb-cli.test.mongo-python-driver.env_vars]]
name = "AWS_PROFILE"
value = "drivers-test-secrets-role-857654397073"
value = "my-profile"

[tool.django-mongodb-cli.test.django]
test_command = "./runtests.py"
Expand All @@ -142,6 +142,22 @@ test_dirs = [ "src/django/tests", "src/django-mongodb-backend/tests" ]
name = "PYMONGOCRYPT_LIB"
value = "/opt/homebrew/lib/libmongocrypt.dylib"

[[tool.django-mongodb-cli.test.django.env_vars]]
name = "MONGODB_URI"
value = "mongodb://localhost:64437/?directConnection=true"

[[tool.django-mongodb-cli.run.mongo-python-driver.env_vars]]
name = "DRIVERS_TOOLS"
value = "/Users/alex.clark/Developer/django-mongodb-cli/src/drivers-evergreen-tools"

[[tool.django-mongodb-cli.run.mongo-python-driver.env_vars]]
name = "MONGODB_URI"
value = "mongodb://localhost:64437/?directConnection=true"

[[tool.django-mongodb-cli.run.mongo-python-driver.env_vars]]
name = "AWS_PROFILE"
value = "my-profile"

[tool.django-mongodb-cli.test.django.migrations_dir]
source = "mongo_migrations"
target = "src/django/tests/mongo_migrations"
Expand Down
41 changes: 32 additions & 9 deletions test/settings/qe.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,35 @@

MONGODB_URI = os.environ.get("MONGODB_URI", "mongodb://localhost:27017")

# Configure KMS providers.
#
# We prefer AWS when FLE_AWS_KEY/FLE_AWS_SECRET are set, mirroring
# src/mongo-python-driver/test/helpers_shared.py. Otherwise we fall back
# to a local KMS for convenience in local development.
AWS_CREDS = {
"accessKeyId": os.environ.get("FLE_AWS_KEY", ""),
"secretAccessKey": os.environ.get("FLE_AWS_SECRET", ""),
}
_USE_AWS_KMS = any(AWS_CREDS.values())

if _USE_AWS_KMS:
# Use the same demo key ARN and region as the PyMongo QE tests.
_AWS_REGION = os.environ.get("FLE_AWS_KMS_REGION", "us-east-1")
_AWS_KEY_ARN = os.environ.get(
"FLE_AWS_KMS_KEY_ARN",
"arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0",
)
KMS_PROVIDERS = {"aws": AWS_CREDS}
KMS_CREDENTIALS = {"aws": {"key": _AWS_KEY_ARN, "region": _AWS_REGION}}
DEFAULT_KMS_PROVIDER = "aws"
else:
pass
# Local-only fallback: matches the original configuration.
# KMS_PROVIDERS = {"local": {"key": os.urandom(96)}}
# KMS_CREDENTIALS = {"aws": {}}
# DEFAULT_KMS_PROVIDER = "local"


DATABASES = {
"default": {
"ENGINE": "django_mongodb_backend",
Expand All @@ -24,16 +53,10 @@
"OPTIONS": {
"auto_encryption_opts": AutoEncryptionOpts(
key_vault_namespace="djangotests_encrypted.__keyVault",
kms_providers={
"local": {
"key": os.urandom(96),
},
},
kms_providers=KMS_PROVIDERS,
),
},
"KMS_CREDENTIALS": {
"aws": {},
},
"KMS_CREDENTIALS": KMS_CREDENTIALS,
},
}

Expand All @@ -57,7 +80,7 @@ def allow_migrate(self, db, app_label, model_name=None, **hints):
return None

def kms_provider(self, model):
return "local"
return DEFAULT_KMS_PROVIDER


DATABASE_ROUTERS = ["django_mongodb_backend.routers.MongoRouter", EncryptedRouter()]
Expand Down