Implement validation-gen lint for CI

Results in errors like:

```
$ ./hack/verify-api-lint.sh
+++ [0317 09:00:04] Generating validation code for 69 targets
F0317 09:00:05.637556 1049736 targets.go:363] lint failed:
  type k8s.io/api/core/v1.PodAffinityTerm:
    field LabelSelector: conflicting tags: {+k8s:optional, +k8s:required}: fields cannot be both optional and required
    field Namespaces: conflicting tags: {+default, +k8s:required}: fields with default values are always optional
!!! [0317 09:00:05] Call tree:
!!! [0317 09:00:05]  1: hack/update-codegen.sh:1132 codegen::validation(...)
```
This commit is contained in:
Tim Hockin
2024-12-28 17:46:20 -08:00
parent 1a694bfd32
commit 252d584cb7
2 changed files with 150 additions and 16 deletions

View File

@@ -108,6 +108,13 @@ fi
# Some of the later codegens depend on the results of this, so it needs to come
# first in the case of regenerating everything.
function codegen::protobuf() {
if [[ -n "${LINT:-}" ]]; then
if [[ "${KUBE_VERBOSE}" -gt 2 ]]; then
kube::log::status "No linter for protobuf codegen"
fi
return
fi
# NOTE: All output from this script needs to be copied back to the calling
# source tree. This is managed in kube::build::copy_output in build/common.sh.
# If the output set is changed update that function.
@@ -122,7 +129,7 @@ function codegen::protobuf() {
| sed 's|^|k8s.io/kubernetes/|;s|k8s.io/kubernetes/staging/src/||' \
| sort -u)
kube::log::status "Generating protobufs for ${#apis[@]} targets"
kube::log::status "protobufs: ${#apis[@]} targets"
if [[ "${DBG_CODEGEN}" == 1 ]]; then
kube::log::status "DBG: generating protobufs for:"
for dir in "${apis[@]}"; do
@@ -154,6 +161,13 @@ function codegen::protobuf() {
# register: generate deep-copy functions and register them with a
# scheme
function codegen::deepcopy() {
if [[ -n "${LINT:-}" ]]; then
if [[ "${KUBE_VERBOSE}" -gt 2 ]]; then
kube::log::status "No linter for deepcopy codegen"
fi
return
fi
# Build the tool.
GOPROXY=off go install \
k8s.io/code-generator/cmd/deepcopy-gen
@@ -179,7 +193,7 @@ function codegen::deepcopy() {
tag_pkgs+=("./$dir")
done
kube::log::status "Generating deepcopy code for ${#tag_pkgs[@]} targets"
kube::log::status "deepcopy: ${#tag_pkgs[@]} targets"
if [[ "${DBG_CODEGEN}" == 1 ]]; then
kube::log::status "DBG: running deepcopy-gen for:"
for dir in "${tag_dirs[@]}"; do
@@ -255,6 +269,13 @@ EOF
# Some of the later codegens depend on the results of this, so it needs to come
# first in the case of regenerating everything.
function codegen::swagger() {
if [[ -n "${LINT:-}" ]]; then
if [[ "${KUBE_VERBOSE}" -gt 2 ]]; then
kube::log::status "No linter for swagger codegen"
fi
return
fi
# Build the tool
GOPROXY=off go install \
./cmd/genswaggertypedocs
@@ -262,7 +283,7 @@ function codegen::swagger() {
local group_versions=()
IFS=" " read -r -a group_versions <<< "meta/v1 meta/v1beta1 ${KUBE_AVAILABLE_GROUP_VERSIONS}"
kube::log::status "Generating swagger for ${#group_versions[@]} targets"
kube::log::status "swagger: ${#group_versions[@]} targets"
git_find -z ':(glob)**/types_swagger_doc_generated.go' | xargs -0 rm -f
@@ -278,6 +299,13 @@ function codegen::swagger() {
# comment-tag in column 0 of one file of the form:
# // +k8s:prerelease-lifecycle-gen=true
function codegen::prerelease() {
if [[ -n "${LINT:-}" ]]; then
if [[ "${KUBE_VERBOSE}" -gt 2 ]]; then
kube::log::status "No linter for prerelease codegen"
fi
return
fi
# Build the tool.
GOPROXY=off go install \
k8s.io/code-generator/cmd/prerelease-lifecycle-gen
@@ -303,7 +331,7 @@ function codegen::prerelease() {
tag_pkgs+=("./$dir")
done
kube::log::status "Generating prerelease-lifecycle code for ${#tag_pkgs[@]} targets"
kube::log::status "prerelease-lifecycle: ${#tag_pkgs[@]} targets"
if [[ "${DBG_CODEGEN}" == 1 ]]; then
kube::log::status "DBG: running prerelease-lifecycle-gen for:"
for dir in "${tag_dirs[@]}"; do
@@ -342,6 +370,13 @@ function codegen::prerelease() {
# FIELDNAME: any object with a field of this name is a candidate
# for having a defaulter generated
function codegen::defaults() {
if [[ -n "${LINT:-}" ]]; then
if [[ "${KUBE_VERBOSE}" -gt 2 ]]; then
kube::log::status "No linter for defaults codegen"
fi
return
fi
# Build the tool.
GOPROXY=off go install \
k8s.io/code-generator/cmd/defaulter-gen
@@ -367,7 +402,7 @@ function codegen::defaults() {
tag_pkgs+=("./$dir")
done
kube::log::status "Generating defaulter code for ${#tag_pkgs[@]} targets"
kube::log::status "defaults: ${#tag_pkgs[@]} targets"
if [[ "${DBG_CODEGEN}" == 1 ]]; then
kube::log::status "DBG: running defaulter-gen for:"
for dir in "${tag_dirs[@]}"; do
@@ -443,7 +478,7 @@ function codegen::validation() {
time
)
kube::log::status "Generating validation code for ${#tag_pkgs[@]} targets"
kube::log::status "validation: ${#tag_pkgs[@]} targets"
if [[ "${DBG_CODEGEN}" == 1 ]]; then
kube::log::status "DBG: running validation-gen for:"
for dir in "${tag_dirs[@]}"; do
@@ -451,13 +486,19 @@ function codegen::validation() {
done
fi
git_find -z ':(glob)**'/"${output_file}" | xargs -0 rm -f
local lint_flag=() # empty arrays expand to no-value (as opposed to "")
if [[ -n "${LINT:-}" ]]; then
lint_flag+=("--lint")
else
git_find -z ':(glob)**'/"${output_file}" | xargs -0 rm -f
fi
validation-gen \
-v "${KUBE_VERBOSE}" \
--go-header-file "${BOILERPLATE_FILENAME}" \
--output-file "${output_file}" \
$(printf -- " --readonly-pkg %s" "${readonly_pkgs[@]}") \
"${lint_flag[@]}" `# may expand to nothing` \
"${tag_pkgs[@]}" \
"$@"
@@ -488,6 +529,13 @@ function codegen::validation() {
# TODO: it might be better in the long term to make peer-types explicit in the
# IDL.
function codegen::conversions() {
if [[ -n "${LINT:-}" ]]; then
if [[ "${KUBE_VERBOSE}" -gt 2 ]]; then
kube::log::status "No linter for conversions codegen"
fi
return
fi
# Build the tool.
GOPROXY=off go install \
k8s.io/code-generator/cmd/conversion-gen
@@ -519,7 +567,7 @@ function codegen::conversions() {
k8s.io/api/core/v1
)
kube::log::status "Generating conversion code for ${#tag_pkgs[@]} targets"
kube::log::status "conversion: ${#tag_pkgs[@]} targets"
if [[ "${DBG_CODEGEN}" == 1 ]]; then
kube::log::status "DBG: running conversion-gen for:"
for dir in "${tag_dirs[@]}"; do
@@ -549,6 +597,13 @@ function codegen::conversions() {
# // +k8s:register-gen=package
#
function codegen::register() {
if [[ -n "${LINT:-}" ]]; then
if [[ "${KUBE_VERBOSE}" -gt 2 ]]; then
kube::log::status "No linter for register codegen"
fi
return
fi
# Build the tool.
GOPROXY=off go install \
k8s.io/code-generator/cmd/register-gen
@@ -574,7 +629,7 @@ function codegen::register() {
tag_pkgs+=("./$dir")
done
kube::log::status "Generating register code for ${#tag_pkgs[@]} targets"
kube::log::status "register: ${#tag_pkgs[@]} targets"
if [[ "${DBG_CODEGEN}" == 1 ]]; then
kube::log::status "DBG: running register-gen for:"
for dir in "${tag_dirs[@]}"; do
@@ -620,6 +675,13 @@ function k8s_tag_files_except() {
# comment-tag in column 0 of one file of the form:
# // +k8s:openapi-gen=true
function codegen::openapi() {
if [[ -n "${LINT:-}" ]]; then
if [[ "${KUBE_VERBOSE}" -gt 2 ]]; then
kube::log::status "No linter for openapi codegen"
fi
return
fi
# Build the tool.
GOPROXY=off go install \
k8s.io/kube-openapi/cmd/openapi-gen
@@ -664,7 +726,7 @@ function codegen::openapi() {
tag_pkgs+=("./$dir")
done
kube::log::status "Generating openapi code"
kube::log::status "openapi: ${#tag_pkgs[@]} targets"
if [[ "${DBG_CODEGEN}" == 1 ]]; then
kube::log::status "DBG: running openapi-gen for:"
for dir in "${tag_dirs[@]}"; do
@@ -698,6 +760,13 @@ function codegen::openapi() {
}
function codegen::applyconfigs() {
if [[ -n "${LINT:-}" ]]; then
if [[ "${KUBE_VERBOSE}" -gt 2 ]]; then
kube::log::status "No linter for applyconfigs codegen"
fi
return
fi
GOPROXY=off go install \
k8s.io/kubernetes/pkg/generated/openapi/cmd/models-schema \
k8s.io/code-generator/cmd/applyconfiguration-gen
@@ -710,7 +779,7 @@ function codegen::applyconfigs() {
| sort -u)
ext_apis+=("k8s.io/apimachinery/pkg/apis/meta/v1")
kube::log::status "Generating apply-config code for ${#ext_apis[@]} targets"
kube::log::status "apply-config: ${#ext_apis[@]} targets"
if [[ "${DBG_CODEGEN}" == 1 ]]; then
kube::log::status "DBG: running applyconfiguration-gen for:"
for api in "${ext_apis[@]}"; do
@@ -740,6 +809,13 @@ function codegen::applyconfigs() {
}
function codegen::clients() {
if [[ -n "${LINT:-}" ]]; then
if [[ "${KUBE_VERBOSE}" -gt 2 ]]; then
kube::log::status "No linter for clients codegen"
fi
return
fi
GOPROXY=off go install \
k8s.io/code-generator/cmd/client-gen
@@ -761,7 +837,7 @@ function codegen::clients() {
gv_dirs+=("${pkg_dir}")
done
kube::log::status "Generating client code for ${#gv_dirs[@]} targets"
kube::log::status "clients: ${#gv_dirs[@]} targets"
if [[ "${DBG_CODEGEN}" == 1 ]]; then
kube::log::status "DBG: running client-gen for:"
for dir in "${gv_dirs[@]}"; do
@@ -795,6 +871,13 @@ function codegen::clients() {
}
function codegen::listers() {
if [[ -n "${LINT:-}" ]]; then
if [[ "${KUBE_VERBOSE}" -gt 2 ]]; then
kube::log::status "No linter for listers codegen"
fi
return
fi
GOPROXY=off go install \
k8s.io/code-generator/cmd/lister-gen
@@ -805,7 +888,7 @@ function codegen::listers() {
| while read -r -d $'\0' F; do dirname "${F}"; done \
| sort -u)
kube::log::status "Generating lister code for ${#ext_apis[@]} targets"
kube::log::status "listers: ${#ext_apis[@]} targets"
if [[ "${DBG_CODEGEN}" == 1 ]]; then
kube::log::status "DBG: running lister-gen for:"
for api in "${ext_apis[@]}"; do
@@ -835,6 +918,13 @@ function codegen::listers() {
}
function codegen::informers() {
if [[ -n "${LINT:-}" ]]; then
if [[ "${KUBE_VERBOSE}" -gt 2 ]]; then
kube::log::status "No linter for informers codegen"
fi
return
fi
GOPROXY=off go install \
k8s.io/code-generator/cmd/informer-gen
@@ -845,7 +935,7 @@ function codegen::informers() {
| while read -r -d $'\0' F; do dirname "${F}"; done \
| sort -u)
kube::log::status "Generating informer code for ${#ext_apis[@]} targets"
kube::log::status "informers: code for ${#ext_apis[@]} targets"
if [[ "${DBG_CODEGEN}" == 1 ]]; then
kube::log::status "DBG: running informer-gen for:"
for api in "${ext_apis[@]}"; do
@@ -884,6 +974,13 @@ function indent() {
}
function codegen::subprojects() {
if [[ -n "${LINT:-}" ]]; then
if [[ "${KUBE_VERBOSE}" -gt 2 ]]; then
kube::log::status "No linter for subprojects codegen"
fi
return
fi
# Call generation on sub-projects.
local subs=(
staging/src/k8s.io/code-generator/examples
@@ -898,7 +995,7 @@ function codegen::subprojects() {
local codegen
codegen="${KUBE_ROOT}/staging/src/k8s.io/code-generator"
for sub in "${subs[@]}"; do
kube::log::status "Generating code for subproject ${sub}"
kube::log::status "subproject ${sub}:"
pushd "${sub}" >/dev/null
CODEGEN_PKG="${codegen}" \
UPDATE_API_KNOWN_VIOLATIONS="${UPDATE_API_KNOWN_VIOLATIONS}" \
@@ -909,6 +1006,13 @@ function codegen::subprojects() {
}
function codegen::protobindings() {
if [[ -n "${LINT:-}" ]]; then
if [[ "${KUBE_VERBOSE}" -gt 2 ]]; then
kube::log::status "No linter for protobindings codegen"
fi
return
fi
# Each element of this array is a directory containing subdirectories which
# eventually contain a file named "api.proto".
local apis=(
@@ -929,7 +1033,7 @@ function codegen::protobindings() {
"staging/src/k8s.io/externaljwt/apis"
)
kube::log::status "Generating protobuf bindings for ${#apis[@]} targets"
kube::log::status "protobuf bindings: ${#apis[@]} targets"
if [[ "${DBG_CODEGEN}" == 1 ]]; then
kube::log::status "DBG: generating protobuf bindings for:"
for dir in "${apis[@]}"; do

30
hack/verify-api-lint.sh Executable file
View File

@@ -0,0 +1,30 @@
#!/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 runs API lint tools.
#
# Usage: `hack/verify-api-lint.sh`.
set -o errexit
set -o nounset
set -o pipefail
KUBE_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
source "${KUBE_ROOT}/hack/lib/init.sh"
cd "${KUBE_ROOT}"
LINT=true hack/update-codegen.sh