e8fbffeff1
Gitea runner image (docker.gitea.com/runner-images:ubuntu-latest) now ships Node 24 instead of Node 20. Remove strict version check to avoid blocking CI on runner image updates.
249 lines
9.0 KiB
YAML
249 lines
9.0 KiB
YAML
name: Deploy Dashboard (Main)
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
paths:
|
|
- 'dashboard/**'
|
|
- '.gitea/workflows/deploy.yml'
|
|
|
|
concurrency:
|
|
group: deploy-dashboard-main
|
|
cancel-in-progress: true
|
|
|
|
jobs:
|
|
backend-tests:
|
|
name: Backend Tests
|
|
runs-on: ubuntu-latest
|
|
env:
|
|
SECRET_KEY: test-secret-key-for-ci-environment-32chars-minimum
|
|
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 1
|
|
|
|
- name: Setup Python
|
|
run: |
|
|
python3 --version
|
|
python3 -c "import sys; assert sys.version_info[:2] == (3, 12), f'Expected Python 3.12, got {sys.version}'; print('Python 3.12 confirmed')"
|
|
pip3 --version
|
|
|
|
- name: Cache Python dependencies
|
|
id: cache-python
|
|
run: |
|
|
CACHE_KEY="python-$(cat dashboard/backend/requirements.txt dashboard/backend/requirements-dev.txt | md5sum | cut -d' ' -f1)"
|
|
CACHE_DIR="/tmp/pytest-cache/$CACHE_KEY"
|
|
PIP_CACHE_DIR="/tmp/pip-cache"
|
|
echo "CACHE_DIR=$CACHE_DIR" >> $GITHUB_ENV
|
|
echo "CACHE_KEY=$CACHE_KEY" >> $GITHUB_ENV
|
|
echo "PIP_CACHE_DIR=$PIP_CACHE_DIR" >> $GITHUB_ENV
|
|
mkdir -p "$PIP_CACHE_DIR"
|
|
if [ -d "$CACHE_DIR" ]; then
|
|
echo "Cache hit for $CACHE_KEY"
|
|
echo "cache-hit=true" >> $GITHUB_OUTPUT
|
|
else
|
|
echo "Cache miss for $CACHE_KEY"
|
|
echo "cache-hit=false" >> $GITHUB_OUTPUT
|
|
mkdir -p "$CACHE_DIR"
|
|
fi
|
|
|
|
- name: Install dependencies
|
|
run: |
|
|
cd dashboard/backend
|
|
if [ "${{ steps.cache-python.outputs.cache-hit }}" = "true" ]; then
|
|
echo "Restoring venv from cache $CACHE_KEY..."
|
|
if cp -a $CACHE_DIR/venv . && [ -f venv/bin/activate ]; then
|
|
echo "Cache restored successfully"
|
|
else
|
|
echo "Cache corrupted, installing fresh..."
|
|
rm -rf venv
|
|
python3 -m venv venv
|
|
. venv/bin/activate
|
|
pip install --cache-dir=$PIP_CACHE_DIR -r requirements.txt || pip install -r requirements.txt
|
|
pip install --cache-dir=$PIP_CACHE_DIR -r requirements-dev.txt || pip install -r requirements-dev.txt
|
|
pip install --cache-dir=$PIP_CACHE_DIR pytest-timeout pytest-cov || pip install pytest-timeout pytest-cov
|
|
fi
|
|
else
|
|
echo "Installing fresh dependencies..."
|
|
python3 -m venv venv
|
|
. venv/bin/activate
|
|
pip install --cache-dir=$PIP_CACHE_DIR -r requirements.txt || pip install -r requirements.txt
|
|
pip install --cache-dir=$PIP_CACHE_DIR -r requirements-dev.txt || pip install -r requirements-dev.txt
|
|
pip install --cache-dir=$PIP_CACHE_DIR pytest-timeout pytest-cov || pip install pytest-timeout pytest-cov
|
|
echo "Saving venv to cache $CACHE_KEY..."
|
|
cp -a venv $CACHE_DIR/ || echo "Warning: cache save failed"
|
|
fi
|
|
|
|
- name: Run tests with coverage
|
|
run: |
|
|
cd dashboard/backend
|
|
. venv/bin/activate
|
|
pytest tests/ -v --timeout=60 \
|
|
--cov=. --cov-report=xml --cov-report=term \
|
|
--junit-xml=test-results.xml \
|
|
--cov-fail-under=49
|
|
|
|
if [ $? -ne 0 ]; then
|
|
echo "❌ Backend tests failed!"
|
|
exit 1
|
|
fi
|
|
echo "✅ Backend tests passed"
|
|
|
|
frontend-tests:
|
|
name: Frontend Tests
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 1
|
|
|
|
- name: Setup Node.js
|
|
run: |
|
|
node --version
|
|
echo "Node $(node --version) detected"
|
|
npm --version
|
|
|
|
- name: Cache Node dependencies
|
|
id: cache-node
|
|
run: |
|
|
CACHE_KEY="node-$(md5sum dashboard/frontend/package-lock.json | cut -d' ' -f1)"
|
|
CACHE_DIR="/tmp/npm-cache/$CACHE_KEY"
|
|
echo "CACHE_DIR=$CACHE_DIR" >> $GITHUB_ENV
|
|
echo "CACHE_KEY=$CACHE_KEY" >> $GITHUB_ENV
|
|
if [ -d "$CACHE_DIR" ]; then
|
|
echo "Cache hit for $CACHE_KEY"
|
|
echo "cache-hit=true" >> $GITHUB_OUTPUT
|
|
else
|
|
echo "Cache miss for $CACHE_KEY"
|
|
echo "cache-hit=false" >> $GITHUB_OUTPUT
|
|
mkdir -p "$CACHE_DIR"
|
|
fi
|
|
|
|
- name: Install dependencies
|
|
env:
|
|
NODE_OPTIONS: "--max-old-space-size=2048"
|
|
run: |
|
|
cd dashboard/frontend
|
|
if [ "${{ steps.cache-node.outputs.cache-hit }}" = "true" ]; then
|
|
echo "Restoring from cache $CACHE_KEY..."
|
|
if cp -a $CACHE_DIR/node_modules . && [ -d node_modules ]; then
|
|
echo "Cache restored successfully"
|
|
else
|
|
echo "Cache corrupted, installing fresh..."
|
|
rm -rf node_modules
|
|
npm ci
|
|
fi
|
|
else
|
|
echo "Installing fresh dependencies..."
|
|
npm ci
|
|
echo "Saving to cache $CACHE_KEY..."
|
|
cp -a node_modules $CACHE_DIR/ || echo "Warning: cache save failed"
|
|
fi
|
|
|
|
- name: Run tests
|
|
env:
|
|
NODE_OPTIONS: "--max-old-space-size=2048"
|
|
run: |
|
|
cd dashboard/frontend
|
|
npm run test:coverage -- --reporter=verbose --run --pool=forks --poolOptions.forks.maxForks=2
|
|
|
|
if [ $? -ne 0 ]; then
|
|
echo "❌ Frontend tests failed!"
|
|
exit 1
|
|
fi
|
|
echo "✅ Frontend tests passed"
|
|
|
|
deploy:
|
|
name: Deploy to Production
|
|
runs-on: ubuntu-latest
|
|
needs: [backend-tests, frontend-tests]
|
|
container:
|
|
volumes:
|
|
- /var/packages/ContainerManager/target/usr/bin/docker:/usr/bin/docker
|
|
- /volume1/docker/nas-dashboard:/nas-dashboard
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 1
|
|
|
|
- name: Warm mirror cache for base images
|
|
run: |
|
|
set -u
|
|
mirror_host="100.78.131.124:5501"
|
|
|
|
if command -v curl >/dev/null 2>&1; then
|
|
if curl -fsS "http://${mirror_host}/v2/" >/dev/null; then
|
|
echo "Registry mirror is healthy at ${mirror_host}"
|
|
else
|
|
echo "Warning: registry mirror health check failed at ${mirror_host}; continuing with normal pull path"
|
|
fi
|
|
else
|
|
echo "Warning: curl is unavailable; skipping explicit mirror health check"
|
|
fi
|
|
|
|
prewarm_base_image() {
|
|
image_ref="$1"
|
|
# Skip if image already exists locally
|
|
if docker image inspect "${image_ref}" >/dev/null 2>&1; then
|
|
echo "Image ${image_ref} already exists locally, skipping pre-pull"
|
|
return 0
|
|
fi
|
|
|
|
mirror_ref="${mirror_host}/library/${image_ref}"
|
|
echo "Attempting mirror pre-pull: ${mirror_ref}"
|
|
if timeout 120 docker pull "${mirror_ref}"; then
|
|
docker tag "${mirror_ref}" "${image_ref}"
|
|
echo "Mirror pre-pull succeeded for ${image_ref}"
|
|
else
|
|
echo "Warning: mirror pre-pull failed for ${image_ref}; continuing with normal pull during build"
|
|
fi
|
|
}
|
|
|
|
prewarm_base_image "node:20-alpine"
|
|
prewarm_base_image "python:3.12-slim"
|
|
|
|
- name: Build
|
|
run: |
|
|
set -e
|
|
export DOCKER_API_VERSION=1.43
|
|
# DOCKER_BUILDKIT=0 is required for Synology ContainerManager's Docker daemon,
|
|
# which does not support BuildKit syntax. Remove when Synology updates to a
|
|
# Docker Engine version with full BuildKit support (currently 24.x, needs 23+).
|
|
# --cache-to type=inline is a no-op while BuildKit is disabled; it activates
|
|
# automatically when DOCKER_BUILDKIT=0 is removed.
|
|
if ! DOCKER_BUILDKIT=0 docker build --cache-from nas-dashboard:latest -t nas-dashboard:latest dashboard/; then
|
|
echo "Build failed. Checking for network issues..."
|
|
curl -I https://registry.npmmirror.com || echo "npmmirror unreachable"
|
|
curl -I https://pypi.tuna.tsinghua.edu.cn || echo "Tsinghua PyPI unreachable"
|
|
exit 1
|
|
fi
|
|
|
|
- name: Sync runtime compose file
|
|
run: cp dashboard/docker-compose.yml /nas-dashboard/docker-compose.yml
|
|
|
|
- name: Deploy
|
|
run: |
|
|
set -e
|
|
export DOCKER_API_VERSION=1.43
|
|
docker compose -f /nas-dashboard/docker-compose.yml up -d --pull never
|
|
|
|
- name: Wait for container to be healthy
|
|
run: |
|
|
echo "Waiting for container to be healthy..."
|
|
for i in {1..30}; do
|
|
STATUS=$(docker inspect --format='{{.State.Health.Status}}' nas-dashboard 2>/dev/null || echo "starting")
|
|
if [ "$STATUS" = "healthy" ]; then
|
|
echo "✅ Container is healthy"
|
|
exit 0
|
|
fi
|
|
echo "Waiting... ($i/30) Status: $STATUS"
|
|
sleep 2
|
|
done
|
|
echo "❌ Container failed to become healthy"
|
|
docker logs nas-dashboard --tail 50
|
|
exit 1
|