diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 000000000..66521fdb1 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,68 @@ +name: Deploy Stacks + +on: + push: + branches: + - main + - dev + - staging + workflow_dispatch: + +concurrency: + group: deploy-${{ github.ref_name }} + cancel-in-progress: true + +jobs: + deploy: + name: Deploy ${{ matrix.service }} + runs-on: self-hosted + strategy: + fail-fast: false + matrix: + include: + - project: ema-dev + build_env_file: portal-web.build.env + service: ema-portal + - project: ema-dev + build_env_file: backoffice-web.build.env + service: ema-backoffice + env: + PROJECT: ${{ matrix.project }} + BRANCH: ${{ github.ref_name }} + DEPLOY_USER: tria + BUILD_ENV_FILE: ${{ matrix.build_env_file }} + DOCKER_BUILDKIT: "1" + COMPOSE_DOCKER_CLI_BUILD: "1" + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Sync environment from server + run: | + chmod +x scripts/deploy/*.sh + ./scripts/deploy/sync-env-from-server.sh "${{ matrix.service }}" + + - name: Set compose project name + run: | + set -euo pipefail + branch_slug=$(echo "${BRANCH}" | tr "[:upper:]" "[:lower:]" | sed -E "s/[^a-z0-9]+/-/g; s/^-+//; s/-+$//") + echo "COMPOSE_PROJECT_NAME=${PROJECT}-${branch_slug}" >> "${GITHUB_ENV}" + + # - name: Configure npm auth for Docker builds + # env: + # NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + # run: ./scripts/deploy/create-npmrc.sh + + - name: Build ${{ matrix.service }} + run: | + set -euo pipefail + docker compose --project-name "${COMPOSE_PROJECT_NAME}" build --no-cache "${{ matrix.service }}" + + - name: Deploy ${{ matrix.service }} + run: | + set -euo pipefail + docker compose --project-name "${COMPOSE_PROJECT_NAME}" up -d "${{ matrix.service }}" + + - name: Remove npm credentials from workspace + if: always() + run: rm -f .npmrc .npmrc_temp diff --git a/.gitignore b/.gitignore index 482dad8a6..0aca787ef 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,22 @@ +# dependencies node_modules/ -.nx -dist/ + +# build output +**/dist/ +.next/ +coverage/ +*.tsbuildinfo +**/*.tsbuildinfo + +# env .env .env.* -!.env.example + +# logs +*.log + +# OS/editor .DS_Store +.idea/ +.vscode/ +.npmrc diff --git a/.npmrc b/.npmrc new file mode 100644 index 000000000..11a7adb31 --- /dev/null +++ b/.npmrc @@ -0,0 +1,2 @@ +@tria-plc:registry=https://npm.pkg.github.com +//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN} diff --git a/Dockerfile b/Dockerfile index 8b252b8c3..f29502bd4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ FROM node:24-alpine AS deps WORKDIR /app COPY package.json package-lock.json* ./ -RUN npm ci +RUN npm install --legacy-peer-deps FROM deps AS base COPY . . diff --git a/docker-compose.yml b/docker-compose.yml index b52313da7..7dddad0ca 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,19 +1,28 @@ -version: "3.9" services: - portal: + ema-portal: build: context: . dockerfile: Dockerfile - target: portal + target: portal + secrets: + - npmrc ports: - - "${PORTAL_PORT:-4200}:80" - env_file: .env + - "${EMA_PORTAL_PORT:-8006}:80" + env_file: + - apps/portal/.env - backoffice: + ema-backoffice: build: context: . dockerfile: Dockerfile - target: backoffice + target: backoffice + secrets: + - npmrc ports: - - "${BACKOFFICE_PORT:-4201}:80" - env_file: .env + - "${EMA_BACKOFFICE_PORT:-8007}:80" + env_file: + - apps/backoffice/.env + +secrets: + npmrc: + file: .npmrc diff --git a/scripts/deploy/sync-env-from-server.sh b/scripts/deploy/sync-env-from-server.sh new file mode 100644 index 000000000..3cc193cf4 --- /dev/null +++ b/scripts/deploy/sync-env-from-server.sh @@ -0,0 +1,82 @@ +#!/usr/bin/env bash +# Sync .env files from the self-hosted runner filesystem into the repo. +# +# Usage: +# PROJECT=ema-portal BRANCH=main ./scripts/deploy/sync-env-from-server.sh ema-portal ema-api ema-backoffice +# +# Server layout (one file per service): +# /home/user/environmen///ema-api.env +# /home/user/environmen///ema-portal.env +# /home/user/environmen///ema-web.build.env + +set -euo pipefail + +DEPLOY_USER="${DEPLOY_USER:-tria}" +BRANCH="${BRANCH:?BRANCH is required}" +BRANCH_SLUG="${BRANCH_SLUG:-$(echo "${BRANCH}" | tr "[:upper:]" "[:lower:]" | sed -E "s/[^a-z0-9]+/-/g; s/^-+//; s/-+$//")}" +ENV_ROOT="${ENV_ROOT:-/home/${DEPLOY_USER}/environment/ema/${BRANCH_SLUG}/${PROJECT:?PROJECT is required}}" + +if [[ ! -d "${ENV_ROOT}" ]]; then + echo "Environment directory not found: ${ENV_ROOT}" >&2 + exit 1 +fi + +echo "Using environment directory: ${ENV_ROOT}" + +declare -A SERVICE_ENV_TARGET=( + ["ema-portal"]="apps/portal/.env" + ["ema-backoffice"]="apps/backoffice/.env" +) + +for service in "$@"; do + src="${ENV_ROOT}/${service}.env" + dest="${SERVICE_ENV_TARGET[${service}]:-}" + + if [[ -z "${dest}" ]]; then + echo "Unknown service: ${service}" >&2 + exit 1 + fi + + if [[ ! -f "${src}" ]]; then + echo "Missing env file: ${src}" >&2 + exit 1 + fi + + mkdir -p "$(dirname "${dest}")" + cp "${src}" "${dest}" + echo "Synced ${src} -> ${dest}" + + port_value=$(sed -n -E 's/^[[:space:]]*PORT[[:space:]]*=[[:space:]]*"?([^"#]+)"?[[:space:]]*(#.*)?$/\1/p' "${src}" | head -n1 | tr -d '[:space:]') + if [[ -z "${port_value}" ]]; then + echo "Missing required PORT in env file: ${src}" >&2 + exit 1 + fi + + if [[ -n "${GITHUB_ENV:-}" ]]; then + service_var=$(echo "${service}" | tr '[:lower:]-' '[:upper:]_') + echo "${service_var}_PORT=${port_value}" >> "${GITHUB_ENV}" + echo "Exported ${service_var}_PORT from ${src}" + + # Forward NEXT_PUBLIC_* vars so docker compose build can inject them as build args. + grep -E '^[[:space:]]*NEXT_PUBLIC_[A-Za-z0-9_]+=' "${src}" \ + | sed -E 's/^[[:space:]]*//' >> "${GITHUB_ENV}" || true + fi +done + +# Optional build-time variables (VITE_API_URL, etc.) +# Set BUILD_ENV_FILE=freight-web.build.env or passenger-web.build.env per workflow. +build_env_file="${BUILD_ENV_FILE:-web.build.env}" +build_env="${ENV_ROOT}/${build_env_file}" +if [[ -f "${build_env}" ]]; then + echo "Loading build variables from ${build_env}" + set -a + # shellcheck disable=SC1090 + source "${build_env}" + set +a + + if [[ -n "${GITHUB_ENV:-}" ]]; then + grep -E '^[[:space:]]*export[[:space:]]+[A-Za-z_][A-Za-z0-9_]*=' "${build_env}" \ + | sed -E 's/^[[:space:]]*export[[:space:]]+//' >> "${GITHUB_ENV}" + echo "Wrote build variables to GITHUB_ENV" + fi +fi