ScriptCollection 3.5.4__py3-none-any.whl → 3.5.7__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.
@@ -259,11 +259,11 @@ def BuildCodeUnit() -> int:
259
259
  parser = argparse.ArgumentParser()
260
260
  parser.add_argument('--codeunitfolder', required=False, default=".")
261
261
  parser.add_argument('--verbosity', required=False, default=1)
262
- parser.add_argument('--targetenvironment', required=False, default="Development")
262
+ parser.add_argument('--targetenvironment', required=False, default="QualityCheck")
263
263
  parser.add_argument('--additionalargumentsfile', required=False, default=None)
264
264
  parser.add_argument('--assume_dependent_codeunits_are_already_built', type=GeneralUtilities.string_to_boolean, const=True, default=False, nargs='?')
265
265
  args = parser.parse_args()
266
- TasksForCommonProjectStructure().build_codeunit(args.codeunitfolder, int(args.verbosity), args.targetenvironment, args.additionalargumentsfile,False, None, args.assume_dependent_codeunits_are_already_built,sys.argv)
266
+ TasksForCommonProjectStructure().build_codeunit(args.codeunitfolder, int(args.verbosity), args.targetenvironment, args.additionalargumentsfile, False, None, args.assume_dependent_codeunits_are_already_built, sys.argv)
267
267
  return 0
268
268
 
269
269
 
@@ -271,10 +271,10 @@ def BuildCodeUnits() -> int:
271
271
  parser = argparse.ArgumentParser()
272
272
  parser.add_argument('--repositoryfolder', required=False, default=".")
273
273
  parser.add_argument('--verbosity', required=False, default=1)
274
- parser.add_argument('--targetenvironment', required=False, default="Development")
274
+ parser.add_argument('--targetenvironment', required=False, default="QualityCheck")
275
275
  parser.add_argument('--additionalargumentsfile', required=False, default=None)
276
276
  args = parser.parse_args()
277
- TasksForCommonProjectStructure().build_codeunits(args.repositoryfolder, int(args.verbosity), args.targetenvironment, args.additionalargumentsfile,False,None,sys.argv)
277
+ TasksForCommonProjectStructure().build_codeunits(args.repositoryfolder, int(args.verbosity), args.targetenvironment, args.additionalargumentsfile, False, None, sys.argv)
278
278
  return 0
279
279
 
280
280
 
@@ -287,7 +287,7 @@ def BuildCodeUnitsC() -> int:
287
287
  parser.add_argument('--image', required=False, default="scbuilder:latest")
288
288
  args = parser.parse_args()
289
289
  GeneralUtilities.reconfigure_standrd_input_and_outputs()
290
- TasksForCommonProjectStructure().build_codeunitsC(args.repositoryfolder, args.image, int(args.verbosity), args.targetenvironment, args.additionalargumentsfile,sys.argv)
290
+ TasksForCommonProjectStructure().build_codeunitsC(args.repositoryfolder, args.image, int(args.verbosity), args.targetenvironment, args.additionalargumentsfile, sys.argv)
291
291
  return 0
292
292
 
293
293
 
@@ -555,6 +555,12 @@ class GeneralUtilities:
555
555
  except AttributeError:
556
556
  return ctypes.windll.shell32.IsUserAnAdmin() == 1
557
557
 
558
+ @staticmethod
559
+ @check_arguments
560
+ def ensure_elevated_privileges() -> None:
561
+ if (not GeneralUtilities.current_user_has_elevated_privileges()):
562
+ raise ValueError("Not enough privileges.")
563
+
558
564
  @staticmethod
559
565
  @check_arguments
560
566
  def rename_names_of_all_files_and_folders(folder: str, replace_from: str, replace_to: str, replace_only_full_match=False):
@@ -29,7 +29,7 @@ from .ProgramRunnerBase import ProgramRunnerBase
29
29
  from .ProgramRunnerPopen import ProgramRunnerPopen
30
30
  from .ProgramRunnerEpew import ProgramRunnerEpew, CustomEpewArgument
31
31
 
32
- version = "3.5.4"
32
+ version = "3.5.7"
33
33
  __version__ = version
34
34
 
35
35
 
@@ -129,17 +129,14 @@ class ScriptCollectionCore:
129
129
 
130
130
  @GeneralUtilities.check_arguments
131
131
  def find_file_by_extension(self, folder: str, extension: str):
132
- result = [file for file in GeneralUtilities.get_direct_files_of_folder(
133
- folder) if file.endswith(f".{extension}")]
132
+ result = [file for file in GeneralUtilities.get_direct_files_of_folder(folder) if file.endswith(f".{extension}")]
134
133
  result_length = len(result)
135
134
  if result_length == 0:
136
- raise FileNotFoundError(
137
- f"No file available in folder '{folder}' with extension '{extension}'.")
135
+ raise FileNotFoundError(f"No file available in folder '{folder}' with extension '{extension}'.")
138
136
  if result_length == 1:
139
137
  return result[0]
140
138
  else:
141
- raise ValueError(
142
- f"Multiple values available in folder '{folder}' with extension '{extension}'.")
139
+ raise ValueError(f"Multiple values available in folder '{folder}' with extension '{extension}'.")
143
140
 
144
141
  @GeneralUtilities.check_arguments
145
142
  def commit_is_signed_by_key(self, repository_folder: str, revision_identifier: str, key: str) -> bool:
@@ -1240,25 +1237,9 @@ class ScriptCollectionCore:
1240
1237
  # 2=Full (Prints StdOut and StdErr of the executed program.)
1241
1238
  # 3=Verbose (Same as "Full" but with some more information.)
1242
1239
 
1243
- if arguments_for_log is None:
1244
- arguments_for_log = ' '.join(arguments_as_array)
1245
- else:
1246
- arguments_for_log = ' '.join(arguments_for_log)
1247
- working_directory = self.__adapt_workingdirectory(working_directory)
1248
- cmd = f'{working_directory}>{program} {arguments_for_log}'
1249
-
1250
- if GeneralUtilities.string_is_none_or_whitespace(title):
1251
- info_for_log = cmd
1252
- else:
1253
- info_for_log = title
1254
-
1255
- if verbosity >= 3:
1256
- GeneralUtilities.write_message_to_stdout(f"Run '{info_for_log}'.")
1257
-
1258
1240
  if isinstance(self.program_runner, ProgramRunnerEpew):
1259
1241
  custom_argument = CustomEpewArgument(print_errors_as_information, log_file, timeoutInSeconds, addLogOverhead, title, log_namespace, verbosity, arguments_for_log)
1260
- popen: Popen = self.program_runner.run_program_argsasarray_async_helper(
1261
- program, arguments_as_array, working_directory, custom_argument, interactive)
1242
+ popen: Popen = self.program_runner.run_program_argsasarray_async_helper(program, arguments_as_array, working_directory, custom_argument, interactive)
1262
1243
  return popen
1263
1244
 
1264
1245
  # Return-values program_runner: Exitcode, StdOut, StdErr, Pid
@@ -1275,12 +1256,12 @@ class ScriptCollectionCore:
1275
1256
  if mock_loader_result[0]:
1276
1257
  return mock_loader_result[1]
1277
1258
 
1259
+ working_directory = self.__adapt_workingdirectory(working_directory)
1260
+
1278
1261
  if arguments_for_log is None:
1279
1262
  arguments_for_log = arguments_as_array
1280
1263
 
1281
- arguments_for_exception_as_string = ' '.join(arguments_for_log)
1282
-
1283
- arguments_for_log_as_string = ' '.join(arguments_for_log)
1264
+ arguments_for_log_as_string: str = ' '.join(arguments_for_log)
1284
1265
  cmd = f'{working_directory}>{program} {arguments_for_log_as_string}'
1285
1266
 
1286
1267
  if GeneralUtilities.string_is_none_or_whitespace(title):
@@ -1290,7 +1271,6 @@ class ScriptCollectionCore:
1290
1271
 
1291
1272
  if verbosity >= 3:
1292
1273
  GeneralUtilities.write_message_to_stdout(f"Run '{info_for_log}'.")
1293
-
1294
1274
  with self.__run_program_argsasarray_async_helper(program, arguments_as_array, working_directory, verbosity, print_errors_as_information, log_file, timeoutInSeconds, addLogOverhead, title, log_namespace, arguments_for_log, custom_argument, interactive) as process:
1295
1275
  pid = process.pid
1296
1276
 
@@ -1362,14 +1342,8 @@ class ScriptCollectionCore:
1362
1342
  stdout = GeneralUtilities.bytes_to_string(stdout).replace('\r', '')
1363
1343
  stderr = GeneralUtilities.bytes_to_string(stderr).replace('\r', '')
1364
1344
 
1365
- if arguments_for_exception_as_string is None:
1366
- arguments_for_exception_as_string = ' '.join(arguments_as_array)
1367
- else:
1368
- arguments_for_exception_as_string = ' '.join(arguments_for_log)
1369
-
1370
1345
  if throw_exception_if_exitcode_is_not_zero and exit_code != 0:
1371
- arguments_for_exception_as_string = ' '.join(arguments_for_log)
1372
- raise ValueError(f"Program '{working_directory}>{program} {arguments_for_exception_as_string}' resulted in exitcode {exit_code}. (StdOut: '{stdout}', StdErr: '{stderr}')")
1346
+ raise ValueError(f"Program '{working_directory}>{program} {arguments_for_log_as_string}' resulted in exitcode {exit_code}. (StdOut: '{stdout}', StdErr: '{stderr}')")
1373
1347
 
1374
1348
  result = (exit_code, stdout, stderr, pid)
1375
1349
  return result
@@ -1387,7 +1361,7 @@ class ScriptCollectionCore:
1387
1361
  mock_loader_result = self.__try_load_mock(program, ' '.join(arguments_as_array), working_directory)
1388
1362
  if mock_loader_result[0]:
1389
1363
  return mock_loader_result[1]
1390
- process: Popen = self.__run_program_argsasarray_async_helper(program, arguments_as_array, working_directory, verbosity, print_errors_as_information, log_file, timeoutInSeconds, addLogOverhead, title, log_namespace, arguments_for_log, custom_argument, interactive)
1364
+ process: Popen = self.__run_program_argsasarray_async_helper(program, arguments_as_array, working_directory, verbosity, print_errors_as_information, log_file, timeoutInSeconds, addLogOverhead, title, log_namespace, arguments_for_log, custom_argument, interactive)
1391
1365
  return process.pid
1392
1366
 
1393
1367
  # Return-values program_runner: Pid
@@ -1555,13 +1529,13 @@ class ScriptCollectionCore:
1555
1529
  return result
1556
1530
 
1557
1531
  @GeneralUtilities.check_arguments
1558
- def generate_certificate_authority(self, folder: str, name: str, subj_c: str, subj_st: str, subj_l: str, subj_o: str, subj_ou: str, days_until_expire: int = None, password: str = None) -> None:
1532
+ def generate_certificate_authority(self, folder: str, name: str, subj_c: str, subj_st: str, subj_l: str, subj_o: str, subj_ou: str, days_until_expire: int = None, password: str = None) -> None:
1559
1533
  if days_until_expire is None:
1560
1534
  days_until_expire = 1825
1561
1535
  if password is None:
1562
1536
  password = GeneralUtilities.generate_password()
1563
- self.run_program(
1564
- "openssl", f'req -new -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -days {days_until_expire} -nodes -x509 -subj /C={subj_c}/ST={subj_st}/L={subj_l}/O={subj_o}/CN={name}/OU={subj_ou} -passout pass:{password} -keyout {name}.key -out {name}.crt', folder)
1537
+ GeneralUtilities.ensure_directory_exists(folder)
1538
+ self.run_program("openssl", f'req -new -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -days {days_until_expire} -nodes -x509 -subj /C={subj_c}/ST={subj_st}/L={subj_l}/O={subj_o}/CN={name}/OU={subj_ou} -passout pass:{password} -keyout {name}.key -out {name}.crt', folder)
1565
1539
 
1566
1540
  @GeneralUtilities.check_arguments
1567
1541
  def generate_certificate(self, folder: str, domain: str, filename: str, subj_c: str, subj_st: str, subj_l: str, subj_o: str, subj_ou: str, days_until_expire: int = None, password: str = None) -> None:
@@ -1610,10 +1584,8 @@ DNS = {domain}
1610
1584
  ca = os.path.join(ca_folder, ca_name)
1611
1585
  password_file = os.path.join(folder, f"{filename}.password")
1612
1586
  password = GeneralUtilities.read_text_from_file(password_file)
1613
- self.run_program(
1614
- "openssl", f'x509 -req -in {filename}.csr -CA {ca}.crt -CAkey {ca}.key -CAcreateserial -CAserial {ca}.srl -out {filename}.crt -days {days_until_expire} -sha256 -extensions v3_req -extfile {filename}.san.conf', folder)
1615
- self.run_program(
1616
- "openssl", f'pkcs12 -export -out {filename}.pfx -inkey {filename}.key -in {filename}.crt -password pass:{password}', folder)
1587
+ self.run_program("openssl", f'x509 -req -in {filename}.csr -CA {ca}.crt -CAkey {ca}.key -CAcreateserial -CAserial {ca}.srl -out {filename}.crt -days {days_until_expire} -sha256 -extensions v3_req -extfile {filename}.san.conf', folder)
1588
+ self.run_program("openssl", f'pkcs12 -export -out {filename}.pfx -inkey {filename}.key -in {filename}.crt -password pass:{password}', folder)
1617
1589
 
1618
1590
  @GeneralUtilities.check_arguments
1619
1591
  def update_dependencies_of_python_in_requirementstxt_file(self, file: str, verbosity: int):
@@ -1661,7 +1633,7 @@ DNS = {domain}
1661
1633
  GeneralUtilities.write_lines_to_file(setup_cfg_file, new_lines)
1662
1634
 
1663
1635
  @GeneralUtilities.check_arguments
1664
- def update_dependencies_of_dotnet_project(self, csproj_file: str, verbosity: int):
1636
+ def update_dependencies_of_dotnet_project(self, csproj_file: str, verbosity: int, ignored_dependencies: list[str]):
1665
1637
  folder = os.path.dirname(csproj_file)
1666
1638
  csproj_filename = os.path.basename(csproj_file)
1667
1639
  GeneralUtilities.write_message_to_stderr(f"Check for updates in {csproj_filename}")
@@ -1670,12 +1642,12 @@ DNS = {domain}
1670
1642
  # Relevant output-lines are something like " > NJsonSchema 10.7.0 10.7.0 10.9.0"
1671
1643
  if ">" in line:
1672
1644
  package_name = line.replace(">", "").strip().split(" ")[0]
1673
- GeneralUtilities.write_message_to_stderr(f"Update package {package_name}")
1674
- self.run_program(
1675
- "dotnet", f"add {csproj_filename} package {package_name}", folder)
1645
+ if not (ignored_dependencies in package_name):
1646
+ GeneralUtilities.write_message_to_stderr(f"Update package {package_name}")
1647
+ self.run_program("dotnet", f"add {csproj_filename} package {package_name}", folder)
1676
1648
 
1677
1649
  @GeneralUtilities.check_arguments
1678
- 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:
1650
+ 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:
1679
1651
 
1680
1652
  # prepare
1681
1653
  GeneralUtilities.ensure_directory_exists(deb_output_folder)
@@ -190,7 +190,7 @@ class TasksForCommonProjectStructure:
190
190
  GeneralUtilities.write_text_to_file(file, re.sub("version = \"\\d+\\.\\d+\\.\\d+\"", f"version = \"{new_version_value}\"", GeneralUtilities.read_text_from_file(file)))
191
191
 
192
192
  @GeneralUtilities.check_arguments
193
- def standardized_tasks_run_testcases_for_python_codeunit(self, run_testcases_file: str, generate_badges: bool, verbosity: int, targetenvironmenttype: str, commandline_arguments: list[str]) -> None:
193
+ def standardized_tasks_run_testcases_for_python_codeunit(self, run_testcases_file: str, generate_badges: bool, verbosity: int, targetenvironmenttype: str, commandline_arguments: list[str]) -> None:
194
194
  codeunitname: str = Path(os.path.dirname(run_testcases_file)).parent.parent.name
195
195
  verbosity = TasksForCommonProjectStructure.get_verbosity_from_commandline_arguments(commandline_arguments, verbosity)
196
196
  repository_folder: str = str(Path(os.path.dirname(run_testcases_file)).parent.parent.parent.absolute())
@@ -765,7 +765,7 @@ class TasksForCommonProjectStructure:
765
765
 
766
766
  @GeneralUtilities.check_arguments
767
767
  def standardized_tasks_generate_coverage_report(self, repository_folder: str, codeunitname: str, verbosity: int, generate_badges: bool, targetenvironmenttype: str, commandline_arguments: list[str], add_testcoverage_history_entry: bool = None) -> None:
768
- """This script expects that the file '<repositorybasefolder>/<codeunitname>/Other/Artifacts/TestCoverage/TestCoverage.xml'
768
+ """This function expects that the file '<repositorybasefolder>/<codeunitname>/Other/Artifacts/TestCoverage/TestCoverage.xml'
769
769
  which contains a test-coverage-report in the cobertura-format exists.
770
770
  This script expectes that the testcoverage-reportfolder is '<repositorybasefolder>/<codeunitname>/Other/Artifacts/TestCoverageReport'.
771
771
  This script expectes that a test-coverage-badges should be added to '<repositorybasefolder>/<codeunitname>/Other/Resources/Badges'."""
@@ -1003,8 +1003,8 @@ class TasksForCommonProjectStructure:
1003
1003
 
1004
1004
  # Copy reference of codeunit to reference-repository
1005
1005
  codeunit_version = self.get_version_of_codeunit_folder(os.path.join(information.repository, codeunitname))
1006
- self.__export_codeunit_reference_content_to_reference_repository(f"v{project_version}", False, reference_folder, information.repository, codeunitname, information.projectname, codeunit_version, information.public_repository_url, f"v{project_version}")
1007
- self.__export_codeunit_reference_content_to_reference_repository("Latest", True, reference_folder, information.repository, codeunitname, information.projectname, codeunit_version, information.public_repository_url, information.target_branch_name)
1006
+ self.__export_codeunit_reference_content_to_reference_repository(f"v{project_version}", False, reference_folder, information.repository, codeunitname, information.projectname, codeunit_version, information.public_repository_url, f"v{project_version}")
1007
+ self.__export_codeunit_reference_content_to_reference_repository("Latest", True, reference_folder, information.repository, codeunitname, information.projectname, codeunit_version, information.public_repository_url, information.target_branch_name)
1008
1008
 
1009
1009
  # Generate reference
1010
1010
  self.__generate_entire_reference(information.projectname, project_version, reference_folder)
@@ -1092,8 +1092,7 @@ class TasksForCommonProjectStructure:
1092
1092
  @GeneralUtilities.check_arguments
1093
1093
  def push_nuget_build_artifact(self, push_script_file: str, codeunitname: str, registry_address: str, api_key: str, repository_folder_name: str):
1094
1094
  # when pusing to "default public" nuget-server then use registry_address: "nuget.org"
1095
- build_artifact_folder = GeneralUtilities.resolve_relative_path(
1096
- f"../../Submodules/{repository_folder_name}/{codeunitname}/Other/Artifacts/BuildResult_NuGet", os.path.dirname(push_script_file))
1095
+ build_artifact_folder = GeneralUtilities.resolve_relative_path(f"../../Submodules/{repository_folder_name}/{codeunitname}/Other/Artifacts/BuildResult_NuGet", os.path.dirname(push_script_file))
1097
1096
  self.__sc.push_nuget_build_artifact(self.__sc.find_file_by_extension(build_artifact_folder, "nupkg"), registry_address, api_key)
1098
1097
 
1099
1098
  @GeneralUtilities.check_arguments
@@ -1101,18 +1100,40 @@ class TasksForCommonProjectStructure:
1101
1100
  if self.__sc.git_repository_has_uncommitted_changes(repository_folder):
1102
1101
  raise ValueError(f"Repository '{repository_folder}' has uncommitted changes.")
1103
1102
 
1103
+ @GeneralUtilities.check_arguments
1104
+ def ensure_certificate_authority_for_development_purposes_is_generated(self, script_file: str):
1105
+ folder_of_current_file = os.path.dirname(script_file)
1106
+ product_folder: str = GeneralUtilities.resolve_relative_path("../..", folder_of_current_file)
1107
+ product_name: str = os.path.basename(product_folder)
1108
+ now = datetime.now()
1109
+ ca_name = f"{product_name}CA_{now.year:04}{now.month:02}{now.day:02}{now.hour:02}{now.min:02}{now.second:02}"
1110
+ ca_folder = os.path.join(product_folder, "Other", "Resources", "CA")
1111
+ generate_certificate = True
1112
+ if os.path.isdir(ca_folder):
1113
+ try:
1114
+ ca_file = self.__sc.find_file_by_extension(ca_folder, "crt") # pylint: disable=unused-variable
1115
+ certificate_is_valid = True # TODO check if certificate is not valid
1116
+ generate_certificate = not certificate_is_valid
1117
+ except FileNotFoundError:
1118
+ pass
1119
+ if generate_certificate:
1120
+ self.__sc.generate_certificate_authority(ca_folder, ca_name, "DE", "SubjST", "SubjL", "SubjO", "SubjOU")
1121
+
1104
1122
  @GeneralUtilities.check_arguments
1105
1123
  def generate_certificate_for_development_purposes_for_external_service(self, service_folder: str, domain: str = None):
1106
1124
  testservice_name = os.path.basename(service_folder)
1107
- self.__generate_certificate_for_development_purposes(testservice_name, os.path.join(service_folder, "Resources"), domain)
1125
+ ca_folder: str = None # TODO
1126
+ self.__generate_certificate_for_development_purposes(testservice_name, os.path.join(service_folder, "Resources"), ca_folder, domain)
1108
1127
 
1109
1128
  @GeneralUtilities.check_arguments
1110
1129
  def generate_certificate_for_development_purposes_for_codeunit(self, codeunit_folder: str, domain: str = None):
1111
1130
  codeunit_name = os.path.basename(codeunit_folder)
1112
- self.__generate_certificate_for_development_purposes(codeunit_name, os.path.join(codeunit_folder, "Other", "Resources"), domain)
1131
+ self.ensure_product_resource_is_imported(codeunit_folder, "CA")
1132
+ ca_folder: str = os.path.join(codeunit_folder, "Other", "Resources", "CA")
1133
+ self.__generate_certificate_for_development_purposes(codeunit_name, os.path.join(codeunit_folder, "Other", "Resources"), ca_folder, domain)
1113
1134
 
1114
1135
  @GeneralUtilities.check_arguments
1115
- def __generate_certificate_for_development_purposes(self, service_name: str, resources_folder: str, domain: str = None):
1136
+ def __generate_certificate_for_development_purposes(self, service_name: str, resources_folder: str, ca_folder: str, domain: str = None):
1116
1137
  if domain is None:
1117
1138
  domain = f"{service_name}.test.local"
1118
1139
  domain = domain.lower()
@@ -1120,9 +1141,6 @@ class TasksForCommonProjectStructure:
1120
1141
  certificate_folder: str = os.path.join(resources_folder, resource_name)
1121
1142
 
1122
1143
  resource_content_filename: str = service_name+resource_name
1123
- ca_resource_name: str = f"{resource_name}Authority"
1124
- dev_ca_name = service_name+ca_resource_name
1125
- ca_folder = os.path.join(resources_folder, ca_resource_name)
1126
1144
  certificate_file = os.path.join(certificate_folder, f"{domain}.crt")
1127
1145
  unsignedcertificate_file = os.path.join(certificate_folder, f"{domain}.unsigned.crt")
1128
1146
  certificate_exists = os.path.exists(certificate_file)
@@ -1134,15 +1152,22 @@ class TasksForCommonProjectStructure:
1134
1152
  if generate_new_certificate:
1135
1153
  GeneralUtilities.ensure_directory_does_not_exist(certificate_folder)
1136
1154
  GeneralUtilities.ensure_directory_exists(certificate_folder)
1137
- GeneralUtilities.ensure_directory_does_not_exist(ca_folder)
1138
- GeneralUtilities.ensure_directory_exists(ca_folder)
1139
1155
  GeneralUtilities.write_message_to_stdout("Generate TLS-certificate for development-purposes.")
1140
- self.__sc.generate_certificate_authority(ca_folder, dev_ca_name, "DE", "SubjST", "SubjL", "SubjO", "SubjOU")
1141
1156
  self.__sc.generate_certificate(certificate_folder, domain, resource_content_filename, "DE", "SubjST", "SubjL", "SubjO", "SubjOU")
1142
1157
  self.__sc.generate_certificate_sign_request(certificate_folder, domain, resource_content_filename, "DE", "SubjST", "SubjL", "SubjO", "SubjOU")
1143
- self.__sc.sign_certificate(certificate_folder, ca_folder, dev_ca_name, domain, resource_content_filename)
1158
+ ca_name = os.path.basename(self.__sc.find_file_by_extension(ca_folder, "crt"))[:-4]
1159
+ self.__sc.sign_certificate(certificate_folder, ca_folder, ca_name, domain, resource_content_filename)
1144
1160
  GeneralUtilities.ensure_file_does_not_exist(unsignedcertificate_file)
1145
1161
 
1162
+ @GeneralUtilities.check_arguments
1163
+ def ensure_product_resource_is_imported(self, codeunit_folder: str, product_resource_name: str) -> None:
1164
+ product_folder = os.path.dirname(codeunit_folder)
1165
+ source_folder = os.path.join(product_folder, "Other", "Resources", product_resource_name)
1166
+ target_folder = os.path.join(codeunit_folder, "Other", "Resources", product_resource_name)
1167
+ GeneralUtilities.ensure_directory_does_not_exist(target_folder)
1168
+ GeneralUtilities.ensure_directory_exists(target_folder)
1169
+ GeneralUtilities.copy_content_of_folder(source_folder, target_folder)
1170
+
1146
1171
  @GeneralUtilities.check_arguments
1147
1172
  def get_codeunits(self, repository_folder: str, ignore_disabled_codeunits: bool = True) -> list[str]:
1148
1173
  result: list[str] = []
@@ -1219,8 +1244,7 @@ class TasksForCommonProjectStructure:
1219
1244
  # hint: arguments can be overwritten by commandline_arguments
1220
1245
  folder_of_this_file = os.path.dirname(create_release_file)
1221
1246
  verbosity = TasksForCommonProjectStructure.get_verbosity_from_commandline_arguments(commandline_arguments, verbosity)
1222
- self.__sc.run_program("python", f"CreateRelease.py --overwrite_verbosity {str(verbosity)}",
1223
- folder_of_this_file, verbosity=verbosity, log_file=logfile, addLogOverhead=addLogOverhead)
1247
+ self.__sc.run_program("python", f"CreateRelease.py --overwrite_verbosity {str(verbosity)}", folder_of_this_file, verbosity=verbosity, log_file=logfile, addLogOverhead=addLogOverhead)
1224
1248
 
1225
1249
  @GeneralUtilities.check_arguments
1226
1250
  def __standardized_tasks_merge_to_stable_branch(self, information: MergeToStableBranchInformationForProjectInCommonProjectFormat) -> str:
@@ -1367,7 +1391,7 @@ class TasksForCommonProjectStructure:
1367
1391
 
1368
1392
  # Check codeunit-conformity
1369
1393
  # TODO check if foldername=="<codeunitname>[.codeunit.xml]" == <codeunitname> in file
1370
- supported_codeunitspecificationversion = "2.7.10" # should always be the latest version of the ProjectTemplates-repository
1394
+ supported_codeunitspecificationversion = "2.8.0" # should always be the latest version of the ProjectTemplates-repository
1371
1395
  codeunit_file = os.path.join(codeunit_folder, f"{codeunit_name}.codeunit.xml")
1372
1396
  if not os.path.isfile(codeunit_file):
1373
1397
  raise ValueError(f'Codeunitfile "{codeunit_file}" does not exist.')
@@ -1383,6 +1407,7 @@ class TasksForCommonProjectStructure:
1383
1407
  raise ValueError(f"ScriptCollection only supports processing codeunits with codeunit-specification-version={supported_codeunitspecificationversion}.")
1384
1408
  schemaLocation = root.xpath('//cps:codeunit/@xsi:schemaLocation', namespaces=namespaces)[0]
1385
1409
  xmlschema.validate(codeunit_file, schemaLocation)
1410
+ # TODO check if the properties codeunithastestablesourcecode, codeunithasupdatabledependencies, throwexceptionifcodeunitfilecannotbevalidated, developmentState and description exist and the values are valid
1386
1411
  except Exception as exception:
1387
1412
  if self.codeunit_throws_exception_if_codeunitfile_is_not_validatable(codeunit_file):
1388
1413
  raise exception
@@ -1398,8 +1423,10 @@ class TasksForCommonProjectStructure:
1398
1423
  # Check for mandatory files
1399
1424
  files = ["Other/Build/Build.py", "Other/QualityCheck/Linting.py", "Other/Reference/GenerateReference.py"]
1400
1425
  if self.codeunit_has_testable_sourcecode(codeunit_file):
1426
+ # TODO check if the testsettings-section appears in the codeunit-file
1401
1427
  files.append("Other/QualityCheck/RunTestcases.py")
1402
1428
  if self.codeunit_has_updatable_dependencies(codeunit_file):
1429
+ # TODO check if the updatesettings-section appears in the codeunit-file
1403
1430
  files.append("Other/UpdateDependencies.py")
1404
1431
  for file in files:
1405
1432
  combined_file = os.path.join(codeunit_folder, file)
@@ -1491,10 +1518,17 @@ class TasksForCommonProjectStructure:
1491
1518
 
1492
1519
  @GeneralUtilities.check_arguments
1493
1520
  def standardized_tasks_build_for_angular_codeunit(self, build_script_file: str, build_environment_target_type: str, verbosity: int, commandline_arguments: list[str]) -> None:
1521
+ build_script_folder = os.path.dirname(build_script_file)
1522
+ codeunit_folder = GeneralUtilities.resolve_relative_path("../..", build_script_folder)
1523
+ GeneralUtilities.ensure_directory_does_not_exist(f"{codeunit_folder}/.angular")
1524
+ self.standardized_tasks_build_for_node_codeunit(build_script_file, build_environment_target_type, verbosity, commandline_arguments)
1525
+
1526
+ @GeneralUtilities.check_arguments
1527
+ def standardized_tasks_build_for_node_codeunit(self, build_script_file: str, build_environment_target_type: str, verbosity: int, commandline_arguments: list[str]) -> None:
1494
1528
  verbosity = TasksForCommonProjectStructure.get_verbosity_from_commandline_arguments(commandline_arguments, verbosity)
1495
1529
  build_script_folder = os.path.dirname(build_script_file)
1496
1530
  codeunit_folder = GeneralUtilities.resolve_relative_path("../..", build_script_folder)
1497
- self.run_with_epew("ng", f"build --configuration {build_environment_target_type}", codeunit_folder, verbosity=verbosity)
1531
+ self.run_with_epew("npm", f"run build-{build_environment_target_type}", codeunit_folder, verbosity=verbosity)
1498
1532
  self.standardized_tasks_build_bom_for_node_project(codeunit_folder, verbosity, commandline_arguments)
1499
1533
  self.copy_source_files_to_output_directory(build_script_file)
1500
1534
 
@@ -1505,11 +1539,14 @@ class TasksForCommonProjectStructure:
1505
1539
 
1506
1540
  @GeneralUtilities.check_arguments
1507
1541
  def standardized_tasks_linting_for_angular_codeunit(self, linting_script_file: str, verbosity: int, build_environment_target_type: str, commandline_arguments: list[str]) -> None:
1542
+ self.standardized_tasks_linting_for_node_codeunit(linting_script_file, verbosity, build_environment_target_type, commandline_arguments)
1543
+
1544
+ @GeneralUtilities.check_arguments
1545
+ def standardized_tasks_linting_for_node_codeunit(self, linting_script_file: str, verbosity: int, build_environment_target_type: str, commandline_arguments: list[str]) -> None:
1508
1546
  verbosity = TasksForCommonProjectStructure.get_verbosity_from_commandline_arguments(commandline_arguments, verbosity)
1509
1547
  build_script_folder = os.path.dirname(linting_script_file)
1510
1548
  codeunit_folder = GeneralUtilities.resolve_relative_path("../..", build_script_folder)
1511
1549
  self.run_with_epew("ng", "lint", codeunit_folder, verbosity=verbosity)
1512
- # TODO check if there are errors in sarif-file
1513
1550
 
1514
1551
  @GeneralUtilities.check_arguments
1515
1552
  def standardized_tasks_run_testcases_for_flutter_project_in_common_project_structure(self, script_file: str, verbosity: int, args: list[str], package_name: str, build_environment_target_type: str, generate_badges: bool):
@@ -1543,7 +1580,7 @@ class TasksForCommonProjectStructure:
1543
1580
  repository_folder = os.path.dirname(codeunit_folder)
1544
1581
 
1545
1582
  # run testcases
1546
- self.run_with_epew("ng", "test --watch=false --browsers ChromeHeadless --code-coverage", codeunit_folder, verbosity=verbosity)
1583
+ self.standardized_tasks_run_testcases_for_node_codeunit(runtestcases_script_file, build_environment_target_type, generate_badges, verbosity, commandline_arguments)
1547
1584
 
1548
1585
  # rename file
1549
1586
  coverage_folder = os.path.join(codeunit_folder, "Other", "Artifacts", "TestCoverage")
@@ -1589,6 +1626,12 @@ class TasksForCommonProjectStructure:
1589
1626
  # post tasks
1590
1627
  self.run_testcases_common_post_task(repository_folder, codeunit_name, verbosity, generate_badges, build_environment_target_type, commandline_arguments)
1591
1628
 
1629
+ @GeneralUtilities.check_arguments
1630
+ def standardized_tasks_run_testcases_for_node_codeunit(self, runtestcases_script_file: str, build_environment_target_type: str, generate_badges: bool, verbosity: int, commandline_arguments: list[str]) -> None:
1631
+ verbosity = TasksForCommonProjectStructure.get_verbosity_from_commandline_arguments(commandline_arguments, verbosity)
1632
+ codeunit_folder = GeneralUtilities.resolve_relative_path("../..", os.path.dirname(runtestcases_script_file))
1633
+ self.run_with_epew("npm", f"run test-{build_environment_target_type}", codeunit_folder, verbosity=verbosity)
1634
+
1592
1635
  @GeneralUtilities.check_arguments
1593
1636
  def __rename_packagename_in_coverage_file(self, file: str, codeunit_name: str) -> None:
1594
1637
  root: etree._ElementTree = etree.parse(file)
@@ -1600,13 +1643,13 @@ class TasksForCommonProjectStructure:
1600
1643
 
1601
1644
  @GeneralUtilities.check_arguments
1602
1645
  def do_npm_install(self, package_json_folder: str, verbosity: int) -> None:
1603
- self.run_with_epew("npm", "install", package_json_folder, verbosity=verbosity)
1646
+ self.run_with_epew("npm", "clean-install", package_json_folder, verbosity=verbosity)
1604
1647
 
1605
1648
  @GeneralUtilities.check_arguments
1606
- def run_with_epew(self, program: str, argument: str, working_directory: str, verbosity: int) -> None:
1649
+ def run_with_epew(self, program: str, argument: 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) -> tuple[int, str, str, int]:
1607
1650
  sc: ScriptCollectionCore = ScriptCollectionCore()
1608
1651
  sc.program_runner = ProgramRunnerEpew()
1609
- sc.run_program(program, argument, working_directory, verbosity=verbosity)
1652
+ return sc.run_program(program, argument, 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)
1610
1653
 
1611
1654
  @GeneralUtilities.check_arguments
1612
1655
  def set_default_constants(self, codeunit_folder: str) -> None:
@@ -1829,17 +1872,33 @@ class TasksForCommonProjectStructure:
1829
1872
  for codeunit in codeunits:
1830
1873
  artifact_files.append(self.__sc.find_file_by_extension(f"{build_artifacts_folder}\\{productname}\\{projectversion}\\{codeunit}", "Productive.Artifacts.zip"))
1831
1874
  changelog_file = os.path.join(repository_folder, "Other", "Resources", "Changelog", f"v{projectversion}.md")
1832
- self.__sc.run_program_argsasarray("gh", ["release", "create", f"v{projectversion}", "--repo", github_repo, "--notes-file", changelog_file, "--title", f"Release v{projectversion}"]+artifact_files, verbosity=verbosity)
1875
+ self.__sc.run_program_argsasarray("gh", ["release", "create", f"v{projectversion}", "--repo", github_repo, "--notes-file", changelog_file, "--title", f"Release v{projectversion}"]+artifact_files, verbosity=verbosity)
1876
+
1877
+ @GeneralUtilities.check_arguments
1878
+ def get_dependencies_which_are_ignored_from_updates(self, codeunit_folder: str, print_warnings_for_ignored_dependencies: bool) -> list[str]:
1879
+ namespaces = {'cps': 'https://projects.aniondev.de/PublicProjects/Common/ProjectTemplates/-/tree/main/Conventions/RepositoryStructure/CommonProjectStructure',
1880
+ 'xsi': 'http://www.w3.org/2001/XMLSchema-instance'}
1881
+ codeunit_name = os.path.basename(codeunit_folder)
1882
+ codeunit_file = os.path.join(codeunit_folder, f"{codeunit_name}.codeunit.xml")
1883
+ root: etree._ElementTree = etree.parse(codeunit_file)
1884
+ ignoreddependencies = root.xpath('//cps:codeunit/cps:properties/cps:updatesettings/cps:ignoreddependencies/cps:ignoreddependency', namespaces=namespaces)
1885
+ result = [x.text.replace("\\n", "").replace("\\r", "").replace("\n", "").replace("\r", "").strip() for x in ignoreddependencies]
1886
+ if print_warnings_for_ignored_dependencies and len(result > 0):
1887
+ GeneralUtilities.write_message_to_stderr(f"Warning: Codeunit {codeunit_name} contains the following dependencies which will are ignoed for automatic updates: "+', '.join(result))
1888
+ return result
1833
1889
 
1834
1890
  @GeneralUtilities.check_arguments
1835
1891
  def update_dependencies_of_typical_flutter_codeunit(self, update_script_file: str, verbosity: int, cmd_args: list[str]) -> None:
1836
- pass # TODO
1892
+ codeunit_folder = GeneralUtilities.resolve_relative_path("..", os.path.dirname(update_script_file))
1893
+ ignored_dependencies = self.get_dependencies_which_are_ignored_from_updates(codeunit_folder, True)
1894
+ # TODO implement
1837
1895
 
1838
1896
  @GeneralUtilities.check_arguments
1839
1897
  def update_dependencies_of_typical_python_codeunit(self, update_script_file: str, verbosity: int, cmd_args: list[str]) -> None:
1840
- # TODO generalize and add option to ignore certain dependencies and to only update patch-versions
1841
- verbosity = self.get_verbosity_from_commandline_arguments(cmd_args, verbosity)
1842
1898
  codeunit_folder = GeneralUtilities.resolve_relative_path("..", os.path.dirname(update_script_file))
1899
+ ignored_dependencies = self.get_dependencies_which_are_ignored_from_updates(codeunit_folder, True)
1900
+ # TODO consider ignored_dependencies
1901
+ verbosity = self.get_verbosity_from_commandline_arguments(cmd_args, verbosity)
1843
1902
  self.__sc.update_dependencies_of_python_in_setupcfg_file(os.path.join(codeunit_folder, "setup.cfg"), verbosity)
1844
1903
  development_requirements_file = os.path.join(codeunit_folder, "requirements.txt")
1845
1904
  if (os.path.isfile(development_requirements_file)):
@@ -1847,22 +1906,47 @@ class TasksForCommonProjectStructure:
1847
1906
 
1848
1907
  @GeneralUtilities.check_arguments
1849
1908
  def update_dependencies_of_typical_dotnet_codeunit(self, update_script_file: str, verbosity: int, cmd_args: list[str]) -> None:
1850
- # TODO generalize and add option to ignore certain dependencies
1851
- verbosity = self.get_verbosity_from_commandline_arguments(cmd_args, verbosity)
1852
1909
  codeunit_folder = GeneralUtilities.resolve_relative_path("..", os.path.dirname(update_script_file))
1910
+ ignored_dependencies = self.get_dependencies_which_are_ignored_from_updates(codeunit_folder, True)
1911
+ verbosity = self.get_verbosity_from_commandline_arguments(cmd_args, verbosity)
1853
1912
  codeunit_name = os.path.basename(codeunit_folder)
1854
1913
 
1855
1914
  build_folder = os.path.join(codeunit_folder, "Other", "Build")
1856
1915
  self.__sc.run_program("python", "Build.py", build_folder, verbosity)
1857
1916
 
1858
1917
  csproj_file = os.path.join(codeunit_folder, codeunit_name, f"{codeunit_name}.csproj")
1859
- self.__sc.update_dependencies_of_dotnet_project(csproj_file, verbosity)
1918
+ self.__sc.update_dependencies_of_dotnet_project(csproj_file, verbosity, ignored_dependencies)
1860
1919
  test_csproj_file = os.path.join(codeunit_folder, f"{codeunit_name}Tests", f"{codeunit_name}Tests.csproj")
1861
- self.__sc.update_dependencies_of_dotnet_project(test_csproj_file, verbosity)
1920
+ self.__sc.update_dependencies_of_dotnet_project(test_csproj_file, verbosity, ignored_dependencies)
1862
1921
 
1863
1922
  @GeneralUtilities.check_arguments
1864
1923
  def update_dependencies_of_typical_node_codeunit(self, update_script_file: str, verbosity: int, cmd_args: list[str]) -> None:
1865
- pass # TODO generalize and add option to ignore certain dependencies
1924
+ current_folder = os.path.dirname(update_script_file)
1925
+ codeunit_folder = GeneralUtilities.resolve_relative_path("..", os.path.dirname(update_script_file))
1926
+ ignored_dependencies = self.get_dependencies_which_are_ignored_from_updates(codeunit_folder, True)
1927
+ # TODO consider ignored_dependencies
1928
+ result = self.run_with_epew("npm", "outdated", current_folder, verbosity, throw_exception_if_exitcode_is_not_zero=False)
1929
+ if result[0] == 0:
1930
+ return # all dependencies up to date
1931
+ elif result[0] == 1:
1932
+ package_json_content = None
1933
+ package_json_file = f"{current_folder}/package.json"
1934
+ with open(package_json_file, "r", encoding="utf-8") as package_json_file_object:
1935
+ package_json_content = json.load(package_json_file_object)
1936
+ lines = GeneralUtilities.string_to_lines(result[1])[1:][:-1]
1937
+ for line in lines:
1938
+ normalized_line_splitted = ' '.join(line.split()).split(" ")
1939
+ package = normalized_line_splitted[0]
1940
+ latest_version = normalized_line_splitted[3]
1941
+ if package in package_json_content["dependencies"]:
1942
+ package_json_content["dependencies"][package] = latest_version
1943
+ if package in package_json_content["devDependencies"]:
1944
+ package_json_content["devDependencies"][package] = latest_version
1945
+ with open(package_json_file, "w", encoding="utf-8") as package_json_file_object:
1946
+ json.dump(package_json_content, package_json_file_object, indent=4)
1947
+ self.run_with_epew("npm", "install --force", current_folder, verbosity)
1948
+ else:
1949
+ GeneralUtilities.write_message_to_stderr("Update dependencies resulted in an error.")
1866
1950
 
1867
1951
  @GeneralUtilities.check_arguments
1868
1952
  def run_local_test_service(self, file: str):
@@ -1925,9 +2009,9 @@ class TasksForCommonProjectStructure:
1925
2009
  @GeneralUtilities.check_arguments
1926
2010
  def create_artifact_for_development_certificate(self, codeunit_folder: str):
1927
2011
  ce_source_folder = GeneralUtilities.resolve_relative_path("Other/Resources/DevelopmentCertificate", codeunit_folder)
1928
- ca_source_folder = GeneralUtilities.resolve_relative_path("Other/Resources/DevelopmentCertificateAuthority", codeunit_folder)
2012
+ ca_source_folder = GeneralUtilities.resolve_relative_path("Other/Resources/CA", codeunit_folder)
1929
2013
  ce_target_folder = GeneralUtilities.resolve_relative_path("Other/Artifacts/DevelopmentCertificate", codeunit_folder)
1930
- ca_target_folder = GeneralUtilities.resolve_relative_path("Other/Artifacts/DevelopmentCertificateAuthority", codeunit_folder)
2014
+ ca_target_folder = GeneralUtilities.resolve_relative_path("Other/Artifacts/A", codeunit_folder)
1931
2015
 
1932
2016
  GeneralUtilities.ensure_directory_exists(ce_target_folder)
1933
2017
  GeneralUtilities.copy_content_of_folder(ce_source_folder, ce_target_folder)
@@ -1968,8 +2052,7 @@ class TasksForCommonProjectStructure:
1968
2052
  # TODO handle additional_arguments_file
1969
2053
  # TODO add option to allow building different codeunits in same project with different images due to their demands
1970
2054
  # TODO check if image provides all demands of codeunit
1971
- self.__sc.run_program(
1972
- "docker", f"run --volume {repository_folder}:/Workspace/Repository " + f"-e repositoryfolder=/Workspace/Repository -e verbosity={verbosity} -e targetenvironment={target_environmenttype} {image}", repository_folder)
2055
+ self.__sc.run_program("docker", f"run --volume {repository_folder}:/Workspace/Repository " + f"-e repositoryfolder=/Workspace/Repository -e verbosity={verbosity} -e targetenvironment={target_environmenttype} {image}", repository_folder)
1973
2056
 
1974
2057
  @GeneralUtilities.check_arguments
1975
2058
  def build_codeunits(self, repository_folder: str, verbosity: int = 1, target_environmenttype: str = "QualityCheck", additional_arguments_file: str = None, is_pre_merge: bool = False, export_target_directory: str = None, commandline_arguments: list[str] = []) -> None:
@@ -1987,6 +2070,14 @@ class TasksForCommonProjectStructure:
1987
2070
  raise ValueError(f'Repository "{repository_folder}" has uncommitted changes.')
1988
2071
  subfolders = [os.path.join(repository_folder, codeunit) for codeunit in codeunits]
1989
2072
  codeunits_with_dependent_codeunits: dict[str, set[str]] = dict[str, set[str]]()
2073
+
2074
+ project_resources_folder = os.path.join(repository_folder, "Other", "Scripts")
2075
+ PrepareBuildCodeunits_script_name = "PrepareBuildCodeunits.py"
2076
+ prepare_build_codeunits_scripts = os.path.join(project_resources_folder, PrepareBuildCodeunits_script_name)
2077
+ if os.path.isfile(prepare_build_codeunits_scripts):
2078
+ GeneralUtilities.write_message_to_stdout(f'Run "{PrepareBuildCodeunits_script_name}"')
2079
+ self.__sc.run_program("python", f"{PrepareBuildCodeunits_script_name}", project_resources_folder)
2080
+
1990
2081
  for subfolder in subfolders:
1991
2082
  codeunit_name: str = os.path.basename(subfolder)
1992
2083
  codeunit_file = os.path.join(subfolder, f"{codeunit_name}.codeunit.xml")
@@ -2212,7 +2303,7 @@ class TasksForCommonProjectStructure:
2212
2303
  deb_output_folder = GeneralUtilities.resolve_relative_path("Other/Artifacts/BuildResult_Deb", codeunit_folder)
2213
2304
  control_file = GeneralUtilities.resolve_relative_path("Other/Build/DebControlFile.txt", codeunit_folder)
2214
2305
  installedsize = self.calculate_deb_package_size(binary_folder)
2215
- control_file_content = self.load_deb_control_file_content(control_file, codeunit_name, self.get_version_of_codeunit_folder(codeunit_folder), installedsize, maintainername, maintaineremail, description)
2306
+ control_file_content = self.load_deb_control_file_content(control_file, codeunit_name, self.get_version_of_codeunit_folder(codeunit_folder), installedsize, maintainername, maintaineremail, description)
2216
2307
  self.__sc.create_deb_package(codeunit_name, binary_folder, control_file_content, deb_output_folder, verbosity, 555)
2217
2308
 
2218
2309
  @GeneralUtilities.check_arguments
@@ -2387,6 +2478,7 @@ class TasksForCommonProjectStructure:
2387
2478
  GeneralUtilities.ensure_directory_exists(os.path.join(update_dependencies_script_folder, "Resources", "CodeAnalysisResult"))
2388
2479
  self.__sc.run_program("python", "UpdateDependencies.py", update_dependencies_script_folder, verbosity)
2389
2480
  if self.__sc.git_repository_has_uncommitted_changes(repository_folder):
2481
+ updated_dependencies = True
2390
2482
  version_of_project = self.get_version_of_project(repository_folder)
2391
2483
  changelog_file = os.path.join(repository_folder, "Other", "Resources", "Changelog", f"v{version_of_project}.md")
2392
2484
  if not os.path.isfile(changelog_file):
@@ -2397,7 +2489,6 @@ class TasksForCommonProjectStructure:
2397
2489
  - Updated dependencies.
2398
2490
  """)
2399
2491
  GeneralUtilities.write_message_to_stdout(f"Updated dependencies in codeunit {codeunit}.")
2400
- updated_dependencies = True
2401
2492
  else:
2402
2493
  GeneralUtilities.write_message_to_stdout(f"There are no dependencies to update in codeunit {codeunit}.")
2403
2494
  if updated_dependencies:
@@ -2423,15 +2514,26 @@ class TasksForCommonProjectStructure:
2423
2514
 
2424
2515
  repository_folder = GeneralUtilities.resolve_relative_path(f"../../Submodules/{generic_prepare_new_release_arguments.product_name}", folder_of_this_file)
2425
2516
  verbosity: int = TasksForCommonProjectStructure.get_verbosity_from_commandline_arguments(generic_prepare_new_release_arguments.commandline_arguments, 1)
2426
- merge_source_branch = "other/next-release"
2517
+
2518
+ merge_source_branch = "other/next-release" # TODO make this configurable
2519
+ main_branch = "main" # TODO make this configurable
2427
2520
 
2428
2521
  # prepare
2429
2522
  self.assert_no_uncommitted_changes(repository_folder)
2430
2523
  self.__sc.git_checkout(repository_folder, merge_source_branch)
2524
+ self.assert_no_uncommitted_changes(repository_folder)
2525
+
2431
2526
  if "--dependencyupdate" in generic_prepare_new_release_arguments.commandline_arguments:
2432
2527
  self.generic_update_dependencies(repository_folder)
2433
- self.merge_to_main_branch(repository_folder, merge_source_branch, verbosity=verbosity, fast_forward_source_branch=True)
2434
- self.__sc.git_commit(build_repository_folder, "Updated submodule due to merge to main-branch.")
2528
+ self.assert_no_uncommitted_changes(repository_folder)
2529
+
2530
+ merge_source_branch_commit_id = self.__sc.git_get_commit_id(repository_folder, merge_source_branch)
2531
+ main_branch_commit_id = self.__sc.git_get_commit_id(repository_folder, main_branch)
2532
+ if merge_source_branch_commit_id == main_branch_commit_id:
2533
+ GeneralUtilities.write_message_to_stdout("Release will not be prepared because there are no changed which can be released.")
2534
+ else:
2535
+ self.merge_to_main_branch(repository_folder, merge_source_branch, verbosity=verbosity, fast_forward_source_branch=True)
2536
+ self.__sc.git_commit(build_repository_folder, "Updated submodule due to merge to main-branch.")
2435
2537
 
2436
2538
  class GenericCreateReleaseArguments():
2437
2539
  current_file: str
@@ -2448,28 +2550,33 @@ class TasksForCommonProjectStructure:
2448
2550
  self.commandline_arguments = commandline_arguments
2449
2551
 
2450
2552
  @GeneralUtilities.check_arguments
2451
- def generic_create_release(self, generic_create_release_arguments: GenericCreateReleaseArguments) -> str:
2553
+ def generic_create_release(self, generic_create_release_arguments: GenericCreateReleaseArguments) -> tuple[bool, str]:
2452
2554
  folder_of_this_file = os.path.dirname(generic_create_release_arguments.current_file)
2453
2555
  build_repository_folder = GeneralUtilities.resolve_relative_path("../..", folder_of_this_file)
2454
2556
  repository_folder_name = generic_create_release_arguments.product_name
2455
2557
  repository_folder = GeneralUtilities.resolve_relative_path(f"../../Submodules/{generic_create_release_arguments.product_name}", folder_of_this_file)
2456
- additional_arguments_file = os.path.join(folder_of_this_file, "AdditionalArguments.configuration")
2457
- verbosity: int = TasksForCommonProjectStructure.get_verbosity_from_commandline_arguments(generic_create_release_arguments.commandline_arguments, 1)
2458
- createReleaseConfiguration: CreateReleaseConfiguration = CreateReleaseConfiguration(
2459
- generic_create_release_arguments.product_name, generic_create_release_arguments.common_remote_name, generic_create_release_arguments.artifacts_target_folder, folder_of_this_file, verbosity, repository_folder, additional_arguments_file, repository_folder_name)
2460
2558
 
2461
- reference_repo: str = os.path.join(build_repository_folder, "Submodules", f"{generic_create_release_arguments.product_name}Reference")
2462
- self.__sc.git_commit(reference_repo, "Updated reference")
2559
+ merge_source_branch = "main" # TODO make this configurable
2560
+ main_branch = "stable" # TODO make this configurable
2463
2561
 
2464
- self.__sc.git_commit(build_repository_folder, "Updated submodule")
2465
-
2466
- # create release
2467
- new_version = self.merge_to_stable_branch(generic_create_release_arguments.current_file, createReleaseConfiguration)
2468
-
2469
- merge_source_branch = "other/next-release"
2470
- self.__sc.git_checkout(repository_folder, merge_source_branch)
2562
+ additional_arguments_file = os.path.join(folder_of_this_file, "AdditionalArguments.configuration")
2563
+ verbosity: int = TasksForCommonProjectStructure.get_verbosity_from_commandline_arguments(generic_create_release_arguments.commandline_arguments, 1)
2564
+ createReleaseConfiguration: CreateReleaseConfiguration = CreateReleaseConfiguration(generic_create_release_arguments.product_name, generic_create_release_arguments.common_remote_name, generic_create_release_arguments.artifacts_target_folder, folder_of_this_file, verbosity, repository_folder, additional_arguments_file, repository_folder_name)
2471
2565
 
2472
- return new_version
2566
+ merge_source_branch_commit_id = self.__sc.git_get_commit_id(repository_folder, merge_source_branch)
2567
+ main_branch_commit_id = self.__sc.git_get_commit_id(repository_folder, main_branch)
2568
+ if merge_source_branch_commit_id == main_branch_commit_id:
2569
+ GeneralUtilities.write_message_to_stdout("Release will not be done because there are no changed which can be released.")
2570
+ return False, None
2571
+ else:
2572
+ reference_repo: str = os.path.join(build_repository_folder, "Submodules", f"{generic_create_release_arguments.product_name}Reference")
2573
+ self.__sc.git_commit(reference_repo, "Updated reference")
2574
+ self.__sc.git_commit(build_repository_folder, "Updated submodule")
2575
+
2576
+ # create release
2577
+ new_version = self.merge_to_stable_branch(generic_create_release_arguments.current_file, createReleaseConfiguration)
2578
+ self.__sc.git_checkout(repository_folder, merge_source_branch)
2579
+ return True, new_version
2473
2580
 
2474
2581
  class UpdateHTTPDocumentationArguments:
2475
2582
  current_file: str
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ScriptCollection
3
- Version: 3.5.4
3
+ Version: 3.5.7
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
@@ -0,0 +1,16 @@
1
+ ScriptCollection/Executables.py,sha256=0I_yTMX-mkbgatm8O7Pvtv2rG5Ep4C0iqUYDL92hINE,19241
2
+ ScriptCollection/GeneralUtilities.py,sha256=urvslHJx_ptJgzGjRoc4KKyFtPYWvs2ifLD_MKACnxg,35810
3
+ ScriptCollection/ProcessesRunner.py,sha256=3mu4ZxzZleQo0Op6o9EYTCFiJfb6kx5ov2YfZfT89mU,1395
4
+ ScriptCollection/ProgramRunnerBase.py,sha256=W4MaDroJHARRtcvPkBC2AS_qgDSRIqOkMvGyycZjtPk,2371
5
+ ScriptCollection/ProgramRunnerEpew.py,sha256=lx_jR3W8KavBpZo44u2FrOca_EWWgUb3_w_YKGRrAyM,6471
6
+ ScriptCollection/ProgramRunnerPopen.py,sha256=5QFplojwfGS8_WdYrg5nE6__QFB5iaMA0EP8OGfgPoY,3526
7
+ ScriptCollection/RPStream.py,sha256=NRRHL3YSP3D9MuAV2jB_--0KUKCsvJGxeKnxgrRZ9kY,1545
8
+ ScriptCollection/ScriptCollectionCore.py,sha256=-HpxrPjlHNPv1Ud4Pxh-vH-dEJJGvw4jyI-_5xsGOKo,96539
9
+ ScriptCollection/TasksForCommonProjectStructure.py,sha256=jExRHYZQfRJWY4NDboREI1NfYjHMvIabsKZ05qi8DoA,186707
10
+ ScriptCollection/UpdateCertificates.py,sha256=lfmVuify-Fqq-vGJusDDUsJVhA-rVLwW2Jx9iLwmkBo,7916
11
+ ScriptCollection/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
+ ScriptCollection-3.5.7.dist-info/METADATA,sha256=cG_gwtTzfmBIksPGZK3VGJZ0Tafat4-G1UeTuQSuyts,7679
13
+ ScriptCollection-3.5.7.dist-info/WHEEL,sha256=Wyh-_nZ0DJYolHNn1_hMa4lM7uDedD_RGVwbmTjyItk,91
14
+ ScriptCollection-3.5.7.dist-info/entry_points.txt,sha256=dwvB9HRGvqst5xlYIGmmwuFN7lBKhxvndmnNrQOfu8w,2153
15
+ ScriptCollection-3.5.7.dist-info/top_level.txt,sha256=hY2hOVH0V0Ce51WB76zKkIWTUNwMUdHo4XDkR2vYVwg,17
16
+ ScriptCollection-3.5.7.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (71.0.3)
2
+ Generator: setuptools (71.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,16 +0,0 @@
1
- ScriptCollection/Executables.py,sha256=PXXsKmof-Lw4gQcQ8IL0diYiU535FVxJfHRdAY7EntA,19233
2
- ScriptCollection/GeneralUtilities.py,sha256=Mcp6ghb6AbS1KsOjEnRw3x4a4mBrAZ6DAjV2j8-LZFM,35589
3
- ScriptCollection/ProcessesRunner.py,sha256=3mu4ZxzZleQo0Op6o9EYTCFiJfb6kx5ov2YfZfT89mU,1395
4
- ScriptCollection/ProgramRunnerBase.py,sha256=W4MaDroJHARRtcvPkBC2AS_qgDSRIqOkMvGyycZjtPk,2371
5
- ScriptCollection/ProgramRunnerEpew.py,sha256=lx_jR3W8KavBpZo44u2FrOca_EWWgUb3_w_YKGRrAyM,6471
6
- ScriptCollection/ProgramRunnerPopen.py,sha256=5QFplojwfGS8_WdYrg5nE6__QFB5iaMA0EP8OGfgPoY,3526
7
- ScriptCollection/RPStream.py,sha256=NRRHL3YSP3D9MuAV2jB_--0KUKCsvJGxeKnxgrRZ9kY,1545
8
- ScriptCollection/ScriptCollectionCore.py,sha256=AxOvDgrExHfoBNBqRQbDtTdqOjvEfIhmRUKanNwZYCc,97562
9
- ScriptCollection/TasksForCommonProjectStructure.py,sha256=JLp43wCRcY62rC0UErBCPOHQaKh6Ujtj3sDTxq3cz54,177788
10
- ScriptCollection/UpdateCertificates.py,sha256=lfmVuify-Fqq-vGJusDDUsJVhA-rVLwW2Jx9iLwmkBo,7916
11
- ScriptCollection/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
- ScriptCollection-3.5.4.dist-info/METADATA,sha256=u8vV56vbKQP8FoiLLJM4Q_nZ0qTd6NMlHMQDjddK4ZQ,7679
13
- ScriptCollection-3.5.4.dist-info/WHEEL,sha256=-oYQCr74JF3a37z2nRlQays_SX2MqOANoqVjBBAP2yE,91
14
- ScriptCollection-3.5.4.dist-info/entry_points.txt,sha256=dwvB9HRGvqst5xlYIGmmwuFN7lBKhxvndmnNrQOfu8w,2153
15
- ScriptCollection-3.5.4.dist-info/top_level.txt,sha256=hY2hOVH0V0Ce51WB76zKkIWTUNwMUdHo4XDkR2vYVwg,17
16
- ScriptCollection-3.5.4.dist-info/RECORD,,