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,130 @@
1
+ import os
2
+ import shutil
3
+ import re
4
+ import zipfile
5
+ from ...GeneralUtilities import GeneralUtilities
6
+ from ...SCLog import LogLevel
7
+ from ..TFCPS_CodeUnitSpecific_Base import TFCPS_CodeUnitSpecific_Base,TFCPS_CodeUnitSpecific_Base_CLI
8
+
9
+ class TFCPS_CodeUnitSpecific_Flutter_Functions(TFCPS_CodeUnitSpecific_Base):
10
+
11
+ def __init__(self,current_file:str,verbosity:LogLevel,targetenvironmenttype:str,use_cache:bool,is_pre_merge:bool):
12
+ super().__init__(current_file, verbosity,targetenvironmenttype,use_cache,is_pre_merge)
13
+
14
+
15
+ @GeneralUtilities.check_arguments
16
+ def build(self,package_name:str,targets:list[str]) -> None:
17
+ codeunit_folder = self.get_codeunit_folder()
18
+ codeunit_name = os.path.basename(codeunit_folder)
19
+ src_folder: str = None
20
+ if package_name is None:
21
+ src_folder = codeunit_folder
22
+ else:
23
+ src_folder = GeneralUtilities.resolve_relative_path(package_name, codeunit_folder) # TODO replace packagename
24
+ artifacts_folder = os.path.join(codeunit_folder, "Other", "Artifacts")
25
+
26
+ target_names: dict[str, str] = {
27
+ "web": "WebApplication",
28
+ "windows": "Windows",
29
+ "ios": "IOS",
30
+ "appbundle": "Android",
31
+ }
32
+ for target in targets:
33
+ self._protected_sc.log.log(f"Build flutter-codeunit {codeunit_name} for target {target_names[target]}...")
34
+ self._protected_sc.run_with_epew("flutter", f"build {target}", src_folder)
35
+ if target == "web":
36
+ web_relase_folder = os.path.join(src_folder, "build/web")
37
+ web_folder = os.path.join(artifacts_folder, "BuildResult_WebApplication")
38
+ GeneralUtilities.ensure_directory_does_not_exist(web_folder)
39
+ GeneralUtilities.ensure_directory_exists(web_folder)
40
+ GeneralUtilities.copy_content_of_folder(web_relase_folder, web_folder)
41
+ elif target == "windows":
42
+ windows_release_folder = os.path.join(src_folder, "build/windows/x64/runner/Release")
43
+ windows_folder = os.path.join(artifacts_folder, "BuildResult_Windows")
44
+ GeneralUtilities.ensure_directory_does_not_exist(windows_folder)
45
+ GeneralUtilities.ensure_directory_exists(windows_folder)
46
+ GeneralUtilities.copy_content_of_folder(windows_release_folder, windows_folder)
47
+ elif target == "ios":
48
+ raise ValueError("building for ios is not implemented yet")
49
+ elif target == "appbundle":
50
+ aab_folder = os.path.join(artifacts_folder, "BuildResult_AAB")
51
+ GeneralUtilities.ensure_directory_does_not_exist(aab_folder)
52
+ GeneralUtilities.ensure_directory_exists(aab_folder)
53
+ aab_relase_folder = os.path.join(src_folder, "build/app/outputs/bundle/release")
54
+ aab_file_original = self._protected_sc.find_file_by_extension(aab_relase_folder, "aab")
55
+ aab_file = os.path.join(aab_folder, f"{codeunit_name}.aab")
56
+ shutil.copyfile(aab_file_original, aab_file)
57
+
58
+ bundletool = self.tfcps_Tools_General.ensure_androidappbundletool_is_available(None,self.use_cache())
59
+ apk_folder = os.path.join(artifacts_folder, "BuildResult_APK")
60
+ GeneralUtilities.ensure_directory_does_not_exist(apk_folder)
61
+ GeneralUtilities.ensure_directory_exists(apk_folder)
62
+ apks_file = f"{apk_folder}/{codeunit_name}.apks"
63
+ self._protected_sc.run_program("java", f"-jar {bundletool} build-apks --bundle={aab_file} --output={apks_file} --mode=universal", aab_relase_folder)
64
+ with zipfile.ZipFile(apks_file, "r") as zip_ref:
65
+ zip_ref.extract("universal.apk", apk_folder)
66
+ GeneralUtilities.ensure_file_does_not_exist(apks_file)
67
+ os.rename(f"{apk_folder}/universal.apk", f"{apk_folder}/{codeunit_name}.apk")
68
+ else:
69
+ raise ValueError(f"Not supported target: {target}")
70
+ self.copy_source_files_to_output_directory()
71
+
72
+ @GeneralUtilities.check_arguments
73
+ def linting(self) -> None:
74
+ pass#TODO
75
+
76
+ @GeneralUtilities.check_arguments
77
+ def do_common_tasks(self,current_codeunit_version:str )-> None:
78
+ self.do_common_tasks_base(current_codeunit_version)
79
+
80
+ @GeneralUtilities.check_arguments
81
+ def generate_reference(self) -> None:
82
+ self.generate_reference_using_docfx()
83
+
84
+
85
+ @GeneralUtilities.check_arguments
86
+ def run_testcases(self,package_name:str) -> None:
87
+ codeunit_folder = self.get_codeunit_folder()
88
+ repository_folder = GeneralUtilities.resolve_relative_path("..", codeunit_folder)
89
+ codeunit_name = os.path.basename(codeunit_folder)
90
+ src_folder = GeneralUtilities.resolve_relative_path(package_name, codeunit_folder)
91
+
92
+ self._protected_sc.run_with_epew("flutter", "test --coverage", src_folder)
93
+ test_coverage_folder_relative = "Other/Artifacts/TestCoverage"
94
+ test_coverage_folder = GeneralUtilities.resolve_relative_path(test_coverage_folder_relative, codeunit_folder)
95
+ GeneralUtilities.ensure_directory_exists(test_coverage_folder)
96
+ coverage_file_relative = f"{test_coverage_folder_relative}/TestCoverage.xml"
97
+ coverage_file = GeneralUtilities.resolve_relative_path(coverage_file_relative, codeunit_folder)
98
+ self._protected_sc.run_with_epew("lcov_cobertura", f"coverage/lcov.info --base-dir . --excludes test --output ../{coverage_file_relative} --demangle", src_folder)
99
+
100
+ # format correctly
101
+ content = GeneralUtilities.read_text_from_file(coverage_file)
102
+ content = re.sub('<![^<]+>', '', content)
103
+ content = re.sub('\\\\', '/', content)
104
+ content = re.sub('\\ name=\\"lib\\"', '', content)
105
+ content = re.sub('\\ filename=\\"lib/', f' filename="{package_name}/lib/', content)
106
+ GeneralUtilities.write_text_to_file(coverage_file, content)
107
+ self.tfcps_Tools_General.merge_packages(coverage_file, self.get_codeunit_name())
108
+ self.tfcps_Tools_General.calculate_entire_line_rate(coverage_file)
109
+ self.run_testcases_common_post_task(repository_folder, codeunit_name, True, self.get_target_environment_type())
110
+
111
+
112
+ def get_dependencies(self)->dict[str,set[str]]:
113
+ return []#TODO
114
+
115
+ @GeneralUtilities.check_arguments
116
+ def get_available_versions(self,dependencyname:str)->list[str]:
117
+ return []#TODO
118
+
119
+ def set_dependency_version(self,name:str,new_version:str)->None:
120
+ raise ValueError(f"Operation is not implemented.")
121
+
122
+ class TFCPS_CodeUnitSpecific_Flutter_CLI:
123
+
124
+ @staticmethod
125
+ def parse(file:str)->TFCPS_CodeUnitSpecific_Flutter_Functions:
126
+ parser=TFCPS_CodeUnitSpecific_Base_CLI.get_base_parser()
127
+ #add custom parameter if desired
128
+ args=parser.parse_args()
129
+ result:TFCPS_CodeUnitSpecific_Flutter_Functions=TFCPS_CodeUnitSpecific_Flutter_Functions(file,LogLevel(int(args.verbosity)),args.targetenvironmenttype,not args.nocache,args.ispremerge)
130
+ return result
File without changes
@@ -0,0 +1,74 @@
1
+ import os
2
+ from lxml import etree
3
+ from ...GeneralUtilities import GeneralUtilities
4
+ from ...ScriptCollectionCore import ScriptCollectionCore
5
+ from ...SCLog import LogLevel
6
+ from ..TFCPS_CodeUnitSpecific_Base import TFCPS_CodeUnitSpecific_Base,TFCPS_CodeUnitSpecific_Base_CLI
7
+
8
+ class TFCPS_CodeUnitSpecific_Go_Functions(TFCPS_CodeUnitSpecific_Base):
9
+
10
+ def __init__(self,current_file:str,verbosity:LogLevel,targetenvironmenttype:str,use_cache:bool,is_pre_merge:bool):
11
+ super().__init__(current_file, verbosity,targetenvironmenttype,use_cache,is_pre_merge)
12
+
13
+ @GeneralUtilities.check_arguments
14
+ def build(self) -> None:
15
+ #TODO
16
+ self.__generate_sbom_for_go_image()
17
+
18
+ @GeneralUtilities.check_arguments
19
+ def __generate_sbom_for_go_image(self) -> None:
20
+ pass#TODO
21
+
22
+ @GeneralUtilities.check_arguments
23
+ def linting(self) -> None:
24
+ pass#TODO
25
+
26
+ @GeneralUtilities.check_arguments
27
+ def __update_coverage_file(self,coverage_file:str) -> None:
28
+ tree = etree.parse(coverage_file)
29
+ root = tree.getroot()
30
+ for package in root.findall(".//package"):
31
+ package.set("name",self.get_codeunit_name())
32
+ for cls in root.findall(".//class"):
33
+ filename = cls.get("filename")
34
+ if filename:
35
+ cls.set("filename", f"./{filename}")
36
+ cls.set("name",str(filename).rsplit("/", 1)[-1])
37
+ tree.write(coverage_file, encoding="utf-8", xml_declaration=True, pretty_print=True)
38
+
39
+ @GeneralUtilities.check_arguments
40
+ def run_testcases(self) -> None:
41
+ test_coverage_folder = os.path.join(self.get_codeunit_folder(), "Other", "Artifacts", "TestCoverage").replace("\\", "/")
42
+ GeneralUtilities.ensure_directory_exists(test_coverage_folder)
43
+ src_folder = GeneralUtilities.resolve_relative_path(self.get_codeunit_name(), self.get_codeunit_folder())
44
+ sc: ScriptCollectionCore = ScriptCollectionCore()
45
+ sc.run_program_argsasarray("go", ["install", "github.com/t-yuki/gocover-cobertura@latest"], src_folder)
46
+ sc.run_program_argsasarray("go", ["test", "-coverprofile=coverage.out", "./..."], src_folder)
47
+ coverage_file:str=f"{test_coverage_folder}/TestCoverage.xml"
48
+ sc.run_program_argsasarray("sh", ["-c", f"gocover-cobertura < coverage.out > {coverage_file}"], src_folder)
49
+ self.__update_coverage_file(coverage_file)
50
+ self.run_testcases_common_post_task(self.get_repository_folder(),self.get_codeunit_name(),True,self.get_type_environment_type())
51
+
52
+ def get_dependencies(self)->dict[str,set[str]]:
53
+ return []#TODO
54
+
55
+ @GeneralUtilities.check_arguments
56
+ def get_available_versions(self,dependencyname:str)->list[str]:
57
+ return []#TODO
58
+
59
+ def set_dependency_version(self,name:str,new_version:str)->None:
60
+ raise ValueError(f"Operation is not implemented.")
61
+
62
+ class TFCPS_CodeUnitSpecific_Go_CLI:
63
+
64
+ @staticmethod
65
+ def parse(file:str)->TFCPS_CodeUnitSpecific_Go_Functions:
66
+ parser=TFCPS_CodeUnitSpecific_Base_CLI.get_base_parser()
67
+ #add custom parameter if desired
68
+ args=parser.parse_args()
69
+ result:TFCPS_CodeUnitSpecific_Go_Functions=TFCPS_CodeUnitSpecific_Go_Functions(file,LogLevel(int(args.verbosity)),args.targetenvironmenttype,not args.nocache,args.ispremerge)
70
+ return result
71
+
72
+ def run_testcases():
73
+ t :TFCPS_CodeUnitSpecific_Go_Functions= TFCPS_CodeUnitSpecific_Go_CLI().parse(__file__)
74
+ t.run_testcases()
File without changes
@@ -0,0 +1,131 @@
1
+ import os
2
+ import re
3
+ from lxml import etree
4
+ from ...GeneralUtilities import GeneralUtilities
5
+ from ...SCLog import LogLevel
6
+ from ..TFCPS_CodeUnitSpecific_Base import TFCPS_CodeUnitSpecific_Base,TFCPS_CodeUnitSpecific_Base_CLI
7
+
8
+ class TFCPS_CodeUnitSpecific_NodeJS_Functions(TFCPS_CodeUnitSpecific_Base):
9
+
10
+
11
+ def __init__(self,current_file:str,verbosity:LogLevel,targetenvironmenttype:str,use_cache:bool,is_pre_merge:bool):
12
+ super().__init__(current_file, verbosity,targetenvironmenttype,use_cache,is_pre_merge)
13
+
14
+
15
+ @GeneralUtilities.check_arguments
16
+ def build(self) -> None:
17
+ self._protected_sc.run_with_epew("npm", "run build", self.get_codeunit_folder(),print_live_output=self._protected_sc.log.loglevel==LogLevel.Diagnostic,encode_argument_in_base64=True)
18
+ self.standardized_tasks_build_bom_for_node_project()
19
+ self.copy_source_files_to_output_directory()
20
+
21
+ @GeneralUtilities.check_arguments
22
+ def linting(self) -> None:
23
+ self._protected_sc.run_with_epew("npm", "run lint", self.get_codeunit_folder(),print_live_output=self._protected_sc.log.loglevel==LogLevel.Diagnostic,encode_argument_in_base64=True)
24
+
25
+ @GeneralUtilities.check_arguments
26
+ def do_common_tasks(self,current_codeunit_version:str)-> None:
27
+ codeunit_version = current_codeunit_version
28
+ codeunit_folder = self.get_codeunit_folder()
29
+ self.do_common_tasks_base(current_codeunit_version)
30
+ self.tfcps_Tools_General.replace_version_in_packagejson_file(GeneralUtilities.resolve_relative_path("./package.json", codeunit_folder), codeunit_version)
31
+ self.tfcps_Tools_General.do_npm_install(codeunit_folder, True,self.use_cache())
32
+ #if generateAPIClientBase.generate_api_client():
33
+ # generateAPIClientGenerate:GenerateAPIClientGenerate=generateAPIClientBase
34
+ # self.tfcps_Tools_General.generate_api_client_from_dependent_codeunit_in_angular(codeunit_folder, generateAPIClientGenerate.name_of_api_providing_codeunit,generateAPIClientGenerate.generate_api_client)
35
+
36
+ @GeneralUtilities.check_arguments
37
+ def generate_reference(self) -> None:
38
+ self.generate_reference_using_docfx()
39
+
40
+
41
+ @GeneralUtilities.check_arguments
42
+ def run_testcases(self) -> None:
43
+ # prepare
44
+ codeunit_name: str =self.get_codeunit_name()
45
+
46
+ codeunit_folder =self.get_codeunit_folder()
47
+ repository_folder = os.path.dirname(codeunit_folder)
48
+
49
+ # run testcases
50
+ self._protected_sc.run_with_epew("npm", f"run test-{self.get_target_environment_type()}", self.get_codeunit_folder(),print_live_output=self._protected_sc.log.loglevel==LogLevel.Diagnostic,encode_argument_in_base64=True)
51
+
52
+ # rename file
53
+ coverage_folder = os.path.join(codeunit_folder, "Other", "Artifacts", "TestCoverage")
54
+ target_file = os.path.join(coverage_folder, "TestCoverage.xml")
55
+ GeneralUtilities.ensure_file_does_not_exist(target_file)
56
+ os.rename(os.path.join(coverage_folder, "cobertura-coverage.xml"), target_file)
57
+ self.__rename_packagename_in_coverage_file(target_file, codeunit_name)
58
+
59
+ # adapt backslashs to slashs
60
+ content = GeneralUtilities.read_text_from_file(target_file)
61
+ content = re.sub('\\\\', '/', content)
62
+ GeneralUtilities.write_text_to_file(target_file, content)
63
+
64
+ # aggregate packages in testcoverage-file
65
+ roottree: etree._ElementTree = etree.parse(target_file)
66
+ existing_classes = list(roottree.xpath('//coverage/packages/package/classes/class'))
67
+
68
+ old_packages_list = roottree.xpath('//coverage/packages/package')
69
+ for package in old_packages_list:
70
+ package.getparent().remove(package)
71
+
72
+ root = roottree.getroot()
73
+ packages_element = root.find("packages")
74
+ package_element = etree.SubElement(packages_element, "package")
75
+ package_element.attrib['name'] = codeunit_name
76
+ package_element.attrib['lines-valid'] = root.attrib["lines-valid"]
77
+ package_element.attrib['lines-covered'] = root.attrib["lines-covered"]
78
+ package_element.attrib['line-rate'] = root.attrib["line-rate"]
79
+ package_element.attrib['branches-valid'] = root.attrib["branches-valid"]
80
+ package_element.attrib['branches-covered'] = root.attrib["branches-covered"]
81
+ package_element.attrib['branch-rate'] = root.attrib["branch-rate"]
82
+ package_element.attrib['timestamp'] = root.attrib["timestamp"]
83
+ package_element.attrib['complexity'] = root.attrib["complexity"]
84
+
85
+ classes_element = etree.SubElement(package_element, "classes")
86
+
87
+ for existing_class in existing_classes:
88
+ classes_element.append(existing_class)
89
+
90
+ result = etree.tostring(roottree, pretty_print=True).decode("utf-8")
91
+ GeneralUtilities.write_text_to_file(target_file, result)
92
+
93
+ # post tasks
94
+ self.run_testcases_common_post_task(repository_folder, codeunit_name, True, self.get_target_environment_type())
95
+
96
+ @GeneralUtilities.check_arguments
97
+ def __rename_packagename_in_coverage_file(self, file: str, codeunit_name: str) -> None:
98
+ root: etree._ElementTree = etree.parse(file)
99
+ packages = root.xpath('//coverage/packages/package')
100
+ for package in packages:
101
+ package.attrib['name'] = codeunit_name
102
+ result = etree.tostring(root).decode("utf-8")
103
+ GeneralUtilities.write_text_to_file(file, result)
104
+
105
+
106
+ @GeneralUtilities.check_arguments
107
+ def standardized_tasks_build_bom_for_node_project(self) -> None:
108
+ relative_path_to_bom_file = f"Other/Artifacts/BOM/{os.path.basename(self.get_codeunit_folder())}.{self.tfcps_Tools_General.get_version_of_codeunit(self.get_codeunit_file())}.sbom.xml"
109
+ self._protected_sc.run_with_epew("cyclonedx-npm", f"--output-format xml --output-file {relative_path_to_bom_file}", self.get_codeunit_folder(),print_live_output=self._protected_sc.log.loglevel==LogLevel.Diagnostic,encode_argument_in_base64=True)
110
+ self._protected_sc.format_xml_file(self.get_codeunit_folder()+"/"+relative_path_to_bom_file)
111
+
112
+
113
+ def get_dependencies(self)->dict[str,set[str]]:
114
+ return []#TODO
115
+
116
+ @GeneralUtilities.check_arguments
117
+ def get_available_versions(self,dependencyname:str)->list[str]:
118
+ return []#TODO
119
+
120
+ def set_dependency_version(self,name:str,new_version:str)->None:
121
+ raise ValueError(f"Operation is not implemented.")
122
+
123
+ class TFCPS_CodeUnitSpecific_NodeJS_CLI:
124
+
125
+ @staticmethod
126
+ def parse(file:str)->TFCPS_CodeUnitSpecific_NodeJS_Functions:
127
+ parser=TFCPS_CodeUnitSpecific_Base_CLI.get_base_parser()
128
+ #add custom parameter if desired
129
+ args=parser.parse_args()
130
+ result:TFCPS_CodeUnitSpecific_NodeJS_Functions=TFCPS_CodeUnitSpecific_NodeJS_Functions(file,LogLevel(int(args.verbosity)),args.targetenvironmenttype,not args.nocache,args.ispremerge)
131
+ return result
File without changes
@@ -0,0 +1,227 @@
1
+ import os
2
+ import re
3
+ from ...GeneralUtilities import GeneralUtilities,Dependency
4
+ from ...SCLog import LogLevel
5
+ from ..TFCPS_CodeUnitSpecific_Base import TFCPS_CodeUnitSpecific_Base,TFCPS_CodeUnitSpecific_Base_CLI
6
+
7
+ class TFCPS_CodeUnitSpecific_Python_Functions(TFCPS_CodeUnitSpecific_Base):
8
+
9
+ def __init__(self,current_file:str,verbosity:LogLevel,targetenvironmenttype:str,use_cache:bool,is_pre_merge:bool):
10
+ super().__init__(current_file, verbosity,targetenvironmenttype,use_cache,is_pre_merge)
11
+
12
+
13
+ @GeneralUtilities.check_arguments
14
+ def build(self) -> None:
15
+ codeunit_folder = self.get_codeunit_folder()
16
+ target_directory = GeneralUtilities.resolve_relative_path("../Artifacts/BuildResult_Wheel", os.path.join(self.get_artifacts_folder()))
17
+ GeneralUtilities.ensure_directory_exists(target_directory)
18
+ self._protected_sc.run_program("python", f"-m build --wheel --outdir {target_directory}", codeunit_folder)
19
+ self.generate_bom_for_python_project( )
20
+ self.copy_source_files_to_output_directory()
21
+
22
+ @GeneralUtilities.check_arguments
23
+ def generate_bom_for_python_project(self) -> None:
24
+ codeunit_folder: str=self.get_codeunit_folder()
25
+ codeunitname: str=self.get_codeunit_name()
26
+ repository_folder = os.path.dirname(codeunit_folder)
27
+
28
+ codeunitversion = self.tfcps_Tools_General.get_version_of_codeunit(self.get_codeunit_file())
29
+ bom_folder = "Other/Artifacts/BOM"
30
+ bom_folder_full = os.path.join(codeunit_folder, bom_folder)
31
+ GeneralUtilities.ensure_directory_exists(bom_folder_full)
32
+ if not os.path.isfile(os.path.join(codeunit_folder, "requirements.txt")):
33
+ raise ValueError(f"Codeunit {codeunitname} does not have a 'requirements.txt'-file.")
34
+ # TODO check that all values from setup.cfg are contained in requirements.txt
35
+ result = self._protected_sc.run_program("cyclonedx-py", "requirements", codeunit_folder)
36
+ bom_file_relative_json = f"{bom_folder}/{codeunitname}.{codeunitversion}.bom.json"
37
+ bom_file_relative_xml = f"{bom_folder}/{codeunitname}.{codeunitversion}.bom.xml"
38
+ bom_file_json = os.path.join(codeunit_folder, bom_file_relative_json)
39
+ bom_file_xml = os.path.join(codeunit_folder, bom_file_relative_xml)
40
+
41
+ GeneralUtilities.ensure_file_exists(bom_file_json)
42
+ GeneralUtilities.write_text_to_file(bom_file_json, result[1])
43
+ cyclonedx_exe=self.tfcps_Tools_General.ensure_cyclonedxcli_is_available(repository_folder,not self.use_cache())
44
+ self._protected_sc.run_program(cyclonedx_exe, f"convert --input-file ./{codeunitname}/{bom_file_relative_json} --input-format json --output-file ./{codeunitname}/{bom_file_relative_xml} --output-format xml", repository_folder)
45
+ self._protected_sc.format_xml_file(bom_file_xml)
46
+ GeneralUtilities.ensure_file_does_not_exist(bom_file_json)
47
+
48
+ @GeneralUtilities.check_arguments
49
+ def linting(self) -> None:
50
+ codeunitname: str = self.get_codeunit_name()
51
+
52
+ repository_folder: str = self.get_repository_folder()
53
+ errors_found = False
54
+ self._protected_sc.log.log(f"Check for linting-issues in codeunit {codeunitname}.")
55
+ src_folder = os.path.join(repository_folder, codeunitname, codeunitname)
56
+ tests_folder = src_folder+"Tests"
57
+ # TODO check if there are errors in sarif-file
58
+ for file in GeneralUtilities.get_all_files_of_folder(src_folder)+GeneralUtilities.get_all_files_of_folder(tests_folder):
59
+ relative_file_path_in_repository = os.path.relpath(file, repository_folder)
60
+ if file.endswith(".py") and os.path.getsize(file) > 0 and not self._protected_sc.file_is_git_ignored(relative_file_path_in_repository, repository_folder):
61
+ self._protected_sc.log.log(f"Check for linting-issues in {os.path.relpath(file, os.path.join(repository_folder, codeunitname))}.")
62
+ linting_result = self._protected_sc.python_file_has_errors(file, repository_folder)
63
+ if (linting_result[0]):
64
+ errors_found = True
65
+ for error in linting_result[1]:
66
+ self._protected_sc.log.log(error, LogLevel.Warning)
67
+ if errors_found:
68
+ raise ValueError("Linting-issues occurred.")
69
+ else:
70
+ self._protected_sc.log.log("No linting-issues found.")
71
+
72
+ @GeneralUtilities.check_arguments
73
+ def do_common_tasks(self,current_codeunit_version:str )-> None:
74
+ self.do_common_tasks_base(current_codeunit_version)
75
+ codeunitname =self.get_codeunit_name()
76
+ codeunit_version = self.tfcps_Tools_General.get_version_of_project(self.get_repository_folder())
77
+ self._protected_sc.replace_version_in_ini_file(GeneralUtilities.resolve_relative_path("./setup.cfg", self.get_codeunit_folder()), codeunit_version)
78
+ self._protected_sc.replace_version_in_python_file(GeneralUtilities.resolve_relative_path(f"./{codeunitname}/{codeunitname}Core.py", self.get_codeunit_folder()), codeunit_version)
79
+
80
+ @GeneralUtilities.check_arguments
81
+ def generate_reference(self) -> None:
82
+ self.generate_reference_using_docfx()
83
+
84
+ @GeneralUtilities.check_arguments
85
+ def run_testcases(self) -> None:
86
+ codeunitname: str =self.get_codeunit_name()
87
+ repository_folder: str = self.get_repository_folder()
88
+ codeunit_folder = os.path.join(repository_folder, codeunitname)
89
+ self._protected_sc.run_program("coverage", f"run -m pytest -s ./{codeunitname}Tests", codeunit_folder)
90
+ self._protected_sc.run_program("coverage", "xml", codeunit_folder)
91
+ coveragefolder = os.path.join(repository_folder, codeunitname, "Other/Artifacts/TestCoverage")
92
+ GeneralUtilities.ensure_directory_exists(coveragefolder)
93
+ coveragefile = os.path.join(coveragefolder, "TestCoverage.xml")
94
+ GeneralUtilities.ensure_file_does_not_exist(coveragefile)
95
+ os.rename(os.path.join(repository_folder, codeunitname, "coverage.xml"), coveragefile)
96
+ self.tfcps_Tools_General.merge_packages(coveragefile,codeunitname)
97
+ self.run_testcases_common_post_task(repository_folder, codeunitname, True, self.get_type_environment_type())
98
+
99
+ def get_dependencies(self)->dict[str,set[str]]:
100
+ return GeneralUtilities.merge_dependency_lists([
101
+ self.get_dependencies_from_setupcfg(),
102
+ self.get_dependencies_from_requirementstxt(),
103
+ self.get_dependencies_from_otherrequirementstxt()
104
+ ])
105
+
106
+ def get_dependencies_from_setupcfg(self)->list[Dependency]:
107
+ setupcfg_file=os.path.join(self.get_codeunit_folder(),"setup.cfg")
108
+ lines = GeneralUtilities.read_lines_from_file(setupcfg_file)
109
+ result:list[Dependency]=[]
110
+ is_in_dependency_section=False
111
+ for line in lines:
112
+ if line=="install_requires =":
113
+ is_in_dependency_section=True
114
+ elif line.startswith(" "):
115
+ if is_in_dependency_section:
116
+ match = re.match(r"^\s*([A-Za-z0-9_\-]+)\s*([<>=!~]+)?\s*(.*)?$", line)
117
+ if match:
118
+ dep_name = match.group(1)
119
+ dep_operator = match.group(2) or None#pylint:disable=unused-variable
120
+ dep_version = match.group(3) or None
121
+ dep=Dependency(dep_name,dep_version)
122
+ result.append(dep)
123
+ else:
124
+ raise ValueError(f"Unparsable dependency-definition-line: \"{line}\"")
125
+ else:
126
+ is_in_dependency_section=False
127
+ return result
128
+
129
+ def get_dependencies_from_requirementstxt(self)->list[Dependency]:
130
+ return self.get_dependencies_from_requirementsfile(os.path.join(self.get_codeunit_folder(),"requirements.txt"))
131
+
132
+ def get_dependencies_from_otherrequirementstxt(self)->list[Dependency]:
133
+ rfile=os.path.join(self.get_codeunit_folder(),"Other","requirements.txt")
134
+ if os.path.isfile(rfile):
135
+ return self.get_dependencies_from_requirementsfile(rfile)
136
+ else:
137
+ return []
138
+
139
+ def get_dependencies_from_requirementsfile(self,file:str)->list[Dependency]:
140
+ lines = GeneralUtilities.read_lines_from_file(file)
141
+ result:list[Dependency]=[]
142
+ for line in lines:
143
+ match = re.match(r"^([A-Za-z0-9_\-]+)\s*([<>=!~]+)?\s*(.*)?$", line)
144
+ if match:
145
+ dep_name = match.group(1)
146
+ dep_operator = match.group(2) or None#pylint:disable=unused-variable
147
+ dep_version = match.group(3) or None
148
+ dep=Dependency(dep_name,dep_version)
149
+ result.append(dep)
150
+
151
+ return result
152
+
153
+ @GeneralUtilities.check_arguments
154
+ def get_available_versions(self,dependencyname:str)->list[str]:
155
+ result=self._protected_sc.run_program("pip3",f"index versions {dependencyname}")
156
+ available_versions_line:str=[line for line in GeneralUtilities.string_to_lines(result[1]) if line.startswith("Available versions: ")][0]
157
+ available_versions=[version_str.strip() for version_str in available_versions_line[len("Available versions: "):].split(",")]
158
+ result=[]
159
+ for v in available_versions:
160
+ if re.match(r"^(\d+).(\d+).(\d+)$", v) is not None:
161
+ result.append(v)
162
+ elif re.match(r"^(\d+).(\d+)$", v) is not None:
163
+ result.append(v+".0")
164
+ elif re.match(r"^(\d+)$", v) is not None:
165
+ result.append(v+".0.0")
166
+ return result
167
+
168
+ def set_dependency_version(self,name:str,new_version:str)->None:
169
+ self.__set_dependency_version_in_setupcfg(name,new_version)
170
+ self.__set_dependency_version_in_requirementstxt(name,new_version)
171
+ self.__set_dependency_version_in_otherrequirementstxt(name,new_version)
172
+
173
+ def __set_dependency_version_in_setupcfg(self,name:str,new_version:str)->None:
174
+ setupcfg_file=os.path.join(self.get_codeunit_folder(),"setup.cfg")
175
+ lines=GeneralUtilities.read_lines_from_file(setupcfg_file)
176
+ new_lines:list[str]=[]
177
+ for line in lines:
178
+ match = re.match("^(\\s*)("+re.escape(name)+")\\s*([<>=!~]+)?\\s*(.*)?$", line)
179
+ if match:
180
+ whitespace = match.group(1)
181
+ dep_name = match.group(2)#pylint:disable=unused-variable
182
+ dep_operator = match.group(3) or None
183
+ dep_version = match.group(4) or None#pylint:disable=unused-variable
184
+ new_line=whitespace+name
185
+ if dep_operator is None:
186
+ dep_operator=">="
187
+ new_line=new_line+dep_operator+new_version
188
+ new_lines.append(new_line)
189
+ else:
190
+ new_lines.append(line)
191
+ GeneralUtilities.write_lines_to_file(setupcfg_file,new_lines)
192
+
193
+ def __set_dependency_version_in_requirementstxt(self,name:str,new_version:str)->None:
194
+ self.__set_dependency_version_in_requirements(name,new_version,os.path.join(self.get_codeunit_folder(),"requirements.txt"))
195
+
196
+ def __set_dependency_version_in_otherrequirementstxt(self,name:str,new_version:str)->None:
197
+ rfile=os.path.join(self.get_codeunit_folder(),"Other","requirements.txt")
198
+ if os.path.isfile(rfile):
199
+ self.__set_dependency_version_in_requirements(name,new_version,rfile)
200
+
201
+ def __set_dependency_version_in_requirements(self,name:str,new_version:str,requirementsfile:str)->None:
202
+ lines=GeneralUtilities.read_lines_from_file(requirementsfile)
203
+ new_lines:list[str]=[]
204
+ for line in lines:
205
+ match = re.match("^("+re.escape(name)+")\\s*([<>=!~]+)?\\s*(.*)?$", line)
206
+ if match:
207
+ dep_name = match.group(1)#pylint:disable=unused-variable
208
+ dep_operator = match.group(2) or None
209
+ dep_version = match.group(3) or None#pylint:disable=unused-variable
210
+ new_line=name
211
+ if dep_operator is None:
212
+ dep_operator=">="
213
+ new_line=new_line+dep_operator+new_version
214
+ new_lines.append(new_line)
215
+ else:
216
+ new_lines.append(line)
217
+ GeneralUtilities.write_lines_to_file(requirementsfile,new_lines)
218
+
219
+ class TFCPS_CodeUnitSpecific_Python_CLI:
220
+
221
+ @staticmethod
222
+ def parse(file:str)->TFCPS_CodeUnitSpecific_Python_Functions:
223
+ parser=TFCPS_CodeUnitSpecific_Base_CLI.get_base_parser()
224
+ #add custom parameter if desired
225
+ args=parser.parse_args()
226
+ result:TFCPS_CodeUnitSpecific_Python_Functions=TFCPS_CodeUnitSpecific_Python_Functions(file,LogLevel(int(args.verbosity)),args.targetenvironmenttype,not args.nocache,args.ispremerge)
227
+ return result
File without changes