Skip to content

Commit 282b7a7

Browse files
authored
New metablock (#25)
* new * lint
1 parent e538e55 commit 282b7a7

File tree

12 files changed

+393
-327
lines changed

12 files changed

+393
-327
lines changed

.dev/install

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
#!/usr/bin/env bash
22

33
pip install -U pip poetry
4-
poetry install --no-root
4+
poetry install

metablock/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from .spaces import Block, Service, Space, SpaceExtension
66
from .user import User
77

8-
__version__ = "0.9.0"
8+
__version__ = "1.0.0"
99

1010
__all__ = [
1111
"Metablock",

metablock/cli.py

Lines changed: 74 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import asyncio
22
import os
3+
import zipfile
34
from pathlib import Path
45

56
import click
@@ -8,6 +9,8 @@
89
from metablock import Metablock
910

1011
METABLOCK_SPACE = os.environ.get("METABLOCK_SPACE", "")
12+
METABLOCK_ENV = os.environ.get("METABLOCK_ENV", "prod")
13+
METABLOCK_BLOCK_ID = os.environ.get("METABLOCK_BLOCK_ID", "")
1114
METABLOCK_API_TOKEN = os.environ.get("METABLOCK_API_TOKEN", "")
1215

1316

@@ -22,15 +25,50 @@ def main() -> None:
2225

2326
@main.command()
2427
@click.argument("path", type=click.Path(exists=True))
25-
@click.option("--space", "space_name", help="Space name", default=METABLOCK_SPACE)
28+
@click.option(
29+
"--space",
30+
"space_name",
31+
help="Space name",
32+
default=METABLOCK_SPACE,
33+
show_default=True,
34+
)
2635
@click.option("--token", help="metablock API token", default=METABLOCK_API_TOKEN)
2736
def apply(path: str, space_name: str, token: str) -> None:
28-
"""Apply metablock manifest"""
37+
"""Apply metablock manifest to a metablock space"""
2938
asyncio.get_event_loop().run_until_complete(
3039
_apply(path, space_name or METABLOCK_SPACE, token or METABLOCK_API_TOKEN)
3140
)
3241

3342

43+
@main.command()
44+
@click.argument("path", type=click.Path(exists=True))
45+
@click.option(
46+
"--env",
47+
help="Environment to ship to",
48+
type=click.Choice(["prod", "stage"]),
49+
default=METABLOCK_ENV,
50+
show_default=True,
51+
)
52+
@click.option(
53+
"--block-id",
54+
help="Block ID",
55+
default=METABLOCK_BLOCK_ID,
56+
show_default=True,
57+
)
58+
@click.option(
59+
"--name",
60+
help="Optional deployment name",
61+
default="shipped from metablock-py",
62+
show_default=True,
63+
)
64+
@click.option("--token", help="metablock API token", default=METABLOCK_API_TOKEN)
65+
def ship(path: str, env: str, block_id: str, name: str, token: str) -> None:
66+
"""Deploy a new version of html block"""
67+
asyncio.get_event_loop().run_until_complete(
68+
_ship(path, env, block_id, name, token or METABLOCK_API_TOKEN)
69+
)
70+
71+
3472
async def _apply(path: str, space_name: str, token: str) -> None:
3573
if not token:
3674
click.echo("metablock API token is required", err=True)
@@ -52,9 +90,41 @@ async def _apply(path: str, space_name: str, token: str) -> None:
5290
block = by_name.get(name)
5391
if block:
5492
# update
55-
await mb.services.update(block.id, **config)
93+
await mb.blocks.update(block.id, **config)
5694
click.echo(f"updated block {name}")
5795
else:
5896
# create
59-
await space.services.create(name=name, **config)
97+
await space.blocks.create(name=name, **config)
6098
click.echo(f"created new block {name}")
99+
100+
101+
async def _ship(path: str, env: str, block_id: str, name: str, token: str) -> None:
102+
if not token:
103+
click.echo("metablock API token is required", err=True)
104+
raise click.Abort()
105+
if not block_id:
106+
click.echo("metablock block-id is required", err=True)
107+
raise click.Abort()
108+
p = Path(path)
109+
if not p.is_dir():
110+
click.echo(f"path {p} does not exist", err=True)
111+
raise click.Abort()
112+
113+
# Create a zip file from the directory
114+
zip_path = p.with_suffix(".zip")
115+
try:
116+
with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zipf:
117+
for file in p.rglob("*"): # Recursively add all files in the directory
118+
arcname = file.relative_to(p) # Preserve relative paths in the archive
119+
zipf.write(file, arcname)
120+
click.echo(f"Created zip file: {zip_path}")
121+
122+
async with Metablock(auth_key=token) as mb:
123+
block = await mb.blocks.get(block_id)
124+
await block.ship(zip_path, name=name, env=env)
125+
click.echo(f"shipped {zip_path} to {block.name} {env}")
126+
finally:
127+
# Clean up the zip file after shipping
128+
if zip_path.exists():
129+
zip_path.unlink()
130+
click.echo(f"Removed temporary zip file: {zip_path}")

metablock/client.py

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,10 @@ def __init__(
4444
}
4545
self.orgs: Orgs = Orgs(self, Org)
4646
self.spaces: Spaces = Spaces(self, Space)
47-
self.blocks: Blocks = Blocks(self, Block, "services")
47+
self.blocks: Blocks = Blocks(self, Block)
4848
self.plugins: Plugins = Plugins(self, Plugin)
4949
self.extensions: Extensions = Extensions(self, Extension)
5050
self.domains = Domains(self)
51-
self.services = self.blocks
5251

5352
@property
5453
def cli(self) -> Self:
@@ -66,7 +65,7 @@ async def __aexit__(self, exc_type: type, exc_val: Any, exc_tb: Any) -> None:
6665
await self.close()
6766

6867
async def spec(self) -> dict:
69-
return await self.request(f"{self.url}/spec")
68+
return await self.request(f"{self.url}/openapi.json")
7069

7170
async def get(self, url: str, **kwargs: Any) -> Any:
7271
kwargs["method"] = "GET"
@@ -93,7 +92,7 @@ async def request(
9392
url: str,
9493
method: str = "",
9594
headers: dict[str, str] | None = None,
96-
callback: Callback | None = None,
95+
callback: Callback | bool | None = None,
9796
wrap: Any = None,
9897
**kw: Any,
9998
) -> Any:
@@ -103,7 +102,9 @@ async def request(
103102
headers_ = self.get_default_headers()
104103
headers_.update(headers or ())
105104
response = await self.session.request(method, url, headers=headers_, **kw)
106-
if callback:
105+
if callback is True:
106+
return response
107+
elif callback:
107108
return await callback(response)
108109
else:
109110
return await self.handle_response(response, wrap=wrap)
@@ -125,10 +126,6 @@ async def get_user(self, **kw: Any) -> User:
125126
kw.setdefault("wrap", self._user)
126127
return await self.get(f"{self.url}/user", **kw)
127128

128-
async def get_space(self, **kw: Any) -> Space:
129-
kw.setdefault("wrap", self._space)
130-
return await self.get(f"{self.url}/space", **kw)
131-
132129
async def update_user(self, **kw: Any) -> User:
133130
kw.setdefault("wrap", self._user)
134131
return await self.patch(f"{self.url}/user", **kw)
@@ -144,6 +141,3 @@ def get_default_headers(self) -> dict[str, str]:
144141

145142
def _user(self, data: dict) -> User:
146143
return User(self, data)
147-
148-
def _space(self, data: dict) -> Space:
149-
return Space(self.spaces, data)

metablock/extensions.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ class Extensions(CrudComponent[Extension]):
1515

1616
# Plugin
1717
class Plugin(MetablockEntity):
18-
"""Object representing an Plugin"""
18+
"""Object representing a Plugin"""
1919

2020
async def blocks(self, **kwargs: Any) -> list[BlockPlugin]:
21-
return await self.cli.get(f"{self.url}/services", **kwargs)
21+
return await self.cli.get(f"{self.url}/blocks", **kwargs)
2222

2323

2424
class Plugins(CrudComponent[Plugin]):

metablock/spaces.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import annotations
22

3+
from pathlib import Path
34
from typing import Any
45

56
from .components import Component, CrudComponent, MetablockEntity
@@ -11,12 +12,7 @@ class Space(MetablockEntity):
1112

1213
@property
1314
def blocks(self) -> SpaceBlocks:
14-
return SpaceBlocks(self, Block, "services")
15-
16-
@property
17-
def services(self) -> SpaceBlocks: # pragma: no cover
18-
# TODO: Deprecate
19-
return self.blocks
15+
return SpaceBlocks(self, Block, "blocks")
2016

2117
@property
2218
def extensions(self) -> SpaceExtensions:
@@ -46,8 +42,14 @@ async def certificate(self, *, callback: Any = None) -> dict:
4642
return await self.cli.get(f"{self.url}/certificate", callback=callback)
4743

4844
async def ship(
49-
self, name: str, bundle: str, env: str = "stage", *, callback: Any = None
45+
self,
46+
bundle_path: str | Path,
47+
name: str = "",
48+
env: str = "stage",
49+
*,
50+
callback: Any = None,
5051
) -> dict:
52+
bundle = str(bundle_path)
5153
return await self.cli.post(
5254
f"{self.url}/deployments",
5355
data=dict(name=name, env=env),

0 commit comments

Comments
 (0)