Coverage for /Users/OORDCOR/Documents/code/bump-my-version/bumpversion/cli.py: 0%
145 statements
« prev ^ index » next coverage.py v7.3.2, created at 2024-02-24 07:45 -0600
« prev ^ index » next coverage.py v7.3.2, created at 2024-02-24 07:45 -0600
1"""bump-my-version Command line interface."""
3from pathlib import Path
4from typing import List, Optional
6import questionary
7import rich_click as click
8from click.core import Context
9from tomlkit import dumps
11from bumpversion import __version__
12from bumpversion.aliases import AliasedGroup
13from bumpversion.bump import do_bump
14from bumpversion.config import get_configuration
15from bumpversion.config.create import create_configuration
16from bumpversion.config.files import find_config_file
17from bumpversion.files import ConfiguredFile, modify_files
18from bumpversion.show import do_show, log_list
19from bumpversion.ui import get_indented_logger, print_info, print_warning, setup_logging
20from bumpversion.utils import get_context, get_overrides
21from bumpversion.visualize import visualize
23logger = get_indented_logger(__name__)
26@click.group(
27 cls=AliasedGroup,
28 invoke_without_command=True,
29 context_settings={
30 "ignore_unknown_options": True,
31 "allow_interspersed_args": True,
32 "help_option_names": ["-h", "--help"],
33 },
34 add_help_option=False,
35)
36@click.version_option(version=__version__)
37@click.pass_context
38def cli(ctx: Context) -> None:
39 """Version bump your Python project."""
40 if ctx.invoked_subcommand is None:
41 ctx.invoke(bump, *ctx.args)
44click.rich_click.OPTION_GROUPS = {
45 "bumpversion bump": [
46 {
47 "name": "Configuration",
48 "options": [
49 "--config-file",
50 "--current-version",
51 "--new-version",
52 "--parse",
53 "--serialize",
54 "--search",
55 "--replace",
56 "--no-configured-files",
57 "--ignore-missing-files",
58 "--ignore-missing-version",
59 ],
60 },
61 {
62 "name": "Output",
63 "options": ["--dry-run", "--verbose"],
64 },
65 {
66 "name": "Committing and tagging",
67 "options": [
68 "--allow-dirty" "--commit",
69 "--commit-args",
70 "--message",
71 "--tag",
72 "--tag-name",
73 "--tag-message",
74 "--sign-tags",
75 ],
76 },
77 ]
78}
81@cli.command(context_settings={"ignore_unknown_options": True})
82@click.argument("args", nargs=-1, type=str)
83@click.option(
84 "--config-file",
85 metavar="FILE",
86 required=False,
87 envvar="BUMPVERSION_CONFIG_FILE",
88 type=click.Path(exists=True),
89 help="Config file to read most of the variables from.",
90)
91@click.option(
92 "-v",
93 "--verbose",
94 count=True,
95 required=False,
96 envvar="BUMPVERSION_VERBOSE",
97 help="Print verbose logging to stderr. Can specify several times for more verbosity.",
98)
99@click.option(
100 "--allow-dirty/--no-allow-dirty",
101 default=None,
102 required=False,
103 envvar="BUMPVERSION_ALLOW_DIRTY",
104 help="Don't abort if working directory is dirty, or explicitly abort if dirty.",
105)
106@click.option(
107 "--current-version",
108 metavar="VERSION",
109 required=False,
110 envvar="BUMPVERSION_CURRENT_VERSION",
111 help="Version that needs to be updated",
112)
113@click.option(
114 "--new-version",
115 metavar="VERSION",
116 required=False,
117 envvar="BUMPVERSION_NEW_VERSION",
118 help="New version that should be in the files",
119)
120@click.option(
121 "--parse",
122 metavar="REGEX",
123 required=False,
124 envvar="BUMPVERSION_PARSE",
125 help="Regex parsing the version string",
126)
127@click.option(
128 "--serialize",
129 metavar="FORMAT",
130 multiple=True,
131 required=False,
132 envvar="BUMPVERSION_SERIALIZE",
133 help="How to format what is parsed back to a version",
134)
135@click.option(
136 "--search",
137 metavar="SEARCH",
138 required=False,
139 envvar="BUMPVERSION_SEARCH",
140 help="Template for complete string to search",
141)
142@click.option(
143 "--replace",
144 metavar="REPLACE",
145 required=False,
146 envvar="BUMPVERSION_REPLACE",
147 help="Template for complete string to replace",
148)
149@click.option(
150 "--regex/--no-regex",
151 default=None,
152 envvar="BUMPVERSION_REGEX",
153 help="Treat the search parameter as a regular expression or explicitly do not treat it as a regular expression.",
154)
155@click.option(
156 "--no-configured-files",
157 is_flag=True,
158 envvar="BUMPVERSION_NO_CONFIGURED_FILES",
159 help=(
160 "Only replace the version in files specified on the command line, "
161 "ignoring the files from the configuration file."
162 ),
163)
164@click.option(
165 "--ignore-missing-files",
166 is_flag=True,
167 envvar="BUMPVERSION_IGNORE_MISSING_FILES",
168 help="Ignore any missing files when searching and replacing in files.",
169)
170@click.option(
171 "--ignore-missing-version",
172 is_flag=True,
173 envvar="BUMPVERSION_IGNORE_MISSING_VERSION",
174 help="Ignore any Version Not Found errors when searching and replacing in files.",
175)
176@click.option(
177 "--dry-run",
178 "-n",
179 is_flag=True,
180 envvar="BUMPVERSION_DRY_RUN",
181 help="Don't write any files, just pretend.",
182)
183@click.option(
184 "--commit/--no-commit",
185 default=None,
186 envvar="BUMPVERSION_COMMIT",
187 help="Commit to version control",
188)
189@click.option(
190 "--tag/--no-tag",
191 default=None,
192 envvar="BUMPVERSION_TAG",
193 help="Create a tag in version control",
194)
195@click.option(
196 "--sign-tags/--no-sign-tags",
197 default=None,
198 envvar="BUMPVERSION_SIGN_TAGS",
199 help="Sign tags if created",
200)
201@click.option(
202 "--tag-name",
203 metavar="TAG_NAME",
204 required=False,
205 envvar="BUMPVERSION_TAG_NAME",
206 help="Tag name (only works with --tag)",
207)
208@click.option(
209 "--tag-message",
210 metavar="TAG_MESSAGE",
211 required=False,
212 envvar="BUMPVERSION_TAG_MESSAGE",
213 help="Tag message",
214)
215@click.option(
216 "-m",
217 "--message",
218 metavar="COMMIT_MSG",
219 required=False,
220 envvar="BUMPVERSION_MESSAGE",
221 help="Commit message",
222)
223@click.option(
224 "--commit-args",
225 metavar="COMMIT_ARGS",
226 required=False,
227 envvar="BUMPVERSION_COMMIT_ARGS",
228 help="Extra arguments to commit command",
229)
230@click.option(
231 "--list",
232 "show_list",
233 is_flag=True,
234 help="List machine readable information",
235)
236def bump(
237 # version_part: str,
238 args: list,
239 config_file: Optional[str],
240 verbose: int,
241 allow_dirty: Optional[bool],
242 current_version: Optional[str],
243 new_version: Optional[str],
244 parse: Optional[str],
245 serialize: Optional[List[str]],
246 search: Optional[str],
247 replace: Optional[str],
248 regex: Optional[bool],
249 no_configured_files: bool,
250 ignore_missing_files: bool,
251 ignore_missing_version: bool,
252 dry_run: bool,
253 commit: Optional[bool],
254 tag: Optional[bool],
255 sign_tags: Optional[bool],
256 tag_name: Optional[str],
257 tag_message: Optional[str],
258 message: Optional[str],
259 commit_args: Optional[str],
260 show_list: bool,
261) -> None:
262 """
263 Change the version.
265 ARGS may contain any of the following:
267 VERSION_PART is the part of the version to increase, e.g. `minor`.
268 Valid values include those given in the `--serialize` / `--parse` option.
270 FILES are additional file(s) to modify.
271 If you want to rewrite only files specified on the command line, use with the
272 `--no-configured-files` option.
273 """
274 setup_logging(verbose)
276 logger.info("Starting BumpVersion %s", __version__)
278 overrides = get_overrides(
279 allow_dirty=allow_dirty,
280 current_version=current_version,
281 parse=parse,
282 serialize=serialize or None,
283 search=search,
284 replace=replace,
285 commit=commit,
286 tag=tag,
287 sign_tags=sign_tags,
288 tag_name=tag_name,
289 tag_message=tag_message,
290 message=message,
291 commit_args=commit_args,
292 ignore_missing_files=ignore_missing_files,
293 ignore_missing_version=ignore_missing_version,
294 regex=regex,
295 )
297 found_config_file = find_config_file(config_file)
298 config = get_configuration(found_config_file, **overrides)
299 if args:
300 if args[0] not in config.parts.keys():
301 raise click.BadArgumentUsage(f"Unknown version part: {args[0]}")
302 version_part = args[0]
303 files = args[1:]
304 else:
305 version_part = None
306 files = args
308 if show_list:
309 print_warning("DEPRECATED: The --list option is deprecated and will be removed in a future version.")
310 log_list(config, version_part, new_version)
311 return
313 config.allow_dirty = allow_dirty if allow_dirty is not None else config.allow_dirty
314 if not config.allow_dirty and config.scm_info.tool:
315 config.scm_info.tool.assert_nondirty()
317 if no_configured_files:
318 config.excluded_paths = list(config.resolved_filemap.keys())
320 if files:
321 config.add_files(files)
322 config.included_paths = files
324 logger.dedent()
325 do_bump(version_part, new_version, config, found_config_file, dry_run)
328@cli.command()
329@click.argument("args", nargs=-1, type=str)
330@click.option(
331 "--config-file",
332 metavar="FILE",
333 required=False,
334 envvar="BUMPVERSION_CONFIG_FILE",
335 type=click.Path(exists=True),
336 help="Config file to read most of the variables from.",
337)
338@click.option(
339 "-f",
340 "--format",
341 "format_",
342 required=False,
343 envvar="BUMPVERSION_FORMAT",
344 type=click.Choice(["default", "yaml", "json"], case_sensitive=False),
345 default="default",
346 help="Config file to read most of the variables from.",
347)
348@click.option(
349 "-i",
350 "--increment",
351 required=False,
352 envvar="BUMPVERSION_INCREMENT",
353 type=str,
354 help="Increment the version part and add `new_version` to the configuration.",
355)
356def show(args: List[str], config_file: Optional[str], format_: str, increment: Optional[str]) -> None:
357 """Show current configuration information."""
358 found_config_file = find_config_file(config_file)
359 config = get_configuration(found_config_file)
361 if not args:
362 do_show("all", config=config, format_=format_, increment=increment)
363 else:
364 do_show(*args, config=config, format_=format_, increment=increment)
367@cli.command()
368@click.argument("files", nargs=-1, type=str)
369@click.option(
370 "--config-file",
371 metavar="FILE",
372 required=False,
373 envvar="BUMPVERSION_CONFIG_FILE",
374 type=click.Path(exists=True),
375 help="Config file to read most of the variables from.",
376)
377@click.option(
378 "-v",
379 "--verbose",
380 count=True,
381 required=False,
382 envvar="BUMPVERSION_VERBOSE",
383 help="Print verbose logging to stderr. Can specify several times for more verbosity.",
384)
385@click.option(
386 "--allow-dirty/--no-allow-dirty",
387 default=None,
388 required=False,
389 envvar="BUMPVERSION_ALLOW_DIRTY",
390 help="Don't abort if working directory is dirty, or explicitly abort if dirty.",
391)
392@click.option(
393 "--current-version",
394 metavar="VERSION",
395 required=False,
396 envvar="BUMPVERSION_CURRENT_VERSION",
397 help="Version that needs to be updated",
398)
399@click.option(
400 "--new-version",
401 metavar="VERSION",
402 required=False,
403 envvar="BUMPVERSION_NEW_VERSION",
404 help="New version that should be in the files. If not specified, it will be None.",
405)
406@click.option(
407 "--parse",
408 metavar="REGEX",
409 required=False,
410 envvar="BUMPVERSION_PARSE",
411 help="Regex parsing the version string",
412)
413@click.option(
414 "--serialize",
415 metavar="FORMAT",
416 multiple=True,
417 required=False,
418 envvar="BUMPVERSION_SERIALIZE",
419 help="How to format what is parsed back to a version",
420)
421@click.option(
422 "--search",
423 metavar="SEARCH",
424 required=False,
425 envvar="BUMPVERSION_SEARCH",
426 help="Template for complete string to search",
427)
428@click.option(
429 "--replace",
430 metavar="REPLACE",
431 required=False,
432 envvar="BUMPVERSION_REPLACE",
433 help="Template for complete string to replace",
434)
435@click.option(
436 "--regex/--no-regex",
437 default=False,
438 envvar="BUMPVERSION_REGEX",
439 help="Treat the search parameter as a regular expression or explicitly do not treat it as a regular expression.",
440)
441@click.option(
442 "--no-configured-files",
443 is_flag=True,
444 envvar="BUMPVERSION_NO_CONFIGURED_FILES",
445 help=(
446 "Only replace the version in files specified on the command line, "
447 "ignoring the files from the configuration file."
448 ),
449)
450@click.option(
451 "--ignore-missing-version",
452 is_flag=True,
453 envvar="BUMPVERSION_IGNORE_MISSING_VERSION",
454 help="Ignore any Version Not Found errors when searching and replacing in files.",
455)
456@click.option(
457 "--ignore-missing-files",
458 is_flag=True,
459 envvar="BUMPVERSION_IGNORE_MISSING_FILES",
460 help="Ignore any missing files when searching and replacing in files.",
461)
462@click.option(
463 "--dry-run",
464 "-n",
465 is_flag=True,
466 envvar="BUMPVERSION_DRY_RUN",
467 help="Don't write any files, just pretend.",
468)
469def replace(
470 files: list,
471 config_file: Optional[str],
472 verbose: int,
473 allow_dirty: Optional[bool],
474 current_version: Optional[str],
475 new_version: Optional[str],
476 parse: Optional[str],
477 serialize: Optional[List[str]],
478 search: Optional[str],
479 replace: Optional[str],
480 regex: bool,
481 no_configured_files: bool,
482 ignore_missing_version: bool,
483 ignore_missing_files: bool,
484 dry_run: bool,
485) -> None:
486 """
487 Replace the version in files.
489 FILES are additional file(s) to modify.
490 If you want to rewrite only files specified on the command line, use with the
491 `--no-configured-files` option.
492 """
493 setup_logging(verbose)
495 logger.info("Starting BumpVersion %s", __version__)
497 overrides = get_overrides(
498 allow_dirty=allow_dirty,
499 current_version=current_version,
500 new_version=new_version,
501 parse=parse,
502 serialize=serialize or None,
503 commit=False,
504 tag=False,
505 sign_tags=False,
506 tag_name=None,
507 tag_message=None,
508 message=None,
509 commit_args=None,
510 ignore_missing_version=ignore_missing_version,
511 ignore_missing_files=ignore_missing_files,
512 regex=regex,
513 )
515 found_config_file = find_config_file(config_file)
516 config = get_configuration(found_config_file, **overrides)
518 config.allow_dirty = allow_dirty if allow_dirty is not None else config.allow_dirty
519 if not config.allow_dirty and config.scm_info.tool:
520 config.scm_info.tool.assert_nondirty()
522 if no_configured_files:
523 config.excluded_paths = list(config.resolved_filemap.keys())
525 if files:
526 config.add_files(files)
527 config.included_paths = files
529 configured_files = [
530 ConfiguredFile(file_cfg, config.version_config, search, replace) for file_cfg in config.files_to_modify
531 ]
533 version = config.version_config.parse(config.current_version)
534 if new_version:
535 next_version = config.version_config.parse(new_version)
536 else:
537 next_version = None
539 ctx = get_context(config, version, next_version)
541 modify_files(configured_files, version, next_version, ctx, dry_run)
544@cli.command()
545@click.option(
546 "--prompt/--no-prompt",
547 default=True,
548 help="Ask the user questions about the configuration.",
549)
550@click.option(
551 "--destination",
552 default="stdout",
553 help="Where to write the sample configuration.",
554 type=click.Choice(["stdout", ".bumpversion.toml", "pyproject.toml"]),
555)
556def sample_config(prompt: bool, destination: str) -> None:
557 """Print a sample configuration file."""
558 if prompt:
559 destination = questionary.select(
560 "Destination", choices=["stdout", ".bumpversion.toml", "pyproject.toml"], default=destination
561 ).ask()
563 destination_config = create_configuration(destination, prompt)
565 if destination == "stdout":
566 print_info(dumps(destination_config))
567 else:
568 Path(destination).write_text(dumps(destination_config))
571@cli.command()
572@click.argument("version", nargs=1, type=str, required=False, default="")
573@click.option(
574 "--config-file",
575 metavar="FILE",
576 required=False,
577 envvar="BUMPVERSION_CONFIG_FILE",
578 type=click.Path(exists=True),
579 help="Config file to read most of the variables from.",
580)
581@click.option("--ascii", is_flag=True, help="Use ASCII characters only.")
582def show_bump(version: str, config_file: Optional[str], ascii: bool) -> None:
583 """Show the possible versions resulting from the bump subcommand."""
584 found_config_file = find_config_file(config_file)
585 config = get_configuration(found_config_file)
586 if not version:
587 version = config.current_version
588 box_style = "ascii" if ascii else "light"
589 visualize(config=config, version_str=version, box_style=box_style)