GitHub Actions
SkillCloud & infraCI/CD workflow patterns, testing pipelines, deployment automation. Use when setting up GitHub Actions workflows for testing, building, linting, or deploying a fullstack app.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the GitHub Actions skill
What this skill tells your AI
The instructions your AI receives, as published by sabahattink/antigravity-fullstack-hq in skills/github-actions/SKILL.md and read by ahel’s review.
Full CI Pipeline
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true # Cancel stale runs on new push
jobs:
# ─── Lint & Type Check ─────────────────────────────────────
lint:
name: Lint & Type Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with: { version: 9 }
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- name: Type check (API)
run: pnpm --filter api run type-check
- name: Type check (Web)
run: pnpm --filter web run type-check
- name: Lint
run: pnpm run lint
# ─── Unit Tests ────────────────────────────────────────────
test-unit:
name: Unit Tests
runs-on: ubuntu-latest
needs: lint
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with: { version: 9 }
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- name: Run unit tests
run: pnpm --filter api run test:cov
- name: Upload coverage
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./apps/api/coverage/lcov.info
# ─── Integration Tests ─────────────────────────────────────
test-integration:
name: Integration Tests
runs-on: ubuntu-latest
needs: lint
services:
postgres:
image: postgres:16-alpine
env:
POSTGRES_DB: test_db
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
ports: ["5432:5432"]
options: >-
--health-cmd pg_isready
--health-interval 5s
--health-timeout 5s
--health-retries 5
redis:
image: redis:7-alpine
ports: ["6379:6379"]
options: >-
--health-cmd "redis-cli ping"
--health-interval 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with: { version: 9 }
- uses: actions/setup-node@v4
with: { node-version: 22, cache: pnpm }
- run: pnpm install --frozen-lockfile
- name: Run migrations
run: pnpm --filter api run migration:run
env:
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test_db
- name: Run integration tests
run: pnpm --filter api run test:integration
env:
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test_db
REDIS_URL: redis://localhost:6379
JWT_SECRET: test-secret-32-chars-minimum-length
# ─── E2E Tests ─────────────────────────────────────────────
test-e2e:
name: E2E Tests (Playwright)
runs-on: ubuntu-latest
needs: [test-unit, test-integration]
timeout-minutes: 20
services:
postgres:
image: postgres:16-alpine
env: { POSTGRES_DB: e2e_db, POSTGRES_USER: postgres, POSTGRES_PASSWORD: postgres }
ports: ["5432:5432"]
options: --health-cmd pg_isready --health-interval 5s --health-retries 5
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with: { version: 9 }
- uses: actions/setup-node@v4
with: { node-version: 22, cache: pnpm }
- run: pnpm install --frozen-lockfile
- name: Cache Playwright browsers
uses: actions/cache@v4
id: pw-cache
with:
path: ~/.cache/ms-playwright
key: playwright-${{ hashFiles('**/package.json') }}
- name: Install Playwright browsers
if: steps.pw-cache.outputs.cache-hit != 'true'
run: pnpm exec playwright install --with-deps chromium
- name: Build apps
env:
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/e2e_db
run: pnpm run build
- name: Run E2E tests
run: pnpm run test:e2e
env:
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/e2e_db
PLAYWRIGHT_BASE_URL: http://localhost:3000
- name: Upload Playwright report
if: failure()
uses: actions/upload-artifact@v4
with:
name: playwright-report
path: playwright-report/
retention-days: 7
Deploy Workflow
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main]
workflow_dispatch:
inputs:
environment:
description: Target environment
required: true
default: staging
type: choice
options: [staging, production]
jobs:
deploy-backend:
name: Deploy API to Railway
runs-on: ubuntu-latest
environment: ${{ github.event.inputs.environment || 'staging' }}
steps:
- uses: actions/checkout@v4
- name: Install Railway CLI
run: npm i -g @railway/cli
- name: Deploy to Railway
run: railway up --service api --detach
env:
RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}
- name: Wait for deployment health
run: |
for i in {1..12}; do
STATUS=$(curl -s -o /dev/null -w "%{http_code}" ${{ vars.API_URL }}/health/liveness)
if [ "$STATUS" == "200" ]; then
echo "API is healthy"
exit 0
fi
echo "Attempt $i: status=$STATUS, waiting..."
sleep 10
done
echo "Health check failed after 2 minutes"
exit 1
deploy-frontend:
name: Deploy Web to Vercel
runs-on: ubuntu-latest
needs: deploy-backend
environment: ${{ github.event.inputs.environment || 'staging' }}
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with: { version: 9 }
- uses: actions/setup-node@v4
with: { node-version: 22, cache: pnpm }
- run: pnpm install --frozen-lockfile
- name: Deploy to Vercel
run: |
pnpm dlx vercel \
--token=${{ secrets.VERCEL_TOKEN }} \
--prod \
${{ github.event.inputs.environment == 'production' && '--prod' || '' }}
env:
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
Reusable Workflow
# .github/workflows/_setup-node.yml
name: Setup Node (Reusable)
on:
workflow_call:
inputs:
node-version:
type: string
default: '22'
jobs:
setup:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with: { version: 9 }
- uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
cache: pnpm
- run: pnpm install --frozen-lockfile
# Usage:
# jobs:
# setup:
# uses: ./.github/workflows/_setup-node.yml
PR Checks & Branch Protection
# .github/workflows/pr-checks.yml
name: PR Checks
on:
pull_request:
types: [opened, synchronize, reopened, edited]
jobs:
pr-title:
name: Validate PR Title
runs-on: ubuntu-latest
steps:
- uses: amannn/action-semantic-pull-request@v5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
types: [feat, fix, refactor, docs, test, chore, perf, ci]
requireScope: false
check-diff:
name: Check Changed Files
runs-on: ubuntu-latest
outputs:
api-changed: ${{ steps.changes.outputs.api }}
web-changed: ${{ steps.changes.outputs.web }}
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v3
id: changes
with:
filters: |
api:
- 'apps/api/**'
- 'packages/**'
web:
- 'apps/web/**'
- 'packages/**'
Secrets Required
# Repository → Settings → Secrets and variables → Actions
RAILWAY_TOKEN — Railway API token for backend deploys
VERCEL_TOKEN — Vercel CLI token
VERCEL_ORG_ID — Vercel organization ID
VERCEL_PROJECT_ID — Vercel project ID
CODECOV_TOKEN — Codecov upload token
# Variables (non-secret)
API_URL — https://api.example.com (for health checks)
Caching Strategy
# Cache node_modules (pnpm store)
- uses: actions/cache@v4
with:
path: ~/.local/share/pnpm/store
key: pnpm-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: pnpm-${{ runner.os }}-
# Cache Next.js build
- uses: actions/cache@v4
with:
path: ${{ github.workspace }}/apps/web/.next/cache
key: nextjs-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ hashFiles('apps/web/**/*.ts', 'apps/web/**/*.tsx') }}
restore-keys: nextjs-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}-
Forbidden Patterns
- Never hardcode secrets as plain text in workflow files
- Never use
continue-on-error: trueto hide test failures - Never deploy without a prior successful test run
- Never use
actions/checkout@v2or older — use v4 - Never skip
--frozen-lockfile— it ensures reproducible installs - Never give workflows more permissions than needed (use
permissions: read-allas default) - Never run E2E tests before unit/integration pass — it wastes expensive minutes
Signals
- GitHub stars
- 30
- Forks
- 9
- Last commit
- Aug 2026
ahel review
S4info
community integration — published by sabahattink, not github
Automated review, not a security audit. Ruleset v1.
Advanced
- Catalog kind
- skill
- Gateway key
github-actions-sabahattink- Source
- github.com/sabahattink/antigravity-fullstack-hq