Coverage for /builds/svesch/cikit/src/cikit/env/cli.py: 82%

39 statements  

« prev     ^ index     » next       coverage.py v7.14.1, created at 2026-10-09 14:17 +0000

1#!/usr/bin/env python3 

2# SPDX-License-Identifier: GPL-3.0-or-later 

3"""Command-line interface for the cikit env package. 

4 

5This module provides a small CLI that resolves cikit environment variables, 

6prints them in a human-readable form, exports them for shell usage, prepares 

7output directories, or generates Markdown documentation. 

8 

9Author: 

10 Sven Schlender 

11Date: 

12 2026-02-18 

13""" 

14 

15import argparse 

16import sys 

17 

18from cikit.errors import CiToolsError 

19 

20from .api import CiEnvironment, prepare_dirs, pretty_print_env, shell_export_lines 

21from .env_vars import get_env_vars 

22 

23 

24def parse_args() -> argparse.Namespace: # pragma: no cover 

25 """Build and parse command line arguments. 

26 

27 The parser provides subcommands for printing resolved environment values, 

28 generating shell exports, preparing output directories, and documenting the 

29 configured environment variable definitions. 

30 

31 Returns: 

32 Parsed command line arguments. 

33 """ 

34 parser = argparse.ArgumentParser(prog="cikit-env", description="cikit env utility") 

35 sub = parser.add_subparsers(dest="command", required=True) 

36 

37 p_print = sub.add_parser("print", help="Print resolved environment values.") 

38 p_print.add_argument("--secrets", action="store_true", help="Include secret values.") 

39 

40 p_export = sub.add_parser("export", help="Print shell export lines.") 

41 p_export.add_argument("--secrets", action="store_true", help="Include secret values.") 

42 

43 doc_parser = sub.add_parser("doc", help="Generate Markdown documentation for env.") 

44 doc_parser.add_argument("--title", default="CI Environment Variables", 

45 help="Markdown section title.") 

46 

47 sub.add_parser("prepare-dirs", help="Create required output directories.") 

48 

49 return parser.parse_args() 

50 

51 

52def generate_markdown_doc(env: CiEnvironment, title: str) -> str: 

53 """Generate a Markdown documentation fragment for environment variables. 

54 

55 Args: 

56 env: Resolved CI environment containing variable definitions. 

57 title: Markdown section title. 

58 

59 Returns: 

60 Markdown-formatted documentation fragment. 

61 """ 

62 lines = [ 

63 f"## {title}", 

64 "", 

65 "| Name | Description | Default | Secret |", 

66 "| --- | --- | --- | --- |", 

67 ] 

68 

69 for var in sorted(env.variables.values(), key=lambda item: item.key): 

70 default = var.default 

71 

72 if callable(default): 

73 default_str = "<dynamic>" 

74 elif default is None: 

75 default_str = "" 

76 else: 

77 default_str = str(default) 

78 

79 secret_str = "Yes" if var.secret else "No" 

80 lines.append(f"| {var.key} | {var.doc} | {default_str} | {secret_str} |") 

81 

82 lines.append("") 

83 

84 return "\n".join(lines) 

85 

86 

87def main_unsafe(args: argparse.Namespace): 

88 """Run the selected env CLI command. 

89 

90 Args: 

91 args: Parsed command line arguments. 

92 

93 Raises: 

94 CiToolsError: If environment resolution fails or the command is unknown. 

95 """ 

96 env = CiEnvironment(get_env_vars()) 

97 

98 if args.command == "print": 98 ↛ 99line 98 didn't jump to line 99 because the condition on line 98 was never true

99 pretty_print_env(env, args.secrets) 

100 

101 elif args.command == "export": 

102 for line in shell_export_lines(env, args.secrets): 

103 print(line) 

104 

105 elif args.command == "prepare-dirs": 105 ↛ 106line 105 didn't jump to line 106 because the condition on line 105 was never true

106 prepare_dirs(env) 

107 

108 elif args.command == "doc": 108 ↛ 112line 108 didn't jump to line 112 because the condition on line 108 was always true

109 print(generate_markdown_doc(env, args.title)) 

110 

111 else: 

112 raise CiToolsError(f"Unknown command: {args.command!r}") 

113 

114 

115def main(): 

116 """Run the env CLI entry point.""" 

117 args = parse_args() 

118 

119 try: 

120 main_unsafe(args) 

121 except CiToolsError as exp: 

122 print(str(exp), file=sys.stderr) 

123 sys.exit(1) 

124 

125 

126if __name__ == "__main__": 126 ↛ exitline 126 didn't exit the module because the condition on line 126 was always true

127 main()