eletrotupi / tcc/ .github/workflows/deploy.ymlc377fb94289224023a0ab5d229329b5a4e06af51
3.7 KB | 148 lines Raw
1
name: Test & Deploy
2

3
on:
4
  push:
5
    branches:
6
      - master
7
      - production
8
    paths:
9
      - 'api/**'
10
      - '.github/workflows/deploy.yml'
11
  pull_request:
12
    paths:
13
      - 'api/**'
14
      - '.github/workflows/deploy.yml'
15

16
env:
17
  REGISTRY: ghcr.io
18
  IMAGE_NAME: ${{ github.repository }}
19

20
jobs:
21
  test:
22
    name: Run test suite
23
    runs-on: ubuntu-latest
24

25
    services:
26
      postgres:
27
        image: postgres:17-alpine
28
        env:
29
          POSTGRES_USER: user
30
          POSTGRES_PASSWORD: password
31
          POSTGRES_DB: postgres
32
        options: >-
33
          --health-cmd "pg_isready -U user"
34
          --health-interval 10s
35
          --health-timeout 5s
36
          --health-retries 5
37
        ports:
38
          - 5432:5432
39

40
    defaults:
41
      run:
42
        working-directory: api
43

44
    env:
45
      DATABASE_URL: postgres://user:password@localhost:5432/orbit_test
46
      NODE_ENV: test
47
      JWT_SECRET: test-secret-key
48
      FRONTEND_URL: http://localhost:8081
49

50
    steps:
51
      - uses: actions/checkout@v4
52

53
      - uses: actions/setup-node@v4
54
        with:
55
          node-version: '24'
56
          cache: 'npm'
57
          cache-dependency-path: api/package-lock.json
58

59
      - name: Install dependencies
60
        run: npm ci
61

62
      - name: Set up test database
63
        run: |
64
          node scripts/create-test-db.mjs
65
          npx prisma generate
66
          npx prisma db push
67

68
      - name: Typecheck (advisory)
69
        run: |
70
          npm run typecheck || echo "::warning title=API typecheck::tsc reported errors (advisory, see log above)"
71

72
      - name: Run tests
73
        run: npx vitest run
74

75
  build-and-push:
76
    name: Build & push image
77
    needs: test
78
    if: github.event_name == 'push'
79
    runs-on: ubuntu-latest
80
    permissions:
81
      contents: read
82
      packages: write
83

84
    outputs:
85
      image_tag: ${{ steps.meta.outputs.version }}
86

87
    steps:
88
      - name: Checkout
89
        uses: actions/checkout@v4
90

91
      - name: Log in to GHCR
92
        uses: docker/login-action@v3
93
        with:
94
          registry: ${{ env.REGISTRY }}
95
          username: ${{ github.actor }}
96
          password: ${{ secrets.GHCR_TOKEN }}
97

98
      - name: Docker metadata
99
        id: meta
100
        uses: docker/metadata-action@v5
101
        with:
102
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
103
          tags: |
104
            # main branch => tag "latest"
105
            type=raw,value=latest,enable=${{ github.ref == 'refs/heads/master' }}
106
            # production branch => tag "production"
107
            # type=raw,value=production,enable=${{ github.ref == 'refs/heads/production' }}
108
            # always tag with short SHA for traceability
109
            type=sha,prefix=,format=short
110

111
      - name: Build and push
112
        uses: docker/build-push-action@v5
113
        with:
114
          context: ./api
115
          file: ./api/Dockerfile.production
116
          push: true
117
          tags: ${{ steps.meta.outputs.tags }}
118
          labels: ${{ steps.meta.outputs.labels }}
119

120
  deploy-production:
121
    name: Deploy to production
122
    needs: build-and-push
123
    runs-on: ubuntu-latest
124
    if: github.ref == 'refs/heads/master'
125
    environment: production
126

127
    steps:
128
      - name: Deploy via SSH
129
        uses: appleboy/ssh-action@v1
130
        with:
131
          host: ${{ secrets.VPS_HOST }}
132
          username: ${{ secrets.VPS_USER }}
133
          key: ${{ secrets.VPS_SSH_KEY }}
134
          script: |
135
            set -e
136
            cd /srv/app/production
137

138
            docker pull ghcr.io/${{ github.repository }}:latest
139

140
            sed -i "s/^IMAGE_TAG=.*/IMAGE_TAG=latest/" .env
141

142
            docker compose up -d --no-deps --force-recreate api
143

144
            # old image layers pile up across deploys; keep roughly the last week
145
            docker image prune -af --filter "until=168h" >/dev/null 2>&1 || true
146

147
            sleep 5
148
            docker compose logs --tail=50 api