Skip to content

Commit 2d4f49a

Browse files
Make GitHub app installation optional during init
1 parent 44bc4d4 commit 2d4f49a

2 files changed

Lines changed: 97 additions & 5 deletions

File tree

codeflash/cli_cmds/init_auth.py

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,17 @@ def enter_api_key_and_save_to_rc() -> None:
147147
os.environ["CODEFLASH_API_KEY"] = api_key
148148

149149

150+
def _skip_github_app_installation(owner: str, repo: str) -> None:
151+
click.echo(
152+
f"Skipping Codeflash GitHub app installation for {owner}/{repo}.{LF}"
153+
"Codeflash setup will continue, but PR creation will stay disabled until you install the app later."
154+
f"{LF}In the meantime you can make local only optimizations by using the '--no-pr' flag with codeflash.{LF}"
155+
)
156+
157+
150158
def install_github_app(git_remote: str) -> None:
159+
from rich.prompt import Confirm
160+
151161
try:
152162
git_repo = git.Repo(search_parent_directories=True)
153163
except git.InvalidGitRepositoryError:
@@ -167,6 +177,17 @@ def install_github_app(git_remote: str) -> None:
167177

168178
else:
169179
try:
180+
should_install = Confirm.ask(
181+
"Do you want to install the Codeflash GitHub app now? You can skip this and continue setup, "
182+
"but Codeflash won't be able to create PRs until the app is installed.",
183+
default=True,
184+
show_default=True,
185+
console=console,
186+
)
187+
if not should_install:
188+
_skip_github_app_installation(owner, repo)
189+
return
190+
170191
click.prompt(
171192
f"Finally, you'll need to install the Codeflash GitHub app by choosing the repository you want to install Codeflash on.{LF}"
172193
f"I will attempt to open the github app page - https://github.com/apps/codeflash-ai/installations/select_target {LF}"
@@ -188,11 +209,7 @@ def install_github_app(git_remote: str) -> None:
188209
count = 2
189210
while not is_github_app_installed_on_repo(owner, repo, suppress_errors=True):
190211
if count == 0:
191-
click.echo(
192-
f"❌ It looks like the Codeflash GitHub App is not installed on the repository {owner}/{repo}.{LF}"
193-
f"You won't be able to create PRs with Codeflash until you install the app.{LF}"
194-
f"In the meantime you can make local only optimizations by using the '--no-pr' flag with codeflash.{LF}"
195-
)
212+
_skip_github_app_installation(owner, repo)
196213
break
197214
click.prompt(
198215
f"❌ It looks like the Codeflash GitHub App is not installed on the repository {owner}/{repo}.{LF}"
@@ -207,3 +224,4 @@ def install_github_app(git_remote: str) -> None:
207224
except (KeyboardInterrupt, EOFError, click.exceptions.Abort):
208225
# leave empty line for the next prompt to be properly rendered
209226
click.echo()
227+
_skip_github_app_installation(owner, repo)

tests/test_init_auth.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
from __future__ import annotations
2+
3+
from unittest.mock import Mock, patch
4+
5+
from codeflash.cli_cmds.init_auth import install_github_app
6+
7+
8+
def _echo_messages(mock: Mock) -> list[str]:
9+
return [str(call.args[0]) for call in mock.call_args_list if call.args]
10+
11+
12+
def _mock_repo_context(monkeypatch) -> None:
13+
git_repo = object()
14+
monkeypatch.setattr("codeflash.cli_cmds.init_auth.git.Repo", Mock(return_value=git_repo))
15+
monkeypatch.setattr("codeflash.cli_cmds.init_auth.get_git_remotes", Mock(return_value=["origin"]))
16+
monkeypatch.setattr("codeflash.cli_cmds.init_auth.get_repo_owner_and_name", Mock(return_value=("octocat", "demo")))
17+
18+
19+
def test_install_github_app_allows_user_to_skip(monkeypatch) -> None:
20+
_mock_repo_context(monkeypatch)
21+
monkeypatch.setattr("codeflash.cli_cmds.init_auth.is_github_app_installed_on_repo", Mock(return_value=False))
22+
echo = Mock()
23+
prompt = Mock()
24+
launch = Mock()
25+
monkeypatch.setattr("codeflash.cli_cmds.init_auth.click.echo", echo)
26+
monkeypatch.setattr("codeflash.cli_cmds.init_auth.click.prompt", prompt)
27+
monkeypatch.setattr("codeflash.cli_cmds.init_auth.click.launch", launch)
28+
29+
with patch("rich.prompt.Confirm.ask", return_value=False) as confirm_ask:
30+
install_github_app("origin")
31+
32+
confirm_ask.assert_called_once()
33+
prompt.assert_not_called()
34+
launch.assert_not_called()
35+
assert any("Skipping Codeflash GitHub app installation for octocat/demo." in message for message in _echo_messages(echo))
36+
37+
38+
def test_install_github_app_skips_on_noninteractive_abort(monkeypatch) -> None:
39+
_mock_repo_context(monkeypatch)
40+
monkeypatch.setattr("codeflash.cli_cmds.init_auth.is_github_app_installed_on_repo", Mock(return_value=False))
41+
echo = Mock()
42+
prompt = Mock()
43+
launch = Mock()
44+
monkeypatch.setattr("codeflash.cli_cmds.init_auth.click.echo", echo)
45+
monkeypatch.setattr("codeflash.cli_cmds.init_auth.click.prompt", prompt)
46+
monkeypatch.setattr("codeflash.cli_cmds.init_auth.click.launch", launch)
47+
48+
with patch("rich.prompt.Confirm.ask", side_effect=EOFError):
49+
install_github_app("origin")
50+
51+
prompt.assert_not_called()
52+
launch.assert_not_called()
53+
assert any("Skipping Codeflash GitHub app installation for octocat/demo." in message for message in _echo_messages(echo))
54+
55+
56+
def test_install_github_app_still_runs_install_flow_when_confirmed(monkeypatch) -> None:
57+
_mock_repo_context(monkeypatch)
58+
monkeypatch.setattr(
59+
"codeflash.cli_cmds.init_auth.is_github_app_installed_on_repo",
60+
Mock(side_effect=[False, True]),
61+
)
62+
echo = Mock()
63+
prompt = Mock(return_value="")
64+
launch = Mock()
65+
monkeypatch.setattr("codeflash.cli_cmds.init_auth.click.echo", echo)
66+
monkeypatch.setattr("codeflash.cli_cmds.init_auth.click.prompt", prompt)
67+
monkeypatch.setattr("codeflash.cli_cmds.init_auth.click.launch", launch)
68+
69+
with patch("rich.prompt.Confirm.ask", return_value=True) as confirm_ask:
70+
install_github_app("origin")
71+
72+
confirm_ask.assert_called_once()
73+
launch.assert_called_once_with("https://github.com/apps/codeflash-ai/installations/select_target")
74+
assert prompt.call_count == 2

0 commit comments

Comments
 (0)