Skip to content

Commit 3f7a14e

Browse files
authored
✨ Add cloud ci print-workflow command (#267)
1 parent ae99761 commit 3f7a14e

5 files changed

Lines changed: 108 additions & 2 deletions

File tree

src/fastapi_cloud_cli/cli.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from .commands.apps.link import link_app
99
from .commands.apps.unlink import unlink_app
1010
from .commands.auth import auth_app
11+
from .commands.ci import ci_app
1112
from .commands.deploy import deploy
1213
from .commands.deployments import deployments_app
1314
from .commands.env import env_app
@@ -70,6 +71,7 @@ def cloud_main(
7071
cloud_app.add_typer(env_app, name="env")
7172
cloud_app.add_typer(auth_app, name="auth")
7273
cloud_app.add_typer(apps_app, name="apps")
74+
cloud_app.add_typer(ci_app, name="ci")
7375
cloud_app.add_typer(deployments_app, name="deployments")
7476
cloud_app.add_typer(teams_app, name="teams")
7577
cloud_app.add_typer(tokens_app, name="tokens")
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import typer
2+
3+
from fastapi_cloud_cli.commands.ci.print_workflow import (
4+
print_workflow as print_workflow_command,
5+
)
6+
7+
ci_app = typer.Typer(
8+
no_args_is_help=True,
9+
help="Manage CI integration helpers.",
10+
)
11+
ci_app.command("print-workflow")(print_workflow_command)
12+
13+
__all__ = ["ci_app"]
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
from typing import Annotated, Any
2+
3+
import typer
4+
from pydantic import BaseModel
5+
from rich_toolkit import RichToolkit
6+
7+
from fastapi_cloud_cli.commands.setup_ci import (
8+
DEFAULT_WORKFLOW_PATH,
9+
_get_default_branch,
10+
_get_workflow_content,
11+
)
12+
from fastapi_cloud_cli.utils.cli import get_rich_toolkit
13+
from fastapi_cloud_cli.utils.execution import JsonOutputOption
14+
15+
16+
class CIWorkflowOutput(BaseModel):
17+
filename: str
18+
content: str
19+
20+
21+
def _render_workflow_output(data: CIWorkflowOutput, toolkit: RichToolkit) -> None:
22+
toolkit.console.print(data.content, markup=False, end="")
23+
24+
25+
def print_workflow(
26+
branch: Annotated[
27+
str | None,
28+
typer.Option(
29+
"--branch",
30+
"-b",
31+
help="Branch that triggers deploys (defaults to the repo's default branch).",
32+
),
33+
] = None,
34+
json_output: JsonOutputOption = False,
35+
) -> Any:
36+
"""Prints the GitHub Actions workflow YAML without writing files or secrets."""
37+
38+
branch = branch or _get_default_branch()
39+
workflow = CIWorkflowOutput(
40+
filename=DEFAULT_WORKFLOW_PATH.name,
41+
content=_get_workflow_content(branch),
42+
)
43+
44+
with get_rich_toolkit(minimal=True, json_output=json_output) as toolkit:
45+
toolkit.success(workflow, render_output=_render_workflow_output)

src/fastapi_cloud_cli/commands/setup_ci.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,8 @@ def _get_default_branch() -> str:
132132
return "main"
133133

134134

135-
def _write_workflow_file(branch: str, workflow_path: Path) -> None:
136-
workflow_content = f"""\
135+
def _get_workflow_content(branch: str) -> str:
136+
return f"""\
137137
name: Deploy to FastAPI Cloud
138138
on:
139139
push:
@@ -149,6 +149,10 @@ def _write_workflow_file(branch: str, workflow_path: Path) -> None:
149149
FASTAPI_CLOUD_TOKEN: ${{{{ secrets.FASTAPI_CLOUD_TOKEN }}}}
150150
FASTAPI_CLOUD_APP_ID: ${{{{ secrets.FASTAPI_CLOUD_APP_ID }}}}
151151
"""
152+
153+
154+
def _write_workflow_file(branch: str, workflow_path: Path) -> None:
155+
workflow_content = _get_workflow_content(branch)
152156
workflow_path.parent.mkdir(parents=True, exist_ok=True)
153157
workflow_path.write_text(workflow_content)
154158

tests/test_cli_ci.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import json
2+
from unittest.mock import patch
3+
4+
from typer.testing import CliRunner
5+
6+
from fastapi_cloud_cli.cli import cloud_app as app
7+
from fastapi_cloud_cli.commands.setup_ci import _get_workflow_content
8+
9+
runner = CliRunner()
10+
11+
12+
def test_print_workflow_uses_default_branch() -> None:
13+
with patch(
14+
"fastapi_cloud_cli.commands.ci.print_workflow._get_default_branch",
15+
return_value="develop",
16+
):
17+
result = runner.invoke(app, ["ci", "print-workflow"])
18+
19+
assert result.exit_code == 0
20+
assert result.stdout == _get_workflow_content("develop")
21+
assert result.stderr == ""
22+
23+
24+
def test_print_workflow_uses_branch_option() -> None:
25+
result = runner.invoke(app, ["ci", "print-workflow", "--branch", "main"])
26+
27+
assert result.exit_code == 0
28+
assert result.stdout == _get_workflow_content("main")
29+
assert result.stderr == ""
30+
31+
32+
def test_print_workflow_json_outputs_envelope() -> None:
33+
result = runner.invoke(app, ["ci", "print-workflow", "--branch", "main", "--json"])
34+
35+
assert result.exit_code == 0
36+
assert json.loads(result.stdout) == {
37+
"data": {
38+
"filename": "deploy.yml",
39+
"content": _get_workflow_content("main"),
40+
}
41+
}
42+
assert result.stderr == ""

0 commit comments

Comments
 (0)