diff --git a/.github/workflows/frontend-cd.yml b/.github/workflows/frontend-cd.yml new file mode 100644 index 0000000..3eeb495 --- /dev/null +++ b/.github/workflows/frontend-cd.yml @@ -0,0 +1,60 @@ +name: Frontend CD + +on: + workflow_run: + workflows: + - Frontend CI + types: + - completed + branches: + - main + workflow_dispatch: {} + +defaults: + run: + working-directory: frontend + +permissions: + contents: read + +jobs: + build-and-deploy: + name: Build and deploy + runs-on: ubuntu-latest + if: ${{ github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' }} + + env: + DEPLOY_SHA: ${{ github.event.workflow_run.head_sha || github.sha }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + ref: ${{ env.DEPLOY_SHA }} + + - name: Set up pnpm + uses: pnpm/action-setup@v4 + with: + version: 10 + + - name: Set up Node 24 + uses: actions/setup-node@v4 + with: + node-version: '24' + cache: pnpm + cache-dependency-path: frontend/pnpm-lock.yaml + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build production bundle + run: pnpm build + + - name: Build Docker image + run: docker build -t verity-frontend:${{ env.DEPLOY_SHA }} . + + - name: Deploy + run: | + echo "Deploy step placeholder — no real deployment is configured yet." + echo "Build artifact and Docker image (verity-frontend:${{ env.DEPLOY_SHA }}) are ready." + echo "Pipeline finished successfully." diff --git a/.github/workflows/frontend-ci.yml b/.github/workflows/frontend-ci.yml new file mode 100644 index 0000000..56b490c --- /dev/null +++ b/.github/workflows/frontend-ci.yml @@ -0,0 +1,58 @@ +name: Frontend CI + +on: + push: + branches: + - '**' + pull_request: + branches: + - main + +defaults: + run: + working-directory: frontend + +permissions: + contents: read + +jobs: + build-and-test: + name: Lint, build, test and coverage gate + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up pnpm + uses: pnpm/action-setup@v4 + with: + version: 10 + + - name: Set up Node 24 + uses: actions/setup-node@v4 + with: + node-version: '24' + cache: pnpm + cache-dependency-path: frontend/pnpm-lock.yaml + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Lint + run: pnpm lint + + - name: Type-check and build + run: pnpm build + + - name: Run tests and check coverage (80% minimum) + run: pnpm test:coverage + + - name: Upload test reports + if: always() + uses: actions/upload-artifact@v4 + with: + name: test-reports + path: | + frontend/coverage + retention-days: 7 diff --git a/README.md b/README.md index e0fe732..57bb949 100644 --- a/README.md +++ b/README.md @@ -279,3 +279,19 @@ Principais pontos: - Responsivo, com testes unitários (Vitest + Testing Library) cobrindo ≥ 80% do código Para instruções de setup, scripts disponíveis e detalhes de arquitetura, veja **[`frontend/README.md`](frontend/README.md)**. + +### CI/CD + +Mesmo modelo do backend, em dois workflows separados (`.github/workflows/frontend-ci.yml` e +`frontend-cd.yml`), pra não misturar com a pipeline do backend: + +- **Frontend CI** — roda em todo push e pull request: instala as dependências (`pnpm install + --frozen-lockfile`), roda o lint (`oxlint`), builda (`tsc -b && vite build` — valida tipos e gera o + bundle de produção) e roda os testes com o gate de cobertura do Vitest (mínimo 80% em statements, + branches, functions e lines, já configurado no `vite.config.ts`). O relatório de cobertura sobe como + artifact do run. +- **Frontend CD** — dispara depois que a CI do frontend passa na `main` (ou manualmente via + `workflow_dispatch`): builda o bundle de novo e builda uma imagem Docker (`verity-frontend:`) a + partir de um `Dockerfile` multi-stage novo (Node + pnpm builda o `dist/`, um `nginx:alpine` enxuto serve + os arquivos estáticos, com fallback de rota pro `index.html` pra funcionar com o client-side routing do + `react-router-dom`). Assim como no backend, o passo de deploy em si ainda é um placeholder. diff --git a/frontend/.dockerignore b/frontend/.dockerignore new file mode 100644 index 0000000..c4cdb3c --- /dev/null +++ b/frontend/.dockerignore @@ -0,0 +1,6 @@ +node_modules/ +dist/ +coverage/ +.git/ +.idea/ +*.md diff --git a/frontend/Dockerfile b/frontend/Dockerfile new file mode 100644 index 0000000..bf30832 --- /dev/null +++ b/frontend/Dockerfile @@ -0,0 +1,12 @@ +FROM node:24-slim AS build +WORKDIR /app +RUN corepack enable +COPY package.json pnpm-lock.yaml ./ +RUN pnpm install --frozen-lockfile +COPY . . +RUN pnpm build + +FROM nginx:1.27-alpine AS runtime +COPY --from=build /app/dist /usr/share/nginx/html +COPY nginx.conf /etc/nginx/conf.d/default.conf +EXPOSE 80 diff --git a/frontend/nginx.conf b/frontend/nginx.conf new file mode 100644 index 0000000..3c25a98 --- /dev/null +++ b/frontend/nginx.conf @@ -0,0 +1,10 @@ +server { + listen 80; + server_name _; + root /usr/share/nginx/html; + index index.html; + + location / { + try_files $uri $uri/ /index.html; + } +}