mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-09 20:17:41 +00:00
rewrite publishing-bot verify script in go
- 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>
This commit is contained in:
parent
1dbf0830c5
commit
b0bf3fba54
@ -10,8 +10,10 @@ require (
|
|||||||
github.com/jcchavezs/porto v0.6.0
|
github.com/jcchavezs/porto v0.6.0
|
||||||
github.com/vektra/mockery/v2 v2.40.3
|
github.com/vektra/mockery/v2 v2.40.3
|
||||||
go.uber.org/automaxprocs v1.5.2
|
go.uber.org/automaxprocs v1.5.2
|
||||||
|
golang.org/x/mod v0.20.0
|
||||||
gotest.tools/gotestsum v1.12.0
|
gotest.tools/gotestsum v1.12.0
|
||||||
honnef.co/go/tools v0.5.1
|
honnef.co/go/tools v0.5.1
|
||||||
|
k8s.io/publishing-bot v0.5.0
|
||||||
sigs.k8s.io/logtools v0.8.1
|
sigs.k8s.io/logtools v0.8.1
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -74,6 +76,7 @@ require (
|
|||||||
github.com/go-xmlfmt/xmlfmt v1.1.2 // indirect
|
github.com/go-xmlfmt/xmlfmt v1.1.2 // indirect
|
||||||
github.com/gobwas/glob v0.2.3 // indirect
|
github.com/gobwas/glob v0.2.3 // indirect
|
||||||
github.com/gofrs/flock v0.8.1 // indirect
|
github.com/gofrs/flock v0.8.1 // indirect
|
||||||
|
github.com/golang/glog v1.2.2 // indirect
|
||||||
github.com/golang/protobuf v1.5.3 // indirect
|
github.com/golang/protobuf v1.5.3 // indirect
|
||||||
github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2 // indirect
|
github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2 // indirect
|
||||||
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a // indirect
|
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a // indirect
|
||||||
@ -190,7 +193,6 @@ require (
|
|||||||
go.uber.org/zap v1.24.0 // indirect
|
go.uber.org/zap v1.24.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc // indirect
|
golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc // indirect
|
||||||
golang.org/x/exp/typeparams v0.0.0-20231219180239-dc181d75b848 // indirect
|
golang.org/x/exp/typeparams v0.0.0-20231219180239-dc181d75b848 // indirect
|
||||||
golang.org/x/mod v0.17.0 // indirect
|
|
||||||
golang.org/x/sync v0.7.0 // indirect
|
golang.org/x/sync v0.7.0 // indirect
|
||||||
golang.org/x/sys v0.20.0 // indirect
|
golang.org/x/sys v0.20.0 // indirect
|
||||||
golang.org/x/term v0.18.0 // indirect
|
golang.org/x/term v0.18.0 // indirect
|
||||||
|
@ -207,6 +207,8 @@ github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
|
|||||||
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
|
github.com/golang/glog v1.2.2 h1:1+mZ9upx1Dh6FmUTFR1naJ77miKiXgALjWOZ3NVFPmY=
|
||||||
|
github.com/golang/glog v1.2.2/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
|
||||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
@ -678,8 +680,8 @@ golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
|||||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
|
golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
|
||||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
@ -1024,6 +1026,8 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9
|
|||||||
honnef.co/go/tools v0.5.1 h1:4bH5o3b5ZULQ4UrBmP+63W9r7qIkqJClEA9ko5YKx+I=
|
honnef.co/go/tools v0.5.1 h1:4bH5o3b5ZULQ4UrBmP+63W9r7qIkqJClEA9ko5YKx+I=
|
||||||
honnef.co/go/tools v0.5.1/go.mod h1:e9irvo83WDG9/irijV44wr3tbhcFeRnfpVlRqVwpzMs=
|
honnef.co/go/tools v0.5.1/go.mod h1:e9irvo83WDG9/irijV44wr3tbhcFeRnfpVlRqVwpzMs=
|
||||||
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
|
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
|
||||||
|
k8s.io/publishing-bot v0.5.0 h1:Hfnhltr+khEcqvoK4GBYrtaA8dHJ50Xjyi+0KGUfU3I=
|
||||||
|
k8s.io/publishing-bot v0.5.0/go.mod h1:S5+zQQhsVUEqdcaohbYf8O+2BeeWRtuYzp4tQLr5An8=
|
||||||
k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||||
mvdan.cc/gofumpt v0.6.0 h1:G3QvahNDmpD+Aek/bNOLrFR2XC6ZAdo62dZu65gmwGo=
|
mvdan.cc/gofumpt v0.6.0 h1:G3QvahNDmpD+Aek/bNOLrFR2XC6ZAdo62dZu65gmwGo=
|
||||||
mvdan.cc/gofumpt v0.6.0/go.mod h1:4L0wf+kgIPZtcCWXynNS2e6bhmj73umwnuXSZarixzA=
|
mvdan.cc/gofumpt v0.6.0/go.mod h1:4L0wf+kgIPZtcCWXynNS2e6bhmj73umwnuXSZarixzA=
|
||||||
|
240
hack/tools/publishing-verifier/publishing-verifier.go
Normal file
240
hack/tools/publishing-verifier/publishing-verifier.go
Normal file
@ -0,0 +1,240 @@
|
|||||||
|
/*
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
@ -36,4 +36,8 @@ import (
|
|||||||
|
|
||||||
// tools like cpu
|
// tools like cpu
|
||||||
_ "go.uber.org/automaxprocs"
|
_ "go.uber.org/automaxprocs"
|
||||||
|
|
||||||
|
// for publishing bot
|
||||||
|
_ "golang.org/x/mod/modfile"
|
||||||
|
_ "k8s.io/publishing-bot/cmd/publishing-bot/config"
|
||||||
)
|
)
|
||||||
|
@ -1,134 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
# Copyright 2019 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.
|
|
||||||
|
|
||||||
import fnmatch
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import json
|
|
||||||
|
|
||||||
|
|
||||||
def get_gomod_dependencies(rootdir, components):
|
|
||||||
all_dependencies = {}
|
|
||||||
for component in components:
|
|
||||||
with open(os.path.join(rootdir, component, "go.mod")) as f:
|
|
||||||
print((component + " dependencies"))
|
|
||||||
all_dependencies[component] = []
|
|
||||||
lines = list(set(f))
|
|
||||||
lines.sort()
|
|
||||||
for line in lines:
|
|
||||||
for dep in components:
|
|
||||||
if dep == component:
|
|
||||||
continue
|
|
||||||
if ("k8s.io/" + dep + " =>") not in line:
|
|
||||||
continue
|
|
||||||
print(("\t"+dep))
|
|
||||||
if dep not in all_dependencies[component]:
|
|
||||||
all_dependencies[component].append(dep)
|
|
||||||
return all_dependencies
|
|
||||||
|
|
||||||
|
|
||||||
def get_rules_dependencies(rules_file):
|
|
||||||
import yaml
|
|
||||||
with open(rules_file) as f:
|
|
||||||
data = yaml.safe_load(f)
|
|
||||||
return data
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
rootdir = os.path.dirname(__file__) + "/../"
|
|
||||||
rootdir = os.path.abspath(rootdir)
|
|
||||||
|
|
||||||
components = []
|
|
||||||
for component in os.listdir(rootdir + '/staging/src/k8s.io/'):
|
|
||||||
components.append(component)
|
|
||||||
components.sort()
|
|
||||||
|
|
||||||
rules_file = "/staging/publishing/rules.yaml"
|
|
||||||
try:
|
|
||||||
import yaml
|
|
||||||
except ImportError:
|
|
||||||
print(("Please install missing pyyaml module and re-run %s" % sys.argv[0]))
|
|
||||||
sys.exit(1)
|
|
||||||
rules_dependencies = get_rules_dependencies(rootdir + rules_file)
|
|
||||||
|
|
||||||
gomod_dependencies = get_gomod_dependencies(rootdir + '/staging/src/k8s.io/', components)
|
|
||||||
|
|
||||||
processed_repos = []
|
|
||||||
for rule in rules_dependencies["rules"]:
|
|
||||||
branch = rule["branches"][0]
|
|
||||||
|
|
||||||
# If this no longer exists in master
|
|
||||||
if rule["destination"] not in gomod_dependencies:
|
|
||||||
# Make sure we don't include a rule to publish it from master
|
|
||||||
for branch in rule["branches"]:
|
|
||||||
if branch["name"] == "master":
|
|
||||||
raise Exception("cannot find master branch for destination %s" % rule["destination"])
|
|
||||||
# And skip validation of publishing rules for it
|
|
||||||
continue
|
|
||||||
|
|
||||||
for item in rule["branches"]:
|
|
||||||
if "dir" in item["source"]:
|
|
||||||
raise Exception("use of deprecated `dir` field in rules for `%s`" % (rule["destination"]))
|
|
||||||
if len(item["source"]["dirs"]) > 1:
|
|
||||||
raise Exception("cannot have more than one directory (`%s`) per source branch `%s` of `%s`" %
|
|
||||||
(item["source"]["dirs"], item["source"]["branch"], rule["destination"])
|
|
||||||
)
|
|
||||||
if not item["source"]["dirs"][0].endswith(rule["destination"]):
|
|
||||||
raise Exception("copy/paste error `%s` refers to `%s`" % (rule["destination"],item["source"]["dir"]))
|
|
||||||
|
|
||||||
if branch["name"] != "master":
|
|
||||||
raise Exception("cannot find master branch for destination %s" % rule["destination"])
|
|
||||||
if branch["source"]["branch"] != "master":
|
|
||||||
raise Exception("cannot find master source branch for destination %s" % rule["destination"])
|
|
||||||
|
|
||||||
# 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 "go" in branch:
|
|
||||||
raise Exception("go version must not be specified for master branch for destination %s" % rule["destination"])
|
|
||||||
|
|
||||||
print(("processing : %s" % rule["destination"]))
|
|
||||||
if rule["destination"] not in gomod_dependencies:
|
|
||||||
raise Exception("missing go.mod for %s" % rule["destination"])
|
|
||||||
processed_repos.append(rule["destination"])
|
|
||||||
processed_deps = []
|
|
||||||
for dep in set(gomod_dependencies[rule["destination"]]):
|
|
||||||
found = False
|
|
||||||
if "dependencies" in branch:
|
|
||||||
for dep2 in branch["dependencies"]:
|
|
||||||
processed_deps.append(dep2["repository"])
|
|
||||||
if dep2["branch"] != "master":
|
|
||||||
raise Exception("Looking for master branch and found : %s for destination", dep2,
|
|
||||||
rule["destination"])
|
|
||||||
if dep2["repository"] == dep:
|
|
||||||
found = True
|
|
||||||
else:
|
|
||||||
raise Exception(
|
|
||||||
"Please add %s as dependencies under destination %s in %s" % (gomod_dependencies[rule["destination"]], rule["destination"], rules_file))
|
|
||||||
if not found:
|
|
||||||
raise Exception("Please add %s as a dependency under destination %s in %s" % (dep, rule["destination"], rules_file))
|
|
||||||
else:
|
|
||||||
print((" found dependency %s" % dep))
|
|
||||||
extraDeps = set(processed_deps) - set(gomod_dependencies[rule["destination"]])
|
|
||||||
if len(extraDeps) > 0:
|
|
||||||
raise Exception("extra dependencies in rules for %s: %s" % (rule["destination"], ','.join(str(s) for s in extraDeps)))
|
|
||||||
items = set(gomod_dependencies.keys()) - set(processed_repos)
|
|
||||||
if len(items) > 0:
|
|
||||||
raise Exception("missing rules for %s" % ','.join(str(s) for s in items))
|
|
||||||
print("Done.")
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
sys.exit(main())
|
|
32
hack/verify-publishing-bot.sh
Executable file
32
hack/verify-publishing-bot.sh
Executable file
@ -0,0 +1,32 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
# This script checks whether staging/publishing/rules.yaml is correct
|
||||||
|
# as per the dependencies in the go.mod of the staging directories
|
||||||
|
# Usage: `hack/verify-publishing-bot.sh`.
|
||||||
|
|
||||||
|
set -o errexit
|
||||||
|
set -o nounset
|
||||||
|
set -o pipefail
|
||||||
|
|
||||||
|
KUBE_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
|
||||||
|
source "${KUBE_ROOT}/hack/lib/init.sh"
|
||||||
|
|
||||||
|
kube::golang::setup_env
|
||||||
|
|
||||||
|
go -C "${KUBE_ROOT}/hack/tools" install ./publishing-verifier
|
||||||
|
|
||||||
|
publishing-verifier "${KUBE_ROOT}"
|
Loading…
Reference in New Issue
Block a user