mirror of
https://github.com/hanzo-ml/kserve.git
synced 2026-10-30 20:53:49 +00:00
Signed-off-by: Jooho Lee <[email protected]> This PR is not about code changes, but rather a new release. It has been tested locally, and further validations will be carried out as part of the 0.18.0 release process. As such, it will be merged manually.
214 lines
7.2 KiB
Bash
Executable File
214 lines
7.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Validate all KServe release artifacts after publishing.
|
|
#
|
|
# Usage:
|
|
# ./hack/release/validate-release.sh <version> [--repo=<owner/repo>]
|
|
#
|
|
# Examples:
|
|
# ./hack/release/validate-release.sh v0.18.0-rc0
|
|
# ./hack/release/validate-release.sh v0.18.0-rc0 --repo=jooho/kserve
|
|
|
|
set -eo pipefail
|
|
|
|
RED='\033[31m'
|
|
GREEN='\033[32m'
|
|
YELLOW='\033[33m'
|
|
BLUE='\033[34m'
|
|
NC='\033[0m'
|
|
|
|
PASS=0
|
|
FAIL=0
|
|
|
|
usage() {
|
|
echo "Usage: $0 <version> [--repo=<owner/repo>]"
|
|
echo ""
|
|
echo "Arguments:"
|
|
echo " version Release version with 'v' prefix (e.g., v0.18.0-rc0)"
|
|
echo ""
|
|
echo "Options:"
|
|
echo " --repo=<owner/repo> Target repository (default: auto-detected)"
|
|
echo ""
|
|
echo "Examples:"
|
|
echo " $0 v0.18.0-rc0"
|
|
echo " $0 v0.18.0-rc0 --repo=jooho/kserve"
|
|
exit 1
|
|
}
|
|
|
|
check_pass() {
|
|
echo -e " ${GREEN}✓${NC} $1"
|
|
((PASS++)) || true
|
|
}
|
|
|
|
check_fail() {
|
|
echo -e " ${RED}✗${NC} $1"
|
|
if [[ -n "$2" ]]; then
|
|
echo -e " ${YELLOW}Fix:${NC} $2"
|
|
fi
|
|
((FAIL++)) || true
|
|
}
|
|
|
|
check_warn() {
|
|
echo -e " ${YELLOW}~${NC} $1"
|
|
}
|
|
|
|
# Parse arguments
|
|
VERSION=""
|
|
REPO_OVERRIDE=""
|
|
|
|
for arg in "$@"; do
|
|
case "$arg" in
|
|
--repo=*) REPO_OVERRIDE="${arg#--repo=}" ;;
|
|
--help|-h) usage ;;
|
|
v*) VERSION="$arg" ;;
|
|
*) echo -e "${RED}Unknown argument: $arg${NC}"; usage ;;
|
|
esac
|
|
done
|
|
|
|
if [[ -z "$VERSION" ]]; then
|
|
echo -e "${RED}Error: version is required${NC}"
|
|
usage
|
|
fi
|
|
|
|
if ! [[ "$VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-rc[0-9]+)?$ ]]; then
|
|
echo -e "${RED}Error: invalid version format: $VERSION${NC}"
|
|
exit 1
|
|
fi
|
|
|
|
# Resolve repo
|
|
if [[ -n "$REPO_OVERRIDE" ]]; then
|
|
REPO="$REPO_OVERRIDE"
|
|
else
|
|
REPO=$(gh repo view --json nameWithOwner --jq '.nameWithOwner' 2>/dev/null || echo "kserve/kserve")
|
|
fi
|
|
|
|
# Parse version components
|
|
VERSION_NO_V="${VERSION#v}"
|
|
BASE_VERSION=$(echo "$VERSION_NO_V" | sed 's/-rc[0-9]*$//')
|
|
MAJOR_MINOR=$(echo "$BASE_VERSION" | cut -d. -f1,2)
|
|
RC=$(echo "$VERSION_NO_V" | grep -o 'rc[0-9]*$' || echo "")
|
|
BRANCH="release-${MAJOR_MINOR}"
|
|
|
|
REGISTRY="docker.io/kserve"
|
|
IMAGES=(
|
|
"kserve-controller"
|
|
"agent"
|
|
"router"
|
|
"storage-initializer"
|
|
"sklearnserver"
|
|
"lgbserver"
|
|
"xgbserver"
|
|
"pmmlserver"
|
|
"huggingfaceserver"
|
|
"llmisvc-controller"
|
|
"kserve-localmodel-controller"
|
|
"kserve-localmodelnode-agent"
|
|
)
|
|
|
|
echo ""
|
|
echo -e "${BLUE}=================================================${NC}"
|
|
echo -e "${BLUE} KServe Release Validation: $VERSION${NC}"
|
|
echo -e "${BLUE} Repo: $REPO${NC}"
|
|
echo -e "${BLUE}=================================================${NC}"
|
|
|
|
# ── 1. Install files ──────────────────────────────────────────
|
|
echo ""
|
|
echo -e "${YELLOW}[1/6] Install files...${NC}"
|
|
INSTALL_DIR="install/${VERSION}"
|
|
if [[ -d "$INSTALL_DIR" ]]; then
|
|
FILE_COUNT=$(find "$INSTALL_DIR" -type f | wc -l)
|
|
if [[ "$FILE_COUNT" -gt 0 ]]; then
|
|
check_pass "install/${VERSION}/ exists ($FILE_COUNT files)"
|
|
else
|
|
check_fail "install/${VERSION}/ is empty" "Run 'make bump-version' and 'generate-install.sh'"
|
|
fi
|
|
else
|
|
check_fail "install/${VERSION}/ not found" "Run 'make bump-version' and 'generate-install.sh'"
|
|
fi
|
|
|
|
# ── 2. Branch ─────────────────────────────────────────────────
|
|
echo ""
|
|
echo -e "${YELLOW}[2/6] Git branch...${NC}"
|
|
if gh api "repos/${REPO}/branches/${BRANCH}" >/dev/null 2>&1; then
|
|
check_pass "Branch ${BRANCH} exists"
|
|
else
|
|
if [[ "$RC" == "rc0" || -z "$RC" ]]; then
|
|
check_fail "Branch ${BRANCH} not found" "Re-run 'Prepare Release (Branch & Tag)' workflow"
|
|
else
|
|
check_warn "Branch ${BRANCH} not found (expected for RC0 only)"
|
|
fi
|
|
fi
|
|
|
|
# ── 3. Tag ────────────────────────────────────────────────────
|
|
echo ""
|
|
echo -e "${YELLOW}[3/6] Git tag...${NC}"
|
|
if gh api "repos/${REPO}/git/ref/tags/${VERSION}" >/dev/null 2>&1; then
|
|
check_pass "Tag ${VERSION} exists"
|
|
else
|
|
check_fail "Tag ${VERSION} not found" "Re-run 'Prepare Release (Branch & Tag)' workflow"
|
|
fi
|
|
|
|
# ── 4. GitHub Release ─────────────────────────────────────────
|
|
echo ""
|
|
echo -e "${YELLOW}[4/6] GitHub Release...${NC}"
|
|
IS_DRAFT=$(gh release view "${VERSION}" --repo "${REPO}" --json isDraft --jq '.isDraft' 2>/dev/null || echo "")
|
|
IS_PRERELEASE=$(gh release view "${VERSION}" --repo "${REPO}" --json isPrerelease --jq '.isPrerelease' 2>/dev/null || echo "")
|
|
RELEASE_URL=$(gh release view "${VERSION}" --repo "${REPO}" --json url --jq '.url' 2>/dev/null || echo "")
|
|
|
|
if [[ -z "$IS_DRAFT" ]]; then
|
|
check_fail "GitHub Release ${VERSION} not found" "Run publish-release.sh"
|
|
else
|
|
if [[ "$IS_DRAFT" == "true" ]]; then
|
|
check_fail "GitHub Release is still a draft" "gh release edit ${VERSION} --repo=${REPO} --draft=false"
|
|
else
|
|
check_pass "GitHub Release published: $RELEASE_URL"
|
|
fi
|
|
|
|
if [[ -n "$RC" && "$IS_PRERELEASE" != "true" ]]; then
|
|
check_fail "RC release should be marked as pre-release" "gh release edit ${VERSION} --repo=${REPO} --prerelease"
|
|
elif [[ -z "$RC" && "$IS_PRERELEASE" == "true" ]]; then
|
|
check_fail "Final release should NOT be marked as pre-release" "gh release edit ${VERSION} --repo=${REPO} --latest"
|
|
else
|
|
check_pass "Pre-release flag correct (isPrerelease=${IS_PRERELEASE})"
|
|
fi
|
|
fi
|
|
|
|
# ── 5. PyPI packages ──────────────────────────────────────────
|
|
echo ""
|
|
echo -e "${YELLOW}[5/6] PyPI packages...${NC}"
|
|
PYPI_VERSION="${VERSION_NO_V}"
|
|
for pkg in kserve kserve-storage; do
|
|
if curl -sf "https://pypi.org/pypi/${pkg}/${PYPI_VERSION}/json" >/dev/null 2>&1; then
|
|
check_pass "PyPI: ${pkg}==${PYPI_VERSION}"
|
|
else
|
|
check_fail "PyPI: ${pkg}==${PYPI_VERSION} not found" "Check 'Upload Python Package' workflow"
|
|
fi
|
|
done
|
|
|
|
# ── 6. Container images ───────────────────────────────────────
|
|
echo ""
|
|
echo -e "${YELLOW}[6/6] Container images...${NC}"
|
|
for image in "${IMAGES[@]}"; do
|
|
IMAGE_REF="${REGISTRY}/${image}:${VERSION}"
|
|
if docker manifest inspect "${IMAGE_REF}" >/dev/null 2>&1; then
|
|
check_pass "Image: ${IMAGE_REF}"
|
|
else
|
|
check_fail "Image: ${IMAGE_REF} not found" "Check Docker Publisher workflows"
|
|
fi
|
|
done
|
|
|
|
# ── Summary ───────────────────────────────────────────────────
|
|
echo ""
|
|
echo -e "${BLUE}=================================================${NC}"
|
|
TOTAL=$((PASS + FAIL))
|
|
if [[ "$FAIL" -eq 0 ]]; then
|
|
echo -e "${GREEN} All checks passed ($PASS/$TOTAL)${NC}"
|
|
echo -e "${GREEN} Release ${VERSION} is fully validated!${NC}"
|
|
else
|
|
echo -e "${RED} $FAIL check(s) failed out of $TOTAL${NC}"
|
|
echo -e "${YELLOW} Fix the issues above and re-run this script.${NC}"
|
|
fi
|
|
echo -e "${BLUE}=================================================${NC}"
|
|
echo ""
|
|
|
|
[[ "$FAIL" -eq 0 ]]
|