From ae51cc9a12a7fde0d7a531cd6740af1ce589ef41 Mon Sep 17 00:00:00 2001 From: Robert Vasek Date: Tue, 25 Feb 2025 21:35:48 +0100 Subject: [PATCH] hack/verify-go-modules.sh: compare dependency versions against k8s.io/kubernetes On-behalf-of: SAP robert.vasek@sap.com Signed-off-by: Robert Vasek --- hack/verify-go-modules.sh | 83 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/hack/verify-go-modules.sh b/hack/verify-go-modules.sh index 401b81197f6..45acb3a2580 100755 --- a/hack/verify-go-modules.sh +++ b/hack/verify-go-modules.sh @@ -15,6 +15,10 @@ # limitations under the License. # This script verifies all go modules in the repository. +# go.mod and go.sum files are checked that both have been +# committed. Versions of dependencies they declare are +# checked to be in line with dependencies in k8s.io/kubernetes, +# and a warning message is printed if they differ in v.. set -o errexit set -o nounset @@ -24,14 +28,93 @@ REPO_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) mapfile -t DIRS < <(find "${REPO_ROOT}" -name go.mod -print0 | xargs -0 dirname) +# list_deps lists dependencies of the supplied go.mod file (dependencies +# with version "v0.0.0" are skipped). The output is a json dictionary in the +# format `{"": "", ...}`. +function list_deps { + gomod_file="${1}" + go mod edit -json "${gomod_file}" \ + | jq -r ' + ( + [ .Require[] + | select(.Version != "v0.0.0") + | { (.Path): .Version } ] + | add + ) + ' +} + +# diff_version_deps lists common dependencies of the two supplied go.mod files +# whose respective versions differ (up to v.). The output is a json +# dictionary in the format: +# `{"": { +# "has": "", +# "wants": "" +# }, ...}` +function diff_version_deps { + has_deps="${1}" + wants_deps="${2}" + jq -s ' + # Extracts v. from a semantic version string. + def major_minor_semver: capture("v(?\\d+)\\.(?\\d+)") + | "v" + .major + "." + .minor; + + map(to_entries) # Convert both input dicts into two separate arrays. + | add # Concatenate those two arrays into a single one. + | group_by(.key) # Group items by `.key`. + | map( # Map each selected item into { "": {"has": "", "wants": ""} }. + select( + # If grouping resulted in two items, it means both arrays have this dependency. + length == 2 + # Compare the v. of both items. + and (.[0].value | major_minor_semver) != (.[1].value | major_minor_semver) + ) + | { (.[0].key): { "has": .[0].value, "wants": .[1].value } } + ) + | add // empty + ' "${has_deps}" "${wants_deps}" +} + +# print_diff_version_deps prints the output of diff_version_deps as a +# human-readable multi-line text. +function print_diff_version_deps { + jq -r "to_entries | map(\"Warning: version mismatch: has \(.key)@\(.value.has), but \(.value.wants) expected\") | join(\"\\n\")" +} + +# Compares versions of dependencies in the supplied go.mod to +# makes sure they are in line with the ones declared in +# k8s.io/kubernetes module and prints the result. +function compare_mod_versions { + gomod_file="${1}" + echo "Verifying dependency versions in ${gomod_file} against ${k8s_gomod}" + deps="$(list_deps ${gomod_file})" + + diff_version_deps <(echo "${deps}") <(echo "${k8s_deps}") \ + | print_diff_version_deps "${gomod_file}" +} + +function gomod_filepath_for { + mod="${1}" + go list -m -json "${mod}" | jq -r .GoMod +} + +k8s_gomod="$(gomod_filepath_for k8s.io/kubernetes)" +k8s_deps="$(list_deps ${k8s_gomod})" + for dir in "${DIRS[@]}"; do ( cd "$dir" echo "Verifying ${dir}" + if ! git diff --quiet HEAD -- go.mod go.sum; then echo "go module files are out of date" git diff HEAD -- go.mod go.sum exit 1 fi + + compare_mod_versions "${dir}/go.mod" ) done + +compare_mod_versions "$(gomod_filepath_for github.com/kcp-dev/client-go)" +compare_mod_versions "$(gomod_filepath_for github.com/kcp-dev/apimachinery/v2)"