Skip to content

Commit 246d11f

Browse files
authored
✨ Add support for creating secrets (#146)
1 parent 6f68eb5 commit 246d11f

File tree

2 files changed

+75
-9
lines changed

2 files changed

+75
-9
lines changed

src/fastapi_cloud_cli/commands/env.py

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,13 @@ def set(
206206
help="A path to the folder containing the app you want to deploy"
207207
),
208208
] = None,
209+
secret: Annotated[
210+
bool,
211+
typer.Option(
212+
"--secret",
213+
help="Mark the environment variable as secret",
214+
),
215+
] = False,
209216
) -> Any:
210217
"""
211218
Set an environment variable for the app.
@@ -233,12 +240,18 @@ def set(
233240
raise typer.Exit(1)
234241

235242
if not name:
236-
name = toolkit.input("Enter the name of the environment variable to set:")
243+
if secret:
244+
name = toolkit.input("Enter the name of the secret to set:")
245+
else:
246+
name = toolkit.input(
247+
"Enter the name of the environment variable to set:"
248+
)
237249

238250
if not value:
239-
value = toolkit.input(
240-
"Enter the value of the environment variable to set:", password=True
241-
)
251+
if secret:
252+
value = toolkit.input("Enter the secret value:", password=True)
253+
else:
254+
value = toolkit.input("Enter the value of the environment variable:")
242255

243256
with toolkit.progress(
244257
"Setting environment variable", transient=True
@@ -247,6 +260,9 @@ def set(
247260
assert value is not None
248261

249262
with handle_http_errors(progress):
250-
_set_environment_variable(app_config.app_id, name, value)
263+
_set_environment_variable(app_config.app_id, name, value, secret)
251264

252-
toolkit.print(f"Environment variable [bold]{name}[/] set.")
265+
if secret:
266+
toolkit.print(f"Secret environment variable [bold]{name}[/] set.")
267+
else:
268+
toolkit.print(f"Environment variable [bold]{name}[/] set.")

tests/test_env_set.py

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,10 @@ def test_shows_a_message_if_app_is_not_configured(logged_in_cli: None) -> None:
4747
def test_shows_a_message_if_something_is_wrong(
4848
logged_in_cli: None, respx_mock: respx.MockRouter, configured_app: Path
4949
) -> None:
50-
respx_mock.post("/apps/123/environment-variables/").mock(return_value=Response(500))
50+
respx_mock.post(
51+
"/apps/123/environment-variables/",
52+
json={"name": "SOME_VAR", "value": "secret", "is_secret": False},
53+
).mock(return_value=Response(500))
5154

5255
with changing_dir(configured_app):
5356
result = runner.invoke(app, ["env", "set", "SOME_VAR", "secret"])
@@ -63,7 +66,10 @@ def test_shows_a_message_if_something_is_wrong(
6366
def test_shows_message_when_it_sets(
6467
logged_in_cli: None, respx_mock: respx.MockRouter, configured_app: Path
6568
) -> None:
66-
respx_mock.post("/apps/123/environment-variables/").mock(return_value=Response(200))
69+
respx_mock.post(
70+
"/apps/123/environment-variables/",
71+
json={"name": "SOME_VAR", "value": "secret", "is_secret": False},
72+
).mock(return_value=Response(200))
6773

6874
with changing_dir(configured_app):
6975
result = runner.invoke(app, ["env", "set", "SOME_VAR", "secret"])
@@ -78,7 +84,10 @@ def test_asks_for_name_and_value(
7884
) -> None:
7985
steps = [*"SOME_VAR", Keys.ENTER, *"secret", Keys.ENTER]
8086

81-
respx_mock.post("/apps/123/environment-variables/").mock(return_value=Response(200))
87+
respx_mock.post(
88+
"/apps/123/environment-variables/",
89+
json={"name": "SOME_VAR", "value": "secret", "is_secret": False},
90+
).mock(return_value=Response(200))
8291

8392
with (
8493
changing_dir(configured_app),
@@ -93,4 +102,45 @@ def test_asks_for_name_and_value(
93102

94103
assert "Environment variable SOME_VAR set" in result.output
95104

105+
106+
@pytest.mark.respx(base_url=settings.base_api_url)
107+
def test_asks_for_name_and_value_for_secret(
108+
logged_in_cli: None, respx_mock: respx.MockRouter, configured_app: Path
109+
) -> None:
110+
steps = [*"SOME_VAR", Keys.ENTER, *"secret", Keys.ENTER]
111+
112+
respx_mock.post(
113+
"/apps/123/environment-variables/",
114+
json={"name": "SOME_VAR", "value": "secret", "is_secret": True},
115+
).mock(return_value=Response(200))
116+
117+
with (
118+
changing_dir(configured_app),
119+
patch("rich_toolkit.container.getchar", side_effect=steps),
120+
):
121+
result = runner.invoke(app, ["env", "set", "--secret"])
122+
123+
assert result.exit_code == 0
124+
125+
assert "Enter the name of the secret" in result.output
126+
assert "Enter the secret value" in result.output
127+
128+
assert "Secret environment variable SOME_VAR set" in result.output
129+
96130
assert "*" * 6 in result.output
131+
132+
133+
@pytest.mark.respx(base_url=settings.base_api_url)
134+
def test_sets_secret_flag(
135+
logged_in_cli: None, respx_mock: respx.MockRouter, configured_app: Path
136+
) -> None:
137+
respx_mock.post(
138+
"/apps/123/environment-variables/",
139+
json={"name": "SOME_VAR", "value": "secret", "is_secret": True},
140+
).mock(return_value=Response(200))
141+
142+
with changing_dir(configured_app):
143+
result = runner.invoke(app, ["env", "set", "SOME_VAR", "secret", "--secret"])
144+
145+
assert result.exit_code == 0
146+
assert "Secret environment variable SOME_VAR set" in result.output

0 commit comments

Comments
 (0)