backlogops-cli 0.4__tar.gz → 0.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {backlogops_cli-0.4 → backlogops_cli-0.5}/PKG-INFO +7 -10
- {backlogops_cli-0.4 → backlogops_cli-0.5}/README_pypi.md +5 -8
- {backlogops_cli-0.4 → backlogops_cli-0.5}/backlogops_cli.egg-info/PKG-INFO +7 -10
- {backlogops_cli-0.4 → backlogops_cli-0.5}/backlogops_cli.egg-info/requires.txt +1 -1
- {backlogops_cli-0.4 → backlogops_cli-0.5}/setup.py +2 -2
- {backlogops_cli-0.4 → backlogops_cli-0.5}/src/backlogops_cli/_command_io.py +96 -1
- {backlogops_cli-0.4 → backlogops_cli-0.5}/src/backlogops_cli/add_releases_to_jira.py +23 -54
- {backlogops_cli-0.4 → backlogops_cli-0.5}/src/backlogops_cli/add_to_jira.py +21 -54
- {backlogops_cli-0.4 → backlogops_cli-0.5}/src/backlogops_cli/encrypt_token_file.py +1 -0
- {backlogops_cli-0.4 → backlogops_cli-0.5}/src/backlogops_cli/jira_fields.py +4 -12
- {backlogops_cli-0.4 → backlogops_cli-0.5}/src/backlogops_cli/order_by_deps.py +2 -3
- {backlogops_cli-0.4 → backlogops_cli-0.5}/src/backlogops_cli/order_by_keys.py +2 -3
- {backlogops_cli-0.4 → backlogops_cli-0.5}/src/backlogops_cli/order_by_release.py +2 -3
- {backlogops_cli-0.4 → backlogops_cli-0.5}/src/backlogops_cli/order_releases.py +2 -3
- {backlogops_cli-0.4 → backlogops_cli-0.5}/src/backlogops_cli/order_releases_in_jira.py +6 -16
- {backlogops_cli-0.4 → backlogops_cli-0.5}/src/backlogops_cli/rank_in_jira.py +6 -16
- {backlogops_cli-0.4 → backlogops_cli-0.5}/src/backlogops_cli/read_jira.py +2 -8
- {backlogops_cli-0.4 → backlogops_cli-0.5}/src/backlogops_cli/rename_releases_in_jira.py +6 -16
- {backlogops_cli-0.4 → backlogops_cli-0.5}/src/backlogops_cli/update_backlog_in_jira.py +6 -18
- {backlogops_cli-0.4 → backlogops_cli-0.5}/src/backlogops_cli/update_releases_in_jira.py +6 -17
- {backlogops_cli-0.4 → backlogops_cli-0.5}/LICENSE.txt +0 -0
- {backlogops_cli-0.4 → backlogops_cli-0.5}/backlogops_cli.egg-info/SOURCES.txt +0 -0
- {backlogops_cli-0.4 → backlogops_cli-0.5}/backlogops_cli.egg-info/dependency_links.txt +0 -0
- {backlogops_cli-0.4 → backlogops_cli-0.5}/backlogops_cli.egg-info/top_level.txt +0 -0
- {backlogops_cli-0.4 → backlogops_cli-0.5}/pyproject.toml +0 -0
- {backlogops_cli-0.4 → backlogops_cli-0.5}/setup.cfg +0 -0
- {backlogops_cli-0.4 → backlogops_cli-0.5}/src/backlogops_cli/__init__.py +0 -0
- {backlogops_cli-0.4 → backlogops_cli-0.5}/src/backlogops_cli/__main__.py +0 -0
- {backlogops_cli-0.4 → backlogops_cli-0.5}/src/backlogops_cli/_migrate_warn.py +0 -0
- {backlogops_cli-0.4 → backlogops_cli-0.5}/src/backlogops_cli/_wizard_io.py +0 -0
- {backlogops_cli-0.4 → backlogops_cli-0.5}/src/backlogops_cli/adjust_release_content.py +0 -0
- {backlogops_cli-0.4 → backlogops_cli-0.5}/src/backlogops_cli/bloc_version_reporter.py +0 -0
- {backlogops_cli-0.4 → backlogops_cli-0.5}/src/backlogops_cli/config_wizard.py +0 -0
- {backlogops_cli-0.4 → backlogops_cli-0.5}/src/backlogops_cli/convert.py +0 -0
- {backlogops_cli-0.4 → backlogops_cli-0.5}/src/backlogops_cli/demo_backlog.py +0 -0
- {backlogops_cli-0.4 → backlogops_cli-0.5}/src/backlogops_cli/estimate_ready_date.py +0 -0
- {backlogops_cli-0.4 → backlogops_cli-0.5}/src/backlogops_cli/extract_keys.py +0 -0
- {backlogops_cli-0.4 → backlogops_cli-0.5}/src/backlogops_cli/list.py +0 -0
- {backlogops_cli-0.4 → backlogops_cli-0.5}/src/backlogops_cli/migrate_cfg.py +0 -0
- {backlogops_cli-0.4 → backlogops_cli-0.5}/src/backlogops_cli/plan_release_dates.py +0 -0
- {backlogops_cli-0.4 → backlogops_cli-0.5}/src/backlogops_cli/preset_wizard.py +0 -0
- {backlogops_cli-0.4 → backlogops_cli-0.5}/src/backlogops_cli/py.typed +0 -0
- {backlogops_cli-0.4 → backlogops_cli-0.5}/src/backlogops_cli/version.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: backlogops-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5
|
|
4
4
|
Summary: Command line interface for backlog operations.
|
|
5
5
|
Author: Tom Björkholm
|
|
6
6
|
Author-email: Tom Björkholm <klausuler_linnet0q@icloud.com>
|
|
@@ -25,7 +25,7 @@ Requires-Python: >=3.12
|
|
|
25
25
|
Description-Content-Type: text/markdown
|
|
26
26
|
License-File: LICENSE.txt
|
|
27
27
|
Requires-Dist: argcomplete>=3.7.0
|
|
28
|
-
Requires-Dist: backlogops>=0.
|
|
28
|
+
Requires-Dist: backlogops>=0.5
|
|
29
29
|
Requires-Dist: versionreporter>=0.4
|
|
30
30
|
Dynamic: author
|
|
31
31
|
Dynamic: license-file
|
|
@@ -50,15 +50,11 @@ There are 3 related packages for backlog operations:
|
|
|
50
50
|
|
|
51
51
|
## Project status
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
place, so the main work from here is on the user experience rather than on new
|
|
55
|
-
core functionality. The three packages share a version number and are released
|
|
56
|
-
together.
|
|
53
|
+
The three packages share a version number and are released together.
|
|
57
54
|
|
|
58
55
|
The library is not meant to ever be "finished": using it for real planning keeps
|
|
59
56
|
surfacing new ideas. Some of those will be added to backlogops itself, and
|
|
60
|
-
others will fit better in separate packages built on top of backlogops.
|
|
61
|
-
adopters are very welcome, and their feedback shapes what comes next.
|
|
57
|
+
others will fit better in separate packages built on top of backlogops.
|
|
62
58
|
|
|
63
59
|
## Available functionality
|
|
64
60
|
|
|
@@ -322,9 +318,10 @@ backlogops_cli serves 2 purposes:
|
|
|
322
318
|
|
|
323
319
|
## Test summary
|
|
324
320
|
|
|
325
|
-
- Test result:
|
|
321
|
+
- Test result: 2450 passed, 9 deselected in 41s
|
|
326
322
|
- No flake8 warnings.
|
|
327
323
|
- No mypy errors found.
|
|
324
|
+
- No pylint warnings.
|
|
328
325
|
- No python layout warnings.
|
|
329
|
-
- Built version(s): 0.
|
|
326
|
+
- Built version(s): 0.5
|
|
330
327
|
- Build and test using Python 3.14.6
|
|
@@ -16,15 +16,11 @@ There are 3 related packages for backlog operations:
|
|
|
16
16
|
|
|
17
17
|
## Project status
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
place, so the main work from here is on the user experience rather than on new
|
|
21
|
-
core functionality. The three packages share a version number and are released
|
|
22
|
-
together.
|
|
19
|
+
The three packages share a version number and are released together.
|
|
23
20
|
|
|
24
21
|
The library is not meant to ever be "finished": using it for real planning keeps
|
|
25
22
|
surfacing new ideas. Some of those will be added to backlogops itself, and
|
|
26
|
-
others will fit better in separate packages built on top of backlogops.
|
|
27
|
-
adopters are very welcome, and their feedback shapes what comes next.
|
|
23
|
+
others will fit better in separate packages built on top of backlogops.
|
|
28
24
|
|
|
29
25
|
## Available functionality
|
|
30
26
|
|
|
@@ -288,9 +284,10 @@ backlogops_cli serves 2 purposes:
|
|
|
288
284
|
|
|
289
285
|
## Test summary
|
|
290
286
|
|
|
291
|
-
- Test result:
|
|
287
|
+
- Test result: 2450 passed, 9 deselected in 41s
|
|
292
288
|
- No flake8 warnings.
|
|
293
289
|
- No mypy errors found.
|
|
290
|
+
- No pylint warnings.
|
|
294
291
|
- No python layout warnings.
|
|
295
|
-
- Built version(s): 0.
|
|
292
|
+
- Built version(s): 0.5
|
|
296
293
|
- Build and test using Python 3.14.6
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: backlogops-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5
|
|
4
4
|
Summary: Command line interface for backlog operations.
|
|
5
5
|
Author: Tom Björkholm
|
|
6
6
|
Author-email: Tom Björkholm <klausuler_linnet0q@icloud.com>
|
|
@@ -25,7 +25,7 @@ Requires-Python: >=3.12
|
|
|
25
25
|
Description-Content-Type: text/markdown
|
|
26
26
|
License-File: LICENSE.txt
|
|
27
27
|
Requires-Dist: argcomplete>=3.7.0
|
|
28
|
-
Requires-Dist: backlogops>=0.
|
|
28
|
+
Requires-Dist: backlogops>=0.5
|
|
29
29
|
Requires-Dist: versionreporter>=0.4
|
|
30
30
|
Dynamic: author
|
|
31
31
|
Dynamic: license-file
|
|
@@ -50,15 +50,11 @@ There are 3 related packages for backlog operations:
|
|
|
50
50
|
|
|
51
51
|
## Project status
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
place, so the main work from here is on the user experience rather than on new
|
|
55
|
-
core functionality. The three packages share a version number and are released
|
|
56
|
-
together.
|
|
53
|
+
The three packages share a version number and are released together.
|
|
57
54
|
|
|
58
55
|
The library is not meant to ever be "finished": using it for real planning keeps
|
|
59
56
|
surfacing new ideas. Some of those will be added to backlogops itself, and
|
|
60
|
-
others will fit better in separate packages built on top of backlogops.
|
|
61
|
-
adopters are very welcome, and their feedback shapes what comes next.
|
|
57
|
+
others will fit better in separate packages built on top of backlogops.
|
|
62
58
|
|
|
63
59
|
## Available functionality
|
|
64
60
|
|
|
@@ -322,9 +318,10 @@ backlogops_cli serves 2 purposes:
|
|
|
322
318
|
|
|
323
319
|
## Test summary
|
|
324
320
|
|
|
325
|
-
- Test result:
|
|
321
|
+
- Test result: 2450 passed, 9 deselected in 41s
|
|
326
322
|
- No flake8 warnings.
|
|
327
323
|
- No mypy errors found.
|
|
324
|
+
- No pylint warnings.
|
|
328
325
|
- No python layout warnings.
|
|
329
|
-
- Built version(s): 0.
|
|
326
|
+
- Built version(s): 0.5
|
|
330
327
|
- Build and test using Python 3.14.6
|
|
@@ -5,7 +5,7 @@ from setuptools import setup
|
|
|
5
5
|
|
|
6
6
|
setup(
|
|
7
7
|
name='backlogops-cli',
|
|
8
|
-
version='0.
|
|
8
|
+
version='0.5',
|
|
9
9
|
description='Command line interface for backlog operations.',
|
|
10
10
|
author='Tom Björkholm',
|
|
11
11
|
author_email='klausuler_linnet0q@icloud.com',
|
|
@@ -15,7 +15,7 @@ setup(
|
|
|
15
15
|
package_data={'backlogops_cli': ['src/py.typed']},
|
|
16
16
|
install_requires=[
|
|
17
17
|
'argcomplete >= 3.7.0',
|
|
18
|
-
'backlogops >= 0.
|
|
18
|
+
'backlogops >= 0.5',
|
|
19
19
|
'versionreporter >= 0.4'
|
|
20
20
|
]
|
|
21
21
|
)
|
|
@@ -12,9 +12,10 @@ underscore in the module name keeps it out of the command listing.
|
|
|
12
12
|
|
|
13
13
|
import argparse
|
|
14
14
|
import sys
|
|
15
|
+
from getpass import getpass
|
|
15
16
|
from pathlib import Path
|
|
16
17
|
from collections.abc import Callable
|
|
17
|
-
from typing import Optional, TextIO
|
|
18
|
+
from typing import Optional, TextIO, TypeVar
|
|
18
19
|
import argcomplete
|
|
19
20
|
from backlogops_cli._migrate_warn import (
|
|
20
21
|
CliMigrateWarnHook, CliPresetMigrateWarnHook)
|
|
@@ -27,6 +28,9 @@ from backlogops import (
|
|
|
27
28
|
resolve_output_config, write_backlog_releases, write_content_changes,
|
|
28
29
|
write_date_changes)
|
|
29
30
|
|
|
31
|
+
ResultT = TypeVar('ResultT')
|
|
32
|
+
"""Result type of a Jira write, carried from the operation to the report."""
|
|
33
|
+
|
|
30
34
|
RANK_ANCHOR_CHOICES = {
|
|
31
35
|
'backlog-top': JiraRankAnchor.BACKLOG_TOP,
|
|
32
36
|
'backlog-bottom': JiraRankAnchor.BACKLOG_BOTTOM,
|
|
@@ -97,6 +101,11 @@ def parsed_args(parser: argparse.ArgumentParser,
|
|
|
97
101
|
return parser.parse_args(args)
|
|
98
102
|
|
|
99
103
|
|
|
104
|
+
def jira_passphrase() -> str:
|
|
105
|
+
"""Ask for the Jira API token pass phrase on the terminal."""
|
|
106
|
+
return getpass('Jira API token pass phrase: ')
|
|
107
|
+
|
|
108
|
+
|
|
100
109
|
def add_input_args(parser: argparse.ArgumentParser) -> None:
|
|
101
110
|
"""Add the input-file and input-config arguments."""
|
|
102
111
|
parser.add_argument('-i', '--input', dest='input', required=True,
|
|
@@ -120,6 +129,18 @@ def add_config_arg(parser: argparse.ArgumentParser) -> None:
|
|
|
120
129
|
'$HOME/.backlogops.cfg.')
|
|
121
130
|
|
|
122
131
|
|
|
132
|
+
def add_preset_arg(parser: argparse.ArgumentParser) -> None:
|
|
133
|
+
"""Add the required ``-p``/``--preset`` Jira preset argument."""
|
|
134
|
+
parser.add_argument('-p', '--preset', dest='preset', required=True,
|
|
135
|
+
help='Name of the Jira preset in the configuration.')
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def add_quiet_arg(parser: argparse.ArgumentParser) -> None:
|
|
139
|
+
"""Add the ``-q``/``--quiet`` flag suppressing the result lists."""
|
|
140
|
+
parser.add_argument('-q', '--quiet', dest='quiet', action='store_true',
|
|
141
|
+
help='Do not print the result lists to stdout.')
|
|
142
|
+
|
|
143
|
+
|
|
123
144
|
def _resolve_config(parsed: argparse.Namespace) -> BacklogOpsConfig:
|
|
124
145
|
"""Return the backlog-ops configuration from ``-c`` or by discovery.
|
|
125
146
|
|
|
@@ -265,6 +286,23 @@ def build_io_parser(description: str, *, with_input: bool = True,
|
|
|
265
286
|
return parser
|
|
266
287
|
|
|
267
288
|
|
|
289
|
+
def build_jira_parser(description: str, *,
|
|
290
|
+
with_input: bool = True) -> argparse.ArgumentParser:
|
|
291
|
+
"""Create a parser with the config, preset and optional input options.
|
|
292
|
+
|
|
293
|
+
The Jira commands all take a backlog-ops configuration and a required
|
|
294
|
+
``-p``/``--preset``. Most also read an input file, so ``with_input``
|
|
295
|
+
adds the input-file and input-config options by default; a command
|
|
296
|
+
that does not read a backlog file passes ``with_input=False``.
|
|
297
|
+
"""
|
|
298
|
+
parser = argparse.ArgumentParser(description=description)
|
|
299
|
+
if with_input:
|
|
300
|
+
add_input_args(parser)
|
|
301
|
+
add_config_arg(parser)
|
|
302
|
+
add_preset_arg(parser)
|
|
303
|
+
return parser
|
|
304
|
+
|
|
305
|
+
|
|
268
306
|
def _write_output(parsed: argparse.Namespace,
|
|
269
307
|
config: Optional[BacklogOpsConfig],
|
|
270
308
|
data: BacklogReleases) -> None:
|
|
@@ -317,6 +355,63 @@ def run_write(parsed: argparse.Namespace,
|
|
|
317
355
|
return 0
|
|
318
356
|
|
|
319
357
|
|
|
358
|
+
def run_write_command(
|
|
359
|
+
build_parser: Callable[[], argparse.ArgumentParser],
|
|
360
|
+
produce: Callable[[argparse.Namespace, Optional[BacklogOpsConfig]],
|
|
361
|
+
BacklogReleases],
|
|
362
|
+
args: Optional[list[str]]) -> int:
|
|
363
|
+
"""Parse the command line and write the produced backlog and releases.
|
|
364
|
+
|
|
365
|
+
Folds argument parsing and :func:`run_write` so an ordering command's
|
|
366
|
+
``main`` stays a single delegating call. ``produce`` receives the
|
|
367
|
+
parsed args and the resolved config (or None) and returns the data.
|
|
368
|
+
"""
|
|
369
|
+
parsed = parsed_args(build_parser(), args)
|
|
370
|
+
return run_write(parsed, lambda config: produce(parsed, config))
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
def write_result_file(config: BacklogOpsConfig, path: str,
|
|
374
|
+
data: BacklogReleases, force: bool) -> None:
|
|
375
|
+
"""Write one backlog-and-releases result file, honoring ``--force``."""
|
|
376
|
+
out_config = resolve_output_config(None, data_file=path,
|
|
377
|
+
presets=config.output_configs,
|
|
378
|
+
auto_ch_hook=CliPresetMigrateWarnHook())
|
|
379
|
+
write_backlog_releases(data, path, out_config, FormatRules(),
|
|
380
|
+
levels=config.get_levels(),
|
|
381
|
+
file_exists_callback=overwrite_callback(force))
|
|
382
|
+
print(f'Wrote {path}')
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
def run_added_to_jira(
|
|
386
|
+
parsed: argparse.Namespace,
|
|
387
|
+
add: Callable[
|
|
388
|
+
[argparse.Namespace, BacklogOpsConfig, BacklogReleases], ResultT],
|
|
389
|
+
report: Callable[[ResultT], str], exists_error: type[Exception],
|
|
390
|
+
fail_note: str) -> int:
|
|
391
|
+
"""Read the input, add it to Jira, and print the added lists.
|
|
392
|
+
|
|
393
|
+
``add`` receives the parsed args, the config and the input data, adds
|
|
394
|
+
to Jira, writes any ``--added``/``--existing`` files, and returns the
|
|
395
|
+
result. ``report`` formats that result for stdout, printed unless
|
|
396
|
+
``-q``/``--quiet`` was given. ``exists_error`` is the key-exists error
|
|
397
|
+
meaning nothing was added; other value or OS errors are reported with
|
|
398
|
+
``fail_note``.
|
|
399
|
+
"""
|
|
400
|
+
try:
|
|
401
|
+
config = required_config(parsed)
|
|
402
|
+
data = read_input(parsed, config)
|
|
403
|
+
result = add(parsed, config, data)
|
|
404
|
+
except exists_error:
|
|
405
|
+
print('Nothing added to Jira.', file=sys.stderr)
|
|
406
|
+
return 1
|
|
407
|
+
except (ValueError, TypeError, KeyError, OSError) as error:
|
|
408
|
+
print(f'{fail_note}: {error}', file=sys.stderr)
|
|
409
|
+
return 1
|
|
410
|
+
if not parsed.quiet:
|
|
411
|
+
print(report(result))
|
|
412
|
+
return 0
|
|
413
|
+
|
|
414
|
+
|
|
320
415
|
DEFAULT_BUFFER_DAYS = 5
|
|
321
416
|
"""Default slack in calendar days added when fitting dates."""
|
|
322
417
|
|
|
@@ -20,27 +20,21 @@ asked on the terminal only when it is needed.
|
|
|
20
20
|
|
|
21
21
|
import argparse
|
|
22
22
|
import sys
|
|
23
|
-
from getpass import getpass
|
|
24
23
|
from typing import Optional
|
|
25
24
|
from backlogops import (
|
|
26
|
-
AddedReleasesToJira, BacklogOpsConfig, BacklogReleases,
|
|
27
|
-
|
|
28
|
-
format_release_result
|
|
25
|
+
AddedReleasesToJira, BacklogOpsConfig, BacklogReleases, JiraConnections,
|
|
26
|
+
OnExistingKey, ReleaseExistsError, add_releases_to_jira,
|
|
27
|
+
format_release_result)
|
|
29
28
|
from backlogops_cli._command_io import (
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
from backlogops_cli._migrate_warn import CliPresetMigrateWarnHook
|
|
29
|
+
add_force_arg, add_quiet_arg, build_jira_parser, jira_passphrase,
|
|
30
|
+
parsed_args, run_added_to_jira, write_result_file)
|
|
33
31
|
|
|
34
32
|
DESCRIPTION = 'Add releases to Jira, creating a new version per release'
|
|
35
33
|
|
|
36
34
|
|
|
37
35
|
def build_parser() -> argparse.ArgumentParser:
|
|
38
36
|
"""Build the command line parser for the add-releases command."""
|
|
39
|
-
parser =
|
|
40
|
-
add_input_args(parser)
|
|
41
|
-
add_config_arg(parser)
|
|
42
|
-
parser.add_argument('-p', '--preset', dest='preset', required=True,
|
|
43
|
-
help='Name of the Jira preset in the configuration.')
|
|
37
|
+
parser = build_jira_parser(DESCRIPTION)
|
|
44
38
|
parser.add_argument('--skip-existing', dest='skip_existing',
|
|
45
39
|
action='store_true',
|
|
46
40
|
help='Skip releases whose name already exists in Jira '
|
|
@@ -52,26 +46,17 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
52
46
|
metavar='FILE',
|
|
53
47
|
help='Write the releases already in Jira, with the '
|
|
54
48
|
'input backlog, to this file. Omit to not write it.')
|
|
55
|
-
parser
|
|
56
|
-
|
|
57
|
-
'lists to stdout.')
|
|
58
|
-
parser.add_argument('-f', '--force', dest='force', action='store_true',
|
|
59
|
-
help='Overwrite existing output files without '
|
|
60
|
-
'asking.')
|
|
49
|
+
add_quiet_arg(parser)
|
|
50
|
+
add_force_arg(parser)
|
|
61
51
|
return parser
|
|
62
52
|
|
|
63
53
|
|
|
64
|
-
def _passphrase() -> str:
|
|
65
|
-
"""Ask for the Jira token pass phrase on the terminal."""
|
|
66
|
-
return getpass('Jira API token pass phrase: ')
|
|
67
|
-
|
|
68
|
-
|
|
69
54
|
def _add(parsed: argparse.Namespace, config: BacklogOpsConfig,
|
|
70
55
|
data: BacklogReleases) -> AddedReleasesToJira:
|
|
71
56
|
"""Add the input releases to Jira using the named preset."""
|
|
72
57
|
print(f"Adding releases to Jira using preset '{parsed.preset}'...",
|
|
73
58
|
file=sys.stderr)
|
|
74
|
-
connections = JiraConnections(config.get_jira_config(),
|
|
59
|
+
connections = JiraConnections(config.get_jira_config(), jira_passphrase)
|
|
75
60
|
mode = (OnExistingKey.SKIP if parsed.skip_existing
|
|
76
61
|
else OnExistingKey.RAISE)
|
|
77
62
|
result = add_releases_to_jira(connections, parsed.preset, data.releases,
|
|
@@ -82,18 +67,6 @@ def _add(parsed: argparse.Namespace, config: BacklogOpsConfig,
|
|
|
82
67
|
return result
|
|
83
68
|
|
|
84
69
|
|
|
85
|
-
def _write_file(config: BacklogOpsConfig, path: str, data: BacklogReleases,
|
|
86
|
-
force: bool) -> None:
|
|
87
|
-
"""Write one backlog-and-releases result to a file."""
|
|
88
|
-
out_config = resolve_output_config(None, data_file=path,
|
|
89
|
-
presets=config.output_configs,
|
|
90
|
-
auto_ch_hook=CliPresetMigrateWarnHook())
|
|
91
|
-
write_backlog_releases(data, path, out_config, FormatRules(),
|
|
92
|
-
levels=config.get_levels(),
|
|
93
|
-
file_exists_callback=overwrite_callback(force))
|
|
94
|
-
print(f'Wrote {path}')
|
|
95
|
-
|
|
96
|
-
|
|
97
70
|
def _write_result_files(parsed: argparse.Namespace, config: BacklogOpsConfig,
|
|
98
71
|
data: BacklogReleases,
|
|
99
72
|
result: AddedReleasesToJira) -> None:
|
|
@@ -101,29 +74,26 @@ def _write_result_files(parsed: argparse.Namespace, config: BacklogOpsConfig,
|
|
|
101
74
|
backlog = list(data.backlog)
|
|
102
75
|
if parsed.added_file is not None:
|
|
103
76
|
added = BacklogReleases(backlog=backlog, releases=result.stored)
|
|
104
|
-
|
|
77
|
+
write_result_file(config, parsed.added_file, added, parsed.force)
|
|
105
78
|
if parsed.existing_file is not None:
|
|
106
79
|
present = BacklogReleases(backlog=backlog,
|
|
107
80
|
releases=result.already_present)
|
|
108
|
-
|
|
81
|
+
write_result_file(config, parsed.existing_file, present, parsed.force)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _add_and_write(parsed: argparse.Namespace, config: BacklogOpsConfig,
|
|
85
|
+
data: BacklogReleases) -> AddedReleasesToJira:
|
|
86
|
+
"""Add the releases to Jira and write any requested result files."""
|
|
87
|
+
result = _add(parsed, config, data)
|
|
88
|
+
_write_result_files(parsed, config, data, result)
|
|
89
|
+
return result
|
|
109
90
|
|
|
110
91
|
|
|
111
92
|
def _run(parsed: argparse.Namespace) -> int:
|
|
112
93
|
"""Read the input, add the releases, write files and print the lists."""
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
result = _add(parsed, config, data)
|
|
117
|
-
_write_result_files(parsed, config, data, result)
|
|
118
|
-
except ReleaseExistsError:
|
|
119
|
-
print('Nothing added to Jira.', file=sys.stderr)
|
|
120
|
-
return 1
|
|
121
|
-
except (ValueError, TypeError, KeyError, OSError) as error:
|
|
122
|
-
print(f'Could not add releases to Jira: {error}', file=sys.stderr)
|
|
123
|
-
return 1
|
|
124
|
-
if not parsed.quiet:
|
|
125
|
-
print(format_release_result(result))
|
|
126
|
-
return 0
|
|
94
|
+
return run_added_to_jira(parsed, _add_and_write, format_release_result,
|
|
95
|
+
ReleaseExistsError,
|
|
96
|
+
'Could not add releases to Jira')
|
|
127
97
|
|
|
128
98
|
|
|
129
99
|
def main(args: Optional[list[str]] = None) -> int:
|
|
@@ -136,8 +106,7 @@ def main(args: Optional[list[str]] = None) -> int:
|
|
|
136
106
|
``0`` on success, ``1`` when the releases cannot be added or a name
|
|
137
107
|
already exists in Jira without ``--skip-existing``.
|
|
138
108
|
"""
|
|
139
|
-
|
|
140
|
-
return _run(parsed)
|
|
109
|
+
return _run(parsed_args(build_parser(), args))
|
|
141
110
|
|
|
142
111
|
|
|
143
112
|
if __name__ == '__main__': # pragma: no cover
|
|
@@ -22,27 +22,21 @@ only when it is needed.
|
|
|
22
22
|
|
|
23
23
|
import argparse
|
|
24
24
|
import sys
|
|
25
|
-
from getpass import getpass
|
|
26
25
|
from typing import Optional
|
|
27
26
|
from backlogops import (
|
|
28
27
|
AddedToJira, BacklogOpsConfig, BacklogReleases, ExistsInJiraError,
|
|
29
|
-
|
|
30
|
-
format_add_result, resolve_output_config, write_backlog_releases)
|
|
28
|
+
JiraConnections, OnExistingKey, add_backlog_to_jira, format_add_result)
|
|
31
29
|
from backlogops_cli._command_io import (
|
|
32
|
-
|
|
33
|
-
parsed_args, rank_anchor,
|
|
34
|
-
|
|
30
|
+
add_force_arg, add_quiet_arg, add_rank_arg, build_jira_parser,
|
|
31
|
+
jira_passphrase, parsed_args, rank_anchor, run_added_to_jira,
|
|
32
|
+
write_result_file)
|
|
35
33
|
|
|
36
34
|
DESCRIPTION = 'Add a backlog to Jira, creating a new issue per item'
|
|
37
35
|
|
|
38
36
|
|
|
39
37
|
def build_parser() -> argparse.ArgumentParser:
|
|
40
38
|
"""Build the command line parser for the add-to-Jira command."""
|
|
41
|
-
parser =
|
|
42
|
-
add_input_args(parser)
|
|
43
|
-
add_config_arg(parser)
|
|
44
|
-
parser.add_argument('-p', '--preset', dest='preset', required=True,
|
|
45
|
-
help='Name of the Jira preset in the configuration.')
|
|
39
|
+
parser = build_jira_parser(DESCRIPTION)
|
|
46
40
|
parser.add_argument('--skip-existing', dest='skip_existing',
|
|
47
41
|
action='store_true',
|
|
48
42
|
help='Skip items whose key already exists in Jira '
|
|
@@ -55,26 +49,17 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
55
49
|
metavar='FILE',
|
|
56
50
|
help='Write the items already in Jira to this file. '
|
|
57
51
|
'Omit to not write it.')
|
|
58
|
-
parser
|
|
59
|
-
|
|
60
|
-
'lists to stdout.')
|
|
61
|
-
parser.add_argument('-f', '--force', dest='force', action='store_true',
|
|
62
|
-
help='Overwrite existing output files without '
|
|
63
|
-
'asking.')
|
|
52
|
+
add_quiet_arg(parser)
|
|
53
|
+
add_force_arg(parser)
|
|
64
54
|
return parser
|
|
65
55
|
|
|
66
56
|
|
|
67
|
-
def _passphrase() -> str:
|
|
68
|
-
"""Ask for the Jira token pass phrase on the terminal."""
|
|
69
|
-
return getpass('Jira API token pass phrase: ')
|
|
70
|
-
|
|
71
|
-
|
|
72
57
|
def _add(parsed: argparse.Namespace, config: BacklogOpsConfig,
|
|
73
58
|
data: BacklogReleases) -> AddedToJira:
|
|
74
59
|
"""Add the input backlog to Jira using the named write preset."""
|
|
75
60
|
print(f"Adding backlog to Jira using preset '{parsed.preset}'...",
|
|
76
61
|
file=sys.stderr)
|
|
77
|
-
connections = JiraConnections(config.get_jira_config(),
|
|
62
|
+
connections = JiraConnections(config.get_jira_config(), jira_passphrase)
|
|
78
63
|
mode = (OnExistingKey.SKIP if parsed.skip_existing
|
|
79
64
|
else OnExistingKey.RAISE)
|
|
80
65
|
result = add_backlog_to_jira(connections, parsed.preset, data.backlog,
|
|
@@ -89,48 +74,31 @@ def _add(parsed: argparse.Namespace, config: BacklogOpsConfig,
|
|
|
89
74
|
return result
|
|
90
75
|
|
|
91
76
|
|
|
92
|
-
def _write_backlog_file(config: BacklogOpsConfig, path: str,
|
|
93
|
-
data: BacklogReleases, force: bool) -> None:
|
|
94
|
-
"""Write one returned backlog and the input releases to a file."""
|
|
95
|
-
out_config = resolve_output_config(None, data_file=path,
|
|
96
|
-
presets=config.output_configs,
|
|
97
|
-
auto_ch_hook=CliPresetMigrateWarnHook())
|
|
98
|
-
write_backlog_releases(data, path, out_config, FormatRules(),
|
|
99
|
-
levels=config.get_levels(),
|
|
100
|
-
file_exists_callback=overwrite_callback(force))
|
|
101
|
-
print(f'Wrote {path}')
|
|
102
|
-
|
|
103
|
-
|
|
104
77
|
def _write_result_files(parsed: argparse.Namespace, config: BacklogOpsConfig,
|
|
105
78
|
data: BacklogReleases, result: AddedToJira) -> None:
|
|
106
79
|
"""Write the added and already-present backlogs to any named files."""
|
|
107
80
|
releases = list(data.releases)
|
|
108
81
|
if parsed.added_file is not None:
|
|
109
82
|
added = BacklogReleases(backlog=result.stored, releases=releases)
|
|
110
|
-
|
|
83
|
+
write_result_file(config, parsed.added_file, added, parsed.force)
|
|
111
84
|
if parsed.existing_file is not None:
|
|
112
85
|
present = BacklogReleases(backlog=result.already_present,
|
|
113
86
|
releases=releases)
|
|
114
|
-
|
|
115
|
-
|
|
87
|
+
write_result_file(config, parsed.existing_file, present, parsed.force)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def _add_and_write(parsed: argparse.Namespace, config: BacklogOpsConfig,
|
|
91
|
+
data: BacklogReleases) -> AddedToJira:
|
|
92
|
+
"""Add the backlog to Jira and write any requested result files."""
|
|
93
|
+
result = _add(parsed, config, data)
|
|
94
|
+
_write_result_files(parsed, config, data, result)
|
|
95
|
+
return result
|
|
116
96
|
|
|
117
97
|
|
|
118
98
|
def _run(parsed: argparse.Namespace) -> int:
|
|
119
99
|
"""Read the input, add it to Jira, write files and print the lists."""
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
data = read_input(parsed, config)
|
|
123
|
-
result = _add(parsed, config, data)
|
|
124
|
-
_write_result_files(parsed, config, data, result)
|
|
125
|
-
except ExistsInJiraError:
|
|
126
|
-
print('Nothing added to Jira.', file=sys.stderr)
|
|
127
|
-
return 1
|
|
128
|
-
except (ValueError, TypeError, KeyError, OSError) as error:
|
|
129
|
-
print(f'Could not add to Jira: {error}', file=sys.stderr)
|
|
130
|
-
return 1
|
|
131
|
-
if not parsed.quiet:
|
|
132
|
-
print(format_add_result(result))
|
|
133
|
-
return 0
|
|
100
|
+
return run_added_to_jira(parsed, _add_and_write, format_add_result,
|
|
101
|
+
ExistsInJiraError, 'Could not add to Jira')
|
|
134
102
|
|
|
135
103
|
|
|
136
104
|
def main(args: Optional[list[str]] = None) -> int:
|
|
@@ -143,8 +111,7 @@ def main(args: Optional[list[str]] = None) -> int:
|
|
|
143
111
|
``0`` on success, ``1`` when the backlog cannot be added or a key
|
|
144
112
|
already exists in Jira without ``--skip-existing``.
|
|
145
113
|
"""
|
|
146
|
-
|
|
147
|
-
return _run(parsed)
|
|
114
|
+
return _run(parsed_args(build_parser(), args))
|
|
148
115
|
|
|
149
116
|
|
|
150
117
|
if __name__ == '__main__': # pragma: no cover
|
|
@@ -58,6 +58,7 @@ EXCEPTIONS = (FileNotFoundError, ValueError, FileExistsError,
|
|
|
58
58
|
NotADirectoryError, OSError)
|
|
59
59
|
|
|
60
60
|
|
|
61
|
+
# pylint: disable-next=too-many-return-statements
|
|
61
62
|
def _run(parsed: argparse.Namespace) -> int:
|
|
62
63
|
"""Run the encrypt-token-file command with the given parsed arguments.
|
|
63
64
|
|
|
@@ -18,34 +18,25 @@ only when it is needed.
|
|
|
18
18
|
|
|
19
19
|
import argparse
|
|
20
20
|
import sys
|
|
21
|
-
from getpass import getpass
|
|
22
21
|
from typing import Optional
|
|
23
22
|
from jira import JIRAError
|
|
24
23
|
from backlogops import (
|
|
25
24
|
JiraConnections, jira_custom_fields, jira_editable_fields)
|
|
26
25
|
from backlogops_cli._command_io import (
|
|
27
|
-
|
|
26
|
+
build_jira_parser, jira_passphrase, parsed_args, required_config)
|
|
28
27
|
|
|
29
28
|
DESCRIPTION = "Print Jira custom fields and an issue's editable fields"
|
|
30
29
|
|
|
31
30
|
|
|
32
31
|
def build_parser() -> argparse.ArgumentParser:
|
|
33
32
|
"""Build the command line parser for the field diagnostic command."""
|
|
34
|
-
parser =
|
|
35
|
-
add_config_arg(parser)
|
|
36
|
-
parser.add_argument('-p', '--preset', dest='preset', required=True,
|
|
37
|
-
help='Name of the Jira preset in the configuration.')
|
|
33
|
+
parser = build_jira_parser(DESCRIPTION, with_input=False)
|
|
38
34
|
parser.add_argument('--issue', dest='issue', metavar='KEY',
|
|
39
35
|
help="Also print the fields this issue's edit "
|
|
40
36
|
'screen offers (for example SCRUM-15).')
|
|
41
37
|
return parser
|
|
42
38
|
|
|
43
39
|
|
|
44
|
-
def _passphrase() -> str:
|
|
45
|
-
"""Ask for the Jira token pass phrase on the terminal."""
|
|
46
|
-
return getpass('Jira API token pass phrase: ')
|
|
47
|
-
|
|
48
|
-
|
|
49
40
|
def _print_pairs(heading: str, pairs: list[tuple[str, str]]) -> None:
|
|
50
41
|
"""Print a heading and each field id and display name pair."""
|
|
51
42
|
print(heading)
|
|
@@ -59,7 +50,8 @@ def _run(parsed: argparse.Namespace) -> int:
|
|
|
59
50
|
"""Print the custom field map and, optionally, editable fields."""
|
|
60
51
|
try:
|
|
61
52
|
config = required_config(parsed)
|
|
62
|
-
connections = JiraConnections(config.get_jira_config(),
|
|
53
|
+
connections = JiraConnections(config.get_jira_config(),
|
|
54
|
+
jira_passphrase)
|
|
63
55
|
customs = jira_custom_fields(connections, parsed.preset)
|
|
64
56
|
editable = (jira_editable_fields(connections, parsed.preset,
|
|
65
57
|
parsed.issue)
|
|
@@ -19,7 +19,7 @@ import sys
|
|
|
19
19
|
from typing import Optional
|
|
20
20
|
from backlogops import BacklogOpsConfig, BacklogReleases, DependencyMode
|
|
21
21
|
from backlogops_cli._command_io import (
|
|
22
|
-
build_io_parser,
|
|
22
|
+
build_io_parser, read_input, run_write_command)
|
|
23
23
|
|
|
24
24
|
DESCRIPTION = 'Reorder a backlog so that dependencies are fulfilled'
|
|
25
25
|
|
|
@@ -61,8 +61,7 @@ def main(args: Optional[list[str]] = None) -> int:
|
|
|
61
61
|
``0`` on success, ``1`` when the data cannot be read, reordered
|
|
62
62
|
or written.
|
|
63
63
|
"""
|
|
64
|
-
|
|
65
|
-
return run_write(parsed, lambda config: _ordered(parsed, config))
|
|
64
|
+
return run_write_command(build_parser, _ordered, args)
|
|
66
65
|
|
|
67
66
|
|
|
68
67
|
if __name__ == '__main__': # pragma: no cover
|
|
@@ -19,7 +19,7 @@ import sys
|
|
|
19
19
|
from typing import Optional
|
|
20
20
|
from backlogops import BacklogOpsConfig, BacklogReleases, read_key_list
|
|
21
21
|
from backlogops_cli._command_io import (
|
|
22
|
-
build_io_parser,
|
|
22
|
+
build_io_parser, read_input, run_write_command)
|
|
23
23
|
|
|
24
24
|
DESCRIPTION = 'Reorder a backlog so that key-list items come first'
|
|
25
25
|
|
|
@@ -50,8 +50,7 @@ def main(args: Optional[list[str]] = None) -> int:
|
|
|
50
50
|
``0`` on success, ``1`` when the data cannot be read, reordered
|
|
51
51
|
or written.
|
|
52
52
|
"""
|
|
53
|
-
|
|
54
|
-
return run_write(parsed, lambda config: _reordered(parsed, config))
|
|
53
|
+
return run_write_command(build_parser, _reordered, args)
|
|
55
54
|
|
|
56
55
|
|
|
57
56
|
if __name__ == '__main__': # pragma: no cover
|
|
@@ -24,7 +24,7 @@ import sys
|
|
|
24
24
|
from typing import Optional
|
|
25
25
|
from backlogops import BacklogOpsConfig, BacklogReleases
|
|
26
26
|
from backlogops_cli._command_io import (
|
|
27
|
-
build_io_parser,
|
|
27
|
+
build_io_parser, read_input, run_write_command)
|
|
28
28
|
|
|
29
29
|
DESCRIPTION = 'Order the backlog to follow the release order'
|
|
30
30
|
|
|
@@ -63,8 +63,7 @@ def main(args: Optional[list[str]] = None) -> int:
|
|
|
63
63
|
``0`` on success, ``1`` when the data cannot be read, ordered or
|
|
64
64
|
written.
|
|
65
65
|
"""
|
|
66
|
-
|
|
67
|
-
return run_write(parsed, lambda config: _ordered(parsed, config))
|
|
66
|
+
return run_write_command(build_parser, _ordered, args)
|
|
68
67
|
|
|
69
68
|
|
|
70
69
|
if __name__ == '__main__': # pragma: no cover
|
|
@@ -20,7 +20,7 @@ import sys
|
|
|
20
20
|
from typing import Optional
|
|
21
21
|
from backlogops import BacklogOpsConfig, BacklogReleases
|
|
22
22
|
from backlogops_cli._command_io import (
|
|
23
|
-
build_io_parser,
|
|
23
|
+
build_io_parser, read_input, run_write_command)
|
|
24
24
|
|
|
25
25
|
DESCRIPTION = 'Order the releases by their planned or estimated date'
|
|
26
26
|
|
|
@@ -53,8 +53,7 @@ def main(args: Optional[list[str]] = None) -> int:
|
|
|
53
53
|
``0`` on success, ``1`` when the data cannot be read, ordered or
|
|
54
54
|
written.
|
|
55
55
|
"""
|
|
56
|
-
|
|
57
|
-
return run_write(parsed, lambda config: _ordered(parsed, config))
|
|
56
|
+
return run_write_command(build_parser, _ordered, args)
|
|
58
57
|
|
|
59
58
|
|
|
60
59
|
if __name__ == '__main__': # pragma: no cover
|
|
@@ -23,14 +23,14 @@ unlocked by a pass phrase asked on the terminal only when it is needed.
|
|
|
23
23
|
|
|
24
24
|
import argparse
|
|
25
25
|
import sys
|
|
26
|
-
from getpass import getpass
|
|
27
26
|
from typing import Optional
|
|
28
27
|
from backlogops import (
|
|
29
28
|
BacklogOpsConfig, JiraConnections, OrderedReleasesInJira,
|
|
30
29
|
format_order_result, order_jira_rel_by_date, order_releases_in_jira,
|
|
31
30
|
read_name_list)
|
|
32
31
|
from backlogops_cli._command_io import (
|
|
33
|
-
|
|
32
|
+
add_quiet_arg, build_jira_parser, jira_passphrase, parsed_args,
|
|
33
|
+
read_input, required_config)
|
|
34
34
|
|
|
35
35
|
DESCRIPTION = 'Order releases in Jira by date, a name list or the input order'
|
|
36
36
|
|
|
@@ -43,10 +43,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
43
43
|
with ``-i``/``--input`` is itself the third source; ``-I`` only names its
|
|
44
44
|
format.
|
|
45
45
|
"""
|
|
46
|
-
parser =
|
|
47
|
-
add_config_arg(parser)
|
|
48
|
-
parser.add_argument('-p', '--preset', dest='preset', required=True,
|
|
49
|
-
help='Name of the Jira preset in the configuration.')
|
|
46
|
+
parser = build_jira_parser(DESCRIPTION, with_input=False)
|
|
50
47
|
source = parser.add_mutually_exclusive_group(required=True)
|
|
51
48
|
source.add_argument('--by-date', dest='by_date', action='store_true',
|
|
52
49
|
help='Order the versions by their release date, '
|
|
@@ -61,16 +58,10 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
61
58
|
parser.add_argument('-I', '--input-config', dest='input_config',
|
|
62
59
|
help='Format of the -i/--input file: a config file '
|
|
63
60
|
'or a preset name.')
|
|
64
|
-
parser
|
|
65
|
-
help='Do not print the result lists to stdout.')
|
|
61
|
+
add_quiet_arg(parser)
|
|
66
62
|
return parser
|
|
67
63
|
|
|
68
64
|
|
|
69
|
-
def _passphrase() -> str:
|
|
70
|
-
"""Ask for the Jira token pass phrase on the terminal."""
|
|
71
|
-
return getpass('Jira API token pass phrase: ')
|
|
72
|
-
|
|
73
|
-
|
|
74
65
|
def _names(parsed: argparse.Namespace, config: BacklogOpsConfig) -> list[str]:
|
|
75
66
|
"""Return the wanted order of names from the chosen name source.
|
|
76
67
|
|
|
@@ -87,7 +78,7 @@ def _order(parsed: argparse.Namespace,
|
|
|
87
78
|
"""Order the releases in Jira using the chosen order source."""
|
|
88
79
|
print(f"Ordering releases in Jira using preset '{parsed.preset}'...",
|
|
89
80
|
file=sys.stderr)
|
|
90
|
-
connections = JiraConnections(config.get_jira_config(),
|
|
81
|
+
connections = JiraConnections(config.get_jira_config(), jira_passphrase)
|
|
91
82
|
if parsed.by_date:
|
|
92
83
|
result = order_jira_rel_by_date(connections, parsed.preset)
|
|
93
84
|
else:
|
|
@@ -120,8 +111,7 @@ def main(args: Optional[list[str]] = None) -> int:
|
|
|
120
111
|
Returns:
|
|
121
112
|
``0`` on success, ``1`` when the order cannot be resolved or applied.
|
|
122
113
|
"""
|
|
123
|
-
|
|
124
|
-
return _run(parsed)
|
|
114
|
+
return _run(parsed_args(build_parser(), args))
|
|
125
115
|
|
|
126
116
|
|
|
127
117
|
if __name__ == '__main__': # pragma: no cover
|
|
@@ -24,24 +24,21 @@ terminal only when it is needed.
|
|
|
24
24
|
|
|
25
25
|
import argparse
|
|
26
26
|
import sys
|
|
27
|
-
from getpass import getpass
|
|
28
27
|
from typing import Optional
|
|
29
28
|
from jira import JIRAError
|
|
30
29
|
from backlogops import (
|
|
31
30
|
BacklogOpsConfig, JiraConnections, RankedInJira, format_rank_result,
|
|
32
31
|
jira_rank_move_keys, read_key_list)
|
|
33
32
|
from backlogops_cli._command_io import (
|
|
34
|
-
RANK_ANCHOR_CHOICES,
|
|
33
|
+
RANK_ANCHOR_CHOICES, add_quiet_arg, build_jira_parser, jira_passphrase,
|
|
34
|
+
parsed_args, required_config)
|
|
35
35
|
|
|
36
36
|
DESCRIPTION = 'Move key-list items to a chosen anchor in the Jira rank order'
|
|
37
37
|
|
|
38
38
|
|
|
39
39
|
def build_parser() -> argparse.ArgumentParser:
|
|
40
40
|
"""Build the command line parser for the rank-in-Jira command."""
|
|
41
|
-
parser =
|
|
42
|
-
add_config_arg(parser)
|
|
43
|
-
parser.add_argument('-p', '--preset', dest='preset', required=True,
|
|
44
|
-
help='Name of the Jira preset in the configuration.')
|
|
41
|
+
parser = build_jira_parser(DESCRIPTION, with_input=False)
|
|
45
42
|
parser.add_argument('-k', '--key-list', dest='key_list', required=True,
|
|
46
43
|
help='Key list file naming the issues to move.')
|
|
47
44
|
parser.add_argument('--anchor', dest='anchor',
|
|
@@ -59,22 +56,16 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
59
56
|
parser.add_argument('--filter', dest='filter', metavar='JQL', default=None,
|
|
60
57
|
help='JQL filter reading the backlog; it may only '
|
|
61
58
|
'order by rank. Omit to use the preset filter.')
|
|
62
|
-
parser
|
|
63
|
-
help='Do not print the result lists to stdout.')
|
|
59
|
+
add_quiet_arg(parser)
|
|
64
60
|
return parser
|
|
65
61
|
|
|
66
62
|
|
|
67
|
-
def _passphrase() -> str:
|
|
68
|
-
"""Ask for the Jira token pass phrase on the terminal."""
|
|
69
|
-
return getpass('Jira API token pass phrase: ')
|
|
70
|
-
|
|
71
|
-
|
|
72
63
|
def _rank(parsed: argparse.Namespace,
|
|
73
64
|
config: BacklogOpsConfig) -> RankedInJira:
|
|
74
65
|
"""Move the key-list items in the Jira rank order using the preset."""
|
|
75
66
|
print(f"Ranking items in Jira using preset '{parsed.preset}'...",
|
|
76
67
|
file=sys.stderr)
|
|
77
|
-
connections = JiraConnections(config.get_jira_config(),
|
|
68
|
+
connections = JiraConnections(config.get_jira_config(), jira_passphrase)
|
|
78
69
|
keys = read_key_list(parsed.key_list)
|
|
79
70
|
result = jira_rank_move_keys(connections, parsed.preset, keys,
|
|
80
71
|
filter_override=parsed.filter,
|
|
@@ -112,8 +103,7 @@ def main(args: Optional[list[str]] = None) -> int:
|
|
|
112
103
|
Returns:
|
|
113
104
|
``0`` on success, ``1`` when the items cannot be ranked.
|
|
114
105
|
"""
|
|
115
|
-
|
|
116
|
-
return _run(parsed)
|
|
106
|
+
return _run(parsed_args(build_parser(), args))
|
|
117
107
|
|
|
118
108
|
|
|
119
109
|
if __name__ == '__main__': # pragma: no cover
|
|
@@ -18,12 +18,11 @@ phrase asked on the terminal only when it is needed.
|
|
|
18
18
|
|
|
19
19
|
import argparse
|
|
20
20
|
import sys
|
|
21
|
-
from getpass import getpass
|
|
22
21
|
from typing import Optional
|
|
23
22
|
from backlogops import (
|
|
24
23
|
BacklogOpsConfig, BacklogReleases, read_jira_from_config)
|
|
25
24
|
from backlogops_cli._command_io import (
|
|
26
|
-
build_io_parser, parsed_args, run_write)
|
|
25
|
+
build_io_parser, jira_passphrase, parsed_args, run_write)
|
|
27
26
|
|
|
28
27
|
DESCRIPTION = 'Read a backlog and releases from Jira and store to a file'
|
|
29
28
|
|
|
@@ -40,11 +39,6 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
40
39
|
return parser
|
|
41
40
|
|
|
42
41
|
|
|
43
|
-
def _passphrase() -> str:
|
|
44
|
-
"""Ask for the Jira token pass phrase on the terminal."""
|
|
45
|
-
return getpass('Jira API token pass phrase: ')
|
|
46
|
-
|
|
47
|
-
|
|
48
42
|
def _warn_if_inconsistent(data: BacklogReleases) -> None:
|
|
49
43
|
"""Warn when the data read from Jira is not fully consistent.
|
|
50
44
|
|
|
@@ -67,7 +61,7 @@ def _read_jira(parsed: argparse.Namespace,
|
|
|
67
61
|
file=sys.stderr)
|
|
68
62
|
data = read_jira_from_config(config, parsed.preset,
|
|
69
63
|
filter_override=parsed.filter,
|
|
70
|
-
passphrase=
|
|
64
|
+
passphrase=jira_passphrase)
|
|
71
65
|
print(f'Read {len(data.backlog)} backlog items and '
|
|
72
66
|
f'{len(data.releases)} releases from Jira.', file=sys.stderr)
|
|
73
67
|
_warn_if_inconsistent(data)
|
|
@@ -22,13 +22,13 @@ phrase asked on the terminal only when it is needed.
|
|
|
22
22
|
|
|
23
23
|
import argparse
|
|
24
24
|
import sys
|
|
25
|
-
from getpass import getpass
|
|
26
25
|
from typing import Optional, Sequence
|
|
27
26
|
from backlogops import (
|
|
28
27
|
BacklogOpsConfig, JiraConnections, ReleaseRename, RenamedReleasesInJira,
|
|
29
28
|
format_rename_result, read_renames, rename_releases_in_jira)
|
|
30
29
|
from backlogops_cli._command_io import (
|
|
31
|
-
|
|
30
|
+
add_quiet_arg, build_jira_parser, jira_passphrase, parsed_args,
|
|
31
|
+
required_config)
|
|
32
32
|
|
|
33
33
|
DESCRIPTION = 'Rename releases in Jira, changing Jira version names'
|
|
34
34
|
|
|
@@ -40,10 +40,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
40
40
|
group, so argparse checks that exactly one way is given. ``--rename``
|
|
41
41
|
takes both names at once, so its old and new name always travel together.
|
|
42
42
|
"""
|
|
43
|
-
parser =
|
|
44
|
-
add_config_arg(parser)
|
|
45
|
-
parser.add_argument('-p', '--preset', dest='preset', required=True,
|
|
46
|
-
help='Name of the Jira preset in the configuration.')
|
|
43
|
+
parser = build_jira_parser(DESCRIPTION, with_input=False)
|
|
47
44
|
source = parser.add_mutually_exclusive_group(required=True)
|
|
48
45
|
source.add_argument('--rename', dest='rename', nargs=2,
|
|
49
46
|
metavar=('OLD', 'NEW'),
|
|
@@ -53,16 +50,10 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
53
50
|
help='Two column file of old and new names for a '
|
|
54
51
|
'batch of renames, with columns separated by tab. '
|
|
55
52
|
'(Spaces are allowed in a release name.)')
|
|
56
|
-
parser
|
|
57
|
-
help='Do not print the result lists to stdout.')
|
|
53
|
+
add_quiet_arg(parser)
|
|
58
54
|
return parser
|
|
59
55
|
|
|
60
56
|
|
|
61
|
-
def _passphrase() -> str:
|
|
62
|
-
"""Ask for the Jira token pass phrase on the terminal."""
|
|
63
|
-
return getpass('Jira API token pass phrase: ')
|
|
64
|
-
|
|
65
|
-
|
|
66
57
|
def _renames(parsed: argparse.Namespace) -> Sequence[ReleaseRename]:
|
|
67
58
|
"""Return the renames from ``--rename`` or the ``--rename-file``.
|
|
68
59
|
|
|
@@ -81,7 +72,7 @@ def _rename(parsed: argparse.Namespace, config: BacklogOpsConfig,
|
|
|
81
72
|
"""Rename the releases in Jira using the named preset."""
|
|
82
73
|
print(f"Renaming releases in Jira using preset '{parsed.preset}'...",
|
|
83
74
|
file=sys.stderr)
|
|
84
|
-
connections = JiraConnections(config.get_jira_config(),
|
|
75
|
+
connections = JiraConnections(config.get_jira_config(), jira_passphrase)
|
|
85
76
|
result = rename_releases_in_jira(connections, parsed.preset, renames)
|
|
86
77
|
print(f'Renamed {len(result.renamed)} releases in Jira; '
|
|
87
78
|
f'{len(result.unchanged)} unchanged; {len(result.missing)} not in '
|
|
@@ -112,8 +103,7 @@ def main(args: Optional[list[str]] = None) -> int:
|
|
|
112
103
|
Returns:
|
|
113
104
|
``0`` on success, ``1`` when the renames cannot be read or applied.
|
|
114
105
|
"""
|
|
115
|
-
|
|
116
|
-
return _run(parsed)
|
|
106
|
+
return _run(parsed_args(build_parser(), args))
|
|
117
107
|
|
|
118
108
|
|
|
119
109
|
if __name__ == '__main__': # pragma: no cover
|
|
@@ -32,15 +32,14 @@ only when it is needed.
|
|
|
32
32
|
|
|
33
33
|
import argparse
|
|
34
34
|
import sys
|
|
35
|
-
from getpass import getpass
|
|
36
35
|
from typing import Optional
|
|
37
36
|
from backlogops import (
|
|
38
37
|
BacklogOpsConfig, ItemNotInJiraError, JiraConnections, LinkUpdate,
|
|
39
38
|
OnMissingKey, UpdatedBacklogInJira, format_backlog_updates,
|
|
40
39
|
update_backlog_in_jira, updatable_backlog_fields)
|
|
41
40
|
from backlogops_cli._command_io import (
|
|
42
|
-
|
|
43
|
-
read_input, required_config)
|
|
41
|
+
add_quiet_arg, add_rank_arg, build_jira_parser, jira_passphrase,
|
|
42
|
+
parsed_args, rank_anchor, read_input, required_config)
|
|
44
43
|
|
|
45
44
|
DESCRIPTION = 'Update a backlog in Jira, changing only the chosen columns'
|
|
46
45
|
|
|
@@ -53,11 +52,7 @@ _STORE_ALL = 'all'
|
|
|
53
52
|
|
|
54
53
|
def build_parser() -> argparse.ArgumentParser:
|
|
55
54
|
"""Build the command line parser for the update-backlog command."""
|
|
56
|
-
parser =
|
|
57
|
-
add_input_args(parser)
|
|
58
|
-
add_config_arg(parser)
|
|
59
|
-
parser.add_argument('-p', '--preset', dest='preset', required=True,
|
|
60
|
-
help='Name of the Jira preset in the configuration.')
|
|
55
|
+
parser = build_jira_parser(DESCRIPTION)
|
|
61
56
|
_add_column_flags(parser)
|
|
62
57
|
parser.add_argument('--on-missing', dest='on_missing',
|
|
63
58
|
choices=sorted(_MISSING_MODES), default='raise',
|
|
@@ -70,8 +65,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
70
65
|
'removing links it no longer has; add only adds '
|
|
71
66
|
'missing links.')
|
|
72
67
|
add_rank_arg(parser)
|
|
73
|
-
parser
|
|
74
|
-
help='Do not print the result lists to stdout.')
|
|
68
|
+
add_quiet_arg(parser)
|
|
75
69
|
return parser
|
|
76
70
|
|
|
77
71
|
|
|
@@ -87,11 +81,6 @@ def _add_column_flags(parser: argparse.ArgumentParser) -> None:
|
|
|
87
81
|
help='Update every mapped writable column but these.')
|
|
88
82
|
|
|
89
83
|
|
|
90
|
-
def _passphrase() -> str:
|
|
91
|
-
"""Ask for the Jira token pass phrase on the terminal."""
|
|
92
|
-
return getpass('Jira API token pass phrase: ')
|
|
93
|
-
|
|
94
|
-
|
|
95
84
|
def _resolve_fields(parsed: argparse.Namespace,
|
|
96
85
|
connections: JiraConnections) -> list[str]:
|
|
97
86
|
"""Return the internal field names to update from the -s/-e flags.
|
|
@@ -118,7 +107,7 @@ def _update(parsed: argparse.Namespace, config: BacklogOpsConfig,
|
|
|
118
107
|
"""Update the input backlog in Jira using the named preset."""
|
|
119
108
|
print(f"Updating backlog in Jira using preset '{parsed.preset}'...",
|
|
120
109
|
file=sys.stderr)
|
|
121
|
-
connections = JiraConnections(config.get_jira_config(),
|
|
110
|
+
connections = JiraConnections(config.get_jira_config(), jira_passphrase)
|
|
122
111
|
fields = _resolve_fields(parsed, connections)
|
|
123
112
|
mode = _MISSING_MODES[parsed.on_missing]
|
|
124
113
|
link_update = _LINK_MODES[parsed.links]
|
|
@@ -169,8 +158,7 @@ def main(args: Optional[list[str]] = None) -> int:
|
|
|
169
158
|
``0`` on success, ``1`` when the backlog cannot be updated or a key
|
|
170
159
|
is not present in Jira with the raise policy.
|
|
171
160
|
"""
|
|
172
|
-
|
|
173
|
-
return _run(parsed)
|
|
161
|
+
return _run(parsed_args(build_parser(), args))
|
|
174
162
|
|
|
175
163
|
|
|
176
164
|
if __name__ == '__main__': # pragma: no cover
|
|
@@ -23,14 +23,14 @@ only when it is needed.
|
|
|
23
23
|
|
|
24
24
|
import argparse
|
|
25
25
|
import sys
|
|
26
|
-
from getpass import getpass
|
|
27
26
|
from typing import Optional
|
|
28
27
|
from backlogops import (
|
|
29
28
|
BacklogOpsConfig, ItemNotInJiraError, JiraConnections, OnMissingKey,
|
|
30
29
|
Releases, UpdatedReleasesInJira, format_release_updates,
|
|
31
30
|
update_releases_in_jira)
|
|
32
31
|
from backlogops_cli._command_io import (
|
|
33
|
-
|
|
32
|
+
add_quiet_arg, build_jira_parser, jira_passphrase, parsed_args,
|
|
33
|
+
read_input, required_config)
|
|
34
34
|
|
|
35
35
|
DESCRIPTION = 'Update releases in Jira, setting dates to the planned dates'
|
|
36
36
|
|
|
@@ -40,11 +40,7 @@ _MISSING_MODES = {'raise': OnMissingKey.RAISE, 'ignore': OnMissingKey.IGNORE,
|
|
|
40
40
|
|
|
41
41
|
def build_parser() -> argparse.ArgumentParser:
|
|
42
42
|
"""Build the command line parser for the update-releases command."""
|
|
43
|
-
parser =
|
|
44
|
-
add_input_args(parser)
|
|
45
|
-
add_config_arg(parser)
|
|
46
|
-
parser.add_argument('-p', '--preset', dest='preset', required=True,
|
|
47
|
-
help='Name of the Jira preset in the configuration.')
|
|
43
|
+
parser = build_jira_parser(DESCRIPTION)
|
|
48
44
|
parser.add_argument('--on-missing', dest='on_missing',
|
|
49
45
|
choices=sorted(_MISSING_MODES), default='raise',
|
|
50
46
|
help='What to do with a release whose name is not in '
|
|
@@ -57,16 +53,10 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
57
53
|
action='store_true',
|
|
58
54
|
help='Update only the releases named with --release; '
|
|
59
55
|
'without it every input release is updated.')
|
|
60
|
-
parser
|
|
61
|
-
help='Do not print the result lists to stdout.')
|
|
56
|
+
add_quiet_arg(parser)
|
|
62
57
|
return parser
|
|
63
58
|
|
|
64
59
|
|
|
65
|
-
def _passphrase() -> str:
|
|
66
|
-
"""Ask for the Jira token pass phrase on the terminal."""
|
|
67
|
-
return getpass('Jira API token pass phrase: ')
|
|
68
|
-
|
|
69
|
-
|
|
70
60
|
def _select(parsed: argparse.Namespace, releases: Releases) -> Releases:
|
|
71
61
|
"""Return the releases to update, limited to --release when asked.
|
|
72
62
|
|
|
@@ -89,7 +79,7 @@ def _update(parsed: argparse.Namespace, config: BacklogOpsConfig,
|
|
|
89
79
|
"""Update the selected releases in Jira using the named preset."""
|
|
90
80
|
print(f"Updating releases in Jira using preset '{parsed.preset}'...",
|
|
91
81
|
file=sys.stderr)
|
|
92
|
-
connections = JiraConnections(config.get_jira_config(),
|
|
82
|
+
connections = JiraConnections(config.get_jira_config(), jira_passphrase)
|
|
93
83
|
mode = _MISSING_MODES[parsed.on_missing]
|
|
94
84
|
result = update_releases_in_jira(connections, parsed.preset, releases,
|
|
95
85
|
on_missing_key=mode)
|
|
@@ -127,8 +117,7 @@ def main(args: Optional[list[str]] = None) -> int:
|
|
|
127
117
|
``0`` on success, ``1`` when the releases cannot be updated or a
|
|
128
118
|
name is not present in Jira with the raise policy.
|
|
129
119
|
"""
|
|
130
|
-
|
|
131
|
-
return _run(parsed)
|
|
120
|
+
return _run(parsed_args(build_parser(), args))
|
|
132
121
|
|
|
133
122
|
|
|
134
123
|
if __name__ == '__main__': # pragma: no cover
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|