Skip to content

ci: switch from dependabot to renovate - #1075

Draft
nielspardon wants to merge 1 commit into
substrait-io:mainfrom
nielspardon:par-renovate
Draft

ci: switch from dependabot to renovate#1075
nielspardon wants to merge 1 commit into
substrait-io:mainfrom
nielspardon:par-renovate

Conversation

@nielspardon

@nielspardon nielspardon commented May 11, 2026

Copy link
Copy Markdown
Member

We are currently using dependabot which has a very limited feature set, for example it can not handle managing a pixi.lock file as demonstrated in https://github.com/substrait-io/substrait/actions/runs/25411815587/job/74535026421?pr=1072

Renovate is also free to use and a much more powerful dependency auto update tool compared to dependabot. It can handle pixi.lock files among other things like e.g. it could also be used to update Git submodules to tags instead of just the latest commit (https://docs.renovatebot.com/modules/manager/git-submodules/#updating-to-specific-tag-values).

It gives more flexibility and helps to address the issue with dependabot not handling the pixi.lock file properly.

Why this runs on our own GitHub Actions workers

Renovate only learned to refresh pixi.lock after bumping dependencies declared in pyproject.toml in renovatebot/renovate#44004, released in Renovate 44.0.0. Because pixi lock can execute arbitrary code from conda package hooks, that same change gated the behaviour behind the global allowedUnsafeExecutions option. That option is globalOnly, so it can never be set from a repository's renovate.json, and it is not allow-listed on the hosted Renovate App's workers.

The gate applies to the pixi manager too, as an explicit breaking change. So from Renovate 44.0.0 on, the hosted App would not refresh pixi.lock for any dependency update. Running Renovate ourselves is the only way to get dependency PRs whose lock file actually matches the manifest, which is the entire problem we set out to fix.

Changes

  • Adds a renovate.json config file configuring semantic commits as the commit style for Renovate and the commit type as build and scope as deps to match the dependabot style following: https://docs.renovatebot.com/configuration-options/#semanticcommitscope
    • :semanticCommitTypeAll(build) is needed for the build type to actually take effect. config:recommended pulls in :semanticPrefixFixDepsChoreOthers, which contributes a matchPackageNames: ["*"] rule setting the type to chore, and package rules override top-level config.
    • Groups pyproject.toml dependency bumps into one PR. The Python dev dependencies and the conda dependencies all share a single pixi.lock, so ungrouped PRs would each rewrite that file and conflict with one another as soon as the first one merges. Major bumps still get their own PR.
    • Disables updates to python. Renovate treats both requires-python and the [tool.pixi.dependencies] pin as dependencies, but changing the supported Python version is a project decision rather than a routine bump. Leaving it enabled also puts a pep440: failed to calculate newValue warning on the Dependency Dashboard, because the range >=3.13,<3.14 cannot be rewritten against a Python pre-release.
    • Enables the pre-commit manager, which is off by default. Our .pre-commit-config.yaml has drifted well behind pyproject.toml (for example ruff v0.8.4 there against >=0.15.22 here) and dependabot cannot see that file at all.
  • Adds a .github/workflows/renovate.yml workflow running self-hosted Renovate every three hours, plus a manual trigger with dry-run and log-level inputs for debugging. It authenticates as a GitHub App the same way release.yml already does, and grants allowedUnsafeExecutions: pixi so pixi.lock is kept in sync. The pinned Renovate version carries a # renovate: comment so Renovate keeps its own version up to date via the customManagers:githubActionsVersions preset.
  • Removes the dependabot.yml configuration file to disable dependabot.
  • Adds a commitlint ignore pattern for Renovate PR descriptions. The dependabot patterns stay for now because dependabot PRs opened before this change are still open.
  • Replaces chore: Configure Renovate #1074

Needed before this can be merged

A substrait-io-owned GitHub App has to be created and installed on this repository, with Contents, Issues, Pull requests, Checks and Commit statuses set to read and write, Workflows set to read and write, and Administration, Dependabot alerts, Members and Metadata set to read. The Workflows permission is required for Renovate to be able to open PRs that touch .github/workflows, which is what dependabot does for us today. Its client ID and private key then go into the RENOVATE_APP_CLIENT_ID and RENOVATE_APP_PRIVATE_KEY repository secrets.

The self-hosted workflow is removable later

A Renovate maintainer has confirmed that Mend will add pixi to allowedUnsafeExecutions on the hosted Renovate App once an internal review lands, at which point self-hosting is no longer required for pixi.lock to be refreshed. renovate.json is identical either way, so migrating later means deleting .github/workflows/renovate.yml and the two RENOVATE_APP_* secrets and installing the App, with no config change. Self-hosting in the meantime is what makes the lock file correct today.

The companion PRs for the other two pixi repositories are therefore config-only, relying on the hosted App: substrait-io/substrait-python#244 and substrait-io/substrait-packaging#52.

What changes about the PRs we receive

Renovate covers ground that our dependabot configuration never did, so expect a batch of new PRs on the first run:

  • The conda dependencies in [tool.pixi.dependencies], which dependabot's pip ecosystem never looked at. They are all within their declared ranges right now, so they only show up via lock file maintenance until one of them moves out of range.
  • go.mod, which had no dependabot ecosystem entry at all. Note that we have no Go job in CI, so those PRs arrive without coverage. Add "gomod": { "enabled": false } if we would rather not receive them.
  • The pre-commit hooks described above. Renovate attaches a note to those PRs saying the pre-commit manager is not supported by the pre-commit maintainers.

Dependencies declared as ranges only get a PR once the new version falls outside the range, so a quiet dependency like ruff>=0.15.22,<1 is expected rather than a sign that something is broken. lockFileMaintenance covers the rest by refreshing the transitive pins in pixi.lock weekly.


This change is Reviewable

@benbellick

Copy link
Copy Markdown
Member

Thanks @nielspardon. Can we include a description in the PR body for why we should switch from dependabot to renovate? I think it has something to do with how dependabot interacts with pixi but it would be great to have it in writing somewhere so we can reference it in the future if something comes up. Thank you!

@nielspardon

Copy link
Copy Markdown
Member Author

updated the description. let me know if the description looks good for you.

Comment thread .github/workflows/pr_title.yml Outdated
@@ -16,8 +16,11 @@ jobs:
echo 'module.exports = {
// Workaround for https://github.com/dependabot/dependabot-core/issues/5923

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this comment still relevant if we no longer use dependabot?

Comment thread renovate.json

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a way to validate that this works before merging?

@nielspardon nielspardon May 12, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been testing this on my private fork and I found that the current pixi support for Renovate is only covering the direct Pixi dependencies in [tool.pixi.dependencies] e.g. NodeJS which when it does update the version also updates the pixi.lock file: https://github.com/nielspardon/substrait/pull/5/changes

When it updates one of the dependencies in the dev dependency group in [dependency-groups] it does not update those using the Pixi manager and Renovate thus also not updating the pixi.lock file currently: https://github.com/nielspardon/substrait/pull/7/changes

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I logged a feature request with Renovate to help us fix this gap: renovatebot/renovate#43260

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI: Renovate also supports postUpgradeTasks if you are hosting it yourself. When using the hosted one with the Github App it does not allow custom commands for security reasons.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for investigating. Hopefully we can figure out something that will work for our setup.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need dependency groups? in our case, what's the difference between dependencies and a dev dependency group? isn't the whole thing a single dev environment anyway?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe we should discuss this in a separate issue. feels unrelated to switching from dependabot to renovate.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, just a possible shortcut 😆 doesn't really matter though if the issue is being addressed in renovate anyway

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue with Renovate is not caused by the dependencies being in a dependency group. We would have the same issue if they were regular Python dependencies in [project.dependencies] in pyproject.toml. The issue is that the pixi support in Renovate today would only update the pixi.lock file when suggesting a dependency update in pixi.toml or in [tool.pixi.dependencies] in pyproject.toml. This is better than dependabot which has no pixi support at all but wouldn't help since we are using pyproject.toml in this repo and no pixi.toml.

The PR I opened in Renovate which got one approval already makes sure the pixi.lock file gets updated when Python dependencies in pyproject.toml (outside of [tool.pixi.dependencies]) get bumped including dependency groups.

Whether we should declare the dependencies as project dependencies or in a dev dependency group is orthogonal in my opinion.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, when the Renovate "configure Renovate" / onboarding PR is raised, y'all will see what's pending from it - you can even put these config changes into that branch (requires write access to repo) and it'll update the PR description to show changes it'll make :)

Signed-off-by: Niels Pardon <par@zurich.ibm.com>
@nielspardon

Copy link
Copy Markdown
Member Author

I ran this end to end on my fork so we can see the behaviour before deciding. The setup there is identical to what this PR proposes, only the GitHub App is mine rather than a substrait-io one.

The result we were after: nielspardon#28 bumps protobuf from 6.33.1 to 6.33.6 in [dependency-groups] of pyproject.toml and regenerates pixi.lock in the same commit, across all four platforms. All 13 CI jobs pass, which also confirms the lock file that Renovate's pixi 0.75.0 produced is still readable by the pixi-version: v0.73.0 we pin in CI. The commit is authored by the App and signed (verified=true) because Renovate uses GitHub's commit API when running as an App.

From the run log, the part that the hosted App cannot do:

install-tool pixi 0.75.0
pixi lock --no-progress --color=never --quiet
  stderr: "✔ Updated lock file\nEnvironment: dev\n  ~ (pypi) protobuf  6.33.1  ->  6.33.6\n"
  updatedArtifacts: ["pixi.lock"]
  2 file(s) to commit

Dependency Dashboard: nielspardon#27 lists everything Renovate detected, including the rate-limited updates queued behind the default limit of two PRs per hour, and gives us checkboxes to pull any of them forward. Dependabot has no equivalent.

A few things the fork run surfaced that are worth knowing before review:

  • Renovate detects prefix-dev/pixi v0.73.0 from the pixi-version input in our workflows, so the pixi version CI uses gets kept up to date too.
  • The conda dependencies in [tool.pixi.dependencies] are all inside their declared ranges right now, so they produce no PR of their own. lockFileMaintenance is what refreshes their pins in pixi.lock, and it is queued on the dashboard.
  • Leaving python updatable put a pep440: failed to calculate newValue warning in the dashboard's Repository Problems, because >=3.13,<3.14 cannot be rewritten against the 3.15.0b4 pre-release. The config in this PR disables python updates, which removes the warning and also keeps the supported Python version a deliberate decision rather than a routine bump.
  • The github-actions manager needs the App to have Workflows: read+write, otherwise Renovate silently cannot open PRs for anything under .github/workflows, which is a job dependabot currently does for us.

@benbellick to answer your earlier question about the commitlint comment: the dependabot ignore patterns still need to stay, because #1061, #1092, #1125, #1126 and #1135 were opened by dependabot and would start failing the PR Title Check without them. I have scoped the dependabot-core link to just those two patterns and added a separate one for Renovate. We can drop the dependabot patterns once those PRs are closed out.

One correction to my earlier comments on this PR: I said the gap was that Renovate only updated pixi.lock for [tool.pixi.dependencies]. That is fixed now, but as of Renovate 44.0.0 the gate applies to the pixi manager as well, so the hosted App now refreshes pixi.lock for nothing at all. Self-hosting is what makes it work, not merely what makes it work better.

@jamietanna

Copy link
Copy Markdown

That is fixed now, but as of Renovate 44.0.0 the gate applies to the pixi manager as well, so the hosted App now refreshes pixi.lock for nothing at all. Self-hosting is what makes it work, not merely what makes it work better.

When I get an internal PR review, we'll be setting allowedUnsafeExecutions=[..., "pixi"] so you'll be able to use pixi lock on the Mend-hosted apps, no need to self-host (unless you want to!)

@nielspardon

Copy link
Copy Markdown
Member Author

That is fixed now, but as of Renovate 44.0.0 the gate applies to the pixi manager as well, so the hosted App now refreshes pixi.lock for nothing at all. Self-hosting is what makes it work, not merely what makes it work better.

When I get an internal PR review, we'll be setting allowedUnsafeExecutions=[..., "pixi"] so you'll be able to use pixi lock on the Mend-hosted apps, no need to self-host (unless you want to!)

That's great to hear. Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants