Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package lychee for openSUSE:Factory checked 
in at 2026-05-04 12:53:16
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/lychee (Old)
 and      /work/SRC/openSUSE:Factory/.lychee.new.30200 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "lychee"

Mon May  4 12:53:16 2026 rev:16 rq:1350441 version:0.24.2

Changes:
--------
--- /work/SRC/openSUSE:Factory/lychee/lychee.changes    2026-04-26 
21:15:27.355570327 +0200
+++ /work/SRC/openSUSE:Factory/.lychee.new.30200/lychee.changes 2026-05-04 
12:56:16.340283420 +0200
@@ -1,0 +2,15 @@
+Sat May 02 09:34:14 UTC 2026 - Alessio Biancalana <[email protected]>
+
+- Update 001-exclude-octocrab.patch:
+  * update the patch to the latest dependencies
+- Update to version 0.24.2:
+  * chore: release v0.24.2 (#2166)
+  * chore: add pypi release (#1931)
+  * feat: user hints (#2021)
+  * chore: update all container images to debian trixie (#2177)
+  * chore(deps): bump the dependencies group with 8 updates
+  * ci: fix flaky binstall-check job (#2170)
+  * fix: typo in README.md (#2173)
+  * fix: update binstall metadata after 0.24.0 restructure (#2165)
+
+-------------------------------------------------------------------

Old:
----
  lychee-0.24.1.tar.zst

New:
----
  lychee-0.24.2.tar.zst

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ lychee.spec ++++++
--- /var/tmp/diff_new_pack.dO997S/_old  2026-05-04 12:56:17.616335940 +0200
+++ /var/tmp/diff_new_pack.dO997S/_new  2026-05-04 12:56:17.620336104 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           lychee
-Version:        0.24.1
+Version:        0.24.2
 Release:        0
 Summary:        Fast, async, stream-based link checker written in Rust
 License:        Apache-2.0 OR MIT

++++++ 001-exclude-octocrab.patch ++++++
--- /var/tmp/diff_new_pack.dO997S/_old  2026-05-04 12:56:17.652337421 +0200
+++ /var/tmp/diff_new_pack.dO997S/_new  2026-05-04 12:56:17.660337751 +0200
@@ -1,11 +1,11 @@
 diff --git a/Cargo.toml b/Cargo.toml
-index 14eea4ec..db0646ff 100644
+index 1e103671..0554e004 100644
 --- a/Cargo.toml
 +++ b/Cargo.toml
 @@ -1,5 +1,6 @@
  [workspace]
  members = ["lychee-bin", "lychee-lib", "examples/*", "benches", "test-utils"]
-+exclude = ["vendor/octocrab-0.49.8"]
++exclude = ["vendor/octocrab-0.49.9"]
  resolver = "2"
  
  [workspace.package]

++++++ _service ++++++
--- /var/tmp/diff_new_pack.dO997S/_old  2026-05-04 12:56:17.700339397 +0200
+++ /var/tmp/diff_new_pack.dO997S/_new  2026-05-04 12:56:17.704339562 +0200
@@ -3,7 +3,7 @@
     <param name="url">https://github.com/lycheeverse/lychee.git</param>
     <param name="versionformat">@PARENT_TAG@</param>
     <param name="scm">git</param>
-    <param name="revision">lychee-v0.24.1</param>
+    <param name="revision">lychee-v0.24.2</param>
     <param name="match-tag">lychee-v*</param>
     <param name="versionrewrite-pattern">lychee-v(.*)</param>
     <param name="versionrewrite-replacement">\1</param>

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.dO997S/_old  2026-05-04 12:56:17.748341373 +0200
+++ /var/tmp/diff_new_pack.dO997S/_new  2026-05-04 12:56:17.752341537 +0200
@@ -1,6 +1,6 @@
 <servicedata>
 <service name="tar_scm">
                 <param 
name="url">https://github.com/lycheeverse/lychee.git</param>
-              <param 
name="changesrevision">1f7e8d5524df4e6b3a9335445886fa54250063e2</param></service></servicedata>
+              <param 
name="changesrevision">2bba271688c1abb1503097a064e6c3bc1d1b6a9b</param></service></servicedata>
 (No newline at EOF)
 

++++++ lychee-0.24.1.tar.zst -> lychee-0.24.2.tar.zst ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lychee-0.24.1/.devcontainer/Dockerfile 
new/lychee-0.24.2/.devcontainer/Dockerfile
--- old/lychee-0.24.1/.devcontainer/Dockerfile  2026-04-24 17:35:48.000000000 
+0200
+++ new/lychee-0.24.2/.devcontainer/Dockerfile  2026-05-01 17:38:40.000000000 
+0200
@@ -1,4 +1,4 @@
-# See here for image contents: 
https://github.com/microsoft/vscode-dev-containers/tree/v0.236.0/containers/rust/.devcontainer/base.Dockerfile
-# [Choice] Debian OS version (use bookworm on local arm64/Apple Silicon): 
buster, bullseye, bookworm
-ARG VARIANT="bookworm"
-FROM mcr.microsoft.com/vscode/devcontainers/rust:0-${VARIANT}
\ No newline at end of file
+# See here for image contents: 
https://github.com/devcontainers/images/blob/v0.4.26/src/rust/.devcontainer/Dockerfile
+# [Choice] Debian OS version (use bookworm, or bullseye on local arm64/Apple 
Silicon): bookworm, buster, bullseye
+ARG VARIANT="trixie"
+FROM mcr.microsoft.com/vscode/devcontainers/rust:0-${VARIANT}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lychee-0.24.1/.devcontainer/devcontainer.json 
new/lychee-0.24.2/.devcontainer/devcontainer.json
--- old/lychee-0.24.1/.devcontainer/devcontainer.json   2026-04-24 
17:35:48.000000000 +0200
+++ new/lychee-0.24.2/.devcontainer/devcontainer.json   2026-05-01 
17:38:40.000000000 +0200
@@ -5,9 +5,9 @@
        "build": {
                "dockerfile": "Dockerfile",
                "args": {
-                       // Use the VARIANT arg to pick a Debian OS version: 
buster, bullseye, bookworm
-                       // Use bookworm when on local on arm64/Apple Silicon.
-                       "VARIANT": "bookworm"
+                       // Use the VARIANT arg to pick a Debian OS version: 
bookworm, buster, bullseye
+                       // Use bookworm, or bullseye on local arm64/Apple 
Silicon.
+                       "VARIANT": "trixie"
                }
        },
        "runArgs": [
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lychee-0.24.1/.github/workflows/ci.yml 
new/lychee-0.24.2/.github/workflows/ci.yml
--- old/lychee-0.24.1/.github/workflows/ci.yml  2026-04-24 17:35:48.000000000 
+0200
+++ new/lychee-0.24.2/.github/workflows/ci.yml  2026-05-01 17:38:40.000000000 
+0200
@@ -68,6 +68,24 @@
       - name: Verify the MSRV
         run: make verify
 
+  binstall-check:
+    runs-on: ubuntu-latest
+    # Skip on release-plz PRs: those bump the version to one that has not been
+    # published yet, so binstall cannot find a matching release. We still want
+    # PR coverage on regular PRs to catch regressions in the binstall metadata.
+    if: ${{ !startsWith(github.head_ref, 'release-plz-') }}
+    env:
+      # Authenticate against api.github.com to avoid 403 rate-limit failures
+      # when binstall queries GitHub releases.
+      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+    steps:
+      - uses: actions/checkout@v6
+      - uses: cargo-bins/cargo-binstall@main
+      # Use `--manifest-path .` so binstall validates the in-tree binstall
+      # metadata. Resolving against the latest published version would mask
+      # metadata fixes (e.g. #2165) until after the next release ships.
+      - run: cargo binstall --manifest-path . --strategies crate-meta-data 
lychee --no-confirm
+
   publish-check:
     runs-on: ubuntu-latest
     steps:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lychee-0.24.1/.github/workflows/pypi.yml 
new/lychee-0.24.2/.github/workflows/pypi.yml
--- old/lychee-0.24.1/.github/workflows/pypi.yml        1970-01-01 
01:00:00.000000000 +0100
+++ new/lychee-0.24.2/.github/workflows/pypi.yml        2026-05-01 
17:38:40.000000000 +0200
@@ -0,0 +1,165 @@
+# This file is autogenerated by maturin v1.10.2
+# To update, run
+#
+#    maturin generate-ci github
+#
+name: PyPI
+
+on:
+  push:
+    tags:
+      - "lychee-v*"
+  workflow_dispatch:
+
+permissions:
+  contents: read
+
+jobs:
+  linux:
+    runs-on: ${{ matrix.platform.runner }}
+    strategy:
+      matrix:
+        platform:
+          - runner: ubuntu-22.04
+            target: x86_64
+          - runner: ubuntu-22.04
+            target: x86
+          - runner: ubuntu-22.04
+            target: aarch64
+            # check the issue https://github.com/aws/aws-lc-rs/issues/1022
+            container: ghcr.io/rust-cross/manylinux_2_28-cross:aarch64
+          - runner: ubuntu-22.04
+            target: armv7
+          - runner: ubuntu-22.04
+            target: s390x
+          - runner: ubuntu-22.04
+            target: ppc64le
+    steps:
+      - uses: actions/checkout@v6
+      - name: Build wheels
+        uses: PyO3/maturin-action@v1
+        with:
+          target: ${{ matrix.platform.target }}
+          args: --release --out dist
+          sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
+          manylinux: auto
+          container: ${{ matrix.platform.container }}
+      - name: Upload wheels
+        uses: actions/upload-artifact@v5
+        with:
+          name: wheels-linux-${{ matrix.platform.target }}
+          path: dist
+
+  musllinux:
+    runs-on: ${{ matrix.platform.runner }}
+    strategy:
+      matrix:
+        platform:
+          - runner: ubuntu-22.04
+            target: x86_64
+          - runner: ubuntu-22.04
+            target: x86
+          - runner: ubuntu-22.04
+            target: aarch64
+          - runner: ubuntu-22.04
+            target: armv7
+    steps:
+      - uses: actions/checkout@v6
+      - name: Build wheels
+        uses: PyO3/maturin-action@v1
+        with:
+          target: ${{ matrix.platform.target }}
+          args: --release --out dist
+          sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
+          manylinux: musllinux_1_2
+      - name: Upload wheels
+        uses: actions/upload-artifact@v5
+        with:
+          name: wheels-musllinux-${{ matrix.platform.target }}
+          path: dist
+
+  windows:
+    runs-on: ${{ matrix.platform.runner }}
+    strategy:
+      matrix:
+        platform:
+          - runner: windows-latest
+            target: x64
+          - runner: windows-latest
+            target: x86
+    steps:
+      - uses: actions/checkout@v6
+      - name: Build wheels
+        uses: PyO3/maturin-action@v1
+        with:
+          target: ${{ matrix.platform.target }}
+          args: --release --out dist
+          sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
+      - name: Upload wheels
+        uses: actions/upload-artifact@v5
+        with:
+          name: wheels-windows-${{ matrix.platform.target }}
+          path: dist
+
+  macos:
+    runs-on: ${{ matrix.platform.runner }}
+    strategy:
+      matrix:
+        platform:
+          - runner: macos-15-intel
+            target: x86_64
+          - runner: macos-14
+            target: aarch64
+    steps:
+      - uses: actions/checkout@v6
+      - name: Build wheels
+        uses: PyO3/maturin-action@v1
+        with:
+          target: ${{ matrix.platform.target }}
+          args: --release --out dist
+          sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
+      - name: Upload wheels
+        uses: actions/upload-artifact@v5
+        with:
+          name: wheels-macos-${{ matrix.platform.target }}
+          path: dist
+
+  sdist:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v6
+      - name: Build sdist
+        uses: PyO3/maturin-action@v1
+        with:
+          command: sdist
+          args: --out dist
+      - name: Upload sdist
+        uses: actions/upload-artifact@v5
+        with:
+          name: wheels-sdist
+          path: dist
+
+  release:
+    name: Release
+    runs-on: ubuntu-latest
+    if: ${{ startsWith(github.ref, 'refs/tags/') || github.event_name == 
'workflow_dispatch' }}
+    needs: [linux, musllinux, windows, macos, sdist]
+    permissions:
+      # Use to sign the release artifacts
+      id-token: write
+      # Used to upload release artifacts
+      contents: write
+      # Used to generate artifact attestation
+      attestations: write
+    steps:
+      - uses: actions/download-artifact@v6
+      - name: Generate artifact attestation
+        uses: actions/attest-build-provenance@v3
+        with:
+          subject-path: "wheels-*/*"
+      - name: Publish to PyPI
+        if: ${{ startsWith(github.ref, 'refs/tags/') }}
+        uses: PyO3/maturin-action@v1
+        with:
+          command: upload
+          args: --non-interactive --skip-existing wheels-*/*
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lychee-0.24.1/Cargo.lock new/lychee-0.24.2/Cargo.lock
--- old/lychee-0.24.1/Cargo.lock        2026-04-24 17:35:48.000000000 +0200
+++ new/lychee-0.24.2/Cargo.lock        2026-05-01 17:38:40.000000000 +0200
@@ -133,9 +133,9 @@
 
 [[package]]
 name = "assert_cmd"
-version = "2.2.0"
+version = "2.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "9a686bbee5efb88a82df0621b236e74d925f470e5445d3220a5648b892ec99c9"
+checksum = "39bae1d3fa576f7c6519514180a72559268dd7d1fe104070956cb687bc6673bd"
 dependencies = [
  "anstyle",
  "bstr",
@@ -451,9 +451,9 @@
 
 [[package]]
 name = "clap"
-version = "4.6.0"
+version = "4.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351"
+checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -473,18 +473,18 @@
 
 [[package]]
 name = "clap_complete"
-version = "4.6.1"
+version = "4.6.3"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "406e68b4de5c59cfb8f750a7cbd4d31ae153788b8352167c1e5f4fc26e8c91e9"
+checksum = "660c0520455b1013b9bcb0393d5f643d7e4454fb69c915b8d6d2aa0e9a45acc3"
 dependencies = [
  "clap",
 ]
 
 [[package]]
 name = "clap_derive"
-version = "4.6.0"
+version = "4.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a"
+checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9"
 dependencies = [
  "heck",
  "proc-macro2",
@@ -592,11 +592,12 @@
 
 [[package]]
 name = "const_format"
-version = "0.2.35"
+version = "0.2.36"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "7faa7469a93a566e9ccc1c73fe783b4a65c274c5ace346038dca9c39fe0030ad"
+checksum = "4481a617ad9a412be3b97c5d403fef8ed023103368908b9c50af598ff467cc1e"
 dependencies = [
  "const_format_proc_macros",
+ "konst",
 ]
 
 [[package]]
@@ -2188,6 +2189,21 @@
 ]
 
 [[package]]
+name = "konst"
+version = "0.2.20"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "128133ed7824fcd73d6e7b17957c5eb7bacb885649bd8c69708b2331a10bcefb"
+dependencies = [
+ "konst_macro_rules",
+]
+
+[[package]]
+name = "konst_macro_rules"
+version = "0.2.19"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "a4933f3f57a8e9d9da04db23fb153356ecaf00cbd14aee46279c33dc80925c37"
+
+[[package]]
 name = "lazy_static"
 version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
@@ -2274,7 +2290,7 @@
 
 [[package]]
 name = "lychee"
-version = "0.24.1"
+version = "0.24.2"
 dependencies = [
  "anyhow",
  "assert-json-diff",
@@ -2325,7 +2341,7 @@
 
 [[package]]
 name = "lychee-lib"
-version = "0.24.1"
+version = "0.24.2"
 dependencies = [
  "async-stream",
  "async-trait",
@@ -2583,9 +2599,9 @@
 
 [[package]]
 name = "octocrab"
-version = "0.49.7"
+version = "0.49.9"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "63f6687a23731011d0117f9f4c3cdabaa7b5e42ca671f42b5cc0657c492540e3"
+checksum = "4ddbc3bb87e8c680febf16f56855bbd8b44a38e18c913334213ab34908e71a09"
 dependencies = [
  "arc-swap",
  "async-trait",
@@ -3346,9 +3362,9 @@
 
 [[package]]
 name = "reqwest"
-version = "0.13.2"
+version = "0.13.3"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "ab3f43e3283ab1488b624b44b0e988d0acea0b3214e694730a055cb6b2efa801"
+checksum = "62e0021ea2c22aed41653bc7e1419abb2c97e038ff2c33d0e1309e49a97deec0"
 dependencies = [
  "base64",
  "bytes",
@@ -4205,7 +4221,7 @@
 
 [[package]]
 name = "test-utils"
-version = "0.24.1"
+version = "0.24.2"
 
 [[package]]
 name = "testing_table"
@@ -4333,9 +4349,9 @@
 
 [[package]]
 name = "tokio"
-version = "1.51.1"
+version = "1.52.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "f66bf9585cda4b724d3e78ab34b73fb2bbaba9011b9bfdf69dc836382ea13b8c"
+checksum = "b67dee974fe86fd92cc45b7a95fdd2f99a36a6d7b0d431a231178d3d670bbcc6"
 dependencies = [
  "bytes",
  "libc",
@@ -4654,9 +4670,9 @@
 
 [[package]]
 name = "uuid"
-version = "1.23.0"
+version = "1.23.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "5ac8b6f42ead25368cf5b098aeb3dc8a1a2c05a3eee8a9a1a68c640edbfc79d9"
+checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76"
 dependencies = [
  "getrandom 0.4.1",
  "js-sys",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lychee-0.24.1/Cargo.toml new/lychee-0.24.2/Cargo.toml
--- old/lychee-0.24.1/Cargo.toml        2026-04-24 17:35:48.000000000 +0200
+++ new/lychee-0.24.2/Cargo.toml        2026-05-01 17:38:40.000000000 +0200
@@ -3,7 +3,7 @@
 resolver = "2"
 
 [workspace.package]
-version = "0.24.1"
+version = "0.24.2"
 
 [profile.release]
 debug = true
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lychee-0.24.1/Dockerfile new/lychee-0.24.2/Dockerfile
--- old/lychee-0.24.1/Dockerfile        2026-04-24 17:35:48.000000000 +0200
+++ new/lychee-0.24.2/Dockerfile        2026-05-01 17:38:40.000000000 +0200
@@ -1,4 +1,4 @@
-FROM rust:bookworm as builder
+FROM rust:trixie AS builder
 
 RUN USER=root cargo new --bin lychee
 WORKDIR /lychee
@@ -23,7 +23,7 @@
 
 # Our production image starts here, which uses
 # the files from the builder image above.
-FROM debian:bookworm-slim
+FROM debian:trixie-slim
 
 RUN apt-get update \
     && DEBIAN_FRONTEND=noninteractive apt-get install -y \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lychee-0.24.1/Dockerfile-CI.Dockerfile 
new/lychee-0.24.2/Dockerfile-CI.Dockerfile
--- old/lychee-0.24.1/Dockerfile-CI.Dockerfile  2026-04-24 17:35:48.000000000 
+0200
+++ new/lychee-0.24.2/Dockerfile-CI.Dockerfile  2026-05-01 17:38:40.000000000 
+0200
@@ -1,4 +1,4 @@
-FROM debian:bookworm-slim AS builder
+FROM debian:trixie-slim AS builder
 WORKDIR /builder
 
 ARG LYCHEE_VERSION="latest"
@@ -21,7 +21,7 @@
     && wget -O - "$BASE_URL/lychee-$ARCH-unknown-linux-gnu.tar.gz" | tar -xz 
--strip-components 1 \
     && chmod +x lychee
 
-FROM debian:bookworm-slim
+FROM debian:trixie-slim
 
 RUN apt-get update \
     && DEBIAN_FRONTEND=noninteractive apt-get install -y \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lychee-0.24.1/README.md new/lychee-0.24.2/README.md
--- old/lychee-0.24.1/README.md 2026-04-24 17:35:48.000000000 +0200
+++ new/lychee-0.24.2/README.md 2026-05-01 17:38:40.000000000 +0200
@@ -178,7 +178,7 @@
 Note that in the past lychee could be configured to use either OpenSSL or 
Rustls.
 [It was decided](https://github.com/lycheeverse/lychee/pull/1928)
 to fully switch to Rustls and drop OpenSSL support.
-Please tell us if this this negatively affects you in any way.
+Please tell us if this negatively affects you in any way.
 
 ## Features
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lychee-0.24.1/benches/Cargo.toml 
new/lychee-0.24.2/benches/Cargo.toml
--- old/lychee-0.24.1/benches/Cargo.toml        2026-04-24 17:35:48.000000000 
+0200
+++ new/lychee-0.24.2/benches/Cargo.toml        2026-05-01 17:38:40.000000000 
+0200
@@ -10,7 +10,7 @@
 [dependencies]
 lychee-lib = { path = "../lychee-lib", default-features = false }
 criterion = "0.8.2"
-tokio = "1.51.1"
+tokio = "1.52.1"
 
 [features]
 email-check = ["lychee-lib/email-check"]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lychee-0.24.1/examples/archive/Cargo.toml 
new/lychee-0.24.2/examples/archive/Cargo.toml
--- old/lychee-0.24.1/examples/archive/Cargo.toml       2026-04-24 
17:35:48.000000000 +0200
+++ new/lychee-0.24.2/examples/archive/Cargo.toml       2026-05-01 
17:38:40.000000000 +0200
@@ -9,7 +9,7 @@
 
 [dependencies]
 lychee-lib = { path = "../../lychee-lib", default-features = false }
-tokio = { version = "1.51.1", features = ["full"] }
+tokio = { version = "1.52.1", features = ["full"] }
 url = "2.5.8"
 
 [features]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lychee-0.24.1/examples/builder/Cargo.toml 
new/lychee-0.24.2/examples/builder/Cargo.toml
--- old/lychee-0.24.1/examples/builder/Cargo.toml       2026-04-24 
17:35:48.000000000 +0200
+++ new/lychee-0.24.2/examples/builder/Cargo.toml       2026-05-01 
17:38:40.000000000 +0200
@@ -9,10 +9,10 @@
 
 [dependencies]
 lychee-lib = { path = "../../lychee-lib", default-features = false }
-tokio = { version = "1.51.1", features = ["full"] }
+tokio = { version = "1.52.1", features = ["full"] }
 regex = "1.12.2"
 http = "1.4.0"
-reqwest = "0.13.2"
+reqwest = "0.13.3"
 
 [features]
 email-check = ["lychee-lib/email-check"]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lychee-0.24.1/examples/chain/Cargo.toml 
new/lychee-0.24.2/examples/chain/Cargo.toml
--- old/lychee-0.24.1/examples/chain/Cargo.toml 2026-04-24 17:35:48.000000000 
+0200
+++ new/lychee-0.24.2/examples/chain/Cargo.toml 2026-05-01 17:38:40.000000000 
+0200
@@ -10,8 +10,8 @@
 [dependencies]
 async-trait = "0.1.88"
 lychee-lib = { path = "../../lychee-lib", default-features = false }
-reqwest = "0.13.2"
-tokio = { version = "1.51.1", features = ["full"] }
+reqwest = "0.13.3"
+tokio = { version = "1.52.1", features = ["full"] }
 
 [features]
 email-check = ["lychee-lib/email-check"]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lychee-0.24.1/examples/client_pool/Cargo.toml 
new/lychee-0.24.2/examples/client_pool/Cargo.toml
--- old/lychee-0.24.1/examples/client_pool/Cargo.toml   2026-04-24 
17:35:48.000000000 +0200
+++ new/lychee-0.24.2/examples/client_pool/Cargo.toml   2026-05-01 
17:38:40.000000000 +0200
@@ -11,7 +11,7 @@
 futures = "0.3.32"
 tokio-stream = "0.1.18"
 lychee-lib = { path = "../../lychee-lib", default-features = false }
-tokio = { version = "1.51.1", features = ["full"] }
+tokio = { version = "1.52.1", features = ["full"] }
 
 [features]
 email-check = ["lychee-lib/email-check"]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lychee-0.24.1/examples/collect_links/Cargo.toml 
new/lychee-0.24.2/examples/collect_links/Cargo.toml
--- old/lychee-0.24.1/examples/collect_links/Cargo.toml 2026-04-24 
17:35:48.000000000 +0200
+++ new/lychee-0.24.2/examples/collect_links/Cargo.toml 2026-05-01 
17:38:40.000000000 +0200
@@ -9,11 +9,11 @@
 
 [dependencies]
 lychee-lib = { path = "../../lychee-lib",  default-features = false }
-tokio = { version = "1.51.1", features = ["full"] }
+tokio = { version = "1.52.1", features = ["full"] }
 regex = "1.12.2"
 http = "1.4.0"
 tokio-stream = "0.1.18"
-reqwest = "0.13.2"
+reqwest = "0.13.3"
 
 [features]
 email-check = ["lychee-lib/email-check"]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lychee-0.24.1/examples/extract/Cargo.toml 
new/lychee-0.24.2/examples/extract/Cargo.toml
--- old/lychee-0.24.1/examples/extract/Cargo.toml       2026-04-24 
17:35:48.000000000 +0200
+++ new/lychee-0.24.2/examples/extract/Cargo.toml       2026-05-01 
17:38:40.000000000 +0200
@@ -9,7 +9,7 @@
 
 [dependencies]
 lychee-lib = { path = "../../lychee-lib", default-features = false }
-tokio = { version = "1.51.1", features = ["full"] }
+tokio = { version = "1.52.1", features = ["full"] }
 
 [features]
 email-check = ["lychee-lib/email-check"]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lychee-0.24.1/examples/simple/Cargo.toml 
new/lychee-0.24.2/examples/simple/Cargo.toml
--- old/lychee-0.24.1/examples/simple/Cargo.toml        2026-04-24 
17:35:48.000000000 +0200
+++ new/lychee-0.24.2/examples/simple/Cargo.toml        2026-05-01 
17:38:40.000000000 +0200
@@ -9,7 +9,7 @@
 
 [dependencies]
 lychee-lib = { path = "../../lychee-lib", default-features = false }
-tokio = { version = "1.51.1", features = ["full"] }
+tokio = { version = "1.52.1", features = ["full"] }
 
 [features]
 email-check = ["lychee-lib/email-check"]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lychee-0.24.1/fixtures/TEST_GITHUB_404.md 
new/lychee-0.24.2/fixtures/TEST_GITHUB_404.md
--- old/lychee-0.24.1/fixtures/TEST_GITHUB_404.md       2026-04-24 
17:35:48.000000000 +0200
+++ new/lychee-0.24.2/fixtures/TEST_GITHUB_404.md       1970-01-01 
01:00:00.000000000 +0100
@@ -1,3 +0,0 @@
-Test file: contains a single **invalid** (e.g. 404) GitHub URL.
-
-Lychee: https://github.com/mre/idiomatic-rust-doesnt-exist-man
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lychee-0.24.1/lychee-bin/CHANGELOG.md 
new/lychee-0.24.2/lychee-bin/CHANGELOG.md
--- old/lychee-0.24.1/lychee-bin/CHANGELOG.md   2026-04-24 17:35:48.000000000 
+0200
+++ new/lychee-0.24.2/lychee-bin/CHANGELOG.md   2026-05-01 17:38:40.000000000 
+0200
@@ -7,6 +7,21 @@
 
 ## [Unreleased]
 
+## 
[0.24.2](https://github.com/lycheeverse/lychee/compare/lychee-v0.24.1...lychee-v0.24.2)
 - 2026-04-30
+
+### Added
+
+- user hints ([#2021](https://github.com/lycheeverse/lychee/pull/2021))
+
+### Fixed
+
+- typo in README.md ([#2173](https://github.com/lycheeverse/lychee/pull/2173))
+- update binstall metadata after 0.24.0 restructure 
([#2165](https://github.com/lycheeverse/lychee/pull/2165))
+
+### Other
+
+- *(deps)* bump the dependencies group with 8 updates
+
 ## 
[0.24.1](https://github.com/lycheeverse/lychee/compare/lychee-v0.24.0...lychee-v0.24.1)
 - 2026-04-24
 
 ### Other
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lychee-0.24.1/lychee-bin/Cargo.toml 
new/lychee-0.24.2/lychee-bin/Cargo.toml
--- old/lychee-0.24.1/lychee-bin/Cargo.toml     2026-04-24 17:35:48.000000000 
+0200
+++ new/lychee-0.24.2/lychee-bin/Cargo.toml     2026-05-01 17:38:40.000000000 
+0200
@@ -15,15 +15,15 @@
 [dependencies]
 # NOTE: We need to specify the version of lychee-lib here because crates.io
 # requires all dependencies to have a version number.
-lychee-lib = { path = "../lychee-lib", version = "0.24.1", default-features = 
false }
+lychee-lib = { path = "../lychee-lib", version = "0.24.2", default-features = 
false }
 
 anyhow = "1.0.102"
 assert-json-diff = "2.0.2"
-clap = { version = "4.6.0", features = ["env", "derive", "cargo", "string"] }
-clap_complete = "4.6.1"
+clap = { version = "4.6.1", features = ["env", "derive", "cargo", "string"] }
+clap_complete = "4.6.3"
 clap_mangen = "0.3.0"
 console = "0.16.3"
-const_format = "0.2.35"
+const_format = "0.2.36"
 csv = "1.4.0"
 dashmap = { version = "6.1.0", features = ["serde"] }
 env_logger = "0.11.10"
@@ -37,7 +37,7 @@
 indicatif = "0.18.4"
 log = "0.4.28"
 regex = "1.12.2"
-reqwest = "0.13.2"
+reqwest = "0.13.3"
 reqwest_cookie_store = { version = "0.10.0", features = ["serde"] }
 rlimit = "0.11.0"
 # Make build work on Apple Silicon.
@@ -51,14 +51,14 @@
 strum = { version = "0.28.0", features = ["derive"] }
 supports-color = "3.0.2"
 tabled = "0.20.0"
-tokio = { version = "1.51.1", features = ["full"] }
+tokio = { version = "1.52.1", features = ["full"] }
 tokio-stream = "0.1.18"
 toml = "1.1.2"
 url = "2.5.8"
 quick-junit = "0.6.0"
 
 [dev-dependencies]
-assert_cmd = "2.2.0"
+assert_cmd = "2.2.1"
 cookie_store = "0.22.1"
 predicates = "3.1.4"
 pretty_assertions = "1.4.1"
@@ -69,7 +69,7 @@
     "registry",
     "env-filter",
 ] }
-uuid = { version = "1.23.0", features = ["v4"] }
+uuid = { version = "1.23.1", features = ["v4"] }
 wiremock = "0.6.5"
 
 [features]
@@ -93,5 +93,3 @@
 # Metadata for cargo-binstall to get the right artifacts
 [package.metadata.binstall]
 pkg-url = "{ repo }/releases/download/{ name }-v{ version }/{ name }-{ target 
}{ archive-suffix }"
-bin-dir = "{ bin }{ binary-ext }"
-pkg-fmt = "tgz"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/lychee-0.24.1/lychee-bin/src/formatters/response/color.rs 
new/lychee-0.24.2/lychee-bin/src/formatters/response/color.rs
--- old/lychee-0.24.1/lychee-bin/src/formatters/response/color.rs       
2026-04-24 17:35:48.000000000 +0200
+++ new/lychee-0.24.2/lychee-bin/src/formatters/response/color.rs       
2026-05-01 17:38:40.000000000 +0200
@@ -1,3 +1,5 @@
+use std::sync::LazyLock;
+
 use lychee_lib::{CacheStatus, ResponseBody, Status};
 
 use crate::formatters::color::{DIM, GREEN, PINK, YELLOW};
@@ -13,7 +15,7 @@
 impl ColorFormatter {
     /// Determine the color for formatted output based on the status of the
     /// response.
-    fn status_color(status: &Status) -> &'static 
std::sync::LazyLock<console::Style> {
+    fn status_color(status: &Status) -> &'static LazyLock<console::Style> {
         match status {
             Status::Ok(_) | Status::Cached(CacheStatus::Ok(_)) => &GREEN,
             Status::Excluded
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lychee-0.24.1/lychee-bin/src/formatters/stats/mod.rs 
new/lychee-0.24.2/lychee-bin/src/formatters/stats/mod.rs
--- old/lychee-0.24.1/lychee-bin/src/formatters/stats/mod.rs    2026-04-24 
17:35:48.000000000 +0200
+++ new/lychee-0.24.2/lychee-bin/src/formatters/stats/mod.rs    2026-05-01 
17:38:40.000000000 +0200
@@ -23,7 +23,10 @@
     io::{Write, stdout},
 };
 
-use crate::{config::Config, formatters::get_stats_formatter};
+use crate::{
+    config::{Config, OutputMode},
+    formatters::{color::YELLOW, get_stats_formatter},
+};
 use anyhow::{Context, Result};
 use lychee_lib::{InputSource, ratelimit::HostStatsMap};
 
@@ -40,7 +43,7 @@
     fn format(&self, stats: OutputStats) -> Result<String>;
 }
 
-/// If configured to do so, output response statistics to stdout or the 
specified output file.
+/// Output response statistics to stdout or the specified output file.
 pub(crate) fn output_statistics(stats: OutputStats, config: &Config) -> 
Result<()> {
     let formatter = get_stats_formatter(&config.format(), &config.mode());
     let formatted_stats = formatter.format(stats)?;
@@ -54,6 +57,25 @@
     Ok(())
 }
 
+/// Output hints to stderr.
+pub(crate) fn output_hints(config: &Config) {
+    let hints = lychee_lib::get_hints();
+
+    if config.verbose().log_level() <= log::Level::Error {
+        return; // log level is too low
+    }
+
+    let prefix = match &config.mode() {
+        OutputMode::Emoji => "💡".into(),
+        OutputMode::Color => YELLOW.apply_to("Hint").to_string() + ":",
+        OutputMode::Plain | OutputMode::Task => "Hint:".into(),
+    };
+
+    for hint in hints {
+        eprintln!("{prefix} {hint}");
+    }
+}
+
 /// Convert a `ResponseStats` `HashMap` to a sorted Vec of key-value pairs.
 /// The returned keys and values are both sorted in natural, case-insensitive 
order.
 /// Additionally, the returned keys are deduplicated and their values are 
merged.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lychee-0.24.1/lychee-bin/src/hints.rs 
new/lychee-0.24.2/lychee-bin/src/hints.rs
--- old/lychee-0.24.1/lychee-bin/src/hints.rs   1970-01-01 01:00:00.000000000 
+0100
+++ new/lychee-0.24.2/lychee-bin/src/hints.rs   2026-05-01 17:38:40.000000000 
+0200
@@ -0,0 +1,111 @@
+use http::StatusCode;
+use lychee_lib::{ErrorKind, Status, StatusCodeSelector, hint};
+
+use crate::{config::Config, formatters::stats::ResponseStats};
+
+/// Collect [`lychee_lib::Hint`]s based on the resulting statistics.
+pub(crate) fn handle_stats(stats: &ResponseStats, config: &Config) {
+    rate_limit(stats, config);
+    github_rate_limit(stats, config);
+    any_redirects(stats, config);
+    rejected_status_codes(stats, config);
+    unfollowed_redirects(stats, config);
+}
+
+fn rate_limit(stats: &ResponseStats, config: &Config) {
+    let default_host_config = config.hosts.is_empty();
+    let first_rate_limited_domain = stats
+        .error_map
+        .values()
+        .flatten()
+        .find(|r| {
+            matches!(
+                r.status,
+                
Status::Error(ErrorKind::RejectedStatusCode(StatusCode::TOO_MANY_REQUESTS))
+            )
+        })
+        .and_then(|b| b.uri.domain());
+
+    if default_host_config && let Some(domain) = first_rate_limited_domain {
+        hint!(
+            "Encountered rate limit responses. \
+            You might be able to work around this by adding 
`[hosts.\"{domain}\"]` to the TOML config \
+            to adjust the `concurrency` and `request_interval` values."
+        );
+    }
+}
+
+/// Github rate limits can be circumvented by specifying a token.
+/// According to the [docs]:
+///
+/// > If you exceed your primary rate limit, you will receive a 403 or 429 
response
+///
+/// [docs]: 
https://docs.github.com/en/rest/using-the-rest-api/rate-limits-for-the-rest-api?apiVersion=2026-03-10#exceeding-the-rate-limit
+fn github_rate_limit(stats: &ResponseStats, config: &Config) {
+    let any_github_errors = stats.error_map.values().flatten().any(|body| {
+        let is_github = body
+            .uri
+            .domain()
+            .is_some_and(|domain| domain.ends_with("github.com"));
+
+        let is_rate_limited = matches!(
+            body.status.code(),
+            Some(StatusCode::FORBIDDEN | StatusCode::TOO_MANY_REQUESTS)
+        );
+
+        is_github && is_rate_limited
+    });
+
+    if config.github_token.is_none() && any_github_errors {
+        hint!(
+            "GitHub seems to be rate limiting us. \
+             You could try setting a GitHub token with `--github-token`"
+        );
+    }
+}
+
+fn any_redirects(stats: &ResponseStats, config: &Config) {
+    let count = stats.redirects;
+    let has_redirects = count > 0;
+    let hides_redirects = config.verbose().log_level() < log::Level::Info;
+
+    if has_redirects && hides_redirects {
+        let noun = if count == 1 { "redirect" } else { "redirects" };
+        hint!(
+            "Followed {count} {noun}. \
+             You might want to consider replacing redirecting URLs with the 
resolved URLs. \
+             Use verbose mode (`-v`/`-vv`) to see redirection details."
+        );
+    }
+}
+
+fn rejected_status_codes(stats: &ResponseStats, config: &Config) {
+    let is_default = config.accept() == StatusCodeSelector::default_accepted();
+    let any_rejected_codes = stats
+        .error_map
+        .values()
+        .flatten()
+        .any(|r| matches!(r.status, 
Status::Error(ErrorKind::RejectedStatusCode(_))));
+
+    if is_default && any_rejected_codes {
+        hint!("You can configure accepted/rejected response codes with `-a` or 
`--accept`");
+    }
+}
+
+fn unfollowed_redirects(stats: &ResponseStats, config: &Config) {
+    let is_small_limit = config.max_redirects() <= 
lychee_lib::DEFAULT_MAX_REDIRECTS;
+    let any_rejected_redirection_codes = 
stats.error_map.values().flatten().any(|r| {
+        matches!(
+            r.status,
+            Status::Error(ErrorKind::RejectedStatusCode(s)) if 
s.is_redirection()
+        )
+    });
+
+    if is_small_limit && any_rejected_redirection_codes {
+        hint!(
+            "Rejected redirectional status codes. \
+             This means some redirects were not followed. \
+             You might want to increase the limit for `-m`/`--max-redirects`."
+        );
+    }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lychee-0.24.1/lychee-bin/src/main.rs 
new/lychee-0.24.2/lychee-bin/src/main.rs
--- old/lychee-0.24.1/lychee-bin/src/main.rs    2026-04-24 17:35:48.000000000 
+0200
+++ new/lychee-0.24.2/lychee-bin/src/main.rs    2026-05-01 17:38:40.000000000 
+0200
@@ -84,12 +84,13 @@
 mod config;
 mod files_from;
 mod formatters;
+mod hints;
 mod parse;
 mod progress;
 mod time;
 mod verbosity;
 
-use crate::formatters::stats::{OutputStats, ResponseStats, output_statistics};
+use crate::formatters::stats::{OutputStats, output_hints, output_statistics};
 use crate::{
     cache::Cache,
     config::{Config, LYCHEE_CACHE_FILE, LYCHEE_IGNORE_FILE, LycheeOptions},
@@ -445,8 +446,7 @@
         commands::dump(params).await?
     } else {
         let (response_stats, cache, exit_code, host_pool) = 
commands::check(params).await?;
-        github_warning(&response_stats, &opts.config);
-        redirect_warning(&response_stats, &opts.config);
+        hints::handle_stats(&response_stats, &opts.config);
 
         let stats = OutputStats {
             response_stats,
@@ -466,40 +466,10 @@
             cookie_jar.save().context("Cannot save cookie jar")?;
         }
 
+        output_hints(&opts.config);
+
         exit_code
     };
 
     Ok(exit_code as i32)
 }
-
-/// Display user-friendly message if there were any issues with GitHub URLs
-fn github_warning(stats: &ResponseStats, config: &Config) {
-    let github_errors = stats
-        .error_map
-        .values()
-        .flatten()
-        .any(|body| body.uri.domain() == Some("github.com"));
-
-    if github_errors && config.github_token.is_none() {
-        warn!(
-            "There were issues with GitHub URLs. You could try setting a 
GitHub token and running lychee again.",
-        );
-    }
-}
-
-/// Display user-friendly message if there were any redirects
-/// in non-verbose mode.
-fn redirect_warning(stats: &ResponseStats, config: &Config) {
-    let redirects = stats.redirects;
-    if redirects > 0 && config.verbose().log_level() < log::Level::Info {
-        let noun = if redirects == 1 {
-            "redirect"
-        } else {
-            "redirects"
-        };
-
-        warn!(
-            "lychee detected {redirects} {noun}. You might want to consider 
replacing redirecting URLs with the resolved URLs. Run lychee in verbose mode 
(-v/--verbose) to see details about the redirections.",
-        );
-    }
-}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lychee-0.24.1/lychee-bin/tests/cli.rs 
new/lychee-0.24.2/lychee-bin/tests/cli.rs
--- old/lychee-0.24.1/lychee-bin/tests/cli.rs   2026-04-24 17:35:48.000000000 
+0200
+++ new/lychee-0.24.2/lychee-bin/tests/cli.rs   2026-05-01 17:38:40.000000000 
+0200
@@ -268,12 +268,11 @@
     /// See https://github.com/lycheeverse/lychee/issues/1355
     #[test]
     fn test_valid_json_output_to_stdout_on_error() -> Result<()> {
-        let test_path = fixtures_path!().join("TEST_GITHUB_404.md");
-
         let mut cmd = cargo_bin_cmd!();
         cmd.arg("--format")
             .arg("json")
-            .arg(test_path)
+            .arg("-")
+            
.write_stdin("https://github.com/mre/idiomatic-rust-doesnt-exist-man";)
             .assert()
             .failure()
             .code(2);
@@ -652,25 +651,6 @@
             .stdout(contains("1 Excluded"));
     }
 
-    #[test]
-    fn test_failure_github_404_no_token() {
-        let test_github_404_path = fixtures_path!().join("TEST_GITHUB_404.md");
-
-        cargo_bin_cmd!()
-            .arg(test_github_404_path)
-            .arg("--no-progress")
-            .env_clear()
-            .assert()
-            .failure()
-            .code(2)
-            .stdout(contains(
-                r#"[404] 
https://github.com/mre/idiomatic-rust-doesnt-exist-man (at 3:9) | Rejected 
status code: 404 Not Found (configurable with "accept" option)"#
-            ))
-            .stderr(contains(
-                "There were issues with GitHub URLs. You could try setting a 
GitHub token and running lychee again.",
-            ));
-    }
-
     #[tokio::test]
     async fn test_stdin_input() {
         let mock_server = mock_server!(StatusCode::OK);
@@ -1413,7 +1393,7 @@
                 mock_server_ok.uri()
             )))
             .stderr(contains(format!(
-                "[404] {}/ (at 2:1) | Rejected status code: 404 Not Found 
(configurable with \"accept\" option)\n",
+                "[404] {}/ (at 2:1) | Rejected status code: 404 Not Found\n",
                 mock_server_err.uri()
             )));
 
@@ -1465,13 +1445,16 @@
         // Run first without cache to generate the cache file
         test_cmd
             .assert()
-            .stderr(contains(format!("[200] {}/ (at 1:1)\n", 
mock_server_ok.uri())))
+            .stderr(contains(format!(
+                "[200] {}/ (at 1:1)\n",
+                mock_server_ok.uri()
+            )))
             .stderr(contains(format!(
                 "[204] {}/ (at 2:1) | 204 No Content\n",
                 mock_server_no_content.uri()
             )))
             .stderr(contains(format!(
-                "[429] {}/ (at 3:1) | Rejected status code: 429 Too Many 
Requests (configurable with \"accept\" option)",
+                "[429] {}/ (at 3:1) | Rejected status code: 429 Too Many 
Requests\n",
                 mock_server_too_many_requests.uri()
             )));
 
@@ -1529,11 +1512,11 @@
             .failure()
             .code(2)
             .stdout(contains(format!(
-                r#"[418] {}/ (at 2:1) | Rejected status code: 418 I'm a teapot 
(configurable with "accept" option)"#,
+                r#"[418] {}/ (at 2:1) | Rejected status code: 418 I'm a 
teapot"#,
                 mock_server_teapot.uri()
             )))
             .stdout(contains(format!(
-                r#"[500] {}/ (at 3:1) | Rejected status code: 500 Internal 
Server Error (configurable with "accept" option)"#,
+                r#"[500] {}/ (at 3:1) | Rejected status code: 500 Internal 
Server Error"#,
                 mock_server_server_error.uri()
             )));
 
@@ -1581,7 +1564,7 @@
             .failure()
             .code(2)
             .stdout(contains(format!(
-                r#"[200] {}/ (at 1:1) | Rejected status code: 200 OK 
(configurable with "accept" option)"#,
+                r#"[200] {}/ (at 1:1) | Rejected status code: 200 OK"#,
                 mock_server_200.uri()
             )));
 
@@ -2015,7 +1998,7 @@
             .assert()
             .failure()
             .stdout(contains(r#"
-[404] http://rust-lang.org/lycheeverse (at 1:1) | Rejected status code: 404 
Not Found (configurable with "accept" option) | Remaps: 
http://github.com/lycheeverse --> http://rust-lang.org/lycheeverse | Followed 1 
redirect. Redirects: http://rust-lang.org/lycheeverse --[301]--> 
https://rust-lang.org/lycheeverse
+[404] http://rust-lang.org/lycheeverse (at 1:1) | Rejected status code: 404 
Not Found | Remaps: http://github.com/lycheeverse --> 
http://rust-lang.org/lycheeverse | Followed 1 redirect. Redirects: 
http://rust-lang.org/lycheeverse --[301]--> https://rust-lang.org/lycheeverse
 "#))
         // It is debugged when URIs are remapped
         .stderr(contains("[DEBUG] Remapping http://github.com/lycheeverse --> 
http://rust-lang.org/lycheeverse";))
@@ -2705,7 +2688,7 @@
         // Non-verbose mode
         redirecting_mock_server!(async |redirect_url: Url, _| {
             let (json, stderr) = run(&redirect_url, false);
-            assert!(stderr.contains("[WARN] lychee detected 1 redirect. You 
might want to consider replacing redirecting URLs"));
+            assert!(stderr.contains("Hint: Followed 1 redirect. You might want 
to"));
             assert_eq!(json["total"], 1);
             assert_eq!(json["redirects"], 1); // there was one redirect
             assert_eq!(json["successful"], 1); // which resolved to a success
@@ -4162,6 +4145,7 @@
             .assert()
             .success();
     }
+
     /// Verifies that loading an older, legacy `.lycheecache` file containing 
a cached error
     /// correctly drops the error and successfully retries the link.
     /// This ensures we don't break existing user CI workflows that have older 
cache files
@@ -4535,8 +4519,7 @@
         std::fs::write(dir.path().join("exclude_workspace.txt"), "")?;
         std::fs::write(dir.path().join("exclude_package.txt"), "")?;
 
-        let mut cmd = cargo_bin_cmd!();
-        let assert = cmd
+        let assert = cargo_bin_cmd!()
             .current_dir(dir.path())
             .arg("--dump-inputs")
             .arg(".")
@@ -4549,6 +4532,58 @@
         assert!(output.contains("exclude_workspace.txt"));
         Ok(())
     }
+
+    /// Verify that lychee will fail before all checks run if the parent of 
the given output path does not exist
+    /// See https://github.com/lycheeverse/lychee/issues/2147
+    #[test]
+    fn test_output_invalid_path() {
+        cargo_bin_cmd!()
+            .arg("--output")
+            .arg("does/not/exist")
+            .arg("-")
+            .assert().failure().stderr(contains(
+            "Output path `does/not/exist` is not writable: parent directory 
`does/not` does not exist",
+        ));
+    }
+
+    #[tokio::test]
+    async fn test_user_hints() {
+        cargo_bin_cmd!()
+            .arg("-")
+            .write_stdin("http://wikipedia.org/this/does/not/exist";)
+            .assert()
+            .stderr(contains("Hint: Followed 1 redirect. You might want to 
consider replacing redirecting URLs with the resolved URLs. Use verbose mode 
(`-v`/`-vv`) to see redirection details.\n"))
+            .stderr(contains("Hint: You can configure accepted/rejected 
response codes with `-a` or `--accept`\n"));
+
+        cargo_bin_cmd!()
+            .arg("-")
+            .arg("--max-redirects=0")
+            .write_stdin("http://rust-lang.org";)
+            .assert()
+            .stderr(contains("Hint: Rejected redirectional status codes. This 
means some redirects were not followed. You might want to increase the limit 
for `-m`/`--max-redirects`."));
+
+        cargo_bin_cmd!()
+            .arg("-")
+            .arg("--max-retries=0")
+            .write_stdin("https://http.codes/429";)
+            .assert()
+            .stderr(contains(r#"Hint: Encountered rate limit responses. You 
might be able to work around this by adding `[hosts."http.codes"]` to the TOML 
config to adjust the `concurrency` and `request_interval` values."#));
+
+        cargo_bin_cmd!()
+            .arg("-")
+            .arg("--accept=200..201,300..301")
+            .assert()
+            .stderr(contains(r#"Hint: Accept range `200..201` only matches the 
single status code 200. Did you mean `200..=201` or `200,201`?"#))
+            .stderr(contains(r#"Hint: Accept range `300..301` only matches the 
single status code 300. Did you mean `300..=301` or `300,301`?"#));
+
+        cargo_bin_cmd!()
+            .arg("-")
+            .arg("--max-redirects=0")
+            .write_stdin("http://rust-lang.org";)
+            .arg("-q") // hide user hints
+            .assert()
+            .stderr(contains("Hint").not());
+    }
 }
 
 #[cfg(unix)]
@@ -4575,16 +4610,3 @@
         "System file descriptor limit is 64 which is too low for the requested 
concurrency of 128. Lowering `max_concurrency` to 44",
     ));
 }
-
-// Verify that lychee will fail before all checks run if the parent of the 
given output path does not exist
-// See https://github.com/lycheeverse/lychee/issues/2147
-#[test]
-fn test_output_invalid_path() {
-    let mut cmd = assert_cmd::Command::cargo_bin("lychee").unwrap();
-    cmd.arg("--output")
-        .arg("does/not/exist")
-        .arg("https://example.com";);
-    cmd.assert().failure().stderr(predicates::str::contains(
-        "Output path `does/not/exist` is not writable: parent directory 
`does/not` does not exist",
-    ));
-}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lychee-0.24.1/lychee-lib/CHANGELOG.md 
new/lychee-0.24.2/lychee-lib/CHANGELOG.md
--- old/lychee-0.24.1/lychee-lib/CHANGELOG.md   2026-04-24 17:35:48.000000000 
+0200
+++ new/lychee-0.24.2/lychee-lib/CHANGELOG.md   2026-05-01 17:38:40.000000000 
+0200
@@ -7,6 +7,20 @@
 
 ## [Unreleased]
 
+## 
[0.24.2](https://github.com/lycheeverse/lychee/compare/lychee-lib-v0.24.1...lychee-lib-v0.24.2)
 - 2026-04-30
+
+### Added
+
+- user hints ([#2021](https://github.com/lycheeverse/lychee/pull/2021))
+
+### Fixed
+
+- typo in README.md ([#2173](https://github.com/lycheeverse/lychee/pull/2173))
+
+### Other
+
+- *(deps)* bump the dependencies group with 8 updates
+
 ## 
[0.24.1](https://github.com/lycheeverse/lychee/compare/lychee-lib-v0.24.0...lychee-lib-v0.24.1)
 - 2026-04-24
 
 ### Other
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lychee-0.24.1/lychee-lib/Cargo.toml 
new/lychee-0.24.2/lychee-lib/Cargo.toml
--- old/lychee-0.24.1/lychee-lib/Cargo.toml     2026-04-24 17:35:48.000000000 
+0200
+++ new/lychee-0.24.2/lychee-lib/Cargo.toml     2026-05-01 17:38:40.000000000 
+0200
@@ -33,7 +33,7 @@
 linkify = "0.11.0"
 log = "0.4.28"
 mailify-lib = { version = "0.2.0", optional = true }
-octocrab = { version = "0.49.7", default-features = false, features = [
+octocrab = { version = "0.49.9", default-features = false, features = [
     "default-client",
     "follow-redirect",
     "jwt-rust-crypto",
@@ -49,7 +49,7 @@
 pulldown-cmark = "0.13.3"
 quick-xml = "0.39.2"
 regex = "1.12.2"
-reqwest = { version = "0.13.2", features = ["json", "gzip"] }
+reqwest = { version = "0.13.3", features = ["json", "gzip"] }
 reqwest_cookie_store = { version = "0.10.0", features = ["serde"] }
 # Make build work on Apple Silicon.
 # See https://github.com/briansmith/ring/issues/1163
@@ -62,7 +62,7 @@
 shellexpand = "3.1.2"
 strum = { version = "0.28.0", features = ["derive"] }
 thiserror = "2.0.18"
-tokio = { version = "1.51.1", features = ["full"] }
+tokio = { version = "1.52.1", features = ["full"] }
 toml = "1.1.2"
 typed-builder = "0.23.2"
 url = { version = "2.5.8", features = ["serde"] }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lychee-0.24.1/lychee-lib/src/lib.rs 
new/lychee-0.24.2/lychee-lib/src/lib.rs
--- old/lychee-0.24.1/lychee-lib/src/lib.rs     2026-04-24 17:35:48.000000000 
+0200
+++ new/lychee-0.24.2/lychee-lib/src/lib.rs     2026-05-01 17:38:40.000000000 
+0200
@@ -103,7 +103,7 @@
         BaseInfo, BasicAuthCredentials, BasicAuthSelector, CacheStatus, 
CookieJar, ErrorKind,
         FileExtensions, FileType, Input, InputContent, InputResolver, 
InputSource, LycheeResult,
         Preprocessor, Redirect, Redirects, Request, RequestError, 
ResolvedInputSource, Response,
-        ResponseBody, Result, Status, StatusCodeSelector, StatusRange, 
StatusRangeError,
+        ResponseBody, Result, Status, StatusCodeSelector, StatusRange, 
StatusRangeError, hints::*,
         uri::raw::RawUri, uri::raw::RawUriSpan, uri::valid::Uri,
     },
 };
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lychee-0.24.1/lychee-lib/src/ratelimit/config.rs 
new/lychee-0.24.2/lychee-lib/src/ratelimit/config.rs
--- old/lychee-0.24.1/lychee-lib/src/ratelimit/config.rs        2026-04-24 
17:35:48.000000000 +0200
+++ new/lychee-0.24.2/lychee-lib/src/ratelimit/config.rs        2026-05-01 
17:38:40.000000000 +0200
@@ -65,11 +65,17 @@
     }
 
     /// Get the number of [`HostConfig`]s
-    #[cfg(test)]
-    pub(crate) fn len(&self) -> usize {
+    #[must_use]
+    pub fn len(&self) -> usize {
         self.0.len()
     }
 
+    /// Returns `true` if if there are no [`HostConfig`]s
+    #[must_use]
+    pub fn is_empty(&self) -> bool {
+        self.0.is_empty()
+    }
+
     /// Get the iterator over all elements
     pub(crate) fn iter(&self) -> Iter<'_, HostKey, HostConfig> {
         self.0.iter()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lychee-0.24.1/lychee-lib/src/types/accept/range.rs 
new/lychee-0.24.2/lychee-lib/src/types/accept/range.rs
--- old/lychee-0.24.1/lychee-lib/src/types/accept/range.rs      2026-04-24 
17:35:48.000000000 +0200
+++ new/lychee-0.24.2/lychee-lib/src/types/accept/range.rs      2026-05-01 
17:38:40.000000000 +0200
@@ -7,6 +7,8 @@
 use regex::Regex;
 use thiserror::Error;
 
+use crate::hint;
+
 /// Smallest accepted value
 const MIN: u16 = 100;
 
@@ -75,6 +77,12 @@
             if inclusive {
                 Self::new(start, end)
             } else {
+                if end == start + 1 {
+                    hint!(
+                        "Accept range `{s}` only matches the single status 
code {start}. \
+                         Did you mean `{start}..={end}` or `{start},{end}`?"
+                    );
+                }
                 Self::new(start, end - 1)
             }
         }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lychee-0.24.1/lychee-lib/src/types/error.rs 
new/lychee-0.24.2/lychee-lib/src/types/error.rs
--- old/lychee-0.24.1/lychee-lib/src/types/error.rs     2026-04-24 
17:35:48.000000000 +0200
+++ new/lychee-0.24.2/lychee-lib/src/types/error.rs     2026-05-01 
17:38:40.000000000 +0200
@@ -152,7 +152,7 @@
 
     /// The given status code was not accepted (this depends on the `accept` 
configuration)
     #[error(
-        r#"Rejected status code: {code} {reason} (configurable with "accept" 
option)"#,
+        "Rejected status code: {code} {reason}",
         code = .0.as_str(),
         reason = .0.canonical_reason().unwrap_or("Unknown status code")
     )]
@@ -479,16 +479,7 @@
     use crate::ErrorKind;
     #[test]
     fn test_error_kind_details() {
-        // Test rejected status code
         let status_error = 
ErrorKind::RejectedStatusCode(http::StatusCode::NOT_FOUND);
         assert!(status_error.to_string().contains("Not Found"));
-
-        // Test redirected status code
-        let redir_error = 
ErrorKind::RejectedStatusCode(http::StatusCode::MOVED_PERMANENTLY);
-        assert!(
-            redir_error
-                .details()
-                .contains(r#"(configurable with "accept" option)"#)
-        );
     }
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lychee-0.24.1/lychee-lib/src/types/hints.rs 
new/lychee-0.24.2/lychee-lib/src/types/hints.rs
--- old/lychee-0.24.1/lychee-lib/src/types/hints.rs     1970-01-01 
01:00:00.000000000 +0100
+++ new/lychee-0.24.2/lychee-lib/src/types/hints.rs     2026-05-01 
17:38:40.000000000 +0200
@@ -0,0 +1,63 @@
+//! Provide the means to display practical user-friendly messages,
+//! which are collected during runtime.
+
+use std::{
+    collections::{BTreeSet, btree_set::IntoIter},
+    fmt::Display,
+    sync::Mutex,
+};
+
+/// Hints are accumulated during the whole program invocation.
+static HINTS: Mutex<BTreeSet<Hint>> = Mutex::new(BTreeSet::new());
+
+/// An informative and friendly message created during the invocation of the 
program
+/// to be displayed before termination, to improve user experience.
+#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
+pub struct Hint(String);
+
+impl Display for Hint {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "{}", self.0)
+    }
+}
+
+impl From<String> for Hint {
+    fn from(value: String) -> Self {
+        Self(value)
+    }
+}
+
+impl From<&str> for Hint {
+    fn from(value: &str) -> Self {
+        Self(value.to_owned())
+    }
+}
+
+/// Collect a [`Hint`] to optionally be shown to users
+/// at a later point in time by using [`get_hints`].
+///
+///
+/// # Panics
+///
+/// Panics if the mutex is poisoned
+pub fn add_hint(hint: Hint) {
+    HINTS.lock().unwrap().insert(hint);
+}
+
+/// Format and collect a [`Hint`].
+/// Helper macro for [`add_hint`].
+#[macro_export]
+macro_rules! hint {
+    ($($arg:tt)*) => {{
+        $crate::add_hint(format!($($arg)*).into());
+    }};
+}
+
+/// Get [`Hint`]s to report to users
+///
+/// # Panics
+///
+/// Panics if the mutex is poisoned
+pub fn get_hints() -> IntoIter<Hint> {
+    HINTS.lock().unwrap().clone().into_iter()
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lychee-0.24.1/lychee-lib/src/types/mod.rs 
new/lychee-0.24.2/lychee-lib/src/types/mod.rs
--- old/lychee-0.24.1/lychee-lib/src/types/mod.rs       2026-04-24 
17:35:48.000000000 +0200
+++ new/lychee-0.24.2/lychee-lib/src/types/mod.rs       2026-05-01 
17:38:40.000000000 +0200
@@ -7,6 +7,7 @@
 mod cookies;
 mod error;
 mod file;
+pub(crate) mod hints;
 mod input;
 mod preprocessor;
 pub(crate) mod redirect_history;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lychee-0.24.1/pyproject.toml 
new/lychee-0.24.2/pyproject.toml
--- old/lychee-0.24.1/pyproject.toml    1970-01-01 01:00:00.000000000 +0100
+++ new/lychee-0.24.2/pyproject.toml    2026-05-01 17:38:40.000000000 +0200
@@ -0,0 +1,24 @@
+[build-system]
+requires = ["maturin>=1.10,<2.0"]
+build-backend = "maturin"
+
+[project]
+name = "lychee-bin"
+requires-python = ">=3"
+classifiers = [
+    "Programming Language :: Rust",
+    "Programming Language :: Python :: Implementation :: CPython",
+]
+dynamic = [
+    "version",
+    "description",
+    "keywords",
+    "authors",
+    "urls",
+    "readme",
+    "license",
+]
+
+[tool.maturin]
+bindings = "bin"
+manifest-path = "lychee-bin/Cargo.toml"

++++++ lychee.obsinfo ++++++
--- /var/tmp/diff_new_pack.dO997S/_old  2026-05-04 12:56:18.372367055 +0200
+++ /var/tmp/diff_new_pack.dO997S/_new  2026-05-04 12:56:18.380367385 +0200
@@ -1,5 +1,5 @@
 name: lychee
-version: 0.24.1
-mtime: 1777044948
-commit: 1f7e8d5524df4e6b3a9335445886fa54250063e2
+version: 0.24.2
+mtime: 1777649920
+commit: 2bba271688c1abb1503097a064e6c3bc1d1b6a9b
 

++++++ vendor.tar.zst ++++++
/work/SRC/openSUSE:Factory/lychee/vendor.tar.zst 
/work/SRC/openSUSE:Factory/.lychee.new.30200/vendor.tar.zst differ: char 7, 
line 1

Reply via email to