Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions docs/contributing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,28 @@ Clone you github fork repo locally and install errbot in development mode from t
From there, anytime you execute `errbot` it will run from the checked out version of Errbot with all your local
changes taken into account.

Updating the dependency lockfile
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Errbot ships a pinned dependency lockfile (``pylock.toml``) in `PEP 751`_ format,
generated by uv_ from the top-level dependencies declared in ``pyproject.toml``.
The lockfile is the source of truth for reproducible installs in CI and for
downstream consumers that want exact versions.

Regenerate the lockfile any time you change a dependency in ``pyproject.toml`` (or
to refresh the pinned versions). From the root of the repository::

# Install uv if you don't have it (https://docs.astral.sh/uv/)
pip install uv

# Recompile the lockfile from pyproject.toml, pinned to the project's
# minimum supported Python version so the resolution covers 3.10+.
uv pip compile pyproject.toml -o pylock.toml \
--format pylock.toml --python-version 3.10

Commit the resulting ``pylock.toml`` alongside your ``pyproject.toml`` change in
the same pull request so the two stay in sync.

Preparing your pull request
^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand All @@ -42,6 +64,56 @@ these guidelines as you open a pull request.
* If you can, please add tests for your code. We know large parts of our codebase
are missing tests, so we won't reject your code if it lacks tests, though.

Releasing Errbot
----------------

This section is for maintainers cutting a release. The flow assumes a CHANGES.rst
maintained by hand under a ``v9.9.9 (unreleased)`` heading on master.

Cutting a release
~~~~~~~~~~~~~~~~~

1. **Open a release PR** that does two edits:

- Bump ``errbot/version.py``::

VERSION = "X.Y.Z"

- Rename the unreleased heading in ``CHANGES.rst`` from ``v9.9.9 (unreleased)``
to ``vX.Y.Z (YYYY-MM-DD)`` and double-check the entries beneath it.

2. **Let CI gate the change.** The test ``tests/release_metadata_test.py`` skips on the
``9.9.9`` sentinel but, once ``version.py`` is bumped, asserts that ``CHANGES.rst``
contains a section heading for the new version. A release PR that forgets the heading
rename will fail this test before it can merge.

3. **Merge the release PR**, then run the release tooling from a clean checkout::

./tools/releases.sh

The script reruns the same pre-release gate, builds the sdist/wheel with
``python -m build``, and calls ``twine`` to publish to PyPI.

4. **Tag the commit** and push the tag::

git tag vX.Y.Z
git push origin vX.Y.Z

5. **Return master to dev mode** in a follow-up PR:

- Reset ``errbot/version.py`` to ``VERSION = "9.9.9"``.
- Add a fresh ``v9.9.9 (unreleased)`` heading at the top of ``CHANGES.rst``.

After this, the gate test goes back to skipping on master and the next release
cycle starts.

Refreshing the lockfile for a release
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

If dependency pins have changed since the previous release, regenerate
``pylock.toml`` (see `Updating the dependency lockfile`_) and include the result
in the release PR.

Contributing documentation & making changes to the website
----------------------------------------------------------

Expand Down Expand Up @@ -94,3 +166,5 @@ to ask your question on Stack Overflow, `tagged errbot
.. _repos.py: https://github.com/errbotio/errbot/blob/master/errbot/repos.py
.. _`issue tracker`: https://github.com/errbotio/errbot/issues/
.. _Gitter: https://gitter.im/errbotio/errbot
.. _uv: https://docs.astral.sh/uv/
.. _`PEP 751`: https://peps.python.org/pep-0751/
170 changes: 170 additions & 0 deletions pylock.toml

Large diffs are not rendered by default.

86 changes: 86 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
[build-system]
requires = ["setuptools>=77"]
build-backend = "setuptools.build_meta"

[project]
name = "errbot"
dynamic = ["version", "readme"]
description = "Errbot is a chatbot designed to be simple to extend with plugins written in Python."
authors = [{name = "errbot.io", email = "info@errbot.io"}]
license = "GPL-3.0-or-later"
license-files = ["COPYING"]
requires-python = ">=3.10"
keywords = ["xmpp", "irc", "slack", "hipchat", "gitter", "tox", "chatbot", "bot", "plugin", "chatops"]
classifiers = [
"Development Status :: 5 - Production/Stable",
"Topic :: Communications :: Chat",
"Topic :: Communications :: Chat :: Internet Relay Chat",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
]
dependencies = [
"setuptools>=78.1.1",
"flask==3.1.3",
"requests==2.32.5",
"jinja2==3.1.6",
"pyOpenSSL==26.1.0",
"colorlog==6.10.1",
"markdown==3.10.2",
"ansi==0.3.7",
"Pygments==2.20.0",
"pygments-markdown-lexer==0.1.0.dev39",
"dulwich==1.2.1",
"deepmerge==2.0",
'daemonize==2.5.0; sys_platform != "win32"',
]

[project.optional-dependencies]
slack = ["errbot-backend-slackv3==0.3.2"]
discord = ["err-backend-discord==3.0.1"]
mattermost = ["err-backend-mattermost==3.0.0"]
IRC = ["irc==20.5.0"]
telegram = ["python-telegram-bot==13.15"]
XMPP = [
"slixmpp==1.12.0; python_version < '3.11'",
"slixmpp==1.15.0; python_version >= '3.11'",
"pyasn1==0.6.3",
"pyasn1-modules==0.4.2",
]
test = ["pytest", "requests"]

[project.urls]
Homepage = "http://errbot.io/"

[project.scripts]
errbot = "errbot.cli:main"

[tool.setuptools.dynamic]
version = {attr = "errbot.version.VERSION"}
readme = {file = ["README.rst", "CHANGES.rst"], content-type = "text/x-rst"}

[tool.setuptools.packages.find]
include = ["errbot", "errbot.*"]

[tool.setuptools.package-data]
errbot = [
"backends/*.plug",
"backends/*.html",
"backends/styles/*.css",
"backends/images/*.svg",
"core_plugins/*.plug",
"core_plugins/*.md",
"core_plugins/templates/*.md",
"storage/*.plug",
"templates/initdir/example.py",
"templates/initdir/example.plug",
"templates/initdir/config.py.tmpl",
"templates/*.md",
"templates/new_plugin.py.tmpl",
]

[tool.ruff.lint.per-file-ignores]
"tests/borken_plugin/broken.py" = ["F401"]
160 changes: 0 additions & 160 deletions setup.py

This file was deleted.

38 changes: 38 additions & 0 deletions tests/release_metadata_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"""Release-time gate.

When ``errbot/version.py`` has been bumped past the dev sentinel ``9.9.9``,
``CHANGES.rst`` must contain a section heading for that version. On master
the sentinel keeps this test skipped; it only fires once a release is being
prepared (or a release branch is checked out), at which point it forces the
maintainer to update CHANGES.rst before the tag goes out.

This replaces the install-time check that lived in setup.py.
"""
import re
from pathlib import Path

import pytest

REPO_ROOT = Path(__file__).resolve().parent.parent
DEV_SENTINEL = "9.9.9"


def _read_version() -> str:
"""Read VERSION from errbot/version.py without importing the package."""
ns: dict = {}
exec((REPO_ROOT / "errbot" / "version.py").read_text(), ns)
return ns["VERSION"]


def test_changes_rst_has_section_for_current_version():
version = _read_version()
if version == DEV_SENTINEL:
pytest.skip(f"dev sentinel {DEV_SENTINEL} — no CHANGES.rst entry expected")

changes = (REPO_ROOT / "CHANGES.rst").read_text()
pattern = rf"^v?{re.escape(version)}\b"
assert re.search(pattern, changes, re.MULTILINE), (
f"CHANGES.rst is missing a section heading for version {version}. "
f"Rename the 'v{DEV_SENTINEL} (unreleased)' heading to the new "
"version, or add a new release section, before tagging."
)
4 changes: 2 additions & 2 deletions tools/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ These are support tools for the project
- creates a temporary directory, clones the repository, builds the python package, and prepares multi-arch docker images.
- **Requirements:**
- `git`
- `pipenv`
- `uv`
- `python 3.12`
- `podman` (for docker image builds)
- **Execution (macOS):**
1. **Pre-requisite:** Open `tools/releases.sh` and update the `RELEASE`, `BRANCH`, and `PYTHON_VERSION` variables to match the target release.
2. Ensure you have the requirements installed (e.g., `brew install pipenv podman`).
2. Ensure you have the requirements installed (e.g., `brew install uv podman`).
3. Make the script executable: `chmod +x tools/releases.sh`
4. Run the script from the project root: `./tools/releases.sh`
5. Follow the manual steps printed at the end of the script to complete the publication.
Loading
Loading