Skip to content

[build] Move dependency updates into a weekly workflow - #17934

Merged
titusfortner merged 2 commits into
trunkfrom
weekly-dependency-updates
Aug 21, 2026
Merged

titusfortner merged 2 commits into
trunkfrom
weekly-dependency-updates

Conversation

@titusfortner

@titusfortner titusfortner commented Aug 21, 2026

Copy link
Copy Markdown
Member

🔗 Related Issues

Finishes work from #17450

💥 What does this PR do?

  • Moves dependency updates from release process into a new weekly Dependency Updates workflow which creates an Automated Updates PR
  • If the PR cannot be created for some reason a Slack message will be sent notifying of the problem.

🔧 Implementation Notes

  • Ruby and Rust are the only bindings whose lockfiles embed Selenium's own version, so updating version should always re-pin (not update).
  • release.yml's reset-dependencies and commit-dependencies are now redundant, since reset-version already produces reconciled lockfiles in its artifact. Removing them also collapses the nightly version bump and its lockfiles into one commit instead of two.
  • Renames the release_updates task to pre_release to match the workflow it mirrors.
  • Each update task's desc now says whether it goes to latest or stays within the declared range: java goes to latest, the rest stay within range. dotnet keeps its desc but gets a comment noting it is a no-op while paket.dependencies pins exact versions under STRATEGY: MIN.
  • Deletes the unreferenced release_update task, which had been whittled down to a bare alias for update_multitool
  • download-artifact throws when a name: is missing, but a pattern: that matches nothing succeeds and downloads nothing. bazel.yml uploads no artifact when there are no changes, so the patch download now uses pattern: (with merge-multiple to keep changes.patch at the root rather than in a per-artifact subdirectory) instead of name: plus continue-on-error. A quiet run is a clean no-op; a real download failure now fails the job instead of being swallowed.

🤖 AI assistance

  • AI assisted (complete below)
    • Tool(s): Claude Code (Opus 5)
    • What was generated: the workflow, the rake task changes, the lockfile analysis that identified Ruby and Rust, and this description
    • I reviewed all AI output and can explain the change

💡 Additional Considerations

  • These version updates do not remove the need for Renovate, and we really need to fix how we are using it
  • We may want to change the frequency of the version updates
  • If we ignore the release PR, we can continue releasing Selenium without ever doing updates, the release process no longer checks it at all
  • Consider defaulting JavaScript updates to use --latest so it updates to latest versions not just within the specified range (this would match the current Java behavior)

🔄 Types of changes

  • Cleanup (formatting, renaming)
  • New feature (non-breaking change which adds functionality and tests!)

@selenium-ci selenium-ci added the B-build Includes scripting, bazel and CI integrations label Aug 21, 2026
@qodo-code-review

Copy link
Copy Markdown
Contributor

PR Summary by Qodo

Move dependency updates to a weekly workflow and re-pin lockfiles on version bumps

✨ Enhancement ⚙️ Configuration changes 🕐 20-40 Minutes

Grey Divider

AI Description

• Add a weekly Dependency Updates workflow that runs updates and opens an automated PR.
• Remove dependency updates from pre-release/release flows to simplify release preparation.
• Re-pin Ruby/Rust lockfiles on version bumps and clarify per-binding update behavior.
Diagram

graph TD
  A["dependency-updates.yml"] --> B["Update job"] --> C["./go update"] --> D[("dependency-updates artifact")]
  D --> E["Create PR"] --> F["Slack notify"]

  subgraph Legend
    direction LR
    _wf["Workflow/Job"] ~~~ _cmd["Command"] ~~~ _art[("Artifact")]
  end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Rely on Renovate/Dependabot for weekly updates
  • ➕ Less bespoke CI logic to maintain
  • ➕ Native per-ecosystem update grouping and scheduling
  • ➕ Better auditability of why versions changed
  • ➖ Monorepo + Bazel + pinned binaries may not be fully supported
  • ➖ May not update custom pinned artifacts (multitool binaries) without extra glue
  • ➖ Requires fixing/retuning current Renovate setup (noted in PR)
2. Keep dependency updates in the pre-release/release workflows
  • ➕ Guarantees release PR always includes a dependency refresh
  • ➕ Single place to reason about “release readiness” changes
  • ➖ Higher coupling between release success and dependency churn
  • ➖ Longer, noisier release-prep PRs; harder rollbacks
  • ➖ More frequent breakages close to release time
3. Open an issue/Slack-only alert instead of auto-creating a PR
  • ➕ Avoids PR noise if updates are frequently non-actionable
  • ➕ Still provides visibility into failures
  • ➖ Loses a concrete, reviewable artifact of changes
  • ➖ Higher manual effort to apply updates consistently

Recommendation: Current approach (weekly automation PR + removing updates from release prep) is a good decoupling step: it reduces release-time risk and keeps dependency churn reviewable on its own cadence. Longer-term, consider migrating parts of this to a repaired Renovate/Dependabot configuration, but keep the custom workflow (or a thin wrapper) for Bazel-specific and pinned-binary updates that off-the-shelf bots won’t handle cleanly.

Files changed (10) +116 / -71

Enhancement (3) +98 / -14
dependency-updates.ymlAdd weekly workflow to generate dependency update PRs +78/-0

Add weekly workflow to generate dependency update PRs

• Introduces a scheduled (weekly) and manually-triggerable workflow that runs './go update' via the reusable Bazel workflow, applies the resulting patch artifact, and opens an automated PR. Adds a failure/cancel path that posts a Slack notification if PR creation cannot proceed.

.github/workflows/dependency-updates.yml

RakefileAdd aggregated update task and rename release_updates to pre_release +11/-11

Add aggregated update task and rename release_updates to pre_release

• Deletes the unused 'release_update' alias, adds a top-level 'update' task that updates all bindings, Rust, and multitool binaries, and renames 'release_updates' to 'pre_release' to align with the workflow. Removes automatic dependency updating from pre-release task execution to match the new weekly automation model.

Rakefile

node.rakeAdd optional --latest support for Node dependency updates +9/-3

Add optional --latest support for Node dependency updates

• Extends 'node:update' to accept an argument ('latest') that adds pnpm’s '--latest' flag, allowing upgrades beyond the declared semver ranges when desired. Continues to refresh the lockfile via 'node:pin' after updating.

rake_tasks/node.rake

Bug fix (2) +8 / -2
ruby.rakeRe-pin Ruby lockfiles/checksums on version bumps and clarify update scope +4/-1

Re-pin Ruby lockfiles/checksums on version bumps and clarify update scope

• Ensures 'rb:version' re-runs 'rb:pin' after updating the version (keeping lockfiles and Bazel gem checksum metadata consistent when the project version is embedded). Updates the dependency update task description to reflect that updates stay within the specified range.

rake_tasks/ruby.rake

rust.rakeRe-pin Cargo/Bazel metadata on Rust version bumps and clarify update scope +4/-1

Re-pin Cargo/Bazel metadata on Rust version bumps and clarify update scope

• Ensures 'rust:version' re-runs 'rust:pin' after updating version fields so Cargo.lock and Bazel crate metadata remain consistent when the version is embedded. Updates the dependency update task description to reflect within-range updates.

rake_tasks/rust.rake

Documentation (3) +3 / -2
dotnet.rakeDocument .NET update behavior as effectively a no-op +1/-0

Document .NET update behavior as effectively a no-op

• Adds an inline comment clarifying that 'dotnet:update' doesn't meaningfully change versions while 'paket.dependencies' pins exact versions under 'STRATEGY: MIN'. Keeps the existing update+pin invocation sequence unchanged.

rake_tasks/dotnet.rake

java.rakeClarify Java update task updates to latest versions +1/-1

Clarify Java update task updates to latest versions

• Updates the task description to explicitly state that Java dependency updates target latest Maven versions (not just within an existing range). No functional change to the update implementation.

rake_tasks/java.rake

python.rakeClarify Python update task stays within specified ranges +1/-1

Clarify Python update task stays within specified ranges

• Updates the task description to state updates go to the latest versions within the specified range. No behavioral changes to the underlying requirements update command.

rake_tasks/python.rake

Other (2) +7 / -53
pre-release.ymlRemove dependency updates from pre-release preparation +5/-28

Remove dependency updates from pre-release preparation

• Drops the dedicated dependency update job and removes dependency/multitool patch application from the release-prep PR creation flow. Also ensures the devtools update step re-pins Ruby dependencies ('./go rb:pin') so version-embedded lockfiles remain consistent.

.github/workflows/pre-release.yml

release.ymlSimplify nightly reset by removing lockfile reset/commit steps +2/-25

Simplify nightly reset by removing lockfile reset/commit steps

• Removes the separate nightly lockfile reset and commit jobs, relying on the existing version reset artifact to contain reconciled lockfiles. Updates downstream job dependencies and failure reporting accordingly.

.github/workflows/release.yml

@qodo-code-review

qodo-code-review Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (1) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Optional artifact download unguarded ✗ Dismissed 🐞 Bug ☼ Reliability ⭐ New
Description
commit-changes.yml (and the new/updated PR-creation workflows) downloads a patch artifact
unconditionally, but the producing bazel.yml job intentionally uploads no artifact when there are
no changes. This can turn normal “no updates” runs into job failures (and trigger failure
notifications) even though downstream steps are written to treat a missing/empty changes.patch as
a no-op.
Code

.github/workflows/commit-changes.yml[R44-45]

+          pattern: ${{ inputs.artifact-name }}
+          merge-multiple: true
Evidence
bazel.yml explicitly makes “no changes” mean “no artifact uploaded”; the updated workflows still
download unconditionally while their shell logic assumes changes.patch may not exist, creating an
inconsistent no-op path.

.github/workflows/bazel.yml[295-308]
.github/workflows/commit-changes.yml[41-61]
.github/workflows/dependency-updates.yml[34-48]
.github/workflows/pin-browsers.yml[33-47]
.github/workflows/ci.yml[168-173]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The consumer workflows now rely on `actions/download-artifact` to behave as a no-op when no patch artifact exists, but the producer (`.github/workflows/bazel.yml`) explicitly skips uploading any artifact when there are no changes (it deletes `changes.patch` and uploads with `if-no-files-found: ignore`). This mismatch can cause failures on legitimate “no changes” runs.

## Issue Context
- Producer behavior: `bazel.yml` creates `changes.patch` only when there is a staged diff, deletes it otherwise, and then uploads with `if-no-files-found: ignore`.
- Consumer behavior: `commit-changes.yml`, `dependency-updates.yml`, and `pin-browsers.yml` expect `changes.patch` may be absent/empty (they check `-s changes.patch`) but still perform an unconditional artifact download step.

## Fix Focus Areas
Choose an approach that makes the no-change path explicitly safe:
- Option A (producer-side): Always upload an artifact (e.g., upload an empty `changes.patch` or a small marker file) so downloads always succeed.
- Option B (consumer-side): Gate the download/apply steps based on an explicit signal from the producer (e.g., a workflow output indicating whether a patch artifact was produced), rather than relying on implicit download semantics.

- .github/workflows/bazel.yml[295-308]
- .github/workflows/commit-changes.yml[41-52]
- .github/workflows/dependency-updates.yml[34-48]
- .github/workflows/pin-browsers.yml[33-47]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Redundant comment in node:update 📘 Rule violation ⚙ Maintainability
Description
The new comment in node:update restates the obvious behavior rather than explaining intent or
rationale, reducing long-term maintainability. This conflicts with the guideline that comments
should explain why, not what.
Code

rake_tasks/node.rake[R49-50]

+  # update versions beyond the specified range
+  upgrade = arguments.to_a.include?('latest')
Evidence
PR Compliance ID 8 requires comments to explain rationale. The comment `# update versions beyond the
specified range merely narrates the following logic (arguments include latest` leading to adding
--latest) without explaining why this behavior/option is needed.

AGENTS.md: Comments Should Explain Why, Not What
rake_tasks/node.rake[47-54]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A newly added comment in `node:update` explains what the next line does (checking for `latest`) instead of why this option exists.

## Issue Context
Compliance guidance prefers comments that capture intent/rationale rather than narrating code.

## Fix Focus Areas
- rake_tasks/node.rake[47-54]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Silent artifact download failure ✗ Dismissed 🐞 Bug ☼ Reliability
Description
In the new weekly workflow, the patch download step is marked continue-on-error and all subsequent
steps are skipped when it fails, so the job can still succeed without creating a PR or triggering
the Slack failure workflow. This can mask real failures (e.g., transient artifact download issues),
leaving dependency updates not happening with no notification.
Code

.github/workflows/dependency-updates.yml[R34-39]

+      - name: Download patch
+        id: download
+        uses: actions/download-artifact@v8
+        with:
+          name: dependency-updates
+        continue-on-error: true
Evidence
The create-pr job explicitly ignores download errors and gates PR creation on download success, so
a failed download results in a successful job with no PR attempt. Separately, bazel.yml may
legitimately produce no artifact when there are no diffs, which is why you need an explicit signal
to avoid alerting on no-op runs while still failing on real download problems.

.github/workflows/dependency-updates.yml[34-47]
.github/workflows/bazel.yml[295-309]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The `create-pr` job ignores artifact download failures (`continue-on-error: true`) and gates all subsequent steps on `steps.download.outcome == 'success'`. This allows the workflow to report success while producing neither a PR nor a Slack alert, even when the missing artifact is due to an actual failure (not simply “no changes”).

## Issue Context
`bazel.yml` uploads `changes.patch` only if there are staged diffs; if the patch is empty it deletes the file and uploads nothing (`if-no-files-found: ignore`). That means “no changes” is a valid reason for the artifact to be missing, but transient download/upload problems are also possible and should be surfaced.

## Fix Focus Areas
- .github/workflows/dependency-updates.yml[34-47]
- .github/workflows/bazel.yml[295-309]

## Suggested fix approach
Choose one of these so you can distinguish “no changes” from “download failed” and still alert on real failures:
1) **Always upload a sentinel artifact** from the `update` job (e.g., a small `result.json` with `has_changes=true/false` plus `changes.patch` when present). Then in `create-pr`, if the sentinel exists but `changes.patch` is missing or download fails, explicitly `exit 1` to trigger `on-failure`.
2) Keep `continue-on-error: true`, but add a follow-up step that queries for the artifact’s existence via `gh api` / REST and fails the job when the artifact should exist but wasn’t downloaded.
3) If you decide missing artifact always means “no changes”, explicitly log that outcome (and consider renaming the Slack message to only cover true PR creation failures).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can tweak Display preferences with a live preview to see your comment before it ships

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Previous reviews

Review updated until commit 700413f

Results up to commit 7409a80 ⚖️ Balanced


🐞 Bugs (0) 📘 Rule violations (1) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)


Remediation recommended
1. Redundant comment in node:update 📘 Rule violation ⚙ Maintainability
Description
The new comment in node:update restates the obvious behavior rather than explaining intent or
rationale, reducing long-term maintainability. This conflicts with the guideline that comments
should explain why, not what.
Code

rake_tasks/node.rake[R49-50]

+  # update versions beyond the specified range
+  upgrade = arguments.to_a.include?('latest')
Evidence
PR Compliance ID 8 requires comments to explain rationale. The comment `# update versions beyond the
specified range merely narrates the following logic (arguments include latest` leading to adding
--latest) without explaining why this behavior/option is needed.

AGENTS.md: Comments Should Explain Why, Not What
rake_tasks/node.rake[47-54]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A newly added comment in `node:update` explains what the next line does (checking for `latest`) instead of why this option exists.

## Issue Context
Compliance guidance prefers comments that capture intent/rationale rather than narrating code.

## Fix Focus Areas
- rake_tasks/node.rake[47-54]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Silent artifact download failure ✗ Dismissed 🐞 Bug ☼ Reliability
Description
In the new weekly workflow, the patch download step is marked continue-on-error and all subsequent
steps are skipped when it fails, so the job can still succeed without creating a PR or triggering
the Slack failure workflow. This can mask real failures (e.g., transient artifact download issues),
leaving dependency updates not happening with no notification.
Code

.github/workflows/dependency-updates.yml[R34-39]

+      - name: Download patch
+        id: download
+        uses: actions/download-artifact@v8
+        with:
+          name: dependency-updates
+        continue-on-error: true
Evidence
The create-pr job explicitly ignores download errors and gates PR creation on download success, so
a failed download results in a successful job with no PR attempt. Separately, bazel.yml may
legitimately produce no artifact when there are no diffs, which is why you need an explicit signal
to avoid alerting on no-op runs while still failing on real download problems.

.github/workflows/dependency-updates.yml[34-47]
.github/workflows/bazel.yml[295-309]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The `create-pr` job ignores artifact download failures (`continue-on-error: true`) and gates all subsequent steps on `steps.download.outcome == 'success'`. This allows the workflow to report success while producing neither a PR nor a Slack alert, even when the missing artifact is due to an actual failure (not simply “no changes”).

## Issue Context
`bazel.yml` uploads `changes.patch` only if there are staged diffs; if the patch is empty it deletes the file and uploads nothing (`if-no-files-found: ignore`). That means “no changes” is a valid reason for the artifact to be missing, but transient download/upload problems are also possible and should be surfaced.

## Fix Focus Areas
- .github/workflows/dependency-updates.yml[34-47]
- .github/workflows/bazel.yml[295-309]

## Suggested fix approach
Choose one of these so you can distinguish “no changes” from “download failed” and still alert on real failures:
1) **Always upload a sentinel artifact** from the `update` job (e.g., a small `result.json` with `has_changes=true/false` plus `changes.patch` when present). Then in `create-pr`, if the sentinel exists but `changes.patch` is missing or download fails, explicitly `exit 1` to trigger `on-failure`.
2) Keep `continue-on-error: true`, but add a follow-up step that queries for the artifact’s existence via `gh api` / REST and fails the job when the artifact should exist but wasn’t downloaded.
3) If you decide missing artifact always means “no changes”, explicitly log that outcome (and consider renaming the Slack message to only cover true PR creation failures).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment thread rake_tasks/node.rake
Comment thread .github/workflows/dependency-updates.yml Outdated
Comment thread .github/workflows/commit-changes.yml
@qodo-code-review

Copy link
Copy Markdown
Contributor

Code review by qodo was updated up to the latest commit 700413f

@titusfortner
titusfortner merged commit 458b8e1 into trunk Aug 21, 2026
28 checks passed
@titusfortner
titusfortner deleted the weekly-dependency-updates branch August 21, 2026 23:29
This was referenced Aug 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

B-build Includes scripting, bazel and CI integrations

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants