Add validation-gen to codegen scripts

Add validation-gen to repository wide codegen scripts and introduce
`./hack/update-codegen.sh validation` as a quick way to run validation-gen.
This commit is contained in:
Joe Betz 2025-03-03 09:49:50 -05:00
parent e892dfac7d
commit 3210f46b5b
2 changed files with 114 additions and 4 deletions

View File

@ -52,7 +52,11 @@ fi
# Generate a list of directories we don't want to play in. # Generate a list of directories we don't want to play in.
DIRS_TO_AVOID=() DIRS_TO_AVOID=()
kube::util::read-array DIRS_TO_AVOID < <( kube::util::read-array DIRS_TO_AVOID < <(
git ls-files -cmo --exclude-standard -- ':!:vendor/*' ':(glob)*/**/go.work' \ git ls-files -cmo --exclude-standard \
-- \
':!:vendor/*' \
':(glob)*/**/go.work' \
':(glob)**/_codegenignore/**' \
| while read -r F; do \ | while read -r F; do \
echo ':!:'"$(dirname "${F}")"; \ echo ':!:'"$(dirname "${F}")"; \
done done
@ -62,7 +66,10 @@ function git_find() {
# Similar to find but faster and easier to understand. We want to include # Similar to find but faster and easier to understand. We want to include
# modified and untracked files because this might be running against code # modified and untracked files because this might be running against code
# which is not tracked by git yet. # which is not tracked by git yet.
git ls-files -cmo --exclude-standard ':!:vendor/*' "${DIRS_TO_AVOID[@]}" "$@" git ls-files -cmo --exclude-standard \
':!:vendor/*' \
"${DIRS_TO_AVOID[@]}" \
"$@"
} }
function git_grep() { function git_grep() {
@ -70,7 +77,9 @@ function git_grep() {
# running against code which is not tracked by git yet. # running against code which is not tracked by git yet.
# We need vendor exclusion added at the end since it has to be part of # We need vendor exclusion added at the end since it has to be part of
# the pathspecs which are specified last. # the pathspecs which are specified last.
git grep --untracked "$@" ':!:vendor/*' "${DIRS_TO_AVOID[@]}" git grep --untracked "$@" \
':!:vendor/*' \
"${DIRS_TO_AVOID[@]}"
} }
# Generate a list of all files that have a `+k8s:` comment-tag. This will be # Generate a list of all files that have a `+k8s:` comment-tag. This will be
@ -380,6 +389,74 @@ function codegen::defaults() {
fi fi
} }
# Validation generation
#
# Any package that wants validation functions generated must include a
# comment-tag in column 0 of one file of the form:
# // +k8s:validation-gen=<VALUE>
#
# The <VALUE> depends on context:
# on packages:
# *: all exported types are candidates for having validation generated
# FIELDNAME: any type with a field of this name is a candidate for
# having validation generated
# on types:
# true: always generate validation for this type
# false: never generate validation for this type
function codegen::validation() {
# Build the tool.
GOPROXY=off go install \
k8s.io/code-generator/cmd/validation-gen
# TODO: Where do we want these output? It should be somewhere internal..
# The result file, in each pkg, of validation generation.
local output_file="${GENERATED_FILE_PREFIX}validations.go"
# All directories that request any form of validation generation.
if [[ "${DBG_CODEGEN}" == 1 ]]; then
kube::log::status "DBG: finding all +k8s:validation-gen tags"
fi
local tag_dirs=()
kube::util::read-array tag_dirs < <( \
grep -l --null '+k8s:validation-gen=' "${ALL_K8S_TAG_FILES[@]}" \
| while read -r -d $'\0' F; do dirname "${F}"; done \
| sort -u)
if [[ "${DBG_CODEGEN}" == 1 ]]; then
kube::log::status "DBG: found ${#tag_dirs[@]} +k8s:validation-gen tagged dirs"
fi
local tag_pkgs=()
for dir in "${tag_dirs[@]}"; do
tag_pkgs+=("./$dir")
done
local extra_pkgs=(
k8s.io/apimachinery/pkg/apis/meta/v1
)
kube::log::status "Generating validation code for ${#tag_pkgs[@]} targets"
if [[ "${DBG_CODEGEN}" == 1 ]]; then
kube::log::status "DBG: running validation-gen for:"
for dir in "${tag_dirs[@]}"; do
kube::log::status "DBG: $dir"
done
fi
git_find -z ':(glob)**'/"${output_file}" | xargs -0 rm -f
validation-gen \
-v "${KUBE_VERBOSE}" \
--go-header-file "${BOILERPLATE_FILENAME}" \
--output-file "${output_file}" \
$(printf -- " --extra-pkg %s" "${extra_pkgs[@]}") \
"${tag_pkgs[@]}" \
"$@"
if [[ "${DBG_CODEGEN}" == 1 ]]; then
kube::log::status "Generated validation code"
fi
}
# Conversion generation # Conversion generation
# Any package that wants conversion functions generated into it must # Any package that wants conversion functions generated into it must

View File

@ -48,7 +48,7 @@ function kube::codegen::internal::grep() {
--exclude-dir vendor --exclude-dir vendor
} }
# Generate tagged helper code: conversions, deepcopy, and defaults # Generate tagged helper code: conversions, deepcopy, defaults and validations
# #
# USAGE: kube::codegen::gen_helpers [FLAGS] <input-dir> # USAGE: kube::codegen::gen_helpers [FLAGS] <input-dir>
# #
@ -111,6 +111,7 @@ function kube::codegen::gen_helpers() {
conversion-gen"${CODEGEN_VERSION_SPEC}" conversion-gen"${CODEGEN_VERSION_SPEC}"
deepcopy-gen"${CODEGEN_VERSION_SPEC}" deepcopy-gen"${CODEGEN_VERSION_SPEC}"
defaulter-gen"${CODEGEN_VERSION_SPEC}" defaulter-gen"${CODEGEN_VERSION_SPEC}"
validation-gen"${CODEGEN_VERSION_SPEC}"
) )
# shellcheck disable=2046 # printf word-splitting is intentional # shellcheck disable=2046 # printf word-splitting is intentional
GO111MODULE=on go install $(printf "k8s.io/code-generator/cmd/%s " "${BINS[@]}") GO111MODULE=on go install $(printf "k8s.io/code-generator/cmd/%s " "${BINS[@]}")
@ -150,6 +151,38 @@ function kube::codegen::gen_helpers() {
"${input_pkgs[@]}" "${input_pkgs[@]}"
fi fi
# Validations
#
local input_pkgs=()
while read -r dir; do
pkg="$(cd "${dir}" && GO111MODULE=on go list -find .)"
input_pkgs+=("${pkg}")
done < <(
( kube::codegen::internal::grep -l --null \
-e '^\s*//\s*+k8s:validation-gen=' \
-r "${in_dir}" \
--include '*.go' \
|| true \
) | while read -r -d $'\0' F; do dirname "${F}"; done \
| LC_ALL=C sort -u
)
if [ "${#input_pkgs[@]}" != 0 ]; then
echo "Generating validation code for ${#input_pkgs[@]} targets"
kube::codegen::internal::findz \
"${in_dir}" \
-type f \
-name zz_generated.validations.go \
| xargs -0 rm -f
"${gobin}/validation-gen" \
-v "${v}" \
--output-file zz_generated.validations.go \
--go-header-file "${boilerplate}" \
"${input_pkgs[@]}"
fi
# Defaults # Defaults
# #
local input_pkgs=() local input_pkgs=()