package owners import ( "context" "flag" "fmt" "os" "path/filepath" "github.com/peterbourgon/ff/v3" "github.com/peterbourgon/ff/v3/ffcli" "gopkg.in/yaml.v2" repoowners "edge-infra.dev/pkg/f8n/devinfra/repo/owners" ) const ( pkg = "pkg/" cmd = "cmd/" pallets = "config/pallets/" ) type arrayFlags []string func (i *arrayFlags) String() string { return "list of strings" } func (i *arrayFlags) Set(value string) error { *i = append(*i, value) return nil } type create struct { *owners teams arrayFlags usernames arrayFlags dirs arrayFlags pkg bool cmd bool pallets bool } // hack owners create func newCreate(o *owners) *ffcli.Command { c := &create{owners: o} fs := flag.NewFlagSet("hack owners create", flag.ExitOnError) c.owners.RegisterFlags(fs) fs.Var(&c.teams, "team", "list of teams to add") fs.Var(&c.usernames, "username", "list of usernames to add") fs.Var(&c.dirs, "dir", "list of directories to create a new OWNERS file") fs.BoolVar(&c.pkg, "pkg", false, "create the /pkg dir") fs.BoolVar(&c.cmd, "cmd", false, "create the /cmd dir") fs.BoolVar(&c.pallets, "pallets", false, "create the config/pallets dir") return &ffcli.Command{ Name: "create", FlagSet: fs, Exec: c.Exec, Options: []ff.Option{ ff.WithEnvVarNoPrefix(), }, } } func (c *create) Exec(_ context.Context, _ []string) error { // if there's no teams or users defined err if len(c.teams) == 0 && len(c.usernames) == 0 { return fmt.Errorf("a team or user must be defined") } // if there's no dir defined err if len(c.dirs) == 0 { return fmt.Errorf("a directory must be defined") } // get all the owners files that exist _, ownersFiles, err := c.collectOwners() if err != nil { return fmt.Errorf("failed to collect OWNERS files: %w", err) } // if the user doesnt give the specific folder flag just assume the dir is the full path if !c.pkg && !c.cmd && !c.pallets { for _, dir := range c.dirs { c.generateFile(dir, ownersFiles) } return c.update() } // create the new files dir := c.dirs[0] // just grab the first dir if len(c.dirs) > 1 { fmt.Printf("⚠️ more than one dir was given but only %s will be used \n", dir) fmt.Println("⚠️ drop the pkg, cmd, or pallet flag for all dirs to be created") } if c.pkg { c.generateFile(filepath.Join(pkg, dir), ownersFiles) } if c.cmd { c.generateFile(filepath.Join(cmd, dir), ownersFiles) } if c.pallets { c.generateFile(filepath.Join(pallets, dir), ownersFiles) } return c.update() } // update the pbot file func (c *create) update() error { u := &update{owners: c.owners} d, err := u.generatePBotCfg() if err != nil { return err } return u.createFile(d) } func (c *create) generateFile(dir string, ownersFiles map[string]repoowners.File) { // if the owner files does not already exist for the // path create it if _, ok := ownersFiles[dir]; !ok { f := repoowners.DefaultFile(c.usernames, c.teams, dir) fp := filepath.Join(c.Paths.RepoRoot, dir, repoowners.FileName) fmt.Printf("✅ %s created \n", fp) err := createPathAndFile(f, fp) if err != nil { fmt.Printf("failed to create file and path: %v", err) } } else { fmt.Printf("〰️ %s already exists ignoring \n", dir) } } func createPathAndFile(file *repoowners.File, path string) error { if err := os.MkdirAll(filepath.Dir(path), 0770); err != nil { return fmt.Errorf("Error creating dirs: %w", err) } _, err := os.Create(path) if err != nil { return fmt.Errorf("could not create file path: %w", err) } yamlData, err := yaml.Marshal(&file) if err != nil { return fmt.Errorf("Error while Marshaling: %w", err) } err = os.WriteFile(path, yamlData, 0644) if err != nil { return fmt.Errorf("unable to write data into the file: %w", err) } return nil }