Skip to content

Commit 21624a9

Browse files
dbasunagrnetserpre-commit-ci[bot]
authored
base PR for set polarion as automated (#36)
* Revert "Revert "base PR for set polarion as automated (#30)" (#34)" This reverts commit 676b64b. * Update apps/polarion/polarion_set_automated.py Co-authored-by: Ruth Netser <[email protected]> * updates to review comments * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * use typing * coverage report percentage change * updates based on review comments --------- Co-authored-by: Ruth Netser <[email protected]> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 74bc3a6 commit 21624a9

File tree

9 files changed

+191
-51
lines changed

9 files changed

+191
-51
lines changed

apps/polarion/exceptions.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
class PolarionTestCaseApprovalError(Exception):
2+
pass
3+
4+
5+
class PolarionTestCaseWithoutRequirementError(Exception):
6+
pass
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
from __future__ import annotations
2+
import logging
3+
import os
4+
from simple_logger.logger import get_logger
5+
6+
import click
7+
8+
from apps.polarion.exceptions import PolarionTestCaseApprovalError
9+
from apps.polarion.polarion_utils import get_polarion_project_id, find_polarion_ids, update_polarion_ids
10+
from typing import List, Dict, Optional
11+
12+
13+
LOGGER = get_logger(name=__name__)
14+
15+
16+
def approve_tests(polarion_project_id: str, added_ids: List[str]) -> Dict[str, List[str]]:
17+
LOGGER.debug(f"Following polarion ids were added: {added_ids}")
18+
return update_polarion_ids(
19+
polarion_ids=list(added_ids), project_id=polarion_project_id, is_automated=True, is_approved=True
20+
)
21+
22+
23+
def remove_approved_tests(polarion_project_id: str, added_ids: Optional[List[str]] = None) -> Dict[str, List[str]]:
24+
removed_polarions = {}
25+
added_ids = added_ids or []
26+
if removed_ids := set(find_polarion_ids(polarion_project_id=polarion_project_id, string_to_match="removed")) - set(
27+
added_ids
28+
):
29+
LOGGER.info(f"Following polarion ids were removed: {removed_ids}")
30+
removed_polarions = update_polarion_ids(
31+
polarion_ids=list(removed_ids), project_id=polarion_project_id, is_automated=False
32+
)
33+
LOGGER.error(f"Following polarion ids marked not automated: {removed_polarions.get('updated')}")
34+
return removed_polarions
35+
36+
37+
@click.command()
38+
@click.option(
39+
"--config-file-path",
40+
help="Provide absolute path to the config file. Any CLI option(s) would override YAML file",
41+
type=click.Path(),
42+
default=os.path.expanduser("~/.config/python-utility-scripts/config.yaml"),
43+
)
44+
@click.option("--project-id", "-p", help="Provide the polarion project id")
45+
@click.option("--verbose", default=False, is_flag=True)
46+
def polarion_approve_automate(config_file_path: str, project_id: str, verbose: bool) -> None:
47+
if verbose:
48+
LOGGER.setLevel(logging.INFO)
49+
else:
50+
logging.disable(logging.ERROR)
51+
polarion_project_id = project_id or get_polarion_project_id(
52+
config_file_path=config_file_path, util_name="pyutils-polarion-set-automated"
53+
)
54+
added_polarions = {}
55+
if added_ids := find_polarion_ids(polarion_project_id=polarion_project_id, string_to_match="added"):
56+
added_polarions = approve_tests(polarion_project_id=polarion_project_id, added_ids=added_ids)
57+
LOGGER.info(f"Following polarion ids were marked automated and approved: {added_polarions.get('updated')}")
58+
59+
removed_polarions = remove_approved_tests(polarion_project_id=polarion_project_id, added_ids=added_ids)
60+
if removed_polarions.get("failed") or added_polarions.get("failed"):
61+
error = "Following polarion ids updates failed."
62+
if removed_polarions.get("failed"):
63+
error += f" Removed ids: {removed_polarions.get('failed')}."
64+
if added_polarions.get("failed"):
65+
error += f" Added ids:: {added_polarions.get('failed')}."
66+
LOGGER.error(error)
67+
raise PolarionTestCaseApprovalError(error)
68+
69+
70+
if __name__ == "__main__":
71+
polarion_approve_automate()

apps/polarion/polarion_utils.py

Lines changed: 72 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
1+
from __future__ import annotations
2+
import re
3+
4+
import click
15
from simple_logger.logger import get_logger
26
import shlex
37
import subprocess
4-
from pylero.exceptions import PyleroLibException
8+
9+
from apps.utils import get_util_config
510
from typing import Dict, List
611

712
LOGGER = get_logger(name=__name__)
13+
AUTOMATED = "automated"
14+
NOT_AUTOMATED = "notautomated"
15+
APPROVED = "approved"
816

917

1018
def git_diff() -> str:
@@ -15,33 +23,78 @@ def git_diff() -> str:
1523
def git_diff_lines() -> Dict[str, List[str]]:
1624
diff: Dict[str, List[str]] = {}
1725
for line in git_diff().splitlines():
18-
LOGGER.debug(line)
26+
LOGGER.info(line)
1927
if line.startswith("+"):
2028
diff.setdefault("added", []).append(line)
29+
if line.startswith("-"):
30+
diff.setdefault("removed", []).append(line)
2131
return diff
2232

2333

2434
def validate_polarion_requirements(
2535
polarion_test_ids: List[str],
2636
polarion_project_id: str,
2737
) -> List[str]:
28-
from pylero.work_item import TestCase, Requirement
29-
3038
tests_with_missing_requirements: List[str] = []
39+
if polarion_test_ids:
40+
from pylero.work_item import TestCase, Requirement
41+
from pylero.exceptions import PyleroLibException
3142

32-
for _id in polarion_test_ids:
33-
has_req = False
34-
LOGGER.debug(f"Checking if {_id} verifies any requirement")
35-
tc = TestCase(project_id=polarion_project_id, work_item_id=_id)
36-
for link in tc.linked_work_items:
37-
try:
38-
Requirement(project_id=polarion_project_id, work_item_id=link.work_item_id)
39-
has_req = True
40-
break
41-
except PyleroLibException:
42-
continue
43-
44-
if not has_req:
45-
LOGGER.error(f"{_id}: Is missing requirement")
46-
tests_with_missing_requirements.append(_id)
43+
for _id in polarion_test_ids:
44+
has_req = False
45+
LOGGER.info(f"Checking if {_id} verifies any requirement")
46+
tc = TestCase(project_id=polarion_project_id, work_item_id=_id)
47+
for link in tc.linked_work_items:
48+
try:
49+
Requirement(project_id=polarion_project_id, work_item_id=link.work_item_id)
50+
has_req = True
51+
break
52+
except PyleroLibException:
53+
continue
54+
55+
if not has_req:
56+
LOGGER.error(f"{_id}: Is missing requirement")
57+
tests_with_missing_requirements.append(_id)
4758
return tests_with_missing_requirements
59+
60+
61+
def find_polarion_ids(polarion_project_id: str, string_to_match: str) -> List[str]:
62+
return re.findall(
63+
rf"pytest.mark.polarion.*({polarion_project_id}-[0-9]+)",
64+
"\n".join(git_diff_lines().get(string_to_match, [])),
65+
re.MULTILINE | re.IGNORECASE,
66+
)
67+
68+
69+
def get_polarion_project_id(util_name: str, config_file_path: str) -> str:
70+
polarion_project_id = get_util_config(util_name=util_name, config_file_path=config_file_path).get("project_id")
71+
if not polarion_project_id:
72+
LOGGER.error("Polarion project id must be passed via config file or command line")
73+
raise click.Abort()
74+
return polarion_project_id
75+
76+
77+
def update_polarion_ids(
78+
project_id: str, is_automated: bool, polarion_ids: List[str], is_approved: bool = False
79+
) -> Dict[str, List[str]]:
80+
updated_ids: Dict[str, List[str]] = {}
81+
if polarion_ids:
82+
automation_status = AUTOMATED if is_automated else NOT_AUTOMATED
83+
84+
from pylero.work_item import TestCase
85+
from pylero.exceptions import PyleroLibException
86+
87+
for id in polarion_ids:
88+
try:
89+
tc = TestCase(project_id=project_id, work_item_id=id)
90+
tc.caseautomation = automation_status
91+
if is_approved:
92+
tc.status = APPROVED
93+
tc.update()
94+
LOGGER.info(f"Polarion {id}: marked as: {automation_status}, approved status set: {is_approved}")
95+
updated_ids.setdefault("updated", []).append(id)
96+
except PyleroLibException as polarion_exception:
97+
error = f"{id}: {polarion_exception}"
98+
LOGGER.error(error)
99+
updated_ids.setdefault("failed", []).append(error)
100+
return updated_ids

apps/polarion/polarion_verify_tc_requirements.py

Lines changed: 17 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
1-
import re
21
import logging
32
from simple_logger.logger import get_logger
43
import os
54
import click
6-
from apps.polarion.polarion_utils import (
7-
git_diff_lines,
8-
validate_polarion_requirements,
9-
)
10-
from apps.utils import get_util_config
5+
6+
from apps.polarion.exceptions import PolarionTestCaseWithoutRequirementError
7+
from apps.polarion.polarion_utils import validate_polarion_requirements, find_polarion_ids, get_polarion_project_id
118

129
LOGGER = get_logger(name="polarion-verify-tc-requirements")
1310

@@ -20,32 +17,24 @@
2017
default=os.path.expanduser("~/.config/python-utility-scripts/config.yaml"),
2118
)
2219
@click.option("--project-id", "-p", help="Provide the polarion project id")
23-
@click.option("--verbosity", default=False, is_flag=True)
24-
def has_verify(config_file_path: str, project_id: str, verbosity: bool) -> None:
25-
if verbosity:
26-
LOGGER.setLevel(logging.DEBUG)
27-
28-
polarion_project_id = project_id or get_util_config(
29-
util_name="pyutils-polarion-verify-tc-requirements",
30-
config_file_path=config_file_path,
31-
).get("project_id")
32-
33-
if not polarion_project_id:
34-
LOGGER.error("Polarion project id must be passed via config file or command line")
35-
raise click.Abort()
36-
37-
if added_ids := re.findall(
38-
rf"pytest.mark.polarion.*({polarion_project_id}-[0-9]+)",
39-
"\n".join(git_diff_lines().get("added", [])),
40-
re.MULTILINE | re.IGNORECASE,
41-
):
42-
LOGGER.debug(f"Checking following ids: {added_ids}")
20+
@click.option("--verbose", default=False, is_flag=True)
21+
def has_verify(config_file_path: str, project_id: str, verbose: bool) -> None:
22+
if verbose:
23+
LOGGER.setLevel(logging.INFO)
24+
else:
25+
logging.disable(logging.ERROR)
26+
polarion_project_id = project_id or get_polarion_project_id(
27+
config_file_path=config_file_path, util_name="pyutils-polarion-verify-tc-requirements"
28+
)
29+
if added_ids := find_polarion_ids(polarion_project_id=polarion_project_id, string_to_match="added"):
30+
LOGGER.info(f"Checking following ids: {added_ids}")
4331
if tests_with_missing_requirements := validate_polarion_requirements(
4432
polarion_test_ids=added_ids,
4533
polarion_project_id=polarion_project_id,
4634
):
47-
click.echo(f"TestCases with missing requirement: {tests_with_missing_requirements}")
48-
raise click.Abort()
35+
raise PolarionTestCaseWithoutRequirementError(
36+
f"TestCases with missing requirement: {tests_with_missing_requirements}"
37+
)
4938

5039

5140
if __name__ == "__main__":

config.example.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@ pyutils-unusedcode:
44
exclude_function_prefix:
55
- "my_exclude_function_prefix"
66
pyutils-polarion-verify-tc-requirements:
7-
project_id: "ABC"
7+
project_id: "ABCDEF"
8+
pyutils-polarion-set-automated:
9+
project_id: "ABCDEF"

poetry.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
omit = ["tests/*"]
33

44
[tool.coverage.report]
5-
fail_under = 75
5+
fail_under = 60
66
skip_empty = true
77

88
[tool.coverage.html]
@@ -47,6 +47,7 @@ packages = [{ include = "apps" }]
4747
[tool.poetry.scripts]
4848
pyutils-unusedcode = "apps.unused_code.unused_code:get_unused_functions"
4949
pyutils-polarion-verify-tc-requirements = "apps.polarion.polarion_verify_tc_requirements:has_verify"
50+
pyutils-polarion-set-automated = "apps.polarion.polarion_set_automated:polarion_approve_automate"
5051

5152
[tool.poetry.dependencies]
5253
python = "^3.8"
@@ -65,6 +66,7 @@ ipython = "*"
6566
enable = true
6667
pattern = "((?P<epoch>\\d+)!)?(?P<base>\\d+(\\.\\d+)*)"
6768

69+
6870
[tool.poetry.group.test.dependencies]
6971
pytest = "^8.0.0"
7072
pytest-cov = "^5.0.0"
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import shlex
2+
import subprocess
3+
from pyhelper_utils.shell import run_command
4+
5+
BASE_COMMAND = "poetry run python apps/polarion/polarion_set_automated.py --verbose"
6+
7+
8+
def test_missing_project_id_set_automated():
9+
rc, _, err = run_command(
10+
command=shlex.split(BASE_COMMAND),
11+
verify_stderr=False,
12+
check=False,
13+
capture_output=False,
14+
stderr=subprocess.PIPE,
15+
)
16+
assert "Polarion project id must be passed via config file or command line" in err
17+
assert not rc

tests/polarion/test_verify_polarion_requirements.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
def test_missing_project_id():
99
rc, _, err = run_command(
10-
command=shlex.split(BASE_COMMAND),
10+
command=shlex.split(f"{BASE_COMMAND} --verbose"),
1111
verify_stderr=False,
1212
check=False,
1313
capture_output=False,

0 commit comments

Comments
 (0)