From 6719dfd6f8478ad6d32a5a6747266dbbe45a19c3 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 14 Mar 2023 07:52:23 -0300 Subject: [PATCH 01/13] [pre-commit.ci] pre-commit autoupdate (#889) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/PyCQA/autoflake: v2.0.1 → v2.0.2](https://github.com/PyCQA/autoflake/compare/v2.0.1...v2.0.2) - [github.com/pre-commit/mirrors-mypy: v1.0.1 → v1.1.1](https://github.com/pre-commit/mirrors-mypy/compare/v1.0.1...v1.1.1) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7c0d9856..c738d55f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/PyCQA/autoflake - rev: v2.0.1 + rev: v2.0.2 hooks: - id: autoflake args: ["--in-place", "--remove-unused-variables", "--remove-all-unused-imports"] @@ -39,7 +39,7 @@ repos: language: python additional_dependencies: [pygments, restructuredtext_lint] - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.0.1 + rev: v1.1.1 hooks: - id: mypy files: ^(src/|testing/) From c7d86097e993e8d8d64557a4c6831139e45826fc Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 4 Apr 2023 09:03:28 -0300 Subject: [PATCH 02/13] [pre-commit.ci] pre-commit autoupdate (#892) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/psf/black: 23.1.0 → 23.3.0](https://github.com/psf/black/compare/23.1.0...23.3.0) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c738d55f..f7407e8e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,7 +5,7 @@ repos: - id: autoflake args: ["--in-place", "--remove-unused-variables", "--remove-all-unused-imports"] - repo: https://github.com/psf/black - rev: 23.1.0 + rev: 23.3.0 hooks: - id: black args: [--safe, --quiet, --target-version, py35] From 982ef0097a577f01665551ecf652a6d4869c99b2 Mon Sep 17 00:00:00 2001 From: Robert Schweizer Date: Thu, 6 Apr 2023 14:46:34 +0200 Subject: [PATCH 03/13] Improve docs of maxschedchunk (#893) --- docs/distribution.rst | 3 ++- src/xdist/plugin.py | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/distribution.rst b/docs/distribution.rst index 1848ef9e..93d52f67 100644 --- a/docs/distribution.rst +++ b/docs/distribution.rst @@ -50,7 +50,8 @@ The test distribution algorithm is configured with the ``--dist`` command-line o .. _distribution modes: * ``--dist load`` **(default)**: Sends pending tests to any worker that is - available, without any guaranteed order. + available, without any guaranteed order. Scheduling can be fine-tuned with + the `--maxschedchunk` option, see output of `pytest --help`. * ``--dist loadscope``: Tests are grouped by **module** for *test functions* and by **class** for *test methods*. Groups are distributed to available diff --git a/src/xdist/plugin.py b/src/xdist/plugin.py index b08b8421..5360b5d5 100644 --- a/src/xdist/plugin.py +++ b/src/xdist/plugin.py @@ -173,6 +173,8 @@ def pytest_addoption(parser): "one - might be useful for a small number of slow tests. " "Larger numbers will allow the scheduler to submit consecutive " "chunks of tests to workers - allows reusing fixtures. " + "Due to implementation reasons, at least 2 tests are scheduled per " + "worker at the start. Only later tests can be scheduled one by one. " "Unlimited if not set." ), ) From 4bed067b067e85f1baa3c6a5d109f6550d055e68 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 11 Apr 2023 07:55:12 -0300 Subject: [PATCH 04/13] [pre-commit.ci] pre-commit autoupdate (#895) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-mypy: v1.1.1 → v1.2.0](https://github.com/pre-commit/mirrors-mypy/compare/v1.1.1...v1.2.0) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f7407e8e..dc0b6328 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -39,7 +39,7 @@ repos: language: python additional_dependencies: [pygments, restructuredtext_lint] - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.1.1 + rev: v1.2.0 hooks: - id: mypy files: ^(src/|testing/) From 6317cc32fab03046f6c74ba5506e972eeee562b5 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 21 Apr 2023 15:15:53 -0300 Subject: [PATCH 05/13] [pre-commit.ci] pre-commit autoupdate (#896) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/PyCQA/autoflake: v2.0.2 → v2.1.0](https://github.com/PyCQA/autoflake/compare/v2.0.2...v2.1.0) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index dc0b6328..04c7814d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/PyCQA/autoflake - rev: v2.0.2 + rev: v2.1.0 hooks: - id: autoflake args: ["--in-place", "--remove-unused-variables", "--remove-all-unused-imports"] From 8fbecd8a23bd927a1f7982fd385a9fab78deb843 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 25 Apr 2023 07:37:20 -0300 Subject: [PATCH 06/13] [pre-commit.ci] pre-commit autoupdate (#897) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/PyCQA/autoflake: v2.1.0 → v2.1.1](https://github.com/PyCQA/autoflake/compare/v2.1.0...v2.1.1) - [github.com/asottile/pyupgrade: v3.3.1 → v3.3.2](https://github.com/asottile/pyupgrade/compare/v3.3.1...v3.3.2) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 04c7814d..fb95c289 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/PyCQA/autoflake - rev: v2.1.0 + rev: v2.1.1 hooks: - id: autoflake args: ["--in-place", "--remove-unused-variables", "--remove-all-unused-imports"] @@ -26,7 +26,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/asottile/pyupgrade - rev: v3.3.1 + rev: v3.3.2 hooks: - id: pyupgrade args: [--py3-plus] From a338075c0bd6f95ce736f61e4d2010b11447db9b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 9 May 2023 05:16:48 +0000 Subject: [PATCH 07/13] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/pyupgrade: v3.3.2 → v3.4.0](https://github.com/asottile/pyupgrade/compare/v3.3.2...v3.4.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index fb95c289..aaf3d3fc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -26,7 +26,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/asottile/pyupgrade - rev: v3.3.2 + rev: v3.4.0 hooks: - id: pyupgrade args: [--py3-plus] From be1d5c401fe542fa6201959ef4fc3a4c6ff067a9 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Fri, 12 May 2023 10:36:32 -0300 Subject: [PATCH 08/13] Make collection progress output less verbose (#901) Fix #555 --- changelog/555.improvement.rst | 1 + src/xdist/dsession.py | 115 ++++++++++++++++++++++++++-------- testing/acceptance_test.py | 36 +++++++---- testing/test_dsession.py | 79 ++++++++++++++++++++++- 4 files changed, 190 insertions(+), 41 deletions(-) create mode 100644 changelog/555.improvement.rst diff --git a/changelog/555.improvement.rst b/changelog/555.improvement.rst new file mode 100644 index 00000000..f70ff53a --- /dev/null +++ b/changelog/555.improvement.rst @@ -0,0 +1 @@ +Improved progress output when collecting nodes to be less verbose. diff --git a/src/xdist/dsession.py b/src/xdist/dsession.py index a622b8bd..908f2700 100644 --- a/src/xdist/dsession.py +++ b/src/xdist/dsession.py @@ -1,3 +1,8 @@ +from __future__ import annotations +import sys +from enum import Enum, auto +from typing import Sequence + import pytest from xdist.remote import Producer @@ -251,14 +256,16 @@ def worker_collectionfinish(self, node, ids): self._session.testscollected = len(ids) self.sched.add_node_collection(node, ids) if self.terminal: - self.trdist.setstatus(node.gateway.spec, "[%d]" % (len(ids))) + self.trdist.setstatus( + node.gateway.spec, WorkerStatus.CollectionDone, tests_collected=len(ids) + ) if self.sched.collection_is_completed: if self.terminal and not self.sched.has_pending: self.trdist.ensure_show_status() self.terminal.write_line("") if self.config.option.verbose > 0: self.terminal.write_line( - "scheduling tests via %s" % (self.sched.__class__.__name__) + f"scheduling tests via {self.sched.__class__.__name__}" ) self.sched.schedule() @@ -345,7 +352,7 @@ def _handlefailures(self, rep): if rep.failed: self.countfailures += 1 if self.maxfail and self.countfailures >= self.maxfail: - self.shouldstop = "stopping after %d failures" % (self.countfailures) + self.shouldstop = f"stopping after {self.countfailures} failures" def triggershutdown(self): self.log("triggering shutdown") @@ -372,32 +379,51 @@ def handle_crashitem(self, nodeid, worker): self.config.hook.pytest_runtest_logreport(report=rep) +class WorkerStatus(Enum): + """Status of each worker during creation/collection.""" + + # Worker spec has just been created. + Created = auto() + + # Worker has been initialized. + Initialized = auto() + + # Worker is now ready for collection. + ReadyForCollection = auto() + + # Worker has finished collection. + CollectionDone = auto() + + class TerminalDistReporter: - def __init__(self, config): + def __init__(self, config) -> None: self.config = config self.tr = config.pluginmanager.getplugin("terminalreporter") - self._status = {} + self._status: dict[str, tuple[WorkerStatus, int]] = {} self._lastlen = 0 self._isatty = getattr(self.tr, "isatty", self.tr.hasmarkup) - def write_line(self, msg): + def write_line(self, msg: str) -> None: self.tr.write_line(msg) - def ensure_show_status(self): + def ensure_show_status(self) -> None: if not self._isatty: self.write_line(self.getstatus()) - def setstatus(self, spec, status, show=True): - self._status[spec.id] = status + def setstatus( + self, spec, status: WorkerStatus, *, tests_collected: int, show: bool = True + ) -> None: + self._status[spec.id] = (status, tests_collected) if show and self._isatty: self.rewrite(self.getstatus()) - def getstatus(self): + def getstatus(self) -> str: if self.config.option.verbose >= 0: - parts = [f"{spec.id} {self._status[spec.id]}" for spec in self._specs] - return " / ".join(parts) - else: - return "bringing up nodes..." + line = get_workers_status_line(list(self._status.values())) + if line: + return line + + return "bringing up nodes..." def rewrite(self, line, newline=False): pline = line + " " * max(self._lastlen - len(line), 0) @@ -409,37 +435,41 @@ def rewrite(self, line, newline=False): self.tr.rewrite(pline, bold=True) @pytest.hookimpl - def pytest_xdist_setupnodes(self, specs): + def pytest_xdist_setupnodes(self, specs) -> None: self._specs = specs for spec in specs: - self.setstatus(spec, "I", show=False) - self.setstatus(spec, "I", show=True) + self.setstatus(spec, WorkerStatus.Created, tests_collected=0, show=False) + self.setstatus(spec, WorkerStatus.Created, tests_collected=0, show=True) self.ensure_show_status() @pytest.hookimpl - def pytest_xdist_newgateway(self, gateway): - if self.config.option.verbose > 0: - rinfo = gateway._rinfo() + def pytest_xdist_newgateway(self, gateway) -> None: + rinfo = gateway._rinfo() + is_local = rinfo.executable == sys.executable + if self.config.option.verbose > 0 and not is_local: version = "%s.%s.%s" % rinfo.version_info[:3] self.rewrite( "[%s] %s Python %s cwd: %s" % (gateway.id, rinfo.platform, version, rinfo.cwd), newline=True, ) - self.setstatus(gateway.spec, "C") + self.setstatus(gateway.spec, WorkerStatus.Initialized, tests_collected=0) @pytest.hookimpl - def pytest_testnodeready(self, node): - if self.config.option.verbose > 0: - d = node.workerinfo + def pytest_testnodeready(self, node) -> None: + d = node.workerinfo + is_local = d.get("executable") == sys.executable + if self.config.option.verbose > 0 and not is_local: infoline = "[{}] Python {}".format( d["id"], d["version"].replace("\n", " -- ") ) self.rewrite(infoline, newline=True) - self.setstatus(node.gateway.spec, "ok") + self.setstatus( + node.gateway.spec, WorkerStatus.ReadyForCollection, tests_collected=0 + ) @pytest.hookimpl - def pytest_testnodedown(self, node, error): + def pytest_testnodedown(self, node, error) -> None: if not error: return self.write_line(f"[{node.gateway.id}] node down: {error}") @@ -457,3 +487,36 @@ def get_default_max_worker_restart(config): # if --max-worker-restart was not provided, use a reasonable default (#226) result = config.option.numprocesses * 4 return result + + +def get_workers_status_line( + status_and_items: Sequence[tuple[WorkerStatus, int]] +) -> str: + """ + Return the line to display during worker setup/collection based on the + status of the workers and number of tests collected for each. + """ + statuses = [s for s, c in status_and_items] + total_workers = len(statuses) + workers_noun = "worker" if total_workers == 1 else "workers" + if status_and_items and all(s == WorkerStatus.CollectionDone for s in statuses): + # All workers collect the same number of items, so we grab + # the total number of items from the first worker. + first = status_and_items[0] + status, tests_collected = first + tests_noun = "item" if tests_collected == 1 else "items" + return f"{total_workers} {workers_noun} [{tests_collected} {tests_noun}]" + if WorkerStatus.CollectionDone in statuses: + done = sum(1 for s, c in status_and_items if c > 0) + return f"collecting: {done}/{total_workers} {workers_noun}" + if WorkerStatus.ReadyForCollection in statuses: + ready = statuses.count(WorkerStatus.ReadyForCollection) + return f"ready: {ready}/{total_workers} {workers_noun}" + if WorkerStatus.Initialized in statuses: + initialized = statuses.count(WorkerStatus.Initialized) + return f"initialized: {initialized}/{total_workers} {workers_noun}" + if WorkerStatus.Created in statuses: + created = statuses.count(WorkerStatus.Created) + return f"created: {created}/{total_workers} {workers_noun}" + + return "" diff --git a/testing/acceptance_test.py b/testing/acceptance_test.py index 1666ba03..79fe2cd0 100644 --- a/testing/acceptance_test.py +++ b/testing/acceptance_test.py @@ -101,7 +101,12 @@ def test_skip(): """ ) result = pytester.runpytest(p1, "-v", "-d", "--tx=popen", "--tx=popen") - result.stdout.fnmatch_lines(["*1*Python*", "*2 failed, 1 passed, 1 skipped*"]) + result.stdout.fnmatch_lines( + [ + "created: 2/2 workers", + "*2 failed, 1 passed, 1 skipped*", + ] + ) assert result.ret == 1 def test_n1_fail_minus_x(self, pytester: pytest.Pytester) -> None: @@ -151,7 +156,12 @@ def test_skip(): """ ) result = pytester.runpytest(p1, "-d", "-v") - result.stdout.fnmatch_lines(["*2*Python*", "*2 failed, 1 passed, 1 skipped*"]) + result.stdout.fnmatch_lines( + [ + "created: 3/3 workers", + "*2 failed, 1 passed, 1 skipped*", + ] + ) assert result.ret == 1 def test_dist_tests_with_crash(self, pytester: pytest.Pytester) -> None: @@ -237,9 +247,6 @@ def pytest_load_initial_conftests(early_config): assert result.ret == 0 result.stdout.fnmatch_lines( [ - "*0* *cwd*", - # "RSyncStart: [G1]", - # "RSyncFinished: [G1]", "*1 passed*", ] ) @@ -276,7 +283,11 @@ def pytest_terminal_summary(terminalreporter): p1 = pytester.makepyfile("def test_func(): pass") result = pytester.runpytest("-v", p1, "-d", "--tx=popen") result.stdout.fnmatch_lines( - ["*0*Python*", "*calculated result is 49*", "*1 passed*"] + [ + "created: 1/1 worker", + "*calculated result is 49*", + "*1 passed*", + ] ) assert result.ret == 0 @@ -393,14 +404,14 @@ def test_ok(): out = result.stdout.str() if verbosity == "-v": assert "scheduling tests" in out - assert "gw" in out + assert "1 worker [1 item]" in out elif verbosity == "-q": assert "scheduling tests" not in out assert "gw" not in out assert "bringing up nodes..." in out else: assert "scheduling tests" not in out - assert "gw" in out + assert "1 worker [1 item]" in out def test_pass_skip_fail(self, pytester: pytest.Pytester) -> None: pytester.makepyfile( @@ -1099,8 +1110,9 @@ def test_this(i): result = pytester.runpytest(*args) assert "test session starts" in result.stdout.str() assert "\x1b[1m" in result.stdout.str() - assert "gw0 [10] / gw1 [10]" in result.stdout.str() - assert "gw0 C / gw1 C" not in result.stdout.str() + assert "created: 2/2 workers" in result.stdout.str() + assert "2 workers [10 items]" in result.stdout.str() + assert "collecting:" not in result.stdout.str() def test_without_terminal_plugin(pytester, request) -> None: @@ -1554,8 +1566,8 @@ def test_collection_crash(testdir): assert result.ret == 1 result.stdout.fnmatch_lines( [ - "gw0 I", - "gw0 [[]0[]]", + "created: 1/1 worker", + "1 worker [[]0 items[]]", "*_ ERROR collecting test_collection_crash.py _*", "E assert 0", "*= 1 error in *", diff --git a/testing/test_dsession.py b/testing/test_dsession.py index 20468e46..f809dc4a 100644 --- a/testing/test_dsession.py +++ b/testing/test_dsession.py @@ -1,7 +1,13 @@ -from xdist.dsession import DSession, get_default_max_worker_restart +from __future__ import annotations +from xdist.dsession import ( + DSession, + get_default_max_worker_restart, + get_workers_status_line, + WorkerStatus, +) from xdist.report import report_collection_diff from xdist.scheduler import EachScheduling, LoadScheduling, WorkStealingScheduling -from typing import Optional +from typing import Sequence import pytest import execnet @@ -473,7 +479,7 @@ def test_report_collection_diff_equal() -> None: def test_default_max_worker_restart() -> None: class config: class option: - maxworkerrestart: Optional[str] = None + maxworkerrestart: str | None = None numprocesses: int = 0 assert get_default_max_worker_restart(config) is None @@ -527,3 +533,70 @@ def test_2011_table(birth_year): reprec = pytester.inline_run("-n1") reprec.assertoutcome(passed=2) assert 0 + + +Created = WorkerStatus.Created +Initialized = WorkerStatus.Initialized +ReadyForCollection = WorkerStatus.ReadyForCollection +CollectionDone = WorkerStatus.CollectionDone + + +@pytest.mark.parametrize( + "status_and_items, expected", + [ + ( + [], + "", + ), + ( + [(Created, 0)], + "created: 1/1 worker", + ), + ( + [(Created, 0), (Created, 0)], + "created: 2/2 workers", + ), + ( + [(Initialized, 0), (Created, 0)], + "initialized: 1/2 workers", + ), + ( + [(Initialized, 0), (Initialized, 0)], + "initialized: 2/2 workers", + ), + ( + [(ReadyForCollection, 0), (Created, 0)], + "ready: 1/2 workers", + ), + ( + [(ReadyForCollection, 0), (ReadyForCollection, 0)], + "ready: 2/2 workers", + ), + ( + [(CollectionDone, 12), (Created, 0)], + "collecting: 1/2 workers", + ), + ( + [(CollectionDone, 12), (CollectionDone, 12)], + "2 workers [12 items]", + ), + ( + [(CollectionDone, 1), (CollectionDone, 1)], + "2 workers [1 item]", + ), + ( + [(CollectionDone, 1)], + "1 worker [1 item]", + ), + # Different number of tests collected will raise an error and should not happen in practice, + # but we test for it anyway. + ( + [(CollectionDone, 1), (CollectionDone, 12)], + "2 workers [1 item]", + ), + ], +) +def test_get_workers_status_line( + status_and_items: Sequence[tuple[WorkerStatus, int]], expected: str +) -> None: + assert get_workers_status_line(status_and_items) == expected From 37b9dbdbf4cdb1508d859f77f929ef0b75ee3aa4 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Fri, 12 May 2023 12:17:55 -0300 Subject: [PATCH 09/13] Deploy via a protected environment and using PyPI trusted publishers (#902) Following recent discussions, this changes the development process as follows: 1. The deploy is now manually triggered after the release PR is approved. 2. The deploy workflow tags the repository only after the package has been published to PyPI. 3. Use PyPI trusted publishers instead of API tokens. Co-authored-by: Ran Benita --- .github/workflows/deploy.yml | 56 ++++++++++++++++++++++-------------- RELEASING.rst | 12 ++------ 2 files changed, 38 insertions(+), 30 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index d30f5081..6111ae1d 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,33 +1,47 @@ name: deploy on: - push: - tags: - - "v*" + workflow_dispatch: + inputs: + version: + description: 'Release version' + required: true + default: '1.2.3' jobs: - deploy: + package: runs-on: ubuntu-latest + env: + SETUPTOOLS_SCM_PRETEND_VERSION: ${{ github.event.inputs.version }} steps: - uses: actions/checkout@v3 + + - name: Build and Check Package + uses: hynek/build-and-inspect-python-package@v1.5 + + deploy: + needs: package + runs-on: ubuntu-latest + environment: deploy + permissions: + id-token: write # For PyPI trusted publishers. + contents: write # For tag. + + steps: + - uses: actions/checkout@v3 + + - name: Download Package + uses: actions/download-artifact@v3 with: - # Needed to fetch tags, which are required by setuptools-scm. - fetch-depth: 0 - - name: Set up Python - uses: actions/setup-python@v2 - with: - python-version: "3.10" - - name: Install build - run: | - python -m pip install --upgrade pip - pip install build - - name: Build package - run: | - python -m build + name: Packages + path: dist + - name: Publish package to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 - with: - user: __token__ - password: ${{ secrets.pypi_token }} + uses: pypa/gh-action-pypi-publish@v1.8.5 + + - name: Push tag + run: | + git tag --annotate --message=v${{ github.event.inputs.version }} v${{ github.event.inputs.version }} ${{ github.sha }} + git push origin v${{ github.event.inputs.version }} diff --git a/RELEASING.rst b/RELEASING.rst index 5cfd7c01..62ce0030 100644 --- a/RELEASING.rst +++ b/RELEASING.rst @@ -32,14 +32,8 @@ To publish a new release ``X.Y.Z``, the steps are as follows: $ tox -e release -- X.Y.Z -#. Commit and push the branch for review. +#. Commit and push the branch to ``upstream`` and open a PR. -#. Once PR is **green** and **approved**, create and push a tag:: +#. Once the PR is **green** and **approved**, start the ``deploy`` workflow manually from the branch ``release-VERSION``, passing ``VERSION`` as parameter. - $ export VERSION=X.Y.Z - $ git tag v$VERSION release-$VERSION - $ git push git@github.com:pytest-dev/pytest-xdist.git v$VERSION - -That will build the package and publish it on ``PyPI`` automatically. - -#. Merge the release PR to `master`. +#. Merge the release PR to ``master``. From 103ee05f010bcf51df278ffaffbd38be256060de Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Fri, 12 May 2023 12:24:33 -0300 Subject: [PATCH 10/13] Release 3.3.0 --- CHANGELOG.rst | 9 +++++++++ changelog/555.improvement.rst | 1 - 2 files changed, 9 insertions(+), 1 deletion(-) delete mode 100644 changelog/555.improvement.rst diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 4a105115..6501b120 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,3 +1,12 @@ +pytest-xdist 3.3.0 (2023-05-12) +=============================== + +Features +-------- + +- `#555 `_: Improved progress output when collecting nodes to be less verbose. + + pytest-xdist 3.2.1 (2023-03-12) =============================== diff --git a/changelog/555.improvement.rst b/changelog/555.improvement.rst deleted file mode 100644 index f70ff53a..00000000 --- a/changelog/555.improvement.rst +++ /dev/null @@ -1 +0,0 @@ -Improved progress output when collecting nodes to be less verbose. From fa08e0987bea6a094deb48fda6b61d37373b4520 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Fri, 12 May 2023 17:28:15 -0300 Subject: [PATCH 11/13] Add check-package step also to 'test' workflow This ensures we do not have any surprises when we try to deploy, which uses the same step to generate the package. --- .github/workflows/test.yml | 8 ++++++++ setup.cfg | 1 + 2 files changed, 9 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7f6effe6..a350ca6d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,6 +10,14 @@ on: - "*" jobs: + + check-package: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Build and Check Package + uses: hynek/build-and-inspect-python-package@v1.5 + test: runs-on: ${{ matrix.os }} diff --git a/setup.cfg b/setup.cfg index 3162a908..77346ade 100644 --- a/setup.cfg +++ b/setup.cfg @@ -2,6 +2,7 @@ name = pytest-xdist description = pytest xdist plugin for distributed testing, most importantly across multiple CPUs long_description = file: README.rst +long_description_content_type = text/x-rst license = MIT author = holger krekel and contributors author_email = pytest-dev@python.org,holger@merlinux.eu From 657ba9ac7fe5f58930f7ed39c359893469c65936 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Fri, 12 May 2023 17:30:53 -0300 Subject: [PATCH 12/13] Only test on-push for master and a specific branch name This avoids testing twice when pushing to the main repository, once for the push, and another for a PR. --- .github/workflows/test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a350ca6d..05de2b21 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -3,7 +3,8 @@ name: test on: push: branches: - - "*" + - master + - "test-me-*" pull_request: branches: From f5b4a5d6edea6a9eb016730f5de0aae8cbc9930e Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Fri, 12 May 2023 17:31:35 -0300 Subject: [PATCH 13/13] Configure 'test' workflow to cancel running jobs for the branch --- .github/workflows/test.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 05de2b21..f4044017 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,6 +10,11 @@ on: branches: - "*" +# Cancel running jobs for the same workflow and branch. +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: check-package: