Coverage for frappe_manager / commands / ngrok.py: 29%

45 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-07-02 18:13 +0530

1from typing import Annotated 

2 

3import typer 

4from typer_examples import example 

5 

6from frappe_manager.metadata_manager import FMConfigManager 

7from frappe_manager.ngrok import create_tunnel 

8from frappe_manager.output_manager import get_global_output_handler 

9from frappe_manager.output_manager.context_managers import spinner, temporary_stop 

10from frappe_manager.site_manager.exceptions import BenchNotRunning 

11from frappe_manager.site_manager.site import Bench 

12from frappe_manager.utils.callbacks import sitename_callback, sites_autocompletion_callback 

13 

14 

15@example( 

16 "Create ngrok tunnel for bench", 

17 "{benchname} --auth-token YOUR_TOKEN", 

18 detail="Creates a public ngrok tunnel for the bench using a specified auth token.", 

19 benchname="mybench", 

20) 

21@example( 

22 "Use saved auth token from config", 

23 "{benchname}", 

24 detail="Uses an auth token stored in FM configuration to create the tunnel without passing it on the command line.", 

25 benchname="mybench", 

26) 

27def ngrok( 

28 ctx: typer.Context, 

29 benchname: Annotated[ 

30 str | None, 

31 typer.Argument( 

32 help="Name of the bench.", 

33 autocompletion=sites_autocompletion_callback, 

34 callback=sitename_callback, 

35 ), 

36 ] = None, 

37 auth_token: Annotated[ 

38 str | None, 

39 typer.Option("--auth-token", "-t", help="Ngrok authentication token", envvar="NGROK_AUTHTOKEN"), 

40 ] = None, 

41 save_token: Annotated[ 

42 bool | None, 

43 typer.Option( 

44 "--save-token/--no-save-token", 

45 help="Save or don't save the ngrok auth token to config for future use", 

46 ), 

47 ] = None, 

48): 

49 """ 

50 Create ngrok tunnel for bench. 

51 

52 Provisions a public URL for local benches using ngrok; requires an auth token either via flag or config. 

53 """ 

54 services_manager = ctx.obj["services"] 

55 verbose = ctx.obj["verbose"] 

56 

57 output = get_global_output_handler() 

58 logger = ctx.obj.get("logger") 

59 bench = Bench.get_object(benchname, services_manager, logger=logger, output_handler=output) 

60 

61 if not bench.running: 

62 raise BenchNotRunning(bench_name=bench.name) 

63 

64 fm_config_manager: FMConfigManager = ctx.obj["fm_config_manager"] 

65 

66 with spinner(output, "Setting up ngrok tunnel"): 

67 if not auth_token and fm_config_manager.ngrok_auth_token: 

68 auth_token = fm_config_manager.ngrok_auth_token 

69 output.print("Using ngrok auth token from config file", emoji_code=":key:") 

70 elif not auth_token: 

71 output.display_error( 

72 "Ngrok auth token is required. Please provide it with --auth-token or set NGROK_AUTHTOKEN environment variable.", 

73 ) 

74 raise typer.Exit(1) 

75 

76 if auth_token and not fm_config_manager.ngrok_auth_token: 

77 output.print("New auth token provided", emoji_code=":new:") 

78 

79 if save_token is None: 

80 with temporary_stop(output): 

81 should_save = output.prompt_ask( 

82 prompt="Do you want to save the ngrok auth token in config for future use?", 

83 choices=["yes", "no"], 

84 required_flag="--save-token or --no-save-token", 

85 ) 

86 else: 

87 should_save = "yes" if save_token else "no" 

88 

89 if should_save == "yes": 

90 output.print("Saving auth token to config...", emoji_code=":floppy_disk:") 

91 fm_config_manager.ngrok_auth_token = auth_token 

92 fm_config_manager.export_to_toml() 

93 output.print("Saved ngrok auth token to config", emoji_code=":white_check_mark:") 

94 

95 output.print(f"Creating ngrok tunnel for {bench.name}", emoji_code=":link:") 

96 

97 try: 

98 create_tunnel(bench.name, auth_token) 

99 except Exception as e: 

100 output.display_error(f"Failed to create tunnel: {e!s}") 

101 raise