Skip to content

Commit 8b73108

Browse files
authored
Add z-stream support (#175)
1 parent db548fa commit 8b73108

File tree

9 files changed

+125
-42
lines changed

9 files changed

+125
-42
lines changed

apps/jira_utils/README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ pyutils-jira --help
1515
```
1616

1717
## Config file
18-
A config file with the jira connection parameters like url, token, resolved_statuses, skip_project_ids, target_versions should be passed to command line option `--cfg-file`
18+
A config file with the jira connection parameters like url, token, resolved_statuses, skip_project_ids,
19+
target_versions should be passed to command line option `--cfg-file`
1920

2021
### Example:
2122

@@ -33,6 +34,7 @@ pyutils-jira:
3334
target_versions:
3435
- 1.0.0
3536
- 2.0.1
37+
- 3.0.z
3638
issue_pattern: "([A-Z]+-[0-9]+)"
3739
version_string_not_targeted_jiras: "vfuture"
3840
```

apps/jira_utils/jira_information.py

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@
1818
LOGGER = get_logger(name=__name__)
1919

2020

21-
@retry(retry=retry_if_exception_type(JIRAError), stop=stop_after_attempt(3), wait=wait_fixed(2))
21+
@retry(
22+
retry=retry_if_exception_type(JIRAError),
23+
stop=stop_after_attempt(3),
24+
wait=wait_fixed(2),
25+
)
2226
@lru_cache
2327
def get_issue(
2428
jira: JIRA,
@@ -97,6 +101,8 @@ def get_jira_information(
97101
file_name: str,
98102
) -> tuple[str, str]:
99103
jira_error_string = ""
104+
re_compile = r"(?<![\d.])\d+\.\d+(?:\.(?:\d+|z))?\b"
105+
100106
try:
101107
# check resolved status:
102108
jira_issue_metadata = get_issue(jira=jira_object, jira_id=jira_id).fields
@@ -105,17 +111,20 @@ def get_jira_information(
105111
if current_jira_status in resolved_status:
106112
jira_error_string += f"{jira_id} current status: {current_jira_status} is resolved."
107113

108-
# validate correct target version if provided:
114+
# validate a correct target version if provided:
109115
if jira_target_versions:
110116
if skip_project_ids and jira_id.startswith(tuple(skip_project_ids)):
111117
return file_name, jira_error_string
112118

113-
fix_version = (
114-
re.search(r"([\d.]+)", jira_issue_metadata.fixVersions[0].name)
115-
if (jira_issue_metadata.fixVersions)
116-
else None
117-
)
118-
current_target_version = fix_version.group(1) if fix_version else target_version_str
119+
# If a bug has a fix version, extract it using regex
120+
if (jira_fix_versions := jira_issue_metadata.fixVersions) and (
121+
found_version := re.findall(re_compile, jira_fix_versions[0].name)
122+
):
123+
current_target_version = found_version[0]
124+
125+
else:
126+
current_target_version = target_version_str
127+
119128
if not any([current_target_version == version for version in jira_target_versions]):
120129
jira_error_string += (
121130
f"{jira_id} target version: {current_target_version}, does not match expected "
@@ -174,8 +183,18 @@ def process_jira_command_line_config_file(
174183
help="Provide comma separated list of Jira Project keys, against which version check should be skipped.",
175184
type=ListParamType(),
176185
)
177-
@click.option("--url", help="Provide the Jira server URL", type=click.STRING, default=os.getenv("JIRA_SERVER_URL"))
178-
@click.option("--token", help="Provide the Jira token.", type=click.STRING, default=os.getenv("JIRA_TOKEN"))
186+
@click.option(
187+
"--url",
188+
help="Provide the Jira server URL",
189+
type=click.STRING,
190+
default=os.getenv("JIRA_SERVER_URL"),
191+
)
192+
@click.option(
193+
"--token",
194+
help="Provide the Jira token.",
195+
type=click.STRING,
196+
default=os.getenv("JIRA_TOKEN"),
197+
)
179198
@click.option(
180199
"--issue-pattern",
181200
help="Provide the regex for Jira ids",
@@ -226,11 +245,15 @@ def get_jira_mismatch(
226245
target_versions=target_versions,
227246
)
228247

229-
jira_obj = JIRA(token_auth=jira_config_dict["token"], options={"server": jira_config_dict["url"]})
248+
jira_obj = JIRA(
249+
token_auth=jira_config_dict["token"],
250+
options={"server": jira_config_dict["url"]},
251+
)
230252
jira_error: dict[str, str] = {}
231253

232254
if jira_id_dict := get_jiras_from_python_files(
233-
issue_pattern=jira_config_dict["issue_pattern"], jira_url=jira_config_dict["url"]
255+
issue_pattern=jira_config_dict["issue_pattern"],
256+
jira_url=jira_config_dict["url"],
234257
):
235258
with concurrent.futures.ThreadPoolExecutor() as executor:
236259
for file_name, ids in jira_id_dict.items():

pyproject.toml

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ dependencies = [
1717
"tenacity>=9.0.0,<10",
1818
"python-simple-logger>=2.0.0,<3",
1919
"pyhelper-utils>=1.0.1,<2",
20-
"ast-comments>=1.2.2"
20+
"ast-comments>=1.2.2",
21+
"click (>=8.1.7)",
2122
]
2223

2324
[[project.authors]]
@@ -39,7 +40,7 @@ dependencies = [
3940
omit = [ "tests/*" ]
4041

4142
[tool.coverage.report]
42-
fail_under = 65
43+
fail_under = 68
4344
skip_empty = true
4445

4546
[tool.coverage.html]
@@ -55,6 +56,7 @@ include = [ "apps" ]
5556
[tool.hatch.build.targets.wheel]
5657
include = [ "apps" ]
5758

59+
5860
[tool.mypy]
5961
show_error_codes = true
6062
warn_unused_ignores = true
@@ -78,7 +80,12 @@ output-format = "grouped"
7880

7981
[dependency-groups]
8082
dev = [ "ipdb>=0.13.13,<0.14", "ipython" ]
81-
test = [ "pytest>=8.0.0,<9", "pytest-cov>=6.0.0,<7" ]
83+
test = [
84+
"ipdb>=0.13.13",
85+
"ipython>=8.18.1",
86+
"pytest>=8.0.0,<9",
87+
"pytest-cov>=6.0.0,<7",
88+
]
8289

8390
[build-system]
8491
requires = [ "hatchling" ]

renovate.json

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
11
{
22
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
3+
"extends": [
4+
":dependencyDashboard",
5+
":maintainLockFilesWeekly",
6+
":prHourlyLimitNone"
7+
],
8+
"prConcurrentLimit": 0,
9+
"lockFileMaintenance": {
10+
"enabled": true
11+
},
312
"packageRules": [
413
{
5-
"matchPackagePatterns": [
6-
"python-simple-logger",
7-
"pylero",
8-
"pyhelper-utils",
9-
"pytest-mock",
10-
"pyyaml",
11-
"ipdb",
12-
"ipython",
13-
"pytest",
14-
"pytest-cov"
15-
],
16-
"groupName": "poetry-deps"
14+
"matchPackagePatterns": ["*"],
15+
"groupName": "python-deps"
1716
}
1817
]
1918
}

tests/jira_utils/test_jira_utils.py

Lines changed: 54 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
)
1414

1515
LOGGER = get_logger(name=__name__)
16-
BASE_COMMAND = "poetry run python apps/jira_utils/jira_information.py --verbose "
16+
BASE_COMMAND = "uv run apps/jira_utils/jira_information.py --verbose "
1717

1818

1919
def test_process_jira_command_line_config_file_empty_config_token() -> None:
@@ -80,7 +80,16 @@ def test_process_jira_command_line_config_file_valid_config(mocker):
8080
# Test case 1: Issue with no jira target versions and not resolved status
8181
("issue1", ["resolved"], [], "1.0", "file1.txt", [], "", "1.0"),
8282
# Test case 2: Issue with no jira target versions, but resolved status
83-
("issue2", ["open"], [], "1.0", "file2.txt", [], "issue2 current status: open is resolved.", "1.0"),
83+
(
84+
"issue2",
85+
["open"],
86+
[],
87+
"1.0",
88+
"file2.txt",
89+
[],
90+
"issue2 current status: open is resolved.",
91+
"1.0",
92+
),
8493
# Test case 3: Issue with no jira target versions, default resolved status
8594
("issue3", [], [], "", "file3.txt", [], "", "1.1"),
8695
# Test case 4: Issue with not resolved state, but matching jira target version
@@ -99,7 +108,29 @@ def test_process_jira_command_line_config_file_valid_config(mocker):
99108
# Test case 6: Issue that would be skipped for version check because of skip
100109
("issue6", ["resolved"], ["1.0"], "1.0", "file6.txt", ["issue"], "", "1.1"),
101110
# Test case 7: Issue that would be skipped for version check but fail resolved check
102-
("issue7", ["open"], ["1.0"], "1.0", "file6.txt", ["issue"], "issue7 current status: open is resolved.", "1.1"),
111+
(
112+
"issue7",
113+
["open"],
114+
["1.0"],
115+
"1.0",
116+
"file6.txt",
117+
["issue"],
118+
"issue7 current status: open is resolved.",
119+
"1.1",
120+
),
121+
# Test case 8: Issue with unresolved state, and matching jira z target version
122+
("issue8", [], ["1.2.z"], "1.2,z", "file4.txt", [], "", "1.2.z"),
123+
# Test case 9: Issue with unresolved state, and jira z target version not matching expected versions
124+
(
125+
"issue8",
126+
[],
127+
["1.2.3"],
128+
"",
129+
"file4.txt",
130+
[],
131+
"issue8 target version: 1.2.z, does not match expected version ['1.2.3'].",
132+
"1.2.z",
133+
),
103134
],
104135
ids=[
105136
"test_no_jira_versions_no_resolved_status",
@@ -109,6 +140,8 @@ def test_process_jira_command_line_config_file_valid_config(mocker):
109140
"test_no_target_versions_not_resolved_state",
110141
"test_skip_version_check",
111142
"test_skip_version_check_fail_status_check",
143+
"test_matching_target_z_version",
144+
"test_non_matching_target_z_version",
112145
],
113146
)
114147
def test_get_jira_information(
@@ -131,8 +164,8 @@ def test_get_jira_information(
131164

132165
if jira_target_versions:
133166
mocker.patch(
134-
"apps.jira_utils.jira_information.re.search",
135-
return_value=mocker.MagicMock(group=lambda x: test_jira_version),
167+
"apps.jira_utils.jira_information.re.findall",
168+
return_value=[test_jira_version],
136169
)
137170
result = get_jira_information(
138171
jira_object=mock_jira,
@@ -160,10 +193,20 @@ def test_get_jira_information(
160193
@pytest.mark.parametrize(
161194
"content_and_expected",
162195
[
163-
pytest.param({"content": "pytest.mark.jira(ABC-1111)", "expected": {"ABC-1111"}}, id="pytest_mark_jira"),
164-
pytest.param({"content": "JIRA ID is jira_id=ABC-1111", "expected": {"ABC-1111"}}, id="jira_id="),
165196
pytest.param(
166-
{"content": "JIRA URL is https://example.com/browse/ABC-1111", "expected": {"ABC-1111"}}, id="jira_url="
197+
{"content": "pytest.mark.jira(ABC-1111)", "expected": {"ABC-1111"}},
198+
id="pytest_mark_jira",
199+
),
200+
pytest.param(
201+
{"content": "JIRA ID is jira_id=ABC-1111", "expected": {"ABC-1111"}},
202+
id="jira_id=",
203+
),
204+
pytest.param(
205+
{
206+
"content": "JIRA URL is https://example.com/browse/ABC-1111",
207+
"expected": {"ABC-1111"},
208+
},
209+
id="jira_url=",
167210
),
168211
pytest.param(
169212
{
@@ -184,6 +227,8 @@ def test_get_jira_information(
184227
)
185228
def test_get_jira_ids_from_file_content(content_and_expected):
186229
jira_ids = get_jira_ids_from_file_content(
187-
file_content=content_and_expected["content"], issue_pattern=r"([A-Z]+-[0-9]+)", jira_url="https://example.com"
230+
file_content=content_and_expected["content"],
231+
issue_pattern=r"([A-Z]+-[0-9]+)",
232+
jira_url="https://example.com",
188233
)
189234
assert jira_ids == content_and_expected["expected"]

tests/polarion/test_polarion_automated.py

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

44
from pyhelper_utils.shell import run_command
55

6-
BASE_COMMAND = "poetry run python apps/polarion/polarion_set_automated.py --verbose"
6+
BASE_COMMAND = "uv run apps/polarion/polarion_set_automated.py --verbose"
77

88

99
def test_missing_required_params_set_automated():

tests/polarion/test_verify_polarion_requirements.py

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

44
from pyhelper_utils.shell import run_command
55

6-
BASE_COMMAND = "poetry run python apps/polarion/polarion_verify_tc_requirements.py"
6+
BASE_COMMAND = "uv run apps/polarion/polarion_verify_tc_requirements.py"
77

88

99
def test_missing_project_id():

tox.ini

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
[tox]
2-
envlist = {python3.9,python3.10,python3.11,python3.12}-{unittest},
2+
envlist = 3.9, 3.1{0,1,2,3}
33
skipsdist = True
44

5-
65
[testenv]
76
setenv =
87
PYTHONPATH = {toxinidir}
98
deps =
109
uv
1110
commands =
12-
uv run pytest tests
11+
uv python pin python{envname}
12+
uv sync --locked --all-extras --dev --group test
13+
uv run pytest tests

uv.lock

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)