artefacts-cli 0.8.0__py3-none-any.whl → 0.9.2__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.
- artefacts/cli/__init__.py +67 -19
- artefacts/cli/app.py +196 -167
- artefacts/cli/app_containers.py +97 -25
- artefacts/cli/app_containers.pyi +3 -0
- artefacts/cli/bagparser.py +4 -0
- artefacts/cli/config.py +62 -0
- artefacts/cli/constants.py +7 -0
- artefacts/cli/containers/__init__.py +5 -5
- artefacts/cli/containers/docker_cm.py +175 -0
- artefacts/cli/containers/docker_utils.py +98 -0
- artefacts/cli/containers/utils.py +20 -8
- artefacts/cli/helpers.py +55 -0
- artefacts/cli/i18n.py +35 -0
- artefacts/cli/locales/art.pot +524 -0
- artefacts/cli/locales/base.pot +995 -0
- artefacts/cli/locales/click.pot +496 -0
- artefacts/cli/other.py +1 -0
- artefacts/cli/ros1.py +21 -6
- artefacts/cli/ros2.py +10 -3
- artefacts/cli/utils.py +8 -4
- artefacts/cli/utils_ros.py +35 -9
- artefacts/cli/version.py +2 -2
- artefacts/copava/__init__.py +1 -0
- {artefacts_cli-0.8.0.dist-info → artefacts_cli-0.9.2.dist-info}/METADATA +10 -3
- artefacts_cli-0.9.2.dist-info/RECORD +33 -0
- {artefacts_cli-0.8.0.dist-info → artefacts_cli-0.9.2.dist-info}/WHEEL +1 -1
- artefacts/cli/containers/docker.py +0 -119
- artefacts_cli-0.8.0.dist-info/RECORD +0 -24
- {artefacts_cli-0.8.0.dist-info → artefacts_cli-0.9.2.dist-info}/entry_points.txt +0 -0
- {artefacts_cli-0.8.0.dist-info → artefacts_cli-0.9.2.dist-info}/top_level.txt +0 -0
artefacts/cli/utils_ros.py
CHANGED
@@ -1,11 +1,18 @@
|
|
1
1
|
from junitparser import JUnitXml, Attr, Element
|
2
2
|
|
3
|
+
from artefacts.cli.i18n import localise
|
4
|
+
|
3
5
|
|
4
6
|
class FailureElement(Element):
|
5
7
|
_tag = "failure"
|
6
8
|
message = Attr()
|
7
9
|
|
8
10
|
|
11
|
+
class ErrorElement(Element):
|
12
|
+
_tag = "error"
|
13
|
+
message = Attr()
|
14
|
+
|
15
|
+
|
9
16
|
def get_TestSuite_error_result(test_suite_name, name, error_msg):
|
10
17
|
return {
|
11
18
|
"suite": test_suite_name,
|
@@ -15,8 +22,8 @@ def get_TestSuite_error_result(test_suite_name, name, error_msg):
|
|
15
22
|
"details": [
|
16
23
|
{
|
17
24
|
"name": name,
|
18
|
-
"
|
19
|
-
"result": "
|
25
|
+
"error_message": error_msg,
|
26
|
+
"result": "error",
|
20
27
|
}
|
21
28
|
],
|
22
29
|
}
|
@@ -36,13 +43,30 @@ def parse_tests_results(file):
|
|
36
43
|
case_details = {
|
37
44
|
"name": case.name,
|
38
45
|
}
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
46
|
+
|
47
|
+
test_result_found = False
|
48
|
+
|
49
|
+
# We look for failures or errors first
|
50
|
+
for element_class, result_status, message in [
|
51
|
+
(FailureElement, "failure", "failure_message"),
|
52
|
+
(ErrorElement, "error", "error_message"),
|
53
|
+
]:
|
54
|
+
try:
|
55
|
+
element = case.child(element_class)
|
56
|
+
case_details[message] = element.message
|
57
|
+
case_details["result"] = result_status
|
58
|
+
success = False
|
59
|
+
test_result_found = True
|
60
|
+
break
|
61
|
+
except AttributeError:
|
62
|
+
pass
|
63
|
+
|
64
|
+
# No Fail or Error = success
|
65
|
+
if not test_result_found:
|
44
66
|
case_details["result"] = "success"
|
67
|
+
|
45
68
|
details.append(case_details)
|
69
|
+
|
46
70
|
suite_results["details"] = details
|
47
71
|
results.append(suite_results)
|
48
72
|
|
@@ -64,8 +88,10 @@ def parse_tests_results(file):
|
|
64
88
|
return results, success
|
65
89
|
|
66
90
|
except Exception as e:
|
67
|
-
print(
|
68
|
-
|
91
|
+
print(
|
92
|
+
localise("[Exception in parse_tests_results] {message}".format(message=e))
|
93
|
+
)
|
94
|
+
print(localise("Test result xml could not be loaded, marking success as False"))
|
69
95
|
result = get_TestSuite_error_result(
|
70
96
|
"unittest.suite.TestSuite",
|
71
97
|
"Error parsing XML test results",
|
artefacts/cli/version.py
CHANGED
@@ -0,0 +1 @@
|
|
1
|
+
from artefacts_copava import *
|
@@ -1,26 +1,28 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: artefacts_cli
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.9.2
|
4
4
|
Author-email: FD <fabian@artefacts.com>, AGC <alejandro@artefacts.com>, TN <tomo@artefacts.com>, EP <eric@artefacts.com>
|
5
|
+
License-Expression: Apache-2.0
|
5
6
|
Project-URL: Homepage, https://github.com/art-e-fact/artefacts-client
|
6
7
|
Project-URL: Bug Tracker, https://github.com/art-e-fact/artefacts-client/issues
|
7
8
|
Project-URL: Changelog, https://github.com/art-e-fact/artefacts-client/CHANGELOG.md
|
8
9
|
Classifier: Programming Language :: Python :: 3
|
9
|
-
Classifier: License :: OSI Approved :: Apache Software License
|
10
10
|
Classifier: Operating System :: OS Independent
|
11
11
|
Requires-Python: >=3.8
|
12
12
|
Description-Content-Type: text/markdown
|
13
13
|
Requires-Dist: artefacts-c2d>=1.7.1
|
14
14
|
Requires-Dist: artefacts-copava>=0.1.11
|
15
|
-
Requires-Dist: click
|
15
|
+
Requires-Dist: artefacts-click
|
16
16
|
Requires-Dist: gitignore_parser>=0.1.11
|
17
17
|
Requires-Dist: junitparser>=2.5
|
18
18
|
Requires-Dist: mcap
|
19
19
|
Requires-Dist: mcap-ros2-support
|
20
20
|
Requires-Dist: PyYAML>=6.0
|
21
21
|
Requires-Dist: requests>=2.27.1
|
22
|
+
Requires-Dist: rospkg
|
22
23
|
Provides-Extra: dev
|
23
24
|
Requires-Dist: awscli; extra == "dev"
|
25
|
+
Requires-Dist: babel==2.17.0; extra == "dev"
|
24
26
|
Requires-Dist: build; extra == "dev"
|
25
27
|
Requires-Dist: docker; extra == "dev"
|
26
28
|
Requires-Dist: lark; extra == "dev"
|
@@ -37,6 +39,7 @@ Requires-Dist: pytest-env; extra == "dev"
|
|
37
39
|
Requires-Dist: pytest-mock; extra == "dev"
|
38
40
|
Requires-Dist: python-markdown-math; extra == "dev"
|
39
41
|
Requires-Dist: ruff>=0.9.2; extra == "dev"
|
42
|
+
Requires-Dist: setuptools_scm>=8; extra == "dev"
|
40
43
|
Requires-Dist: twine; extra == "dev"
|
41
44
|
|
42
45
|
# Artefacts CLI
|
@@ -102,3 +105,7 @@ mkdocs serve -a 127.0.0.1:7000
|
|
102
105
|
```
|
103
106
|
|
104
107
|
The docs are automatically deployed by the documentation workflow.
|
108
|
+
|
109
|
+
## Development notes
|
110
|
+
|
111
|
+
We use Pyre for static analysis. If it does not work out of the box, please consider adapting the `.pyre_configuration` file included with this repository. One assumption is that developers work in a virtual environment under `./venv`.
|
@@ -0,0 +1,33 @@
|
|
1
|
+
artefacts/__init__.py,sha256=VLmogtpRQeJjQjAORV8ClSJ5qF-57Hxx3apvgy9H1zk,76
|
2
|
+
artefacts/cli/__init__.py,sha256=H_HWGto-Emwy7YJwk0hqONKkq5oBTLqnlde85PDLg_Y,13554
|
3
|
+
artefacts/cli/app.py,sha256=EhRqZ8_8_sawYBtmObMNvq6wrpsHk-23W6SvbDFFUCc,25344
|
4
|
+
artefacts/cli/app_containers.py,sha256=oTWEAIE0m0nQQV7d33q75OL9-Bql0gDEnWGkmgCBnWE,8503
|
5
|
+
artefacts/cli/app_containers.pyi,sha256=3fBxcSppJr6EOEcUojvflG3Eegg7lv2Qp0dNQQILrP4,63
|
6
|
+
artefacts/cli/bagparser.py,sha256=aegvhIgwF-C1giGQWKB-cn0I2fW_iVamFwYm7YkfIyo,3738
|
7
|
+
artefacts/cli/config.py,sha256=_9j5yn_A3GF2pLdpORzrNIC78tfR64eFr_7QzypAOc8,2170
|
8
|
+
artefacts/cli/constants.py,sha256=l7xoXiKaZIpcn3JFwf5Tf5Kprfmf9x63AUfdTQQ3zGA,435
|
9
|
+
artefacts/cli/errors.py,sha256=BiCRo3IwVjtEotaFtmwsGTZiX-TRE69KqLrEQItLsag,34
|
10
|
+
artefacts/cli/helpers.py,sha256=OIoJcJzsGBpqSLE8pN5tEzPStC_nzYoZ0aP0NJ0jJsw,1335
|
11
|
+
artefacts/cli/i18n.py,sha256=qcTt_u1rdASzUfG1ANigGgqoqw3igt28AVO2VqFCV20,913
|
12
|
+
artefacts/cli/logger.py,sha256=PklhdEs-T8p9eogX7O_i6Gmw3v707y1Z0vgVwxBu96Q,792
|
13
|
+
artefacts/cli/other.py,sha256=c1rbtVkJ7DnmlPAf0bbkT_PNDcEoXbMqD2JIg_ShBaE,1391
|
14
|
+
artefacts/cli/parameters.py,sha256=msf2aG-tmw0ahxwrPpB2W6KqdMj5A-nw9DPG9flkHTg,788
|
15
|
+
artefacts/cli/ros1.py,sha256=tE6WK8SQZPPdWwFnOdIDTNv7chhr6AXY53gDYOEHJhY,9995
|
16
|
+
artefacts/cli/ros2.py,sha256=7iP7gtl7wLHo-7eIZPkFNRMHDrp5z-oexVmczed11Ks,8619
|
17
|
+
artefacts/cli/utils.py,sha256=-lMkPo5UtvnYG1D8NGnbOwO8jT4GXhYuwMxs29A393Q,4239
|
18
|
+
artefacts/cli/utils_ros.py,sha256=lOQSMtcRl3OHZ1t_dpZZnP5YdeydLBlcVNs9h91ZXa4,2845
|
19
|
+
artefacts/cli/version.py,sha256=eeYYTSIkrgfRwSQ7LKo_py3xs3DvzgfWiAtK4K1JM4A,511
|
20
|
+
artefacts/cli/containers/__init__.py,sha256=x3g6nz5TLRtF1bU0mlIN0aDd0Gwv3V3skE1aW9uVK5k,2274
|
21
|
+
artefacts/cli/containers/docker_cm.py,sha256=vOd6qoXc-WEA9ZXDkV-nHF7j5MXmaKFw8bz_qsdakqk,6480
|
22
|
+
artefacts/cli/containers/docker_utils.py,sha256=jGZJy0kapWnFwo5BBudtgI1gY9PXhLTgKCgecNsFUZ8,2966
|
23
|
+
artefacts/cli/containers/utils.py,sha256=O86S4SE-Ajd07f4GnwwFjqGQWu2s-KeB829DkWYJJbQ,2408
|
24
|
+
artefacts/cli/locales/art.pot,sha256=W3s62uHTSWPNAqmnZ9p_19npQW2oonoc28j8Bj96Eo0,13967
|
25
|
+
artefacts/cli/locales/base.pot,sha256=Pd3ojlQiqsbS3RXrFkJWckyepU3K10hEKBH0dIb5iHg,27188
|
26
|
+
artefacts/cli/locales/click.pot,sha256=nWt25hFB8_U87KeTIgSMucVZqw6mo8oQGrw3KvcFmVA,13852
|
27
|
+
artefacts/copava/__init__.py,sha256=rBf3JxQob2YHGnhuQPoMQQ06fzL-j2BCrLzqF_aZBSw,31
|
28
|
+
artefacts/wrappers/artefacts_ros1_meta.launch,sha256=9tN7_0xLH8jW27KYFerhF3NuWDx2dED3ks_qoGVZAPw,1412
|
29
|
+
artefacts_cli-0.9.2.dist-info/METADATA,sha256=e2L4g9PTOE72GRR1VTNRsM7YP9pdhouE6cBo750-npU,3529
|
30
|
+
artefacts_cli-0.9.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
31
|
+
artefacts_cli-0.9.2.dist-info/entry_points.txt,sha256=nlTXRzilNjccbi53FgaRWCQPkG-pv61HRkaCkrKjlec,58
|
32
|
+
artefacts_cli-0.9.2.dist-info/top_level.txt,sha256=FdaMV1C9m36MWa-2Stm5xVODv7hss_nRYNwR83j_7ow,10
|
33
|
+
artefacts_cli-0.9.2.dist-info/RECORD,,
|
@@ -1,119 +0,0 @@
|
|
1
|
-
from collections.abc import Generator
|
2
|
-
import json
|
3
|
-
import os
|
4
|
-
from pathlib import Path
|
5
|
-
import platform
|
6
|
-
from typing import Any, Tuple
|
7
|
-
from uuid import uuid4
|
8
|
-
|
9
|
-
from artefacts.cli.constants import DEFAULT_API_URL
|
10
|
-
from artefacts.cli.containers import CMgr
|
11
|
-
from artefacts.cli.utils import ensure_available
|
12
|
-
|
13
|
-
ensure_available("docker")
|
14
|
-
|
15
|
-
import docker # noqa: E402
|
16
|
-
from docker import APIClient # noqa: E402
|
17
|
-
|
18
|
-
|
19
|
-
class DockerManager(CMgr):
|
20
|
-
def __init__(self):
|
21
|
-
self.client = APIClient()
|
22
|
-
|
23
|
-
def build(self, **kwargs) -> Tuple[str, Generator]:
|
24
|
-
kwargs["tag"] = kwargs.pop("name")
|
25
|
-
# Ensure `path` is a string, the Docker package does not support pathlib.
|
26
|
-
kwargs["path"] = str(kwargs.pop("path"))
|
27
|
-
# Remove intermediate containers
|
28
|
-
kwargs["rm"] = True
|
29
|
-
logs = []
|
30
|
-
img_id = None
|
31
|
-
for entry in self.client.build(**kwargs):
|
32
|
-
line_data = [
|
33
|
-
json.loads(v) for v in entry.decode("utf-8").split("\r\n") if len(v) > 0
|
34
|
-
]
|
35
|
-
for data in line_data:
|
36
|
-
if "stream" in data:
|
37
|
-
line = data["stream"].strip()
|
38
|
-
if not line.startswith("---") and len(line) > 0:
|
39
|
-
print(f"[{kwargs['tag'].split('/')[-1]}] {line}")
|
40
|
-
logs.append(line)
|
41
|
-
elif "aux" in data and "ID" in data["aux"]:
|
42
|
-
img_id = data["aux"]["ID"]
|
43
|
-
if img_id is None:
|
44
|
-
img_id = self.client.inspect_image(kwargs["tag"])["Id"]
|
45
|
-
return img_id, iter(logs)
|
46
|
-
|
47
|
-
def check(
|
48
|
-
self,
|
49
|
-
image: str,
|
50
|
-
) -> bool:
|
51
|
-
return len(self.client.images(name=image)) > 0
|
52
|
-
|
53
|
-
def run(
|
54
|
-
self,
|
55
|
-
image: str,
|
56
|
-
project: str,
|
57
|
-
jobname: str = None,
|
58
|
-
artefacts_dir: str = Path("~/.artefacts").expanduser(),
|
59
|
-
api_url: str = DEFAULT_API_URL,
|
60
|
-
api_key: str = None,
|
61
|
-
with_gui: bool = False,
|
62
|
-
) -> Tuple[Any, Generator]:
|
63
|
-
"""
|
64
|
-
Run an application as an Artefacts-enabled container in a Docker engine
|
65
|
-
|
66
|
-
The arguments are considered straightforward, except the different
|
67
|
-
priorities between `artefacts_dir` and `api_key`:
|
68
|
-
* `api_key` has the highest priority. When specified, `artefacts_dir`
|
69
|
-
is ignored. The container will rely on the key as an environment
|
70
|
-
variable (ARTEFACTS_KEY).
|
71
|
-
* Whenever `api_key` is not provided, the container gets `artefacts_dir`
|
72
|
-
mounted as volume. The directory must contain a valid configuration
|
73
|
-
with the project's key.
|
74
|
-
"""
|
75
|
-
env = {
|
76
|
-
"JOB_ID": str(uuid4()),
|
77
|
-
"ARTEFACTS_JOB_NAME": jobname,
|
78
|
-
"ARTEFACTS_API_URL": api_url,
|
79
|
-
}
|
80
|
-
|
81
|
-
env["ARTEFACTS_KEY"] = self._get_artefacts_api_key(project, artefacts_dir)
|
82
|
-
if env["ARTEFACTS_KEY"] is None:
|
83
|
-
return None, iter(
|
84
|
-
[
|
85
|
-
f"Missing API key for the project. Does `{artefacts_dir}/config` exist and contain your key? Alternatively ARTEFACTS_KEY can be set with the key."
|
86
|
-
]
|
87
|
-
)
|
88
|
-
try:
|
89
|
-
if platform.system() in ["Darwin", "Windows"]:
|
90
|
-
# Assume we run in Docker Desktop
|
91
|
-
env["DISPLAY"] = "host.docker.internal:0"
|
92
|
-
else:
|
93
|
-
env["DISPLAY"] = os.environ.get("DISPLAY", ":0")
|
94
|
-
|
95
|
-
if not with_gui:
|
96
|
-
env["QT_QPA_PLATFORM"] = "offscreen"
|
97
|
-
|
98
|
-
container_conf = dict(
|
99
|
-
image=image,
|
100
|
-
environment=env,
|
101
|
-
detach=False,
|
102
|
-
host_config=self.client.create_host_config(
|
103
|
-
network_mode="host",
|
104
|
-
),
|
105
|
-
)
|
106
|
-
|
107
|
-
container = self.client.create_container(**container_conf)
|
108
|
-
self.client.start(container=container.get("Id"))
|
109
|
-
|
110
|
-
for entry in self.client.logs(container=container.get("Id"), stream=True):
|
111
|
-
print(entry.decode("utf-8").strip())
|
112
|
-
|
113
|
-
return container, iter([])
|
114
|
-
except docker.errors.ImageNotFound:
|
115
|
-
return None, iter(
|
116
|
-
[f"Image {image} not found by Docker. Perhaps need to build first?"]
|
117
|
-
)
|
118
|
-
except Exception as e:
|
119
|
-
return None, iter([f"Failed to run from {image}. All we know: {e}"])
|
@@ -1,24 +0,0 @@
|
|
1
|
-
artefacts/__init__.py,sha256=VLmogtpRQeJjQjAORV8ClSJ5qF-57Hxx3apvgy9H1zk,76
|
2
|
-
artefacts/cli/__init__.py,sha256=qIHUUf51UoviMtChkO5Qn-9ZzC5nH7vPE-QlqC30cRE,12080
|
3
|
-
artefacts/cli/app.py,sha256=2ogpU_zZuynCu3lz5Ai2PqFiVFiGVdBZojeD7qNZqyk,24831
|
4
|
-
artefacts/cli/app_containers.py,sha256=sRjm-z1Bbp81UE-GFrXv-0XiB6bCDsiMcsEOuT24dww,6413
|
5
|
-
artefacts/cli/bagparser.py,sha256=FE_QaztC9pg4hQzTjGSdyve6mzZbHJbyqa3wqvZSbxE,3702
|
6
|
-
artefacts/cli/constants.py,sha256=bvsVDwqkAc49IZN7j6k6IL6EG87bECHd_VINtKJqbv8,320
|
7
|
-
artefacts/cli/errors.py,sha256=BiCRo3IwVjtEotaFtmwsGTZiX-TRE69KqLrEQItLsag,34
|
8
|
-
artefacts/cli/logger.py,sha256=PklhdEs-T8p9eogX7O_i6Gmw3v707y1Z0vgVwxBu96Q,792
|
9
|
-
artefacts/cli/other.py,sha256=Jp15jLjttMk0JW15EAU5hgQNAkbX7vMGyjdWectehlw,1317
|
10
|
-
artefacts/cli/parameters.py,sha256=msf2aG-tmw0ahxwrPpB2W6KqdMj5A-nw9DPG9flkHTg,788
|
11
|
-
artefacts/cli/ros1.py,sha256=rKepZckAuy5O_qraF2CW5GiTmTZHar7LRD4pvESy6T0,9622
|
12
|
-
artefacts/cli/ros2.py,sha256=UMC1-6h0LhUhvXZist134WG18Tgm0y1DZeHqFNDOEKk,8495
|
13
|
-
artefacts/cli/utils.py,sha256=oy56o3N361srwhIvbMxwSPg8I_-tC7xcWtTSINTF2rE,4125
|
14
|
-
artefacts/cli/utils_ros.py,sha256=D6NSsF-5EfkQjCa6KAL7pFNRpu3JyH3nb0UEEz2SEqQ,2156
|
15
|
-
artefacts/cli/version.py,sha256=fSm5pLlwHxfTD7vBTVEqChJUua9ilUsdQYNN_V3u3iE,511
|
16
|
-
artefacts/cli/containers/__init__.py,sha256=K0efkJXNCqXH-qYBqhCE_8zVUCHbVmeuKH-y_fE8s4M,2254
|
17
|
-
artefacts/cli/containers/docker.py,sha256=R0yA-aIZCyYWN7gzim_Dhn1owpKI9ekMu6qbz5URYbQ,4311
|
18
|
-
artefacts/cli/containers/utils.py,sha256=bILX0uvazUJq7hoqKk4ztRzI_ZerYs04XQdKdx1ltjk,2002
|
19
|
-
artefacts/wrappers/artefacts_ros1_meta.launch,sha256=9tN7_0xLH8jW27KYFerhF3NuWDx2dED3ks_qoGVZAPw,1412
|
20
|
-
artefacts_cli-0.8.0.dist-info/METADATA,sha256=D2FpCO_zKGpEeeoRiUnaMLV5mcZS14Wu-rc4MpVq7zs,3183
|
21
|
-
artefacts_cli-0.8.0.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
22
|
-
artefacts_cli-0.8.0.dist-info/entry_points.txt,sha256=nlTXRzilNjccbi53FgaRWCQPkG-pv61HRkaCkrKjlec,58
|
23
|
-
artefacts_cli-0.8.0.dist-info/top_level.txt,sha256=FdaMV1C9m36MWa-2Stm5xVODv7hss_nRYNwR83j_7ow,10
|
24
|
-
artefacts_cli-0.8.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|