Coverage for  / home / runner / work / bijux-cli / bijux-cli / src / bijux_cli / cli / commands / config / reload.py: 100%

30 statements  

« prev     ^ index     » next       coverage.py v7.13.2, created at 2026-01-26 17:59 +0000

1# SPDX-License-Identifier: Apache-2.0 

2# Copyright © 2025 Bijan Mousavi 

3 

4"""Implements the `config reload` subcommand for the Bijux CLI. 

5 

6This module contains the logic for manually reloading the application's 

7configuration from its source file on disk. It discards any in-memory 

8settings and replaces them with the content of the configuration file, 

9emitting a structured confirmation upon success. 

10 

11Output Contract: 

12 * Success: `{"status": "reloaded"}` 

13 * Error: `{"error": str, "code": int}` 

14 

15Exit Codes: 

16 * `0`: Success. 

17 * `2`: The configuration file could not be read or parsed. 

18""" 

19 

20from __future__ import annotations 

21 

22import platform 

23 

24import typer 

25 

26from bijux_cli.cli.core.command import ( 

27 ascii_safe, 

28 new_run_command, 

29 validate_common_flags, 

30) 

31from bijux_cli.cli.core.constants import ( 

32 OPT_FORMAT, 

33 OPT_LOG_LEVEL, 

34 OPT_PRETTY, 

35 OPT_QUIET, 

36) 

37from bijux_cli.cli.core.help_text import ( 

38 HELP_FORMAT, 

39 HELP_LOG_LEVEL, 

40 HELP_NO_PRETTY, 

41 HELP_QUIET, 

42) 

43from bijux_cli.core.di import DIContainer 

44from bijux_cli.core.enums import ErrorType 

45from bijux_cli.core.exit_policy import ExitIntentError 

46from bijux_cli.core.precedence import current_execution_policy, resolve_exit_intent 

47from bijux_cli.services.config.contracts import ConfigProtocol 

48 

49 

50def reload_config( 

51 ctx: typer.Context, 

52 quiet: bool = typer.Option(False, *OPT_QUIET, help=HELP_QUIET), 

53 fmt: str = typer.Option("json", *OPT_FORMAT, help=HELP_FORMAT), 

54 pretty: bool = typer.Option(True, OPT_PRETTY, help=HELP_NO_PRETTY), 

55 log_level: str = typer.Option("info", *OPT_LOG_LEVEL, help=HELP_LOG_LEVEL), 

56) -> None: 

57 """Reloads the configuration from disk and emits a structured result. 

58 

59 This function forces a refresh of the application's configuration from its 

60 persistent storage file. It is useful when the configuration has been 

61 modified externally. A success or error payload is always emitted. 

62 

63 Args: 

64 ctx (typer.Context): The Typer context for the CLI. 

65 quiet (bool): If True, suppresses all output except for errors. 

66 fmt (str): The output format, "json" or "yaml". 

67 pretty (bool): If True, pretty-prints the output. log_level (str): Logging level for diagnostics. 

68 

69 Returns: 

70 None: 

71 

72 Raises: 

73 SystemExit: Always exits with a contract-compliant status code and 

74 payload, indicating success or detailing the error. 

75 """ 

76 command = "config reload" 

77 effective = current_execution_policy() 

78 fmt_lower = validate_common_flags( 

79 fmt, 

80 command, 

81 effective.quiet, 

82 include_runtime=effective.include_runtime, 

83 log_level=effective.log_level, 

84 ) 

85 quiet = effective.quiet 

86 include_runtime = effective.include_runtime 

87 pretty = effective.pretty 

88 

89 config_svc = DIContainer.current().resolve(ConfigProtocol) 

90 

91 try: 

92 config_svc.reload() 

93 except Exception as exc: 

94 intent = resolve_exit_intent( 

95 message=f"Failed to reload config: {exc}", 

96 code=2, 

97 failure="reload_failed", 

98 command=command, 

99 fmt=fmt_lower, 

100 quiet=quiet, 

101 include_runtime=include_runtime, 

102 error_type=ErrorType.USER_INPUT, 

103 log_level=effective.log_level, 

104 ) 

105 raise ExitIntentError(intent) from exc 

106 

107 def payload_builder(include_runtime: bool) -> dict[str, object]: 

108 """Builds the payload confirming a successful configuration reload. 

109 

110 Args: 

111 include_runtime (bool): If True, includes Python and platform info. 

112 

113 Returns: 

114 dict[str, object]: The structured payload. 

115 """ 

116 payload: dict[str, object] = {"status": "reloaded"} 

117 if include_runtime: 

118 payload.update( 

119 { 

120 "python": ascii_safe(platform.python_version(), "python_version"), 

121 "platform": ascii_safe(platform.platform(), "platform"), 

122 } 

123 ) 

124 return payload 

125 

126 new_run_command( 

127 command_name=command, 

128 payload_builder=payload_builder, 

129 quiet=quiet, 

130 fmt=fmt_lower, 

131 pretty=pretty, 

132 log_level=log_level, 

133 )