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
79 changes: 69 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,45 +7,104 @@ Allows you to spin up versioned Appwrite deployments for easy testing via CLI of
```sh
pip install appwrite-lab
```
## Appwrite Lab features (in progress)
## Appwrite Lab features
- [x] Spin up ephemeral Appwrite instances with Docker/Podman
- [x] Automatically grab API keys (for programmatic access)
- [x] Environment syncing
- [x] Environment syncing (with `appwrite.json`)
- [x] Clean teardowns
- [x] Test suite

## Appwrite Lab in progress features
- [ ] Test suite
## Appwrite Lab (in progress)
- [ ] Appwrite data population

## CLI Usage
### Help with appwrite-lab CLI
```sh
appwrite-lab --help
```
or
```sh
awlab --help
```

### To get started spinning up a lab instance, use:

To get started spinning up a lab instance, use:
```sh
awlab new lab test --version 1.7.4
```
#### Example of additional args:
Additional arguments can be found here.
```sh
awlab new lab --help
```

```sh
appwrite-lab new lab test-lab --version 1.7.4
awlab new lab test --version 1.7.4 --port 8005 --email test@example.com --password xxxxxxx12
```

To teardown,
### To teardown

```sh
appwrite-lab stop test-lab
awlab stop test
```
### Listing Appwrite Labs
```sh
awlab list labs
```

### Sync an Appwrite lab from your prod lab schema
Run in the same folder where your `appwrite.json` is located to sync `all` resources:
```sh
appwrite-lab sync test-lab
awlab sync test
```
or sync a specific resource:

```sh
appwrite-lab sync test-lab --resource functions
awlab sync test --resource functions
```

## Python usage

### Creating a lab
```py
from appwrite_lab import Labs
from appwrite_lab.models import AppwriteLabCreation

labs = Labs()
lab_res = labs.new(
name="test",
version="1.7.4",
auth=AppwriteLabCreation(
admin_email="test@example.com",
admin_password="xxxxxxx12",
project_id=None, # for auto gen
project_name=None, # for auto gen
)
port=8005
)

assert lab_res.data
```

#### Random generation that's compliant
```py
from appwrite_lab.models import AppwriteLabCreation

auth = AppwriteLabCreation.generate()
```

### Syncing a lab
```py
from appwrite_lab import Labs
from appwrite_lab.automations.models import Expiration

Labs().sync_with_appwrite_config(
name="test",
appwrite_json="appwrite.json", # if not directly in folder
sync_type="all",
expiration=Expiration.THIRTY_DAYS,
)
```
## Known Troubleshooting
### Podman support and Selinux
Since I am mimicking the `compose` file that Appwrite provides, it was not designed to work rootless, but I have adjusted to work also on Fedora. You will need to turn `selinux` off for now to use.
Expand Down
12 changes: 8 additions & 4 deletions appwrite_lab/_orchestrator.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
import tempfile
from pathlib import Path

from appwrite_lab.automations.models import BaseVarModel, AppwriteAPIKeyCreation
from appwrite_lab.automations.models import (
BaseVarModel,
AppwriteAPIKeyCreation,
AppwriteUserCreation,
)
from ._state import State
from dataclasses import dataclass
from .models import Lab, Automation, Project
Expand Down Expand Up @@ -162,7 +166,7 @@ def deploy_appwrite_lab(
name: str,
version: str,
port: int,
meta: dict[str, str],
auth: AppwriteUserCreation | None = None,
**kwargs: dict[str, str],
):
"""
Expand All @@ -172,11 +176,11 @@ def deploy_appwrite_lab(
name: The name to give to the deployment/project.
version: The version of the service to deploy.
port: The port to use for the Appwrite service. Must not be in use by another service.
meta: Extra metadata to pass to the deployment.
auth: The authentication credentials.

"""
# sync
appwrite_config = meta.get("appwrite_config", {})
appwrite_config = asdict(auth) if auth else {}

pods_by_project = self.get_pods_by_project(name)
if len(pods_by_project) > 0:
Expand Down
17 changes: 16 additions & 1 deletion appwrite_lab/automations/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,19 @@
from .common import AppwriteCLI
from .utils import PlaywrightAutomationError
from .models import (
AppwriteLabCreation,
AppwriteUserCreation,
AppwriteProjectCreation,
AppwriteSyncProject,
AppwriteAPIKeyCreation,
)

__all__ = ("AppwriteCLI", "PlaywrightAutomationError")
__all__ = (
"AppwriteCLI",
"PlaywrightAutomationError",
"AppwriteLabCreation",
"AppwriteUserCreation",
"AppwriteProjectCreation",
"AppwriteSyncProject",
"AppwriteAPIKeyCreation",
)
26 changes: 26 additions & 0 deletions appwrite_lab/automations/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,32 @@ class AppwriteAPIKeyCreation(BaseVarModel):
key_expiry: Expiration


@dataclass
class AppwriteLabCreation(BaseVarModel):
admin_email: str | None = None
admin_password: str | None = None
project_id: str | None = None
project_name: str | None = None
url: str | None = None

def generate(self):
"""Generate random data for model"""
random_key = str(uuid.uuid4())
password = random_key[:16]
last_six = random_key[-6:]
admin_password = password
admin_email = f"admin{last_six}@local.dev"
project_id = random_key
project_name = f"test-project-{last_six}"

return AppwriteUserCreation(
admin_email=admin_email,
admin_password=admin_password,
project_id=project_id,
project_name=project_name,
)


@dataclass
class AppwriteUserCreation(BaseVarModel):
url: str
Expand Down
2 changes: 1 addition & 1 deletion appwrite_lab/cli/list_menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
labs = get_global_labs()


@list_menu.command(name="labs")
@list_menu.command(name="labs", help="List resources.")
def get_labs():
"""List all ephemeral Appwrite instances."""
headers, pods = labs.orchestrator.get_formatted_labs(collapsed=True)
Expand Down
16 changes: 8 additions & 8 deletions appwrite_lab/cli/new_menu.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import typer
from appwrite_lab.utils import console
from appwrite_lab import get_global_labs
from appwrite_lab.automations.models import Expiration
from appwrite_lab.automations.models import Expiration, AppwriteUserCreation

new_menu = typer.Typer(name="new", help="Create a new resource.")

Expand Down Expand Up @@ -59,18 +59,18 @@ def new_lab(
with console.status(
f"Creating lab '{name}'{extra_str}...", spinner="dots"
) as status:
creds = {
"admin_email": email,
"admin_password": password,
"project_id": project_id,
"project_name": project_name,
}
creds = AppwriteUserCreation(
admin_email=email,
admin_password=password,
project_id=project_id,
project_name=project_name,
)

labs.new(
name=name,
version=version,
port=port,
meta={"appwrite_config": creds},
auth=creds,
just_deploy=just_deploy,
)
status.update(f"Creating lab '{name}'... done")
Expand Down
7 changes: 5 additions & 2 deletions appwrite_lab/labs.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from ._orchestrator import ServiceOrchestrator, Response
from .models import Automation, Lab
from appwrite_lab.automations.models import (
AppwriteLabCreation,
AppwriteProjectCreation,
AppwriteSyncProject,
AppwriteAPIKeyCreation,
Expand All @@ -25,7 +26,7 @@ def new(
name: str,
version: str,
port: int,
meta: dict[str, str] = {},
auth: AppwriteLabCreation | None = None,
just_deploy: bool = False,
):
"""
Expand All @@ -35,9 +36,11 @@ def new(
name: The name of the lab.
version: The version of the lab.
port: The port of the lab.
auth: The authentication credentials.
just_deploy: Deploy the lab without creating an API key or project.
"""
return self.orchestrator.deploy_appwrite_lab(
name, version, port, meta, just_deploy=just_deploy
name, version, port, auth, just_deploy=just_deploy
)

def get_lab(self, name: str) -> Lab | None:
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "appwrite-lab"
version = "0.0.7"
version = "0.1.0"
description = "Zero-click Appwrite test environments."
readme = "README.md"
requires-python = ">=3.11"
Expand Down
Loading