ci: simplify Gitea admin deploy for act_runner
Some checks failed
Deploy admin to VPS / Build, push, and deploy admin (push) Has been cancelled
Some checks failed
Deploy admin to VPS / Build, push, and deploy admin (push) Has been cancelled
Single-job build/push/deploy plus nginx site install so self-hosted runners do not stall on multi-job graphs.
This commit is contained in:
parent
a307400f83
commit
ba1cf3efe2
@ -1,5 +1,7 @@
|
||||
name: Deploy admin to VPS
|
||||
|
||||
# Single-job flow — Gitea act_runner is more reliable without multi-job graphs
|
||||
# (same lesson as telegrambot deploy). Quality still runs on pull_request.
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
@ -9,62 +11,11 @@ concurrency:
|
||||
group: deploy-admin-production
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
# PR merges: build + deploy only (quality ran on pull_request).
|
||||
# Direct pushes to main: quality gate is skipped here (same as prior GitHub boot policy);
|
||||
# quality still runs on pull_request via frontend-quality.yml.
|
||||
jobs:
|
||||
gate:
|
||||
name: Detect direct push to main
|
||||
deploy:
|
||||
name: Build, push, and deploy admin
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
run_quality: ${{ steps.detect.outputs.run_quality }}
|
||||
steps:
|
||||
- id: detect
|
||||
env:
|
||||
# Via env — never interpolate commit text into the script body
|
||||
# (backticks/`$()` in messages would otherwise become shell command substitution).
|
||||
EVENT_NAME: ${{ github.event_name }}
|
||||
COMMIT_MSG: ${{ github.event.head_commit.message || '' }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if [ "$EVENT_NAME" = "workflow_dispatch" ]; then
|
||||
echo "run_quality=false" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
msg="$COMMIT_MSG"
|
||||
if printf '%s' "$msg" | grep -qiE 'merge pull request #[0-9]+'; then
|
||||
echo "run_quality=false" >> "$GITHUB_OUTPUT"
|
||||
elif printf '%s' "$msg" | grep -qE '\(#[0-9]+\)[[:space:]]*$'; then
|
||||
echo "run_quality=false" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
# Admin boot: deploy first; quality runs on pull_request workflow.
|
||||
echo "Direct push to main — skipping quality gate for deploy."
|
||||
echo "run_quality=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
quality:
|
||||
needs: gate
|
||||
if: needs.gate.outputs.run_quality == 'true'
|
||||
uses: ./.gitea/workflows/frontend-quality.yml
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
|
||||
build:
|
||||
name: Build and push admin image
|
||||
needs: [gate, quality]
|
||||
if: >-
|
||||
always() &&
|
||||
needs.gate.result == 'success' &&
|
||||
(needs.quality.result == 'success' || needs.quality.result == 'skipped')
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
outputs:
|
||||
image: ${{ steps.meta.outputs.image }}
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
@ -74,7 +25,6 @@ jobs:
|
||||
set -euo pipefail
|
||||
owner="$(echo '${{ github.repository_owner }}' | tr '[:upper:]' '[:lower:]')"
|
||||
repo="$(echo '${{ github.event.repository.name }}' | tr '[:upper:]' '[:lower:]')"
|
||||
# Gitea container registry (same host as git.ghabilee.ir)
|
||||
echo "image=git.ghabilee.ir/${owner}/${repo}" >> "$GITHUB_OUTPUT"
|
||||
echo "registry=git.ghabilee.ir" >> "$GITHUB_OUTPUT"
|
||||
|
||||
@ -94,7 +44,24 @@ jobs:
|
||||
scp -i "$HOME/.ssh/vps_key" -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new \
|
||||
"${VPS_USER}@${VPS_HOST}:${env_path}" .env.production
|
||||
test -s .env.production
|
||||
rm -f "$HOME/.ssh/vps_key"
|
||||
|
||||
- name: Install nginx site definition on VPS
|
||||
env:
|
||||
SSH_KEY: ${{ secrets.VPS_SSH_KEY }}
|
||||
VPS_HOST: ${{ secrets.VPS_HOST }}
|
||||
VPS_USER: ${{ secrets.VPS_USER }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
SSH=(ssh -i "$HOME/.ssh/vps_key" -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new)
|
||||
scp -i "$HOME/.ssh/vps_key" -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new \
|
||||
deploy/nginx/backoffice.conf \
|
||||
"${VPS_USER}@${VPS_HOST}:/etc/nginx/sites-available/backoffice"
|
||||
"${SSH[@]}" "${VPS_USER}@${VPS_HOST}" '
|
||||
set -eu
|
||||
ln -sfn /etc/nginx/sites-available/backoffice /etc/nginx/sites-enabled/backoffice
|
||||
nginx -t
|
||||
systemctl reload nginx
|
||||
'
|
||||
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
|
||||
@ -112,42 +79,16 @@ jobs:
|
||||
IMAGE_TAG: ${{ github.sha }}
|
||||
run: ./scripts/ci-build-image.sh
|
||||
|
||||
- name: Remove production build environment
|
||||
if: always()
|
||||
run: rm -f .env.production
|
||||
|
||||
deploy:
|
||||
name: Stage or deploy admin
|
||||
needs: build
|
||||
if: ${{ !cancelled() && needs.build.result == 'success' }}
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 25
|
||||
permissions:
|
||||
contents: read
|
||||
packages: read
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Copy Compose definition and deploy
|
||||
- name: Deploy container on VPS
|
||||
env:
|
||||
REGISTRY_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
REGISTRY_USER: ${{ github.actor }}
|
||||
REGISTRY_HOST: git.ghabilee.ir
|
||||
ADMIN_IMAGE: ${{ needs.build.outputs.image }}:${{ github.sha }}
|
||||
ADMIN_IMAGE: ${{ steps.meta.outputs.image }}:${{ github.sha }}
|
||||
VPS_HOST: ${{ secrets.VPS_HOST }}
|
||||
VPS_USER: ${{ secrets.VPS_USER }}
|
||||
SSH_KEY: ${{ secrets.VPS_SSH_KEY }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
install -m 700 -d "$HOME/.ssh"
|
||||
printf '%s\n' "$SSH_KEY" > "$HOME/.ssh/vps_key"
|
||||
chmod 600 "$HOME/.ssh/vps_key"
|
||||
ssh -i "$HOME/.ssh/vps_key" -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new \
|
||||
"${VPS_USER}@${VPS_HOST}" '
|
||||
set -eu
|
||||
install -d -m 0750 /opt/ghabilee-admin
|
||||
test -s /opt/ghabilee-admin/.env
|
||||
'
|
||||
scp -i "$HOME/.ssh/vps_key" -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new \
|
||||
deploy/docker-compose.production.yml \
|
||||
"${VPS_USER}@${VPS_HOST}:/opt/ghabilee-admin/docker-compose.yml"
|
||||
@ -163,7 +104,6 @@ jobs:
|
||||
health="$(docker inspect --format '{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}' ghabilee-admin 2>/dev/null || echo missing)"
|
||||
echo "Admin health ${attempt}/36: ${health}"
|
||||
if [ "$health" = healthy ]; then
|
||||
# فقط بعد از healthy: ایمیجهای unused (تگهای قبلی) را پاک کن؛ volumeها دست نخورند
|
||||
if [ -x /opt/ghabilee/scripts/docker-prune.sh ]; then
|
||||
/opt/ghabilee/scripts/docker-prune.sh full
|
||||
else
|
||||
@ -176,50 +116,23 @@ jobs:
|
||||
done
|
||||
exit 1
|
||||
REMOTE
|
||||
rm -f "$HOME/.ssh/vps_key"
|
||||
|
||||
notify-success:
|
||||
name: Notify Telegram (success)
|
||||
needs: deploy
|
||||
# `quality` is intentionally skipped after PR merges. `success()` treats
|
||||
# that skipped upstream job as non-success and would skip this job too.
|
||||
if: ${{ always() && needs.deploy.result == 'success' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Notify ops group of successful admin deploy
|
||||
- name: Notify Telegram
|
||||
if: always()
|
||||
env:
|
||||
DEPLOY_SHA: ${{ github.sha }}
|
||||
DEPLOY_STATUS: success
|
||||
DEPLOY_STATUS: ${{ job.status }}
|
||||
DEPLOY_COMMIT_SUBJECT: ${{ github.event.head_commit.message }}
|
||||
SSH_KEY: ${{ secrets.VPS_SSH_KEY }}
|
||||
VPS_HOST: ${{ secrets.VPS_HOST }}
|
||||
VPS_USER: ${{ secrets.VPS_USER }}
|
||||
run: |
|
||||
export DEPLOY_VERSION="$(node -p "require('./package.json').version")"
|
||||
chmod +x scripts/notify-via-vps.sh scripts/notify-ops-telegram.sh scripts/notify-deploy.sh
|
||||
./scripts/notify-via-vps.sh
|
||||
|
||||
notify-failed:
|
||||
name: Notify Telegram (failed)
|
||||
needs: [gate, quality, build, deploy]
|
||||
if: failure()
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Notify ops group of failed admin deploy
|
||||
env:
|
||||
DEPLOY_SHA: ${{ github.sha }}
|
||||
DEPLOY_STATUS: failed
|
||||
DEPLOY_COMMIT_SUBJECT: ${{ github.event.head_commit.message }}
|
||||
SSH_KEY: ${{ secrets.VPS_SSH_KEY }}
|
||||
VPS_HOST: ${{ secrets.VPS_HOST }}
|
||||
VPS_USER: ${{ secrets.VPS_USER }}
|
||||
run: |
|
||||
# Do not gate on -x: notify-via-vps.sh may be 100644 in git; chmod first
|
||||
# (the old `if [[ -x ... ]]` skipped the whole notify and still exited 0).
|
||||
export DEPLOY_VERSION="$(node -p "require('./package.json').version" 2>/dev/null || echo '?')"
|
||||
chmod +x scripts/notify-via-vps.sh scripts/notify-ops-telegram.sh scripts/notify-deploy.sh
|
||||
./scripts/notify-via-vps.sh
|
||||
# Map Gitea job.status to notify script expectations
|
||||
case "${DEPLOY_STATUS}" in
|
||||
success) export DEPLOY_STATUS=success ;;
|
||||
*) export DEPLOY_STATUS=failed ;;
|
||||
esac
|
||||
chmod +x scripts/notify-via-vps.sh scripts/notify-ops-telegram.sh scripts/notify-deploy.sh || true
|
||||
./scripts/notify-via-vps.sh || true
|
||||
rm -f .env.production "$HOME/.ssh/vps_key"
|
||||
|
||||
35
deploy/nginx/backoffice.conf
Normal file
35
deploy/nginx/backoffice.conf
Normal file
@ -0,0 +1,35 @@
|
||||
# Admin backoffice — TLS terminated by Nginx, app on 127.0.0.1:3009
|
||||
# DNS: point backoffice.ghabilee.ir at this VPS, then:
|
||||
# certbot --nginx -d backoffice.ghabilee.ir
|
||||
|
||||
map $http_upgrade $connection_upgrade {
|
||||
default upgrade;
|
||||
'' close;
|
||||
}
|
||||
|
||||
upstream ghabilee_admin {
|
||||
server 127.0.0.1:3009;
|
||||
keepalive 16;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name backoffice.ghabilee.ir;
|
||||
|
||||
location /.well-known/acme-challenge/ {
|
||||
root /var/www/html;
|
||||
}
|
||||
|
||||
location / {
|
||||
proxy_pass http://ghabilee_admin;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_read_timeout 60s;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user