136 lines
4.3 KiB
YAML
136 lines
4.3 KiB
YAML
name: UI – CI/CD
|
||
|
||
on:
|
||
workflow_dispatch:
|
||
push:
|
||
paths:
|
||
- ui/**
|
||
- .github/workflows/ui.yml
|
||
pull_request:
|
||
branches: [main]
|
||
paths:
|
||
- ui/**
|
||
- .github/workflows/ui.yml
|
||
|
||
env:
|
||
IMAGE: ghcr.io/${{ github.repository_owner }}/dashboard-ui
|
||
# IMAGE_LC is set in the docker job (owner must be lowercase for Docker)
|
||
|
||
jobs:
|
||
# ── 1. Build & test ──────────────────────────────────────────────────────────
|
||
ci:
|
||
name: Build & test
|
||
runs-on: ubuntu-latest
|
||
defaults:
|
||
run:
|
||
working-directory: ui
|
||
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Setup Node 20
|
||
uses: actions/setup-node@v4
|
||
with:
|
||
node-version: 20
|
||
cache: npm
|
||
cache-dependency-path: ui/package-lock.json
|
||
|
||
- name: Install dependencies
|
||
run: npm ci
|
||
|
||
- name: Lint
|
||
run: npm run lint
|
||
|
||
- name: Unit tests
|
||
run: npm test -- --watch=false --browsers=ChromeHeadless
|
||
|
||
- name: Inject API credentials
|
||
run: |
|
||
sed -i "s/__API_USERNAME__/${{ secrets.API_USERNAME }}/g" src/environments/environment.prod.ts
|
||
sed -i "s/__API_PASSWORD__/${{ secrets.API_PASSWORD }}/g" src/environments/environment.prod.ts
|
||
|
||
- name: Production build
|
||
run: npm run build -- --configuration production
|
||
|
||
# ── 2. Docker build & push ───────────────────────────────────────────────────
|
||
docker:
|
||
name: Docker build & push
|
||
runs-on: ubuntu-latest
|
||
needs: ci
|
||
if: github.ref == 'refs/heads/main'
|
||
outputs:
|
||
sha_tag: ${{ steps.tag.outputs.sha }}
|
||
|
||
permissions:
|
||
contents: read
|
||
packages: write
|
||
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Compute image tags
|
||
id: tag
|
||
run: |
|
||
OWNER="${{ github.repository_owner }}"
|
||
IMAGE_LC="ghcr.io/${OWNER,,}/dashboard-ui"
|
||
echo "image=${IMAGE_LC}" >> $GITHUB_OUTPUT
|
||
echo "sha=${IMAGE_LC}:${{ github.sha }}" >> $GITHUB_OUTPUT
|
||
BRANCH="${{ github.head_ref || github.ref_name }}"
|
||
SAFE="${BRANCH//\//-}"
|
||
if [ "${{ github.ref }}" = "refs/heads/main" ]; then
|
||
echo "extra=${IMAGE_LC}:latest" >> $GITHUB_OUTPUT
|
||
else
|
||
echo "extra=${IMAGE_LC}:branch-${SAFE}" >> $GITHUB_OUTPUT
|
||
fi
|
||
|
||
- name: Inject API credentials
|
||
run: |
|
||
sed -i "s/__API_USERNAME__/${{ secrets.API_USERNAME }}/g" ui/src/environments/environment.prod.ts
|
||
sed -i "s/__API_PASSWORD__/${{ secrets.API_PASSWORD }}/g" ui/src/environments/environment.prod.ts
|
||
|
||
- name: Login to GHCR
|
||
uses: docker/login-action@v3
|
||
with:
|
||
registry: ghcr.io
|
||
username: ${{ github.actor }}
|
||
password: ${{ secrets.GITHUB_TOKEN }}
|
||
|
||
- name: Build & push
|
||
uses: docker/build-push-action@v5
|
||
with:
|
||
context: ui
|
||
push: true
|
||
tags: |
|
||
${{ steps.tag.outputs.sha }}
|
||
${{ steps.tag.outputs.extra }}
|
||
|
||
# ── 3. Deploy to physical server (SSH) ───────────────────────────────────────
|
||
deploy:
|
||
name: Deploy
|
||
runs-on: ubuntu-latest
|
||
needs: docker
|
||
if: github.ref == 'refs/heads/main'
|
||
|
||
steps:
|
||
- name: SSH deploy
|
||
env:
|
||
SSH_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
|
||
SSH_CERT: ${{ secrets.SSH_CERTIFICATE }}
|
||
SHA_TAG: ${{ needs.docker.outputs.sha_tag }}
|
||
run: |
|
||
echo "$SSH_KEY" > /tmp/deploy_key
|
||
echo "$SSH_CERT" > /tmp/deploy_key-cert.pub
|
||
chmod 600 /tmp/deploy_key
|
||
ssh -i /tmp/deploy_key \
|
||
-p ${{ secrets.SSH_PORT }} \
|
||
-o StrictHostKeyChecking=no \
|
||
-o IdentitiesOnly=yes \
|
||
${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} \
|
||
"sudo -iu e << 'EOF'
|
||
docker pull $SHA_TAG
|
||
docker stop dashboard-ui 2>/dev/null || true
|
||
docker rm dashboard-ui 2>/dev/null || true
|
||
docker run -d --name dashboard-ui --restart unless-stopped -p 80:80 $SHA_TAG
|
||
EOF"
|
||
rm /tmp/deploy_key /tmp/deploy_key-cert.pub
|