Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/golangci-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,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
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,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
Expand Down
19 changes: 19 additions & 0 deletions docs/assets/crd/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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/gateway-api@v1.6.0/apis/v1#Group
- name: Kind
package: sigs.k8s.io/gateway-api/apis/v1
link: https://pkg.go.dev/sigs.k8s.io/gateway-api@v1.6.0/apis/v1#Kind
- name: ObjectName
package: sigs.k8s.io/gateway-api/apis/v1
link: https://pkg.go.dev/sigs.k8s.io/gateway-api@v1.6.0/apis/v1#ObjectName
- name: SectionName
package: sigs.k8s.io/gateway-api/apis/v1
link: https://pkg.go.dev/sigs.k8s.io/gateway-api@v1.6.0/apis/v1#SectionName
- name: Duration
package: time
link: https://pkg.go.dev/time#Duration
10 changes: 8 additions & 2 deletions docs/assets/template/type.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}
Expand Down
13 changes: 6 additions & 7 deletions docs/en/latest/reference/api-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 implementation should record a `ResolvedRefs` or similar Condition in the Policy's status. |
| `group` _[Group](https://pkg.go.dev/sigs.k8s.io/gateway-api@v1.6.0/apis/v1#Group)_ | Group is the group of the target resource. |
| `kind` _[Kind](https://pkg.go.dev/sigs.k8s.io/gateway-api@v1.6.0/apis/v1#Kind)_ | Kind is kind of the target resource. |
| `name` _[ObjectName](https://pkg.go.dev/sigs.k8s.io/gateway-api@v1.6.0/apis/v1#ObjectName)_ | Name is the name of the target resource. |
| `sectionName` _[SectionName](https://pkg.go.dev/sigs.k8s.io/gateway-api@v1.6.0/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, the Policy must fail to attach, and the policy implementation should record a `ResolvedRefs` or similar Condition in the Policy's status. |


_Appears in:_
Expand Down Expand Up @@ -664,8 +664,7 @@ _Appears in:_
| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#condition-v1-meta) array_ | |


_Appears in:_
- [ConsumerStatus](#consumerstatus)


#### Timeout

Expand Down Expand Up @@ -804,7 +803,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. |
Expand Down
74 changes: 74 additions & 0 deletions scripts/check-crd-doc-links.py
Original file line number Diff line number Diff line change
@@ -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())
Loading