---
name: github-actions-gen
description: |
  트리거: "github actions", "CI CD 설정", "워크플로우 만들어줘", "깃허브 액션", "ci 파이프라인", "배포 자동화"
  수행: CI/CD 파이프라인 YAML 생성. 테스트 → 빌드 → 도커 푸시 → 배포 단계. 언어·프레임워크별 맞춤 설정
  출력: .github/workflows/*.yml 파일들
---

# GitHub Actions CI/CD Generator

## 목적

프로젝트의 언어, 프레임워크, 배포 대상(서버, AWS, GCP, Vercel 등)에 맞는 GitHub Actions 워크플로우를 생성한다.
테스트 → 빌드 → 도커 이미지 푸시 → 배포의 전체 파이프라인을 자동화한다.

## 실행 절차

1. **프로젝트 분석**: 언어/런타임, 테스트 프레임워크, 빌드 도구 파악
2. **배포 대상 확인**: VPS(SSH), AWS ECS/EKS, GCP Cloud Run, Vercel, Kubernetes 등
3. **워크플로우 설계**: CI(테스트+빌드) / CD(배포) 분리 or 통합 결정
4. **캐싱 전략 적용**: node_modules, pip, Go modules, Docker layer 캐싱
5. **시크릿 목록 명시**: 필요한 GitHub Secrets 항목 주석으로 안내
6. **브랜치 전략 반영**: main → 프로덕션, develop → 스테이징 분기 처리

## 출력 형식

### Node.js 풀 파이프라인 예시

```yaml
# .github/workflows/ci-cd.yml
name: CI/CD Pipeline

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main, develop]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}
  NODE_VERSION: '20'

jobs:
  # ──────────────────────────────────────────
  # Job 1: 코드 품질 검사 + 테스트
  # ──────────────────────────────────────────
  test:
    name: Test & Lint
    runs-on: ubuntu-latest
    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: Run ESLint
        run: npm run lint

      - name: Run type check
        run: npm run typecheck

      - name: Run tests
        run: npm run test:ci
        env:
          CI: true

      - name: Upload coverage
        uses: codecov/codecov-action@v4
        if: always()
        with:
          token: ${{ secrets.CODECOV_TOKEN }}
          fail_ci_if_error: false

  # ──────────────────────────────────────────
  # Job 2: 도커 이미지 빌드 & 푸시
  # ──────────────────────────────────────────
  build:
    name: Build & Push Docker Image
    runs-on: ubuntu-latest
    needs: test
    if: github.event_name == 'push'
    permissions:
      contents: read
      packages: write
    outputs:
      image-tag: ${{ steps.meta.outputs.tags }}
      image-digest: ${{ steps.build.outputs.digest }}
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Log in to GitHub Container Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract metadata
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          tags: |
            type=ref,event=branch
            type=sha,prefix={{branch}}-
            type=raw,value=latest,enable={{is_default_branch}}

      - 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
          build-args: |
            NEXT_PUBLIC_API_URL=${{ vars.NEXT_PUBLIC_API_URL }}

  # ──────────────────────────────────────────
  # Job 3: 스테이징 배포 (develop 브랜치)
  # ──────────────────────────────────────────
  deploy-staging:
    name: Deploy to Staging
    runs-on: ubuntu-latest
    needs: build
    if: github.ref == 'refs/heads/develop'
    environment:
      name: staging
      url: https://staging.example.com
    steps:
      - name: Deploy to staging server via SSH
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.STAGING_HOST }}
          username: ${{ secrets.STAGING_USER }}
          key: ${{ secrets.STAGING_SSH_KEY }}
          script: |
            cd /opt/myapp
            echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
            docker compose pull app
            docker compose up -d app
            docker image prune -f

  # ──────────────────────────────────────────
  # Job 4: 프로덕션 배포 (main 브랜치)
  # ──────────────────────────────────────────
  deploy-production:
    name: Deploy to Production
    runs-on: ubuntu-latest
    needs: build
    if: github.ref == 'refs/heads/main'
    environment:
      name: production
      url: https://example.com
    steps:
      - name: Deploy to production server via SSH
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.PROD_HOST }}
          username: ${{ secrets.PROD_USER }}
          key: ${{ secrets.PROD_SSH_KEY }}
          script: |
            cd /opt/myapp
            echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
            docker compose pull app
            docker compose up -d --no-deps app
            docker image prune -f
            # 헬스체크 대기
            for i in $(seq 1 12); do
              if curl -sf http://localhost:3000/api/health; then
                echo "Deployment successful"
                exit 0
              fi
              echo "Waiting for app to start ($i/12)..."
              sleep 5
            done
            echo "Deployment health check failed"
            exit 1
```

### 필요한 GitHub Secrets 목록

```
# CI/CD 시크릿 설정 가이드
# Settings > Secrets and variables > Actions 에서 추가

CODECOV_TOKEN          # Codecov 업로드 토큰 (선택)
STAGING_HOST           # 스테이징 서버 IP/도메인
STAGING_USER           # SSH 사용자 이름
STAGING_SSH_KEY        # SSH 개인키 (-----BEGIN OPENSSH PRIVATE KEY-----)
PROD_HOST              # 프로덕션 서버 IP/도메인
PROD_USER              # SSH 사용자 이름
PROD_SSH_KEY           # SSH 개인키
```

### AWS ECS 배포 변형

```yaml
  deploy-ecs:
    name: Deploy to AWS ECS
    runs-on: ubuntu-latest
    needs: build
    steps:
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ap-northeast-2

      - name: Download task definition
        run: |
          aws ecs describe-task-definition \
            --task-definition myapp \
            --query taskDefinition > task-definition.json

      - name: Update ECS task definition with new image
        id: task-def
        uses: aws-actions/amazon-ecs-render-task-definition@v1
        with:
          task-definition: task-definition.json
          container-name: myapp
          image: ${{ needs.build.outputs.image-tag }}

      - name: Deploy to ECS
        uses: aws-actions/amazon-ecs-deploy-task-definition@v1
        with:
          task-definition: ${{ steps.task-def.outputs.task-definition }}
          service: myapp-service
          cluster: myapp-cluster
          wait-for-service-stability: true
```

## 사용 예시

**입력:**
> "Python FastAPI 프로젝트 GitHub Actions 만들어줘. pytest 테스트하고 GCP Cloud Run에 배포."

**출력:**
- `.github/workflows/ci.yml` - pytest + flake8 + mypy
- `.github/workflows/cd.yml` - Artifact Registry 푸시 + Cloud Run 배포
- Secrets 목록 주석

## 주의사항

- `actions/checkout@v4` 등 모든 액션은 최신 메이저 버전 태그 사용
- 시크릿은 절대 `echo`로 출력하거나 로그에 노출하지 않음
- `environment` 설정으로 프로덕션 배포 전 승인 게이트 활성화 권장
- Docker 레이어 캐싱은 `type=gha` (GitHub Actions Cache) 사용
- `needs:` 의존성으로 job 실행 순서 명시적 제어
- PR에서는 빌드/테스트만, push에서 배포 트리거 (이중 실행 방지)
