Files
kustomize/travis/module-span/multi-module-span.go
2020-09-17 16:18:17 -07:00

101 lines
3.5 KiB
Go

// multi-module-span script:
// A script which can detect when a pull request would make changes which
// span a series of restricted directories (ex: multiple go modules or projects)
//
// When a pull request includes files which span two modules the script will
// exit with a non-zero exit code.
//
// Running:
// go run multi-module-span.go -owner=kubernetes-sigs -repo=kustomize -pr=2997 cmd/config api/ kustomize/ kyaml/
package main
import (
"context"
"flag"
"fmt"
"os"
"strings"
"github.com/google/go-github/github"
)
func main() {
owner := flag.String("owner", "", "the github repository owner name")
repo := flag.String("repo", "", "the github repository name")
pullrequest := flag.Int("pr", -1, "the pull request number")
flag.Parse()
// Treat all following arguments as restricted directories
restrictedPaths := flag.Args()
// Short circuit check if restricted paths is less than 2
// Conflicts won't exist in this scenario so we don't need to call the API
if len(restrictedPaths) <= 1 {
fmt.Println("Check not run. Add at least two restricted paths and run again.")
os.Exit(0)
}
client := github.NewClient(nil)
files, err := ListAllPullRequestFiles(client, owner, pullrequest, repo)
if err != nil {
fmt.Println("Unable to retrieve pull request details:", err.Error())
os.Exit(2)
}
contributedRestrictedPaths := CountRestrictedPathUses(files, restrictedPaths)
modifiedRestrictedDirectories := CountModifiedRestrictedDirectories(contributedRestrictedPaths)
// Exit with error if two or more restricted directories where modified
if modifiedRestrictedDirectories > 1 {
fmt.Println("Modifications to multiple restricted directories occurred.")
os.Exit(1)
}
}
// ListAllPullRequestFiles retrieves as many files as possible for the
// target pull request.
//
// NOTE: GitHub API limits ListFiles to a maximum of 3000 files. Very large
// changes which exceed this limit may pass this check even if they
// do contain spanning changes.
// see: https://developer.github.com/v3/pulls/#list-pull-requests-files
func ListAllPullRequestFiles(client *github.Client, owner *string, pullrequest *int, repo *string) ([]*github.CommitFile, error) {
// GitHub returns the first 30 files by default, increase this value
options := &github.ListOptions{PerPage: 3000}
files, _, err := client.PullRequests.ListFiles(context.Background(), *owner, *repo, *pullrequest, options)
return files, err
}
// CountModifiedRestrictedDirectories Accepts a map of paths and the number of
// occurances and returns the count of the paths which had a non-zero value.
func CountModifiedRestrictedDirectories(contributedRestrictedPaths map[string]int) int {
modifiedRestrictedDirectories := 0
for _, occurance := range contributedRestrictedPaths {
if occurance != 0 {
modifiedRestrictedDirectories++
}
}
return modifiedRestrictedDirectories
}
// CountRestrictedPathUses Constructs a map that contains the number of
// references keyed to each restricted path. This provides details about how
// many files in the list are associated with each restricted path.
func CountRestrictedPathUses(files []*github.CommitFile, restrictedPaths []string) map[string]int {
contributedRestrictedPaths := make(map[string]int)
for _, path := range restrictedPaths {
contributedRestrictedPaths[path] = 0
}
for _, file := range files {
for path := range contributedRestrictedPaths {
if strings.HasPrefix(*file.Filename, path) {
contributedRestrictedPaths[path]++
}
}
}
return contributedRestrictedPaths
}