-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[chore] generate issue templates with githubgen (#28655)
Remove a bash script, use go code instead. --------- Co-authored-by: Andrzej Stencel <[email protected]>
- Loading branch information
1 parent
fbd61ae
commit 4ea95dc
Showing
6 changed files
with
430 additions
and
344 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,195 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
package main | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"os" | ||
"path/filepath" | ||
"sort" | ||
"strings" | ||
|
||
"github.com/google/go-github/v53/github" | ||
) | ||
|
||
const allowlistHeader = `# Code generated by githubgen. DO NOT EDIT. | ||
##################################################### | ||
# | ||
# List of components in OpenTelemetry Collector Contrib | ||
# waiting on owners to be assigned | ||
# | ||
##################################################### | ||
# | ||
# Learn about membership in OpenTelemetry community: | ||
# https://github.com/open-telemetry/community/blob/main/community-membership.md | ||
# | ||
# | ||
# Learn about CODEOWNERS file format: | ||
# https://help.github.com/en/articles/about-code-owners | ||
# | ||
## | ||
# NOTE: New components MUST have a codeowner. Add new components to the CODEOWNERS file instead of here. | ||
## | ||
## COMMON & SHARED components | ||
internal/common | ||
` | ||
|
||
const unmaintainedHeader = ` | ||
## UNMAINTAINED components | ||
## The Github issue template generation code needs this to generate the corresponding labels. | ||
` | ||
|
||
const codeownersHeader = `# Code generated by githubgen. DO NOT EDIT. | ||
##################################################### | ||
# | ||
# List of approvers for OpenTelemetry Collector Contrib | ||
# | ||
##################################################### | ||
# | ||
# Learn about membership in OpenTelemetry community: | ||
# https://github.com/open-telemetry/community/blob/main/community-membership.md | ||
# | ||
# | ||
# Learn about CODEOWNERS file format: | ||
# https://help.github.com/en/articles/about-code-owners | ||
# | ||
# NOTE: Lines should be entered in the following format: | ||
# <component_path_relative_from_project_root>/<min_1_space><owner_1><space><owner_2><space>..<owner_n> | ||
# extension/oauth2clientauthextension/ @open-telemetry/collector-contrib-approvers @pavankrish123 @jpkrohling | ||
# Path separator and minimum of 1 space between component path and owners is | ||
# important for validation steps | ||
# | ||
* @open-telemetry/collector-contrib-approvers | ||
` | ||
|
||
type codeownersGenerator struct { | ||
} | ||
|
||
func (cg codeownersGenerator) generate(data *githubData) error { | ||
allowlistData, err := os.ReadFile(data.allowlistFilePath) | ||
if err != nil { | ||
return err | ||
} | ||
allowlistLines := strings.Split(string(allowlistData), "\n") | ||
|
||
allowlist := make(map[string]struct{}, len(allowlistLines)) | ||
for _, line := range allowlistLines { | ||
allowlist[line] = struct{}{} | ||
} | ||
var missingCodeowners []string | ||
var duplicateCodeowners []string | ||
members, err := getGithubMembers() | ||
if err != nil { | ||
return err | ||
} | ||
for _, codeowner := range data.codeowners { | ||
_, present := members[codeowner] | ||
|
||
if !present { | ||
_, allowed := allowlist[codeowner] | ||
allowed = allowed || strings.HasPrefix(codeowner, "open-telemetry/") | ||
if !allowed { | ||
missingCodeowners = append(missingCodeowners, codeowner) | ||
} | ||
} else if _, ok := allowlist[codeowner]; ok { | ||
duplicateCodeowners = append(duplicateCodeowners, codeowner) | ||
} | ||
} | ||
if len(missingCodeowners) > 0 { | ||
sort.Strings(missingCodeowners) | ||
return fmt.Errorf("codeowners are not members: %s", strings.Join(missingCodeowners, ", ")) | ||
} | ||
if len(duplicateCodeowners) > 0 { | ||
sort.Strings(duplicateCodeowners) | ||
return fmt.Errorf("codeowners members duplicate in allowlist: %s", strings.Join(duplicateCodeowners, ", ")) | ||
} | ||
|
||
codeowners := codeownersHeader | ||
deprecatedList := "## DEPRECATED components\n" | ||
unmaintainedList := "\n## UNMAINTAINED components\n" | ||
|
||
unmaintainedCodeowners := unmaintainedHeader | ||
currentFirstSegment := "" | ||
LOOP: | ||
for _, key := range data.folders { | ||
m := data.components[key] | ||
for stability := range m.Status.Stability { | ||
if stability == unmaintainedStatus { | ||
unmaintainedList += key + "/\n" | ||
unmaintainedCodeowners += fmt.Sprintf("%s/%s @open-telemetry/collector-contrib-approvers \n", key, strings.Repeat(" ", data.maxLength-len(key))) | ||
continue LOOP | ||
} | ||
if stability == "deprecated" && (m.Status.Codeowners == nil || len(m.Status.Codeowners.Active) == 0) { | ||
deprecatedList += key + "/\n" | ||
} | ||
} | ||
|
||
if m.Status.Codeowners != nil { | ||
parts := strings.Split(key, string(os.PathSeparator)) | ||
firstSegment := parts[0] | ||
if firstSegment != currentFirstSegment { | ||
currentFirstSegment = firstSegment | ||
codeowners += "\n" | ||
} | ||
owners := "" | ||
for _, owner := range m.Status.Codeowners.Active { | ||
owners += " " | ||
owners += "@" + owner | ||
} | ||
codeowners += fmt.Sprintf("%s/%s @open-telemetry/collector-contrib-approvers%s\n", key, strings.Repeat(" ", data.maxLength-len(key)), owners) | ||
} | ||
} | ||
|
||
err = os.WriteFile(filepath.Join(".github", "CODEOWNERS"), []byte(codeowners+unmaintainedCodeowners), 0600) | ||
if err != nil { | ||
return err | ||
} | ||
err = os.WriteFile(filepath.Join(".github", "ALLOWLIST"), []byte(allowlistHeader+deprecatedList+unmaintainedList), 0600) | ||
if err != nil { | ||
return err | ||
} | ||
return nil | ||
} | ||
|
||
func getGithubMembers() (map[string]struct{}, error) { | ||
githubToken := os.Getenv("GITHUB_TOKEN") | ||
if githubToken == "" { | ||
return nil, fmt.Errorf("Set the environment variable `GITHUB_TOKEN` to a PAT token to authenticate") | ||
} | ||
client := github.NewTokenClient(context.Background(), githubToken) | ||
var allUsers []*github.User | ||
pageIndex := 0 | ||
for { | ||
users, resp, err := client.Organizations.ListMembers(context.Background(), "open-telemetry", | ||
&github.ListMembersOptions{ | ||
PublicOnly: false, | ||
ListOptions: github.ListOptions{ | ||
PerPage: 50, | ||
Page: pageIndex, | ||
}, | ||
}, | ||
) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer resp.Body.Close() | ||
if len(users) == 0 { | ||
break | ||
} | ||
allUsers = append(allUsers, users...) | ||
pageIndex++ | ||
} | ||
|
||
usernames := make(map[string]struct{}, len(allUsers)) | ||
for _, u := range allUsers { | ||
usernames[*u.Login] = struct{}{} | ||
} | ||
return usernames, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
package main | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"os" | ||
"path/filepath" | ||
"sort" | ||
"strings" | ||
|
||
"gopkg.in/yaml.v3" | ||
) | ||
|
||
const ( | ||
maxDependabotUpdates = 220 | ||
dependabotHeader = `# File generated by "make gendependabot"; DO NOT EDIT. | ||
` | ||
) | ||
|
||
type dependabotSchedule struct { | ||
Interval yaml.Node `yaml:"interval"` | ||
Day yaml.Node `yaml:"day"` | ||
} | ||
|
||
type dependabotUpdate struct { | ||
PackageEcosystem yaml.Node `yaml:"package-ecosystem"` | ||
Directory yaml.Node `yaml:"directory"` | ||
Schedule dependabotSchedule `yaml:"schedule"` | ||
Priority int `yaml:"-"` | ||
} | ||
|
||
type dependabotData struct { | ||
Version int `yaml:"version"` | ||
Updates []dependabotUpdate `yaml:"updates"` | ||
} | ||
|
||
func makePriority(status *Status) int { | ||
// not an internal component such as pkg/**, and no distributions: | ||
if (status.Class == "receiver" || status.Class == "processor" || status.Class == "exporter" || status.Class == "connector" || status.Class == "extension" || status.Class == "cmd") && | ||
len(status.Distributions) == 0 && status.Class != "" { | ||
return 1 | ||
} | ||
// start with a score of 2 | ||
maxScore := 2 | ||
for stability := range status.Stability { | ||
switch stability { | ||
case "deprecated": // stay with 2 | ||
case "unmaintained": | ||
return 1 | ||
case "alpha": | ||
if maxScore < 3 { | ||
maxScore = 3 | ||
} | ||
case "beta": | ||
if maxScore < 4 { | ||
maxScore = 4 | ||
} | ||
case "stable": | ||
if maxScore < 5 { | ||
maxScore = 5 | ||
} | ||
} | ||
} | ||
return maxScore | ||
} | ||
|
||
func newDependabotUpdate(directory string, priority int) dependabotUpdate { | ||
return dependabotUpdate{ | ||
PackageEcosystem: yaml.Node{Value: "gomod", Style: yaml.DoubleQuotedStyle, Kind: yaml.ScalarNode}, | ||
Directory: yaml.Node{Value: "/" + directory, Style: yaml.DoubleQuotedStyle, Kind: yaml.ScalarNode}, | ||
Schedule: dependabotSchedule{ | ||
Interval: yaml.Node{Value: "weekly", Style: yaml.DoubleQuotedStyle, Kind: yaml.ScalarNode}, | ||
Day: yaml.Node{Value: "wednesday", Style: yaml.DoubleQuotedStyle, Kind: yaml.ScalarNode}, | ||
}, | ||
Priority: priority, | ||
} | ||
} | ||
|
||
type dependabotGenerator struct { | ||
} | ||
|
||
func (dg dependabotGenerator) generate(data *githubData) error { | ||
dependabotData := data.dependabotData | ||
sort.Slice(dependabotData.Updates, func(i, j int) bool { | ||
return dependabotData.Updates[i].Priority > dependabotData.Updates[j].Priority | ||
}) | ||
removed := dependabotData.Updates[maxDependabotUpdates:] | ||
dependabotData.Updates = dependabotData.Updates[:maxDependabotUpdates] | ||
if len(removed) > 0 { | ||
sort.Slice(removed, func(i, j int) bool { | ||
return strings.Compare(removed[i].Directory.Value, removed[j].Directory.Value) < 0 | ||
}) | ||
fmt.Printf("The following modules were not added to Dependabot to keep within limits of %d\n", maxDependabotUpdates) | ||
for _, update := range removed { | ||
fmt.Printf(" - %q\n", update.Directory.Value) | ||
} | ||
} | ||
|
||
sort.Slice(dependabotData.Updates, func(i, j int) bool { | ||
return strings.Compare(dependabotData.Updates[i].Directory.Value, dependabotData.Updates[j].Directory.Value) < 0 | ||
}) | ||
|
||
var yamlContents bytes.Buffer | ||
encoder := yaml.NewEncoder(&yamlContents) | ||
encoder.SetIndent(2) | ||
err := encoder.Encode(dependabotData) | ||
if err != nil { | ||
return err | ||
} | ||
err = os.WriteFile(filepath.Join(".github", "dependabot.yml"), append([]byte(dependabotHeader), yamlContents.Bytes()...), 0600) | ||
return err | ||
} |
Oops, something went wrong.