Skip to content

Commit 567f432

Browse files
authored
ci: create test and deployment workflow (#1)
* chore: create nvm file * ci: add GitHub Actions workflow for testing and building * ci: implement deployment workflow using GitHub Actions * chore: add test script and initial sanity test * ci: migrate workflows from pnpm to npm for dependency management and script execution * ci: remove npm cache configuration from workflows * chore: update build scripts in package.json for CI and development * ci: update build command in workflows to use build:ci for consistency * ci: update deploy workflow to allow manual triggering and comment out push event * ci: enhance workflows with concurrency settings and paths-ignore for pull requests * ci: rename APPLICATION_ID to CLIENT_ID in environment files and workflows * ci: update test workflow to use CLIENT_ID instead of APPLICATION_ID
1 parent 4dc31d8 commit 567f432

6 files changed

Lines changed: 181 additions & 3 deletions

File tree

.env.example

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
DISCORD_TOKEN="" # Your bot token
2-
APPLICATION_ID="" # Your bot's application ID
2+
CLIENT_ID="" # Your bot's application ID

.github/workflows/deploy.yml

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
name: Deploy
2+
3+
on:
4+
workflow_dispatch: # Manual trigger only
5+
# Uncomment below when VPS is ready:
6+
# push:
7+
# branches: [ "main" ]
8+
# paths-ignore:
9+
# - 'docs/**'
10+
# - '.gitignore'
11+
# - 'LICENSE'
12+
13+
concurrency:
14+
group: ${{ github.workflow }}-${{ github.ref }}
15+
cancel-in-progress: false
16+
17+
jobs:
18+
build-test-and-deploy:
19+
runs-on: ubuntu-latest
20+
steps:
21+
- name: Checkout
22+
uses: actions/checkout@v4
23+
24+
- name: Setup Node.js
25+
uses: actions/setup-node@v4
26+
with:
27+
node-version-file: .nvmrc
28+
29+
- 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
36+
37+
- name: Lint
38+
run: npm run lint
39+
40+
- name: Build
41+
run: npm run build:ci
42+
env:
43+
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
44+
CLIENT_ID: ${{ secrets.CLIENT_ID }}
45+
46+
- name: Run tests
47+
run: npm test
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
62+
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
75+
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"
90+
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
122+

.github/workflows/test.yml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
name: Test
2+
3+
on:
4+
pull_request:
5+
branches: [ "**" ]
6+
paths-ignore:
7+
- 'docs/**'
8+
- '.gitignore'
9+
- 'LICENSE'
10+
11+
concurrency:
12+
group: ${{ github.workflow }}-${{ github.ref }}
13+
cancel-in-progress: true
14+
15+
jobs:
16+
build-and-test:
17+
runs-on: ubuntu-latest
18+
steps:
19+
- name: Checkout
20+
uses: actions/checkout@v4
21+
22+
- name: Setup Node.js
23+
uses: actions/setup-node@v4
24+
with:
25+
node-version-file: .nvmrc
26+
27+
- name: Install dependencies
28+
run: |
29+
if [ -f package-lock.json ]; then
30+
npm ci --no-audit --no-fund
31+
else
32+
npm install --no-audit --no-fund
33+
fi
34+
35+
- name: Lint
36+
run: npm run lint
37+
38+
- name: Build
39+
run: npm run build:ci
40+
env:
41+
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
42+
CLIENT_ID: ${{ secrets.CLIENT_ID }}
43+
44+
- name: Run tests
45+
run: npm test
46+

.nvmrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
v22.20.0

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
"description": "Web Dev & Web Design discord bot",
55
"type": "module",
66
"scripts": {
7-
"build": "pnpm run build:ts && pnpm run build:copy",
7+
"build:ci": "tsup && node scripts/copy-assets.js",
8+
"build:dev": "pnpm run build:ts && pnpm run build:copy",
89
"build:ts": "tsup",
910
"build:copy": "node scripts/copy-assets.js",
1011
"start": "node dist/index.js",
@@ -14,7 +15,8 @@
1415
"lint:fix": "biome lint --fix .",
1516
"format": "biome format --write .",
1617
"check": "biome check .",
17-
"check:fix": "biome check --write ."
18+
"check:fix": "biome check --write .",
19+
"test": "node --test"
1820
},
1921
"keywords": [],
2022
"author": "",

test/sanity.test.mjs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import assert from 'node:assert/strict';
2+
import test from 'node:test';
3+
4+
test('sanity: 1 + 1 equals 2', () => {
5+
assert.equal(1 + 1, 2);
6+
});
7+

0 commit comments

Comments
 (0)