Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 103 additions & 0 deletions magefile.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,36 @@
package main

import (
"bufio"
"io/fs"
"io/ioutil"
"os"
"path/filepath"
"strings"

"github.com/magefile/mage/mg"
"github.com/magefile/mage/sh"
"github.com/pkg/errors"
"gopkg.in/yaml.v2"
)

var (
// GoImportsLocalPrefix is a string prefix matching imports that should be
// grouped after third-party packages.
GoImportsLocalPrefix = "github.com/elastic"
)

const (
buildDir = "./build"

codeownersPath = ".github/CODEOWNERS"
)

func Check() error {
mg.Deps(build)
mg.Deps(format)
mg.Deps(modTidy)
mg.Deps(checkPackageOwners)
Comment thread
jsoriano marked this conversation as resolved.
Outdated
return nil
}

Expand Down Expand Up @@ -109,3 +119,96 @@ func findFilesRecursive(match func(path string, info os.FileInfo) bool) ([]strin
func modTidy() error {
return sh.RunV("go", "mod", "tidy")
}

func checkPackageOwners() error {
codeowners, err := readGithubOwners()
if err != nil {
return err
}

const packagesDir = "packages"
return filepath.WalkDir(packagesDir, func(path string, d fs.DirEntry, err error) error {
if d.IsDir() {
if path != packagesDir && filepath.Dir(path) != packagesDir {
return fs.SkipDir
}
return nil
}
if d.Name() != "manifest.yml" {
return nil
}

return codeowners.checkManifest(path)
})
}

type githubOwners map[string][]string

func readGithubOwners() (githubOwners, error) {
f, err := os.Open(codeownersPath)
if err != nil {
return nil, errors.Wrapf(err, "failed to open %q", codeownersPath)
}
defer f.Close()

codeowners := make(githubOwners)

scanner := bufio.NewScanner(f)
lineNumber := 0
for scanner.Scan() {
lineNumber++
line := strings.TrimSpace(scanner.Text())
if len(line) == 0 || strings.HasPrefix(line, "#") {
continue
}
fields := strings.Fields(line)
if len(fields) < 2 {
return nil, errors.Errorf("invalid line %d in %q: %q", lineNumber, codeownersPath, line)
}
path, owners := fields[0], fields[1:]

// It is ok to overwrite because latter lines have precedence in these files.
codeowners[path] = owners
}

Comment thread
jsoriano marked this conversation as resolved.
Outdated
return codeowners, nil
}

func (codeowners githubOwners) checkManifest(path string) error {
pkgDir := filepath.Dir(path)
owners, found := codeowners["/"+pkgDir]
if !found {
return errors.Errorf("there is no owner for %q in %q", pkgDir, codeownersPath)
}

content, err := ioutil.ReadFile(path)
if err != nil {
return err
}

var manifest struct {
Owner struct {
Github string `yaml:"github"`
} `yaml:"owner"`
}
err = yaml.Unmarshal(content, &manifest)
if err != nil {
return err
}

if manifest.Owner.Github == "" {
return errors.Errorf("no owner specified in %q", path)
}

found = false
for _, owner := range owners {
if owner == "@"+manifest.Owner.Github {
found = true
break
}
}
if !found {
return errors.Errorf("owner %q defined in %q is not in %q", manifest.Owner.Github, path, codeownersPath)
}
return nil
}