@@ -26,7 +26,38 @@ set -o pipefail
26
26
27
27
REPO_ROOT=$( cd " $( dirname " ${BASH_SOURCE[0]} " ) /.." && pwd)
28
28
29
- mapfile -t DIRS < <( find " ${REPO_ROOT} " -name go.mod -print0 | xargs -0 dirname)
29
+ if [[ ! -f " ${REPO_ROOT} /go.work" ]]; then
30
+ (
31
+ cd " ${REPO_ROOT} "
32
+ go work init
33
+ go work use -r .
34
+ )
35
+ fi
36
+
37
+ # Array of all modules inside the repository, sorted in
38
+ # descending topological order (dependant comes before its dependee).
39
+ mapfile -t MODULE_DIRS < <(
40
+ for mod in $( tsort <(
41
+ # Lines in format "<Dependant> <Dependee>" are fed into `tsort` to perform the topological sort.
42
+ for dir in $( go list -m -json | jq -r ' .Dir' ) ; do
43
+ (
44
+ cd " ${dir} "
45
+ # Prints the dependency graph where we extract only the direct
46
+ # github.com/kcp-dev/kcp/* dependencies of the currently examined module,
47
+ # and we discard the dependency version (the line is in format
48
+ # "<This module> <Its dependency>@<Version>", so we split by '@' and get the
49
+ # first part). We skip when no such deps are found.
50
+ go mod graph \
51
+ | grep -E " ^$( go mod edit -json | jq -r ' .Module.Path' ) github.com/kcp-dev/kcp/" \
52
+ | cut -d' @' -f1 \
53
+ || true
54
+ )
55
+ done
56
+ ) | tac) ; do # We need to reverse the lines (with `tac`) to have a descending order.
57
+ # We have sorted module paths. We need to convert them into their respective directory locations.
58
+ go list -m -json " $mod " | jq -r ' .Dir'
59
+ done
60
+ )
30
61
31
62
# list_deps lists dependencies of the supplied go.mod file (dependencies
32
63
# with version "v0.0.0" are skipped). The output is a json dictionary in the
@@ -55,42 +86,40 @@ function diff_version_deps {
55
86
has_deps=" ${1} "
56
87
wants_deps=" ${2} "
57
88
jq -s '
58
- # Extracts v<Maj>.<Min> from a semantic version string.
59
- def major_minor_semver: capture("v(?<major>\\d+)\\.(?<minor>\\d+)")
60
- | "v" + .major + "." + .minor;
61
-
62
89
map(to_entries) # Convert both input dicts into two separate arrays.
63
90
| add # Concatenate those two arrays into a single one.
64
91
| group_by(.key) # Group items by `.key`.
65
92
| map( # Map each selected item into { "<Dep>": {"has": "<Version0>", "wants": "<Version1>"} }.
66
93
select(
67
94
# If grouping resulted in two items, it means both arrays have this dependency.
68
95
length == 2
69
- # Compare the v<Maj>.<Min> of both items .
70
- and (.[0].value | major_minor_semver) != ( .[1].value | major_minor_semver )
96
+ # And the dependency has a version mismatch .
97
+ and (.[0].value != .[1].value)
71
98
)
72
99
| { (.[0].key): { "has": .[0].value, "wants": .[1].value } }
73
100
)
74
101
| add // empty
75
102
' " ${has_deps} " " ${wants_deps} "
76
103
}
77
104
78
- # print_diff_version_deps prints the output of diff_version_deps as a
79
- # human-readable multi-line text.
105
+ # print_diff_version_deps prints the output of diff_version_deps (expected in stdin)
106
+ # as a human-readable multi-line text.
107
+ # Returns 1 if any lines were printed (i.e. errors were found).
80
108
function print_diff_version_deps {
81
- jq -r " to_entries | map(\" Warning: version mismatch: has \(.key)@\(.value.has), but \(.value.wants) expected\" ) | join(\"\\ n\" )"
109
+ jq -r '
110
+ to_entries
111
+ | map("Version mismatch: \(.key) is \(.value.has), but \(.value.wants) expected")
112
+ | join("\n")
113
+ '
82
114
}
83
115
84
116
# Compares versions of dependencies in the supplied go.mod to
85
117
# makes sure they are in line with the ones declared in
86
- # k8s.io/kubernetes module and prints the result .
87
- function compare_mod_versions {
118
+ # k8s.io/kubernetes module.
119
+ function compare_mod_versions_with_k8s_deps {
88
120
gomod_file=" ${1} "
89
- echo " Verifying dependency versions in ${gomod_file} against ${k8s_gomod} "
90
121
deps=" $( list_deps ${gomod_file} ) "
91
-
92
- diff_version_deps <( echo " ${deps} " ) <( echo " ${k8s_deps} " ) \
93
- | print_diff_version_deps " ${gomod_file} "
122
+ diff_version_deps <( echo " ${deps} " ) <( echo " ${k8s_deps} " )
94
123
}
95
124
96
125
function gomod_filepath_for {
@@ -101,20 +130,27 @@ function gomod_filepath_for {
101
130
k8s_gomod=" $( gomod_filepath_for k8s.io/kubernetes) "
102
131
k8s_deps=" $( list_deps ${k8s_gomod} ) "
103
132
104
- for dir in " ${DIRS [@]} " ; do
133
+ for dir in " ${MODULE_DIRS [@]} " ; do
105
134
(
106
135
cd " $dir "
107
136
echo " Verifying ${dir} "
108
137
109
- if ! git diff --quiet HEAD -- go.mod go.sum; then
110
- git --no-pager diff HEAD -- go.mod go.sum
111
- echo " Error: go.mod and/or go.sum in ${dir} files have been modified, inspect and commit them before continuing" 1>&2
138
+ if ! go mod tidy -diff ; then
139
+ echo " Error: go.mod and/or go.sum is not clean, run 'go mod tidy' before continuing" 1>&2
112
140
exit 1
113
141
fi
114
142
115
- compare_mod_versions " ${dir} /go.mod"
143
+ gomod_file=" ${dir} /go.mod"
144
+ echo " Verifying dependency versions in ${gomod_file} against ${k8s_gomod} "
145
+
146
+ diff=" $( compare_mod_versions_with_k8s_deps ${dir} /go.mod) "
147
+ if [[ -n " ${diff} " ]]; then
148
+ echo " ${diff} " | print_diff_version_deps 1>&2
149
+ echo " ${diff} " | grep -q " k8s.io/" && {
150
+ echo " Error: dependencies from '*k8s.io/*' must be in line with ${k8s_gomod} " 1>&2
151
+ exit 1
152
+ } || true
153
+ echo " Continuing because no fatal errors found"
154
+ fi
116
155
)
117
156
done
118
-
119
- compare_mod_versions " $( gomod_filepath_for github.com/kcp-dev/client-go) "
120
- compare_mod_versions " $( gomod_filepath_for github.com/kcp-dev/apimachinery/v2) "
0 commit comments