ScriptCollection 3.5.93__py3-none-any.whl → 3.5.95__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.
@@ -12,6 +12,7 @@ import math
12
12
  import os
13
13
  from queue import Queue, Empty
14
14
  from concurrent.futures import ThreadPoolExecutor
15
+ import xml.etree.ElementTree as ET
15
16
  from pathlib import Path
16
17
  from subprocess import Popen
17
18
  import re
@@ -32,7 +33,7 @@ from .ProgramRunnerBase import ProgramRunnerBase
32
33
  from .ProgramRunnerPopen import ProgramRunnerPopen
33
34
  from .ProgramRunnerEpew import ProgramRunnerEpew, CustomEpewArgument
34
35
 
35
- version = "3.5.93"
36
+ version = "3.5.95"
36
37
  __version__ = version
37
38
 
38
39
 
@@ -2052,7 +2053,7 @@ chmod {permission} {link_file}
2052
2053
  if productname is None:
2053
2054
  productname = os.path.basename(repository)
2054
2055
  if subfolder is None:
2055
- subfolder = "Other/Resources/Reference"
2056
+ subfolder = "Other/Reference"
2056
2057
  reference_root_folder = f"{repository}/{subfolder}"
2057
2058
  reference_content_folder = reference_root_folder + "/Technical"
2058
2059
  if os.path.isdir(reference_root_folder):
@@ -2152,7 +2153,6 @@ TXDX
2152
2153
  - [Repository](TXDX)
2153
2154
  - [Productive-System](TXDX)
2154
2155
  - [QualityCheck-system](TXDX)
2155
-
2156
2156
  """.replace("XDX", "ODO"))
2157
2157
 
2158
2158
  @GeneralUtilities.check_arguments
@@ -2242,3 +2242,10 @@ TXDX
2242
2242
  raise ValueError(f"Folder '{folder}' does not exist.")
2243
2243
 
2244
2244
  GeneralUtilities.ensure_directory_exists(path)
2245
+
2246
+ @GeneralUtilities.check_arguments
2247
+ def format_xml_file(self, file: str) -> None:
2248
+ encoding = "utf-8"
2249
+ element = ET.XML(GeneralUtilities.read_text_from_file(file, encoding))
2250
+ ET.indent(element)
2251
+ GeneralUtilities.write_text_to_file(file, ET.tostring(element, encoding="unicode"), encoding)
@@ -307,6 +307,7 @@ class TasksForCommonProjectStructure:
307
307
  @GeneralUtilities.check_arguments
308
308
  def generate_bom_for_python_project(self, verbosity: int, codeunit_folder: str, codeunitname: str, commandline_arguments: list[str]) -> None:
309
309
  self.assert_is_codeunit_folder(codeunit_folder)
310
+ repository_folder = os.path.dirname(codeunit_folder)
310
311
  verbosity = TasksForCommonProjectStructure.get_verbosity_from_commandline_arguments(commandline_arguments, verbosity)
311
312
  codeunitversion = self.get_version_of_codeunit_folder(codeunit_folder)
312
313
  bom_folder = "Other/Artifacts/BOM"
@@ -316,9 +317,20 @@ class TasksForCommonProjectStructure:
316
317
  raise ValueError(f"Codeunit {codeunitname} does not have a 'requirements.txt'-file.")
317
318
  # TODO check that all values from setup.cfg are contained in requirements.txt
318
319
  result = self.__sc.run_program("cyclonedx-py", "requirements", codeunit_folder, verbosity=verbosity)
319
- bom_file = os.path.join(codeunit_folder, f"{bom_folder}/{codeunitname}.{codeunitversion}.bom.json")
320
- GeneralUtilities.ensure_file_exists(bom_file)
321
- GeneralUtilities.write_text_to_file(bom_file, result[1])
320
+ bom_file_relative_json = f"{bom_folder}/{codeunitname}.{codeunitversion}.bom.json"
321
+ bom_file_relative_xml = f"{bom_folder}/{codeunitname}.{codeunitversion}.bom.xml"
322
+ bom_file_json = os.path.join(codeunit_folder, bom_file_relative_json)
323
+ bom_file_xml = os.path.join(codeunit_folder, bom_file_relative_xml)
324
+
325
+ GeneralUtilities.ensure_file_exists(bom_file_json)
326
+ GeneralUtilities.write_text_to_file(bom_file_json, result[1])
327
+ self.ensure_cyclonedxcli_is_available(repository_folder)
328
+ cyclonedx_exe = os.path.join(repository_folder, "Other/Resources/CycloneDXCLI/cyclonedx-cli")
329
+ if GeneralUtilities.current_system_is_windows():
330
+ cyclonedx_exe = cyclonedx_exe+".exe"
331
+ self.__sc.run_program(cyclonedx_exe, f"convert --input-file ./{codeunitname}/{bom_file_relative_json} --input-format json --output-file ./{codeunitname}/{bom_file_relative_xml} --output-format xml", repository_folder)
332
+ self.__sc.format_xml_file(bom_file_xml)
333
+ GeneralUtilities.ensure_file_does_not_exist(bom_file_json)
322
334
 
323
335
  @GeneralUtilities.check_arguments
324
336
  def standardized_tasks_push_wheel_file_to_registry(self, wheel_file: str, api_key: str, repository: str, gpg_identity: str, verbosity: int) -> None:
@@ -759,7 +771,7 @@ class TasksForCommonProjectStructure:
759
771
  target = f"{codeunit_folder}\\{bomfile_folder}\\{codeunit_name}.{codeunitversion}.sbom.xml"
760
772
  GeneralUtilities.ensure_file_does_not_exist(target)
761
773
  os.rename(f"{codeunit_folder}\\{bomfile_folder}\\bom.xml", target)
762
- # TODO format the sbom.xml-file
774
+ self.__sc.format_xml_file(target)
763
775
 
764
776
  @GeneralUtilities.check_arguments
765
777
  def standardized_tasks_run_linting_for_flutter_project_in_common_project_structure(self, script_file: str, default_verbosity: int, args: list[str]):
@@ -1348,25 +1360,29 @@ class TasksForCommonProjectStructure:
1348
1360
  repository_folder = GeneralUtilities.resolve_relative_path("..", codeunit_folder)
1349
1361
  dependent_codeunit_folder = os.path.join(repository_folder, dependent_codeunit_name).replace("\\", "/")
1350
1362
  t = TasksForCommonProjectStructure()
1351
- sbom_file = f"{codeunitname}/Other/Artifacts/BOM/{codeunitname}.{t.get_version_of_codeunit_folder(codeunit_folder)}.sbom.xml"
1352
- dependent_sbom_file = f"{dependent_codeunit_name}/Other/Artifacts/BOM/{dependent_codeunit_name}.{t.get_version_of_codeunit_folder(dependent_codeunit_folder)}.sbom.xml"
1363
+ sbom_file = f"{repository_folder}/{codeunitname}/Other/Artifacts/BOM/{codeunitname}.{t.get_version_of_codeunit_folder(codeunit_folder)}.sbom.xml"
1364
+ dependent_sbom_file = f"{repository_folder}/{dependent_codeunit_name}/Other/Artifacts/BOM/{dependent_codeunit_name}.{t.get_version_of_codeunit_folder(dependent_codeunit_folder)}.sbom.xml"
1353
1365
  self.merge_sbom_file(repository_folder, dependent_sbom_file, sbom_file)
1354
1366
 
1355
1367
  @GeneralUtilities.check_arguments
1356
- def merge_sbom_file(self, repository_folder: str, source_sbom_file: str, target_sbom_file: str) -> None:
1357
- GeneralUtilities.assert_file_exists(os.path.join(repository_folder, source_sbom_file))
1358
- GeneralUtilities.assert_file_exists(os.path.join(repository_folder, target_sbom_file))
1359
- target_original_sbom_file = os.path.dirname(target_sbom_file)+"/"+os.path.basename(target_sbom_file)+".original.xml"
1360
- os.rename(os.path.join(repository_folder, target_sbom_file), os.path.join(repository_folder, target_original_sbom_file))
1361
- ScriptCollectionCore().run_program("docker", f"run --rm -v {repository_folder}:/Repository cyclonedx/cyclonedx-cli merge --input-files /Repository/{source_sbom_file} /Repository/{target_original_sbom_file} --output-file /Repository/{target_sbom_file}")
1362
- GeneralUtilities.ensure_file_does_not_exist(os.path.join(repository_folder, target_original_sbom_file))
1363
- # TODO format the sbom.xml-file
1368
+ def merge_sbom_file(self, repository_folder: str, source_sbom_file_relative: str, target_sbom_file_relative: str) -> None:
1369
+ GeneralUtilities.assert_file_exists(os.path.join(repository_folder, source_sbom_file_relative))
1370
+ GeneralUtilities.assert_file_exists(os.path.join(repository_folder, target_sbom_file_relative))
1371
+ target_original_sbom_file_relative = os.path.dirname(target_sbom_file_relative)+"/"+os.path.basename(target_sbom_file_relative)+".original.xml"
1372
+ os.rename(os.path.join(repository_folder, target_sbom_file_relative), os.path.join(repository_folder, target_original_sbom_file_relative))
1373
+
1374
+ self.ensure_cyclonedxcli_is_available(repository_folder)
1375
+ cyclonedx_exe = os.path.join(repository_folder, "Other/Resources/CycloneDXCLI/cyclonedx-cli")
1376
+ if GeneralUtilities.current_system_is_windows():
1377
+ cyclonedx_exe = cyclonedx_exe+".exe"
1378
+ self.__sc.run_program(cyclonedx_exe, f"merge --input-files {source_sbom_file_relative} {target_original_sbom_file_relative} --output-file {target_sbom_file_relative}", repository_folder)
1379
+ GeneralUtilities.ensure_file_does_not_exist(os.path.join(repository_folder, target_original_sbom_file_relative))
1380
+ self.__sc.format_xml_file(os.path.join(repository_folder, target_sbom_file_relative))
1364
1381
 
1365
1382
  @GeneralUtilities.check_arguments
1366
1383
  def standardized_tasks_build_for_docker_project_with_additional_build_arguments(self, build_script_file: str, target_environment_type: str, verbosity: int, commandline_arguments: list[str], custom_arguments: dict[str, str]) -> None:
1367
1384
  use_cache: bool = False
1368
1385
  verbosity = TasksForCommonProjectStructure.get_verbosity_from_commandline_arguments(commandline_arguments, verbosity)
1369
- sc: ScriptCollectionCore = ScriptCollectionCore()
1370
1386
  codeunitname: str = Path(os.path.dirname(build_script_file)).parent.parent.name
1371
1387
  codeunit_folder = GeneralUtilities.resolve_relative_path("../..", str(os.path.dirname(build_script_file)))
1372
1388
  codeunitname_lower = codeunitname.lower()
@@ -1381,7 +1397,7 @@ class TasksForCommonProjectStructure:
1381
1397
  args.append("--no-cache")
1382
1398
  args.append(".")
1383
1399
  codeunit_content_folder = os.path.join(codeunit_folder)
1384
- sc.run_program_argsasarray("docker", args, codeunit_content_folder, verbosity=verbosity, print_errors_as_information=True)
1400
+ self.__sc.run_program_argsasarray("docker", args, codeunit_content_folder, verbosity=verbosity, print_errors_as_information=True)
1385
1401
  artifacts_folder = GeneralUtilities.resolve_relative_path("Other/Artifacts", codeunit_folder)
1386
1402
  app_artifacts_folder = os.path.join(artifacts_folder, "BuildResult_OCIImage")
1387
1403
  GeneralUtilities.ensure_directory_does_not_exist(app_artifacts_folder)
@@ -1400,7 +1416,7 @@ class TasksForCommonProjectStructure:
1400
1416
  codeunitversion = self.get_version_of_codeunit(os.path.join(codeunit_folder, f"{codeunitname}.codeunit.xml"))
1401
1417
  GeneralUtilities.ensure_directory_exists(sbom_folder)
1402
1418
  self.__sc.run_program_argsasarray("docker", ["sbom", "--format", "cyclonedx", f"{codeunitname_lower}:{codeunitversion}", "--output", f"{codeunitname}.{codeunitversion}.sbom.xml"], sbom_folder, verbosity=verbosity, print_errors_as_information=True)
1403
- # TODO format the sbom.xml-file
1419
+ self.__sc.format_xml_file(sbom_folder+f"/{codeunitname}.{codeunitversion}.sbom.xml")
1404
1420
 
1405
1421
  @GeneralUtilities.check_arguments
1406
1422
  def push_docker_build_artifact(self, push_artifacts_file: str, registry: str, verbosity: int, push_readme: bool, commandline_arguments: list[str], repository_folder_name: str) -> None:
@@ -1470,8 +1486,8 @@ class TasksForCommonProjectStructure:
1470
1486
  @GeneralUtilities.check_arguments
1471
1487
  def standardized_tasks_do_common_tasks(self, common_tasks_scripts_file: str, codeunit_version: str, verbosity: int, targetenvironmenttype: str, clear_artifacts_folder: bool, additional_arguments_file: str, assume_dependent_codeunits_are_already_built: bool, commandline_arguments: list[str]) -> None:
1472
1488
  additional_arguments_file = self.get_additionalargumentsfile_from_commandline_arguments(commandline_arguments, additional_arguments_file)
1473
- target_environmenttype = self.get_targetenvironmenttype_from_commandline_arguments(commandline_arguments, targetenvironmenttype)
1474
- assume_dependent_codeunits_are_already_built = self.get_assume_dependent_codeunits_are_already_built_from_commandline_arguments(commandline_arguments, assume_dependent_codeunits_are_already_built)
1489
+ target_environmenttype = self.get_targetenvironmenttype_from_commandline_arguments(commandline_arguments, targetenvironmenttype)#pylint: disable=unused-variable
1490
+ # assume_dependent_codeunits_are_already_built = self.get_assume_dependent_codeunits_are_already_built_from_commandline_arguments(commandline_arguments, assume_dependent_codeunits_are_already_built)
1475
1491
  if commandline_arguments is None:
1476
1492
  raise ValueError('The "commandline_arguments"-parameter is not defined.')
1477
1493
  if len(commandline_arguments) == 0:
@@ -1571,8 +1587,8 @@ class TasksForCommonProjectStructure:
1571
1587
  GeneralUtilities.ensure_directory_does_not_exist(artifacts_folder)
1572
1588
 
1573
1589
  # Get artifacts from dependent codeunits
1574
- if assume_dependent_codeunits_are_already_built:
1575
- self.build_dependent_code_units(repository_folder, codeunit_name, verbosity, target_environmenttype, additional_arguments_file, commandline_arguments)
1590
+ # if assume_dependent_codeunits_are_already_built:
1591
+ # self.build_dependent_code_units(repository_folder, codeunit_name, verbosity, target_environmenttype, additional_arguments_file, commandline_arguments)
1576
1592
  self.copy_artifacts_from_dependent_code_units(repository_folder, codeunit_name)
1577
1593
 
1578
1594
  # Update codeunit-version
@@ -1730,8 +1746,9 @@ class TasksForCommonProjectStructure:
1730
1746
  def standardized_tasks_build_bom_for_node_project(self, codeunit_folder: str, verbosity: int, commandline_arguments: list[str]) -> None:
1731
1747
  self.assert_is_codeunit_folder(codeunit_folder)
1732
1748
  verbosity = TasksForCommonProjectStructure.get_verbosity_from_commandline_arguments(commandline_arguments, verbosity)
1733
- self.run_with_epew("cyclonedx-npm", f"--output-format xml --output-file Other/Artifacts/BOM/{os.path.basename(codeunit_folder)}.{self.get_version_of_codeunit_folder(codeunit_folder)}.sbom.xml", codeunit_folder, verbosity=verbosity)
1734
- # TODO format the sbom.xml-file
1749
+ relative_path_to_bom_file = f"Other/Artifacts/BOM/{os.path.basename(codeunit_folder)}.{self.get_version_of_codeunit_folder(codeunit_folder)}.sbom.xml"
1750
+ self.run_with_epew("cyclonedx-npm", f"--output-format xml --output-file {relative_path_to_bom_file}", codeunit_folder, verbosity=verbosity)
1751
+ self.__sc.format_xml_file(codeunit_folder+"/"+relative_path_to_bom_file)
1735
1752
 
1736
1753
  @GeneralUtilities.check_arguments
1737
1754
  def standardized_tasks_linting_for_angular_codeunit(self, linting_script_file: str, verbosity: int, build_environment_target_type: str, commandline_arguments: list[str]) -> None:
@@ -2333,6 +2350,7 @@ class TasksForCommonProjectStructure:
2333
2350
  command_with_args = f"{command_with_args} {{{{.CLI_ARGS}}}}"
2334
2351
  lines.append(f" {name}:")
2335
2352
  lines.append(f' desc: "{description}"')
2353
+ lines.append(' silent: true')
2336
2354
  lines.append(f' dir: "{cwd}"')
2337
2355
  lines.append(" cmds:")
2338
2356
  lines.append(f" - {command_with_args}")
@@ -2432,7 +2450,19 @@ class TasksForCommonProjectStructure:
2432
2450
  GeneralUtilities.copy_content_of_folder(ca_source_folder, ca_target_folder)
2433
2451
 
2434
2452
  @GeneralUtilities.check_arguments
2435
- def get_sorted_codeunits(self, codeunits=dict[str, set[str]]) -> list[str]:
2453
+ def get_sorted_codeunits(self, repository_folder: str) -> list[str]:
2454
+ codeunits_with_dependent_codeunits: dict[str, set[str]] = dict[str, set[str]]()
2455
+ subfolders = GeneralUtilities.get_direct_folders_of_folder(repository_folder)
2456
+ for subfolder in subfolders:
2457
+ codeunit_name: str = os.path.basename(subfolder)
2458
+ codeunit_file = os.path.join(subfolder, f"{codeunit_name}.codeunit.xml")
2459
+ if os.path.exists(codeunit_file):
2460
+ codeunits_with_dependent_codeunits[codeunit_name] = self.get_dependent_code_units(codeunit_file)
2461
+ sorted_codeunits = self._internal_get_sorted_codeunits_by_dict(codeunits_with_dependent_codeunits)
2462
+ return sorted_codeunits
2463
+
2464
+ @GeneralUtilities.check_arguments
2465
+ def _internal_get_sorted_codeunits_by_dict(self, codeunits=dict[str, set[str]]) -> list[str]:
2436
2466
  result_typed = list(TopologicalSorter(codeunits).static_order())
2437
2467
  result = list()
2438
2468
  for item in result_typed:
@@ -2475,16 +2505,36 @@ class TasksForCommonProjectStructure:
2475
2505
  self.__sc.assert_is_git_repository(repository_folder)
2476
2506
  repository_folder = GeneralUtilities.resolve_relative_path_from_current_working_directory(repository_folder)
2477
2507
  codeunits = self.get_codeunits(repository_folder, False)
2508
+ project_version = self.get_version_of_project(repository_folder)
2509
+
2510
+ now = datetime.now()
2511
+ if not self.__suport_information_exists(repository_folder, project_version):
2512
+ support_time = timedelta(days=365*2+30*3+1) # TODO make this configurable
2513
+ until = now + support_time
2514
+ until_day = datetime(until.year, until.month, until.day, 0, 0, 0)
2515
+ self.mark_current_version_as_supported(repository_folder, project_version, now, until_day)
2516
+
2517
+ project_resources_folder = os.path.join(repository_folder, "Other", "Scripts")
2518
+ PrepareBuildCodeunits_script_name = "PrepareBuildCodeunits.py"
2519
+ prepare_build_codeunits_scripts = os.path.join(project_resources_folder, PrepareBuildCodeunits_script_name)
2520
+ if os.path.isfile(prepare_build_codeunits_scripts):
2521
+ GeneralUtilities.write_message_to_stdout(f'Run "{PrepareBuildCodeunits_script_name}"')
2522
+ 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)
2523
+ if result[0] != 0:
2524
+ raise ValueError(f"PrepareBuildCodeunits.py resulted in exitcode {result[0]}.")
2525
+
2526
+ self.__do_repository_checks(repository_folder, project_version)
2478
2527
  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)
2479
2528
 
2480
2529
  @GeneralUtilities.check_arguments
2481
- 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:
2530
+ 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, check_for_new_files: bool = True) -> None:
2531
+ codeunits_list = {", ".join(codeunits)}
2482
2532
  if verbosity > 2:
2483
- GeneralUtilities.write_message_to_stdout(f"Start building codeunits for repository '{repository_folder}'...")
2533
+ GeneralUtilities.write_message_to_stdout(f"Start building codeunits ({codeunits_list}) in repository '{repository_folder}'...")
2484
2534
  self.__sc.assert_is_git_repository(repository_folder)
2485
2535
  self.__check_target_environmenttype(target_environmenttype)
2486
2536
  repository_folder = GeneralUtilities.resolve_relative_path_from_current_working_directory(repository_folder)
2487
- repository_name = os.path.dirname(repository_folder)
2537
+ repository_name = os.path.basename(repository_folder)
2488
2538
  contains_uncommitted_changes_at_begin = self.__sc.git_repository_has_uncommitted_changes(repository_folder)
2489
2539
  if contains_uncommitted_changes_at_begin:
2490
2540
  if is_pre_merge:
@@ -2492,57 +2542,38 @@ class TasksForCommonProjectStructure:
2492
2542
  else:
2493
2543
  if do_git_clean_when_no_changes:
2494
2544
  self.__sc.run_program("git", "clean -dfx", repository_folder)
2495
- subfolders = [os.path.join(repository_folder, codeunit) for codeunit in codeunits]
2545
+ codeunit_subfolders = [os.path.join(repository_folder, codeunit) for codeunit in codeunits]
2496
2546
  codeunits_with_dependent_codeunits: dict[str, set[str]] = dict[str, set[str]]()
2497
2547
 
2498
- project_resources_folder = os.path.join(repository_folder, "Other", "Scripts")
2499
- PrepareBuildCodeunits_script_name = "PrepareBuildCodeunits.py"
2500
- prepare_build_codeunits_scripts = os.path.join(project_resources_folder, PrepareBuildCodeunits_script_name)
2501
- if os.path.isfile(prepare_build_codeunits_scripts):
2502
- GeneralUtilities.write_message_to_stdout(f'Run "{PrepareBuildCodeunits_script_name}"')
2503
- 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)
2504
- if result[0] != 0:
2505
- raise ValueError(f"PrepareBuildCodeunits.py resulted in exitcode {result[0]}.")
2506
-
2507
- for subfolder in subfolders:
2548
+ for subfolder in codeunit_subfolders:
2508
2549
  codeunit_name: str = os.path.basename(subfolder)
2509
2550
  codeunit_file = os.path.join(subfolder, f"{codeunit_name}.codeunit.xml")
2510
- if os.path.exists(codeunit_file):
2511
- codeunits_with_dependent_codeunits[codeunit_name] = self.get_dependent_code_units(codeunit_file)
2512
- else:
2513
- raise ValueError(f"{repository_folder} does not have a codeunit with name {codeunit_name}.")
2514
- sorted_codeunits = self.get_sorted_codeunits(codeunits_with_dependent_codeunits)
2551
+ GeneralUtilities.assert_condition(os.path.exists(codeunit_file), f"Codeunit-file '{codeunit_file}' does nost exist.")
2552
+ codeunits_with_dependent_codeunits[codeunit_name] = self.get_dependent_code_units(codeunit_file)
2553
+ sorted_codeunits = self.get_sorted_codeunits(repository_folder)
2554
+ sorted_codeunits = [codeunit for codeunit in sorted_codeunits if codeunit in codeunits]
2515
2555
  project_version = self.get_version_of_project(repository_folder)
2516
2556
 
2517
- now = datetime.now()
2518
2557
  message = f"Build codeunits in product {repository_name}..."
2519
2558
  if note is not None:
2520
2559
  message = f"{message} ({note})"
2521
2560
  GeneralUtilities.write_message_to_stdout(message)
2522
2561
 
2523
- if not self.__suport_information_exists(repository_folder, project_version):
2524
- support_time = timedelta(days=365*2+30*3+1) # TODO make this configurable
2525
- until = now + support_time
2526
- until_day = datetime(until.year, until.month, until.day, 0, 0, 0)
2527
- self.mark_current_version_as_supported(repository_folder, project_version, now, until_day)
2528
-
2529
2562
  if len(sorted_codeunits) == 0:
2530
2563
  raise ValueError(f'No codeunit found in subfolders of "{repository_folder}".')
2531
2564
  else:
2532
2565
  if verbosity > 1:
2533
- GeneralUtilities.write_message_to_stdout(f"Attempt to build codeunits for version {project_version} in the following order:")
2566
+ GeneralUtilities.write_message_to_stdout(f"Attempt to build codeunits ({codeunits_list}) for project version {project_version} in the following order:")
2534
2567
  i = 0
2535
2568
  for codeunit in sorted_codeunits:
2536
2569
  i = i+1
2537
2570
  GeneralUtilities.write_message_to_stdout(f"{i}.: {codeunit}")
2538
- self.__do_repository_checks(repository_folder, project_version)
2539
- line = "----------"
2540
2571
  for codeunit in sorted_codeunits:
2541
- GeneralUtilities.write_message_to_stdout(line)
2572
+ GeneralUtilities.write_message_to_stdout(GeneralUtilities.get_line())
2542
2573
  self.__build_codeunit(os.path.join(repository_folder, codeunit), verbosity, target_environmenttype, additional_arguments_file, is_pre_merge, assume_dependent_codeunits_are_already_built, commandline_arguments)
2543
- GeneralUtilities.write_message_to_stdout(line)
2574
+ GeneralUtilities.write_message_to_stdout(GeneralUtilities.get_line())
2544
2575
  contains_uncommitted_changes_at_end = self.__sc.git_repository_has_uncommitted_changes(repository_folder)
2545
- if contains_uncommitted_changes_at_end and not is_pre_merge:
2576
+ if contains_uncommitted_changes_at_end and (not is_pre_merge) and check_for_new_files:
2546
2577
  if contains_uncommitted_changes_at_begin:
2547
2578
  GeneralUtilities.write_message_to_stdout(f'There are still uncommitted changes in the repository "{repository_folder}".')
2548
2579
  else:
@@ -2551,6 +2582,7 @@ class TasksForCommonProjectStructure:
2551
2582
  GeneralUtilities.write_message_to_stderr(f"Warning: {message}")
2552
2583
  else:
2553
2584
  raise ValueError(message)
2585
+
2554
2586
  if export_target_directory is not None:
2555
2587
  project_name = self.get_project_name(repository_folder)
2556
2588
  for codeunit in sorted_codeunits:
@@ -2574,9 +2606,14 @@ class TasksForCommonProjectStructure:
2574
2606
  self.__sc.assert_is_git_repository(repository_folder)
2575
2607
  self.__check_if_changelog_exists(repository_folder, project_version)
2576
2608
  self.__check_whether_security_txt_exists(repository_folder)
2609
+ self.__check_whether_general_reference_exists(repository_folder)
2577
2610
  self.__check_whether_workspace_file_exists(repository_folder)
2578
2611
  self.__check_for_staged_or_committed_ignored_files(repository_folder)
2579
2612
 
2613
+ @GeneralUtilities.check_arguments
2614
+ def __check_whether_general_reference_exists(self, repository_folder: str) -> None:
2615
+ GeneralUtilities.assert_file_exists(os.path.join(repository_folder, "Other", "Reference", "Reference.md"))
2616
+
2580
2617
  @GeneralUtilities.check_arguments
2581
2618
  def __check_if_changelog_exists(self, repository_folder: str, project_version: str) -> None:
2582
2619
  self.__sc.assert_is_git_repository(repository_folder)
@@ -2693,6 +2730,17 @@ class TasksForCommonProjectStructure:
2693
2730
  def ensure_androidappbundletool_is_available(self, target_folder: str) -> None:
2694
2731
  self.ensure_file_from_github_assets_is_available(target_folder, "google", "bundletool", "AndroidAppBundleTool", "bundletool.jar", lambda latest_version: f"bundletool-all-{latest_version}.jar")
2695
2732
 
2733
+ @GeneralUtilities.check_arguments
2734
+ def ensure_cyclonedxcli_is_available(self, target_folder: str) -> None:
2735
+ local_filename = "cyclonedx-cli"
2736
+ filename_on_github: str
2737
+ if GeneralUtilities.current_system_is_windows():
2738
+ filename_on_github = "cyclonedx-win-x64.exe"
2739
+ local_filename = local_filename+".exe"
2740
+ else:
2741
+ filename_on_github = "cyclonedx-linux-x64"
2742
+ self.ensure_file_from_github_assets_is_available(target_folder, "CycloneDX", "cyclonedx-cli", "CycloneDXCLI", local_filename, lambda latest_version: filename_on_github)
2743
+
2696
2744
  @GeneralUtilities.check_arguments
2697
2745
  def ensure_file_from_github_assets_is_available(self, target_folder: str, githubuser: str, githubprojectname: str, resource_name: str, local_filename: str, get_filename_on_github) -> None:
2698
2746
  resource_folder = os.path.join(target_folder, "Other", "Resources", resource_name)
@@ -2703,11 +2751,11 @@ class TasksForCommonProjectStructure:
2703
2751
  GeneralUtilities.ensure_directory_does_not_exist(resource_folder)
2704
2752
  GeneralUtilities.ensure_directory_exists(resource_folder)
2705
2753
  headers = {'Cache-Control': 'no-cache'}
2706
- response = requests.get(f"https://api.github.com/repos/{githubuser}/{githubprojectname}/releases/latest", timeout=5, headers=headers)
2707
- latest_version = response.json()["name"]
2754
+ response = requests.get(f"https://api.github.com/repos/{githubuser}/{githubprojectname}/releases/latest", timeout=10, headers=headers)
2755
+ latest_version = response.json()["tag_name"]
2708
2756
  filename_on_github = get_filename_on_github(latest_version)
2709
- jar_link = f"https://github.com/{githubuser}/{githubprojectname}/releases/download/{latest_version}/{filename_on_github}"
2710
- urllib.request.urlretrieve(jar_link, file)
2757
+ link = f"https://github.com/{githubuser}/{githubprojectname}/releases/download/{latest_version}/{filename_on_github}"
2758
+ urllib.request.urlretrieve(link, file)
2711
2759
  else:
2712
2760
  if file_exists:
2713
2761
  GeneralUtilities.write_message_to_stdout(f"Warning: Can not check for updates of {resource_name} due to missing internet-connection.")
@@ -2715,22 +2763,49 @@ class TasksForCommonProjectStructure:
2715
2763
  raise ValueError(f"Can not download {resource_name}.")
2716
2764
 
2717
2765
  @GeneralUtilities.check_arguments
2718
- def generate_svg_files_from_plantuml_files(self, target_folder: str) -> None:
2719
- self.ensure_plantuml_is_available(target_folder)
2720
- plant_uml_folder = os.path.join(target_folder, "Other", "Resources", "PlantUML")
2721
- files_folder = os.path.join(target_folder, "Other", "Resources", "Reference")
2766
+ def generate_svg_files_from_plantuml_files_for_repository(self, repository_folder: str) -> None:
2767
+ self.__sc.assert_is_git_repository(repository_folder)
2768
+ self.ensure_plantuml_is_available(repository_folder)
2769
+ plant_uml_folder = os.path.join(repository_folder, "Other", "Resources", "PlantUML")
2770
+ target_folder = os.path.join(repository_folder, "Other", "Reference")
2771
+ self.__generate_svg_files_from_plantuml(target_folder, plant_uml_folder)
2772
+
2773
+ @GeneralUtilities.check_arguments
2774
+ def generate_svg_files_from_plantuml_files_for_codeunit(self, codeunit_folder: str) -> None:
2775
+ self.assert_is_codeunit_folder(codeunit_folder)
2776
+ repository_folder = os.path.dirname(codeunit_folder)
2777
+ self.ensure_plantuml_is_available(repository_folder)
2778
+ plant_uml_folder = os.path.join(repository_folder, "Other", "Resources", "PlantUML")
2779
+ target_folder = os.path.join(codeunit_folder, "Other", "Reference")
2780
+ self.__generate_svg_files_from_plantuml(target_folder, plant_uml_folder)
2781
+
2782
+ @GeneralUtilities.check_arguments
2783
+ def __generate_svg_files_from_plantuml(self, diagrams_files_folder: str, plant_uml_folder: str) -> None:
2722
2784
  sc = ScriptCollectionCore()
2723
- for file in GeneralUtilities.get_all_files_of_folder(files_folder):
2785
+ for file in GeneralUtilities.get_all_files_of_folder(diagrams_files_folder):
2724
2786
  if file.endswith(".plantuml"):
2725
- argument = ['-jar', f'{plant_uml_folder}/plantuml.jar', os.path.basename(file).replace("\\", "/"), '-tsvg']
2726
- sc.run_program_argsasarray("java", argument, os.path.dirname(file), verbosity=0)
2727
- # TODO format content of file
2787
+ output_filename = self.get_output_filename_for_plantuml_filename(file)
2788
+ argument = ['-jar', f'{plant_uml_folder}/plantuml.jar', '-tsvg', os.path.basename(file)]
2789
+ folder = os.path.dirname(file)
2790
+ sc.run_program_argsasarray("java", argument, folder, verbosity=0)
2791
+ result_file = folder+"/" + output_filename
2792
+ GeneralUtilities.assert_file_exists(result_file)
2793
+ self.__sc.format_xml_file(result_file)
2794
+
2795
+ @GeneralUtilities.check_arguments
2796
+ def get_output_filename_for_plantuml_filename(self, plantuml_file: str) -> str:
2797
+ for line in GeneralUtilities.read_lines_from_file(plantuml_file):
2798
+ prefix = "@startuml "
2799
+ if line.startswith(prefix):
2800
+ title = line[len(prefix):]
2801
+ return title+".svg"
2802
+ return Path(plantuml_file).stem+".svg"
2728
2803
 
2729
2804
  @GeneralUtilities.check_arguments
2730
2805
  def generate_codeunits_overview_diagram(self, repository_folder: str) -> None:
2731
2806
  self.__sc.assert_is_git_repository(repository_folder)
2732
2807
  project_name: str = os.path.basename(repository_folder)
2733
- target_folder = os.path.join(repository_folder, "Other", "Resources", "Reference", "Technical", "Diagrams")
2808
+ target_folder = os.path.join(repository_folder, "Other", "Reference", "Technical", "Diagrams")
2734
2809
  GeneralUtilities.ensure_directory_exists(target_folder)
2735
2810
  target_file = os.path.join(target_folder, "CodeUnits-Overview.plantuml")
2736
2811
  lines = ["@startuml CodeUnits-Overview"]
@@ -2856,10 +2931,9 @@ class TasksForCommonProjectStructure:
2856
2931
  GeneralUtilities.write_message_to_stdout(f"Warning: Codeunit {codeunit_name} is disabled.")
2857
2932
  return
2858
2933
 
2859
- artifacts_folder = os.path.join(codeunit_folder, "Other", "Artifacts")
2860
2934
  GeneralUtilities.write_message_to_stdout(f"Start building codeunit {codeunit_name}.")
2861
2935
  GeneralUtilities.write_message_to_stdout(f"Build-environmenttype: {target_environmenttype}")
2862
- GeneralUtilities.ensure_directory_does_not_exist(artifacts_folder)
2936
+ self.__sc.run_program("git", "clean -dfx", codeunit_folder)
2863
2937
 
2864
2938
  verbosity_for_executed_programs = self.get_verbosity_from_commandline_arguments(commandline_arguments, verbosity)
2865
2939
 
@@ -2935,6 +3009,7 @@ class TasksForCommonProjectStructure:
2935
3009
  GeneralUtilities.write_message_to_stdout('Run "OnBuildingFinished.py"...')
2936
3010
  self.__sc.run_program("python", f"OnBuildingFinished.py{additional_arguments_f}{general_argument}", other_folder, verbosity=verbosity_for_executed_programs, throw_exception_if_exitcode_is_not_zero=True, print_live_output=2 < verbosity)
2937
3011
 
3012
+ artifacts_folder = os.path.join(codeunit_folder, "Other", "Artifacts")
2938
3013
  artifactsinformation_file = os.path.join(artifacts_folder, f"{codeunit_name}.artifactsinformation.xml")
2939
3014
  codeunit_version = self.get_version_of_codeunit(codeunit_file)
2940
3015
  GeneralUtilities.ensure_file_exists(artifactsinformation_file)
@@ -2964,9 +3039,10 @@ class TasksForCommonProjectStructure:
2964
3039
  # Prepare
2965
3040
  GeneralUtilities.write_message_to_stdout("Update dependencies...")
2966
3041
  self.__sc.assert_is_git_repository(repository_folder)
2967
- codeunits = self.get_codeunits(repository_folder)
3042
+ codeunits = self.get_sorted_codeunits(repository_folder)
2968
3043
  update_dependencies_script_filename = "UpdateDependencies.py"
2969
- self.build_codeunits(repository_folder, target_environmenttype="QualityCheck", do_git_clean_when_no_changes=True, note="Prepare dependency-update") # Required because update dependencies is not always possible for not-buildet codeunits (depends on the programming language or package manager)
3044
+ target_environmenttype = "QualityCheck"
3045
+ self.build_codeunits(repository_folder, target_environmenttype=target_environmenttype, do_git_clean_when_no_changes=True, note="Prepare dependency-update") # Required because update dependencies is not always possible for not-buildet codeunits (depends on the programming language or package manager)
2970
3046
 
2971
3047
  # update dependencies of resources
2972
3048
  global_scripts_folder = os.path.join(repository_folder, "Other", "Scripts")
@@ -2982,6 +3058,7 @@ class TasksForCommonProjectStructure:
2982
3058
  update_dependencies_script_folder = os.path.join(codeunit_folder, "Other")
2983
3059
  GeneralUtilities.ensure_directory_exists(os.path.join(update_dependencies_script_folder, "Resources", "CodeAnalysisResult"))
2984
3060
  self.__sc.run_program("python", update_dependencies_script_filename, update_dependencies_script_folder, verbosity, print_live_output=True)
3061
+ self.build_specific_codeunits(repository_folder, [codeunit], 0, target_environmenttype, None, False, None, True, [], False, "Build due to updated dependencies", False)
2985
3062
  if self.__sc.git_repository_has_uncommitted_changes(repository_folder):
2986
3063
  version_of_project = self.get_version_of_project(repository_folder)
2987
3064
  changelog_file = os.path.join(repository_folder, "Other", "Resources", "Changelog", f"v{version_of_project}.md")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: ScriptCollection
3
- Version: 3.5.93
3
+ Version: 3.5.95
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
@@ -6,12 +6,12 @@ ScriptCollection/ProgramRunnerEpew.py,sha256=4pjEd0r9Fcz3TTDv0MdTSd5KkigYXcWUVI1
6
6
  ScriptCollection/ProgramRunnerPopen.py,sha256=BPY7-ZMIlqT7JOKz8qlB5c0laF2Js-ijzqk09GxZC48,3821
7
7
  ScriptCollection/RPStream.py,sha256=NRRHL3YSP3D9MuAV2jB_--0KUKCsvJGxeKnxgrRZ9kY,1545
8
8
  ScriptCollection/SCLog.py,sha256=l4aekBiGoNkKGtvO_Er3NY_K7ts4ZWtIGlhq07I-4LY,30
9
- ScriptCollection/ScriptCollectionCore.py,sha256=IGIu5wl1wm25-KnLo7MLOaNFkVZuQjEr69PGHxkCFGg,123625
10
- ScriptCollection/TasksForCommonProjectStructure.py,sha256=UICi0p_m_uGOLP3c-Rk-dCxN0IzXIM0O_FwwRGNoHCM,221680
9
+ ScriptCollection/ScriptCollectionCore.py,sha256=BNaVHYzgDngTNPvdu1RmI5CcoBYXa5eER6MbOG9ECZA,123973
10
+ ScriptCollection/TasksForCommonProjectStructure.py,sha256=WLpk9nRa6p_fFCHTJ3YO8mOxyrs1D8V2CuXem38qi84,226908
11
11
  ScriptCollection/UpdateCertificates.py,sha256=Eynbgu7k9jLxApP2D_8Il77B6BFjJap6K7oTeEAZYbk,7790
12
12
  ScriptCollection/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
- scriptcollection-3.5.93.dist-info/METADATA,sha256=USfCKrvr35eIM7vkEptzfc9tbnXP1IGw7D2dluFS5dA,7664
14
- scriptcollection-3.5.93.dist-info/WHEEL,sha256=EaM1zKIUYa7rQnxGiOCGhzJABRwy4WO57rWMR3_tj4I,91
15
- scriptcollection-3.5.93.dist-info/entry_points.txt,sha256=fYCGWGNGijBQHhFe6UAO-BEpfEOxLyNJemukt5ElSzs,3644
16
- scriptcollection-3.5.93.dist-info/top_level.txt,sha256=hY2hOVH0V0Ce51WB76zKkIWTUNwMUdHo4XDkR2vYVwg,17
17
- scriptcollection-3.5.93.dist-info/RECORD,,
13
+ scriptcollection-3.5.95.dist-info/METADATA,sha256=vVDkmhbE3EFINXPutGygcmV-cNd_sEKd0AFPwvsSF8g,7664
14
+ scriptcollection-3.5.95.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
15
+ scriptcollection-3.5.95.dist-info/entry_points.txt,sha256=fYCGWGNGijBQHhFe6UAO-BEpfEOxLyNJemukt5ElSzs,3644
16
+ scriptcollection-3.5.95.dist-info/top_level.txt,sha256=hY2hOVH0V0Ce51WB76zKkIWTUNwMUdHo4XDkR2vYVwg,17
17
+ scriptcollection-3.5.95.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.9.1)
2
+ Generator: setuptools (76.0.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5