This is an automated email from the ASF dual-hosted git repository.

AlinsRan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-ingress-controller.git


The following commit(s) were added to refs/heads/master by this push:
     new 4d1df161 docs: fix generated CRD reference self-links (#2904)
4d1df161 is described below

commit 4d1df161dd8c92888284fd0267b421dad74c75f3
Author: Traky Deng <[email protected]>
AuthorDate: Wed Nov 4 09:47:12 2026 +0800

    docs: fix generated CRD reference self-links (#2904)
---
 .github/workflows/golangci-lint.yml       |  2 +
 Makefile                                  |  4 ++
 docs/assets/crd/config.yaml               | 19 ++++++++
 docs/assets/template/type.tpl             | 10 ++++-
 docs/en/latest/reference/api-reference.md | 13 +++---
 scripts/check-crd-doc-links.py            | 74 +++++++++++++++++++++++++++++++
 6 files changed, 113 insertions(+), 9 deletions(-)

diff --git a/.github/workflows/golangci-lint.yml 
b/.github/workflows/golangci-lint.yml
index 6ba322be..0b804332 100644
--- a/.github/workflows/golangci-lint.yml
+++ b/.github/workflows/golangci-lint.yml
@@ -62,3 +62,5 @@ jobs:
             echo "docs/en/latest/reference/api-reference.md has changed. 
Please run 'make generate-crd-docs' and commit the updated file."
             exit 1
           fi
+      - name: Check CRD Docs Links
+        run: make check-crd-doc-links
diff --git a/Makefile b/Makefile
index 8154940e..589b1931 100644
--- a/Makefile
+++ b/Makefile
@@ -509,6 +509,10 @@ generate-crd-docs: manifests ## Generate CRD reference 
documentation in a single
                --max-depth=100
        @echo "CRD reference documentation generated at $(CRD_DOCS_OUTPUT)"
 
+.PHONY: check-crd-doc-links
+check-crd-doc-links: ## Check links to headings in the generated CRD reference
+       @python3 scripts/check-crd-doc-links.py $(CRD_DOCS_OUTPUT)
+
 .PHONY: generate-crd-docs-grouped
 generate-crd-docs-grouped: manifests ## Generate CRD reference documentation 
grouped by API group
        @mkdir -p docs/crd/groups
diff --git a/docs/assets/crd/config.yaml b/docs/assets/crd/config.yaml
index c224cc42..88e5ec16 100644
--- a/docs/assets/crd/config.yaml
+++ b/docs/assets/crd/config.yaml
@@ -28,3 +28,22 @@ render:
   # Version of Kubernetes to use when generating links to Kubernetes API 
documentation.
   # NOTE: Quotes are required, otherwise the value will be intepreted as a 
number so versions ending with `0` like 1.30 would be covreted to "1.3" in 
results.
   kubernetesVersion: "1.30"
+  # Link types defined outside the generated API packages to their 
authoritative references.
+  # Without these mappings, crd-ref-docs treats them as local types and emits 
fragments for
+  # headings that are not part of this document.
+  knownTypes:
+    - name: Group
+      package: sigs.k8s.io/gateway-api/apis/v1
+      link: https://pkg.go.dev/sigs.k8s.io/[email protected]/apis/v1#Group
+    - name: Kind
+      package: sigs.k8s.io/gateway-api/apis/v1
+      link: https://pkg.go.dev/sigs.k8s.io/[email protected]/apis/v1#Kind
+    - name: ObjectName
+      package: sigs.k8s.io/gateway-api/apis/v1
+      link: 
https://pkg.go.dev/sigs.k8s.io/[email protected]/apis/v1#ObjectName
+    - name: SectionName
+      package: sigs.k8s.io/gateway-api/apis/v1
+      link: 
https://pkg.go.dev/sigs.k8s.io/[email protected]/apis/v1#SectionName
+    - name: Duration
+      package: time
+      link: https://pkg.go.dev/time#Duration
diff --git a/docs/assets/template/type.tpl b/docs/assets/template/type.tpl
index 57f6a433..0c499c8f 100644
--- a/docs/assets/template/type.tpl
+++ b/docs/assets/template/type.tpl
@@ -50,9 +50,15 @@
 
 {{ end }}
 
-{{ if $type.References -}}
+{{ $renderedReferences := list -}}
+{{ range $type.SortedReferences -}}
+{{ if markdownShouldRenderType . -}}
+{{ $renderedReferences = append $renderedReferences . -}}
+{{ end -}}
+{{ end -}}
+{{ if $renderedReferences -}}
 _Appears in:_
-{{- range $type.SortedReferences }}
+{{- range $renderedReferences }}
 - {{ markdownRenderTypeLink . }}
 {{- end }}
 {{- end }}
diff --git a/docs/en/latest/reference/api-reference.md 
b/docs/en/latest/reference/api-reference.md
index a120c1c6..ae6b8bf0 100644
--- a/docs/en/latest/reference/api-reference.md
+++ b/docs/en/latest/reference/api-reference.md
@@ -234,10 +234,10 @@ _Base type:_ `LocalPolicyTargetReferenceWithSectionName`
 
 | Field | Description |
 | --- | --- |
-| `group` _[Group](#group)_ | Group is the group of the target resource. |
-| `kind` _[Kind](#kind)_ | Kind is kind of the target resource. |
-| `name` _[ObjectName](#objectname)_ | Name is the name of the target 
resource. |
-| `sectionName` _[SectionName](#sectionname)_ | SectionName is the name of a 
section within the target resource. When unspecified, this targetRef targets 
the entire resource. In the following resources, SectionName is interpreted as 
the following:<br /><br /> • Gateway: Listener name<br /> • HTTPRoute: 
HTTPRouteRule name<br /> • Service: Port name<br /><br /> If a SectionName is 
specified, but does not exist on the targeted object, the Policy must fail to 
attach, and the policy implement [...]
+| `group` 
_[Group](https://pkg.go.dev/sigs.k8s.io/[email protected]/apis/v1#Group)_ | 
Group is the group of the target resource. |
+| `kind` 
_[Kind](https://pkg.go.dev/sigs.k8s.io/[email protected]/apis/v1#Kind)_ | Kind 
is kind of the target resource. |
+| `name` 
_[ObjectName](https://pkg.go.dev/sigs.k8s.io/[email protected]/apis/v1#ObjectName)_
 | Name is the name of the target resource. |
+| `sectionName` 
_[SectionName](https://pkg.go.dev/sigs.k8s.io/[email protected]/apis/v1#SectionName)_
 | SectionName is the name of a section within the target resource. When 
unspecified, this targetRef targets the entire resource. In the following 
resources, SectionName is interpreted as the following:<br /><br /> • Gateway: 
Listener name<br /> • HTTPRoute: HTTPRouteRule name<br /> • Service: Port 
name<br /><br /> If a SectionName is specified, but does not exist on the 
targeted object, [...]
 
 
 _Appears in:_
@@ -666,8 +666,7 @@ _Appears in:_
 | `conditions` 
_[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#condition-v1-meta)
 array_ |  |
 
 
-_Appears in:_
-- [ConsumerStatus](#consumerstatus)
+
 
 #### Timeout
 
@@ -806,7 +805,7 @@ ActiveHealthCheck defines the active upstream health check 
configuration.
 | Field | Description |
 | --- | --- |
 | `type` _string_ | Type is the health check type. Can be `http`, `https`, or 
`tcp`. |
-| `timeout` _[Duration](#duration)_ | Timeout sets health check timeout in 
seconds. |
+| `timeout` _[Duration](https://pkg.go.dev/time#Duration)_ | Timeout sets 
health check timeout in seconds. |
 | `concurrency` _integer_ | Concurrency sets the number of targets to be 
checked at the same time. |
 | `host` _string_ | Host sets the upstream host. |
 | `port` _integer_ | Port sets the upstream port. |
diff --git a/scripts/check-crd-doc-links.py b/scripts/check-crd-doc-links.py
new file mode 100644
index 00000000..1e508dd4
--- /dev/null
+++ b/scripts/check-crd-doc-links.py
@@ -0,0 +1,74 @@
+#!/usr/bin/env python3
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""Verify that generated CRD reference self-links have matching headings."""
+
+from __future__ import annotations
+
+import re
+import sys
+from collections import defaultdict
+from pathlib import Path
+from urllib.parse import unquote
+
+
+HEADING_PATTERN = re.compile(r"^#{1,6}\s+(.+?)\s*#*\s*$")
+SELF_LINK_PATTERN = re.compile(r"\]\(#([^)]+)\)")
+
+
+def heading_slug(heading: str) -> str:
+    """Match Docusaurus' generated IDs for the plain headings in this file."""
+    return re.sub(r"[^\w -]", "", heading.lower()).replace(" ", "-")
+
+
+def main() -> int:
+    path = Path(sys.argv[1] if len(sys.argv) > 1 else 
"docs/en/latest/reference/api-reference.md")
+    lines = path.read_text(encoding="utf-8").splitlines()
+
+    anchors: set[str] = set()
+    occurrences: defaultdict[str, int] = defaultdict(int)
+    for line in lines:
+        match = HEADING_PATTERN.match(line)
+        if not match:
+            continue
+        base = heading_slug(match.group(1))
+        count = occurrences[base]
+        occurrences[base] += 1
+        anchors.add(base if count == 0 else f"{base}-{count}")
+
+    missing: list[tuple[int, str]] = []
+    checked = 0
+    for line_number, line in enumerate(lines, start=1):
+        for match in SELF_LINK_PATTERN.finditer(line):
+            checked += 1
+            fragment = unquote(match.group(1))
+            if fragment not in anchors:
+                missing.append((line_number, fragment))
+
+    if missing:
+        print(f"Broken generated CRD self-links in {path}:", file=sys.stderr)
+        for line_number, fragment in missing:
+            print(f"  line {line_number}: #{fragment}", file=sys.stderr)
+        return 1
+
+    print(f"Generated CRD self-links: {checked} checked, all targets exist.")
+    return 0
+
+
+if __name__ == "__main__":
+    raise SystemExit(main())

Reply via email to