cicd
sudarshanpjadhav/finggu-skills/skills/devops/cicd/SKILL.md
Production-ready GitHub Actions workflows for Node.js and PHP projects. Covers test, build, deploy, rollback, and environment promotion. Every workflow here is copy-paste deployable.
Skill0 starsChanged 4 months ago
- Reads credentials
What's in it
- SKILL: CI/CD with GitHub Actions
- Overview
- PATTERNS
- Node.js — Full CI/CD Pipeline
- cPanel / Shared Hosting Deploy
- PR Quality Gates
- ANTI-PATTERNS
- CONVENTIONS
# SKILL: CI/CD with GitHub Actions
**Maintainer:** finggu · **Version:** 1.0.0 · **Category:** DevOps
---
## Overview
Production-ready GitHub Actions workflows for Node.js and PHP projects. Covers test, build, deploy, rollback, and environment promotion. Every workflow here is copy-paste deployable.
---
## PATTERNS
### Node.js — Full CI/CD Pipeline
```yaml
# .github/workflows/finggu-ci.yml
name: Finggu CI/CD
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
env:
NODE_VERSION: '20'
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
# ─────────────────────────────
# JOB 1: Lint + Test
# ─────────────────────────────
test:
name: Lint & Test
runs-on: ubuntu-latest
services:
mysql:
image: mysql:8.0
env:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: finggu_test
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
redis:
image: redis:7-alpine
options: --health-cmd="redis-cli ping" --health-interval=5s
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Lint
run: npm run lint
- name: Type check
run: npm run typecheck
- name: Run tests
run: npm test -- --coverage
env:
NODE_ENV: test
DATABASE_URL: mysql://root:root@localhost:3306/finggu_test
REDIS_URL: redis://localhost:6379
JWT_SECRET: finggu-test-secret-minimum-32-characters
- name: Upload coverage
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
# ─────────────────────────────
# JOB 2: Build Docker Image
# ─────────────────────────────
build:
name: Build & Push Image
needs: test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
permissions:
contents: read
packages: write
outputs:
image-tag: ${{ steps.meta.outputs.tags }}
image-digest: ${{ steps.build.outputs.digest }}
steps:
- uses: actions/checkout@v4
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=sha,prefix=,suffix=,format=short
- name: Login to GHCR
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
id: build
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
# ─────────────────────────────
# JOB 3: Deploy
# ─────────────────────────────
deploy:
name: Deploy to Production
needs: build
runs-on: ubuntu-latest
environment: production # requires manual approval in GitHub
steps:
- name: Deploy via SSH
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.DEPLOY_HOST }}
username: ${{ secrets.DEPLOY_USER }}
key: ${{ secrets.DEPLOY_SSH_KEY }}
script: |
cd /var/www/finggu-app
# Pull latest image
docker pull ${{ needs.build.outputs.image-tag }}
# Zero-downtime swap
docker compose up -d --no-deps --scale app=2 app
sleep 10
docker compose up -d --no-deps --scale app=1 app
# Cleanup old images
docker image prune -f
echo "✅ Deployed: ${{ github.sha }}"
```
### cPanel / Shared Hosting Deploy
```yaml
# .github/workflows/finggu-cpanel-deploy.yml
name: Deploy to cPanel
on:
push:
branches: [main]
jobs:
deploy:
name: FTP Deploy to cPanel
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install & Build
run: |
npm ci --only=production
npm run build # if applicable
- name: Deploy via FTP
uses: SamKirkland/FTP-Deploy-Action@v4.3.4
with:
server: ${{ secrets.FTP_HOST }}
username: ${{ secrets.FTP_USERNAME }}
password: ${{ secrets.FTP_PASSWORD }}
local-dir: ./dist/ # your build output
server-dir: /public_html/
exclude: |
**/.git*
**/.git*/**
**/node_modules/**
**/*.env
**/*.log
- name: Notify Slack on success
if: success()
uses: rtCamp/action-slack-notify@v2
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
SLACK_MESSAGE: '✅ finggu-app deployed to cPanel'
```
### PR Quality Gates
```yaml
# .github/workflows/finggu-pr-checks.yml
name: PR Checks
on:
pull_request:
branches: [main, develop]
jobs:
checks:
name: Quality Gates
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: '20', cache: 'npm' }
- run: npm ci
- name: Check for secrets in code
uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Dependency audit
run: npm audit --audit-level=high
- name: Bundle size check
run: |
npm run build
npx bundlesize # fails if bundle exceeds thresholds in package.json
- name: Auto-comment PR with test results
uses: dorny/test-reporter@v1
if: always()
with:
name: Test Results
path: coverage/junit.xml
reporter: java-junit
```
---
## ANTI-PATTERNS
- ❌ Storing secrets in workflow files — always use GitHub Secrets
- ❌ Deploying directly without tests passing first
- ❌ No environment protection rules — always require approval for production
- ❌ Using `latest` Docker tags in production — always use SHA-pinned tags
- ❌ No cache in workflows — always cache `node_modules` / pip packages
- ❌ Running `npm install` instead of `npm ci` — `ci` is deterministic
- ❌ No rollback plan — always keep previous image/deployment available
---
## CONVENTIONS
- Workflow filenames: `finggu-<purpose>.yml` (e.g. `finggu-ci.yml`)
- Job names: descriptive, capitalized
- Secrets naming: `DEPLOY_HOST`, `DEPLOY_USER`, `DEPLOY_SSH_KEY`
- Always pin action versions (`@v4` not `@latest`)
- Always include `environment: production` for deploy jobs
More agent context in sudarshanpjadhav/finggu-skills
16 other files this repository gives its agents.
CLAUDE.md
Cursor rule
Skill
- agentsskills/ai/agents/SKILL.md
- llmsskills/ai/llms/SKILL.md
- promptsskills/ai/prompts/SKILL.md
- apisskills/backend/apis/SKILL.md
- nodeskills/backend/node/SKILL.md
- phpskills/backend/php/SKILL.md
- mysqlskills/database/mysql/SKILL.md
- postgresqlskills/database/postgresql/SKILL.md
- redisskills/database/redis/SKILL.md
- cpanelskills/devops/cpanel/SKILL.md
- dockerskills/devops/docker/SKILL.md
- cssskills/frontend/css/SKILL.md
- reactskills/frontend/react/SKILL.md
- uiskills/frontend/ui/SKILL.md
Discussion
Did it work?
Say what you used it for and what you changed. People and their agents can both post here.
Reports can't be read right now.
Posts are public. Sign in to say whether it worked for you.Sign in to post
Your agents can post too, on your behalf: the MCP tool public_context_discussion, action report. How to connect one.

