Coverage for laskea/cli.py: 61.61%

86 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2023-12-10 22:19:18 +00:00

1"""Commandline API gateway for laskea.""" 

2import sys 

3 

4import requests_cache 

5import typer 

6 

7import laskea 

8import laskea.config as cfg 

9import laskea.laskea as fill 

10from laskea import env 

11 

12app = typer.Typer( 

13 add_completion=False, 

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

15 no_args_is_help=True, 

16) 

17 

18Version = typer.Option( 

19 False, 

20 '-V', 

21 '--version', 

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

23 is_eager=True, 

24) 

25 

26Input = typer.Option( 

27 '', 

28 '-i', 

29 '--input', 

30 help='Path to input file', 

31 metavar='<sourcepath>', 

32) 

33 

34ConfigurationPath = typer.Option( 

35 '', 

36 '-c', 

37 '--config', 

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

39 metavar='<configpath>', 

40) 

41 

42Dryness = typer.Option( 

43 False, 

44 '-n', 

45 '--dry-run', 

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

47) 

48 

49Verbosity = typer.Option( 

50 False, 

51 '-v', 

52 '--verbose', 

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

54) 

55 

56Quietness = typer.Option( 

57 False, 

58 '-q', 

59 '--quiet', 

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

61) 

62 

63Strictness = typer.Option( 

64 False, 

65 '-s', 

66 '--strict', 

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

68) 

69 

70Checksums = typer.Option( 

71 False, 

72 '-C', 

73 '--checksums', 

74 help='Enable checksums (default is False)', 

75) 

76 

77CacheExpiry = typer.Option( 

78 180, 

79 '-x', 

80 '--cache-expiry-seconds', 

81 help='Request cache expiry in seconds', 

82) 

83 

84JqlQuery = typer.Option( 

85 '', 

86 '-j', 

87 '--jql-query', 

88 help=( 

89 'The query in JQL format.' 

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

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

92 ), 

93 metavar='<jql-query>', 

94) 

95 

96KeyMagic = typer.Option( 

97 False, 

98 '-k', 

99 '--key-magic', 

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

101) 

102 

103FieldSeparator = typer.Option( 

104 laskea.PIPE, 

105 '-d', 

106 '--delimiter', 

107 help=( 

108 'Delimiter / field separator' 

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

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

111 ), 

112 metavar='<field-separator>', 

113) 

114 

115Replacement = typer.Option( 

116 laskea.FS_SLUG, 

117 '-r', 

118 '--replacement', 

119 help=( 

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

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

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

123 ), 

124 metavar='<replacement-text>', 

125) 

126 

127 

128@app.callback(invoke_without_command=True) 

129def callback(version: bool = Version) -> None: 

130 """Calculate (Finnish: laskea) some parts.""" 

131 if version: 

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

133 raise typer.Exit() 

134 

135 

136@app.command('template') 

137def app_template() -> int: 

138 """ 

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

140 """ 

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

142 return sys.exit(0) 

143 

144 

145@app.command('report') 

146def report( 

147 shallow: bool = typer.Option( 

148 False, 

149 '-s', 

150 '--shallow', 

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

152 ), 

153) -> int: 

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

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

156 return sys.exit(0) 

157 

158 

159@app.command('update') 

160def update( # noqa 

161 source: list[str], 

162 inp: str = Input, 

163 conf: str = ConfigurationPath, 

164 verify: bool = Dryness, 

165 verbose: bool = Verbosity, 

166 quiet: bool = Quietness, 

167 strict: bool = Strictness, 

168 checksums: bool = Checksums, 

169 expires: int = CacheExpiry, 

170) -> int: 

171 """ 

172 Fill in some parts of the input document. 

173 

174 You can set some options per evironment variables: 

175 

176 \b 

177 * LASKEA_USER='remote-user' 

178 * LASKEA_TOKEN='remote-secret' 

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

180 * LASKEA_CACHE_EXPIRY_SECONDS=180 

181 * LASKEA_COL_FIELDS: '[ 

182 "Key", 

183 "Summary", 

184 "Custom Field Name", 

185 ["Custom Field Other", "Display Name"] 

186 ]' 

187 * LASKEA_COL_MAPS='{ 

188 "key": [ 

189 "key", 

190 "key" 

191 ], 

192 "summary": [ 

193 "summary", 

194 "fields.summary" 

195 ], 

196 "custom field name": [ 

197 "customfield_11501", 

198 "fields.customfield_11501" 

199 ], 

200 "custom field other": [ 

201 "customfield_13901", 

202 "fields.customfield_13901[].value" 

203 ] 

204 }' 

205 * LASKEA_COL_FILTERS='{ 

206 "key": {}, 

207 "summary": {}, 

208 "custom field name": { 

209 "order": ["keep", "drop", "replace"], 

210 "keep": [ 

211 ["startswith", "ABC-"], 

212 ["contains", "Z"], 

213 ["icontains", "m"], 

214 ["equals", "DEF-42"], 

215 ["endswith", "-123"] 

216 ], 

217 "drop": [ 

218 ["matches", "[A-Z]+-\\d+"] 

219 ], 

220 "replace": [ 

221 ["DEF-", "definition-"] 

222 ] 

223 }, 

224 "custom field other": {} 

225 }' 

226 * LASKEA_JOIN_STRING=' <br>' 

227 * LASKEA_LF_ONLY='AnythingTruthy' 

228 * LASKEA_CAPTION='empty or special DSL' 

229 * LASKEA_IS_CLOUD='WhenNotConnectingToJiraServerButJiraCloud' 

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

231 * LASKEA_DEBUG='AnythingTruthy' 

232 * LASKEA_VERBOSE='AnythingTruthy' 

233 * LASKEA_STRICT='AnythingTruthy' 

234 * LASKEA_CHECKSUMS='AnythingTruthy' 

235 

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

237 """ 

238 command = 'update' 

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

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

241 laskea.QUIET = True 

242 laskea.DEBUG = False 

243 laskea.VERBOSE = False 

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

245 laskea.VERBOSE = True 

246 

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

248 laskea.STRICT = True 

249 

250 if checksums: 250 ↛ 251line 250 didn't jump to line 251, because the condition on line 250 was never true

251 laskea.CHECKSUMS = True 

252 

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

254 laskea.DRY_RUN = True 

255 

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

257 laskea.CACHE_EXPIRY_SECONDS = expires 

258 options = { 

259 'quiet': quiet, 

260 'strict': strict, 

261 'verbose': verbose, 

262 'checksums': checksums, 

263 } 

264 cfg.process(conf, options) 

265 

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

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

268 

269 

270@app.command('csv') 

271def svl_cmd( # noqa 

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

273 jql_query: str = JqlQuery, 

274 conf: str = ConfigurationPath, 

275 key_magic: bool = KeyMagic, 

276 field_sep: str = FieldSeparator, 

277 replacement: str = Replacement, 

278 verify: bool = Dryness, 

279 verbose: bool = Verbosity, 

280 strict: bool = Strictness, 

281 checksums: bool = Checksums, 

282 expires: int = CacheExpiry, 

283) -> int: 

284 """ 

285 Export query result as separated values list. 

286 

287 You can set some options per evironment variables: 

288 

289 \b 

290 * LASKEA_USER='remote-user' 

291 * LASKEA_TOKEN='remote-secret' 

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

293 * LASKEA_CACHE_EXPIRY_SECONDS=180 

294 * LASKEA_COL_FIELDS: '[ 

295 "Key", 

296 "Summary", 

297 "Custom Field Name", 

298 ["Custom Field Other", "Display Name"] 

299 ]' 

300 * LASKEA_COL_MAPS='{ 

301 "key": [ 

302 "key", 

303 "key" 

304 ], 

305 "summary": [ 

306 "summary", 

307 "fields.summary" 

308 ], 

309 "custom field name": [ 

310 "customfield_11501", 

311 "fields.customfield_11501" 

312 ], 

313 "custom field other": [ 

314 "customfield_13901", 

315 "fields.customfield_13901[].value" 

316 ] 

317 }' 

318 * LASKEA_COL_FILTERS='{ 

319 "key": {}, 

320 "summary": {}, 

321 "custom field name": { 

322 "order": ["keep", "drop", "replace"], 

323 "keep": [ 

324 ["startswith", "ABC-"], 

325 ["contains", "Z"], 

326 ["icontains", "m"], 

327 ["equals", "DEF-42"], 

328 ["endswith", "-123"] 

329 ], 

330 "drop": [ 

331 ["matches", "[A-Z]+-\\d+"] 

332 ], 

333 "replace": [ 

334 ["DEF-", "definition-"] 

335 ] 

336 }, 

337 "custom field other": {} 

338 }' 

339 * LASKEA_JOIN_STRING=' <br>' 

340 * LASKEA_LF_ONLY='AnythingTruthy' 

341 * LASKEA_CAPTION='empty or special DSL' 

342 * LASKEA_IS_CLOUD='WhenNotConnectingToJiraServerButJiraCloud' 

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

344 * LASKEA_DEBUG='AnythingTruthy' 

345 * LASKEA_VERBOSE='AnythingTruthy' 

346 * LASKEA_STRICT='AnythingTruthy' 

347 * LASKEA_CHECKSUMS='AnythingTruthy' 

348 

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

350 """ 

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

352 jql = jql_query.strip() 

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

354 jql = query 

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

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

357 return sys.exit(2) 

358 quiet = True 

359 laskea.QUIET = True 

360 laskea.DEBUG = False 

361 laskea.VERBOSE = False 

362 if verbose: 

363 laskea.VERBOSE = True 

364 

365 if strict: 

366 laskea.STRICT = True 

367 

368 if checksums: 

369 laskea.CHECKSUMS = True 

370 

371 if transaction_mode == 'dry-run': 

372 laskea.DRY_RUN = True 

373 

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

375 laskea.CACHE_EXPIRY_SECONDS = expires 

376 options = { 

377 'quiet': quiet, 

378 'strict': strict, 

379 'verbose': verbose, 

380 'checksums': checksums, 

381 } 

382 if conf: 

383 cfg.process(conf, options) 

384 

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

386 

387 

388@app.command('version') 

389def app_version() -> None: 

390 """ 

391 Display the laskea version and exit. 

392 """ 

393 callback(True)