backlogops-cli 0.7__tar.gz → 0.9__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.
Files changed (45) hide show
  1. {backlogops_cli-0.7 → backlogops_cli-0.9}/PKG-INFO +11 -7
  2. {backlogops_cli-0.7 → backlogops_cli-0.9}/README_pypi.md +6 -3
  3. {backlogops_cli-0.7 → backlogops_cli-0.9}/backlogops_cli.egg-info/PKG-INFO +11 -7
  4. {backlogops_cli-0.7 → backlogops_cli-0.9}/backlogops_cli.egg-info/SOURCES.txt +1 -0
  5. backlogops_cli-0.9/backlogops_cli.egg-info/requires.txt +5 -0
  6. {backlogops_cli-0.7 → backlogops_cli-0.9}/setup.py +5 -4
  7. {backlogops_cli-0.7 → backlogops_cli-0.9}/src/backlogops_cli/_command_io.py +28 -1
  8. {backlogops_cli-0.7 → backlogops_cli-0.9}/src/backlogops_cli/_wizard_io.py +1 -2
  9. backlogops_cli-0.9/src/backlogops_cli/config_edit.py +115 -0
  10. {backlogops_cli-0.7 → backlogops_cli-0.9}/src/backlogops_cli/migrate_cfg.py +4 -17
  11. backlogops_cli-0.7/backlogops_cli.egg-info/requires.txt +0 -4
  12. {backlogops_cli-0.7 → backlogops_cli-0.9}/LICENSE.txt +0 -0
  13. {backlogops_cli-0.7 → backlogops_cli-0.9}/backlogops_cli.egg-info/dependency_links.txt +0 -0
  14. {backlogops_cli-0.7 → backlogops_cli-0.9}/backlogops_cli.egg-info/top_level.txt +0 -0
  15. {backlogops_cli-0.7 → backlogops_cli-0.9}/pyproject.toml +0 -0
  16. {backlogops_cli-0.7 → backlogops_cli-0.9}/setup.cfg +0 -0
  17. {backlogops_cli-0.7 → backlogops_cli-0.9}/src/backlogops_cli/__init__.py +0 -0
  18. {backlogops_cli-0.7 → backlogops_cli-0.9}/src/backlogops_cli/__main__.py +0 -0
  19. {backlogops_cli-0.7 → backlogops_cli-0.9}/src/backlogops_cli/_migrate_warn.py +0 -0
  20. {backlogops_cli-0.7 → backlogops_cli-0.9}/src/backlogops_cli/add_releases_to_jira.py +0 -0
  21. {backlogops_cli-0.7 → backlogops_cli-0.9}/src/backlogops_cli/add_to_jira.py +0 -0
  22. {backlogops_cli-0.7 → backlogops_cli-0.9}/src/backlogops_cli/adjust_release_content.py +0 -0
  23. {backlogops_cli-0.7 → backlogops_cli-0.9}/src/backlogops_cli/bloc_version_reporter.py +0 -0
  24. {backlogops_cli-0.7 → backlogops_cli-0.9}/src/backlogops_cli/config_wizard.py +0 -0
  25. {backlogops_cli-0.7 → backlogops_cli-0.9}/src/backlogops_cli/convert.py +0 -0
  26. {backlogops_cli-0.7 → backlogops_cli-0.9}/src/backlogops_cli/demo_backlog.py +0 -0
  27. {backlogops_cli-0.7 → backlogops_cli-0.9}/src/backlogops_cli/encrypt_token_file.py +0 -0
  28. {backlogops_cli-0.7 → backlogops_cli-0.9}/src/backlogops_cli/estimate_ready_date.py +0 -0
  29. {backlogops_cli-0.7 → backlogops_cli-0.9}/src/backlogops_cli/extract_keys.py +0 -0
  30. {backlogops_cli-0.7 → backlogops_cli-0.9}/src/backlogops_cli/jira_fields.py +0 -0
  31. {backlogops_cli-0.7 → backlogops_cli-0.9}/src/backlogops_cli/list.py +0 -0
  32. {backlogops_cli-0.7 → backlogops_cli-0.9}/src/backlogops_cli/order_by_deps.py +0 -0
  33. {backlogops_cli-0.7 → backlogops_cli-0.9}/src/backlogops_cli/order_by_keys.py +0 -0
  34. {backlogops_cli-0.7 → backlogops_cli-0.9}/src/backlogops_cli/order_by_release.py +0 -0
  35. {backlogops_cli-0.7 → backlogops_cli-0.9}/src/backlogops_cli/order_releases.py +0 -0
  36. {backlogops_cli-0.7 → backlogops_cli-0.9}/src/backlogops_cli/order_releases_in_jira.py +0 -0
  37. {backlogops_cli-0.7 → backlogops_cli-0.9}/src/backlogops_cli/plan_release_dates.py +0 -0
  38. {backlogops_cli-0.7 → backlogops_cli-0.9}/src/backlogops_cli/preset_wizard.py +0 -0
  39. {backlogops_cli-0.7 → backlogops_cli-0.9}/src/backlogops_cli/py.typed +0 -0
  40. {backlogops_cli-0.7 → backlogops_cli-0.9}/src/backlogops_cli/rank_in_jira.py +0 -0
  41. {backlogops_cli-0.7 → backlogops_cli-0.9}/src/backlogops_cli/read_jira.py +0 -0
  42. {backlogops_cli-0.7 → backlogops_cli-0.9}/src/backlogops_cli/rename_releases_in_jira.py +0 -0
  43. {backlogops_cli-0.7 → backlogops_cli-0.9}/src/backlogops_cli/update_backlog_in_jira.py +0 -0
  44. {backlogops_cli-0.7 → backlogops_cli-0.9}/src/backlogops_cli/update_releases_in_jira.py +0 -0
  45. {backlogops_cli-0.7 → backlogops_cli-0.9}/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.7
3
+ Version: 0.9
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>
@@ -23,9 +23,10 @@ Classifier: Typing :: Typed
23
23
  Requires-Python: >=3.12
24
24
  Description-Content-Type: text/markdown
25
25
  License-File: LICENSE.txt
26
- Requires-Dist: argcomplete>=3.7.1
27
- Requires-Dist: backlogops>=0.7
28
- Requires-Dist: wizard-ui-bridge[textual]>=1.2
26
+ Requires-Dist: argcomplete>=3.7.2
27
+ Requires-Dist: backlogops>=0.9
28
+ Requires-Dist: wizard-ui-bridge[textual]>=1.3
29
+ Requires-Dist: edit-cfg-json-textual==0.0.2
29
30
  Requires-Dist: versionreporter>=0.4
30
31
  Dynamic: author
31
32
  Dynamic: license-file
@@ -248,6 +249,9 @@ backlogops_cli serves 2 purposes:
248
249
  python3 -m backlogops_cli.adjust_release_content
249
250
  Adjust release content to fit the planned release dates
250
251
 
252
+ python3 -m backlogops_cli.config_edit
253
+ Edit a configuration file in a full-screen editor
254
+
251
255
  python3 -m backlogops_cli.config_wizard
252
256
  Create a backlog-ops configuration file via a wizard
253
257
 
@@ -318,10 +322,10 @@ backlogops_cli serves 2 purposes:
318
322
 
319
323
  ## Test summary
320
324
 
321
- - Test result: 2453 passed, 9 deselected in 38s
325
+ - Test result: 2232 passed, 1 deselected in 44s
322
326
  - No flake8 warnings.
323
327
  - No mypy errors found.
324
328
  - No pylint warnings.
325
329
  - No python layout warnings.
326
- - Built version(s): 0.7
327
- - Build and test using Python 3.14.6
330
+ - Built version(s): 0.9
331
+ - Build and test using Python 3.14.7
@@ -214,6 +214,9 @@ backlogops_cli serves 2 purposes:
214
214
  python3 -m backlogops_cli.adjust_release_content
215
215
  Adjust release content to fit the planned release dates
216
216
 
217
+ python3 -m backlogops_cli.config_edit
218
+ Edit a configuration file in a full-screen editor
219
+
217
220
  python3 -m backlogops_cli.config_wizard
218
221
  Create a backlog-ops configuration file via a wizard
219
222
 
@@ -284,10 +287,10 @@ backlogops_cli serves 2 purposes:
284
287
 
285
288
  ## Test summary
286
289
 
287
- - Test result: 2453 passed, 9 deselected in 38s
290
+ - Test result: 2232 passed, 1 deselected in 44s
288
291
  - No flake8 warnings.
289
292
  - No mypy errors found.
290
293
  - No pylint warnings.
291
294
  - No python layout warnings.
292
- - Built version(s): 0.7
293
- - Build and test using Python 3.14.6
295
+ - Built version(s): 0.9
296
+ - Build and test using Python 3.14.7
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: backlogops-cli
3
- Version: 0.7
3
+ Version: 0.9
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>
@@ -23,9 +23,10 @@ Classifier: Typing :: Typed
23
23
  Requires-Python: >=3.12
24
24
  Description-Content-Type: text/markdown
25
25
  License-File: LICENSE.txt
26
- Requires-Dist: argcomplete>=3.7.1
27
- Requires-Dist: backlogops>=0.7
28
- Requires-Dist: wizard-ui-bridge[textual]>=1.2
26
+ Requires-Dist: argcomplete>=3.7.2
27
+ Requires-Dist: backlogops>=0.9
28
+ Requires-Dist: wizard-ui-bridge[textual]>=1.3
29
+ Requires-Dist: edit-cfg-json-textual==0.0.2
29
30
  Requires-Dist: versionreporter>=0.4
30
31
  Dynamic: author
31
32
  Dynamic: license-file
@@ -248,6 +249,9 @@ backlogops_cli serves 2 purposes:
248
249
  python3 -m backlogops_cli.adjust_release_content
249
250
  Adjust release content to fit the planned release dates
250
251
 
252
+ python3 -m backlogops_cli.config_edit
253
+ Edit a configuration file in a full-screen editor
254
+
251
255
  python3 -m backlogops_cli.config_wizard
252
256
  Create a backlog-ops configuration file via a wizard
253
257
 
@@ -318,10 +322,10 @@ backlogops_cli serves 2 purposes:
318
322
 
319
323
  ## Test summary
320
324
 
321
- - Test result: 2453 passed, 9 deselected in 38s
325
+ - Test result: 2232 passed, 1 deselected in 44s
322
326
  - No flake8 warnings.
323
327
  - No mypy errors found.
324
328
  - No pylint warnings.
325
329
  - No python layout warnings.
326
- - Built version(s): 0.7
327
- - Build and test using Python 3.14.6
330
+ - Built version(s): 0.9
331
+ - Build and test using Python 3.14.7
@@ -16,6 +16,7 @@ src/backlogops_cli/add_releases_to_jira.py
16
16
  src/backlogops_cli/add_to_jira.py
17
17
  src/backlogops_cli/adjust_release_content.py
18
18
  src/backlogops_cli/bloc_version_reporter.py
19
+ src/backlogops_cli/config_edit.py
19
20
  src/backlogops_cli/config_wizard.py
20
21
  src/backlogops_cli/convert.py
21
22
  src/backlogops_cli/demo_backlog.py
@@ -0,0 +1,5 @@
1
+ argcomplete>=3.7.2
2
+ backlogops>=0.9
3
+ wizard-ui-bridge[textual]>=1.3
4
+ edit-cfg-json-textual==0.0.2
5
+ versionreporter>=0.4
@@ -5,7 +5,7 @@ from setuptools import setup
5
5
 
6
6
  setup(
7
7
  name='backlogops-cli',
8
- version='0.7',
8
+ version='0.9',
9
9
  description='Command line interface for backlog operations.',
10
10
  author='Tom Björkholm',
11
11
  author_email='klausuler_linnet0q@icloud.com',
@@ -14,9 +14,10 @@ setup(
14
14
  package_dir={'backlogops_cli': 'src/backlogops_cli'},
15
15
  package_data={'backlogops_cli': ['src/py.typed']},
16
16
  install_requires=[
17
- 'argcomplete >= 3.7.1',
18
- 'backlogops >= 0.7',
19
- 'wizard-ui-bridge[textual] >= 1.2',
17
+ 'argcomplete >= 3.7.2',
18
+ 'backlogops >= 0.9',
19
+ 'wizard-ui-bridge[textual] >= 1.3',
20
+ 'edit-cfg-json-textual == 0.0.2',
20
21
  'versionreporter >= 0.4'
21
22
  ]
22
23
  )
@@ -17,12 +17,14 @@ from pathlib import Path
17
17
  from collections.abc import Callable
18
18
  from typing import Optional, TextIO, TypeVar
19
19
  import argcomplete
20
+ from config_as_json import Config
20
21
  from backlogops_cli._migrate_warn import (
21
22
  CliMigrateWarnHook, CliPresetMigrateWarnHook)
22
23
  from backlogops_cli.bloc_version_reporter import BloCliVersionReporter
23
24
  from backlogops import (
24
25
  BacklogOpsConfig, BacklogReleases, FileExistsCb, FormatRules,
25
- JiraRankAnchor, Levels, ReleaseChanges, ReleaseDateChanges,
26
+ InputFormatConfig, JiraRankAnchor, Levels, OutputFormatConfig,
27
+ ReleaseChanges, ReleaseDateChanges,
26
28
  allow_overwrite, format_content_changes, format_date_changes,
27
29
  get_backlog_ops_config, read_backlog_releases, resolve_input_config,
28
30
  resolve_output_config, write_backlog_releases, write_content_changes,
@@ -38,6 +40,31 @@ RANK_ANCHOR_CHOICES = {
38
40
  'last-key': JiraRankAnchor.LAST_KEY}
39
41
  """Command-line anchor names mapped to :class:`JiraRankAnchor` members."""
40
42
 
43
+ KIND_CLASSES: dict[str, type[Config]] = {
44
+ 'config': BacklogOpsConfig, 'input': InputFormatConfig,
45
+ 'output': OutputFormatConfig}
46
+ """Map a ``--kind`` value to the configuration class it names.
47
+
48
+ Shared by every command that is told which kind of configuration file it is
49
+ given, so that the migrate and the edit command cannot come to mean
50
+ different things by one kind name.
51
+ """
52
+
53
+
54
+ def add_kind_arg(parser: argparse.ArgumentParser) -> None:
55
+ """Add the ``-k``/``--kind`` option saying what the input file is."""
56
+ parser.add_argument('-k', '--kind', dest='kind', default='config',
57
+ choices=sorted(KIND_CLASSES),
58
+ help="What the input file is: 'config' (default, a "
59
+ "backlog-ops configuration file), 'input' (an input "
60
+ "format preset file), or 'output' (an output format "
61
+ 'preset file).')
62
+
63
+
64
+ def kind_class(parsed: argparse.Namespace) -> type[Config]:
65
+ """Return the configuration class the ``--kind`` value names."""
66
+ return KIND_CLASSES[parsed.kind]
67
+
41
68
 
42
69
  def rank_anchor(value: Optional[str]) -> Optional[JiraRankAnchor]:
43
70
  """Return the anchor for a CLI anchor name, or None for a None value."""
@@ -23,10 +23,9 @@ from config_as_json import Config
23
23
  from config_as_json.file_extension import fix_file_extension
24
24
  from wizard_ui_bridge import WizardUiBridge, WizardUiBridgeConsole, \
25
25
  make_text_ui_bridge
26
- from backlogops import safe_write_config
26
+ from backlogops import CONFIG_EXTENSION, safe_write_config
27
27
  from backlogops_cli._command_io import add_force_arg, overwrite_callback
28
28
 
29
- CONFIG_EXTENSION = '.cfg'
30
29
  _ConfigT = TypeVar('_ConfigT', bound=Config)
31
30
 
32
31
 
@@ -0,0 +1,115 @@
1
+ #! /usr/local/bin/python3
2
+ """Edit a configuration file in a full-screen terminal editor.
3
+
4
+ The whole configuration is shown at once, folded where it is deep, so a
5
+ single value can be changed without walking through every question the
6
+ wizard asks. The editor is the one of ``edit-cfg-json-textual``, so it needs
7
+ a terminal; where the input is redirected, the wizard command is the way in.
8
+
9
+ ``-i`` says which file to edit and ``-k``/``--kind`` what kind of file it
10
+ is: the backlog-ops configuration, or a stand-alone input or output preset.
11
+ Without ``-o`` the file that was read is the file that Save writes, which is
12
+ what an editor is normally asked to do; with ``-o`` the input file is left
13
+ alone. Saving validates the whole configuration through its own class first
14
+ and refuses to write values the library would not read back, and what it
15
+ writes over is kept as that name plus ``.bak``.
16
+ """
17
+
18
+ # PYTHON_ARGCOMPLETE_OK
19
+ # Copyright (c) 2026, Tom Björkholm
20
+ # MIT License
21
+
22
+ import argparse
23
+ import sys
24
+ from pathlib import Path
25
+ from typing import Optional
26
+ from config_as_json.file_extension import fix_file_extension
27
+ from edit_cfg_json import EditModel
28
+ from edit_cfg_json_textual import TextualEditor
29
+ from backlogops import (
30
+ CONFIG_EXTENSION, default_edit_config, edit_model_for)
31
+ from backlogops_cli._command_io import add_kind_arg, kind_class, parsed_args
32
+
33
+ DESCRIPTION = 'Edit a configuration file in a full-screen editor'
34
+
35
+ EDIT_ERRORS = (ValueError, TypeError, KeyError, OSError)
36
+ """Errors raised when the file to edit cannot be opened."""
37
+
38
+
39
+ def build_parser() -> argparse.ArgumentParser:
40
+ """Build the command line parser for the config edit command."""
41
+ parser = argparse.ArgumentParser(description=DESCRIPTION)
42
+ parser.add_argument('-i', '--input', dest='input', required=True,
43
+ help='Existing configuration file to edit. The '
44
+ f'{CONFIG_EXTENSION} extension is assumed when the '
45
+ 'file is not found as named.')
46
+ parser.add_argument('-o', '--output', dest='output',
47
+ help='Configuration file that Save writes. Without '
48
+ '-o the edited file is written, which leaves no '
49
+ f'second copy behind. The {CONFIG_EXTENSION} '
50
+ 'extension is added to a name that has none.')
51
+ add_kind_arg(parser)
52
+ return parser
53
+
54
+
55
+ def _input_file(parsed: argparse.Namespace) -> str:
56
+ """Return the file to edit, assuming the extension when needed.
57
+
58
+ Raises:
59
+ ValueError: Neither the given name nor the completed one is a file.
60
+ """
61
+ path = fix_file_extension(parsed.input, CONFIG_EXTENSION, for_reading=True)
62
+ if not Path(path).is_file():
63
+ raise ValueError(f'Configuration file to edit not found: {path}')
64
+ return path
65
+
66
+
67
+ def _model_to_edit(parsed: argparse.Namespace) -> EditModel:
68
+ """Return the edit model for the file and kind that were asked for.
69
+
70
+ Raises:
71
+ ValueError: The file cannot be found or cannot be opened for
72
+ editing, or the class cannot be constructed.
73
+ """
74
+ return edit_model_for(default_edit_config(kind_class(parsed)),
75
+ in_file=_input_file(parsed), out_file=parsed.output,
76
+ stderr_file=sys.stderr)
77
+
78
+
79
+ def _report(model: EditModel) -> int:
80
+ """Print what the session wrote, and answer with the exit code.
81
+
82
+ Closing an editor is not a failure, so a session that saved nothing
83
+ still succeeds; it says so, because a user who meant to save would
84
+ otherwise be told nothing at all. What a save did is the editor's own
85
+ message, which names the file it wrote and where what it wrote over is.
86
+ """
87
+ if model.saved_config is None:
88
+ print('Closed without saving.')
89
+ return 0
90
+ print(model.save_message)
91
+ return 0
92
+
93
+
94
+ def main(args: Optional[list[str]] = None) -> int:
95
+ """Open the configuration file in the editor and report what was saved.
96
+
97
+ Args:
98
+ args: Optional replacement for ``sys.argv[1:]``, mainly for tests.
99
+
100
+ Returns:
101
+ ``0`` when the session ran, whether or not anything was saved,
102
+ ``1`` when the file cannot be opened for editing.
103
+ """
104
+ parsed = parsed_args(build_parser(), args)
105
+ try:
106
+ model = _model_to_edit(parsed)
107
+ except EDIT_ERRORS as error:
108
+ print(f'Could not open the configuration: {error}', file=sys.stderr)
109
+ return 1
110
+ TextualEditor().run_editor(model)
111
+ return _report(model)
112
+
113
+
114
+ if __name__ == '__main__': # pragma: no cover
115
+ sys.exit(main())
@@ -17,18 +17,11 @@ existing output file, so the destination must not exist.
17
17
  import argparse
18
18
  import sys
19
19
  from typing import Optional
20
- from config_as_json import Config, migrate_cfg
21
- from backlogops import (
22
- BacklogOpsConfig, InputFormatConfig, OutputFormatConfig)
23
- from backlogops_cli._command_io import parsed_args
20
+ from config_as_json import migrate_cfg
21
+ from backlogops_cli._command_io import add_kind_arg, kind_class, parsed_args
24
22
 
25
23
  DESCRIPTION = 'Migrate a configuration file to the current file format'
26
24
 
27
- KIND_CLASSES: dict[str, type[Config]] = {
28
- 'config': BacklogOpsConfig, 'input': InputFormatConfig,
29
- 'output': OutputFormatConfig}
30
- """Map a ``--kind`` value to the configuration class used to migrate it."""
31
-
32
25
  MIGRATE_ERRORS = (ValueError, TypeError, KeyError, OSError)
33
26
  """Errors raised when an input file cannot be read or written."""
34
27
 
@@ -41,12 +34,7 @@ def build_parser() -> argparse.ArgumentParser:
41
34
  parser.add_argument('-o', '--output', dest='output', required=True,
42
35
  help='New configuration file to create. It must '
43
36
  'not already exist.')
44
- parser.add_argument('-k', '--kind', dest='kind', default='config',
45
- choices=sorted(KIND_CLASSES),
46
- help="What the input file is: 'config' (default, a "
47
- "backlog-ops configuration file), 'input' (an input "
48
- "format preset file), or 'output' (an output format "
49
- 'preset file).')
37
+ add_kind_arg(parser)
50
38
  return parser
51
39
 
52
40
 
@@ -66,9 +54,8 @@ def main(args: Optional[list[str]] = None) -> int:
66
54
  already exists, or the data cannot be written.
67
55
  """
68
56
  parsed = parsed_args(build_parser(), args)
69
- config_class = KIND_CLASSES[parsed.kind]
70
57
  try:
71
- migrate_cfg(parsed.input, parsed.output, config_class)
58
+ migrate_cfg(parsed.input, parsed.output, kind_class(parsed))
72
59
  except SystemExit as error:
73
60
  return _exit_code(error)
74
61
  except MIGRATE_ERRORS as error:
@@ -1,4 +0,0 @@
1
- argcomplete>=3.7.1
2
- backlogops>=0.7
3
- wizard-ui-bridge[textual]>=1.2
4
- versionreporter>=0.4
File without changes
File without changes