From 07e12266e3c76cbfb186511a4df595e8b3cf0fbb Mon Sep 17 00:00:00 2001 From: Wiktoria Van Harneveldt Date: Sun, 5 Oct 2025 14:14:58 +0200 Subject: [PATCH 01/12] chore: create nvm file --- .nvmrc | 1 + 1 file changed, 1 insertion(+) create mode 100644 .nvmrc diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..c07f712 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +v22.20.0 \ No newline at end of file From c90cbeaad7d0f9ca30b44f3f056863e757595151 Mon Sep 17 00:00:00 2001 From: Wiktoria Van Harneveldt Date: Sun, 5 Oct 2025 14:47:37 +0200 Subject: [PATCH 02/12] ci: add GitHub Actions workflow for testing and building --- .github/workflows/test.yml | 39 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..94589b3 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,39 @@ +name: Test + +on: + pull_request: + branches: [ "**" ] + +jobs: + build-and-test: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version-file: .nvmrc + cache: 'pnpm' + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 10 + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Lint + run: pnpm run lint + + - name: Build + run: pnpm run build + env: + DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }} + APPLICATION_ID: ${{ secrets.APPLICATION_ID }} + + - name: Run tests + run: pnpm run test + From 67351d537e02ee0ccd7c3d9739238a16bb86141b Mon Sep 17 00:00:00 2001 From: Wiktoria Van Harneveldt Date: Sun, 5 Oct 2025 14:47:42 +0200 Subject: [PATCH 03/12] ci: implement deployment workflow using GitHub Actions --- .github/workflows/deploy.yml | 115 +++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 .github/workflows/deploy.yml diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..a81e314 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,115 @@ +name: Deploy + +on: + push: + branches: [ "main" ] + +jobs: + build-test-and-deploy: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version-file: .nvmrc + cache: 'pnpm' + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 10 + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Lint + run: pnpm run lint + + - name: Build + run: pnpm run build + env: + DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }} + APPLICATION_ID: ${{ secrets.APPLICATION_ID }} + + - name: Run tests + run: pnpm run test + + - name: Package artifact + run: | + tar -czf release.tar.gz dist package.json pnpm-lock.yaml .nvmrc + + - name: Create .env file from secrets + env: + DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }} + APPLICATION_ID: ${{ secrets.APPLICATION_ID }} + run: | + set -euo pipefail + printf "DISCORD_TOKEN=%s\n" "$DISCORD_TOKEN" > .env + printf "APPLICATION_ID=%s\n" "$APPLICATION_ID" >> .env + printf "NODE_ENV=production\n" >> .env + + - name: Copy artifact to VPS + env: + SSH_HOST: ${{ secrets.SSH_HOST }} + SSH_USER: ${{ secrets.SSH_USER }} + SSH_PORT: ${{ secrets.SSH_PORT }} + SSH_KEY: ${{ secrets.SSH_KEY }} + run: | + mkdir -p ~/.ssh + echo "$SSH_KEY" > ~/.ssh/id_ed25519 + chmod 600 ~/.ssh/id_ed25519 + ssh -o StrictHostKeyChecking=no -i ~/.ssh/id_ed25519 -p ${SSH_PORT:-22} $SSH_USER@$SSH_HOST "mkdir -p ~/apps/webdev-bot/releases" + 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 + + - name: Upload .env to VPS + env: + SSH_HOST: ${{ secrets.SSH_HOST }} + SSH_USER: ${{ secrets.SSH_USER }} + SSH_PORT: ${{ secrets.SSH_PORT }} + SSH_KEY: ${{ secrets.SSH_KEY }} + APP_DIR: ${{ secrets.APP_DIR }} + run: | + mkdir -p ~/.ssh + echo "$SSH_KEY" > ~/.ssh/id_ed25519 + chmod 600 ~/.ssh/id_ed25519 + 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" + scp -i ~/.ssh/id_ed25519 -P ${SSH_PORT:-22} -o StrictHostKeyChecking=no .env $SSH_USER@$SSH_HOST:${APP_DIR:-"~/apps/webdev-bot"}/shared/.env + 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" + + - name: Deploy on VPS + env: + SSH_HOST: ${{ secrets.SSH_HOST }} + SSH_USER: ${{ secrets.SSH_USER }} + SSH_PORT: ${{ secrets.SSH_PORT }} + SSH_KEY: ${{ secrets.SSH_KEY }} + APP_DIR: ${{ secrets.APP_DIR }} + run: | + mkdir -p ~/.ssh + echo "$SSH_KEY" > ~/.ssh/id_ed25519 + chmod 600 ~/.ssh/id_ed25519 + ssh -o StrictHostKeyChecking=no -i ~/.ssh/id_ed25519 -p ${SSH_PORT:-22} $SSH_USER@$SSH_HOST << 'EOF' + set -euo pipefail + APP_DIR=${APP_DIR:-"~/apps/webdev-bot"} + mkdir -p "$APP_DIR/current" "$APP_DIR/releases" "$APP_DIR/shared" + cd "$APP_DIR" + rm -rf current/* + tar -xzf releases/release.tar.gz -C current + cd current + # Load env from shared/.env for the PM2 process + set -a + if [ -f "$APP_DIR/shared/.env" ]; then . "$APP_DIR/shared/.env"; fi + set +a + if command -v pnpm >/dev/null 2>&1; then + pnpm install --prod --frozen-lockfile || true + else + if command -v corepack >/dev/null 2>&1; then corepack enable; fi + npm i -g pnpm@10 || true + pnpm install --prod --frozen-lockfile || true + fi + pm2 describe webdev-bot >/dev/null 2>&1 && pm2 restart webdev-bot || pm2 start "node dist/index.js" --name webdev-bot + pm2 save || true + EOF + From ad38bd3be9410793446a0d9826bb0d9f750988f8 Mon Sep 17 00:00:00 2001 From: Wiktoria Van Harneveldt Date: Sun, 5 Oct 2025 14:48:50 +0200 Subject: [PATCH 04/12] chore: add test script and initial sanity test --- package.json | 3 ++- test/sanity.test.mjs | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 test/sanity.test.mjs diff --git a/package.json b/package.json index af79db5..c30478f 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,8 @@ "lint:fix": "biome lint --fix .", "format": "biome format --write .", "check": "biome check .", - "check:fix": "biome check --write ." + "check:fix": "biome check --write .", + "test": "node --test" }, "keywords": [], "author": "", diff --git a/test/sanity.test.mjs b/test/sanity.test.mjs new file mode 100644 index 0000000..33a4ced --- /dev/null +++ b/test/sanity.test.mjs @@ -0,0 +1,7 @@ +import assert from 'node:assert/strict'; +import test from 'node:test'; + +test('sanity: 1 + 1 equals 2', () => { + assert.equal(1 + 1, 2); +}); + From 356041c592615bdc9fbcf9f589da6064127998f1 Mon Sep 17 00:00:00 2001 From: Wiktoria Van Harneveldt Date: Sun, 5 Oct 2025 14:52:51 +0200 Subject: [PATCH 05/12] ci: migrate workflows from pnpm to npm for dependency management and script execution --- .github/workflows/deploy.yml | 30 ++++++++++++++---------------- .github/workflows/test.yml | 20 ++++++++++---------- 2 files changed, 24 insertions(+), 26 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index a81e314..03954d3 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -15,31 +15,31 @@ jobs: uses: actions/setup-node@v4 with: node-version-file: .nvmrc - cache: 'pnpm' - - - name: Setup pnpm - uses: pnpm/action-setup@v4 - with: - version: 10 + cache: 'npm' - name: Install dependencies - run: pnpm install --frozen-lockfile + run: | + if [ -f package-lock.json ]; then + npm ci --no-audit --no-fund + else + npm install --no-audit --no-fund + fi - name: Lint - run: pnpm run lint + run: npm run lint - name: Build - run: pnpm run build + run: npm run build env: DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }} APPLICATION_ID: ${{ secrets.APPLICATION_ID }} - name: Run tests - run: pnpm run test + run: npm test - name: Package artifact run: | - tar -czf release.tar.gz dist package.json pnpm-lock.yaml .nvmrc + tar -czf release.tar.gz dist package.json package-lock.json .nvmrc || tar -czf release.tar.gz dist package.json .nvmrc - name: Create .env file from secrets env: @@ -102,12 +102,10 @@ jobs: set -a if [ -f "$APP_DIR/shared/.env" ]; then . "$APP_DIR/shared/.env"; fi set +a - if command -v pnpm >/dev/null 2>&1; then - pnpm install --prod --frozen-lockfile || true + if [ -f package-lock.json ]; then + npm ci --omit=dev --no-audit --no-fund || true else - if command -v corepack >/dev/null 2>&1; then corepack enable; fi - npm i -g pnpm@10 || true - pnpm install --prod --frozen-lockfile || true + npm install --omit=dev --no-audit --no-fund || true fi pm2 describe webdev-bot >/dev/null 2>&1 && pm2 restart webdev-bot || pm2 start "node dist/index.js" --name webdev-bot pm2 save || true diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 94589b3..c2873d5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,25 +15,25 @@ jobs: uses: actions/setup-node@v4 with: node-version-file: .nvmrc - cache: 'pnpm' - - - name: Setup pnpm - uses: pnpm/action-setup@v4 - with: - version: 10 + cache: 'npm' - name: Install dependencies - run: pnpm install --frozen-lockfile + run: | + if [ -f package-lock.json ]; then + npm ci --no-audit --no-fund + else + npm install --no-audit --no-fund + fi - name: Lint - run: pnpm run lint + run: npm run lint - name: Build - run: pnpm run build + run: npm run build env: DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }} APPLICATION_ID: ${{ secrets.APPLICATION_ID }} - name: Run tests - run: pnpm run test + run: npm test From 45c130979209f795b88e797be588a6abe512d22e Mon Sep 17 00:00:00 2001 From: Wiktoria Van Harneveldt Date: Sun, 5 Oct 2025 14:54:49 +0200 Subject: [PATCH 06/12] ci: remove npm cache configuration from workflows --- .github/workflows/deploy.yml | 1 - .github/workflows/test.yml | 1 - 2 files changed, 2 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 03954d3..e2a22da 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -15,7 +15,6 @@ jobs: uses: actions/setup-node@v4 with: node-version-file: .nvmrc - cache: 'npm' - name: Install dependencies run: | diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c2873d5..8ad6c7f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,7 +15,6 @@ jobs: uses: actions/setup-node@v4 with: node-version-file: .nvmrc - cache: 'npm' - name: Install dependencies run: | From 8c188e7d2a77a3b75a357d0ccf8243072bb48973 Mon Sep 17 00:00:00 2001 From: Wiktoria Van Harneveldt Date: Sun, 5 Oct 2025 15:03:49 +0200 Subject: [PATCH 07/12] chore: update build scripts in package.json for CI and development --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 04a9b13..2bdec20 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,8 @@ "description": "Web Dev & Web Design discord bot", "type": "module", "scripts": { - "build": "pnpm run build:ts && pnpm run build:copy", + "build:ci": "tsup && node scripts/copy-assets.js", + "build:dev": "pnpm run build:ts && pnpm run build:copy", "build:ts": "tsup", "build:copy": "node scripts/copy-assets.js", "start": "node dist/index.js", From 85ce51adbdef4b5af68da99d1d4be096a7ed40d3 Mon Sep 17 00:00:00 2001 From: Wiktoria Van Harneveldt Date: Sun, 5 Oct 2025 15:05:13 +0200 Subject: [PATCH 08/12] ci: update build command in workflows to use build:ci for consistency --- .github/workflows/deploy.yml | 2 +- .github/workflows/test.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index e2a22da..ca5482a 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -28,7 +28,7 @@ jobs: run: npm run lint - name: Build - run: npm run build + run: npm run build:ci env: DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }} APPLICATION_ID: ${{ secrets.APPLICATION_ID }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8ad6c7f..7a73815 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -28,7 +28,7 @@ jobs: run: npm run lint - name: Build - run: npm run build + run: npm run build:ci env: DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }} APPLICATION_ID: ${{ secrets.APPLICATION_ID }} From 0b0b1ffbf3abc96aded5360ba2c5918c82f15d32 Mon Sep 17 00:00:00 2001 From: Wiktoria Van Harneveldt Date: Sun, 5 Oct 2025 15:09:04 +0200 Subject: [PATCH 09/12] ci: update deploy workflow to allow manual triggering and comment out push event --- .github/workflows/deploy.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index ca5482a..118a4e4 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,8 +1,10 @@ name: Deploy on: - push: - branches: [ "main" ] + workflow_dispatch: # Manual trigger only + # Uncomment below when VPS is ready: + # push: + # branches: [ "main" ] jobs: build-test-and-deploy: From b30d4c13649a6c7ba0954b93cb5410db874ee085 Mon Sep 17 00:00:00 2001 From: Wiktoria Van Harneveldt Date: Sun, 5 Oct 2025 15:27:21 +0200 Subject: [PATCH 10/12] ci: enhance workflows with concurrency settings and paths-ignore for pull requests --- .github/workflows/deploy.yml | 8 ++++++++ .github/workflows/test.yml | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 118a4e4..44beea0 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -5,6 +5,14 @@ on: # Uncomment below when VPS is ready: # push: # branches: [ "main" ] + # paths-ignore: + # - 'docs/**' + # - '.gitignore' + # - 'LICENSE' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: false jobs: build-test-and-deploy: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7a73815..eafa205 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -3,6 +3,14 @@ name: Test on: pull_request: branches: [ "**" ] + paths-ignore: + - 'docs/**' + - '.gitignore' + - 'LICENSE' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: build-and-test: From 172a5402d9165ed6c7256b1954bc688d8b40ce79 Mon Sep 17 00:00:00 2001 From: Wiktoria Van Harneveldt Date: Sun, 5 Oct 2025 16:00:00 +0200 Subject: [PATCH 11/12] ci: rename APPLICATION_ID to CLIENT_ID in environment files and workflows --- .env.example | 2 +- .github/workflows/deploy.yml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.env.example b/.env.example index 027465f..9c885f7 100644 --- a/.env.example +++ b/.env.example @@ -1,2 +1,2 @@ DISCORD_TOKEN="" # Your bot token -APPLICATION_ID="" # Your bot's application ID +CLIENT_ID="" # Your bot's application ID diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 44beea0..a950248 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -41,7 +41,7 @@ jobs: run: npm run build:ci env: DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }} - APPLICATION_ID: ${{ secrets.APPLICATION_ID }} + CLIENT_ID: ${{ secrets.CLIENT_ID }} - name: Run tests run: npm test @@ -53,11 +53,11 @@ jobs: - name: Create .env file from secrets env: DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }} - APPLICATION_ID: ${{ secrets.APPLICATION_ID }} + CLIENT_ID: ${{ secrets.CLIENT_ID }} run: | set -euo pipefail printf "DISCORD_TOKEN=%s\n" "$DISCORD_TOKEN" > .env - printf "APPLICATION_ID=%s\n" "$APPLICATION_ID" >> .env + printf "CLIENT_ID=%s\n" "$CLIENT_ID" >> .env printf "NODE_ENV=production\n" >> .env - name: Copy artifact to VPS From 2d566b20beb69ddcbace1f1ef8a5e61f30e68928 Mon Sep 17 00:00:00 2001 From: Wiktoria Van Harneveldt Date: Sun, 5 Oct 2025 16:04:33 +0200 Subject: [PATCH 12/12] ci: update test workflow to use CLIENT_ID instead of APPLICATION_ID --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index eafa205..4cc4865 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -39,7 +39,7 @@ jobs: run: npm run build:ci env: DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }} - APPLICATION_ID: ${{ secrets.APPLICATION_ID }} + CLIENT_ID: ${{ secrets.CLIENT_ID }} - name: Run tests run: npm test