Skip to content

Commit fb09cc8

Browse files
authored
Merge pull request #323 from reportportal/develop
Release
2 parents 156ec50 + d43d35b commit fb09cc8

File tree

16 files changed

+248
-52
lines changed

16 files changed

+248
-52
lines changed

.github/workflows/release.yml

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,21 @@
1+
# Copyright 2022 EPAM Systems
2+
# Licensed under the Apache License, Version 2.0 (the "License");
3+
# you may not use this file except in compliance with the License.
4+
# You may obtain a copy of the License at
5+
#
6+
# https://www.apache.org/licenses/LICENSE-2.0
7+
#
8+
# Unless required by applicable law or agreed to in writing, software
9+
# distributed under the License is distributed on an "AS IS" BASIS,
10+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
# See the License for the specific language governing permissions and
12+
# limitations under the License.
13+
114
name: Release Pytest agent
215

316
on:
417
push:
5-
branches: ['master']
18+
branches: [ 'master' ]
619
paths-ignore:
720
- '.github/**'
821
- CHANGELOG.md
@@ -20,19 +33,19 @@ env:
2033

2134
jobs:
2235
deploy:
23-
runs-on: ubuntu-latest
36+
runs-on: ubuntu-20.04
2437
steps:
25-
- uses: actions/checkout@v2
38+
- uses: actions/checkout@v3
2639

2740
- name: Generate versions
28-
uses: HardNorth/github-version-generate@v1.1.2
41+
uses: HardNorth/github-version-generate@v1
2942
with:
3043
version-source: file
3144
version-file: ${{ env.VERSION_FILE }}
3245
version-file-extraction-pattern: ${{ env.VERSION_EXTRACT_PATTERN }}
3346

3447
- name: Setup git credentials
35-
uses: oleksiyrudenko/gha-git-credentials@v2
48+
uses: oleksiyrudenko/gha-git-credentials@v2.1.1
3649
with:
3750
name: 'reportportal.io'
3851
@@ -45,7 +58,7 @@ jobs:
4558
git push --tags
4659
4760
- name: Set up Python
48-
uses: actions/setup-python@v2
61+
uses: actions/setup-python@v4
4962
with:
5063
python-version: '3.6'
5164

@@ -62,7 +75,7 @@ jobs:
6275
password: ${{ secrets.PYPI_PASSWORD }}
6376

6477
- name: Checkout develop branch
65-
uses: actions/checkout@v2
78+
uses: actions/checkout@v3
6679
with:
6780
ref: 'develop'
6881
fetch-depth: 0
@@ -82,22 +95,18 @@ jobs:
8295
8396
- name: Read changelog Entry
8497
id: readChangelogEntry
85-
uses: mindsers/changelog-reader-action@v1.3.1
98+
uses: mindsers/changelog-reader-action@v2
8699
with:
87100
version: ${{ env.RELEASE_VERSION }}
88101
path: ./${{ env.CHANGE_LOG_FILE }}
89102

90103
- name: Create Release
91104
id: createRelease
92-
uses: actions/create-release@v1
93-
env:
94-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
105+
uses: ncipollo/release-action@v1
95106
with:
96-
tag_name: ${{ env.RELEASE_VERSION }}
97-
release_name: Release ${{ env.RELEASE_VERSION }}
98-
body: ${{ steps.readChangelogEntry.outputs.log_entry }}
99-
draft: false
100-
prerelease: false
107+
tag: ${{ env.RELEASE_VERSION }}
108+
name: Release ${{ env.RELEASE_VERSION }}
109+
body: ${{ steps.readChangelogEntry.outputs.changes }}
101110

102111
- name: Merge release branch into develop
103112
id: mergeIntoDevelop

.github/workflows/tests.yml

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,47 @@
1+
# Copyright 2022 EPAM Systems
2+
# Licensed under the Apache License, Version 2.0 (the "License");
3+
# you may not use this file except in compliance with the License.
4+
# You may obtain a copy of the License at
5+
#
6+
# https://www.apache.org/licenses/LICENSE-2.0
7+
#
8+
# Unless required by applicable law or agreed to in writing, software
9+
# distributed under the License is distributed on an "AS IS" BASIS,
10+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
# See the License for the specific language governing permissions and
12+
# limitations under the License.
13+
114
name: Tests
215

3-
on: [push, pull_request]
16+
on: [ push, pull_request ]
417

518
jobs:
619
build:
7-
runs-on: ubuntu-latest
20+
runs-on: ubuntu-20.04
821
strategy:
922
matrix:
10-
python-version: [2.7, 3.6, 3.7, 3.8, 3.9, '3.10']
23+
python-version: [ '2.7', '3.6', '3.7', '3.8', '3.9', '3.10' ]
1124
steps:
12-
- uses: actions/checkout@v2
13-
- name: Set up Python ${{ matrix.python-version }}
14-
uses: actions/setup-python@v2
15-
with:
16-
python-version: ${{ matrix.python-version }}
17-
- name: Install dependencies
18-
run: |
19-
python -m pip install --upgrade pip
20-
pip install tox tox-gh-actions
21-
- name: Test with tox
22-
run: tox
23-
- name: Upload coverage to Codecov
24-
if: matrix.python-version == 3.6 && success()
25-
uses: codecov/codecov-action@v1
26-
with:
27-
files: coverage.xml
28-
flags: unittests
29-
name: codecov-client-reportportal
30-
path_to_write_report: codecov_report.txt
25+
- name: Checkout repository
26+
uses: actions/checkout@v3
27+
28+
- name: Set up Python ${{ matrix.python-version }}
29+
uses: actions/setup-python@v4
30+
with:
31+
python-version: ${{ matrix.python-version }}
32+
33+
- name: Install dependencies
34+
run: |
35+
python -m pip install --upgrade pip
36+
pip install tox tox-gh-actions
37+
38+
- name: Test with tox
39+
run: tox
40+
41+
- name: Upload coverage to Codecov
42+
if: matrix.python-version == 3.6 && success()
43+
uses: codecov/codecov-action@v3
44+
with:
45+
files: coverage.xml
46+
flags: unittests
47+
name: codecov-client-reportportal

.pre-commit-config.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ repos:
2121
rev: v1.0.1
2222
hooks:
2323
- id: rst-linter
24-
- repo: https://gitlab.com/pycqa/flake8.git
25-
rev: 3.9.0
24+
- repo: https://github.com/pycqa/flake8
25+
rev: 5.0.4
2626
hooks:
2727
- id: flake8

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## [Unreleased]
44
### Added
5+
- Support for thread logs and `rp_thread_logging` flag, by @dagansandler
6+
7+
## [5.1.2]
8+
### Added
59
- `rp_log_batch_payload_size` parameter, by @HardNorth
610
### Changed
711
- Feature [#311](https://github.com/reportportal/agent-python-pytest/issues/311):

README.rst

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ Pytest plugin for reporting test results of the Pytest to the Reportal Portal.
2121
* Contribution
2222
* Examples
2323
* Launching
24-
* Send attachement (screenshots)
24+
* Send attachment (screenshots)
2525
* Troubleshooting
2626
* Integration with GA
2727
* Copyright Notice
@@ -108,11 +108,12 @@ The following parameters are optional:
108108
- :code:`rp_hierarchy_dirs_level = 0` - Directory starting hierarchy level (from pytest.ini level) (default `0`)
109109
- :code:`rp_hierarchy_dirs = True` - Enables hierarchy for tests directories, default `False`. Doesn't support 'xdist' plugin.
110110
- :code:`rp_hierarchy_dir_path_separator` - Path separator to display directories in test hierarchy. In case of empty value current system path separator will be used (os.path.sep)
111-
- :code:`rp_hierarchy_code` - Enables hierarchy for inner classes and parametrized tests, default `False`
111+
- :code:`rp_hierarchy_code` - Enables hierarchy for inner classes and parametrized tests, default `False`. Doesn't support 'xdist' plugin.
112112
- :code:`rp_issue_system_url = https://bugzilla.some.com/show_bug.cgi?id={issue_id}` - issue URL (issue_id will be filled by parameter from pytest mark)
113113
- :code:`rp_issue_id_marks = True` - Enables adding marks for issue ids (e.g. "issue:123456")
114114
- :code:`rp_verify_ssl = True` - Verify SSL when connecting to the server
115115
- :code:`rp_mode = DEFAULT` - DEBUG or DEFAULT launch mode. DEBUG launches are displayed in a separate tab and not visible to anyone except owner
116+
- :code:`rp_thread_logging` - EXPERIMENTAL - Enables support for reporting logs from threads by patching the builtin Thread class. Use with caution.
116117

117118

118119
If you like to override the above parameters from command line, or from CI environment based on your build, then pass
@@ -223,10 +224,10 @@ Example:
223224
assert False
224225
225226
226-
Send attachement (screenshots)
227+
Send attachment (screenshots)
227228
------------------------------
228229

229-
https://github.com/reportportal/client-Python#send-attachement-screenshots
230+
https://github.com/reportportal/client-Python#send-attachment-screenshots
230231

231232
Test internal steps, aka "Nested steps"
232233
---------------------------------------

examples/threads/__init__.py

Whitespace-only changes.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import logging
2+
import threading
3+
4+
from reportportal_client.steps import step
5+
6+
log = logging.getLogger(__name__)
7+
8+
9+
def worker():
10+
log.info("TEST_INFO")
11+
log.debug("TEST_DEBUG")
12+
13+
14+
def test_log():
15+
t = threading.Thread(target=worker)
16+
log.info("TEST_BEFORE_THREADING")
17+
with step("Some nesting where the thread logs should go"):
18+
t.start()
19+
t.join()

pytest_reportportal/config.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ def __init__(self, pytest_config):
6060
self.rp_log_level = get_actual_log_level(pytest_config, 'rp_log_level')
6161
self.rp_log_format = self.find_option(pytest_config, 'rp_log_format')
6262
self.rp_mode = self.find_option(pytest_config, 'rp_mode')
63+
self.rp_thread_logging = self.find_option(
64+
pytest_config, 'rp_thread_logging'
65+
)
6366
self.rp_parent_item_id = self.find_option(pytest_config,
6467
'rp_parent_item_id')
6568
self.rp_project = self.find_option(pytest_config,

pytest_reportportal/plugin.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
from pytest_reportportal import LAUNCH_WAIT_TIMEOUT
1818
from .config import AgentConfig
19-
from .rp_logging import patching_logger_class
19+
from .rp_logging import patching_logger_class, patching_thread_class
2020
from .service import PyTestServiceClass
2121

2222
log = logging.getLogger(__name__)
@@ -204,6 +204,24 @@ def pytest_configure(config):
204204
config.workerinput['py_test_service'])
205205

206206

207+
@pytest.hookimpl(hookwrapper=True)
208+
def pytest_runtestloop(session):
209+
"""
210+
Control start and finish of all test items in the session.
211+
212+
:param session: pytest.Session
213+
:return: generator object
214+
"""
215+
config = session.config
216+
if not config._rp_enabled:
217+
yield
218+
return
219+
220+
agent_config = config._reporter_config
221+
with patching_thread_class(agent_config):
222+
yield
223+
224+
207225
@pytest.hookimpl(hookwrapper=True)
208226
def pytest_runtest_protocol(item):
209227
"""
@@ -341,6 +359,14 @@ def add_shared_option(name, help, default=None, action='store'):
341359
help='Visibility of current launch [DEFAULT, DEBUG]',
342360
default='DEFAULT'
343361
)
362+
add_shared_option(
363+
name='rp_thread_logging',
364+
help='EXPERIMENTAL: Report logs from threads. '
365+
'This option applies a patch to the builtin Thread class, '
366+
'and so it is turned off by default. Use with caution.',
367+
default=False,
368+
action='store_true'
369+
)
344370

345371
parser.addini(
346372
'rp_launch_attributes',

pytest_reportportal/rp_logging.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,94 @@
11
"""RPLogger class for low-level logging in tests."""
22

33
import logging
4+
import threading
45
from contextlib import contextmanager
56
from functools import wraps
7+
8+
from reportportal_client.client import RPClient
9+
10+
from reportportal_client._local import current, set_current
611
from reportportal_client import RPLogger
712

813

14+
@contextmanager
15+
def patching_thread_class(config):
16+
"""
17+
Add patch for Thread class.
18+
19+
Set the parent thread client as the child thread's local client
20+
"""
21+
if not config.rp_thread_logging:
22+
# Do nothing
23+
yield
24+
else:
25+
original_start = threading.Thread.start
26+
original_run = threading.Thread.run
27+
try:
28+
def wrap_start(original_func):
29+
@wraps(original_func)
30+
def _start(self, *args, **kwargs):
31+
"""Save the invoking thread's client if there is one."""
32+
# Prevent an endless loop of workers being spawned
33+
if "_monitor" not in self.name:
34+
current_client = current()
35+
self.parent_rp_client = current_client
36+
return original_func(self, *args, **kwargs)
37+
38+
return _start
39+
40+
def wrap_run(original_func):
41+
@wraps(original_func)
42+
def _run(self, *args, **kwargs):
43+
"""Create a new client for the invoked thread."""
44+
client = None
45+
if (
46+
hasattr(self, "parent_rp_client")
47+
and self.parent_rp_client
48+
and not current()
49+
):
50+
parent = self.parent_rp_client
51+
client = RPClient(
52+
endpoint=parent.endpoint,
53+
project=parent.project,
54+
token=parent.token,
55+
log_batch_size=parent.log_batch_size,
56+
is_skipped_an_issue=parent.is_skipped_an_issue,
57+
verify_ssl=parent.verify_ssl,
58+
retries=config.rp_retries,
59+
launch_id=parent.launch_id
60+
)
61+
if parent.current_item():
62+
client._item_stack.append(
63+
parent.current_item()
64+
)
65+
client.start()
66+
try:
67+
return original_func(self, *args, **kwargs)
68+
finally:
69+
if client:
70+
# Stop the client and remove any references
71+
client.terminate()
72+
self.parent_rp_client = None
73+
del self.parent_rp_client
74+
set_current(None)
75+
76+
return _run
77+
78+
if not hasattr(threading.Thread, "patched"):
79+
# patch
80+
threading.Thread.patched = True
81+
threading.Thread.start = wrap_start(original_start)
82+
threading.Thread.run = wrap_run(original_run)
83+
yield
84+
85+
finally:
86+
if hasattr(threading.Thread, "patched"):
87+
threading.Thread.start = original_start
88+
threading.Thread.run = original_run
89+
del threading.Thread.patched
90+
91+
992
@contextmanager
1093
def patching_logger_class():
1194
"""

0 commit comments

Comments
 (0)