...

Source file src/edge-infra.dev/pkg/tools/hack/cmd/owners/owners.go

Documentation: edge-infra.dev/pkg/tools/hack/cmd/owners

     1  package owners
     2  
     3  import (
     4  	"context"
     5  	"flag"
     6  	"fmt"
     7  	"io/fs"
     8  	"os"
     9  	"path/filepath"
    10  	"sort"
    11  	"strings"
    12  
    13  	"github.com/peterbourgon/ff/v3"
    14  	"github.com/peterbourgon/ff/v3/ffcli"
    15  	"gopkg.in/yaml.v2"
    16  
    17  	repoowners "edge-infra.dev/pkg/f8n/devinfra/repo/owners"
    18  	"edge-infra.dev/pkg/f8n/devinfra/repo/owners/policybot/policy"
    19  	"edge-infra.dev/pkg/tools/hack"
    20  )
    21  
    22  const (
    23  	policyBotFile = ".github/policy-bot.yaml"
    24  	rootRulesFile = ".github/repo-policy-bot-rules.yaml"
    25  )
    26  
    27  var ignoreList = [4]string{".git/", "tmp/", ".vscode/", "testdata"}
    28  
    29  type owners struct {
    30  	*hack.Hack
    31  
    32  	policyBotFile string
    33  	rootRulesFile string
    34  }
    35  
    36  func New(root *hack.Hack) *ffcli.Command {
    37  	o := &owners{Hack: root}
    38  
    39  	fs := flag.NewFlagSet("hack owners", flag.ContinueOnError)
    40  	o.RegisterFlags(fs)
    41  
    42  	return &ffcli.Command{
    43  		Name:    "owners",
    44  		FlagSet: fs,
    45  		Exec:    o.Exec,
    46  		Subcommands: []*ffcli.Command{
    47  			newUpdate(o),
    48  			newCreate(o),
    49  			newVerify(o),
    50  			newList(o),
    51  		},
    52  		Options: []ff.Option{
    53  			ff.WithEnvVarNoPrefix(),
    54  		},
    55  	}
    56  }
    57  
    58  func (o *owners) RegisterFlags(fs *flag.FlagSet) {
    59  	fs.StringVar(&o.policyBotFile, "policy-bot-config", policyBotFile,
    60  		"path to policy-bot configuration, used for reading and updating")
    61  	fs.StringVar(&o.rootRulesFile, "root-rules", rootRulesFile,
    62  		"path to file containing root rules to OR with all generated rules")
    63  }
    64  
    65  func (o *owners) Exec(_ context.Context, _ []string) error {
    66  	flag.Usage()
    67  	return nil
    68  }
    69  
    70  func (o *owners) collectOwners() ([]string, map[string]repoowners.File, error) {
    71  	files := map[string]repoowners.File{}
    72  	fileKeys := []string{}
    73  	dir := o.Paths.RepoRoot
    74  
    75  	if err := filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
    76  		if err != nil {
    77  			return err
    78  		}
    79  
    80  		// check the path against the list of ignored directories
    81  		for _, x := range ignoreList {
    82  			if strings.Contains(path, x) {
    83  				return filepath.SkipDir
    84  			}
    85  		}
    86  
    87  		if d.IsDir() || d.Name() != repoowners.FileName {
    88  			return nil
    89  		}
    90  
    91  		f, err := o.loadOwnersFile(path)
    92  		if err != nil {
    93  			return err
    94  		}
    95  
    96  		// make path relative to repo root
    97  		pathKey, err := filepath.Rel(dir, filepath.Dir(path))
    98  		if err != nil {
    99  			return err
   100  		}
   101  		fileKeys = append(fileKeys, pathKey)
   102  		files[pathKey] = *f
   103  
   104  		return nil
   105  	}); err != nil {
   106  		return nil, nil, err
   107  	}
   108  
   109  	sort.Slice(fileKeys, func(i, j int) bool {
   110  		return fileKeys[i] < fileKeys[j]
   111  	})
   112  
   113  	return fileKeys, files, nil
   114  }
   115  
   116  func (o *owners) loadOwnersFile(path string) (*repoowners.File, error) {
   117  	d, err := os.ReadFile(path)
   118  	if err != nil {
   119  		return nil, fmt.Errorf("failed to read %s: %w", path, err)
   120  	}
   121  
   122  	f := &repoowners.File{}
   123  	if err := yaml.UnmarshalStrict(d, f); err != nil {
   124  		return nil, fmt.Errorf("failed to parse %s: %w", path, err)
   125  	}
   126  
   127  	return f, nil
   128  }
   129  
   130  func (o *owners) getPolicyBotConfig() ([]byte, error) {
   131  	return os.ReadFile(filepath.Join(o.Paths.RepoRoot, o.policyBotFile))
   132  }
   133  
   134  // stolen from pbot
   135  // https://github.com/palantir/policy-bot/blob/da581a398aa00701bd481bc9c4bd5f4e2fc831ec/server/handler/validate.go#L70
   136  func isValidLocalPolicy(requestPolicy []byte) (bool, error) {
   137  	var policyConfig policy.Config
   138  	if err := yaml.UnmarshalStrict(requestPolicy, &policyConfig); err != nil {
   139  		return false, err
   140  	}
   141  
   142  	if _, err := policy.ParsePolicy(&policyConfig); err != nil {
   143  		return false, err
   144  	}
   145  
   146  	return true, nil
   147  }
   148  

View as plain text