1- name : Deploy
1+ name : Build, Test and Deploy Discord Bot to VPS
22
33on :
44 workflow_dispatch : # Manual trigger only
1010 # - '.gitignore'
1111 # - 'LICENSE'
1212
13- concurrency :
14- group : ${{ github.workflow }}-${{ github.ref }}
15- cancel-in-progress : false
16-
1713jobs :
18- build-test-and- deploy :
14+ build-test-deploy :
1915 runs-on : ubuntu-latest
16+
2017 steps :
21- - name : Checkout
18+ - name : Checkout code
2219 uses : actions/checkout@v4
2320
24- - name : Setup Node.js
21+ - name : Set up Node
2522 uses : actions/setup-node@v4
2623 with :
2724 node-version-file : .nvmrc
2825
2926 - name : Install dependencies
30- run : |
31- if [ -f package-lock.json ]; then
32- npm ci --no-audit --no-fund
33- else
34- npm install --no-audit --no-fund
35- fi
27+ run : npm ci
3628
3729 - name : Lint
3830 run : npm run lint
3931
40- - name : Build
32+ - name : Build bot
4133 run : npm run build:ci
42- env :
43- DISCORD_TOKEN : ${{ secrets.DISCORD_TOKEN }}
44- CLIENT_ID : ${{ secrets.CLIENT_ID }}
4534
4635 - name : Run tests
47- run : npm run test:ci
48-
49- - name : Package artifact
50- run : |
51- tar -czf release.tar.gz dist package.json package-lock.json .nvmrc || tar -czf release.tar.gz dist package.json .nvmrc
52-
53- - name : Create .env file from secrets
54- env :
55- DISCORD_TOKEN : ${{ secrets.DISCORD_TOKEN }}
56- CLIENT_ID : ${{ secrets.CLIENT_ID }}
57- run : |
58- set -euo pipefail
59- printf "DISCORD_TOKEN=%s\n" "$DISCORD_TOKEN" > .env
60- printf "CLIENT_ID=%s\n" "$CLIENT_ID" >> .env
61- printf "NODE_ENV=production\n" >> .env
36+ run : npm test:ci
6237
63- - name : Copy artifact to VPS
64- env :
65- SSH_HOST : ${{ secrets.SSH_HOST }}
66- SSH_USER : ${{ secrets.SSH_USER }}
67- SSH_PORT : ${{ secrets.SSH_PORT }}
68- SSH_KEY : ${{ secrets.SSH_KEY }}
69- run : |
70- mkdir -p ~/.ssh
71- echo "$SSH_KEY" > ~/.ssh/id_ed25519
72- chmod 600 ~/.ssh/id_ed25519
73- ssh -o StrictHostKeyChecking=no -i ~/.ssh/id_ed25519 -p ${SSH_PORT:-22} $SSH_USER@$SSH_HOST "mkdir -p ~/apps/webdev-bot/releases"
74- scp -i ~/.ssh/id_ed25519 -P ${SSH_PORT:-22} -o StrictHostKeyChecking=no release.tar.gz $SSH_USER@$SSH_HOST:~/apps/webdev-bot/releases/release.tar.gz
38+ - name : Package build output
39+ run : tar czf bot-build.tar.gz ./dist
7540
76- - name : Upload .env to VPS
77- env :
78- SSH_HOST : ${{ secrets.SSH_HOST }}
79- SSH_USER : ${{ secrets.SSH_USER }}
80- SSH_PORT : ${{ secrets.SSH_PORT }}
81- SSH_KEY : ${{ secrets.SSH_KEY }}
82- APP_DIR : ${{ secrets.APP_DIR }}
83- run : |
84- mkdir -p ~/.ssh
85- echo "$SSH_KEY" > ~/.ssh/id_ed25519
86- chmod 600 ~/.ssh/id_ed25519
87- ssh -o StrictHostKeyChecking=no -i ~/.ssh/id_ed25519 -p ${SSH_PORT:-22} $SSH_USER@$SSH_HOST "mkdir -p ${APP_DIR:-\"~/apps/webdev-bot\"}/shared && chmod 700 ${APP_DIR:-\"~/apps/webdev-bot\"}/shared"
88- scp -i ~/.ssh/id_ed25519 -P ${SSH_PORT:-22} -o StrictHostKeyChecking=no .env $SSH_USER@$SSH_HOST:${APP_DIR:-"~/apps/webdev-bot"}/shared/.env
89- ssh -o StrictHostKeyChecking=no -i ~/.ssh/id_ed25519 -p ${SSH_PORT:-22} $SSH_USER@$SSH_HOST "chmod 600 ${APP_DIR:-\"~/apps/webdev-bot\"}/shared/.env"
41+ - name : Copy build artifact to VPS
42+ uses : appleboy/scp-action@v0.1.7
43+ with :
44+ host : ${{ secrets.VPS_HOST }}
45+ username : ${{ secrets.VPS_USER }}
46+ key : ${{ secrets.VPS_SSH_KEY }}
47+ source : " bot-build.tar.gz"
48+ target : " /home/${{ secrets.VPS_USER }}/discord-bot/"
9049
91- - name : Deploy on VPS
92- env :
93- SSH_HOST : ${{ secrets.SSH_HOST }}
94- SSH_USER : ${{ secrets.SSH_USER }}
95- SSH_PORT : ${{ secrets.SSH_PORT }}
96- SSH_KEY : ${{ secrets.SSH_KEY }}
97- APP_DIR : ${{ secrets.APP_DIR }}
98- run : |
99- mkdir -p ~/.ssh
100- echo "$SSH_KEY" > ~/.ssh/id_ed25519
101- chmod 600 ~/.ssh/id_ed25519
102- ssh -o StrictHostKeyChecking=no -i ~/.ssh/id_ed25519 -p ${SSH_PORT:-22} $SSH_USER@$SSH_HOST << 'EOF'
103- set -euo pipefail
104- APP_DIR=${APP_DIR:-"~/apps/webdev-bot"}
105- mkdir -p "$APP_DIR/current" "$APP_DIR/releases" "$APP_DIR/shared"
106- cd "$APP_DIR"
107- rm -rf current/*
108- tar -xzf releases/release.tar.gz -C current
109- cd current
110- # Load env from shared/.env for the PM2 process
111- set -a
112- if [ -f "$APP_DIR/shared/.env" ]; then . "$APP_DIR/shared/.env"; fi
113- set +a
114- if [ -f package-lock.json ]; then
115- npm ci --omit=dev --no-audit --no-fund || true
116- else
117- npm install --omit=dev --no-audit --no-fund || true
118- fi
119- pm2 describe webdev-bot >/dev/null 2>&1 && pm2 restart webdev-bot || pm2 start "node dist/index.js" --name webdev-bot
120- pm2 save || true
121- EOF
50+ - name : Create .env file on VPS
51+ uses : appleboy/ssh-action@v1.0.3
52+ with :
53+ host : ${{ secrets.VPS_HOST }}
54+ username : ${{ secrets.VPS_USER }}
55+ key : ${{ secrets.VPS_SSH_KEY }}
56+ script : |
57+ echo "DISCORD_TOKEN=${{ secrets.DISCORD_TOKEN }}" > /home/${{ secrets.VPS_USER }}/discord-bot/.env
58+ echo "CLIENT_ID=${{ secrets.CLIENT_ID }}" >> /home/${{ secrets.VPS_USER }}/discord-bot/.env
12259
60+ - name : Extract and restart bot on VPS
61+ uses : appleboy/ssh-action@v1.0.3
62+ with :
63+ host : ${{ secrets.VPS_HOST }}
64+ username : ${{ secrets.VPS_USER }}
65+ key : ${{ secrets.VPS_SSH_KEY }}
66+ script : |
67+ cd /home/${{ secrets.VPS_USER }}/discord-bot/
68+ tar xzf bot-build.tar.gz
69+ pm2 restart bot || pm2 start ./dist/index.js --name bot
0 commit comments