Skip to content
Merged
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
93 changes: 93 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
name: Release

# Pushing a tag like v5.0.10 builds the package, publishes it to PyPI with
# Trusted Publishing and creates the GitHub release. See RELEASING.md.

on:
push:
tags: ["v*"]

permissions:
contents: read

jobs:
build:
runs-on: ubuntu-24.04
permissions:
contents: read
id-token: write
attestations: write
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.13"
- run: python -m pip install -r requirements/build.txt
- name: Tag must match the package version
run: |
version=$(sed -n 's/^__version__ = "\(.*\)"$/\1/p' jsonrpcserver/__init__.py)
if [ "v$version" != "$GITHUB_REF_NAME" ]; then
echo "Tag $GITHUB_REF_NAME does not match __version__ $version"
exit 1
fi
- name: CHANGELOG must have an entry for this version
run: grep -q "^## ${GITHUB_REF_NAME#v}\b" CHANGELOG.md
- run: python -m build
- run: python -m twine check --strict dist/*
- run: check-wheel-contents dist/*.whl
- name: Metadata must not link to hijacked domains
run: python .github/scripts/check_metadata.py dist/*
- uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2
with:
subject-path: dist/*
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: dist
path: dist/
if-no-files-found: error

publish:
needs: build
runs-on: ubuntu-24.04
environment:
name: pypi
url: https://pypi.org/project/jsonrpcserver/
permissions:
id-token: write
steps:
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: dist
path: dist/
- uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2

github-release:
needs: publish
runs-on: ubuntu-24.04
permissions:
contents: write
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: dist
path: dist/
- name: Create the GitHub release from the CHANGELOG entry
env:
GH_TOKEN: ${{ github.token }}
run: |
version="${GITHUB_REF_NAME#v}"
awk -v v="## $version" '
index($0, v) == 1 { on = 1; next }
on && /^## / { exit }
on { print }
' CHANGELOG.md > notes.md
gh release create "$GITHUB_REF_NAME" dist/* \
--repo "$GITHUB_REPOSITORY" \
--title "$version" \
--notes-file notes.md \
--verify-tag
29 changes: 25 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

## 5.0.10

The first release since the project moved to
[bensynapse/jsonrpcserver](https://github.com/bensynapse/jsonrpcserver). It
fixes a security problem, so please upgrade. Code that works with 5.0.9 keeps
working, apart from the security fix and the "Behaviour changes" below.

### Security

When a method raised an exception it didn't catch, the error response sent to
Expand Down Expand Up @@ -93,6 +98,22 @@ it requests, and runs every code example in the docs. The websockets example
uses the current `websockets.asyncio` API (#287). A new Security page covers
the settings to check before exposing a server.

### Packaging

- A wheel is published as well as the source distribution, so installs no
longer have to build the package.
- The package metadata says it needs Python 3.8 or later, and lists 3.8 to
3.14. CI tests all of those, plus free-threaded 3.14.
- The project links on PyPI point to this repository and the new docs. The
old website domains belong to someone else now. Please don't follow links
to them from older releases.
- `jsonrpcserver.__version__` gives the version.
- The `test` extra now includes everything the tests need (`pytest-asyncio`
and `hypothesis` were missing). The `examples` extra is gone, because the
examples it was for are in the docs now, with their own requirements file.
- The build uses `pyproject.toml` with flit instead of `setup.py`. The
dependencies are the same as in 5.0.9.

### Deprecations

Three functions in `jsonrpcserver.response` have new names. The old names still
Expand Down Expand Up @@ -151,7 +172,7 @@ work in 5.x but give a `DeprecationWarning`, and will be removed in 6.0.

## 5.0.6 (Jan 14, 2022)

- Fix reversed Result Either type ([#227](https://github.com/explodinglabs/jsonrpcserver/pull/227)).
- Fix reversed Result Either type ([#227](https://github.com/bensynapse/jsonrpcserver/pull/227)).

## 5.0.5 (Nov 27, 2021)

Expand Down Expand Up @@ -185,9 +206,9 @@ A complete rebuild, with a few important usage changes.

## 4.2.0 (Nov 9, 2020)

- Add ability to use custom serializer and deserializer ([#125](https://github.com/explodinglabs/jsonrpcserver/pull/125))
- Add ability to use custom method name ([#127](https://github.com/explodinglabs/jsonrpcserver/pull/127))
- Deny additional parameters in json-rpc request ([#128](https://github.com/explodinglabs/jsonrpcserver/pull/128))
- Add ability to use custom serializer and deserializer ([#125](https://github.com/bensynapse/jsonrpcserver/pull/125))
- Add ability to use custom method name ([#127](https://github.com/bensynapse/jsonrpcserver/pull/127))
- Deny additional parameters in json-rpc request ([#128](https://github.com/bensynapse/jsonrpcserver/pull/128))

Thanks to deptyped.

Expand Down
2 changes: 0 additions & 2 deletions MANIFEST.in

This file was deleted.

68 changes: 68 additions & 0 deletions RELEASING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Releasing

Releases are published by `.github/workflows/release.yml` when a tag like
`v5.0.10` is pushed. It builds and checks the sdist and wheel, and attests
their build provenance. Then it uploads them to PyPI with Trusted Publishing
and creates the GitHub release from the CHANGELOG entry. Nobody needs a PyPI
token.

## One-time setup on PyPI

This needs an Owner or Maintainer role on the `jsonrpcserver` project on PyPI.

1. Open https://pypi.org/manage/project/jsonrpcserver/settings/publishing/
2. Under "Add a new publisher", choose **GitHub** and fill in exactly:

| Field | Value |
|---|---|
| Owner | `bensynapse` |
| Repository name | `jsonrpcserver` |
| Workflow name | `release.yml` |
| Environment name | `pypi` |

3. Click "Add".

The `pypi` environment already exists in the GitHub repo settings. It only
accepts deployments from tags matching `v*`. To require a manual approval
before each upload, add yourself under "Required reviewers" in
Settings → Environments → pypi.

## Each release

1. Merge a pull request that sets `__version__` in `jsonrpcserver/__init__.py`
and adds a `## <version>` section to CHANGELOG.md. The release workflow
fails if either is missing or they don't match the tag.
2. Tag the merge commit on main and push the tag:

```sh
git fetch origin
git tag -a v5.0.10 <commit> -m "5.0.10"
git push origin v5.0.10
```

3. Watch the "Release" workflow in the Actions tab.
4. Check the result:

```sh
curl -s https://pypi.org/pypi/jsonrpcserver/json | python3 -c \
"import sys, json; i = json.load(sys.stdin)['info']; print(i['version'], i['project_urls'])"
```

The release should have two files, a `.tar.gz` and a `.whl`.

## If the upload fails

- `invalid-publisher`: the PyPI publisher settings above don't match. Check
every field, including the `.yml` in the workflow name.
- `File already exists`: that version is already on PyPI, and PyPI never
allows the same file twice. Bump the version and tag again.

A failed run can be re-run from the Actions tab once the cause is fixed. If the
tag itself was wrong, delete it locally and on GitHub
(`git push origin :refs/tags/v5.0.10`) before tagging again. Never delete a tag
whose version reached PyPI.

## Docs

The docs site deploys itself from main through `.github/workflows/docs.yml`,
so it changes when the docs change, not at release time.
11 changes: 10 additions & 1 deletion jsonrpcserver/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
"""Use __all__ so mypy considers these re-exported."""
"""Process incoming JSON-RPC requests in Python.

Write methods with @method, then pass each request string to dispatch, or to
async_dispatch in an asyncio server. Documentation:
https://bensynapse.github.io/jsonrpcserver/
"""

# __all__ also tells type checkers that these names are re-exported.
__all__ = [
"Error",
"InvalidParams",
Expand Down Expand Up @@ -31,3 +37,6 @@
from .methods import method
from .result import Error, InvalidParams, Result, Success
from .server import serve

__version__ = "5.0.10"
"""The version of jsonrpcserver, as a string. Added in 5.0.10."""
71 changes: 71 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,73 @@
[build-system]
requires = ["flit_core>=3.12,<5"]
build-backend = "flit_core.buildapi"

[project]
name = "jsonrpcserver"
dynamic = ["version"]
description = "Process incoming JSON-RPC requests in Python"
readme = "README.md"
license = "MIT"
license-files = ["LICENSE"]
requires-python = ">=3.8"
authors = [
{name = "Beau Barker", email = "beau@explodinglabs.com"},
]
maintainers = [
{name = "bensynapse"},
]
keywords = ["json-rpc", "jsonrpc", "json-rpc-2.0", "rpc", "server"]
classifiers = [
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Programming Language :: Python :: Free Threading :: 3 - Stable",
"Programming Language :: Python :: Implementation :: CPython",
"Topic :: Internet",
"Topic :: Software Development :: Libraries :: Python Modules",
"Typing :: Typed",
]
# The same ranges as 5.0.9, so upgrading never forces a different jsonschema
# or oslash.
dependencies = [
"jsonschema<5",
"oslash<1",
]

[project.urls]
Homepage = "https://bensynapse.github.io/jsonrpcserver/"
Documentation = "https://bensynapse.github.io/jsonrpcserver/"
Repository = "https://github.com/bensynapse/jsonrpcserver"
Issues = "https://github.com/bensynapse/jsonrpcserver/issues"
Changelog = "https://github.com/bensynapse/jsonrpcserver/blob/main/CHANGELOG.md"

[project.optional-dependencies]
test = [
"hypothesis",
"pytest",
"pytest-asyncio",
"pytest-cov",
]

[tool.flit.sdist]
include = [
"CHANGELOG.md",
"docs/",
"mkdocs.yml",
"requirements/",
"tests/",
"tox.ini",
]

[tool.ruff]
target-version = "py38"

Expand Down Expand Up @@ -37,6 +107,7 @@ reportUnnecessaryTypeIgnoreComment = "error"

[tool.pytest.ini_options]
testpaths = ["tests"]
asyncio_default_fixture_loop_scope = "function"

[tool.coverage.run]
branch = true
Expand Down
47 changes: 0 additions & 47 deletions setup.py

This file was deleted.

9 changes: 9 additions & 0 deletions tests/test_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
"""__version__ must match the installed package metadata."""

from importlib.metadata import version

import jsonrpcserver


def test_version() -> None:
assert jsonrpcserver.__version__ == version("jsonrpcserver")