From 85be59eb865b0ac4cc09c8f55b76292e155cc504 Mon Sep 17 00:00:00 2001 From: utagawa kiki Date: Thu, 4 May 2023 19:51:31 +0900 Subject: [PATCH 1/6] Fix publish package workflow (#74) * use Python 3.11 for deploy * install build * use build with build phase * use pypa/gh-action-pypi-publish@release/v1 * remove wheel explicit dependency --- .github/workflows/deploy.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 7125462..d7fc2a1 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -12,19 +12,19 @@ jobs: - name: Checkout uses: actions/checkout@v3 - - name: Set up Python 3.7 + - name: Set up Python uses: actions/setup-python@v4 with: - python-version: 3.7 + python-version: '3.11' - name: Install dependencies for build - run: pip install --upgrade setuptools wheel + run: pip install --upgrade setuptools build - name: Build - run: python setup.py sdist bdist_wheel + run: python -m build - name: Publish package - uses: pypa/gh-action-pypi-publish@master + uses: pypa/gh-action-pypi-publish@release/v1 with: user: __token__ password: ${{ secrets.pypi_password }} From 1a87abb05e36128509b7ebd5987dbf8aad7ec47c Mon Sep 17 00:00:00 2001 From: utagawa kiki Date: Thu, 4 May 2023 20:01:51 +0900 Subject: [PATCH 2/6] bump to version 0.2.0 (#73) * bump version to 0.2.0 * changelog of version 0.2.0 * add #74 to changelog * add #56 --- CHANGELOG.md | 13 +++++++++++++ pyproject.toml | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 60f51dc..1ac4394 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 0.2.0 (2023-05-04) + +### Incompatible changes + +- Require python 3.7+ #66 (thanks to @ssbarnea) + +### Other changes + +- Fix publish package workflow #74 +- Handle cases where pytest itself fails #70 (thanks to @edgarrmondragon) +- Adopt PEP-621 for packaging #65 (thanks to @ssbarnea) +- Bump pre-commit/action from 2.0.0 to 3.0.0 #56 + ## 0.1.8 (2022-12-20) No functionality change. diff --git a/pyproject.toml b/pyproject.toml index baf4fd5..69c327f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ build-backend = "setuptools.build_meta" [project] # https://peps.python.org/pep-0621/#readme requires-python = ">=3.7" -version = "0.1.8" +version = "0.2.0" name = "pytest-github-actions-annotate-failures" description = "pytest plugin to annotate failed tests with a workflow command for GitHub Actions" readme = "README.md" From abef23d5f82285fe9ea6c2956343b7c7a57b5e3b Mon Sep 17 00:00:00 2001 From: Benedikt Fuchs Date: Mon, 1 May 2023 00:10:21 +0200 Subject: [PATCH 3/6] add parsing of multiline errors --- .../plugin.py | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/pytest_github_actions_annotate_failures/plugin.py b/pytest_github_actions_annotate_failures/plugin.py index de61ee9..b89bf7b 100644 --- a/pytest_github_actions_annotate_failures/plugin.py +++ b/pytest_github_actions_annotate_failures/plugin.py @@ -3,6 +3,7 @@ from __future__ import annotations import os +import re import sys from collections import OrderedDict from typing import TYPE_CHECKING @@ -45,7 +46,7 @@ def pytest_runtest_makereport(item: Item, call): filesystempath = os.path.join(runpath, filesystempath) # try to convert to absolute path in GitHub Actions - workspace = os.environ.get("GITHUB_WORKSPACE") + workspace = os.environ.get("GITHUB_WORKSPACE", "") if workspace: full_path = os.path.abspath(filesystempath) try: @@ -79,13 +80,33 @@ def pytest_runtest_makereport(item: Item, call): _, lineno, message = report.longrepr longrepr += "\n\n" + message elif isinstance(report.longrepr, str): - longrepr += "\n\n" + report.longrepr - + parsed_errors = _try_parse_multi_error_string_message(workspace, filesystempath, report.longrepr) + if parsed_errors is not None: + for _lineno, _message in parsed_errors: + print( + _error_workflow_command(filesystempath, lineno, _lineno + "\n\n" + _message), file=sys.stderr + ) + return + else: + longrepr += "\n\n" + report.longrepr print( _error_workflow_command(filesystempath, lineno, longrepr), file=sys.stderr ) +def _try_parse_multi_error_string_message(workspace, filesystempath, longrepr): + pathspec_regex = re.compile( + rf"(?:(?:{re.escape(workspace)}/)?{re.escape(filesystempath)}:)?(\d+):(?:\d+:)?\s*(.+)") + matches = [ + pathspec_regex.match(line) + for line in longrepr.strip().split("\n") + ] + if not all(matches): + return None + + return [(int(match.group(1)), match.group(2)) for match in matches] + + def _error_workflow_command(filesystempath, lineno, longrepr): # Build collection of arguments. Ordering is strict for easy testing details_dict = OrderedDict() From 13d47998cba1cbcb7c16367873cd7c168fb49e37 Mon Sep 17 00:00:00 2001 From: Benedikt Fuchs Date: Mon, 1 May 2023 01:16:26 +0200 Subject: [PATCH 4/6] fix wrong parameterization --- pytest_github_actions_annotate_failures/plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pytest_github_actions_annotate_failures/plugin.py b/pytest_github_actions_annotate_failures/plugin.py index b89bf7b..1753a77 100644 --- a/pytest_github_actions_annotate_failures/plugin.py +++ b/pytest_github_actions_annotate_failures/plugin.py @@ -84,7 +84,7 @@ def pytest_runtest_makereport(item: Item, call): if parsed_errors is not None: for _lineno, _message in parsed_errors: print( - _error_workflow_command(filesystempath, lineno, _lineno + "\n\n" + _message), file=sys.stderr + _error_workflow_command(filesystempath, _lineno, longrepr + "\n\n" + _message), file=sys.stderr ) return else: From c76bd7c923ade77843ec697cf0b3bb153ed46242 Mon Sep 17 00:00:00 2001 From: Benedikt Fuchs Date: Mon, 1 May 2023 01:23:17 +0200 Subject: [PATCH 5/6] group errors on same line --- pytest_github_actions_annotate_failures/plugin.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/pytest_github_actions_annotate_failures/plugin.py b/pytest_github_actions_annotate_failures/plugin.py index 1753a77..df79c1d 100644 --- a/pytest_github_actions_annotate_failures/plugin.py +++ b/pytest_github_actions_annotate_failures/plugin.py @@ -104,7 +104,17 @@ def _try_parse_multi_error_string_message(workspace, filesystempath, longrepr): if not all(matches): return None - return [(int(match.group(1)), match.group(2)) for match in matches] + errors_per_line = {} + + for match in matches: + line_no = int(match.group(1)) + message = match.group(2) + if line_no not in errors_per_line: + errors_per_line[line_no] = message + else: + errors_per_line[line_no] += "\n" + message + + return errors_per_line.items() def _error_workflow_command(filesystempath, lineno, longrepr): From d1a4b30d9d70438572b45137870e609d8d6e5f94 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Tue, 16 May 2023 20:45:59 -0400 Subject: [PATCH 6/6] chore: move to using Ruff (#71) Signed-off-by: Henry Schreiner --- .flake8 | 3 -- .pre-commit-config.yaml | 15 +++----- MANIFEST.in | 1 - plugin_test.py | 7 ++-- pyproject.toml | 38 +++++++++++++++++++ .../plugin.py | 16 ++++---- 6 files changed, 54 insertions(+), 26 deletions(-) delete mode 100644 .flake8 diff --git a/.flake8 b/.flake8 deleted file mode 100644 index b23915d..0000000 --- a/.flake8 +++ /dev/null @@ -1,3 +0,0 @@ -[flake8] -ignore = E203, E231, E501, E722, W503, B950 -select = C,E,F,W,B,B9,I diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index df86f85..c8fcc59 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v3.1.0 + rev: "v4.4.0" hooks: - id: check-added-large-files - id: check-case-conflict @@ -12,17 +12,14 @@ repos: - id: mixed-line-ending - id: requirements-txt-fixer - id: trailing-whitespace - - id: fix-encoding-pragma - repo: https://github.com/mgedmin/check-manifest - rev: "0.42" + rev: "0.49" hooks: - id: check-manifest -- repo: https://github.com/PyCQA/flake8 - rev: 3.8.3 +- repo: https://github.com/charliermarsh/ruff-pre-commit + rev: "v0.0.262" hooks: - - id: flake8 - additional_dependencies: - - flake8-bugbear - - flake8-import-order + - id: ruff + args: ["--fix", "--show-fixes"] diff --git a/MANIFEST.in b/MANIFEST.in index d07d8e6..ee937c8 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,7 +1,6 @@ include *.py include *.txt include *.yaml -include .flake8 include .pre-commit-config.yaml include CHANGELOG.md include LICENSE diff --git a/plugin_test.py b/plugin_test.py index 7e489ff..a580e9e 100644 --- a/plugin_test.py +++ b/plugin_test.py @@ -1,10 +1,9 @@ -# -*- coding: utf-8 -*- -import os +from __future__ import annotations -from packaging import version +import os import pytest - +from packaging import version pytest_plugins = "pytester" diff --git a/pyproject.toml b/pyproject.toml index 69c327f..7e3ba1e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,3 +49,41 @@ changelog = "https://github.com/pytest-dev/pytest-github-actions-annotate-failur [project.entry-points.pytest11] pytest_github_actions_annotate_failures = "pytest_github_actions_annotate_failures.plugin" + + +[tool.ruff] +select = [ + "E", "F", "W", # flake8 + "B", # flake8-bugbear + "I", # isort + "ARG", # flake8-unused-arguments + "C4", # flake8-comprehensions + "EM", # flake8-errmsg + "ICN", # flake8-import-conventions + "ISC", # flake8-implicit-str-concat + "G", # flake8-logging-format + "PGH", # pygrep-hooks + "PIE", # flake8-pie + "PL", # pylint + "PT", # flake8-pytest-style + "RET", # flake8-return + "RUF", # Ruff-specific + "SIM", # flake8-simplify + "UP", # pyupgrade + "YTT", # flake8-2020 + "EXE", # flake8-executable +] +extend-ignore = [ + "PLR", # Design related pylint codes + "E501", # Line too long + "PT004", # Use underscore for non-returning fixture (use usefixture instead) +] +target-version = "py37" +unfixable = [ + "T20", # Removes print statements + "F841", # Removes unused variables +] +isort.required-imports = ["from __future__ import annotations"] + +[tool.ruff.per-file-ignores] +"tests/**" = ["T20"] diff --git a/pytest_github_actions_annotate_failures/plugin.py b/pytest_github_actions_annotate_failures/plugin.py index de61ee9..8cf1e62 100644 --- a/pytest_github_actions_annotate_failures/plugin.py +++ b/pytest_github_actions_annotate_failures/plugin.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from __future__ import annotations @@ -7,9 +6,8 @@ from collections import OrderedDict from typing import TYPE_CHECKING -from _pytest._code.code import ExceptionRepr - import pytest +from _pytest._code.code import ExceptionRepr if TYPE_CHECKING: from _pytest.nodes import Item @@ -26,7 +24,7 @@ @pytest.hookimpl(tryfirst=True, hookwrapper=True) -def pytest_runtest_makereport(item: Item, call): +def pytest_runtest_makereport(item: Item, call): # noqa: ARG001 # execute all other hooks to obtain the report object outcome = yield report: CollectReport = outcome.get_result() @@ -93,13 +91,13 @@ def _error_workflow_command(filesystempath, lineno, longrepr): if lineno is not None: details_dict["line"] = lineno - details = ",".join("{}={}".format(k, v) for k, v in details_dict.items()) + details = ",".join(f"{k}={v}" for k, v in details_dict.items()) if longrepr is None: - return "\n::error {}".format(details) - else: - longrepr = _escape(longrepr) - return "\n::error {}::{}".format(details, longrepr) + return f"\n::error {details}" + + longrepr = _escape(longrepr) + return f"\n::error {details}::{longrepr}" def _escape(s):