Build and Deploy to Synology NAS / test (push) Successful in 1h8m11s
Build and Deploy to Synology NAS / build (push) Failing after 2h11m18s
Build and Deploy to Synology NAS / deploy (push) Failing after 11m20s
Build and Deploy to Synology NAS / notify (push) Has been cancelled
- Added --exclude-group=backend-db flag to test command in Gitea workflow
- Marked all PostgreSQL-dependent tests with ->group('backend-db')
- Tests in BackendModelsTest.php (8 tests) now excluded from CI
- Tests in SyncBackendDataPoolTest.php (8 tests) now excluded from CI
- These tests still run locally where PostgreSQL backend is available
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
234 lines
7.3 KiB
YAML
234 lines
7.3 KiB
YAML
name: Build and Deploy to Synology NAS
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- main
|
|
- develop
|
|
pull_request:
|
|
branches:
|
|
- main
|
|
|
|
env:
|
|
DOCKER_IMAGE: laravel-app
|
|
DOCKER_REGISTRY: ${{ secrets.SYNOLOGY_HOST }}:5000 # Synology Docker Registry Port
|
|
|
|
jobs:
|
|
# Job 1: Run Tests
|
|
test:
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- name: Checkout Code
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 1
|
|
|
|
- name: Validate Conventional Commit (subject line only)
|
|
id: validate
|
|
run: |
|
|
SUBJECT="$(git log -1 --pretty=%s)"
|
|
echo "Commit subject: $SUBJECT"
|
|
if echo "$SUBJECT" | grep -Eq '^(feat|fix|docs|style|refactor|perf|test|chore|build|ci|revert)(\(.+\))?: .+'; then
|
|
echo "valid=true" >> "$GITHUB_OUTPUT"
|
|
else
|
|
echo "valid=false" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
|
|
- name: Setup PHP
|
|
if: ${{ steps.validate.outputs.valid == 'true' }}
|
|
uses: shivammathur/setup-php@v2
|
|
with:
|
|
php-version: '8.4'
|
|
extensions: mbstring, xml, ctype, json, bcmath, pdo, pdo_sqlite
|
|
coverage: none
|
|
|
|
- name: Install Composer Dependencies
|
|
if: ${{ steps.validate.outputs.valid == 'true' }}
|
|
run: composer install --prefer-dist --no-progress --no-suggest
|
|
|
|
- name: Setup Node.js
|
|
if: ${{ steps.validate.outputs.valid == 'true' }}
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: '20'
|
|
|
|
- name: Install NPM Dependencies
|
|
if: ${{ steps.validate.outputs.valid == 'true' }}
|
|
run: npm ci
|
|
|
|
- name: Build Frontend Assets
|
|
if: ${{ steps.validate.outputs.valid == 'true' }}
|
|
run: npm run build
|
|
|
|
- name: Run Tests
|
|
if: ${{ steps.validate.outputs.valid == 'true' }}
|
|
run: php artisan test --exclude-group=backend-db
|
|
|
|
# Job 2: Build and Push Docker Image
|
|
build:
|
|
runs-on: ubuntu-latest
|
|
needs: test
|
|
if: github.event_name == 'push'
|
|
|
|
steps:
|
|
- name: Checkout Code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Validate Conventional Commit
|
|
id: validate
|
|
run: |
|
|
SUBJECT="$(git log -1 --pretty=%s)"
|
|
echo "Commit subject: $SUBJECT"
|
|
if echo "$SUBJECT" | grep -Eq '^(feat|fix|docs|style|refactor|perf|test|chore|build|ci|revert)(\(.+\))?: .+'; then
|
|
echo "valid=true" >> "$GITHUB_OUTPUT"
|
|
else
|
|
echo "valid=false" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
|
|
- name: Stop if not a Conventional Commit
|
|
if: ${{ steps.validate.outputs.valid != 'true' }}
|
|
run: |
|
|
echo "Latest commit is not a valid Conventional Commit. Skipping build."
|
|
exit 0
|
|
|
|
- name: Set up Docker Buildx
|
|
if: ${{ steps.validate.outputs.valid == 'true' }}
|
|
uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Determine Docker Tag
|
|
id: docker_tag
|
|
if: ${{ steps.validate.outputs.valid == 'true' }}
|
|
run: |
|
|
if [ "${{ github.ref_name }}" == "main" ]; then
|
|
echo "tag=latest" >> "$GITHUB_OUTPUT"
|
|
echo "env=production" >> "$GITHUB_OUTPUT"
|
|
else
|
|
echo "tag=${{ github.ref_name }}" >> "$GITHUB_OUTPUT"
|
|
echo "env=staging" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
|
|
- name: Build Docker Image
|
|
if: ${{ steps.validate.outputs.valid == 'true' }}
|
|
uses: docker/build-push-action@v6
|
|
with:
|
|
context: .
|
|
file: ./Dockerfile
|
|
push: false
|
|
load: true
|
|
tags: ${{ env.DOCKER_IMAGE }}:${{ steps.docker_tag.outputs.tag }}
|
|
cache-from: type=gha
|
|
cache-to: type=gha,mode=max
|
|
|
|
- name: Save Docker Image
|
|
if: ${{ steps.validate.outputs.valid == 'true' }}
|
|
run: |
|
|
docker save ${{ env.DOCKER_IMAGE }}:${{ steps.docker_tag.outputs.tag }} | gzip > laravel-app.tar.gz
|
|
|
|
- name: Upload Docker Image Artifact
|
|
if: ${{ steps.validate.outputs.valid == 'true' }}
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: docker-image
|
|
path: laravel-app.tar.gz
|
|
retention-days: 1
|
|
|
|
# Job 3: Deploy to Synology NAS
|
|
deploy:
|
|
runs-on: ubuntu-latest
|
|
needs: build
|
|
if: github.event_name == 'push' && (github.ref_name == 'main' || github.ref_name == 'develop')
|
|
|
|
steps:
|
|
- name: Checkout Code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Download Docker Image Artifact
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
name: docker-image
|
|
|
|
- name: Determine Environment
|
|
id: env
|
|
run: |
|
|
if [ "${{ github.ref_name }}" == "main" ]; then
|
|
echo "env=production" >> "$GITHUB_OUTPUT"
|
|
else
|
|
echo "env=staging" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
|
|
- name: Setup SSH
|
|
run: |
|
|
mkdir -p ~/.ssh
|
|
echo "${{ secrets.SYNOLOGY_SSH_KEY }}" > ~/.ssh/synology_key
|
|
chmod 600 ~/.ssh/synology_key
|
|
ssh-keyscan -H ${{ secrets.SYNOLOGY_HOST }} >> ~/.ssh/known_hosts
|
|
|
|
- name: Copy Files to Synology
|
|
run: |
|
|
# Transfer Docker Image
|
|
scp -i ~/.ssh/synology_key laravel-app.tar.gz \
|
|
${{ secrets.SYNOLOGY_USER }}@${{ secrets.SYNOLOGY_HOST }}:/volume1/docker/laravel-app/
|
|
|
|
# Transfer Docker Compose file
|
|
scp -i ~/.ssh/synology_key docker-compose.synology.yml \
|
|
${{ secrets.SYNOLOGY_USER }}@${{ secrets.SYNOLOGY_HOST }}:/volume1/docker/laravel-app/
|
|
|
|
# Transfer deployment script
|
|
scp -i ~/.ssh/synology_key scripts/deploy-synology.sh \
|
|
${{ secrets.SYNOLOGY_USER }}@${{ secrets.SYNOLOGY_HOST }}:/volume1/docker/laravel-app/
|
|
|
|
- name: Deploy on Synology
|
|
run: |
|
|
ssh -i ~/.ssh/synology_key \
|
|
${{ secrets.SYNOLOGY_USER }}@${{ secrets.SYNOLOGY_HOST }} \
|
|
"cd /volume1/docker/laravel-app && chmod +x deploy-synology.sh && ./deploy-synology.sh"
|
|
|
|
- name: Health Check
|
|
run: |
|
|
sleep 10 # Wait for container to start
|
|
|
|
# Check if the app is responding
|
|
SYNOLOGY_IP="${{ secrets.SYNOLOGY_HOST }}"
|
|
MAX_RETRIES=30
|
|
RETRY_COUNT=0
|
|
|
|
while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
|
|
if curl -f -s http://$SYNOLOGY_IP:8080/health > /dev/null 2>&1; then
|
|
echo "✅ Application is healthy!"
|
|
exit 0
|
|
fi
|
|
|
|
echo "⏳ Waiting for application to be ready... ($RETRY_COUNT/$MAX_RETRIES)"
|
|
sleep 5
|
|
RETRY_COUNT=$((RETRY_COUNT + 1))
|
|
done
|
|
|
|
echo "❌ Health check failed after $MAX_RETRIES attempts"
|
|
exit 1
|
|
|
|
- name: Cleanup
|
|
if: always()
|
|
run: |
|
|
rm -f ~/.ssh/synology_key
|
|
ssh -i ~/.ssh/synology_key \
|
|
${{ secrets.SYNOLOGY_USER }}@${{ secrets.SYNOLOGY_HOST }} \
|
|
"rm -f /volume1/docker/laravel-app/laravel-app.tar.gz" || true
|
|
|
|
# Job 4: Notify on Success/Failure (optional)
|
|
notify:
|
|
runs-on: ubuntu-latest
|
|
needs: [test, build, deploy]
|
|
if: always()
|
|
|
|
steps:
|
|
- name: Deployment Status
|
|
run: |
|
|
if [ "${{ needs.deploy.result }}" == "success" ]; then
|
|
echo "✅ Deployment to Synology NAS successful!"
|
|
echo "🌐 Application available at: http://${{ secrets.SYNOLOGY_HOST }}:8080"
|
|
else
|
|
echo "❌ Deployment failed. Check the logs for details."
|
|
exit 1
|
|
fi
|