Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f9dda3d617 | |||
| 83a3d072fc | |||
| 7f8193fbc6 | |||
| d3ed0bb4ba | |||
| 99fa146a5c |
+80
-58
@@ -146,7 +146,7 @@ jobs:
|
||||
shell: sh
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
run: "set -eu\nif command -v git >/dev/null 2>&1; then\n if [ ! -d .git ]; then\n git init -q\n git config user.email \"ci@localhost\"\n git config user.name \"CI\"\n git add .\n git commit -q -m \"current\"\n REPO_URL=\"https://x-access-token:${GITHUB_TOKEN}@${GITHUB_SERVER_URL#https://}/${GITHUB_REPOSITORY}.git\"\n git remote add origin \"$REPO_URL\"\n fi\n git fetch origin main --depth=1 -q 2>/dev/null || echo \"WARN: cannot fetch main, will check all migrations\"\nelse\n echo \"WARN: git not available, will check all migrations\"\nfi\n"
|
||||
run: "set +e\nif command -v git >/dev/null 2>&1; then\n if [ ! -d .git ]; then\n git init -q\n git config user.email \"ci@localhost\"\n git config user.name \"CI\"\n git add .\n git commit -q -m \"current\"\n REPO_URL=\"https://x-access-token:${GITHUB_TOKEN}@${GITHUB_SERVER_URL#https://}/${GITHUB_REPOSITORY}.git\"\n git remote add origin \"$REPO_URL\"\n fi\n git fetch origin main --depth=1 -q 2>/dev/null || echo \"WARN: cannot fetch main, will check all migrations\"\nelse\n echo \"WARN: git not available, will check all migrations\"\nfi\nexit 0\n"
|
||||
- name: Check migration safety
|
||||
shell: sh
|
||||
run: "set -eu\nif git rev-parse origin/main >/dev/null 2>&1; then\n python3 scripts/check_migration_safety.py --allow-medium-risk --diff-against origin/main\nelse\n python3 scripts/check_migration_safety.py --allow-medium-risk\nfi\n"
|
||||
@@ -375,7 +375,7 @@ jobs:
|
||||
'
|
||||
- name: Install dependencies
|
||||
shell: sh
|
||||
run: "set -eu\nNPM_CACHE_VOLUME=\"xiaoxia-npm-cache\"\nif ! docker volume inspect \"$NPM_CACHE_VOLUME\" >/dev/null 2>&1; then\n docker volume create \"$NPM_CACHE_VOLUME\" >/dev/null\n echo \"Created npm cache volume: $NPM_CACHE_VOLUME\"\nfi\n\ndocker run --rm \\\n -v \"$PWD:/workspace\" \\\n -v \"$NPM_CACHE_VOLUME:/workspace/apps/web/node_modules\" -w /workspace/apps/web \\\n docker.m.daocloud.io/library/node:20 \\\n sh -lc 'PACKAGE_LOCK_HASH=$(md5sum package-lock.json 2>/dev/null | cut -d\" \" -f1)\nCACHE_HASH_FILE=\"node_modules/.package-lock-hash\"\nCACHE_VALID=false\nif [ -f \"$CACHE_HASH_FILE\" ] && [ \"$(cat \"$CACHE_HASH_FILE\")\" = \"$PACKAGE_LOCK_HASH\" ] && [ -x \"node_modules/.bin/eslint\" ]; then\n CACHE_VALID=true\n echo \"Cache hit: dependencies valid, skipping npm ci\"\nfi\nif [ \"$CACHE_VALID\" = \"false\" ]; then\n echo \"Cache miss or invalid: running npm ci...\"\n if ! npm ci --include=dev; then\n echo \"npm ci failed, cleaning node_modules and retrying...\"\n rm -rf node_modules\n mkdir -p node_modules\n npm ci --include=dev\n fi\n echo \"$PACKAGE_LOCK_HASH\" > \"$CACHE_HASH_FILE\"\n echo \"Dependencies installed, cache updated\"\nfi'\n"
|
||||
run: "set -eu\nNPM_CACHE_VOLUME=\"xiaoxia-npm-cache\"\nif ! docker volume inspect \"$NPM_CACHE_VOLUME\" >/dev/null 2>&1; then\n docker volume create \"$NPM_CACHE_VOLUME\" >/dev/null\n echo \"Created npm cache volume: $NPM_CACHE_VOLUME\"\nfi\n\ndocker run --rm \\\n -v \"$PWD:/workspace\" \\\n -v \"$NPM_CACHE_VOLUME:/workspace/apps/web/node_modules\" -w /workspace/apps/web \\\n docker.m.daocloud.io/library/node:20 \\\n sh -lc 'PACKAGE_LOCK_HASH=$(md5sum package-lock.json 2>/dev/null | cut -d\" \" -f1)\nCACHE_HASH_FILE=\"node_modules/.package-lock-hash\"\nCACHE_VALID=false\nif [ -f \"$CACHE_HASH_FILE\" ] && [ \"$(cat \"$CACHE_HASH_FILE\")\" = \"$PACKAGE_LOCK_HASH\" ] && [ -x \"node_modules/.bin/eslint\" ] && [ -x \"node_modules/.bin/tsc\" ] && [ -x \"node_modules/.bin/prettier\" ] && [ -x \"node_modules/.bin/vitest\" ]; then\n CACHE_VALID=true\n echo \"Cache hit: dependencies valid, skipping npm ci\"\nfi\nif [ \"$CACHE_VALID\" = \"false\" ]; then\n echo \"Cache miss or invalid: running npm ci...\"\n if ! npm ci --include=dev; then\n echo \"npm ci failed, cleaning node_modules and retrying...\"\n rm -rf node_modules\n mkdir -p node_modules\n npm ci --include=dev\n fi\n # Post-install integrity check: verify all critical tools exist\n if [ ! -x \"node_modules/.bin/eslint\" ] || [ ! -x \"node_modules/.bin/tsc\" ] || [ ! -x \"node_modules/.bin/prettier\" ] || [ ! -x \"node_modules/.bin/vitest\" ]; then\n echo \"Post-install check failed: critical binaries missing, cleaning and retrying...\"\n rm -rf node_modules\n mkdir -p node_modules\n npm ci --include=dev\n fi\n echo \"$PACKAGE_LOCK_HASH\" > \"$CACHE_HASH_FILE\"\n echo \"Dependencies installed, cache updated\"\nfi'\n"
|
||||
- name: Run ESLint
|
||||
shell: sh
|
||||
run: "set -eu\nNPM_CACHE_VOLUME=\"xiaoxia-npm-cache\"\nif ! docker volume inspect \"$NPM_CACHE_VOLUME\" >/dev/null 2>&1; then\n docker volume create \"$NPM_CACHE_VOLUME\" >/dev/null\n echo \"Created npm cache volume: $NPM_CACHE_VOLUME\"\nfi\n\ndocker run --rm \\\n -v \"$PWD:/workspace\" \\\n -v \"$NPM_CACHE_VOLUME:/workspace/apps/web/node_modules\" -w /workspace/apps/web \\\n docker.m.daocloud.io/library/node:20 \\\n sh -lc 'npx --no-install eslint src --ext .ts,.tsx --max-warnings 50'\n"
|
||||
@@ -448,8 +448,20 @@ jobs:
|
||||
run: "set -eu\n# 确保使用 docker-container driver 以支持 cache export 功能\nif ! docker buildx inspect ci-builder > /dev/null 2>&1; then\n docker buildx create --use --name ci-builder --driver docker-container\n echo \"Created ci-builder (docker-container driver)\"\nelse\n docker buildx use ci-builder\n echo \"Using existing ci-builder\"\nfi\ndocker buildx inspect --bootstrap\n"
|
||||
- name: Build and push API image (buildx cache)
|
||||
shell: sh
|
||||
run: "set -eu\nREGISTRY=\"git.xiaoxiajianji.com/xiaoxia/xiaoxia-saas\"\nIMAGE_NAME=\"xiaoxia-saas-api\"\nCACHE_REF=\"${REGISTRY}/api-cache:develop\"\n\nCACHE_FROM=\"type=registry,ref=${CACHE_REF},ignore-error=true\"\n\nif [ \"${CACHE_MODE}\" = \"read-write\" ]; then\n CACHE_TO=\"type=registry,ref=${CACHE_REF},mode=max\"\n echo \"Building API image with read-write cache...\"\n docker buildx build --build-arg APP_VERSION=\"${GITHUB_SHA}\" --cache-from \"${CACHE_FROM}\" --cache-to \"${CACHE_TO}\" -f infra/docker/api.Dockerfile -t \"${REGISTRY}/${IMAGE_NAME}:${GITHUB_SHA}\" --push .\nelse\n echo \"Building API image with read-only cache...\"\n docker buildx build --build-arg APP_VERSION=\"${GITHUB_SHA}\" --cache-from \"${CACHE_FROM}\" -f infra/docker/api.Dockerfile -t \"${REGISTRY}/${IMAGE_NAME}:${GITHUB_SHA}\" --push .\nfi\necho\
|
||||
\ \"API image pushed: ${REGISTRY}/${IMAGE_NAME}:${GITHUB_SHA}\"\n"
|
||||
run: "set -eu
|
||||
REGISTRY=\"git.xiaoxiajianji.com/xiaoxia/xiaoxia-saas\"
|
||||
IMAGE_TAG=\"${REGISTRY}/xiaoxia-saas-api:${GITHUB_SHA}\"
|
||||
CACHE_REF=\"${REGISTRY}/api-cache:${GITHUB_REF_NAME}\"
|
||||
|
||||
bash scripts/ci/docker_build_push.sh \
|
||||
infra/docker/api.Dockerfile \
|
||||
\"${IMAGE_TAG}\" \
|
||||
\"${CACHE_REF}\" \
|
||||
APP_VERSION=\"${GITHUB_SHA}\"
|
||||
|
||||
echo
|
||||
echo \"API image pushed: ${IMAGE_TAG}\"
|
||||
"
|
||||
- name: Job duration summary
|
||||
if: always()
|
||||
shell: sh
|
||||
@@ -510,8 +522,20 @@ jobs:
|
||||
run: "set -eu\n# 确保使用 docker-container driver 以支持 cache export 功能\nif ! docker buildx inspect ci-builder > /dev/null 2>&1; then\n docker buildx create --use --name ci-builder --driver docker-container\n echo \"Created ci-builder (docker-container driver)\"\nelse\n docker buildx use ci-builder\n echo \"Using existing ci-builder\"\nfi\ndocker buildx inspect --bootstrap\n"
|
||||
- name: Build and push Worker image (buildx cache)
|
||||
shell: sh
|
||||
run: "set -eu\nREGISTRY=\"git.xiaoxiajianji.com/xiaoxia/xiaoxia-saas\"\nIMAGE_NAME=\"xiaoxia-saas-worker\"\nCACHE_REF=\"${REGISTRY}/worker-cache:develop\"\n\nCACHE_FROM=\"type=registry,ref=${CACHE_REF},ignore-error=true\"\n\nif [ \"${CACHE_MODE}\" = \"read-write\" ]; then\n CACHE_TO=\"type=registry,ref=${CACHE_REF},mode=min\"\n echo \"Building Worker image with read-write cache...\"\n docker buildx build --build-arg APP_VERSION=\"${GITHUB_SHA}\" --cache-from \"${CACHE_FROM}\" --cache-to \"${CACHE_TO}\" -f infra/docker/worker.Dockerfile -t \"${REGISTRY}/${IMAGE_NAME}:${GITHUB_SHA}\" --push .\nelse\n echo \"Building Worker image with read-only cache...\"\n docker buildx build --build-arg APP_VERSION=\"${GITHUB_SHA}\" --cache-from \"${CACHE_FROM}\" -f infra/docker/worker.Dockerfile -t \"${REGISTRY}/${IMAGE_NAME}:${GITHUB_SHA}\" --push \
|
||||
\ .\nfi\necho \"Worker image pushed: ${REGISTRY}/${IMAGE_NAME}:${GITHUB_SHA}\"\n"
|
||||
run: "set -eu
|
||||
REGISTRY=\"git.xiaoxiajianji.com/xiaoxia/xiaoxia-saas\"
|
||||
IMAGE_TAG=\"${REGISTRY}/xiaoxia-saas-worker:${GITHUB_SHA}\"
|
||||
CACHE_REF=\"${REGISTRY}/worker-cache:${GITHUB_REF_NAME}\"
|
||||
|
||||
bash scripts/ci/docker_build_push.sh \
|
||||
infra/docker/worker.Dockerfile \
|
||||
\"${IMAGE_TAG}\" \
|
||||
\"${CACHE_REF}\" \
|
||||
APP_VERSION=\"${GITHUB_SHA}\"
|
||||
|
||||
echo
|
||||
echo \"WORKER image pushed: ${IMAGE_TAG}\"
|
||||
"
|
||||
- name: Job duration summary
|
||||
if: always()
|
||||
shell: sh
|
||||
@@ -575,8 +599,20 @@ jobs:
|
||||
run: "set -eu\n# 确保使用 docker-container driver 以支持 cache export 功能\nif ! docker buildx inspect ci-builder > /dev/null 2>&1; then\n docker buildx create --use --name ci-builder --driver docker-container\n echo \"Created ci-builder (docker-container driver)\"\nelse\n docker buildx use ci-builder\n echo \"Using existing ci-builder\"\nfi\ndocker buildx inspect --bootstrap\n"
|
||||
- name: Build and push Web image (buildx cache)
|
||||
shell: sh
|
||||
run: "set -eu\nREGISTRY=\"git.xiaoxiajianji.com/xiaoxia/xiaoxia-saas\"\nIMAGE_NAME=\"xiaoxia-saas-web\"\nCACHE_REF=\"${REGISTRY}/web-cache:develop\"\nNGINX_CONF=\"infra/docker/nginx-staging.conf\"\n\nCACHE_FROM=\"type=registry,ref=${CACHE_REF},ignore-error=true\"\n\nif [ \"${CACHE_MODE}\" = \"read-write\" ]; then\n CACHE_TO=\"type=registry,ref=${CACHE_REF},mode=max\"\n echo \"Building Web image with read-write cache...\"\n docker buildx build --cache-from \"${CACHE_FROM}\" --cache-to \"${CACHE_TO}\" -f infra/docker/web-artifact.Dockerfile --build-arg \"NGINX_CONF=${NGINX_CONF}\" -t \"${REGISTRY}/${IMAGE_NAME}:${GITHUB_SHA}\" --push .\nelse\n echo \"Building Web image with read-only cache...\"\n docker buildx build --cache-from \"${CACHE_FROM}\" -f infra/docker/web-artifact.Dockerfile --build-arg \"NGINX_CONF=${NGINX_CONF}\" -t \"${REGISTRY}/${IMAGE_NAME}:${GITHUB_SHA}\"\
|
||||
\ --push .\nfi\necho \"Web image pushed: ${REGISTRY}/${IMAGE_NAME}:${GITHUB_SHA}\"\n"
|
||||
run: "set -eu
|
||||
REGISTRY=\"git.xiaoxiajianji.com/xiaoxia/xiaoxia-saas\"
|
||||
IMAGE_TAG=\"${REGISTRY}/xiaoxia-saas-web:${GITHUB_SHA}\"
|
||||
CACHE_REF=\"${REGISTRY}/web-cache:${GITHUB_REF_NAME}\"
|
||||
|
||||
bash scripts/ci/docker_build_push.sh \
|
||||
infra/docker/web.Dockerfile \
|
||||
\"${IMAGE_TAG}\" \
|
||||
\"${CACHE_REF}\" \
|
||||
APP_VERSION=\"${GITHUB_SHA}\"
|
||||
|
||||
echo
|
||||
echo \"WEB image pushed: ${IMAGE_TAG}\"
|
||||
"
|
||||
- name: Job duration summary
|
||||
if: always()
|
||||
shell: sh
|
||||
@@ -825,24 +861,20 @@ jobs:
|
||||
run: "set -eu\n# 确保使用 docker-container driver 以支持 cache export 功能\nif ! docker buildx inspect ci-builder > /dev/null 2>&1; then\n docker buildx create --use --name ci-builder --driver docker-container\n echo \"Created ci-builder (docker-container driver)\"\nelse\n docker buildx use ci-builder\n echo \"Using existing ci-builder\"\nfi\ndocker buildx inspect --bootstrap\n"
|
||||
- name: Build and push API image (buildx cache)
|
||||
shell: sh
|
||||
run: 'set -eu
|
||||
run: "set -eu
|
||||
REGISTRY=\"git.xiaoxiajianji.com/xiaoxia/xiaoxia-saas\"
|
||||
IMAGE_TAG=\"${REGISTRY}/xiaoxia-saas-api:${GITHUB_SHA}\"
|
||||
CACHE_REF=\"${REGISTRY}/api-cache:${GITHUB_REF_NAME}\"
|
||||
|
||||
REGISTRY="git.xiaoxiajianji.com/xiaoxia/xiaoxia-saas"
|
||||
bash scripts/ci/docker_build_push.sh \
|
||||
infra/docker/api.Dockerfile \
|
||||
\"${IMAGE_TAG}\" \
|
||||
\"${CACHE_REF}\" \
|
||||
APP_VERSION=\"${GITHUB_SHA}\"
|
||||
|
||||
IMAGE_NAME="xiaoxia-saas-api"
|
||||
|
||||
VERSION="${GITHUB_REF_NAME}"
|
||||
|
||||
CACHE_REF="${REGISTRY}/api-cache:main"
|
||||
|
||||
|
||||
echo "Building Production API image: ${VERSION}"
|
||||
|
||||
docker buildx build --build-arg APP_VERSION="${VERSION}" --cache-from "type=registry,ref=${CACHE_REF},ignore-error=true" --cache-to "type=registry,ref=${CACHE_REF},mode=max" -f infra/docker/api.Dockerfile -t "${REGISTRY}/${IMAGE_NAME}:${VERSION}" --push .
|
||||
|
||||
echo "Production API image pushed: ${REGISTRY}/${IMAGE_NAME}:${VERSION}"
|
||||
|
||||
'
|
||||
echo
|
||||
echo \"API image pushed: ${IMAGE_TAG}\"
|
||||
"
|
||||
- name: Job duration summary
|
||||
if: always()
|
||||
shell: sh
|
||||
@@ -900,24 +932,20 @@ jobs:
|
||||
run: "set -eu\n# 确保使用 docker-container driver 以支持 cache export 功能\nif ! docker buildx inspect ci-builder > /dev/null 2>&1; then\n docker buildx create --use --name ci-builder --driver docker-container\n echo \"Created ci-builder (docker-container driver)\"\nelse\n docker buildx use ci-builder\n echo \"Using existing ci-builder\"\nfi\ndocker buildx inspect --bootstrap\n"
|
||||
- name: Build and push Worker image (buildx cache)
|
||||
shell: sh
|
||||
run: 'set -eu
|
||||
run: "set -eu
|
||||
REGISTRY=\"git.xiaoxiajianji.com/xiaoxia/xiaoxia-saas\"
|
||||
IMAGE_TAG=\"${REGISTRY}/xiaoxia-saas-worker:${GITHUB_SHA}\"
|
||||
CACHE_REF=\"${REGISTRY}/worker-cache:${GITHUB_REF_NAME}\"
|
||||
|
||||
REGISTRY="git.xiaoxiajianji.com/xiaoxia/xiaoxia-saas"
|
||||
bash scripts/ci/docker_build_push.sh \
|
||||
infra/docker/worker.Dockerfile \
|
||||
\"${IMAGE_TAG}\" \
|
||||
\"${CACHE_REF}\" \
|
||||
APP_VERSION=\"${GITHUB_SHA}\"
|
||||
|
||||
IMAGE_NAME="xiaoxia-saas-worker"
|
||||
|
||||
VERSION="${GITHUB_REF_NAME}"
|
||||
|
||||
CACHE_REF="${REGISTRY}/worker-cache:main"
|
||||
|
||||
|
||||
echo "Building Production Worker image: ${VERSION}"
|
||||
|
||||
docker buildx build --build-arg APP_VERSION="${VERSION}" --cache-from "type=registry,ref=${CACHE_REF},ignore-error=true" --cache-to "type=registry,ref=${CACHE_REF},mode=min" -f infra/docker/worker.Dockerfile -t "${REGISTRY}/${IMAGE_NAME}:${VERSION}" --push .
|
||||
|
||||
echo "Production Worker image pushed: ${REGISTRY}/${IMAGE_NAME}:${VERSION}"
|
||||
|
||||
'
|
||||
echo
|
||||
echo \"WORKER image pushed: ${IMAGE_TAG}\"
|
||||
"
|
||||
- name: Job duration summary
|
||||
if: always()
|
||||
shell: sh
|
||||
@@ -978,26 +1006,20 @@ jobs:
|
||||
run: "set -eu\n# 确保使用 docker-container driver 以支持 cache export 功能\nif ! docker buildx inspect ci-builder > /dev/null 2>&1; then\n docker buildx create --use --name ci-builder --driver docker-container\n echo \"Created ci-builder (docker-container driver)\"\nelse\n docker buildx use ci-builder\n echo \"Using existing ci-builder\"\nfi\ndocker buildx inspect --bootstrap\n"
|
||||
- name: Build and push Web image (buildx cache)
|
||||
shell: sh
|
||||
run: 'set -eu
|
||||
run: "set -eu
|
||||
REGISTRY=\"git.xiaoxiajianji.com/xiaoxia/xiaoxia-saas\"
|
||||
IMAGE_TAG=\"${REGISTRY}/xiaoxia-saas-web:${GITHUB_SHA}\"
|
||||
CACHE_REF=\"${REGISTRY}/web-cache:${GITHUB_REF_NAME}\"
|
||||
|
||||
REGISTRY="git.xiaoxiajianji.com/xiaoxia/xiaoxia-saas"
|
||||
bash scripts/ci/docker_build_push.sh \
|
||||
infra/docker/web.Dockerfile \
|
||||
\"${IMAGE_TAG}\" \
|
||||
\"${CACHE_REF}\" \
|
||||
APP_VERSION=\"${GITHUB_SHA}\"
|
||||
|
||||
IMAGE_NAME="xiaoxia-saas-web"
|
||||
|
||||
VERSION="${GITHUB_REF_NAME}"
|
||||
|
||||
CACHE_REF="${REGISTRY}/web-cache:main"
|
||||
|
||||
NGINX_CONF="infra/docker/nginx-production.conf"
|
||||
|
||||
|
||||
echo "Building Production Web image: ${VERSION}"
|
||||
|
||||
docker buildx build --cache-from "type=registry,ref=${CACHE_REF},ignore-error=true" --cache-to "type=registry,ref=${CACHE_REF},mode=max" -f infra/docker/web-artifact.Dockerfile --build-arg "NGINX_CONF=${NGINX_CONF}" -t "${REGISTRY}/${IMAGE_NAME}:${VERSION}" --push .
|
||||
|
||||
echo "Production Web image pushed: ${REGISTRY}/${IMAGE_NAME}:${VERSION}"
|
||||
|
||||
'
|
||||
echo
|
||||
echo \"WEB image pushed: ${IMAGE_TAG}\"
|
||||
"
|
||||
- name: Cleanup old Docker images
|
||||
if: always()
|
||||
shell: sh
|
||||
|
||||
Executable
+71
@@ -0,0 +1,71 @@
|
||||
#!/bin/bash
|
||||
# 通用Docker镜像构建+推送脚本(构建与缓存解耦)
|
||||
# 用法: docker_build_push.sh <Dockerfile> <image_tag> <cache_ref> [build_arg...]
|
||||
set -eu
|
||||
|
||||
DOCKERFILE="$1"
|
||||
IMAGE_TAG="$2"
|
||||
CACHE_REF="$3"
|
||||
shift 3
|
||||
BUILD_ARGS=""
|
||||
for arg in "$@"; do
|
||||
BUILD_ARGS="$BUILD_ARGS --build-arg $arg"
|
||||
done
|
||||
|
||||
if ! docker buildx inspect ci-builder > /dev/null 2>&1; then
|
||||
docker buildx create --use --name ci-builder --driver docker-container
|
||||
echo "Created ci-builder"
|
||||
else
|
||||
docker buildx use ci-builder
|
||||
echo "Using existing ci-builder"
|
||||
fi
|
||||
docker buildx inspect --bootstrap
|
||||
|
||||
CACHE_FROM="type=registry,ref=${CACHE_REF},ignore-error=true"
|
||||
|
||||
echo "=== Step 1: Build & push image (read-only cache) ==="
|
||||
docker buildx build \
|
||||
$BUILD_ARGS \
|
||||
--cache-from "${CACHE_FROM}" \
|
||||
-f "${DOCKERFILE}" \
|
||||
-t "${IMAGE_TAG}" \
|
||||
--push \
|
||||
.
|
||||
|
||||
echo "Image pushed: ${IMAGE_TAG}"
|
||||
|
||||
echo ""
|
||||
echo "=== Step 2: Push cache (best effort, retries 3x) ==="
|
||||
CACHE_TO="type=registry,ref=${CACHE_REF},mode=max,compression=zstd"
|
||||
|
||||
MAX_RETRIES=3
|
||||
SUCCESS=0
|
||||
for attempt in $(seq 1 $MAX_RETRIES); do
|
||||
echo "Cache push attempt $attempt/$MAX_RETRIES"
|
||||
if docker buildx build \
|
||||
$BUILD_ARGS \
|
||||
--cache-from "${CACHE_FROM}" \
|
||||
--cache-to "${CACHE_TO}" \
|
||||
-f "${DOCKERFILE}" \
|
||||
-t "${IMAGE_TAG}" \
|
||||
--push \
|
||||
.; then
|
||||
echo "Cache pushed (attempt $attempt)"
|
||||
SUCCESS=1
|
||||
break
|
||||
else
|
||||
echo "Cache push failed (attempt $attempt)"
|
||||
if [ $attempt -lt $MAX_RETRIES ]; then
|
||||
WAIT=$((attempt * 5))
|
||||
echo "Retrying in ${WAIT}s..."
|
||||
sleep $WAIT
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $SUCCESS -eq 0 ]; then
|
||||
echo "WARNING: Cache push failed after $MAX_RETRIES attempts (non-fatal)"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Build completed: ${IMAGE_TAG}"
|
||||
@@ -44,7 +44,7 @@ class TestEditTemplate:
|
||||
def test_create_empty_name_raises(self):
|
||||
try:
|
||||
EditTemplate.create(" ")
|
||||
assert False, "应该抛出 ValueError"
|
||||
raise AssertionError("应该抛出 ValueError")
|
||||
except ValueError as e:
|
||||
assert "模板名称不能为空" in str(e)
|
||||
|
||||
@@ -74,14 +74,14 @@ class TestEditPlan:
|
||||
def test_create_empty_name_raises(self):
|
||||
try:
|
||||
EditPlan.create("tpl-1", " ")
|
||||
assert False, "应该抛出 ValueError"
|
||||
raise AssertionError("应该抛出 ValueError")
|
||||
except ValueError as e:
|
||||
assert "计划名称不能为空" in str(e)
|
||||
|
||||
def test_create_empty_template_id_raises(self):
|
||||
try:
|
||||
EditPlan.create(" ", "test")
|
||||
assert False, "应该抛出 ValueError"
|
||||
raise AssertionError("应该抛出 ValueError")
|
||||
except ValueError as e:
|
||||
assert "template_id 不能为空" in str(e)
|
||||
|
||||
@@ -112,7 +112,7 @@ class TestEditPlan:
|
||||
p = EditPlan.create("tpl-1", "test")
|
||||
try:
|
||||
p.start_rendering() # draft → rendering 不合法
|
||||
assert False, "应该抛出 ValueError"
|
||||
raise AssertionError("应该抛出 ValueError")
|
||||
except ValueError as e:
|
||||
logger.warning(f"Operation failed in tests/unit/test_phase8_edit_models.py: {e}", exc_info=True)
|
||||
|
||||
@@ -120,7 +120,7 @@ class TestEditPlan:
|
||||
p = EditPlan.create("tpl-1", "test")
|
||||
try:
|
||||
p.mark_completed() # draft → completed 不合法
|
||||
assert False, "应该抛出 ValueError"
|
||||
raise AssertionError("应该抛出 ValueError")
|
||||
except ValueError as e:
|
||||
logger.warning(f"Operation failed in tests/unit/test_phase8_edit_models.py: {e}", exc_info=True)
|
||||
|
||||
@@ -128,7 +128,7 @@ class TestEditPlan:
|
||||
p = EditPlan.create("tpl-1", "test")
|
||||
try:
|
||||
p.reset_to_draft() # draft → draft 不合法
|
||||
assert False, "应该抛出 ValueError"
|
||||
raise AssertionError("应该抛出 ValueError")
|
||||
except ValueError as e:
|
||||
logger.warning(f"Operation failed in tests/unit/test_phase8_edit_models.py: {e}", exc_info=True)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user