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.
- ScriptCollection/AnionBuildPlatform.py +2 -0
- ScriptCollection/ScriptCollectionCore.py +1 -1
- ScriptCollection/TFCPS/Docker/TFCPS_CodeUnitSpecific_Docker.py +88 -0
- ScriptCollection/TFCPS/Docker/__init__.py +0 -0
- ScriptCollection/TFCPS/DotNet/CertificateGeneratorInformationBase.py +8 -0
- ScriptCollection/TFCPS/DotNet/CertificateGeneratorInformationGenerate.py +6 -0
- ScriptCollection/TFCPS/DotNet/CertificateGeneratorInformationNoGenerate.py +7 -0
- ScriptCollection/TFCPS/DotNet/TFCPS_CodeUnitSpecific_DotNet.py +479 -0
- ScriptCollection/TFCPS/DotNet/__init__.py +0 -0
- ScriptCollection/TFCPS/Flutter/TFCPS_CodeUnitSpecific_Flutter.py +43 -0
- ScriptCollection/TFCPS/Flutter/__init__.py +0 -0
- ScriptCollection/TFCPS/NodeJS/TFCPS_CodeUnitSpecific_NodeJS.py +123 -0
- ScriptCollection/TFCPS/NodeJS/__init__.py +0 -0
- ScriptCollection/TFCPS/Python/TFCPS_CodeUnitSpecific_Python.py +114 -0
- ScriptCollection/TFCPS/Python/__init__.py +0 -0
- ScriptCollection/TFCPS/TFCPS_CodeUnitSpecific_Base.py +417 -0
- ScriptCollection/TFCPS/TFCPS_CodeUnit_BuildCodeUnit.py +120 -0
- ScriptCollection/TFCPS/TFCPS_CodeUnit_BuildCodeUnits.py +80 -0
- ScriptCollection/TFCPS/TFCPS_CreateRelease.py +97 -0
- ScriptCollection/TFCPS/TFCPS_Generic.py +43 -0
- ScriptCollection/TFCPS/TFCPS_MergeToMain.py +125 -0
- ScriptCollection/TFCPS/TFCPS_MergeToStable.py +361 -0
- ScriptCollection/TFCPS/TFCPS_Tools_Dependencies.py +16 -0
- ScriptCollection/TFCPS/TFCPS_Tools_General.py +1076 -0
- ScriptCollection/TFCPS/__init__.py +0 -0
- {scriptcollection-4.0.11.dist-info → scriptcollection-4.0.13.dist-info}/METADATA +1 -1
- scriptcollection-4.0.13.dist-info/RECORD +41 -0
- scriptcollection-4.0.11.dist-info/RECORD +0 -17
- {scriptcollection-4.0.11.dist-info → scriptcollection-4.0.13.dist-info}/WHEEL +0 -0
- {scriptcollection-4.0.11.dist-info → scriptcollection-4.0.13.dist-info}/entry_points.txt +0 -0
- {scriptcollection-4.0.11.dist-info → scriptcollection-4.0.13.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,417 @@
|
|
1
|
+
import os
|
2
|
+
import traceback
|
3
|
+
from pathlib import Path
|
4
|
+
import shutil
|
5
|
+
import re
|
6
|
+
import json
|
7
|
+
import argparse
|
8
|
+
from abc import ABC
|
9
|
+
import xmlschema
|
10
|
+
from lxml import etree
|
11
|
+
from ..GeneralUtilities import GeneralUtilities
|
12
|
+
from ..ScriptCollectionCore import ScriptCollectionCore
|
13
|
+
from ..SCLog import LogLevel
|
14
|
+
from .TFCPS_Tools_General import TFCPS_Tools_General
|
15
|
+
from .TFCPS_Tools_Dependencies import TFCPS_Tools_Dependencies,Dependency
|
16
|
+
|
17
|
+
class TFCPS_CodeUnitSpecific_Base(ABC):
|
18
|
+
|
19
|
+
__current_file:str=None
|
20
|
+
__target_environment_type:str
|
21
|
+
__repository_folder:str=None
|
22
|
+
__codeunit_folder:str=None
|
23
|
+
__current_folder:str=None
|
24
|
+
__verbosity:LogLevel=None
|
25
|
+
__use_cache:bool=None
|
26
|
+
tfcps_Tools_General:TFCPS_Tools_General
|
27
|
+
_protected_sc:ScriptCollectionCore
|
28
|
+
__is_pre_merge:bool=False#TODO must be setable to true
|
29
|
+
__validate_developers_of_repository:bool=True#TODO must be setable to false
|
30
|
+
|
31
|
+
def __init__(self,current_file:str,verbosity:LogLevel,target_envionment_type:str,use_cache:bool):
|
32
|
+
self.__verbosity=verbosity
|
33
|
+
self.__use_cache=use_cache
|
34
|
+
self.__target_environment_type=target_envionment_type
|
35
|
+
self.__current_file = str(Path(current_file).absolute())
|
36
|
+
self.__current_folder = os.path.dirname(self.__current_file)
|
37
|
+
self.__codeunit_folder=self.__search_codeunit_folder()
|
38
|
+
self._protected_sc=ScriptCollectionCore()#TODO set loglevel
|
39
|
+
self.tfcps_Tools_General=TFCPS_Tools_General(self._protected_sc)
|
40
|
+
self.tfcps_Tools_General.assert_is_codeunit_folder(self.__codeunit_folder)
|
41
|
+
self.__repository_folder=GeneralUtilities.resolve_relative_path("..",self.__codeunit_folder)
|
42
|
+
self._protected_sc.assert_is_git_repository(self.__repository_folder)
|
43
|
+
|
44
|
+
def __search_codeunit_folder(self)->str:
|
45
|
+
current_path:str=os.path.dirname(self.__current_file)
|
46
|
+
enabled:bool=True
|
47
|
+
while enabled:
|
48
|
+
try:
|
49
|
+
current_path=GeneralUtilities.resolve_relative_path("..",current_path)
|
50
|
+
foldername=os.path.basename(current_path)
|
51
|
+
codeunit_file:str=os.path.join(current_path,f"{foldername}.codeunit.xml")
|
52
|
+
if os.path.isfile(codeunit_file):
|
53
|
+
return current_path
|
54
|
+
except:
|
55
|
+
enabled=False
|
56
|
+
raise ValueError(f"Can not find codeunit-folder for folder \"{self.__current_file}\".")
|
57
|
+
|
58
|
+
def update_dependencies_default(self):
|
59
|
+
d:TFCPS_Tools_Dependencies=TFCPS_Tools_Dependencies()
|
60
|
+
dependencies:list[Dependency]=d.get_dependencies()
|
61
|
+
for dependency in dependencies:
|
62
|
+
if dependency.current_version!=dependency.latest_version:
|
63
|
+
pass#TODO update dependency
|
64
|
+
|
65
|
+
def get_version_of_project(self)->str:
|
66
|
+
return self.tfcps_Tools_General.get_version_of_project(self.get_repository_folder())
|
67
|
+
|
68
|
+
@GeneralUtilities.check_arguments
|
69
|
+
def do_common_tasks_base(self,current_codeunit_version:str):
|
70
|
+
|
71
|
+
repository_folder: str =self.get_repository_folder()
|
72
|
+
self._protected_sc.assert_is_git_repository(repository_folder)
|
73
|
+
codeunit_name: str = self.get_codeunit_name()
|
74
|
+
project_version = self.tfcps_Tools_General.get_version_of_project(repository_folder)
|
75
|
+
if current_codeunit_version is None:
|
76
|
+
current_codeunit_version=project_version
|
77
|
+
codeunit_folder = os.path.join(repository_folder, codeunit_name)
|
78
|
+
|
79
|
+
# check codeunit-conformity
|
80
|
+
# TODO check if foldername=="<codeunitname>[.codeunit.xml]" == <codeunitname> in file
|
81
|
+
supported_codeunitspecificationversion = "2.9.4" # should always be the latest version of the ProjectTemplates-repository
|
82
|
+
codeunit_file = os.path.join(codeunit_folder, f"{codeunit_name}.codeunit.xml")
|
83
|
+
if not os.path.isfile(codeunit_file):
|
84
|
+
raise ValueError(f'Codeunitfile "{codeunit_file}" does not exist.')
|
85
|
+
# TODO implement usage of self.reference_latest_version_of_xsd_when_generating_xml
|
86
|
+
namespaces = {'cps': 'https://projects.aniondev.de/PublicProjects/Common/ProjectTemplates/-/tree/main/Conventions/RepositoryStructure/CommonProjectStructure', 'xsi': 'http://www.w3.org/2001/XMLSchema-instance'}
|
87
|
+
root: etree._ElementTree = etree.parse(codeunit_file)
|
88
|
+
|
89
|
+
# check codeunit-spcecification-version
|
90
|
+
try:
|
91
|
+
codeunit_file_version = root.xpath('//cps:codeunit/@codeunitspecificationversion', namespaces=namespaces)[0]
|
92
|
+
if codeunit_file_version != supported_codeunitspecificationversion:
|
93
|
+
raise ValueError(f"ScriptCollection only supports processing codeunits with codeunit-specification-version={supported_codeunitspecificationversion}.")
|
94
|
+
schemaLocation = root.xpath('//cps:codeunit/@xsi:schemaLocation', namespaces=namespaces)[0]
|
95
|
+
xmlschema.validate(codeunit_file, schemaLocation)
|
96
|
+
# TODO check if the properties codeunithastestablesourcecode, codeunithasupdatabledependencies, throwexceptionifcodeunitfilecannotbevalidated, developmentState and description exist and the values are valid
|
97
|
+
except Exception as exception:
|
98
|
+
self._protected_sc.log.log_exception(f'Codeunitfile "{codeunit_file}" can not be validated due to the following exception:', exception,traceback,LogLevel.Warning)
|
99
|
+
|
100
|
+
# check codeunit-name
|
101
|
+
codeunit_name_in_codeunit_file = root.xpath('//cps:codeunit/cps:name/text()', namespaces=namespaces)[0]
|
102
|
+
if codeunit_name != codeunit_name_in_codeunit_file:
|
103
|
+
raise ValueError(f"The folder-name ('{codeunit_name}') is not equal to the codeunit-name ('{codeunit_name_in_codeunit_file}').")
|
104
|
+
|
105
|
+
# check owner-name
|
106
|
+
codeunit_ownername_in_codeunit_file = self.tfcps_Tools_General. get_codeunit_owner_name(self.get_codeunit_file())
|
107
|
+
GeneralUtilities.assert_condition(GeneralUtilities.string_has_content(codeunit_ownername_in_codeunit_file), "No valid name for codeunitowner given.")
|
108
|
+
|
109
|
+
# check owner-emailaddress
|
110
|
+
codeunit_owneremailaddress_in_codeunit_file = self.tfcps_Tools_General.get_codeunit_owner_emailaddress(self.get_codeunit_file())
|
111
|
+
GeneralUtilities.assert_condition(GeneralUtilities.string_has_content(codeunit_owneremailaddress_in_codeunit_file), "No valid email-address for codeunitowner given.")
|
112
|
+
|
113
|
+
# check development-state
|
114
|
+
developmentstate = root.xpath('//cps:properties/@developmentstate', namespaces=namespaces)[0]
|
115
|
+
developmentstate_active = "Active development"
|
116
|
+
developmentstate_maintenance = "Maintenance-updates only"
|
117
|
+
developmentstate_inactive = "Inactive"
|
118
|
+
GeneralUtilities.assert_condition(developmentstate in (developmentstate_active, developmentstate_maintenance, developmentstate_inactive), f"Invalid development-state. Must be '{developmentstate_active}' or '{developmentstate_maintenance}' or '{developmentstate_inactive}' but was '{developmentstate}'.")
|
119
|
+
|
120
|
+
# check for mandatory files
|
121
|
+
files = ["Other/Build/Build.py", "Other/QualityCheck/Linting.py", "Other/Reference/GenerateReference.py"]
|
122
|
+
if self.tfcps_Tools_General.codeunit_has_testable_sourcecode(self.get_codeunit_file()):
|
123
|
+
# TODO check if the testsettings-section appears in the codeunit-file
|
124
|
+
files.append("Other/QualityCheck/RunTestcases.py")
|
125
|
+
if self.tfcps_Tools_General.codeunit_has_updatable_dependencies(self.get_codeunit_file()):
|
126
|
+
# TODO check if the updatesettings-section appears in the codeunit-file
|
127
|
+
files.append("Other/UpdateDependencies.py")
|
128
|
+
for file in files:
|
129
|
+
combined_file = os.path.join(codeunit_folder, file)
|
130
|
+
if not os.path.isfile(combined_file):
|
131
|
+
raise ValueError(f'The mandatory file "{file}" does not exist in the codeunit-folder.')
|
132
|
+
|
133
|
+
if os.path.isfile(os.path.join(codeunit_folder, "Other", "requirements.txt")):
|
134
|
+
self.install_requirementstxt_for_codeunit()
|
135
|
+
|
136
|
+
# check developer
|
137
|
+
if self.__validate_developers_of_repository:
|
138
|
+
expected_authors: list[tuple[str, str]] = []
|
139
|
+
expected_authors_in_xml = root.xpath('//cps:codeunit/cps:developerteam/cps:developer', namespaces=namespaces)
|
140
|
+
for expected_author in expected_authors_in_xml:
|
141
|
+
author_name = expected_author.xpath('./cps:developername/text()', namespaces=namespaces)[0]
|
142
|
+
author_emailaddress = expected_author.xpath('./cps:developeremailaddress/text()', namespaces=namespaces)[0]
|
143
|
+
expected_authors.append((author_name, author_emailaddress))
|
144
|
+
actual_authors: list[tuple[str, str]] = self.tfcps_Tools_General.get_all_authors_and_committers_of_repository(repository_folder, codeunit_name)
|
145
|
+
# TODO refactor this check to only check commits which are behind this but which are not already on main
|
146
|
+
# TODO verify also if the commit is signed by a valid key of the author
|
147
|
+
for actual_author in actual_authors:
|
148
|
+
if not (actual_author) in expected_authors:
|
149
|
+
actual_author_formatted = f"{actual_author[0]} <{actual_author[1]}>"
|
150
|
+
raise ValueError(f'Author/Comitter "{actual_author_formatted}" is not in the codeunit-developer-team. If {actual_author} is a authorized developer for this codeunit you should consider defining this in the codeunit-file or adapting the name using a .mailmap-file (see https://git-scm.com/docs/gitmailmap). The developer-team-check can also be disabled using the property validate_developers_of_repository.')
|
151
|
+
|
152
|
+
dependent_codeunits = self.tfcps_Tools_General.get_dependent_code_units(codeunit_file)
|
153
|
+
for dependent_codeunit in dependent_codeunits:
|
154
|
+
if not self.tfcps_Tools_General.dependent_codeunit_exists(repository_folder, dependent_codeunit):
|
155
|
+
raise ValueError(f"Codeunit {codeunit_name} does have dependent codeunit {dependent_codeunit} which does not exist.")
|
156
|
+
|
157
|
+
# TODO implement cycle-check for dependent codeunits
|
158
|
+
|
159
|
+
artifacts_folder = os.path.join(codeunit_folder, "Other", "Artifacts")
|
160
|
+
GeneralUtilities.ensure_directory_does_not_exist(artifacts_folder)
|
161
|
+
|
162
|
+
# get artifacts from dependent codeunits
|
163
|
+
self.tfcps_Tools_General.copy_artifacts_from_dependent_code_units(repository_folder, codeunit_name)
|
164
|
+
|
165
|
+
# update codeunit-version
|
166
|
+
self.tfcps_Tools_General.write_version_to_codeunit_file(self.get_codeunit_file(), current_codeunit_version)
|
167
|
+
|
168
|
+
# set project version
|
169
|
+
package_json_file = os.path.join(repository_folder, "package.json") # TDOO move this to a general project-specific (and codeunit-independent-script)
|
170
|
+
if os.path.isfile(package_json_file):
|
171
|
+
package_json_data: str = None
|
172
|
+
with open(package_json_file, "r", encoding="utf-8") as f1:
|
173
|
+
package_json_data = json.load(f1)
|
174
|
+
package_json_data["version"] = project_version
|
175
|
+
with open(package_json_file, "w", encoding="utf-8") as f2:
|
176
|
+
json.dump(package_json_data, f2, indent=2)
|
177
|
+
GeneralUtilities.write_text_to_file(package_json_file, GeneralUtilities.read_text_from_file(package_json_file).replace("\r", ""))
|
178
|
+
|
179
|
+
# set default constants
|
180
|
+
self.tfcps_Tools_General.set_default_constants(os.path.join(codeunit_folder))
|
181
|
+
|
182
|
+
# Copy changelog-file
|
183
|
+
changelog_folder = os.path.join(repository_folder, "Other", "Resources", "Changelog")
|
184
|
+
changelog_file = os.path.join(changelog_folder, f"v{project_version}.md")
|
185
|
+
target_folder = os.path.join(codeunit_folder, "Other", "Artifacts", "Changelog")
|
186
|
+
GeneralUtilities.ensure_directory_exists(target_folder)
|
187
|
+
shutil.copy(changelog_file, target_folder)
|
188
|
+
|
189
|
+
# Hints-file
|
190
|
+
hints_file = os.path.join(codeunit_folder, "Other", "Reference", "ReferenceContent", "Hints.md")
|
191
|
+
if not os.path.isfile(hints_file):
|
192
|
+
raise ValueError(f"Hints-file '{hints_file}' does not exist.")
|
193
|
+
|
194
|
+
# Copy license-file
|
195
|
+
self.tfcps_Tools_General.copy_licence_file(self.get_codeunit_folder())
|
196
|
+
|
197
|
+
# Generate diff-report
|
198
|
+
self.tfcps_Tools_General.generate_diff_report(repository_folder, codeunit_name, self.tfcps_Tools_General.get_version_of_codeunit(self.get_codeunit_file()))
|
199
|
+
|
200
|
+
# TODO check for secrets using TruffleHog
|
201
|
+
# TODO run static code analysis tool to search for vulnerabilities
|
202
|
+
|
203
|
+
d:TFCPS_Tools_Dependencies=TFCPS_Tools_Dependencies()
|
204
|
+
dependencies:list[Dependency]=d.get_dependencies()
|
205
|
+
for dependency in dependencies:
|
206
|
+
#TODO show warning if the latest version of dependency is too old
|
207
|
+
if dependency.current_version!=dependency.latest_version:
|
208
|
+
dependency_is_disabled_for_update=False#TODO read this value from codeunit-file
|
209
|
+
if not dependency_is_disabled_for_update:
|
210
|
+
self._protected_sc.log.log(f"Dependency \"{dependency.name}\" is used in the outdated version v{dependency.current_version} and can be upudated to v{dependency.latest_version}",LogLevel.Warning)
|
211
|
+
|
212
|
+
|
213
|
+
|
214
|
+
|
215
|
+
@GeneralUtilities.check_arguments
|
216
|
+
def generate_reference_using_docfx(self=None):
|
217
|
+
reference_folder =os.path.join( self.get_codeunit_folder(),"Other","Reference")
|
218
|
+
generated_reference_folder = GeneralUtilities.resolve_relative_path("../Artifacts/Reference", reference_folder)
|
219
|
+
GeneralUtilities.ensure_directory_does_not_exist(generated_reference_folder)
|
220
|
+
GeneralUtilities.ensure_directory_exists(generated_reference_folder)
|
221
|
+
obj_folder = os.path.join(reference_folder, "obj")
|
222
|
+
GeneralUtilities.ensure_folder_exists_and_is_empty(obj_folder)
|
223
|
+
self._protected_sc.run_program("docfx", "-t default,templates/darkfx docfx.json", reference_folder)
|
224
|
+
GeneralUtilities.ensure_directory_does_not_exist(obj_folder)
|
225
|
+
|
226
|
+
@GeneralUtilities.check_arguments
|
227
|
+
def use_cache(self)->bool:
|
228
|
+
return self.__use_cache
|
229
|
+
|
230
|
+
@GeneralUtilities.check_arguments
|
231
|
+
def update_dependencies_base(self):
|
232
|
+
self.update_dependencies_default()
|
233
|
+
|
234
|
+
@GeneralUtilities.check_arguments
|
235
|
+
def get_codeunit_folder(self)->str:
|
236
|
+
return self.__codeunit_folder
|
237
|
+
|
238
|
+
@GeneralUtilities.check_arguments
|
239
|
+
def get_codeunit_name(self)->str:
|
240
|
+
return os.path.basename(self.__codeunit_folder)
|
241
|
+
|
242
|
+
@GeneralUtilities.check_arguments
|
243
|
+
def get_repository_folder(self)->str:
|
244
|
+
return self.__repository_folder
|
245
|
+
|
246
|
+
@GeneralUtilities.check_arguments
|
247
|
+
def get_current_folder(self)->str:
|
248
|
+
return self.__current_folder
|
249
|
+
|
250
|
+
@GeneralUtilities.check_arguments
|
251
|
+
def get_verbosity(self)->LogLevel:
|
252
|
+
return self.__verbosity
|
253
|
+
|
254
|
+
@GeneralUtilities.check_arguments
|
255
|
+
def get_artifacts_folder(self) -> str:
|
256
|
+
return os.path.join(self.get_codeunit_folder(), "Other", "Artifacts")
|
257
|
+
|
258
|
+
@GeneralUtilities.check_arguments
|
259
|
+
def get_codeunit_file(self) -> str:
|
260
|
+
return os.path.join(self.get_codeunit_folder(), f"{self.get_codeunit_name()}.codeunit.xml")
|
261
|
+
|
262
|
+
def get_type_environment_type(self)->str:
|
263
|
+
return self.__target_environment_type
|
264
|
+
|
265
|
+
def get_target_environment_type(self)->str:
|
266
|
+
return self.__target_environment_type
|
267
|
+
|
268
|
+
@GeneralUtilities.check_arguments
|
269
|
+
def copy_source_files_to_output_directory(self) -> None:
|
270
|
+
self._protected_sc.log.log("Copy sourcecode...")
|
271
|
+
codeunit_folder =self.get_codeunit_folder()
|
272
|
+
result = self._protected_sc.run_program_argsasarray("git", ["ls-tree", "-r", "HEAD", "--name-only"], codeunit_folder)
|
273
|
+
files = [f for f in result[1].split('\n') if len(f) > 0]
|
274
|
+
for file in files:
|
275
|
+
full_source_file = os.path.join(codeunit_folder, file)
|
276
|
+
if os.path.isfile(full_source_file):
|
277
|
+
# Reson of isdir-check:
|
278
|
+
# Prevent trying to copy files which are not exist.
|
279
|
+
# Otherwise exceptions occurr because uncommitted deletions of files will result in an error here.
|
280
|
+
target_file = os.path.join(codeunit_folder, "Other", "Artifacts", "SourceCode", file)
|
281
|
+
target_folder = os.path.dirname(target_file)
|
282
|
+
GeneralUtilities.ensure_directory_exists(target_folder)
|
283
|
+
shutil.copyfile(full_source_file, target_file)
|
284
|
+
|
285
|
+
@GeneralUtilities.check_arguments
|
286
|
+
def run_testcases_common_post_task(self, repository_folder: str, codeunit_name: str, generate_badges: bool, targetenvironmenttype: str) -> None:
|
287
|
+
self._protected_sc.assert_is_git_repository(repository_folder)
|
288
|
+
coverage_file_folder = os.path.join(repository_folder, codeunit_name, "Other/Artifacts/TestCoverage")
|
289
|
+
coveragefiletarget = os.path.join(coverage_file_folder, "TestCoverage.xml")
|
290
|
+
self.__update_path_of_source_in_testcoverage_file(repository_folder, codeunit_name)
|
291
|
+
self.__standardized_tasks_generate_coverage_report(repository_folder, codeunit_name, generate_badges, targetenvironmenttype)
|
292
|
+
self.__check_testcoverage(coveragefiletarget, repository_folder, codeunit_name)
|
293
|
+
self.__format_xml_file(coveragefiletarget)
|
294
|
+
|
295
|
+
@GeneralUtilities.check_arguments
|
296
|
+
def __format_xml_file(self, xmlfile:str) -> None:
|
297
|
+
GeneralUtilities.write_text_to_file(xmlfile,self.__format_xml_content( GeneralUtilities.read_text_from_file(xmlfile)))
|
298
|
+
|
299
|
+
@GeneralUtilities.check_arguments
|
300
|
+
def __format_xml_content(self, xml:str) -> None:
|
301
|
+
root = etree.fromstring(xml)
|
302
|
+
return etree.tostring(root, pretty_print=True, encoding="unicode")
|
303
|
+
|
304
|
+
@GeneralUtilities.check_arguments
|
305
|
+
def __standardized_tasks_generate_coverage_report(self, repository_folder: str, codeunitname: str, generate_badges: bool, targetenvironmenttype: str, add_testcoverage_history_entry: bool = None) -> None:
|
306
|
+
"""This function expects that the file '<repositorybasefolder>/<codeunitname>/Other/Artifacts/TestCoverage/TestCoverage.xml'
|
307
|
+
which contains a test-coverage-report in the cobertura-format exists.
|
308
|
+
This script expectes that the testcoverage-reportfolder is '<repositorybasefolder>/<codeunitname>/Other/Artifacts/TestCoverageReport'.
|
309
|
+
This script expectes that a test-coverage-badges should be added to '<repositorybasefolder>/<codeunitname>/Other/Resources/Badges'."""
|
310
|
+
self._protected_sc.log.log("Generate testcoverage report..")
|
311
|
+
self._protected_sc.assert_is_git_repository(repository_folder)
|
312
|
+
codeunit_version = self.tfcps_Tools_General.get_version_of_codeunit(self.get_codeunit_file())
|
313
|
+
verbosity=0#TODO use loglevel-value here
|
314
|
+
if verbosity == 0:
|
315
|
+
verbose_argument_for_reportgenerator = "Off"
|
316
|
+
elif verbosity == 1:
|
317
|
+
verbose_argument_for_reportgenerator = "Error"
|
318
|
+
elif verbosity == 2:
|
319
|
+
verbose_argument_for_reportgenerator = "Info"
|
320
|
+
elif verbosity == 3:
|
321
|
+
verbose_argument_for_reportgenerator = "Verbose"
|
322
|
+
else:
|
323
|
+
raise ValueError(f"Unknown value for verbosity: {GeneralUtilities.str_none_safe(verbosity)}")
|
324
|
+
|
325
|
+
# Generating report
|
326
|
+
GeneralUtilities.ensure_directory_does_not_exist(os.path.join(repository_folder, codeunitname, f"{codeunitname}/Other/Artifacts/TestCoverageReport"))
|
327
|
+
GeneralUtilities.ensure_directory_exists(os.path.join(repository_folder, codeunitname, "Other/Artifacts/TestCoverageReport"))
|
328
|
+
|
329
|
+
if add_testcoverage_history_entry is None:
|
330
|
+
add_testcoverage_history_entry = self.__is_pre_merge
|
331
|
+
|
332
|
+
history_folder = f"{codeunitname}/Other/Resources/TestCoverageHistory"
|
333
|
+
history_folder_full = os.path.join(repository_folder, history_folder)
|
334
|
+
GeneralUtilities.ensure_directory_exists(history_folder_full)
|
335
|
+
history_argument = f" -historydir:{history_folder}"
|
336
|
+
argument = f"-reports:{codeunitname}/Other/Artifacts/TestCoverage/TestCoverage.xml -targetdir:{codeunitname}/Other/Artifacts/TestCoverageReport --verbosity:{verbose_argument_for_reportgenerator}{history_argument} -title:{codeunitname} -tag:v{codeunit_version}"
|
337
|
+
self._protected_sc.run_program("reportgenerator", argument, repository_folder)
|
338
|
+
if not add_testcoverage_history_entry:
|
339
|
+
os.remove(GeneralUtilities.get_direct_files_of_folder(history_folder_full)[-1])
|
340
|
+
|
341
|
+
# Generating badges
|
342
|
+
if generate_badges:
|
343
|
+
testcoverageubfolger = "Other/Resources/TestCoverageBadges"
|
344
|
+
fulltestcoverageubfolger = os.path.join(repository_folder, codeunitname, testcoverageubfolger)
|
345
|
+
GeneralUtilities.ensure_directory_does_not_exist(fulltestcoverageubfolger)
|
346
|
+
GeneralUtilities.ensure_directory_exists(fulltestcoverageubfolger)
|
347
|
+
self._protected_sc.run_program("reportgenerator", f"-reports:Other/Artifacts/TestCoverage/TestCoverage.xml -targetdir:{testcoverageubfolger} -reporttypes:Badges --verbosity:{verbose_argument_for_reportgenerator}", os.path.join(repository_folder, codeunitname))
|
348
|
+
|
349
|
+
@GeneralUtilities.check_arguments
|
350
|
+
def __update_path_of_source_in_testcoverage_file(self, repository_folder: str, codeunitname: str) -> None:
|
351
|
+
self._protected_sc.assert_is_git_repository(repository_folder)
|
352
|
+
self._protected_sc.log.log("Update paths of source files in testcoverage files..")
|
353
|
+
folder = f"{repository_folder}/{codeunitname}/Other/Artifacts/TestCoverage"
|
354
|
+
filename = "TestCoverage.xml"
|
355
|
+
full_file = os.path.join(folder, filename)
|
356
|
+
GeneralUtilities.write_text_to_file(full_file, re.sub("<source>.+<\\/source>", f"<source><!--[repository]/-->./{codeunitname}/</source>", GeneralUtilities.read_text_from_file(full_file)))
|
357
|
+
self.__remove_not_existing_files_from_testcoverage_file(full_file, repository_folder, codeunitname)
|
358
|
+
|
359
|
+
@GeneralUtilities.check_arguments
|
360
|
+
def __remove_not_existing_files_from_testcoverage_file(self, testcoveragefile: str, repository_folder: str, codeunit_name: str) -> None:
|
361
|
+
self._protected_sc.assert_is_git_repository(repository_folder)
|
362
|
+
root: etree._ElementTree = etree.parse(testcoveragefile)
|
363
|
+
codeunit_folder = os.path.join(repository_folder, codeunit_name)
|
364
|
+
xpath = f"//coverage/packages/package[@name='{codeunit_name}']/classes/class"
|
365
|
+
coverage_report_classes = root.xpath(xpath)
|
366
|
+
found_existing_files = False
|
367
|
+
for coverage_report_class in coverage_report_classes:
|
368
|
+
filename = coverage_report_class.attrib['filename']
|
369
|
+
file = os.path.join(codeunit_folder, filename)
|
370
|
+
if os.path.isfile(file):
|
371
|
+
found_existing_files = True
|
372
|
+
else:
|
373
|
+
coverage_report_class.getparent().remove(coverage_report_class)
|
374
|
+
GeneralUtilities.assert_condition(found_existing_files, f"No existing files in testcoderage-report-file \"{testcoveragefile}\".")
|
375
|
+
result = etree.tostring(root).decode("utf-8")
|
376
|
+
GeneralUtilities.write_text_to_file(testcoveragefile, result)
|
377
|
+
|
378
|
+
@GeneralUtilities.check_arguments
|
379
|
+
def __check_testcoverage(self, testcoverage_file_in_cobertura_format: str, repository_folder: str, codeunitname: str) -> None:
|
380
|
+
self._protected_sc.assert_is_git_repository(repository_folder)
|
381
|
+
self._protected_sc.log.log("Check testcoverage..")
|
382
|
+
root: etree._ElementTree = etree.parse(testcoverage_file_in_cobertura_format)
|
383
|
+
if len(root.xpath('//coverage/packages/package')) != 1:
|
384
|
+
raise ValueError(f"'{testcoverage_file_in_cobertura_format}' must contain exactly 1 package.")
|
385
|
+
if root.xpath('//coverage/packages/package[1]/@name')[0] != codeunitname:
|
386
|
+
raise ValueError(f"The package name of the tested package in '{testcoverage_file_in_cobertura_format}' must be '{codeunitname}'.")
|
387
|
+
rates=root.xpath('//coverage/packages/package[1]/@line-rate')
|
388
|
+
coverage_in_percent = round(float(str(rates[0]))*100, 2)
|
389
|
+
technicalminimalrequiredtestcoverageinpercent = 0
|
390
|
+
if not technicalminimalrequiredtestcoverageinpercent < coverage_in_percent:
|
391
|
+
raise ValueError(f"The test-coverage of package '{codeunitname}' must be greater than {technicalminimalrequiredtestcoverageinpercent}%.")
|
392
|
+
minimalrequiredtestcoverageinpercent = self.get_testcoverage_threshold_from_codeunit_file()
|
393
|
+
if (coverage_in_percent < minimalrequiredtestcoverageinpercent):
|
394
|
+
raise ValueError(f"The testcoverage for codeunit {codeunitname} must be {minimalrequiredtestcoverageinpercent}% or more but is {coverage_in_percent}%.")
|
395
|
+
|
396
|
+
@GeneralUtilities.check_arguments
|
397
|
+
def get_testcoverage_threshold_from_codeunit_file(self):
|
398
|
+
root: etree._ElementTree = etree.parse(self.get_codeunit_file())
|
399
|
+
return float(str(root.xpath('//cps:properties/cps:testsettings/@minimalcodecoverageinpercent', namespaces={'cps': 'https://projects.aniondev.de/PublicProjects/Common/ProjectTemplates/-/tree/main/Conventions/RepositoryStructure/CommonProjectStructure'})[0]))
|
400
|
+
|
401
|
+
|
402
|
+
@GeneralUtilities.check_arguments
|
403
|
+
def install_requirementstxt_for_codeunit(self):
|
404
|
+
self._protected_sc.install_requirementstxt_file(self.get_codeunit_folder()+"/Other/requirements.txt")
|
405
|
+
|
406
|
+
class TFCPS_CodeUnitSpecific_Base_CLI():
|
407
|
+
|
408
|
+
@staticmethod
|
409
|
+
@GeneralUtilities.check_arguments
|
410
|
+
def get_base_parser()->argparse.ArgumentParser:
|
411
|
+
parser = argparse.ArgumentParser()
|
412
|
+
verbosity_values = ", ".join(f"{lvl.value}={lvl.name}" for lvl in LogLevel)
|
413
|
+
parser.add_argument('-e', '--targetenvironmenttype', required=False, default="QualityCheck")
|
414
|
+
parser.add_argument('-a', '--additionalargumentsfile', required=False, default=None)
|
415
|
+
parser.add_argument('-v', '--verbosity', required=False, default=3, help=f"Sets the loglevel. Possible values: {verbosity_values}")
|
416
|
+
parser.add_argument('-c', '--nocache', action='store_true', required=False, default=False)
|
417
|
+
return parser
|
@@ -0,0 +1,120 @@
|
|
1
|
+
import os
|
2
|
+
import re
|
3
|
+
from ..GeneralUtilities import GeneralUtilities
|
4
|
+
from ..ScriptCollectionCore import ScriptCollectionCore
|
5
|
+
from ..SCLog import LogLevel
|
6
|
+
from .TFCPS_Tools_General import TFCPS_Tools_General
|
7
|
+
|
8
|
+
|
9
|
+
class TFCPS_CodeUnit_BuildCodeUnit:
|
10
|
+
|
11
|
+
codeunit_folder: str
|
12
|
+
repository_folder: str
|
13
|
+
sc: ScriptCollectionCore = ScriptCollectionCore()
|
14
|
+
codeunit_name: str
|
15
|
+
tFCPS_Tools: TFCPS_Tools_General
|
16
|
+
target_environment_type: str
|
17
|
+
additionalargumentsfile: str
|
18
|
+
use_cache: bool
|
19
|
+
|
20
|
+
def __init__(self, codeunit_folder: str, verbosity: LogLevel, target_environment_type: str, additionalargumentsfile: str, use_cache: bool):
|
21
|
+
self.sc = ScriptCollectionCore()
|
22
|
+
self.sc.log.loglevel = verbosity
|
23
|
+
self.tFCPS_Tools = TFCPS_Tools_General(self.sc)
|
24
|
+
self.tFCPS_Tools.assert_is_codeunit_folder(codeunit_folder)
|
25
|
+
self.codeunit_folder = codeunit_folder
|
26
|
+
self.codeunit_name = os.path.basename(self.codeunit_folder)
|
27
|
+
self.target_environment_type = target_environment_type
|
28
|
+
self.additionalargumentsfile = additionalargumentsfile
|
29
|
+
self.use_cache = use_cache
|
30
|
+
|
31
|
+
@GeneralUtilities.check_arguments
|
32
|
+
def build_codeunit(self) -> None:
|
33
|
+
codeunit_file: str = str(os.path.join(self.codeunit_folder, f"{self.codeunit_name}.codeunit.xml"))
|
34
|
+
|
35
|
+
if not self.tFCPS_Tools.codeunit_is_enabled(codeunit_file):
|
36
|
+
self.sc.log.log(f"Codeunit {self.codeunit_name} is disabled.", LogLevel.Warning)
|
37
|
+
return
|
38
|
+
|
39
|
+
self.sc.log.log(f"Build codeunit {self.codeunit_name}...")
|
40
|
+
|
41
|
+
GeneralUtilities.ensure_folder_exists_and_is_empty(self.codeunit_folder+"/Other/Artifacts")
|
42
|
+
|
43
|
+
arguments: str = f"--targetenvironmenttype {self.target_environment_type} --additionalargumentsfile {self.additionalargumentsfile} --verbosity {int(self.sc.log.loglevel)}"
|
44
|
+
if not self.use_cache:
|
45
|
+
arguments = f"{arguments} --nocache"
|
46
|
+
|
47
|
+
self.sc.log.log("Do common tasks...")
|
48
|
+
self.sc.run_program("python", f"CommonTasks.py {arguments}", os.path.join(self.codeunit_folder, "Other"), print_live_output=True)
|
49
|
+
self.verify_artifact_exists(self.codeunit_folder, dict[str, bool]({"Changelog": False, "License": True, "DiffReport": True}))
|
50
|
+
|
51
|
+
self.sc.log.log("Build...")
|
52
|
+
self.sc.run_program("python", f"Build.py {arguments}", os.path.join(self.codeunit_folder, "Other", "Build"), print_live_output=True)
|
53
|
+
artifacts = {"BuildResult_.+": True, "BOM": False, "SourceCode": self.tFCPS_Tools.codeunit_has_testable_sourcecode(codeunit_file)}
|
54
|
+
self.verify_artifact_exists(self.codeunit_folder, dict[str, bool](artifacts))
|
55
|
+
|
56
|
+
if self.tFCPS_Tools.codeunit_has_testable_sourcecode(codeunit_file):
|
57
|
+
self.sc.log.log("Run testcases...")
|
58
|
+
self.sc.run_program("python", f"RunTestcases.py {arguments}", os.path.join(self.codeunit_folder, "Other", "QualityCheck"), print_live_output=True)
|
59
|
+
self.verify_artifact_exists(self.codeunit_folder, dict[str, bool]({"TestCoverage": True, "TestCoverageReport": False}))
|
60
|
+
|
61
|
+
self.sc.log.log("Check for linting-issues...")
|
62
|
+
linting_result = self.sc.run_program("python", f"Linting.py {arguments}", os.path.join(self.codeunit_folder, "Other", "QualityCheck"), print_live_output=True, throw_exception_if_exitcode_is_not_zero=False)
|
63
|
+
if linting_result[0] != 0:
|
64
|
+
self.sc.log.log("Linting-issues were found.", LogLevel.Warning)
|
65
|
+
|
66
|
+
self.sc.log.log("Generate reference...")
|
67
|
+
self.sc.run_program("python", "GenerateReference.py", os.path.join(self.codeunit_folder, "Other", "Reference"), print_live_output=True)
|
68
|
+
self.verify_artifact_exists(self.codeunit_folder, dict[str, bool]({"Reference": True}))
|
69
|
+
|
70
|
+
if os.path.isfile(os.path.join(self.codeunit_folder, "Other", "OnBuildingFinished.py")):
|
71
|
+
self.sc.log.log('Run "OnBuildingFinished.py"...')
|
72
|
+
self.sc.run_program("python", f"OnBuildingFinished.py {arguments}", os.path.join(self.codeunit_folder, "Other"), print_live_output=True)
|
73
|
+
|
74
|
+
artifacts_folder = os.path.join(self.codeunit_folder, "Other", "Artifacts")
|
75
|
+
artifactsinformation_file = os.path.join(artifacts_folder, f"{self.codeunit_name}.artifactsinformation.xml")
|
76
|
+
codeunit_version = self.tFCPS_Tools.get_version_of_codeunit(codeunit_file)
|
77
|
+
GeneralUtilities.ensure_file_exists(artifactsinformation_file)
|
78
|
+
artifacts_list = []
|
79
|
+
for artifact_folder in GeneralUtilities.get_direct_folders_of_folder(artifacts_folder):
|
80
|
+
artifact_name = os.path.basename(artifact_folder)
|
81
|
+
artifacts_list.append(f" <cps:artifact>{artifact_name}<cps:artifact>")
|
82
|
+
artifacts = '\n'.join(artifacts_list)
|
83
|
+
moment = GeneralUtilities.datetime_to_string(GeneralUtilities.get_now())
|
84
|
+
# TODO implement usage of reference_latest_version_of_xsd_when_generating_xml
|
85
|
+
GeneralUtilities.write_text_to_file(artifactsinformation_file, f"""<?xml version="1.0" encoding="UTF-8" ?>
|
86
|
+
<cps:artifactsinformation xmlns:cps="https://projects.aniondev.de/PublicProjects/Common/ProjectTemplates/-/tree/main/Conventions/RepositoryStructure/CommonProjectStructure" artifactsinformationspecificationversion="1.0.0"
|
87
|
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://raw.githubusercontent.com/anionDev/ProjectTemplates/main/Templates/Conventions/RepositoryStructure/CommonProjectStructure/artifactsinformation.xsd">
|
88
|
+
<cps:name>{self.codeunit_name}</cps:name>
|
89
|
+
<cps:version>{codeunit_version}</cps:version>
|
90
|
+
<cps:timestamp>{moment}</cps:timestamp>
|
91
|
+
<cps:targetenvironmenttype>{self.target_environment_type}</cps:targetenvironmenttype>
|
92
|
+
<cps:artifacts>
|
93
|
+
{artifacts}
|
94
|
+
</cps:artifacts>
|
95
|
+
</cps:artifactsinformation>""")
|
96
|
+
# TODO validate artifactsinformation_file against xsd
|
97
|
+
self.sc.log.log(f"Finished building codeunit {self.codeunit_name} without errors.")
|
98
|
+
|
99
|
+
@GeneralUtilities.check_arguments
|
100
|
+
def verify_artifact_exists(self, codeunit_folder: str, artifact_name_regexes: dict[str, bool]) -> None:
|
101
|
+
codeunit_name: str = os.path.basename(codeunit_folder)
|
102
|
+
artifacts_folder = os.path.join(codeunit_folder, "Other/Artifacts")
|
103
|
+
existing_artifacts = [os.path.basename(x) for x in GeneralUtilities.get_direct_folders_of_folder(artifacts_folder)]
|
104
|
+
for artifact_name_regex, required in artifact_name_regexes.items():
|
105
|
+
artifact_exists = False
|
106
|
+
for existing_artifact in existing_artifacts:
|
107
|
+
pattern = re.compile(artifact_name_regex)
|
108
|
+
if pattern.match(existing_artifact):
|
109
|
+
artifact_exists = True
|
110
|
+
if not artifact_exists:
|
111
|
+
message = f"Codeunit {codeunit_name} does not contain an artifact which matches the name '{artifact_name_regex}'."
|
112
|
+
if required:
|
113
|
+
raise ValueError(message)
|
114
|
+
else:
|
115
|
+
self.sc.log.log(message, LogLevel.Warning)
|
116
|
+
|
117
|
+
@GeneralUtilities.check_arguments
|
118
|
+
def update_dependencies(self) -> None:
|
119
|
+
self.sc.log.log("Update dependencies...")
|
120
|
+
self.sc.run_program("python", "UpdateDependencies.py", os.path.join(self.codeunit_folder, "Other"))
|
@@ -0,0 +1,80 @@
|
|
1
|
+
import os
|
2
|
+
from ..GeneralUtilities import GeneralUtilities
|
3
|
+
from ..ScriptCollectionCore import ScriptCollectionCore
|
4
|
+
from ..SCLog import LogLevel
|
5
|
+
from .TFCPS_CodeUnit_BuildCodeUnit import TFCPS_CodeUnit_BuildCodeUnit
|
6
|
+
from .TFCPS_Tools_General import TFCPS_Tools_General
|
7
|
+
|
8
|
+
class TFCPS_CodeUnit_BuildCodeUnits:
|
9
|
+
repository:str=None
|
10
|
+
tFCPS_Other:TFCPS_Tools_General=None
|
11
|
+
sc:ScriptCollectionCore=None
|
12
|
+
target_environment_type:str=None
|
13
|
+
additionalargumentsfile:str=None
|
14
|
+
__use_cache:bool
|
15
|
+
__is_pre_merge:bool
|
16
|
+
|
17
|
+
def __init__(self,repository:str,loglevel:LogLevel,target_environment_type:str,additionalargumentsfile:str,use_cache:bool,is_pre_merge:bool):
|
18
|
+
self.sc=ScriptCollectionCore()
|
19
|
+
self.sc.log.loglevel=loglevel
|
20
|
+
self.__use_cache=use_cache
|
21
|
+
self.sc.assert_is_git_repository(repository)
|
22
|
+
self.repository=repository
|
23
|
+
self.tFCPS_Other:TFCPS_Tools_General=TFCPS_Tools_General(self.sc)
|
24
|
+
allowed_target_environment_types=["Development","QualityCheck","Productive"]
|
25
|
+
GeneralUtilities.assert_condition(target_environment_type in allowed_target_environment_types,"Unknown target-environment-type. Allowed values are: "+", ".join(allowed_target_environment_types))
|
26
|
+
self.target_environment_type=target_environment_type
|
27
|
+
self.additionalargumentsfile=additionalargumentsfile
|
28
|
+
self.__is_pre_merge=is_pre_merge
|
29
|
+
|
30
|
+
@GeneralUtilities.check_arguments
|
31
|
+
def build_codeunits(self) -> None:
|
32
|
+
self.sc.log.log(GeneralUtilities.get_line())
|
33
|
+
self.sc.log.log(f"Start building codeunits. (Target environment-type: {self.target_environment_type})")
|
34
|
+
changelog_file=os.path.join(self.repository,"Other","Resources","Changelog",f"v{self.tFCPS_Other.get_version_of_project(self.repository)}.md")
|
35
|
+
GeneralUtilities.assert_file_exists(changelog_file,f"Changelogfile \"{changelog_file}\" does not exist. Try to create it for example using \"sccreatechangelogentry -m ...\".")
|
36
|
+
if os.path.isfile( os.path.join(self.repository,"Other","Scripts","PrepareBuildCodeunits.py")):
|
37
|
+
arguments:str=f"--targetenvironmenttype {self.target_environment_type} --additionalargumentsfile {self.additionalargumentsfile} --verbosity {int(self.sc.log.loglevel)}"
|
38
|
+
if not self.__use_cache:
|
39
|
+
arguments=f"{arguments} --nocache"
|
40
|
+
if self.sc.git_repository_has_uncommitted_changes(self.repository):
|
41
|
+
self.sc.log.log("No-cache-option can not be applied because there are uncommited changes in the repository.",LogLevel.Warning)
|
42
|
+
else:
|
43
|
+
self.sc.run_program("git","clean -dfx",self.repository)
|
44
|
+
self.sc.log.log("Prepare build codeunits...")
|
45
|
+
self.sc.run_program("python", f"PrepareBuildCodeunits.py {arguments}", os.path.join(self.repository,"Other","Scripts"),print_live_output=True)
|
46
|
+
codeunits:list[str]=self.tFCPS_Other.get_codeunits(self.repository)
|
47
|
+
self.sc.log.log("Codeunits will be built in the following order:")
|
48
|
+
for codeunit_name in codeunits:
|
49
|
+
self.sc.log.log(" - "+codeunit_name)
|
50
|
+
for codeunit_name in codeunits:
|
51
|
+
tFCPS_CodeUnit_BuildCodeUnit:TFCPS_CodeUnit_BuildCodeUnit = TFCPS_CodeUnit_BuildCodeUnit(os.path.join(self.repository,codeunit_name),self.sc.log.loglevel,self.target_environment_type,self.additionalargumentsfile,self.use_cache())
|
52
|
+
self.sc.log.log(GeneralUtilities.get_line())
|
53
|
+
tFCPS_CodeUnit_BuildCodeUnit.build_codeunit()
|
54
|
+
self.sc.log.log(GeneralUtilities.get_line())
|
55
|
+
self.sc.log.log("Finished building codeunits.")
|
56
|
+
self.sc.log.log(GeneralUtilities.get_line())
|
57
|
+
|
58
|
+
|
59
|
+
@GeneralUtilities.check_arguments
|
60
|
+
def use_cache(self) -> bool:
|
61
|
+
return self.__use_cache
|
62
|
+
|
63
|
+
|
64
|
+
@GeneralUtilities.check_arguments
|
65
|
+
def is_pre_merge(self) -> bool:
|
66
|
+
return self.__is_pre_merge
|
67
|
+
|
68
|
+
@GeneralUtilities.check_arguments
|
69
|
+
def update_dependencies(self) -> None:
|
70
|
+
self.update_year_in_license_file()
|
71
|
+
|
72
|
+
#TODO update project-wide-dependencies here
|
73
|
+
codeunits:list[str]=self.tFCPS_Other.get_codeunits(self.repository)
|
74
|
+
for codeunit_name in codeunits:
|
75
|
+
tFCPS_CodeUnit_BuildCodeUnit:TFCPS_CodeUnit_BuildCodeUnit = TFCPS_CodeUnit_BuildCodeUnit(os.path.join(self.repository,codeunit_name),self.sc.log.loglevel,self.target_environment_type,self.additionalargumentsfile,self.use_cache())
|
76
|
+
tFCPS_CodeUnit_BuildCodeUnit.update_dependencies()
|
77
|
+
|
78
|
+
@GeneralUtilities.check_arguments
|
79
|
+
def update_year_in_license_file(self) -> None:
|
80
|
+
self.sc.update_year_in_first_line_of_file(os.path.join(self.repository, "License.txt"))
|