generated from haoqimao/MatchU--
Push to dev triggers docker compose build/deploy on label-ac-1 runner. Co-authored-by: Cursor <cursoragent@cursor.com>
131 lines
4.2 KiB
YAML
131 lines
4.2 KiB
YAML
name: Deploy
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- dev
|
|
|
|
jobs:
|
|
deploy:
|
|
name: Build and deploy
|
|
runs-on: label-ac-1
|
|
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Prepare environment
|
|
env:
|
|
PROD_ENV_FILE: ${{ secrets.PROD_ENV_FILE }}
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
install_pkg() {
|
|
if command -v dnf >/dev/null 2>&1; then
|
|
dnf install -y "$@"
|
|
elif command -v apt-get >/dev/null 2>&1; then
|
|
apt-get update -qq && apt-get install -y "$@"
|
|
elif command -v yum >/dev/null 2>&1; then
|
|
yum install -y "$@"
|
|
elif command -v apk >/dev/null 2>&1; then
|
|
apk add --no-cache "$@"
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
if [ -n "${PROD_ENV_FILE:-}" ]; then
|
|
umask 077
|
|
printf '%s\n' "$PROD_ENV_FILE" > .env
|
|
fi
|
|
test -f .env || {
|
|
echo "Missing .env. Add a Gitea secret named PROD_ENV_FILE with the full .env content (see .env.vps.example)."
|
|
exit 1
|
|
}
|
|
if ! command -v docker >/dev/null 2>&1; then
|
|
echo "Docker not found. On the host run once: bash deploy/scripts/bootstrap-server.sh"
|
|
exit 1
|
|
fi
|
|
|
|
if ! docker compose version >/dev/null 2>&1; then
|
|
echo "==> 安装 docker compose v2 plugin..."
|
|
if ! install_pkg docker-compose-plugin; then
|
|
echo "==> 包源没有 docker-compose-plugin,回退到下载官方二进制..."
|
|
case "$(uname -m)" in
|
|
x86_64) COMPOSE_ARCH=x86_64 ;;
|
|
aarch64|arm64) COMPOSE_ARCH=aarch64 ;;
|
|
*) echo "不支持的架构: $(uname -m)"; exit 1 ;;
|
|
esac
|
|
PLUGIN_DIR=/usr/local/lib/docker/cli-plugins
|
|
mkdir -p "$PLUGIN_DIR"
|
|
curl -fsSL -o "$PLUGIN_DIR/docker-compose" \
|
|
"https://github.com/docker/compose/releases/latest/download/docker-compose-linux-$COMPOSE_ARCH"
|
|
chmod +x "$PLUGIN_DIR/docker-compose"
|
|
fi
|
|
docker compose version
|
|
fi
|
|
|
|
- name: Show Docker info
|
|
run: |
|
|
docker --version
|
|
docker compose version
|
|
|
|
- name: Build images
|
|
run: docker compose build matchu
|
|
|
|
- name: Start services
|
|
run: docker compose up -d --build --remove-orphans
|
|
|
|
- name: Health check
|
|
run: |
|
|
set -euo pipefail
|
|
for i in $(seq 1 15); do
|
|
if docker compose ps matchu --format '{{.State}}' 2>/dev/null | grep -q running; then
|
|
break
|
|
fi
|
|
echo "Waiting for matchu container to start... ($i/15)"
|
|
sleep 2
|
|
done
|
|
docker compose exec -T matchu node - <<'NODE'
|
|
const http = require('http');
|
|
|
|
function probe() {
|
|
return new Promise((resolve, reject) => {
|
|
const req = http.get('http://127.0.0.1:3000/api/status', { timeout: 3000 }, (res) => {
|
|
let body = '';
|
|
res.on('data', (c) => { body += c; });
|
|
res.on('end', () => {
|
|
try {
|
|
const data = JSON.parse(body);
|
|
if (data.ok === true) resolve(data);
|
|
else reject(new Error(`status ok=${data.ok}`));
|
|
} catch (e) {
|
|
reject(e);
|
|
}
|
|
});
|
|
});
|
|
req.on('error', reject);
|
|
req.on('timeout', () => { req.destroy(); reject(new Error('timeout')); });
|
|
});
|
|
}
|
|
|
|
(async () => {
|
|
let last;
|
|
for (let i = 0; i < 30; i++) {
|
|
try {
|
|
await probe();
|
|
console.log('matchu health ok');
|
|
return;
|
|
} catch (e) {
|
|
last = e;
|
|
await new Promise((r) => setTimeout(r, 2000));
|
|
}
|
|
}
|
|
throw last;
|
|
})().catch((e) => {
|
|
console.error('matchu health check failed:', e);
|
|
process.exit(1);
|
|
});
|
|
NODE
|
|
docker compose ps
|