Skip to content

Commit e6ed6cb

Browse files
authored
Merge pull request #5611 from spiffxp/link-to-owners-in-readme
generator: make subproject owners links useful
2 parents e331270 + 1ffc41d commit e6ed6cb

File tree

31 files changed

+549
-404
lines changed

31 files changed

+549
-404
lines changed

committee-product-security/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ The following [subprojects][subproject-definition] are owned by the Product Secu
3232
### security
3333
Policies and documentation for the Product Security Committee
3434
- **Owners:**
35-
- https://raw.githubusercontent.com/kubernetes/security/master/OWNERS
35+
- [kubernetes/security](https://github.com/kubernetes/security/blob/master/OWNERS)
3636

3737
[subproject-definition]: https://github.com/kubernetes/community/blob/master/governance.md#subprojects
3838
<!-- BEGIN CUSTOM CONTENT -->

committee-steering/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,11 @@ The following [subprojects][subproject-definition] are owned by the Steering Com
4242
### funding
4343
Funding requests for project infrastructure, events, and consulting
4444
- **Owners:**
45-
- https://raw.githubusercontent.com/kubernetes/funding/master/OWNERS
45+
- [kubernetes/funding](https://github.com/kubernetes/funding/blob/master/OWNERS)
4646
### steering
4747
Steering Committee policy and documentation
4848
- **Owners:**
49-
- https://raw.githubusercontent.com/kubernetes/steering/master/OWNERS
49+
- [kubernetes/steering](https://github.com/kubernetes/steering/blob/master/OWNERS)
5050

5151
[subproject-definition]: https://github.com/kubernetes/community/blob/master/governance.md#subprojects
5252
<!-- BEGIN CUSTOM CONTENT -->

generator/app.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"net/url"
2424
"os"
2525
"path/filepath"
26+
"regexp"
2627
"sort"
2728
"strings"
2829
"text/template"
@@ -47,6 +48,9 @@ const (
4748
endCustomMarkdown = "<!-- END CUSTOM CONTENT -->"
4849
beginCustomYaml = "## BEGIN CUSTOM CONTENT"
4950
endCustomYaml = "## END CUSTOM CONTENT"
51+
52+
regexRawGitHubURL = "https://raw.githubusercontent.com/(?P<org>[^/]+)/(?P<repo>[^/]+)/(?P<branch>[^/]+)/(?P<path>.*)"
53+
regexGitHubURL = "https://github.com/(?P<org>[^/]+)/(?P<repo>[^/]+)/(blob|tree)/(?P<branch>[^/]+)/(?P<path>.*)"
5054
)
5155

5256
var (
@@ -246,6 +250,8 @@ func (c *Context) Sort() {
246250
func (c *Context) Validate() []error {
247251
errors := []error{}
248252
people := make(map[string]Person)
253+
reRawGitHubURL := regexp.MustCompile(regexRawGitHubURL)
254+
reGitHubURL := regexp.MustCompile(regexGitHubURL)
249255
for prefix, groups := range c.PrefixToGroupMap() {
250256
for _, group := range groups {
251257
expectedDir := group.DirName(prefix)
@@ -294,6 +300,21 @@ func (c *Context) Validate() []error {
294300
errors = append(errors, fmt.Errorf("%s: has no subprojects", group.Dir))
295301
}
296302
}
303+
if prefix != "committee" && prefix != "sig" {
304+
if len(group.Subprojects) > 0 {
305+
errors = append(errors, fmt.Errorf("%s: only sigs and committees can own code / have subprojects, found: %v", group.Dir, group.Subprojects))
306+
}
307+
}
308+
for _, subproject := range group.Subprojects {
309+
if len(subproject.Owners) == 0 {
310+
errors = append(errors, fmt.Errorf("%s/%s: subproject has no owners", group.Dir, subproject.Name))
311+
}
312+
for _, ownerURL := range subproject.Owners {
313+
if !reRawGitHubURL.MatchString(ownerURL) && !reGitHubURL.MatchString(ownerURL) {
314+
errors = append(errors, fmt.Errorf("%s/%s: subproject owners should match regexp %s, found: %s", group.Dir, subproject.Name, regexRawGitHubURL, ownerURL))
315+
}
316+
}
317+
}
297318
}
298319
}
299320
return errors
@@ -353,6 +374,38 @@ func getExistingContent(path string, fileFormat string) (string, error) {
353374
var funcMap = template.FuncMap{
354375
"tzUrlEncode": tzURLEncode,
355376
"trimSpace": strings.TrimSpace,
377+
"trimSuffix": strings.TrimSuffix,
378+
"githubURL": githubURL,
379+
"orgRepoPath": orgRepoPath,
380+
}
381+
382+
// githubURL converts a raw GitHub url (links directly to file contents) into a
383+
// regular GitHub url (links to Code view for file), otherwise returns url untouched
384+
func githubURL(url string) string {
385+
re := regexp.MustCompile(regexRawGitHubURL)
386+
mat := re.FindStringSubmatchIndex(url)
387+
if mat == nil {
388+
return url
389+
}
390+
result := re.ExpandString([]byte{}, "https://github.com/${org}/${repo}/blob/${branch}/${path}", url, mat)
391+
return string(result)
392+
}
393+
394+
// orgRepoPath converts either
395+
// - a regular GitHub url of form https://github.com/org/repo/blob/branch/path/to/file
396+
// - a raw GitHub url of form https://raw.githubusercontent.com/org/repo/branch/path/to/file
397+
// to a string of form 'org/repo/path/to/file'
398+
func orgRepoPath(url string) string {
399+
for _, regex := range []string{regexRawGitHubURL, regexGitHubURL} {
400+
re := regexp.MustCompile(regex)
401+
mat := re.FindStringSubmatchIndex(url)
402+
if mat == nil {
403+
continue
404+
}
405+
result := re.ExpandString([]byte{}, "${org}/${repo}/${path}", url, mat)
406+
return string(result)
407+
}
408+
return url
356409
}
357410

358411
// tzUrlEncode returns a url encoded string without the + shortcut. This is
@@ -509,6 +562,7 @@ func main() {
509562
log.Fatal(err)
510563
}
511564

565+
fmt.Println("Generating group READMEs")
512566
for prefix, groups := range ctx.PrefixToGroupMap() {
513567
err = createGroupReadme(groups, prefix)
514568
if err != nil {

generator/app_test.go

Lines changed: 78 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -155,19 +155,22 @@ func TestGroupDirName(t *testing.T) {
155155
func TestCreateGroupReadmes(t *testing.T) {
156156
baseGeneratorDir = "generated"
157157
templateDir = "../../generator"
158+
const groupType = "sig"
158159

159-
groups := []Group{
160-
{Name: "Foo"},
161-
{Name: "Bar"},
160+
groups := []Group{}
161+
for _, n := range []string{"Foo", "Bar"} {
162+
g := Group{Name: n}
163+
g.Dir = g.DirName(groupType)
164+
groups = append(groups, g)
162165
}
163166

164-
err := createGroupReadme(groups, "sig")
167+
err := createGroupReadme(groups, groupType)
165168
if err != nil {
166169
t.Fatal(err)
167170
}
168171

169172
for _, group := range groups {
170-
path := filepath.Join(baseGeneratorDir, group.DirName("sig"), "README.md")
173+
path := filepath.Join(baseGeneratorDir, group.DirName(groupType), "README.md")
171174
if !pathExists(path) {
172175
t.Fatalf("%s should exist", path)
173176
}
@@ -233,3 +236,73 @@ func TestFullGeneration(t *testing.T) {
233236
}
234237
}
235238
}
239+
240+
func TestGitHubURL(t *testing.T) {
241+
cases := []struct {
242+
name string
243+
url string
244+
expected string
245+
}{
246+
{
247+
name: "kubernetes-sigs root raw github url",
248+
url: "https://raw.githubusercontent.com/kubernetes-sigs/boskos/main/OWNERS",
249+
expected: "https://github.com/kubernetes-sigs/boskos/blob/main/OWNERS",
250+
},
251+
{
252+
name: "kubernetes non-root raw github url",
253+
url: "https://raw.githubusercontent.com/kubernetes/kubernetes/main/test/OWNERS",
254+
expected: "https://github.com/kubernetes/kubernetes/blob/main/test/OWNERS",
255+
},
256+
{
257+
name: "kubernetes github url should be unchanged",
258+
url: "https://github.com/kubernetes/kubernetes/blob/main/test/OWNERS",
259+
expected: "https://github.com/kubernetes/kubernetes/blob/main/test/OWNERS",
260+
},
261+
{
262+
name: "non-github url should be unchanged",
263+
url: "https://viewsource.com/github/kubernetes/community/generator/app.go",
264+
expected: "https://viewsource.com/github/kubernetes/community/generator/app.go",
265+
},
266+
}
267+
for _, c := range cases {
268+
actual := githubURL(c.url)
269+
if actual != c.expected {
270+
t.Errorf("FAIL %s: got: '%s' but expected: '%s'", c.name, actual, c.expected)
271+
}
272+
}
273+
}
274+
275+
func TestOrgRepoPath(t *testing.T) {
276+
cases := []struct {
277+
name string
278+
url string
279+
expected string
280+
}{
281+
{
282+
name: "kubernetes-sigs root raw github url",
283+
url: "https://raw.githubusercontent.com/kubernetes-sigs/boskos/main/OWNERS",
284+
expected: "kubernetes-sigs/boskos/OWNERS",
285+
},
286+
{
287+
name: "kubernetes non-root raw github url",
288+
url: "https://raw.githubusercontent.com/kubernetes/kubernetes/main/test/OWNERS",
289+
expected: "kubernetes/kubernetes/test/OWNERS",
290+
},
291+
{
292+
name: "kubernetes github url",
293+
url: "https://github.com/kubernetes/kubernetes/blob/main/test/OWNERS",
294+
expected: "kubernetes/kubernetes/test/OWNERS",
295+
},
296+
{
297+
name: "non-github url should be unchanged",
298+
url: "https://viewsource.com/github/kubernetes/community/generator/app.go",
299+
expected: "https://viewsource.com/github/kubernetes/community/generator/app.go",
300+
},
301+
}
302+
for _, c := range cases {
303+
actual := orgRepoPath(c.url)
304+
if actual != c.expected {
305+
t.Errorf("FAIL %s: got: '%s' but expected: '%s'", c.name, actual, c.expected)
306+
}
307+
}
308+
}

generator/committee_readme.tmpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ The following [subprojects][subproject-definition] are owned by the {{.Name}} Co
6666
{{- end }}
6767
- **Owners:**
6868
{{- range .Owners }}
69-
- {{.}}
69+
- [{{trimSuffix (orgRepoPath .) "/OWNERS"}}]({{githubURL .}})
7070
{{- end }}
7171
{{- if .Contact }}
7272
- **Contact:**

generator/sig_readme.tmpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ The following [subprojects][subproject-definition] are owned by sig-{{.Label}}:
7676
{{- end }}
7777
- **Owners:**
7878
{{- range .Owners }}
79-
- {{.}}
79+
- [{{trimSuffix (orgRepoPath .) "/OWNERS"}}]({{githubURL .}})
8080
{{- end }}
8181
{{- if .Contact }}
8282
- **Contact:**

generator/testdata/sigs.yaml

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,23 @@
11
sigs:
2-
- name: Foo
3-
- name: Bar
2+
- dir: sig-foo
3+
name: Foo
4+
label: foo
5+
charter_link: foo-charter
6+
mission_statement: covers foo
7+
subprojects:
8+
- name: sub-foo
9+
owners:
10+
- "https://raw.githubusercontent.com/org/foo/main/OWNERS"
11+
- dir: sig-bar
12+
name: Bar
13+
label: bar
14+
charter_link: charter-bar
15+
mission_statement: owns areas related to bar
16+
subprojects:
17+
- name: sub-bar
18+
owners:
19+
- "https://raw.githubusercontent.com/org/bar/main/test/OWNERS"
420
workinggroups:
5-
- name: Baz
21+
- dir: wg-baz
22+
name: Baz
23+
label: baz

0 commit comments

Comments
 (0)