Skip to content

Commit a68a2f0

Browse files
authored
chore(deps): quarterly batch dependency upgrade 2026-Q2 (#995)
* initial commit * use xrpld:develop image * fix tests * chore(deps): upgrade requests from 2.32.4 to 2.33.1 * chore(deps): upgrade sphinx-rtd-theme from 3.0.2 to 3.1.0 * chore(deps): upgrade packaging from 25.0 to 26.2 * chore(deps): upgrade types-deprecated from 1.2.15.20241117 to 1.3.1.20260408 * chore(deps): upgrade poethepoet from 0.30.0 to 0.37.0 * update dependencies * make explanation brief
1 parent 8879e95 commit a68a2f0

10 files changed

Lines changed: 621 additions & 267 deletions

File tree

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ small
4343

4444
[node_db]
4545
type=NuDB
46-
path=/var/lib/rippled/db/nudb
46+
path=/var/lib/xrpld/db/nudb
4747
advisory_delete=0
4848

4949
# How many ledgers do we want to keep (history)?
@@ -58,10 +58,10 @@ online_delete=256
5858
256
5959

6060
[database_path]
61-
/var/lib/rippled/db
61+
/var/lib/xrpld/db
6262

6363
[debug_logfile]
64-
/var/log/rippled/debug.log
64+
/var/log/xrpld/debug.log
6565

6666
[sntp_servers]
6767
time.windows.com
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Batch Dependency Upgrade
2+
3+
Batches all open Dependabot PRs into a single upgrade PR.
4+
5+
## Prerequisites
6+
7+
- `pyenv` installed with Python versions matching the CI matrix (see `.github/workflows/unit_test.yml`)
8+
- `poetry` installed (the project uses Poetry for dependency management)
9+
- Docker daemon running — the skill starts a rippled container for integration tests
10+
11+
## Usage
12+
13+
From the xrpl-py repo root, start a new Claude Code session and run:
14+
15+
```
16+
/batch-deps-upgrade
17+
```
18+
19+
## What it does
20+
21+
1. Discovers all open Dependabot PRs via `gh pr list`
22+
2. Applies upgrades to `pyproject.toml`, runs `poetry lock` and `poetry install`
23+
3. Validates with lint, type-check, unit tests, integration tests, and faucet tests across all CI Python versions
24+
4. Generates output files and a commit message for the human to use
25+
26+
## Python version testing
27+
28+
The skill reads the CI workflow files to determine which Python versions to test against. It uses `pyenv` and `poetry env use` to switch between versions, matching the CI matrix exactly. Lint and type-check run on a single version; unit, integration, and faucet tests run across the full matrix.
29+
30+
## After it finishes
31+
32+
1. Review the changes and generated files. Ask Claude questions about specific changes if they don't make sense — the code changes may need multiple rounds of discussion and correction before they're ready.
33+
2. Stage and commit using the suggested commit message (the skill already creates a branch)
34+
3. Push and open a PR using the generated PR description
35+
4. After merge, close the superseded Dependabot PRs listed in the description
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
---
2+
name: batch-deps-upgrade
3+
description: Batch all open Dependabot dependency upgrade PRs into a single PR
4+
disable-model-invocation: true
5+
---
6+
7+
Batch all open Dependabot dependency upgrade PRs into a single PR for this repository.
8+
9+
## Step 1: Discover
10+
11+
Run: gh pr list --repo XRPLF/xrpl-py --label dependencies --state open --limit 500 --json number,title,headRefName,body,url
12+
13+
Parse each PR to extract package names and versions. Dependabot PRs come in two formats:
14+
15+
- **Single-package PRs**: title is `bump <pkg> from <old> to <new>` — parse from title
16+
- **Grouped PRs**: title is `bump <pkg1> and <pkg2>` with no versions — parse from PR body, which contains a structured list of package updates with version ranges
17+
18+
If any PR can't be parsed from either title or body, flag it for manual review. Build a table of all proposed upgrades. Report the table to the user before proceeding.
19+
20+
## Step 2: Apply all upgrades
21+
22+
1. Create a branch from main: `deps/batch-deps-upgrade-YYYY-QN` (use current year and quarter)
23+
2. Check for **dependency conflicts** before upgrading. For each proposed upgrade, review `pyproject.toml` constraints and run `poetry show <pkg>` to check if any other dependency pins a version range that would block the upgrade. Mark conflicts as Skipped (dependency conflict: <details>) and do not attempt them.
24+
3. For each remaining dependency, apply the upgrade:
25+
- **Direct deps** (listed in `pyproject.toml` under `[tool.poetry.dependencies]` or `[tool.poetry.group.dev.dependencies]`): update the version constraint in `pyproject.toml` to the new version using caret (`^<new_version>`), then run `poetry update <pkg>`. Always update `pyproject.toml` for direct deps — even if the current constraint already allows the new version — so the pinned minimum stays current.
26+
- **Transitive deps** (not in `pyproject.toml`): run `poetry update <pkg>` to update within the existing constraint range
27+
4. After all upgrades are applied, run `poetry lock` to regenerate `poetry.lock`. **Do NOT delete `poetry.lock` and regenerate from scratch**.
28+
5. Run `poetry install` to sync the virtual environment.
29+
6. Diff `pyproject.toml` and `poetry.lock` against main to classify each Dependabot PR as:
30+
- Upgraded: version changed
31+
- No-op: version was already current or newer
32+
7. If any upgrade changes the public API of the library (new errors, changed return types, removed functionality) and results in a breaking change, add an entry under `## [Unreleased]` in `CHANGELOG.md`.
33+
8. Verify completeness: every PR from Step 1 must have a status (Upgraded, No-op, or Skipped). If any PR is unaccounted for, stop and report it before proceeding.
34+
35+
## Step 3: Validate
36+
37+
Run the **full validation suite across all Python versions** from the CI matrix. Repeat until everything passes.
38+
39+
### Determine Python versions
40+
41+
Read each workflow file under `.github/workflows/` to determine the Python versions used:
42+
43+
- `.github/workflows/unit_test.yml` — the `unit-test` job uses a matrix of Python versions; the `lint-and-type-check` job uses a single Python version (not a matrix)
44+
- `.github/workflows/integration_test.yml` — the `integration-test` job uses a matrix of Python versions
45+
- `.github/workflows/faucet_test.yml` — the `faucet-test` job uses a matrix of Python versions
46+
47+
Extract the exact Python versions from each workflow's `matrix.python-version` array (or the `PYTHON_VERSION` env var for lint). These versions are the source of truth for validation.
48+
49+
### Switching between Python versions
50+
51+
To switch Python versions for testing, use `pyenv` and `poetry`:
52+
53+
```bash
54+
pyenv install <version> # install if not already present
55+
pyenv local <version> # set the local Python version
56+
poetry env use python<version> # point poetry to the correct interpreter
57+
poetry install # reinstall deps for this interpreter
58+
```
59+
60+
Replace `<version>` with the target version (e.g. `3.10`, `3.11`, `3.12`, `3.13`, `3.14`). After running all tests for one version, repeat these steps to switch to the next.
61+
62+
### Validation order
63+
64+
Run validation **in parallel across all Python versions** from the unit test matrix to speed things up. For each Python version, create a separate working directory (e.g. using `git worktree` or by spawning parallel agents) so that each version's virtual environment does not interfere with the others.
65+
66+
For each Python version, run the following in order:
67+
68+
1. **Lint and type-check** (only on the single lint Python version from the `lint-and-type-check` job):
69+
70+
```bash
71+
poetry run poe lint
72+
poetry run mypy --strict --implicit-reexport xrpl
73+
```
74+
75+
2. **Unit tests**:
76+
77+
```bash
78+
poetry run poe test_unit
79+
poetry run coverage report --fail-under=85
80+
```
81+
82+
3. **Integration tests** (requires a single shared xrpld Docker container — start it once before running integration tests for any Python version):
83+
- Pre-run cleanup: `docker rm -f xrpld-service 2>/dev/null || true`
84+
- Start the container:
85+
```bash
86+
docker run \
87+
--detach \
88+
--publish 5005:5005 \
89+
--publish 6006:6006 \
90+
--volume "$PWD/.ci-config/:/etc/opt/xrpld/" \
91+
--name xrpld-service \
92+
rippleci/xrpld:develop --standalone
93+
```
94+
- Wait for port 6006 with a bounded timeout:
95+
```bash
96+
SECONDS=0
97+
until nc -z localhost 6006 || [ $SECONDS -gt 120 ]; do sleep 2; done
98+
if ! nc -z localhost 6006; then
99+
echo "Error: xrpld did not start within 120s"
100+
docker logs xrpld-service
101+
exit 1
102+
fi
103+
```
104+
- Run for each Python version:
105+
```bash
106+
poetry run poe test_integration
107+
poetry run coverage report --fail-under=70
108+
```
109+
- Stop container after all versions complete: `docker logs xrpld-service && docker stop xrpld-service`
110+
111+
4. **Faucet tests**:
112+
```bash
113+
poetry run poe test_faucet
114+
```
115+
116+
Collect results from all parallel runs. All Python versions must pass.
117+
118+
### Handling failures
119+
120+
If any step fails, **attempt to fix the breaking change with code modifications before rolling back**. Common patterns:
121+
122+
- **Type annotation changes**: newer versions of type stubs or mypy may require updated annotations. Fix the annotations.
123+
- **Deprecated API removals**: if an upgraded dependency removes a previously deprecated function, update calls to use the replacement API.
124+
- **Import path changes**: some packages reorganize their module structure on major bumps. Update import statements.
125+
- **Test compatibility**: if a test utility changes behavior (e.g., aiounittest, coverage), update test configuration or code accordingly.
126+
127+
Only roll back and mark as Skipped if:
128+
129+
- The fix requires a large-scale migration across the codebase
130+
- The upgrade is blocked by an external dependency constraint you cannot update
131+
132+
If a failure is traced to a specific dependency upgrade, revert that upgrade in `pyproject.toml`, re-run `poetry lock && poetry install`, mark it as Skipped, and re-run validation until green.
133+
134+
## Step 4: Generate Outputs
135+
136+
After all upgrades are applied and validation passes, generate the following outputs:
137+
138+
### 4a. Code changes note
139+
140+
Write `.claude/skills/batch-deps-upgrade/code-changes.md` documenting every non-`pyproject.toml` source code change, explaining what broke, why, and the minimal fix applied.
141+
142+
### 4b. PR description
143+
144+
Write `.claude/skills/batch-deps-upgrade/pr-description.md` following the repo's PR template (`.github/pull_request_template.md`):
145+
146+
- For "High Level Overview of Change", summarize the batch upgrade.
147+
- For "Context of Change", explain that this batches Dependabot PRs to reduce merge noise.
148+
- For "Type of Change", determine dynamically:
149+
- Check "Breaking change" ONLY if any upgrade visibly changes the library's public API (e.g., error messages, return types, removed functions). This aligns with whether a `CHANGELOG.md` entry was added in Step 2.7.
150+
- Otherwise, do not check any Type of Change — dependency upgrades are maintenance and don't fit "Refactor" (which means restructuring code without behavior change). Note in the PR body that the upgrade is maintenance.
151+
- For "Did you update CHANGELOG.md?", check "Yes" if an entry was added, otherwise check "No, this change does not impact library users".
152+
- Include a "Superseded Dependabot PRs" section with a table: PR (linked), Package, From, To, Status, MajorVersionUpgrade
153+
- Status values: Upgraded, No-op (reason), Skipped (dependency conflict / CI failure: error)
154+
- MajorVersionUpgrade: `No` if the major version number did not change. Otherwise `Yes` plus a link for each major version crossed. For example, 1.x → 3.x yields `Yes ([v2](url), [v3](url))`. Each link should point to the package's release notes or changelog for that major version. Verify each link returns HTTP 200 and has meaningful content (e.g., `curl -sL -o /dev/null -w "%{http_code}" <url>`); if a package doesn't publish per-version GitHub releases, fall back to the CHANGELOG file or the closest valid release tag.
155+
- For every **major version upgrade**, add a "Major version upgrade notes" section below the table. For each major-version package, include:
156+
- A link to the release notes
157+
- A brief summary of key changes (breaking changes, deprecations, new features)
158+
- An explanation of why no code changes were required, OR a summary of the code changes that were made. This helps reviewers understand the impact without having to read the full release notes themselves.
159+
- Closing instructions with two paragraphs:
160+
1. "After merging, close the following superseded PRs (Skipped ones remain open for future handling): #X, #Y, #Z" — list only Upgraded and No-op PRs.
161+
2. "The following PRs were Skipped and should remain open: #A (package-a), #B (package-b), ..." — annotate each with the package name. These stay open so Dependabot keeps rebasing them.

.github/workflows/integration_test.yml

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: Integration test
22

33
env:
44
POETRY_VERSION: 2.1.1
5-
RIPPLED_DOCKER_IMAGE: rippleci/rippled:develop
5+
XRPLD_DOCKER_IMAGE: rippleci/xrpld:develop
66

77
on:
88
push:
@@ -42,7 +42,13 @@ jobs:
4242

4343
- name: Run docker in background
4444
run: |
45-
docker run --detach --rm -p 5005:5005 -p 6006:6006 --volume "${{ github.workspace }}/.ci-config/":"/etc/opt/ripple/" --name rippled-service --health-cmd="rippled server_info || exit 1" --health-interval=5s --health-retries=10 --health-timeout=2s --env GITHUB_ACTIONS=true --env CI=true --entrypoint bash ${{ env.RIPPLED_DOCKER_IMAGE }} -c "mkdir -p /var/lib/rippled/db/ && rippled -a"
45+
docker run \
46+
--detach \
47+
--publish 5005:5005 \
48+
--publish 6006:6006 \
49+
--volume "${{ github.workspace }}/.ci-config/":"/etc/opt/xrpld/" \
50+
--name xrpld-service \
51+
${{ env.XRPLD_DOCKER_IMAGE }} --standalone
4652
4753
- name: Install poetry
4854
if: steps.cache-poetry.outputs.cache-hit != 'true'
@@ -70,4 +76,4 @@ jobs:
7076
7177
- name: Stop docker container
7278
if: always()
73-
run: docker stop rippled-service
79+
run: docker logs xrpld-service && docker stop xrpld-service

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,3 +135,5 @@ dmypy.json
135135

136136
# MacOS artifacts
137137
.DS_Store
138+
139+
.claude/worktrees/

CONTRIBUTING.md

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -87,21 +87,28 @@ poetry run poe test_unit
8787

8888
#### Integration Tests
8989

90-
To run integration tests, you'll need a standalone rippled node running with WS port `6006` and JSON RPC port `5005`. You can run a docker container for this:
90+
To run integration tests, you'll need a standalone `xrpld` node running with WS port `6006` and JSON RPC port `5005`. You can run a docker container for this:
9191

9292
```bash
93-
docker run -dit -p 5005:5005 -p 6006:6006 --volume $PWD/.ci-config/:/etc/opt/ripple/ --entrypoint bash rippleci/rippled:develop -c 'mkdir -p /var/lib/rippled/db/ && rippled -a'
93+
docker run \
94+
--detach \
95+
--publish 5005:5005 \
96+
--publish 6006:6006 \
97+
--volume "$PWD/.ci-config/:/etc/opt/xrpld/" \
98+
--name xrpld-service \
99+
rippleci/xrpld:develop --standalone
94100
```
95101

96102
Breaking down the command:
97103

98-
- `docker run -p 5005:5005 -p 6006:6006` starts a Docker container with an open port for admin JsonRPC and WebSocket requests.
99-
- `-it` allows you to interact with the container.
100-
- `-d` runs the docker container in detached mode. The container will run in the background and developer gets back control of the terminal
101-
- `-t` starts a terminal in the container for you to send commands to.
102-
- `--volume $PWD/.ci-config:/etc/opt/ripple/` mounts the directories as indicated. It must be an absolute path, so we use `$PWD` instead of `./`. `rippled` software searches the location `/etc/opt/ripple/` (default behavior) for the config files. Hence there is no need to explicitly specify the config-file path.
103-
- `rippleci/rippled:develop` is an image that is regularly updated with the latest build of the `develop` branch of `rippled`.
104-
- `-a` starts `rippled` in standalone mode
104+
- `--detach` — run in background
105+
- `--publish 5005:5005 --publish 6006:6006` — expose JSON-RPC and WebSocket ports
106+
- `--volume "$PWD/.ci-config/:/etc/opt/xrpld/"` — mount local config into the container
107+
- `--name xrpld-service` — name the container
108+
- `rippleci/xrpld:develop` — latest `develop` branch build of xrpld
109+
- `--standalone` — start xrpld in standalone mode
110+
111+
When you're done, stop and remove the container with `docker stop xrpld-service && docker rm xrpld-service`.
105112

106113
Then to actually run the tests, run the command:
107114

0 commit comments

Comments
 (0)