Skip to content

Merge branch 'main' into claude/update-prod-runner-script-Lq2gS #16

Merge branch 'main' into claude/update-prod-runner-script-Lq2gS

Merge branch 'main' into claude/update-prod-runner-script-Lq2gS #16

Workflow file for this run

name: Deploy
on:
push:
branches: [main]
workflow_dispatch:
permissions:
contents: read
env:
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
AFFILIATE_SOURCE: GambleCodez
ADMIN_IDS: "6668510825"
DISCORD_CODE_GENERATION_IMAGE_URL: "https://github.com/gamblecodezcom/Runewager/blob/38c1bbab2d954238829852981514ce92c49d8b10/images/discord_code_generation.png"
DISCORD_VERIFY_IMAGE_URL: "https://github.com/gamblecodezcom/Runewager/blob/38c1bbab2d954238829852981514ce92c49d8b10/images/discord_verify.png"
MAX_ANALYTICS_EVENTS: "2000"
MAX_ONBOARDING_STEPS_HISTORY: "500"
MINI_APP_CLAIM_URL: "https://t.me/RuneWager_bot/claim"
MINI_APP_PLAY_URL: "https://t.me/RuneWager_bot/Play"
MINI_APP_PROFILE_URL: "https://t.me/RuneWager_bot/profile"
PORT: "3000"
PROMO_AMOUNT_SC: "3.5"
PROMO_BONUS_RULE: "Bonus added once your account is verified and meets eligibility requirements. Limit once per account/IP. New users are defined as accounts that have never redeemed a promo code before."
PROMO_CLAIM_LIMIT: "600"
PROMO_CODE: SPORTS3.5
PROMO_ENTRY_IMAGE_URL: "https://github.com/gamblecodezcom/Runewager/blob/225428f813f2b3caf74f9716fff4b13ef0b74992/images/promo_entry.png"
RW_DISCORD_JOIN: "https://discord.gg/runewagers"
RW_DISCORD_LINK: "https://discord.com/channels/1100486422395355197/1249181934811349052"
RW_DISCORD_SUPPORT: "https://discord.com/channels/1100486422395355197/1249182067296567338"
DEPLOY_MODE: normal
jobs:
quality-gates:
name: Quality Gates
runs-on: ubuntu-latest
outputs:
commit_hash: ${{ steps.meta.outputs.commit_hash }}
deploy_time: ${{ steps.meta.outputs.deploy_time }}
version: ${{ steps.meta.outputs.version }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install deps
run: npm ci
- name: Build metadata
id: meta
run: |
echo "commit_hash=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT"
echo "deploy_time=$(date -u '+%Y-%m-%dT%H:%M:%SZ')" >> "$GITHUB_OUTPUT"
echo "version=$(node -p "require('./package.json').version")" >> "$GITHUB_OUTPUT"
- name: Syntax check
run: npm run check
- name: Tests
run: npm test
- name: Security audit (non-blocking)
run: npm audit --audit-level=high || true
- name: Notify deploy start
env:
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
run: |
chmod +x scripts/notify-telegram.sh
./scripts/notify-telegram.sh \
"πŸš€ *Deploy Starting*

Check failure on line 76 in .github/workflows/deploy.yml

View workflow run for this annotation

GitHub Actions / .github/workflows/deploy.yml

Invalid workflow file

You have an error in your yaml syntax on line 76
Repo: \`${{ github.repository }}\`
Branch: \`${{ github.ref_name }}\`
Commit: \`${{ steps.meta.outputs.commit_hash }}\`
Version: \`${{ steps.meta.outputs.version }}\`
Mode: \`${DEPLOY_MODE}\`
By: \`${{ github.actor }}\`"
deploy:
name: Deploy to VPS
runs-on: ubuntu-latest
needs: quality-gates
environment:
name: production
steps:
- uses: actions/checkout@v4
- name: Setup SSH
env:
SERVER_KEY: ${{ secrets.SERVER_KEY }}
SERVER_HOST: ${{ secrets.SERVER_HOST }}
run: |
mkdir -p ~/.ssh
chmod 700 ~/.ssh
printf '%s\n' "$SERVER_KEY" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
ssh-keyscan -H "$SERVER_HOST" >> ~/.ssh/known_hosts
cat >> ~/.ssh/config <<EOF
Host deploy_target
HostName $SERVER_HOST
User ${{ secrets.SERVER_USER }}
IdentityFile ~/.ssh/deploy_key
StrictHostKeyChecking yes
ConnectTimeout 15
EOF
- name: Save pre-deploy SHA
id: pre
run: |
SHA=$(ssh deploy_target "cd /var/www/html/Runewager && git rev-parse HEAD || echo none")
echo "sha=$SHA" >> "$GITHUB_OUTPUT"
- name: Pre-deploy health snapshot
run: |
ssh deploy_target "
set -e
cd /var/www/html/Runewager
echo 'Checking .env exists...'
if [ ! -f .env ]; then
echo 'ERROR: .env missing on VPS' >&2
exit 1
fi
echo 'Checking port 3000 usage...'
lsof -i :3000 || true
echo 'Checking memory/disk...'
free -m || true
df -h . || true
"
- name: Deploy (git pull origin main only)
run: |
ssh deploy_target "
set -e
cd /var/www/html/Runewager
git fetch origin main
git reset --hard origin/main
echo 'Updated to:' \$(git rev-parse --short HEAD)
"
- name: Install deps on VPS
run: |
ssh deploy_target "
cd /var/www/html/Runewager
npm ci --omit=dev
"
- name: Validate Node + Telegram + mini-apps
env:
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
run: |
ssh deploy_target "
set -e
cd /var/www/html/Runewager
echo 'Checking Node version...'
NODE_VER=\$(node -v)
NODE_MAJOR=\$(echo \$NODE_VER | sed 's/v\([0-9]*\).*/\1/')
if [ \"\$NODE_MAJOR\" -lt 20 ]; then
echo 'ERROR: Node 20+ required, found' \$NODE_VER
exit 1
fi
echo 'Checking Telegram API...'
curl -fsS --max-time 5 \"https://api.telegram.org/bot${{ secrets.BOT_TOKEN }}/getMe\" >/dev/null || {
echo 'ERROR: Telegram API not reachable'
exit 1
}
echo 'Checking mini-app endpoints...'
curl -fsS --max-time 5 '${{ env.MINI_APP_PLAY_URL }}' >/dev/null || echo 'WARN: MINI_APP_PLAY_URL not responding'
curl -fsS --max-time 5 '${{ env.MINI_APP_CLAIM_URL }}' >/dev/null || echo 'WARN: MINI_APP_CLAIM_URL not responding'
curl -fsS --max-time 5 '${{ env.MINI_APP_PROFILE_URL }}' >/dev/null || echo 'WARN: MINI_APP_PROFILE_URL not responding'
"
- name: Wait 15 seconds
run: sleep 15
- name: Restart service (systemd β†’ prod-run.sh fallback)
id: restart
run: |
ssh deploy_target "
cd /var/www/html/Runewager
echo 'Trying systemd restart...'
if systemctl restart runewager.service 2>/dev/null; then
sleep 5
if systemctl is-active runewager.service >/dev/null; then
echo 'Systemd restart OK'
exit 0
fi
fi
echo 'Systemd failed β€” trying prod-run.sh restart...'
if bash prod-run.sh restart 2>/dev/null; then
echo 'prod-run.sh restart OK'
exit 0
fi
echo 'Both restart methods failed'
exit 1
"
- name: Health + status check
run: |
ssh deploy_target "
set -e
cd /var/www/html/Runewager
if [ -x ./health-check.sh ]; then
./health-check.sh --status
else
curl -fsS http://127.0.0.1:3000/health >/dev/null
fi
"
- name: Notify success
if: success()
env:
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
run: |
chmod +x scripts/notify-telegram.sh
./scripts/notify-telegram.sh \
"βœ… *Deploy Successful*
Commit: \`${{ needs.quality-gates.outputs.commit_hash }}\`
Version: \`${{ needs.quality-gates.outputs.version }}\`
Time: \`${{ needs.quality-gates.outputs.deploy_time }}\`"
- name: Rollback on failure
if: failure()
env:
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
run: |
PRE="${{ steps.pre.outputs.sha }}"
chmod +x scripts/notify-telegram.sh
./scripts/notify-telegram.sh \
"❌ *Deploy Failed β€” Rolling Back*
Previous SHA: \`${PRE}\`"
ssh deploy_target "
cd /var/www/html/Runewager
if [ \"$PRE\" != \"none\" ] && [ -n \"$PRE\" ]; then
git reset --hard $PRE
npm ci --omit=dev || true
systemctl restart runewager.service || bash prod-run.sh restart || true
else
echo 'No previous SHA recorded, skipping git rollback'
fi
"
./scripts/notify-telegram.sh \
"πŸ”„ *Rollback Complete*
Restored to: \`${PRE}\`"