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
@@ -1,1170 +0,0 @@
1
- from datetime import datetime
2
- import os
3
- from pathlib import Path
4
- import shutil
5
- import re
6
- import tempfile
7
- import json
8
- import configparser
9
- import xmlschema
10
- from lxml import etree
11
- from .GeneralUtilities import GeneralUtilities
12
- from .ScriptCollectionCore import ScriptCollectionCore
13
- from .ProgramRunnerEpew import ProgramRunnerEpew
14
-
15
-
16
- class CodeUnitConfiguration():
17
- name: str
18
- push_to_registry_script: str
19
- additional_arguments_file: str
20
-
21
- def __init__(self, name: str, push_to_registry_script: str, additional_arguments_file: str):
22
-
23
- self.name = name
24
- self.push_to_registry_script = push_to_registry_script
25
- self.additional_arguments_file = additional_arguments_file
26
-
27
-
28
- class CreateReleaseConfiguration():
29
- projectname: str
30
- remotename: str
31
- artifacts_folder: str
32
- codeunits: dict[str, CodeUnitConfiguration]
33
- verbosity: int
34
- reference_repository_remote_name: str = None
35
- reference_repository_branch_name: str = "main"
36
- build_repository_branch: str = "main"
37
- public_repository_url: str
38
-
39
- def __init__(self, projectname: str, remotename: str, build_artifacts_target_folder: str, codeunits: dict[str, CodeUnitConfiguration],
40
- verbosity: int, public_repository_url: str):
41
-
42
- self.projectname = projectname
43
- self.remotename = remotename
44
- self.artifacts_folder = build_artifacts_target_folder
45
- self.codeunits = codeunits
46
- self.verbosity = verbosity
47
- self.public_repository_url = public_repository_url
48
- self.reference_repository_remote_name = self.remotename
49
-
50
-
51
- class CreateReleaseInformationForProjectInCommonProjectFormat:
52
- projectname: str
53
- repository: str
54
- artifacts_folder: str
55
- verbosity: int = 1
56
- reference_repository: str = None
57
- public_repository_url: str = None
58
- target_branch_name: str = None
59
- codeunits: dict[str, CodeUnitConfiguration]
60
- target_environmenttype_for_qualitycheck: str = "QualityCheck"
61
- target_environmenttype_for_productive: str = "Productive"
62
-
63
- def __init__(self, repository: str, artifacts_folder: str, projectname: str, public_repository_url: str, target_branch_name: str):
64
- self.repository = repository
65
- self.public_repository_url = public_repository_url
66
- self.target_branch_name = target_branch_name
67
- self.artifacts_folder = artifacts_folder
68
- if projectname is None:
69
- projectname = os.path.basename(self.repository)
70
- else:
71
- self.projectname = projectname
72
- self.reference_repository = GeneralUtilities.resolve_relative_path(f"../{projectname}Reference", repository)
73
-
74
-
75
- class MergeToStableBranchInformationForProjectInCommonProjectFormat:
76
- repository: str
77
- sourcebranch: str = "main"
78
- targetbranch: str = "stable"
79
- sign_git_tags: bool = True
80
- codeunits: dict[str, CodeUnitConfiguration]
81
- target_environmenttype_for_qualitycheck: str = "QualityCheck"
82
- target_environmenttype_for_productive: str = "Productive"
83
-
84
- push_source_branch: bool = False
85
- push_source_branch_remote_name: str = None
86
- push_target_branch: bool = False
87
- push_target_branch_remote_name: str = None
88
-
89
- verbosity: int = 1
90
-
91
- def __init__(self, repository: str):
92
- self.repository = repository
93
-
94
-
95
- class TasksForCommonProjectStructure:
96
- __sc: ScriptCollectionCore = None
97
- reference_latest_version_of_xsd_when_generating_xml: bool = True
98
-
99
- def __init__(self, sc: ScriptCollectionCore = None):
100
- if sc is None:
101
- sc = ScriptCollectionCore()
102
- self.__sc = sc
103
-
104
- @GeneralUtilities.check_arguments
105
- def get_build_folder_in_repository_in_common_repository_format(self, repository_folder: str, codeunit_name: str) -> str:
106
- return os.path.join(repository_folder, codeunit_name, "Other", "Build")
107
-
108
- @GeneralUtilities.check_arguments
109
- def get_artifacts_folder_in_repository_in_common_repository_format(self, repository_folder: str, codeunit_name: str) -> str:
110
- return os.path.join(repository_folder, codeunit_name, "Other", "Artifacts")
111
-
112
- @GeneralUtilities.check_arguments
113
- def get_wheel_file_in_repository_in_common_repository_format(self, repository_folder: str, codeunit_name: str) -> str:
114
- return self.__sc.find_file_by_extension(os.path.join(self.get_artifacts_folder_in_repository_in_common_repository_format(repository_folder, codeunit_name),
115
- "BuildResult_Wheel"), "whl")
116
-
117
- @GeneralUtilities.check_arguments
118
- def __get_testcoverage_threshold_from_codeunit_file(self, codeunit_file):
119
- root: etree._ElementTree = etree.parse(codeunit_file)
120
- return float(str(root.xpath('//cps:minimalcodecoverageinpercent/text()', namespaces={
121
- 'cps': 'https://projects.aniondev.de/PublicProjects/Common/ProjectTemplates/-/tree/main/Conventions/RepositoryStructure/CommonProjectStructure'
122
- })[0]))
123
-
124
- @GeneralUtilities.check_arguments
125
- def check_testcoverage_for_project_in_common_project_structure(self, testcoverage_file_in_cobertura_format: str, repository_folder: str, codeunitname: str):
126
- root: etree._ElementTree = etree.parse(testcoverage_file_in_cobertura_format)
127
- coverage_in_percent = round(float(str(root.xpath('//coverage/@line-rate')[0]))*100, 2)
128
- codeunit_file = os.path.join(repository_folder, codeunitname, f"{codeunitname}.codeunit.xml")
129
- threshold_in_percent = self.__get_testcoverage_threshold_from_codeunit_file(codeunit_file)
130
- minimalrequiredtestcoverageinpercent = threshold_in_percent
131
- if (coverage_in_percent < minimalrequiredtestcoverageinpercent):
132
- raise ValueError(f"The testcoverage must be {minimalrequiredtestcoverageinpercent}% or more but is {coverage_in_percent}%.")
133
-
134
- @GeneralUtilities.check_arguments
135
- def replace_version_in_python_file(self, file: str, new_version_value: str):
136
- GeneralUtilities.write_text_to_file(file, re.sub("version = \"\\d+\\.\\d+\\.\\d+\"", f"version = \"{new_version_value}\"",
137
- GeneralUtilities.read_text_from_file(file)))
138
-
139
- @GeneralUtilities.check_arguments
140
- def __standardized_tasks_run_testcases_for_python_codeunit(self, repository_folder: str, codeunitname: str, verbosity: int):
141
- codeunit_folder = os.path.join(repository_folder, codeunitname)
142
- self.__sc.run_program("coverage", "run -m pytest", codeunit_folder, verbosity=verbosity)
143
- self.__sc.run_program("coverage", "xml", codeunit_folder, verbosity=verbosity)
144
- coveragefolder = os.path.join(repository_folder, codeunitname, "Other/Artifacts/TestCoverage")
145
- GeneralUtilities.ensure_directory_exists(coveragefolder)
146
- coveragefile = os.path.join(coveragefolder, "TestCoverage.xml")
147
- GeneralUtilities.ensure_file_does_not_exist(coveragefile)
148
- os.rename(os.path.join(repository_folder, codeunitname, "coverage.xml"), coveragefile)
149
- self.check_testcoverage_for_project_in_common_project_structure(coveragefile, repository_folder, codeunitname)
150
-
151
- @staticmethod
152
- @GeneralUtilities.check_arguments
153
- def __adjust_source_in_testcoverage_file(testcoverage_file: str, codeunitname: str) -> None:
154
- GeneralUtilities.write_text_to_file(testcoverage_file, re.sub("<source>.+<\\/source>", f"<source>{codeunitname}</source>",
155
- GeneralUtilities.read_text_from_file(testcoverage_file)))
156
-
157
- @staticmethod
158
- @GeneralUtilities.check_arguments
159
- def update_path_of_source(repository_folder: str, codeunitname: str) -> None:
160
- folder = f"{repository_folder}/{codeunitname}/Other/Artifacts/TestCoverage"
161
- filename = "TestCoverage.xml"
162
- full_file = os.path.join(folder, filename)
163
- TasksForCommonProjectStructure.__adjust_source_in_testcoverage_file(full_file, codeunitname)
164
-
165
- @GeneralUtilities.check_arguments
166
- def standardized_tasks_run_testcases_for_python_codeunit_in_common_project_structure(self, run_testcases_file: str, generate_badges: bool, verbosity: int, targetenvironmenttype: str,
167
- commandline_arguments: list[str]):
168
- codeunitname: str = Path(os.path.dirname(run_testcases_file)).parent.parent.name
169
- verbosity = TasksForCommonProjectStructure.get_verbosity_from_commandline_arguments(commandline_arguments, verbosity)
170
- repository_folder: str = str(Path(os.path.dirname(run_testcases_file)).parent.parent.parent.absolute())
171
- self.__standardized_tasks_run_testcases_for_python_codeunit(repository_folder, codeunitname, verbosity)
172
- self.standardized_tasks_generate_coverage_report(repository_folder, codeunitname, verbosity, generate_badges, targetenvironmenttype, commandline_arguments)
173
- self.update_path_of_source(repository_folder, codeunitname)
174
-
175
- @GeneralUtilities.check_arguments
176
- def standardized_tasks_build_for_python_codeunit_in_common_project_structure(self, buildscript_file: str, verbosity: int, targetenvironmenttype: str, commandline_arguments: list[str]):
177
- codeunitname: str = Path(os.path.dirname(buildscript_file)).parent.parent.name
178
- verbosity = TasksForCommonProjectStructure.get_verbosity_from_commandline_arguments(commandline_arguments, verbosity)
179
- codeunit_folder = str(Path(os.path.dirname(buildscript_file)).parent.parent.absolute())
180
- repository_folder: str = str(Path(os.path.dirname(buildscript_file)).parent.parent.parent.absolute())
181
- target_directory = GeneralUtilities.resolve_relative_path(
182
- "../Artifacts/BuildResult_Wheel", os.path.join(self.get_artifacts_folder_in_repository_in_common_repository_format(repository_folder, codeunitname)))
183
- GeneralUtilities.ensure_directory_exists(target_directory)
184
- self.__sc.run_program("python", f"-m build --wheel --outdir {target_directory}", codeunit_folder, verbosity=verbosity)
185
-
186
- @GeneralUtilities.check_arguments
187
- def standardized_tasks_push_wheel_file_to_registry(self, wheel_file: str, api_key: str, repository: str, gpg_identity: str, verbosity: int) -> None:
188
- # repository-value when PyPi should be used: "pypi"
189
- # gpg_identity-value when wheel-file should not be signed: None
190
- folder = os.path.dirname(wheel_file)
191
- filename = os.path.basename(wheel_file)
192
-
193
- if gpg_identity is None:
194
- gpg_identity_argument = ""
195
- else:
196
- gpg_identity_argument = f" --sign --identity {gpg_identity}"
197
-
198
- if verbosity > 2:
199
- verbose_argument = " --verbose"
200
- else:
201
- verbose_argument = ""
202
-
203
- twine_argument = f"upload{gpg_identity_argument} --repository {repository} --non-interactive {filename} --disable-progress-bar"
204
- twine_argument = f"{twine_argument} --username __token__ --password {api_key}{verbose_argument}"
205
- self.__sc.run_program("twine", twine_argument, folder, verbosity=verbosity, throw_exception_if_exitcode_is_not_zero=True)
206
-
207
- @GeneralUtilities.check_arguments
208
- def push_wheel_build_artifact_of_repository_in_common_file_structure(self, push_build_artifacts_file, product_name, codeunitname, repository: str,
209
- apikey: str, gpg_identity: str, verbosity: int, commandline_arguments: list[str]) -> None:
210
- verbosity = TasksForCommonProjectStructure.get_verbosity_from_commandline_arguments(commandline_arguments, verbosity)
211
- folder_of_this_file = os.path.dirname(push_build_artifacts_file)
212
- repository_folder = GeneralUtilities.resolve_relative_path(f"..{os.path.sep}../Submodules{os.path.sep}{product_name}", folder_of_this_file)
213
- wheel_file = self.get_wheel_file_in_repository_in_common_repository_format(repository_folder, codeunitname)
214
- self.standardized_tasks_push_wheel_file_to_registry(wheel_file, apikey, repository, gpg_identity, verbosity)
215
-
216
- @GeneralUtilities.check_arguments
217
- def get_version_of_codeunit(self, codeunit_file: str) -> None:
218
- root: etree._ElementTree = etree.parse(codeunit_file)
219
- result = str(root.xpath('//cps:version/text()',
220
- namespaces={'cps': 'https://projects.aniondev.de/PublicProjects/Common/ProjectTemplates/-/tree/main/Conventions/RepositoryStructure/CommonProjectStructure'})[0])
221
- return result
222
-
223
- @GeneralUtilities.check_arguments
224
- def get_version_of_codeunit_folder(self, codeunit_folder: str) -> None:
225
- codeunit_file = os.path.join(codeunit_folder, f"{os.path.basename(codeunit_folder)}.codeunit.xml")
226
- return self.get_version_of_codeunit(codeunit_file)
227
-
228
- @staticmethod
229
- @GeneralUtilities.check_arguments
230
- def get_buildconfigurationdevelopment_from_commandline_arguments(commandline_arguments: list[str], default_value: str) -> str:
231
- return TasksForCommonProjectStructure.get_string_value_from_commandline_arguments(commandline_arguments, "buildconfigurationdevelopment", default_value)
232
-
233
- @staticmethod
234
- @GeneralUtilities.check_arguments
235
- def get_buildconfigurationqualitycheck_from_commandline_arguments(commandline_arguments: list[str], default_value: str) -> str:
236
- return TasksForCommonProjectStructure.get_string_value_from_commandline_arguments(commandline_arguments, "buildconfigurationqualitycheck", default_value)
237
-
238
- @staticmethod
239
- @GeneralUtilities.check_arguments
240
- def get_buildconfigurationproductive_from_commandline_arguments(commandline_arguments: list[str], default_value: str) -> str:
241
- return TasksForCommonProjectStructure.get_string_value_from_commandline_arguments(commandline_arguments, "buildconfigurationproductive", default_value)
242
-
243
- @staticmethod
244
- @GeneralUtilities.check_arguments
245
- def get_string_value_from_commandline_arguments(commandline_arguments: list[str], property_name: str, default_value: str) -> str:
246
- result = TasksForCommonProjectStructure.get_property_from_commandline_arguments(commandline_arguments, property_name)
247
- if result is None:
248
- return default_value
249
- else:
250
- return result
251
-
252
- @staticmethod
253
- @GeneralUtilities.check_arguments
254
- def get_verbosity_from_commandline_arguments(commandline_arguments: list[str], default_value: int) -> int:
255
- result = TasksForCommonProjectStructure.get_property_from_commandline_arguments(commandline_arguments, "verbosity")
256
- if result is None:
257
- return default_value
258
- else:
259
- return int(result)
260
-
261
- @staticmethod
262
- @GeneralUtilities.check_arguments
263
- def get_targetenvironmenttype_from_commandline_arguments(commandline_arguments: list[str], default_value: str) -> str:
264
- result = TasksForCommonProjectStructure.get_property_from_commandline_arguments(commandline_arguments, "targetenvironmenttype")
265
- if result is None:
266
- return default_value
267
- else:
268
- return result
269
-
270
- @staticmethod
271
- @GeneralUtilities.check_arguments
272
- def get_additionalargumentsfile_from_commandline_arguments(commandline_arguments: list[str], default_value: str) -> str:
273
- result = TasksForCommonProjectStructure.get_property_from_commandline_arguments(commandline_arguments, "additionalargumentsfile")
274
- if result is None:
275
- return default_value
276
- else:
277
- return result
278
-
279
- @staticmethod
280
- @GeneralUtilities.check_arguments
281
- def get_filestosign_from_commandline_arguments(commandline_arguments: list[str], default_value: dict[str, str]) -> dict[str, str]():
282
- result_plain = TasksForCommonProjectStructure.get_property_from_commandline_arguments(commandline_arguments, "sign")
283
- if result_plain is None:
284
- return default_value
285
- else:
286
- result: dict[str, str] = dict[str, str]()
287
- files_tuples = GeneralUtilities.to_list(result_plain, ";")
288
- for files_tuple in files_tuples:
289
- splitted = files_tuple.split("=")
290
- result[splitted[0]] = splitted[1]
291
- return result
292
-
293
- @staticmethod
294
- @GeneralUtilities.check_arguments
295
- def get_property_from_commandline_arguments(commandline_arguments: list[str], property_name: str) -> str:
296
- result: str = None
297
- for commandline_argument in commandline_arguments[1:]:
298
- prefix = f"--overwrite_{property_name}"
299
- if commandline_argument.startswith(prefix):
300
- if m := re.match(f"^{re.escape(prefix)}=(.+)$", commandline_argument):
301
- result = m.group(1)
302
- return result
303
-
304
- @GeneralUtilities.check_arguments
305
- def update_version_of_codeunit_to_project_version(self, common_tasks_file: str, current_version: str) -> None:
306
- codeunit_name: str = os.path.basename(GeneralUtilities.resolve_relative_path("..", os.path.dirname(common_tasks_file)))
307
- codeunit_file: str = os.path.join(GeneralUtilities.resolve_relative_path("..", os.path.dirname(common_tasks_file)), f"{codeunit_name}.codeunit.xml")
308
- self.write_version_to_codeunit_file(codeunit_file, current_version)
309
-
310
- @GeneralUtilities.check_arguments
311
- def t4_transform(self, commontasks_script_file_of_current_file: str, verbosity: int):
312
- sc = ScriptCollectionCore()
313
- codeunit_folder: str = str(Path(os.path.dirname(commontasks_script_file_of_current_file)).parent.absolute())
314
- codeunitname: str = os.path.basename(str(Path(os.path.dirname(commontasks_script_file_of_current_file)).parent.absolute()))
315
- csproj_folder = os.path.join(codeunit_folder, codeunitname)
316
- for search_result in Path(csproj_folder).glob('**/*.tt'):
317
- tt_file = str(search_result)
318
- relative_path_to_tt_file = str(Path(tt_file).relative_to(Path(csproj_folder)))
319
- sc.run_program("texttransform", relative_path_to_tt_file, csproj_folder, verbosity=verbosity)
320
-
321
- @GeneralUtilities.check_arguments
322
- def standardized_tasks_generate_reference_by_docfx(self, generate_reference_script_file: str, verbosity: int, targetenvironmenttype: str, commandline_arguments: list[str]) -> None:
323
- verbosity = TasksForCommonProjectStructure.get_verbosity_from_commandline_arguments(commandline_arguments, verbosity)
324
- folder_of_current_file = os.path.dirname(generate_reference_script_file)
325
- generated_reference_folder = GeneralUtilities.resolve_relative_path("../Artifacts/Reference", folder_of_current_file)
326
- GeneralUtilities.ensure_directory_does_not_exist(generated_reference_folder)
327
- GeneralUtilities.ensure_directory_exists(generated_reference_folder)
328
- obj_folder = os.path.join(folder_of_current_file, "obj")
329
- GeneralUtilities.ensure_directory_does_not_exist(obj_folder)
330
- GeneralUtilities.ensure_directory_exists(obj_folder)
331
- self.__sc.run_program("docfx", "docfx.json", folder_of_current_file, verbosity)
332
- GeneralUtilities.ensure_directory_does_not_exist(obj_folder)
333
-
334
- @GeneralUtilities.check_arguments
335
- def __standardized_tasks_build_for_dotnet_build(self, csproj_file: str, buildconfiguration: str, originaloutputfolder: str, files_to_sign: dict[str, str], commitid: str,
336
- verbosity: int, runtimes: list[str]):
337
- for runtime in runtimes:
338
- outputfolder = originaloutputfolder+runtime
339
- csproj_file_folder = os.path.dirname(csproj_file)
340
- csproj_file_name = os.path.basename(csproj_file)
341
- self.__sc.run_program("dotnet", "clean", csproj_file_folder, verbosity=verbosity)
342
- GeneralUtilities.ensure_directory_does_not_exist(os.path.join(csproj_file_folder, "bin"))
343
- GeneralUtilities.ensure_directory_does_not_exist(os.path.join(csproj_file_folder, "obj"))
344
- GeneralUtilities.ensure_directory_does_not_exist(outputfolder)
345
- GeneralUtilities.ensure_directory_exists(outputfolder)
346
- # TODO pass commitid, timestamp and if desired something like keypair, certificate to the src-code
347
- self.__sc.run_program("dotnet", f"build {csproj_file_name} -c {buildconfiguration} -o {outputfolder} --runtime {runtime}", csproj_file_folder, verbosity=verbosity)
348
- for file, keyfile in files_to_sign.items():
349
- self.__sc.dotnet_sign_file(os.path.join(outputfolder, file), keyfile, verbosity)
350
-
351
- @GeneralUtilities.check_arguments
352
- def standardized_tasks_build_for_dotnet_project_in_common_project_structure(self, buildscript_file: str, default_target_environmenttype: str,
353
- target_environmenttype_mapping: dict[str, str], runtimes: list[str], verbosity: int, commandline_arguments: list[str]):
354
- # hint: arguments can be overwritten by commandline_arguments
355
- # this function builds an exe or dll
356
- target_environmenttype = self.get_targetenvironmenttype_from_commandline_arguments(commandline_arguments, default_target_environmenttype)
357
- self.__standardized_tasks_build_for_dotnet_project_in_common_project_structure(
358
- buildscript_file, target_environmenttype_mapping, default_target_environmenttype, verbosity, target_environmenttype, runtimes, commandline_arguments)
359
-
360
- @GeneralUtilities.check_arguments
361
- def standardized_tasks_build_for_dotnet_library_project_in_common_project_structure(self, buildscript_file: str, default_target_environmenttype: str,
362
- target_environmenttype_mapping: dict[str, str], runtimes: list[str],
363
- verbosity: int, commandline_arguments: list[str]):
364
- # hint: arguments can be overwritten by commandline_arguments
365
- # this function builds an exe or dll and converts it to a nupkg-file
366
- target_environmenttype = self.get_targetenvironmenttype_from_commandline_arguments(commandline_arguments, default_target_environmenttype)
367
- self.__standardized_tasks_build_for_dotnet_project_in_common_project_structure(
368
- buildscript_file, target_environmenttype_mapping, default_target_environmenttype, verbosity, target_environmenttype, runtimes, commandline_arguments)
369
- self.__standardized_tasks_build_nupkg_for_dotnet_create_package(buildscript_file, verbosity, commandline_arguments)
370
-
371
- @GeneralUtilities.check_arguments
372
- def __get_dotnet_buildconfiguration_by_target_environmenttype(self, targetenvironmenttype: str, default_value: str, commandline_arguments: list[str]):
373
- if targetenvironmenttype == "Development":
374
- return self.get_buildconfigurationdevelopment_from_commandline_arguments(commandline_arguments, default_value)
375
- if targetenvironmenttype == "QualityCheck":
376
- return self.get_buildconfigurationqualitycheck_from_commandline_arguments(commandline_arguments, default_value)
377
- if targetenvironmenttype == "Productive":
378
- return self.get_buildconfigurationproductive_from_commandline_arguments(commandline_arguments, "Release")
379
- raise ValueError(f"Unknown build-environmenttype: {targetenvironmenttype}")
380
-
381
- @GeneralUtilities.check_arguments
382
- def get_default_target_environmenttype_mapping(self) -> dict[str, str]:
383
- return {
384
- "Development": "Development",
385
- "QualityCheck": "QualityCheck",
386
- "Productive": "Productive"
387
- }
388
-
389
- @GeneralUtilities.check_arguments
390
- def __standardized_tasks_build_for_dotnet_project_in_common_project_structure(self, buildscript_file: str, target_environmenttype_mapping: dict[str, str],
391
- default_build_configuration: str, verbosity: int, target_environmenttype: str,
392
- runtimes: list[str], commandline_arguments: list[str]):
393
- dotnet_build_configuration: str = target_environmenttype_mapping[target_environmenttype]
394
- codeunitname: str = os.path.basename(str(Path(os.path.dirname(buildscript_file)).parent.parent.absolute()))
395
- verbosity = TasksForCommonProjectStructure.get_verbosity_from_commandline_arguments(commandline_arguments, verbosity)
396
- files_to_sign: dict[str, str] = TasksForCommonProjectStructure.get_filestosign_from_commandline_arguments(commandline_arguments, dict())
397
- repository_folder: str = str(Path(os.path.dirname(buildscript_file)).parent.parent.parent.absolute())
398
- commitid = self.__sc.git_get_commit_id(repository_folder)
399
- outputfolder = GeneralUtilities.resolve_relative_path("../Artifacts", os.path.dirname(buildscript_file))
400
- codeunit_folder = os.path.join(repository_folder, codeunitname)
401
- csproj_file = os.path.join(codeunit_folder, codeunitname, codeunitname+".csproj")
402
- csproj_test_file = os.path.join(codeunit_folder, codeunitname+"Tests", codeunitname+"Tests.csproj")
403
- buildconfiguration = self.__get_dotnet_buildconfiguration_by_target_environmenttype(dotnet_build_configuration, default_build_configuration, commandline_arguments)
404
-
405
- self.__sc.run_program("dotnet", "restore", codeunit_folder, verbosity=verbosity)
406
- self.__standardized_tasks_build_for_dotnet_build(csproj_file, buildconfiguration,
407
- os.path.join(outputfolder, "BuildResult_DotNet_"), files_to_sign, commitid, verbosity, runtimes)
408
- self.__standardized_tasks_build_for_dotnet_build(csproj_test_file, buildconfiguration,
409
- os.path.join(outputfolder, "BuildResult_DotNetTests_"), files_to_sign, commitid, verbosity, runtimes)
410
- self.generate_sbom_for_dotnet_project(codeunit_folder)
411
-
412
- @GeneralUtilities.check_arguments
413
- def __standardized_tasks_build_nupkg_for_dotnet_create_package(self, buildscript_file: str, verbosity: int, commandline_arguments: list[str]):
414
- codeunitname: str = os.path.basename(str(Path(os.path.dirname(buildscript_file)).parent.parent.absolute()))
415
- verbosity = TasksForCommonProjectStructure.get_verbosity_from_commandline_arguments(commandline_arguments, verbosity)
416
- repository_folder: str = str(Path(os.path.dirname(buildscript_file)).parent.parent.parent.absolute())
417
- build_folder = os.path.join(repository_folder, codeunitname, "Other", "Build")
418
- outputfolder = GeneralUtilities.resolve_relative_path("../Artifacts/BuildResult_NuGet", os.path.dirname(buildscript_file))
419
- root: etree._ElementTree = etree.parse(os.path.join(build_folder, f"{codeunitname}.nuspec"))
420
- current_version = root.xpath("//*[name() = 'package']/*[name() = 'metadata']/*[name() = 'version']/text()")[0]
421
- nupkg_filename = f"{codeunitname}.{current_version}.nupkg"
422
- nupkg_file = f"{build_folder}/{nupkg_filename}"
423
- GeneralUtilities.ensure_file_does_not_exist(nupkg_file)
424
- commit_id = self.__sc.git_get_commit_id(repository_folder)
425
- self.__sc.run_program("nuget", f"pack {codeunitname}.nuspec -Properties \"commitid={commit_id}\"", build_folder, verbosity=verbosity)
426
- GeneralUtilities.ensure_directory_does_not_exist(outputfolder)
427
- GeneralUtilities.ensure_directory_exists(outputfolder)
428
- os.rename(nupkg_file, f"{outputfolder}/{nupkg_filename}")
429
-
430
- @GeneralUtilities.check_arguments
431
- def generate_sbom_for_dotnet_project(self, codeunit_folder: str) -> None:
432
- codeunit_name = os.path.basename(codeunit_folder)
433
- sc = ScriptCollectionCore()
434
- bomfile_folder = "Other\\Artifacts\\BOM"
435
- sc.run_program("dotnet", f"CycloneDX {codeunit_name}\\{codeunit_name}.csproj -o {bomfile_folder}", codeunit_folder)
436
- target = f"{codeunit_folder}\\{bomfile_folder}\\{codeunit_name}.sbom.xml"
437
- GeneralUtilities.ensure_file_does_not_exist(target)
438
- os.rename(f"{codeunit_folder}\\{bomfile_folder}\\bom.xml", target)
439
-
440
- @GeneralUtilities.check_arguments
441
- def standardized_tasks_linting_for_python_codeunit_in_common_project_structure(self, linting_script_file: str, verbosity: int, targetenvironmenttype: str, commandline_arguments: list[str]):
442
- codeunitname: str = Path(os.path.dirname(linting_script_file)).parent.parent.name
443
- verbosity = TasksForCommonProjectStructure.get_verbosity_from_commandline_arguments(commandline_arguments, verbosity)
444
- repository_folder: str = str(Path(os.path.dirname(linting_script_file)).parent.parent.parent.absolute())
445
- errors_found = False
446
- GeneralUtilities.write_message_to_stdout(f"Check for linting-issues in codeunit {codeunitname}.")
447
- src_folder = os.path.join(repository_folder, codeunitname, codeunitname)
448
- tests_folder = src_folder+"Tests"
449
- for file in GeneralUtilities.get_all_files_of_folder(src_folder)+GeneralUtilities.get_all_files_of_folder(tests_folder):
450
- relative_file_path_in_repository = os.path.relpath(file, repository_folder)
451
- if file.endswith(".py") and os.path.getsize(file) > 0 and not self.__sc.file_is_git_ignored(relative_file_path_in_repository, repository_folder):
452
- GeneralUtilities.write_message_to_stdout(f"Check for linting-issues in {os.path.relpath(file,os.path.join(repository_folder,codeunitname))}.")
453
- linting_result = self.__sc.python_file_has_errors(file, repository_folder)
454
- if (linting_result[0]):
455
- errors_found = True
456
- for error in linting_result[1]:
457
- GeneralUtilities.write_message_to_stderr(error)
458
- if errors_found:
459
- raise Exception("Linting-issues occurred.")
460
- else:
461
- GeneralUtilities.write_message_to_stdout("No linting-issues found.")
462
-
463
- @GeneralUtilities.check_arguments
464
- def standardized_tasks_generate_coverage_report(self, repository_folder: str, codeunitname: str, verbosity: int, generate_badges: bool, targetenvironmenttype: str,
465
- commandline_arguments: list[str]):
466
- """This script expects that the file '<repositorybasefolder>/<codeunitname>/Other/Artifacts/TestCoverage/TestCoverage.xml'
467
- which contains a test-coverage-report in the cobertura-format exists.
468
- This script expectes that the testcoverage-reportfolder is '<repositorybasefolder>/<codeunitname>/Other/Artifacts/TestCoverageReport'.
469
- This script expectes that a test-coverage-badges should be added to '<repositorybasefolder>/<codeunitname>/Other/Resources/Badges'."""
470
- verbosity = self.get_verbosity_from_commandline_arguments(commandline_arguments, verbosity)
471
- if verbosity == 0:
472
- verbose_argument_for_reportgenerator = "Off"
473
- if verbosity == 1:
474
- verbose_argument_for_reportgenerator = "Error"
475
- if verbosity == 2:
476
- verbose_argument_for_reportgenerator = "Info"
477
- if verbosity == 3:
478
- verbose_argument_for_reportgenerator = "Verbose"
479
-
480
- # Generating report
481
- GeneralUtilities.ensure_directory_does_not_exist(os.path.join(repository_folder, codeunitname, f"{codeunitname}/Other/Artifacts/TestCoverageReport"))
482
- GeneralUtilities.ensure_directory_exists(os.path.join(repository_folder, codeunitname, f"{codeunitname}/Other/Artifacts/TestCoverageReport"))
483
- self.__sc.run_program("reportgenerator", f"-reports:{codeunitname}/Other/Artifacts/TestCoverage/TestCoverage.xml " +
484
- f"-targetdir:{codeunitname}/Other/Artifacts/TestCoverageReport --verbosity={verbose_argument_for_reportgenerator}", repository_folder)
485
-
486
- if generate_badges:
487
- # Generating badges
488
- testcoverageubfolger = f"{codeunitname}/Other/Resources/TestCoverageBadges"
489
- fulltestcoverageubfolger = os.path.join(repository_folder, codeunitname, testcoverageubfolger)
490
- GeneralUtilities.ensure_directory_does_not_exist(fulltestcoverageubfolger)
491
- GeneralUtilities.ensure_directory_exists(fulltestcoverageubfolger)
492
- self.__sc.run_program("reportgenerator", f"-reports:{codeunitname}/Other/Artifacts/TestCoverage/TestCoverage.xml -targetdir:{testcoverageubfolger} " +
493
- f"-reporttypes:Badges --verbosity={verbose_argument_for_reportgenerator}", repository_folder, verbosity=verbosity)
494
-
495
- @GeneralUtilities.check_arguments
496
- def standardized_tasks_run_testcases_for_dotnet_project_in_common_project_structure(self, runtestcases_file: str, targetenvironmenttype: str, verbosity: int, generate_badges: bool,
497
- commandline_arguments: list[str]):
498
- codeunit_name: str = os.path.basename(str(Path(os.path.dirname(runtestcases_file)).parent.parent.absolute()))
499
- verbosity = TasksForCommonProjectStructure.get_verbosity_from_commandline_arguments(commandline_arguments, verbosity)
500
- repository_folder: str = str(Path(os.path.dirname(runtestcases_file)).parent.parent.parent.absolute())
501
- testprojectname = codeunit_name+"Tests"
502
- coverage_file_folder = os.path.join(repository_folder, codeunit_name, "Other/Artifacts/TestCoverage")
503
- coveragefiletarget = os.path.join(coverage_file_folder, "TestCoverage.xml")
504
- buildconfiguration = self.__get_dotnet_buildconfiguration_by_target_environmenttype(targetenvironmenttype, codeunit_name, commandline_arguments)
505
- with tempfile.TemporaryDirectory() as temp_directory:
506
- self.__sc.run_program_argsasarray("dotnet", ["test", f"{testprojectname}/{testprojectname}.csproj", "-c", buildconfiguration,
507
- "--verbosity", "normal", "--collect", "XPlat Code Coverage", "--results-directory", temp_directory],
508
- os.path.join(repository_folder, codeunit_name), verbosity=verbosity)
509
- temp_directory_subdir = GeneralUtilities.get_direct_folders_of_folder(temp_directory)[0]
510
- test_coverage_file = GeneralUtilities.get_direct_files_of_folder(temp_directory_subdir)[0]
511
- GeneralUtilities.ensure_directory_exists(coverage_file_folder)
512
- GeneralUtilities.ensure_file_does_not_exist(coveragefiletarget)
513
- shutil.copy(test_coverage_file, coveragefiletarget)
514
- self.standardized_tasks_generate_coverage_report(repository_folder, codeunit_name, verbosity, generate_badges, targetenvironmenttype, commandline_arguments)
515
- self.check_testcoverage_for_project_in_common_project_structure(coveragefiletarget, repository_folder, codeunit_name)
516
- self.update_path_of_source(repository_folder, codeunit_name)
517
-
518
- @GeneralUtilities.check_arguments
519
- def write_version_to_codeunit_file(self, codeunit_file: str, current_version: str) -> None:
520
- versionregex = "\\d+\\.\\d+\\.\\d+"
521
- versiononlyregex = f"^{versionregex}$"
522
- pattern = re.compile(versiononlyregex)
523
- if pattern.match(current_version):
524
- GeneralUtilities.write_text_to_file(codeunit_file, re.sub(f"<cps:version>{versionregex}<\\/cps:version>",
525
- f"<cps:version>{current_version}</cps:version>", GeneralUtilities.read_text_from_file(codeunit_file)))
526
- else:
527
- raise ValueError(f"Version '{current_version}' does not match version-regex '{versiononlyregex}'.")
528
-
529
- @GeneralUtilities.check_arguments
530
- def standardized_tasks_linting_for_dotnet_project_in_common_project_structure(self, linting_script_file: str, verbosity: int, targetenvironmenttype: str, commandline_arguments: list[str]):
531
- verbosity = TasksForCommonProjectStructure.get_verbosity_from_commandline_arguments(commandline_arguments, verbosity)
532
- # TODO implement function
533
-
534
- @GeneralUtilities.check_arguments
535
- def __export_codeunit_reference_content_to_reference_repository(self, project_version_identifier: str, replace_existing_content: bool, target_folder_for_reference_repository: str,
536
- repository: str, codeunitname, projectname: str, codeunit_version: str, public_repository_url: str, branch: str) -> None:
537
- target_folder = os.path.join(target_folder_for_reference_repository, project_version_identifier, codeunitname)
538
- if os.path.isdir(target_folder) and not replace_existing_content:
539
- raise ValueError(f"Folder '{target_folder}' already exists.")
540
- GeneralUtilities.ensure_directory_does_not_exist(target_folder)
541
- GeneralUtilities.ensure_directory_exists(target_folder)
542
- title = f"{codeunitname}-reference (codeunit v{codeunit_version}, conained in project {projectname} ({project_version_identifier}))"
543
- if public_repository_url is None:
544
- repo_url_html = ""
545
- else:
546
- repo_url_html = f'<a href="{public_repository_url}/tree/{branch}/{codeunitname}">Source-code</a><br>'
547
- index_file_for_reference = os.path.join(target_folder, "index.html")
548
- index_file_content = f"""<!DOCTYPE html>
549
- <html lang="en">
550
- <head>
551
- <meta charset="UTF-8">
552
- <title>{title}</title>
553
- <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
554
- </head>
555
- <body>
556
- <h1 class="display-1">{title}</h1>
557
- <hr/>
558
- Available reference-content for {codeunitname}:<br>
559
- {repo_url_html}
560
- <a href="./Reference/index.html">Reference</a><br>
561
- <a href="./TestCoverageReport/index.html">TestCoverageReport</a><br>
562
- </body>
563
- </html>
564
- """ # see https://getbootstrap.com/docs/5.1/getting-started/introduction/
565
- GeneralUtilities.ensure_file_exists(index_file_for_reference)
566
- GeneralUtilities.write_text_to_file(index_file_for_reference, index_file_content)
567
- other_folder_in_repository = os.path.join(repository, codeunitname, "Other")
568
- source_generatedreference = os.path.join(other_folder_in_repository, "Artifacts", "Reference")
569
- target_generatedreference = os.path.join(target_folder, "Reference")
570
- shutil.copytree(source_generatedreference, target_generatedreference)
571
- source_testcoveragereport = os.path.join(other_folder_in_repository, "Artifacts", "TestCoverageReport")
572
- target_testcoveragereport = os.path.join(target_folder, "TestCoverageReport")
573
- shutil.copytree(source_testcoveragereport, target_testcoveragereport)
574
-
575
- @GeneralUtilities.check_arguments
576
- def __standardized_tasks_release_buildartifact_for_project_in_common_project_format(self, information: CreateReleaseInformationForProjectInCommonProjectFormat) -> None:
577
- # This function is intended to be called directly after standardized_tasks_merge_to_stable_branch_for_project_in_common_project_format
578
- project_version = self.__sc.get_semver_version_from_gitversion(information.repository)
579
- target_folder_base = os.path.join(information.artifacts_folder, information.projectname, project_version)
580
- if os.path.isdir(target_folder_base):
581
- raise ValueError(f"The folder '{target_folder_base}' already exists.")
582
- GeneralUtilities.ensure_directory_exists(target_folder_base)
583
-
584
- for codeunitname, codeunit_configuration in information.codeunits.items():
585
- codeunit_folder = os.path.join(information.repository, codeunitname)
586
- codeunit_version = self.get_version_of_codeunit(os.path.join(codeunit_folder, f"{codeunitname}.codeunit.xml"))
587
- self.build_codeunit(os.path.join(information.repository, codeunitname), information.verbosity, information.target_environmenttype_for_productive,
588
- codeunit_configuration.additional_arguments_file)
589
-
590
- reference_repository_target_for_project = os.path.join(information.reference_repository, "ReferenceContent")
591
-
592
- for codeunitname, codeunit_configuration in information.codeunits.items():
593
- codeunit_folder = os.path.join(information.repository, codeunitname)
594
- codeunit_version = self.get_version_of_codeunit(os.path.join(codeunit_folder, f"{codeunitname}.codeunit.xml"))
595
-
596
- target_folder_for_codeunit = os.path.join(target_folder_base, codeunitname)
597
- GeneralUtilities.ensure_directory_exists(target_folder_for_codeunit)
598
- shutil.copytree(os.path.join(codeunit_folder, "Other", "Artifacts"), os.path.join(target_folder_for_codeunit, "Artifacts"))
599
-
600
- for codeunitname, codeunit_configuration in information.codeunits.items():
601
- push_artifact_to_registry_script = codeunit_configuration.push_to_registry_script
602
- folder = os.path.dirname(push_artifact_to_registry_script)
603
- file = os.path.basename(push_artifact_to_registry_script)
604
- GeneralUtilities.write_message_to_stdout(f"Push buildartifact of codeunit {codeunitname}.")
605
- self.__sc.run_program("python", file, folder, verbosity=information.verbosity, throw_exception_if_exitcode_is_not_zero=True)
606
-
607
- # Copy reference of codeunit to reference-repository
608
- self.__export_codeunit_reference_content_to_reference_repository(f"v{project_version}", False, reference_repository_target_for_project, information.repository,
609
- codeunitname, information.projectname, codeunit_version, information.public_repository_url,
610
- f"v{project_version}")
611
- self.__export_codeunit_reference_content_to_reference_repository("Latest", True, reference_repository_target_for_project, information.repository,
612
- codeunitname, information.projectname, codeunit_version, information.public_repository_url,
613
- information.target_branch_name)
614
-
615
- GeneralUtilities.write_message_to_stdout("Create entire reference")
616
- all_available_version_identifier_folders_of_reference = list(
617
- folder for folder in GeneralUtilities.get_direct_folders_of_folder(reference_repository_target_for_project))
618
- all_available_version_identifier_folders_of_reference.reverse() # move newer versions above
619
- all_available_version_identifier_folders_of_reference.insert(0, all_available_version_identifier_folders_of_reference.pop()) # move latest version to the top
620
- reference_versions_html_lines = []
621
- for all_available_version_identifier_folder_of_reference in all_available_version_identifier_folders_of_reference:
622
- version_identifier_of_project = os.path.basename(all_available_version_identifier_folder_of_reference)
623
- if version_identifier_of_project == "Latest":
624
- latest_version_hint = f" (v {project_version})"
625
- else:
626
- latest_version_hint = ""
627
- reference_versions_html_lines.append('<hr>')
628
- reference_versions_html_lines.append(f'<h2 class="display-2">{version_identifier_of_project}{latest_version_hint}</h2>')
629
- reference_versions_html_lines.append("Contained codeunits:<br>")
630
- reference_versions_html_lines.append("<ul>")
631
- for codeunit_reference_folder in list(folder for folder in GeneralUtilities.get_direct_folders_of_folder(all_available_version_identifier_folder_of_reference)):
632
- codeunit_folder = os.path.join(information.repository, codeunitname)
633
- codeunit_version = self.get_version_of_codeunit(os.path.join(codeunit_folder, f"{codeunitname}.codeunit.xml"))
634
- reference_versions_html_lines.append(f'<li><a href="./{version_identifier_of_project}/{os.path.basename(codeunit_reference_folder)}/index.html">' +
635
- f'{os.path.basename(codeunit_reference_folder)} {version_identifier_of_project}</a></li>')
636
- reference_versions_html_lines.append("</ul>")
637
-
638
- reference_versions_links_file_content = " \n".join(reference_versions_html_lines)
639
- title = f"{information.projectname}-reference"
640
- reference_index_file = os.path.join(reference_repository_target_for_project, "index.html")
641
- reference_index_file_content = f"""<!DOCTYPE html>
642
- <html lang="en">
643
-
644
- <head>
645
- <meta charset="UTF-8">
646
- <title>{title}</title>
647
- <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
648
- </head>
649
-
650
- <body>
651
- <h1 class="display-1">{title}</h1>
652
- <hr/>
653
- {reference_versions_links_file_content}
654
- </body>
655
-
656
- </html>
657
- """ # see https://getbootstrap.com/docs/5.1/getting-started/introduction/
658
- GeneralUtilities.write_text_to_file(reference_index_file, reference_index_file_content)
659
-
660
- @GeneralUtilities.check_arguments
661
- def push_nuget_build_artifact_for_project_in_standardized_project_structure(self, push_script_file: str, codeunitname: str,
662
- registry_address: str, api_key: str):
663
- # when pusing to "default public" nuget-server then use registry_address: "nuget.org"
664
- build_artifact_folder = GeneralUtilities.resolve_relative_path(
665
- f"../../Submodules/{codeunitname}/{codeunitname}/Other/Artifacts/BuildResult_NuGet", os.path.dirname(push_script_file))
666
- self.__sc.push_nuget_build_artifact_of_repository_in_common_file_structure(self.__sc.find_file_by_extension(build_artifact_folder, "nupkg"),
667
- registry_address, api_key)
668
-
669
- @GeneralUtilities.check_arguments
670
- def assert_no_uncommitted_changes(self, repository_folder: str):
671
- if self.__sc.git_repository_has_uncommitted_changes(repository_folder):
672
- raise ValueError(f"Repository '{repository_folder}' has uncommitted changes.")
673
-
674
- @GeneralUtilities.check_arguments
675
- def get_codeunits(self, repository_folder: str) -> list[str]:
676
- result: list[str] = []
677
- for direct_subfolder in GeneralUtilities.get_direct_folders_of_folder(repository_folder):
678
- subfoldername = os.path.basename(direct_subfolder)
679
- if os.path.isfile(os.path.join(direct_subfolder, f"{subfoldername}.codeunit.xml")):
680
- result.append(subfoldername)
681
- return result
682
-
683
- @GeneralUtilities.check_arguments
684
- def prepare_release_by_building_code_units_and_committing_changes(self, repository_folder: str, build_repository_folder: str, codeunits: dict[str, CodeUnitConfiguration],
685
- new_version_branch_name: str = "other/next-release", main_branch_name: str = "main", verbosity: int = 1) -> None:
686
- self.assert_no_uncommitted_changes(repository_folder)
687
- repository_name = os.path.basename(repository_folder)
688
- self.__sc.git_checkout(repository_folder, new_version_branch_name)
689
- for codeunitname, codeunit_confoguration in codeunits.items():
690
- self.build_codeunit(os.path.join(repository_folder, codeunitname), verbosity, "QualityCheck", codeunit_confoguration.additional_arguments_file)
691
- self.__sc.git_commit(repository_folder, "Updates due to building code-units.")
692
- self.__sc.git_merge(repository_folder, new_version_branch_name, main_branch_name, False, True, f'Merge branch {new_version_branch_name} into {main_branch_name}')
693
- self.__sc.git_checkout(repository_folder, main_branch_name)
694
- self.__sc.git_commit(build_repository_folder, f"Updated submodule {repository_name}")
695
-
696
- @GeneralUtilities.check_arguments
697
- def create_release_for_project_in_standardized_release_repository_format(self, create_release_file: str, createReleaseConfiguration: CreateReleaseConfiguration):
698
-
699
- GeneralUtilities.write_message_to_stdout(f"Create release for project {createReleaseConfiguration.projectname}.")
700
- folder_of_create_release_file_file = os.path.abspath(os.path.dirname(create_release_file))
701
-
702
- build_repository_folder = GeneralUtilities.resolve_relative_path(f"..{os.path.sep}..", folder_of_create_release_file_file)
703
- self.assert_no_uncommitted_changes(build_repository_folder)
704
-
705
- self.__sc.git_checkout(build_repository_folder, createReleaseConfiguration.build_repository_branch)
706
-
707
- repository_folder = GeneralUtilities.resolve_relative_path(f"Submodules{os.path.sep}{createReleaseConfiguration.projectname}", build_repository_folder)
708
- mergeToStableBranchInformation = MergeToStableBranchInformationForProjectInCommonProjectFormat(repository_folder)
709
- mergeToStableBranchInformation.verbosity = createReleaseConfiguration.verbosity
710
- mergeToStableBranchInformation.push_target_branch = createReleaseConfiguration.remotename is not None
711
- mergeToStableBranchInformation.push_target_branch_remote_name = createReleaseConfiguration.remotename
712
- mergeToStableBranchInformation.push_source_branch = createReleaseConfiguration.remotename is not None
713
- mergeToStableBranchInformation.push_source_branch_remote_name = createReleaseConfiguration.remotename
714
- mergeToStableBranchInformation.codeunits = createReleaseConfiguration.codeunits
715
- new_project_version = self.__standardized_tasks_merge_to_stable_branch_for_project_in_common_project_format(mergeToStableBranchInformation)
716
-
717
- createReleaseInformation = CreateReleaseInformationForProjectInCommonProjectFormat(repository_folder, createReleaseConfiguration.artifacts_folder,
718
- createReleaseConfiguration.projectname, createReleaseConfiguration.public_repository_url,
719
- mergeToStableBranchInformation.targetbranch)
720
- createReleaseInformation.verbosity = createReleaseConfiguration.verbosity
721
- createReleaseInformation.codeunits = createReleaseConfiguration.codeunits
722
- self.__standardized_tasks_release_buildartifact_for_project_in_common_project_format(createReleaseInformation)
723
-
724
- self.__sc.git_commit(createReleaseInformation.reference_repository, f"Added reference of {createReleaseConfiguration.projectname} v{new_project_version}")
725
- if createReleaseConfiguration.reference_repository_remote_name is not None:
726
- self.__sc.git_push(createReleaseInformation.reference_repository, createReleaseConfiguration.reference_repository_remote_name, createReleaseConfiguration.reference_repository_branch_name,
727
- createReleaseConfiguration.reference_repository_branch_name, verbosity=createReleaseConfiguration.verbosity)
728
- self.__sc.git_commit(build_repository_folder, f"Added {createReleaseConfiguration.projectname} release v{new_project_version}")
729
- GeneralUtilities.write_message_to_stdout(f"Finished release for project {createReleaseConfiguration.projectname} successfully.")
730
- return new_project_version
731
-
732
- @GeneralUtilities.check_arguments
733
- def create_release_starter_for_repository_in_standardized_format(self, create_release_file: str, logfile: str, verbosity: int, addLogOverhead: bool,
734
- commandline_arguments: list[str]):
735
- # hint: arguments can be overwritten by commandline_arguments
736
- folder_of_this_file = os.path.dirname(create_release_file)
737
- verbosity = TasksForCommonProjectStructure.get_verbosity_from_commandline_arguments(commandline_arguments, verbosity)
738
- self.__sc.run_program("python", f"CreateRelease.py --overwrite_verbosity={str(verbosity)}",
739
- folder_of_this_file, verbosity=verbosity, log_file=logfile, addLogOverhead=addLogOverhead)
740
-
741
- @GeneralUtilities.check_arguments
742
- def __standardized_tasks_merge_to_stable_branch_for_project_in_common_project_format(self, information: MergeToStableBranchInformationForProjectInCommonProjectFormat) -> str:
743
-
744
- src_branch_commit_id = self.__sc.git_get_commit_id(information.repository, information.sourcebranch)
745
- if (src_branch_commit_id == self.__sc.git_get_commit_id(information.repository, information.targetbranch)):
746
- GeneralUtilities.write_message_to_stderr(
747
- f"Can not merge because the source-branch and the target-branch are on the same commit (commit-id: {src_branch_commit_id})")
748
-
749
- self.assert_no_uncommitted_changes(information.repository)
750
- self.__sc.git_checkout(information.repository, information.sourcebranch)
751
- self.__sc.run_program("git", "clean -dfx", information.repository, verbosity=information.verbosity, throw_exception_if_exitcode_is_not_zero=True)
752
- project_version = self.__sc.get_semver_version_from_gitversion(information.repository)
753
- success = False
754
- try:
755
- for _, codeunit in information.codeunits.items():
756
- GeneralUtilities.write_message_to_stdout(f"Start processing codeunit {codeunit.name}.")
757
- self.build_codeunit(os.path.join(information.repository, codeunit.name), information.verbosity,
758
- information.target_environmenttype_for_qualitycheck, codeunit.additional_arguments_file)
759
- GeneralUtilities.write_message_to_stdout(f"Finished processing codeunit {codeunit.name}.")
760
-
761
- self.assert_no_uncommitted_changes(information.repository)
762
- success = True
763
- except Exception as exception:
764
- GeneralUtilities.write_exception_to_stderr(exception, "Error while doing merge-tasks. Merge will be aborted.")
765
-
766
- if not success:
767
- raise Exception("Release was not successful.")
768
-
769
- commit_id = self.__sc.git_merge(information.repository, information.sourcebranch, information.targetbranch, True)
770
- self.__sc.git_create_tag(information.repository, commit_id, f"v{project_version}", information.sign_git_tags)
771
-
772
- if information.push_source_branch:
773
- GeneralUtilities.write_message_to_stdout("Push source-branch...")
774
- self.__sc.git_push(information.repository, information.push_source_branch_remote_name,
775
- information.sourcebranch, information.sourcebranch, pushalltags=True, verbosity=information.verbosity)
776
-
777
- if information.push_target_branch:
778
- GeneralUtilities.write_message_to_stdout("Push target-branch...")
779
- self.__sc.git_push(information.repository, information.push_target_branch_remote_name,
780
- information.targetbranch, information.targetbranch, pushalltags=True, verbosity=information.verbosity)
781
-
782
- return project_version
783
-
784
- @GeneralUtilities.check_arguments
785
- def standardized_tasks_build_for_docker_library_project_in_common_project_structure(self, build_script_file: str, build_configuration: str, verbosity: int, commandline_arguments: list[str]):
786
- use_cache: bool = build_configuration == "QualityCheck"
787
- verbosity = self.get_verbosity_from_commandline_arguments(commandline_arguments, verbosity)
788
- sc: ScriptCollectionCore = ScriptCollectionCore()
789
- codeunitname: str = Path(os.path.dirname(build_script_file)).parent.parent.name
790
- codeunit_folder = GeneralUtilities.resolve_relative_path("../..", str(os.path.dirname(build_script_file)))
791
-
792
- codeunitname_lower = codeunitname.lower()
793
- version = self.get_version_of_codeunit(os.path.join(codeunit_folder, f"{codeunitname}.codeunit.xml"))
794
- args = ["image", "build", "--pull", "--force-rm", "--progress=plain", "--build-arg", f"environmenttypeStage={build_configuration}",
795
- "--tag", f"{codeunitname_lower}:latest", "--tag", f"{codeunitname_lower}:{version}", "--file", "Dockerfile"]
796
- if not use_cache:
797
- args.append("--no-cache")
798
- args.append(".")
799
- codeunit_content_folder = os.path.join(codeunit_folder, codeunitname)
800
- sc.run_program_argsasarray("docker", args, codeunit_content_folder, verbosity=verbosity, print_errors_as_information=True)
801
- artifacts_folder = GeneralUtilities.resolve_relative_path("Other/Artifacts", codeunit_folder)
802
- app_artifacts_folder = os.path.join(artifacts_folder, "BuildResult_OCIImage")
803
- GeneralUtilities.ensure_directory_does_not_exist(app_artifacts_folder)
804
- GeneralUtilities.ensure_directory_exists(app_artifacts_folder)
805
- sc.run_program_argsasarray("docker", ["save", "--output", f"{codeunitname}_v{version}.tar",
806
- f"{codeunitname_lower}:{version}"], app_artifacts_folder, verbosity=verbosity, print_errors_as_information=True)
807
-
808
- @GeneralUtilities.check_arguments
809
- def push_docker_build_artifact_of_repository_in_common_file_structure(self, push_artifacts_file: str, registry: str, product_name: str, codeunitname: str,
810
- verbosity: int, commandline_arguments: list[str]):
811
- folder_of_this_file = os.path.dirname(push_artifacts_file)
812
- verbosity = self.get_verbosity_from_commandline_arguments(commandline_arguments, verbosity)
813
- repository_folder = GeneralUtilities.resolve_relative_path(f"..{os.path.sep}..{os.path.sep}Submodules{os.path.sep}{product_name}", folder_of_this_file)
814
- codeunit_folder = os.path.join(repository_folder, codeunitname)
815
- artifacts_folder = self.get_artifacts_folder_in_repository_in_common_repository_format(repository_folder, codeunitname)
816
- applicationimage_folder = os.path.join(artifacts_folder, "ApplicationImage")
817
- sc = ScriptCollectionCore()
818
- image_file = sc.find_file_by_extension(applicationimage_folder, "tar")
819
- image_filename = os.path.basename(image_file)
820
- version = self.get_version_of_codeunit(os.path.join(codeunit_folder, f"{codeunitname}.codeunit.xml"))
821
- image_tag_name = codeunitname.lower()
822
- image_latest = f"{registry}/{image_tag_name}:latest"
823
- image_version = f"{registry}/{image_tag_name}:{version}"
824
- GeneralUtilities.write_message_to_stdout("Load image...")
825
- sc.run_program("docker", f"load --input {image_filename}", applicationimage_folder, verbosity=verbosity)
826
- GeneralUtilities.write_message_to_stdout("Tag image...")
827
- sc.run_program("docker", f"tag {image_tag_name}:{version} {image_latest}", verbosity=verbosity)
828
- sc.run_program("docker", f"tag {image_tag_name}:{version} {image_version}", verbosity=verbosity)
829
- GeneralUtilities.write_message_to_stdout("Push image...")
830
- sc.run_program("docker", f"push {image_latest}", verbosity=verbosity)
831
- sc.run_program("docker", f"push {image_version}", verbosity=verbosity)
832
-
833
- @GeneralUtilities.check_arguments
834
- def get_dependent_code_units(self, codeunit_file: str) -> list[str]:
835
- root: etree._ElementTree = etree.parse(codeunit_file)
836
- return root.xpath('//cps:dependentcodeunit/text()', namespaces={
837
- 'cps': 'https://projects.aniondev.de/PublicProjects/Common/ProjectTemplates/-/tree/main/Conventions/RepositoryStructure/CommonProjectStructure'
838
- })
839
-
840
- @GeneralUtilities.check_arguments
841
- def standardized_tasks_run_testcases_for_docker_project_in_common_project_structure(self, run_testcases_script_file: str, verbosity: int, targetenvironmenttype: str,
842
- commandline_arguments: list[str]):
843
- codeunit_folder = GeneralUtilities.resolve_relative_path("../..", str(os.path.dirname(run_testcases_script_file)))
844
- repository_folder: str = str(Path(os.path.dirname(run_testcases_script_file)).parent.parent.parent.absolute())
845
- codeunitname: str = Path(os.path.dirname(run_testcases_script_file)).parent.parent.name
846
- date = int(round(datetime.now().timestamp()))
847
- # TODO generate real coverage report
848
- dummy_test_coverage_file = f"""<?xml version="1.0" ?>
849
- <coverage version="6.3.2" timestamp="{date}" lines-valid="0" lines-covered="0" line-rate="0" branches-covered="0" branches-valid="0" branch-rate="0" complexity="0">
850
- <sources>
851
- <source>{codeunitname}</source>
852
- </sources>
853
- <packages>
854
- <package name="{codeunitname}" line-rate="0" branch-rate="0" complexity="0">
855
- </package>
856
- </packages>
857
- </coverage>"""
858
- artifacts_folder = GeneralUtilities.resolve_relative_path("Other/Artifacts", codeunit_folder)
859
- testcoverage_artifacts_folder = os.path.join(artifacts_folder, "TestCoverage")
860
- GeneralUtilities.ensure_directory_exists(testcoverage_artifacts_folder)
861
- testcoverage_file = os.path.join(testcoverage_artifacts_folder, "TestCoverage.xml")
862
- GeneralUtilities.ensure_file_exists(testcoverage_file)
863
- GeneralUtilities.write_text_to_file(testcoverage_file, dummy_test_coverage_file)
864
- self.standardized_tasks_generate_coverage_report(repository_folder, codeunitname, verbosity, True, targetenvironmenttype, commandline_arguments)
865
- self.update_path_of_source(repository_folder, codeunitname)
866
-
867
- @GeneralUtilities.check_arguments
868
- def standardized_tasks_linting_for_docker_project_in_common_project_structure(self, linting_script_file: str, verbosity: int, targetenvironmenttype: str, commandline_arguments: list[str]) -> None:
869
- verbosity = self.get_verbosity_from_commandline_arguments(commandline_arguments, verbosity)
870
- # TODO
871
-
872
- @GeneralUtilities.check_arguments
873
- def standardized_tasks_do_common_tasks(self, common_tasks_scripts_file: str, version: str, verbosity: int, targetenvironmenttype: str, clear_artifacts_folder: bool,
874
- additional_arguments_file: str, commandline_arguments: list[str]) -> None:
875
- additional_arguments_file = self.get_additionalargumentsfile_from_commandline_arguments(commandline_arguments, additional_arguments_file)
876
- target_environmenttype = self.get_targetenvironmenttype_from_commandline_arguments(commandline_arguments, targetenvironmenttype)
877
- if commandline_arguments is None:
878
- raise ValueError('The "commandline_arguments"-parameter is not defined.')
879
- if len(commandline_arguments) == 0:
880
- raise ValueError('An empty array as argument for the "commandline_arguments"-parameter is not valid.')
881
- commandline_arguments = commandline_arguments[1:]
882
- repository_folder: str = str(Path(os.path.dirname(common_tasks_scripts_file)).parent.parent.absolute())
883
- codeunitname: str = str(os.path.basename(Path(os.path.dirname(common_tasks_scripts_file)).parent.absolute()))
884
- verbosity = self.get_verbosity_from_commandline_arguments(commandline_arguments, verbosity)
885
- GeneralUtilities.write_message_to_stdout(f"Build-environmenttype: {targetenvironmenttype}")
886
-
887
- # Clear previously builded artifacts if desired:
888
- if clear_artifacts_folder:
889
- artifacts_folder = os.path.join(repository_folder, codeunitname, "Other", "Artifacts")
890
- GeneralUtilities.ensure_directory_does_not_exist(artifacts_folder)
891
-
892
- # Check codeunit-conformity
893
- # TODO check if foldername=="<codeunitname>[.codeunit.xml]"==codeunitname in file
894
- codeunitfile = os.path.join(repository_folder, codeunitname, f"{codeunitname}.codeunit.xml")
895
- if not os.path.isfile(codeunitfile):
896
- raise Exception(f'Codeunitfile "{codeunitfile}" does not exist.')
897
- # TODO implement usage of self.reference_latest_version_of_xsd_when_generating_xml
898
- namespaces = {'cps': 'https://projects.aniondev.de/PublicProjects/Common/ProjectTemplates/-/tree/main/Conventions/RepositoryStructure/CommonProjectStructure',
899
- 'xsi': 'http://www.w3.org/2001/XMLSchema-instance'}
900
- root: etree._ElementTree = etree.parse(codeunitfile)
901
- codeunit_file_version = root.xpath('//cps:codeunit/@codeunitspecificationversion', namespaces=namespaces)[0]
902
- supported_codeunitspecificationversion = "1.1.0"
903
- if codeunit_file_version != supported_codeunitspecificationversion:
904
- raise ValueError(f"ScriptCollection only supports processing codeunits with codeunit-specification-version={supported_codeunitspecificationversion}.")
905
- schemaLocation = root.xpath('//cps:codeunit/@xsi:schemaLocation', namespaces=namespaces)[0]
906
- xmlschema.validate(codeunitfile, schemaLocation)
907
-
908
- # Build dependent code units
909
- self.build_dependent_code_units(repository_folder, codeunitname, verbosity, target_environmenttype, additional_arguments_file)
910
-
911
- # Update version
912
- self.update_version_of_codeunit_to_project_version(common_tasks_scripts_file, version)
913
-
914
- # set default constants
915
- self.set_default_constants(os.path.join(repository_folder, codeunitname))
916
-
917
- # check for cycles in dependent code unitss
918
- # TODO implement codeunit-sycle-check
919
-
920
- # Check if changelog exists
921
- changelog_folder = os.path.join(repository_folder, "Other", "Resources", "Changelog")
922
- changelog_file = os.path.join(changelog_folder, f"v{version}.md")
923
- if not os.path.isfile(changelog_file):
924
- raise ValueError(f"Changelog-file '{changelog_file}' does not exist.")
925
-
926
- @GeneralUtilities.check_arguments
927
- def get_version_of_project(self, repository_folder: str):
928
- return ScriptCollectionCore().get_semver_version_from_gitversion(repository_folder)
929
-
930
- @GeneralUtilities.check_arguments
931
- def replace_common_variables_in_nuspec_file(self, codeunit_folder: str):
932
- codeunit_name = os.path.basename(codeunit_folder)
933
- version = self.get_version_of_codeunit_folder(codeunit_folder)
934
- nuspec_file = os.path.join(codeunit_folder, "Other", "Build", f"{codeunit_name}.nuspec")
935
- self.__sc.replace_version_in_nuspec_file(nuspec_file, version)
936
-
937
- @GeneralUtilities.check_arguments
938
- def standardized_tasks_build_for_node_project_in_common_project_structure(self, build_script_file: str,
939
- build_configuration: str, verbosity: int, commandline_arguments: list[str]):
940
- # TODO use unused parameter
941
- sc = ScriptCollectionCore()
942
- verbosity = self.get_verbosity_from_commandline_arguments(commandline_arguments, verbosity)
943
- sc.program_runner = ProgramRunnerEpew()
944
- build_script_folder = os.path.dirname(build_script_file)
945
- codeunit_folder = GeneralUtilities.resolve_relative_path("../..", build_script_folder)
946
- sc.run_program("npm", "run build", codeunit_folder)
947
-
948
- @GeneralUtilities.check_arguments
949
- def standardized_tasks_linting_for_node_project_in_common_project_structure(self, linting_script_file: str, verbosity: int,
950
- target_environmenttype: str, commandline_arguments: list[str]):
951
- # TODO use unused parameter
952
- sc = ScriptCollectionCore()
953
- verbosity = self.get_verbosity_from_commandline_arguments(commandline_arguments, verbosity)
954
- sc.program_runner = ProgramRunnerEpew()
955
- build_script_folder = os.path.dirname(linting_script_file)
956
- codeunit_folder = GeneralUtilities.resolve_relative_path("../..", build_script_folder)
957
- sc.run_program("npm", "run lint", codeunit_folder)
958
-
959
- @GeneralUtilities.check_arguments
960
- def standardized_tasks_run_testcases_for_node_project_in_common_project_structure(self, runtestcases_script_file: str,
961
- targetenvironmenttype: str, generate_badges: bool, verbosity: int,
962
- commandline_arguments: list[str]):
963
- # TODO really use targetenvironmenttype etc.
964
- sc = ScriptCollectionCore()
965
- verbosity = self.get_verbosity_from_commandline_arguments(commandline_arguments, verbosity)
966
- sc.program_runner = ProgramRunnerEpew()
967
- build_script_folder = os.path.dirname(runtestcases_script_file)
968
- codeunit_folder = GeneralUtilities.resolve_relative_path("../..", build_script_folder)
969
- sc.run_program("npm", "run test", codeunit_folder)
970
- coverage_folder = os.path.join(codeunit_folder, "Other", "Artifacts", "TestCoverage")
971
- target_file = os.path.join(coverage_folder, "TestCoverage.xml")
972
- GeneralUtilities.ensure_file_does_not_exist(target_file)
973
- os.rename(os.path.join(coverage_folder, "cobertura-coverage.xml"), target_file)
974
- repository_folder = GeneralUtilities.resolve_relative_path("..", codeunit_folder)
975
- codeunitname = os.path.basename(codeunit_folder)
976
- self.check_testcoverage_for_project_in_common_project_structure(target_file, repository_folder, codeunitname)
977
- self.standardized_tasks_generate_coverage_report(repository_folder, codeunitname, verbosity, generate_badges, targetenvironmenttype, commandline_arguments)
978
- self.update_path_of_source(repository_folder, codeunitname)
979
-
980
- @GeneralUtilities.check_arguments
981
- def do_npm_install(self, package_json_folder: str, verbosity: int):
982
- sc = ScriptCollectionCore()
983
- sc.program_runner = ProgramRunnerEpew()
984
- sc.run_program("npm", "install", package_json_folder, verbosity=verbosity)
985
-
986
- @GeneralUtilities. check_arguments
987
- def set_default_constants(self, codeunit_folder: str):
988
- self.set_constant_for_commitid(codeunit_folder)
989
- self.set_constant_for_commitdate(codeunit_folder)
990
-
991
- @GeneralUtilities. check_arguments
992
- def set_constant_for_commitid(self, codeunit_folder: str):
993
- commit_id = self.__sc.git_get_commit_id(codeunit_folder)
994
- self.set_constant(codeunit_folder, "commitid", commit_id)
995
-
996
- @GeneralUtilities. check_arguments
997
- def set_constant_for_commitdate(self, codeunit_folder: str):
998
- commit_date: datetime = self.__sc.git_get_commit_date(codeunit_folder)
999
- self.set_constant(codeunit_folder, "commitdate", GeneralUtilities.datetime_to_string(commit_date))
1000
-
1001
- @GeneralUtilities. check_arguments
1002
- def set_constant(self, codeunit_folder: str, constantname: str, constant_value: str, documentationsummary: str = None, constants_valuefile: str = None):
1003
- if documentationsummary is None:
1004
- documentationsummary = ""
1005
- constants_folder = os.path.join(codeunit_folder, "Other", "Resources", "Constants")
1006
- GeneralUtilities.ensure_directory_exists(constants_folder)
1007
- constants_metafile = os.path.join(constants_folder, f"{constantname}.constant.xml")
1008
- if constants_valuefile is None:
1009
- constants_valuefile_folder = constants_folder
1010
- constants_valuefile_name = f"{constantname}.value.xml"
1011
- constants_valuefiler_reference = f"./{constants_valuefile_name}"
1012
- else:
1013
- constants_valuefile_folder = os.path.dirname(constants_valuefile)
1014
- constants_valuefile_name = os.path.basename(constants_valuefile)
1015
- constants_valuefiler_reference = os.path.join(constants_valuefile_folder, constants_valuefile_name)
1016
-
1017
- # TODO implement usage of self.reference_latest_version_of_xsd_when_generating_xml
1018
- GeneralUtilities.write_text_to_file(constants_metafile, f"""<?xml version="1.0" encoding="UTF-8" ?>
1019
- <cps:constant xmlns:cps="https://projects.aniondev.de/PublicProjects/Common/ProjectTemplates/-/tree/main/Conventions/RepositoryStructure/CommonProjectStructure" constantspecificationversion="1.1.0"
1020
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://projects.aniondev.de/PublicProjects/Common/ProjectTemplates/-/raw/main/Conventions/RepositoryStructure/CommonProjectStructure/constant.xsd">
1021
- <cps:name>{constantname}</cps:name>
1022
- <cps:documentationsummary>{documentationsummary}</cps:documentationsummary>
1023
- <cps:path>{constants_valuefiler_reference}</cps:path>
1024
- </cps:constant>""")
1025
- # TODO validate generated xml against xsd
1026
- GeneralUtilities.write_text_to_file(os.path.join(constants_valuefile_folder, constants_valuefile_name), constant_value)
1027
-
1028
- @GeneralUtilities.check_arguments
1029
- def generate_openapi_file(self, buildscript_file: str, runtime: str) -> None:
1030
- codeunitname = os.path.basename(str(Path(os.path.dirname(buildscript_file)).parent.parent.absolute()))
1031
- repository_folder = str(Path(os.path.dirname(buildscript_file)).parent.parent.parent.absolute())
1032
- artifacts_folder = os.path.join(repository_folder, codeunitname, "Other", "Artifacts")
1033
- GeneralUtilities.ensure_directory_exists(os.path.join(artifacts_folder, "APISpecification"))
1034
- self.__sc.run_program("swagger", f"tofile --output APISpecification\\{codeunitname}.api.json BuildResult_DotNet_{runtime}\\{codeunitname}.dll v1", artifacts_folder)
1035
-
1036
- @GeneralUtilities.check_arguments
1037
- def replace_version_in_package_file(self: ScriptCollectionCore, package_json_file: str, version: str):
1038
- filename = package_json_file
1039
- with open(filename, 'r', encoding="utf-8") as f:
1040
- data = json.load(f)
1041
- data['version'] = version
1042
- os.remove(filename)
1043
- with open(filename, 'w', encoding="utf-8") as f:
1044
- json.dump(data, f, indent=2)
1045
-
1046
- @GeneralUtilities.check_arguments
1047
- def build_dependent_code_units(self, repo_folder: str, codeunit_name: str, verbosity: int, target_environmenttype: str, additional_arguments_file: str) -> None:
1048
- codeunit_file = os.path.join(repo_folder, codeunit_name, codeunit_name + ".codeunit.xml")
1049
- dependent_codeunits = self.get_dependent_code_units(codeunit_file)
1050
- dependent_codeunits_folder = os.path.join(repo_folder, codeunit_name, "Other", "Resources", "DependentCodeUnits")
1051
- GeneralUtilities.ensure_directory_does_not_exist(dependent_codeunits_folder)
1052
- if 0 < len(dependent_codeunits):
1053
- GeneralUtilities.write_message_to_stdout(f"Start building dependent codeunits for {codeunit_name}.")
1054
- for dependent_codeunit in dependent_codeunits:
1055
- other_folder = os.path.join(repo_folder, dependent_codeunit, "Other")
1056
- artifacts_folder = os.path.join(other_folder, "Artifacts")
1057
- self.build_codeunit(os.path.join(repo_folder, dependent_codeunit), verbosity, target_environmenttype, additional_arguments_file)
1058
- target_folder = os.path.join(dependent_codeunits_folder, dependent_codeunit)
1059
- GeneralUtilities.ensure_directory_does_not_exist(target_folder)
1060
- shutil.copytree(artifacts_folder, target_folder)
1061
- GeneralUtilities.write_message_to_stdout(f"Finished building dependent codeunits for {codeunit_name}.")
1062
-
1063
- @GeneralUtilities.check_arguments
1064
- def add_github_release(self, productname: str, version: str, build_artifacts_folder: str, github_username: str, repository_folder: str):
1065
- github_repo = f"{github_username}/{productname}"
1066
- artifacts_file = f"{build_artifacts_folder}\\{productname}\\{version}\\{productname}.v{version}.artifacts.zip"
1067
- release_title = f"Release v{version}"
1068
- changelog_file = os.path.join(repository_folder, "Other", "Resources", "Changelog", f"v{version}.md")
1069
- self.__sc.run_program_argsasarray("gh", ["release", "create", f"v{version}", "-R", github_repo,
1070
- artifacts_file, "-F", changelog_file, "-t", release_title])
1071
-
1072
- @GeneralUtilities.check_arguments
1073
- def create_archive_of_artifacts(self, project_name: str, version: str, build_artifacts_folder: str):
1074
- build_artifacts_folder_for_project = f"{build_artifacts_folder}\\{project_name}"
1075
- folder = f"{build_artifacts_folder_for_project}\\{version}"
1076
- filename_without_extension = f"{project_name}.v{version}.artifacts"
1077
- filename = f"{filename_without_extension}.zip"
1078
- GeneralUtilities.ensure_file_does_not_exist(filename)
1079
- shutil.make_archive(filename_without_extension, 'zip', folder)
1080
- shutil.move(filename, folder)
1081
-
1082
- @GeneralUtilities.check_arguments
1083
- def build_codeunits(self, repository_folder: str, verbosity: int = 1, target_environmenttype: str = "QualityCheck", additional_arguments_file: str = None) -> None:
1084
- codeunits = []
1085
- subfolders = GeneralUtilities.get_direct_folders_of_folder(repository_folder)
1086
- for subfolder in subfolders:
1087
- codeunit_name = os.path.basename(subfolder)
1088
- codeunit_file = os.path.join(subfolder, f"{codeunit_name}.codeunit.xml")
1089
- if os.path.exists(codeunit_file):
1090
- codeunits.append(codeunit_name)
1091
- # TODO set order (the "last" should be first to not overwrite its artifacts)
1092
- for codeunit in codeunits:
1093
- self.build_codeunit(os.path.join(repository_folder, codeunit), verbosity, target_environmenttype, additional_arguments_file)
1094
-
1095
- @GeneralUtilities.check_arguments
1096
- def build_codeunit(self, codeunit_folder: str, verbosity: int = 1, target_environmenttype: str = "QualityCheck", additional_arguments_file: str = None) -> None:
1097
- now = datetime.now()
1098
- codeunit_folder = GeneralUtilities.resolve_relative_path_from_current_working_directory(codeunit_folder)
1099
- codeunit_name: str = os.path.basename(codeunit_folder)
1100
- codeunit_file = os.path.join(codeunit_folder, f"{codeunit_name}.codeunit.xml")
1101
- if (not os.path.isfile(codeunit_file)):
1102
- raise ValueError(f'"{codeunit_folder}" is no codeunit-folder.')
1103
- artifacts_folder = os.path.join(codeunit_folder, "Other", "Artifacts")
1104
- GeneralUtilities.write_message_to_stdout(f"Start building codeunit {codeunit_name}.")
1105
- GeneralUtilities.write_message_to_stdout(f"Build-environmenttype: {target_environmenttype}")
1106
-
1107
- other_folder = os.path.join(codeunit_folder, "Other")
1108
- build_folder = os.path.join(other_folder, "Build")
1109
- quality_folder = os.path.join(other_folder, "QualityCheck")
1110
- reference_folder = os.path.join(other_folder, "Reference")
1111
- additional_arguments_c: str = ""
1112
- additional_arguments_b: str = ""
1113
- additional_arguments_r: str = ""
1114
- additional_arguments_l: str = ""
1115
- additional_arguments_g: str = ""
1116
- general_argument = f'--overwrite_verbosity={str(verbosity)} --overwrite_targetenvironmenttype={target_environmenttype}'
1117
- if additional_arguments_file is None:
1118
- c_additional_argument = ""
1119
- else:
1120
- config = configparser.ConfigParser()
1121
- config.read(additional_arguments_file)
1122
- section_name = f"{codeunit_name}_Configuration"
1123
- if config.has_option(section_name, "ArgumentsForCommonTasks"):
1124
- additional_arguments_c = config.get(section_name, "ArgumentsForCommonTasks")
1125
- if config.has_option(section_name, "ArgumentsForBuild"):
1126
- additional_arguments_b = config.get(section_name, "ArgumentsForBuild")
1127
- if config.has_option(section_name, "ArgumentsForRunTestcases"):
1128
- additional_arguments_r = config.get(section_name, "ArgumentsForRunTestcases")
1129
- if config.has_option(section_name, "ArgumentsForLinting"):
1130
- additional_arguments_l = config.get(section_name, "ArgumentsForLinting")
1131
- if config.has_option(section_name, "ArgumentsForGenerateReference"):
1132
- additional_arguments_g = config.get(section_name, "ArgumentsForGenerateReference")
1133
- c_additional_argument = f'--overwrite_additionalargumentsfile="{additional_arguments_file}"'
1134
-
1135
- GeneralUtilities.write_message_to_stdout('Run "CommonTasks.py"...')
1136
- self.__sc.run_program("python", f"CommonTasks.py {additional_arguments_c} {general_argument} {c_additional_argument}", other_folder, verbosity=verbosity)
1137
- GeneralUtilities.write_message_to_stdout('Run "Build.py"...')
1138
- self.__sc.run_program("python", f"Build.py {additional_arguments_b} {general_argument}", build_folder, verbosity=verbosity)
1139
- GeneralUtilities.write_message_to_stdout('Run "RunTestcases.py"...')
1140
- self.__sc.run_program("python", f"RunTestcases.py {additional_arguments_r} {general_argument}", quality_folder, verbosity=verbosity)
1141
- GeneralUtilities.write_message_to_stdout('Run "Linting.py"...')
1142
- self.__sc.run_program("python", f"Linting.py {additional_arguments_l} {general_argument}", quality_folder, verbosity=verbosity)
1143
- GeneralUtilities.write_message_to_stdout('Run "GenerateReference.py"...')
1144
- self.__sc.run_program("python", f"GenerateReference.py {additional_arguments_g} {general_argument}", reference_folder, verbosity=verbosity)
1145
-
1146
- artifactsinformation_file = os.path.join(artifacts_folder, f"{codeunit_name}.artifactsinformation.xml")
1147
- version = self.get_version_of_codeunit(codeunit_file)
1148
- GeneralUtilities.ensure_file_exists(artifactsinformation_file)
1149
- artifacts_list = []
1150
- for artifact_folder in GeneralUtilities.get_direct_folders_of_folder(artifacts_folder):
1151
- artifact_name = os.path.basename(artifact_folder)
1152
- artifacts_list.append(f" <cps:artifact>{artifact_name}<cps:artifact>")
1153
- artifacts = '\n'.join(artifacts_list)
1154
- moment = GeneralUtilities.datetime_to_string(now)
1155
- # TODO implement usage of self.reference_latest_version_of_xsd_when_generating_xml
1156
- GeneralUtilities.write_text_to_file(artifactsinformation_file, f"""<?xml version="1.0" encoding="UTF-8" ?>
1157
- <cps:artifactsinformation xmlns:cps="https://projects.aniondev.de/PublicProjects/Common/ProjectTemplates/-/tree/main/Conventions/RepositoryStructure/CommonProjectStructure" artifactsinformationspecificationversion="1.0.0"
1158
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://raw.githubusercontent.com/anionDev/ProjectTemplates/main/Templates/Conventions/RepositoryStructure/CommonProjectStructure/artifactsinformation.xsd">
1159
- <cps:name>{codeunit_name}</cps:name>
1160
- <cps:version>{version}</cps:version>
1161
- <cps:timestamp>{moment}</cps:timestamp>
1162
- <cps:targetenvironmenttype>{target_environmenttype}</cps:targetenvironmenttype>
1163
- <cps:artifacts>
1164
- {artifacts}
1165
- </cps:artifacts>
1166
- </cps:artifactsinformation>""")
1167
- # TODO validate artifactsinformation_file against xsd
1168
- shutil.copyfile(codeunit_file,
1169
- os.path.join(artifacts_folder, f"{codeunit_name}.codeunit.xml"))
1170
- GeneralUtilities.write_message_to_stdout(f"Finished building codeunit {codeunit_name}.")