Skip to content

Commit 4d03e80

Browse files
committed
Issue #50 include openeo-api and openeo-process versions in reports
1 parent 2019ce4 commit 4d03e80

File tree

4 files changed

+242
-6
lines changed

4 files changed

+242
-6
lines changed

src/openeo_test_suite/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "0.2.0"
1+
__version__ = "0.2.1"

src/openeo_test_suite/lib/pytest_plugin.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import argparse
2+
import json
23
import shlex
34
import sys
5+
from pathlib import Path
46

57
import openeo
68
import pytest
@@ -14,6 +16,7 @@
1416
set_backend_under_test,
1517
)
1618
from openeo_test_suite.lib.process_selection import set_process_selection_from_config
19+
from openeo_test_suite.lib.version import get_openeo_versions
1720

1821

1922
def pytest_addoption(parser: pytest.Parser):
@@ -84,10 +87,12 @@ def pytest_configure(config: pytest.Config):
8487

8588
# Add some additional info to HTML report
8689
# https://pytest-html.readthedocs.io/en/latest/user_guide.html#environment
87-
config.stash[pytest_metadata.plugin.metadata_key]["Invocation"] = _invocation()
88-
config.stash[pytest_metadata.plugin.metadata_key][
89-
"openEO Test Suite version"
90-
] = openeo_test_suite.__version__
90+
config.stash[pytest_metadata.plugin.metadata_key].update(
91+
{
92+
"Invocation": _invocation(),
93+
"openEO versions": get_openeo_versions(),
94+
}
95+
)
9196

9297

9398
def _invocation() -> str:
@@ -99,7 +104,7 @@ def pytest_report_header(config: pytest.Config):
99104
"""Implementation of `pytest_report_header` hook."""
100105
# Add info to terminal report
101106
return [
102-
f"openEO Test Suite {openeo_test_suite.__version__}",
107+
f"openEO versions: {get_openeo_versions()}",
103108
f"Invoked with: {_invocation()}",
104109
]
105110

src/openeo_test_suite/lib/version.py

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
import json
2+
import logging
3+
import subprocess
4+
from pathlib import Path
5+
from typing import Dict, List, Optional, Union
6+
7+
import openeo_test_suite
8+
9+
_log = logging.getLogger(__name__)
10+
11+
12+
_ON_ERROR_IGNORE = "ignore"
13+
_ON_ERROR_WARN = "warn"
14+
_ON_ERROR_FAIL = "fail"
15+
16+
17+
# TODO: make this compatible with packaging?
18+
PROJECT_ROOT = Path(openeo_test_suite.__file__).parents[2]
19+
20+
21+
def get_openeo_versions() -> Dict[str, str]:
22+
return {
23+
"openeo-test-suite": get_openeo_test_suite_version(name_prefix=None),
24+
"openeo-api": get_openeo_api_spec_version(name_prefix=None),
25+
"openeo-processes": get_openeo_processes_spec_version(name_prefix=None),
26+
}
27+
28+
29+
def _join_non_empties(*parts: str, glue: str = " ") -> str:
30+
"""Join non-empty parts"""
31+
return glue.join(p for p in parts if p)
32+
33+
34+
def get_openeo_test_suite_version(
35+
*,
36+
name_prefix: Optional[str] = "openeo-test-suite",
37+
on_error: str = _ON_ERROR_WARN,
38+
git_describe: bool = True,
39+
) -> str:
40+
"""Build openeo-test-suite version, optionally with name prefix and git rev suffix (if possible)"""
41+
return _join_non_empties(
42+
name_prefix,
43+
openeo_test_suite.__version__,
44+
_git_describe(PROJECT_ROOT, on_error=on_error) if git_describe else None,
45+
)
46+
47+
48+
def get_openeo_api_spec_version(
49+
*,
50+
name_prefix: Optional[str] = "openeo-api",
51+
on_error: str = _ON_ERROR_WARN,
52+
git_describe: bool = True,
53+
) -> str:
54+
"""Build version of current openeo-api submodule, optionally with name prefix and git rev suffix (if possible)"""
55+
package_path = PROJECT_ROOT / "assets" / "openeo-api" / "package.json"
56+
return _join_non_empties(
57+
name_prefix,
58+
_get_js_package_version(package_path, on_error=on_error),
59+
_git_describe(package_path, on_error=on_error) if git_describe else None,
60+
)
61+
62+
63+
def get_openeo_processes_spec_version(
64+
*,
65+
name_prefix: Optional[str] = "openeo-processes",
66+
on_error: str = _ON_ERROR_WARN,
67+
git_describe: bool = True,
68+
) -> str:
69+
"""Build version of current openeo-processes submodule, optionally with name prefix and git rev suffix (if possible)"""
70+
package_path = PROJECT_ROOT / "assets" / "processes" / "dev" / "package.json"
71+
return _join_non_empties(
72+
name_prefix,
73+
_get_js_package_version(package_path, on_error=on_error),
74+
_git_describe(package_path, on_error=on_error) if git_describe else None,
75+
)
76+
77+
78+
def _get_js_package_version(
79+
package_path: Path, on_error: str = _ON_ERROR_WARN, default: str = "unknown"
80+
) -> str:
81+
"""
82+
Get version of a "package.json" JS project
83+
84+
:param package_path: path to package.json file
85+
"""
86+
try:
87+
package_metadata = json.loads(package_path.read_text())
88+
version = package_metadata["version"]
89+
except Exception as e:
90+
if on_error == _ON_ERROR_WARN:
91+
_log.warning(f"Failed to parse package version from {package_path}: {e}")
92+
elif on_error == _ON_ERROR_IGNORE:
93+
pass
94+
else:
95+
raise
96+
version = default
97+
return version
98+
99+
100+
def _git_describe(
101+
path: Path, *, wrap: str = "()", on_error: str = _ON_ERROR_WARN
102+
) -> Union[str, None]:
103+
"""
104+
Get short git rev description (possibly with "dirty" indicator), e.g. 'abc123' or 'abc123-dirty'
105+
"""
106+
try:
107+
if not path.is_dir():
108+
path = path.parent
109+
assert path.is_dir()
110+
command = ["git", "describe", "--always", "--dirty"]
111+
description = subprocess.check_output(command, cwd=path).strip().decode("utf-8")
112+
if wrap:
113+
description = f"{wrap[0]}{description}{wrap[-1]}"
114+
except Exception:
115+
if on_error == _ON_ERROR_WARN:
116+
_log.warning(f"Failed to git-describe {path}")
117+
elif on_error == _ON_ERROR_IGNORE:
118+
pass
119+
else:
120+
raise
121+
description = None
122+
return description
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import re
2+
import subprocess
3+
4+
import pytest
5+
6+
from openeo_test_suite.lib.version import (
7+
_ON_ERROR_FAIL,
8+
_ON_ERROR_IGNORE,
9+
_ON_ERROR_WARN,
10+
PROJECT_ROOT,
11+
_get_js_package_version,
12+
_git_describe,
13+
get_openeo_api_spec_version,
14+
get_openeo_processes_spec_version,
15+
get_openeo_test_suite_version,
16+
)
17+
18+
19+
def test_get_openeo_test_suite_version():
20+
assert re.fullmatch(
21+
r"openeo-test-suite [0-9.]+ \([0-9a-f]+(-dirty)?\)",
22+
get_openeo_test_suite_version(),
23+
)
24+
assert re.fullmatch(
25+
r"[0-9.]+ \([0-9a-f]+(-dirty)?\)",
26+
get_openeo_test_suite_version(name_prefix=None),
27+
)
28+
assert re.fullmatch(
29+
r"[0-9.]+", get_openeo_test_suite_version(name_prefix=None, git_describe=False)
30+
)
31+
32+
33+
def test_get_openeo_api_spec_version():
34+
assert re.fullmatch(
35+
r"openeo-api [0-9.a-z-]+ \([0-9a-f]+\)", get_openeo_api_spec_version()
36+
)
37+
assert re.fullmatch(
38+
r"[0-9.a-z-]+",
39+
get_openeo_api_spec_version(name_prefix=None, git_describe=False),
40+
)
41+
42+
43+
def test_get_openeo_processes_spec_version():
44+
assert re.fullmatch(
45+
r"openeo-processes [0-9.a-z-]+ \([0-9a-f]+\)",
46+
get_openeo_processes_spec_version(),
47+
)
48+
assert re.fullmatch(
49+
r"[0-9.a-z-]+",
50+
get_openeo_processes_spec_version(name_prefix=None, git_describe=False),
51+
)
52+
53+
54+
def test_get_js_package_version(tmp_path):
55+
path = tmp_path / "package.json"
56+
path.write_text('{"version":"1.2.3"}')
57+
assert _get_js_package_version(path) == "1.2.3"
58+
59+
60+
def test_get_js_package_version_on_error_default(tmp_path, caplog):
61+
path = tmp_path / "package.json"
62+
assert _get_js_package_version(path) == "unknown"
63+
assert "Failed to parse package version from" in caplog.text
64+
65+
66+
def test_get_js_package_version_on_error_ignore(tmp_path, caplog):
67+
path = tmp_path / "package.json"
68+
assert _get_js_package_version(path, on_error=_ON_ERROR_IGNORE) == "unknown"
69+
assert caplog.text == ""
70+
71+
72+
def test_get_js_package_version_on_error_warn(tmp_path, caplog):
73+
path = tmp_path / "package.json"
74+
assert _get_js_package_version(path, on_error=_ON_ERROR_WARN) == "unknown"
75+
assert "Failed to parse package version from" in caplog.text
76+
77+
78+
def test_get_js_package_version_on_error_fail(tmp_path, caplog):
79+
path = tmp_path / "package.json"
80+
with pytest.raises(FileNotFoundError):
81+
_ = _get_js_package_version(path, on_error=_ON_ERROR_FAIL)
82+
83+
84+
def test_git_describe():
85+
assert re.fullmatch(r"\([0-9a-f]+(-dirty)?\)", _git_describe(PROJECT_ROOT))
86+
87+
88+
def test_git_describe_wrap():
89+
assert re.fullmatch(r"<[0-9a-f]+(-dirty)?>", _git_describe(PROJECT_ROOT, wrap="<>"))
90+
91+
92+
def test_git_describe_on_error_default(tmp_path, caplog):
93+
assert _git_describe(tmp_path) is None
94+
assert "Failed to git-describe" in caplog.text
95+
96+
97+
def test_git_describe_on_error_ignore(tmp_path, caplog):
98+
assert _git_describe(tmp_path, on_error=_ON_ERROR_IGNORE) is None
99+
assert caplog.text == ""
100+
101+
102+
def test_git_describe_on_error_warn(tmp_path, caplog):
103+
assert _git_describe(tmp_path, on_error=_ON_ERROR_WARN) is None
104+
assert "Failed to git-describe" in caplog.text
105+
106+
107+
def test_git_describe_on_error_fail(tmp_path, caplog):
108+
with pytest.raises(subprocess.CalledProcessError):
109+
_ = _git_describe(tmp_path, on_error=_ON_ERROR_FAIL)

0 commit comments

Comments
 (0)