ScriptCollection 3.3.23__py3-none-any.whl → 4.0.78__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.
Files changed (47) hide show
  1. ScriptCollection/AnionBuildPlatform.py +206 -0
  2. ScriptCollection/{UpdateCertificates.py → CertificateUpdater.py} +149 -128
  3. ScriptCollection/Executables.py +868 -292
  4. ScriptCollection/GeneralUtilities.py +609 -107
  5. ScriptCollection/ImageUpdater.py +648 -0
  6. ScriptCollection/ProcessesRunner.py +41 -0
  7. ScriptCollection/ProgramRunnerBase.py +47 -42
  8. ScriptCollection/ProgramRunnerMock.py +2 -0
  9. ScriptCollection/ProgramRunnerPopen.py +57 -50
  10. ScriptCollection/ProgramRunnerSudo.py +108 -0
  11. ScriptCollection/SCLog.py +115 -0
  12. ScriptCollection/ScriptCollectionCore.py +2541 -1383
  13. ScriptCollection/TFCPS/Docker/TFCPS_CodeUnitSpecific_Docker.py +95 -0
  14. ScriptCollection/TFCPS/Docker/__init__.py +0 -0
  15. ScriptCollection/TFCPS/DotNet/CertificateGeneratorInformationBase.py +8 -0
  16. ScriptCollection/TFCPS/DotNet/CertificateGeneratorInformationGenerate.py +6 -0
  17. ScriptCollection/TFCPS/DotNet/CertificateGeneratorInformationNoGenerate.py +7 -0
  18. ScriptCollection/TFCPS/DotNet/TFCPS_CodeUnitSpecific_DotNet.py +485 -0
  19. ScriptCollection/TFCPS/DotNet/__init__.py +0 -0
  20. ScriptCollection/TFCPS/Flutter/TFCPS_CodeUnitSpecific_Flutter.py +130 -0
  21. ScriptCollection/TFCPS/Flutter/__init__.py +0 -0
  22. ScriptCollection/TFCPS/Go/TFCPS_CodeUnitSpecific_Go.py +74 -0
  23. ScriptCollection/TFCPS/Go/__init__.py +0 -0
  24. ScriptCollection/TFCPS/NodeJS/TFCPS_CodeUnitSpecific_NodeJS.py +131 -0
  25. ScriptCollection/TFCPS/NodeJS/__init__.py +0 -0
  26. ScriptCollection/TFCPS/Python/TFCPS_CodeUnitSpecific_Python.py +227 -0
  27. ScriptCollection/TFCPS/Python/__init__.py +0 -0
  28. ScriptCollection/TFCPS/TFCPS_CodeUnitSpecific_Base.py +418 -0
  29. ScriptCollection/TFCPS/TFCPS_CodeUnit_BuildCodeUnit.py +128 -0
  30. ScriptCollection/TFCPS/TFCPS_CodeUnit_BuildCodeUnits.py +136 -0
  31. ScriptCollection/TFCPS/TFCPS_CreateRelease.py +95 -0
  32. ScriptCollection/TFCPS/TFCPS_Generic.py +43 -0
  33. ScriptCollection/TFCPS/TFCPS_MergeToMain.py +122 -0
  34. ScriptCollection/TFCPS/TFCPS_MergeToStable.py +350 -0
  35. ScriptCollection/TFCPS/TFCPS_PreBuildCodeunitsScript.py +47 -0
  36. ScriptCollection/TFCPS/TFCPS_Tools_General.py +1356 -0
  37. ScriptCollection/TFCPS/__init__.py +0 -0
  38. {ScriptCollection-3.3.23.dist-info → scriptcollection-4.0.78.dist-info}/METADATA +26 -21
  39. scriptcollection-4.0.78.dist-info/RECORD +43 -0
  40. {ScriptCollection-3.3.23.dist-info → scriptcollection-4.0.78.dist-info}/WHEEL +1 -1
  41. scriptcollection-4.0.78.dist-info/entry_points.txt +64 -0
  42. ScriptCollection/Hardening.py +0 -59
  43. ScriptCollection/ProgramRunnerEpew.py +0 -122
  44. ScriptCollection/TasksForCommonProjectStructure.py +0 -1170
  45. ScriptCollection-3.3.23.dist-info/RECORD +0 -15
  46. ScriptCollection-3.3.23.dist-info/entry_points.txt +0 -24
  47. {ScriptCollection-3.3.23.dist-info → scriptcollection-4.0.78.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,95 @@
1
+ import os
2
+ from ...GeneralUtilities import GeneralUtilities
3
+ from ...SCLog import LogLevel
4
+ from ..TFCPS_CodeUnitSpecific_Base import TFCPS_CodeUnitSpecific_Base,TFCPS_CodeUnitSpecific_Base_CLI
5
+
6
+ class TFCPS_CodeUnitSpecific_Docker_Functions(TFCPS_CodeUnitSpecific_Base):
7
+
8
+ def __init__(self,current_file:str,verbosity:LogLevel,targetenvironmenttype:str,use_cache:bool,is_pre_merge:bool):
9
+ super().__init__(current_file, verbosity,targetenvironmenttype,use_cache,is_pre_merge)
10
+
11
+
12
+ @GeneralUtilities.check_arguments
13
+ def build(self=None) -> None:
14
+
15
+ codeunitname: str =self.get_codeunit_name()
16
+ codeunit_folder =self.get_codeunit_folder()
17
+ codeunitname_lower = codeunitname.lower()
18
+ codeunit_file =self.get_codeunit_file()
19
+ codeunitversion = self.tfcps_Tools_General.get_version_of_codeunit(codeunit_file)
20
+ args = ["image", "build", "--pull", "--force-rm", "--progress=plain", "--build-arg", f"TargetEnvironmentType={self.get_target_environment_type()}", "--build-arg", f"CodeUnitName={codeunitname}", "--build-arg", f"CodeUnitVersion={codeunitversion}", "--build-arg", f"CodeUnitOwnerName={self.tfcps_Tools_General.get_codeunit_owner_name(self.get_codeunit_file())}", "--build-arg", f"CodeUnitOwnerEMailAddress={self.tfcps_Tools_General.get_codeunit_owner_emailaddress(self.get_codeunit_file())}"]
21
+ custom_arguments:dict[str,str]={}#TODO must be setable from outside
22
+ if custom_arguments is not None:
23
+ for custom_argument_key, custom_argument_value in custom_arguments.items():
24
+ args.append("--build-arg")
25
+ args.append(f"{custom_argument_key}={custom_argument_value}")
26
+ args = args+["--tag", f"{codeunitname_lower}:latest", "--tag", f"{codeunitname_lower}:{codeunitversion}", "--file", f"{codeunitname}/Dockerfile"]
27
+ if not self.use_cache():
28
+ args.append("--no-cache")
29
+ args.append(".")
30
+ codeunit_content_folder = os.path.join(codeunit_folder)
31
+ self._protected_sc.run_program_argsasarray("docker", args, codeunit_content_folder, print_errors_as_information=True)
32
+ artifacts_folder = GeneralUtilities.resolve_relative_path("Other/Artifacts", codeunit_folder)
33
+ app_artifacts_folder = os.path.join(artifacts_folder, "BuildResult_OCIImage")
34
+ GeneralUtilities.ensure_directory_does_not_exist(app_artifacts_folder)
35
+ GeneralUtilities.ensure_directory_exists(app_artifacts_folder)
36
+ self._protected_sc.run_program_argsasarray("docker", ["save", "--output", f"{codeunitname}_v{codeunitversion}.tar", f"{codeunitname_lower}:{codeunitversion}"], app_artifacts_folder, print_errors_as_information=True)
37
+ self.copy_source_files_to_output_directory()
38
+ self.__generate_sbom_for_docker_image()
39
+
40
+
41
+ @GeneralUtilities.check_arguments
42
+ def __generate_sbom_for_docker_image(self) -> None:
43
+
44
+ codeunitname=self.get_codeunit_name()
45
+ codeunit_folder =self.get_codeunit_folder()
46
+ artifacts_folder = GeneralUtilities.resolve_relative_path("Other/Artifacts", codeunit_folder)
47
+ codeunitname_lower = codeunitname.lower()
48
+ sbom_folder = os.path.join(artifacts_folder, "BOM")
49
+ codeunitversion = self.tfcps_Tools_General.get_version_of_codeunit(self.get_codeunit_file())
50
+ GeneralUtilities.ensure_directory_exists(sbom_folder)
51
+ self._protected_sc.run_program_argsasarray("docker", ["sbom", "--format", "cyclonedx", f"{codeunitname_lower}:{codeunitversion}", "--output", f"{codeunitname}.{codeunitversion}.sbom.xml"], sbom_folder, print_errors_as_information=True)
52
+ self._protected_sc.format_xml_file(sbom_folder+f"/{codeunitname}.{codeunitversion}.sbom.xml")
53
+
54
+ @GeneralUtilities.check_arguments
55
+ def linting(self=None) -> None:
56
+ pass#TODO
57
+
58
+ @GeneralUtilities.check_arguments
59
+ def do_common_tasks(self,current_codeunit_version:str )-> None:
60
+ codeunitname =self.get_codeunit_name()
61
+ codeunit_folder = self.get_codeunit_folder()
62
+ codeunit_version = current_codeunit_version
63
+ self._protected_sc.replace_version_in_dockerfile_file(GeneralUtilities.resolve_relative_path(f"./{codeunitname}/Dockerfile", codeunit_folder), codeunit_version)
64
+ self.do_common_tasks_base(current_codeunit_version)
65
+ self.tfcps_Tools_General.standardized_tasks_update_version_in_docker_examples(codeunit_folder,codeunit_version)
66
+
67
+ @GeneralUtilities.check_arguments
68
+ def generate_reference(self=None) -> None:
69
+ self.generate_reference_using_docfx()
70
+
71
+ @GeneralUtilities.check_arguments
72
+ def run_testcases(self=None) -> None:
73
+ pass#TODO
74
+
75
+ @GeneralUtilities.check_arguments
76
+ def get_dependencies(self)->dict[str,set[str]]:
77
+ return []#TODO
78
+
79
+ @GeneralUtilities.check_arguments
80
+ def get_available_versions(self,dependencyname:str)->list[str]:
81
+ return []#TODO
82
+
83
+ @GeneralUtilities.check_arguments
84
+ def set_dependency_version(self,name:str,new_version:str)->None:
85
+ raise ValueError(f"Operation is not implemented.")
86
+
87
+ class TFCPS_CodeUnitSpecific_Docker_CLI:
88
+
89
+ @staticmethod
90
+ def parse(file:str)->TFCPS_CodeUnitSpecific_Docker_Functions:
91
+ parser=TFCPS_CodeUnitSpecific_Base_CLI.get_base_parser()
92
+ #add custom parameter if desired
93
+ args=parser.parse_args()
94
+ result:TFCPS_CodeUnitSpecific_Docker_Functions=TFCPS_CodeUnitSpecific_Docker_Functions(file,LogLevel(int(args.verbosity)),args.targetenvironmenttype,not args.nocache,args.ispremerge)
95
+ return result
File without changes
@@ -0,0 +1,8 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+
4
+ class CertificateGeneratorInformationBase(ABC):
5
+
6
+ @abstractmethod
7
+ def generate_certificate(self)->bool:
8
+ raise ValueError("Method is abstract")
@@ -0,0 +1,6 @@
1
+ from .CertificateGeneratorInformationBase import CertificateGeneratorInformationBase
2
+
3
+ class CertificateGeneratorInformationGenerate(CertificateGeneratorInformationBase):
4
+
5
+ def generate_certificate(self)->bool:
6
+ return True
@@ -0,0 +1,7 @@
1
+ from .CertificateGeneratorInformationBase import CertificateGeneratorInformationBase
2
+
3
+
4
+ class CertificateGeneratorInformationNoGenerate(CertificateGeneratorInformationBase):
5
+
6
+ def generate_certificate(self)->bool:
7
+ return False
@@ -0,0 +1,485 @@
1
+ import os
2
+ import re
3
+ import shutil
4
+ import tempfile
5
+ import uuid
6
+ import json
7
+ from lxml import etree
8
+ import yaml
9
+ from .CertificateGeneratorInformationBase import CertificateGeneratorInformationBase
10
+ from ...GeneralUtilities import GeneralUtilities
11
+ from ...SCLog import LogLevel
12
+ from ..TFCPS_CodeUnitSpecific_Base import TFCPS_CodeUnitSpecific_Base,TFCPS_CodeUnitSpecific_Base_CLI
13
+
14
+ class TFCPS_CodeUnitSpecific_DotNet_Functions(TFCPS_CodeUnitSpecific_Base):
15
+
16
+ is_library:bool
17
+ csproj_file:bool
18
+
19
+ def __init__(self,current_file:str,verbosity:LogLevel,targetenvironmenttype:str,use_cache:bool,is_pre_merge:bool):
20
+ super().__init__(current_file, verbosity,targetenvironmenttype,use_cache,is_pre_merge)
21
+ self.csproj_file=os.path.join(self.get_codeunit_folder(), self.get_codeunit_name(), self.get_codeunit_name() + ".csproj")
22
+ self.is_library="<OutputType>Library</OutputType>" in GeneralUtilities.read_text_from_file(self.csproj_file)#TODO do a real check by checking this property using xpath
23
+
24
+ @GeneralUtilities.check_arguments
25
+ def build(self,runtimes:list[str],generate_open_api_spec:bool) -> None:
26
+ if self.is_library:
27
+ self.standardized_tasks_build_for_dotnet_library_project(runtimes)
28
+ GeneralUtilities.assert_condition(not generate_open_api_spec,"OpenAPI-Specification can not be generated for a library.")
29
+ else:
30
+ self.standardized_tasks_build_for_dotnet_project(runtimes)
31
+ if generate_open_api_spec:
32
+ self.generate_openapi_file(runtimes[0])
33
+
34
+ @GeneralUtilities.check_arguments
35
+ def generate_openapi_file(self, runtime: str) -> None:
36
+ swagger_document_name: str = "APISpecification"
37
+ self._protected_sc.log.log("Generate OpenAPI-specification-file...")
38
+ codeunitname =self.get_codeunit_name()
39
+ repository_folder =self.get_repository_folder()
40
+ codeunit_folder = os.path.join(repository_folder, codeunitname)
41
+ artifacts_folder = os.path.join(codeunit_folder, "Other", "Artifacts")
42
+ GeneralUtilities.ensure_directory_exists(os.path.join(artifacts_folder, "APISpecification"))
43
+ codeunit_version = self.tfcps_Tools_General.get_version_of_codeunit(os.path.join(codeunit_folder,f"{codeunitname}.codeunit.xml"))
44
+
45
+ versioned_api_spec_file = f"APISpecification/{codeunitname}.v{codeunit_version}.api.json"
46
+ self._protected_sc.run_program("swagger", f"tofile --output {versioned_api_spec_file} BuildResult_DotNet_{runtime}/{codeunitname}.dll {swagger_document_name}", artifacts_folder)
47
+ api_file: str = os.path.join(artifacts_folder, versioned_api_spec_file)
48
+ shutil.copyfile(api_file, os.path.join(artifacts_folder, f"APISpecification/{codeunitname}.latest.api.json"))
49
+
50
+ resources_folder = os.path.join(codeunit_folder, "Other", "Resources")
51
+ GeneralUtilities.ensure_directory_exists(resources_folder)
52
+ resources_apispec_folder = os.path.join(resources_folder, "APISpecification")
53
+ GeneralUtilities.ensure_directory_exists(resources_apispec_folder)
54
+ resource_target_file = os.path.join(resources_apispec_folder, f"{codeunitname}.api.json")
55
+ GeneralUtilities.ensure_file_does_not_exist(resource_target_file)
56
+ shutil.copyfile(api_file, resource_target_file)
57
+
58
+ with open(api_file, encoding="utf-8") as api_file_content:
59
+ reloaded_json = json.load(api_file_content)
60
+
61
+ yamlfile1: str = str(os.path.join(artifacts_folder, f"APISpecification/{codeunitname}.v{codeunit_version}.api.yaml"))
62
+ GeneralUtilities.ensure_file_does_not_exist(yamlfile1)
63
+ GeneralUtilities.ensure_file_exists(yamlfile1)
64
+ with open(yamlfile1, "w+", encoding="utf-8") as yamlfile:
65
+ yaml.dump(reloaded_json, yamlfile, allow_unicode=True)
66
+
67
+ yamlfile2: str = str(os.path.join(artifacts_folder, f"APISpecification/{codeunitname}.latest.api.yaml"))
68
+ GeneralUtilities.ensure_file_does_not_exist(yamlfile2)
69
+ shutil.copyfile(yamlfile1, yamlfile2)
70
+
71
+ yamlfile3: str = str(os.path.join(resources_apispec_folder, f"{codeunitname}.api.yaml"))
72
+ GeneralUtilities.ensure_file_does_not_exist(yamlfile3)
73
+ shutil.copyfile(yamlfile1, yamlfile3)
74
+
75
+ @GeneralUtilities.check_arguments
76
+ def __standardized_tasks_build_for_dotnet_build(self, csproj_file: str, originaloutputfolder: str, files_to_sign: dict[str, str], commitid: str, runtimes: list[str], target_environmenttype_mapping: dict[str, str], copy_license_file_to_target_folder: bool, repository_folder: str, codeunit_name: str) -> None:
77
+ self._protected_sc.assert_is_git_repository(repository_folder)
78
+ csproj_filename = os.path.basename(csproj_file)
79
+ self._protected_sc.log.log(f"Build {csproj_filename}...")
80
+ dotnet_build_configuration: str = self.get_target_environment_type()
81
+ codeunit_folder = os.path.join(repository_folder, codeunit_name)
82
+ csproj_file_folder = os.path.dirname(csproj_file)
83
+ csproj_file_name = os.path.basename(csproj_file)
84
+ csproj_file_name_without_extension = csproj_file_name.split(".")[0]
85
+ sarif_folder = os.path.join(codeunit_folder, "Other", "Resources", "CodeAnalysisResult")
86
+ GeneralUtilities.ensure_directory_exists(sarif_folder)
87
+ gitkeep_file = os.path.join(sarif_folder, ".gitkeep")
88
+ GeneralUtilities.ensure_file_exists(gitkeep_file)
89
+ for runtime in runtimes:
90
+ outputfolder = originaloutputfolder+runtime
91
+ GeneralUtilities.ensure_directory_does_not_exist(os.path.join(csproj_file_folder, "obj"))
92
+ GeneralUtilities.ensure_directory_does_not_exist(outputfolder)
93
+ self._protected_sc.run_program("dotnet", "clean", csproj_file_folder)
94
+ GeneralUtilities.ensure_directory_exists(outputfolder)
95
+ self._protected_sc.run_program("dotnet", "restore", codeunit_folder)
96
+ self._protected_sc.run_program_argsasarray("dotnet", ["build", csproj_file_name, "-c", dotnet_build_configuration, "-o", outputfolder, "--runtime", runtime], csproj_file_folder)
97
+ if copy_license_file_to_target_folder:
98
+ license_file = os.path.join(repository_folder, "License.txt")
99
+ target = os.path.join(outputfolder, f"{codeunit_name}.License.txt")
100
+ shutil.copyfile(license_file, target)
101
+ if 0 < len(files_to_sign):
102
+ for key, value in files_to_sign.items():
103
+ dll_file = key
104
+ snk_file = value
105
+ dll_file_full = os.path.join(outputfolder, dll_file)
106
+ if os.path.isfile(dll_file_full):
107
+ GeneralUtilities.assert_condition(self._protected_sc.run_program("sn", f"-vf {dll_file}", outputfolder, throw_exception_if_exitcode_is_not_zero=False)[0] == 1, f"Pre-verifying of {dll_file} failed.")
108
+ self._protected_sc.run_program_argsasarray("sn", ["-R", dll_file, snk_file], outputfolder)
109
+ GeneralUtilities.assert_condition(self._protected_sc.run_program("sn", f"-vf {dll_file}", outputfolder, throw_exception_if_exitcode_is_not_zero=False)[0] == 0, f"Verifying of {dll_file} failed.")
110
+ sarif_filename = f"{csproj_file_name_without_extension}.sarif"
111
+ sarif_source_file = os.path.join(sarif_folder, sarif_filename)
112
+ if os.path.exists(sarif_source_file):
113
+ sarif_folder_target = os.path.join(codeunit_folder, "Other", "Artifacts", "CodeAnalysisResult")
114
+ GeneralUtilities.ensure_directory_exists(sarif_folder_target)
115
+ sarif_target_file = os.path.join(sarif_folder_target, sarif_filename)
116
+ GeneralUtilities.ensure_file_does_not_exist(sarif_target_file)
117
+ shutil.copyfile(sarif_source_file, sarif_target_file)
118
+
119
+ @GeneralUtilities.check_arguments
120
+ def standardized_tasks_build_for_dotnet_project(self,runtimes:list[str]) -> None:
121
+ self.__standardized_tasks_build_for_dotnet_project(runtimes)
122
+
123
+ @GeneralUtilities.check_arguments
124
+ def standardized_tasks_build_for_dotnet_library_project(self,runtimes:list[str]) -> None:
125
+ self.__standardized_tasks_build_for_dotnet_project( runtimes)
126
+ self.__standardized_tasks_build_nupkg_for_dotnet_create_package(runtimes)
127
+
128
+
129
+ @staticmethod
130
+ @GeneralUtilities.check_arguments
131
+ def get_filestosign_from_commandline_arguments( default_value: dict[str, str]) -> dict[str, str]:
132
+ result_plain =None# TODO TasksForCommonProjectStructure.get_property_from_commandline_arguments(commandline_arguments, "sign")
133
+ if result_plain is None:
134
+ return default_value
135
+ else:
136
+ result: dict[str, str] = dict[str, str]()
137
+ files_tuples = GeneralUtilities.to_list(result_plain, ";")
138
+ for files_tuple in files_tuples:
139
+ splitted = files_tuple.split("=")
140
+ result[splitted[0]] = splitted[1]
141
+ return result
142
+
143
+ @GeneralUtilities.check_arguments
144
+ def __standardized_tasks_build_for_dotnet_project(self,runtimes:list[str]) -> None:
145
+
146
+ target_environment_type: str=self.get_target_environment_type()
147
+ copy_license_file_to_target_folder: bool=True
148
+ codeunitname: str = self.get_codeunit_name()
149
+
150
+ files_to_sign: dict[str, str] = self.get_filestosign_from_commandline_arguments( dict())
151
+ repository_folder: str = self.get_repository_folder()
152
+ commitid = self._protected_sc.git_get_commit_id(repository_folder)
153
+ outputfolder = GeneralUtilities.resolve_relative_path("./Other/Artifacts", self.get_codeunit_folder())
154
+ codeunit_folder = os.path.join(repository_folder, codeunitname)
155
+ csproj_file = os.path.join(codeunit_folder, codeunitname, codeunitname + ".csproj")
156
+ csproj_test_file = os.path.join(codeunit_folder, codeunitname+"Tests", codeunitname+"Tests.csproj")
157
+ self.__standardized_tasks_build_for_dotnet_build(csproj_file, os.path.join(outputfolder, "BuildResult_DotNet_"), files_to_sign, commitid, runtimes, target_environment_type, copy_license_file_to_target_folder, repository_folder, codeunitname)
158
+ self.__standardized_tasks_build_for_dotnet_build(csproj_test_file, os.path.join(outputfolder, "BuildResultTests_DotNet_"), files_to_sign, commitid, runtimes, target_environment_type, copy_license_file_to_target_folder, repository_folder, codeunitname)
159
+ self.generate_sbom_for_dotnet_project(codeunit_folder)
160
+ self.copy_source_files_to_output_directory()
161
+
162
+ @GeneralUtilities.check_arguments
163
+ def __standardized_tasks_build_nupkg_for_dotnet_create_package(self,runtimes:list[str]) -> None:
164
+ codeunitname: str = self.get_codeunit_name()
165
+ repository_folder: str =self.get_repository_folder()
166
+ build_folder = os.path.join(repository_folder, codeunitname, "Other", "Build")
167
+ outputfolder = GeneralUtilities.resolve_relative_path("./Other/Artifacts/BuildResult_NuGet",self.get_codeunit_folder())
168
+ root: etree._ElementTree = etree.parse(os.path.join(build_folder, f"{codeunitname}.nuspec"))
169
+ current_version = root.xpath("//*[name() = 'package']/*[name() = 'metadata']/*[name() = 'version']/text()")[0]
170
+ nupkg_filename = f"{codeunitname}.{current_version}.nupkg"
171
+ nupkg_file = f"{build_folder}/{nupkg_filename}"
172
+ GeneralUtilities.ensure_file_does_not_exist(nupkg_file)
173
+ commit_id = self._protected_sc.git_get_commit_id(repository_folder)
174
+ self._protected_sc.run_program("nuget", f"pack {codeunitname}.nuspec -Properties \"commitid={commit_id}\"", build_folder)
175
+ GeneralUtilities.ensure_directory_does_not_exist(outputfolder)
176
+ GeneralUtilities.ensure_directory_exists(outputfolder)
177
+ os.rename(nupkg_file, f"{outputfolder}/{nupkg_filename}")
178
+
179
+ @GeneralUtilities.check_arguments
180
+ def generate_sbom_for_dotnet_project(self, codeunit_folder: str) -> None:
181
+ self._protected_sc.log.log("Generate SBOM...")
182
+ codeunit_name = os.path.basename(codeunit_folder)
183
+ bomfile_folder = "Other\\Artifacts\\BOM"
184
+ self._protected_sc.run_program_argsasarray("dotnet", ["CycloneDX", f"{codeunit_name}\\{codeunit_name}.csproj", "-o", bomfile_folder, "--disable-github-licenses"], codeunit_folder)
185
+ codeunitversion = self.tfcps_Tools_General.get_version_of_codeunit(os.path.join(codeunit_folder, f"{codeunit_name}.codeunit.xml"))
186
+ target = f"{codeunit_folder}\\{bomfile_folder}\\{codeunit_name}.{codeunitversion}.sbom.xml"
187
+ GeneralUtilities.ensure_file_does_not_exist(target)
188
+ os.rename(f"{codeunit_folder}\\{bomfile_folder}\\bom.xml", target)
189
+ self._protected_sc.format_xml_file(target)
190
+
191
+ @GeneralUtilities.check_arguments
192
+ def linting(self=None) -> None:
193
+ pass#TODO
194
+
195
+ @GeneralUtilities.check_arguments
196
+ def do_common_tasks(self,current_codeunit_version:str,certificateGeneratorInformation:CertificateGeneratorInformationBase)-> None:
197
+ self.do_common_tasks_base(current_codeunit_version)
198
+ codeunit_name =self.get_codeunit_name()
199
+ codeunit_version = self.tfcps_Tools_General.get_version_of_project(self.get_repository_folder()) # Should always be the same as the project-version #TODO make this configurable from outside
200
+ folder_of_current_file =os.path.join(self.get_codeunit_folder(),"Other")
201
+ self._protected_sc.replace_version_in_csproj_file(GeneralUtilities.resolve_relative_path(f"../{codeunit_name}/{codeunit_name}.csproj", folder_of_current_file), codeunit_version)
202
+ self._protected_sc.replace_version_in_csproj_file(GeneralUtilities.resolve_relative_path(f"../{codeunit_name}Tests/{codeunit_name}Tests.csproj", folder_of_current_file), codeunit_version)
203
+ if self.is_library:
204
+ self._protected_sc.replace_version_in_nuspec_file(GeneralUtilities.resolve_relative_path(f"./Build/{codeunit_name}.nuspec", folder_of_current_file), codeunit_version)
205
+ if certificateGeneratorInformation.generate_certificate():
206
+ self.tfcps_Tools_General.set_constants_for_certificate_private_information(self.get_codeunit_folder())
207
+ self.standardized_task_verify_standard_format_csproj_files()
208
+
209
+ @GeneralUtilities.check_arguments
210
+ def standardized_task_verify_standard_format_csproj_files(self) -> bool:
211
+ codeunit_folder=self.get_codeunit_folder()
212
+ repository_folder = os.path.dirname(codeunit_folder)
213
+ codeunit_name = os.path.basename(codeunit_folder)
214
+ codeunit_folder = os.path.join(repository_folder, codeunit_name)
215
+ codeunit_version = self.tfcps_Tools_General.get_version_of_codeunit(self.get_codeunit_file())
216
+
217
+ csproj_project_name = codeunit_name
218
+ csproj_file = os.path.join(codeunit_folder, csproj_project_name, csproj_project_name+".csproj")
219
+ result1: tuple[bool, str, list[str]] = self.__standardized_task_verify_standard_format_for_project_csproj_file(csproj_file, codeunit_folder, codeunit_name, codeunit_version)
220
+ if not result1[0]:
221
+ hints: str = "\n".join(result1[2])
222
+ raise ValueError(f"'{csproj_file}' with content '{GeneralUtilities.read_text_from_file(csproj_file)}' does not match the standardized .csproj-file-format which is defined by the regex '{result1[1]}'.\n{hints}")
223
+
224
+ test_csproj_project_name = csproj_project_name+"Tests"
225
+ test_csproj_file = os.path.join(codeunit_folder, test_csproj_project_name, test_csproj_project_name+".csproj")
226
+ result2: tuple[bool, str, list[str]] = self.__standardized_task_verify_standard_format_for_test_csproj_file(test_csproj_file, codeunit_name, codeunit_version)
227
+ if not result2[0]:
228
+ hints: str = "\n".join(result2[2])
229
+ raise ValueError(f"'{test_csproj_file}' with content '{GeneralUtilities.read_text_from_file(test_csproj_file)}' does not match the standardized .csproj-file-format which is defined by the regex '{result2[1]}'.\n{hints}")
230
+
231
+ def __standardized_task_verify_standard_format_for_project_csproj_file(self, csproj_file: str, codeunit_folder: str, codeunit_name: str, codeunit_version: str) -> tuple[bool, str, str]:
232
+ codeunit_name_regex = re.escape(codeunit_name)
233
+ codeunit_description = self.tfcps_Tools_General.get_codeunit_description(self.get_codeunit_file())
234
+ codeunit_version_regex = re.escape(codeunit_version)
235
+ codeunit_description_regex = re.escape(codeunit_description)
236
+ regex = f"""^<Project Sdk=\\"Microsoft\\.NET\\.Sdk\\">
237
+ <PropertyGroup>
238
+ <TargetFramework>([^<]+)<\\/TargetFramework>
239
+ <Authors>([^<]+)<\\/Authors>
240
+ <Version>{codeunit_version_regex}<\\/Version>
241
+ <AssemblyVersion>{codeunit_version_regex}<\\/AssemblyVersion>
242
+ <FileVersion>{codeunit_version_regex}<\\/FileVersion>
243
+ <SelfContained>false<\\/SelfContained>
244
+ <IsPackable>false<\\/IsPackable>
245
+ <PreserveCompilationContext>false<\\/PreserveCompilationContext>
246
+ <GenerateRuntimeConfigurationFiles>true<\\/GenerateRuntimeConfigurationFiles>
247
+ <Copyright>([^<]+)<\\/Copyright>
248
+ <Description>{codeunit_description_regex}<\\/Description>
249
+ <PackageProjectUrl>https:\\/\\/([^<]+)<\\/PackageProjectUrl>
250
+ <RepositoryUrl>https:\\/\\/([^<]+)\\.git<\\/RepositoryUrl>
251
+ <RootNamespace>([^<]+)\\.Core<\\/RootNamespace>
252
+ <ProduceReferenceAssembly>false<\\/ProduceReferenceAssembly>
253
+ <Nullable>(disable|enable|warnings|annotations)<\\/Nullable>
254
+ <Configurations>Development;QualityCheck;Productive<\\/Configurations>
255
+ <IsTestProject>false<\\/IsTestProject>
256
+ <LangVersion>([^<]+)<\\/LangVersion>
257
+ <PackageRequireLicenseAcceptance>true<\\/PackageRequireLicenseAcceptance>
258
+ <GenerateSerializationAssemblies>Off<\\/GenerateSerializationAssemblies>
259
+ <AppendTargetFrameworkToOutputPath>false<\\/AppendTargetFrameworkToOutputPath>
260
+ <OutputPath>\\.\\.\\\\Other\\\\Artifacts\\\\BuildResult_DotNet_win\\-x64<\\/OutputPath>
261
+ <PlatformTarget>([^<]+)<\\/PlatformTarget>
262
+ <WarningLevel>\\d<\\/WarningLevel>
263
+ <Prefer32Bit>false<\\/Prefer32Bit>
264
+ <SignAssembly>true<\\/SignAssembly>
265
+ <AssemblyOriginatorKeyFile>\\.\\.\\\\\\.\\.\\\\Other\\\\Resources\\\\PublicKeys\\\\StronglyNamedKey\\\\([^<]+)PublicKey\\.snk<\\/AssemblyOriginatorKeyFile>
266
+ <DelaySign>true<\\/DelaySign>
267
+ <NoWarn>([^<]+)<\\/NoWarn>
268
+ <WarningsAsErrors>([^<]+)<\\/WarningsAsErrors>
269
+ <ErrorLog>\\.\\.\\\\Other\\\\Resources\\\\CodeAnalysisResult\\\\{codeunit_name_regex}\\.sarif<\\/ErrorLog>
270
+ <OutputType>([^<]+)<\\/OutputType>
271
+ <DocumentationFile>\\.\\.\\\\Other\\\\Artifacts\\\\MetaInformation\\\\{codeunit_name_regex}\\.xml<\\/DocumentationFile>(\\n|.)*
272
+ <\\/PropertyGroup>
273
+ <PropertyGroup Condition=\\\"'\\$\\(Configuration\\)'=='Development'\\\">
274
+ <DebugType>full<\\/DebugType>
275
+ <DebugSymbols>true<\\/DebugSymbols>
276
+ <Optimize>false<\\/Optimize>
277
+ <DefineConstants>TRACE;DEBUG;Development<\\/DefineConstants>
278
+ <ErrorReport>prompt<\\/ErrorReport>
279
+ <\\/PropertyGroup>
280
+ <PropertyGroup Condition=\\\"'\\$\\(Configuration\\)'=='QualityCheck'\\\">
281
+ <DebugType>portable<\\/DebugType>
282
+ <DebugSymbols>true<\\/DebugSymbols>
283
+ <Optimize>false<\\/Optimize>
284
+ <DefineConstants>TRACE;QualityCheck<\\/DefineConstants>
285
+ <ErrorReport>none<\\/ErrorReport>
286
+ <\\/PropertyGroup>
287
+ <PropertyGroup Condition=\\\"'\\$\\(Configuration\\)'=='Productive'\\\">
288
+ <DebugType>portable<\\/DebugType>
289
+ <DebugSymbols>true<\\/DebugSymbols>
290
+ <Optimize>false<\\/Optimize>
291
+ <DefineConstants>Productive<\\/DefineConstants>
292
+ <ErrorReport>none<\\/ErrorReport>
293
+ <\\/PropertyGroup>(\\n|.)*
294
+ <\\/Project>$"""
295
+ result = self.__standardized_task_verify_standard_format_for_csproj_files(regex, csproj_file)
296
+ return (result[0], regex, result[1])
297
+
298
+ def __standardized_task_verify_standard_format_for_test_csproj_file(self, csproj_file: str, codeunit_name: str, codeunit_version: str) -> tuple[bool, str, str]:
299
+ codeunit_name_regex = re.escape(codeunit_name)
300
+ codeunit_version_regex = re.escape(codeunit_version)
301
+ regex = f"""^<Project Sdk=\\"Microsoft\\.NET\\.Sdk\\">
302
+ <PropertyGroup>
303
+ <TargetFramework>([^<]+)<\\/TargetFramework>
304
+ <Authors>([^<]+)<\\/Authors>
305
+ <Version>{codeunit_version_regex}<\\/Version>
306
+ <AssemblyVersion>{codeunit_version_regex}<\\/AssemblyVersion>
307
+ <FileVersion>{codeunit_version_regex}<\\/FileVersion>
308
+ <SelfContained>false<\\/SelfContained>
309
+ <IsPackable>false<\\/IsPackable>
310
+ <PreserveCompilationContext>false<\\/PreserveCompilationContext>
311
+ <GenerateRuntimeConfigurationFiles>true<\\/GenerateRuntimeConfigurationFiles>
312
+ <Copyright>([^<]+)<\\/Copyright>
313
+ <Description>{codeunit_name_regex}Tests is the test-project for {codeunit_name_regex}\\.<\\/Description>
314
+ <PackageProjectUrl>https:\\/\\/([^<]+)<\\/PackageProjectUrl>
315
+ <RepositoryUrl>https:\\/\\/([^<]+)\\.git</RepositoryUrl>
316
+ <RootNamespace>([^<]+)\\.Tests<\\/RootNamespace>
317
+ <ProduceReferenceAssembly>false<\\/ProduceReferenceAssembly>
318
+ <Nullable>(disable|enable|warnings|annotations)<\\/Nullable>
319
+ <Configurations>Development;QualityCheck;Productive<\\/Configurations>
320
+ <IsTestProject>true<\\/IsTestProject>
321
+ <LangVersion>([^<]+)<\\/LangVersion>
322
+ <PackageRequireLicenseAcceptance>true<\\/PackageRequireLicenseAcceptance>
323
+ <GenerateSerializationAssemblies>Off<\\/GenerateSerializationAssemblies>
324
+ <AppendTargetFrameworkToOutputPath>false<\\/AppendTargetFrameworkToOutputPath>
325
+ <OutputPath>\\.\\.\\\\Other\\\\Artifacts\\\\BuildResultTests_DotNet_win\\-x64<\\/OutputPath>
326
+ <PlatformTarget>([^<]+)<\\/PlatformTarget>
327
+ <WarningLevel>\\d<\\/WarningLevel>
328
+ <Prefer32Bit>false<\\/Prefer32Bit>
329
+ <SignAssembly>true<\\/SignAssembly>
330
+ <AssemblyOriginatorKeyFile>\\.\\.\\\\\\.\\.\\\\Other\\\\Resources\\\\PublicKeys\\\\StronglyNamedKey\\\\([^<]+)PublicKey\\.snk<\\/AssemblyOriginatorKeyFile>
331
+ <DelaySign>true<\\/DelaySign>
332
+ <NoWarn>([^<]+)<\\/NoWarn>
333
+ <WarningsAsErrors>([^<]+)<\\/WarningsAsErrors>
334
+ <ErrorLog>\\.\\.\\\\Other\\\\Resources\\\\CodeAnalysisResult\\\\{codeunit_name_regex}Tests\\.sarif<\\/ErrorLog>
335
+ <OutputType>Library<\\/OutputType>(\\n|.)*
336
+ <\\/PropertyGroup>
337
+ <PropertyGroup Condition=\\\"'\\$\\(Configuration\\)'=='Development'\\\">
338
+ <DebugType>full<\\/DebugType>
339
+ <DebugSymbols>true<\\/DebugSymbols>
340
+ <Optimize>false<\\/Optimize>
341
+ <DefineConstants>TRACE;DEBUG;Development<\\/DefineConstants>
342
+ <ErrorReport>prompt<\\/ErrorReport>
343
+ <\\/PropertyGroup>
344
+ <PropertyGroup Condition=\\\"'\\$\\(Configuration\\)'=='QualityCheck'\\\">
345
+ <DebugType>portable<\\/DebugType>
346
+ <DebugSymbols>true<\\/DebugSymbols>
347
+ <Optimize>false<\\/Optimize>
348
+ <DefineConstants>TRACE;QualityCheck<\\/DefineConstants>
349
+ <ErrorReport>none<\\/ErrorReport>
350
+ <\\/PropertyGroup>
351
+ <PropertyGroup Condition=\\\"'\\$\\(Configuration\\)'=='Productive'\\\">
352
+ <DebugType>portable<\\/DebugType>
353
+ <DebugSymbols>true<\\/DebugSymbols>
354
+ <Optimize>false<\\/Optimize>
355
+ <DefineConstants>Productive<\\/DefineConstants>
356
+ <ErrorReport>none<\\/ErrorReport>
357
+ <\\/PropertyGroup>(\\n|.)*
358
+ <\\/Project>$"""
359
+ result = self.__standardized_task_verify_standard_format_for_csproj_files(regex, csproj_file)
360
+ return (result[0], regex, result[1])
361
+
362
+ def __standardized_task_verify_standard_format_for_csproj_files(self, regex: str, csproj_file: str) -> tuple[bool, list[str]]:
363
+ filename = os.path.basename(csproj_file)
364
+ self._protected_sc.log.log(f"Check {filename}...",LogLevel.Debug)
365
+ file_content = GeneralUtilities.read_text_from_file(csproj_file)
366
+ regex_for_check = regex.replace("\r", GeneralUtilities.empty_string).replace("\n", "\\n")
367
+ file_content = file_content.replace("\r", GeneralUtilities.empty_string)
368
+ match = re.match(regex_for_check, file_content)
369
+ result = match is not None
370
+ hints = None
371
+ if not result:
372
+ hints = self.get_hints_for_csproj(regex, file_content)
373
+ return (result, hints)
374
+
375
+ @GeneralUtilities.check_arguments
376
+ def get_hints_for_csproj(self, regex: str, file_content: str) -> list[str]:
377
+ result: list[str] = []
378
+ regex_lines = GeneralUtilities.string_to_lines(regex)
379
+ file_content_lines = GeneralUtilities.string_to_lines(file_content)
380
+ #amount_of_regexes = len(regex_lines)
381
+ amount_of_lines = len(file_content_lines)
382
+ if amount_of_lines< len(regex_lines):
383
+ result.append("csproj-file has less lines than the regex requires.")
384
+ return result
385
+ for i in range(35):
386
+ s = file_content_lines[i]
387
+ r = regex_lines[i]
388
+ if not re.match(r, s):
389
+ result.append(f"Line {i+1} does not match: Regex='{r}' String='{s}'")
390
+ return result
391
+
392
+ @GeneralUtilities.check_arguments
393
+ def generate_reference(self) -> None:
394
+ self.generate_reference_using_docfx()
395
+
396
+
397
+ @GeneralUtilities.check_arguments
398
+ def update_year_for_dotnet_codeunit(self) -> None:
399
+ codeunit_folder:str=self.get_codeunit_folder()
400
+ codeunit_name = os.path.basename(codeunit_folder)
401
+ csproj_file = os.path.join(codeunit_folder, codeunit_name, f"{codeunit_name}.csproj")
402
+ self._protected_sc.update_year_in_copyright_tags(csproj_file)
403
+ csprojtests_file = os.path.join(codeunit_folder, f"{codeunit_name}Tests", f"{codeunit_name}Tests.csproj")
404
+ self._protected_sc.update_year_in_copyright_tags(csprojtests_file)
405
+ nuspec_file = os.path.join(codeunit_folder, "Other", "Build", f"{codeunit_name}.nuspec")
406
+ if os.path.isfile(nuspec_file):
407
+ self._protected_sc.update_year_in_copyright_tags(nuspec_file)
408
+
409
+ @GeneralUtilities.check_arguments
410
+ def run_testcases(self) -> None:
411
+ self._protected_sc.log.log("Run testcases...")
412
+ dotnet_build_configuration: str = self.get_target_environment_type()
413
+ codeunit_name: str = self.get_codeunit_name()
414
+
415
+ repository_folder: str = self.get_repository_folder().replace("\\", "/")
416
+ coverage_file_folder = os.path.join(repository_folder, codeunit_name, "Other/Artifacts/TestCoverage")
417
+ temp_folder = os.path.join(tempfile.gettempdir(), str(uuid.uuid4()))
418
+ GeneralUtilities.ensure_directory_exists(temp_folder)
419
+ runsettings_file = "runsettings.xml"
420
+ codeunit_folder = f"{repository_folder}/{codeunit_name}"
421
+ arg = f"test . -c {dotnet_build_configuration}"
422
+ if os.path.isfile(os.path.join(codeunit_folder, runsettings_file)):
423
+ arg = f"{arg} --settings {runsettings_file}"
424
+ arg = f"{arg} /p:CollectCoverage=true /p:CoverletOutput=../Other/Artifacts/TestCoverage/Testcoverage /p:CoverletOutputFormat=cobertura"
425
+ test_run_result=self._protected_sc.run_program("dotnet", arg, codeunit_folder, print_live_output=True)#pylint:disable=unused-variable
426
+ target_file = os.path.join(coverage_file_folder, "TestCoverage.xml")
427
+ GeneralUtilities.ensure_file_does_not_exist(target_file)
428
+ os.rename(os.path.join(coverage_file_folder, "Testcoverage.cobertura.xml"), target_file)
429
+ self.__remove_unrelated_package_from_testcoverage_file(target_file, codeunit_name)
430
+ root: etree._ElementTree = etree.parse(target_file)
431
+ source_base_path_in_coverage_file: str = root.xpath("//coverage/sources/source/text()")[0].replace("\\", "/")
432
+ content = GeneralUtilities.read_text_from_file(target_file)
433
+ GeneralUtilities.assert_condition(source_base_path_in_coverage_file.startswith(repository_folder) or repository_folder.startswith(source_base_path_in_coverage_file), f"Unexpected path for coverage. Sourcepath: \"{source_base_path_in_coverage_file}\"; repository: \"{repository_folder}\"")
434
+ content = re.sub('\\\\', '/', content)
435
+ content = re.sub("filename=\"([^\"]+)\"", lambda match: self.__standardized_tasks_run_testcases_for_dotnet_project_helper(source_base_path_in_coverage_file, codeunit_folder, match), content)
436
+ GeneralUtilities.write_text_to_file(target_file, content)
437
+ self.run_testcases_common_post_task(repository_folder, codeunit_name, True, self.get_target_environment_type())
438
+ artifacts_folder = os.path.join(repository_folder, codeunit_name, "Other", "Artifacts")
439
+ for subfolder in GeneralUtilities.get_direct_folders_of_folder(artifacts_folder):
440
+ if os.path.basename(subfolder).startswith("BuildResultTests_DotNet_"):
441
+ GeneralUtilities.ensure_directory_does_not_exist(subfolder)
442
+
443
+
444
+ @GeneralUtilities.check_arguments
445
+ def __remove_unrelated_package_from_testcoverage_file(self, file: str, codeunit_name: str) -> None:
446
+ root: etree._ElementTree = etree.parse(file)
447
+ packages = root.xpath('//coverage/packages/package')
448
+ for package in packages:
449
+ if package.attrib['name'] != codeunit_name:
450
+ package.getparent().remove(package)
451
+ result = etree.tostring(root).decode("utf-8")
452
+ GeneralUtilities.write_text_to_file(file, result)
453
+
454
+ @GeneralUtilities.check_arguments
455
+ def __standardized_tasks_run_testcases_for_dotnet_project_helper(self, source: str, codeunit_folder: str, match: re.Match) -> str:
456
+ filename = match.group(1)
457
+ file = os.path.join(source, filename)
458
+ GeneralUtilities.assert_condition(file.startswith(codeunit_folder), f"Unexpected path for coverage-file. File: \"{file}\"; codeunitfolder: \"{codeunit_folder}\"")
459
+ filename_relative = f".{file[len(codeunit_folder):]}"
460
+ return f'filename="{filename_relative}"'
461
+
462
+
463
+ def get_dependencies(self)->dict[str,set[str]]:
464
+ return []#TODO
465
+
466
+ @GeneralUtilities.check_arguments
467
+ def get_available_versions(self,dependencyname:str)->list[str]:
468
+ return []#TODO
469
+
470
+ def set_dependency_version(self,name:str,new_version:str)->None:
471
+ raise ValueError(f"Operation is not implemented.")
472
+ #self.update_year_for_dotnet_codeunit()
473
+ #csproj_file:str=os.path.join(self.get_codeunit_folder(), self.get_codeunit_name(), self.get_codeunit_name() + ".csproj")
474
+ #self._protected_sc.update_dependencies_of_dotnet_project(csproj_file,[])#TODO set ignored codeunits
475
+
476
+
477
+ class TFCPS_CodeUnitSpecific_DotNet_CLI:
478
+
479
+ @staticmethod
480
+ def parse(file:str)->TFCPS_CodeUnitSpecific_DotNet_Functions:
481
+ parser=TFCPS_CodeUnitSpecific_Base_CLI.get_base_parser()
482
+ #add custom parameter if desired
483
+ args=parser.parse_args()
484
+ result:TFCPS_CodeUnitSpecific_DotNet_Functions=TFCPS_CodeUnitSpecific_DotNet_Functions(file,LogLevel(int(args.verbosity)),args.targetenvironmenttype,not args.nocache,args.ispremerge)
485
+ return result
File without changes