spl-core 7.14.0__tar.gz → 7.14.0rc2.dev1__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 (72) hide show
  1. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/PKG-INFO +12 -13
  2. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/pyproject.toml +17 -17
  3. spl_core-7.14.0rc2.dev1/src/spl_core/__init__.py +1 -0
  4. spl_core-7.14.0rc2.dev1/src/spl_core/test_utils/artifacts_archiver.py +349 -0
  5. spl_core-7.14.0/src/spl_core/__init__.py +0 -1
  6. spl_core-7.14.0/src/spl_core/test_utils/artifacts_archiver.py +0 -654
  7. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/LICENSE +0 -0
  8. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/README.md +0 -0
  9. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/__run.py +0 -0
  10. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/common/__init__.py +0 -0
  11. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/common/path.py +0 -0
  12. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/common.cmake +0 -0
  13. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/conan.cmake +0 -0
  14. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/config/KConfig +0 -0
  15. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/gcov_maid/__init__.py +0 -0
  16. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/gcov_maid/gcov_maid.py +0 -0
  17. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kconfig/__init__.py +0 -0
  18. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kconfig/kconfig.py +0 -0
  19. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kconfig.cmake +0 -0
  20. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/__init__.py +0 -0
  21. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/create.py +0 -0
  22. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/application/.vscode/cmake-variants.json +0 -0
  23. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/application/KConfig +0 -0
  24. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/application/src/greeter/CMakeLists.txt +0 -0
  25. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/application/src/greeter/doc/_images/screenshot.png +0 -0
  26. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/application/src/greeter/doc/index.md +0 -0
  27. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/application/src/greeter/src/greeter.c +0 -0
  28. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/application/src/greeter/src/greeter.h +0 -0
  29. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/application/src/greeter/test/test_greeter.cc +0 -0
  30. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/application/src/main/CMakeLists.txt +0 -0
  31. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/application/src/main/doc/index.md +0 -0
  32. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/application/src/main/src/main.c +0 -0
  33. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/application/test/EnglishVariant/test__EnglishVariant.py +0 -0
  34. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/application/test/German/test__GermanVariant.py +0 -0
  35. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/application/variants/EnglishVariant/config.cmake +0 -0
  36. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/application/variants/EnglishVariant/parts.cmake +0 -0
  37. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/application/variants/GermanVariant/config.cmake +0 -0
  38. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/application/variants/GermanVariant/config.txt +0 -0
  39. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/application/variants/GermanVariant/parts.cmake +0 -0
  40. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/project/.gitignore +0 -0
  41. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/project/.vscode/cmake-kits.json +0 -0
  42. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/project/.vscode/extensions.json +0 -0
  43. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/project/.vscode/launch.json +0 -0
  44. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/project/.vscode/settings.json +0 -0
  45. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/project/.vscode/tasks.json +0 -0
  46. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/project/CMakeLists.txt +0 -0
  47. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/project/README.md +0 -0
  48. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/project/bootstrap.json +0 -0
  49. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/project/build.bat +0 -0
  50. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/project/build.ps1 +0 -0
  51. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/project/conf.py +0 -0
  52. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/project/doc/Doxyfile.in +0 -0
  53. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/project/doc/common/index.md +0 -0
  54. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/project/doc/components/index.md +0 -0
  55. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/project/doc/doxygen-awesome/LICENSE +0 -0
  56. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/project/doc/doxygen-awesome/doxygen-awesome.css +0 -0
  57. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/project/doc/software_architecture/index.md +0 -0
  58. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/project/doc/software_requirements/index.md +0 -0
  59. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/project/doc/test_report_template.txt +0 -0
  60. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/project/index.md +0 -0
  61. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/project/pypeline.yaml +0 -0
  62. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/project/pyproject.toml +0 -0
  63. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/project/pytest.ini +0 -0
  64. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/project/scoopfile.json +0 -0
  65. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/project/tools/toolchains/clang/toolchain.cmake +0 -0
  66. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/kickstart/templates/project/tools/toolchains/gcc/toolchain.cmake +0 -0
  67. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/main.py +0 -0
  68. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/spl.cmake +0 -0
  69. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/steps/collect_pr_changes.py +0 -0
  70. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/test_utils/archive_artifacts_collection.py +0 -0
  71. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/test_utils/base_variant_test_runner.py +0 -0
  72. {spl_core-7.14.0 → spl_core-7.14.0rc2.dev1}/src/spl_core/test_utils/spl_build.py +0 -0
@@ -1,45 +1,44 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: spl-core
3
- Version: 7.14.0
3
+ Version: 7.14.0rc2.dev1
4
4
  Summary: Software Product Line Support for CMake
5
5
  License: MIT
6
6
  License-File: LICENSE
7
7
  Author: Avengineers
8
8
  Author-email: karsten.guenther@kamg.de
9
- Requires-Python: >=3.10,<3.12
9
+ Requires-Python: >=3.11,<3.12
10
10
  Classifier: Development Status :: 2 - Pre-Alpha
11
11
  Classifier: Intended Audience :: Developers
12
12
  Classifier: License :: OSI Approved :: MIT License
13
13
  Classifier: Natural Language :: English
14
14
  Classifier: Operating System :: OS Independent
15
15
  Classifier: Programming Language :: Python :: 3
16
- Classifier: Programming Language :: Python :: 3.10
17
16
  Classifier: Programming Language :: Python :: 3.11
18
17
  Classifier: Topic :: Software Development :: Libraries
19
- Requires-Dist: cookiecutter (==2.6.0)
18
+ Requires-Dist: cookiecutter (>=2.6,<3.0)
20
19
  Requires-Dist: doxysphinx (>=3.3,<4.0)
21
20
  Requires-Dist: gcovr (>=8.3,<9.0)
22
21
  Requires-Dist: hammocking (>=0.8,<0.10)
23
22
  Requires-Dist: kconfiglib (>=14.1,<15.0)
24
- Requires-Dist: mlx-traceability (>=10,<12)
23
+ Requires-Dist: mlx-traceability (>=10,<13)
25
24
  Requires-Dist: myst-parser (>=0.16)
26
25
  Requires-Dist: py-app-dev (>=2.1,<3.0)
27
26
  Requires-Dist: py7zr (>=1.0.0,<2.0.0)
28
27
  Requires-Dist: pypeline-runner (>=1,<=2)
29
28
  Requires-Dist: pypeline-semantic-release (>=0.4.1,<=0.5.0)
30
- Requires-Dist: sphinx (>=7.3,<8.0)
29
+ Requires-Dist: sphinx (>=8.2,<9.0)
31
30
  Requires-Dist: sphinx-book-theme (>=1.1,<2.0)
32
31
  Requires-Dist: sphinx-copybutton (>=0.5,<0.6)
33
- Requires-Dist: sphinx-design (>=0.5,<0.7)
34
- Requires-Dist: sphinx-needs (>=2.0,<3.0)
35
- Requires-Dist: sphinx-new-tab-link (>=0.4,<0.9)
32
+ Requires-Dist: sphinx-design (>=0.5,<0.8)
33
+ Requires-Dist: sphinx-needs (>=2,<7)
34
+ Requires-Dist: sphinx-new-tab-link (>=0.4,<0.10)
36
35
  Requires-Dist: sphinx-rtd-size (>=0.2,<0.3)
37
- Requires-Dist: sphinx-rtd-theme (>=2.0,<3.0)
36
+ Requires-Dist: sphinx-rtd-theme (>=2,<4)
38
37
  Requires-Dist: sphinx-test-reports (>=1.0,<2.0)
39
38
  Requires-Dist: sphinxcontrib-datatemplates (>=0.11,<0.12)
40
- Requires-Dist: sphinxcontrib-mermaid (>=0.9,<0.10)
41
- Requires-Dist: sphinxcontrib-plantuml (>=0.29,<0.31)
42
- Requires-Dist: typer (>=0,<1)
39
+ Requires-Dist: sphinxcontrib-mermaid (>=1.1,<2.0)
40
+ Requires-Dist: sphinxcontrib-plantuml (>=0.29,<0.33)
41
+ Requires-Dist: typer (>=0.20,<0.21)
43
42
  Project-URL: Bug Tracker, https://github.com/avengineers/spl-core/issues
44
43
  Project-URL: Changelog, https://github.com/avengineers/spl-core/blob/develop/CHANGELOG.md
45
44
  Project-URL: Documentation, https://spl-core.readthedocs.io
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "spl-core"
3
- version = "7.14.0"
3
+ version = "7.14.0-rc2.dev.1"
4
4
  description = "Software Product Line Support for CMake"
5
5
  authors = ["Avengineers <karsten.guenther@kamg.de>"]
6
6
  license = "MIT"
@@ -24,37 +24,37 @@ please = "spl_core.main:main"
24
24
  "Changelog" = "https://github.com/avengineers/spl-core/blob/develop/CHANGELOG.md"
25
25
 
26
26
  [tool.poetry.dependencies]
27
- python = ">=3.10,<3.12"
27
+ python = ">=3.11,<3.12"
28
28
  py-app-dev = "^2.1"
29
- cookiecutter = "==2.6.0"
29
+ cookiecutter = "^2.6"
30
30
  gcovr = "^8.3"
31
31
  hammocking = ">=0.8,<0.10"
32
32
  kconfiglib = "^14.1"
33
- typer = "^0"
33
+ typer = "^0.20"
34
34
  doxysphinx = "^3.3"
35
- sphinx = "^7.3"
36
- sphinx-rtd-theme = "^2.0"
37
- sphinxcontrib-mermaid = "^0.9"
38
- sphinx-needs = "^2.0"
35
+ sphinx = "^8.2"
36
+ sphinx-rtd-theme = ">=2,<4"
37
+ sphinxcontrib-mermaid = "^1.1"
38
+ sphinx-needs = ">=2,<7"
39
39
  sphinx-test-reports = "^1.0"
40
40
  sphinx-rtd-size = "^0.2"
41
41
  sphinxcontrib-datatemplates = "^0.11"
42
- sphinxcontrib-plantuml = ">=0.29,<0.31"
42
+ sphinxcontrib-plantuml = ">=0.29,<0.33"
43
43
  sphinx-copybutton = "^0.5"
44
- sphinx-new-tab-link = ">=0.4,<0.9"
44
+ sphinx-new-tab-link = ">=0.4,<0.10"
45
45
  myst-parser = ">=0.16"
46
- mlx-traceability = ">=10,<12"
46
+ mlx-traceability = ">=10,<13"
47
47
  sphinx-book-theme = "^1.1"
48
- sphinx-design = ">=0.5,<0.7"
48
+ sphinx-design = ">=0.5,<0.8"
49
49
  pypeline-semantic-release = ">=0.4.1,<=0.5.0"
50
50
  pypeline-runner = ">=1,<=2"
51
51
  py7zr = "^1.0.0"
52
52
 
53
53
  [tool.poetry.group.dev.dependencies]
54
- pytest = ">=7,<9"
55
- pytest-cov = "^4.0"
56
- pre-commit = "^3.1.1"
57
- ruff = ">=0.5,<0.13"
54
+ pytest = ">=7,<11"
55
+ pytest-cov = ">=4,<9"
56
+ pre-commit = "^4.4"
57
+ ruff = ">=0.5,<0.20"
58
58
  jinja2 = "*"
59
59
  testfixtures = "*"
60
60
  junitparser = "*"
@@ -62,7 +62,7 @@ mashumaro = "*"
62
62
  loguru = "*"
63
63
  flake8 = "*"
64
64
  pipenv = "*"
65
- python-semantic-release = "^9.16.1"
65
+ python-semantic-release = "^9.21"
66
66
 
67
67
  [tool.semantic_release]
68
68
  version_toml = ["pyproject.toml:tool.poetry.version"]
@@ -0,0 +1 @@
1
+ __version__ = "7.14.0-rc2.dev.1"
@@ -0,0 +1,349 @@
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
+ @staticmethod
193
+ def calculate_retention_period(branch_name: str, is_tag: bool) -> int:
194
+ """
195
+ Calculate the retention period in days based on branch name or tag.
196
+
197
+ Args:
198
+ branch_name: The name of the branch
199
+ is_tag: Whether this is a tag build
200
+
201
+ Returns:
202
+ Retention period in days:
203
+ - 84 days for "develop" branch
204
+ - -1 (infinite) for release branches (release/*)
205
+ - -1 (infinite) for tags
206
+ - 28 days for everything else (PRs, feature branches, etc.)
207
+ """
208
+ if is_tag:
209
+ return -1 # Infinite retention for tags
210
+ elif branch_name == "develop":
211
+ return 84 # Length of a PI (Program Increment)
212
+ elif branch_name.startswith("release/"):
213
+ return -1 # Infinite retention for release branches
214
+ else:
215
+ return 28 # 4 weeks for PRs, feature branches, and other branches
216
+
217
+ def create_rt_upload_json(self, out_dir: Path) -> Path:
218
+ """
219
+ Create a single rt-upload.json file containing all archives.
220
+
221
+ This function replicates the logic from the Jenkinsfile for determining the RT_TARGET
222
+ and creating the upload specification file. It uses Jenkins environment variables
223
+ when available, otherwise falls back to default values.
224
+
225
+ Args:
226
+ output_dir: Directory where the rt-upload.json file will be created
227
+
228
+ Returns:
229
+ Path to the created rt-upload.json file
230
+ """
231
+ # Set local defaults first
232
+ change_id = None
233
+ branch_name = "local_branch"
234
+ build_number = "local_build"
235
+ is_tag = False
236
+
237
+ # Adapt values when Jenkins environment is detected
238
+ # TODO: check if an existing library can be used for CI context detection
239
+ if os.environ.get("JENKINS_URL"):
240
+ change_id = os.environ.get("CHANGE_ID")
241
+ jenkins_branch_name = os.environ.get("BRANCH_NAME")
242
+ jenkins_build_number = os.environ.get("BUILD_NUMBER")
243
+ tag_name = os.environ.get("TAG_NAME")
244
+
245
+ if change_id:
246
+ # Pull request case
247
+ branch_name = f"PR-{change_id}"
248
+ elif tag_name:
249
+ # Tag build case
250
+ branch_name = tag_name
251
+ is_tag = True
252
+ elif jenkins_branch_name:
253
+ # Regular branch case
254
+ branch_name = jenkins_branch_name
255
+
256
+ if jenkins_build_number:
257
+ build_number = jenkins_build_number
258
+
259
+ # Calculate retention period based on branch/tag
260
+ retention_period = self.calculate_retention_period(branch_name, is_tag)
261
+
262
+ # Create the files array for Artifactory upload format
263
+ files_array = []
264
+
265
+ for archive_name, archive in self.archives.items():
266
+ if archive_name in self._target_repos:
267
+ target_repo = self._target_repos[archive_name]
268
+
269
+ # Construct the RT target path
270
+ rt_target = f"{target_repo}/{branch_name}/{build_number}/"
271
+
272
+ # Add this archive to the files array with retention_period property
273
+ files_array.append(
274
+ {
275
+ "pattern": archive.archive_name,
276
+ "target": rt_target,
277
+ "recursive": "false",
278
+ "flat": "false",
279
+ "regexp": "false",
280
+ "props": f"retention_period={retention_period}",
281
+ }
282
+ )
283
+
284
+ # Create the single rt-upload.json file
285
+ json_path = out_dir / "rt-upload.json"
286
+
287
+ spec = {"files": files_array}
288
+
289
+ with open(json_path, "w") as f:
290
+ json.dump(spec, f, indent=4)
291
+
292
+ return json_path
293
+
294
+ def list_archives(self) -> List[str]:
295
+ """
296
+ Get a list of all archive names.
297
+
298
+ Returns:
299
+ List of archive names
300
+ """
301
+ return list(self.archives.keys())
302
+
303
+ def create_archive(self, archive_name: str = "default") -> Path:
304
+ """
305
+ Create a specific archive (convenience method for single-archive use case).
306
+
307
+ Args:
308
+ archive_name: Name of the archive to create (defaults to "default")
309
+
310
+ Returns:
311
+ Path to the created archive file
312
+
313
+ Raises:
314
+ KeyError: If the specified archive_name doesn't exist
315
+ """
316
+ if archive_name not in self.archives:
317
+ raise KeyError(f"Archive '{archive_name}' not found. Available archives: {list(self.archives.keys())}")
318
+
319
+ return self.archives[archive_name].create_archive()
320
+
321
+
322
+ # Example usage:
323
+ #
324
+ # ## Simple single-archive use case with target repo:
325
+ # archiver = ArtifactsArchiver()
326
+ # archiver.add_archive(Path("./build/output"), "results.7z", "my-repo/results") # uses "default" name
327
+ # archiver.register([Path("./build/test_report.xml"), Path("./build/coverage.html")]) # registers to "default"
328
+ # archive_path = archiver.create_archive() # creates the "default" archive
329
+ # upload_json = archiver.create_rt_upload_json(Path("./build/output"))
330
+ #
331
+ # ## Simple single-archive use case without target repo (archive only):
332
+ # archiver = ArtifactsArchiver()
333
+ # archiver.add_archive(Path("./build/output"), "results.7z") # no target repo, uses "default" name
334
+ # archiver.register([Path("./build/test_report.xml"), Path("./build/coverage.html")])
335
+ # archive_path = archiver.create_archive() # creates the "default" archive
336
+ # # upload_json = archiver.create_rt_upload_json(Path("./build/output")) # would create empty JSON
337
+ #
338
+ # ## Multi-archive use case:
339
+ # archiver = ArtifactsArchiver()
340
+ # archiver.add_archive(Path("./build/output"), "test_results.7z", "my-repo/test-results", "test_results")
341
+ # archiver.add_archive(Path("./build/output"), "coverage.7z", "my-repo/coverage", "coverage_reports")
342
+ # archiver.add_archive(Path("./build/output"), "docs.7z", None, "documentation") # no target repo for docs
343
+ #
344
+ # archiver.register([Path("./build/test_report.xml")], "test_results")
345
+ # archiver.register([Path("./build/coverage.html")], "coverage_reports")
346
+ # archiver.register([Path("./build/docs/")], "documentation")
347
+ #
348
+ # created_files = archiver.create_all_archives()
349
+ # upload_json = archiver.create_rt_upload_json(Path("./build/output")) # only includes archives with target repos
@@ -1 +0,0 @@
1
- __version__ = "7.14.0"