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