diff --git a/hack/apidiff.sh b/hack/apidiff.sh index f00c19d40ad..fa70631de38 100755 --- a/hack/apidiff.sh +++ b/hack/apidiff.sh @@ -26,6 +26,11 @@ Usage: $0 [-r ] [directory ...]" Default is the current working tree instead of a revision. -r : Report change in code added since this revision. Default is the common base of origin/master and HEAD. + -b Build all packages in that directory after replacing + Kubernetes dependencies with the current content of the + staging repo. May be given more than once. Must be an + absolute path. + WARNING: this will modify the go.mod in that directory. [directory]: Check one or more specific directory instead of everything. EOF exit 1 @@ -40,7 +45,8 @@ source "${KUBE_ROOT}/hack/lib/init.sh" base= target= -while getopts "r:t:" o; do +builds=() +while getopts "r:t:b:" o; do case "${o}" in r) base="${OPTARG}" @@ -58,6 +64,14 @@ while getopts "r:t:" o; do usage fi ;; + b) + if [ ! "${OPTARG}" ]; then + echo "ERROR: -${o} needs a non-empty parameter" >&2 + echo >&2 + usage + fi + builds+=("${OPTARG}") + ;; *) usage ;; @@ -136,6 +150,8 @@ output_name () { # run invokes apidiff once per target and stores the output # file(s) in the given directory. +# +# shellcheck disable=SC2317 # "Command appears to be unreachable" - gets called indirectly. run () { out="$1" mkdir -p "$out" @@ -144,31 +160,44 @@ run () { done } -# runWorktree checks out a specific revision, then invokes run there. -runWorktree () { - local out="$1" - local worktree="$2" - local rev="$3" +# inWorktree checks out a specific revision, then invokes the given +# command there. +# +# shellcheck disable=SC2317 # "Command appears to be unreachable" - gets called indirectly. +inWorktree () { + local worktree="$1" + shift + local rev="$1" + shift # Create a copy of the repo with the specific revision checked out. - git worktree add -f -d "${worktree}" "${rev}" - # Clean up the copy on exit. - kube::util::trap_add "git worktree remove -f ${worktree}" EXIT + # Might already have been done before. + if ! [ -d "${worktree}" ]; then + git worktree add -f -d "${worktree}" "${rev}" + # Clean up the copy on exit. + kube::util::trap_add "git worktree remove -f ${worktree}" EXIT + fi # Ready for apidiff. ( cd "${worktree}" - run "${out}" + "$@" ) } +# inTarget runs the given command in the target revision of Kubernetes, +# checking it out in a work tree if necessary. +inTarget () { + if [ -z "${target}" ]; then + "$@" + else + inWorktree "${KUBE_TEMP}/target" "${target}" "$@" + fi +} + # Dump old and new api state. -if [ -z "${target}" ]; then - run "${KUBE_TEMP}/after" -else - runWorktree "${KUBE_TEMP}/after" "${KUBE_TEMP}/target" "${target}" -fi -runWorktree "${KUBE_TEMP}/before" "${KUBE_TEMP}/base" "${base}" +inTarget run "${KUBE_TEMP}/after" +inWorktree "${KUBE_TEMP}/base" "${base}" run "${KUBE_TEMP}/before" # Now produce a report. All changes get reported because exporting some API # unnecessarily might also be good to know, but the final exit code will only @@ -199,4 +228,93 @@ for d in "${targets[@]}"; do compare "${d}" "${KUBE_TEMP}/before/$(output_name "${d}")" "${KUBE_TEMP}/after/$(output_name "${d}")" done +# tryBuild checks whether some other project builds with the staging repos +# of the current Kubernetes directory. +# +# shellcheck disable=SC2317 # "Command appears to be unreachable" - gets called indirectly. +tryBuild () { + local build="$1" + + # Replace all staging repos, whether the project uses them or not (playing it safe...). + local repo + for repo in $(cd staging/src; find k8s.io -name go.mod); do + local path + repo=$(dirname "${repo}") + path="$(pwd)/staging/src/${repo}" + ( + cd "$build" + go mod edit -replace "${repo}"="${path}" + ) + done + + # We only care about building. Breaking compilation of unit tests is also + # annoying, but does not affect downstream consumers. + ( + cd "$build" + rm -rf vendor + go mod tidy + go build ./... + ) +} + +if [ $res -ne 0 ]; then + cat <