diff --git a/.github/workflows/compatibility.yml b/.github/workflows/compatibility.yml index 34b96c0..fb1f1cc 100644 --- a/.github/workflows/compatibility.yml +++ b/.github/workflows/compatibility.yml @@ -24,9 +24,11 @@ jobs: - { os: ubuntu-24.04, python: '3.12', wheel: cp312-manylinux_x86_64 } - { os: ubuntu-24.04, python: '3.13', wheel: cp313-manylinux_x86_64 } - { os: ubuntu-24.04, python: '3.14', wheel: '' } + - { os: ubuntu-24.04, python: '3.15', wheel: cp315-manylinux_x86_64 } - { os: windows-2025, python: '3.12', wheel: cp312-win_amd64 } - { os: windows-2025, python: '3.13', wheel: cp313-win_amd64 } - { os: windows-2025, python: '3.14', wheel: '' } + - { os: windows-2025, python: '3.15', wheel: cp315-win_amd64 } defaults: run: shell: bash @@ -59,13 +61,14 @@ jobs: PY cp .github/scripts/amulet_leveldb_smoke.py amulet-src/tests/test_backport_smoke.py git -C amulet-src diff --check - - name: Setup Python + - name: Setup host Python + if: matrix.python != '3.15' uses: actions/setup-python@v6 with: python-version: ${{ matrix.python }} - name: Install cibuildwheel if: matrix.python != '3.14' - run: python -m pip install 'cibuildwheel~=4.1' + run: python -m pip install 'cibuildwheel==4.2.0' - name: Build and test Amulet wheel if: matrix.python != '3.14' env: @@ -81,6 +84,18 @@ jobs: uses: astral-sh/setup-uv@v7 with: enable-cache: true + - name: Download exact Endstone CPython 3.15 Wheel + if: matrix.python == '3.15' + uses: actions/download-artifact@v8 + with: + repository: EndstoneMC/endstone + run-id: 38045137884 + github-token: ${{ github.token }} + pattern: endstone-*-cp315-cp315-*.whl + path: endstone-dist + merge-multiple: true + skip-decompress: true + - name: Test installed EndKeep with matched Amulet run: | uv venv .venv --python '${{ matrix.python }}' @@ -89,15 +104,24 @@ jobs: else PYTHON=.venv/bin/python fi + if [[ "${{ matrix.python }}" == "3.15" ]]; then + if [[ "${{ runner.os }}" == "Windows" ]]; then + ENDSTONE_WHEEL="$(find endstone-dist -name '*cp315*win_amd64.whl' -print -quit)" + else + ENDSTONE_WHEEL="$(find endstone-dist -name '*cp315*manylinux*.whl' -print -quit)" + fi + test -n "$ENDSTONE_WHEEL" + uv pip install --python "$PYTHON" "$ENDSTONE_WHEEL" + fi # Fresh dependency resolution: do NOT seed the local Amulet build. - # This must fetch the exact published GitHub Release Wheel on 3.12/3.13. + # This must fetch the exact published GitHub Release Wheel on 3.12/3.13/3.15. uv pip install --python "$PYTHON" -e '.[dev]' "$PYTHON" - <<'PY' from importlib.metadata import distribution from packaging.requirements import Requirement requires = distribution("endstone-endkeep").requires or [] amulet = [Requirement(req) for req in requires if Requirement(req).name == "amulet-leveldb"] - assert len(amulet) == 5, [str(req) for req in amulet] + assert len(amulet) == 7, [str(req) for req in amulet] print("Packaged Amulet selectors:", *amulet, sep="\\n") PY uv pip check --python "$PYTHON" @@ -118,11 +142,11 @@ jobs: retention-days: 7 verified-backports: - name: Collect verified CPython 3.12/3.13 Wheels + name: Collect verified compatibility Wheels needs: full-matrix runs-on: ubuntu-24.04 steps: - - name: Download four tested wheel artifacts + - name: Download tested wheel artifacts uses: actions/download-artifact@v4 with: pattern: amulet-compat-* @@ -138,8 +162,8 @@ jobs: root = Path("dist") wheels = sorted(root.glob("*.whl")) - assert len(wheels) == 4, [p.name for p in wheels] - for abi in ("cp312", "cp313"): + assert len(wheels) == 6, [p.name for p in wheels] + for abi in ("cp312", "cp313", "cp315"): for platform in ("manylinux_", "win_amd64"): matches = [ p for p in wheels @@ -164,7 +188,7 @@ jobs: - name: Upload verified wheel set for review (not a GitHub Release) uses: actions/upload-artifact@v4 with: - name: amulet-backports-verified-four-wheels + name: amulet-backports-verified-six-wheels path: | dist/*.whl dist/SHA256SUMS diff --git a/AGENTS.md b/AGENTS.md index 3cbd7a4..5ad0ec6 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,7 +1,7 @@ # Working on EndKeep EndKeep is a Python plugin for Endstone that creates incremental backups of -Minecraft Bedrock worlds. EndKeep targets Python 3.12–3.14 +Minecraft Bedrock worlds. EndKeep targets Python 3.12–3.15 on Linux and Windows x86-64 with Endstone 0.11. For Endstone API usage, see [Endstone's documentation](https://endstone.dev/). @@ -36,11 +36,11 @@ uv run --no-sync pytest - Update user documentation for visible behavior changes. Explain what server owners need to do; keep internal implementation notes out of usage guides. - Do not create releases or rewrite version tags unless explicitly requested. -- Python 3.12/3.13 resolves pinned, SHA256-verified Amulet-LevelDB compatibility +- Python 3.12/3.13/3.15 resolves pinned, SHA256-verified Amulet-LevelDB compatibility Wheels from the dedicated GitHub Release. Test a clean EndKeep install without pre-installing the dependency. The upstream Amulet version metadata currently prevents regenerating a universal uv.lock; prefer `uv pip install` instead of `uv sync`. -- The six-combination compatibility workflow is not a substitute for +- The eight-combination compatibility workflow is not a substitute for testing real BDS worlds, especially NTFS crash and directory metadata durability. See [Contributing](CONTRIBUTING.md) and the diff --git a/CHANGELOG.md b/CHANGELOG.md index 99b4ff6..ed16cb1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [Unreleased] +### Added +- Support Python 3.15 on Linux and Windows x86-64 using SHA256-pinned Amulet-LevelDB 3.0.7a0 compatibility Wheels. +- Validate Python 3.15 against Endstone CPython 3.15 development Wheels in bds-test-lab. + ## [0.3.0] - 2026-10-10 ### Added diff --git a/README.md b/README.md index c9822c2..d6ed09e 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ without storing a complete world copy each time, and lets you restore an earlier ## Installation -Requires **Endstone 0.11** and **Python 3.12–3.14**. +Requires **Endstone 0.11** and **Python 3.12–3.15**. 1. Download the plugin `.whl` from [Releases](https://github.com/ReallocAll/endkeep/releases/latest). 2. Place it in the server's `plugins/` directory. diff --git a/pyproject.toml b/pyproject.toml index 3999881..5e16e41 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,12 +7,14 @@ name = "endstone-endkeep" dynamic = ["version"] dependencies = [ "endstone>=0.11,<0.12", - # Official upstream Wheel for Python 3.14; pinned, tested backports for 3.12 and 3.13. + # Official upstream Wheel for Python 3.14; SHA256-pinned compatibility Wheels for 3.12, 3.13 and 3.15. "amulet-leveldb==3.0.7a0; python_version == '3.14'", 'amulet-leveldb @ https://github.com/ReallocAll/endkeep/releases/download/amulet-leveldb-3.0.7a0-compat-cp312-cp313/amulet_leveldb-3.0.7a0%2B0.g736228e.dirty-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl#sha256=283e7e57e4d15d7ee59457a89db8c43be9a1cd85c7174844f3a1f1bd14d93bbd ; python_version == "3.12" and sys_platform == "linux" and platform_machine == "x86_64"', 'amulet-leveldb @ https://github.com/ReallocAll/endkeep/releases/download/amulet-leveldb-3.0.7a0-compat-cp312-cp313/amulet_leveldb-3.0.7a0%2B0.g736228e.dirty-cp312-cp312-win_amd64.whl#sha256=9033156a570ceef3613486a681b990f442788b636da1018838eb6ffdd3dca73f ; python_version == "3.12" and sys_platform == "win32" and platform_machine == "AMD64"', 'amulet-leveldb @ https://github.com/ReallocAll/endkeep/releases/download/amulet-leveldb-3.0.7a0-compat-cp312-cp313/amulet_leveldb-3.0.7a0%2B0.g736228e.dirty-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl#sha256=718d5ff3887b4d848f811a49ab6a7fe3e0b1f863821029190714c4ea5362d9fc ; python_version == "3.13" and sys_platform == "linux" and platform_machine == "x86_64"', 'amulet-leveldb @ https://github.com/ReallocAll/endkeep/releases/download/amulet-leveldb-3.0.7a0-compat-cp312-cp313/amulet_leveldb-3.0.7a0%2B0.g736228e.dirty-cp313-cp313-win_amd64.whl#sha256=28dc6037e3d16355a5120baba1ec61065d020f65500ca9de20d97deaaac0ab2f ; python_version == "3.13" and sys_platform == "win32" and platform_machine == "AMD64"', + 'amulet-leveldb @ https://github.com/ReallocAll/endkeep/releases/download/amulet-leveldb-3.0.7a0-compat-cp315/amulet_leveldb-3.0.7a0%2B0.g736228e.dirty-cp315-cp315-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl#sha256=7fec1e03a2d72d1c08944726c08909fd811cf7ad905e6f124cea581bcfc554ad ; python_version == "3.15" and sys_platform == "linux" and platform_machine == "x86_64"', + 'amulet-leveldb @ https://github.com/ReallocAll/endkeep/releases/download/amulet-leveldb-3.0.7a0-compat-cp315/amulet_leveldb-3.0.7a0%2B0.g736228e.dirty-cp315-cp315-win_amd64.whl#sha256=a54e2004f50b8fe5ac2a23edb7cd5c5e60fbc9a8d44fadf282e17b0d3416a611 ; python_version == "3.15" and sys_platform == "win32" and platform_machine == "AMD64"', "zstandard>=0.23,<1", "tomlkit>=0.13,<1", ] @@ -23,7 +25,7 @@ description = "Crash-safe logical incremental world backups for Endstone" readme = "README.md" license = { file = "LICENSE" } keywords = ["endstone", "minecraft", "bedrock", "backup", "leveldb"] -requires-python = ">=3.12,<3.15" +requires-python = ">=3.12,<3.16" classifiers = [ "License :: OSI Approved :: MIT License", "Operating System :: POSIX :: Linux", @@ -32,6 +34,7 @@ classifiers = [ "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", + "Programming Language :: Python :: 3.15", ] [project.optional-dependencies]