From d1697fc811d413c6df8b2d8806292a5d07c0027c Mon Sep 17 00:00:00 2001 From: Samuel James Date: Tue, 23 Jun 2026 22:52:35 +0000 Subject: [PATCH] Add Forgejo Actions CI, remove GitHub Actions (#1) --- .forgejo/workflows/ci.yml | 32 ++++++++ .github/workflows/deploy.yml | 140 ----------------------------------- 2 files changed, 32 insertions(+), 140 deletions(-) create mode 100644 .forgejo/workflows/ci.yml delete mode 100644 .github/workflows/deploy.yml diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml new file mode 100644 index 0000000..bcf151a --- /dev/null +++ b/.forgejo/workflows/ci.yml @@ -0,0 +1,32 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + validate: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Node + uses: actions/setup-node@v4 + with: + node-version: 22 + + - name: Install + type-check + build frontend + run: | + npm ci + npx tsc --noEmit + npm run build + + - name: Install + type-check + build backend + working-directory: backend + run: | + npm ci + npx tsc --noEmit + npm run build diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml deleted file mode 100644 index 7ff00cb..0000000 --- a/.github/workflows/deploy.yml +++ /dev/null @@ -1,140 +0,0 @@ -name: Deploy to racknerd1 - -# Deploys ArchNest (frontend + backend + guacd) to racknerd1 via Docker Compose. -# -# Triggers: -# - push to main (automatic) -# - manual run from the Actions tab (workflow_dispatch) -# -# Required GitHub Actions repo secrets (Settings -> Secrets and variables -> Actions): -# RACKNERD_HOST - racknerd1 hostname or IP the runner can SSH to -# RACKNERD_USER - deploy SSH user (must be in the docker group) -# RACKNERD_SSH_KEY - private SSH key (PEM) for that user -# RACKNERD_PORT - SSH port (optional, defaults to 22) -# -# One-time host setup (NOT done by this workflow, see README Deployment section): -# - Docker + Docker Compose installed, deploy user in the docker group -# - mkdir -p /opt/archnest -# - Create /opt/archnest/.env from .env.example with real generated secrets -# (ARCHNEST_JWT_SECRET, ARCHNEST_SECRET_KEY, ARCHNEST_GUAC_CRYPT_KEY, ...). -# This workflow refuses to deploy if that file is missing, and never -# overwrites it, so live secrets/data are safe across deploys. - -on: - push: - branches: [main] - workflow_dispatch: {} - -# Prevent overlapping deploys clobbering each other. -concurrency: - group: deploy-racknerd1 - cancel-in-progress: false - -env: - DEPLOY_PATH: /opt/archnest - -jobs: - # Fail fast on build/type errors before touching the server. - validate: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Set up Node - uses: actions/setup-node@v4 - with: - node-version: 22 - - - name: Install + type-check + build frontend - run: | - npm ci - npx tsc --noEmit - npm run build - - - name: Install + type-check + build backend - working-directory: backend - run: | - npm ci - npx tsc --noEmit - npm run build - - deploy: - needs: validate - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Pre-flight - confirm host .env exists (don't deploy without secrets) - uses: appleboy/ssh-action@v1.2.0 - with: - host: ${{ secrets.RACKNERD_HOST }} - username: ${{ secrets.RACKNERD_USER }} - key: ${{ secrets.RACKNERD_SSH_KEY }} - port: ${{ secrets.RACKNERD_PORT || 22 }} - script: | - set -e - mkdir -p ${{ env.DEPLOY_PATH }} - if [ ! -f ${{ env.DEPLOY_PATH }}/.env ]; then - echo "::error::Missing ${{ env.DEPLOY_PATH }}/.env on the host." - echo "Create it from .env.example with real secrets before deploying." - echo "It is intentionally never created/overwritten by this workflow." - exit 1 - fi - echo ".env present - proceeding." - - - name: Copy repo to racknerd1 - uses: appleboy/scp-action@v0.1.7 - with: - host: ${{ secrets.RACKNERD_HOST }} - username: ${{ secrets.RACKNERD_USER }} - key: ${{ secrets.RACKNERD_SSH_KEY }} - port: ${{ secrets.RACKNERD_PORT || 22 }} - source: "." - target: ${{ env.DEPLOY_PATH }} - # Keep the host-only .env (and any other untracked host state) intact. - rm: false - overwrite: true - - - name: Build, restart, and clean up - uses: appleboy/ssh-action@v1.2.0 - with: - host: ${{ secrets.RACKNERD_HOST }} - username: ${{ secrets.RACKNERD_USER }} - key: ${{ secrets.RACKNERD_SSH_KEY }} - port: ${{ secrets.RACKNERD_PORT || 22 }} - command_timeout: 20m - script: | - set -e - cd ${{ env.DEPLOY_PATH }} - docker compose up -d --build --remove-orphans - docker image prune -f - - - name: Health check (backend /api/health) - uses: appleboy/ssh-action@v1.2.0 - with: - host: ${{ secrets.RACKNERD_HOST }} - username: ${{ secrets.RACKNERD_USER }} - key: ${{ secrets.RACKNERD_SSH_KEY }} - port: ${{ secrets.RACKNERD_PORT || 22 }} - script: | - set -e - echo "Waiting for backend to become healthy..." - for i in $(seq 1 30); do - if curl -fsS http://127.0.0.1:4000/api/health >/dev/null 2>&1; then - echo "Backend healthy." - # Confirm the frontend container is serving too. - if curl -fsS http://127.0.0.1:8080/ >/dev/null 2>&1; then - echo "Frontend healthy. Deploy succeeded." - exit 0 - fi - echo "Frontend not ready yet..." - fi - sleep 5 - done - echo "::error::Health check failed after ~150s. Dumping container status + logs." - cd ${{ env.DEPLOY_PATH }} - docker compose ps || true - docker compose logs --tail=80 || true - exit 1