diff --git a/.github/workflows/changelog-checker.yaml b/.github/workflows/changelog-checker.yaml new file mode 100644 index 0000000..dd9533e --- /dev/null +++ b/.github/workflows/changelog-checker.yaml @@ -0,0 +1,43 @@ +name: Check Changelog Entry + +on: + pull_request: + types: [opened, synchronize, reopened, labeled, unlabeled] + +permissions: + contents: read + pull-requests: read + +jobs: + check-changelog: + if: > + !contains(github.event.pull_request.labels.*.name, 'no-changelog') && + github.event.pull_request.user.login != 'dependabot[bot]' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + with: + fetch-depth: 0 + - name: Check for direct CHANGES file edits + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_NUMBER: ${{ github.event.pull_request.number }} + REPO: ${{ github.repository }} + run: | + echo "Checking for changelog file in PR #$PR_NUMBER" + changed_files=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \ + "https://api.github.com/repos/$REPO/pulls/$PR_NUMBER/files" | jq -r '.[].filename') + echo "Changed files: $changed_files" + if echo "$changed_files" | grep -qE "^CHANGES\.rst$"; then + echo "Do not edit the changelog file directly." + echo "Create a new file in the \`changes\` directory, see \`changes/README.rst\` for details." + exit 1 + fi + - name: Set up Python + uses: actions/setup-python@v7 + with: + python-version: "3.x" + - name: Install towncrier + run: python -m pip install -U pip towncrier + - name: Check changelog entry + run: towncrier check --compare-with origin/${{ github.event.pull_request.base.ref }} diff --git a/CHANGES.rst b/CHANGES.rst index e0a9691..4aa1e68 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,32 +1,10 @@ Changelog ========= -16.5 (unreleased) ------------------ - -Bug fixes -+++++++++ - -- Prevent a rerun when a fixture teardown raises an error matching - ``--rerun-except``. Previously only the error from the current test stage - was considered, so a ``--rerun-except``-matching error raised during - teardown was ignored and the test was rerun anyway. - Fixes `#270 `_. - -- Create a new test class instance for each rerun. Previously the instance of - the failed attempt was reused, so state stored on ``self`` leaked into the - rerun and broke test isolation. Fixtures cached at class scope or higher are - still not re-executed. - Fixes `#268 `_. - -Features -++++++++ - -- Add ``--max-suite-reruns`` option to cap the total number of reruns across - the entire test suite. Once the limit is reached, no further reruns occur - regardless of per-test ``--reruns`` or ``@pytest.mark.flaky`` settings. - Fixes `#298 `_. +.. Do not edit this file manually any more, create a change log entry file in +.. the changes directory, see changes/README.rst for details. +.. towncrier release notes start 16.4 (2026-07-01) ----------------- diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 675b3e1..da323ef 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -37,5 +37,30 @@ Preparing Pull Requests #. Follow **PEP 8** for naming and `black `_ for formatting. -#. Add a line item to the current **unreleased** version in ``CHANGES.rst``, - unless the change is trivial. +#. Add a change log entry, unless the change is trivial. Do **not** edit + ``CHANGES.rst`` -- it is generated at release time. Instead create a file in + the ``changes/`` directory named after the GitHub issue or pull request + number, with an extension naming the kind of change, for example + ``changes/270.bugfix.rst``. See `changes/README.rst + `_ + for the available types and the expected style. + + +Making a release +---------------- + +Releases are made with `zest.releaser +`_ together with the +``zestreleaser.towncrier`` plugin, which runs ``towncrier build`` at the right +moment so ``CHANGES.rst`` is assembled from the files in ``changes/``:: + + $ pip install --group release + $ fullrelease + +``pip install --group release`` requires pip 25.1 or newer; with an older pip +use ``pip install "zest.releaser[recommended]" zestreleaser.towncrier`` +instead. + +To preview the change log for the next release without writing anything:: + + $ towncrier build --draft --version 17.0 diff --git a/MANIFEST.in b/MANIFEST.in index d32163a..87b645b 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -9,3 +9,6 @@ exclude *.yaml recursive-include docs *.py recursive-include docs *.rst recursive-include docs *.txt + +graft changes +prune changes diff --git a/changes/268.bugfix.rst b/changes/268.bugfix.rst new file mode 100644 index 0000000..e13ec3f --- /dev/null +++ b/changes/268.bugfix.rst @@ -0,0 +1 @@ +Create a new test class instance for each rerun. Previously the instance of the failed attempt was reused, so state stored on ``self`` leaked into the rerun and broke test isolation. Fixtures cached at class scope or higher are still not re-executed. diff --git a/changes/270.bugfix.rst b/changes/270.bugfix.rst new file mode 100644 index 0000000..9113b7f --- /dev/null +++ b/changes/270.bugfix.rst @@ -0,0 +1 @@ +Prevent a rerun when a fixture teardown raises an error matching ``--rerun-except``. Previously only the error from the current test stage was considered, so a ``--rerun-except``-matching error raised during teardown was ignored and the test was rerun anyway. diff --git a/changes/298.feature.rst b/changes/298.feature.rst new file mode 100644 index 0000000..d910681 --- /dev/null +++ b/changes/298.feature.rst @@ -0,0 +1 @@ +Add ``--max-suite-reruns`` option to cap the total number of reruns across the entire test suite. Once the limit is reached, no further reruns occur regardless of per-test ``--reruns`` or ``@pytest.mark.flaky`` settings. diff --git a/changes/README.rst b/changes/README.rst new file mode 100644 index 0000000..9f55e8d --- /dev/null +++ b/changes/README.rst @@ -0,0 +1,63 @@ +Writing change log entries +========================== + +.. caution:: + Do not edit the ``CHANGES.rst`` file manually, this file is now autogenerated + at release time. This prevents getting conflicts in that file during merge + time. + +File name +--------- + +To add an entry to the change log, take the number of the GitHub issue and you +create a file inside of the ``changes/`` directory, named after that issue +number with an extension telling the type of change, followed by ``.rst``. The +allowed types are: + +* ``feature``: You added a new feature. +* ``bugfix``: You fixed a bug. +* ``doc``: You improved the documentation. +* ``removal``: You deprecated or removed a public API. +* ``breaking``: You changed the public API in a way which requires changes in + the consumers of the API. +* ``misc``: You changed something which is of minor interest to the users of + this package, e. g. the development or test setup. + +Example: If your GitHub issue number is 270 and you fixed the bug reported +there, you create a file named ``270.bugfix.rst`` in the ``changes/`` +directory. You can also let towncrier create it for you:: + + $ towncrier create --content "Fix the thing." 270.bugfix + +If your pull request does not have an issue, use the number of the pull request +itself. + +Each type is rendered as a sub-headline in the change log. If your changes match +multiple types and should show up below different sub-headlines in the change +log or you resolved multiple issues just create multiple files in ``changes/``. +If the files contain the same text, the entries in the changelog will get +deduplicated. + +The part before the type must be the plain issue number -- do not add a +description to it, as it ends up in the change log as the issue reference. If +you need more than one entry of the *same* type for the *same* issue, append a +counter between the type and the extension, e. g. ``270.misc.rst`` and +``270.misc.2.rst``. The counter is only used to keep the file names unique and +to order the entries, it does not show up in the change log. + +Contents of a changes entry +--------------------------- + +In the contents of the file you tell what you have changed. You can use +reStructuredText markup here. Please do *not* repeat the issue number in the +file: the link to the GitHub issue is added automatically from the file name. + +Do not hard wrap the text of an entry: towncrier re-wraps each paragraph to fit +the change log, and hard wrapping produces a ragged result. + +In order to maintain a consistent style in the change log, it is preferred to +keep the entries to the point, in sentence case, and in an imperative tone -- an +entry should complete the sentence “This change will …”. In rare cases, where +one line is not enough, use a summary line in an imperative tone followed by a +blank line separating it from a description of the feature/change in one or more +paragraphs. diff --git a/pyproject.toml b/pyproject.toml index f452f10..0f38e11 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,6 +50,11 @@ entry-points.pytest11.rerunfailures = "pytest_rerunfailures" [dependency-groups] dev = [ "mypy>=2.1", + "towncrier>=25.8", +] +release = [ + "zest-releaser[recommended]>=9.9", + "zestreleaser-towncrier>=2", ] [tool.setuptools.dynamic] @@ -78,6 +83,28 @@ lint.pydocstyle.convention = "google" [tool.check-manifest] ignore = [ ".pre-commit-config.yaml" ] +[tool.towncrier] +directory = "changes" +filename = "CHANGES.rst" +title_format = "{version} ({project_date})" +issue_format = "`#{issue} `_" +underlines = [ + "-", + "+", + "~", +] +wrap = true +# An empty ignore list turns on strict validation of news fragment file names. +ignore = [ ] +type = [ + { directory = "breaking", name = "Breaking Changes", showcontent = true }, + { directory = "removal", name = "Deprecations and Removals", showcontent = true }, + { directory = "feature", name = "Features", showcontent = true }, + { directory = "bugfix", name = "Bug Fixes", showcontent = true }, + { directory = "doc", name = "Documentation", showcontent = true }, + { directory = "misc", name = "Misc", showcontent = true }, +] + [tool.mypy] python_version = "3.10" warn_return_any = true