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
« 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
4import requests_cache
5import typer
7import laskea
8import laskea.config as cfg
9import laskea.laskea as fill
10from laskea import env
12app = typer.Typer(
13 add_completion=False,
14 context_settings={'help_option_names': ['-h', '--help']},
15 no_args_is_help=True,
16)
18Version = typer.Option(
19 False,
20 '-V',
21 '--version',
22 help='Display the laskea version and exit',
23 is_eager=True,
24)
26Input = typer.Option(
27 '',
28 '-i',
29 '--input',
30 help='Path to input file',
31 metavar='<sourcepath>',
32)
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)
42Dryness = typer.Option(
43 False,
44 '-n',
45 '--dry-run',
46 help='Dry run (default is False)',
47)
49Verbosity = typer.Option(
50 False,
51 '-v',
52 '--verbose',
53 help='Verbose output (default is False)',
54)
56Quietness = typer.Option(
57 False,
58 '-q',
59 '--quiet',
60 help='Minimal output (default is False)',
61)
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)
70Checksums = typer.Option(
71 False,
72 '-C',
73 '--checksums',
74 help='Enable checksums (default is False)',
75)
77CacheExpiry = typer.Option(
78 180,
79 '-x',
80 '--cache-expiry-seconds',
81 help='Request cache expiry in seconds',
82)
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)
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)
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)
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)
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()
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)
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)
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.
174 You can set some options per evironment variables:
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'
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
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
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
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
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)
266 paths = (inp,) if inp else tuple(source)
267 return sys.exit(fill.process(command, transaction_mode, paths, options))
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.
287 You can set some options per evironment variables:
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'
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
365 if strict:
366 laskea.STRICT = True
368 if checksums:
369 laskea.CHECKSUMS = True
371 if transaction_mode == 'dry-run':
372 laskea.DRY_RUN = True
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)
385 return sys.exit(laskea.svl(jql, key_magic=key_magic, field_sep=field_sep, replacement=replacement))
388@app.command('version')
389def app_version() -> None:
390 """
391 Display the laskea version and exit.
392 """
393 callback(True)