spl-core 7.10.0__tar.gz → 7.11.1__tar.gz

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 (77) hide show
  1. {spl_core-7.10.0 → spl_core-7.11.1}/PKG-INFO +5 -3
  2. {spl_core-7.10.0 → spl_core-7.11.1}/pyproject.toml +3 -2
  3. spl_core-7.11.1/src/spl_core/__init__.py +1 -0
  4. spl_core-7.11.1/src/spl_core/kickstart/templates/application/src/greeter/doc/index.md +31 -0
  5. spl_core-7.10.0/src/spl_core/kickstart/templates/application/src/main/doc/index.rst → spl_core-7.11.1/src/spl_core/kickstart/templates/application/src/main/doc/index.md +7 -6
  6. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kickstart/templates/project/conf.py +20 -10
  7. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kickstart/templates/project/doc/Doxyfile.in +1 -1
  8. spl_core-7.11.1/src/spl_core/kickstart/templates/project/doc/common/index.md +3 -0
  9. spl_core-7.11.1/src/spl_core/kickstart/templates/project/doc/components/index.md +21 -0
  10. spl_core-7.11.1/src/spl_core/kickstart/templates/project/doc/software_architecture/index.md +3 -0
  11. spl_core-7.11.1/src/spl_core/kickstart/templates/project/doc/software_requirements/index.md +8 -0
  12. spl_core-7.11.1/src/spl_core/kickstart/templates/project/index.md +40 -0
  13. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kickstart/templates/project/pypeline.yaml +1 -0
  14. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kickstart/templates/project/pyproject.toml +7 -4
  15. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/spl.cmake +2 -1
  16. spl_core-7.11.1/src/spl_core/test_utils/artifacts_archiver.py +318 -0
  17. spl_core-7.10.0/src/spl_core/__init__.py +0 -1
  18. spl_core-7.10.0/src/spl_core/kickstart/templates/application/src/greeter/doc/index.rst +0 -26
  19. spl_core-7.10.0/src/spl_core/kickstart/templates/project/doc/common/index.rst +0 -5
  20. spl_core-7.10.0/src/spl_core/kickstart/templates/project/doc/components/index.rst +0 -22
  21. spl_core-7.10.0/src/spl_core/kickstart/templates/project/doc/software_architecture/index.rst +0 -2
  22. spl_core-7.10.0/src/spl_core/kickstart/templates/project/doc/software_requirements/index.rst +0 -7
  23. spl_core-7.10.0/src/spl_core/kickstart/templates/project/index.rst +0 -39
  24. {spl_core-7.10.0 → spl_core-7.11.1}/LICENSE +0 -0
  25. {spl_core-7.10.0 → spl_core-7.11.1}/README.md +0 -0
  26. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/__run.py +0 -0
  27. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/common/__init__.py +0 -0
  28. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/common/path.py +0 -0
  29. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/common.cmake +0 -0
  30. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/conan.cmake +0 -0
  31. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/config/KConfig +0 -0
  32. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/gcov_maid/__init__.py +0 -0
  33. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/gcov_maid/gcov_maid.py +0 -0
  34. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kconfig/__init__.py +0 -0
  35. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kconfig/kconfig.py +0 -0
  36. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kconfig.cmake +0 -0
  37. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kickstart/__init__.py +0 -0
  38. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kickstart/create.py +0 -0
  39. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kickstart/templates/application/.vscode/cmake-variants.json +0 -0
  40. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kickstart/templates/application/KConfig +0 -0
  41. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kickstart/templates/application/src/greeter/CMakeLists.txt +0 -0
  42. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kickstart/templates/application/src/greeter/doc/_images/screenshot.png +0 -0
  43. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kickstart/templates/application/src/greeter/src/greeter.c +0 -0
  44. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kickstart/templates/application/src/greeter/src/greeter.h +0 -0
  45. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kickstart/templates/application/src/greeter/test/test_greeter.cc +0 -0
  46. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kickstart/templates/application/src/main/CMakeLists.txt +0 -0
  47. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kickstart/templates/application/src/main/src/main.c +0 -0
  48. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kickstart/templates/application/test/EnglishVariant/test__EnglishVariant.py +0 -0
  49. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kickstart/templates/application/test/German/test__GermanVariant.py +0 -0
  50. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kickstart/templates/application/variants/EnglishVariant/config.cmake +0 -0
  51. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kickstart/templates/application/variants/EnglishVariant/parts.cmake +0 -0
  52. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kickstart/templates/application/variants/GermanVariant/config.cmake +0 -0
  53. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kickstart/templates/application/variants/GermanVariant/config.txt +0 -0
  54. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kickstart/templates/application/variants/GermanVariant/parts.cmake +0 -0
  55. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kickstart/templates/project/.gitignore +0 -0
  56. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kickstart/templates/project/.vscode/cmake-kits.json +0 -0
  57. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kickstart/templates/project/.vscode/extensions.json +0 -0
  58. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kickstart/templates/project/.vscode/launch.json +0 -0
  59. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kickstart/templates/project/.vscode/settings.json +0 -0
  60. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kickstart/templates/project/.vscode/tasks.json +0 -0
  61. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kickstart/templates/project/CMakeLists.txt +0 -0
  62. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kickstart/templates/project/README.md +0 -0
  63. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kickstart/templates/project/bootstrap.json +0 -0
  64. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kickstart/templates/project/build.bat +0 -0
  65. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kickstart/templates/project/build.ps1 +0 -0
  66. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kickstart/templates/project/doc/doxygen-awesome/LICENSE +0 -0
  67. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kickstart/templates/project/doc/doxygen-awesome/doxygen-awesome.css +0 -0
  68. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kickstart/templates/project/doc/test_report_template.txt +0 -0
  69. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kickstart/templates/project/pytest.ini +0 -0
  70. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kickstart/templates/project/scoopfile.json +0 -0
  71. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kickstart/templates/project/tools/toolchains/clang/toolchain.cmake +0 -0
  72. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/kickstart/templates/project/tools/toolchains/gcc/toolchain.cmake +0 -0
  73. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/main.py +0 -0
  74. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/steps/collect_pr_changes.py +0 -0
  75. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/test_utils/archive_artifacts_collection.py +0 -0
  76. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/test_utils/base_variant_test_runner.py +0 -0
  77. {spl_core-7.10.0 → spl_core-7.11.1}/src/spl_core/test_utils/spl_build.py +0 -0
@@ -1,8 +1,9 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: spl-core
3
- Version: 7.10.0
3
+ Version: 7.11.1
4
4
  Summary: Software Product Line Support for CMake
5
5
  License: MIT
6
+ License-File: LICENSE
6
7
  Author: Avengineers
7
8
  Author-email: karsten.guenther@kamg.de
8
9
  Requires-Python: >=3.10,<3.12
@@ -20,9 +21,10 @@ Requires-Dist: doxysphinx (>=3.3,<4.0)
20
21
  Requires-Dist: gcovr (>=8.3,<9.0)
21
22
  Requires-Dist: hammocking (>=0.8,<0.10)
22
23
  Requires-Dist: kconfiglib (>=14.1,<15.0)
23
- Requires-Dist: mlx-traceability (>=10.0,<11.0)
24
+ Requires-Dist: mlx-traceability (>=10,<12)
24
25
  Requires-Dist: myst-parser (>=0.16)
25
26
  Requires-Dist: py-app-dev (>=2.1,<3.0)
27
+ Requires-Dist: py7zr (>=1.0.0,<2.0.0)
26
28
  Requires-Dist: pypeline-runner (>=1,<=2)
27
29
  Requires-Dist: pypeline-semantic-release (>=0.4.1,<=0.5.0)
28
30
  Requires-Dist: sphinx (>=7.3,<8.0)
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "spl-core"
3
- version = "7.10.0"
3
+ version = "7.11.1"
4
4
  description = "Software Product Line Support for CMake"
5
5
  authors = ["Avengineers <karsten.guenther@kamg.de>"]
6
6
  license = "MIT"
@@ -43,11 +43,12 @@ sphinxcontrib-plantuml = ">=0.29,<0.31"
43
43
  sphinx-copybutton = "^0.5"
44
44
  sphinx-new-tab-link = ">=0.4,<0.9"
45
45
  myst-parser = ">=0.16"
46
- mlx-traceability = "^10.0"
46
+ mlx-traceability = ">=10,<12"
47
47
  sphinx-book-theme = "^1.1"
48
48
  sphinx-design = ">=0.5,<0.7"
49
49
  pypeline-semantic-release = ">=0.4.1,<=0.5.0"
50
50
  pypeline-runner = ">=1,<=2"
51
+ py7zr = "^1.0.0"
51
52
 
52
53
  [tool.poetry.group.dev.dependencies]
53
54
  pytest = ">=7,<9"
@@ -0,0 +1 @@
1
+ __version__ = "7.11.1"
@@ -0,0 +1,31 @@
1
+ # Software Detailed Design
2
+
3
+ ```{figure} _images/screenshot.png
4
+ ```
5
+
6
+ ```{mermaid}
7
+
8
+ graph TD
9
+ A[Start] --> B{Language}
10
+ B -->|DE| C[Hallo Welt]
11
+ B -->|EN| D[Hello World]
12
+
13
+ C --> E[End]
14
+ D --> E
15
+
16
+ ```
17
+
18
+ Requirements
19
+ ------------
20
+
21
+ ```{spec} Say Hello
22
+ :id: SWDD_GREETER-001
23
+ :integrity: QM
24
+
25
+ {% if config.LANG_DE %}
26
+ It shall greet the user with ``Hallo Welt``.
27
+ {% else %}
28
+ It shall greet the user with ``Hello World``.
29
+ {% endif %}
30
+
31
+ ```
@@ -1,11 +1,12 @@
1
- Software Detailed Design
2
- ========================
1
+ # Software Detailed Design
3
2
 
4
- .. contents:: Table of Contents
5
- :depth: 2
3
+ ```{toctree}
4
+ :maxdepth: 2
5
+ :caption: Table of Contents
6
+ :class: toc
7
+ ```
6
8
 
7
- Introduction
8
- ------------
9
+ ## Introduction
9
10
 
10
11
  This is the documentation for the ``Main`` component.
11
12
 
@@ -29,7 +29,7 @@ exclude_patterns = [
29
29
  "**/test_results.rst", # We renamed this file, but nobody deletes it.
30
30
  ]
31
31
 
32
- include_patterns = ["index.rst", "doc/**"]
32
+ include_patterns = ["index.md", "doc/**"]
33
33
 
34
34
  # configuration of built-in stuff ###########################################
35
35
  # @see https://www.sphinx-doc.org/en/master/usage/configuration.html
@@ -119,9 +119,7 @@ extensions.append("sphinxcontrib.datatemplates")
119
119
 
120
120
  # needs_types - this option allows the setup of own need types like bugs, user_stories and more.
121
121
  needs_types = [
122
- dict(
123
- directive="req", title="Requirement", prefix="R_", color="#BFD8D2", style="node"
124
- ),
122
+ dict(directive="req", title="Requirement", prefix="R_", color="#BFD8D2", style="node"),
125
123
  dict(
126
124
  directive="spec",
127
125
  title="Specification",
@@ -136,9 +134,7 @@ needs_types = [
136
134
  color="#DF744A",
137
135
  style="node",
138
136
  ),
139
- dict(
140
- directive="test", title="Test Case", prefix="T_", color="#DCB239", style="node"
141
- ),
137
+ dict(directive="test", title="Test Case", prefix="T_", color="#DCB239", style="node"),
142
138
  ]
143
139
 
144
140
  # Define own options
@@ -161,19 +157,33 @@ needs_global_options = {
161
157
  "results": "[[tr_link('title', 'case')]]",
162
158
  }
163
159
 
160
+ # Parse markdown files
161
+ extensions.append("myst_parser")
162
+ myst_enable_extensions = [
163
+ "colon_fence",
164
+ "deflist",
165
+ "html_admonition",
166
+ "html_image",
167
+ ]
168
+
169
+ # The suffix of source filenames.
170
+ source_suffix = [
171
+ ".rst",
172
+ ".md",
173
+ ]
174
+
164
175
  # Provide all config values to jinja
165
176
  html_context = {
166
177
  "build_config": {},
167
178
  "config": {},
179
+ "timestamp": f"{datetime.datetime.now(tz=datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')} UTC",
168
180
  }
169
181
 
170
182
  # pass build configuration to jinja
171
183
  if "SPHINX_BUILD_CONFIGURATION_FILE" in os.environ:
172
184
  with open(os.environ["SPHINX_BUILD_CONFIGURATION_FILE"], "r") as file:
173
185
  html_context["build_config"] = json.load(file)
174
- include_patterns.extend(
175
- html_context["build_config"].get("include_patterns", [])
176
- )
186
+ include_patterns.extend(html_context["build_config"].get("include_patterns", []))
177
187
 
178
188
  # pass feature configuration to jinja
179
189
  if "AUTOCONF_JSON_FILE" in os.environ:
@@ -2356,7 +2356,7 @@ INCLUDE_FILE_PATTERNS =
2356
2356
  # recursively expanded use the := operator instead of the = operator.
2357
2357
  # This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
2358
2358
 
2359
- PREDEFINED = "static_scope_file=static"
2359
+ PREDEFINED = "SPLE_TESTABLE_STATIC=static"
2360
2360
 
2361
2361
  # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
2362
2362
  # tag can be used to specify a list of macro names that should be expanded. The
@@ -0,0 +1,3 @@
1
+ # Common Documentation of the Project
2
+
3
+ Some text...
@@ -0,0 +1,21 @@
1
+ # Components
2
+
3
+ {% for component_info in build_config.components_info %}
4
+ {% if component_info.has_docs %}
5
+
6
+ ## {{ component_info.long_name or component_info.name }}
7
+
8
+ ```{toctree}
9
+ :maxdepth: 2
10
+
11
+ /{{ component_info.path }}/doc/index
12
+ {% if (build_config.target == 'reports') and component_info.has_reports %}
13
+ /{{ component_info.reports_output_dir }}/unit_test_spec
14
+ /{{ component_info.reports_output_dir }}/unit_test_results
15
+ /{{ component_info.reports_output_dir }}/doxygen/html/index
16
+ /{{ component_info.reports_output_dir }}/coverage
17
+ {% endif %}
18
+ ```
19
+
20
+ {% endif %}
21
+ {% endfor %}
@@ -0,0 +1,3 @@
1
+ # Software Architecture
2
+
3
+ Some text...
@@ -0,0 +1,8 @@
1
+ # Software Requirements
2
+
3
+ ```{req} Requirement 001
4
+ :status: open
5
+
6
+ This is a requirement.
7
+
8
+ ```
@@ -0,0 +1,40 @@
1
+ {% if build_config.component_info %}
2
+
3
+ # Software Component Report
4
+
5
+ **Variant:** {{ build_config.variant }}<br/>
6
+ **Component:** {{ build_config.component_info.long_name }}<br/>
7
+ **Timestamp:** {{ timestamp }}
8
+
9
+ ```{toctree}
10
+ :maxdepth: 2
11
+
12
+ {{ build_config.component_info.path }}/doc/index
13
+ {% if build_config.component_info.has_reports %}
14
+ {{ build_config.component_info.reports_output_dir }}/unit_test_spec
15
+ {{ build_config.component_info.reports_output_dir }}/unit_test_results
16
+ {{ build_config.component_info.reports_output_dir }}/doxygen/html/index
17
+ {{ build_config.component_info.reports_output_dir }}/coverage
18
+ {% endif %}
19
+ ```
20
+
21
+ {% else %}
22
+
23
+ # Variant Report
24
+
25
+ **Variant:** {{ build_config.variant }}<br/>
26
+ **Timestamp:** {{ timestamp }}
27
+
28
+ ```{toctree}
29
+ :maxdepth: 1
30
+ :caption: Contents
31
+
32
+ doc/software_architecture/index
33
+ doc/software_requirements/index
34
+ doc/components/index
35
+ {% if build_config.target == 'reports' %}
36
+ {{ build_config.reports_output_dir }}/coverage
37
+ {% endif %}
38
+ ```
39
+
40
+ {% endif %}
@@ -3,6 +3,7 @@ pipeline:
3
3
  module: pypeline.steps.create_venv
4
4
  config:
5
5
  bootstrap_script: .bootstrap/bootstrap.py
6
+ python_executable: python311
6
7
  - step: ScoopInstall
7
8
  module: pypeline.steps.scoop_install
8
9
  - step: GenerateEnvSetupScript
@@ -2,17 +2,20 @@
2
2
  name = "spled"
3
3
  version = "0.0.1"
4
4
  description = "SPL demo project"
5
- authors = [
6
- {name = "Avengineers"},
7
- ]
5
+ authors = [{ name = "Avengineers" }]
8
6
  requires-python = "<3.12,>=3.10"
9
7
 
10
8
  dependencies = [
11
- "spl-core>=7,<8",
9
+ "spl-core (>=7,<8)",
12
10
  "pypeline-runner>=1,<2",
13
11
  "pytest>=8,<9",
14
12
  "pip_system_certs>=4.0,<5",
13
+ "myst-parser>=4.0,<5",
14
+ "pypeline-semantic-release (>=0.4.1,<0.5.0)",
15
15
  ]
16
16
 
17
17
  [tool.poetry]
18
18
  package-mode = false
19
+
20
+ [tool.ruff]
21
+ line-length = 180
@@ -110,7 +110,8 @@ endfunction(_spl_hook_end_of_configure)
110
110
  set(_CONFIGURATION_TARGET configuration.stamp)
111
111
  add_custom_command(
112
112
  OUTPUT ${_CONFIGURATION_TARGET}
113
- COMMAND set "KCONFIG_CONFIG=${CMAKE_SOURCE_DIR}/variants/${VARIANT}/config.txt" && cd ${CMAKE_SOURCE_DIR} && guiconfig
113
+ COMMAND ${CMAKE_COMMAND} -E env KCONFIG_CONFIG=${CMAKE_SOURCE_DIR}/variants/${VARIANT}/config.txt VARIANT=${VARIANT} guiconfig
114
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
114
115
  )
115
116
 
116
117
  add_custom_target(configuration DEPENDS ${_CONFIGURATION_TARGET})
@@ -0,0 +1,318 @@
1
+ import json
2
+ import os
3
+ from dataclasses import dataclass
4
+ from pathlib import Path
5
+ from typing import Dict, List, Optional
6
+
7
+ import py7zr
8
+
9
+
10
+ class ArtifactsArchive:
11
+ """
12
+ This class represents a single archive containing artifacts.
13
+ It collects artifacts to be packed and archived.
14
+
15
+ Currently supports 7z and Artifactory.
16
+ """
17
+
18
+ @dataclass
19
+ class ArchiveArtifact:
20
+ """
21
+ Represents a single artifact to be archived.
22
+ This class holds the archive path (relative to the output directory of the 7z archive)
23
+ and the absolute path of the artifact.
24
+ It is used to ensure that artifacts are correctly archived with their intended paths.
25
+ """
26
+
27
+ archive_path: Path
28
+ absolute_path: Path
29
+
30
+ def __init__(self, out_dir: Path, archive_name: str) -> None:
31
+ self.out_dir: Path = out_dir
32
+ self.archive_name: str = archive_name
33
+ self.archive_artifacts: List[ArtifactsArchive.ArchiveArtifact] = []
34
+
35
+ def register(self, artifacts: List[Path]) -> None:
36
+ """
37
+ Register artifacts for archiving.
38
+ Args:
39
+ artifacts: List of paths to artifacts (files or directories) to be archived.
40
+ """
41
+ for artifact in artifacts:
42
+ self._add_artifact(artifact)
43
+
44
+ def _add_artifact(self, artifact_path: Path) -> None:
45
+ """
46
+ Add an artifact (file or directory) to the archive list.
47
+ Args:
48
+ artifact_path: path to the artifact to be archived.
49
+ """
50
+ # Convert to absolute path first
51
+ absolute_path = artifact_path.resolve() if not artifact_path.is_absolute() else artifact_path
52
+
53
+ # Calculate the relative path from out_dir for the archive
54
+ if absolute_path.is_relative_to(self.out_dir.absolute()):
55
+ archive_path = absolute_path.relative_to(self.out_dir.absolute())
56
+ else:
57
+ # If not relative to out_dir, just use the name
58
+ archive_path = Path(absolute_path.name)
59
+
60
+ self.archive_artifacts.append(
61
+ self.ArchiveArtifact(
62
+ archive_path=archive_path,
63
+ absolute_path=absolute_path,
64
+ )
65
+ )
66
+
67
+ def create_archive(self) -> Path:
68
+ """
69
+ Create a 7z file containing the collected artifacts.
70
+ Returns:
71
+ Path: The path to the created 7z file.
72
+ Raises:
73
+ Exception: If there is an error creating the 7z file.
74
+ """
75
+ # Construct the full archive path
76
+ archive_path = self.out_dir / self.archive_name
77
+
78
+ # Create output directory if it doesn't exist
79
+ archive_path.parent.mkdir(parents=True, exist_ok=True)
80
+
81
+ # Delete the file if it already exists
82
+ if archive_path.exists():
83
+ archive_path.unlink()
84
+
85
+ if not self.archive_artifacts:
86
+ print("Warning: No artifacts registered for archiving")
87
+ # Create empty 7z file
88
+ with py7zr.SevenZipFile(archive_path, "w") as archive:
89
+ pass
90
+ return archive_path
91
+
92
+ try:
93
+ with py7zr.SevenZipFile(archive_path, "w") as archive:
94
+ for artifact in self.archive_artifacts:
95
+ if not artifact.absolute_path.exists():
96
+ print(f"Warning: Artifact {artifact.absolute_path} does not exist, skipping")
97
+ continue
98
+
99
+ try:
100
+ if artifact.absolute_path.is_file():
101
+ archive.write(artifact.absolute_path, arcname=str(artifact.archive_path))
102
+ elif artifact.absolute_path.is_dir():
103
+ # py7zr can handle directories directly
104
+ archive.writeall(artifact.absolute_path, arcname=str(artifact.archive_path))
105
+ except Exception as file_error:
106
+ print(f"Warning: Failed to add {artifact.absolute_path} to archive: {file_error}")
107
+ continue
108
+
109
+ print(f"7z file created at: {archive_path}")
110
+ return archive_path
111
+ except Exception as e:
112
+ print(f"Error creating artifacts 7z file: {e}")
113
+ raise e
114
+
115
+
116
+ class ArtifactsArchiver:
117
+ """
118
+ This class manages multiple ArtifactsArchive instances.
119
+ It provides a unified interface for registering artifacts to different archives.
120
+ """
121
+
122
+ def __init__(self) -> None:
123
+ self.archives: Dict[str, ArtifactsArchive] = {}
124
+ self._target_repos: Dict[str, str] = {}
125
+
126
+ def add_archive(self, out_dir: Path, archive_filename: str, target_repo: Optional[str] = None, archive_name: str = "default") -> ArtifactsArchive:
127
+ """
128
+ Add a new archive to the archiver.
129
+
130
+ Args:
131
+ out_dir: Output directory for the archive
132
+ archive_filename: Filename for the archive
133
+ target_repo: Target repository path for Artifactory upload (optional)
134
+ archive_name: Name identifier for the archive (defaults to "default")
135
+
136
+ Returns:
137
+ The created ArtifactsArchive instance
138
+ """
139
+ archive = ArtifactsArchive(out_dir, archive_filename)
140
+ self.archives[archive_name] = archive
141
+ # Store the target repo information for this archive only if provided
142
+ if target_repo is not None:
143
+ self._target_repos[archive_name] = target_repo
144
+ return archive
145
+
146
+ def register(self, artifacts: List[Path], archive_name: str = "default") -> None:
147
+ """
148
+ Register artifacts for archiving to a specific archive.
149
+
150
+ Args:
151
+ artifacts: List of paths to artifacts (files or directories) to be archived.
152
+ archive_name: Name of the archive to register artifacts to (defaults to "default")
153
+
154
+ Raises:
155
+ KeyError: If the specified archive_name doesn't exist
156
+ """
157
+ if archive_name not in self.archives:
158
+ raise KeyError(f"Archive '{archive_name}' not found. Available archives: {list(self.archives.keys())}")
159
+
160
+ self.archives[archive_name].register(artifacts)
161
+
162
+ def get_archive(self, archive_name: str) -> ArtifactsArchive:
163
+ """
164
+ Get a specific archive by name.
165
+
166
+ Args:
167
+ archive_name: Name of the archive to retrieve
168
+
169
+ Returns:
170
+ The ArtifactsArchive instance
171
+
172
+ Raises:
173
+ KeyError: If the specified archive_name doesn't exist
174
+ """
175
+ if archive_name not in self.archives:
176
+ raise KeyError(f"Archive '{archive_name}' not found. Available archives: {list(self.archives.keys())}")
177
+
178
+ return self.archives[archive_name]
179
+
180
+ def create_all_archives(self) -> Dict[str, Path]:
181
+ """
182
+ Create all registered archives.
183
+
184
+ Returns:
185
+ Dictionary mapping archive names to their created file paths
186
+ """
187
+ created_archives = {}
188
+ for archive_name, archive in self.archives.items():
189
+ created_archives[archive_name] = archive.create_archive()
190
+ return created_archives
191
+
192
+ def create_rt_upload_json(self, out_dir: Path) -> Path:
193
+ """
194
+ Create a single rt-upload.json file containing all archives.
195
+
196
+ This function replicates the logic from the Jenkinsfile for determining the RT_TARGET
197
+ and creating the upload specification file. It uses Jenkins environment variables
198
+ when available, otherwise falls back to default values.
199
+
200
+ Args:
201
+ output_dir: Directory where the rt-upload.json file will be created
202
+
203
+ Returns:
204
+ Path to the created rt-upload.json file
205
+ """
206
+ # Set local defaults first
207
+ change_id = None
208
+ branch_name = "local_branch"
209
+ build_number = "local_build"
210
+
211
+ # Adapt values when Jenkins environment is detected
212
+ # TODO: check if an existing library can be used for CI context detection
213
+ if os.environ.get("JENKINS_URL"):
214
+ change_id = os.environ.get("CHANGE_ID")
215
+ jenkins_branch_name = os.environ.get("BRANCH_NAME")
216
+ jenkins_build_number = os.environ.get("BUILD_NUMBER")
217
+ tag_name = os.environ.get("TAG_NAME")
218
+
219
+ if change_id:
220
+ # Pull request case
221
+ branch_name = f"PR-{change_id}"
222
+ elif tag_name:
223
+ # Tag build case
224
+ branch_name = tag_name
225
+ elif jenkins_branch_name:
226
+ # Regular branch case
227
+ branch_name = jenkins_branch_name
228
+
229
+ if jenkins_build_number:
230
+ build_number = jenkins_build_number
231
+
232
+ # Create the files array for Artifactory upload format
233
+ files_array = []
234
+
235
+ for archive_name, archive in self.archives.items():
236
+ if archive_name in self._target_repos:
237
+ target_repo = self._target_repos[archive_name]
238
+
239
+ # Construct the RT target path
240
+ rt_target = f"{target_repo}/{branch_name}/{build_number}/"
241
+
242
+ # Add this archive to the files array
243
+ files_array.append(
244
+ {
245
+ "pattern": archive.archive_name,
246
+ "target": rt_target,
247
+ "recursive": "false",
248
+ "flat": "false",
249
+ "regexp": "false",
250
+ }
251
+ )
252
+
253
+ # Create the single rt-upload.json file
254
+ json_path = out_dir / "rt-upload.json"
255
+
256
+ spec = {"files": files_array}
257
+
258
+ with open(json_path, "w") as f:
259
+ json.dump(spec, f, indent=4)
260
+
261
+ return json_path
262
+
263
+ def list_archives(self) -> List[str]:
264
+ """
265
+ Get a list of all archive names.
266
+
267
+ Returns:
268
+ List of archive names
269
+ """
270
+ return list(self.archives.keys())
271
+
272
+ def create_archive(self, archive_name: str = "default") -> Path:
273
+ """
274
+ Create a specific archive (convenience method for single-archive use case).
275
+
276
+ Args:
277
+ archive_name: Name of the archive to create (defaults to "default")
278
+
279
+ Returns:
280
+ Path to the created archive file
281
+
282
+ Raises:
283
+ KeyError: If the specified archive_name doesn't exist
284
+ """
285
+ if archive_name not in self.archives:
286
+ raise KeyError(f"Archive '{archive_name}' not found. Available archives: {list(self.archives.keys())}")
287
+
288
+ return self.archives[archive_name].create_archive()
289
+
290
+
291
+ # Example usage:
292
+ #
293
+ # ## Simple single-archive use case with target repo:
294
+ # archiver = ArtifactsArchiver()
295
+ # archiver.add_archive(Path("./build/output"), "results.7z", "my-repo/results") # uses "default" name
296
+ # archiver.register([Path("./build/test_report.xml"), Path("./build/coverage.html")]) # registers to "default"
297
+ # archive_path = archiver.create_archive() # creates the "default" archive
298
+ # upload_json = archiver.create_rt_upload_json(Path("./build/output"))
299
+ #
300
+ # ## Simple single-archive use case without target repo (archive only):
301
+ # archiver = ArtifactsArchiver()
302
+ # archiver.add_archive(Path("./build/output"), "results.7z") # no target repo, uses "default" name
303
+ # archiver.register([Path("./build/test_report.xml"), Path("./build/coverage.html")])
304
+ # archive_path = archiver.create_archive() # creates the "default" archive
305
+ # # upload_json = archiver.create_rt_upload_json(Path("./build/output")) # would create empty JSON
306
+ #
307
+ # ## Multi-archive use case:
308
+ # archiver = ArtifactsArchiver()
309
+ # archiver.add_archive(Path("./build/output"), "test_results.7z", "my-repo/test-results", "test_results")
310
+ # archiver.add_archive(Path("./build/output"), "coverage.7z", "my-repo/coverage", "coverage_reports")
311
+ # archiver.add_archive(Path("./build/output"), "docs.7z", None, "documentation") # no target repo for docs
312
+ #
313
+ # archiver.register([Path("./build/test_report.xml")], "test_results")
314
+ # archiver.register([Path("./build/coverage.html")], "coverage_reports")
315
+ # archiver.register([Path("./build/docs/")], "documentation")
316
+ #
317
+ # created_files = archiver.create_all_archives()
318
+ # upload_json = archiver.create_rt_upload_json(Path("./build/output")) # only includes archives with target repos
@@ -1 +0,0 @@
1
- __version__ = "7.10.0"
@@ -1,26 +0,0 @@
1
- Software Detailed Design
2
- ========================
3
-
4
- .. figure:: _images/screenshot.png
5
-
6
- .. mermaid::
7
-
8
- graph TD
9
- A[Start] --> B{Language}
10
- B -->|DE| C[Hallo Welt]
11
- B -->|EN| D[Hello World]
12
- C --> E[End]
13
- D --> E
14
-
15
- Requirements
16
- ------------
17
-
18
- .. spec:: Say Hello
19
- :id: SWDD_GREETER-001
20
- :integrity: QM
21
-
22
- {% if config.LANG_DE %}
23
- It shall greet the user with ``Hallo Welt``.
24
- {% else %}
25
- It shall greet the user with ``Hello World``.
26
- {% endif %}
@@ -1,5 +0,0 @@
1
- Common Documentation of the Project
2
- ===================================
3
-
4
-
5
- Some text...
@@ -1,22 +0,0 @@
1
- Components
2
- ==========
3
-
4
- {% for component_info in build_config.components_info %}
5
- {% if component_info.has_docs %}
6
-
7
- {{ component_info.long_name or component_info.name }}
8
- -----------------------------------------------------
9
-
10
- .. toctree::
11
- :maxdepth: 2
12
-
13
- /{{ component_info.path }}/doc/index
14
- {% if (build_config.target == 'reports') and component_info.has_reports %}
15
- /{{ component_info.reports_output_dir }}/unit_test_results
16
- /{{ component_info.reports_output_dir }}/doxygen/html/index
17
- /{{ component_info.reports_output_dir }}/coverage
18
- {% endif %}
19
-
20
-
21
- {% endif %}
22
- {% endfor %}
@@ -1,2 +0,0 @@
1
- Software Architecture
2
- =====================
@@ -1,7 +0,0 @@
1
- Software Requirements
2
- #####################
3
-
4
- .. req:: Requirement 001
5
- :status: open
6
-
7
- ...
@@ -1,39 +0,0 @@
1
- {% if build_config.component_info %}
2
-
3
- Software Component Report
4
- #########################
5
-
6
- | **Variant:** {{ build_config.variant }}
7
- | **Component:** {{ build_config.component_info.long_name }}
8
-
9
- .. toctree::
10
- :maxdepth: 2
11
-
12
- {{ build_config.component_info.path }}/doc/index
13
- {% if build_config.component_info.has_reports %}
14
- {{ build_config.component_info.reports_output_dir }}/unit_test_spec
15
- {{ build_config.component_info.reports_output_dir }}/unit_test_results
16
- {{ build_config.component_info.reports_output_dir }}/doxygen/html/index
17
- {{ build_config.component_info.reports_output_dir }}/coverage
18
- {% endif %}
19
-
20
- {% else %}
21
-
22
- Variant Report
23
- ##############
24
-
25
- **Variant:** {{ build_config.variant }}
26
-
27
- .. toctree::
28
- :maxdepth: 1
29
- :caption: Contents
30
-
31
- doc/software_requirements/index
32
- doc/software_architecture/index
33
- doc/components/index
34
- {% if build_config.target == 'reports' %}
35
- {{ build_config.reports_output_dir }}/coverage
36
- {% endif %}
37
- doc/results/index
38
-
39
- {% endif %}
File without changes
File without changes