Skip to content

Commit 70897aa

Browse files
rikatzshaneutt
authored andcommitted
Automate GEP TOC generation and validate (#4075)
* Fix GEP API and geps metadata The GEP API is using a wrong structure/tag name for some fields, so this PR fixes the markers. Additionally the metadata.yaml files from some GEPs are fixed to reflect the right GEP API structure * Implement automatic NAV generation This change makes the navigation section of GW API website to be generated. The modification adds a new Go program that is able to transverse the GEP directory and generate a navigation section correctly from the existing GEPs. Additionally, some scripts and Makefiles are added to verify if the generated nav.yml file reflects the current state of GEPs, a Github Action that fails in case nav.yml is outdated * Add the new generated nav file
1 parent 6af8dc8 commit 70897aa

File tree

22 files changed

+548
-189
lines changed

22 files changed

+548
-189
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
name: Website Table of Content Validation
2+
3+
on:
4+
pull_request:
5+
types: [opened, edited, synchronize, reopened]
6+
7+
# Remove all permissions from GITHUB_TOKEN except metadata.
8+
permissions: {}
9+
10+
jobs:
11+
gep-validation:
12+
name: Verify if nav is updated
13+
runs-on: ubuntu-latest
14+
strategy:
15+
fail-fast: false
16+
steps:
17+
- name: Checkout code
18+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2
19+
with:
20+
persist-credentials: false
21+
- name: Set up Go
22+
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # tag=v5.5.0
23+
- name: Run MKDocs nav Validation
24+
run: |
25+
make verify-mkdocs-nav

.yamllint.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ ignore: |
44
.github/
55
.golangci.yml
66
mkdocs.yml
7+
nav.yml
78
cloudbuild.yaml
89
config/crd
910

Makefile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,14 @@ live-docs:
182182
docker build -t gw/mkdocs hack/mkdocs/image
183183
docker run --rm -it -p 3000:3000 -v ${PWD}:/docs gw/mkdocs
184184

185+
.PHONY: verify-mkdocs-nav
186+
verify-mkdocs-nav:
187+
hack/verify-mkdocs-nav.sh
188+
189+
.PHONY: update-mkdocs-nav
190+
update-mkdocs-nav:
191+
hack/update-mkdocs-nav.sh
192+
185193
.PHONY: api-ref-docs
186194
api-ref-docs:
187195
crd-ref-docs \

cmd/gepstoc/main.go

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
/*
2+
Copyright 2025 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package main
18+
19+
import (
20+
"bytes"
21+
"flag"
22+
"fmt"
23+
"html/template"
24+
"io/fs"
25+
"log"
26+
"os"
27+
"path/filepath"
28+
"slices"
29+
"sort"
30+
"strconv"
31+
"strings"
32+
33+
"sigs.k8s.io/yaml"
34+
35+
gep "sigs.k8s.io/gateway-api/pkg/gep"
36+
)
37+
38+
var (
39+
GEPSDir string
40+
MKDocsTemplate string
41+
SkipGEPNumber string
42+
)
43+
44+
// Those are the GEPs that will be included in the final navigation bar
45+
// The order established below will be the order that the statuses will be shown
46+
var includeGEPStatus = []gep.GEPStatus{
47+
gep.GEPStatusImplementable,
48+
gep.GEPStatusExperimental,
49+
gep.GEPStatusStandard,
50+
gep.GEPStatusMemorandum,
51+
}
52+
53+
type GEPArray []GEPList
54+
55+
type GEPList struct {
56+
GepType string
57+
Geps []uint
58+
}
59+
60+
type TemplateData struct {
61+
GEPData GEPArray
62+
}
63+
64+
const kindDetails = "GEPDetails"
65+
66+
func main() {
67+
flag.StringVar(&GEPSDir, "g", "", "Defines the absolute path of the directory containing the GEPs")
68+
flag.StringVar(&MKDocsTemplate, "t", "", "Defines the absolute path of mkdocs.yaml file")
69+
flag.StringVar(&SkipGEPNumber, "s", "696", "Defines GEPs number to be skipped, should be comma-separated")
70+
flag.Parse()
71+
72+
if GEPSDir == "" || MKDocsTemplate == "" {
73+
log.Fatal("-g and -c are mandatory arguments")
74+
}
75+
76+
if strings.Contains(SkipGEPNumber, " ") {
77+
log.Fatal("-s flag should not contain spaces")
78+
}
79+
80+
skipGep := strings.Split(SkipGEPNumber, ",")
81+
82+
geps, err := walkGEPs(GEPSDir, skipGep)
83+
if err != nil {
84+
panic(err)
85+
}
86+
87+
tmpl, err := template.ParseFiles(MKDocsTemplate)
88+
if err != nil {
89+
log.Fatalf("error reading mkdocs template: %s", err)
90+
}
91+
92+
tmplData := TemplateData{
93+
GEPData: geps,
94+
}
95+
96+
buf := &bytes.Buffer{}
97+
98+
if err := tmpl.Execute(buf, tmplData); err != nil {
99+
panic(err)
100+
}
101+
fmt.Print(buf.String())
102+
}
103+
104+
func walkGEPs(dir string, skipGEPs []string) (GEPArray, error) {
105+
gepArray := make(GEPArray, 0)
106+
tmpMap := make(map[gep.GEPStatus]GEPList)
107+
108+
err := filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
109+
if err != nil {
110+
return fmt.Errorf("error accessing %s: %w", path, err)
111+
}
112+
if d.IsDir() || d.Name() != "metadata.yaml" {
113+
return nil
114+
}
115+
116+
content, err := os.ReadFile(path)
117+
if err != nil {
118+
return err
119+
}
120+
121+
gepDetail := &gep.GEPDetail{}
122+
log.Printf("checking %s", path)
123+
if err := yaml.Unmarshal(content, gepDetail); err != nil {
124+
return err
125+
}
126+
127+
if gepDetail.Kind != kindDetails {
128+
return nil
129+
}
130+
131+
// Skip the GEPs types we don't care
132+
if !slices.Contains(includeGEPStatus, gepDetail.Status) {
133+
return nil
134+
}
135+
136+
// Skip the GEPs numbers we don't care
137+
if slices.Contains(skipGEPs, strconv.FormatUint(uint64(gepDetail.Number), 10)) {
138+
return nil
139+
}
140+
141+
// Add the GEP to a map indexed by GEP types, so we can provide the sorted array
142+
// easily later
143+
_, ok := tmpMap[gepDetail.Status]
144+
if !ok {
145+
tmpMap[gepDetail.Status] = GEPList{
146+
GepType: string(gepDetail.Status),
147+
Geps: make([]uint, 0),
148+
}
149+
}
150+
151+
item := tmpMap[gepDetail.Status]
152+
item.Geps = append(item.Geps, gepDetail.Number)
153+
tmpMap[gepDetail.Status] = item
154+
return nil
155+
})
156+
if err != nil {
157+
return nil, err
158+
}
159+
160+
// Include the GEPs toc on the desired order
161+
for _, v := range includeGEPStatus {
162+
if geps, ok := tmpMap[v]; ok {
163+
gepArray = append(gepArray, geps)
164+
}
165+
}
166+
167+
for i := range gepArray {
168+
sort.SliceStable(gepArray[i].Geps, func(x, y int) bool {
169+
return gepArray[i].Geps[x] < gepArray[i].Geps[y]
170+
})
171+
}
172+
173+
return gepArray, nil
174+
}

geps/gep-1494/metadata.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ authors:
1010
- jgao1025
1111
# references is a list of hyperlinks to relevant external references.
1212
# It's intended to be used for storing GitHub discussions, Google docs, etc.
13-
references: {}
13+
references: []
1414
# featureNames is a list of the feature names introduced by the GEP, if there
1515
# are any. This will allow us to track which feature was introduced by which GEP.
1616
featureNames:

geps/gep-1731/metadata.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@ relationships:
1111
# obsoletes indicates that a GEP makes the linked GEP obsolete, and completely
1212
# replaces that GEP. The obsoleted GEP MUST have its obsoletedBy field
1313
# set back to this GEP, and MUST be moved to Declined.
14-
obsoletes: {}
15-
obsoletedBy: {}
14+
obsoletes: []
15+
obsoletedBy: []
1616
# extends indicates that a GEP extends the linked GEP, adding more detail
1717
# or additional implementation. The extended GEP MUST have its extendedBy
1818
# field set back to this GEP.
19-
extends: {}
19+
extends: []
2020
extendedBy:
2121
- number: 3388
2222
name: Retry Budgets
@@ -44,4 +44,4 @@ featureNames:
4444
- SupportHTTPRouteRetryConnectionError
4545
# changelog is a list of hyperlinks to PRs that make changes to the GEP, in
4646
# ascending date order.
47-
changelog: {}
47+
changelog: []

geps/gep-3388/metadata.yaml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,18 @@ relationships:
1212
# obsoletes indicates that a GEP makes the linked GEP obsolete, and completely
1313
# replaces that GEP. The obsoleted GEP MUST have its obsoletedBy field
1414
# set back to this GEP, and MUST be moved to Declined.
15-
obsoletes: {}
16-
obsoletedBy: {}
15+
obsoletes: []
16+
obsoletedBy: []
1717
# extends indicates that a GEP extends the linked GEP, adding more detail
1818
# or additional implementation. The extended GEP MUST have its extendedBy
1919
# field set back to this GEP.
2020
extends:
2121
- number: 1731
2222
name: HTTPRoute Retries
23-
extendedBy: {}
23+
extendedBy: []
2424
# seeAlso indicates other GEPs that are relevant in some way without being
2525
# covered by an existing relationship.
26-
seeAlso: {}
26+
seeAlso: []
2727
# references is a list of hyperlinks to relevant external references.
2828
# It's intended to be used for storing GitHub discussions, Google docs, etc.
2929
references:
@@ -34,7 +34,7 @@ references:
3434
- https://github.com/kubernetes-sigs/gateway-api/pull/3695
3535
# featureNames is a list of the feature names introduced by the GEP, if there
3636
# are any. This will allow us to track which feature was introduced by which GEP.
37-
featureNames: {}
37+
featureNames: []
3838
# changelog is a list of hyperlinks to PRs that make changes to the GEP, in
3939
# ascending date order.
40-
changelog: {}
40+
changelog: []

geps/gep-3567/metadata.yaml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,23 @@ relationships:
1111
# obsoletes indicates that a GEP makes the linked GEP obsolete, and completely
1212
# replaces that GEP. The obsoleted GEP MUST have its obsoletedBy field
1313
# set back to this GEP, and MUST be moved to Declined.
14-
obsoletes: {}
15-
obsoletedBy: {}
14+
obsoletes: []
15+
obsoletedBy: []
1616
# extends indicates that a GEP extends the linked GEP, adding more detail
1717
# or additional implementation. The extended GEP MUST have its extendedBy
1818
# field set back to this GEP.
19-
extends: {}
20-
extendedBy: {}
19+
extends: []
20+
extendedBy: []
2121
# seeAlso indicates other GEPs that are relevant in some way without being
2222
# covered by an existing relationship.
23-
seeAlso: {}
23+
seeAlso: []
2424
# references is a list of hyperlinks to relevant external references.
2525
# It's intended to be used for storing GitHub discussions, Google docs, etc.
26-
references: {}
26+
references: []
2727
# featureNames is a list of the feature names introduced by the GEP, if there
2828
# are any. This will allow us to track which feature was introduced by which GEP.
2929
featureNames:
3030
- GatewayReturn421
3131
# changelog is a list of hyperlinks to PRs that make changes to the GEP, in
3232
# ascending date order.
33-
changelog: {}
33+
changelog: []

geps/gep-3779/metadata.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ authors:
1010
- aryan16
1111
# references is a list of hyperlinks to relevant external references.
1212
# It's intended to be used for storing GitHub discussions, Google docs, etc.
13-
references: {}
13+
references: []
1414
# featureNames is a list of the feature names introduced by the GEP, if there
1515
# are any. This will allow us to track which feature was introduced by which GEP.
16-
featureNames: {}
16+
featureNames: []
1717
# changelog is a list of hyperlinks to PRs that make changes to the GEP, in
1818
# ascending date order.
19-
changelog: {}
19+
changelog: []

geps/gep-3792/metadata.yaml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,23 @@ relationships:
1111
# obsoletes indicates that a GEP makes the linked GEP obsolete, and completely
1212
# replaces that GEP. The obsoleted GEP MUST have its obsoletedBy field
1313
# set back to this GEP, and MUST be moved to Declined.
14-
obsoletes: {}
15-
obsoletedBy: {}
14+
obsoletes: []
15+
obsoletedBy: []
1616
# extends indicates that a GEP extends the linked GEP, adding more detail
1717
# or additional implementation. The extended GEP MUST have its extendedBy
1818
# field set back to this GEP.
19-
extends: {}
20-
extendedBy: {}
19+
extends: []
20+
extendedBy: []
2121
# seeAlso indicates other GEPs that are relevant in some way without being
2222
# covered by an existing relationship.
23-
seeAlso: {}
23+
seeAlso: []
2424
# references is a list of hyperlinks to relevant external references.
2525
# It's intended to be used for storing GitHub discussions, Google docs, etc.
26-
references: {}
26+
references: []
2727
# featureNames is a list of the feature names introduced by the GEP, if there
2828
# are any. This will allow us to track which feature was introduced by which GEP.
2929
# This is the value added to supportedFeatures and the conformance tests, in string form.
30-
featureNames: {}
30+
featureNames: []
3131
# changelog is a list of hyperlinks to PRs that make changes to the GEP, in
3232
# ascending date order.
33-
changelog: {}
33+
changelog: []

0 commit comments

Comments
 (0)