From c67d11b54316b415f37cbc8bbeb133d233844108 Mon Sep 17 00:00:00 2001 From: Yonas Tewabe Date: Fri, 7 Aug 2026 14:05:21 +0300 Subject: [PATCH] Add script to sync .env files from Env Manager API This script syncs .env files from the Env Manager API into the repository for various services. It handles authorization, error checking, and exports relevant environment variables for GitHub actions. --- scripts/deploy/sync-env-from-app.sh | 84 +++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 scripts/deploy/sync-env-from-app.sh diff --git a/scripts/deploy/sync-env-from-app.sh b/scripts/deploy/sync-env-from-app.sh new file mode 100644 index 000000000..bc228a432 --- /dev/null +++ b/scripts/deploy/sync-env-from-app.sh @@ -0,0 +1,84 @@ +#!/usr/bin/env bash +# Sync .env files from the Env Manager API into the repo. +# +# Usage: +# ENV_MANAGER_TOKEN=xxx ./scripts/deploy/sync-env-from-server.sh freight-api freight-portal freight-backoffice +# +# You normally only need to pass the token via the action secret, and BRANCH +# via the job-level env (e.g. `BRANCH: ${{ github.ref_name }}` in the workflow): +# env: +# BRANCH: ${{ github.ref_name }} +# ENV_MANAGER_TOKEN: ${{ secrets.ENV_MANAGER_TOKEN }} +# +# API layout (one endpoint per service): +# GET https://env.smart.aaca.gov.et/api/env/edr//?format=dotenv +# Header: Authorization: Bearer +set -euo pipefail + +PROJECT="edr" +ENV_MANAGER_URL="https://env.smart.aaca.gov.et" +BRANCH="${BRANCH:?BRANCH is required}" +ENV_MANAGER_TOKEN="${ENV_MANAGER_TOKEN:?ENV_MANAGER_TOKEN is required}" + +declare -A SERVICE_ENV_TARGET=( + ["freight-api"]="apps/edr-freight-api/.env" + ["freight-portal"]="apps/edr-freight-web/portal/.env" + ["freight-backoffice"]="apps/edr-freight-web/backoffice/.env" + ["gps-tracker"]="apps/edr-gps-tracker/.env" + ["passenger-api"]="apps/edr-passenger-api/.env" + ["passenger-portal"]="apps/edr-passenger-web/portal/.env" + ["passenger-backoffice"]="apps/edr-passenger-web/backoffice/.env" + ["payment-api"]="apps/edr-payment-api/.env" +) + +for service in "$@"; do + dest="${SERVICE_ENV_TARGET[${service}]:-}" + if [[ -z "${dest}" ]]; then + echo "Unknown service: ${service}" >&2 + exit 1 + fi + + url="${ENV_MANAGER_URL}/api/env/${PROJECT}/${BRANCH}/${service}?format=dotenv" + mkdir -p "$(dirname "${dest}")" + + tmp_file="$(mktemp)" + trap 'rm -f "${tmp_file}"' RETURN 2>/dev/null || true + + http_status=$(curl -fsS -o "${tmp_file}" -w "%{http_code}" \ + -H "Authorization: Bearer ${ENV_MANAGER_TOKEN}" \ + "${url}") || { + echo "Failed to fetch env for '${service}' from ${url}" >&2 + rm -f "${tmp_file}" + exit 1 + } + + if [[ "${http_status}" != "200" ]]; then + echo "Env Manager returned HTTP ${http_status} for '${service}' (${url})" >&2 + rm -f "${tmp_file}" + exit 1 + fi + + if [[ ! -s "${tmp_file}" ]]; then + echo "Env Manager returned an empty response for '${service}' (${url})" >&2 + rm -f "${tmp_file}" + exit 1 + fi + + mv "${tmp_file}" "${dest}" + echo "Synced ${url} -> ${dest}" + + port_value=$(sed -n -E 's/^[[:space:]]*PORT[[:space:]]*=[[:space:]]*"?([^"#]+)"?[[:space:]]*(#.*)?$/\1/p' "${dest}" | head -n1 | tr -d '[:space:]') + if [[ -z "${port_value}" ]]; then + echo "Missing required PORT in env file for '${service}' (${dest})" >&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 ${dest}" + # Forward NEXT_PUBLIC_* and VITE_* vars so docker compose build can inject them as build args. + grep -E '^[[:space:]]*(NEXT_PUBLIC_|VITE_)[A-Za-z0-9_]+=' "${dest}" \ + | sed -E 's/^[[:space:]]*//' >> "${GITHUB_ENV}" || true + fi +done