Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
node_modules
dist
coverage
.git
.github
.idea
data
*.log
.env
128 changes: 99 additions & 29 deletions .github/workflows/cd.yml
Original file line number Diff line number Diff line change
@@ -1,39 +1,109 @@
name: TheraBot CD

on:
push:
branches:
- master
pull_request:
branches:
- master
workflow_dispatch:
push:
branches:
- master
pull_request:
branches:
- master

jobs:
test:

runs-on: ubuntu-latest
env:
NODE_VERSION: "24"

steps:
- name: Checkout
uses: actions/checkout@v3

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: lts/*
jobs:
audit:
name: Audit dependencies
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- run: npm audit --omit=dev

- name: Audit
run: npm audit --omit=dev
get_sha:
name: Get short SHA for image tags
runs-on: ubuntu-latest
outputs:
sha_short: ${{ steps.get_sha.outputs.sha_short }}
steps:
- uses: actions/checkout@v6
- id: get_sha
run: echo "sha_short=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT"

- name: Install packages
run: npm ci
test:
name: Unit tests
needs: [audit]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- run: npm ci
- run: npm test

- name: Run tests
run: npm test
build-image:
name: Build image
needs: [audit]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- run: docker compose -f deploy/compose.yaml build therabot
- run: docker save -o therabot-image.tar ghcr.io/ionaru/therabot:latest
- uses: actions/upload-artifact@v7
with:
name: therabot-image
path: therabot-image.tar
retention-days: 1

- name: Build
run: npm run build
push-image:
name: Push image
if: github.event_name == 'push'
needs: [get_sha, test, build-image]
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/download-artifact@v8
with:
name: therabot-image
- run: docker load -i therabot-image.tar
- run: docker tag ghcr.io/ionaru/therabot:latest ghcr.io/ionaru/therabot:${{ needs.get_sha.outputs.sha_short }}
- uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- run: docker push -a ghcr.io/ionaru/therabot

- name: Deploy
if: github.event_name == 'push'
run: npx -q @ionaru/teamcity-deploy teamcity.saturnserver.org TheraBot_Build ${{ secrets.API_TOKEN }}
deploy:
needs: [get_sha, push-image]
if: github.event_name == 'push'
runs-on: ubuntu-latest
concurrency:
group: deploy
cancel-in-progress: false
steps:
- uses: appleboy/ssh-action@v1.2.5
with:
command_timeout: 30m
host: ${{ secrets.DEPLOY_HOST }}
username: ${{ secrets.DEPLOY_USER }}
key: ${{ secrets.DEPLOY_KEY }}
script: |
$ErrorActionPreference = "Stop"
cd ${{ secrets.DEPLOY_PATH }}
git fetch -a
git switch -d ${{ needs.get_sha.outputs.sha_short }}
docker system prune --all -f
$env:THERABOT_GIT_REVISION = "${{ needs.get_sha.outputs.sha_short }}"
$env:DOCKER_CONFIG = "/docker-no-creds"
docker compose -p therabot -f deploy/compose.yaml pull
docker compose -p therabot -f deploy/compose.yaml up --pull=never --no-build --remove-orphans -d --wait
$deployExit = $LASTEXITCODE
docker compose -p therabot -f deploy/compose.yaml logs therabot
if ($deployExit -ne 0) { exit $deployExit }
28 changes: 0 additions & 28 deletions Dockerfile

This file was deleted.

34 changes: 34 additions & 0 deletions deploy/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# ---- Build stage: compile TypeScript to dist/ ----
FROM node:24-alpine AS build

WORKDIR /app

# Install all dependencies (including dev) for the build.
COPY package.json package-lock.json tsconfig.json ./
RUN npm ci

# Compile the application.
COPY src ./src
RUN npm run build

# ---- Runtime stage: production image ----
FROM node:24-alpine AS runtime

ENV NODE_ENV=production
WORKDIR /app

# Install production dependencies only. Everything is pure JavaScript now
# (SQLite is provided by Node's built-in node:sqlite), so there is no native
# compilation and no build toolchain is required.
COPY package.json package-lock.json ./
RUN npm ci --omit=dev && npm cache clean --force

# Copy the compiled application from the build stage.
COPY --from=build /app/dist ./dist

# The SQLite database (data/therabot.db) and ESI cache (data/cache.json) live
# here; mounted as a volume in production.
RUN mkdir -p /app/data
VOLUME /app/data

CMD ["node", "dist/main.js"]
17 changes: 17 additions & 0 deletions deploy/compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
services:
therabot:
image: ghcr.io/ionaru/therabot:${THERABOT_GIT_REVISION:-latest}
build:
context: ../
dockerfile: deploy/Dockerfile
environment:
- THERABOT_ID
- THERABOT_KEY
- THERABOT_TOKEN
- DEBUG
volumes:
- ${THERABOT_DATA_VOLUME:-data}:/app/data
restart: unless-stopped

volumes:
data:
16 changes: 0 additions & 16 deletions docker-compose.yml

This file was deleted.

125 changes: 0 additions & 125 deletions migrations/1571080868409-Initial.ts

This file was deleted.

Loading
Loading