perf(ci): parallel image builds + pip cache
CI/CD Pipeline / Validate Code Quality And Tests (pull_request) Failing after 1m36s
CI/CD Pipeline / Unit Tests (pull_request) Failing after 1m34s
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 3m16s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Failing after 24s
CI/CD Pipeline / Validate Code Quality And Tests (pull_request) Failing after 1m36s
CI/CD Pipeline / Unit Tests (pull_request) Failing after 1m34s
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 3m16s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Failing after 24s
This commit is contained in:
+401
-29
@@ -84,6 +84,13 @@ jobs:
|
||||
python3 -m pip --version
|
||||
echo "CI environment is ready"
|
||||
|
||||
- name: Cache pip dependencies
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: pip-${{ runner.os }}-${{ hashFiles('requirements-base.txt', 'requirements.txt', 'requirements-dev.txt') }}
|
||||
restore-keys: |
|
||||
pip-${{ runner.os }}-
|
||||
- name: Install dependencies
|
||||
shell: sh
|
||||
run: |
|
||||
@@ -213,6 +220,13 @@ jobs:
|
||||
tar.extract(member, '.')
|
||||
PY
|
||||
|
||||
- name: Cache pip dependencies
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: pip-${{ runner.os }}-${{ hashFiles('requirements-base.txt', 'requirements.txt', 'requirements-dev.txt') }}
|
||||
restore-keys: |
|
||||
pip-${{ runner.os }}-
|
||||
- name: Install dependencies
|
||||
shell: sh
|
||||
run: |
|
||||
@@ -312,6 +326,13 @@ jobs:
|
||||
python3 -m pip --version
|
||||
echo "CI environment is ready"
|
||||
|
||||
- name: Cache pip dependencies
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: pip-${{ runner.os }}-${{ hashFiles('requirements-base.txt', 'requirements.txt', 'requirements-dev.txt') }}
|
||||
restore-keys: |
|
||||
pip-${{ runner.os }}-
|
||||
- name: Install dependencies
|
||||
shell: sh
|
||||
run: |
|
||||
@@ -587,14 +608,17 @@ jobs:
|
||||
echo "=== CI 失败通知 ==="
|
||||
FAILED_JOB="Frontend Lint" python3 scripts/ci_notify_failure.py
|
||||
|
||||
deploy-staging:
|
||||
name: Build & Push Staging (Watchtower auto-deploy)
|
||||
build-staging-api:
|
||||
name: Build Staging API Image
|
||||
runs-on: saas
|
||||
timeout-minutes: 30
|
||||
timeout-minutes: 25
|
||||
needs: [validate, frontend-lint]
|
||||
|
||||
if: github.event_name == 'push' && (github.ref_name == 'main' || github.ref_name == 'develop')
|
||||
|
||||
env:
|
||||
BUILD_ONLY: api
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
shell: sh
|
||||
@@ -641,16 +665,195 @@ jobs:
|
||||
tar.extract(member, '.')
|
||||
INNERPY
|
||||
|
||||
- name: Build and push all images to Gitea Registry
|
||||
|
||||
- name: Build and push api image
|
||||
shell: sh
|
||||
env:
|
||||
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
||||
REGISTRY_TOKEN: ${ secrets.REGISTRY_TOKEN }
|
||||
ALLOW_SHARED_PRODUCTION_BUILD_HOST: "true"
|
||||
run: |
|
||||
set -eu
|
||||
chmod +x scripts/build_release_images.sh
|
||||
ALLOW_SHARED_PRODUCTION_BUILD_HOST=true REGISTRY_TOKEN="${REGISTRY_TOKEN}" \
|
||||
BUILD_ONLY="${BUILD_ONLY}" \
|
||||
ALLOW_SHARED_PRODUCTION_BUILD_HOST=true \
|
||||
REGISTRY_TOKEN="${REGISTRY_TOKEN}" \
|
||||
scripts/build_release_images.sh "${GITHUB_SHA}" staging
|
||||
|
||||
- name: Notify CI failure
|
||||
if: failure()
|
||||
shell: sh
|
||||
run: |
|
||||
set +e
|
||||
echo "=== CI 失败通知 ==="
|
||||
FAILED_JOB="Build Staging API Image" python3 scripts/ci_notify_failure.py
|
||||
|
||||
build-staging-worker:
|
||||
name: Build Staging Worker Image
|
||||
runs-on: saas
|
||||
timeout-minutes: 25
|
||||
needs: [validate, frontend-lint]
|
||||
|
||||
if: github.event_name == 'push' && (github.ref_name == 'main' || github.ref_name == 'develop')
|
||||
|
||||
env:
|
||||
BUILD_ONLY: worker
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
shell: sh
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
set -eu
|
||||
python3 - <<'INNERPY'
|
||||
import io, os, tarfile, time, urllib.request, urllib.error
|
||||
url = f"{os.environ['GITHUB_API_URL']}/repos/{os.environ['GITHUB_REPOSITORY']}/archive/{os.environ['GITHUB_SHA']}.tar.gz"
|
||||
request = urllib.request.Request(url, headers={"Authorization": f"token {os.environ['GITHUB_TOKEN']}"})
|
||||
last_err = None
|
||||
for attempt in range(5):
|
||||
try:
|
||||
with urllib.request.urlopen(request, timeout=120) as response:
|
||||
archive = response.read()
|
||||
break
|
||||
except urllib.error.HTTPError as e:
|
||||
last_err = e
|
||||
if e.code >= 500 and attempt < 4:
|
||||
wait = 2 ** attempt
|
||||
print(f"Checkout HTTP {e.code}, retrying in {wait}s (attempt {attempt+1}/5)...")
|
||||
time.sleep(wait)
|
||||
continue
|
||||
raise
|
||||
except Exception as e:
|
||||
last_err = e
|
||||
if attempt < 4:
|
||||
wait = 2 ** attempt
|
||||
print(f"Checkout error: {e}, retrying in {wait}s (attempt {attempt+1}/5)...")
|
||||
time.sleep(wait)
|
||||
continue
|
||||
else:
|
||||
raise last_err
|
||||
with tarfile.open(fileobj=io.BytesIO(archive), mode='r:gz') as tar:
|
||||
root_prefix = tar.getmembers()[0].name.split('/', 1)[0] + '/'
|
||||
for member in tar.getmembers():
|
||||
name = member.name
|
||||
if name == root_prefix[:-1]:
|
||||
continue
|
||||
if name.startswith(root_prefix):
|
||||
member.name = name[len(root_prefix):]
|
||||
if member.name:
|
||||
tar.extract(member, '.')
|
||||
INNERPY
|
||||
|
||||
|
||||
- name: Build and push worker image
|
||||
shell: sh
|
||||
env:
|
||||
REGISTRY_TOKEN: ${ secrets.REGISTRY_TOKEN }
|
||||
ALLOW_SHARED_PRODUCTION_BUILD_HOST: "true"
|
||||
run: |
|
||||
set -eu
|
||||
chmod +x scripts/build_release_images.sh
|
||||
BUILD_ONLY="${BUILD_ONLY}" \
|
||||
ALLOW_SHARED_PRODUCTION_BUILD_HOST=true \
|
||||
REGISTRY_TOKEN="${REGISTRY_TOKEN}" \
|
||||
scripts/build_release_images.sh "${GITHUB_SHA}" staging
|
||||
|
||||
- name: Notify CI failure
|
||||
if: failure()
|
||||
shell: sh
|
||||
run: |
|
||||
set +e
|
||||
echo "=== CI 失败通知 ==="
|
||||
FAILED_JOB="Build Staging Worker Image" python3 scripts/ci_notify_failure.py
|
||||
|
||||
build-staging-web:
|
||||
name: Build Staging Web Image
|
||||
runs-on: saas
|
||||
timeout-minutes: 25
|
||||
needs: [validate, frontend-lint]
|
||||
|
||||
if: github.event_name == 'push' && (github.ref_name == 'main' || github.ref_name == 'develop')
|
||||
|
||||
env:
|
||||
BUILD_ONLY: web
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
shell: sh
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
set -eu
|
||||
python3 - <<'INNERPY'
|
||||
import io, os, tarfile, time, urllib.request, urllib.error
|
||||
url = f"{os.environ['GITHUB_API_URL']}/repos/{os.environ['GITHUB_REPOSITORY']}/archive/{os.environ['GITHUB_SHA']}.tar.gz"
|
||||
request = urllib.request.Request(url, headers={"Authorization": f"token {os.environ['GITHUB_TOKEN']}"})
|
||||
last_err = None
|
||||
for attempt in range(5):
|
||||
try:
|
||||
with urllib.request.urlopen(request, timeout=120) as response:
|
||||
archive = response.read()
|
||||
break
|
||||
except urllib.error.HTTPError as e:
|
||||
last_err = e
|
||||
if e.code >= 500 and attempt < 4:
|
||||
wait = 2 ** attempt
|
||||
print(f"Checkout HTTP {e.code}, retrying in {wait}s (attempt {attempt+1}/5)...")
|
||||
time.sleep(wait)
|
||||
continue
|
||||
raise
|
||||
except Exception as e:
|
||||
last_err = e
|
||||
if attempt < 4:
|
||||
wait = 2 ** attempt
|
||||
print(f"Checkout error: {e}, retrying in {wait}s (attempt {attempt+1}/5)...")
|
||||
time.sleep(wait)
|
||||
continue
|
||||
else:
|
||||
raise last_err
|
||||
with tarfile.open(fileobj=io.BytesIO(archive), mode='r:gz') as tar:
|
||||
root_prefix = tar.getmembers()[0].name.split('/', 1)[0] + '/'
|
||||
for member in tar.getmembers():
|
||||
name = member.name
|
||||
if name == root_prefix[:-1]:
|
||||
continue
|
||||
if name.startswith(root_prefix):
|
||||
member.name = name[len(root_prefix):]
|
||||
if member.name:
|
||||
tar.extract(member, '.')
|
||||
INNERPY
|
||||
|
||||
|
||||
- name: Build and push web image
|
||||
shell: sh
|
||||
env:
|
||||
REGISTRY_TOKEN: ${ secrets.REGISTRY_TOKEN }
|
||||
ALLOW_SHARED_PRODUCTION_BUILD_HOST: "true"
|
||||
run: |
|
||||
set -eu
|
||||
chmod +x scripts/build_release_images.sh
|
||||
BUILD_ONLY="${BUILD_ONLY}" \
|
||||
ALLOW_SHARED_PRODUCTION_BUILD_HOST=true \
|
||||
REGISTRY_TOKEN="${REGISTRY_TOKEN}" \
|
||||
scripts/build_release_images.sh "${GITHUB_SHA}" staging
|
||||
|
||||
- name: Notify CI failure
|
||||
if: failure()
|
||||
shell: sh
|
||||
run: |
|
||||
set +e
|
||||
echo "=== CI 失败通知 ==="
|
||||
FAILED_JOB="Build Staging Web Image" python3 scripts/ci_notify_failure.py
|
||||
|
||||
deploy-staging:
|
||||
name: Deploy Staging (Watchtower auto-deploy)
|
||||
runs-on: saas
|
||||
timeout-minutes: 20
|
||||
needs: [build-staging-api, build-staging-worker, build-staging-web]
|
||||
|
||||
if: github.event_name == 'push' && (github.ref_name == 'main' || github.ref_name == 'develop')
|
||||
|
||||
steps:
|
||||
- name: Tag and push :staging images (Watchtower auto-update)
|
||||
shell: sh
|
||||
env:
|
||||
@@ -662,6 +865,7 @@ jobs:
|
||||
printf '%s' "${REGISTRY_TOKEN}" | docker login git.xiaoxiajianji.com -u xiaoxia --password-stdin 2>/dev/null
|
||||
fi
|
||||
for svc in api worker web; do
|
||||
docker pull "${REGISTRY}/xiaoxia-saas-${svc}:${GITHUB_SHA}"
|
||||
docker tag "${REGISTRY}/xiaoxia-saas-${svc}:${GITHUB_SHA}" "${REGISTRY}/xiaoxia-saas-${svc}:staging"
|
||||
docker push "${REGISTRY}/xiaoxia-saas-${svc}:staging"
|
||||
done
|
||||
@@ -732,9 +936,7 @@ jobs:
|
||||
run: |
|
||||
set +e
|
||||
echo "=== CI 失败通知 ==="
|
||||
FAILED_JOB="Build & Push Staging (Watchtower auto-deploy)" python3 scripts/ci_notify_failure.py
|
||||
|
||||
|
||||
FAILED_JOB="Deploy Staging" python3 scripts/ci_notify_failure.py
|
||||
|
||||
staging-e2e:
|
||||
name: Staging E2E Tests
|
||||
@@ -887,14 +1089,17 @@ jobs:
|
||||
|
||||
|
||||
|
||||
build-production-runtime-images:
|
||||
name: Build Production Runtime Images
|
||||
build-prod-api:
|
||||
name: Build Production API Image
|
||||
runs-on: saas
|
||||
timeout-minutes: 30
|
||||
timeout-minutes: 25
|
||||
needs: [validate, frontend-lint]
|
||||
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
|
||||
env:
|
||||
BUILD_ONLY: api
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
shell: sh
|
||||
@@ -902,7 +1107,7 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
set -eu
|
||||
python3 - <<'PY'
|
||||
python3 - <<'INNERPY'
|
||||
import io, os, tarfile, time, urllib.request, urllib.error
|
||||
url = f"{os.environ['GITHUB_API_URL']}/repos/{os.environ['GITHUB_REPOSITORY']}/archive/{os.environ['GITHUB_SHA']}.tar.gz"
|
||||
request = urllib.request.Request(url, headers={"Authorization": f"token {os.environ['GITHUB_TOKEN']}"})
|
||||
@@ -927,7 +1132,6 @@ jobs:
|
||||
print(f"Checkout error: {e}, retrying in {wait}s (attempt {attempt+1}/5)...")
|
||||
time.sleep(wait)
|
||||
continue
|
||||
raise
|
||||
else:
|
||||
raise last_err
|
||||
with tarfile.open(fileobj=io.BytesIO(archive), mode='r:gz') as tar:
|
||||
@@ -940,47 +1144,215 @@ jobs:
|
||||
member.name = name[len(root_prefix):]
|
||||
if member.name:
|
||||
tar.extract(member, '.')
|
||||
PY
|
||||
INNERPY
|
||||
|
||||
- name: Build and push all images (api + worker + web, with buildx cache)
|
||||
|
||||
- name: Build and push production api image
|
||||
shell: sh
|
||||
env:
|
||||
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
||||
REGISTRY_TOKEN: ${ secrets.REGISTRY_TOKEN }
|
||||
run: |
|
||||
set -eu
|
||||
chmod +x scripts/build_release_images.sh
|
||||
REGISTRY_TOKEN="${REGISTRY_TOKEN}" scripts/build_release_images.sh "${GITHUB_REF_NAME}"
|
||||
BUILD_ONLY="${BUILD_ONLY}" \
|
||||
REGISTRY_TOKEN="${REGISTRY_TOKEN}" \
|
||||
scripts/build_release_images.sh "${GITHUB_REF_NAME}"
|
||||
|
||||
|
||||
- name: Cleanup old Docker images
|
||||
if: always()
|
||||
shell: sh
|
||||
run: |
|
||||
set -eu
|
||||
if [ -f scripts/cleanup_old_images.sh ]; then
|
||||
chmod +x scripts/cleanup_old_images.sh
|
||||
scripts/cleanup_old_images.sh
|
||||
else
|
||||
echo "Cleanup script not found, doing basic prune..."
|
||||
docker image prune -f 2>/dev/null || true
|
||||
fi
|
||||
set +e
|
||||
docker image prune -f 2>/dev/null || true
|
||||
echo "Disk usage after cleanup:"
|
||||
df -h / | tail -1
|
||||
|
||||
- name: Notify CI failure
|
||||
if: failure()
|
||||
shell: sh
|
||||
run: |
|
||||
set +e
|
||||
echo "=== CI 失败通知 ==="
|
||||
FAILED_JOB="Build Production Runtime Images" python3 scripts/ci_notify_failure.py
|
||||
FAILED_JOB="Build Production API Image" python3 scripts/ci_notify_failure.py
|
||||
|
||||
build-prod-worker:
|
||||
name: Build Production Worker Image
|
||||
runs-on: saas
|
||||
timeout-minutes: 25
|
||||
needs: [validate, frontend-lint]
|
||||
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
|
||||
env:
|
||||
BUILD_ONLY: worker
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
shell: sh
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
set -eu
|
||||
python3 - <<'INNERPY'
|
||||
import io, os, tarfile, time, urllib.request, urllib.error
|
||||
url = f"{os.environ['GITHUB_API_URL']}/repos/{os.environ['GITHUB_REPOSITORY']}/archive/{os.environ['GITHUB_SHA']}.tar.gz"
|
||||
request = urllib.request.Request(url, headers={"Authorization": f"token {os.environ['GITHUB_TOKEN']}"})
|
||||
last_err = None
|
||||
for attempt in range(5):
|
||||
try:
|
||||
with urllib.request.urlopen(request, timeout=120) as response:
|
||||
archive = response.read()
|
||||
break
|
||||
except urllib.error.HTTPError as e:
|
||||
last_err = e
|
||||
if e.code >= 500 and attempt < 4:
|
||||
wait = 2 ** attempt
|
||||
print(f"Checkout HTTP {e.code}, retrying in {wait}s (attempt {attempt+1}/5)...")
|
||||
time.sleep(wait)
|
||||
continue
|
||||
raise
|
||||
except Exception as e:
|
||||
last_err = e
|
||||
if attempt < 4:
|
||||
wait = 2 ** attempt
|
||||
print(f"Checkout error: {e}, retrying in {wait}s (attempt {attempt+1}/5)...")
|
||||
time.sleep(wait)
|
||||
continue
|
||||
else:
|
||||
raise last_err
|
||||
with tarfile.open(fileobj=io.BytesIO(archive), mode='r:gz') as tar:
|
||||
root_prefix = tar.getmembers()[0].name.split('/', 1)[0] + '/'
|
||||
for member in tar.getmembers():
|
||||
name = member.name
|
||||
if name == root_prefix[:-1]:
|
||||
continue
|
||||
if name.startswith(root_prefix):
|
||||
member.name = name[len(root_prefix):]
|
||||
if member.name:
|
||||
tar.extract(member, '.')
|
||||
INNERPY
|
||||
|
||||
|
||||
- name: Build and push production worker image
|
||||
shell: sh
|
||||
env:
|
||||
REGISTRY_TOKEN: ${ secrets.REGISTRY_TOKEN }
|
||||
run: |
|
||||
set -eu
|
||||
chmod +x scripts/build_release_images.sh
|
||||
BUILD_ONLY="${BUILD_ONLY}" \
|
||||
REGISTRY_TOKEN="${REGISTRY_TOKEN}" \
|
||||
scripts/build_release_images.sh "${GITHUB_REF_NAME}"
|
||||
|
||||
|
||||
- name: Cleanup old Docker images
|
||||
if: always()
|
||||
shell: sh
|
||||
run: |
|
||||
set +e
|
||||
docker image prune -f 2>/dev/null || true
|
||||
echo "Disk usage after cleanup:"
|
||||
df -h / | tail -1
|
||||
- name: Notify CI failure
|
||||
if: failure()
|
||||
shell: sh
|
||||
run: |
|
||||
set +e
|
||||
echo "=== CI 失败通知 ==="
|
||||
FAILED_JOB="Build Production Worker Image" python3 scripts/ci_notify_failure.py
|
||||
|
||||
build-prod-web:
|
||||
name: Build Production Web Image
|
||||
runs-on: saas
|
||||
timeout-minutes: 25
|
||||
needs: [validate, frontend-lint]
|
||||
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
|
||||
env:
|
||||
BUILD_ONLY: web
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
shell: sh
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
set -eu
|
||||
python3 - <<'INNERPY'
|
||||
import io, os, tarfile, time, urllib.request, urllib.error
|
||||
url = f"{os.environ['GITHUB_API_URL']}/repos/{os.environ['GITHUB_REPOSITORY']}/archive/{os.environ['GITHUB_SHA']}.tar.gz"
|
||||
request = urllib.request.Request(url, headers={"Authorization": f"token {os.environ['GITHUB_TOKEN']}"})
|
||||
last_err = None
|
||||
for attempt in range(5):
|
||||
try:
|
||||
with urllib.request.urlopen(request, timeout=120) as response:
|
||||
archive = response.read()
|
||||
break
|
||||
except urllib.error.HTTPError as e:
|
||||
last_err = e
|
||||
if e.code >= 500 and attempt < 4:
|
||||
wait = 2 ** attempt
|
||||
print(f"Checkout HTTP {e.code}, retrying in {wait}s (attempt {attempt+1}/5)...")
|
||||
time.sleep(wait)
|
||||
continue
|
||||
raise
|
||||
except Exception as e:
|
||||
last_err = e
|
||||
if attempt < 4:
|
||||
wait = 2 ** attempt
|
||||
print(f"Checkout error: {e}, retrying in {wait}s (attempt {attempt+1}/5)...")
|
||||
time.sleep(wait)
|
||||
continue
|
||||
else:
|
||||
raise last_err
|
||||
with tarfile.open(fileobj=io.BytesIO(archive), mode='r:gz') as tar:
|
||||
root_prefix = tar.getmembers()[0].name.split('/', 1)[0] + '/'
|
||||
for member in tar.getmembers():
|
||||
name = member.name
|
||||
if name == root_prefix[:-1]:
|
||||
continue
|
||||
if name.startswith(root_prefix):
|
||||
member.name = name[len(root_prefix):]
|
||||
if member.name:
|
||||
tar.extract(member, '.')
|
||||
INNERPY
|
||||
|
||||
|
||||
- name: Build and push production web image
|
||||
shell: sh
|
||||
env:
|
||||
REGISTRY_TOKEN: ${ secrets.REGISTRY_TOKEN }
|
||||
run: |
|
||||
set -eu
|
||||
chmod +x scripts/build_release_images.sh
|
||||
BUILD_ONLY="${BUILD_ONLY}" \
|
||||
REGISTRY_TOKEN="${REGISTRY_TOKEN}" \
|
||||
scripts/build_release_images.sh "${GITHUB_REF_NAME}"
|
||||
|
||||
|
||||
- name: Cleanup old Docker images
|
||||
if: always()
|
||||
shell: sh
|
||||
run: |
|
||||
set +e
|
||||
docker image prune -f 2>/dev/null || true
|
||||
echo "Disk usage after cleanup:"
|
||||
df -h / | tail -1
|
||||
- name: Notify CI failure
|
||||
if: failure()
|
||||
shell: sh
|
||||
run: |
|
||||
set +e
|
||||
echo "=== CI 失败通知 ==="
|
||||
FAILED_JOB="Build Production Web Image" python3 scripts/ci_notify_failure.py
|
||||
|
||||
deploy-production:
|
||||
name: Deploy Production
|
||||
runs-on: saas
|
||||
timeout-minutes: 20
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
needs: build-production-runtime-images
|
||||
needs: [build-prod-api, build-prod-worker, build-prod-web]
|
||||
|
||||
steps:
|
||||
- name: Install SSH client
|
||||
|
||||
Reference in New Issue
Block a user