renovate-apply
Apply the dependency updates Renovate finds, in your working copy, without a pull request. One commit per group, the same grouping your Renovate configuration gives a pull request. Nothing is pushed.
Full documentation: https://jbsilva.github.io/renovate-apply/
$ rnv
renovate-apply: scanning /home/you/infra ...
applied deps: update the atuin images
ghcr.io/atuinsh/atuin v18.13.3 -> 18.22.0
postgres 18-alpine, new digest
applied deps: update the hook revs
astral-sh/ruff-pre-commit v0.16.5 -> v0.16.8
crate-ci/typos v1.50.1 -> v1.50.2
Committed. Nothing is pushed.
Why this exists
Renovate can read a local working copy. renovate --platform=local finds every pending update and
reports it. It cannot write one: the local platform turns the run into a lookup-only dry run as it
starts, so the run ends after the lookup, before the step that edits a file. No flag turns that off,
because the clamp is inside the platform, not in the configuration.
So the updates Renovate finds on your laptop can only be applied by hand, or by merging the pull requests it opens on the server. This tool is the missing half: it runs that same scan, reads the JSON report, and makes the replacement the report describes for each update.
The edit is not guesswork. For every dependency, the report carries replaceString, the exact text
the manager found in the file, and autoReplaceStringTemplate, how to write that text again with
the new version or digest in it. That pair is Renovate's own auto-replace, handed over as data.
Highlights
- Works with everything Renovate's own managers report: image tags and digests in compose files and Dockerfiles, GitHub Actions SHA pins with their version comment, pre-commit and prek hook revs, versions matched by a custom regex manager, and the rest
- One commit per Renovate branch, so a grouped pull request and a local run produce the same commits
- Refreshes
uv.lockwhen it raises a floor inpyproject.toml, and commits the two together, the way Renovate's own pull request carries them - Reads your repository's Renovate configuration by running Renovate itself, so grouping, holds, package rules and versioning schemes all apply without being restated here
- Holds every major back until you ask for it
- Never skips your git hooks, and never commits anything it did not write
- Never leaves a
pyproject.tomlthat does not lock: such a group is undone and held back --dry-runto read first,--no-commitor--stageto review everything at once
Requirements
- Python 3.15+
git- Either
renovateonPATH(npm i -g renovate) or Node.js, fornpxto fetch it - Optional:
gh, logged in, orGITHUB_TOKENin the environment. Without a token, everything Renovate looks up on GitHub is rate limited, and updates can silently go missing. Prefer either to--token, which puts the token in argv and in your shell history.
Installation
uv tool install renovate-apply
Or run it without installing:
uvx renovate-apply --dry-run
Usage
$ renovate-apply --help
| Command | What it does |
|---|---|
rnv |
Scan, apply, one commit per group |
rnv --dry-run |
Say what would change and write nothing |
rnv --no-commit |
Write the files and stop, for one review of everything |
rnv --stage |
Write and stage the files, and commit nothing |
rnv --major |
Include the major updates, which are held back by default |
rnv --skip python |
Hold a dependency back by name, as a glob, repeatable |
rnv --prefix "build(deps):" |
Set the first word of every commit subject |
rnv --no-lock |
Do not refresh uv.lock after editing a pyproject.toml |
rnv ~/code/other-repo |
Work on another repository |
renovate-apply and rnv are the same command.
The working copy must be clean before a run that commits: a commit takes the whole index, not only the files this staged, so anything else in flight would be swept into a dependency commit.
Commit messages
The subject says what a person needs in git log --oneline; the body lists the group, aligned:
deps: update the action pins
astral-sh/setup-uv v10.1.0 -> v10.2.0
github/codeql-action v4.38.0 -> v4.38.2
docker/setup-buildx-action v4.3.0 -> v4.4.1
actions/upload-artifact v7.0.1 -> v7.0.2
Match --prefix to what your renovate.json5 writes, so local commits and merged pull requests
read alike: deps: for commitMessagePrefix, build(deps): for semantic commits.
Per-repository defaults
Any option can be set once, in the pyproject.toml of the repository being updated:
[tool.renovate-apply]
prefix = "build(deps):"
skip = ["python"]
The file is read from the directory being updated, so rnv ~/code/other-repo takes that
repository's settings and not those of wherever you happen to be standing. Only that directory is
read, never a parent of it, and a flag typed for one run wins over the file.
A repository without a pyproject.toml (an infrastructure repository, say) passes the flags
instead.
What is held back
Nothing is applied silently past a hold. Whatever is held is listed at the end of the run, with the reason:
- Majors, unless
--major. Renovate can be configured to send some majors to the dependency dashboard to be approved by hand. The report does not say which ones carry that flag, so holding every major is the only reading that cannot contradict your configuration. - Updates Renovate would not open yet, the ones still waiting out
minimumReleaseAge. A security fix bypasses that hold in Renovate, and bypasses it here too. - Renames, where Renovate wants to replace a dependency with a different one. That edit is not a version bump, and this tool does not write it.
- Lock file updates, where the range in the manifest already allows the new version, so only the
lock file beside it moves. There is no edit to make in the package file, and moving the lock file
takes that package manager. Only
uv.lockis refreshed here, after an edit to its manifest. - Updates that do not lock, where
uv lockfinds no solution for the new floor inpyproject.toml. The group is undone,uv.lockincluded, and uv's explanation is printed. - A line two managers found, when a regex manager in your Renovate configuration matches a line a built-in manager also reads. Renovate reports the line twice. The first update makes the edit, and the second is listed with it.
- Anything named in
--skip, as a glob. That is the answer to the blind spot above on an update that is not a major: a repository that keepsrequires-pythonon the dependency dashboard writesskip = ["python"]once and stops being asked.
Limits
dependencyDashboardApprovalis invisible. Renovate resolves it per package and the report does not carry it, so this tool cannot see which updates your configuration wants approved by hand. Holding every major covers the usual case;--skipcovers the rest.- Lock files: uv only. A
pyproject.tomlwith auv.lockbeside it is relocked and committed together. Any other package manager's lock file is left untouched, so run its update yourself. - Renovate's lock file maintenance is not applied. Those branches carry no dependency updates, so they are not in the report at all.
- A group that cannot be applied is reported and passed over. The groups after it are still applied and committed, and the run ends non-zero. Only a failure before the first group, such as a scan that did not run or a working copy that is not clean, ends the run with nothing done.
- The scan is a full Renovate run, so it takes as long as Renovate takes, usually under a minute.
- A dependency Renovate cannot look up is one this cannot apply. Everything upstream of the report is Renovate's own behavior, configuration included.
- This writes files and commits. It never pushes, never merges and never deploys.
Development
uv sync --group dev --group test
uv run pytest
uv run poe check
uv run poe docs # preview the documentation site
License
MIT. See LICENSE.
Metadata
Release files for renovate-apply 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| renovate_apply-0.1.1.tar.gz | 28.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| renovate_apply-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 59.3 kB
Release files / renovate_apply-0.1.1.tar.gz
| Download URL | renovate_apply-0.1.1.tar.gz |
|---|---|
| Size | 28.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
659a73c50e9e5b95acf25258c1f31e119c908d1ec6c6c44ef2a136e6607e8ac8
|
|
BLAKE2b-256 checksum How to use checksums |
9569452734a3ebf85a1d744865997e83a25a490ac2ba7f6801449eef0372b71e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.
Transparency logRelease files / renovate_apply-0.1.1-py3-none-any.whl
| Download URL | renovate_apply-0.1.1-py3-none-any.whl |
|---|---|
| Size | 31.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e58365e0d9d8a814ba1212b58257309a8e7b398daf13056bdcf1c5b7fb1c946f
|
|
BLAKE2b-256 checksum How to use checksums |
2e3aec49fefc7acac800aa0b6385dd8a86bd300bba4e6e35bff2098089be776a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.
Transparency log