Coverage for laskea/cli.py: 60.22%

71 statements  

« prev     ^ index     » next       coverage.py v7.3.0, created at 2023-08-17 13:24:57 +00:00

1#! /usr/bin/env python3 

2# -*- coding: utf-8 -*- 

3"""Commandline API gateway for laskea.""" 

4import sys 

5from typing import List 

6 

7import requests_cache 

8import typer 

9 

10import laskea 

11import laskea.config as cfg 

12import laskea.laskea as fill 

13from laskea import env 

14 

15app = typer.Typer( 

16 add_completion=False, 

17 context_settings={'help_option_names': ['-h', '--help']}, 

18 no_args_is_help=True, 

19) 

20 

21 

22@app.callback(invoke_without_command=True) 

23def callback( 

24 version: bool = typer.Option( 

25 False, 

26 '-V', 

27 '--version', 

28 help='Display the laskea version and exit', 

29 is_eager=True, 

30 ) 

31) -> None: 

32 """ 

33 Calculate (Finnish: laskea) some parts. 

34 """ 

35 if version: 

36 typer.echo(f'{laskea.APP_NAME} version {laskea.__version__}') 

37 raise typer.Exit() 

38 

39 

40@app.command('template') 

41def app_template() -> int: 

42 """ 

43 Write a template of a well-formed JSON configuration to standard out and exit 

44 

45 The strategy for looking up configurations is to start at the current working 

46 directory trying to read a file with the name `.laskea.json` else try to read 

47 same named file in the user folder (home). 

48 

49 In case an explicit path is given to the config option of commands that offer 

50 it, only that path is considered. 

51 """ 

52 sys.stdout.write(cfg.generate_template()) 

53 return sys.exit(0) 

54 

55 

56@app.command('report') 

57def report( 

58 shallow: bool = typer.Option( 

59 False, 

60 '-s', 

61 '--shallow', 

62 help='Shallow reporting - no setuptools required (default is False)', 

63 ), 

64) -> int: 

65 """Output either text options for the user to report her env or the report of the environment for support.""" 

66 sys.stdout.write(env.report(shallow)) 

67 return sys.exit(0) 

68 

69 

70@app.command('update') 

71def update( # noqa 

72 source: List[str], 

73 inp: str = typer.Option( 

74 '', 

75 '-i', 

76 '--input', 

77 help='Path to input file', 

78 metavar='<sourcepath>', 

79 ), 

80 conf: str = typer.Option( 

81 '', 

82 '-c', 

83 '--config', 

84 help=f'Path to config file (default is $HOME/{laskea.DEFAULT_CONFIG_NAME})', 

85 metavar='<configpath>', 

86 ), 

87 verify: bool = typer.Option( 

88 False, 

89 '-n', 

90 '--dry-run', 

91 help='Dry run (default is False)', 

92 ), 

93 verbose: bool = typer.Option( 

94 False, 

95 '-v', 

96 '--verbose', 

97 help='Verbose output (default is False)', 

98 ), 

99 quiet: bool = typer.Option( 

100 False, 

101 '-q', 

102 '--quiet', 

103 help='Minimal output (default is False)', 

104 ), 

105 strict: bool = typer.Option( 

106 False, 

107 '-s', 

108 '--strict', 

109 help='Ouput noisy warnings on console and in the processed document (default is False)', 

110 ), 

111 expires: int = typer.Option( 

112 180, 

113 '-x', 

114 '--cache-expiry-seconds', 

115 help='Request cache expiry in seconds', 

116 ), 

117) -> int: 

118 """ 

119 Fill in some parts of the input document. 

120 

121 You can set some options per evironment variables: 

122 

123 \b 

124 * LASKEA_USER='remote-user' 

125 * LASKEA_TOKEN='remote-secret' 

126 * LASKEA_BASE_URL='https://remote-jira-instance.example.com/' 

127 * LASKEA_CACHE_EXPIRY_SECONDS=180 

128 * LASKEA_COL_FIELDS: '["Key", "Summary", "Custom Field Name"]' 

129 * LASKEA_COL_MAPS='{"key": ["key", "key"], "summary": ["summary", "fields.summary"], 

130 "custom field name": ["customfield_123", "fields.customfield_123"]}' 

131 * LASKEA_JOIN_STRING=' <br>' 

132 * LASKEA_LF_ONLY='AnythingTruthy' 

133 * LASKEA_IS_CLOUD='WhenNotConnectingToJiraServerButJiraCloud' 

134 * LASKEA_MARKERS='[[[fill ]]] [[[end]]]' 

135 * LASKEA_DEBUG='AnythingTruthy' 

136 * LASKEA_VERBOSE='AnythingTruthy' 

137 * LASKEA_STRICT='AnythingTruthy' 

138 

139 The quiet option (if given) disables any conflicting verbosity setting. 

140 """ 

141 command = 'update' 

142 transaction_mode = 'commit' if not verify else 'dry-run' 

143 if quiet: 143 ↛ 144line 143 didn't jump to line 144, because the condition on line 143 was never true

144 laskea.QUIET = True 

145 laskea.DEBUG = False 

146 laskea.VERBOSE = False 

147 elif verbose: 147 ↛ 148line 147 didn't jump to line 148, because the condition on line 147 was never true

148 laskea.VERBOSE = True 

149 

150 if strict: 150 ↛ 151line 150 didn't jump to line 151, because the condition on line 150 was never true

151 laskea.STRICT = True 

152 

153 if transaction_mode == 'dry-run': 153 ↛ 154line 153 didn't jump to line 154, because the condition on line 153 was never true

154 laskea.DRY_RUN = True 

155 

156 requests_cache.install_cache(cache_name='.laskea_cache', backend='sqlite', expire_after=expires) 

157 laskea.CACHE_EXPIRY_SECONDS = expires 

158 options = { 

159 'quiet': quiet, 

160 'strict': strict, 

161 'verbose': verbose, 

162 } 

163 cfg.process(conf, options) 

164 

165 paths = (inp,) if inp else tuple(source) 

166 return sys.exit(fill.process(command, transaction_mode, paths, options)) 

167 

168 

169@app.command('csv') 

170def svl_cmd( # noqa 

171 query: str = typer.Argument(''), 

172 jql_query: str = typer.Option( 

173 '', 

174 '-j', 

175 '--jql-query', 

176 help=( 

177 'The query in JQL format.' 

178 '\nFor example given a project YES and two issues 123 and 124:' 

179 "\n'project = YES and key in (YES-123, YES-124) order by created DESC'" 

180 ), 

181 metavar='<jql-query>', 

182 ), 

183 conf: str = typer.Option( 

184 '', 

185 '-c', 

186 '--config', 

187 help=f'Path to config file (default is $HOME/{laskea.DEFAULT_CONFIG_NAME})', 

188 metavar='<configpath>', 

189 ), 

190 key_magic: bool = typer.Option( 

191 False, 

192 '-k', 

193 '--key-magic', 

194 help='Apply magic to key by replacing with markdown like link (default is False)', 

195 ), 

196 field_sep: str = typer.Option( 

197 laskea.PIPE, 

198 '-d', 

199 '--delimiter', 

200 help=( 

201 'Delimiter / field separator' 

202 '\nOn output, header and data cell values will have any occurences' 

203 '\nof the field separator replaced with the replacement string' 

204 ), 

205 metavar='<field-separator>', 

206 ), 

207 replacement: str = typer.Option( 

208 laskea.FS_SLUG, 

209 '-r', 

210 '--replacement', 

211 help=( 

212 'Replacement string for occurences of FS in text\n' 

213 '\nOn output, header and data cell values will have any occurences' 

214 '\nof the field separator replaced with the replacement string' 

215 ), 

216 metavar='<replacement-text>', 

217 ), 

218 verify: bool = typer.Option( 

219 False, 

220 '-n', 

221 '--dry-run', 

222 help='Dry run (default is False)', 

223 ), 

224 verbose: bool = typer.Option( 

225 False, 

226 '-v', 

227 '--verbose', 

228 help='Verbose output (default is False)', 

229 ), 

230 strict: bool = typer.Option( 

231 False, 

232 '-s', 

233 '--strict', 

234 help='Ouput noisy warnings on console and in the processed document (default is False)', 

235 ), 

236 expires: int = typer.Option( 

237 180, 

238 '-x', 

239 '--cache-expiry-seconds', 

240 help='Request cache expiry in seconds', 

241 ), 

242) -> int: 

243 """ 

244 Export query result as separated values list. 

245 

246 You can set some options per evironment variables: 

247 

248 \b 

249 * LASKEA_USER='remote-user' 

250 * LASKEA_TOKEN='remote-secret' 

251 * LASKEA_BASE_URL='https://remote-jira-instance.example.com/' 

252 * LASKEA_CACHE_EXPIRY_SECONDS=180 

253 * LASKEA_COL_FIELDS: '["Key", "Summary", "Custom Field Name"]' 

254 * LASKEA_COL_MAPS='{"key": ["key", "key"], "summary": ["summary", "fields.summary"], 

255 "custom field name": ["customfield_123", "fields.customfield_123"]}' 

256 * LASKEA_JOIN_STRING=' <br>' 

257 * LASKEA_LF_ONLY='AnythingTruthy' 

258 * LASKEA_IS_CLOUD='WhenNotConnectingToJiraServerButJiraCloud' 

259 * LASKEA_MARKERS='[[[fill ]]] [[[end]]]' 

260 * LASKEA_DEBUG='AnythingTruthy' 

261 * LASKEA_VERBOSE='AnythingTruthy' 

262 * LASKEA_STRICT='AnythingTruthy' 

263 

264 The quiet option (if given) disables any conflicting verbosity setting. 

265 """ 

266 transaction_mode = 'commit' if not verify else 'dry-run' 

267 jql = jql_query.strip() 

268 if not jql and query: 268 ↛ 269line 268 didn't jump to line 269, because the condition on line 268 was never true

269 jql = query 

270 if not jql: 270 ↛ 273line 270 didn't jump to line 273, because the condition on line 270 was never false

271 print('JQL query required.', file=sys.stderr) 

272 return sys.exit(2) 

273 quiet = True 

274 laskea.QUIET = True 

275 laskea.DEBUG = False 

276 laskea.VERBOSE = False 

277 if verbose: 

278 laskea.VERBOSE = True 

279 

280 if strict: 

281 laskea.STRICT = True 

282 

283 if transaction_mode == 'dry-run': 

284 laskea.DRY_RUN = True 

285 

286 requests_cache.install_cache(cache_name='.laskea_cache', backend='sqlite', expire_after=expires) 

287 laskea.CACHE_EXPIRY_SECONDS = expires 

288 options = { 

289 'quiet': quiet, 

290 'strict': strict, 

291 'verbose': verbose, 

292 } 

293 if conf: 

294 cfg.process(conf, options) 

295 

296 return sys.exit(laskea.svl(jql, key_magic=key_magic, field_sep=field_sep, replacement=replacement)) 

297 

298 

299@app.command('version') 

300def app_version() -> None: 

301 """ 

302 Display the laskea version and exit. 

303 """ 

304 callback(True)