Skip to content

Rescue errors in metadata_cascades_for_dep to prevent PR message loss#14905

Open
yeikel wants to merge 2 commits into
dependabot:mainfrom
yeikel:rescue-metadata-cascade-errors
Open

Rescue errors in metadata_cascades_for_dep to prevent PR message loss#14905
yeikel wants to merge 2 commits into
dependabot:mainfrom
yeikel:rescue-metadata-cascade-errors

Conversation

@yeikel
Copy link
Copy Markdown
Contributor

@yeikel yeikel commented May 4, 2026

What are you trying to accomplish?

When metadata_cascades_for_dep encounters a network error (e.g., GitHub API timeout), it now gracefully handles the failure by returning an empty string and logging the error via suppress_error. This allows the PR message to be assembled without the metadata cascade sections (changelog, commits, releases) but still includes the important intro line and message content.

Previously, any error in metadata fetching would propagate up to pr_message's top-level rescue, causing the entire PR body to be discarded and replaced with just the header and footer (or an empty string).

Fixes #14904

Reproduction steps

Minimal setup - a Maven project with a public GitHub-hosted dependency:

<!-- pom.xml -->
<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example</groupId>
  <artifactId>app</artifactId>
  <version>1.0.0</version>
  <dependencies>
    <dependency>
      <groupId>com.google.guava</groupId>
      <artifactId>guava</artifactId>
      <version>31.0-jre</version>
    </dependency>
  </dependencies>
</project>

How to trigger the bug - block api.github.com during PR message generation to simulate a GitHub API timeout:

# In a shell where you'll run the updater, add a hosts entry to block GitHub API:
echo "0.0.0.0 api.github.com" >> /etc/hosts

Updater CLI flow:

# Run the updater against a real or test repo with the above pom.xml
bin/dependabot update maven --repo <owner>/<repo> --dependency guava

Observed pr-body before this patch:

(empty string. The entire body was discarded.)

The error SocketError: Failed to open TCP connection to api.github.com:443 was raised inside MetadataPresenter#to_s, propagated through metadata_cascades_for_dep up to pr_message's top-level rescue, which returned only suffixed_pr_message_header + prefixed_pr_message_footer. When no custom header/footer is configured, this produces an empty string.

Observed pr-body after this patch:

Bumps [guava](https://github.com/google/guava) from 31.0-jre to 32.0-jre.

The intro line is preserved. Metadata sections (changelog, commits, releases) are omitted for the affected dependency only.

Test-level reproduction (no network blocking needed):

# Stubs MetadataPresenter#to_s to raise for a single-dependency PR
allow_any_instance_of(MetadataPresenter).to receive(:to_s)
  .and_raise(SocketError, 'Connection refused for api.github.com')

# In a grouped PR, one dependency's cascade raises while the other renders normally
stub_request(:get, "https://api.github.com/repos/.../CHANGELOG.md?ref=master")
  .to_raise(SocketError, 'Connection refused for api.github.com')

Both cases are covered by the new regression tests in message_builder_spec.rb.

Anything you want to highlight for special attention from reviewers?

  • The rescue is scoped to metadata_cascades_for_dep, not pr_message, so only the enrichment content (changelog, commits, releases) for the failing dependency is dropped. The intro/body is preserved.
  • For grouped PRs, a failure in one dependency's metadata cascade does not affect other dependencies' metadata sections.

How will you know you've accomplished your goal?

The existing and new tests pass, including:

  • Single dependency: metadata_cascades_for_dep raises, PR message retains intro
  • Single dependency: MetadataPresenter#to_s raises directly, PR message retains intro
  • Grouped PR: one dependency's metadata raises, other dependency's metadata still renders

Checklist

  • I have run the complete test suite to ensure all tests and linters pass.
  • I have thoroughly tested my code changes to ensure they work as expected, including adding additional tests for new functionality.
  • I have written clear and descriptive commit messages.
  • I have provided a detailed description of the changes in the pull request, including the problem it addresses, how it fixes the problem, and any relevant details about the implementation.
  • I have ensured that the code is well-documented and easy to understand.

@yeikel yeikel force-pushed the rescue-metadata-cascade-errors branch from 0636bf6 to f6ae25e Compare May 4, 2026 17:17
@yeikel yeikel force-pushed the rescue-metadata-cascade-errors branch from f6ae25e to cd291c0 Compare May 4, 2026 17:30
@yeikel yeikel marked this pull request as ready for review May 4, 2026 17:30
@yeikel yeikel requested a review from a team as a code owner May 4, 2026 17:30
@yeikel yeikel force-pushed the rescue-metadata-cascade-errors branch 3 times, most recently from afa8d6b to 44dd26c Compare May 6, 2026 20:23
@yeikel yeikel force-pushed the rescue-metadata-cascade-errors branch from 44dd26c to da4c1b0 Compare May 13, 2026 15:01
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Rescues errors raised while building the metadata cascade section of a PR message, so that transient network failures (e.g., GitHub API timeouts) no longer wipe out the entire PR body. The error is logged via the existing suppress_error helper and an empty string is returned, allowing the rest of the message to be assembled.

Changes:

  • Wrap metadata_cascades_for_dep body in a rescue StandardError that calls suppress_error and returns "".
  • Update an existing spec that previously asserted a blank message on SocketError to now expect the intro line.
  • Add a new spec stubbing MetadataPresenter#to_s to raise SocketError, asserting the PR body still contains the intro line.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
common/lib/dependabot/pull_request_creator/message_builder.rb Adds rescue in metadata_cascades_for_dep to suppress errors and return an empty cascade.
common/spec/dependabot/pull_request_creator/message_builder_spec.rb Updates existing SocketError expectation and adds a new test simulating GitHub unreachable during metadata fetching.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

@v-HaripriyaC
Copy link
Copy Markdown
Contributor

v-HaripriyaC commented May 19, 2026

@yeikel , thanks for raising this PR, and sorry for delay. I have two requests before merge:

Thanks for working on this — the fix looks to be in the right place.

metadata_cascades_for_dep is building optional enrichment content like changelog, releases, and commits. Failures there should not cause the entire PR body to be dropped. Right now, if MetadataPresenter#to_s raises, the exception bubbles up to pr_message, which rescues at the top level and returns only the header/footer or an empty body. That matches the bug reported in #14904.

Handling the error inside metadata_cascades_for_dep, logging it via suppress_error, and returning "" seems like the correct degradation behavior: preserve the main PR intro/body and omit only the metadata sections.

Before this is merged, I’d like to see two follow-ups:

Add one more regression test for a grouped or multi-dependency PR

make one dependency’s metadata cascade raise
verify the overall PR message still renders
verify the failure is isolated to that dependency’s metadata block and does not affect the rest of the message
Add reproducible steps to the PR description or in a comment The linked issue explains the general scenario, but it is still difficult for a reviewer to replay deterministically. It would help to include:

the minimal manifest used
how GitHub metadata access was blocked or forced to timeout
the exact updater / CLI flow used
the observed pr-body before and after the change
A good reproduction flow would be:

use a minimal Maven project with a public dependency
allow package resolution to succeed
block or timeout api.github.com during PR message generation
before this patch: pr-body becomes empty
after this patch: the intro line is preserved and metadata sections are omitted
With those additions, I’d be comfortable approving this.

@yeikel yeikel force-pushed the rescue-metadata-cascade-errors branch 2 times, most recently from a620515 to bcdba0b Compare May 25, 2026 02:35
yeikel added 2 commits May 24, 2026 22:35
When metadata_cascades_for_dep encounters a network error (e.g., GitHub API timeout), it now gracefully handles the failure by returning an empty string and logging the error via suppress_error. This allows the PR message to be assembled without the metadata cascade sections (changelog, commits, releases) but still includes the important intro line and message content.

Previously, any error in metadata fetching would propagate up to pr_message's top-level rescue, causing the entire PR body to be discarded and replaced with just the header and footer.

Fixes dependabot#14904
Verifies that when one dependency's metadata cascade raises in a
multi-dependency PR, the other dependency's metadata is unaffected
and the overall PR message still renders.
@yeikel yeikel force-pushed the rescue-metadata-cascade-errors branch from bcdba0b to 228f3dc Compare May 25, 2026 02:35
@yeikel
Copy link
Copy Markdown
Contributor Author

yeikel commented May 25, 2026

@yeikel , thanks for raising this PR, and sorry for delay. I have two requests before merge:

Thanks for working on this — the fix looks to be in the right place.

metadata_cascades_for_dep is building optional enrichment content like changelog, releases, and commits. Failures there should not cause the entire PR body to be dropped. Right now, if MetadataPresenter#to_s raises, the exception bubbles up to pr_message, which rescues at the top level and returns only the header/footer or an empty body. That matches the bug reported in #14904.

Handling the error inside metadata_cascades_for_dep, logging it via suppress_error, and returning "" seems like the correct degradation behavior: preserve the main PR intro/body and omit only the metadata sections.

Before this is merged, I’d like to see two follow-ups:

Add one more regression test for a grouped or multi-dependency PR

make one dependency’s metadata cascade raise verify the overall PR message still renders verify the failure is isolated to that dependency’s metadata block and does not affect the rest of the message Add reproducible steps to the PR description or in a comment The linked issue explains the general scenario, but it is still difficult for a reviewer to replay deterministically. It would help to include:

the minimal manifest used how GitHub metadata access was blocked or forced to timeout the exact updater / CLI flow used the observed pr-body before and after the change A good reproduction flow would be:

use a minimal Maven project with a public dependency allow package resolution to succeed block or timeout api.github.com during PR message generation before this patch: pr-body becomes empty after this patch: the intro line is preserved and metadata sections are omitted With those additions, I’d be comfortable approving this.

Thanks for the detailed review, @v-HaripriyaC!

Both requests are addressed in the latest commit:

  1. Grouped PR regression test

Added a new context inside when updating multiple dependencies in message_builder_spec.rb. It stubs only statesman's CHANGELOG.md endpoint to raise SocketError, then asserts three things independently:

  • The PR intro line still names both business and statesman
  • business's metadata (changelog) renders normally proving the failure is isolated
  • statesman's section header is present but its metadata block is omitted (no statesman's changelog)
  1. Reproduction steps

Updated the PR description with:

  • A minimal Maven pom.xml with a public dependency (guava)
  • The exact mechanism to simulate a GitHub API timeout (/etc/hosts block on api.github.com)
  • The updater CLI invocation
  • The pr-body before and after the patch (empty string → intro preserved)
  • The equivalent test-level stubs used in the spec so reviewers can replay deterministically without network changes

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.

The pull request body is empty when any of the metadata retrieval steps fails

3 participants