Skip to content

feat(links): add GitHub URL remaps for line-number and fragment anchors#28

Merged
zeitlinger merged 1 commit intomainfrom
github-url-remaps
Feb 18, 2026
Merged

feat(links): add GitHub URL remaps for line-number and fragment anchors#28
zeitlinger merged 1 commit intomainfrom
github-url-remaps

Conversation

@zeitlinger
Copy link
Copy Markdown
Member

Summary

  • Add ordered remaps in build_remap_args() for GitHub /blob/ and /tree/ URLs with line-number anchors (#L123) and other fragments (#section)
  • Line-number anchors are stripped (they're JS-rendered and unverifiable by lychee); other fragments are remapped to raw.githubusercontent.com as a workaround for lychee#1729
  • Consuming repos no longer need custom remap rules in lychee.toml for these patterns
  • Add LYCHEE_SKIP_GITHUB_REMAPS=true opt-out env var

Context

GitHub blob URLs with line-number anchors (#L6) are JavaScript-rendered and can't be verified by lychee (which fetches static HTML). When the existing branch remap rewrites blob/main/blob/<pr-branch>/, these URLs fail fragment checking.

Since lychee uses first-match-wins (no chaining), config file remaps never run after flint's CLI --remap matches. The fix belongs here in build_remap_args().

Remap order (first-match-wins)

For /blob/ URLs:

  1. Line-number anchors (#L123): strip fragment, check file on base branch
  2. Other fragment URLs (#section): remap to raw.githubusercontent.com + head branch
  3. Non-fragment URLs: branch-remap only (existing behavior)

For /tree/ URLs: rules 1 and 3 only (no raw remap needed).

Test plan

  • Run mise run lint:links --full in a consuming repo (e.g. grafana-opentelemetry-java) with a #L6 link
  • Verify the link passes without custom remap rules in lychee.toml
  • CI passes

Copilot AI review requested due to automatic review settings February 18, 2026 07:47
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

This PR updates the lychee link-lint task to better handle GitHub /blob/ and /tree/ URLs that include fragments, especially line-number anchors that lychee can’t verify reliably on GitHub’s JS-rendered pages.

Changes:

  • Add ordered GitHub --remap rules for /blob/ and /tree/ URLs to handle line-number anchors and other fragments.
  • Strip #L123 fragments (and introduce a raw-content remap for other fragments) to reduce false negatives during fragment checking.
  • Add LYCHEE_SKIP_GITHUB_REMAPS=true to opt out of GitHub-specific CLI remaps emitted by the task.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tasks/lint/links.sh Outdated
Comment on lines +75 to +78
# 1. Line-number anchors (#L123): strip fragment, check file on base branch
echo "--remap"
echo "^${base_url}/blob/${base_ref}/(.*?)#L[0-9]+\$ ${base_url}/blob/${base_ref}/\$1"

Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

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

The line-anchor remap keeps the URL on the base branch (${base_ref}), which contradicts the function’s stated goal of making base-branch links resolve on the PR/head branch. This will make PRs fail when they add a new file (or rename/move one) and link to it via .../blob/${base_ref}/...#L123, because the stripped URL will 404 on the base branch even though it exists on the head branch. Consider stripping the fragment but still rewriting to the head repo/ref (similar to the non-fragment rule).

Copilot uses AI. Check for mistakes.
Comment thread tasks/lint/links.sh Outdated
Comment on lines +90 to +92
# 1. Line-number anchors: strip fragment (unlikely for tree but consistent)
echo "--remap"
echo "^${base_url}/tree/${base_ref}/(.*?)#L[0-9]+\$ ${base_url}/tree/${base_ref}/\$1"
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

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

Same issue as the /blob/ rule: the /tree/ line-anchor remap strips the fragment but keeps the URL on the base branch. If a PR introduces a new directory/link target (or moves it) and uses a .../tree/${base_ref}/...#L123 link, the remapped URL will be checked against the base branch and can 404 even though it exists on the head branch. Consider stripping the fragment while still remapping to ${head_url}/tree/${head_ref}/....

Suggested change
# 1. Line-number anchors: strip fragment (unlikely for tree but consistent)
echo "--remap"
echo "^${base_url}/tree/${base_ref}/(.*?)#L[0-9]+\$ ${base_url}/tree/${base_ref}/\$1"
# 1. Line-number anchors: strip fragment, remap to head branch
echo "--remap"
echo "^${base_url}/tree/${base_ref}/(.*?)#L[0-9]+\$ ${head_url}/tree/${head_ref}/\$1"

Copilot uses AI. Check for mistakes.
Comment thread tasks/lint/links.sh Outdated
# fragment. We strip the fragment and check the file exists instead.
#
# For other fragment URLs (#section), we remap to raw.githubusercontent.com
# which lets lychee verify the fragment in the raw HTML (workaround for
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

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

The comment says raw.githubusercontent.com “lets lychee verify the fragment in the raw HTML”, but raw.githubusercontent.com serves the raw file contents (not rendered HTML). Consider rewording to avoid implying GitHub is returning HTML here (e.g., “verify fragments against the raw content”, or describing the specific behavior lychee uses for fragment checks).

Suggested change
# which lets lychee verify the fragment in the raw HTML (workaround for
# which lets lychee verify the fragment against the raw file content (workaround for

Copilot uses AI. Check for mistakes.
Comment thread tasks/lint/links.sh Outdated
# 2. Other fragments → remap to raw.githubusercontent.com
# 3. No fragment → remap to head branch (existing behavior)
#
# Set LYCHEE_SKIP_GITHUB_REMAPS=true to disable all GitHub-specific remaps.
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

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

LYCHEE_SKIP_GITHUB_REMAPS=true currently only disables the GitHub remaps emitted by build_remap_args(), but this repo’s .github/config/lychee.toml also defines a GitHub remap. Consider clarifying the comment to avoid implying this env var disables all GitHub remapping behavior in lychee, or remove/move the config remap if the intent is to centralize remaps here.

Suggested change
# Set LYCHEE_SKIP_GITHUB_REMAPS=true to disable all GitHub-specific remaps.
# Set LYCHEE_SKIP_GITHUB_REMAPS=true to disable the GitHub-specific remaps
# emitted by this function (does not affect remaps defined in lychee config).

Copilot uses AI. Check for mistakes.
@zeitlinger zeitlinger force-pushed the github-url-remaps branch 4 times, most recently from 0b01df2 to 7da8508 Compare February 18, 2026 09:33
GitHub blob URLs with line-number anchors (#L123) are JavaScript-rendered
and can't be verified by lychee. When the existing branch remap rewrites
blob/main/ to blob/<pr-branch>/, these URLs fail fragment checking.

Add ordered remaps in build_remap_args() (first-match-wins):
1. Line-number anchors (#L123): strip the fragment, check file exists
2. Other fragment URLs (#section): remap to raw.githubusercontent.com
   (workaround for lychee#1729)
3. Non-fragment URLs: branch-remap only (existing behavior)

This removes the need for consuming repos to maintain their own remap
rules in lychee.toml for these common patterns.

Also add LYCHEE_SKIP_GITHUB_REMAPS=true opt-out env var.
Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
@zeitlinger zeitlinger merged commit 5b59065 into main Feb 18, 2026
7 checks passed
@zeitlinger zeitlinger deleted the github-url-remaps branch February 18, 2026 09:41
zeitlinger pushed a commit that referenced this pull request Feb 18, 2026
🤖 I have created a release *beep* *boop*
---


## [0.6.0](v0.5.0...v0.6.0)
(2026-02-18)


### Features

* **links:** add GitHub URL remaps for line-number and fragment anchors
([#28](#28))
([5b59065](5b59065))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
zeitlinger pushed a commit that referenced this pull request Apr 13, 2026
## flint v0.20.0 — Rust rewrite

flint has been rewritten from scratch in Rust. The bash + Docker stack
is replaced by a fast, cross-platform native binary with no container
dependency.

### Highlights

- **Native binary** — no Docker, no bash wrappers; runs anywhere mise
can install a Rust crate
- **Parallel linting** — all checks run concurrently
- **Diff-aware** — only checks files changed since the merge base by
default (`--full` for everything)
- **`flint update`** — migrates obsolete `mise.toml` tool keys
automatically (e.g. `ubi:` → `github:`, `npm:markdownlint-cli` →
`npm:markdownlint-cli2`)
- **`flint hook install`** — installs a pre-commit hook without any mise
task knowledge
- **New linters**: `gofmt`, `google-java-format`, `ktlint`,
`dotnet-format`, `markdownlint-cli2`, `xmllint` (via `cargo:xmloxide`),
`license-header` (pure-Rust, no binary)
- **Windows support** — ktlint self-executing JAR handled via explicit
`java -jar` invocation

### Migration

See
[AGENTS-V2.md](https://github.com/grafana/flint/blob/main/AGENTS-V2.md)
and [README.md](https://github.com/grafana/flint/blob/main/README.md)
for full setup instructions.

Quick reference for existing consumers:

```toml
[tools]
# While installing from source (pre-crates.io release):
"cargo:https://github.com/grafana/flint" = "branch:main"

[env]
FLINT_CONFIG_DIR = ".github/config"

[tasks.lint]
run = "flint run"

[tasks."lint:fix"]
run = "flint run --fix"
```

Remove: `lint:super-linter`, `lint:links`, `lint:renovate-deps`,
`setup:native-lint-tools`, `setup:pre-commit-hook` tasks. Run `flint
update` to auto-migrate any obsolete tool keys.

> [!NOTE]
> The changelog below includes entries from the legacy v1 bash era — see
[README-V1.md](https://github.com/grafana/flint/blob/main/README-V1.md)
for v1 docs.

---

##
[0.20.0](flint-v0.19.0...flint-v0.20.0)
(2026-04-13)


### Features

* add flint v2 Rust binary
([#139](#139))
([19f2b25](19f2b25))
* add native linting mode and version mapping infrastructure
([#93](#93))
([24b06da](24b06da))
* add Renovate shareable preset for consuming repos
([#17](#17))
([8a06590](8a06590))
* consolidate link checking and add autofix flags
([#7](#7))
([086a5e9](086a5e9))
* flint update command, explicit JAR flag, v0.20.0
([#146](#146))
([b43bf52](b43bf52))
* handle line-number anchors and issue comments globally
([#56](#56))
([cf751df](cf751df))
* **links:** add GitHub URL remaps for line-number and fragment anchors
([#28](#28))
([5b59065](5b59065))
* **links:** auto-remap base-branch GitHub URLs to PR branch
([#18](#18))
([dd6cc61](dd6cc61))
* **renovate:** support SHA-pinned URLs in Renovate preset
([#21](#21))
([4fd1f28](4fd1f28))
* **super-linter:** default to slim image
([#24](#24))
([c8eeab8](c8eeab8))
* support NATIVE env var for container-free linting
([#107](#107))
([0a8193d](0a8193d))


### Bug Fixes

* activate mise environment in native lint mode
([#123](#123))
([d0fec45](d0fec45))
* add 'mise run fix' hint to lint failure output
([#90](#90))
([5b4ad5d](5b4ad5d))
* decouple version mapping generation from pinned super-linter version
([#112](#112))
([5370e77](5370e77))
* **deps:** update rust crate crossterm to 0.29
([#156](#156))
([c59ae3e](c59ae3e))
* **deps:** update rust crate similar to v3
([#160](#160))
([684be4e](684be4e))
* **deps:** update rust crate toml to v1
([#161](#161))
([3aae614](3aae614))
* **deps:** update rust crate toml_edit to 0.25
([#158](#158))
([42d9efd](42d9efd))
* exclude GitHub compare links from lychee checks
([#10](#10))
([e714608](e714608))
* fail native lint when enabled tools are missing
([#111](#111))
([163bb6b](163bb6b))
* improve link checker reliability against GitHub rate limiting
([#95](#95))
([7a5282d](7a5282d))
* include staged files in native lint file list
([#135](#135))
([34412d6](34412d6))
* **links:** add regex anchors to remap patterns
([#19](#19))
([2e17348](2e17348))
* native lint in worktrees, trust toml, use ec binary, drop isort
([#134](#134))
([8594bba](8594bba))
* **release-please:** fix footer not appearing on release PRs
([#40](#40))
([d7a55e4](d7a55e4))
* remap same-repo GitHub URLs to local file paths
([#100](#100))
([b4feadd](b4feadd))
* **renovate-deps:** forward GITHUB_TOKEN as GITHUB_COM_TOKEN
([#132](#132))
([4d6510b](4d6510b))
* replace broken release-please PR comment with docs
([#12](#12))
([817b37d](817b37d))
* run shellcheck on .bats files in native mode
([#137](#137))
([a4fd3f8](a4fd3f8))
* strip Scroll to Text Fragment anchors in link checks
([#86](#86))
([b630cdf](b630cdf))
* tighten markdownlint config for native mode
([#106](#106))
([6ef25b2](6ef25b2))
* use remap instead of exclude for issue comment anchors
([#58](#58))
([656f355](656f355))

---
> [!IMPORTANT]
> Close and reopen this PR to trigger CI checks.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This was referenced Apr 16, 2026
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.

2 participants