From be9b656fad71e4f254a5f27a0a1b1307466ffddc Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Thu, 4 Jun 2026 19:35:46 +0000 Subject: [PATCH 1/2] Add lychee link checker config and CI workflow Adds a lychee configuration and a Links GitHub Actions workflow so that stale or redirecting links are caught automatically going forward. The checker runs on push, pull request, and weekly to catch external link rot. max_redirects is 0 so links that have moved are surfaced and can be updated to their canonical destination. Part of STF-557. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/links.yml | 32 +++++++++++++++++++ .gitignore | 1 + lychee.toml | 64 +++++++++++++++++++++++++++++++++++++ mise.lock | 28 ++++++++++++++++ mise.toml | 5 +++ 5 files changed, 130 insertions(+) create mode 100644 .github/workflows/links.yml create mode 100644 lychee.toml diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml new file mode 100644 index 00000000..5e3255ba --- /dev/null +++ b/.github/workflows/links.yml @@ -0,0 +1,32 @@ +name: Links + +on: + push: + pull_request: + schedule: + - cron: "0 13 * * 1" # weekly, to catch external link rot without a commit + workflow_dispatch: + +permissions: + contents: read + +jobs: + linkChecker: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Setup mise + uses: jdx/mise-action@6d1e696aa24c1aa1bcc1adea0212707c71ab78a8 # v3.6.1 + with: + install: false + + # Install only lychee (not the repo's full toolchain) and run the check. + - name: Check links + env: + MISE_AUTO_INSTALL: "false" + run: | + mise install lychee + mise run check-links diff --git a/.gitignore b/.gitignore index 2dcc0bf1..58a3e4a0 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ pom.xml.versionsBackup target reports Test.java +.lycheecache diff --git a/lychee.toml b/lychee.toml new file mode 100644 index 00000000..d8993aad --- /dev/null +++ b/lychee.toml @@ -0,0 +1,64 @@ +# Lychee link checker configuration +# https://lychee.cli.rs/#/usage/config +# +# Run locally with: +# lychee './**/*.md' './src/**/*.java' './pom.xml' + +# Include URL fragments in checks +include_fragments = true + +# Don't allow any redirects, so links that have moved are surfaced and updated +# to their canonical destination. +max_redirects = 0 + +# Accept these HTTP status codes +# 100-103: Informational responses +# 200-299: Success responses +# 403: Forbidden (some sites use this for rate limiting) +# 429: Too Many Requests +# 500-599: Server errors (temporary issues shouldn't fail CI) +# 999: LinkedIn's custom status code +accept = ["100..=103", "200..=299", "403", "429", "500..=599", "999"] + +# Exclude URL patterns from checking (treated as regular expressions) +exclude = [ + '^file://', + # Live / auth-gated endpoints that appear as string literals or require login + '^https://geoip\.maxmind\.com', + '^https://geolite\.info', + '^https://minfraud\.maxmind\.com', + '^https://sandbox\.maxmind\.com', + '^https://updates\.maxmind\.com', + '^https://www\.maxmind\.com/en/accounts/', + 'https://www\.maxmind\.com/en/account/login', + # XML namespace identifiers in pom.xml (not real links) + '^http://www\.w3\.org/', + '^http://maven\.apache\.org/', + '^https://maven\.apache\.org/xsd/', + '^http://java\.sun\.com/', + '^http://schemas\.', + # Maven property placeholder in a build-time download URL (not a real link) + 'japicmp\.baselineVersion', + # Placeholders / local + '^https?://example\.(com|org|net)', + '^http://localhost', + '127\.0\.0\.1', +] + +# Exclude file paths from getting checked (treated as regular expressions) +exclude_path = [ + '(^|/)node_modules/', + '(^|/)target/', + '(^|/)\.git/', + # Test fixtures (MaxMind-DB submodule) contain example URLs, not ours + '(^|/)src/test/resources/', + # Changelog: historical entries are preserved as-is, not rewritten + '(^|/)CHANGELOG\.md$', +] + +# Cache results for 1 day to speed up repeated checks +cache = true +max_cache_age = "1d" + +# Skip missing input files instead of erroring +skip_missing = true diff --git a/mise.lock b/mise.lock index 9b150a1f..a1cae619 100644 --- a/mise.lock +++ b/mise.lock @@ -36,6 +36,34 @@ url = "https://github.com/gohugoio/hugo/releases/download/v0.161.1/hugo_0.161.1_ version = "26.0.1" backend = "core:java" +[[tools.lychee]] +version = "0.23.0" +backend = "aqua:lycheeverse/lychee" + +[tools.lychee."platforms.linux-arm64"] +checksum = "sha256:97eb93b02a7d78a752fc33e5b0983439ccaadbf3db952b68a0a4401acd92e6e0" +url = "https://github.com/lycheeverse/lychee/releases/download/lychee-v0.23.0/lychee-aarch64-unknown-linux-gnu.tar.gz" + +[tools.lychee."platforms.linux-arm64-musl"] +checksum = "sha256:97eb93b02a7d78a752fc33e5b0983439ccaadbf3db952b68a0a4401acd92e6e0" +url = "https://github.com/lycheeverse/lychee/releases/download/lychee-v0.23.0/lychee-aarch64-unknown-linux-gnu.tar.gz" + +[tools.lychee."platforms.linux-x64"] +checksum = "sha256:5538440d2c69a45a0a09983271e5dee0c2fe7137d8035d25b2632e10a66a090a" +url = "https://github.com/lycheeverse/lychee/releases/download/lychee-v0.23.0/lychee-x86_64-unknown-linux-musl.tar.gz" + +[tools.lychee."platforms.linux-x64-musl"] +checksum = "sha256:5538440d2c69a45a0a09983271e5dee0c2fe7137d8035d25b2632e10a66a090a" +url = "https://github.com/lycheeverse/lychee/releases/download/lychee-v0.23.0/lychee-x86_64-unknown-linux-musl.tar.gz" + +[tools.lychee."platforms.macos-arm64"] +checksum = "sha256:4c8034900e11083b68ac6f6582c377ff1f704e268991999e09d717973e493e7f" +url = "https://github.com/lycheeverse/lychee/releases/download/lychee-v0.23.0/lychee-arm64-macos.dmg" + +[tools.lychee."platforms.windows-x64"] +checksum = "sha256:0fda7ff0a60c0250939fc25361c2d4e6e7853c31c996733fdd5a1dd760bcb824" +url = "https://github.com/lycheeverse/lychee/releases/download/lychee-v0.23.0/lychee-x86_64-windows.exe" + [[tools.maven]] version = "3.9.15" backend = "aqua:apache/maven" diff --git a/mise.toml b/mise.toml index 4a11f83e..9ac550c4 100644 --- a/mise.toml +++ b/mise.toml @@ -9,6 +9,7 @@ disable_backends = [ [tools] hugo = "latest" java = "latest" +lychee = "latest" maven = "latest" [tasks.build-docs] @@ -19,6 +20,10 @@ run = "hugo --source docs --minify" description = "Serve the docs site locally with Hugo dev server" run = "hugo server --source docs" +[tasks.check-links] +description = "Check links with lychee" +run = "lychee --no-progress './**/*.md' './src/**/*.java' './pom.xml'" + [hooks] enter = "mise install --quiet --locked" From 0b38d5926c8dd5fd1a92f29f89d196741811a794 Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Thu, 4 Jun 2026 19:35:52 +0000 Subject: [PATCH 2/2] Update stale and redirecting links Validated all links with lychee and updated those that were out of date or redirected elsewhere: - dev.maxmind.com/geoip doc URLs now use canonical trailing-slash form - www.maxmind.com/ -> www.maxmind.com/en/home (pom.xml) - www.maxmind.com/en/correction -> /en/geoip-data-correction-request - www.maxmind.com/en/support -> support.maxmind.com/knowledge-base Historical CHANGELOG.md entries are intentionally left unchanged. Part of STF-557. Co-Authored-By: Claude Opus 4.8 (1M context) --- CLAUDE.md | 2 +- README.md | 14 +++++++------- pom.xml | 4 ++-- .../java/com/maxmind/geoip2/WebServiceClient.java | 2 +- .../com/maxmind/geoip2/model/CityResponse.java | 2 +- .../com/maxmind/geoip2/model/CountryResponse.java | 2 +- .../com/maxmind/geoip2/model/InsightsResponse.java | 2 +- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 9e893205..e22e9d6e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -397,7 +397,7 @@ public interface JsonSerializable { ## Additional Resources - [API Documentation](https://maxmind.github.io/GeoIP2-java/) -- [GeoIP Web Services Docs](https://dev.maxmind.com/geoip/docs/web-services) +- [GeoIP Web Services Docs](https://dev.maxmind.com/geoip/docs/web-services/) - [MaxMind DB Format](https://maxmind.github.io/MaxMind-DB/) - GitHub Issues: https://github.com/maxmind/GeoIP2-java/issues diff --git a/README.md b/README.md index 9cfcdfcb..396209fa 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,8 @@ ## Description ## This distribution provides an API for the GeoIP and GeoLite [web -services](https://dev.maxmind.com/geoip/docs/web-services?lang=en) and -[databases](https://dev.maxmind.com/geoip/docs/databases?lang=en). +services](https://dev.maxmind.com/geoip/docs/web-services/?lang=en) and +[databases](https://dev.maxmind.com/geoip/docs/databases/?lang=en). ## Installation ## @@ -491,7 +491,7 @@ try (DatabaseReader reader = new DatabaseReader.Builder(database).build()) { For details on the possible errors returned by the web service itself, [see the GeoIP web service -documentation](https://dev.maxmind.com/geoip/docs/web-services?lang=en). +documentation](https://dev.maxmind.com/geoip/docs/web-services/?lang=en). If the web service returns an explicit error document, this is thrown as an `AddressNotFoundException`, an `AuthenticationException`, an @@ -537,7 +537,7 @@ Because of these factors, it is possible for any web service to return a record where some or all of the attributes are unpopulated. [See our web-service developer -documentation](https://dev.maxmind.com/geoip/docs/web-services?lang=en) for +documentation](https://dev.maxmind.com/geoip/docs/web-services/?lang=en) for details on what data each web service may return. The only piece of data which is always returned is the `ip_address` @@ -562,7 +562,7 @@ the GeoNames premium data set. If the problem you find is that an IP address is incorrectly mapped, please -[submit your correction to MaxMind](https://www.maxmind.com/en/correction). +[submit your correction to MaxMind](https://www.maxmind.com/en/geoip-data-correction-request). If you find some other sort of mistake, like an incorrect spelling, please check [the GeoNames site](https://www.geonames.org/) first. Once @@ -573,7 +573,7 @@ data set, it will be automatically incorporated into future MaxMind releases. If you are a paying MaxMind customer and you're not sure where to submit -a correction, please [contact MaxMind support](https://www.maxmind.com/en/support) +a correction, please [contact MaxMind support](https://support.maxmind.com/knowledge-base) for help. ## Other Support ## @@ -583,7 +583,7 @@ Please report all issues with this code using the If you are having an issue with a MaxMind service that is not specific to the client API, please -[contact MaxMind support](https://www.maxmind.com/en/support). +[contact MaxMind support](https://support.maxmind.com/knowledge-base). ## Requirements ## diff --git a/pom.xml b/pom.xml index aff1a8da..8e34ad0b 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ jar MaxMind GeoIP API GeoIP webservice client and database reader - https://dev.maxmind.com/geoip?lang=en + https://dev.maxmind.com/geoip/?lang=en Apache License, Version 2.0 @@ -17,7 +17,7 @@ MaxMind, Inc. - https://www.maxmind.com/ + https://www.maxmind.com/en/home https://github.com/maxmind/GeoIP2-java diff --git a/src/main/java/com/maxmind/geoip2/WebServiceClient.java b/src/main/java/com/maxmind/geoip2/WebServiceClient.java index 80ba873f..1178dae9 100644 --- a/src/main/java/com/maxmind/geoip2/WebServiceClient.java +++ b/src/main/java/com/maxmind/geoip2/WebServiceClient.java @@ -91,7 +91,7 @@ *

Exceptions

*

* For details on the possible errors returned by the web service itself, see the GeoIP web + * href="https://dev.maxmind.com/geoip/docs/web-services/?lang=en">the GeoIP web * service documentation. *

*

diff --git a/src/main/java/com/maxmind/geoip2/model/CityResponse.java b/src/main/java/com/maxmind/geoip2/model/CityResponse.java index f93997d3..9d1fd8e6 100644 --- a/src/main/java/com/maxmind/geoip2/model/CityResponse.java +++ b/src/main/java/com/maxmind/geoip2/model/CityResponse.java @@ -40,7 +40,7 @@ * to most specific (smallest). If the response did not contain any * subdivisions, this is an empty list. * @param traits Record for the traits of the requested IP address. - * @see GeoIP Web + * @see GeoIP Web * Services */ public record CityResponse( diff --git a/src/main/java/com/maxmind/geoip2/model/CountryResponse.java b/src/main/java/com/maxmind/geoip2/model/CountryResponse.java index 1d20f2e6..ad30b78e 100644 --- a/src/main/java/com/maxmind/geoip2/model/CountryResponse.java +++ b/src/main/java/com/maxmind/geoip2/model/CountryResponse.java @@ -25,7 +25,7 @@ * represented country is used for things like military bases. It is * only present when the represented country differs from the country. * @param traits Record for the traits of the requested IP address. - * @see GeoIP Web + * @see GeoIP Web * Services */ public record CountryResponse( diff --git a/src/main/java/com/maxmind/geoip2/model/InsightsResponse.java b/src/main/java/com/maxmind/geoip2/model/InsightsResponse.java index f8462583..b5fa3ea4 100644 --- a/src/main/java/com/maxmind/geoip2/model/InsightsResponse.java +++ b/src/main/java/com/maxmind/geoip2/model/InsightsResponse.java @@ -43,7 +43,7 @@ * to most specific (smallest). If the response did not contain any * subdivisions, this is an empty list. * @param traits Record for the traits of the requested IP address. - * @see GeoIP Web + * @see GeoIP Web * Services */ public record InsightsResponse(