Coverage for src/cli/entrypoint.py: 57.34%
361 statements
« prev ^ index » next coverage.py v7.17.2, created at 2026-11-08 13:49 +0000
« prev ^ index » next coverage.py v7.17.2, created at 2026-11-08 13:49 +0000
1#!/usr/bin/env python3
3# Standard libraries
4from argparse import Namespace
5from enum import Enum
6from importlib.resources import files as resources_files
7from pathlib import Path
8from tempfile import _TemporaryFileWrapper as TempFile, NamedTemporaryFile
9from time import sleep
10from typing import List
12# Components
13from ..features.argcomplete import Argcomplete
14from ..features.commitizen import Commitizen
15from ..features.gcil import Gcil
16from ..features.git import Git
17from ..features.mise import Mise
18from ..features.precommit import PreCommit
19from ..features.radiandevcore import RadianDevCore
20from ..features.readme import Readme
21from ..features.templates import Templates
22from ..package.bundle import Bundle
23from ..package.version import Version
24from ..prints.colors import Colors
25from ..system.commands import Commands
26from ..system.platform import Platform
28# Entrypoint class, pylint: disable=too-few-public-methods,too-many-statements
29class Entrypoint:
31 # Enumerations
32 Result = Enum('Result', [
33 'SUCCESS',
34 'FINALIZE',
35 'ERROR',
36 'CRITICAL',
37 ])
39 # CLI, pylint: disable=too-many-boolean-expressions,too-many-branches,too-many-locals
40 @staticmethod
41 def cli(options: Namespace, ) -> Result:
43 # Variables
44 asset: str
45 command_add: List[str]
46 command_add_string: str
47 command_commit: List[str]
48 command_commit_string: str
49 configurations_existed: bool = False
50 configurations_revision: str = ''
51 configurations_files: List[str] = []
52 data: str
53 include_components: bool = False
54 include_prefix: str
55 include_remotes: bool = False
56 include_sources: bool = False
57 include_value: str
58 local_ci_data: str
59 local_template: str
61 # Configure pre-commit
62 PreCommit.configure()
64 # List hooks
65 if options.list:
67 # Detect hooks directory
68 hooks_dir = Git.hooks_dir()
70 # List hooks directory
71 if Path(hooks_dir).exists():
73 # Detect hooks files
74 hooks_files = Git.hooks_files()
76 # List hooks files
77 if hooks_files:
78 print(' ')
79 print(f'{Colors.GREEN} ===['
80 f'{Colors.YELLOW} List hooks: '
81 f'{Colors.YELLOW_LIGHT}Hooks installed in '
82 f'{Colors.CYAN}"{hooks_dir}"'
83 f'{Colors.GREEN} ]==='
84 f'{Colors.RESET}')
85 print(' ')
86 for hook in hooks_files:
87 print(f'{Colors.BOLD} - Hook: {Colors.RESET}{hook}')
88 print(' ')
89 Platform.flush()
91 # Missing hooks files
92 else:
93 print(' ')
94 print(f'{Colors.GREEN} ===['
95 f'{Colors.YELLOW} List hooks: '
96 f'{Colors.YELLOW_LIGHT}No hooks installed in '
97 f'{Colors.CYAN}"{hooks_dir}"'
98 f'{Colors.GREEN} ]==='
99 f'{Colors.RESET}')
100 print(' ')
101 Platform.flush()
103 # Missing hooks directory
104 else:
105 print(' ')
106 print(f'{Colors.GREEN} ===['
107 f'{Colors.YELLOW} List hooks: '
108 f'{Colors.YELLOW_LIGHT}No hooks directory found in '
109 f'{Colors.CYAN}"{hooks_dir}"'
110 f'{Colors.GREEN} ]==='
111 f'{Colors.RESET}')
112 print(' ')
113 Platform.flush()
115 # Prepare dependencies
116 if options.install or options.configure or options.enable or options.autoupdate \
117 or options.clean or options.run:
119 # Install pre-commit dependency
120 if options.install or not PreCommit.exists():
121 print(' ')
122 print(f'{Colors.GREEN} ===['
123 f'{Colors.YELLOW} Install dependencies: '
124 f'{Colors.YELLOW_LIGHT}{PreCommit.TITLE}'
125 f'{Colors.GREEN} ]==='
126 f'{Colors.RESET}')
127 print(' ')
128 Platform.flush()
129 PreCommit.dependencies()
131 # Install commitizen dependency
132 if options.install or not Commitizen.exists() or not Commitizen.compatible():
133 print(' ')
134 print(f'{Colors.GREEN} ===['
135 f'{Colors.YELLOW} Install dependencies: '
136 f'{Colors.YELLOW_LIGHT}{Commitizen.TITLE}'
137 f'{Colors.GREEN} ]==='
138 f'{Colors.RESET}')
139 print(' ')
140 Platform.flush()
141 Commitizen.dependencies()
143 # Install argcomplete completion
144 if options.install and not Argcomplete.configured():
145 print(' ')
146 print(f'{Colors.GREEN} ===['
147 f'{Colors.YELLOW} Install bash completion: '
148 f'{Colors.YELLOW_LIGHT}argcomplete'
149 f'{Colors.GREEN} ]==='
150 f'{Colors.RESET}')
151 print(' ')
152 Platform.flush()
153 Argcomplete.configure()
154 if Platform.IS_TTY_STDIN:
155 sleep(2)
157 # Install commitizen completion
158 if options.install and not Commitizen.configured():
159 print(' ')
160 print(f'{Colors.GREEN} ===['
161 f'{Colors.YELLOW} Install dependencies: '
162 f'{Colors.YELLOW_LIGHT}commitizen completion'
163 f'{Colors.GREEN} ]==='
164 f'{Colors.RESET}')
165 print(' ')
166 Platform.flush()
167 commitizen_file: str = Commitizen.configure()
168 print(f'commitizen completion enabled in: {commitizen_file}')
169 if Platform.IS_TTY_STDIN:
170 sleep(1)
172 # Bind specific configurations
173 if options.config:
174 Commitizen.set_configuration(options.config + Platform.PATH_SEPARATOR +
175 Commitizen.CONFIGURATION_FILE)
176 PreCommit.set_configuration(options.config + Platform.PATH_SEPARATOR +
177 PreCommit.CONFIGURATION_FILE)
179 # Bind default configurations
180 elif options.default:
182 # Bind configurations files, pylint: disable=consider-using-with
183 commitizen_configuration: TempFile = NamedTemporaryFile( # type: ignore[type-arg]
184 delete_on_close=True,
185 suffix=Commitizen.CONFIGURATION_EXTENSION,
186 )
187 precommit_configuration: TempFile = NamedTemporaryFile( # type: ignore[type-arg]
188 delete_on_close=True,
189 suffix=PreCommit.CONFIGURATION_EXTENSION,
190 )
192 # Bind configurations flags
193 Commitizen.set_configuration(commitizen_configuration.name)
194 PreCommit.set_configuration(precommit_configuration.name)
196 # Default pre-commit configuration
197 with open(
198 precommit_configuration.name,
199 encoding='utf8',
200 mode='w+t',
201 ) as file:
203 # Acquire pre-commit configuration
204 file.write(resources_files(Bundle.RESOURCES_ASSETS) \
205 .joinpath(PreCommit.CONFIGURATION_TEMPLATE) \
206 .read_text(encoding='utf8') \
207 .replace(PreCommit.REV_TEMPLATE, Version.revision()))
208 file.flush()
210 # Default commitizen configuration
211 with open(
212 commitizen_configuration.name,
213 encoding='utf8',
214 mode='w+t',
215 ) as file:
217 # Acquire commitizen configuration
218 file.write(resources_files(Bundle.RESOURCES_ASSETS) \
219 .joinpath(Commitizen.CONFIGURATION_FILE) \
220 .read_text(encoding='utf8') \
221 .replace(PreCommit.REV_TEMPLATE, Version.revision()))
222 file.flush()
224 # Autoupdate pre-commit hooks
225 if not options.offline and Git.is_repository():
226 PreCommit.autoupdate()
228 # Configure useless excludes
229 PreCommit.configure_useless_excludes(
230 default=options.default,
231 configuration_file=precommit_configuration.name,
232 )
234 # Configure unused hooks
235 PreCommit.configure_unused_hooks(
236 default=options.default,
237 configuration_file=precommit_configuration.name,
238 hooks_disable=[
239 PreCommit.HOOK_CHECK_HOOKS_APPLY,
240 PreCommit.HOOK_CHECK_USELESS_EXCLUDES,
241 ],
242 )
244 # Configre gcil hooks
245 Gcil.configure_hooks(
246 configuration_file=precommit_configuration.name,
247 autoupdate=not options.offline,
248 )
250 # Autoupdate pre-commit hooks
251 if not options.offline and Git.is_repository():
252 PreCommit.autoupdate()
254 # Configure sources
255 if options.configure:
257 # Install sources configurations
258 print(' ')
259 print(f'{Colors.GREEN} ===['
260 f'{Colors.YELLOW} Configure sources: '
261 f'{Colors.YELLOW_LIGHT}{Bundle.NAME}'
262 f'{Colors.GREEN} ]==='
263 f'{Colors.RESET}')
264 print(' ')
266 # Export pre-commit assets file
267 if Path(PreCommit.CONFIGURATION_FILE).exists():
268 configurations_existed = True
269 configurations_revision = PreCommit.revision()
270 print(
271 f'exporting configuration in {PreCommit.CONFIGURATION_FILE} configuration'
272 )
273 configurations_files += [PreCommit.CONFIGURATION_FILE]
274 data = resources_files(Bundle.RESOURCES_ASSETS) \
275 .joinpath(PreCommit.CONFIGURATION_TEMPLATE) \
276 .read_text(encoding='utf8') \
277 .replace(PreCommit.REV_TEMPLATE, Version.revision())
278 with open(
279 PreCommit.CONFIGURATION_FILE,
280 encoding='utf8',
281 mode='w',
282 ) as f:
283 f.write(data)
284 if Platform.IS_TTY_STDIN:
285 sleep(0.5)
287 # Export Commitizen assets file
288 if Path(Commitizen.CONFIGURATION_FILE).exists():
289 configurations_existed = True
290 print(
291 f'exporting configuration in {Commitizen.CONFIGURATION_FILE} configuration'
292 )
293 configurations_files += [Commitizen.CONFIGURATION_FILE]
294 data = resources_files(Bundle.RESOURCES_ASSETS) \
295 .joinpath(Commitizen.CONFIGURATION_FILE) \
296 .read_text(encoding='utf8') \
297 .replace(PreCommit.REV_TEMPLATE, Version.revision())
298 with open(
299 Commitizen.CONFIGURATION_FILE,
300 encoding='utf8',
301 mode='w',
302 ) as f:
303 f.write(data)
304 if Platform.IS_TTY_STDIN:
305 sleep(0.5)
307 # Autoupdate pre-commit hooks
308 if not options.offline and Git.is_repository():
309 PreCommit.autoupdate()
311 # Configure useless excludes
312 PreCommit.configure_useless_excludes(default=options.default)
314 # Configure unused hooks
315 PreCommit.configure_unused_hooks(
316 default=options.default,
317 hooks_disable=[
318 PreCommit.HOOK_CHECK_HOOKS_APPLY,
319 PreCommit.HOOK_CHECK_USELESS_EXCLUDES,
320 ],
321 )
323 # Configre gcil hooks
324 Gcil.configure_hooks(
325 configuration_file=PreCommit.CONFIGURATION_FILE,
326 autoupdate=not options.offline,
327 )
329 # Autoupdate pre-commit hooks
330 if not options.offline and Git.is_repository():
331 PreCommit.autoupdate()
333 # Export components templates
334 if options.configure and Gcil.exists():
336 # Prepare components stage
337 components_stage: str = options.stage if options.stage else 'test'
339 # Detect if components in sources
340 if options.components:
341 include_components = True
342 elif options.remotes:
343 include_remotes = True
344 elif options.no_components:
345 include_sources = True
346 elif any(Bundle.COMPONENTS_SAAS_DOMAIN in url for url in Git.urls()):
347 include_components = True
348 else:
349 include_remotes = True
351 # Bind components version
352 if include_components:
354 # Install components configurations
355 print(' ')
356 print(f'{Colors.GREEN} ===['
357 f'{Colors.YELLOW} Configure sources: '
358 f'{Colors.YELLOW_LIGHT}components'
359 f'{Colors.GREEN} ]==='
360 f'{Colors.RESET}')
361 print(' ')
363 # Inject component in .gitlab-ci.yml
364 include_value = Bundle.COMPONENTS_SAAS_COMMITS.replace(
365 Bundle.COMPONENTS_PACKAGE_VERSION,
366 Version.revision(),
367 )
368 include_prefix = Bundle.COMPONENTS_SAAS_COMMITS.split(
369 Bundle.COMPONENTS_PACKAGE_VERSION,
370 1,
371 )[0]
372 local_ci_data = ''
373 with open(Gcil.FILE, encoding='utf8') as local_ci_file:
374 local_ci_data = local_ci_file.read()
375 if include_value not in local_ci_data:
376 configurations_files += [Gcil.FILE]
377 with open(
378 Gcil.FILE,
379 encoding='utf8',
380 mode='w',
381 ) as f:
382 if f'component: {include_prefix}' not in local_ci_data:
383 f.write(
384 Gcil.EOL.join([
385 'include:',
386 f' - component: {include_value}',
387 ' inputs:',
388 f' stage: {components_stage}',
389 ' name: commits',
390 '',
391 '',
392 ]))
393 else:
394 local_ci_data = Gcil.EOL.join([
395 f'{line[0:line.find(include_prefix)]}{include_value}' #
396 if f'component: {include_prefix}' in line #
397 else line #
398 for line in local_ci_data.splitlines()
399 ]) + Gcil.EOL
400 if 'stages:' not in local_ci_data.splitlines():
401 f.write(
402 Gcil.EOL.join([
403 'stages:',
404 f' - {components_stage}',
405 '',
406 ]))
407 f.write(local_ci_data)
409 # Bind remotes version
410 elif include_remotes:
412 # Install remotes configurations
413 print(' ')
414 print(f'{Colors.GREEN} ===['
415 f'{Colors.YELLOW} Configure sources: '
416 f'{Colors.YELLOW_LIGHT}remotes'
417 f'{Colors.GREEN} ]==='
418 f'{Colors.RESET}')
419 print(' ')
421 # Inject remote in .gitlab-ci.yml
422 include_value = Bundle.COMPONENTS_REMOTE_COMMITS.replace(
423 Bundle.COMPONENTS_PACKAGE_VERSION,
424 Version.revision(),
425 )
426 include_prefix = Bundle.COMPONENTS_REMOTE_COMMITS.split(
427 Bundle.COMPONENTS_PACKAGE_VERSION,
428 1,
429 )[0]
430 local_ci_data = ''
431 with open(Gcil.FILE, encoding='utf8') as local_ci_file:
432 local_ci_data = local_ci_file.read()
433 if include_value not in local_ci_data:
434 configurations_files += [Gcil.FILE]
435 with open(
436 Gcil.FILE,
437 encoding='utf8',
438 mode='w',
439 ) as f:
440 if f'remote: {include_prefix}' not in local_ci_data:
441 f.write(
442 Gcil.EOL.join([
443 'include:',
444 f' - remote: {include_value}',
445 ' inputs:',
446 f' stage: {components_stage}',
447 ' name: commits',
448 '',
449 '',
450 ]))
451 else:
452 local_ci_data = Gcil.EOL.join([
453 f'{line[0:line.find(include_prefix)]}{include_value}' #
454 if f'remote: {include_prefix}' in line #
455 else line #
456 for line in local_ci_data.splitlines()
457 ]) + Gcil.EOL
458 if 'stages:' not in local_ci_data.splitlines():
459 f.write(
460 Gcil.EOL.join([
461 'stages:',
462 f' - {components_stage}',
463 '',
464 ]))
465 f.write(local_ci_data)
467 # Export components sources
468 elif include_sources:
470 # Install templates configurations
471 print(' ')
472 print(f'{Colors.GREEN} ===['
473 f'{Colors.YELLOW} Configure sources: '
474 f'{Colors.YELLOW_LIGHT}templates'
475 f'{Colors.GREEN} ]==='
476 f'{Colors.RESET}')
477 print(' ')
479 # Export templates files
480 for asset in [
481 Templates.COMMITS_FILE,
482 ]:
484 # Export template file
485 print(f'exporting components in {asset} local template')
486 Path(Templates.GITLAB_CI_LOCAL_FOLDER).mkdir(
487 parents=False,
488 exist_ok=True,
489 )
490 local_template = f'{Templates.GITLAB_CI_LOCAL_FOLDER}/{asset}'
491 configurations_files += [local_template]
492 data = resources_files(Bundle.RESOURCES_ASSETS) \
493 .joinpath(asset) \
494 .read_text(encoding='utf8')
495 with open(
496 local_template,
497 encoding='utf8',
498 mode='w',
499 ) as f:
500 f.write(data)
501 if Platform.IS_TTY_STDIN:
502 sleep(0.5)
504 # Inject template in .gitlab-ci.yml
505 local_ci_data = ''
506 with open(Gcil.FILE, encoding='utf8') as local_ci_file:
507 local_ci_data = local_ci_file.read()
508 if asset not in local_ci_data:
509 configurations_files += [Gcil.FILE]
510 with open(
511 Gcil.FILE,
512 encoding='utf8',
513 mode='w',
514 ) as f:
515 f.write(
516 Gcil.EOL.join([
517 'include:',
518 f' - local: \'/{local_template}\'',
519 ' inputs:',
520 f' stage: {components_stage}',
521 f' name: {asset.rsplit("/", 1)[-1].split(".", 1)[0]}',
522 '',
523 '',
524 ]))
525 if 'stages:' not in local_ci_data.split():
526 f.write(
527 Gcil.EOL.join([
528 'stages:',
529 f' - {components_stage}',
530 '',
531 ]))
532 f.write(local_ci_data)
534 # Register configured file
535 configurations_files += [Gcil.FILE]
537 # Enable pre-commit hooks
538 if not options.enable:
539 options.enable = True
541 # Configure sources or badges
542 if options.configure or options.badges:
544 # Inject badge to README
545 if Readme.exists() or options.badges:
547 # Configure README sources
548 print(' ')
549 print(f'{Colors.GREEN} ===['
550 f'{Colors.YELLOW} Configure sources: '
551 f'{Colors.YELLOW_LIGHT}{Readme.FILE}'
552 f'{Colors.GREEN} ]==='
553 f'{Colors.RESET}')
554 print(' ')
556 # Acquire README contents
557 readme_lines: List[str] = Readme.read()
559 # Prepare empty README
560 if not readme_lines:
561 readme_lines = [f'# {Path.cwd().name}{Readme.EOL}']
563 # Prepare README without empty lines
564 if all(line.strip() for line in readme_lines):
565 if not readme_lines[-1].endswith(Readme.EOL):
566 readme_lines[-1] = f'{readme_lines[-1]}{Readme.EOL}'
567 readme_lines += [f'{Readme.EOL}']
568 readme_lines += ['']
570 # Check badges in READE
571 bundle_found: bool = any(
572 line.startswith(f'[![{Bundle.NAME}]') for line in readme_lines)
573 guidelines_found: bool = any(
574 line.startswith(f'[![{RadianDevCore.Guidelines.BADGE_TEXT}]')
575 for line in readme_lines)
576 gcil_found: bool = any(
577 line.startswith(f'[![{Gcil.BADGE_TEXT}]') for line in readme_lines)
579 # Detect gcil usage
580 gcil_exists: bool = Gcil.exists()
581 gcil_configured: bool = Gcil.configured()
582 gcil_installed: bool = Gcil.installed()
583 gcil_needed: bool = gcil_exists and (gcil_configured or gcil_installed)
585 # Validate badge in README
586 if not bundle_found \
587 or not guidelines_found \
588 or (not gcil_found and gcil_needed):
590 # Inject badge lines
591 print(f'injecting badge in {Readme.FILE} documentation')
592 for i, line in enumerate(readme_lines):
594 # Ignore non-empty lines
595 if line.strip():
596 continue
598 # Handle empty line
599 if not line:
600 line = Readme.EOL
602 # Inject badges separator
603 readme_lines.insert(
604 i + 1,
605 line,
606 )
608 # Inject RadianDevCore guidelines badge
609 if not guidelines_found:
610 readme_lines.insert(
611 i + 1,
612 f'[![{RadianDevCore.Guidelines.BADGE_TEXT}]'
613 f'({RadianDevCore.Guidelines.BADGE_IMAGE})]'
614 f'({RadianDevCore.Guidelines.BADGE_URL}){line}',
615 )
617 # Inject pre-commit-crocodile badge
618 if not bundle_found:
619 readme_lines.insert(
620 i + 1,
621 f'[![{Bundle.NAME}]'
622 f'({Bundle.BADGE})]'
623 f'({Bundle.DOCUMENTATION}){line}',
624 )
626 # Inject gcil badge
627 if not gcil_found and gcil_needed:
628 readme_lines.insert(
629 i + 1,
630 f'[![{Gcil.BADGE_TEXT}]'
631 f'({Gcil.BADGE_IMAGE})]'
632 f'({Gcil.BADGE_URL}){line}',
633 )
635 # Preserve README documentation
636 break
638 # Export README contents
639 Readme.write(readme_lines)
641 # Register configured file
642 configurations_files += [Readme.FILE]
644 # Keep existing README
645 else:
646 print(f'keeping original {Readme.FILE} documentation')
648 # Register mise configuration file
649 if options.configure and Path(Mise.CONFIG_LOCAL).exists():
650 configurations_files += [Mise.CONFIG_LOCAL]
652 # Show sources status
653 if Git.is_repository():
654 print(' ')
655 print(f'{Colors.GREEN} ===['
656 f'{Colors.YELLOW} Sources status: '
657 f'{Colors.YELLOW_LIGHT}git status'
658 f'{Colors.GREEN} ]==='
659 f'{Colors.RESET}')
660 print(' ')
661 Git.status(untracked=True)
663 # Configure sources
664 if options.configure \
665 and Git.is_repository() \
666 and Git.intend(configurations_files) \
667 and Git.diff(configurations_files):
669 # Show commit hints
670 print(' ')
671 print(f'{Colors.GREEN} ===['
672 f'{Colors.YELLOW} Update sources: '
673 f'{Colors.YELLOW_LIGHT}git'
674 f'{Colors.GREEN} ]==='
675 f'{Colors.RESET}')
676 print(' ')
677 command_add = [
678 Git.BINARY,
679 'add',
680 '--patch' if options.patch else '-v',
681 ] + [f'./{asset}' for asset in configurations_files]
682 if configurations_existed and configurations_revision == Version.revision():
683 command_commit = [
684 Git.BINARY,
685 'commit',
686 '-m',
687 f'chore(pre-commit): refresh with \'{Bundle.NAME}\' {Version.get()}',
688 '-s',
689 ]
690 elif configurations_existed:
691 command_commit = [
692 Git.BINARY,
693 'commit',
694 '-m',
695 f'chore(pre-commit): migrate to \'{Bundle.NAME}\' {Version.get()}',
696 '-s',
697 ]
698 else:
699 command_commit = [
700 Git.BINARY,
701 'commit',
702 '-m',
703 f'chore(pre-commit): import \'{Bundle.NAME}\' {Version.get()}',
704 '-s',
705 ]
706 command_add_string = ' '.join([
707 f'{argument}' if "'" in argument else argument #
708 for argument in command_add
709 ])
710 command_commit_string = ' '.join([
711 f'"{argument}"' if "'" in argument else argument
712 for argument in command_commit
713 ])
714 print(f'{Colors.BOLD} - Add configurations: '
715 f'{Colors.CYAN}{command_add_string}'
716 f'{Colors.RESET}')
717 print(f'{Colors.BOLD} - Commit changes: '
718 f'{Colors.CYAN}{command_commit_string}'
719 f'{Colors.RESET}')
720 Platform.flush()
722 # Commit changes automatically
723 if options.commit:
724 print(' ')
725 Commands.run(Git.BINARY, command_add[1:])
726 Platform.flush()
728 # Discard rejected pre-commit configuration changes
729 if options.patch \
730 and PreCommit.CONFIGURATION_FILE in configurations_files \
731 and Git.diff([PreCommit.CONFIGURATION_FILE]) \
732 and Git.commit_exists(f'HEAD:{PreCommit.CONFIGURATION_FILE}'):
733 print(' ')
734 print(f'discarding unstaged {PreCommit.CONFIGURATION_FILE} changes')
735 Git.restore([PreCommit.CONFIGURATION_FILE])
736 Platform.flush()
738 if not Git.staging_empty():
739 print(' ')
740 Commands.run(Git.BINARY, command_commit[1:])
741 Platform.flush()
743 # Delay user interactions
744 if Platform.IS_TTY_STDIN:
745 if options.commit:
746 sleep(1)
747 else:
748 sleep(3)
750 # Configure badges
751 elif options.badges and configurations_files and Git.is_repository():
753 # Show commit hints
754 print(' ')
755 print(f'{Colors.GREEN} ===['
756 f'{Colors.YELLOW} Update sources: '
757 f'{Colors.YELLOW_LIGHT}git'
758 f'{Colors.GREEN} ]==='
759 f'{Colors.RESET}')
760 print(' ')
761 command_add = [
762 Git.BINARY,
763 'add',
764 '--patch' if options.patch else '-v',
765 ] + [f'./{asset}' for asset in configurations_files]
766 command_commit = [
767 Git.BINARY,
768 'commit',
769 '-m',
770 'docs(readme): add applicable badges to the documentation',
771 '-s',
772 ]
773 command_add_string = ' '.join([
774 f'{argument}' if "'" in argument else argument #
775 for argument in command_add
776 ])
777 command_commit_string = ' '.join([
778 f'"{argument}"' if "'" in argument else argument
779 for argument in command_commit
780 ])
781 print(f'{Colors.BOLD} - Add configurations: '
782 f'{Colors.CYAN}{command_add_string}'
783 f'{Colors.RESET}')
784 print(f'{Colors.BOLD} - Commit changes: '
785 f'{Colors.CYAN}{command_commit_string}'
786 f'{Colors.RESET}')
787 Platform.flush()
789 # Commit changes automatically
790 if options.commit:
791 print(' ')
792 Commands.run(Git.BINARY, command_add[1:])
793 Platform.flush()
794 if not Git.staging_empty():
795 print(' ')
796 Commands.run(Git.BINARY, command_commit[1:])
797 Platform.flush()
799 # Delay user interactions
800 if Platform.IS_TTY_STDIN:
801 if options.commit:
802 sleep(1)
803 else:
804 sleep(3)
806 # Enable hooks
807 if options.enable and Git.is_repository():
809 # Detect Git remotes
810 git_remotes: List[str] = Git.remotes()
812 # Enable Git hooks
813 print(' ')
814 print(f'{Colors.GREEN} ===['
815 f'{Colors.YELLOW} Enable hooks: '
816 f'{Colors.YELLOW_LIGHT}Git remote'
817 f'{Colors.GREEN} ]==='
818 f'{Colors.RESET}')
819 print(' ')
820 print(f'detected Git remotes: {", ".join(git_remotes)}')
821 Platform.flush()
822 for remote in git_remotes:
823 print(f'updating git remote for {remote}')
824 Git.update_remote_head(remote)
826 # Enable pre-commit hooks
827 print(' ')
828 print(f'{Colors.GREEN} ===['
829 f'{Colors.YELLOW} Enable hooks: '
830 f'{Colors.YELLOW_LIGHT}{PreCommit.TITLE}'
831 f'{Colors.GREEN} ]==='
832 f'{Colors.RESET}')
833 print(' ')
834 Platform.flush()
835 PreCommit.install()
837 # Run pre-commit hooks
838 if not options.run and Path(PreCommit.CONFIGURATION_FILE).exists():
839 options.run = True
841 # Ignore GitLab CI stage from --configure
842 options.stage = None
844 # Disable hooks
845 if options.disable:
847 # Disable pre-commit hooks
848 print(' ')
849 print(f'{Colors.GREEN} ===['
850 f'{Colors.YELLOW} Disable hooks: '
851 f'{Colors.YELLOW_LIGHT}{PreCommit.TITLE}'
852 f'{Colors.GREEN} ]==='
853 f'{Colors.RESET}')
854 print(' ')
855 Platform.flush()
856 PreCommit.uninstall()
858 # Autoupdate hooks
859 if options.autoupdate:
861 # Autoupdate pre-commit hooks
862 print(' ')
863 print(f'{Colors.GREEN} ===['
864 f'{Colors.YELLOW} Autoupdate hooks: '
865 f'{Colors.YELLOW_LIGHT}{PreCommit.TITLE}'
866 f'{Colors.GREEN} ]==='
867 f'{Colors.RESET}')
868 print(' ')
869 Platform.flush()
870 PreCommit.autoupdate()
872 # Cleanup hooks
873 if options.clean:
875 # Disable pre-commit hooks
876 print(' ')
877 print(f'{Colors.GREEN} ===['
878 f'{Colors.YELLOW} Cleanup hooks: '
879 f'{Colors.YELLOW_LIGHT}{PreCommit.TITLE}'
880 f'{Colors.GREEN} ]==='
881 f'{Colors.RESET}')
882 print(' ')
883 Platform.flush()
884 PreCommit.clean()
886 # Run hooks
887 if options.run:
889 # Run pre-commit hooks
890 print(' ')
891 print(f'{Colors.GREEN} ===['
892 f'{Colors.YELLOW} Run hooks: '
893 f'{Colors.YELLOW_LIGHT}{PreCommit.TITLE}'
894 f'{Colors.CYAN}{f" (stage: {options.stage})" if options.stage else ""}'
895 f'{Colors.GREEN} ]==='
896 f'{Colors.RESET}')
897 print(' ')
898 Platform.flush()
899 if options.stage == 'list':
900 hooks_stages: List[str] = PreCommit.stages()
901 print(f'{Colors.BOLD}Supported {PreCommit.TITLE} hooks stages:'
902 f'{Colors.RESET} {", ".join(hooks_stages)}')
903 else:
904 PreCommit.run(
905 all_files=True,
906 stage=options.stage,
907 )
909 # Run commitizen hooks
910 if Git.is_repository() and Git.commit_exists('HEAD'):
911 print(' ')
912 print(f'{Colors.GREEN} ===['
913 f'{Colors.YELLOW} Run hooks: '
914 f'{Colors.YELLOW_LIGHT}commitizen'
915 f'{Colors.GREEN} ]==='
916 f'{Colors.RESET}')
917 print(' ')
918 Platform.flush()
919 if Git.commit_exists('HEAD~1'):
920 Commitizen.check('HEAD~1..HEAD')
921 else:
922 Commitizen.check('HEAD')
924 # Result
925 return Entrypoint.Result.SUCCESS