Skip to content

refactor(core): preserve error sources and print the cause chain#1653

Merged
mergify[bot] merged 1 commit into
mainfrom
devs/JulianMaurin/feat/rust-cli-excellence/preserve-error-sources-print-cause-chain--21542b1c
Jun 22, 2026
Merged

refactor(core): preserve error sources and print the cause chain#1653
mergify[bot] merged 1 commit into
mainfrom
devs/JulianMaurin/feat/rust-cli-excellence/preserve-error-sources-print-cause-chain--21542b1c

Conversation

@JulianMaurin

@JulianMaurin JulianMaurin commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Every non-Io CliError variant was Variant(String), so a wrapped
cause could only survive by being flattened into the message with
format!("...: {e}")source() was always None and a typed
lower-level error (e.g. InvalidJunitXml, QuarantineFailed) was
collapsed via .to_string(), losing its type.

Give CliError two ways to keep a cause:

  • Source(#[from] Box<dyn Error + Send + Sync>) — transparent: same
    Display, preserves the typed error as a downcastable, chainable
    source. From<InvalidJunitXml> / From<QuarantineFailed> now use
    it instead of .to_string() (output unchanged — both are
    self-describing leaves).
  • Wrapped { context, #[source] source } via CliError::wrap(ctx, e)
    — a context headline plus a preserved cause, for "doing X failed
    because of Y".

main() now walks source() and prints each cause as a
caused by: line. Io drops its #[from] (kept as a manual From)
so its full-message Display isn't also exposed as a source and
double-printed; it stays a self-contained leaf.

This is the idiomatic foundation; commands adopt wrap() for their
network/IO failures in later commits.

Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com

@mergify

mergify Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Merge Protections

🟢 All 5 merge protections satisfied — ready to merge.

Show 5 satisfied protections

🟢 🤖 Continuous Integration

  • all of:
    • check-success=ci-gate

🟢 👀 Review Requirements

  • any of:
    • #approved-reviews-by>=2
    • author = dependabot[bot]
    • author = mergify-ci-bot
    • author = renovate[bot]

🟢 Enforce conventional commit

Make sure that we follow https://www.conventionalcommits.org/en/v1.0.0/

  • title ~= ^(fix|feat|docs|style|refactor|perf|test|build|ci|chore|revert|ui)(?:\(.+\))?:

🟢 🔎 Reviews

  • #changes-requested-reviews-by = 0
  • #review-requested = 0
  • #review-threads-unresolved = 0

🟢 📕 PR description

  • body ~= (?ms:.{48,})

@JulianMaurin

JulianMaurin commented Jun 19, 2026

Copy link
Copy Markdown
Contributor Author

This pull request is part of a Mergify stack:

# Pull Request Link
1 refactor(core): preserve error sources and print the cause chain #1653 👈
2 fix(self-update): exit with the GitHub-API code and retry transients #1654
3 feat(http): honor GitHub rate limits and bound connect time #1655
4 feat(cli): add a global --color flag and fix queue-show glyphs #1656
5 feat(cli): add a -v/-vv verbosity ladder backed by tracing #1657
6 feat(cli): generate shell completions and a man page #1658
7 test: golden-snapshot the CLI surface and guard schema drift #1659
8 refactor: dedupe the GIT_SEQUENCE_EDITOR lookup and drop port cruft #1660
9 docs(agents): rewrite AGENTS.md for the Rust workspace #1661
10 fix(cli): render stack-squash validation errors via clap #1671

@JulianMaurin

JulianMaurin commented Jun 19, 2026

Copy link
Copy Markdown
Contributor Author

Revision history

# Type Changes Reason Date
1 initial c583cb3 2026-06-19 07:52 UTC
2 rebase c583cb3 → 9454772 (rebase only) 2026-06-19 07:52 UTC
3 rebase 9454772 → 3dbd4b7 (rebase only) 2026-06-19 16:51 UTC
4 rebase 3dbd4b7 → 7adfa85 (rebase only) 2026-06-22 13:00 UTC

@mergify mergify Bot requested a review from a team June 19, 2026 07:58
@JulianMaurin JulianMaurin force-pushed the devs/JulianMaurin/feat/rust-cli-excellence/model-stack-native-clap-subcommand-tree--ccded108 branch from 6ba7b33 to 6dbc5f9 Compare June 19, 2026 16:51
@JulianMaurin JulianMaurin force-pushed the devs/JulianMaurin/feat/rust-cli-excellence/preserve-error-sources-print-cause-chain--21542b1c branch from 9454772 to 3dbd4b7 Compare June 19, 2026 16:51
@mergify mergify Bot had a problem deploying to Mergify Merge Protections June 19, 2026 16:51 Failure
Base automatically changed from devs/JulianMaurin/feat/rust-cli-excellence/model-stack-native-clap-subcommand-tree--ccded108 to main June 22, 2026 12:49
Every non-Io `CliError` variant was `Variant(String)`, so a wrapped
cause could only survive by being flattened into the message with
`format!("...: {e}")` — `source()` was always `None` and a typed
lower-level error (e.g. `InvalidJunitXml`, `QuarantineFailed`) was
collapsed via `.to_string()`, losing its type.

Give `CliError` two ways to keep a cause:

- `Source(#[from] Box<dyn Error + Send + Sync>)` — transparent: same
  Display, preserves the typed error as a downcastable, chainable
  source. `From<InvalidJunitXml>` / `From<QuarantineFailed>` now use
  it instead of `.to_string()` (output unchanged — both are
  self-describing leaves).
- `Wrapped { context, #[source] source }` via `CliError::wrap(ctx, e)`
  — a context headline plus a preserved cause, for "doing X failed
  because of Y".

`main()` now walks `source()` and prints each cause as a
`caused by:` line. `Io` drops its `#[from]` (kept as a manual `From`)
so its full-message Display isn't also exposed as a source and
double-printed; it stays a self-contained leaf.

This is the idiomatic foundation; commands adopt `wrap()` for their
network/IO failures in later commits.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Change-Id: I21542b1cd0b25214b9e197bc9b2228136a357dc4
@JulianMaurin JulianMaurin force-pushed the devs/JulianMaurin/feat/rust-cli-excellence/preserve-error-sources-print-cause-chain--21542b1c branch from 3dbd4b7 to 7adfa85 Compare June 22, 2026 13:00
@mergify mergify Bot deployed to Mergify Merge Protections June 22, 2026 13:00 Active
@mergify mergify Bot requested a review from a team June 22, 2026 13:07
@mergify

mergify Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Queued — the merge queue status continues in this comment ↓.

@mergify

mergify Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Merge Queue Status

  • Entered queue2026-06-22 13:35 UTC · Rule: default
  • Checks skipped · PR is already up-to-date
  • Merged2026-06-22 13:35 UTC · at 7adfa852dd4ddc027d3ad120cb7cfb6b6bab3f2f · squash

This pull request spent 11 seconds in the queue, including 2 seconds running CI.

Required conditions to merge

@mergify mergify Bot added the queued label Jun 22, 2026
@mergify mergify Bot merged commit c29c949 into main Jun 22, 2026
22 checks passed
@mergify mergify Bot deleted the devs/JulianMaurin/feat/rust-cli-excellence/preserve-error-sources-print-cause-chain--21542b1c branch June 22, 2026 13:35
@mergify mergify Bot removed the queued label Jun 22, 2026
mergify Bot pushed a commit that referenced this pull request Jun 22, 2026
…1654)

`mergify self-update` mapped every failure — including GitHub network,
API, and release-integrity errors — to `CliError::Generic` (exit 1),
so a flaky-GitHub update was indistinguishable from a local bug and
wrapping scripts got the wrong exit code.

Classify GitHub failures as `CliError::GitHubApi` (exit 5): the release
metadata fetch, the asset/SHA256SUMS downloads, and the
release-integrity checks (missing/malformed checksum entry, checksum
mismatch). Purely-local failures (locating the binary, temp dirs,
writing the archive, the atomic swap, spawning the extractor) stay
`Generic`/`Io`.

Add a 3-attempt retry with backoff around the network reads
(`fetch_latest_release`, the asset and SHA256SUMS downloads), which are
one-shot and idempotent, so a transient blip no longer fails the
update. Integrity checks run outside the retry so a real mismatch
fails fast.

self-update keeps its own `reqwest` rather than `mergify_core::http`:
that client is path/JSON/auth-oriented, while self-update does
unauthenticated binary downloads across two hosts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Depends-On: #1653
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants