8e472ac996
CI/CD - ERP Core / scripts (pull_request) Failing after 12m21s
CI/CD - ERP Core / e2e-typecheck (pull_request) Failing after 13m13s
CI/CD - ERP Core / frontend (pull_request) Failing after 14m5s
CI/CD - ERP Core / backend (pull_request) Failing after 14m57s
CI/CD - ERP Core / detect (pull_request) Failing after 13m42s
CI/CD - ERP Core / Build & Deploy (pull_request) Failing after 12m47s
CI/CD - ERP Core / ci-ok (pull_request) Failing after 14m58s
132 lines
5.3 KiB
Bash
132 lines
5.3 KiB
Bash
#!/usr/bin/env bash
|
|
# Shared settings + helpers for the ERP-Core CI/CD scripts. Sourced by the other scripts, never
|
|
# run directly. Runbook: docs/40-DEPLOYMENT.md (values here must match the server bootstrap, §4).
|
|
# shellcheck disable=SC2034 # variables are consumed by the scripts that source this file
|
|
set -euo pipefail
|
|
|
|
# ── Repository (folders whose git tree hash decides what is checked / built / deployed) ─────
|
|
BACKEND_PATH="Backend/ERPCore"
|
|
BACKEND_TESTS_PATH="Backend/ERPCore.Tests"
|
|
MIGRATIONS_PATH="Backend/ERPCore/Migrations"
|
|
FRONTEND_PATH="Frontend/erp-system"
|
|
E2E_PATH="Testing/e2e"
|
|
GITEA_URL="${GITEA_URL:-https://gitea.hexdive.com}"
|
|
REPO_SLUG="New_REP_SYSTEM/ERP-core"
|
|
REPO_GIT_URL="$GITEA_URL/$REPO_SLUG.git"
|
|
|
|
# ── Server layout of the ON-HOLD two-environment design (deploy/on-hold/). Active production does
|
|
# not use these paths — see .gitea/workflows/ci-cd.yml (erpcore.service, /home/erp/core/publish).
|
|
# ERP_ROOT still hosts the build lock taken by ci-backend.sh. ─────────────────────────────────
|
|
ERP_ROOT="${ERP_ROOT:-/opt/erpcore}"
|
|
RELEASES_DIR="$ERP_ROOT/releases/backend"
|
|
BUILD_LOCK="$ERP_ROOT/.build.lock"
|
|
BACKUP_DIR="${ERP_BACKUP_DIR:-/var/backups/erpcore}"
|
|
E2E_REPORTS_DIR="${ERP_E2E_REPORTS_DIR:-/var/lib/erpcore/e2e-reports}"
|
|
|
|
# ── Build images (builds run in CPU/memory-capped containers on the shared 8 GB VPS) ───────
|
|
DOTNET_SDK_IMAGE="mcr.microsoft.com/dotnet/sdk:10.0"
|
|
NODE_IMAGE="node:24-alpine"
|
|
WEB_IMAGE_REPO="erp-web"
|
|
DOTNET_EF_VERSION="10.0.9" # keep in step with Microsoft.EntityFrameworkCore.* in ERPCore.csproj
|
|
|
|
log() { printf '[erp] %s\n' "$*"; }
|
|
warn() { printf '[erp] WARNING: %s\n' "$*" >&2; }
|
|
fail() {
|
|
printf '[erp] ERROR: %s\n' "$*" >&2
|
|
exit 1
|
|
}
|
|
|
|
# load_env <test|release> — per-environment values. Ports, unit/container names and database
|
|
# names must match the server (systemd unit, Apache vhosts, /etc/erpcore/<env>.env).
|
|
# While both branches are on hold every call fails, so the lines after the case are unreachable.
|
|
# shellcheck disable=SC2317
|
|
load_env() {
|
|
ERP_ENV="$1"
|
|
case "$ERP_ENV" in
|
|
# ON HOLD — test environment (deploy/on-hold/README.md, docs/40-DEPLOYMENT.md "On hold").
|
|
# test)
|
|
# SERVICE="erpcore@test"
|
|
# BACKEND_PORT=5230
|
|
# WEB_CONTAINER="erp-web-test"
|
|
# WEB_PORT=3030
|
|
# DB_NAME="ERPCoreStaging"
|
|
# BACKUP_POLICY="on-migration"
|
|
# HEALTH_TIMEOUT=90
|
|
# PUBLIC_URL="https://test-erp.hexdive.com"
|
|
# ;;
|
|
# ON HOLD — the two-environment layout for release (/opt/erpcore, erpcore@release). NOT how
|
|
# production runs today: the active deploy is .gitea/workflows/ci-cd.yml → erpcore.service +
|
|
# /home/erp/core/publish. Nothing active calls load_env.
|
|
# release)
|
|
# SERVICE="erpcore@release"
|
|
# BACKEND_PORT=5220
|
|
# WEB_CONTAINER="erp-web"
|
|
# WEB_PORT=3020
|
|
# DB_NAME="ERPCore"
|
|
# BACKUP_POLICY="always"
|
|
# HEALTH_TIMEOUT=300
|
|
# PUBLIC_URL="https://erp.hexdive.com"
|
|
# ;;
|
|
*) fail "unknown environment '$ERP_ENV' (expected test or release)" ;;
|
|
esac
|
|
ENV_DIR="$ERP_ROOT/$ERP_ENV"
|
|
STATE_DIR="$ENV_DIR/.deployed"
|
|
CURRENT_LINK="$ENV_DIR/backend/current"
|
|
}
|
|
|
|
# env_for_branch <branch> — the environment a push to <branch> deploys to.
|
|
env_for_branch() {
|
|
case "$1" in
|
|
# ON HOLD — test environment: Dev) echo test ;;
|
|
production) echo release ;;
|
|
*) return 1 ;;
|
|
esac
|
|
}
|
|
|
|
# tree_hash <path> [rev] — git tree (or blob) id of a path. Identical folder content gives an
|
|
# identical hash no matter which commit, branch or merge produced it — that is what lets a
|
|
# Dev → production release reuse the build test already made. Empty if the path is absent.
|
|
tree_hash() { git rev-parse --verify --quiet "${2:-HEAD}:$1" 2>/dev/null || true; }
|
|
|
|
read_state() { cat "$STATE_DIR/$1" 2>/dev/null || true; }
|
|
write_state() {
|
|
mkdir -p "$STATE_DIR"
|
|
printf '%s\n' "$2" >"$STATE_DIR/$1.tmp"
|
|
mv -f "$STATE_DIR/$1.tmp" "$STATE_DIR/$1"
|
|
}
|
|
# record_history <side> <hash> <result> — append-only audit of every deploy attempt.
|
|
record_history() {
|
|
mkdir -p "$STATE_DIR"
|
|
printf '%s\t%s\t%s\t%s\tsha=%s\trun=%s\n' "$(date -u +%FT%TZ)" "$1" "$2" "$3" \
|
|
"${GITHUB_SHA:-manual}" "${GITHUB_RUN_NUMBER:-}" >>"$STATE_DIR/history.log"
|
|
}
|
|
|
|
# set_output <name> <value> — Gitea Actions step output (only logged when run by hand).
|
|
set_output() {
|
|
if [[ -n "${GITHUB_OUTPUT:-}" ]]; then printf '%s=%s\n' "$1" "$2" >>"$GITHUB_OUTPUT"; fi
|
|
log "$1=$2"
|
|
}
|
|
|
|
# with_build_lock — serialize heavy work on this host. The runner's capacity is 1 today; this
|
|
# keeps two jobs from writing the same releases/<hash>.tmp or image tag if that is ever raised.
|
|
with_build_lock() {
|
|
mkdir -p "$ERP_ROOT"
|
|
exec 9>"$BUILD_LOCK"
|
|
flock 9
|
|
}
|
|
|
|
# git_remote <git args...> — run git with the ERPSECRET token as an HTTP header (never echoed,
|
|
# never written to .git/config).
|
|
git_remote() {
|
|
: "${ERP_GIT_TOKEN:?ERP_GIT_TOKEN (secrets.ERPSECRET) is required}"
|
|
local basic
|
|
basic="$(printf 'oauth2:%s' "$ERP_GIT_TOKEN" | base64 | tr -d '\n')"
|
|
git -c "http.extraHeader=Authorization: Basic $basic" "$@"
|
|
}
|
|
|
|
# selinux_mount_suffix — ":z" relabels bind mounts on SELinux hosts (AlmaLinux) so containers
|
|
# can read them; empty elsewhere (e.g. a developer laptop).
|
|
selinux_mount_suffix() {
|
|
if command -v selinuxenabled >/dev/null 2>&1 && selinuxenabled; then echo ":z"; fi
|
|
}
|