ScriptCollection 3.5.84__py3-none-any.whl → 3.5.86__py3-none-any.whl

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.
@@ -379,6 +379,7 @@ def CreateChangelogEntry() -> int:
379
379
  parser.add_argument('-f', '--repositoryfolder', required=False, default=".")
380
380
  parser.add_argument('-m', '--message', required=False, default="Updates.")
381
381
  parser.add_argument('-c', '--commit', action='store_true', required=False, default=False)
382
+ parser.add_argument('-f', '--force', action='store_true', required=False, default=False)
382
383
  args = parser.parse_args()
383
384
 
384
385
  folder: str = None
@@ -386,7 +387,7 @@ def CreateChangelogEntry() -> int:
386
387
  folder = args.repositoryfolder
387
388
  else:
388
389
  folder = GeneralUtilities.resolve_relative_path(args.repositoryfolder, os.getcwd())
389
- TasksForCommonProjectStructure().create_changelog_entry(folder, args.message, args.commit)
390
+ TasksForCommonProjectStructure().create_changelog_entry(folder, args.message, args.commit, args.force)
390
391
  return 0
391
392
 
392
393
 
@@ -538,18 +539,18 @@ def Copy() -> int:
538
539
  if os.path.isfile(args.target) or os.path.isdir(args.target):
539
540
  raise ValueError(f"Can not copy to '{args.target}' because the target already exists.")
540
541
 
541
- source=args.source
542
+ source = args.source
542
543
  if not os.path.isabs(source):
543
- source=GeneralUtilities.resolve_relative_path(source,os.getcwd())
544
- target=args.target
544
+ source = GeneralUtilities.resolve_relative_path(source, os.getcwd())
545
+ target = args.target
545
546
  if not os.path.isabs(target):
546
- target=GeneralUtilities.resolve_relative_path(target,os.getcwd())
547
+ target = GeneralUtilities.resolve_relative_path(target, os.getcwd())
547
548
 
548
549
  if os.path.isfile(source):
549
550
  shutil.copyfile(source, target)
550
551
  elif os.path.isdir(source):
551
552
  GeneralUtilities.ensure_directory_exists(target)
552
- GeneralUtilities.copy_content_of_folder(source,target)
553
+ GeneralUtilities.copy_content_of_folder(source, target)
553
554
  else:
554
555
  raise ValueError(f"'{source}' can not be copied because the path does not exist.")
555
556
  return 0
@@ -575,26 +576,26 @@ def PrintCurrecntWorkingDirectory() -> int:
575
576
  def ListFolderContent() -> int:
576
577
  parser = argparse.ArgumentParser(description="This function lists folder-content.")
577
578
  parser.add_argument('-p', '--path', required=True)
578
- parser.add_argument('-f', '--excludefiles', action='store_true', required=False,default=False)
579
- parser.add_argument('-d', '--excludedirectories', action='store_true', required=False,default=False)
580
- parser.add_argument('-n', '--printonlynamewithoutpath', action='store_true', required=False,default=False)
579
+ parser.add_argument('-f', '--excludefiles', action='store_true', required=False, default=False)
580
+ parser.add_argument('-d', '--excludedirectories', action='store_true', required=False, default=False)
581
+ parser.add_argument('-n', '--printonlynamewithoutpath', action='store_true', required=False, default=False)
581
582
  # TODO add option to also list transitively list subfolder
582
583
  # TODO add option to show only content which matches a filter by extension or regex or glob-pattern
583
- args=parser.parse_args()
584
- folder=args.path
584
+ args = parser.parse_args()
585
+ folder = args.path
585
586
  if not os.path.isabs(folder):
586
- folder=GeneralUtilities.resolve_relative_path(folder,os.getcwd())
587
- content=[]
587
+ folder = GeneralUtilities.resolve_relative_path(folder, os.getcwd())
588
+ content = []
588
589
  if not args.excludefiles:
589
- content=content+GeneralUtilities.get_direct_files_of_folder(folder)
590
+ content = content+GeneralUtilities.get_direct_files_of_folder(folder)
590
591
  if not args.excludedirectories:
591
- content=content+GeneralUtilities.get_direct_folders_of_folder(folder)
592
+ content = content+GeneralUtilities.get_direct_folders_of_folder(folder)
592
593
  for contentitem in content:
593
- content_to_print:str=None
594
+ content_to_print: str = None
594
595
  if args.printonlynamewithoutpath:
595
- content_to_print=os.path.basename(contentitem)
596
+ content_to_print = os.path.basename(contentitem)
596
597
  else:
597
- content_to_print= contentitem
598
+ content_to_print = contentitem
598
599
  GeneralUtilities.write_message_to_stdout(content_to_print)
599
600
  return 0
600
601
 
@@ -32,7 +32,7 @@ from .ProgramRunnerBase import ProgramRunnerBase
32
32
  from .ProgramRunnerPopen import ProgramRunnerPopen
33
33
  from .ProgramRunnerEpew import ProgramRunnerEpew, CustomEpewArgument
34
34
 
35
- version = "3.5.84"
35
+ version = "3.5.86"
36
36
  __version__ = version
37
37
 
38
38
 
@@ -192,7 +192,7 @@ class ScriptCollectionCore:
192
192
  until_as_string = self.__datetime_to_string_for_git(until)
193
193
  result = filter(lambda line: not GeneralUtilities.string_is_none_or_whitespace(line), self.run_program("git", f'log --since "{since_as_string}" --until "{until_as_string}" --pretty=format:"%H" --no-patch', repository_folder, throw_exception_if_exitcode_is_not_zero=True)[1].split("\n").replace("\r", ""))
194
194
  if ignore_commits_which_are_not_in_history_of_head:
195
- result = [commit_id for commit_id in result if self.git_commit_is_ancestor( repository_folder, commit_id)]
195
+ result = [commit_id for commit_id in result if self.git_commit_is_ancestor(repository_folder, commit_id)]
196
196
  return result
197
197
 
198
198
  @GeneralUtilities.check_arguments
@@ -303,7 +303,7 @@ class ScriptCollectionCore:
303
303
 
304
304
  @GeneralUtilities.check_arguments
305
305
  def git_pull_with_retry(self, folder: str, remote: str, localbranchname: str, remotebranchname: str, force: bool = False, amount_of_attempts: int = 5) -> None:
306
- GeneralUtilities.retry_action(lambda: self.git_pull_with_retry(folder, remote,localbranchname,remotebranchname), amount_of_attempts)
306
+ GeneralUtilities.retry_action(lambda: self.git_pull_with_retry(folder, remote, localbranchname, remotebranchname), amount_of_attempts)
307
307
 
308
308
  @GeneralUtilities.check_arguments
309
309
  def git_pull(self, folder: str, remote: str, localbranchname: str, remotebranchname: str, force: bool = False) -> None:
@@ -381,7 +381,7 @@ class ScriptCollectionCore:
381
381
  def git_unstage_all_changes(self, directory: str) -> None:
382
382
  self.assert_is_git_repository(directory)
383
383
  self.run_program_argsasarray("git", ["reset"], directory, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)
384
- #TODO check if this will also be done for submodules
384
+ # TODO check if this will also be done for submodules
385
385
 
386
386
  @GeneralUtilities.check_arguments
387
387
  def git_stage_file(self, directory: str, file: str) -> None:
@@ -405,10 +405,10 @@ class ScriptCollectionCore:
405
405
  self.assert_is_git_repository(directory)
406
406
  self.run_program_argsasarray("git", ['clean', '-df'], directory, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)
407
407
  self.run_program_argsasarray("git", ['checkout', '.'], directory, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)
408
- #TODO check if this will also be done for submodules
408
+ # TODO check if this will also be done for submodules
409
409
 
410
410
  @GeneralUtilities.check_arguments
411
- def git_commit(self, directory: str, message: str="Saved changes.", author_name: str = None, author_email: str = None, stage_all_changes: bool = True, no_changes_behavior: int = 0) -> str:
411
+ def git_commit(self, directory: str, message: str = "Saved changes.", author_name: str = None, author_email: str = None, stage_all_changes: bool = True, no_changes_behavior: int = 0) -> str:
412
412
  """no_changes_behavior=0 => No commit; no_changes_behavior=1 => Commit anyway; no_changes_behavior=2 => Exception"""
413
413
  self.assert_is_git_repository(directory)
414
414
  author_name = GeneralUtilities.str_none_safe(author_name).strip()
@@ -448,7 +448,7 @@ class ScriptCollectionCore:
448
448
  if message is None:
449
449
  message = f"Created {target_for_tag}"
450
450
  argument.extend(["-s", '-m', message])
451
- self.run_program_argsasarray( "git", argument, directory, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)
451
+ self.run_program_argsasarray("git", argument, directory, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)
452
452
 
453
453
  @GeneralUtilities.check_arguments
454
454
  def git_delete_tag(self, directory: str, tag: str) -> None:
@@ -456,9 +456,10 @@ class ScriptCollectionCore:
456
456
  self.run_program_argsasarray("git", ["tag", "--delete", tag], directory, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)
457
457
 
458
458
  @GeneralUtilities.check_arguments
459
- def git_checkout(self, directory: str, branch: str,undo_all_changes_after_checkout:bool=True) -> None:
459
+ def git_checkout(self, directory: str, branch: str, undo_all_changes_after_checkout: bool = True, assert_no_uncommitted_changes: bool = True) -> None:
460
460
  self.assert_is_git_repository(directory)
461
- GeneralUtilities.assert_condition(self.git_repository_has_uncommitted_changes(directory),f"Repository '{directory}' has uncommitted changes..")
461
+ if assert_no_uncommitted_changes:
462
+ GeneralUtilities.assert_condition(not self.git_repository_has_uncommitted_changes(directory), f"Repository '{directory}' has uncommitted changes.")
462
463
  self.run_program_argsasarray("git", ["checkout", branch], directory, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)
463
464
  self.run_program_argsasarray("git", ["submodule", "update", "--recursive"], directory, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)
464
465
  if undo_all_changes_after_checkout:
@@ -470,9 +471,9 @@ class ScriptCollectionCore:
470
471
  self.run_program_argsasarray("git", ["merge", "--abort"], directory, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)
471
472
 
472
473
  @GeneralUtilities.check_arguments
473
- def git_merge(self, directory: str, sourcebranch: str, targetbranch: str, fastforward: bool = True, commit: bool = True, commit_message: str = None) -> str:
474
+ def git_merge(self, directory: str, sourcebranch: str, targetbranch: str, fastforward: bool = True, commit: bool = True, commit_message: str = None, undo_all_changes_after_checkout: bool = True, assert_no_uncommitted_changes: bool = True) -> str:
474
475
  self.assert_is_git_repository(directory)
475
- self.git_checkout(directory, targetbranch)
476
+ self.git_checkout(directory, targetbranch, undo_all_changes_after_checkout, assert_no_uncommitted_changes)
476
477
  args = ["merge"]
477
478
  if not commit:
478
479
  args.append("--no-commit")
@@ -662,28 +663,28 @@ class ScriptCollectionCore:
662
663
  GeneralUtilities.assert_condition(self.is_git_repository(folder), f"'{folder}' is not a git-repository.")
663
664
 
664
665
  @GeneralUtilities.check_arguments
665
- def list_content(self, path: str,include_files:bool,include_folder:bool,printonlynamewithoutpath:bool) -> list[str]:
666
+ def list_content(self, path: str, include_files: bool, include_folder: bool, printonlynamewithoutpath: bool) -> list[str]:
666
667
  """This function works platform-independent also for non-local-executions if the ScriptCollection commandline-commands are available as global command on the target-system."""
667
668
  if self.program_runner.will_be_executed_locally():
668
- result=[]
669
+ result = []
669
670
  if include_files:
670
- result=result + GeneralUtilities.get_direct_files_of_folder(path)
671
+ result = result + GeneralUtilities.get_direct_files_of_folder(path)
671
672
  if include_folder:
672
- result=result + GeneralUtilities.get_direct_folders_of_folder(path)
673
+ result = result + GeneralUtilities.get_direct_folders_of_folder(path)
673
674
  return result
674
675
  else:
675
- arguments=["--path", path]
676
+ arguments = ["--path", path]
676
677
  if not include_files:
677
- arguments=arguments+["--excludefiles"]
678
+ arguments = arguments+["--excludefiles"]
678
679
  if not include_folder:
679
- arguments=arguments+["--excludedirectories"]
680
+ arguments = arguments+["--excludedirectories"]
680
681
  if printonlynamewithoutpath:
681
- arguments=arguments+["--printonlynamewithoutpath"]
682
+ arguments = arguments+["--printonlynamewithoutpath"]
682
683
  exit_code, stdout, stderr, _ = self.run_program_argsasarray("sclistfoldercontent", arguments)
683
684
  if exit_code == 0:
684
- result:list[str]=[]
685
+ result: list[str] = []
685
686
  for line in stdout.split("\n"):
686
- normalized_line=line.replace("\r","")
687
+ normalized_line = line.replace("\r", "")
687
688
  result.append(normalized_line)
688
689
  return result
689
690
  else:
@@ -720,7 +721,7 @@ class ScriptCollectionCore:
720
721
  raise ValueError(f"Fatal error occurrs while checking whether folder '{path}' exists. StdErr: '{stderr}'")
721
722
 
722
723
  @GeneralUtilities.check_arguments
723
- def remove(self, path: str) ->None:
724
+ def remove(self, path: str) -> None:
724
725
  """This function works platform-independent also for non-local-executions if the ScriptCollection commandline-commands are available as global command on the target-system."""
725
726
  if self.program_runner.will_be_executed_locally(): # works only locally, but much more performant than always running an external program
726
727
  if os.path.isdir(path):
@@ -738,17 +739,17 @@ class ScriptCollectionCore:
738
739
  raise ValueError(f"Fatal error occurrs while removing folder '{path}'. StdErr: '{stderr}'")
739
740
 
740
741
  @GeneralUtilities.check_arguments
741
- def rename(self, source:str,target:str) ->None:
742
+ def rename(self, source: str, target: str) -> None:
742
743
  """This function works platform-independent also for non-local-executions if the ScriptCollection commandline-commands are available as global command on the target-system."""
743
744
  if self.program_runner.will_be_executed_locally(): # works only locally, but much more performant than always running an external program
744
745
  os.rename(source, target)
745
746
  else:
746
- exit_code, _, stderr, _ = self.run_program_argsasarray("screname", ["--source", source,"--target",target], throw_exception_if_exitcode_is_not_zero=False) # works platform-indepent
747
+ exit_code, _, stderr, _ = self.run_program_argsasarray("screname", ["--source", source, "--target", target], throw_exception_if_exitcode_is_not_zero=False) # works platform-indepent
747
748
  if exit_code != 0:
748
749
  raise ValueError(f"Fatal error occurrs while renaming '{source}' to '{target}'. StdErr: '{stderr}'")
749
750
 
750
751
  @GeneralUtilities.check_arguments
751
- def copy(self, source:str,target:str) ->None:
752
+ def copy(self, source: str, target: str) -> None:
752
753
  """This function works platform-independent also for non-local-executions if the ScriptCollection commandline-commands are available as global command on the target-system."""
753
754
  if self.program_runner.will_be_executed_locally(): # works only locally, but much more performant than always running an external program
754
755
  if os.path.isfile(target) or os.path.isdir(target):
@@ -757,11 +758,11 @@ class ScriptCollectionCore:
757
758
  shutil.copyfile(source, target)
758
759
  elif os.path.isdir(source):
759
760
  GeneralUtilities.ensure_directory_exists(target)
760
- GeneralUtilities.copy_content_of_folder(source,target)
761
+ GeneralUtilities.copy_content_of_folder(source, target)
761
762
  else:
762
763
  raise ValueError(f"'{source}' can not be copied because the path does not exist.")
763
764
  else:
764
- exit_code, _, stderr, _ = self.run_program_argsasarray("sccopy", ["--source", source,"--target", target], throw_exception_if_exitcode_is_not_zero=False) # works platform-indepent
765
+ exit_code, _, stderr, _ = self.run_program_argsasarray("sccopy", ["--source", source, "--target", target], throw_exception_if_exitcode_is_not_zero=False) # works platform-indepent
765
766
  if exit_code != 0:
766
767
  raise ValueError(f"Fatal error occurrs while copying '{source}' to '{target}'. StdErr: '{stderr}'")
767
768
 
@@ -1086,14 +1087,11 @@ class ScriptCollectionCore:
1086
1087
 
1087
1088
  @GeneralUtilities.check_arguments
1088
1089
  def SCShow2FAAsQRCode(self, csvfile: str) -> None:
1089
- separator_line = "--------------------------------------------------------"
1090
1090
  lines = GeneralUtilities.read_csv_file(csvfile, True)
1091
1091
  lines.sort(key=lambda items: ''.join(items).lower())
1092
1092
  for line in lines:
1093
- GeneralUtilities.write_message_to_stdout(separator_line)
1094
- self.__print_qr_code_by_csv_line(
1095
- line[0], line[1], line[2], line[3], line[4])
1096
- GeneralUtilities.write_message_to_stdout(separator_line)
1093
+ self.__print_qr_code_by_csv_line(line[0], line[1], line[2], line[3], line[4])
1094
+ GeneralUtilities.write_message_to_stdout(GeneralUtilities.get_longline())
1097
1095
 
1098
1096
  @GeneralUtilities.check_arguments
1099
1097
  def SCCalculateBitcoinBlockHash(self, block_version_number: str, previousblockhash: str, transactionsmerkleroot: str, timestamp: str, target: str, nonce: str) -> str:
@@ -1381,7 +1379,7 @@ class ScriptCollectionCore:
1381
1379
  return popen
1382
1380
 
1383
1381
  @staticmethod
1384
- def __enqueue_output(file:IO, queue:Queue):
1382
+ def __enqueue_output(file: IO, queue: Queue):
1385
1383
  for line in iter(file.readline, ''):
1386
1384
  queue.put(line)
1387
1385
  file.close()
@@ -1403,7 +1401,7 @@ class ScriptCollectionCore:
1403
1401
  return False
1404
1402
 
1405
1403
  @staticmethod
1406
- def __read_popen_pipes(p: Popen,print_live_output:bool,print_errors_as_information:bool) -> tuple[list[str], list[str]]:
1404
+ def __read_popen_pipes(p: Popen, print_live_output: bool, print_errors_as_information: bool) -> tuple[list[str], list[str]]:
1407
1405
  p_id = p.pid
1408
1406
  with ThreadPoolExecutor(2) as pool:
1409
1407
  q_stdout = Queue()
@@ -1420,8 +1418,8 @@ class ScriptCollectionCore:
1420
1418
  while (ScriptCollectionCore.__continue_process_reading(p_id, p, q_stdout, q_stderr, reading_stdout_last_time_resulted_in_exception, reading_stderr_last_time_resulted_in_exception)):
1421
1419
  try:
1422
1420
  while not q_stdout.empty():
1423
- out_line:str=q_stdout.get_nowait()
1424
- out_line=out_line.replace("\r","").replace("\n","")
1421
+ out_line: str = q_stdout.get_nowait()
1422
+ out_line = out_line.replace("\r", "").replace("\n", "")
1425
1423
  if GeneralUtilities.string_has_content(out_line):
1426
1424
  stdout_result.append(out_line)
1427
1425
  reading_stdout_last_time_resulted_in_exception = False
@@ -1434,8 +1432,8 @@ class ScriptCollectionCore:
1434
1432
 
1435
1433
  try:
1436
1434
  while not q_stderr.empty():
1437
- err_line:str=q_stderr.get_nowait()
1438
- err_line=err_line.replace("\r","").replace("\n","")
1435
+ err_line: str = q_stderr.get_nowait()
1436
+ err_line = err_line.replace("\r", "").replace("\n", "")
1439
1437
  if GeneralUtilities.string_has_content(err_line):
1440
1438
  stderr_result.append(err_line)
1441
1439
  reading_stderr_last_time_resulted_in_exception = False
@@ -1493,7 +1491,7 @@ class ScriptCollectionCore:
1493
1491
  GeneralUtilities.ensure_file_exists(log_file)
1494
1492
  pid = process.pid
1495
1493
 
1496
- outputs: tuple[list[str], list[str]] = ScriptCollectionCore.__read_popen_pipes(process,print_live_output,print_errors_as_information)
1494
+ outputs: tuple[list[str], list[str]] = ScriptCollectionCore.__read_popen_pipes(process, print_live_output, print_errors_as_information)
1497
1495
 
1498
1496
  for out_line_plain in outputs[0]:
1499
1497
  if out_line_plain is not None:
@@ -1550,8 +1548,8 @@ class ScriptCollectionCore:
1550
1548
 
1551
1549
  # Return-values program_runner: Exitcode, StdOut, StdErr, Pid
1552
1550
  @GeneralUtilities.check_arguments
1553
- def run_program_with_retry(self, program: str, arguments: str = "", working_directory: str = None, verbosity: int = 1, print_errors_as_information: bool = False, log_file: str = None, timeoutInSeconds: int = 600, addLogOverhead: bool = False, title: str = None, log_namespace: str = "", arguments_for_log: list[str] = None, throw_exception_if_exitcode_is_not_zero: bool = True, custom_argument: object = None, interactive: bool = False, print_live_output: bool = False,amount_of_attempts:int=5) -> tuple[int, str, str, int]:
1554
- return GeneralUtilities.retry_action(lambda: self.run_program(program, arguments,working_directory,verbosity,print_errors_as_information,log_file,timeoutInSeconds,addLogOverhead,title,log_namespace,arguments_for_log,throw_exception_if_exitcode_is_not_zero,custom_argument,interactive,print_live_output), amount_of_attempts)
1551
+ def run_program_with_retry(self, program: str, arguments: str = "", working_directory: str = None, verbosity: int = 1, print_errors_as_information: bool = False, log_file: str = None, timeoutInSeconds: int = 600, addLogOverhead: bool = False, title: str = None, log_namespace: str = "", arguments_for_log: list[str] = None, throw_exception_if_exitcode_is_not_zero: bool = True, custom_argument: object = None, interactive: bool = False, print_live_output: bool = False, amount_of_attempts: int = 5) -> tuple[int, str, str, int]:
1552
+ return GeneralUtilities.retry_action(lambda: self.run_program(program, arguments, working_directory, verbosity, print_errors_as_information, log_file, timeoutInSeconds, addLogOverhead, title, log_namespace, arguments_for_log, throw_exception_if_exitcode_is_not_zero, custom_argument, interactive, print_live_output), amount_of_attempts)
1555
1553
 
1556
1554
  # Return-values program_runner: Exitcode, StdOut, StdErr, Pid
1557
1555
  @GeneralUtilities.check_arguments
@@ -1851,50 +1849,47 @@ DNS = {domain}
1851
1849
  folder = os.path.dirname(csproj_file)
1852
1850
  csproj_filename = os.path.basename(csproj_file)
1853
1851
  GeneralUtilities.write_message_to_stdout(f"Check for updates in {csproj_filename}")
1854
- result = self.run_program_with_retry("dotnet", f"list {csproj_filename} package --outdated", folder,print_errors_as_information=True)
1852
+ result = self.run_program_with_retry("dotnet", f"list {csproj_filename} package --outdated", folder, print_errors_as_information=True)
1855
1853
  for line in result[1].replace("\r", "").split("\n"):
1856
1854
  # Relevant output-lines are something like " > NJsonSchema 10.7.0 10.7.0 10.9.0"
1857
1855
  if ">" in line:
1858
1856
  package_name = line.replace(">", "").strip().split(" ")[0]
1859
1857
  if not (package_name in ignored_dependencies):
1860
1858
  GeneralUtilities.write_message_to_stdout(f"Update package {package_name}...")
1861
- self.run_program("dotnet", f"add {csproj_filename} package {package_name}", folder,print_errors_as_information=True)
1862
-
1859
+ self.run_program("dotnet", f"add {csproj_filename} package {package_name}", folder, print_errors_as_information=True)
1863
1860
 
1864
1861
  @GeneralUtilities.check_arguments
1865
- def dotnet_package_is_available(self,package_name:str,package_version:str,source:str):
1866
- default_source_address="nuget.org"
1867
- if source==default_source_address:
1862
+ def dotnet_package_is_available(self, package_name: str, package_version: str, source: str):
1863
+ default_source_address = "nuget.org"
1864
+ if source == default_source_address:
1868
1865
  GeneralUtilities.write_message_to_stdout(f"Wait until package {package_name} v{package_version} is available on {source}.")
1869
1866
  headers = {'Cache-Control': 'no-cache'}
1870
- r=requests.get(f"https://api.{default_source_address}/v3-flatcontainer/{package_name.lower()}/{package_version}/{package_name.lower()}.nuspec", timeout=5,headers=headers)
1871
- return r.status_code==200
1867
+ r = requests.get(f"https://api.{default_source_address}/v3-flatcontainer/{package_name.lower()}/{package_version}/{package_name.lower()}.nuspec", timeout=5, headers=headers)
1868
+ return r.status_code == 200
1872
1869
  else:
1873
1870
  raise ValueError(f"dotnet_package_is_available is not implemented yet for other sources than {default_source_address}.")
1874
1871
 
1875
1872
  @GeneralUtilities.check_arguments
1876
- def wait_until_dotnet_package_is_available(self,package_name:str,package_version:str,source:str):
1877
- while not self.dotnet_package_is_available(package_name,package_version,source):
1873
+ def wait_until_dotnet_package_is_available(self, package_name: str, package_version: str, source: str):
1874
+ while not self.dotnet_package_is_available(package_name, package_version, source):
1878
1875
  time.sleep(5)
1879
1876
 
1880
-
1881
1877
  @GeneralUtilities.check_arguments
1882
- def python_package_is_available(self,package_name:str,package_version:str,source:str):
1883
- default_source_address="pypi.org"
1884
- if source==default_source_address:
1878
+ def python_package_is_available(self, package_name: str, package_version: str, source: str):
1879
+ default_source_address = "pypi.org"
1880
+ if source == default_source_address:
1885
1881
  GeneralUtilities.write_message_to_stdout(f"Wait until package {package_name} v{package_version} is available on {source}.")
1886
1882
  headers = {'Cache-Control': 'no-cache'}
1887
- r=requests.get(f"https://{default_source_address}/pypi/{package_name}/{package_version}/json", timeout=5,headers=headers)
1888
- return r.status_code==200
1883
+ r = requests.get(f"https://{default_source_address}/pypi/{package_name}/{package_version}/json", timeout=5, headers=headers)
1884
+ return r.status_code == 200
1889
1885
  else:
1890
1886
  raise ValueError(f"python_package_is_available is not implemented yet for other sources than {default_source_address}.")
1891
1887
 
1892
1888
  @GeneralUtilities.check_arguments
1893
- def wait_until_python_package_is_available(self,package_name:str,package_version:str,source:str):
1894
- while not self.python_package_is_available(package_name,package_version,source):
1889
+ def wait_until_python_package_is_available(self, package_name: str, package_version: str, source: str):
1890
+ while not self.python_package_is_available(package_name, package_version, source):
1895
1891
  time.sleep(5)
1896
1892
 
1897
-
1898
1893
  @GeneralUtilities.check_arguments
1899
1894
  def create_deb_package(self, toolname: str, binary_folder: str, control_file_content: str, deb_output_folder: str, verbosity: int, permission_of_executable_file_as_octet_triple: int) -> None:
1900
1895
 
@@ -1018,7 +1018,7 @@ class TasksForCommonProjectStructure:
1018
1018
  target_folder_base = os.path.join(information.artifacts_folder, information.projectname, project_version)
1019
1019
  GeneralUtilities.ensure_directory_exists(target_folder_base)
1020
1020
 
1021
- self.build_codeunits(information.repository, information.verbosity, information.target_environmenttype_for_productive, information.additional_arguments_file, False, information.export_target, [], True, "Generate artifacts")# Generate artifacts after merge (because now are constants like commit-id of the new version available)
1021
+ self.build_codeunits(information.repository, information.verbosity, information.target_environmenttype_for_productive, information.additional_arguments_file, False, information.export_target, [], True, "Generate artifacts") # Generate artifacts after merge (because now are constants like commit-id of the new version available)
1022
1022
 
1023
1023
  reference_folder = os.path.join(information.reference_repository, "ReferenceContent")
1024
1024
 
@@ -1252,7 +1252,7 @@ class TasksForCommonProjectStructure:
1252
1252
 
1253
1253
  self.__sc.git_checkout(repository_folder, source_branch)
1254
1254
  self.build_codeunits(repository_folder, verbosity, TasksForCommonProjectStructure.get_qualitycheck_environment_name(), additional_arguments_file, True, None, [], True, "Check if product is buildable")
1255
- self.__sc.git_merge(repository_folder, source_branch, target_branch, False, False, None)
1255
+ self.__sc.git_merge(repository_folder, source_branch, target_branch, False, False, None, False, False)
1256
1256
  self.__sc.git_commit(repository_folder, f'Merge branch {source_branch} into {target_branch}', stage_all_changes=True, no_changes_behavior=1)
1257
1257
  self.__sc.git_checkout(repository_folder, target_branch)
1258
1258
  if fast_forward_source_branch:
@@ -1300,8 +1300,8 @@ class TasksForCommonProjectStructure:
1300
1300
  # hint: arguments can be overwritten by commandline_arguments
1301
1301
  folder_of_this_file = os.path.dirname(create_release_file)
1302
1302
  verbosity = TasksForCommonProjectStructure.get_verbosity_from_commandline_arguments(commandline_arguments, verbosity)
1303
- result=self.__sc.run_program("python", f"CreateRelease.py --overwrite_verbosity {str(verbosity)}", folder_of_this_file, verbosity=verbosity, log_file=logfile, addLogOverhead=addLogOverhead,print_live_output=True,throw_exception_if_exitcode_is_not_zero=False)
1304
- if result[0]!=0:
1303
+ result = self.__sc.run_program("python", f"CreateRelease.py --overwrite_verbosity {str(verbosity)}", folder_of_this_file, verbosity=verbosity, log_file=logfile, addLogOverhead=addLogOverhead, print_live_output=True, throw_exception_if_exitcode_is_not_zero=False)
1304
+ if result[0] != 0:
1305
1305
  raise ValueError(f"CreateRelease.py resulted in exitcode {result[0]}.")
1306
1306
 
1307
1307
  @GeneralUtilities.check_arguments
@@ -1315,7 +1315,7 @@ class TasksForCommonProjectStructure:
1315
1315
  self.__sc.run_program("git", "clean -dfx", information.repository, verbosity=information.verbosity, throw_exception_if_exitcode_is_not_zero=True)
1316
1316
  project_version = self.__sc.get_semver_version_from_gitversion(information.repository)
1317
1317
 
1318
- self.build_codeunits(information.repository, information.verbosity, information.target_environmenttype_for_qualitycheck, information.additional_arguments_file, False, information.export_target, [], True, "Productive build")#verify hat codeunits are buildable with productive-config before merge
1318
+ self.build_codeunits(information.repository, information.verbosity, information.target_environmenttype_for_qualitycheck, information.additional_arguments_file, False, information.export_target, [], True, "Productive build") # verify hat codeunits are buildable with productive-config before merge
1319
1319
 
1320
1320
  self.assert_no_uncommitted_changes(information.repository)
1321
1321
 
@@ -2445,11 +2445,11 @@ class TasksForCommonProjectStructure:
2445
2445
  self.__sc.assert_is_git_repository(repository_folder)
2446
2446
  repository_folder = GeneralUtilities.resolve_relative_path_from_current_working_directory(repository_folder)
2447
2447
  codeunits = self.get_codeunits(repository_folder, False)
2448
- self.build_specific_codeunits(repository_folder, codeunits, verbosity, target_environmenttype, additional_arguments_file, is_pre_merge, export_target_directory, False, commandline_arguments, do_git_clean_when_no_changes,note)
2448
+ self.build_specific_codeunits(repository_folder, codeunits, verbosity, target_environmenttype, additional_arguments_file, is_pre_merge, export_target_directory, False, commandline_arguments, do_git_clean_when_no_changes, note)
2449
2449
 
2450
2450
  @GeneralUtilities.check_arguments
2451
2451
  def build_specific_codeunits(self, repository_folder: str, codeunits: list[str], verbosity: int = 1, target_environmenttype: str = "QualityCheck", additional_arguments_file: str = None, is_pre_merge: bool = False, export_target_directory: str = None, assume_dependent_codeunits_are_already_built: bool = True, commandline_arguments: list[str] = [], do_git_clean_when_no_changes: bool = False, note: str = None) -> None:
2452
- if verbosity>2:
2452
+ if verbosity > 2:
2453
2453
  GeneralUtilities.write_message_to_stdout(f"Start building codeunits for repository '{repository_folder}'...")
2454
2454
  self.__sc.assert_is_git_repository(repository_folder)
2455
2455
  self.__check_target_environmenttype(target_environmenttype)
@@ -2470,8 +2470,8 @@ class TasksForCommonProjectStructure:
2470
2470
  prepare_build_codeunits_scripts = os.path.join(project_resources_folder, PrepareBuildCodeunits_script_name)
2471
2471
  if os.path.isfile(prepare_build_codeunits_scripts):
2472
2472
  GeneralUtilities.write_message_to_stdout(f'Run "{PrepareBuildCodeunits_script_name}"')
2473
- result=self.__sc.run_program("python", f"{PrepareBuildCodeunits_script_name}", project_resources_folder,throw_exception_if_exitcode_is_not_zero=False, print_live_output=True)
2474
- if result[0]!=0:
2473
+ result = self.__sc.run_program("python", f"{PrepareBuildCodeunits_script_name}", project_resources_folder, throw_exception_if_exitcode_is_not_zero=False, print_live_output=True)
2474
+ if result[0] != 0:
2475
2475
  raise ValueError(f"PrepareBuildCodeunits.py resulted in exitcode {result[0]}.")
2476
2476
 
2477
2477
  for subfolder in subfolders:
@@ -2903,7 +2903,7 @@ class TasksForCommonProjectStructure:
2903
2903
  # update dependencies of resources
2904
2904
  global_scripts_folder = os.path.join(repository_folder, "Other", "Scripts")
2905
2905
  if os.path.isfile(os.path.join(global_scripts_folder, update_dependencies_script_filename)):
2906
- self.__sc.run_program("python", update_dependencies_script_filename, global_scripts_folder,print_live_output=True)
2906
+ self.__sc.run_program("python", update_dependencies_script_filename, global_scripts_folder, print_live_output=True)
2907
2907
 
2908
2908
  # update dependencies of codeunits
2909
2909
  for codeunit in codeunits:
@@ -2913,7 +2913,7 @@ class TasksForCommonProjectStructure:
2913
2913
  codeunit_folder = os.path.join(repository_folder, codeunit)
2914
2914
  update_dependencies_script_folder = os.path.join(codeunit_folder, "Other")
2915
2915
  GeneralUtilities.ensure_directory_exists(os.path.join(update_dependencies_script_folder, "Resources", "CodeAnalysisResult"))
2916
- self.__sc.run_program("python", update_dependencies_script_filename, update_dependencies_script_folder, verbosity,print_live_output=True)
2916
+ self.__sc.run_program("python", update_dependencies_script_filename, update_dependencies_script_folder, verbosity, print_live_output=True)
2917
2917
  if self.__sc.git_repository_has_uncommitted_changes(repository_folder):
2918
2918
  version_of_project = self.get_version_of_project(repository_folder)
2919
2919
  changelog_file = os.path.join(repository_folder, "Other", "Resources", "Changelog", f"v{version_of_project}.md")
@@ -2961,9 +2961,13 @@ class TasksForCommonProjectStructure:
2961
2961
  # prepare
2962
2962
  self.assert_no_uncommitted_changes(repository_folder)
2963
2963
  self.assert_no_uncommitted_changes(reference_folder)
2964
- self.__sc.git_checkout(repository_folder, merge_source_branch)
2964
+ self.assert_no_uncommitted_changes(build_repository_folder)
2965
+ self.__sc.git_checkout(repository_folder, merge_source_branch, True)
2966
+ self.__sc.git_checkout(reference_folder, "main", True)
2967
+ self.__sc.git_checkout(build_repository_folder, "main", True)
2965
2968
  self.assert_no_uncommitted_changes(repository_folder)
2966
2969
  self.assert_no_uncommitted_changes(reference_folder)
2970
+ self.__sc.git_commit(build_repository_folder, "Updated submodules")
2967
2971
 
2968
2972
  if "--dependencyupdate" in generic_prepare_new_release_arguments.commandline_arguments:
2969
2973
  self.generic_update_dependencies(repository_folder)
@@ -2985,7 +2989,6 @@ class TasksForCommonProjectStructure:
2985
2989
  self.__sc.git_commit(build_repository_folder, "Updated submodule due to merge to main-branch.")
2986
2990
  GeneralUtilities.write_message_to_stdout(f"Finished prepare release for {generic_prepare_new_release_arguments.product_name}.")
2987
2991
 
2988
-
2989
2992
  class GenericCreateReleaseArguments():
2990
2993
  current_file: str
2991
2994
  product_name: str
@@ -3025,6 +3028,7 @@ class TasksForCommonProjectStructure:
3025
3028
  self.__sc.git_checkout(repository_folder, merge_source_branch)
3026
3029
  reference_repo: str = os.path.join(build_repository_folder, "Submodules", f"{generic_create_release_arguments.product_name}Reference")
3027
3030
  self.__sc.git_commit(reference_repo, "Updated reference")
3031
+ self.__sc.git_push_with_retry(reference_repo, generic_create_release_arguments.common_remote_name, "main", "main")
3028
3032
  self.__sc.git_commit(build_repository_folder, "Updated submodule")
3029
3033
 
3030
3034
  # create release
@@ -3051,8 +3055,11 @@ class TasksForCommonProjectStructure:
3051
3055
  self.main_branch_name = "main"
3052
3056
 
3053
3057
  @GeneralUtilities.check_arguments
3054
- def create_changelog_entry(self, repositoryfolder: str, message: str, commit: bool):
3058
+ def create_changelog_entry(self, repositoryfolder: str, message: str, commit: bool, force: bool):
3055
3059
  self.__sc.assert_is_git_repository(repositoryfolder)
3060
+ random_file = os.path.join(repositoryfolder, str(uuid.uuid4()))
3061
+ if force and not self.__sc.git_repository_has_uncommitted_changes(repositoryfolder):
3062
+ GeneralUtilities.ensure_file_exists(random_file)
3056
3063
  current_version = self.get_version_of_project(repositoryfolder)
3057
3064
  changelog_file = os.path.join(repositoryfolder, "Other", "Resources", "Changelog", f"v{current_version}.md")
3058
3065
  if os.path.isdir(changelog_file):
@@ -3065,6 +3072,9 @@ class TasksForCommonProjectStructure:
3065
3072
 
3066
3073
  - {message}
3067
3074
  """)
3075
+ GeneralUtilities.ensure_file_does_not_exist(random_file)
3076
+ if commit:
3077
+ self.__sc.git_commit(repositoryfolder, f"Added changelog-file for v{current_version}.")
3068
3078
 
3069
3079
  @GeneralUtilities.check_arguments
3070
3080
  def update_http_documentation(self, update_http_documentation_arguments: UpdateHTTPDocumentationArguments):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: ScriptCollection
3
- Version: 3.5.84
3
+ Version: 3.5.86
4
4
  Summary: The ScriptCollection is the place for reusable scripts.
5
5
  Home-page: https://github.com/anionDev/ScriptCollection
6
6
  Author: Marius Göcke
@@ -24,7 +24,7 @@ Requires-Python: >=3.10
24
24
  Description-Content-Type: text/markdown
25
25
  Requires-Dist: build>=1.2.2.post1
26
26
  Requires-Dist: coverage>=7.6.12
27
- Requires-Dist: cyclonedx-bom>=5.2.0
27
+ Requires-Dist: cyclonedx-bom>=5.3.0
28
28
  Requires-Dist: defusedxml>=0.7.1
29
29
  Requires-Dist: keyboard>=0.13.5
30
30
  Requires-Dist: lcov-cobertura>=2.1.1
@@ -1,16 +1,16 @@
1
- ScriptCollection/Executables.py,sha256=KAs82A9AsrpTY39Ohg1UrtZN-6e5_Ql17UbLlO0fZfA,30037
1
+ ScriptCollection/Executables.py,sha256=XwnhziKm3HdsJNkvj2TCTf-KS2e4RKibpNcNTZOHFJ4,30175
2
2
  ScriptCollection/GeneralUtilities.py,sha256=VVbbGFD4qLwWV211-E-n3faP2fZGc8mOBlKLd0oKHl4,40765
3
3
  ScriptCollection/ProcessesRunner.py,sha256=3mu4ZxzZleQo0Op6o9EYTCFiJfb6kx5ov2YfZfT89mU,1395
4
4
  ScriptCollection/ProgramRunnerBase.py,sha256=2kMIAqdc65UjBAddOZkzy_aFx9h5roZ5a4bQNM6RV6Y,2480
5
5
  ScriptCollection/ProgramRunnerEpew.py,sha256=4pjEd0r9Fcz3TTDv0MdTSd5KkigYXcWUVI1X43regfU,6477
6
6
  ScriptCollection/ProgramRunnerPopen.py,sha256=BPY7-ZMIlqT7JOKz8qlB5c0laF2Js-ijzqk09GxZC48,3821
7
7
  ScriptCollection/RPStream.py,sha256=NRRHL3YSP3D9MuAV2jB_--0KUKCsvJGxeKnxgrRZ9kY,1545
8
- ScriptCollection/ScriptCollectionCore.py,sha256=0W4WdCHN8FXmZbrdEWirYschKwJkFqdPNvWw2dwLG6c,123057
9
- ScriptCollection/TasksForCommonProjectStructure.py,sha256=n6og3gADK7oBd5_9F-XNKVlQ0bO9EL7irdOSJAh-Vtc,215940
8
+ ScriptCollection/ScriptCollectionCore.py,sha256=QsyoePkvnrP1DpEy0V5wiOHewiim649hlPR0uQN5fJw,123286
9
+ ScriptCollection/TasksForCommonProjectStructure.py,sha256=0G2onG2crhkn3ivRqfVtHcg9WgwRXT488X0zEy8CSe4,216807
10
10
  ScriptCollection/UpdateCertificates.py,sha256=Eynbgu7k9jLxApP2D_8Il77B6BFjJap6K7oTeEAZYbk,7790
11
11
  ScriptCollection/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
- ScriptCollection-3.5.84.dist-info/METADATA,sha256=xs5tu_QAF5oTpfKaQI9fQP_9n5REeh8yXqh8lH4_5-k,7664
13
- ScriptCollection-3.5.84.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
14
- ScriptCollection-3.5.84.dist-info/entry_points.txt,sha256=1jAL5AuB8mvdw2v-6E7wCZFThurQxchiQynL8DCi-Yg,3545
15
- ScriptCollection-3.5.84.dist-info/top_level.txt,sha256=hY2hOVH0V0Ce51WB76zKkIWTUNwMUdHo4XDkR2vYVwg,17
16
- ScriptCollection-3.5.84.dist-info/RECORD,,
12
+ scriptcollection-3.5.86.dist-info/METADATA,sha256=JSg4iWzozzhdD_I0svPAbfBywMaZYuum13ycscoCcdk,7664
13
+ scriptcollection-3.5.86.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
14
+ scriptcollection-3.5.86.dist-info/entry_points.txt,sha256=1jAL5AuB8mvdw2v-6E7wCZFThurQxchiQynL8DCi-Yg,3545
15
+ scriptcollection-3.5.86.dist-info/top_level.txt,sha256=hY2hOVH0V0Ce51WB76zKkIWTUNwMUdHo4XDkR2vYVwg,17
16
+ scriptcollection-3.5.86.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.8.0)
2
+ Generator: setuptools (75.8.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5