123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195 |
- // 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
- }
|