diff --git a/.github/workflows/services-www-releases-dispatch-release.yml b/.github/workflows/services-www-releases-dispatch-release.yml index 1acba8d..7f2b0a8 100644 --- a/.github/workflows/services-www-releases-dispatch-release.yml +++ b/.github/workflows/services-www-releases-dispatch-release.yml @@ -4,9 +4,242 @@ on: workflow_dispatch: jobs: + setup-stage: + name: Setup - Stage + runs-on: ubuntu-latest + outputs: + cache-hit: ${{ steps.cache-pnpm-store.outputs.cache-hit }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 9.12.3 + + - name: Setup Node.js with pnpm cache + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: 'pnpm' + + - name: Cache pnpm store + id: cache-pnpm-store + uses: actions/cache@v3 + with: + path: ~/.pnpm-store + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + build-configs: + name: Build - Configs + needs: setup-stage + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 9.12.3 + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: 'pnpm' + - name: Install dependencies + run: pnpm install --frozen-lockfile + - name: Build Jest config + run: pnpm --filter @ermnvldmr/jest-config build + - name: Build Vite config + run: pnpm --filter @ermnvldmr/vite-config build + - name: Build Storybook config + run: pnpm --filter @ermnvldmr/storybook-config build + - name: Upload Config Artifacts + uses: actions/upload-artifact@v4 + with: + name: config-artifacts + path: | + packages/jest-config/dist + packages/vite-config/dist + packages/storybook-config/dist + retention-days: 1 + + lint-www: + name: Lint - WWW & Deps + needs: build-configs + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 9.12.3 + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: 'pnpm' + - name: Install dependencies + run: pnpm install --frozen-lockfile + - name: Download Config Artifacts + uses: actions/download-artifact@v4 + with: + name: config-artifacts + path: packages + - name: Lint STL package + run: pnpm --filter @ermnvldmr/stl lint + - name: Lint UI package + run: pnpm --filter @ermnvldmr/ui lint + - name: Lint WWW service + run: pnpm --filter @ermnvldmr/www lint + + typecheck-www: + name: Typecheck - WWW & Deps + needs: build-configs + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 9.12.3 + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: 'pnpm' + - name: Install dependencies + run: pnpm install --frozen-lockfile + - name: Download Config Artifacts + uses: actions/download-artifact@v4 + with: + name: config-artifacts + path: packages + - name: Typecheck STL package + run: pnpm --filter @ermnvldmr/stl typecheck + - name: Typecheck UI package + run: pnpm --filter @ermnvldmr/ui typecheck + - name: Typecheck WWW service + run: pnpm --filter @ermnvldmr/www typecheck + + build-storybook: + name: Build - Storybook + needs: build-configs + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 9.12.3 + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: 'pnpm' + - name: Install dependencies + run: pnpm install --frozen-lockfile + - name: Download Config Artifacts + uses: actions/download-artifact@v4 + with: + name: config-artifacts + path: packages + - name: Build WWW Storybook + run: pnpm --filter @ermnvldmr/www build-storybook + - name: Upload Storybook build + uses: actions/upload-artifact@v4 + with: + name: storybook-static + path: services/www/storybook-static/ + retention-days: 1 + + test-www: + name: Test - Unit + needs: build-configs + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 9.12.3 + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: 'pnpm' + - name: Install dependencies + run: pnpm install --frozen-lockfile + - name: Download Config Artifacts + uses: actions/download-artifact@v4 + with: + name: config-artifacts + path: packages + - name: Test STL package + run: pnpm --filter @ermnvldmr/stl test:coverage + - name: Test UI package + run: pnpm --filter @ermnvldmr/ui test:coverage + - name: Test WWW service + run: pnpm --filter @ermnvldmr/www test:coverage + + test-storybook: + name: Test - Storybook + needs: build-storybook + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 9.12.3 + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: 'pnpm' + - name: Install dependencies + run: pnpm install --frozen-lockfile + - name: Download Config Artifacts + uses: actions/download-artifact@v4 + with: + name: config-artifacts + path: packages + - name: Install Playwright browsers + run: pnpm --filter @ermnvldmr/www exec playwright install --with-deps chromium + - name: Download Storybook build + uses: actions/download-artifact@v4 + with: + name: storybook-static + path: services/www/storybook-static/ + - name: Serve Storybook and run tests + run: pnpm --filter @ermnvldmr/www test:storybook:ci + + build-www: + name: Build - WWW Service + needs: build-configs + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 9.12.3 + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: 'pnpm' + - name: Install dependencies + run: pnpm install --frozen-lockfile + - name: Download Config Artifacts + uses: actions/download-artifact@v4 + with: + name: config-artifacts + path: packages + - name: Build WWW service + run: pnpm --filter @ermnvldmr/www build + release-tag-docker: name: Release - Tag & Docker + needs: [lint-www, typecheck-www, test-www, test-storybook, build-www] runs-on: ubuntu-latest + environment: services-www-releases-publish permissions: contents: write packages: write @@ -60,3 +293,26 @@ jobs: push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} + + deploy: + name: Deploy - VPS + needs: release-tag-docker + runs-on: ubuntu-latest + environment: + name: services-www-releases-deploy + url: https://ermnvldmr.com + steps: + - name: Deploy via SSH + uses: appleboy/ssh-action@v1.0.3 + with: + host: ${{ secrets.DEPLOY_VPS_HOST }} + username: ${{ secrets.DEPLOY_VPS_USER }} + key: ${{ secrets.DEPLOY_VPS_SSH_KEY }} + port: ${{ secrets.DEPLOY_VPS_SSH_PORT || 22 }} + script: | + cd /srv/ermnvldmr.com + git pull + chmod +x ci/scripts/deploy-new-tags.sh + # Use the short SHA to match the tag from release-tag-docker + export WWW_TAG="sha-$(echo ${{ github.sha }} | cut -c1-7)" + ./ci/scripts/deploy-new-tags.sh \ No newline at end of file diff --git a/ci/deploy/docker-compose.yml b/ci/deploy/docker-compose.yml index 3af83a7..bb1d56c 100644 --- a/ci/deploy/docker-compose.yml +++ b/ci/deploy/docker-compose.yml @@ -37,6 +37,20 @@ services: security_opt: - no-new-privileges:true + www: + image: ghcr.io/deytenit/ermnvldmr.com/www:${WWW_TAG} + container_name: com-ermnvldmr-www + restart: always + networks: + - com-ermnvldmr-enclave + deploy: + resources: + limits: + cpus: '0.25' + memory: 128M + security_opt: + - no-new-privileges:true + networks: com-ermnvldmr-direct: name: com-ermnvldmr-direct diff --git a/ci/deploy/nginx/conf.d/www.conf b/ci/deploy/nginx/conf.d/www.conf new file mode 100644 index 0000000..8c084e3 --- /dev/null +++ b/ci/deploy/nginx/conf.d/www.conf @@ -0,0 +1,41 @@ +server { + listen 80; + server_name ermnvldmr.com www.ermnvldmr.com; + + location /.well-known/acme-challenge/ { + root /var/www/certbot; + } + + location / { + return 301 https://$host$request_uri; + } +} + +server { + listen 443 ssl; + http2 on; + server_name ermnvldmr.com www.ermnvldmr.com; + + ssl_certificate /etc/letsencrypt/live/ermnvldmr.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/ermnvldmr.com/privkey.pem; + + # Optimized SSL settings + ssl_session_timeout 1d; + ssl_session_cache shared:SSL:50m; + ssl_session_tickets off; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; + ssl_prefer_server_ciphers off; + + # HSTS + add_header Strict-Transport-Security "max-age=63072000" always; + + location / { + proxy_pass http://com-ermnvldmr-www:80; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +}