ScriptCollection 3.5.5__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.
@@ -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.5"
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:
@@ -1262,13 +1259,9 @@ class ScriptCollectionCore:
1262
1259
  working_directory = self.__adapt_workingdirectory(working_directory)
1263
1260
 
1264
1261
  if arguments_for_log is None:
1265
- arguments_for_log = ' '.join(arguments_as_array)
1266
- else:
1267
- arguments_for_log = ' '.join(arguments_for_log)
1268
-
1269
- arguments_for_exception_as_string = arguments_for_log
1262
+ arguments_for_log = arguments_as_array
1270
1263
 
1271
- arguments_for_log_as_string = arguments_for_log
1264
+ arguments_for_log_as_string: str = ' '.join(arguments_for_log)
1272
1265
  cmd = f'{working_directory}>{program} {arguments_for_log_as_string}'
1273
1266
 
1274
1267
  if GeneralUtilities.string_is_none_or_whitespace(title):
@@ -1278,7 +1271,6 @@ class ScriptCollectionCore:
1278
1271
 
1279
1272
  if verbosity >= 3:
1280
1273
  GeneralUtilities.write_message_to_stdout(f"Run '{info_for_log}'.")
1281
-
1282
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:
1283
1275
  pid = process.pid
1284
1276
 
@@ -1350,14 +1342,8 @@ class ScriptCollectionCore:
1350
1342
  stdout = GeneralUtilities.bytes_to_string(stdout).replace('\r', '')
1351
1343
  stderr = GeneralUtilities.bytes_to_string(stderr).replace('\r', '')
1352
1344
 
1353
- if arguments_for_exception_as_string is None:
1354
- arguments_for_exception_as_string = ' '.join(arguments_as_array)
1355
- else:
1356
- arguments_for_exception_as_string = ' '.join(arguments_for_log)
1357
-
1358
1345
  if throw_exception_if_exitcode_is_not_zero and exit_code != 0:
1359
- arguments_for_exception_as_string = ' '.join(arguments_for_log)
1360
- 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}')")
1361
1347
 
1362
1348
  result = (exit_code, stdout, stderr, pid)
1363
1349
  return result
@@ -1543,13 +1529,13 @@ class ScriptCollectionCore:
1543
1529
  return result
1544
1530
 
1545
1531
  @GeneralUtilities.check_arguments
1546
- 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:
1547
1533
  if days_until_expire is None:
1548
1534
  days_until_expire = 1825
1549
1535
  if password is None:
1550
1536
  password = GeneralUtilities.generate_password()
1551
- self.run_program(
1552
- "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)
1553
1539
 
1554
1540
  @GeneralUtilities.check_arguments
1555
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:
@@ -1598,10 +1584,8 @@ DNS = {domain}
1598
1584
  ca = os.path.join(ca_folder, ca_name)
1599
1585
  password_file = os.path.join(folder, f"{filename}.password")
1600
1586
  password = GeneralUtilities.read_text_from_file(password_file)
1601
- self.run_program(
1602
- "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)
1603
- self.run_program(
1604
- "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)
1605
1589
 
1606
1590
  @GeneralUtilities.check_arguments
1607
1591
  def update_dependencies_of_python_in_requirementstxt_file(self, file: str, verbosity: int):
@@ -1649,7 +1633,7 @@ DNS = {domain}
1649
1633
  GeneralUtilities.write_lines_to_file(setup_cfg_file, new_lines)
1650
1634
 
1651
1635
  @GeneralUtilities.check_arguments
1652
- 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]):
1653
1637
  folder = os.path.dirname(csproj_file)
1654
1638
  csproj_filename = os.path.basename(csproj_file)
1655
1639
  GeneralUtilities.write_message_to_stderr(f"Check for updates in {csproj_filename}")
@@ -1658,12 +1642,12 @@ DNS = {domain}
1658
1642
  # Relevant output-lines are something like " > NJsonSchema 10.7.0 10.7.0 10.9.0"
1659
1643
  if ">" in line:
1660
1644
  package_name = line.replace(">", "").strip().split(" ")[0]
1661
- GeneralUtilities.write_message_to_stderr(f"Update package {package_name}")
1662
- self.run_program(
1663
- "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)
1664
1648
 
1665
1649
  @GeneralUtilities.check_arguments
1666
- 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:
1667
1651
 
1668
1652
  # prepare
1669
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())
@@ -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)
@@ -1494,7 +1521,7 @@ class TasksForCommonProjectStructure:
1494
1521
  build_script_folder = os.path.dirname(build_script_file)
1495
1522
  codeunit_folder = GeneralUtilities.resolve_relative_path("../..", build_script_folder)
1496
1523
  GeneralUtilities.ensure_directory_does_not_exist(f"{codeunit_folder}/.angular")
1497
- self.standardized_tasks_build_for_angular_codeunit(build_script_file, build_environment_target_type, verbosity, commandline_arguments)
1524
+ self.standardized_tasks_build_for_node_codeunit(build_script_file, build_environment_target_type, verbosity, commandline_arguments)
1498
1525
 
1499
1526
  @GeneralUtilities.check_arguments
1500
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:
@@ -1845,17 +1872,33 @@ class TasksForCommonProjectStructure:
1845
1872
  for codeunit in codeunits:
1846
1873
  artifact_files.append(self.__sc.find_file_by_extension(f"{build_artifacts_folder}\\{productname}\\{projectversion}\\{codeunit}", "Productive.Artifacts.zip"))
1847
1874
  changelog_file = os.path.join(repository_folder, "Other", "Resources", "Changelog", f"v{projectversion}.md")
1848
- 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
1849
1889
 
1850
1890
  @GeneralUtilities.check_arguments
1851
1891
  def update_dependencies_of_typical_flutter_codeunit(self, update_script_file: str, verbosity: int, cmd_args: list[str]) -> None:
1852
- pass # TODO generalize and add option to ignore certain dependencies
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
1853
1895
 
1854
1896
  @GeneralUtilities.check_arguments
1855
1897
  def update_dependencies_of_typical_python_codeunit(self, update_script_file: str, verbosity: int, cmd_args: list[str]) -> None:
1856
- # TODO generalize and add option to ignore certain dependencies and to only update patch-versions
1857
- verbosity = self.get_verbosity_from_commandline_arguments(cmd_args, verbosity)
1858
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)
1859
1902
  self.__sc.update_dependencies_of_python_in_setupcfg_file(os.path.join(codeunit_folder, "setup.cfg"), verbosity)
1860
1903
  development_requirements_file = os.path.join(codeunit_folder, "requirements.txt")
1861
1904
  if (os.path.isfile(development_requirements_file)):
@@ -1863,22 +1906,25 @@ class TasksForCommonProjectStructure:
1863
1906
 
1864
1907
  @GeneralUtilities.check_arguments
1865
1908
  def update_dependencies_of_typical_dotnet_codeunit(self, update_script_file: str, verbosity: int, cmd_args: list[str]) -> None:
1866
- # TODO generalize and add option to ignore certain dependencies
1867
- verbosity = self.get_verbosity_from_commandline_arguments(cmd_args, verbosity)
1868
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)
1869
1912
  codeunit_name = os.path.basename(codeunit_folder)
1870
1913
 
1871
1914
  build_folder = os.path.join(codeunit_folder, "Other", "Build")
1872
1915
  self.__sc.run_program("python", "Build.py", build_folder, verbosity)
1873
1916
 
1874
1917
  csproj_file = os.path.join(codeunit_folder, codeunit_name, f"{codeunit_name}.csproj")
1875
- self.__sc.update_dependencies_of_dotnet_project(csproj_file, verbosity)
1918
+ self.__sc.update_dependencies_of_dotnet_project(csproj_file, verbosity, ignored_dependencies)
1876
1919
  test_csproj_file = os.path.join(codeunit_folder, f"{codeunit_name}Tests", f"{codeunit_name}Tests.csproj")
1877
- 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)
1878
1921
 
1879
1922
  @GeneralUtilities.check_arguments
1880
1923
  def update_dependencies_of_typical_node_codeunit(self, update_script_file: str, verbosity: int, cmd_args: list[str]) -> None:
1881
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
1882
1928
  result = self.run_with_epew("npm", "outdated", current_folder, verbosity, throw_exception_if_exitcode_is_not_zero=False)
1883
1929
  if result[0] == 0:
1884
1930
  return # all dependencies up to date
@@ -1963,9 +2009,9 @@ class TasksForCommonProjectStructure:
1963
2009
  @GeneralUtilities.check_arguments
1964
2010
  def create_artifact_for_development_certificate(self, codeunit_folder: str):
1965
2011
  ce_source_folder = GeneralUtilities.resolve_relative_path("Other/Resources/DevelopmentCertificate", codeunit_folder)
1966
- 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)
1967
2013
  ce_target_folder = GeneralUtilities.resolve_relative_path("Other/Artifacts/DevelopmentCertificate", codeunit_folder)
1968
- 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)
1969
2015
 
1970
2016
  GeneralUtilities.ensure_directory_exists(ce_target_folder)
1971
2017
  GeneralUtilities.copy_content_of_folder(ce_source_folder, ce_target_folder)
@@ -2006,8 +2052,7 @@ class TasksForCommonProjectStructure:
2006
2052
  # TODO handle additional_arguments_file
2007
2053
  # TODO add option to allow building different codeunits in same project with different images due to their demands
2008
2054
  # TODO check if image provides all demands of codeunit
2009
- self.__sc.run_program(
2010
- "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)
2011
2056
 
2012
2057
  @GeneralUtilities.check_arguments
2013
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:
@@ -2025,6 +2070,14 @@ class TasksForCommonProjectStructure:
2025
2070
  raise ValueError(f'Repository "{repository_folder}" has uncommitted changes.')
2026
2071
  subfolders = [os.path.join(repository_folder, codeunit) for codeunit in codeunits]
2027
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
+
2028
2081
  for subfolder in subfolders:
2029
2082
  codeunit_name: str = os.path.basename(subfolder)
2030
2083
  codeunit_file = os.path.join(subfolder, f"{codeunit_name}.codeunit.xml")
@@ -2250,7 +2303,7 @@ class TasksForCommonProjectStructure:
2250
2303
  deb_output_folder = GeneralUtilities.resolve_relative_path("Other/Artifacts/BuildResult_Deb", codeunit_folder)
2251
2304
  control_file = GeneralUtilities.resolve_relative_path("Other/Build/DebControlFile.txt", codeunit_folder)
2252
2305
  installedsize = self.calculate_deb_package_size(binary_folder)
2253
- 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)
2254
2307
  self.__sc.create_deb_package(codeunit_name, binary_folder, control_file_content, deb_output_folder, verbosity, 555)
2255
2308
 
2256
2309
  @GeneralUtilities.check_arguments
@@ -2425,6 +2478,7 @@ class TasksForCommonProjectStructure:
2425
2478
  GeneralUtilities.ensure_directory_exists(os.path.join(update_dependencies_script_folder, "Resources", "CodeAnalysisResult"))
2426
2479
  self.__sc.run_program("python", "UpdateDependencies.py", update_dependencies_script_folder, verbosity)
2427
2480
  if self.__sc.git_repository_has_uncommitted_changes(repository_folder):
2481
+ updated_dependencies = True
2428
2482
  version_of_project = self.get_version_of_project(repository_folder)
2429
2483
  changelog_file = os.path.join(repository_folder, "Other", "Resources", "Changelog", f"v{version_of_project}.md")
2430
2484
  if not os.path.isfile(changelog_file):
@@ -2435,7 +2489,6 @@ class TasksForCommonProjectStructure:
2435
2489
  - Updated dependencies.
2436
2490
  """)
2437
2491
  GeneralUtilities.write_message_to_stdout(f"Updated dependencies in codeunit {codeunit}.")
2438
- updated_dependencies = True
2439
2492
  else:
2440
2493
  GeneralUtilities.write_message_to_stdout(f"There are no dependencies to update in codeunit {codeunit}.")
2441
2494
  if updated_dependencies:
@@ -2461,15 +2514,26 @@ class TasksForCommonProjectStructure:
2461
2514
 
2462
2515
  repository_folder = GeneralUtilities.resolve_relative_path(f"../../Submodules/{generic_prepare_new_release_arguments.product_name}", folder_of_this_file)
2463
2516
  verbosity: int = TasksForCommonProjectStructure.get_verbosity_from_commandline_arguments(generic_prepare_new_release_arguments.commandline_arguments, 1)
2464
- 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
2465
2520
 
2466
2521
  # prepare
2467
2522
  self.assert_no_uncommitted_changes(repository_folder)
2468
2523
  self.__sc.git_checkout(repository_folder, merge_source_branch)
2524
+ self.assert_no_uncommitted_changes(repository_folder)
2525
+
2469
2526
  if "--dependencyupdate" in generic_prepare_new_release_arguments.commandline_arguments:
2470
2527
  self.generic_update_dependencies(repository_folder)
2471
- self.merge_to_main_branch(repository_folder, merge_source_branch, verbosity=verbosity, fast_forward_source_branch=True)
2472
- 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.")
2473
2537
 
2474
2538
  class GenericCreateReleaseArguments():
2475
2539
  current_file: str
@@ -2486,28 +2550,33 @@ class TasksForCommonProjectStructure:
2486
2550
  self.commandline_arguments = commandline_arguments
2487
2551
 
2488
2552
  @GeneralUtilities.check_arguments
2489
- 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]:
2490
2554
  folder_of_this_file = os.path.dirname(generic_create_release_arguments.current_file)
2491
2555
  build_repository_folder = GeneralUtilities.resolve_relative_path("../..", folder_of_this_file)
2492
2556
  repository_folder_name = generic_create_release_arguments.product_name
2493
2557
  repository_folder = GeneralUtilities.resolve_relative_path(f"../../Submodules/{generic_create_release_arguments.product_name}", folder_of_this_file)
2494
- additional_arguments_file = os.path.join(folder_of_this_file, "AdditionalArguments.configuration")
2495
- verbosity: int = TasksForCommonProjectStructure.get_verbosity_from_commandline_arguments(generic_create_release_arguments.commandline_arguments, 1)
2496
- createReleaseConfiguration: CreateReleaseConfiguration = CreateReleaseConfiguration(
2497
- 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)
2498
-
2499
- reference_repo: str = os.path.join(build_repository_folder, "Submodules", f"{generic_create_release_arguments.product_name}Reference")
2500
- self.__sc.git_commit(reference_repo, "Updated reference")
2501
-
2502
- self.__sc.git_commit(build_repository_folder, "Updated submodule")
2503
2558
 
2504
- # create release
2505
- new_version = self.merge_to_stable_branch(generic_create_release_arguments.current_file, createReleaseConfiguration)
2559
+ merge_source_branch = "main" # TODO make this configurable
2560
+ main_branch = "stable" # TODO make this configurable
2506
2561
 
2507
- merge_source_branch = "other/next-release"
2508
- 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)
2509
2565
 
2510
- 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
2511
2580
 
2512
2581
  class UpdateHTTPDocumentationArguments:
2513
2582
  current_file: str
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ScriptCollection
3
- Version: 3.5.5
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
@@ -5,12 +5,12 @@ ScriptCollection/ProgramRunnerBase.py,sha256=W4MaDroJHARRtcvPkBC2AS_qgDSRIqOkMvG
5
5
  ScriptCollection/ProgramRunnerEpew.py,sha256=lx_jR3W8KavBpZo44u2FrOca_EWWgUb3_w_YKGRrAyM,6471
6
6
  ScriptCollection/ProgramRunnerPopen.py,sha256=5QFplojwfGS8_WdYrg5nE6__QFB5iaMA0EP8OGfgPoY,3526
7
7
  ScriptCollection/RPStream.py,sha256=NRRHL3YSP3D9MuAV2jB_--0KUKCsvJGxeKnxgrRZ9kY,1545
8
- ScriptCollection/ScriptCollectionCore.py,sha256=2HgYhQ22DDDs9s1Qjuvd7fKUWsOPrnaYSoHimWbC_ow,97054
9
- ScriptCollection/TasksForCommonProjectStructure.py,sha256=kz6AZENxwC7oYJp3Neuhs-oLbyXkn-p0j-2AQ6fHBMA,181486
8
+ ScriptCollection/ScriptCollectionCore.py,sha256=-HpxrPjlHNPv1Ud4Pxh-vH-dEJJGvw4jyI-_5xsGOKo,96539
9
+ ScriptCollection/TasksForCommonProjectStructure.py,sha256=jExRHYZQfRJWY4NDboREI1NfYjHMvIabsKZ05qi8DoA,186707
10
10
  ScriptCollection/UpdateCertificates.py,sha256=lfmVuify-Fqq-vGJusDDUsJVhA-rVLwW2Jx9iLwmkBo,7916
11
11
  ScriptCollection/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
- ScriptCollection-3.5.5.dist-info/METADATA,sha256=K1hVO826FAyAgMcqSqTxuf1lJ3F_Y4rIQbQ7QVffMQg,7679
13
- ScriptCollection-3.5.5.dist-info/WHEEL,sha256=Wyh-_nZ0DJYolHNn1_hMa4lM7uDedD_RGVwbmTjyItk,91
14
- ScriptCollection-3.5.5.dist-info/entry_points.txt,sha256=dwvB9HRGvqst5xlYIGmmwuFN7lBKhxvndmnNrQOfu8w,2153
15
- ScriptCollection-3.5.5.dist-info/top_level.txt,sha256=hY2hOVH0V0Ce51WB76zKkIWTUNwMUdHo4XDkR2vYVwg,17
16
- ScriptCollection-3.5.5.dist-info/RECORD,,
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,,