testit-cli 2.10.0.post580__tar.gz → 2.10.2.post580__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.
- testit_cli-2.10.2.post580/PKG-INFO +146 -0
- testit_cli-2.10.2.post580/README.md +113 -0
- {testit_cli-2.10.0.post580 → testit_cli-2.10.2.post580}/setup.py +2 -2
- {testit_cli-2.10.0.post580 → testit_cli-2.10.2.post580}/src/testit_cli/apiclient.py +20 -2
- {testit_cli-2.10.0.post580 → testit_cli-2.10.2.post580}/src/testit_cli/click_commands.py +27 -3
- {testit_cli-2.10.0.post580 → testit_cli-2.10.2.post580}/src/testit_cli/converter.py +4 -2
- {testit_cli-2.10.0.post580 → testit_cli-2.10.2.post580}/src/testit_cli/models/config.py +4 -0
- {testit_cli-2.10.0.post580 → testit_cli-2.10.2.post580}/src/testit_cli/models/testrun.py +2 -1
- testit_cli-2.10.2.post580/src/testit_cli/models/testrun_link.py +10 -0
- {testit_cli-2.10.0.post580 → testit_cli-2.10.2.post580}/src/testit_cli/service.py +27 -1
- testit_cli-2.10.2.post580/src/testit_cli/testrun_metadata.py +131 -0
- testit_cli-2.10.2.post580/src/testit_cli.egg-info/PKG-INFO +146 -0
- {testit_cli-2.10.0.post580 → testit_cli-2.10.2.post580}/src/testit_cli.egg-info/SOURCES.txt +4 -1
- testit_cli-2.10.2.post580/src/testit_cli.egg-info/requires.txt +4 -0
- testit_cli-2.10.2.post580/tests/test_testrun_metadata.py +151 -0
- testit_cli-2.10.0.post580/PKG-INFO +0 -65
- testit_cli-2.10.0.post580/README.md +0 -32
- testit_cli-2.10.0.post580/src/testit_cli.egg-info/PKG-INFO +0 -65
- testit_cli-2.10.0.post580/src/testit_cli.egg-info/requires.txt +0 -4
- {testit_cli-2.10.0.post580 → testit_cli-2.10.2.post580}/LICENSE +0 -0
- {testit_cli-2.10.0.post580 → testit_cli-2.10.2.post580}/setup.cfg +0 -0
- {testit_cli-2.10.0.post580 → testit_cli-2.10.2.post580}/src/testit_cli/__init__.py +0 -0
- {testit_cli-2.10.0.post580 → testit_cli-2.10.2.post580}/src/testit_cli/__main__.py +0 -0
- {testit_cli-2.10.0.post580 → testit_cli-2.10.2.post580}/src/testit_cli/autotests_filter.py +0 -0
- {testit_cli-2.10.0.post580 → testit_cli-2.10.2.post580}/src/testit_cli/dir_worker.py +0 -0
- {testit_cli-2.10.0.post580 → testit_cli-2.10.2.post580}/src/testit_cli/file_worker.py +0 -0
- {testit_cli-2.10.0.post580 → testit_cli-2.10.2.post580}/src/testit_cli/filter_factory.py +0 -0
- {testit_cli-2.10.0.post580 → testit_cli-2.10.2.post580}/src/testit_cli/html_escape_utils.py +0 -0
- {testit_cli-2.10.0.post580 → testit_cli-2.10.2.post580}/src/testit_cli/http_retry.py +0 -0
- {testit_cli-2.10.0.post580 → testit_cli-2.10.2.post580}/src/testit_cli/importer.py +0 -0
- {testit_cli-2.10.0.post580 → testit_cli-2.10.2.post580}/src/testit_cli/logger.py +0 -0
- {testit_cli-2.10.0.post580 → testit_cli-2.10.2.post580}/src/testit_cli/models/__init__.py +0 -0
- {testit_cli-2.10.0.post580 → testit_cli-2.10.2.post580}/src/testit_cli/models/mode.py +0 -0
- {testit_cli-2.10.0.post580 → testit_cli-2.10.2.post580}/src/testit_cli/models/status_type.py +0 -0
- {testit_cli-2.10.0.post580 → testit_cli-2.10.2.post580}/src/testit_cli/models/testcase.py +0 -0
- {testit_cli-2.10.0.post580 → testit_cli-2.10.2.post580}/src/testit_cli/parser.py +0 -0
- {testit_cli-2.10.0.post580 → testit_cli-2.10.2.post580}/src/testit_cli/service_factory.py +0 -0
- {testit_cli-2.10.0.post580 → testit_cli-2.10.2.post580}/src/testit_cli/validation.py +0 -0
- {testit_cli-2.10.0.post580 → testit_cli-2.10.2.post580}/src/testit_cli.egg-info/dependency_links.txt +0 -0
- {testit_cli-2.10.0.post580 → testit_cli-2.10.2.post580}/src/testit_cli.egg-info/entry_points.txt +0 -0
- {testit_cli-2.10.0.post580 → testit_cli-2.10.2.post580}/src/testit_cli.egg-info/top_level.txt +0 -0
- {testit_cli-2.10.0.post580 → testit_cli-2.10.2.post580}/tests/test_click.py +0 -0
- {testit_cli-2.10.0.post580 → testit_cli-2.10.2.post580}/tests/test_service.py +0 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: testit-cli
|
|
3
|
+
Version: 2.10.2.post580
|
|
4
|
+
Summary: This tool is the command line wrapper of Test IT allowing you to upload the test results in real time to Test IT
|
|
5
|
+
Home-page: https://pypi.org/project/testit-cli/
|
|
6
|
+
Author: Integration team
|
|
7
|
+
Author-email: integrations@testit.software
|
|
8
|
+
License: Apache-2.0
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.6
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Requires-Dist: testit-api-client==7.6.1.post580
|
|
20
|
+
Requires-Dist: validators
|
|
21
|
+
Requires-Dist: tqdm
|
|
22
|
+
Requires-Dist: click~=8.0.4
|
|
23
|
+
Dynamic: author
|
|
24
|
+
Dynamic: author-email
|
|
25
|
+
Dynamic: classifier
|
|
26
|
+
Dynamic: description
|
|
27
|
+
Dynamic: description-content-type
|
|
28
|
+
Dynamic: home-page
|
|
29
|
+
Dynamic: license
|
|
30
|
+
Dynamic: license-file
|
|
31
|
+
Dynamic: requires-dist
|
|
32
|
+
Dynamic: summary
|
|
33
|
+
|
|
34
|
+
# Test IT CLI
|
|
35
|
+
|
|
36
|
+
[](https://pypi.python.org/pypi/testit-cli)
|
|
38
|
+
[](https://pypi.python.org/pypi/testit-cli)
|
|
39
|
+
|
|
40
|
+
This tool is the command line wrapper of Test IT allowing you to upload the test results in real time to Test IT.
|
|
41
|
+
You can see more information in [official documentation](https://docs.testit.software/user-guide/integrations/cli.html)
|
|
42
|
+
|
|
43
|
+
## Compatibility
|
|
44
|
+
|
|
45
|
+
| Test IT | Test IT CLI |
|
|
46
|
+
|---------|----------------|
|
|
47
|
+
| 3.5+ | 0.1 |
|
|
48
|
+
| 4.4 | 1.0 |
|
|
49
|
+
| 4.5 | 1.2 |
|
|
50
|
+
| 4.6 | 1.5 |
|
|
51
|
+
| 5.0 | 2.0 |
|
|
52
|
+
| 5.2 | 2.1 |
|
|
53
|
+
| 5.2.2 | 2.2.1.post522 |
|
|
54
|
+
| 5.2.3 | 2.3.0.post523 |
|
|
55
|
+
| 5.3 | 2.4.5.post530 |
|
|
56
|
+
| 5.4 | 2.4.11.post540 |
|
|
57
|
+
| 5.5 | 2.7.2.post550 |
|
|
58
|
+
| 5.6 | 2.8.1.post560 |
|
|
59
|
+
| 5.7 | 2.9.1.post570 |
|
|
60
|
+
| 5.8 | 2.10.0.post580 |
|
|
61
|
+
| Cloud | 2.8.0 + |
|
|
62
|
+
|
|
63
|
+
1. For current versions, see the releases tab.
|
|
64
|
+
2. Starting with 5.2, we have added a TMS postscript, which means that the utility is compatible with a specific enterprise version.
|
|
65
|
+
3. If you are in doubt about which version to use, check with the support staff. support@yoonion.ru
|
|
66
|
+
|
|
67
|
+
## Test run tags and links
|
|
68
|
+
|
|
69
|
+
You can attach **test run** tags and links (for example a CI job URL) via CLI flags or environment variables.
|
|
70
|
+
They are applied when the test run is **created**, or merged into an **existing** run as early as possible (not only after results upload finishes).
|
|
71
|
+
|
|
72
|
+
| Intent | CLI | Env |
|
|
73
|
+
|--------|-----|-----|
|
|
74
|
+
| Tags | `--testruntags` / `-trt` | `TMS_TEST_RUN_TAGS` |
|
|
75
|
+
| Links | `--testrunlinks` / `-trl` | `TMS_TEST_RUN_LINKS` |
|
|
76
|
+
|
|
77
|
+
Supported commands: `testrun create`, `results import`, `results upload`.
|
|
78
|
+
|
|
79
|
+
### Tags format
|
|
80
|
+
|
|
81
|
+
Comma-separated list or JSON array:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
--testruntags "smoke,nightly"
|
|
85
|
+
--testruntags '["smoke","nightly"]'
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Links format
|
|
89
|
+
|
|
90
|
+
JSON array of objects. `url` is required; `title`, `description`, and `type` are optional.
|
|
91
|
+
|
|
92
|
+
**Link types for a test run:**
|
|
93
|
+
|
|
94
|
+
- `Related`
|
|
95
|
+
- `BlockedBy`
|
|
96
|
+
- `Defect`
|
|
97
|
+
- `Issue`
|
|
98
|
+
- `Requirement`
|
|
99
|
+
- `Repository`
|
|
100
|
+
|
|
101
|
+
If `type` is omitted, `Related` is used.
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
--testrunlinks '[{"url":"https://gitlab.example.com/group/project/-/jobs/12345","title":"CI Job","type":"Related"}]'
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Examples
|
|
108
|
+
|
|
109
|
+
Create a test run with tags and a CI job link (visible while the run is still In progress):
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
testit testrun create \
|
|
113
|
+
--url "$TMS_URL" \
|
|
114
|
+
--token "$TMS_TOKEN" \
|
|
115
|
+
--project-id "$TMS_PROJECT_ID" \
|
|
116
|
+
--testruntags "smoke,ci" \
|
|
117
|
+
--testrunlinks "[{\"url\":\"$CI_JOB_URL\",\"title\":\"CI Job\",\"type\":\"Related\"}]" \
|
|
118
|
+
--output ./testrun.id
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Same via env vars:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
export TMS_TEST_RUN_TAGS='smoke,ci'
|
|
125
|
+
export TMS_TEST_RUN_LINKS="[{\"url\":\"$CI_JOB_URL\",\"title\":\"CI Job\",\"type\":\"Related\"}]"
|
|
126
|
+
testit testrun create -u "$TMS_URL" -t "$TMS_TOKEN" -pi "$TMS_PROJECT_ID" -o ./testrun.id
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Merge tags/links into an existing run when uploading results:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
testit results upload \
|
|
133
|
+
--url "$TMS_URL" \
|
|
134
|
+
--token "$TMS_TOKEN" \
|
|
135
|
+
--configuration-id "$TMS_CONFIGURATION_ID" \
|
|
136
|
+
--testrun-id "$TMS_TEST_RUN_ID" \
|
|
137
|
+
--testruntags "nightly" \
|
|
138
|
+
--testrunlinks "[{\"url\":\"$CI_JOB_URL\",\"title\":\"CI Job\",\"type\":\"Related\"}]" \
|
|
139
|
+
--results ./results
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Notes:
|
|
143
|
+
|
|
144
|
+
- Test run tags/links are independent from autotest/result tags and links.
|
|
145
|
+
- On an existing run, new tags/links are **merged** (existing values are kept; duplicates by tag name / link URL are skipped).
|
|
146
|
+
- Empty or omitted values mean “do not change tags/links”.
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Test IT CLI
|
|
2
|
+
|
|
3
|
+
[](https://pypi.python.org/pypi/testit-cli)
|
|
5
|
+
[](https://pypi.python.org/pypi/testit-cli)
|
|
6
|
+
|
|
7
|
+
This tool is the command line wrapper of Test IT allowing you to upload the test results in real time to Test IT.
|
|
8
|
+
You can see more information in [official documentation](https://docs.testit.software/user-guide/integrations/cli.html)
|
|
9
|
+
|
|
10
|
+
## Compatibility
|
|
11
|
+
|
|
12
|
+
| Test IT | Test IT CLI |
|
|
13
|
+
|---------|----------------|
|
|
14
|
+
| 3.5+ | 0.1 |
|
|
15
|
+
| 4.4 | 1.0 |
|
|
16
|
+
| 4.5 | 1.2 |
|
|
17
|
+
| 4.6 | 1.5 |
|
|
18
|
+
| 5.0 | 2.0 |
|
|
19
|
+
| 5.2 | 2.1 |
|
|
20
|
+
| 5.2.2 | 2.2.1.post522 |
|
|
21
|
+
| 5.2.3 | 2.3.0.post523 |
|
|
22
|
+
| 5.3 | 2.4.5.post530 |
|
|
23
|
+
| 5.4 | 2.4.11.post540 |
|
|
24
|
+
| 5.5 | 2.7.2.post550 |
|
|
25
|
+
| 5.6 | 2.8.1.post560 |
|
|
26
|
+
| 5.7 | 2.9.1.post570 |
|
|
27
|
+
| 5.8 | 2.10.0.post580 |
|
|
28
|
+
| Cloud | 2.8.0 + |
|
|
29
|
+
|
|
30
|
+
1. For current versions, see the releases tab.
|
|
31
|
+
2. Starting with 5.2, we have added a TMS postscript, which means that the utility is compatible with a specific enterprise version.
|
|
32
|
+
3. If you are in doubt about which version to use, check with the support staff. support@yoonion.ru
|
|
33
|
+
|
|
34
|
+
## Test run tags and links
|
|
35
|
+
|
|
36
|
+
You can attach **test run** tags and links (for example a CI job URL) via CLI flags or environment variables.
|
|
37
|
+
They are applied when the test run is **created**, or merged into an **existing** run as early as possible (not only after results upload finishes).
|
|
38
|
+
|
|
39
|
+
| Intent | CLI | Env |
|
|
40
|
+
|--------|-----|-----|
|
|
41
|
+
| Tags | `--testruntags` / `-trt` | `TMS_TEST_RUN_TAGS` |
|
|
42
|
+
| Links | `--testrunlinks` / `-trl` | `TMS_TEST_RUN_LINKS` |
|
|
43
|
+
|
|
44
|
+
Supported commands: `testrun create`, `results import`, `results upload`.
|
|
45
|
+
|
|
46
|
+
### Tags format
|
|
47
|
+
|
|
48
|
+
Comma-separated list or JSON array:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
--testruntags "smoke,nightly"
|
|
52
|
+
--testruntags '["smoke","nightly"]'
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Links format
|
|
56
|
+
|
|
57
|
+
JSON array of objects. `url` is required; `title`, `description`, and `type` are optional.
|
|
58
|
+
|
|
59
|
+
**Link types for a test run:**
|
|
60
|
+
|
|
61
|
+
- `Related`
|
|
62
|
+
- `BlockedBy`
|
|
63
|
+
- `Defect`
|
|
64
|
+
- `Issue`
|
|
65
|
+
- `Requirement`
|
|
66
|
+
- `Repository`
|
|
67
|
+
|
|
68
|
+
If `type` is omitted, `Related` is used.
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
--testrunlinks '[{"url":"https://gitlab.example.com/group/project/-/jobs/12345","title":"CI Job","type":"Related"}]'
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Examples
|
|
75
|
+
|
|
76
|
+
Create a test run with tags and a CI job link (visible while the run is still In progress):
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
testit testrun create \
|
|
80
|
+
--url "$TMS_URL" \
|
|
81
|
+
--token "$TMS_TOKEN" \
|
|
82
|
+
--project-id "$TMS_PROJECT_ID" \
|
|
83
|
+
--testruntags "smoke,ci" \
|
|
84
|
+
--testrunlinks "[{\"url\":\"$CI_JOB_URL\",\"title\":\"CI Job\",\"type\":\"Related\"}]" \
|
|
85
|
+
--output ./testrun.id
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Same via env vars:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
export TMS_TEST_RUN_TAGS='smoke,ci'
|
|
92
|
+
export TMS_TEST_RUN_LINKS="[{\"url\":\"$CI_JOB_URL\",\"title\":\"CI Job\",\"type\":\"Related\"}]"
|
|
93
|
+
testit testrun create -u "$TMS_URL" -t "$TMS_TOKEN" -pi "$TMS_PROJECT_ID" -o ./testrun.id
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Merge tags/links into an existing run when uploading results:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
testit results upload \
|
|
100
|
+
--url "$TMS_URL" \
|
|
101
|
+
--token "$TMS_TOKEN" \
|
|
102
|
+
--configuration-id "$TMS_CONFIGURATION_ID" \
|
|
103
|
+
--testrun-id "$TMS_TEST_RUN_ID" \
|
|
104
|
+
--testruntags "nightly" \
|
|
105
|
+
--testrunlinks "[{\"url\":\"$CI_JOB_URL\",\"title\":\"CI Job\",\"type\":\"Related\"}]" \
|
|
106
|
+
--results ./results
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Notes:
|
|
110
|
+
|
|
111
|
+
- Test run tags/links are independent from autotest/result tags and links.
|
|
112
|
+
- On an existing run, new tags/links are **merged** (existing values are kept; duplicates by tag name / link URL are skipped).
|
|
113
|
+
- Empty or omitted values mean “do not change tags/links”.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from setuptools import find_packages, setup
|
|
2
2
|
|
|
3
|
-
VERSION = "2.10.
|
|
3
|
+
VERSION = "2.10.2.post580"
|
|
4
4
|
|
|
5
5
|
setup(
|
|
6
6
|
name='testit-cli',
|
|
@@ -26,7 +26,7 @@ setup(
|
|
|
26
26
|
py_modules=['testit_cli'],
|
|
27
27
|
packages=find_packages(where='src'),
|
|
28
28
|
package_dir={'': 'src'},
|
|
29
|
-
install_requires=['testit-api-client==7.6.
|
|
29
|
+
install_requires=['testit-api-client==7.6.1.post580', 'validators', 'tqdm', 'click~=8.0.4'],
|
|
30
30
|
entry_points={
|
|
31
31
|
'console_scripts': [
|
|
32
32
|
'testit = testit_cli.__main__:console_main'
|
|
@@ -55,9 +55,20 @@ class ApiClient:
|
|
|
55
55
|
self.__projects_api = ProjectsApi(api_client=client)
|
|
56
56
|
self.__workflows_api = WorkflowsApi(api_client=client)
|
|
57
57
|
|
|
58
|
-
def create_test_run(
|
|
58
|
+
def create_test_run(
|
|
59
|
+
self,
|
|
60
|
+
project_id: str,
|
|
61
|
+
name: str,
|
|
62
|
+
tags: typing.Optional[typing.List[str]] = None,
|
|
63
|
+
links: typing.Optional[typing.List] = None,
|
|
64
|
+
) -> TestRun:
|
|
59
65
|
"""Function creates test run and returns test run id."""
|
|
60
|
-
|
|
66
|
+
create_kwargs = {"project_id": project_id, "name": name}
|
|
67
|
+
if tags:
|
|
68
|
+
create_kwargs["tags"] = tags
|
|
69
|
+
if links:
|
|
70
|
+
create_kwargs["links"] = links
|
|
71
|
+
model = CreateEmptyRequest(**create_kwargs)
|
|
61
72
|
model = HtmlEscapeUtils.escape_html_in_object(model)
|
|
62
73
|
logging.debug(f"Creating test run with model: {model}")
|
|
63
74
|
|
|
@@ -67,6 +78,13 @@ class ApiClient:
|
|
|
67
78
|
)
|
|
68
79
|
|
|
69
80
|
logging.info(f'Created new testrun (ID: {test_run.id})')
|
|
81
|
+
if tags or links:
|
|
82
|
+
logging.info(
|
|
83
|
+
"Applied tags/links on create for testrun (ID: %s): tags=%s links=%s",
|
|
84
|
+
test_run.id,
|
|
85
|
+
tags,
|
|
86
|
+
links,
|
|
87
|
+
)
|
|
70
88
|
logging.debug(f"Test run created: {test_run}")
|
|
71
89
|
|
|
72
90
|
return Converter.test_run_v2_get_model_to_test_run(test_run)
|
|
@@ -4,6 +4,7 @@ from itertools import chain
|
|
|
4
4
|
|
|
5
5
|
from .models.config import Config
|
|
6
6
|
from .service_factory import ServiceFactory
|
|
7
|
+
from .testrun_metadata import parse_testrun_links, parse_testrun_tags
|
|
7
8
|
from .validation import validate_uuid, validate_url
|
|
8
9
|
|
|
9
10
|
|
|
@@ -61,11 +62,24 @@ class ExtraArgsForOption(click.Option):
|
|
|
61
62
|
return retval
|
|
62
63
|
|
|
63
64
|
|
|
65
|
+
_TESTRUN_TAGS_HELP = (
|
|
66
|
+
"Test run tags: comma-separated or JSON array "
|
|
67
|
+
"(smoke,nightly or [\"smoke\",\"nightly\"])"
|
|
68
|
+
)
|
|
69
|
+
_TESTRUN_LINKS_HELP = (
|
|
70
|
+
"Test run links as JSON array "
|
|
71
|
+
'([{"url":"https://ci.example/jobs/1","title":"CI Job","type":"Related"}]). '
|
|
72
|
+
"Types: Related, BlockedBy, Defect, Issue, Requirement, Repository"
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
|
|
64
76
|
@results.command("upload")
|
|
65
77
|
@click.option("-u", "--url", type=str, envvar='TMS_URL', required=True, help="Set url address of the Test IT instance (https://demo.testit.software)", callback=validate_url)
|
|
66
78
|
@click.option("-t", "--token", type=str, envvar='TMS_TOKEN', required=True, help="Set API token (T2lKd2pLZGI4WHRhaVZUejNl)")
|
|
67
79
|
@click.option("-ci", "--configuration-id", type=str, envvar='TMS_CONFIGURATION_ID', required=True, help="Set configuration id (15dbb164-c1aa-4cbf-830c-8c01ae14f4fb)", callback=validate_uuid)
|
|
68
80
|
@click.option("-ti", "--testrun-id", type=str, envvar='TMS_TEST_RUN_ID', required=True, help="Set test run id (3802f329-190c-4617-8bb0-2c3696abeb8f)", callback=validate_uuid)
|
|
81
|
+
@click.option("-trt", "--testruntags", type=str, envvar='TMS_TEST_RUN_TAGS', default=None, help=_TESTRUN_TAGS_HELP)
|
|
82
|
+
@click.option("-trl", "--testrunlinks", type=str, envvar='TMS_TEST_RUN_LINKS', default=None, help=_TESTRUN_LINKS_HELP)
|
|
69
83
|
@click.option("-s", "--separator", type=str, help="Separate the classname value in the results into namespace and classname (.)", default=None)
|
|
70
84
|
@click.option("-ns", "--namespace", type=str, help="Set namespace (NameSpace01)", default=None)
|
|
71
85
|
@click.option("-cn", "--classname", type=str, help="Set classname (ClassName01)", default=None)
|
|
@@ -74,13 +88,15 @@ class ExtraArgsForOption(click.Option):
|
|
|
74
88
|
@click.option("-d", "--debug", is_flag=True, help="Set debug logs")
|
|
75
89
|
@click.option("-dcv", "--disable-cert-validation", is_flag=True, help="Disables certificate validation")
|
|
76
90
|
@click.option("-iff", "--ignore-flaky-failure", is_flag=True, help="Ignore status flakyFailure in results")
|
|
77
|
-
def upload_results(url, token, configuration_id, testrun_id, separator, namespace, classname, results, debug, attachments, disable_cert_validation, ignore_flaky_failure):
|
|
91
|
+
def upload_results(url, token, configuration_id, testrun_id, testruntags, testrunlinks, separator, namespace, classname, results, debug, attachments, disable_cert_validation, ignore_flaky_failure):
|
|
78
92
|
"""Uploading results from different streams"""
|
|
79
93
|
config = Config(
|
|
80
94
|
url=url,
|
|
81
95
|
token=token,
|
|
82
96
|
configuration_id=configuration_id,
|
|
83
97
|
testrun_id=testrun_id,
|
|
98
|
+
testrun_tags=parse_testrun_tags(testruntags),
|
|
99
|
+
testrun_links=parse_testrun_links(testrunlinks),
|
|
84
100
|
separator=separator,
|
|
85
101
|
namespace=namespace,
|
|
86
102
|
classname=classname,
|
|
@@ -102,6 +118,8 @@ def upload_results(url, token, configuration_id, testrun_id, separator, namespac
|
|
|
102
118
|
@click.option("-ci", "--configuration-id", type=str, envvar='TMS_CONFIGURATION_ID', required=True, help="Set configuration id (15dbb164-c1aa-4cbf-830c-8c01ae14f4fb)", callback=validate_uuid)
|
|
103
119
|
@click.option("-ti", "--testrun-id", type=str, envvar='TMS_TEST_RUN_ID', help="Set test run id (3802f329-190c-4617-8bb0-2c3696abeb8f)", default=None, callback=validate_uuid)
|
|
104
120
|
@click.option("-tn", "--testrun-name", type=str, envvar='TMS_TEST_RUN_NAME', help="Set test run name (TestRun01)", default=None)
|
|
121
|
+
@click.option("-trt", "--testruntags", type=str, envvar='TMS_TEST_RUN_TAGS', default=None, help=_TESTRUN_TAGS_HELP)
|
|
122
|
+
@click.option("-trl", "--testrunlinks", type=str, envvar='TMS_TEST_RUN_LINKS', default=None, help=_TESTRUN_LINKS_HELP)
|
|
105
123
|
@click.option("-s", "--separator", type=str, help="Separate the classname value in the results into namespace and classname (.)", default=None)
|
|
106
124
|
@click.option("-ns", "--namespace", type=str, help="Set namespace (NameSpace01)", default=None)
|
|
107
125
|
@click.option("-cn", "--classname", type=str, help="Set classname (ClassName01)", default=None)
|
|
@@ -110,7 +128,7 @@ def upload_results(url, token, configuration_id, testrun_id, separator, namespac
|
|
|
110
128
|
@click.option("-d", "--debug", is_flag=True, help="Set debug logs")
|
|
111
129
|
@click.option("-dcv", "--disable-cert-validation", is_flag=True, help="Disables certificate validation")
|
|
112
130
|
@click.option("-iff", "--ignore-flaky-failure", is_flag=True, help="Ignore status flakyFailure in results")
|
|
113
|
-
def import_results(url, token, project_id, configuration_id, testrun_id, testrun_name, separator, namespace, classname, results, debug,
|
|
131
|
+
def import_results(url, token, project_id, configuration_id, testrun_id, testrun_name, testruntags, testrunlinks, separator, namespace, classname, results, debug,
|
|
114
132
|
attachments, disable_cert_validation, ignore_flaky_failure):
|
|
115
133
|
"""Uploading the first test results"""
|
|
116
134
|
if testrun_id is not None and testrun_name is not None:
|
|
@@ -123,6 +141,8 @@ def import_results(url, token, project_id, configuration_id, testrun_id, testrun
|
|
|
123
141
|
configuration_id=configuration_id,
|
|
124
142
|
testrun_id=testrun_id,
|
|
125
143
|
testrun_name=testrun_name,
|
|
144
|
+
testrun_tags=parse_testrun_tags(testruntags),
|
|
145
|
+
testrun_links=parse_testrun_links(testrunlinks),
|
|
126
146
|
separator=separator,
|
|
127
147
|
namespace=namespace,
|
|
128
148
|
classname=classname,
|
|
@@ -148,17 +168,21 @@ def testrun():
|
|
|
148
168
|
@click.option("-t", "--token", type=str, envvar='TMS_TOKEN', required=True, help="Set API token (T2lKd2pLZGI4WHRhaVZUejNl)")
|
|
149
169
|
@click.option("-pi", "--project-id", type=str, envvar='TMS_PROJECT_ID', required=True, help="Set project id (5236eb3f-7c05-46f9-a609-dc0278896464)", callback=validate_uuid)
|
|
150
170
|
@click.option("-tn", "--testrun-name", type=str, envvar='TMS_TEST_RUN_NAME', help="Set test run name (TestRun01)", default=None)
|
|
171
|
+
@click.option("-trt", "--testruntags", type=str, envvar='TMS_TEST_RUN_TAGS', default=None, help=_TESTRUN_TAGS_HELP)
|
|
172
|
+
@click.option("-trl", "--testrunlinks", type=str, envvar='TMS_TEST_RUN_LINKS', default=None, help=_TESTRUN_LINKS_HELP)
|
|
151
173
|
@click.option("-o", "--output", type=str, required=True, help="Set file path for output (FILE)")
|
|
152
174
|
@click.option("-a", "--attachments", multiple=True, type=list, help="Path to attachments for test run (multiple)", default=[], cls=ExtraArgsForOption)
|
|
153
175
|
@click.option("-d", "--debug", is_flag=True, help="Set debug logs")
|
|
154
176
|
@click.option("-dcv", "--disable-cert-validation", is_flag=True, help="Disables certificate validation")
|
|
155
|
-
def create_test_run(url, token, project_id, testrun_name, output, debug, attachments, disable_cert_validation):
|
|
177
|
+
def create_test_run(url, token, project_id, testrun_name, testruntags, testrunlinks, output, debug, attachments, disable_cert_validation):
|
|
156
178
|
"""Creating a new test run"""
|
|
157
179
|
config = Config(
|
|
158
180
|
url=url,
|
|
159
181
|
token=token,
|
|
160
182
|
project_id=project_id,
|
|
161
183
|
testrun_name=testrun_name,
|
|
184
|
+
testrun_tags=parse_testrun_tags(testruntags),
|
|
185
|
+
testrun_links=parse_testrun_links(testrunlinks),
|
|
162
186
|
is_debug=debug,
|
|
163
187
|
output=output,
|
|
164
188
|
paths_to_attachments=list(chain.from_iterable(attachments)),
|
|
@@ -137,7 +137,8 @@ class Converter:
|
|
|
137
137
|
description=test_run_model.description,
|
|
138
138
|
launch_source=test_run_model.launch_source,
|
|
139
139
|
attachments=cls.attachment_models_to_attachment_put_models(test_run_model.attachments),
|
|
140
|
-
links=cls.link_models_to_link_put_models(test_run_model.links)
|
|
140
|
+
links=cls.link_models_to_link_put_models(test_run_model.links),
|
|
141
|
+
tags=list(test_run_model.tags) if test_run_model.tags else [],
|
|
141
142
|
)
|
|
142
143
|
|
|
143
144
|
@classmethod
|
|
@@ -199,5 +200,6 @@ class Converter:
|
|
|
199
200
|
description=test_run.description,
|
|
200
201
|
launch_source=test_run.launch_source,
|
|
201
202
|
attachments=test_run.attachments,
|
|
202
|
-
links=test_run.links
|
|
203
|
+
links=test_run.links,
|
|
204
|
+
tags=test_run.tags,
|
|
203
205
|
)
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
from dataclasses import dataclass, field
|
|
2
2
|
import typing
|
|
3
3
|
|
|
4
|
+
from .testrun_link import TestRunLink
|
|
5
|
+
|
|
4
6
|
|
|
5
7
|
@dataclass
|
|
6
8
|
class Config:
|
|
@@ -15,6 +17,8 @@ class Config:
|
|
|
15
17
|
configuration_ids: typing.Optional[list[str]] = None
|
|
16
18
|
testrun_id: typing.Optional[str] = None
|
|
17
19
|
testrun_name: typing.Optional[str] = None
|
|
20
|
+
testrun_tags: typing.Optional[list[str]] = None
|
|
21
|
+
testrun_links: typing.Optional[list[TestRunLink]] = None
|
|
18
22
|
separator: typing.Optional[str] = None
|
|
19
23
|
namespace: typing.Optional[str] = None
|
|
20
24
|
classname: typing.Optional[str] = None
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from dataclasses import dataclass
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
2
|
from typing import List
|
|
3
3
|
from testit_api_client.model.assign_attachment_api_model import AssignAttachmentApiModel
|
|
4
4
|
from testit_api_client.model.link_put_model import LinkPutModel
|
|
@@ -14,3 +14,4 @@ class TestRun:
|
|
|
14
14
|
launch_source: str
|
|
15
15
|
attachments: List[AssignAttachmentApiModel]
|
|
16
16
|
links: List[LinkPutModel]
|
|
17
|
+
tags: List[str] = field(default_factory=list)
|
|
@@ -13,6 +13,7 @@ from .apiclient import ApiClient
|
|
|
13
13
|
from .dir_worker import DirWorker
|
|
14
14
|
from .file_worker import FileWorker
|
|
15
15
|
from .importer import Importer
|
|
16
|
+
from .testrun_metadata import merge_links, merge_tags, to_create_link_models, to_link_put_models
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
class Service:
|
|
@@ -72,9 +73,32 @@ class Service:
|
|
|
72
73
|
def __create_test_run(self) -> TestRun:
|
|
73
74
|
return self.__api_client.create_test_run(
|
|
74
75
|
self.__config.project_id,
|
|
75
|
-
self.__config.testrun_name
|
|
76
|
+
self.__config.testrun_name,
|
|
77
|
+
tags=self.__config.testrun_tags,
|
|
78
|
+
links=to_create_link_models(self.__config.testrun_links),
|
|
76
79
|
)
|
|
77
80
|
|
|
81
|
+
def __merge_configured_metadata(self, test_run: TestRun) -> None:
|
|
82
|
+
test_run.tags = merge_tags(test_run.tags, self.__config.testrun_tags)
|
|
83
|
+
test_run.links = merge_links(
|
|
84
|
+
test_run.links,
|
|
85
|
+
to_link_put_models(self.__config.testrun_links),
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
def __apply_testrun_tags_and_links(self, test_run: TestRun) -> TestRun:
|
|
89
|
+
if not self.__config.testrun_tags and not self.__config.testrun_links:
|
|
90
|
+
return test_run
|
|
91
|
+
|
|
92
|
+
self.__merge_configured_metadata(test_run)
|
|
93
|
+
self.__api_client.update_test_run(test_run)
|
|
94
|
+
logging.info(
|
|
95
|
+
"Merged tags/links into testrun (ID: %s): tags=%s links=%s",
|
|
96
|
+
test_run.id,
|
|
97
|
+
self.__config.testrun_tags,
|
|
98
|
+
self.__config.testrun_links,
|
|
99
|
+
)
|
|
100
|
+
return test_run
|
|
101
|
+
|
|
78
102
|
def __upload_attachments(self) -> list[AttachmentPutModel]:
|
|
79
103
|
files = []
|
|
80
104
|
|
|
@@ -94,6 +118,7 @@ class Service:
|
|
|
94
118
|
else:
|
|
95
119
|
test_run = self.__api_client.get_test_run(self.__config.testrun_id)
|
|
96
120
|
self.__config.project_id = test_run.project_id
|
|
121
|
+
test_run = self.__apply_testrun_tags_and_links(test_run)
|
|
97
122
|
|
|
98
123
|
logging.info("Sending test results to Test IT ...")
|
|
99
124
|
|
|
@@ -104,6 +129,7 @@ class Service:
|
|
|
104
129
|
logging.info("Successfully sent test results")
|
|
105
130
|
|
|
106
131
|
def __update_test_run_with_attachments(self, test_run: TestRun) -> None:
|
|
132
|
+
self.__merge_configured_metadata(test_run)
|
|
107
133
|
attachments: typing.List[AssignAttachmentApiModel] = Converter.attachment_put_models_to_assign_attachments(
|
|
108
134
|
self.__upload_attachments())
|
|
109
135
|
test_run.attachments.extend(attachments)
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"""Parse and merge test run tags/links (config → API)."""
|
|
2
|
+
import json
|
|
3
|
+
import logging
|
|
4
|
+
from typing import List, Optional
|
|
5
|
+
|
|
6
|
+
from testit_api_client.model.create_link_api_model import CreateLinkApiModel
|
|
7
|
+
from testit_api_client.model.link_put_model import LinkPutModel
|
|
8
|
+
from testit_api_client.model.link_type import LinkType
|
|
9
|
+
|
|
10
|
+
from .models.testrun_link import TestRunLink
|
|
11
|
+
|
|
12
|
+
LINK_TYPES = ("Related", "BlockedBy", "Defect", "Issue", "Requirement", "Repository")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def parse_testrun_tags(raw: Optional[str]) -> Optional[List[str]]:
|
|
16
|
+
if raw is None or not str(raw).strip():
|
|
17
|
+
return None
|
|
18
|
+
text = str(raw).strip()
|
|
19
|
+
if text.startswith("["):
|
|
20
|
+
try:
|
|
21
|
+
data = json.loads(text)
|
|
22
|
+
except json.JSONDecodeError as exc:
|
|
23
|
+
logging.warning("Invalid test run tags JSON: %s", exc)
|
|
24
|
+
return None
|
|
25
|
+
if not isinstance(data, list):
|
|
26
|
+
logging.warning("Test run tags JSON must be an array of strings")
|
|
27
|
+
return None
|
|
28
|
+
tags = [str(item).strip() for item in data if str(item).strip()]
|
|
29
|
+
return tags or None
|
|
30
|
+
tags = [part.strip() for part in text.split(",") if part.strip()]
|
|
31
|
+
return tags or None
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def parse_testrun_links(raw: Optional[str]) -> Optional[List[TestRunLink]]:
|
|
35
|
+
if raw is None or not str(raw).strip():
|
|
36
|
+
return None
|
|
37
|
+
try:
|
|
38
|
+
data = json.loads(str(raw).strip())
|
|
39
|
+
except json.JSONDecodeError as exc:
|
|
40
|
+
logging.warning("Invalid test run links JSON: %s", exc)
|
|
41
|
+
return None
|
|
42
|
+
if not isinstance(data, list):
|
|
43
|
+
logging.warning("Test run links JSON must be an array of objects")
|
|
44
|
+
return None
|
|
45
|
+
links = []
|
|
46
|
+
for item in data:
|
|
47
|
+
if not isinstance(item, dict):
|
|
48
|
+
logging.warning("Skipping invalid test run link entry: %s", item)
|
|
49
|
+
continue
|
|
50
|
+
url = item.get("url")
|
|
51
|
+
if not url or not str(url).strip():
|
|
52
|
+
logging.warning("Skipping test run link without url: %s", item)
|
|
53
|
+
continue
|
|
54
|
+
link_type = item.get("type")
|
|
55
|
+
if link_type is not None and str(link_type) not in LINK_TYPES:
|
|
56
|
+
logging.warning(
|
|
57
|
+
"Unknown link type %r; allowed: %s. Using Related.",
|
|
58
|
+
link_type,
|
|
59
|
+
", ".join(LINK_TYPES),
|
|
60
|
+
)
|
|
61
|
+
link_type = "Related"
|
|
62
|
+
links.append(
|
|
63
|
+
TestRunLink(
|
|
64
|
+
url=str(url).strip(),
|
|
65
|
+
title=item.get("title"),
|
|
66
|
+
description=item.get("description"),
|
|
67
|
+
link_type=str(link_type) if link_type is not None else None,
|
|
68
|
+
)
|
|
69
|
+
)
|
|
70
|
+
return links or None
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _to_link_type(value: Optional[str]) -> LinkType:
|
|
74
|
+
name = value or "Related"
|
|
75
|
+
try:
|
|
76
|
+
return LinkType(name)
|
|
77
|
+
except Exception:
|
|
78
|
+
return LinkType("Related")
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def to_create_link_models(links: Optional[List[TestRunLink]]) -> Optional[List[CreateLinkApiModel]]:
|
|
82
|
+
if not links:
|
|
83
|
+
return None
|
|
84
|
+
return [
|
|
85
|
+
CreateLinkApiModel(
|
|
86
|
+
url=link.url,
|
|
87
|
+
title=link.title,
|
|
88
|
+
description=link.description,
|
|
89
|
+
type=_to_link_type(link.link_type),
|
|
90
|
+
has_info=False,
|
|
91
|
+
)
|
|
92
|
+
for link in links
|
|
93
|
+
]
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def to_link_put_models(links: Optional[List[TestRunLink]]) -> List[LinkPutModel]:
|
|
97
|
+
if not links:
|
|
98
|
+
return []
|
|
99
|
+
return [
|
|
100
|
+
LinkPutModel(
|
|
101
|
+
url=link.url,
|
|
102
|
+
title=link.title,
|
|
103
|
+
description=link.description,
|
|
104
|
+
type=_to_link_type(link.link_type),
|
|
105
|
+
has_info=False,
|
|
106
|
+
)
|
|
107
|
+
for link in links
|
|
108
|
+
]
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def merge_tags(existing: Optional[List[str]], incoming: Optional[List[str]]) -> List[str]:
|
|
112
|
+
result = list(existing or [])
|
|
113
|
+
seen = set(result)
|
|
114
|
+
for tag in incoming or []:
|
|
115
|
+
if tag not in seen:
|
|
116
|
+
result.append(tag)
|
|
117
|
+
seen.add(tag)
|
|
118
|
+
return result
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def merge_links(
|
|
122
|
+
existing: Optional[List[LinkPutModel]],
|
|
123
|
+
incoming: Optional[List[LinkPutModel]],
|
|
124
|
+
) -> List[LinkPutModel]:
|
|
125
|
+
result = list(existing or [])
|
|
126
|
+
seen = {link.url for link in result}
|
|
127
|
+
for link in incoming or []:
|
|
128
|
+
if link.url not in seen:
|
|
129
|
+
result.append(link)
|
|
130
|
+
seen.add(link.url)
|
|
131
|
+
return result
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: testit-cli
|
|
3
|
+
Version: 2.10.2.post580
|
|
4
|
+
Summary: This tool is the command line wrapper of Test IT allowing you to upload the test results in real time to Test IT
|
|
5
|
+
Home-page: https://pypi.org/project/testit-cli/
|
|
6
|
+
Author: Integration team
|
|
7
|
+
Author-email: integrations@testit.software
|
|
8
|
+
License: Apache-2.0
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.6
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Requires-Dist: testit-api-client==7.6.1.post580
|
|
20
|
+
Requires-Dist: validators
|
|
21
|
+
Requires-Dist: tqdm
|
|
22
|
+
Requires-Dist: click~=8.0.4
|
|
23
|
+
Dynamic: author
|
|
24
|
+
Dynamic: author-email
|
|
25
|
+
Dynamic: classifier
|
|
26
|
+
Dynamic: description
|
|
27
|
+
Dynamic: description-content-type
|
|
28
|
+
Dynamic: home-page
|
|
29
|
+
Dynamic: license
|
|
30
|
+
Dynamic: license-file
|
|
31
|
+
Dynamic: requires-dist
|
|
32
|
+
Dynamic: summary
|
|
33
|
+
|
|
34
|
+
# Test IT CLI
|
|
35
|
+
|
|
36
|
+
[](https://pypi.python.org/pypi/testit-cli)
|
|
38
|
+
[](https://pypi.python.org/pypi/testit-cli)
|
|
39
|
+
|
|
40
|
+
This tool is the command line wrapper of Test IT allowing you to upload the test results in real time to Test IT.
|
|
41
|
+
You can see more information in [official documentation](https://docs.testit.software/user-guide/integrations/cli.html)
|
|
42
|
+
|
|
43
|
+
## Compatibility
|
|
44
|
+
|
|
45
|
+
| Test IT | Test IT CLI |
|
|
46
|
+
|---------|----------------|
|
|
47
|
+
| 3.5+ | 0.1 |
|
|
48
|
+
| 4.4 | 1.0 |
|
|
49
|
+
| 4.5 | 1.2 |
|
|
50
|
+
| 4.6 | 1.5 |
|
|
51
|
+
| 5.0 | 2.0 |
|
|
52
|
+
| 5.2 | 2.1 |
|
|
53
|
+
| 5.2.2 | 2.2.1.post522 |
|
|
54
|
+
| 5.2.3 | 2.3.0.post523 |
|
|
55
|
+
| 5.3 | 2.4.5.post530 |
|
|
56
|
+
| 5.4 | 2.4.11.post540 |
|
|
57
|
+
| 5.5 | 2.7.2.post550 |
|
|
58
|
+
| 5.6 | 2.8.1.post560 |
|
|
59
|
+
| 5.7 | 2.9.1.post570 |
|
|
60
|
+
| 5.8 | 2.10.0.post580 |
|
|
61
|
+
| Cloud | 2.8.0 + |
|
|
62
|
+
|
|
63
|
+
1. For current versions, see the releases tab.
|
|
64
|
+
2. Starting with 5.2, we have added a TMS postscript, which means that the utility is compatible with a specific enterprise version.
|
|
65
|
+
3. If you are in doubt about which version to use, check with the support staff. support@yoonion.ru
|
|
66
|
+
|
|
67
|
+
## Test run tags and links
|
|
68
|
+
|
|
69
|
+
You can attach **test run** tags and links (for example a CI job URL) via CLI flags or environment variables.
|
|
70
|
+
They are applied when the test run is **created**, or merged into an **existing** run as early as possible (not only after results upload finishes).
|
|
71
|
+
|
|
72
|
+
| Intent | CLI | Env |
|
|
73
|
+
|--------|-----|-----|
|
|
74
|
+
| Tags | `--testruntags` / `-trt` | `TMS_TEST_RUN_TAGS` |
|
|
75
|
+
| Links | `--testrunlinks` / `-trl` | `TMS_TEST_RUN_LINKS` |
|
|
76
|
+
|
|
77
|
+
Supported commands: `testrun create`, `results import`, `results upload`.
|
|
78
|
+
|
|
79
|
+
### Tags format
|
|
80
|
+
|
|
81
|
+
Comma-separated list or JSON array:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
--testruntags "smoke,nightly"
|
|
85
|
+
--testruntags '["smoke","nightly"]'
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Links format
|
|
89
|
+
|
|
90
|
+
JSON array of objects. `url` is required; `title`, `description`, and `type` are optional.
|
|
91
|
+
|
|
92
|
+
**Link types for a test run:**
|
|
93
|
+
|
|
94
|
+
- `Related`
|
|
95
|
+
- `BlockedBy`
|
|
96
|
+
- `Defect`
|
|
97
|
+
- `Issue`
|
|
98
|
+
- `Requirement`
|
|
99
|
+
- `Repository`
|
|
100
|
+
|
|
101
|
+
If `type` is omitted, `Related` is used.
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
--testrunlinks '[{"url":"https://gitlab.example.com/group/project/-/jobs/12345","title":"CI Job","type":"Related"}]'
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Examples
|
|
108
|
+
|
|
109
|
+
Create a test run with tags and a CI job link (visible while the run is still In progress):
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
testit testrun create \
|
|
113
|
+
--url "$TMS_URL" \
|
|
114
|
+
--token "$TMS_TOKEN" \
|
|
115
|
+
--project-id "$TMS_PROJECT_ID" \
|
|
116
|
+
--testruntags "smoke,ci" \
|
|
117
|
+
--testrunlinks "[{\"url\":\"$CI_JOB_URL\",\"title\":\"CI Job\",\"type\":\"Related\"}]" \
|
|
118
|
+
--output ./testrun.id
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Same via env vars:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
export TMS_TEST_RUN_TAGS='smoke,ci'
|
|
125
|
+
export TMS_TEST_RUN_LINKS="[{\"url\":\"$CI_JOB_URL\",\"title\":\"CI Job\",\"type\":\"Related\"}]"
|
|
126
|
+
testit testrun create -u "$TMS_URL" -t "$TMS_TOKEN" -pi "$TMS_PROJECT_ID" -o ./testrun.id
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Merge tags/links into an existing run when uploading results:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
testit results upload \
|
|
133
|
+
--url "$TMS_URL" \
|
|
134
|
+
--token "$TMS_TOKEN" \
|
|
135
|
+
--configuration-id "$TMS_CONFIGURATION_ID" \
|
|
136
|
+
--testrun-id "$TMS_TEST_RUN_ID" \
|
|
137
|
+
--testruntags "nightly" \
|
|
138
|
+
--testrunlinks "[{\"url\":\"$CI_JOB_URL\",\"title\":\"CI Job\",\"type\":\"Related\"}]" \
|
|
139
|
+
--results ./results
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Notes:
|
|
143
|
+
|
|
144
|
+
- Test run tags/links are independent from autotest/result tags and links.
|
|
145
|
+
- On an existing run, new tags/links are **merged** (existing values are kept; duplicates by tag name / link URL are skipped).
|
|
146
|
+
- Empty or omitted values mean “do not change tags/links”.
|
|
@@ -17,6 +17,7 @@ src/testit_cli/logger.py
|
|
|
17
17
|
src/testit_cli/parser.py
|
|
18
18
|
src/testit_cli/service.py
|
|
19
19
|
src/testit_cli/service_factory.py
|
|
20
|
+
src/testit_cli/testrun_metadata.py
|
|
20
21
|
src/testit_cli/validation.py
|
|
21
22
|
src/testit_cli.egg-info/PKG-INFO
|
|
22
23
|
src/testit_cli.egg-info/SOURCES.txt
|
|
@@ -30,5 +31,7 @@ src/testit_cli/models/mode.py
|
|
|
30
31
|
src/testit_cli/models/status_type.py
|
|
31
32
|
src/testit_cli/models/testcase.py
|
|
32
33
|
src/testit_cli/models/testrun.py
|
|
34
|
+
src/testit_cli/models/testrun_link.py
|
|
33
35
|
tests/test_click.py
|
|
34
|
-
tests/test_service.py
|
|
36
|
+
tests/test_service.py
|
|
37
|
+
tests/test_testrun_metadata.py
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
from unittest.mock import Mock
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
from testit_api_client.model.link_put_model import LinkPutModel
|
|
5
|
+
from testit_api_client.model.link_type import LinkType
|
|
6
|
+
|
|
7
|
+
from src.testit_cli.models.testrun import TestRun
|
|
8
|
+
from src.testit_cli.models.testrun_link import TestRunLink
|
|
9
|
+
from src.testit_cli.service import Service
|
|
10
|
+
from src.testit_cli.testrun_metadata import (
|
|
11
|
+
merge_links,
|
|
12
|
+
merge_tags,
|
|
13
|
+
parse_testrun_links,
|
|
14
|
+
parse_testrun_tags,
|
|
15
|
+
to_create_link_models,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@pytest.mark.parametrize(
|
|
20
|
+
"raw, expected",
|
|
21
|
+
[
|
|
22
|
+
(None, None),
|
|
23
|
+
("", None),
|
|
24
|
+
(" ", None),
|
|
25
|
+
("smoke, nightly", ["smoke", "nightly"]),
|
|
26
|
+
('["smoke", "nightly"]', ["smoke", "nightly"]),
|
|
27
|
+
("smoke", ["smoke"]),
|
|
28
|
+
],
|
|
29
|
+
)
|
|
30
|
+
def test_parse_testrun_tags(raw, expected):
|
|
31
|
+
assert parse_testrun_tags(raw) == expected
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def test_parse_testrun_tags_invalid_json_array():
|
|
35
|
+
assert parse_testrun_tags("[") is None
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def test_parse_testrun_links_ok():
|
|
39
|
+
raw = (
|
|
40
|
+
'[{"url":"https://ci.example/jobs/1","title":"CI Job","type":"Related"},'
|
|
41
|
+
'{"url":"https://ci.example/jobs/2"}]'
|
|
42
|
+
)
|
|
43
|
+
links = parse_testrun_links(raw)
|
|
44
|
+
assert links == [
|
|
45
|
+
TestRunLink(
|
|
46
|
+
url="https://ci.example/jobs/1",
|
|
47
|
+
title="CI Job",
|
|
48
|
+
description=None,
|
|
49
|
+
link_type="Related",
|
|
50
|
+
),
|
|
51
|
+
TestRunLink(
|
|
52
|
+
url="https://ci.example/jobs/2",
|
|
53
|
+
title=None,
|
|
54
|
+
description=None,
|
|
55
|
+
link_type=None,
|
|
56
|
+
),
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@pytest.mark.parametrize("raw", [None, "", "not-json", "{}", '[{"title":"x"}]'])
|
|
61
|
+
def test_parse_testrun_links_invalid(raw):
|
|
62
|
+
assert parse_testrun_links(raw) is None
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def test_merge_tags_and_links_dedupe():
|
|
66
|
+
assert merge_tags(["a"], ["a", "b"]) == ["a", "b"]
|
|
67
|
+
related = LinkType("Related")
|
|
68
|
+
existing = [LinkPutModel(url="https://a", type=related, has_info=False)]
|
|
69
|
+
incoming = [
|
|
70
|
+
LinkPutModel(url="https://a", type=related, has_info=False),
|
|
71
|
+
LinkPutModel(url="https://b", type=related, has_info=False),
|
|
72
|
+
]
|
|
73
|
+
merged = merge_links(existing, incoming)
|
|
74
|
+
assert [link.url for link in merged] == ["https://a", "https://b"]
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def test_to_create_link_models_defaults_type():
|
|
78
|
+
models = to_create_link_models([TestRunLink(url="https://ci.example/1")])
|
|
79
|
+
assert models is not None
|
|
80
|
+
assert len(models) == 1
|
|
81
|
+
assert models[0].url == "https://ci.example/1"
|
|
82
|
+
assert str(models[0].type) == "Related"
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def test_create_test_run_passes_tags_and_links():
|
|
86
|
+
api_client = Mock()
|
|
87
|
+
api_client.create_test_run.return_value = TestRun(
|
|
88
|
+
id="run-1",
|
|
89
|
+
project_id="proj-1",
|
|
90
|
+
state="InProgress",
|
|
91
|
+
name="Run",
|
|
92
|
+
description="",
|
|
93
|
+
launch_source="",
|
|
94
|
+
attachments=[],
|
|
95
|
+
links=[],
|
|
96
|
+
tags=["smoke"],
|
|
97
|
+
)
|
|
98
|
+
api_client.upload_attachments.return_value = []
|
|
99
|
+
config = Mock(
|
|
100
|
+
project_id="proj-1",
|
|
101
|
+
testrun_name="Run",
|
|
102
|
+
testrun_tags=["smoke"],
|
|
103
|
+
testrun_links=[TestRunLink(url="https://ci.example/1", title="CI", link_type="Related")],
|
|
104
|
+
paths_to_attachments=[],
|
|
105
|
+
output="out.txt",
|
|
106
|
+
)
|
|
107
|
+
service = Service(config, api_client, Mock(), Mock(), Mock())
|
|
108
|
+
service._Service__write_to_output = Mock()
|
|
109
|
+
|
|
110
|
+
service.create_test_run()
|
|
111
|
+
|
|
112
|
+
kwargs = api_client.create_test_run.call_args.kwargs
|
|
113
|
+
assert kwargs["tags"] == ["smoke"]
|
|
114
|
+
assert kwargs["links"] is not None
|
|
115
|
+
assert kwargs["links"][0].url == "https://ci.example/1"
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def test_upload_results_merges_tags_and_links_early():
|
|
119
|
+
related = LinkType("Related")
|
|
120
|
+
existing = TestRun(
|
|
121
|
+
id="run-1",
|
|
122
|
+
project_id="proj-1",
|
|
123
|
+
state="InProgress",
|
|
124
|
+
name="Run",
|
|
125
|
+
description="",
|
|
126
|
+
launch_source="",
|
|
127
|
+
attachments=[],
|
|
128
|
+
links=[LinkPutModel(url="https://existing", type=related, has_info=False)],
|
|
129
|
+
tags=["ui"],
|
|
130
|
+
)
|
|
131
|
+
api_client = Mock()
|
|
132
|
+
api_client.get_test_run.return_value = existing
|
|
133
|
+
api_client.upload_attachments.return_value = []
|
|
134
|
+
parser = Mock()
|
|
135
|
+
parser.read_file.return_value = []
|
|
136
|
+
importer = Mock()
|
|
137
|
+
config = Mock(
|
|
138
|
+
testrun_id="run-1",
|
|
139
|
+
testrun_tags=["smoke"],
|
|
140
|
+
testrun_links=[TestRunLink(url="https://ci.example/1")],
|
|
141
|
+
paths_to_attachments=[],
|
|
142
|
+
project_id=None,
|
|
143
|
+
)
|
|
144
|
+
service = Service(config, api_client, parser, importer, Mock())
|
|
145
|
+
|
|
146
|
+
service.upload_results()
|
|
147
|
+
|
|
148
|
+
assert api_client.update_test_run.call_count >= 1
|
|
149
|
+
first_update = api_client.update_test_run.call_args_list[0].args[0]
|
|
150
|
+
assert first_update.tags == ["ui", "smoke"]
|
|
151
|
+
assert [link.url for link in first_update.links] == ["https://existing", "https://ci.example/1"]
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: testit-cli
|
|
3
|
-
Version: 2.10.0.post580
|
|
4
|
-
Summary: This tool is the command line wrapper of Test IT allowing you to upload the test results in real time to Test IT
|
|
5
|
-
Home-page: https://pypi.org/project/testit-cli/
|
|
6
|
-
Author: Integration team
|
|
7
|
-
Author-email: integrations@testit.software
|
|
8
|
-
License: Apache-2.0
|
|
9
|
-
Classifier: Programming Language :: Python :: 3
|
|
10
|
-
Classifier: Programming Language :: Python :: 3.6
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
-
Description-Content-Type: text/markdown
|
|
18
|
-
License-File: LICENSE
|
|
19
|
-
Requires-Dist: testit-api-client==7.6.0.post580
|
|
20
|
-
Requires-Dist: validators
|
|
21
|
-
Requires-Dist: tqdm
|
|
22
|
-
Requires-Dist: click~=8.0.4
|
|
23
|
-
Dynamic: author
|
|
24
|
-
Dynamic: author-email
|
|
25
|
-
Dynamic: classifier
|
|
26
|
-
Dynamic: description
|
|
27
|
-
Dynamic: description-content-type
|
|
28
|
-
Dynamic: home-page
|
|
29
|
-
Dynamic: license
|
|
30
|
-
Dynamic: license-file
|
|
31
|
-
Dynamic: requires-dist
|
|
32
|
-
Dynamic: summary
|
|
33
|
-
|
|
34
|
-
# Test IT CLI
|
|
35
|
-
|
|
36
|
-
[](https://pypi.python.org/pypi/testit-cli)
|
|
38
|
-
[](https://pypi.python.org/pypi/testit-cli)
|
|
39
|
-
|
|
40
|
-
This tool is the command line wrapper of Test IT allowing you to upload the test results in real time to Test IT.
|
|
41
|
-
You can see more information in [official documentation](https://docs.testit.software/user-guide/integrations/cli.html)
|
|
42
|
-
|
|
43
|
-
## Compatibility
|
|
44
|
-
|
|
45
|
-
| Test IT | Test IT CLI |
|
|
46
|
-
|---------|----------------|
|
|
47
|
-
| 3.5+ | 0.1 |
|
|
48
|
-
| 4.4 | 1.0 |
|
|
49
|
-
| 4.5 | 1.2 |
|
|
50
|
-
| 4.6 | 1.5 |
|
|
51
|
-
| 5.0 | 2.0 |
|
|
52
|
-
| 5.2 | 2.1 |
|
|
53
|
-
| 5.2.2 | 2.2.1.post522 |
|
|
54
|
-
| 5.2.3 | 2.3.0.post523 |
|
|
55
|
-
| 5.3 | 2.4.5.post530 |
|
|
56
|
-
| 5.4 | 2.4.11.post540 |
|
|
57
|
-
| 5.5 | 2.7.2.post550 |
|
|
58
|
-
| 5.6 | 2.8.1.post560 |
|
|
59
|
-
| 5.7 | 2.9.1.post570 |
|
|
60
|
-
| 5.8 | 2.10.0.post580 |
|
|
61
|
-
| Cloud | 2.8.0 + |
|
|
62
|
-
|
|
63
|
-
1. For current versions, see the releases tab.
|
|
64
|
-
2. Starting with 5.2, we have added a TMS postscript, which means that the utility is compatible with a specific enterprise version.
|
|
65
|
-
3. If you are in doubt about which version to use, check with the support staff. support@yoonion.ru
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
# Test IT CLI
|
|
2
|
-
|
|
3
|
-
[](https://pypi.python.org/pypi/testit-cli)
|
|
5
|
-
[](https://pypi.python.org/pypi/testit-cli)
|
|
6
|
-
|
|
7
|
-
This tool is the command line wrapper of Test IT allowing you to upload the test results in real time to Test IT.
|
|
8
|
-
You can see more information in [official documentation](https://docs.testit.software/user-guide/integrations/cli.html)
|
|
9
|
-
|
|
10
|
-
## Compatibility
|
|
11
|
-
|
|
12
|
-
| Test IT | Test IT CLI |
|
|
13
|
-
|---------|----------------|
|
|
14
|
-
| 3.5+ | 0.1 |
|
|
15
|
-
| 4.4 | 1.0 |
|
|
16
|
-
| 4.5 | 1.2 |
|
|
17
|
-
| 4.6 | 1.5 |
|
|
18
|
-
| 5.0 | 2.0 |
|
|
19
|
-
| 5.2 | 2.1 |
|
|
20
|
-
| 5.2.2 | 2.2.1.post522 |
|
|
21
|
-
| 5.2.3 | 2.3.0.post523 |
|
|
22
|
-
| 5.3 | 2.4.5.post530 |
|
|
23
|
-
| 5.4 | 2.4.11.post540 |
|
|
24
|
-
| 5.5 | 2.7.2.post550 |
|
|
25
|
-
| 5.6 | 2.8.1.post560 |
|
|
26
|
-
| 5.7 | 2.9.1.post570 |
|
|
27
|
-
| 5.8 | 2.10.0.post580 |
|
|
28
|
-
| Cloud | 2.8.0 + |
|
|
29
|
-
|
|
30
|
-
1. For current versions, see the releases tab.
|
|
31
|
-
2. Starting with 5.2, we have added a TMS postscript, which means that the utility is compatible with a specific enterprise version.
|
|
32
|
-
3. If you are in doubt about which version to use, check with the support staff. support@yoonion.ru
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: testit-cli
|
|
3
|
-
Version: 2.10.0.post580
|
|
4
|
-
Summary: This tool is the command line wrapper of Test IT allowing you to upload the test results in real time to Test IT
|
|
5
|
-
Home-page: https://pypi.org/project/testit-cli/
|
|
6
|
-
Author: Integration team
|
|
7
|
-
Author-email: integrations@testit.software
|
|
8
|
-
License: Apache-2.0
|
|
9
|
-
Classifier: Programming Language :: Python :: 3
|
|
10
|
-
Classifier: Programming Language :: Python :: 3.6
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
-
Description-Content-Type: text/markdown
|
|
18
|
-
License-File: LICENSE
|
|
19
|
-
Requires-Dist: testit-api-client==7.6.0.post580
|
|
20
|
-
Requires-Dist: validators
|
|
21
|
-
Requires-Dist: tqdm
|
|
22
|
-
Requires-Dist: click~=8.0.4
|
|
23
|
-
Dynamic: author
|
|
24
|
-
Dynamic: author-email
|
|
25
|
-
Dynamic: classifier
|
|
26
|
-
Dynamic: description
|
|
27
|
-
Dynamic: description-content-type
|
|
28
|
-
Dynamic: home-page
|
|
29
|
-
Dynamic: license
|
|
30
|
-
Dynamic: license-file
|
|
31
|
-
Dynamic: requires-dist
|
|
32
|
-
Dynamic: summary
|
|
33
|
-
|
|
34
|
-
# Test IT CLI
|
|
35
|
-
|
|
36
|
-
[](https://pypi.python.org/pypi/testit-cli)
|
|
38
|
-
[](https://pypi.python.org/pypi/testit-cli)
|
|
39
|
-
|
|
40
|
-
This tool is the command line wrapper of Test IT allowing you to upload the test results in real time to Test IT.
|
|
41
|
-
You can see more information in [official documentation](https://docs.testit.software/user-guide/integrations/cli.html)
|
|
42
|
-
|
|
43
|
-
## Compatibility
|
|
44
|
-
|
|
45
|
-
| Test IT | Test IT CLI |
|
|
46
|
-
|---------|----------------|
|
|
47
|
-
| 3.5+ | 0.1 |
|
|
48
|
-
| 4.4 | 1.0 |
|
|
49
|
-
| 4.5 | 1.2 |
|
|
50
|
-
| 4.6 | 1.5 |
|
|
51
|
-
| 5.0 | 2.0 |
|
|
52
|
-
| 5.2 | 2.1 |
|
|
53
|
-
| 5.2.2 | 2.2.1.post522 |
|
|
54
|
-
| 5.2.3 | 2.3.0.post523 |
|
|
55
|
-
| 5.3 | 2.4.5.post530 |
|
|
56
|
-
| 5.4 | 2.4.11.post540 |
|
|
57
|
-
| 5.5 | 2.7.2.post550 |
|
|
58
|
-
| 5.6 | 2.8.1.post560 |
|
|
59
|
-
| 5.7 | 2.9.1.post570 |
|
|
60
|
-
| 5.8 | 2.10.0.post580 |
|
|
61
|
-
| Cloud | 2.8.0 + |
|
|
62
|
-
|
|
63
|
-
1. For current versions, see the releases tab.
|
|
64
|
-
2. Starting with 5.2, we have added a TMS postscript, which means that the utility is compatible with a specific enterprise version.
|
|
65
|
-
3. If you are in doubt about which version to use, check with the support staff. support@yoonion.ru
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{testit_cli-2.10.0.post580 → testit_cli-2.10.2.post580}/src/testit_cli/models/status_type.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{testit_cli-2.10.0.post580 → testit_cli-2.10.2.post580}/src/testit_cli.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{testit_cli-2.10.0.post580 → testit_cli-2.10.2.post580}/src/testit_cli.egg-info/entry_points.txt
RENAMED
|
File without changes
|
{testit_cli-2.10.0.post580 → testit_cli-2.10.2.post580}/src/testit_cli.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|