flowstash-cli 0.3.0__tar.gz → 0.4.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/PKG-INFO +2 -2
  2. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/pyproject.toml +2 -2
  3. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/commands/build.py +44 -20
  4. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/commands/deploy.py +44 -20
  5. flowstash_cli-0.3.0/src/flowstash/cli/templates/_config/[env]/.env +0 -3
  6. flowstash_cli-0.3.0/src/flowstash/cli/templates/_config/shared/.env +0 -2
  7. flowstash_cli-0.3.0/src/flowstash/cli/templates/_deployment/shared/.env +0 -5
  8. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/__init__.py +0 -0
  9. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/commands/__init__.py +0 -0
  10. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/commands/apikey.py +0 -0
  11. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/commands/auth.py +0 -0
  12. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/commands/client.py +0 -0
  13. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/commands/project.py +0 -0
  14. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/commands/run.py +0 -0
  15. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/commands/webhook.py +0 -0
  16. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/core/__init__.py +0 -0
  17. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/core/api_client.py +0 -0
  18. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/core/auth_server.py +0 -0
  19. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/core/builder.py +0 -0
  20. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/core/config.py +0 -0
  21. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/core/docker_utils.py +0 -0
  22. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/core/patcher.py +0 -0
  23. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/main.py +0 -0
  24. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/templates/AGENTS.md +0 -0
  25. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/templates/README.md +0 -0
  26. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/templates/_.dockerignore +0 -0
  27. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/templates/_.flowstash +0 -0
  28. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/templates/_api_main.py +0 -0
  29. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/templates/_config/[env]/(backend-asyncio)/backend.yaml +0 -0
  30. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/templates/_config/[env]/(backend-dramatiq)/backend.yaml +0 -0
  31. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/templates/_config/[env]/(backend-managed)/backend.yaml +0 -0
  32. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/templates/_config/[env]/(observability-logfile)/observability.yaml +0 -0
  33. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/templates/_config/[env]/(observability-managed)/observability.yaml +0 -0
  34. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/templates/_config/[env]/_backend.yaml +0 -0
  35. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/templates/_config/shared/backend.yaml +0 -0
  36. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/templates/_config/shared/clients/demoClient.yaml +0 -0
  37. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/templates/_config/shared/clients.yaml +0 -0
  38. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/templates/_deployment/[env]/(backend-asyncio)/docker-compose.yaml +0 -0
  39. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/templates/_deployment/[env]/(backend-dramatiq)/docker-compose.yaml +0 -0
  40. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/templates/_deployment/shared/api.Dockerfile +0 -0
  41. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/templates/_deployment/shared/worker.Dockerfile +0 -0
  42. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/templates/_pyproject.toml +0 -0
  43. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/templates/_src/_api/__init__.py +0 -0
  44. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/templates/_src/_api/_routes/webhooks.py +0 -0
  45. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/templates/_src/_shared/__init__.py +0 -0
  46. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/templates/_src/_shared/clients/client.py +0 -0
  47. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/templates/_src/_shared/models/models.py +0 -0
  48. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/templates/_src/_shared/tasks/sharedTasks.py +0 -0
  49. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/templates/_src/_worker/__init__.py +0 -0
  50. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/templates/_src/_worker/tasks/tasks.py +0 -0
  51. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/templates/_worker_main.py +0 -0
  52. {flowstash_cli-0.3.0 → flowstash_cli-0.4.1}/src/flowstash/cli/ui/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: flowstash-cli
3
- Version: 0.3.0
3
+ Version: 0.4.1
4
4
  Summary: CLI for the flowstash Managed Platform
5
5
  Author: juraj.bezdek@gmail.com
6
6
  Author-email: juraj.bezdek@gmail.com
@@ -9,7 +9,7 @@ Classifier: Programming Language :: Python :: 3
9
9
  Classifier: Programming Language :: Python :: 3.11
10
10
  Classifier: Programming Language :: Python :: 3.12
11
11
  Classifier: Programming Language :: Python :: 3.13
12
- Requires-Dist: flowstash-runtime (>=0.3.0,<0.4.0)
12
+ Requires-Dist: flowstash-runtime (>=0.4.1,<0.5.0)
13
13
  Requires-Dist: httpx (>=0.27.0)
14
14
  Requires-Dist: keyring (>=25.0.0)
15
15
  Requires-Dist: libcst (>=1.1.0)
@@ -1,11 +1,11 @@
1
1
  [project]
2
2
  name = "flowstash-cli"
3
- version = "0.3.0"
3
+ version = "0.4.1"
4
4
  description = "CLI for the flowstash Managed Platform"
5
5
  authors = [{name = "juraj.bezdek@gmail.com", email = "juraj.bezdek@gmail.com"}]
6
6
  requires-python = ">=3.11"
7
7
  dependencies = [
8
- "flowstash-runtime>=0.3.0,<0.4.0",
8
+ "flowstash-runtime>=0.4.1,<0.5.0",
9
9
  "typer[all]>=0.12.0",
10
10
  "httpx>=0.27.0",
11
11
  "pyyaml>=6.0.1",
@@ -14,26 +14,34 @@ app = typer.Typer()
14
14
  console = Console()
15
15
 
16
16
  from .project import find_project_root
17
- from ..core.docker_utils import check_docker_binary, check_docker_daemon, get_docker_compose_cmd
17
+ from ..core.docker_utils import (
18
+ check_docker_binary,
19
+ check_docker_daemon,
20
+ get_docker_compose_cmd,
21
+ )
22
+
18
23
 
19
24
  async def run_managed_build(tag: str = "latest"):
20
25
  project_config = load_project_config()
21
26
  if not project_config or not project_config.project_id:
22
- console.print("[red]Project not linked. Run 'flowstash init' to link to a managed project.[/red]")
27
+ console.print(
28
+ "[red]Project not linked. Run 'flowstash init' to link to a managed project.[/red]"
29
+ )
23
30
  raise typer.Exit(code=1)
24
-
31
+
25
32
  api = APIClient()
26
33
  # ... rest of existing managed build logic ...
27
34
  # (I'll keep the existing implementation but wrap it)
28
35
 
36
+
29
37
  @app.command()
30
38
  def build(
31
39
  env: str = typer.Argument(..., help="Environment to build"),
32
- tag: str = typer.Option("latest", "--tag", "-t", help="Tag for the image")
40
+ tag: str = typer.Option("latest", "--tag", "-t", help="Tag for the image"),
33
41
  ):
34
42
  """Build project artifacts/images for the specified environment."""
35
43
  project_config = load_project_config()
36
-
44
+
37
45
  # Check if env is managed
38
46
  is_managed = False
39
47
  if project_config:
@@ -41,7 +49,7 @@ def build(
41
49
  if em.name == env:
42
50
  is_managed = em.managed
43
51
  break
44
-
52
+
45
53
  if is_managed:
46
54
  result = asyncio.run(run_build_flow(tag))
47
55
  console.print(f"[green]Managed build completed successfully![/green]")
@@ -59,7 +67,9 @@ def build(
59
67
 
60
68
  compose_file = root / "deployment" / env / "docker-compose.yaml"
61
69
  if not compose_file.exists():
62
- console.print(f"[red]No docker-compose.yaml found for env '{env}' at {compose_file}[/red]")
70
+ console.print(
71
+ f"[red]No docker-compose.yaml found for env '{env}' at {compose_file}[/red]"
72
+ )
63
73
  raise typer.Exit(code=1)
64
74
 
65
75
  cmd = get_docker_compose_cmd() + ["-f", str(compose_file), "build"]
@@ -71,12 +81,13 @@ def build(
71
81
  console.print("[red]Local build failed.[/red]")
72
82
  raise typer.Exit(code=1)
73
83
 
84
+
74
85
  async def run_build_flow(tag: str = "latest"):
75
86
  # (Moved existing run_build_flow logic here for completeness in the file)
76
87
  project_config = load_project_config()
77
88
  project_id = project_config.project_id
78
89
  api = APIClient()
79
-
90
+
80
91
  try:
81
92
  with Progress(
82
93
  SpinnerColumn(),
@@ -85,26 +96,35 @@ async def run_build_flow(tag: str = "latest"):
85
96
  task = progress.add_task(description="Bundling source code...", total=None)
86
97
  tar_path = bundle_source(Path.cwd())
87
98
  progress.update(task, description="Source bundled.")
88
-
89
- task = progress.add_task(description="Requesting upload path...", total=None)
90
- upload_data = await api.get("/v1/builds/upload-path")
99
+
100
+ task = progress.add_task(
101
+ description="Requesting upload path...", total=None
102
+ )
103
+ upload_data = await api.get(
104
+ "/v1/builds/upload-path?project_id=" + project_id
105
+ )
91
106
  build_id = upload_data["build_id"]
92
107
  upload_url = upload_data["upload_url"]
93
108
  progress.update(task, description="Upload path received.")
94
-
109
+
95
110
  task = progress.add_task(description="Uploading source...", total=None)
96
111
  with open(tar_path, "rb") as f:
97
112
  data = f.read()
98
- await api.put_binary(upload_url, data, headers={"Content-Type": "application/gzip"})
113
+ await api.put_binary(
114
+ upload_url, data, headers={"Content-Type": "application/gzip"}
115
+ )
99
116
  progress.update(task, description="Source uploaded.")
100
-
117
+
101
118
  task = progress.add_task(description="Triggering build...", total=None)
102
- trigger_resp = await api.post(f"/v1/builds/{build_id}/trigger", json={"image_tag": tag})
103
-
119
+ trigger_resp = await api.post(
120
+ f"/v1/builds/{build_id}/trigger",
121
+ json={"image_tag": tag, "project_id": project_id},
122
+ )
123
+
104
124
  # update build_id to the triggered true GCP build ID
105
125
  build_id = trigger_resp["build_id"]
106
126
  progress.update(task, description=f"Build triggered (ID: {build_id}).")
107
-
127
+
108
128
  task = progress.add_task(description="Building...", total=None)
109
129
  while True:
110
130
  status_data = await api.get(f"/v1/builds/{build_id}/status")
@@ -113,11 +133,15 @@ async def run_build_flow(tag: str = "latest"):
113
133
  progress.update(task, description="Build successful!")
114
134
  return status_data
115
135
  elif status in ["FAILURE", "INTERNAL_ERROR", "TIMEOUT", "CANCELLED"]:
116
- progress.update(task, description=f"[red]Build failed: {status}[/red]")
136
+ progress.update(
137
+ task, description=f"[red]Build failed: {status}[/red]"
138
+ )
117
139
  console.print(f"[red]Build ended with status: {status}[/red]")
118
- log_url = status_data.get('log_url')
140
+ log_url = status_data.get("log_url")
119
141
  if log_url:
120
- console.print(f"Check logs here: [link={log_url}]{log_url}[/link]")
142
+ console.print(
143
+ f"Check logs here: [link={log_url}]{log_url}[/link]"
144
+ )
121
145
  raise typer.Exit(code=1)
122
146
  await asyncio.sleep(5)
123
147
  except Exception as e:
@@ -13,12 +13,12 @@ console = Console()
13
13
 
14
14
  # Status labels shown to the user while polling
15
15
  _STATUS_LABELS = {
16
- "QUEUED": "Queued, waiting for deployment to start...",
17
- "DEPLOYING": "Deploying services to Cloud Run...",
18
- "HEALTH_CHECK": "Health-checking API and Worker...",
16
+ "QUEUED": "Queued, waiting for deployment to start...",
17
+ "DEPLOYING": "Deploying services...",
18
+ "HEALTH_CHECK": "Health-checking API and Worker...",
19
19
  "SYNCING_SCHEDULES": "Fetching and syncing scheduled tasks...",
20
- "DEPLOYED": "Deployed successfully ✓",
21
- "FAILED": "Deployment failed.",
20
+ "DEPLOYED": "Deployed successfully ✓",
21
+ "FAILED": "Deployment failed.",
22
22
  }
23
23
 
24
24
  _TERMINAL_STATUSES = {"DEPLOYED", "FAILED"}
@@ -27,7 +27,9 @@ _TERMINAL_STATUSES = {"DEPLOYED", "FAILED"}
27
27
  async def run_deploy_flow(env: str, artifact_id: Optional[str] = None):
28
28
  project_config = load_project_config()
29
29
  if not project_config:
30
- console.print("[red]No .flowstash found. Please run 'flowstash init' first.[/red]")
30
+ console.print(
31
+ "[red]No .flowstash found. Please run 'flowstash init' first.[/red]"
32
+ )
31
33
  raise typer.Exit(code=1)
32
34
 
33
35
  project_id = project_config.project_id
@@ -51,11 +53,14 @@ async def run_deploy_flow(env: str, artifact_id: Optional[str] = None):
51
53
  ) as progress:
52
54
  # 2. Trigger deployment
53
55
  task = progress.add_task(description="Triggering deployment...", total=None)
54
- deploy_data = await api.post("/v1/deploy", json={
55
- "project_id": project_id,
56
- "artifact_id": artifact_id,
57
- "env_vars": {"ENVIRONMENT": env}
58
- })
56
+ deploy_data = await api.post(
57
+ "/v1/deploy",
58
+ json={
59
+ "project_id": project_id,
60
+ "artifact_id": artifact_id,
61
+ "env_vars": {"ENVIRONMENT": env},
62
+ },
63
+ )
59
64
  deploy_id = deploy_data["deploy_id"]
60
65
  progress.update(task, description=f"Deployment triggered (ID: {deploy_id}).")
61
66
 
@@ -85,18 +90,25 @@ async def run_deploy_flow(env: str, artifact_id: Optional[str] = None):
85
90
  @app.command()
86
91
  def deploy(
87
92
  env: str = typer.Argument(..., help="Environment to deploy to"),
88
- artifact: Optional[str] = typer.Option(None, "--artifact", "-a", help="Artifact ID to deploy"),
89
- non_interactive: bool = typer.Option(False, "--non-interactive", help="Do not ask for confirmation")
93
+ artifact: Optional[str] = typer.Option(
94
+ None, "--artifact", "-a", help="Artifact ID to deploy"
95
+ ),
96
+ non_interactive: bool = typer.Option(
97
+ False, "--non-interactive", help="Do not ask for confirmation"
98
+ ),
90
99
  ):
91
100
  """Deploy an artifact to the managed platform for a specified environment."""
92
101
  project_config = load_project_config()
93
102
  if not project_config:
94
- console.print("[red]No .flowstash found. Please run 'flowstash init' first.[/red]")
103
+ console.print(
104
+ "[red]No .flowstash found. Please run 'flowstash init' first.[/red]"
105
+ )
95
106
  raise typer.Exit(code=1)
96
107
 
97
108
  # Ask for confirmation unless non-interactive is provided
98
109
  if not non_interactive:
99
110
  from rich.prompt import Confirm
111
+
100
112
  if not Confirm.ask(f"Are you sure you want to deploy to '{env}'?"):
101
113
  console.print("Deployment cancelled.")
102
114
  raise typer.Exit(code=0)
@@ -109,21 +121,31 @@ def deploy(
109
121
  break
110
122
 
111
123
  if not is_managed:
112
- console.print(f"[red]Environment '{env}' is not managed. Deployment is only supported for managed environments.[/red]")
113
- console.print("[yellow]Update your .flowstash environments if this is incorrect.[/yellow]")
124
+ console.print(
125
+ f"[red]Environment '{env}' is not managed. Deployment is only supported for managed environments.[/red]"
126
+ )
127
+ console.print(
128
+ "[yellow]Update your .flowstash environments if this is incorrect.[/yellow]"
129
+ )
114
130
  raise typer.Exit(code=1)
115
131
 
116
132
  project_id = project_config.project_id
117
133
  if not project_id:
118
134
  if not non_interactive:
119
135
  from rich.prompt import Confirm
120
- if Confirm.ask("Project ID not found. Would you like to link to a managed project now?"):
136
+
137
+ if Confirm.ask(
138
+ "Project ID not found. Would you like to link to a managed project now?"
139
+ ):
121
140
  from .project import _link_project
141
+
122
142
  _link_project(project_config)
123
143
  project_id = project_config.project_id
124
144
 
125
145
  if not project_id:
126
- console.print("[red]project_id not found in .flowstash. Use 'flowstash init' or link to a project.[/red]")
146
+ console.print(
147
+ "[red]project_id not found in .flowstash. Use 'flowstash init' or link to a project.[/red]"
148
+ )
127
149
  raise typer.Exit(code=1)
128
150
 
129
151
  result = asyncio.run(run_deploy_flow(env, artifact))
@@ -133,11 +155,13 @@ def deploy(
133
155
  console.print(f" Deployment ID : [bold]{result['deploy_id']}[/bold]")
134
156
  if api_url:
135
157
  console.print(f" API URL : [bold]{api_url}[/bold]")
136
-
158
+
137
159
  scheduled_tasks = result.get("scheduled_tasks")
138
160
  if scheduled_tasks:
139
161
  console.print(" Scheduled Tasks:")
140
162
  for task in scheduled_tasks:
141
- console.print(f" - [cyan]{task['task_name']}[/cyan] : [yellow]{task['cron']}[/yellow]")
163
+ console.print(
164
+ f" - [cyan]{task['task_name']}[/cyan] : [yellow]{task['cron']}[/yellow]"
165
+ )
142
166
  elif scheduled_tasks is not None:
143
167
  console.print(" Scheduled Tasks: [dim]None[/dim]")
@@ -1,3 +0,0 @@
1
- # Specific Envirment Variables for this enviroment belong here
2
- # i.e.
3
- # FOO_SEVICE_BASE_URL=dev/prod.rest.domain.com/v1
@@ -1,2 +0,0 @@
1
- # Flowstash managed observability API key (required when storeType: managed)
2
- # FLOWSTASH_API_KEY=
@@ -1,5 +0,0 @@
1
- # Any ENV variables that should have the same value for any enviroment bellong here
2
- # i.e.
3
- # TEST_ENV_VAR=demo-value
4
- # DEMO_CLIENT_ID=123
5
- # DEMO_CLIENT_SECRET=456