From 354e691cebaed3b987d3780640c3279b28d0f884 Mon Sep 17 00:00:00 2001 From: host-db Date: Sat, 20 Jun 2026 11:57:31 +0200 Subject: [PATCH] feat: initial hello-world app with CI/CD pipeline --- .gitea/workflows/ci.yml | 69 +++++++++++++++++++++++++++++++++++++++++ Dockerfile | 15 +++++++++ docker-compose.prod.yml | 26 ++++++++++++++++ index.js | 15 +++++++++ package.json | 14 +++++++++ 5 files changed, 139 insertions(+) create mode 100644 .gitea/workflows/ci.yml create mode 100644 Dockerfile create mode 100644 docker-compose.prod.yml create mode 100644 index.js create mode 100644 package.json diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml new file mode 100644 index 0000000..ffad165 --- /dev/null +++ b/.gitea/workflows/ci.yml @@ -0,0 +1,69 @@ +name: CI/CD Pipeline +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + lint-test: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 22 + + - name: Install deps + run: npm ci + + - name: Lint + run: npm run lint + + - name: Test + run: npm test + + build-push: + needs: lint-test + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/main' + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build and push + uses: docker/build-push-action@v6 + with: + context: . + push: true + tags: registry.home:5000/admin/hello-world:${{ github.sha }},registry.home:5000/admin/hello-world:latest + + deploy: + needs: build-push + runs-on: self-hosted + if: github.ref == 'refs/heads/main' + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Deploy to VPS + run: | + mkdir -p ~/.ssh + echo "${{ secrets.DEPLOY_KEY }}" > ~/.ssh/deploy_key + chmod 600 ~/.ssh/deploy_key + ssh -i ~/.ssh/deploy_key -o StrictHostKeyChecking=accept-new root@100.89.217.78 << 'EOF' + mkdir -p /opt/stacks/hello-world + cd /opt/stacks/hello-world + docker compose -f docker-compose.prod.yml pull + docker compose -f docker-compose.prod.yml up -d + sleep 5 + curl -f http://localhost:3000/health || docker compose -f docker-compose.prod.yml up -d --force-recreate + EOF + env: + TAG: ${{ github.sha }} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..1bcc24e --- /dev/null +++ b/Dockerfile @@ -0,0 +1,15 @@ +FROM node:22-bookworm-slim + +WORKDIR /app + +COPY package.json package-lock.json* ./ +RUN npm ci --only=production + +COPY . . + +EXPOSE 3000 + +HEALTHCHECK --interval=30s --timeout=5s --retries=3 \ + CMD node -e "require('http').get('http://localhost:3000/health', r => {process.exit(r.statusCode === 200 ? 0 : 1)})" + +CMD ["node", "index.js"] diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml new file mode 100644 index 0000000..ddda545 --- /dev/null +++ b/docker-compose.prod.yml @@ -0,0 +1,26 @@ +services: + app: + image: registry.home:5000/admin/hello-world:${TAG:-latest} + restart: unless-stopped + networks: + - app-net + - traefik + environment: + - PORT=3000 + labels: + - "traefik.enable=true" + - "traefik.http.routers.hello.rule=Host(`hello.home`)" + - "traefik.http.routers.hello.tls.certresolver=letsencrypt" + - "traefik.http.routers.hello.middlewares=sec-headers@file" + - "traefik.http.services.hello.loadbalancer.server.port=3000" + healthcheck: + test: ["CMD", "node", "-e", "require('http').get('http://localhost:3000/health', r => {process.exit(r.statusCode === 200 ? 0 : 1)})"] + interval: 30s + timeout: 5s + retries: 3 + +networks: + app-net: + internal: true + traefik: + external: true diff --git a/index.js b/index.js new file mode 100644 index 0000000..141b9e7 --- /dev/null +++ b/index.js @@ -0,0 +1,15 @@ +const express = require('express'); +const app = express(); +const PORT = process.env.PORT || 3000; + +app.get('/', (req, res) => { + res.json({ message: 'Hello World from Gitea CI/CD!', timestamp: new Date().toISOString() }); +}); + +app.get('/health', (req, res) => { + res.json({ status: 'ok' }); +}); + +app.listen(PORT, () => { + console.log(`Server running on port ${PORT}`); +}); diff --git a/package.json b/package.json new file mode 100644 index 0000000..cc33ac8 --- /dev/null +++ b/package.json @@ -0,0 +1,14 @@ +{ + "name": "hello-world", + "version": "1.0.0", + "description": "Test app for Gitea CI/CD pipeline", + "main": "index.js", + "scripts": { + "start": "node index.js", + "test": "node -e \"console.log('TESTS PASSED'); process.exit(0)\"", + "lint": "node -e \"console.log('LINT OK'); process.exit(0)\"" + }, + "dependencies": { + "express": "^4.21.0" + } +}