mirror of
https://github.com/optim-enterprises-bv/kubernetes.git
synced 2025-11-08 14:23:30 +00:00
- setup scripts to trigger publishing-bot verify - add golang verify script and remove python verification code - pin k8s.io/publishing-bot to v0.5.0 Signed-off-by: Akhil Mohan <akhilerm@gmail.com>
241 lines
7.2 KiB
Go
241 lines
7.2 KiB
Go
/*
|
|
Copyright 2024 The Kubernetes Authors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"golang.org/x/mod/modfile"
|
|
"k8s.io/publishing-bot/cmd/publishing-bot/config"
|
|
)
|
|
|
|
var (
|
|
rulesFile string
|
|
componentsDirectory string
|
|
)
|
|
|
|
// getGoModDependencies gets all the staging dependencies for all the modules
|
|
// in the given directory
|
|
func getGoModDependencies(dir string) (map[string][]string, error) {
|
|
allDependencies := make(map[string][]string)
|
|
components, err := os.ReadDir(dir)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for _, component := range components {
|
|
componentName := component.Name()
|
|
if !component.IsDir() {
|
|
// currently there is no hard check that the staging directory should not contain
|
|
// other files
|
|
continue
|
|
}
|
|
gomodFilePath := filepath.Join(dir, componentName, "go.mod")
|
|
gomodFileContent, err := os.ReadFile(gomodFilePath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
fmt.Printf("%s dependencies", componentName)
|
|
|
|
allDependencies[componentName] = make([]string, 0)
|
|
|
|
gomodFile, err := modfile.Parse(gomodFilePath, gomodFileContent, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
// get all the other dependencies from within staging, i.e all the modules in replace
|
|
// section
|
|
for _, module := range gomodFile.Replace {
|
|
dep := strings.TrimPrefix(module.Old.Path, "k8s.io/")
|
|
if dep == componentName {
|
|
continue
|
|
}
|
|
allDependencies[componentName] = append(allDependencies[componentName], dep)
|
|
}
|
|
}
|
|
return allDependencies, nil
|
|
}
|
|
|
|
// diffSlice returns the difference of s1-s2
|
|
func diffSlice(s1, s2 []string) []string {
|
|
var diff []string
|
|
set := make(map[string]struct{}, len(s2))
|
|
for _, s := range s2 {
|
|
set[s] = struct{}{}
|
|
}
|
|
for _, s := range s1 {
|
|
if _, ok := set[s]; !ok {
|
|
diff = append(diff, s)
|
|
}
|
|
}
|
|
return diff
|
|
}
|
|
|
|
// getKeys returns a slice with only the keys of the given map
|
|
func getKeys[K comparable, V any](m map[K]V) []K {
|
|
var keys []K
|
|
for k := range m {
|
|
keys = append(keys, k)
|
|
}
|
|
return keys
|
|
}
|
|
|
|
// checkValidSourceDirectory checks if proper source directory fields are used in rules
|
|
func checkValidSourceDirectory(rule config.RepositoryRule) error {
|
|
for _, branch := range rule.Branches {
|
|
if branch.Source.Dir != "" {
|
|
return fmt.Errorf("use of deprecated `dir` field in rules for `%s`", rule.DestinationRepository)
|
|
}
|
|
if len(branch.Source.Dirs) > 1 {
|
|
return fmt.Errorf("cannot have more than one directory (%s) per source branch `%s` of `%s`",
|
|
branch.Source.Dirs,
|
|
branch.Source.Branch,
|
|
rule.DestinationRepository,
|
|
)
|
|
}
|
|
if !strings.HasSuffix(branch.Source.Dirs[0], rule.DestinationRepository) {
|
|
return fmt.Errorf("copy/paste error `%s` refers to `%s`", rule.DestinationRepository, branch.Source.Dirs[0])
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// checkMasterBranch checks if the master branch of destination repository refers to the master
|
|
// of the source
|
|
func checkMasterBranch(rule config.RepositoryRule) error {
|
|
branch := rule.Branches[0]
|
|
if branch.Name != "master" {
|
|
return fmt.Errorf("cannot find master branch for destination `%s`", rule.DestinationRepository)
|
|
}
|
|
|
|
if branch.Source.Branch != "master" {
|
|
return fmt.Errorf("cannot find master source branch for destination `%s`", rule.DestinationRepository)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func checkDependencies(rule config.RepositoryRule, gomodDependencies map[string][]string) error {
|
|
var processedDeps []string
|
|
branch := rule.Branches[0]
|
|
for _, dep := range gomodDependencies[rule.DestinationRepository] {
|
|
found := false
|
|
if len(branch.Dependencies) > 0 {
|
|
for _, dep2 := range branch.Dependencies {
|
|
processedDeps = append(processedDeps, dep2.Repository)
|
|
if dep2.Branch != "master" {
|
|
return fmt.Errorf("looking for master branch of %s and found : %s for destination", dep2.Repository, rule.DestinationRepository)
|
|
}
|
|
if dep2.Repository == dep {
|
|
found = true
|
|
}
|
|
}
|
|
} else {
|
|
return fmt.Errorf("Please add %s as dependencies under destination %s", gomodDependencies[rule.DestinationRepository], rule.DestinationRepository)
|
|
}
|
|
if !found {
|
|
return fmt.Errorf("Please add %s as a dependency under destination %s", dep, rule.DestinationRepository)
|
|
} else {
|
|
fmt.Printf("dependency %s found\n", dep)
|
|
}
|
|
}
|
|
// check if all deps are processed.
|
|
extraDeps := diffSlice(processedDeps, gomodDependencies[rule.DestinationRepository])
|
|
if len(extraDeps) > 0 {
|
|
return fmt.Errorf("extra dependencies in rules for %s: %s", rule.DestinationRepository, strings.Join(extraDeps, ","))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func verifyPublishingBotRules() error {
|
|
rules, err := config.LoadRules(rulesFile)
|
|
if err != nil {
|
|
return fmt.Errorf("error loading rules: %v", err)
|
|
}
|
|
|
|
gomodDependencies, err := getGoModDependencies(componentsDirectory)
|
|
|
|
var processedRepos []string
|
|
for _, rule := range rules.Rules {
|
|
branch := rule.Branches[0]
|
|
|
|
// if this no longer exists in master
|
|
if _, ok := gomodDependencies[rule.DestinationRepository]; !ok {
|
|
// make sure we dont include a rule to publish it from master
|
|
for _, branch := range rule.Branches {
|
|
if branch.Name == "master" {
|
|
err := fmt.Errorf("cannot find master branch for destination `%s`", rule.DestinationRepository)
|
|
panic(err)
|
|
}
|
|
}
|
|
// and skip the validation of publishing rules for it
|
|
continue
|
|
}
|
|
|
|
if err := checkValidSourceDirectory(rule); err != nil {
|
|
return fmt.Errorf("error validating source directory: %v", err)
|
|
}
|
|
|
|
if err := checkMasterBranch(rule); err != nil {
|
|
return fmt.Errorf("error validating master branch: %v", err)
|
|
}
|
|
|
|
// we specify the go version for all master branches through `default-go-version`
|
|
// so ensure we don't specify explicit go version for master branch in rules
|
|
if branch.GoVersion != "" {
|
|
err := fmt.Errorf("go version must not be specified for master branch for destination `%s`", rule.DestinationRepository)
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Printf("processing : %s", rule.DestinationRepository)
|
|
if _, ok := gomodDependencies[rule.DestinationRepository]; !ok {
|
|
err := fmt.Errorf("missing go.mod for `%s`", rule.DestinationRepository)
|
|
panic(err)
|
|
}
|
|
processedRepos = append(processedRepos, rule.DestinationRepository)
|
|
|
|
if err := checkDependencies(rule, gomodDependencies); err != nil {
|
|
return fmt.Errorf("error validating dependencies: %v", err)
|
|
}
|
|
}
|
|
|
|
// check if all repos are processed.
|
|
items := diffSlice(getKeys(gomodDependencies), processedRepos)
|
|
if len(items) > 0 {
|
|
err := fmt.Errorf("missing rules for %s", strings.Join(items, ","))
|
|
panic(err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func main() {
|
|
if len(os.Args) != 2 {
|
|
panic("invalid number of arguments")
|
|
}
|
|
|
|
kubeRoot := os.Args[1]
|
|
stagingDirectory := kubeRoot + "/staging/"
|
|
rulesFile = stagingDirectory + "publishing/rules.yaml"
|
|
componentsDirectory = stagingDirectory + "src/k8s.io/"
|
|
|
|
if err := verifyPublishingBotRules(); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|