#!/bin/bash # PR构建专用:只构建不推送,只读缓存不写,用于PR阶段验证Dockerfile set -eu NO_CACHE_FLAG="" if [ "$1" = "--no-cache" ]; then NO_CACHE_FLAG="--no-cache" shift fi DOCKERFILE="$1" IMAGE_TAG="$2" CACHE_REF="$3" shift 3 BUILD_ARGS="" for arg in "$@"; do BUILD_ARGS="$BUILD_ARGS --build-arg $arg" done BUILDER_NAME="ci-pr-builder-${GITHUB_RUN_ID:-local}" if ! docker buildx inspect "$BUILDER_NAME" > /dev/null 2>&1; then docker buildx create --use --name "$BUILDER_NAME" --driver docker-container else docker buildx use "$BUILDER_NAME" fi docker buildx inspect --bootstrap CACHE_NAME=$(echo "$CACHE_REF" | tr "/" "_" | tr ":" "-") LOCAL_CACHE_DIR="/tmp/buildx-cache/${CACHE_NAME}" mkdir -p "$LOCAL_CACHE_DIR" echo "=== PR Build: build only, no push, read-only cache ===" echo "Dockerfile: ${DOCKERFILE}" echo "Image tag: ${IMAGE_TAG}" echo "" build_with_retry() { local attempt=1 local max_attempts=2 while [ $attempt -le $max_attempts ]; do local build_output local exit_code set +e build_output=$(docker buildx build \ $NO_CACHE_FLAG \ $BUILD_ARGS \ --cache-from "type=local,src=${LOCAL_CACHE_DIR}" \ --cache-from "type=registry,ref=${CACHE_REF}" \ -f "${DOCKERFILE}" \ -t "${IMAGE_TAG}" \ --load \ . 2>&1) exit_code=$? set -e if [ $exit_code -eq 0 ]; then echo "$build_output" return 0 fi if echo "$build_output" | grep -qE "parent snapshot.*not found|snapshot.*does not exist|cache.*corrupt|failed to compute cache key"; then echo "$build_output" echo "Local cache corrupted, cleaning and retrying ($attempt/$max_attempts)..." rm -rf "${LOCAL_CACHE_DIR}" mkdir -p "${LOCAL_CACHE_DIR}" docker buildx prune -f -a >/dev/null 2>&1 || true attempt=$((attempt + 1)) else echo "$build_output" return $exit_code fi done echo "Local cache failed, building with registry cache only..." docker buildx build \ $NO_CACHE_FLAG \ $BUILD_ARGS \ --cache-from "type=registry,ref=${CACHE_REF}" \ -f "${DOCKERFILE}" \ -t "${IMAGE_TAG}" \ --load \ . } build_with_retry echo "" echo "PR build OK (not pushed): ${IMAGE_TAG}"